|
1 /* |
|
2 * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 /** |
|
27 * Note: Lifted from uncrunch.c from jdk sources |
|
28 */ |
|
29 #include <stdio.h> |
|
30 #include <string.h> |
|
31 #include <errno.h> |
|
32 #include <time.h> |
|
33 |
|
34 #include <stdlib.h> |
|
35 |
|
36 #ifndef _MSC_VER |
|
37 #include <strings.h> |
|
38 #endif |
|
39 |
|
40 #include "defines.h" |
|
41 #include "bytes.h" |
|
42 #include "utils.h" |
|
43 |
|
44 #include "constants.h" |
|
45 #include "unpack.h" |
|
46 |
|
47 #include "zip.h" |
|
48 |
|
49 #ifdef NO_ZLIB |
|
50 |
|
51 inline bool jar::deflate_bytes(bytes& head, bytes& tail) { |
|
52 return false; |
|
53 } |
|
54 inline uint jar::get_crc32(uint c, uchar *ptr, uint len) { return 0; } |
|
55 #define Z_NULL NULL |
|
56 |
|
57 #else // Have ZLIB |
|
58 |
|
59 #include <zlib.h> |
|
60 |
|
61 inline uint jar::get_crc32(uint c, uchar *ptr, uint len) { return crc32(c, ptr, len); } |
|
62 |
|
63 #endif // End of ZLIB |
|
64 |
|
65 #ifdef sparc |
|
66 #define SWAP_BYTES(a) \ |
|
67 ((((a) << 8) & 0xff00) | 0x00ff) & (((a) >> 8) | 0xff00) |
|
68 #else |
|
69 #define SWAP_BYTES(a) (a) |
|
70 #endif |
|
71 |
|
72 #define GET_INT_LO(a) \ |
|
73 SWAP_BYTES(a & 0xFFFF) |
|
74 |
|
75 #define GET_INT_HI(a) \ |
|
76 SWAP_BYTES((a >> 16) & 0xFFFF); |
|
77 |
|
78 |
|
79 void jar::init(unpacker* u_) { |
|
80 BYTES_OF(*this).clear(); |
|
81 u = u_; |
|
82 u->jarout = this; |
|
83 } |
|
84 |
|
85 // Write data to the ZIP output stream. |
|
86 void jar::write_data(void* buff, int len) { |
|
87 while (len > 0) { |
|
88 int rc = fwrite(buff, 1, len, jarfp); |
|
89 if (rc <= 0) { |
|
90 fprintf(u->errstrm, "Error: write on output file failed err=%d\n",errno); |
|
91 exit(1); // Called only from the native standalone unpacker |
|
92 } |
|
93 output_file_offset += rc; |
|
94 buff = ((char *)buff) + rc; |
|
95 len -= rc; |
|
96 } |
|
97 } |
|
98 |
|
99 void jar::add_to_jar_directory(const char* fname, bool store, int modtime, |
|
100 int len, int clen, uLong crc) { |
|
101 uint fname_length = strlen(fname); |
|
102 ushort header[23]; |
|
103 if (modtime == 0) modtime = default_modtime; |
|
104 uLong dostime = get_dostime(modtime); |
|
105 |
|
106 header[0] = SWAP_BYTES(0x4B50); |
|
107 header[1] = SWAP_BYTES(0x0201); |
|
108 header[2] = SWAP_BYTES(0xA); |
|
109 |
|
110 // required version |
|
111 header[3] = SWAP_BYTES(0xA); |
|
112 |
|
113 // flags 02 = maximum sub-compression flag |
|
114 header[4] = ( store ) ? 0x0 : SWAP_BYTES(0x2); |
|
115 |
|
116 // Compression method 8=deflate. |
|
117 header[5] = ( store ) ? 0x0 : SWAP_BYTES(0x08); |
|
118 |
|
119 // Last modified date and time. |
|
120 header[6] = GET_INT_LO(dostime); |
|
121 header[7] = GET_INT_HI(dostime); |
|
122 |
|
123 // CRC |
|
124 header[8] = GET_INT_LO(crc); |
|
125 header[9] = GET_INT_HI(crc); |
|
126 |
|
127 // Compressed length: |
|
128 header[10] = GET_INT_LO(clen); |
|
129 header[11] = GET_INT_HI(clen); |
|
130 |
|
131 // Uncompressed length. |
|
132 header[12] = GET_INT_LO(len); |
|
133 header[13] = GET_INT_HI(len); |
|
134 |
|
135 // Filename length |
|
136 header[14] = SWAP_BYTES(fname_length); |
|
137 // So called "extra field" length. |
|
138 header[15] = 0; |
|
139 // So called "comment" length. |
|
140 header[16] = 0; |
|
141 // Disk number start |
|
142 header[17] = 0; |
|
143 // File flags => binary |
|
144 header[18] = 0; |
|
145 // More file flags |
|
146 header[19] = 0; |
|
147 header[20] = 0; |
|
148 // Offset within ZIP file. |
|
149 header[21] = GET_INT_LO(output_file_offset); |
|
150 header[22] = GET_INT_HI(output_file_offset); |
|
151 |
|
152 // Copy the whole thing into the central directory. |
|
153 central_directory.append(header, sizeof(header)); |
|
154 |
|
155 // Copy the fname to the header. |
|
156 central_directory.append(fname, fname_length); |
|
157 |
|
158 central_directory_count++; |
|
159 } |
|
160 |
|
161 void jar::write_jar_header(const char* fname, bool store, int modtime, |
|
162 int len, int clen, uint crc) { |
|
163 uint fname_length = strlen(fname); |
|
164 ushort header[15]; |
|
165 if (modtime == 0) modtime = default_modtime; |
|
166 uLong dostime = get_dostime(modtime); |
|
167 |
|
168 // ZIP LOC magic. |
|
169 header[0] = SWAP_BYTES(0x4B50); |
|
170 header[1] = SWAP_BYTES(0x0403); |
|
171 |
|
172 // Version |
|
173 header[2] = SWAP_BYTES(0xA); |
|
174 |
|
175 // flags 02 = maximum sub-compression flag |
|
176 header[3] = ( store ) ? 0x0 : SWAP_BYTES(0x2); |
|
177 |
|
178 // Compression method = deflate |
|
179 header[4] = ( store ) ? 0x0 : SWAP_BYTES(0x08); |
|
180 |
|
181 // Last modified date and time. |
|
182 header[5] = GET_INT_LO(dostime); |
|
183 header[6] = GET_INT_HI(dostime); |
|
184 |
|
185 // CRC |
|
186 header[7] = GET_INT_LO(crc); |
|
187 header[8] = GET_INT_HI(crc); |
|
188 |
|
189 // Compressed length: |
|
190 header[9] = GET_INT_LO(clen); |
|
191 header[10] = GET_INT_HI(clen); |
|
192 |
|
193 // Uncompressed length. |
|
194 header[11] = GET_INT_LO(len); |
|
195 header[12] = GET_INT_HI(len); |
|
196 |
|
197 // Filename length |
|
198 header[13] = SWAP_BYTES(fname_length); |
|
199 // So called "extra field" length. |
|
200 header[14] = 0; |
|
201 |
|
202 // Write the LOC header to the output file. |
|
203 write_data(header, sizeof(header)); |
|
204 |
|
205 // Copy the fname to the header. |
|
206 write_data((char*)fname, fname_length); |
|
207 } |
|
208 |
|
209 static const char marker_comment[] = ZIP_ARCHIVE_MARKER_COMMENT; |
|
210 |
|
211 void jar::write_central_directory() { |
|
212 bytes mc; mc.set(marker_comment); |
|
213 |
|
214 ushort header[11]; |
|
215 |
|
216 // Create the End of Central Directory structure. |
|
217 header[0] = SWAP_BYTES(0x4B50); |
|
218 header[1] = SWAP_BYTES(0x0605); |
|
219 // disk numbers |
|
220 header[2] = 0; |
|
221 header[3] = 0; |
|
222 // Number of entries in central directory. |
|
223 header[4] = SWAP_BYTES(central_directory_count); |
|
224 header[5] = SWAP_BYTES(central_directory_count); |
|
225 // Size of the central directory} |
|
226 header[6] = GET_INT_LO(central_directory.size()); |
|
227 header[7] = GET_INT_HI(central_directory.size()); |
|
228 // Offset of central directory within disk. |
|
229 header[8] = GET_INT_LO(output_file_offset); |
|
230 header[9] = GET_INT_HI(output_file_offset); |
|
231 // zipfile comment length; |
|
232 header [10] = SWAP_BYTES(mc.len); |
|
233 |
|
234 // Write the central directory. |
|
235 printcr(2, "Central directory at %d\n", output_file_offset); |
|
236 write_data(central_directory.b); |
|
237 |
|
238 // Write the End of Central Directory structure. |
|
239 printcr(2, "end-of-directory at %d\n", output_file_offset); |
|
240 write_data(header, sizeof(header)); |
|
241 |
|
242 printcr(2, "writing zip comment\n"); |
|
243 // Write the comment. |
|
244 write_data(mc); |
|
245 } |
|
246 |
|
247 // Public API |
|
248 |
|
249 // Open a Jar file and initialize. |
|
250 void jar::openJarFile(const char* fname) { |
|
251 if (!jarfp) { |
|
252 printcr(1, "jar::openJarFile: opening %s\n",fname); |
|
253 jarfp = fopen(fname, "wb"); |
|
254 if (!jarfp) { |
|
255 fprintf(u->errstrm, "Error: Could not open jar file: %s\n",fname); |
|
256 exit(3); // Called only from the native standalone unpacker |
|
257 } |
|
258 } |
|
259 } |
|
260 |
|
261 // Add a ZIP entry and copy the file data |
|
262 void jar::addJarEntry(const char* fname, |
|
263 bool deflate_hint, int modtime, |
|
264 bytes& head, bytes& tail) { |
|
265 int len = head.len + tail.len; |
|
266 int clen = 0; |
|
267 |
|
268 uint crc = get_crc32(0L,Z_NULL,0); |
|
269 if (head.len != 0) |
|
270 crc = get_crc32(crc, (uchar *)head.ptr, head.len); |
|
271 if (tail.len != 0) |
|
272 crc = get_crc32(crc, (uchar *)tail.ptr, tail.len); |
|
273 |
|
274 bool deflate = (deflate_hint && len > 0); |
|
275 |
|
276 if (deflate) { |
|
277 if (deflate_bytes(head, tail) == false) { |
|
278 printcr(2, "Reverting to store fn=%s\t%d -> %d\n", |
|
279 fname, len, deflated.size()); |
|
280 deflate = false; |
|
281 } |
|
282 } |
|
283 clen = (deflate) ? deflated.size() : len; |
|
284 add_to_jar_directory(fname, !deflate, modtime, len, clen, crc); |
|
285 write_jar_header( fname, !deflate, modtime, len, clen, crc); |
|
286 |
|
287 if (deflate) { |
|
288 write_data(deflated.b); |
|
289 } else { |
|
290 write_data(head); |
|
291 write_data(tail); |
|
292 } |
|
293 } |
|
294 |
|
295 // Add a ZIP entry for a directory name no data |
|
296 void jar::addDirectoryToJarFile(const char* dir_name) { |
|
297 bool store = true; |
|
298 add_to_jar_directory((const char*)dir_name, store, default_modtime, 0, 0, 0); |
|
299 write_jar_header( (const char*)dir_name, store, default_modtime, 0, 0, 0); |
|
300 } |
|
301 |
|
302 // Write out the central directory and close the jar file. |
|
303 void jar::closeJarFile(bool central) { |
|
304 if (jarfp) { |
|
305 fflush(jarfp); |
|
306 if (central) write_central_directory(); |
|
307 fflush(jarfp); |
|
308 fclose(jarfp); |
|
309 printcr(2, "jar::closeJarFile:closed jar-file\n"); |
|
310 } |
|
311 reset(); |
|
312 } |
|
313 |
|
314 /* Convert the date y/n/d and time h:m:s to a four byte DOS date and |
|
315 * time (date in high two bytes, time in low two bytes allowing magnitude |
|
316 * comparison). |
|
317 */ |
|
318 inline |
|
319 uLong jar::dostime(int y, int n, int d, int h, int m, int s) { |
|
320 return y < 1980 ? dostime(1980, 1, 1, 0, 0, 0) : |
|
321 (((uLong)y - 1980) << 25) | ((uLong)n << 21) | ((uLong)d << 16) | |
|
322 ((uLong)h << 11) | ((uLong)m << 5) | ((uLong)s >> 1); |
|
323 } |
|
324 |
|
325 #ifdef _REENTRANT // solaris |
|
326 extern "C" struct tm *gmtime_r(const time_t *, struct tm *); |
|
327 #else |
|
328 #define gmtime_r(t, s) gmtime(t) |
|
329 #endif |
|
330 /* |
|
331 * Return the Unix time in DOS format |
|
332 */ |
|
333 uLong jar::get_dostime(int modtime) { |
|
334 // see defines.h |
|
335 if (modtime != 0 && modtime == modtime_cache) |
|
336 return dostime_cache; |
|
337 if (modtime != 0 && default_modtime == 0) |
|
338 default_modtime = modtime; // catch a reasonable default |
|
339 time_t t = modtime; |
|
340 struct tm sbuf; |
|
341 struct tm* s = gmtime_r(&t, &sbuf); |
|
342 modtime_cache = modtime; |
|
343 dostime_cache = dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday, |
|
344 s->tm_hour, s->tm_min, s->tm_sec); |
|
345 //printf("modtime %d => %d\n", modtime_cache, dostime_cache); |
|
346 return dostime_cache; |
|
347 } |
|
348 |
|
349 |
|
350 |
|
351 #ifndef NO_ZLIB |
|
352 |
|
353 /* Returns true on success, and will set the clen to the compressed |
|
354 length, the caller should verify if true and clen less than the |
|
355 input data |
|
356 */ |
|
357 bool jar::deflate_bytes(bytes& head, bytes& tail) { |
|
358 int len = head.len + tail.len; |
|
359 |
|
360 z_stream zs; |
|
361 BYTES_OF(zs).clear(); |
|
362 |
|
363 // NOTE: the window size should always be -MAX_WBITS normally -15. |
|
364 // unzip/zipup.c and java/Deflater.c |
|
365 |
|
366 int error = deflateInit2(&zs, Z_BEST_COMPRESSION, Z_DEFLATED, |
|
367 -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); |
|
368 if (error != Z_OK) { |
|
369 switch (error) { |
|
370 case Z_MEM_ERROR: |
|
371 printcr(2, "Error: deflate error : Out of memory \n"); |
|
372 break; |
|
373 case Z_STREAM_ERROR: |
|
374 printcr(2,"Error: deflate error : Invalid compression level \n"); |
|
375 break; |
|
376 case Z_VERSION_ERROR: |
|
377 printcr(2,"Error: deflate error : Invalid version\n"); |
|
378 break; |
|
379 default: |
|
380 printcr(2,"Error: Internal deflate error error = %d\n", error); |
|
381 } |
|
382 return false; |
|
383 } |
|
384 |
|
385 deflated.empty(); |
|
386 zs.next_out = (uchar*) deflated.grow(len + (len/2)); |
|
387 zs.avail_out = deflated.size(); |
|
388 |
|
389 zs.next_in = (uchar*)head.ptr; |
|
390 zs.avail_in = head.len; |
|
391 |
|
392 bytes* first = &head; |
|
393 bytes* last = &tail; |
|
394 if (last->len == 0) { |
|
395 first = null; |
|
396 last = &head; |
|
397 } else if (first->len == 0) { |
|
398 first = null; |
|
399 } |
|
400 |
|
401 if (first != null && error == Z_OK) { |
|
402 zs.next_in = (uchar*) first->ptr; |
|
403 zs.avail_in = first->len; |
|
404 error = deflate(&zs, Z_NO_FLUSH); |
|
405 } |
|
406 if (error == Z_OK) { |
|
407 zs.next_in = (uchar*) last->ptr; |
|
408 zs.avail_in = last->len; |
|
409 error = deflate(&zs, Z_FINISH); |
|
410 } |
|
411 if (error == Z_STREAM_END) { |
|
412 if (len > zs.total_out ) { |
|
413 printcr(2, "deflate compressed data %d -> %d\n", len, zs.total_out); |
|
414 deflated.b.len = zs.total_out; |
|
415 deflateEnd(&zs); |
|
416 return true; |
|
417 } |
|
418 printcr(2, "deflate expanded data %d -> %d\n", len, zs.total_out); |
|
419 deflateEnd(&zs); |
|
420 return false; |
|
421 } |
|
422 |
|
423 deflateEnd(&zs); |
|
424 printcr(2, "Error: deflate error deflate did not finish error=%d\n",error); |
|
425 return false; |
|
426 } |
|
427 |
|
428 // Callback for fetching data from a GZIP input stream |
|
429 static jlong read_input_via_gzip(unpacker* u, |
|
430 void* buf, jlong minlen, jlong maxlen) { |
|
431 assert(minlen <= maxlen); // don't talk nonsense |
|
432 jlong numread = 0; |
|
433 char* bufptr = (char*) buf; |
|
434 char* inbuf = u->gzin->inbuf; |
|
435 size_t inbuflen = sizeof(u->gzin->inbuf); |
|
436 unpacker::read_input_fn_t read_gzin_fn = |
|
437 (unpacker::read_input_fn_t) u->gzin->read_input_fn; |
|
438 z_stream& zs = *(z_stream*) u->gzin->zstream; |
|
439 while (numread < minlen) { |
|
440 int readlen = (1 << 16); // pretty arbitrary |
|
441 if (readlen > (maxlen - numread)) |
|
442 readlen = (int)(maxlen - numread); |
|
443 zs.next_out = (uchar*) bufptr; |
|
444 zs.avail_out = readlen; |
|
445 if (zs.avail_in == 0) { |
|
446 zs.avail_in = (int) read_gzin_fn(u, inbuf, 1, inbuflen); |
|
447 zs.next_in = (uchar*) inbuf; |
|
448 } |
|
449 int error = inflate(&zs, Z_NO_FLUSH); |
|
450 if (error != Z_OK && error != Z_STREAM_END) { |
|
451 u->abort("error inflating input"); |
|
452 break; |
|
453 } |
|
454 int nr = readlen - zs.avail_out; |
|
455 numread += nr; |
|
456 bufptr += nr; |
|
457 assert(numread <= maxlen); |
|
458 if (error == Z_STREAM_END) { |
|
459 enum { TRAILER_LEN = 8 }; |
|
460 // skip 8-byte trailer |
|
461 if (zs.avail_in >= TRAILER_LEN) { |
|
462 zs.avail_in -= TRAILER_LEN; |
|
463 } else { |
|
464 // Bug: 5023768,we read past the TRAILER_LEN to see if there is |
|
465 // any extraneous data, as we dont support concatenated .gz |
|
466 // files just yet. |
|
467 int extra = (int) read_gzin_fn(u, inbuf, 1, inbuflen); |
|
468 zs.avail_in += extra - TRAILER_LEN; |
|
469 } |
|
470 // %%% should check final CRC and length here |
|
471 // %%% should check for concatenated *.gz files here |
|
472 if (zs.avail_in > 0) |
|
473 u->abort("garbage after end of deflated input stream"); |
|
474 // pop this filter off: |
|
475 u->gzin->free(); |
|
476 break; |
|
477 } |
|
478 } |
|
479 |
|
480 //fprintf(u->errstrm, "readInputFn(%d,%d) => %d (gunzip)\n", |
|
481 // (int)minlen, (int)maxlen, (int)numread); |
|
482 return numread; |
|
483 } |
|
484 |
|
485 void gunzip::init(unpacker* u_) { |
|
486 BYTES_OF(*this).clear(); |
|
487 u = u_; |
|
488 assert(u->gzin == null); // once only, please |
|
489 read_input_fn = (void*)(intptr_t)u->read_input_fn; |
|
490 zstream = NEW(z_stream, 1); |
|
491 u->gzin = this; |
|
492 u->read_input_fn = read_input_via_gzip; |
|
493 } |
|
494 |
|
495 void gunzip::start(int magic) { |
|
496 assert((magic & GZIP_MAGIC_MASK) == GZIP_MAGIC); |
|
497 int gz_flg = (magic & 0xFF); // keep "flg", discard other 3 bytes |
|
498 enum { |
|
499 FHCRC = (1<<1), |
|
500 FEXTRA = (1<<2), |
|
501 FNAME = (1<<3), |
|
502 FCOMMENT = (1<<4) |
|
503 }; |
|
504 char gz_mtime[4]; |
|
505 char gz_xfl[1]; |
|
506 char gz_os[1]; |
|
507 char gz_extra_len[2]; |
|
508 char gz_hcrc[2]; |
|
509 char gz_ignore; |
|
510 // do not save extra, name, comment |
|
511 read_fixed_field(gz_mtime, sizeof(gz_mtime)); |
|
512 read_fixed_field(gz_xfl, sizeof(gz_xfl)); |
|
513 read_fixed_field(gz_os, sizeof(gz_os)); |
|
514 if (gz_flg & FEXTRA) { |
|
515 read_fixed_field(gz_extra_len, sizeof(gz_extra_len)); |
|
516 int extra_len = gz_extra_len[0] & 0xFF; |
|
517 extra_len += (gz_extra_len[1] & 0xFF) << 8; |
|
518 for (; extra_len > 0; extra_len--) { |
|
519 read_fixed_field(&gz_ignore, 1); |
|
520 } |
|
521 } |
|
522 int null_terms = 0; |
|
523 if (gz_flg & FNAME) null_terms++; |
|
524 if (gz_flg & FCOMMENT) null_terms++; |
|
525 for (; null_terms; null_terms--) { |
|
526 for (;;) { |
|
527 gz_ignore = 0; |
|
528 read_fixed_field(&gz_ignore, 1); |
|
529 if (gz_ignore == 0) break; |
|
530 } |
|
531 } |
|
532 if (gz_flg & FHCRC) |
|
533 read_fixed_field(gz_hcrc, sizeof(gz_hcrc)); |
|
534 |
|
535 if (aborting()) return; |
|
536 |
|
537 // now the input stream is ready to read into the inflater |
|
538 int error = inflateInit2((z_stream*) zstream, -MAX_WBITS); |
|
539 if (error != Z_OK) { abort("cannot create input"); return; } |
|
540 } |
|
541 |
|
542 void gunzip::free() { |
|
543 assert(u->gzin == this); |
|
544 u->gzin = null; |
|
545 u->read_input_fn = (unpacker::read_input_fn_t) this->read_input_fn; |
|
546 inflateEnd((z_stream*) zstream); |
|
547 mtrace('f', zstream, 0); |
|
548 ::free(zstream); |
|
549 zstream = null; |
|
550 mtrace('f', this, 0); |
|
551 ::free(this); |
|
552 } |
|
553 |
|
554 void gunzip::read_fixed_field(char* buf, size_t buflen) { |
|
555 if (aborting()) return; |
|
556 jlong nr = ((unpacker::read_input_fn_t)read_input_fn) |
|
557 (u, buf, buflen, buflen); |
|
558 if (nr != buflen) |
|
559 u->abort("short stream header"); |
|
560 } |
|
561 |
|
562 #else // NO_ZLIB |
|
563 |
|
564 void gunzip::free() { |
|
565 } |
|
566 |
|
567 #endif // NO_ZLIB |