1 /* src/vm/zip.c - ZIP file handling for bootstrap classloader
3 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6 Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Christian Thalinger
31 $Id: zip.c 4022 2006-01-01 16:31:40Z twisti $
46 #include "mm/memory.h"
47 #include "vm/global.h"
48 #include "vm/hashtable.h"
54 /* start size for classes hashtable *******************************************/
56 #define HASHTABLE_CLASSES_SIZE (1 << 10)
60 http://www.pkware.com/business_and_developers/developer/popups/appnote.txt
63 /* all signatures in the ZIP file have a length of 4 bytes ********************/
65 #define SIGNATURE_LENGTH 4
68 /* Local file header ***********************************************************
70 local file header signature 4 bytes (0x04034b50)
71 version needed to extract 2 bytes
72 general purpose bit flag 2 bytes
73 compression method 2 bytes
74 last mod file time 2 bytes
75 last mod file date 2 bytes
77 compressed size 4 bytes
78 uncompressed size 4 bytes
79 file name length 2 bytes
80 extra field length 2 bytes
82 file name (variable size)
83 extra field (variable size)
85 *******************************************************************************/
87 #define LFH_HEADER_SIZE 30
89 #define LFH_SIGNATURE 0x04034b50
90 #define LFH_FILE_NAME_LENGTH 26
91 #define LFH_EXTRA_FIELD_LENGTH 28
93 typedef struct lfh lfh;
104 /* Central directory structure *************************************************
115 central file header signature 4 bytes (0x02014b50)
116 version made by 2 bytes
117 version needed to extract 2 bytes
118 general purpose bit flag 2 bytes
119 compression method 2 bytes
120 last mod file time 2 bytes
121 last mod file date 2 bytes
123 compressed size 4 bytes
124 uncompressed size 4 bytes
125 file name length 2 bytes
126 extra field length 2 bytes
127 file comment length 2 bytes
128 disk number start 2 bytes
129 internal file attributes 2 bytes
130 external file attributes 4 bytes
131 relative offset of local header 4 bytes
133 file name (variable size)
134 extra field (variable size)
135 file comment (variable size)
139 header signature 4 bytes (0x05054b50)
141 signature data (variable size)
143 *******************************************************************************/
145 #define CDSFH_HEADER_SIZE 46
147 #define CDSFH_SIGNATURE 0x02014b50
148 #define CDSFH_COMPRESSION_METHOD 10
149 #define CDSFH_COMPRESSED_SIZE 20
150 #define CDSFH_UNCOMPRESSED_SIZE 24
151 #define CDSFH_FILE_NAME_LENGTH 28
152 #define CDSFH_EXTRA_FIELD_LENGTH 30
153 #define CDSFH_FILE_COMMENT_LENGTH 32
154 #define CDSFH_RELATIVE_OFFSET 42
155 #define CDSFH_FILENAME 46
157 typedef struct cdsfh cdsfh;
160 u2 compressionmethod;
165 u2 filecommentlength;
170 /* End of central directory record *********************************************
172 end of central dir signature 4 bytes (0x06054b50)
173 number of this disk 2 bytes
174 number of the disk with the
175 start of the central directory 2 bytes
176 total number of entries in the
177 central directory on this disk 2 bytes
178 total number of entries in
179 the central directory 2 bytes
180 size of the central directory 4 bytes
181 offset of start of central
182 directory with respect to
183 the starting disk number 4 bytes
184 .ZIP file comment length 2 bytes
185 .ZIP file comment (variable size)
187 *******************************************************************************/
189 #define EOCDR_SIGNATURE 0x06054b50
190 #define EOCDR_ENTRIES 10
191 #define EOCDR_OFFSET 16
193 typedef struct eocdr eocdr;
201 /* zip_open ********************************************************************
205 *******************************************************************************/
207 hashtable *zip_open(char *path)
210 hashtable_zipfile_entry *htzfe;
212 u1 lfh_signature[SIGNATURE_LENGTH];
219 const char *filename;
220 const char *classext;
222 u4 key; /* hashkey computed from utf-text */
223 u4 slot; /* slot in hashtable */
225 /* first of all, open the file */
227 if ((fd = open(path, O_RDONLY)) == -1)
230 /* check for signature in first local file header */
232 if (read(fd, lfh_signature, SIGNATURE_LENGTH) != SIGNATURE_LENGTH)
235 if (SUCK_LE_U4(lfh_signature) != LFH_SIGNATURE)
238 /* get the file length */
240 if ((len = lseek(fd, 0, SEEK_END)) == -1)
243 /* we better mmap the file */
245 filep = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
247 /* some older compilers, like DEC OSF cc, don't like comparisons
250 if ((ptrint) filep == (ptrint) MAP_FAILED)
253 /* find end of central directory record */
255 for (p = filep + len; p >= filep; p--)
256 if (SUCK_LE_U4(p) == EOCDR_SIGNATURE)
259 /* get number of entries in central directory */
261 eocdr.entries = SUCK_LE_U2(p + EOCDR_ENTRIES);
262 eocdr.offset = SUCK_LE_U4(p + EOCDR_OFFSET);
264 /* create hashtable for filenames */
268 hashtable_create(ht, HASHTABLE_CLASSES_SIZE);
270 /* add all file entries into the hashtable */
272 for (i = 0, p = filep + eocdr.offset; i < eocdr.entries; i++) {
273 /* check file header signature */
275 if (SUCK_LE_U4(p) != CDSFH_SIGNATURE)
278 /* we found an entry */
280 cdsfh.compressionmethod = SUCK_LE_U2(p + CDSFH_COMPRESSION_METHOD);
281 cdsfh.compressedsize = SUCK_LE_U4(p + CDSFH_COMPRESSED_SIZE);
282 cdsfh.uncompressedsize = SUCK_LE_U4(p + CDSFH_UNCOMPRESSED_SIZE);
283 cdsfh.filenamelength = SUCK_LE_U2(p + CDSFH_FILE_NAME_LENGTH);
284 cdsfh.extrafieldlength = SUCK_LE_U2(p + CDSFH_EXTRA_FIELD_LENGTH);
285 cdsfh.filecommentlength = SUCK_LE_U2(p + CDSFH_FILE_COMMENT_LENGTH);
286 cdsfh.relativeoffset = SUCK_LE_U4(p + CDSFH_RELATIVE_OFFSET);
288 /* create utf8 string of filename, strip .class from classes */
290 filename = (const char *) (p + CDSFH_FILENAME);
291 classext = filename + cdsfh.filenamelength - strlen(".class");
293 if (strncmp(classext, ".class", strlen(".class")) == 0)
294 u = utf_new(filename, cdsfh.filenamelength - strlen(".class"));
296 u = utf_new(filename, cdsfh.filenamelength);
298 /* insert class into hashtable */
300 htzfe = NEW(hashtable_zipfile_entry);
303 htzfe->compressionmethod = cdsfh.compressionmethod;
304 htzfe->compressedsize = cdsfh.compressedsize;
305 htzfe->uncompressedsize = cdsfh.uncompressedsize;
306 htzfe->data = filep + cdsfh.relativeoffset;
308 /* get hashtable slot */
310 key = utf_hashkey(u->text, u->blength);
311 slot = key & (ht->size - 1);
313 /* insert into external chain */
315 htzfe->hashlink = ht->ptr[slot];
317 /* insert hashtable zipfile entry */
319 ht->ptr[slot] = htzfe;
322 /* move to next central directory structure file header */
326 cdsfh.filenamelength +
327 cdsfh.extrafieldlength +
328 cdsfh.filecommentlength;
331 /* return pointer to hashtable */
337 /* zip_find ********************************************************************
341 *******************************************************************************/
343 hashtable_zipfile_entry *zip_find(list_classpath_entry *lce, utf *u)
346 u4 key; /* hashkey computed from utf-text */
347 u4 slot; /* slot in hashtable */
348 hashtable_zipfile_entry *htzfe; /* hashtable element */
350 /* get classes hashtable from the classpath entry */
354 /* get the hashtable slot of the name searched */
356 key = utf_hashkey(u->text, u->blength);
357 slot = key & (ht->size - 1);
358 htzfe = ht->ptr[slot];
360 /* search external hash chain for utf-symbol */
363 if (htzfe->filename == u)
366 /* next element in external chain */
368 htzfe = htzfe->hashlink;
371 /* file not found in this archive */
377 /* zip_get ********************************************************************
381 *******************************************************************************/
383 classbuffer *zip_get(list_classpath_entry *lce, classinfo *c)
385 hashtable_zipfile_entry *htzfe;
393 /* try to find the class in the current archive */
395 if ((htzfe = zip_find(lce, c->name)) == NULL)
398 /* read stuff from local file header */
400 lfh.filenamelength = SUCK_LE_U2(htzfe->data + LFH_FILE_NAME_LENGTH);
401 lfh.extrafieldlength = SUCK_LE_U2(htzfe->data + LFH_EXTRA_FIELD_LENGTH);
403 indata = htzfe->data +
406 lfh.extrafieldlength;
408 /* allocate buffer for uncompressed data */
410 outdata = MNEW(u1, htzfe->uncompressedsize);
412 /* how is the file stored? */
414 switch (htzfe->compressionmethod) {
416 /* fill z_stream structure */
419 zs.avail_in = htzfe->compressedsize;
420 zs.next_out = outdata;
421 zs.avail_out = htzfe->uncompressedsize;
427 /* initialize this inflate run */
429 if (inflateInit2(&zs, -MAX_WBITS) != Z_OK)
432 /* decompress the file into buffer */
434 err = inflate(&zs, Z_SYNC_FLUSH);
436 if ((err != Z_STREAM_END) && (err != Z_OK))
439 /* finish this inflate run */
441 if (inflateEnd(&zs) != Z_OK)
446 /* uncompressed file, just copy the data */
447 MCOPY(outdata, indata, u1, htzfe->compressedsize);
454 /* allocate classbuffer */
456 cb = NEW(classbuffer);
459 cb->size = htzfe->uncompressedsize;
462 cb->path = lce->path;
464 /* return the filled classbuffer structure */
471 * These are local overrides for various environment variables in Emacs.
472 * Please do not remove this and leave it at the end of the file, where
473 * Emacs will automagically detect them.
474 * ---------------------------------------------------------------------
477 * indent-tabs-mode: t