1 /* zip.c -- IO on .zip files using zlib
2 Version 0.15 beta, Mar 19th, 1998,
4 Read zip.h for more info
29 /* compile with -Dlocal if your debugger can't find static symbols */
32 # define VERSIONMADEBY (0x0) /* platform depedent */
36 #define Z_BUFSIZE (16384)
39 #ifndef Z_MAXFILENAMEINZIP
40 #define Z_MAXFILENAMEINZIP (256)
44 # define ALLOC(size) (malloc(size))
47 # define TRYFREE(p) {if (p) free(p);}
51 #define SIZECENTRALDIRITEM (0x2e)
52 #define SIZEZIPLOCALHEADER (0x1e)
55 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
69 const char zip_copyright
[] =
70 " zip 0.15 Copyright 1998 Gilles Vollant ";
73 #define SIZEDATA_INDATABLOCK (4096-(4*4))
75 #define LOCALHEADERMAGIC (0x04034b50)
76 #define CENTRALHEADERMAGIC (0x02014b50)
77 #define ENDHEADERMAGIC (0x06054b50)
79 #define FLAG_LOCALHEADER_OFFSET (0x06)
80 #define CRC_LOCALHEADER_OFFSET (0x0e)
82 #define SIZECENTRALHEADER (0x2e) /* 46 */
84 typedef struct linkedlist_datablock_internal_s
86 struct linkedlist_datablock_internal_s
* next_datablock
;
87 uLong avail_in_this_block
;
88 uLong filled_in_this_block
;
89 uLong unused
; /* for future use and alignement */
90 unsigned char data
[SIZEDATA_INDATABLOCK
];
91 } linkedlist_datablock_internal
;
93 typedef struct linkedlist_data_s
95 linkedlist_datablock_internal
* first_block
;
96 linkedlist_datablock_internal
* last_block
;
102 z_stream stream
; /* zLib stream structure for inflate */
103 int stream_initialised
; /* 1 is stream is initialised */
104 uInt pos_in_buffered_data
; /* last written byte in buffered_data */
106 uLong pos_local_header
; /* offset of the local header of the file
108 char* central_header
; /* central header data for the current file */
109 uLong size_centralheader
; /* size of the central header for cur file */
110 uLong flag
; /* flag of the file currently writing */
112 int method
; /* compression method of file currenty wr.*/
113 Byte buffered_data
[Z_BUFSIZE
];/* buffer contain compressed data to be writ*/
121 linkedlist_data central_dir
;/* datablock with central dir in construction*/
122 int in_opened_file_inzip
; /* 1 if a file in the zip is currently writ.*/
123 curfile_info ci
; /* info on the file curretly writing */
125 uLong begin_pos
; /* position of the beginning of the zipfile */
129 local linkedlist_datablock_internal
* allocate_new_datablock()
131 linkedlist_datablock_internal
* ldi
;
132 ldi
= (linkedlist_datablock_internal
*)
133 ALLOC(sizeof(linkedlist_datablock_internal
));
136 ldi
->next_datablock
= NULL
;
137 ldi
->filled_in_this_block
= 0 ;
138 ldi
->avail_in_this_block
= SIZEDATA_INDATABLOCK
;
143 local
void free_datablock(ldi
)
144 linkedlist_datablock_internal
* ldi
;
148 linkedlist_datablock_internal
* ldinext
= ldi
->next_datablock
;
154 local
void init_linkedlist(ll
)
157 ll
->first_block
= ll
->last_block
= NULL
;
160 local
void free_linkedlist(ll
)
163 free_datablock(ll
->first_block
);
164 ll
->first_block
= ll
->last_block
= NULL
;
168 local
int add_data_in_datablock(ll
,buf
,len
)
173 linkedlist_datablock_internal
* ldi
;
174 const unsigned char* from_copy
;
177 return ZIP_INTERNALERROR
;
179 if (ll
->last_block
== NULL
)
181 ll
->first_block
= ll
->last_block
= allocate_new_datablock();
182 if (ll
->first_block
== NULL
)
183 return ZIP_INTERNALERROR
;
186 ldi
= ll
->last_block
;
187 from_copy
= (unsigned char*)buf
;
193 unsigned char* to_copy
;
195 if (ldi
->avail_in_this_block
==0)
197 ldi
->next_datablock
= allocate_new_datablock();
198 if (ldi
->next_datablock
== NULL
)
199 return ZIP_INTERNALERROR
;
200 ldi
= ldi
->next_datablock
;
201 ll
->last_block
= ldi
;
204 if (ldi
->avail_in_this_block
< len
)
205 copy_this
= (uInt
)ldi
->avail_in_this_block
;
207 copy_this
= (uInt
)len
;
209 to_copy
= &(ldi
->data
[ldi
->filled_in_this_block
]);
211 for (i
=0;i
<copy_this
;i
++)
212 *(to_copy
+i
)=*(from_copy
+i
);
214 ldi
->filled_in_this_block
+= copy_this
;
215 ldi
->avail_in_this_block
-= copy_this
;
216 from_copy
+= copy_this
;
223 local
int write_datablock(fout
,ll
)
227 linkedlist_datablock_internal
* ldi
;
228 ldi
= ll
->first_block
;
231 if (ldi
->filled_in_this_block
> 0)
232 if (fwrite(ldi
->data
,(uInt
)ldi
->filled_in_this_block
,1,fout
)!=1)
234 ldi
= ldi
->next_datablock
;
239 /****************************************************************************/
241 /* ===========================================================================
242 Outputs a long in LSB order to the given file
243 nbByte == 1, 2 or 4 (byte, short or long)
246 local
int ziplocal_putValue
OF((FILE *file
, uLong x
, int nbByte
));
247 local
int ziplocal_putValue (file
, x
, nbByte
)
252 unsigned char buf
[4];
254 for (n
= 0; n
< nbByte
; n
++) {
255 buf
[n
] = (unsigned char)(x
& 0xff);
258 if (fwrite(buf
,nbByte
,1,file
)!=1)
264 local
void ziplocal_putValue_inmemory
OF((void* dest
, uLong x
, int nbByte
));
265 local
void ziplocal_putValue_inmemory (dest
, x
, nbByte
)
270 unsigned char* buf
=(unsigned char*)dest
;
272 for (n
= 0; n
< nbByte
; n
++) {
273 buf
[n
] = (unsigned char)(x
& 0xff);
277 /****************************************************************************/
280 local uLong
ziplocal_TmzDateToDosDate(ptm
,dosDate
)
284 uLong year
= (uLong
)ptm
->tm_year
;
290 (uLong
) (((ptm
->tm_mday
) + (32 * (ptm
->tm_mon
+1)) + (512 * year
)) << 16) |
291 ((ptm
->tm_sec
/2) + (32* ptm
->tm_min
) + (2048 * (uLong
)ptm
->tm_hour
));
295 /****************************************************************************/
297 extern zipFile ZEXPORT
zipOpen (pathname
, append
)
298 const char *pathname
;
304 ziinit
.filezip
= fopen(pathname
,(append
== 0) ? "wb" : "ab");
305 if (ziinit
.filezip
== NULL
)
307 ziinit
.begin_pos
= ftell(ziinit
.filezip
);
308 ziinit
.in_opened_file_inzip
= 0;
309 ziinit
.ci
.stream_initialised
= 0;
310 ziinit
.number_entry
= 0;
311 init_linkedlist(&(ziinit
.central_dir
));
314 zi
= (zip_internal
*)ALLOC(sizeof(zip_internal
));
317 fclose(ziinit
.filezip
);
325 extern int ZEXPORT
zipOpenNewFileInZip (file
, filename
, zipfi
,
326 extrafield_local
, size_extrafield_local
,
327 extrafield_global
, size_extrafield_global
,
328 comment
, method
, level
)
330 const char* filename
;
331 const zip_fileinfo
* zipfi
;
332 const void* extrafield_local
;
333 uInt size_extrafield_local
;
334 const void* extrafield_global
;
335 uInt size_extrafield_global
;
347 return ZIP_PARAMERROR
;
348 if ((method
!=0) && (method
!=Z_DEFLATED
))
349 return ZIP_PARAMERROR
;
351 zi
= (zip_internal
*)file
;
353 if (zi
->in_opened_file_inzip
== 1)
355 err
= zipCloseFileInZip (file
);
367 size_comment
= strlen(comment
);
369 size_filename
= strlen(filename
);
375 if (zipfi
->dosDate
!= 0)
376 zi
->ci
.dosDate
= zipfi
->dosDate
;
377 else zi
->ci
.dosDate
= ziplocal_TmzDateToDosDate(&zipfi
->tmz_date
,zipfi
->dosDate
);
381 if ((level
==8) || (level
==9))
389 zi
->ci
.method
= method
;
390 zi
->ci
.stream_initialised
= 0;
391 zi
->ci
.pos_in_buffered_data
= 0;
392 zi
->ci
.pos_local_header
= ftell(zi
->filezip
);
393 zi
->ci
.size_centralheader
= SIZECENTRALHEADER
+ size_filename
+
394 size_extrafield_global
+ size_comment
;
395 zi
->ci
.central_header
= (char*)ALLOC((uInt
)zi
->ci
.size_centralheader
);
397 ziplocal_putValue_inmemory(zi
->ci
.central_header
,(uLong
)CENTRALHEADERMAGIC
,4);
399 ziplocal_putValue_inmemory(zi
->ci
.central_header
+4,(uLong
)VERSIONMADEBY
,2);
400 ziplocal_putValue_inmemory(zi
->ci
.central_header
+6,(uLong
)20,2);
401 ziplocal_putValue_inmemory(zi
->ci
.central_header
+8,(uLong
)zi
->ci
.flag
,2);
402 ziplocal_putValue_inmemory(zi
->ci
.central_header
+10,(uLong
)zi
->ci
.method
,2);
403 ziplocal_putValue_inmemory(zi
->ci
.central_header
+12,(uLong
)zi
->ci
.dosDate
,4);
404 ziplocal_putValue_inmemory(zi
->ci
.central_header
+16,(uLong
)0,4); /*crc*/
405 ziplocal_putValue_inmemory(zi
->ci
.central_header
+20,(uLong
)0,4); /*compr size*/
406 ziplocal_putValue_inmemory(zi
->ci
.central_header
+24,(uLong
)0,4); /*uncompr size*/
407 ziplocal_putValue_inmemory(zi
->ci
.central_header
+28,(uLong
)size_filename
,2);
408 ziplocal_putValue_inmemory(zi
->ci
.central_header
+30,(uLong
)size_extrafield_global
,2);
409 ziplocal_putValue_inmemory(zi
->ci
.central_header
+32,(uLong
)size_comment
,2);
410 ziplocal_putValue_inmemory(zi
->ci
.central_header
+34,(uLong
)0,2); /*disk nm start*/
413 ziplocal_putValue_inmemory(zi
->ci
.central_header
+36,(uLong
)0,2);
415 ziplocal_putValue_inmemory(zi
->ci
.central_header
+36,(uLong
)zipfi
->internal_fa
,2);
418 ziplocal_putValue_inmemory(zi
->ci
.central_header
+38,(uLong
)0,4);
420 ziplocal_putValue_inmemory(zi
->ci
.central_header
+38,(uLong
)zipfi
->external_fa
,4);
422 ziplocal_putValue_inmemory(zi
->ci
.central_header
+42,(uLong
)zi
->ci
.pos_local_header
,4);
424 for (i
=0;i
<size_filename
;i
++)
425 *(zi
->ci
.central_header
+SIZECENTRALHEADER
+i
) = *(filename
+i
);
427 for (i
=0;i
<size_extrafield_global
;i
++)
428 *(zi
->ci
.central_header
+SIZECENTRALHEADER
+size_filename
+i
) =
429 *(((const char*)extrafield_global
)+i
);
431 for (i
=0;i
<size_comment
;i
++)
432 *(zi
->ci
.central_header
+SIZECENTRALHEADER
+size_filename
+
433 size_extrafield_global
+i
) = *(filename
+i
);
434 if (zi
->ci
.central_header
== NULL
)
435 return ZIP_INTERNALERROR
;
437 /* write the local header */
438 err
= ziplocal_putValue(zi
->filezip
,(uLong
)LOCALHEADERMAGIC
,4);
441 err
= ziplocal_putValue(zi
->filezip
,(uLong
)20,2);/* version needed to extract */
443 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.flag
,2);
446 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.method
,2);
449 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.dosDate
,4);
452 err
= ziplocal_putValue(zi
->filezip
,(uLong
)0,4); /* crc 32, unknown */
454 err
= ziplocal_putValue(zi
->filezip
,(uLong
)0,4); /* compressed size, unknown */
456 err
= ziplocal_putValue(zi
->filezip
,(uLong
)0,4); /* uncompressed size, unknown */
459 err
= ziplocal_putValue(zi
->filezip
,(uLong
)size_filename
,2);
462 err
= ziplocal_putValue(zi
->filezip
,(uLong
)size_extrafield_local
,2);
464 if ((err
==ZIP_OK
) && (size_filename
>0))
465 if (fwrite(filename
,(uInt
)size_filename
,1,zi
->filezip
)!=1)
468 if ((err
==ZIP_OK
) && (size_extrafield_local
>0))
469 if (fwrite(extrafield_local
,(uInt
)size_extrafield_local
,1,zi
->filezip
)
473 zi
->ci
.stream
.avail_in
= (uInt
)0;
474 zi
->ci
.stream
.avail_out
= (uInt
)Z_BUFSIZE
;
475 zi
->ci
.stream
.next_out
= zi
->ci
.buffered_data
;
476 zi
->ci
.stream
.total_in
= 0;
477 zi
->ci
.stream
.total_out
= 0;
479 if ((err
==ZIP_OK
) && (zi
->ci
.method
== Z_DEFLATED
))
481 zi
->ci
.stream
.zalloc
= (alloc_func
)0;
482 zi
->ci
.stream
.zfree
= (free_func
)0;
483 zi
->ci
.stream
.opaque
= (voidpf
)0;
485 err
= deflateInit2(&zi
->ci
.stream
, level
,
486 Z_DEFLATED
, -MAX_WBITS
, DEF_MEM_LEVEL
, 0);
489 zi
->ci
.stream_initialised
= 1;
494 zi
->in_opened_file_inzip
= 1;
498 extern int ZEXPORT
zipWriteInFileInZip (file
, buf
, len
)
507 return ZIP_PARAMERROR
;
508 zi
= (zip_internal
*)file
;
510 if (zi
->in_opened_file_inzip
== 0)
511 return ZIP_PARAMERROR
;
513 zi
->ci
.stream
.next_in
= buf
;
514 zi
->ci
.stream
.avail_in
= len
;
515 zi
->ci
.crc32
= crc32(zi
->ci
.crc32
,buf
,len
);
517 while ((err
==ZIP_OK
) && (zi
->ci
.stream
.avail_in
>0))
519 if (zi
->ci
.stream
.avail_out
== 0)
521 if (fwrite(zi
->ci
.buffered_data
,(uInt
)zi
->ci
.pos_in_buffered_data
,1,zi
->filezip
)
524 zi
->ci
.pos_in_buffered_data
= 0;
525 zi
->ci
.stream
.avail_out
= (uInt
)Z_BUFSIZE
;
526 zi
->ci
.stream
.next_out
= zi
->ci
.buffered_data
;
529 if (zi
->ci
.method
== Z_DEFLATED
)
531 uLong uTotalOutBefore
= zi
->ci
.stream
.total_out
;
532 err
=deflate(&zi
->ci
.stream
, Z_NO_FLUSH
);
533 zi
->ci
.pos_in_buffered_data
+= (uInt
)(zi
->ci
.stream
.total_out
- uTotalOutBefore
) ;
539 if (zi
->ci
.stream
.avail_in
< zi
->ci
.stream
.avail_out
)
540 copy_this
= zi
->ci
.stream
.avail_in
;
542 copy_this
= zi
->ci
.stream
.avail_out
;
543 for (i
=0;i
<copy_this
;i
++)
544 *(((char*)zi
->ci
.stream
.next_out
)+i
) =
545 *(((const char*)zi
->ci
.stream
.next_in
)+i
);
547 zi
->ci
.stream
.avail_in
-= copy_this
;
548 zi
->ci
.stream
.avail_out
-= copy_this
;
549 zi
->ci
.stream
.next_in
+= copy_this
;
550 zi
->ci
.stream
.next_out
+= copy_this
;
551 zi
->ci
.stream
.total_in
+= copy_this
;
552 zi
->ci
.stream
.total_out
+= copy_this
;
553 zi
->ci
.pos_in_buffered_data
+= copy_this
;
561 extern int ZEXPORT
zipCloseFileInZip (file
)
568 return ZIP_PARAMERROR
;
569 zi
= (zip_internal
*)file
;
571 if (zi
->in_opened_file_inzip
== 0)
572 return ZIP_PARAMERROR
;
573 zi
->ci
.stream
.avail_in
= 0;
575 if (zi
->ci
.method
== Z_DEFLATED
)
578 uLong uTotalOutBefore
;
579 if (zi
->ci
.stream
.avail_out
== 0)
581 if (fwrite(zi
->ci
.buffered_data
,(uInt
)zi
->ci
.pos_in_buffered_data
,1,zi
->filezip
)
584 zi
->ci
.pos_in_buffered_data
= 0;
585 zi
->ci
.stream
.avail_out
= (uInt
)Z_BUFSIZE
;
586 zi
->ci
.stream
.next_out
= zi
->ci
.buffered_data
;
588 uTotalOutBefore
= zi
->ci
.stream
.total_out
;
589 err
=deflate(&zi
->ci
.stream
, Z_FINISH
);
590 zi
->ci
.pos_in_buffered_data
+= (uInt
)(zi
->ci
.stream
.total_out
- uTotalOutBefore
) ;
593 if (err
==Z_STREAM_END
)
594 err
=ZIP_OK
; /* this is normal */
596 if ((zi
->ci
.pos_in_buffered_data
>0) && (err
==ZIP_OK
))
597 if (fwrite(zi
->ci
.buffered_data
,(uInt
)zi
->ci
.pos_in_buffered_data
,1,zi
->filezip
)
601 if ((zi
->ci
.method
== Z_DEFLATED
) && (err
==ZIP_OK
))
603 err
=deflateEnd(&zi
->ci
.stream
);
604 zi
->ci
.stream_initialised
= 0;
607 ziplocal_putValue_inmemory(zi
->ci
.central_header
+16,(uLong
)zi
->ci
.crc32
,4); /*crc*/
608 ziplocal_putValue_inmemory(zi
->ci
.central_header
+20,
609 (uLong
)zi
->ci
.stream
.total_out
,4); /*compr size*/
610 ziplocal_putValue_inmemory(zi
->ci
.central_header
+24,
611 (uLong
)zi
->ci
.stream
.total_in
,4); /*uncompr size*/
614 err
= add_data_in_datablock(&zi
->central_dir
,zi
->ci
.central_header
,
615 (uLong
)zi
->ci
.size_centralheader
);
616 free(zi
->ci
.central_header
);
620 long cur_pos_inzip
= ftell(zi
->filezip
);
621 if (fseek(zi
->filezip
,
622 zi
->ci
.pos_local_header
+ 14,SEEK_SET
)!=0)
626 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.crc32
,4); /* crc 32, unknown */
628 if (err
==ZIP_OK
) /* compressed size, unknown */
629 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.stream
.total_out
,4);
631 if (err
==ZIP_OK
) /* uncompressed size, unknown */
632 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.stream
.total_in
,4);
634 if (fseek(zi
->filezip
,
635 cur_pos_inzip
,SEEK_SET
)!=0)
640 zi
->in_opened_file_inzip
= 0;
645 extern int ZEXPORT
zipClose (file
, global_comment
)
647 const char* global_comment
;
651 uLong size_centraldir
= 0;
652 uLong centraldir_pos_inzip
;
653 uInt size_global_comment
;
655 return ZIP_PARAMERROR
;
656 zi
= (zip_internal
*)file
;
658 if (zi
->in_opened_file_inzip
== 1)
660 err
= zipCloseFileInZip (file
);
663 if (global_comment
==NULL
)
664 size_global_comment
= 0;
666 size_global_comment
= strlen(global_comment
);
669 centraldir_pos_inzip
= ftell(zi
->filezip
);
672 linkedlist_datablock_internal
* ldi
= zi
->central_dir
.first_block
;
675 if ((err
==ZIP_OK
) && (ldi
->filled_in_this_block
>0))
676 if (fwrite(ldi
->data
,(uInt
)ldi
->filled_in_this_block
,
680 size_centraldir
+= ldi
->filled_in_this_block
;
681 ldi
= ldi
->next_datablock
;
684 free_datablock(zi
->central_dir
.first_block
);
686 if (err
==ZIP_OK
) /* Magic End */
687 err
= ziplocal_putValue(zi
->filezip
,(uLong
)ENDHEADERMAGIC
,4);
689 if (err
==ZIP_OK
) /* number of this disk */
690 err
= ziplocal_putValue(zi
->filezip
,(uLong
)0,2);
692 if (err
==ZIP_OK
) /* number of the disk with the start of the central directory */
693 err
= ziplocal_putValue(zi
->filezip
,(uLong
)0,2);
695 if (err
==ZIP_OK
) /* total number of entries in the central dir on this disk */
696 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->number_entry
,2);
698 if (err
==ZIP_OK
) /* total number of entries in the central dir */
699 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->number_entry
,2);
701 if (err
==ZIP_OK
) /* size of the central directory */
702 err
= ziplocal_putValue(zi
->filezip
,(uLong
)size_centraldir
,4);
704 if (err
==ZIP_OK
) /* offset of start of central directory with respect to the
705 starting disk number */
706 err
= ziplocal_putValue(zi
->filezip
,(uLong
)centraldir_pos_inzip
,4);
708 if (err
==ZIP_OK
) /* zipfile comment length */
709 err
= ziplocal_putValue(zi
->filezip
,(uLong
)size_global_comment
,2);
711 if ((err
==ZIP_OK
) && (size_global_comment
>0))
712 if (fwrite(global_comment
,(uInt
)size_global_comment
,1,zi
->filezip
) !=1 )