📄 jar.c
字号:
/* * Copyright (c) 1998-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: jar.c * OVERVIEW: Structures and operations for reading a jar file. * The JAR file can either be a file, or it can be mapped * into memory. * AUTHOR: Tasneem Sayeed, Consumer & Embedded division * Frank Yellin *=======================================================================*//*========================================================================= * Include files *=======================================================================*/#include "global.h"#include "jar.h"#include "inflate.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/* 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 DECLARE_TEMPORARY_ROOT# undef DECLARE_TEMPORARY_ROOT_FROM_BASE# define START_TEMPORARY_ROOTS {# define END_TEMPORARY_ROOTS }# define mallocBytes(x) malloc(x)# define DECLARE_TEMPORARY_ROOT(type, name, value) type name = value# define DECLARE_TEMPORARY_ROOT_FROM_BASE(type, name, value, base) \ type name = value# define freeBytes(x) free(x)#else# define freeBytes(x)#endif#if JAR_FILES_USE_STDIO#include "stdio.h"#endif/*========================================================================= * Forward declarations of static functions *=======================================================================*/static void *loadJARFileEntryInternal(JAR_INFO entry, const unsigned char *centralInfo, long *lengthP, int extraBytes);static unsigned long jarCRC32(unsigned char *data, unsigned long length);static int jar_getBytes(char *, int, void* p);/*========================================================================= * JAR Data Stream structure *=======================================================================*/#define LOCSIG (('P' << 0) + ('K' << 8) + (3 << 16) + (4 << 24))#define CENSIG (('P' << 0) + ('K' << 8) + (1 << 16) + (2 << 24))#define ENDSIG (('P' << 0) + ('K' << 8) + (5 << 16) + (6 << 24))/* * Supported compression types */#define STORED 0#define DEFLATED 8/* * Header sizes including signatures */#define LOCHDRSIZ 30#define CENHDRSIZ 46#define ENDHDRSIZ 22/* * Header field access macros */#define CH(b, n) ((long)(((unsigned char *)(b))[n]))#define SH(b, n) ((long)(CH(b, n) | (CH(b, n+1) << 8)))#define LG(b, n) ((long)(SH(b, n) | (SH(b, n+2) << 16)))#define GETSIG(b) LG(b, 0) /* signature *//* * Macros for getting local file header (LOC) fields */#define LOCVER(b) SH(b, 4) /* version needed to extract */#define LOCFLG(b) SH(b, 6) /* encrypt flags */#define LOCHOW(b) SH(b, 8) /* compression method */#define LOCTIM(b) LG(b, 10) /* modification time */#define LOCCRC(b) LG(b, 14) /* uncompressed file crc-32 value */#define LOCSIZ(b) LG(b, 18) /* compressed size */#define LOCLEN(b) LG(b, 22) /* uncompressed size */#define LOCNAM(b) SH(b, 26) /* filename size */#define LOCEXT(b) SH(b, 28) /* extra field size *//* * Macros for getting central directory header (CEN) fields */#define CENVEM(b) SH(b, 4) /* version made by */#define CENVER(b) SH(b, 6) /* version needed to extract */#define CENFLG(b) SH(b, 8) /* general purpose bit flags */#define CENHOW(b) SH(b, 10) /* compression method */#define CENTIM(b) LG(b, 12) /* file modification time (DOS format) */#define CENCRC(b) LG(b, 16) /* crc of uncompressed data */#define CENSIZ(b) LG(b, 20) /* compressed size */#define CENLEN(b) LG(b, 24) /* uncompressed size */#define CENNAM(b) SH(b, 28) /* length of filename */#define CENEXT(b) SH(b, 30) /* length of extra field */#define CENCOM(b) SH(b, 32) /* file comment length */#define CENDSK(b) SH(b, 34) /* disk number start */#define CENATT(b) SH(b, 36) /* internal file attributes */#define CENATX(b) LG(b, 38) /* external file attributes */#define CENOFF(b) LG(b, 42) /* offset of local header *//* * Macros for getting end of central directory header (END) fields */#define ENDSUB(b) SH(b, 8) /* number of entries on this disk */#define ENDTOT(b) SH(b, 10) /* total number of entries */#define ENDSIZ(b) LG(b, 12) /* central directory size */#define ENDOFF(b) LG(b, 16) /* central directory offset */#define ENDCOM(b) SH(b, 20) /* size of zip file comment *//*========================================================================= * JAR file reading operations *=======================================================================*//*========================================================================= * FUNCTION: openJARFile * OVERVIEW: Opens a Jar file so that it can be read using * loadJARFileEntry or by loadJARFileEntries * * This function has two slightly different calling sequences, depending on * whether JAR files are read using STDIO (JAR_FILES_USE_STDIO) or whether * they are already in memory: * parameters: * nameOrAddress: * JAR_FILES_USE_STDIO: name of the jar file * !JAR_FILES_USE_STDIO: address of the jar file * length: * JAR_FILES_USE_STDIO: ignored * !JAR_FILES_USE_STDIO: length of the jar file * entry: * Address of data structure that is filled in with information about * the JAR file, if the "open" is successful. * * returns: * TRUE if the "open" succeeds, false otherwise. *=======================================================================*/bool_topenJARFile(void *nameOrAddress, int length, JAR_INFO entry){ long currentOffset, minOffset; unsigned const char *bp;#if JAR_FILES_USE_STDIO unsigned char *buffer = (unsigned char *)str_buffer; unsigned const int bufferSize = STRINGBUFFERSIZE; FILE *file = fopen((char *)nameOrAddress, "rb"); if (file == NULL) { goto failureReturn; } /* Get the length of the file */ fseek(file, 0, SEEK_END); length = ftell(file); fseek(file, 0, SEEK_SET);#else const unsigned char *jarFile = nameOrAddress; const unsigned char *buffer;#endif /* JAR_FILES_USE_STDIO */ /* Calculate the smallest possible offset for the end header. It * can be at most 0xFFFF + ENDHDRSIZ bytes from the end of the file, but * the file must also have a local header and a central header */ minOffset = length - (0xFFFF + ENDHDRSIZ); if (minOffset < LOCHDRSIZ + CENHDRSIZ) { minOffset = LOCHDRSIZ + CENHDRSIZ; } /* In order to simplify the code, both JAR_FILES_USE_STDIO and * !JAR_FILES_USE_STDIO assume that "buffer" contains the contents * of part of the file. currentOffset contains the offset of buffer[0]. * * For JAR_FILES_USE_STDIO, buffer is a temporary buffer into which we * read the contents of the file. For !JAR_FILES_USE_STDIO, buffer * is a pointer into the actual jar file. */#if JAR_FILES_USE_STDIO /* Read in the last ENDHDRSIZ bytes into the buffer. 99% of the time, * the file won't have a comment, and this is the only read we'll need */ if ( (fseek(file, -ENDHDRSIZ, SEEK_END) < 0) || (fread(buffer, sizeof(char), ENDHDRSIZ, file) != ENDHDRSIZ)) { goto failureReturn; } /* Set currentOffset to be the offset of buffer[0] */ currentOffset = length - ENDHDRSIZ; /* Set bp to be the location at which to start looking */ bp = buffer;#else /* Create a pseudo buffer, that actually points at the jarFile */ buffer = jarFile + minOffset; /* Set currentOffset to be the offset of buffer[0] */ currentOffset = minOffset; /* Set bp to be the location at which to start looking */ bp = jarFile + length - ENDHDRSIZ; /* Where to start looking */#endif /* JAR_FILES_USE_STDIO */ for (;;) { /* "buffer" contains a block of data from the file, starting at * currentOffset "position" in the file. * We investigate whether currentOffset + (bp - buffer) is the start * of the end header in the zip file. * * We use a simplified version of Knuth-Morris-Pratt search algorithm. * The header we're looking for is 'P' 'K' 5 6 */ switch(bp[0]) { case '\006': /* The header must start at least 3 bytes back */ bp -= 3; break; case '\005': /* The header must start at least 2 bytes back */ bp -= 2; break; case 'K': /* The header must start at least 1 byte back */ bp -= 1; break; case 'P': /* Either this is the header, or the header must * start at least 4 back */ if (bp[1] == 'K' && bp[2] == 5 && bp[3] == 6) { /* We have what may be a header. Let's make sure the * implied length of the jar file matches the actual * length. */ int endpos = currentOffset + (bp - buffer); if (endpos + ENDHDRSIZ + ENDCOM(bp) == length) { unsigned long cenOffset = endpos - ENDSIZ(bp); unsigned long locOffset = cenOffset - ENDOFF(bp);#if JAR_FILES_USE_STDIO if ( fseek(file, locOffset, SEEK_SET) >= 0 && getc(file) == 'P' && getc(file) == 'K' && getc(file) == 3 && getc(file) == 4) { entry->u.jar.file = file; entry->u.jar.cenOffset = cenOffset; entry->u.jar.locOffset = locOffset; return TRUE; }#else const unsigned char *cenPtr = jarFile + cenOffset; const unsigned char *locPtr = jarFile + locOffset; if (GETSIG(locPtr) == LOCSIG) { entry->u.mjar.base = jarFile; entry->u.mjar.cenPtr = cenPtr; entry->u.mjar.locPtr = locPtr; return TRUE; }#endif /* JAR_FILES_USE_STDIO */ goto failureReturn; } } /* FALL THROUGH */ default: /* The header must start at least four characters back, since * the current character isn't in the header */ bp -= 4; } if (bp < buffer) {#if JAR_FILES_USE_STDIO /* We've moved outside our window into the file. We must * move the window backwards */ int count = currentOffset - minOffset; /* Bytes left in file */ if (count <= 0) { /* Nothing left to read. Time to give up */ goto failureReturn; } else { /* up to ((bp - buffer) + ENDHDRSIZ) bytes in the buffer might * still be part of the end header, so the most bytes we can * actually read are * bufferSize - ((bp - buffer) + ENDHDRSIZE). */ int available = (bufferSize - ENDHDRSIZ) + (buffer - bp); if (count > available) { count = available; } } /* Back up, while keeping our virtual currentOffset the same */ currentOffset -= count; bp += count; memmove(buffer + count, buffer, bufferSize - count); if ( (fseek(file, currentOffset, SEEK_SET) < 0) || (fread(buffer, sizeof(char), count, file) != (unsigned)count)) { goto failureReturn; }#else /* There's nothing left to do. */ goto failureReturn;#endif /* JAR_FILE_USE_STDIO */ } } /* end of for loop */failureReturn: #if JAR_FILES_USE_STDIO if (file != NULL) { fclose(file); }#endif /* JAR_FILES_USE_STDIO */ return FALSE;}/*========================================================================= * FUNCTION: closeJARFile * OVERVIEW: Close a jar file that had previous been opened by * openJARFile * parameters: * JAR_INFO: structure previously filled in by openJARFile * * returns: * nothing
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -