1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
42 static void inttox (int in
, char *out
);
43 static void longtox (long in
, char *out
);
45 /****************************************************************
49 * Opens a new ZIP file and creates a new ZIPfile structure to
50 * control the process of installing files into a zip.
53 JzipOpen(char *filename
, char *comment
)
56 PRExplodedTime prtime
;
58 zipfile
= PORT_ZAlloc(sizeof(ZIPfile
));
62 /* Construct time and date */
63 PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters
, &prtime
);
64 zipfile
->date
= ((prtime
.tm_year
- 1980) << 9) |
65 ((prtime
.tm_month
+ 1) << 5) |
67 zipfile
->time
= (prtime
.tm_hour
<< 11) |
68 (prtime
.tm_min
<< 5) |
69 (prtime
.tm_sec
& 0x3f);
73 (zipfile
->fp
= PR_Open(filename
,
74 PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
, 0777)) == NULL
) {
76 if (PR_GetErrorTextLength()) {
77 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
78 PR_GetErrorText(nsprErr
);
82 PR_fprintf(errorFD
, "%s: can't open output jar, %s.%s\n",
84 filename
, nsprErr
? nsprErr
: "");
93 zipfile
->filename
= PORT_ZAlloc(strlen(filename
) + 1);
94 if (!zipfile
->filename
)
96 PORT_Strcpy(zipfile
->filename
, filename
);
99 zipfile
->comment
= PORT_ZAlloc(strlen(comment
) + 1);
100 if (!zipfile
->comment
)
102 PORT_Strcpy(zipfile
->comment
, comment
);
111 my_alloc_func(void*opaque
, uInt items
, uInt size
)
113 return PORT_Alloc(items
* size
);
119 my_free_func(void*opaque
, void*address
)
127 handle_zerror(int err
, char *msg
)
133 errorCount
++; /* unless Z_OK...see below */
137 PR_fprintf(errorFD
, "No error: %s\n", msg
);
138 errorCount
--; /* this was incremented above */
141 PR_fprintf(errorFD
, "Deflation ran out of memory: %s\n", msg
);
144 PR_fprintf(errorFD
, "Invalid compression level: %s\n", msg
);
146 case Z_VERSION_ERROR
:
147 PR_fprintf(errorFD
, "Incompatible compression library version: %s\n",
151 PR_fprintf(errorFD
, "Compression data error: %s\n", msg
);
154 PR_fprintf(errorFD
, "Unknown error in compression library: %s\n", msg
);
162 /****************************************************************
166 * Adds a new file into a ZIP file. The ZIP file must have already
167 * been opened with JzipOpen.
170 JzipAdd(char *fullname
, char *filename
, ZIPfile
*zipfile
, int compression_level
)
176 unsigned long local_size_pos
;
182 Bytef outbuf
[BUFSIZ
];
185 if ( !fullname
|| !filename
|| !zipfile
) {
194 if ( (readfp
= PR_Open(fullname
, PR_RDONLY
, 0777)) == NULL
) {
196 if (PR_GetErrorTextLength()) {
197 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
198 PR_GetErrorText(nsprErr
);
202 PR_fprintf(errorFD
, "%s: %s\n", fullname
, nsprErr
? nsprErr
:
211 * Make sure the input file is not the output file.
212 * Add a few bytes to the end of the JAR file and see if the input file
220 inputSize
= PR_Available(readfp
);
222 endOfJar
= PR_Seek(zipfp
, 0L, PR_SEEK_CUR
);
224 if (PR_Write(zipfp
, "abcde", 5) < 5) {
227 if (PR_GetErrorTextLength()) {
228 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
229 PR_GetErrorText(nsprErr
);
233 PR_fprintf(errorFD
, "Writing to zip file: %s\n",
234 nsprErr
? nsprErr
: "");
241 isSame
= (PR_Available(readfp
) != inputSize
);
243 PR_Seek(zipfp
, endOfJar
, PR_SEEK_SET
);
246 /* It's the same file! Forget it! */
252 if (verbosity
>= 0) {
253 PR_fprintf(outputFD
, "adding %s to %s...", fullname
, zipfile
->filename
);
256 entry
= PORT_ZAlloc(sizeof(ZIPentry
));
260 entry
->filename
= PORT_Strdup(filename
);
261 entry
->comment
= NULL
;
263 /* Set up local file header */
264 longtox(LSIG
, entry
->local
.signature
);
265 inttox(strlen(filename
), entry
->local
.filename_len
);
266 inttox(zipfile
->time
, entry
->local
.time
);
267 inttox(zipfile
->date
, entry
->local
.date
);
268 inttox(Z_DEFLATED
, entry
->local
.method
);
270 /* Set up central directory entry */
271 longtox(CSIG
, entry
->central
.signature
);
272 inttox(strlen(filename
), entry
->central
.filename_len
);
273 if (entry
->comment
) {
274 inttox(strlen(entry
->comment
), entry
->central
.commentfield_len
);
276 longtox(PR_Seek(zipfile
->fp
, 0, PR_SEEK_CUR
),
277 entry
->central
.localhdr_offset
);
278 inttox(zipfile
->time
, entry
->central
.time
);
279 inttox(zipfile
->date
, entry
->central
.date
);
280 inttox(Z_DEFLATED
, entry
->central
.method
);
282 /* Compute crc. Too bad we have to process the whole file to do this*/
283 crc
= crc32(0L, NULL
, 0);
284 while ( (num
= PR_Read(readfp
, inbuf
, BUFSIZ
)) > 0) {
285 crc
= crc32(crc
, inbuf
, num
);
287 PR_Seek(readfp
, 0L, PR_SEEK_SET
);
290 longtox(crc
, entry
->local
.crc32
);
291 longtox(crc
, entry
->central
.crc32
);
293 /* Stick this entry onto the end of the list */
295 if ( zipfile
->list
== NULL
) {
297 zipfile
->list
= entry
;
302 while (pe
->next
!= NULL
) {
309 * Start writing stuff out
312 local_size_pos
= PR_Seek(zipfp
, 0, PR_SEEK_CUR
) + 18;
314 if (PR_Write(zipfp
, &entry
->local
, sizeof(struct ZipLocal
))
315 < sizeof(struct ZipLocal
)) {
317 if (PR_GetErrorTextLength()) {
318 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
319 PR_GetErrorText(nsprErr
);
323 PR_fprintf(errorFD
, "Writing zip data: %s\n", nsprErr
? nsprErr
:
332 if ( PR_Write(zipfp
, filename
, strlen(filename
)) < strlen(filename
)) {
334 if (PR_GetErrorTextLength()) {
335 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
336 PR_GetErrorText(nsprErr
);
340 PR_fprintf(errorFD
, "Writing zip data: %s\n", nsprErr
? nsprErr
:
351 /* Initialize zstream */
352 zstream
.zalloc
= my_alloc_func
;
353 zstream
.zfree
= my_free_func
;
354 zstream
.opaque
= NULL
;
355 zstream
.next_in
= inbuf
;
356 zstream
.avail_in
= BUFSIZ
;
357 zstream
.next_out
= outbuf
;
358 zstream
.avail_out
= BUFSIZ
;
359 /* Setting the windowBits to -MAX_WBITS is an undocumented feature of
360 * zlib (see deflate.c in zlib). It is the same thing that Java does
361 * when you specify the nowrap option for deflation in java.util.zip.
362 * It causes zlib to leave out its headers and footers, which don't
363 * work in PKZIP files.
365 err
= deflateInit2(&zstream
, compression_level
, Z_DEFLATED
,
366 -MAX_WBITS
, 8 /*default*/, Z_DEFAULT_STRATEGY
);
368 handle_zerror(err
, zstream
.msg
);
372 while ( (zstream
.avail_in
= PR_Read(readfp
, inbuf
, BUFSIZ
)) > 0) {
373 zstream
.next_in
= inbuf
;
374 /* Process this chunk of data */
375 while (zstream
.avail_in
> 0) {
376 err
= deflate(&zstream
, Z_NO_FLUSH
);
378 handle_zerror(err
, zstream
.msg
);
381 if (zstream
.avail_out
<= 0) {
382 if ( PR_Write(zipfp
, outbuf
, BUFSIZ
) < BUFSIZ
) {
384 if (PR_GetErrorTextLength()) {
385 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
386 PR_GetErrorText(nsprErr
);
390 PR_fprintf(errorFD
, "Writing zip data: %s\n",
391 nsprErr
? nsprErr
: "");
397 zstream
.next_out
= outbuf
;
398 zstream
.avail_out
= BUFSIZ
;
403 /* Now flush everything */
405 err
= deflate(&zstream
, Z_FINISH
);
406 if (err
== Z_STREAM_END
) {
408 } else if (err
== Z_OK
) {
409 /* output buffer full, repeat */
411 handle_zerror(err
, zstream
.msg
);
414 if ( PR_Write(zipfp
, outbuf
, BUFSIZ
) < BUFSIZ
) {
416 if (PR_GetErrorTextLength()) {
417 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
418 PR_GetErrorText(nsprErr
);
422 PR_fprintf(errorFD
, "Writing zip data: %s\n",
423 nsprErr
? nsprErr
: "");
429 zstream
.avail_out
= BUFSIZ
;
430 zstream
.next_out
= outbuf
;
433 /* If there's any output left, write it out. */
434 if (zstream
.next_out
!= outbuf
) {
435 if ( PR_Write(zipfp
, outbuf
, zstream
.next_out
- outbuf
) <
436 zstream
.next_out
- outbuf
) {
438 if (PR_GetErrorTextLength()) {
439 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
440 PR_GetErrorText(nsprErr
);
444 PR_fprintf(errorFD
, "Writing zip data: %s\n",
445 nsprErr
? nsprErr
: "");
451 zstream
.avail_out
= BUFSIZ
;
452 zstream
.next_out
= outbuf
;
455 /* Now that we know the compressed size, write this to the headers */
456 longtox(zstream
.total_in
, entry
->local
.orglen
);
457 longtox(zstream
.total_out
, entry
->local
.size
);
458 if (PR_Seek(zipfp
, local_size_pos
, PR_SEEK_SET
) == -1) {
460 if (PR_GetErrorTextLength()) {
461 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
462 PR_GetErrorText(nsprErr
);
466 PR_fprintf(errorFD
, "Accessing zip file: %s\n", nsprErr
? nsprErr
: "");
472 if ( PR_Write(zipfp
, entry
->local
.size
, 8) != 8) {
474 if (PR_GetErrorTextLength()) {
475 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
476 PR_GetErrorText(nsprErr
);
480 PR_fprintf(errorFD
, "Writing zip data: %s\n", nsprErr
? nsprErr
: "");
486 if (PR_Seek(zipfp
, 0L, PR_SEEK_END
) == -1) {
488 if (PR_GetErrorTextLength()) {
489 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
490 PR_GetErrorText(nsprErr
);
494 PR_fprintf(errorFD
, "Accessing zip file: %s\n",
495 nsprErr
? nsprErr
: "");
501 longtox(zstream
.total_in
, entry
->central
.orglen
);
502 longtox(zstream
.total_out
, entry
->central
.size
);
504 /* Close out the deflation operation */
505 err
= deflateEnd(&zstream
);
507 handle_zerror(err
, zstream
.msg
);
513 if ((zstream
.total_in
> zstream
.total_out
) && (zstream
.total_in
> 0)) {
514 deflate_percent
= (int)
515 ((zstream
.total_in
- zstream
.total_out
) *100 / zstream
.total_in
);
519 if (verbosity
>= 0) {
520 PR_fprintf(outputFD
, "(deflated %d%%)\n", deflate_percent
);
527 /********************************************************************
530 * Finishes the ZipFile. ALSO DELETES THE ZIPFILE STRUCTURE PASSED IN!!
533 JzipClose(ZIPfile
*zipfile
)
535 ZIPentry
* pe
, *dead
;
537 struct ZipEnd zipend
;
538 unsigned int entrycount
= 0;
544 if (!zipfile
->filename
) {
550 zipfile
->central_start
= PR_Seek(zipfp
, 0L, PR_SEEK_CUR
);
552 /* Write out all the central directories */
557 /* Write central directory info */
558 if ( PR_Write(zipfp
, &pe
->central
, sizeof(struct ZipCentral
))
559 < sizeof(struct ZipCentral
)) {
561 if (PR_GetErrorTextLength()) {
562 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
563 PR_GetErrorText(nsprErr
);
567 PR_fprintf(errorFD
, "Writing zip data: %s\n",
568 nsprErr
? nsprErr
: "");
576 if ( PR_Write(zipfp
, pe
->filename
, strlen(pe
->filename
))
577 < strlen(pe
->filename
)) {
579 if (PR_GetErrorTextLength()) {
580 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
581 PR_GetErrorText(nsprErr
);
585 PR_fprintf(errorFD
, "Writing zip data: %s\n",
586 nsprErr
? nsprErr
: "");
593 /* Write file comment */
595 if ( PR_Write(zipfp
, pe
->comment
, strlen(pe
->comment
))
596 < strlen(pe
->comment
)) {
598 if (PR_GetErrorTextLength()) {
599 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
600 PR_GetErrorText(nsprErr
);
604 PR_fprintf(errorFD
, "Writing zip data: %s\n",
605 nsprErr
? nsprErr
: "");
613 /* Delete the structure */
616 if (dead
->filename
) {
617 PORT_Free(dead
->filename
);
620 PORT_Free(dead
->comment
);
624 zipfile
->central_end
= PR_Seek(zipfile
->fp
, 0L, PR_SEEK_CUR
);
626 /* Create the ZipEnd structure */
627 PORT_Memset(&zipend
, 0, sizeof(zipend
));
628 longtox(ESIG
, zipend
.signature
);
629 inttox(entrycount
, zipend
.total_entries_disk
);
630 inttox(entrycount
, zipend
.total_entries_archive
);
631 longtox(zipfile
->central_end
- zipfile
->central_start
,
632 zipend
.central_dir_size
);
633 longtox(zipfile
->central_start
, zipend
.offset_central_dir
);
634 if (zipfile
->comment
) {
635 inttox(strlen(zipfile
->comment
), zipend
.commentfield_len
);
638 /* Write out ZipEnd xtructure */
639 if ( PR_Write(zipfp
, &zipend
, sizeof(zipend
)) < sizeof(zipend
)) {
641 if (PR_GetErrorTextLength()) {
642 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
643 PR_GetErrorText(nsprErr
);
647 PR_fprintf(errorFD
, "Writing zip data: %s\n",
648 nsprErr
? nsprErr
: "");
655 /* Write out Zipfile comment */
656 if (zipfile
->comment
) {
657 if ( PR_Write(zipfp
, zipfile
->comment
, strlen(zipfile
->comment
))
658 < strlen(zipfile
->comment
)) {
660 if (PR_GetErrorTextLength()) {
661 nsprErr
= PR_Malloc(PR_GetErrorTextLength());
662 PR_GetErrorText(nsprErr
);
666 PR_fprintf(errorFD
, "Writing zip data: %s\n",
667 nsprErr
? nsprErr
: "");
677 /* Free the memory of the zipfile structure */
678 if (zipfile
->filename
) {
679 PORT_Free(zipfile
->filename
);
681 if (zipfile
->comment
) {
682 PORT_Free(zipfile
->comment
);
690 /**********************************************
693 * Converts a two byte ugly endianed integer
694 * to our platform's integer.
698 static void inttox (int in
, char *out
)
700 out
[0] = (in
& 0xFF);
701 out
[1] = (in
& 0xFF00) >> 8;
705 /*********************************************
708 * Converts a four byte ugly endianed integer
709 * to our platform's integer.
713 static void longtox (long in
, char *out
)
715 out
[0] = (in
& 0xFF);
716 out
[1] = (in
& 0xFF00) >> 8;
717 out
[2] = (in
& 0xFF0000) >> 16;
718 out
[3] = (in
& 0xFF000000) >> 24;