📄 inflate.c
字号:
/* * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. * * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING * THIS SOFTWARE OR ITS DERIVATIVES. * * Use is subject to license terms. *//*========================================================================= * SYSTEM: KVM * SUBSYSTEM: JAR file reader / inflater. * FILE: inflate.c * OVERVIEW: Routines for inflating (decompressing) the contents * of a JAR file. The routines are optimized to reduce * code size and run-time memory requirement so that * they can run happily on small devices. * AUTHOR: Ioi Lam, Consumer & Embedded, Sun Microsystems, Inc. * Refined by Tasneem Sayeed, Consumer & Embedded * Frank Yellin *=======================================================================*//*========================================================================= * Include files *=======================================================================*/#ifdef INFLATE_DEBUG_FILE#include "sys/stat.h"#endif#include "global.h"#include "assert.h"#include "jar.h"/* Assume that we're being compiled as part of the KVM, unless told * otherwise */#ifndef COMPILING_FOR_KVM# define COMPILING_FOR_KVM 1#endif#include "inflate.h"#include "inflateint.h"#include "inflatetables.h"static bool_t decodeDynamicHuffmanTables(inflaterState *state, HuffmanCodeTable **lcodesPtr, HuffmanCodeTable **dcodesPtr);static HuffmanCodeTable *makeCodeTable(inflaterState *state, unsigned char *codelen, unsigned numElems, unsigned maxQuickBits);static bool_t inflateHuffman(inflaterState *state, bool_t fixedHuffman);static bool_t inflateStored(inflaterState *state);/*========================================================================= * Decompression functions *=======================================================================*//*=========================================================================== * FUNCTION: inflateData * TYPE: jar file decoding * INTERFACE: * parameters: method, compressed data, compressed length, * decompressed data, decompressed size * returns: TRUE if the data was encoded in a supported <method> and the * size of the decoded data is exactly the same as <decompLen> * FALSE if an error occurs * NOTE: * The caller of this method must insure that this function can safely * up to INFLATER_EXTRA_BYTES beyond compData + compLen without causing * any problems. * The inflater algorithm occasionally reads one more byte than it needs * to. But it double checks that it doesn't actually care what's in that * extra byte. *===========================================================================*//* Change some definitions so that this compiles niceless, even if it * compiled as part of something that requires real malloc() and free() */#if !COMPILING_FOR_KVM# undef START_TEMPORARY_ROOTS# undef END_TEMPORARY_ROOTS# undef ASSERTING_NO_ALLOCATION # undef END_ASSERTING_NO_ALLOCATION # undef INDICATE_DYNAMICALLY_INSIDE_TEMPORARY_ROOTS# undef IS_TEMPORARY_ROOT# define START_TEMPORARY_ROOTS# define END_TEMPORARY_ROOTS# define ASSERTING_NO_ALLOCATION # define END_ASSERTING_NO_ALLOCATION # define INDICATE_DYNAMICALLY_INSIDE_TEMPORARY_ROOTS# define IS_TEMPORARY_ROOT(var, value) var = value# define mallocBytes(x) malloc(x)# define freeBytes(x) if (x == NULL) {} else free(x)#else# define freeBytes(x)#endif/* These three macros are provided because some ports may want to * put the output bytes into something other than the provided outFile * buffer. */#ifndef INFLATER_PUT_BYTE# define INFLATER_PUT_BYTE(offset, value) outFile[offset] = value;#endif#ifndef INFLATER_GET_BYTE# define INFLATER_GET_BYTE(offset) outFile[offset]#endif#ifndef INFLATER_FLUSH_OUTPUT# define INFLATER_FLUSH_OUTPUT()#endifbool_tinflateData(void *compData, /* compressed data source */ JarGetByteFunctionType getBytes, int compLen, /* length of compressed data */ UNSIGNED_CHAR_HANDLE decompData, int decompLen) /* length of decompression buffer */{ inflaterState stateStruct; bool_t result; inflateBufferIndex = inflateBufferCount = 0;/* Temporarily define state, so that LOAD_IN, LOAD_OUT, etc. macros work */#define state (&stateStruct) stateStruct.outFileH = decompData; stateStruct.outOffset = 0; stateStruct.outLength = decompLen; stateStruct.inFile = compData; stateStruct.inData = 0; stateStruct.inDataSize = 0; stateStruct.inRemaining = compLen + INFLATER_EXTRA_BYTES; stateStruct.getBytes = getBytes;#ifdef INFLATE_DEBUG_FILE { static int length = 0; if (length == 0) { struct stat stat_buffer; stat(INFLATE_DEBUG_FILE, &stat_buffer); length = stat_buffer.st_size;; } if (length == decompLen) { FILE *f = fopen(INFLATE_DEBUG_FILE, "rb"); state->jarDebugBytes = malloc(length); fseek(f, 0, SEEK_SET); fread(state->jarDebugBytes, sizeof(char), length, f); fclose(f); } else { state->jarDebugBytes = NULL; } }#endif for(;;) { int type; DECLARE_IN_VARIABLES LOAD_IN; NEEDBITS(3); type = NEXTBITS(3); DUMPBITS(3); STORE_IN; switch (type >> 1) { default: case BTYPE_INVALID: ziperr(KVM_MSG_JAR_INVALID_BTYPE); result = FALSE; break; case BTYPE_NO_COMPRESSION: result = inflateStored(state); break; case BTYPE_FIXED_HUFFMAN: result = inflateHuffman(state, TRUE); break; case BTYPE_DYNA_HUFFMAN: START_TEMPORARY_ROOTS result = inflateHuffman(state, FALSE); END_TEMPORARY_ROOTS break; } if (!result) { break; } else if (type & 1) { INFLATER_FLUSH_OUTPUT(); if (state->inRemaining + (state->inDataSize >> 3) != INFLATER_EXTRA_BYTES) { ziperr(KVM_MSG_JAR_INPUT_BIT_ERROR); result = FALSE; } else if (state->outOffset != state->outLength) { ziperr(KVM_MSG_JAR_OUTPUT_BIT_ERROR); result = FALSE; } break; } }#ifdef INFLATE_DEBUG_FILE if (state->jarDebugBytes != NULL) { free(state->jarDebugBytes); }#endif /* Remove temporary definition of state defined above */#undef state return result;}static bool_tinflateStored(inflaterState *state){ DECLARE_IN_VARIABLES DECLARE_OUT_VARIABLES unsigned len, nlen; LOAD_IN; LOAD_OUT; DUMPBITS(inDataSize & 7); /* move to byte boundary */ NEEDBITS(32) len = NEXTBITS(16); DUMPBITS(16); nlen = NEXTBITS(16); DUMPBITS(16); ASSERT(inDataSize == 0); if (len + nlen != 0xFFFF) { ziperr(KVM_MSG_JAR_BAD_LENGTH_FIELD); return FALSE; } else if (inRemaining < len) { ziperr(KVM_MSG_JAR_INPUT_OVERFLOW); return FALSE; } else if (outOffset + len > outLength) { ziperr(KVM_MSG_JAR_OUTPUT_OVERFLOW); return FALSE; } else { int count; while (len > 0) { if (inflateBufferCount > 0) { /* we have data buffered, copy it first */ memcpy(&outFile[outOffset], &inflateBuffer[inflateBufferIndex], (count = (inflateBufferCount <= len ? inflateBufferCount : len))); len -= count; inflateBufferCount -= count; inflateBufferIndex += count; outOffset += count; inRemaining -= count; } if (len > 0) { /* need more, refill the buffer */ outFile[outOffset++] = NEXTBYTE; len--; inRemaining--; } } } STORE_IN; STORE_OUT; return TRUE;}static bool_tinflateHuffman(inflaterState *state, bool_t fixedHuffman){ bool_t noerror = FALSE; DECLARE_IN_VARIABLES DECLARE_OUT_VARIABLES unsigned int quickDataSize = 0, quickDistanceSize = 0; unsigned int code, litxlen; HuffmanCodeTable *lcodes, *dcodes; if (!fixedHuffman) { INDICATE_DYNAMICALLY_INSIDE_TEMPORARY_ROOTS; IS_TEMPORARY_ROOT(lcodes, NULL); IS_TEMPORARY_ROOT(dcodes, NULL); if (!decodeDynamicHuffmanTables(state, &lcodes, &dcodes)) { noerror = TRUE; goto done; } quickDataSize = lcodes->h.quickBits; quickDistanceSize = dcodes->h.quickBits; UPDATE_IN_OUT_AFTER_POSSIBLE_GC; } LOAD_IN; LOAD_OUT; for (;;) { if (inRemaining < 0) { goto done_loop; } NEEDBITS(MAX_BITS + MAX_ZIP_EXTRA_LENGTH_BITS); if (fixedHuffman) { /* literal (hex) * 0x100 - 0x117 7 0.0000.00 - 0.0101.11 * 0 - 8f 8 0.0110.000 - 1.0111.111 * 118 - 11f 8 1.1000.000 - 1.1000.111 * 90 - ff 9 1.1001.0000 - 1.1111.1111 */ /* Get 9 bits, and reverse them. */ code = NEXTBITS(9); code = REVERSE_9BITS(code); if (code < 0x060) { /* A 7-bit code */ DUMPBITS(7); litxlen = 0x100 + (code >> 2); } else if (code < 0x190) { DUMPBITS(8); litxlen = (code >> 1) + ((code < 0x180) ? (0x000 - 0x030) : (0x118 - 0x0c0)); } else { DUMPBITS(9); litxlen = 0x90 + code - 0x190; } } else { GET_HUFFMAN_ENTRY(lcodes, quickDataSize, litxlen, done_loop); } if (litxlen <= 255) { if (outOffset < outLength) {#ifdef INFLATE_DEBUG_FILE if (state->jarDebugBytes && state->jarDebugBytes[outOffset] != litxlen) { ziperr(KVM_MSG_JAR_DRAGON_SINGLE_BYTE); }#endif INFLATER_PUT_BYTE(outOffset, litxlen); outOffset++; } else { goto done_loop; } } else if (litxlen == 256) { /* end of block */ noerror = TRUE; goto done_loop; } else if (litxlen > 285) { ziperr(KVM_MSG_JAR_INVALID_LITERAL_OR_LENGTH); goto done_loop; } else { unsigned int n = litxlen - LITXLEN_BASE; unsigned int length = ll_length_base[n]; unsigned int moreBits = ll_extra_bits[n]; unsigned int d0, distance; /* The NEEDBITS(..) above took care of this */ length += NEXTBITS(moreBits); DUMPBITS(moreBits); NEEDBITS(MAX_BITS); if (fixedHuffman) { d0 = REVERSE_5BITS(NEXTBITS(5)); DUMPBITS(5);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -