Path: blob/master/src/java.base/share/native/libzip/zip_util.c
41149 views
/*1* Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* Support for reading ZIP/JAR files.27*/2829#include <stdio.h>30#include <stdlib.h>31#include <stddef.h>32#include <string.h>33#include <fcntl.h>34#include <limits.h>35#include <time.h>36#include <ctype.h>37#include <assert.h>3839#include "jni.h"40#include "jni_util.h"41#include "jlong.h"42#include "jvm.h"43#include "io_util.h"44#include "io_util_md.h"45#include "zip_util.h"46#include <zlib.h>4748#ifdef _ALLBSD_SOURCE49#define off64_t off_t50#define mmap64 mmap51#endif5253/* USE_MMAP means mmap the CEN & ENDHDR part of the zip file. */54#ifdef USE_MMAP55#include <sys/mman.h>56#endif5758#define MAXREFS 0xFFFF /* max number of open zip file references */5960#define MCREATE() JVM_RawMonitorCreate()61#define MLOCK(lock) JVM_RawMonitorEnter(lock)62#define MUNLOCK(lock) JVM_RawMonitorExit(lock)63#define MDESTROY(lock) JVM_RawMonitorDestroy(lock)6465#define CENSIZE(cen) (CENHDR + CENNAM(cen) + CENEXT(cen) + CENCOM(cen))6667static jzfile *zfiles = 0; /* currently open zip files */68static void *zfiles_lock = 0;6970static void freeCEN(jzfile *);7172#ifndef PATH_MAX73#define PATH_MAX 102474#endif7576static jint INITIAL_META_COUNT = 2; /* initial number of entries in meta name array */7778/*79* Declare library specific JNI_Onload entry if static build80*/81#ifdef STATIC_BUILD82DEF_STATIC_JNI_OnLoad83#endif8485/*86* The ZFILE_* functions exist to provide some platform-independence with87* respect to file access needs.88*/8990/*91* Opens the named file for reading, returning a ZFILE.92*93* Compare this with winFileHandleOpen in windows/native/java/io/io_util_md.c.94* This function does not take JNIEnv* and uses CreateFile (instead of95* CreateFileW). The expectation is that this function will be called only96* from ZIP_Open_Generic, which in turn is used by the JVM, where we do not97* need to concern ourselves with wide chars.98*/99static ZFILE100ZFILE_Open(const char *fname, int flags) {101#ifdef WIN32102WCHAR *wfname, *wprefixed_fname;103size_t fname_length;104jlong fhandle;105const DWORD access =106(flags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :107(flags & O_WRONLY) ? GENERIC_WRITE :108GENERIC_READ;109const DWORD sharing =110FILE_SHARE_READ | FILE_SHARE_WRITE;111const DWORD disposition =112/* Note: O_TRUNC overrides O_CREAT */113(flags & O_TRUNC) ? CREATE_ALWAYS :114(flags & O_CREAT) ? OPEN_ALWAYS :115OPEN_EXISTING;116const DWORD maybeWriteThrough =117(flags & (O_SYNC | O_DSYNC)) ?118FILE_FLAG_WRITE_THROUGH :119FILE_ATTRIBUTE_NORMAL;120const DWORD maybeDeleteOnClose =121(flags & O_TEMPORARY) ?122FILE_FLAG_DELETE_ON_CLOSE :123FILE_ATTRIBUTE_NORMAL;124const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;125126fname_length = strlen(fname);127if (fname_length < MAX_PATH) {128return (jlong)CreateFile(129fname, /* path name in multibyte char */130access, /* Read and/or write permission */131sharing, /* File sharing flags */132NULL, /* Security attributes */133disposition, /* creation disposition */134flagsAndAttributes, /* flags and attributes */135NULL);136} else {137/* Get required buffer size to convert to Unicode */138int wfname_len = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,139fname, -1, NULL, 0);140if (wfname_len == 0) {141return (jlong)INVALID_HANDLE_VALUE;142}143if ((wfname = (WCHAR*)malloc(wfname_len * sizeof(WCHAR))) == NULL) {144return (jlong)INVALID_HANDLE_VALUE;145}146if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,147fname, -1, wfname, wfname_len) == 0) {148free(wfname);149return (jlong)INVALID_HANDLE_VALUE;150}151wprefixed_fname = getPrefixed(wfname, (int)fname_length);152fhandle = (jlong)CreateFileW(153wprefixed_fname, /* Wide char path name */154access, /* Read and/or write permission */155sharing, /* File sharing flags */156NULL, /* Security attributes */157disposition, /* creation disposition */158flagsAndAttributes, /* flags and attributes */159NULL);160free(wfname);161free(wprefixed_fname);162return fhandle;163}164#else165return open(fname, flags, 0);166#endif167}168169/*170* The io_util_md.h files do not provide IO_CLOSE, hence we use platform171* specifics.172*/173static void174ZFILE_Close(ZFILE zfd) {175#ifdef WIN32176CloseHandle((HANDLE) zfd);177#else178close(zfd);179#endif180}181182static int183ZFILE_read(ZFILE zfd, char *buf, jint nbytes) {184#ifdef WIN32185return (int) IO_Read(zfd, buf, nbytes);186#else187return read(zfd, buf, nbytes);188#endif189}190191/*192* Initialize zip file support. Return 0 if successful otherwise -1193* if could not be initialized.194*/195static jint196InitializeZip()197{198static jboolean inited = JNI_FALSE;199200// Initialize errno to 0. It may be set later (e.g. during memory201// allocation) but we can disregard previous values.202errno = 0;203204if (inited)205return 0;206zfiles_lock = MCREATE();207if (zfiles_lock == 0) {208return -1;209}210inited = JNI_TRUE;211212return 0;213}214215/*216* Reads len bytes of data into buf.217* Returns 0 if all bytes could be read, otherwise returns -1.218*/219static int220readFully(ZFILE zfd, void *buf, jlong len) {221char *bp = (char *) buf;222223while (len > 0) {224jlong limit = ((((jlong) 1) << 31) - 1);225jint count = (len < limit) ?226(jint) len :227(jint) limit;228jint n = ZFILE_read(zfd, bp, count);229if (n > 0) {230bp += n;231len -= n;232} else if (n == -1 && errno == EINTR) {233/* Retry after EINTR (interrupted by signal). */234continue;235} else { /* EOF or IO error */236return -1;237}238}239return 0;240}241242/*243* Reads len bytes of data from the specified offset into buf.244* Returns 0 if all bytes could be read, otherwise returns -1.245*/246static int247readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset)248{249if (IO_Lseek(zfd, offset, SEEK_SET) == -1) {250return -1; /* lseek failure. */251}252253return readFully(zfd, buf, len);254}255256/*257* Allocates a new zip file object for the specified file name.258* Returns the zip file object or NULL if not enough memory.259*/260static jzfile *261allocZip(const char *name)262{263jzfile *zip;264if (((zip = calloc(1, sizeof(jzfile))) != NULL) &&265((zip->name = strdup(name)) != NULL) &&266((zip->lock = MCREATE()) != NULL)) {267zip->zfd = -1;268return zip;269}270271if (zip != NULL) {272free(zip->name);273free(zip);274}275return NULL;276}277278/*279* Frees all native resources owned by the specified zip file object.280*/281static void282freeZip(jzfile *zip)283{284/* First free any cached jzentry */285ZIP_FreeEntry(zip,0);286if (zip->lock != NULL) MDESTROY(zip->lock);287free(zip->name);288freeCEN(zip);289290#ifdef USE_MMAP291if (zip->usemmap) {292if (zip->maddr != NULL)293munmap((char *)zip->maddr, zip->mlen);294} else295#endif296{297free(zip->cencache.data);298}299if (zip->comment != NULL)300free(zip->comment);301if (zip->zfd != -1) ZFILE_Close(zip->zfd);302free(zip);303}304305/* The END header is followed by a variable length comment of size < 64k. */306static const jlong END_MAXLEN = 0xFFFF + ENDHDR;307308#define READBLOCKSZ 128309310static jboolean verifyEND(jzfile *zip, jlong endpos, char *endbuf) {311/* ENDSIG matched, however the size of file comment in it does not312match the real size. One "common" cause for this problem is some313"extra" bytes are padded at the end of the zipfile.314Let's do some extra verification, we don't care about the performance315in this situation.316*/317jlong cenpos = endpos - ENDSIZ(endbuf);318jlong locpos = cenpos - ENDOFF(endbuf);319char buf[4];320return (cenpos >= 0 &&321locpos >= 0 &&322readFullyAt(zip->zfd, buf, sizeof(buf), cenpos) != -1 &&323CENSIG_AT(buf) &&324readFullyAt(zip->zfd, buf, sizeof(buf), locpos) != -1 &&325LOCSIG_AT(buf));326}327328/*329* Searches for end of central directory (END) header. The contents of330* the END header will be read and placed in endbuf. Returns the file331* position of the END header, otherwise returns -1 if the END header332* was not found or an error occurred.333*/334static jlong335findEND(jzfile *zip, void *endbuf)336{337char buf[READBLOCKSZ];338jlong pos;339const jlong len = zip->len;340const ZFILE zfd = zip->zfd;341const jlong minHDR = len - END_MAXLEN > 0 ? len - END_MAXLEN : 0;342const jlong minPos = minHDR - (sizeof(buf)-ENDHDR);343jint clen;344345for (pos = len - sizeof(buf); pos >= minPos; pos -= (sizeof(buf)-ENDHDR)) {346347int i;348jlong off = 0;349if (pos < 0) {350/* Pretend there are some NUL bytes before start of file */351off = -pos;352memset(buf, '\0', (size_t)off);353}354355if (readFullyAt(zfd, buf + off, sizeof(buf) - off,356pos + off) == -1) {357return -1; /* System error */358}359360/* Now scan the block backwards for END header signature */361for (i = sizeof(buf) - ENDHDR; i >= 0; i--) {362if (buf[i+0] == 'P' &&363buf[i+1] == 'K' &&364buf[i+2] == '\005' &&365buf[i+3] == '\006' &&366((pos + i + ENDHDR + ENDCOM(buf + i) == len)367|| verifyEND(zip, pos + i, buf + i))) {368/* Found END header */369memcpy(endbuf, buf + i, ENDHDR);370371clen = ENDCOM(endbuf);372if (clen != 0) {373zip->comment = malloc(clen + 1);374if (zip->comment == NULL) {375return -1;376}377if (readFullyAt(zfd, zip->comment, clen, pos + i + ENDHDR)378== -1) {379free(zip->comment);380zip->comment = NULL;381return -1;382}383zip->comment[clen] = '\0';384zip->clen = clen;385}386return pos + i;387}388}389}390391return -1; /* END header not found */392}393394/*395* Searches for the ZIP64 end of central directory (END) header. The396* contents of the ZIP64 END header will be read and placed in end64buf.397* Returns the file position of the ZIP64 END header, otherwise returns398* -1 if the END header was not found or an error occurred.399*400* The ZIP format specifies the "position" of each related record as401* ...402* [central directory]403* [zip64 end of central directory record]404* [zip64 end of central directory locator]405* [end of central directory record]406*407* The offset of zip64 end locator can be calculated from endpos as408* "endpos - ZIP64_LOCHDR".409* The "offset" of zip64 end record is stored in zip64 end locator.410*/411static jlong412findEND64(jzfile *zip, void *end64buf, jlong endpos)413{414char loc64[ZIP64_LOCHDR];415jlong end64pos;416if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) {417return -1; // end64 locator not found418}419end64pos = ZIP64_LOCOFF(loc64);420if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR, end64pos) == -1) {421return -1; // end64 record not found422}423return end64pos;424}425426/*427* Returns a hash code value for a C-style NUL-terminated string.428*/429static unsigned int430hash(const char *s)431{432int h = 0;433while (*s != '\0')434h = 31*h + *s++;435return h;436}437438/*439* Returns a hash code value for a string of a specified length.440*/441static unsigned int442hashN(const char *s, int length)443{444int h = 0;445while (length-- > 0)446h = 31*h + *s++;447return h;448}449450static unsigned int451hash_append(unsigned int hash, char c)452{453return ((int)hash)*31 + c;454}455456/*457* Returns true if the specified entry's name begins with the string458* "META-INF/" irrespective of case.459*/460static int461isMetaName(const char *name, int length)462{463const char *s;464if (length < (int)sizeof("META-INF/") - 1)465return 0;466for (s = "META-INF/"; *s != '\0'; s++) {467char c = *name++;468// Avoid toupper; it's locale-dependent469if (c >= 'a' && c <= 'z') c += 'A' - 'a';470if (*s != c)471return 0;472}473return 1;474}475476/*477* Increases the capacity of zip->metanames.478* Returns non-zero in case of allocation error.479*/480static int481growMetaNames(jzfile *zip)482{483jint i;484/* double the meta names array */485const jint new_metacount = zip->metacount << 1;486zip->metanames =487realloc(zip->metanames, new_metacount * sizeof(zip->metanames[0]));488if (zip->metanames == NULL) return -1;489for (i = zip->metacount; i < new_metacount; i++)490zip->metanames[i] = NULL;491zip->metacurrent = zip->metacount;492zip->metacount = new_metacount;493return 0;494}495496/*497* Adds name to zip->metanames.498* Returns non-zero in case of allocation error.499*/500static int501addMetaName(jzfile *zip, const char *name, int length)502{503jint i;504if (zip->metanames == NULL) {505zip->metacount = INITIAL_META_COUNT;506zip->metanames = calloc(zip->metacount, sizeof(zip->metanames[0]));507if (zip->metanames == NULL) return -1;508zip->metacurrent = 0;509}510511i = zip->metacurrent;512513/* current meta name array isn't full yet. */514if (i < zip->metacount) {515zip->metanames[i] = (char *) malloc(length+1);516if (zip->metanames[i] == NULL) return -1;517memcpy(zip->metanames[i], name, length);518zip->metanames[i][length] = '\0';519zip->metacurrent++;520return 0;521}522523/* No free entries in zip->metanames? */524if (growMetaNames(zip) != 0) return -1;525return addMetaName(zip, name, length);526}527528static void529freeMetaNames(jzfile *zip)530{531if (zip->metanames) {532jint i;533for (i = 0; i < zip->metacount; i++)534free(zip->metanames[i]);535free(zip->metanames);536zip->metanames = NULL;537}538}539540/* Free Zip data allocated by readCEN() */541static void542freeCEN(jzfile *zip)543{544free(zip->entries); zip->entries = NULL;545free(zip->table); zip->table = NULL;546freeMetaNames(zip);547}548549/*550* Counts the number of CEN headers in a central directory extending551* from BEG to END. Might return a bogus answer if the zip file is552* corrupt, but will not crash.553*/554static jint555countCENHeaders(unsigned char *beg, unsigned char *end)556{557jint count = 0;558ptrdiff_t i;559for (i = 0; i + CENHDR <= end - beg; i += CENSIZE(beg + i))560count++;561return count;562}563564#define ZIP_FORMAT_ERROR(message) \565if (1) { zip->msg = message; goto Catch; } else ((void)0)566567/*568* Reads zip file central directory. Returns the file position of first569* CEN header, otherwise returns -1 if an error occurred. If zip->msg != NULL570* then the error was a zip format error and zip->msg has the error text.571* Always pass in -1 for knownTotal; it's used for a recursive call.572*/573static jlong574readCEN(jzfile *zip, jint knownTotal)575{576/* Following are unsigned 32-bit */577jlong endpos, end64pos, cenpos, cenlen, cenoff;578/* Following are unsigned 16-bit */579jint total, tablelen, i, j;580unsigned char *cenbuf = NULL;581unsigned char *cenend;582unsigned char *cp;583#ifdef USE_MMAP584static jlong pagesize;585jlong offset;586#endif587unsigned char endbuf[ENDHDR];588jint endhdrlen = ENDHDR;589jzcell *entries;590jint *table;591592/* Clear previous zip error */593zip->msg = NULL;594/* Get position of END header */595if ((endpos = findEND(zip, endbuf)) == -1)596return -1; /* no END header or system error */597598if (endpos == 0) return 0; /* only END header present */599600freeCEN(zip);601/* Get position and length of central directory */602cenlen = ENDSIZ(endbuf);603cenoff = ENDOFF(endbuf);604total = ENDTOT(endbuf);605if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL ||606total == ZIP64_MAGICCOUNT) {607unsigned char end64buf[ZIP64_ENDHDR];608if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) {609cenlen = ZIP64_ENDSIZ(end64buf);610cenoff = ZIP64_ENDOFF(end64buf);611total = (jint)ZIP64_ENDTOT(end64buf);612endpos = end64pos;613endhdrlen = ZIP64_ENDHDR;614}615}616617if (cenlen > endpos) {618ZIP_FORMAT_ERROR("invalid END header (bad central directory size)");619}620cenpos = endpos - cenlen;621622/* Get position of first local file (LOC) header, taking into623* account that there may be a stub prefixed to the zip file. */624zip->locpos = cenpos - cenoff;625if (zip->locpos < 0) {626ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)");627}628#ifdef USE_MMAP629if (zip->usemmap) {630/* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to631* read the jar file contents. However, this greatly increased the perceived632* footprint numbers because the mmap'ed pages were adding into the totals shown633* by 'ps' and 'top'. We switched to mmaping only the central directory of jar634* file while calling 'read' to read the rest of jar file. Here are a list of635* reasons apart from above of why we are doing so:636* 1. Greatly reduces mmap overhead after startup complete;637* 2. Avoids dual path code maintainance;638* 3. Greatly reduces risk of address space (not virtual memory) exhaustion.639*/640if (pagesize == 0) {641pagesize = (jlong)sysconf(_SC_PAGESIZE);642if (pagesize == 0) goto Catch;643}644if (cenpos > pagesize) {645offset = cenpos & ~(pagesize - 1);646} else {647offset = 0;648}649/* When we are not calling recursively, knownTotal is -1. */650if (knownTotal == -1) {651void* mappedAddr;652/* Mmap the CEN and END part only. We have to figure653out the page size in order to make offset to be multiples of654page size.655*/656zip->mlen = cenpos - offset + cenlen + endhdrlen;657zip->offset = offset;658mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset);659zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL :660(unsigned char*)mappedAddr;661662if (zip->maddr == NULL) {663jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n");664goto Catch;665}666}667cenbuf = zip->maddr + cenpos - offset;668} else669#endif670{671if ((cenbuf = malloc((size_t) cenlen)) == NULL ||672(readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1))673goto Catch;674}675676cenend = cenbuf + cenlen;677678/* Initialize zip file data structures based on the total number679* of central directory entries as stored in ENDTOT. Since this680* is a 2-byte field, but we (and other zip implementations)681* support approx. 2**31 entries, we do not trust ENDTOT, but682* treat it only as a strong hint. When we call ourselves683* recursively, knownTotal will have the "true" value.684*685* Keep this path alive even with the Zip64 END support added, just686* for zip files that have more than 0xffff entries but don't have687* the Zip64 enabled.688*/689total = (knownTotal != -1) ? knownTotal : total;690entries = zip->entries = calloc(total, sizeof(entries[0]));691tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions692table = zip->table = malloc(tablelen * sizeof(table[0]));693/* According to ISO C it is perfectly legal for malloc to return zero694* if called with a zero argument. We check this for 'entries' but not695* for 'table' because 'tablelen' can't be zero (see computation above). */696if ((entries == NULL && total != 0) || table == NULL) goto Catch;697for (j = 0; j < tablelen; j++)698table[j] = ZIP_ENDCHAIN;699700/* Iterate through the entries in the central directory */701for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) {702/* Following are unsigned 16-bit */703jint method, nlen;704unsigned int hsh;705706if (i >= total) {707/* This will only happen if the zip file has an incorrect708* ENDTOT field, which usually means it contains more than709* 65535 entries. */710cenpos = readCEN(zip, countCENHeaders(cenbuf, cenend));711goto Finally;712}713714method = CENHOW(cp);715nlen = CENNAM(cp);716717if (!CENSIG_AT(cp)) {718ZIP_FORMAT_ERROR("invalid CEN header (bad signature)");719}720if (CENFLG(cp) & 1) {721ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)");722}723if (method != STORED && method != DEFLATED) {724ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)");725}726if (cp + CENHDR + nlen > cenend) {727ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");728}729/* if the entry is metadata add it to our metadata names */730if (isMetaName((char *)cp+CENHDR, nlen))731if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0)732goto Catch;733734/* Record the CEN offset and the name hash in our hash cell. */735entries[i].cenpos = cenpos + (cp - cenbuf);736entries[i].hash = hashN((char *)cp+CENHDR, nlen);737738/* Add the entry to the hash table */739hsh = entries[i].hash % tablelen;740entries[i].next = table[hsh];741table[hsh] = i;742}743if (cp != cenend) {744ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");745}746zip->total = i;747goto Finally;748749Catch:750freeCEN(zip);751cenpos = -1;752753Finally:754#ifdef USE_MMAP755if (!zip->usemmap)756#endif757free(cenbuf);758759return cenpos;760}761762/*763* Opens a zip file with the specified mode. Returns the jzfile object764* or NULL if an error occurred. If a zip error occurred then *pmsg will765* be set to the error message text if pmsg != 0. Otherwise, *pmsg will be766* set to NULL. Caller is responsible to free the error message.767*/768jzfile *769ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified)770{771jzfile *zip = NULL;772773/* Clear zip error message */774if (pmsg != NULL) {775*pmsg = NULL;776}777778zip = ZIP_Get_From_Cache(name, pmsg, lastModified);779780if (zip == NULL && pmsg != NULL && *pmsg == NULL) {781ZFILE zfd = ZFILE_Open(name, mode);782zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified);783}784return zip;785}786787/*788* Returns the jzfile corresponding to the given file name from the cache of789* zip files, or NULL if the file is not in the cache. If the name is longer790* than PATH_MAX or a zip error occurred then *pmsg will be set to the error791* message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller792* is responsible to free the error message.793*/794jzfile *795ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified)796{797char buf[PATH_MAX];798jzfile *zip;799800if (InitializeZip()) {801return NULL;802}803804/* Clear zip error message */805if (pmsg != 0) {806*pmsg = NULL;807}808809if (strlen(name) >= PATH_MAX) {810if (pmsg) {811*pmsg = strdup("zip file name too long");812}813return NULL;814}815strcpy(buf, name);816JVM_NativePath(buf);817name = buf;818819MLOCK(zfiles_lock);820for (zip = zfiles; zip != NULL; zip = zip->next) {821if (strcmp(name, zip->name) == 0822&& (zip->lastModified == lastModified || zip->lastModified == 0)823&& zip->refs < MAXREFS) {824zip->refs++;825break;826}827}828MUNLOCK(zfiles_lock);829return zip;830}831832/*833* Reads data from the given file descriptor to create a jzfile, puts the834* jzfile in a cache, and returns that jzfile. Returns NULL in case of error.835* If a zip error occurs, then *pmsg will be set to the error message text if836* pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller is responsible to837* free the error message.838*/839840jzfile *841ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)842{843return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE);844}845846jzfile *847ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified,848jboolean usemmap)849{850char errbuf[256];851jlong len;852jzfile *zip;853854if ((zip = allocZip(name)) == NULL) {855return NULL;856}857858#ifdef USE_MMAP859zip->usemmap = usemmap;860#endif861zip->refs = 1;862zip->lastModified = lastModified;863864if (zfd == -1) {865if (pmsg && getLastErrorString(errbuf, sizeof(errbuf)) > 0)866*pmsg = strdup(errbuf);867freeZip(zip);868return NULL;869}870871// Assumption, zfd refers to start of file. Trivially, reuse errbuf.872if (readFully(zfd, errbuf, 4) != -1) { // errors will be handled later873zip->locsig = LOCSIG_AT(errbuf) ? JNI_TRUE : JNI_FALSE;874}875876len = zip->len = IO_Lseek(zfd, 0, SEEK_END);877if (len <= 0) {878if (len == 0) { /* zip file is empty */879if (pmsg) {880*pmsg = strdup("zip file is empty");881}882} else { /* error */883if (pmsg && getLastErrorString(errbuf, sizeof(errbuf)) > 0)884*pmsg = strdup(errbuf);885}886ZFILE_Close(zfd);887freeZip(zip);888return NULL;889}890891zip->zfd = zfd;892if (readCEN(zip, -1) < 0) {893/* An error occurred while trying to read the zip file */894if (pmsg != 0) {895/* Set the zip error message */896if (zip->msg != NULL)897*pmsg = strdup(zip->msg);898}899freeZip(zip);900return NULL;901}902MLOCK(zfiles_lock);903zip->next = zfiles;904zfiles = zip;905MUNLOCK(zfiles_lock);906907return zip;908}909910/*911* Opens a zip file for reading. Returns the jzfile object or NULL912* if an error occurred. If a zip error occurred then *msg will be913* set to the error message text if msg != 0. Otherwise, *msg will be914* set to NULL. Caller doesn't need to free the error message.915*/916JNIEXPORT jzfile *917ZIP_Open(const char *name, char **pmsg)918{919jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY, 0);920if (file == NULL && pmsg != NULL && *pmsg != NULL) {921free(*pmsg);922*pmsg = "Zip file open error";923}924return file;925}926927/*928* Closes the specified zip file object.929*/930JNIEXPORT void931ZIP_Close(jzfile *zip)932{933MLOCK(zfiles_lock);934if (--zip->refs > 0) {935/* Still more references so just return */936MUNLOCK(zfiles_lock);937return;938}939/* No other references so close the file and remove from list */940if (zfiles == zip) {941zfiles = zfiles->next;942} else {943jzfile *zp;944for (zp = zfiles; zp->next != 0; zp = zp->next) {945if (zp->next == zip) {946zp->next = zip->next;947break;948}949}950}951MUNLOCK(zfiles_lock);952freeZip(zip);953return;954}955956/* Empirically, most CEN headers are smaller than this. */957#define AMPLE_CEN_HEADER_SIZE 160958959/* A good buffer size when we want to read CEN headers sequentially. */960#define CENCACHE_PAGESIZE 8192961962static char *963readCENHeader(jzfile *zip, jlong cenpos, jint bufsize)964{965jint censize;966ZFILE zfd = zip->zfd;967char *cen;968if (bufsize > zip->len - cenpos)969bufsize = (jint)(zip->len - cenpos);970if ((cen = malloc(bufsize)) == NULL) goto Catch;971if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch;972censize = CENSIZE(cen);973if (censize <= bufsize) return cen;974if ((cen = realloc(cen, censize)) == NULL) goto Catch;975if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch;976return cen;977978Catch:979free(cen);980return NULL;981}982983static char *984sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos)985{986cencache *cache = &zip->cencache;987char *cen;988if (cache->data != NULL989&& (cenpos >= cache->pos)990&& (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE))991{992cen = cache->data + cenpos - cache->pos;993if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE)994/* A cache hit */995return cen;996}997998if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL)999return NULL;1000free(cache->data);1001cache->data = cen;1002cache->pos = cenpos;1003return cen;1004}10051006typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;10071008/*1009* Return a new initialized jzentry corresponding to a given hash cell.1010* In case of error, returns NULL.1011* We already sanity-checked all the CEN headers for ZIP format errors1012* in readCEN(), so we don't check them again here.1013* The ZIP lock should be held here.1014*/1015static jzentry *1016newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)1017{1018jlong locoff;1019jint nlen, elen, clen;1020jzentry *ze;1021char *cen;10221023if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;1024ze->name = NULL;1025ze->extra = NULL;1026ze->comment = NULL;10271028#ifdef USE_MMAP1029if (zip->usemmap) {1030cen = (char*) zip->maddr + zc->cenpos - zip->offset;1031} else1032#endif1033{1034if (accessHint == ACCESS_RANDOM)1035cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);1036else1037cen = sequentialAccessReadCENHeader(zip, zc->cenpos);1038if (cen == NULL) goto Catch;1039}10401041nlen = CENNAM(cen);1042elen = CENEXT(cen);1043clen = CENCOM(cen);1044ze->time = CENTIM(cen);1045ze->size = CENLEN(cen);1046ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);1047ze->crc = CENCRC(cen);1048locoff = CENOFF(cen);1049ze->pos = -(zip->locpos + locoff);1050ze->flag = CENFLG(cen);10511052if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;1053memcpy(ze->name, cen + CENHDR, nlen);1054ze->name[nlen] = '\0';1055ze->nlen = nlen;1056if (elen > 0) {1057char *extra = cen + CENHDR + nlen;10581059/* This entry has "extra" data */1060if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;1061ze->extra[0] = (unsigned char) elen;1062ze->extra[1] = (unsigned char) (elen >> 8);1063memcpy(ze->extra+2, extra, elen);1064if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||1065locoff == ZIP64_MAGICVAL) {1066jint off = 0;1067while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data1068jint sz = SH(extra, off + 2);1069if (SH(extra, off) == ZIP64_EXTID) {1070off += 4;1071if (ze->size == ZIP64_MAGICVAL) {1072// if invalid zip64 extra fields, just skip1073if (sz < 8 || (off + 8) > elen)1074break;1075ze->size = LL(extra, off);1076sz -= 8;1077off += 8;1078}1079if (ze->csize == ZIP64_MAGICVAL) {1080if (sz < 8 || (off + 8) > elen)1081break;1082ze->csize = LL(extra, off);1083sz -= 8;1084off += 8;1085}1086if (locoff == ZIP64_MAGICVAL) {1087if (sz < 8 || (off + 8) > elen)1088break;1089ze->pos = -(zip->locpos + LL(extra, off));1090sz -= 8;1091off += 8;1092}1093break;1094}1095off += (sz + 4);1096}1097}1098}10991100if (clen > 0) {1101/* This entry has a comment */1102if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch;1103memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);1104ze->comment[clen] = '\0';1105}1106goto Finally;11071108Catch:1109free(ze->name);1110free(ze->extra);1111free(ze->comment);1112free(ze);1113ze = NULL;11141115Finally:1116#ifdef USE_MMAP1117if (!zip->usemmap)1118#endif1119if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);1120return ze;1121}11221123/*1124* Free the given jzentry.1125* In fact we maintain a one-entry cache of the most recently used1126* jzentry for each zip. This optimizes a common access pattern.1127*/11281129void1130ZIP_FreeEntry(jzfile *jz, jzentry *ze)1131{1132jzentry *last;1133ZIP_Lock(jz);1134last = jz->cache;1135jz->cache = ze;1136ZIP_Unlock(jz);1137if (last != NULL) {1138/* Free the previously cached jzentry */1139free(last->name);1140if (last->extra) free(last->extra);1141if (last->comment) free(last->comment);1142free(last);1143}1144}11451146/*1147* Returns the zip entry corresponding to the specified name, or1148* NULL if not found.1149*/1150jzentry *1151ZIP_GetEntry(jzfile *zip, char *name, jint ulen)1152{1153if (ulen == 0) {1154return ZIP_GetEntry2(zip, name, (jint)strlen(name), JNI_FALSE);1155}1156return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE);1157}11581159jboolean equals(char* name1, int len1, char* name2, int len2) {1160if (len1 != len2) {1161return JNI_FALSE;1162}1163while (len1-- > 0) {1164if (*name1++ != *name2++) {1165return JNI_FALSE;1166}1167}1168return JNI_TRUE;1169}11701171/*1172* Returns the zip entry corresponding to the specified name, or1173* NULL if not found.1174* This method supports embedded null character in "name", use ulen1175* for the length of "name".1176*/1177jzentry *1178ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash)1179{1180unsigned int hsh = hashN(name, ulen);1181jint idx;1182jzentry *ze = 0;11831184ZIP_Lock(zip);1185if (zip->total == 0) {1186goto Finally;1187}11881189idx = zip->table[hsh % zip->tablelen];11901191/*1192* This while loop is an optimization where a double lookup1193* for name and name+/ is being performed. The name char1194* array has enough room at the end to try again with a1195* slash appended if the first table lookup does not succeed.1196*/1197while(1) {11981199/* Check the cached entry first */1200ze = zip->cache;1201if (ze && equals(ze->name, ze->nlen, name, ulen)) {1202/* Cache hit! Remove and return the cached entry. */1203zip->cache = 0;1204ZIP_Unlock(zip);1205return ze;1206}1207ze = 0;12081209/*1210* Search down the target hash chain for a cell whose1211* 32 bit hash matches the hashed name.1212*/1213while (idx != ZIP_ENDCHAIN) {1214jzcell *zc = &zip->entries[idx];12151216if (zc->hash == hsh) {1217/*1218* OK, we've found a ZIP entry whose 32 bit hashcode1219* matches the name we're looking for. Try to read1220* its entry information from the CEN. If the CEN1221* name matches the name we're looking for, we're1222* done.1223* If the names don't match (which should be very rare)1224* we keep searching.1225*/1226ze = newEntry(zip, zc, ACCESS_RANDOM);1227if (ze && equals(ze->name, ze->nlen, name, ulen)) {1228break;1229}1230if (ze != 0) {1231/* We need to release the lock across the free call */1232ZIP_Unlock(zip);1233ZIP_FreeEntry(zip, ze);1234ZIP_Lock(zip);1235}1236ze = 0;1237}1238idx = zc->next;1239}12401241/* Entry found, return it */1242if (ze != 0) {1243break;1244}12451246/* If no need to try appending slash, we are done */1247if (!addSlash) {1248break;1249}12501251/* Slash is already there? */1252if (ulen > 0 && name[ulen - 1] == '/') {1253break;1254}12551256/* Add slash and try once more */1257name[ulen++] = '/';1258name[ulen] = '\0';1259hsh = hash_append(hsh, '/');1260idx = zip->table[hsh % zip->tablelen];1261addSlash = JNI_FALSE;1262}12631264Finally:1265ZIP_Unlock(zip);1266return ze;1267}12681269/*1270* Returns the n'th (starting at zero) zip file entry, or NULL if the1271* specified index was out of range.1272*/1273JNIEXPORT jzentry *1274ZIP_GetNextEntry(jzfile *zip, jint n)1275{1276jzentry *result;1277if (n < 0 || n >= zip->total) {1278return 0;1279}1280ZIP_Lock(zip);1281result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL);1282ZIP_Unlock(zip);1283return result;1284}12851286/*1287* Locks the specified zip file for reading.1288*/1289void1290ZIP_Lock(jzfile *zip)1291{1292MLOCK(zip->lock);1293}12941295/*1296* Unlocks the specified zip file.1297*/1298void1299ZIP_Unlock(jzfile *zip)1300{1301MUNLOCK(zip->lock);1302}13031304/*1305* Returns the offset of the entry data within the zip file.1306* Returns -1 if an error occurred, in which case zip->msg will1307* contain the error text.1308*/1309jlong1310ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)1311{1312/* The Zip file spec explicitly allows the LOC extra data size to1313* be different from the CEN extra data size, although the JDK1314* never creates such zip files. Since we cannot trust the CEN1315* extra data size, we need to read the LOC to determine the entry1316* data offset. We do this lazily to avoid touching the virtual1317* memory page containing the LOC when initializing jzentry1318* objects. (This speeds up javac by a factor of 10 when the JDK1319* is installed on a very slow filesystem.)1320*/1321if (entry->pos <= 0) {1322unsigned char loc[LOCHDR];1323if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) {1324zip->msg = "error reading zip file";1325return -1;1326}1327if (!LOCSIG_AT(loc)) {1328zip->msg = "invalid LOC header (bad signature)";1329return -1;1330}1331entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc);1332}1333return entry->pos;1334}13351336/*1337* Reads bytes from the specified zip entry. Assumes that the zip1338* file had been previously locked with ZIP_Lock(). Returns the1339* number of bytes read, or -1 if an error occurred. If zip->msg != 01340* then a zip error occurred and zip->msg contains the error text.1341*1342* The current implementation does not support reading an entry that1343* has the size bigger than 2**32 bytes in ONE invocation.1344*/1345jint1346ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)1347{1348jlong entry_size;1349jlong start;13501351if (zip == 0) {1352return -1;1353}13541355/* Clear previous zip error */1356zip->msg = NULL;13571358if (entry == 0) {1359zip->msg = "ZIP_Read: jzentry is NULL";1360return -1;1361}13621363entry_size = (entry->csize != 0) ? entry->csize : entry->size;13641365/* Check specified position */1366if (pos < 0 || pos > entry_size - 1) {1367zip->msg = "ZIP_Read: specified offset out of range";1368return -1;1369}13701371/* Check specified length */1372if (len <= 0)1373return 0;1374if (len > entry_size - pos)1375len = (jint)(entry_size - pos);13761377/* Get file offset to start reading data */1378start = ZIP_GetEntryDataOffset(zip, entry);1379if (start < 0)1380return -1;1381start += pos;13821383if (start + len > zip->len) {1384zip->msg = "ZIP_Read: corrupt zip file: invalid entry size";1385return -1;1386}13871388if (readFullyAt(zip->zfd, buf, len, start) == -1) {1389zip->msg = "ZIP_Read: error reading zip file";1390return -1;1391}1392return len;1393}139413951396/* The maximum size of a stack-allocated buffer.1397*/1398#define BUF_SIZE 409613991400/*1401* This function is used by the runtime system to load compressed entries1402* from ZIP/JAR files specified in the class path. It is defined here1403* so that it can be dynamically loaded by the runtime if the zip library1404* is found.1405*1406* The current implementation does not support reading an entry that1407* has the size bigger than 2**32 bytes in ONE invocation.1408*/1409jboolean1410InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg)1411{1412z_stream strm;1413char tmp[BUF_SIZE];1414jlong pos = 0;1415jlong count = entry->csize;14161417*msg = 0; /* Reset error message */14181419if (count == 0) {1420*msg = "inflateFully: entry not compressed";1421return JNI_FALSE;1422}14231424memset(&strm, 0, sizeof(z_stream));1425if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {1426*msg = strm.msg;1427return JNI_FALSE;1428}14291430strm.next_out = buf;1431strm.avail_out = (uInt)entry->size;14321433while (count > 0) {1434jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count;1435ZIP_Lock(zip);1436n = ZIP_Read(zip, entry, pos, tmp, n);1437ZIP_Unlock(zip);1438if (n <= 0) {1439if (n == 0) {1440*msg = "inflateFully: Unexpected end of file";1441}1442inflateEnd(&strm);1443return JNI_FALSE;1444}1445pos += n;1446count -= n;1447strm.next_in = (Bytef *)tmp;1448strm.avail_in = n;1449do {1450switch (inflate(&strm, Z_PARTIAL_FLUSH)) {1451case Z_OK:1452break;1453case Z_STREAM_END:1454if (count != 0 || strm.total_out != (uInt)entry->size) {1455*msg = "inflateFully: Unexpected end of stream";1456inflateEnd(&strm);1457return JNI_FALSE;1458}1459break;1460default:1461break;1462}1463} while (strm.avail_in > 0);1464}14651466inflateEnd(&strm);1467return JNI_TRUE;1468}14691470/*1471* The current implementation does not support reading an entry that1472* has the size bigger than 2**32 bytes in ONE invocation.1473*/1474JNIEXPORT jzentry *1475ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP)1476{1477jzentry *entry = ZIP_GetEntry(zip, name, 0);1478if (entry) {1479*sizeP = (jint)entry->size;1480*nameLenP = (jint)strlen(entry->name);1481}1482return entry;1483}14841485/*1486* Reads a zip file entry into the specified byte array1487* When the method completes, it releases the jzentry.1488* Note: this is called from the separately delivered VM (hotspot/classic)1489* so we have to be careful to maintain the expected behaviour.1490*/1491JNIEXPORT jboolean1492ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)1493{1494char *msg;1495char tmpbuf[1024];14961497if (entry == 0) {1498jio_fprintf(stderr, "jzentry was invalid");1499return JNI_FALSE;1500}15011502strcpy(entryname, entry->name);1503if (entry->csize == 0) {1504/* Entry is stored */1505jlong pos = 0;1506jlong size = entry->size;1507while (pos < size) {1508jint n;1509jlong limit = ((((jlong) 1) << 31) - 1);1510jint count = (size - pos < limit) ?1511/* These casts suppress a VC++ Internal Compiler Error */1512(jint) (size - pos) :1513(jint) limit;1514ZIP_Lock(zip);1515n = ZIP_Read(zip, entry, pos, buf, count);1516msg = zip->msg;1517ZIP_Unlock(zip);1518if (n == -1) {1519if (msg == 0) {1520getErrorString(errno, tmpbuf, sizeof(tmpbuf));1521msg = tmpbuf;1522}1523jio_fprintf(stderr, "%s: %s\n", zip->name, msg);1524return JNI_FALSE;1525}1526buf += n;1527pos += n;1528}1529} else {1530/* Entry is compressed */1531int ok = InflateFully(zip, entry, buf, &msg);1532if (!ok) {1533if ((msg == NULL) || (*msg == 0)) {1534msg = zip->msg;1535}1536if (msg == 0) {1537getErrorString(errno, tmpbuf, sizeof(tmpbuf));1538msg = tmpbuf;1539}1540jio_fprintf(stderr, "%s: %s\n", zip->name, msg);1541return JNI_FALSE;1542}1543}15441545ZIP_FreeEntry(zip, entry);15461547return JNI_TRUE;1548}15491550JNIEXPORT jboolean1551ZIP_InflateFully(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg)1552{1553z_stream strm;1554int i = 0;1555memset(&strm, 0, sizeof(z_stream));15561557*pmsg = 0; /* Reset error message */15581559if (inflateInit2(&strm, MAX_WBITS) != Z_OK) {1560*pmsg = strm.msg;1561return JNI_FALSE;1562}15631564strm.next_out = (Bytef *) outBuf;1565strm.avail_out = (uInt)outLen;1566strm.next_in = (Bytef *) inBuf;1567strm.avail_in = (uInt)inLen;15681569do {1570switch (inflate(&strm, Z_PARTIAL_FLUSH)) {1571case Z_OK:1572break;1573case Z_STREAM_END:1574if (strm.total_out != (uInt)outLen) {1575*pmsg = "INFLATER_inflateFully: Unexpected end of stream";1576inflateEnd(&strm);1577return JNI_FALSE;1578}1579break;1580case Z_DATA_ERROR:1581*pmsg = "INFLATER_inflateFully: Compressed data corrupted";1582inflateEnd(&strm);1583return JNI_FALSE;1584case Z_MEM_ERROR:1585*pmsg = "INFLATER_inflateFully: out of memory";1586inflateEnd(&strm);1587return JNI_FALSE;1588default:1589*pmsg = "INFLATER_inflateFully: internal error";1590inflateEnd(&strm);1591return JNI_FALSE;1592}1593} while (strm.avail_in > 0);15941595inflateEnd(&strm);1596return JNI_TRUE;1597}15981599static voidpf tracking_zlib_alloc(voidpf opaque, uInt items, uInt size) {1600size_t* needed = (size_t*) opaque;1601*needed += (size_t) items * (size_t) size;1602return (voidpf) calloc((size_t) items, (size_t) size);1603}16041605static void tracking_zlib_free(voidpf opaque, voidpf address) {1606free((void*) address);1607}16081609static voidpf zlib_block_alloc(voidpf opaque, uInt items, uInt size) {1610char** range = (char**) opaque;1611voidpf result = NULL;1612size_t needed = (size_t) items * (size_t) size;16131614if (range[1] - range[0] >= (ptrdiff_t) needed) {1615result = (voidpf) range[0];1616range[0] += needed;1617}16181619return result;1620}16211622static void zlib_block_free(voidpf opaque, voidpf address) {1623/* Nothing to do. */1624}16251626static char const* deflateInit2Wrapper(z_stream* strm, int level) {1627int err = deflateInit2(strm, level >= 0 && level <= 9 ? level : Z_DEFAULT_COMPRESSION,1628Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);1629if (err == Z_MEM_ERROR) {1630return "Out of memory in deflateInit2";1631}16321633if (err != Z_OK) {1634return "Internal error in deflateInit2";1635}16361637return NULL;1638}16391640JNIEXPORT char const*1641ZIP_GZip_InitParams(size_t inLen, size_t* outLen, size_t* tmpLen, int level) {1642z_stream strm;1643*tmpLen = 0;1644char const* errorMsg;16451646memset(&strm, 0, sizeof(z_stream));1647strm.zalloc = tracking_zlib_alloc;1648strm.zfree = tracking_zlib_free;1649strm.opaque = (voidpf) tmpLen;16501651errorMsg = deflateInit2Wrapper(&strm, level);16521653if (errorMsg == NULL) {1654*outLen = (size_t) deflateBound(&strm, (uLong) inLen);1655deflateEnd(&strm);1656}16571658return errorMsg;1659}16601661JNIEXPORT size_t1662ZIP_GZip_Fully(char* inBuf, size_t inLen, char* outBuf, size_t outLen, char* tmp, size_t tmpLen,1663int level, char* comment, char const** pmsg) {1664z_stream strm;1665gz_header hdr;1666int err;1667char* block[] = {tmp, tmpLen + tmp};1668size_t result = 0;16691670memset(&strm, 0, sizeof(z_stream));1671strm.zalloc = zlib_block_alloc;1672strm.zfree = zlib_block_free;1673strm.opaque = (voidpf) block;16741675*pmsg = deflateInit2Wrapper(&strm, level);16761677if (*pmsg == NULL) {1678strm.next_out = (Bytef *) outBuf;1679strm.avail_out = (uInt) outLen;1680strm.next_in = (Bytef *) inBuf;1681strm.avail_in = (uInt) inLen;16821683if (comment != NULL) {1684memset(&hdr, 0, sizeof(hdr));1685hdr.comment = (Bytef*) comment;1686deflateSetHeader(&strm, &hdr);1687}16881689err = deflate(&strm, Z_FINISH);16901691if (err == Z_OK || err == Z_BUF_ERROR) {1692*pmsg = "Buffer too small";1693} else if (err != Z_STREAM_END) {1694*pmsg = "Intern deflate error";1695} else {1696result = (size_t) strm.total_out;1697}16981699deflateEnd(&strm);1700}17011702return result;1703}170417051706