diff options
Diffstat (limited to 'security/nss/lib/jar/jarfile.c')
-rw-r--r-- | security/nss/lib/jar/jarfile.c | 1151 |
1 files changed, 1151 insertions, 0 deletions
diff --git a/security/nss/lib/jar/jarfile.c b/security/nss/lib/jar/jarfile.c new file mode 100644 index 000000000..19a3eaa02 --- /dev/null +++ b/security/nss/lib/jar/jarfile.c @@ -0,0 +1,1151 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * JARFILE + * + * Parsing of a Jar file + */ + +#define JAR_SIZE 256 + +#include "jar.h" + +#include "jarint.h" +#include "jarfile.h" + +/* commercial compression */ +#include "jzlib.h" + +#if defined(XP_UNIX) || defined(XP_BEOS) +#include "sys/stat.h" +#endif + +#include "sechash.h" /* for HASH_GetHashObject() */ + +/* extracting */ + +static int jar_guess_jar (char *filename, JAR_FILE fp); + +static int jar_inflate_memory + (unsigned int method, long *length, long expected_out_len, char ZHUGEP **data); + +static int jar_physical_extraction + (JAR_FILE fp, char *outpath, long offset, long length); + +static int jar_physical_inflate + (JAR_FILE fp, char *outpath, long offset, + long length, unsigned int method); + +static int jar_verify_extract + (JAR *jar, char *path, char *physical_path); + +static JAR_Physical *jar_get_physical (JAR *jar, char *pathname); + +static int jar_extract_manifests (JAR *jar, jarArch format, JAR_FILE fp); + +static int jar_extract_mf (JAR *jar, jarArch format, JAR_FILE fp, char *ext); + + +/* indexing */ + +static int jar_gen_index (JAR *jar, jarArch format, JAR_FILE fp); + +static int jar_listtar (JAR *jar, JAR_FILE fp); + +static int jar_listzip (JAR *jar, JAR_FILE fp); + + +/* conversions */ + +static int dosdate (char *date, char *s); + +static int dostime (char *time, char *s); + +static unsigned int xtoint (unsigned char *ii); + +static unsigned long xtolong (unsigned char *ll); + +static long atoo (char *s); + +/* + * J A R _ p a s s _ a r c h i v e + * + * For use by naive clients. Slam an entire archive file + * into this function. We extract manifests, parse, index + * the archive file, and do whatever nastiness. + * + */ + +int JAR_pass_archive + (JAR *jar, jarArch format, char *filename, const char *url) + { + JAR_FILE fp; + int status = 0; + + if (filename == NULL) + return JAR_ERR_GENERAL; + + if ((fp = JAR_FOPEN (filename, "rb")) != NULL) + { + if (format == jarArchGuess) + format = (jarArch)jar_guess_jar (filename, fp); + + jar->format = format; + jar->url = url ? PORT_Strdup (url) : NULL; + jar->filename = PORT_Strdup (filename); + + status = jar_gen_index (jar, format, fp); + + if (status == 0) + status = jar_extract_manifests (jar, format, fp); + + JAR_FCLOSE (fp); + + if (status < 0) + return status; + + /* people were expecting it this way */ + return jar->valid; + } + else + { + /* file not found */ + return JAR_ERR_FNF; + } + } + +/* + * J A R _ p a s s _ a r c h i v e _ u n v e r i f i e d + * + * Same as JAR_pass_archive, but doesn't parse signatures. + * + */ +int JAR_pass_archive_unverified + (JAR *jar, jarArch format, char *filename, const char *url) +{ + JAR_FILE fp; + int status = 0; + + if (filename == NULL) { + return JAR_ERR_GENERAL; + } + + if ((fp = JAR_FOPEN (filename, "rb")) != NULL) { + if (format == jarArchGuess) { + format = (jarArch)jar_guess_jar (filename, fp); + } + + jar->format = format; + jar->url = url ? PORT_Strdup (url) : NULL; + jar->filename = PORT_Strdup (filename); + + status = jar_gen_index (jar, format, fp); + + if (status == 0) { + status = jar_extract_mf(jar, format, fp, "mf"); + } + + JAR_FCLOSE (fp); + + if (status < 0) { + return status; + } + + /* people were expecting it this way */ + return jar->valid; + } else { + /* file not found */ + return JAR_ERR_FNF; + } +} + +/* + * J A R _ v e r i f i e d _ e x t r a c t + * + * Optimization: keep a file descriptor open + * inside the JAR structure, so we don't have to + * open the file 25 times to run java. + * + */ + +int JAR_verified_extract + (JAR *jar, char *path, char *outpath) + { + int status; + + status = JAR_extract (jar, path, outpath); + + if (status >= 0) + return jar_verify_extract (jar, path, outpath); + else + return status; + } + +int JAR_extract + (JAR *jar, char *path, char *outpath) + { + int result; + + JAR_Physical *phy; + + if (jar->fp == NULL && jar->filename) + { + jar->fp = (FILE*)JAR_FOPEN (jar->filename, "rb"); + } + + if (jar->fp == NULL) + { + /* file not found */ + return JAR_ERR_FNF; + } + + phy = jar_get_physical (jar, path); + + if (phy) + { + if (phy->compression != 0 && phy->compression != 8) + { + /* unsupported compression method */ + result = JAR_ERR_CORRUPT; + } + + if (phy->compression == 0) + { + result = jar_physical_extraction + ((PRFileDesc*)jar->fp, outpath, phy->offset, phy->length); + } + else + { + result = jar_physical_inflate + ((PRFileDesc*)jar->fp, outpath, phy->offset, phy->length, + (unsigned int) phy->compression); + } + +#if defined(XP_UNIX) || defined(XP_BEOS) + if (phy->mode) + chmod (outpath, 0400 | (mode_t) phy->mode); +#endif + } + else + { + /* pathname not found in archive */ + result = JAR_ERR_PNF; + } + + return result; + } + +/* + * p h y s i c a l _ e x t r a c t i o n + * + * This needs to be done in chunks of say 32k, instead of + * in one bulk calloc. (Necessary under Win16 platform.) + * This is done for uncompressed entries only. + * + */ + +#define CHUNK 32768 + +static int jar_physical_extraction + (JAR_FILE fp, char *outpath, long offset, long length) + { + JAR_FILE out; + + char *buffer; + long at, chunk; + + int status = 0; + + buffer = (char *) PORT_ZAlloc (CHUNK); + + if (buffer == NULL) + return JAR_ERR_MEMORY; + + if ((out = JAR_FOPEN (outpath, "wb")) != NULL) + { + at = 0; + + JAR_FSEEK (fp, offset, (PRSeekWhence)0); + + while (at < length) + { + chunk = (at + CHUNK <= length) ? CHUNK : length - at; + + if (JAR_FREAD (fp, buffer, chunk) != chunk) + { + status = JAR_ERR_DISK; + break; + } + + at += chunk; + + if (JAR_FWRITE (out, buffer, chunk) < chunk) + { + /* most likely a disk full error */ + status = JAR_ERR_DISK; + break; + } + } + JAR_FCLOSE (out); + } + else + { + /* error opening output file */ + status = JAR_ERR_DISK; + } + + PORT_Free (buffer); + return status; + } + +/* + * j a r _ p h y s i c a l _ i n f l a t e + * + * Inflate a range of bytes in a file, writing the inflated + * result to "outpath". Chunk based. + * + */ + +/* input and output chunks differ, assume 4x compression */ + +#define ICHUNK 8192 +#define OCHUNK 32768 + +static int jar_physical_inflate + (JAR_FILE fp, char *outpath, long offset, + long length, unsigned int method) + { + z_stream zs; + + JAR_FILE out; + + long at, chunk; + char *inbuf, *outbuf; + + int status = 0; + + unsigned long prev_total, ochunk, tin; + + if ((inbuf = (char *) PORT_ZAlloc (ICHUNK)) == NULL) + return JAR_ERR_MEMORY; + + if ((outbuf = (char *) PORT_ZAlloc (OCHUNK)) == NULL) + { + PORT_Free (inbuf); + return JAR_ERR_MEMORY; + } + + PORT_Memset (&zs, 0, sizeof (zs)); + status = inflateInit2 (&zs, -MAX_WBITS); + + if (status != Z_OK) + return JAR_ERR_GENERAL; + + if ((out = JAR_FOPEN (outpath, "wb")) != NULL) + { + at = 0; + + JAR_FSEEK (fp, offset, (PRSeekWhence)0); + + while (at < length) + { + chunk = (at + ICHUNK <= length) ? ICHUNK : length - at; + + if (JAR_FREAD (fp, inbuf, chunk) != chunk) + { + /* incomplete read */ + return JAR_ERR_CORRUPT; + } + + at += chunk; + + zs.next_in = (Bytef *) inbuf; + zs.avail_in = chunk; + zs.avail_out = OCHUNK; + + tin = zs.total_in; + + while ((zs.total_in - tin < chunk) || (zs.avail_out == 0)) + { + prev_total = zs.total_out; + + zs.next_out = (Bytef *) outbuf; + zs.avail_out = OCHUNK; + + status = inflate (&zs, Z_NO_FLUSH); + + if (status != Z_OK && status != Z_STREAM_END) + { + /* error during decompression */ + return JAR_ERR_CORRUPT; + } + + ochunk = zs.total_out - prev_total; + + if (JAR_FWRITE (out, outbuf, ochunk) < ochunk) + { + /* most likely a disk full error */ + status = JAR_ERR_DISK; + break; + } + + if (status == Z_STREAM_END) + break; + } + } + + JAR_FCLOSE (out); + status = inflateEnd (&zs); + } + else + { + /* error opening output file */ + status = JAR_ERR_DISK; + } + + PORT_Free (inbuf); + PORT_Free (outbuf); + + return status; + } + +/* + * j a r _ i n f l a t e _ m e m o r y + * + * Call zlib to inflate the given memory chunk. It is re-XP_ALLOC'd, + * and thus appears to operate inplace to the caller. + * + */ + +static int jar_inflate_memory + (unsigned int method, long *length, long expected_out_len, char ZHUGEP **data) + { + int status; + z_stream zs; + + long insz, outsz; + + char *inbuf, *outbuf; + + inbuf = *data; + insz = *length; + + outsz = expected_out_len; + outbuf = (char*)PORT_ZAlloc (outsz); + + if (outbuf == NULL) + return JAR_ERR_MEMORY; + + PORT_Memset (&zs, 0, sizeof (zs)); + + status = inflateInit2 (&zs, -MAX_WBITS); + + if (status < 0) + { + /* error initializing zlib stream */ + return JAR_ERR_GENERAL; + } + + zs.next_in = (Bytef *) inbuf; + zs.next_out = (Bytef *) outbuf; + + zs.avail_in = insz; + zs.avail_out = outsz; + + status = inflate (&zs, Z_FINISH); + + if (status != Z_OK && status != Z_STREAM_END) + { + /* error during deflation */ + return JAR_ERR_GENERAL; + } + + status = inflateEnd (&zs); + + if (status != Z_OK) + { + /* error during deflation */ + return JAR_ERR_GENERAL; + } + + PORT_Free (*data); + + *data = outbuf; + *length = zs.total_out; + + return 0; + } + +/* + * v e r i f y _ e x t r a c t + * + * Validate signature on the freshly extracted file. + * + */ + +static int jar_verify_extract (JAR *jar, char *path, char *physical_path) + { + int status; + JAR_Digest dig; + + PORT_Memset (&dig, 0, sizeof (JAR_Digest)); + status = JAR_digest_file (physical_path, &dig); + + if (!status) + status = JAR_verify_digest (jar, path, &dig); + + return status; + } + +/* + * g e t _ p h y s i c a l + * + * Let's get physical. + * Obtains the offset and length of this file in the jar file. + * + */ + +static JAR_Physical *jar_get_physical (JAR *jar, char *pathname) + { + JAR_Item *it; + + JAR_Physical *phy; + + ZZLink *link; + ZZList *list; + + list = jar->phy; + + if (ZZ_ListEmpty (list)) + return NULL; + + for (link = ZZ_ListHead (list); + !ZZ_ListIterDone (list, link); + link = link->next) + { + it = link->thing; + if (it->type == jarTypePhy + && it->pathname && !PORT_Strcmp (it->pathname, pathname)) + { + phy = (JAR_Physical *) it->data; + return phy; + } + } + + return NULL; + } + +/* + * j a r _ e x t r a c t _ m a n i f e s t s + * + * Extract the manifest files and parse them, + * from an open archive file whose contents are known. + * + */ + +static int jar_extract_manifests (JAR *jar, jarArch format, JAR_FILE fp) + { + int status; + + if (format != jarArchZip && format != jarArchTar) + return JAR_ERR_CORRUPT; + + if ((status = jar_extract_mf (jar, format, fp, "mf")) < 0) + return status; + + if ((status = jar_extract_mf (jar, format, fp, "sf")) < 0) + return status; + + if ((status = jar_extract_mf (jar, format, fp, "rsa")) < 0) + return status; + + if ((status = jar_extract_mf (jar, format, fp, "dsa")) < 0) + return status; + + return 0; + } + +/* + * j a r _ e x t r a c t _ m f + * + * Extracts manifest files based on an extension, which + * should be .MF, .SF, .RSA, etc. Order of the files is now no + * longer important when zipping jar files. + * + */ + +static int jar_extract_mf (JAR *jar, jarArch format, JAR_FILE fp, char *ext) + { + JAR_Item *it; + + JAR_Physical *phy; + + ZZLink *link; + ZZList *list; + + char *fn, *e; + char ZHUGEP *manifest; + + long length; + int status, ret = 0, num; + + list = jar->phy; + + if (ZZ_ListEmpty (list)) + return JAR_ERR_PNF; + + for (link = ZZ_ListHead (list); + !ZZ_ListIterDone (list, link); + link = link->next) + { + it = link->thing; + if (it->type == jarTypePhy + && !PORT_Strncmp (it->pathname, "META-INF", 8)) + { + phy = (JAR_Physical *) it->data; + + if (PORT_Strlen (it->pathname) < 8) + continue; + + fn = it->pathname + 8; + if (*fn == '/' || *fn == '\\') fn++; + + if (*fn == 0) + { + /* just a directory entry */ + continue; + } + + /* skip to extension */ + for (e = fn; *e && *e != '.'; e++) + /* yip */ ; + + /* and skip dot */ + if (*e == '.') e++; + + if (PORT_Strcasecmp (ext, e)) + { + /* not the right extension */ + continue; + } + + if (phy->length == 0) + { + /* manifest files cannot be zero length! */ + return JAR_ERR_CORRUPT; + } + + /* Read in the manifest and parse it */ + /* FIX? Does this break on win16 for very very large manifest files? */ + +#ifdef XP_WIN16 + PORT_Assert( phy->length+1 < 0xFFFF ); +#endif + + manifest = (char ZHUGEP *) PORT_ZAlloc (phy->length + 1); + if (manifest) + { + JAR_FSEEK (fp, phy->offset, (PRSeekWhence)0); + num = JAR_FREAD (fp, manifest, phy->length); + + if (num != phy->length) + { + /* corrupt archive file */ + return JAR_ERR_CORRUPT; + } + + if (phy->compression == 8) + { + length = phy->length; + + status = jar_inflate_memory ((unsigned int) phy->compression, &length, phy->uncompressed_length, &manifest); + + if (status < 0) + return status; + } + else if (phy->compression) + { + /* unsupported compression method */ + return JAR_ERR_CORRUPT; + } + else + length = phy->length; + + status = JAR_parse_manifest + (jar, manifest, length, it->pathname, "url"); + + PORT_Free (manifest); + + if (status < 0 && ret == 0) ret = status; + } + else + return JAR_ERR_MEMORY; + } + else if (it->type == jarTypePhy) + { + /* ordinary file */ + } + } + + return ret; + } + +/* + * j a r _ g e n _ i n d e x + * + * Generate an index for the various types of + * known archive files. Right now .ZIP and .TAR + * + */ + +static int jar_gen_index (JAR *jar, jarArch format, JAR_FILE fp) + { + int result = JAR_ERR_CORRUPT; + JAR_FSEEK (fp, 0, (PRSeekWhence)0); + + switch (format) + { + case jarArchZip: + result = jar_listzip (jar, fp); + break; + + case jarArchTar: + result = jar_listtar (jar, fp); + break; + + case jarArchGuess: + case jarArchNone: + return JAR_ERR_GENERAL; + } + + JAR_FSEEK (fp, 0, (PRSeekWhence)0); + return result; + } + + +/* + * j a r _ l i s t z i p + * + * List the physical contents of a Phil Katz + * style .ZIP file into the JAR linked list. + * + */ + +static int jar_listzip (JAR *jar, JAR_FILE fp) + { + int err = 0; + + long pos = 0L; + char filename [JAR_SIZE]; + + char date [9], time [9]; + char sig [4]; + + unsigned int compression; + unsigned int filename_len, extra_len; + + struct ZipLocal *Local; + struct ZipCentral *Central; + struct ZipEnd *End; + + /* phy things */ + + ZZLink *ent; + JAR_Item *it; + JAR_Physical *phy; + + Local = (struct ZipLocal *) PORT_ZAlloc (30); + Central = (struct ZipCentral *) PORT_ZAlloc (46); + End = (struct ZipEnd *) PORT_ZAlloc (22); + + if (!Local || !Central || !End) + { + /* out of memory */ + err = JAR_ERR_MEMORY; + goto loser; + } + + while (1) + { + JAR_FSEEK (fp, pos, (PRSeekWhence)0); + + if (JAR_FREAD (fp, (char *) sig, 4) != 4) + { + /* zip file ends prematurely */ + err = JAR_ERR_CORRUPT; + goto loser; + } + + JAR_FSEEK (fp, pos, (PRSeekWhence)0); + + if (xtolong ((unsigned char *)sig) == LSIG) + { + JAR_FREAD (fp, (char *) Local, 30); + + filename_len = xtoint ((unsigned char *) Local->filename_len); + extra_len = xtoint ((unsigned char *) Local->extrafield_len); + + if (filename_len >= JAR_SIZE) + { + /* corrupt zip file */ + err = JAR_ERR_CORRUPT; + goto loser; + } + + if (JAR_FREAD (fp, filename, filename_len) != filename_len) + { + /* truncated archive file */ + err = JAR_ERR_CORRUPT; + goto loser; + } + + filename [filename_len] = 0; + + /* Add this to our jar chain */ + + phy = (JAR_Physical *) PORT_ZAlloc (sizeof (JAR_Physical)); + + if (phy == NULL) + { + err = JAR_ERR_MEMORY; + goto loser; + } + + /* We will index any file that comes our way, but when it comes + to actually extraction, compression must be 0 or 8 */ + + compression = xtoint ((unsigned char *) Local->method); + phy->compression = compression >= 0 && + compression <= 255 ? compression : 222; + + phy->offset = pos + 30 + filename_len + extra_len; + phy->length = xtolong ((unsigned char *) Local->size); + phy->uncompressed_length = xtolong((unsigned char *) Local->orglen); + + dosdate (date, Local->date); + dostime (time, Local->time); + + it = (JAR_Item*)PORT_ZAlloc (sizeof (JAR_Item)); + if (it == NULL) + { + err = JAR_ERR_MEMORY; + goto loser; + } + + it->pathname = PORT_Strdup (filename); + + it->type = jarTypePhy; + + it->data = (unsigned char *) phy; + it->size = sizeof (JAR_Physical); + + ent = ZZ_NewLink (it); + + if (ent == NULL) + { + err = JAR_ERR_MEMORY; + goto loser; + } + + ZZ_AppendLink (jar->phy, ent); + + pos = phy->offset + phy->length; + } + else if (xtolong ( (unsigned char *)sig) == CSIG) + { + if (JAR_FREAD (fp, (char *) Central, 46) != 46) + { + /* apparently truncated archive */ + err = JAR_ERR_CORRUPT; + goto loser; + } + +#if defined(XP_UNIX) || defined(XP_BEOS) + /* with unix we need to locate any bits from + the protection mask in the external attributes. */ + { + unsigned int attr; + + /* determined empirically */ + attr = Central->external_attributes [2]; + + if (attr) + { + /* we have to read the filename, again */ + + filename_len = xtoint ((unsigned char *) Central->filename_len); + + if (filename_len >= JAR_SIZE) + { + /* corrupt in central directory */ + err = JAR_ERR_CORRUPT; + goto loser; + } + + if (JAR_FREAD (fp, filename, filename_len) != filename_len) + { + /* truncated in central directory */ + err = JAR_ERR_CORRUPT; + goto loser; + } + + filename [filename_len] = 0; + + /* look up this name again */ + phy = jar_get_physical (jar, filename); + + if (phy) + { + /* always allow access by self */ + phy->mode = 0400 | attr; + } + } + } +#endif + + pos += 46 + xtoint ( (unsigned char *)Central->filename_len) + + xtoint ( (unsigned char *)Central->commentfield_len) + + xtoint ( (unsigned char *)Central->extrafield_len); + } + else if (xtolong ( (unsigned char *)sig) == ESIG) + { + if (JAR_FREAD (fp, (char *) End, 22) != 22) + { + err = JAR_ERR_CORRUPT; + goto loser; + } + else + break; + } + else + { + /* garbage in archive */ + err = JAR_ERR_CORRUPT; + goto loser; + } + } + +loser: + + if (Local) PORT_Free (Local); + if (Central) PORT_Free (Central); + if (End) PORT_Free (End); + + return err; + } + +/* + * j a r _ l i s t t a r + * + * List the physical contents of a Unix + * .tar file into the JAR linked list. + * + */ + +static int jar_listtar (JAR *jar, JAR_FILE fp) + { + long pos = 0L; + + long sz, mode; + time_t when; + union TarEntry tarball; + + char *s; + + /* phy things */ + + JAR_Physical *phy; + + while (1) + { + JAR_FSEEK (fp, pos, (PRSeekWhence)0); + + if (JAR_FREAD (fp, (char *) &tarball, 512) < 512) + break; + + if (!*tarball.val.filename) + break; + + when = atoo (tarball.val.time); + sz = atoo (tarball.val.size); + mode = atoo (tarball.val.mode); + + + /* Tag the end of filename */ + + s = tarball.val.filename; + while (*s && *s != ' ') s++; + *s = 0; + + + /* Add to our linked list */ + + phy = (JAR_Physical *) PORT_ZAlloc (sizeof (JAR_Physical)); + + if (phy == NULL) + return JAR_ERR_MEMORY; + + phy->compression = 0; + phy->offset = pos + 512; + phy->length = sz; + + ADDITEM (jar->phy, jarTypePhy, + tarball.val.filename, phy, sizeof (JAR_Physical)); + + + /* Advance to next file entry */ + + sz += 511; + sz = (sz / 512) * 512; + + pos += sz + 512; + } + + return 0; + } + +/* + * d o s d a t e + * + * Not used right now, but keep it in here because + * it will be needed. + * + */ + +static int dosdate (char *date, char *s) + { + int num = xtoint ( (unsigned char *)s); + + PR_snprintf (date, 9, "%02d-%02d-%02d", + ((num >> 5) & 0x0F), (num & 0x1F), ((num >> 9) + 80)); + + return 0; + } + +/* + * d o s t i m e + * + * Not used right now, but keep it in here because + * it will be needed. + * + */ + +static int dostime (char *time, char *s) + { + int num = xtoint ( (unsigned char *)s); + + PR_snprintf (time, 6, "%02d:%02d", + ((num >> 11) & 0x1F), ((num >> 5) & 0x3F)); + + return 0; + } + +/* + * x t o i n t + * + * Converts a two byte ugly endianed integer + * to our platform's integer. + * + */ + +static unsigned int xtoint (unsigned char *ii) + { + return (int) (ii [0]) | ((int) ii [1] << 8); + } + +/* + * x t o l o n g + * + * Converts a four byte ugly endianed integer + * to our platform's integer. + * + */ + +static unsigned long xtolong (unsigned char *ll) + { + unsigned long ret; + + ret = ( + (((unsigned long) ll [0]) << 0) | + (((unsigned long) ll [1]) << 8) | + (((unsigned long) ll [2]) << 16) | + (((unsigned long) ll [3]) << 24) + ); + + return ret; + } + +/* + * a t o o + * + * Ascii octal to decimal. + * Used for integer encoding inside tar files. + * + */ + +static long atoo (char *s) + { + long num = 0L; + + while (*s == ' ') s++; + + while (*s >= '0' && *s <= '7') + { + num <<= 3; + num += *s++ - '0'; + } + + return num; + } + +/* + * g u e s s _ j a r + * + * Try to guess what kind of JAR file this is. + * Maybe tar, maybe zip. Look in the file for magic + * or at its filename. + * + */ + +static int jar_guess_jar (char *filename, JAR_FILE fp) + { + char *ext; + + ext = filename + PORT_Strlen (filename) - 4; + + if (!PORT_Strcmp (ext, ".tar")) + return jarArchTar; + + return jarArchZip; + } |