1 /* zip.c -- IO on .zip files using zlib
2 Version 0.15 beta, Mar 19th, 1998,
4 Read zip.h for more info
30 /* compile with -Dlocal if your debugger can't find static symbols */
33 # define VERSIONMADEBY (0x0) /* platform depedent */
37 #define Z_BUFSIZE (16384)
40 #ifndef Z_MAXFILENAMEINZIP
41 #define Z_MAXFILENAMEINZIP (256)
45 # define ALLOC(size) (malloc(size))
48 # define TRYFREE(p) {if (p) free(p);}
52 #define SIZECENTRALDIRITEM (0x2e)
53 #define SIZEZIPLOCALHEADER (0x1e)
56 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
70 const char zip_copyright
[] =
71 " zip 0.15 Copyright 1998 Gilles Vollant ";
74 #define SIZEDATA_INDATABLOCK (4096-(4*4))
76 #define LOCALHEADERMAGIC (0x04034b50)
77 #define CENTRALHEADERMAGIC (0x02014b50)
78 #define ENDHEADERMAGIC (0x06054b50)
80 #define FLAG_LOCALHEADER_OFFSET (0x06)
81 #define CRC_LOCALHEADER_OFFSET (0x0e)
83 #define SIZECENTRALHEADER (0x2e) /* 46 */
85 typedef struct linkedlist_datablock_internal_s
87 struct linkedlist_datablock_internal_s
* next_datablock
;
88 uLong avail_in_this_block
;
89 uLong filled_in_this_block
;
90 uLong unused
; /* for future use and alignement */
91 unsigned char data
[SIZEDATA_INDATABLOCK
];
92 } linkedlist_datablock_internal
;
94 typedef struct linkedlist_data_s
96 linkedlist_datablock_internal
* first_block
;
97 linkedlist_datablock_internal
* last_block
;
103 z_stream stream
; /* zLib stream structure for inflate */
104 int stream_initialised
; /* 1 is stream is initialised */
105 uInt pos_in_buffered_data
; /* last written byte in buffered_data */
107 uLong pos_local_header
; /* offset of the local header of the file
109 char* central_header
; /* central header data for the current file */
110 uLong size_centralheader
; /* size of the central header for cur file */
111 uLong flag
; /* flag of the file currently writing */
113 int method
; /* compression method of file currenty wr.*/
114 Byte buffered_data
[Z_BUFSIZE
];/* buffer contain compressed data to be writ*/
122 linkedlist_data central_dir
;/* datablock with central dir in construction*/
123 int in_opened_file_inzip
; /* 1 if a file in the zip is currently writ.*/
124 curfile_info ci
; /* info on the file curretly writing */
126 uLong begin_pos
; /* position of the beginning of the zipfile */
130 local linkedlist_datablock_internal
* allocate_new_datablock()
132 linkedlist_datablock_internal
* ldi
;
133 ldi
= (linkedlist_datablock_internal
*)
134 ALLOC(sizeof(linkedlist_datablock_internal
));
137 ldi
->next_datablock
= NULL
;
138 ldi
->filled_in_this_block
= 0 ;
139 ldi
->avail_in_this_block
= SIZEDATA_INDATABLOCK
;
144 local
void free_datablock(ldi
)
145 linkedlist_datablock_internal
* ldi
;
149 linkedlist_datablock_internal
* ldinext
= ldi
->next_datablock
;
155 local
void init_linkedlist(ll
)
158 ll
->first_block
= ll
->last_block
= NULL
;
161 local
void free_linkedlist(ll
)
164 free_datablock(ll
->first_block
);
165 ll
->first_block
= ll
->last_block
= NULL
;
169 local
int add_data_in_datablock(ll
,buf
,len
)
174 linkedlist_datablock_internal
* ldi
;
175 const unsigned char* from_copy
;
178 return ZIP_INTERNALERROR
;
180 if (ll
->last_block
== NULL
)
182 ll
->first_block
= ll
->last_block
= allocate_new_datablock();
183 if (ll
->first_block
== NULL
)
184 return ZIP_INTERNALERROR
;
187 ldi
= ll
->last_block
;
188 from_copy
= (unsigned char*)buf
;
194 unsigned char* to_copy
;
196 if (ldi
->avail_in_this_block
==0)
198 ldi
->next_datablock
= allocate_new_datablock();
199 if (ldi
->next_datablock
== NULL
)
200 return ZIP_INTERNALERROR
;
201 ldi
= ldi
->next_datablock
;
202 ll
->last_block
= ldi
;
205 if (ldi
->avail_in_this_block
< len
)
206 copy_this
= (uInt
)ldi
->avail_in_this_block
;
208 copy_this
= (uInt
)len
;
210 to_copy
= &(ldi
->data
[ldi
->filled_in_this_block
]);
212 for (i
=0;i
<copy_this
;i
++)
213 *(to_copy
+i
)=*(from_copy
+i
);
215 ldi
->filled_in_this_block
+= copy_this
;
216 ldi
->avail_in_this_block
-= copy_this
;
217 from_copy
+= copy_this
;
224 local
int write_datablock(fout
,ll
)
228 linkedlist_datablock_internal
* ldi
;
229 ldi
= ll
->first_block
;
232 if (ldi
->filled_in_this_block
> 0)
233 if (fwrite(ldi
->data
,(uInt
)ldi
->filled_in_this_block
,1,fout
)!=1)
235 ldi
= ldi
->next_datablock
;
240 /****************************************************************************/
242 /* ===========================================================================
243 Outputs a long in LSB order to the given file
244 nbByte == 1, 2 or 4 (byte, short or long)
247 local
int ziplocal_putValue
OF((FILE *file
, uLong x
, int nbByte
));
248 local
int ziplocal_putValue (file
, x
, nbByte
)
253 unsigned char buf
[4];
255 for (n
= 0; n
< nbByte
; n
++) {
256 buf
[n
] = (unsigned char)(x
& 0xff);
259 if (fwrite(buf
,nbByte
,1,file
)!=1)
265 local
void ziplocal_putValue_inmemory
OF((void* dest
, uLong x
, int nbByte
));
266 local
void ziplocal_putValue_inmemory (dest
, x
, nbByte
)
271 unsigned char* buf
=(unsigned char*)dest
;
273 for (n
= 0; n
< nbByte
; n
++) {
274 buf
[n
] = (unsigned char)(x
& 0xff);
278 /****************************************************************************/
281 local uLong
ziplocal_TmzDateToDosDate(ptm
,dosDate
)
285 uLong year
= (uLong
)ptm
->tm_year
;
291 (uLong
) (((ptm
->tm_mday
) + (32 * (ptm
->tm_mon
+1)) + (512 * year
)) << 16) |
292 ((ptm
->tm_sec
/2) + (32* ptm
->tm_min
) + (2048 * (uLong
)ptm
->tm_hour
));
296 /****************************************************************************/
298 extern zipFile ZEXPORT
zipOpen (pathname
, append
)
299 const char *pathname
;
305 ziinit
.filezip
= fopen(pathname
,(append
== 0) ? "wb" : "ab");
306 if (ziinit
.filezip
== NULL
)
308 ziinit
.begin_pos
= ftell(ziinit
.filezip
);
309 ziinit
.in_opened_file_inzip
= 0;
310 ziinit
.ci
.stream_initialised
= 0;
311 ziinit
.number_entry
= 0;
312 init_linkedlist(&(ziinit
.central_dir
));
315 zi
= (zip_internal
*)ALLOC(sizeof(zip_internal
));
318 fclose(ziinit
.filezip
);
326 extern int ZEXPORT
zipOpenNewFileInZip (file
, filename
, zipfi
,
327 extrafield_local
, size_extrafield_local
,
328 extrafield_global
, size_extrafield_global
,
329 comment
, method
, level
)
331 const char* filename
;
332 const zip_fileinfo
* zipfi
;
333 const void* extrafield_local
;
334 uInt size_extrafield_local
;
335 const void* extrafield_global
;
336 uInt size_extrafield_global
;
348 return ZIP_PARAMERROR
;
349 if ((method
!=0) && (method
!=Z_DEFLATED
))
350 return ZIP_PARAMERROR
;
352 zi
= (zip_internal
*)file
;
354 if (zi
->in_opened_file_inzip
== 1)
356 err
= zipCloseFileInZip (file
);
368 size_comment
= strlen(comment
);
370 size_filename
= strlen(filename
);
376 if (zipfi
->dosDate
!= 0)
377 zi
->ci
.dosDate
= zipfi
->dosDate
;
378 else zi
->ci
.dosDate
= ziplocal_TmzDateToDosDate(&zipfi
->tmz_date
,zipfi
->dosDate
);
382 if ((level
==8) || (level
==9))
390 zi
->ci
.method
= method
;
391 zi
->ci
.stream_initialised
= 0;
392 zi
->ci
.pos_in_buffered_data
= 0;
393 zi
->ci
.pos_local_header
= ftell(zi
->filezip
);
394 zi
->ci
.size_centralheader
= SIZECENTRALHEADER
+ size_filename
+
395 size_extrafield_global
+ size_comment
;
396 zi
->ci
.central_header
= (char*)ALLOC((uInt
)zi
->ci
.size_centralheader
);
398 ziplocal_putValue_inmemory(zi
->ci
.central_header
,(uLong
)CENTRALHEADERMAGIC
,4);
400 ziplocal_putValue_inmemory(zi
->ci
.central_header
+4,(uLong
)VERSIONMADEBY
,2);
401 ziplocal_putValue_inmemory(zi
->ci
.central_header
+6,(uLong
)20,2);
402 ziplocal_putValue_inmemory(zi
->ci
.central_header
+8,(uLong
)zi
->ci
.flag
,2);
403 ziplocal_putValue_inmemory(zi
->ci
.central_header
+10,(uLong
)zi
->ci
.method
,2);
404 ziplocal_putValue_inmemory(zi
->ci
.central_header
+12,(uLong
)zi
->ci
.dosDate
,4);
405 ziplocal_putValue_inmemory(zi
->ci
.central_header
+16,(uLong
)0,4); /*crc*/
406 ziplocal_putValue_inmemory(zi
->ci
.central_header
+20,(uLong
)0,4); /*compr size*/
407 ziplocal_putValue_inmemory(zi
->ci
.central_header
+24,(uLong
)0,4); /*uncompr size*/
408 ziplocal_putValue_inmemory(zi
->ci
.central_header
+28,(uLong
)size_filename
,2);
409 ziplocal_putValue_inmemory(zi
->ci
.central_header
+30,(uLong
)size_extrafield_global
,2);
410 ziplocal_putValue_inmemory(zi
->ci
.central_header
+32,(uLong
)size_comment
,2);
411 ziplocal_putValue_inmemory(zi
->ci
.central_header
+34,(uLong
)0,2); /*disk nm start*/
414 ziplocal_putValue_inmemory(zi
->ci
.central_header
+36,(uLong
)0,2);
416 ziplocal_putValue_inmemory(zi
->ci
.central_header
+36,(uLong
)zipfi
->internal_fa
,2);
419 ziplocal_putValue_inmemory(zi
->ci
.central_header
+38,(uLong
)0,4);
421 ziplocal_putValue_inmemory(zi
->ci
.central_header
+38,(uLong
)zipfi
->external_fa
,4);
423 ziplocal_putValue_inmemory(zi
->ci
.central_header
+42,(uLong
)zi
->ci
.pos_local_header
,4);
425 for (i
=0;i
<size_filename
;i
++)
426 *(zi
->ci
.central_header
+SIZECENTRALHEADER
+i
) = *(filename
+i
);
428 for (i
=0;i
<size_extrafield_global
;i
++)
429 *(zi
->ci
.central_header
+SIZECENTRALHEADER
+size_filename
+i
) =
430 *(((const char*)extrafield_global
)+i
);
432 for (i
=0;i
<size_comment
;i
++)
433 *(zi
->ci
.central_header
+SIZECENTRALHEADER
+size_filename
+
434 size_extrafield_global
+i
) = *(filename
+i
);
435 if (zi
->ci
.central_header
== NULL
)
436 return ZIP_INTERNALERROR
;
438 /* write the local header */
439 err
= ziplocal_putValue(zi
->filezip
,(uLong
)LOCALHEADERMAGIC
,4);
442 err
= ziplocal_putValue(zi
->filezip
,(uLong
)20,2);/* version needed to extract */
444 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.flag
,2);
447 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.method
,2);
450 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.dosDate
,4);
453 err
= ziplocal_putValue(zi
->filezip
,(uLong
)0,4); /* crc 32, unknown */
455 err
= ziplocal_putValue(zi
->filezip
,(uLong
)0,4); /* compressed size, unknown */
457 err
= ziplocal_putValue(zi
->filezip
,(uLong
)0,4); /* uncompressed size, unknown */
460 err
= ziplocal_putValue(zi
->filezip
,(uLong
)size_filename
,2);
463 err
= ziplocal_putValue(zi
->filezip
,(uLong
)size_extrafield_local
,2);
465 if ((err
==ZIP_OK
) && (size_filename
>0))
466 if (fwrite(filename
,(uInt
)size_filename
,1,zi
->filezip
)!=1)
469 if ((err
==ZIP_OK
) && (size_extrafield_local
>0))
470 if (fwrite(extrafield_local
,(uInt
)size_extrafield_local
,1,zi
->filezip
)
474 zi
->ci
.stream
.avail_in
= (uInt
)0;
475 zi
->ci
.stream
.avail_out
= (uInt
)Z_BUFSIZE
;
476 zi
->ci
.stream
.next_out
= zi
->ci
.buffered_data
;
477 zi
->ci
.stream
.total_in
= 0;
478 zi
->ci
.stream
.total_out
= 0;
480 if ((err
==ZIP_OK
) && (zi
->ci
.method
== Z_DEFLATED
))
482 zi
->ci
.stream
.zalloc
= (alloc_func
)0;
483 zi
->ci
.stream
.zfree
= (free_func
)0;
484 zi
->ci
.stream
.opaque
= (voidpf
)0;
486 err
= deflateInit2(&zi
->ci
.stream
, level
,
487 Z_DEFLATED
, -MAX_WBITS
, DEF_MEM_LEVEL
, 0);
490 zi
->ci
.stream_initialised
= 1;
495 zi
->in_opened_file_inzip
= 1;
499 extern int ZEXPORT
zipWriteInFileInZip (file
, buf
, len
)
508 return ZIP_PARAMERROR
;
509 zi
= (zip_internal
*)file
;
511 if (zi
->in_opened_file_inzip
== 0)
512 return ZIP_PARAMERROR
;
514 zi
->ci
.stream
.next_in
= buf
;
515 zi
->ci
.stream
.avail_in
= len
;
516 zi
->ci
.crc32
= crc32(zi
->ci
.crc32
,buf
,len
);
518 while ((err
==ZIP_OK
) && (zi
->ci
.stream
.avail_in
>0))
520 if (zi
->ci
.stream
.avail_out
== 0)
522 if (fwrite(zi
->ci
.buffered_data
,(uInt
)zi
->ci
.pos_in_buffered_data
,1,zi
->filezip
)
525 zi
->ci
.pos_in_buffered_data
= 0;
526 zi
->ci
.stream
.avail_out
= (uInt
)Z_BUFSIZE
;
527 zi
->ci
.stream
.next_out
= zi
->ci
.buffered_data
;
530 if (zi
->ci
.method
== Z_DEFLATED
)
532 uLong uTotalOutBefore
= zi
->ci
.stream
.total_out
;
533 err
=deflate(&zi
->ci
.stream
, Z_NO_FLUSH
);
534 zi
->ci
.pos_in_buffered_data
+= (uInt
)(zi
->ci
.stream
.total_out
- uTotalOutBefore
) ;
540 if (zi
->ci
.stream
.avail_in
< zi
->ci
.stream
.avail_out
)
541 copy_this
= zi
->ci
.stream
.avail_in
;
543 copy_this
= zi
->ci
.stream
.avail_out
;
544 for (i
=0;i
<copy_this
;i
++)
545 *(((char*)zi
->ci
.stream
.next_out
)+i
) =
546 *(((const char*)zi
->ci
.stream
.next_in
)+i
);
548 zi
->ci
.stream
.avail_in
-= copy_this
;
549 zi
->ci
.stream
.avail_out
-= copy_this
;
550 zi
->ci
.stream
.next_in
+= copy_this
;
551 zi
->ci
.stream
.next_out
+= copy_this
;
552 zi
->ci
.stream
.total_in
+= copy_this
;
553 zi
->ci
.stream
.total_out
+= copy_this
;
554 zi
->ci
.pos_in_buffered_data
+= copy_this
;
562 extern int ZEXPORT
zipCloseFileInZip (file
)
569 return ZIP_PARAMERROR
;
570 zi
= (zip_internal
*)file
;
572 if (zi
->in_opened_file_inzip
== 0)
573 return ZIP_PARAMERROR
;
574 zi
->ci
.stream
.avail_in
= 0;
576 if (zi
->ci
.method
== Z_DEFLATED
)
579 uLong uTotalOutBefore
;
580 if (zi
->ci
.stream
.avail_out
== 0)
582 if (fwrite(zi
->ci
.buffered_data
,(uInt
)zi
->ci
.pos_in_buffered_data
,1,zi
->filezip
)
585 zi
->ci
.pos_in_buffered_data
= 0;
586 zi
->ci
.stream
.avail_out
= (uInt
)Z_BUFSIZE
;
587 zi
->ci
.stream
.next_out
= zi
->ci
.buffered_data
;
589 uTotalOutBefore
= zi
->ci
.stream
.total_out
;
590 err
=deflate(&zi
->ci
.stream
, Z_FINISH
);
591 zi
->ci
.pos_in_buffered_data
+= (uInt
)(zi
->ci
.stream
.total_out
- uTotalOutBefore
) ;
594 if (err
==Z_STREAM_END
)
595 err
=ZIP_OK
; /* this is normal */
597 if ((zi
->ci
.pos_in_buffered_data
>0) && (err
==ZIP_OK
))
598 if (fwrite(zi
->ci
.buffered_data
,(uInt
)zi
->ci
.pos_in_buffered_data
,1,zi
->filezip
)
602 if ((zi
->ci
.method
== Z_DEFLATED
) && (err
==ZIP_OK
))
604 err
=deflateEnd(&zi
->ci
.stream
);
605 zi
->ci
.stream_initialised
= 0;
608 ziplocal_putValue_inmemory(zi
->ci
.central_header
+16,(uLong
)zi
->ci
.crc32
,4); /*crc*/
609 ziplocal_putValue_inmemory(zi
->ci
.central_header
+20,
610 (uLong
)zi
->ci
.stream
.total_out
,4); /*compr size*/
611 ziplocal_putValue_inmemory(zi
->ci
.central_header
+24,
612 (uLong
)zi
->ci
.stream
.total_in
,4); /*uncompr size*/
615 err
= add_data_in_datablock(&zi
->central_dir
,zi
->ci
.central_header
,
616 (uLong
)zi
->ci
.size_centralheader
);
617 free(zi
->ci
.central_header
);
621 long cur_pos_inzip
= ftell(zi
->filezip
);
622 if (fseek(zi
->filezip
,
623 zi
->ci
.pos_local_header
+ 14,SEEK_SET
)!=0)
627 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.crc32
,4); /* crc 32, unknown */
629 if (err
==ZIP_OK
) /* compressed size, unknown */
630 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.stream
.total_out
,4);
632 if (err
==ZIP_OK
) /* uncompressed size, unknown */
633 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->ci
.stream
.total_in
,4);
635 if (fseek(zi
->filezip
,
636 cur_pos_inzip
,SEEK_SET
)!=0)
641 zi
->in_opened_file_inzip
= 0;
646 extern int ZEXPORT
zipClose (file
, global_comment
)
648 const char* global_comment
;
652 uLong size_centraldir
= 0;
653 uLong centraldir_pos_inzip
;
654 uInt size_global_comment
;
656 return ZIP_PARAMERROR
;
657 zi
= (zip_internal
*)file
;
659 if (zi
->in_opened_file_inzip
== 1)
661 err
= zipCloseFileInZip (file
);
664 if (global_comment
==NULL
)
665 size_global_comment
= 0;
667 size_global_comment
= strlen(global_comment
);
670 centraldir_pos_inzip
= ftell(zi
->filezip
);
673 linkedlist_datablock_internal
* ldi
= zi
->central_dir
.first_block
;
676 if ((err
==ZIP_OK
) && (ldi
->filled_in_this_block
>0))
677 if (fwrite(ldi
->data
,(uInt
)ldi
->filled_in_this_block
,
681 size_centraldir
+= ldi
->filled_in_this_block
;
682 ldi
= ldi
->next_datablock
;
685 free_datablock(zi
->central_dir
.first_block
);
687 if (err
==ZIP_OK
) /* Magic End */
688 err
= ziplocal_putValue(zi
->filezip
,(uLong
)ENDHEADERMAGIC
,4);
690 if (err
==ZIP_OK
) /* number of this disk */
691 err
= ziplocal_putValue(zi
->filezip
,(uLong
)0,2);
693 if (err
==ZIP_OK
) /* number of the disk with the start of the central directory */
694 err
= ziplocal_putValue(zi
->filezip
,(uLong
)0,2);
696 if (err
==ZIP_OK
) /* total number of entries in the central dir on this disk */
697 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->number_entry
,2);
699 if (err
==ZIP_OK
) /* total number of entries in the central dir */
700 err
= ziplocal_putValue(zi
->filezip
,(uLong
)zi
->number_entry
,2);
702 if (err
==ZIP_OK
) /* size of the central directory */
703 err
= ziplocal_putValue(zi
->filezip
,(uLong
)size_centraldir
,4);
705 if (err
==ZIP_OK
) /* offset of start of central directory with respect to the
706 starting disk number */
707 err
= ziplocal_putValue(zi
->filezip
,(uLong
)centraldir_pos_inzip
,4);
709 if (err
==ZIP_OK
) /* zipfile comment length */
710 err
= ziplocal_putValue(zi
->filezip
,(uLong
)size_global_comment
,2);
712 if ((err
==ZIP_OK
) && (size_global_comment
>0))
713 if (fwrite(global_comment
,(uInt
)size_global_comment
,1,zi
->filezip
) !=1 )