示例#1
0
/*
 * 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;
}