/* * Return the uncompressed length of a packed data block, or a * negative error code. */ long rnc_ulen (void *packed) { unsigned char *p = packed; if (blong (p) != RNC_SIGNATURE) return RNC_FILE_IS_NOT_RNC; return blong (p+4); }
/* * Decompress a packed data block. Returns the unpacked length if * successful, or negative error codes if not. * * If COMPRESSOR is defined, it also returns the leeway number * (which gets stored at offset 16 into the compressed-file header) * in `*leeway', if `leeway' isn't NULL. */ long rnc_unpack (void *packed, void *unpacked #ifdef COMPRESSOR , long *leeway #endif , long packed_len, long unpacked_len) { unsigned char *input = packed; unsigned char *output = unpacked; unsigned char *inputend, *outputend; bit_stream bs; huf_table raw, dist, len; unsigned long ch_count; unsigned long ret_len; unsigned out_crc; #ifdef COMPRESSOR long lee = 0; #endif if(unpacked_len >= 0) { ret_len = unpacked_len; outputend = output + ret_len; inputend = input + packed_len; out_crc = 0; goto rnc_unpack_go; } if (blong(input) != RNC_SIGNATURE) return RNC_FILE_IS_NOT_RNC; ret_len = blong (input+4); outputend = output + ret_len; inputend = input + 18 + blong(input+8); input += 18; /* skip header */ /* * Check the packed-data CRC. Also save the unpacked-data CRC * for later. */ if (rnc_crc(input, inputend-input) != bword(input-4)) return RNC_PACKED_CRC_ERROR; out_crc = bword(input-6); rnc_unpack_go: bitread_init (&bs, &input); bit_advance (&bs, 2, &input); /* discard first two bits */ /* * Process chunks. */ while (output < outputend) { #ifdef COMPRESSOR long this_lee; #endif read_huftable (&raw, &bs, &input); read_huftable (&dist, &bs, &input); read_huftable (&len, &bs, &input); ch_count = bit_read (&bs, 0xFFFF, 16, &input); while (1) { long length, posn; length = huf_read (&raw, &bs, &input); if (length == -1) return RNC_HUF_DECODE_ERROR; if (length) { while (length--) *output++ = *input++; bitread_fix (&bs, &input); } if (--ch_count <= 0) break; posn = huf_read (&dist, &bs, &input); if (posn == -1) return RNC_HUF_DECODE_ERROR; length = huf_read (&len, &bs, &input); if (length == -1) return RNC_HUF_DECODE_ERROR; posn += 1; length += 2; while (length--) { *output = output[-posn]; output++; } #ifdef COMPRESSOR this_lee = (inputend - input) - (outputend - output); if (lee < this_lee) lee = this_lee; #endif } } if (outputend != output) return RNC_FILE_SIZE_MISMATCH; #ifdef COMPRESSOR if (leeway) *leeway = lee; #endif if(unpacked_len >= 0) { // do nothing } else { /* * Check the unpacked-data CRC. */ if (rnc_crc(outputend-ret_len, ret_len) != out_crc) return RNC_UNPACKED_CRC_ERROR; } return ret_len; }
// If COMPRESSOR is defined, it also returns the leeway number // (which gets stored at offset 16 into the compressed-file header) // in `*leeway', if `leeway' isn't NULL. long rnc_unpack (void *packed, void *unpacked, unsigned int flags #ifdef COMPRESSOR , long *leeway #endif ) { unsigned char *input = (unsigned char *)packed; unsigned char *output = (unsigned char *)unpacked; unsigned char *inputend, *outputend; bit_stream bs; huf_table raw, dist, len; unsigned long ch_count; unsigned long ret_len, inp_len; long out_crc; #ifdef COMPRESSOR long lee = 0; #endif if (blong(input) != RNC_SIGNATURE) if (!(flags&RNC_IGNORE_HEADER_VAL_ERROR)) return RNC_HEADER_VAL_ERROR; ret_len = blong (input+4); inp_len = blong (input+8); if ((ret_len>(1<<30))||(inp_len>(1<<30))) return RNC_HEADER_VAL_ERROR; outputend = output + ret_len; inputend = input + 18 + inp_len; input += 18; // skip header // Check the packed-data CRC. Also save the unpacked-data CRC // for later. if (rnc_crc(input, inputend-input) != (long)bword(input-4)) if (!(flags&RNC_IGNORE_PACKED_CRC_ERROR)) return RNC_PACKED_CRC_ERROR; out_crc = bword(input-6); bitread_init (&bs, &input, inputend); bit_advance (&bs, 2, &input, inputend); // discard first two bits // Process chunks. while (output < outputend) { #ifdef COMPRESSOR long this_lee; #endif if (inputend-input<6) { if (!(flags&RNC_IGNORE_HUF_EXCEEDS_RANGE)) return RNC_HUF_EXCEEDS_RANGE; else {output=outputend;ch_count=0;break;} } read_huftable (&raw, &bs, &input, inputend); read_huftable (&dist, &bs, &input, inputend); read_huftable (&len, &bs, &input, inputend); ch_count = bit_read (&bs, 0xFFFF, 16, &input, inputend); while (1) { long length, posn; length = huf_read (&raw, &bs, &input,inputend); if (length == -1) { if (!(flags&RNC_IGNORE_HUF_DECODE_ERROR)) return RNC_HUF_DECODE_ERROR; else {output=outputend;ch_count=0;break;} } if (length) { while (length--) { if ((input>=inputend)||(output>=outputend)) { if (!(flags&RNC_IGNORE_HUF_EXCEEDS_RANGE)) return RNC_HUF_EXCEEDS_RANGE; else {output=outputend;ch_count=0;break;} } *output++ = *input++; } bitread_fix (&bs, &input, inputend); } if (--ch_count <= 0) break; posn = huf_read (&dist, &bs, &input,inputend); if (posn == -1) { if (!(flags&RNC_IGNORE_HUF_DECODE_ERROR)) return RNC_HUF_DECODE_ERROR; else {output=outputend;ch_count=0;break;} } length = huf_read (&len, &bs, &input,inputend); if (length == -1) { if (!(flags&RNC_IGNORE_HUF_DECODE_ERROR)) return RNC_HUF_DECODE_ERROR; else {output=outputend;ch_count=0;break;} } posn += 1; length += 2; while (length--) { if (((output-posn)<(unsigned char *)unpacked) || ((output-posn)>(unsigned char *)outputend) || ((output)<(unsigned char *)unpacked) || ((output)>(unsigned char *)outputend)) { if (!(flags&RNC_IGNORE_HUF_EXCEEDS_RANGE)) return RNC_HUF_EXCEEDS_RANGE; else {output=outputend-1;ch_count=0;break;} } *output = output[-posn]; output++; } #ifdef COMPRESSOR this_lee = (inputend - input) - (outputend - output); if (lee < this_lee) lee = this_lee; #endif } } if (outputend != output) { if (!(flags&RNC_IGNORE_FILE_SIZE_MISMATCH)) return RNC_FILE_SIZE_MISMATCH; } #ifdef COMPRESSOR if (leeway) *leeway = lee; #endif // Check the unpacked-data CRC. if (rnc_crc(outputend-ret_len, ret_len) != out_crc) { if (!(flags&RNC_IGNORE_UNPACKED_CRC_ERROR)) return RNC_UNPACKED_CRC_ERROR; } return ret_len; }