📄 jar.c
字号:
*=======================================================================*/voidcloseJARFile(JAR_INFO entry){#if JAR_FILES_USE_STDIO fclose((FILE *)entry->u.jar.file);#endif}/*========================================================================= * FUNCTION: loadJARFileEntry() * OVERVIEW: Reads an entry in a jar file * * INTERFACE: * parameters: JAR_INFO: structure returned by openJARFile * filename: name of entry to read * lengthP: on return, contains length of entry in jar file * (does >>NOT<< include extraBytes) * extraBytes: value has this many extra bytes padded at the * beginning. * * NOTE: The result is malloc'ed on the heap. It is up to the caller to protect * this result from garbage collection *=======================================================================*/void *loadJARFileEntry(JAR_INFO entry, const char *filename, long *lengthP, int extraBytes){ unsigned int filenameLength = strlen(filename); unsigned int nameLength;#if JAR_FILES_USE_STDIO unsigned char *p = (unsigned char *)str_buffer; /* temporary storage */ int offset = entry->u.jar.cenOffset; /* offset of first header */ FILE *file = entry->u.jar.file;#else unsigned const char *p = entry->u.mjar.cenPtr; /* pointer to first header */#endif while(TRUE) { #if JAR_FILES_USE_STDIO /* Offset contains the offset of the next central header. Read the * header into the temporary buffer */ if (/* Go to the header */ (fseek(file, offset, SEEK_SET) < 0) /* Read the bytes */ || (fread(p, sizeof(char), CENHDRSIZ, file) != CENHDRSIZ)) { return NULL; }#endif /* p contains the current central header */ if (GETSIG(p) != CENSIG) { /* We've reached the end of the headers */ return NULL; } nameLength = CENNAM(p); if (nameLength == filenameLength) { #if JAR_FILES_USE_STDIO if (fread(p + CENHDRSIZ, sizeof(char), nameLength, file) != nameLength) { return NULL; }#endif if (memcmp(p + CENHDRSIZ, filename, nameLength) == 0) { break; } }#if JAR_FILES_USE_STDIO /* Set offset to the next central header */ offset += CENHDRSIZ + nameLength + CENEXT(p) + CENCOM(p);#else /* Have p point to the next central header */ p += CENHDRSIZ + nameLength + CENEXT(p) + CENCOM(p);#endif } return loadJARFileEntryInternal(entry, p, lengthP, extraBytes);}/*========================================================================= * FUNCTION: loadJARFileEntries() * OVERVIEW: Reads multiple jar entries from a jar file * * INTERFACE: * parameters: JAR_INFO: structure returned by openJARFile * testFunction: callback to determine whether to read * the specified file * runFunction: callback called after each jar file is read. * info: Info passed to testFunction and runFunction. * * NOTE: The jar files are malloc'ed on the heap. It is up to the caller * to ensure that they are handled correctly. * * The testFuction is called as: * bool_t testFunction(const char *name, int nameLength, * int *extraBytes, void *info) * It should return TRUE or FALSE, indicating whether to read the specified * jar file or not. * name: name of entry (not NULL terminated) * nameLength: length of name * extraBytes: *extraBytes contains 0, but the test function can * change this to indicate that padding is needed at the * beginning of the entry. * info: Arg passed to loadJARFileEntries * * The runFunction is called for any entry for which the testFunction * returned TRUE * void runFunction(const char *name, int nameLength, * void *value, long length, void*info); * The arguments are as follows: * name: name of entry (not NULL terminated) * nameLength: length of name * value: Decoded jar entry, or NULL if a problem. * length: Length of jar file entry (not included extra bytes) * info: Arg passed to loadJARFileEntries *=======================================================================*/voidloadJARFileEntries(JAR_INFO entry, JARFileTestFunction testFunction, JARFileRunFunction runFunction, void *info){ const char *name; unsigned int nameLength;#if JAR_FILES_USE_STDIO unsigned char *p = (unsigned char *)str_buffer; /* temporary storage */ FILE *file = entry->u.jar.file; unsigned long offset = entry->u.jar.cenOffset;#else /* Start at the beginning of the central header */ unsigned const char *p = entry->u.mjar.cenPtr; #endif for (;;) { #if JAR_FILES_USE_STDIO if (/* Go to the next central header */ (fseek(file, offset, SEEK_SET) < 0) /* Read the bytes */ || (fread(p, sizeof(char), CENHDRSIZ, file) != CENHDRSIZ) ) { break; } /* Set offset to the next central header */#endif if (GETSIG(p) != CENSIG) { /* We've reached the end of the headers */ break; } name = (const char *)p + CENHDRSIZ; nameLength = CENNAM(p); #if JAR_FILES_USE_STDIO if (fread(p+CENHDRSIZ, sizeof(char), nameLength, file) != nameLength) { break; } /* We need to update the offset now, rather than later, since * the temporary buffer might get overwritten. */ offset += CENHDRSIZ + nameLength + CENEXT(p) + CENCOM(p);#endif if (name[nameLength - 1] != '/') { START_TEMPORARY_ROOTS DECLARE_TEMPORARY_ROOT(JAR_INFO, entryX, entry); int extraBytes = 0; if (testFunction(name, nameLength, &extraBytes, info)) { long length; unsigned char *value = loadJARFileEntryInternal(entryX, p, &length, extraBytes); runFunction(name, nameLength, value, length, info); } entry = entryX; END_TEMPORARY_ROOTS }#if !JAR_FILES_USE_STDIO p += CENHDRSIZ + nameLength + CENEXT(p) + CENCOM(p);#endif }}/*========================================================================= * FUNCTION: loadJARFileEntryInternal() * OVERVIEW: Internal function for reading a jar file * * parameters: * JAR_INFO: structure returned by openJARFile. * centralInfo: pointer to info in central directory for this entry * lengthP: On return, contains length of the entry (not including * padding caused by extraBytes) * extraBytes: Pad the entry with this many extra bytes at the front. * returns: * result of decompressing the Jar entry. * * NOTE: If JAR_FILES_USE_STDIO, then centralInfo points at str_buffer, * which contains the central header. If !JAR_FILES_USE_STDIO, then * centralInfo points at the actual bytes. */ static void *loadJARFileEntryInternal(JAR_INFO entry, const unsigned char *centralInfo, long *lengthP, int extraBytes) { unsigned long decompLen = CENLEN(centralInfo); /* the decompressed length */ unsigned long compLen = CENSIZ(centralInfo); /* the compressed length */ unsigned long method = CENHOW(centralInfo); /* how it is stored */ unsigned long expectedCRC = CENCRC(centralInfo); /* expected CRC */ unsigned long actualCRC; unsigned char *result = NULL;#if JAR_FILES_USE_STDIO FILE *file = entry->u.jar.file; unsigned long locOffset = entry->u.jar.locOffset; unsigned char *p = (unsigned char *)str_buffer;#else unsigned const char *locPtr = entry->u.mjar.locPtr; const unsigned char *p;#endif /* Make sure file is not encrypted */ if ((CENFLG(centralInfo) & 1) == 1) { goto errorReturn; } /* This may cause a GC, so we have to extract out of "entry" all the * info we need, before calling this. */ result = (unsigned char *)mallocBytes(extraBytes + decompLen);#if !COMPILING_FOR_KVM if (result == NULL) { goto errorReturn; }#endif#if JAR_FILES_USE_STDIO if (/* Go to the beginning of the LOC header */ (fseek(file, locOffset + CENOFF(centralInfo), SEEK_SET) < 0) /* Read it */ || (fread(p, sizeof(char), LOCHDRSIZ, file) != LOCHDRSIZ) /* Skip over name and extension, if any */ || (fseek(file, LOCNAM(p) + LOCEXT(p), SEEK_CUR) < 0)) { goto errorReturn; }#else /* Go to the beginning of the LOC header */ p = locPtr + CENOFF(centralInfo); /* Skip over the actual bits of the header */ p += LOCHDRSIZ + LOCNAM(p) + LOCEXT(p);#endif switch (method) { case STORED: /* The actual bits are right there in the file */ if (compLen != decompLen) { goto errorReturn; }#if JAR_FILES_USE_STDIO fread(result + extraBytes, sizeof(char), decompLen, file);#else memcpy(result + extraBytes, p, decompLen);#endif break; case DEFLATED: { bool_t inflateOK; START_TEMPORARY_ROOTS DECLARE_TEMPORARY_ROOT_FROM_BASE(unsigned char*, decompData, result + extraBytes, result);#if JAR_FILES_USE_STDIO void *arg = file;#else void *arg = &p;#endif inflateOK = inflateData(arg, (JarGetByteFunctionType)jar_getBytes, compLen, &decompData, decompLen); /* The inflater can allocate memory, so we need to regenerate * value from decompData. */ result = decompData - extraBytes; END_TEMPORARY_ROOTS if (!inflateOK) { goto errorReturn; } break; } default: /* Unknown method */ goto errorReturn; break; } if (result != NULL) { actualCRC = jarCRC32(result + extraBytes, decompLen); if (actualCRC != expectedCRC) { goto errorReturn; } } *lengthP = decompLen; return (void *)result;errorReturn: freeBytes(result); *lengthP = 0; return NULL;}/*========================================================================= * FUNCTION: jarCRC32 * OVERVIEW: Returns the CRC of an array of bytes, using the same * algorithm as used by the JAR reader. * INTERFACE: * parameters: data: pointer to the array of bytes * length: length of data, in bytes * returns: CRC *=======================================================================*/static unsigned longjarCRC32(unsigned char *data, unsigned long length) { unsigned long crc = 0xFFFFFFFF; unsigned int j; for ( ; length > 0; length--, data++) { crc ^= *data; for (j = 8; j > 0; --j) { crc = (crc & 1) ? ((crc >> 1) ^ 0xedb88320) : (crc >> 1); } } return ~crc;}/* * Callback passed to inflate, to read the next byte of data. */static intjar_getBytes(char *buff, int length, void* p) {#if JAR_FILES_USE_STDIO return fread(buff, sizeof(char), length, (FILE *)p);#else return *(*(unsigned char **)p)++;#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -