1 /* zip.c -- IO on .zip files using zlib
2 Version 0.15 beta, Mar 19th, 1998,
4 Read zip.h for more info
14 # define DEF_MEM_LEVEL 8
31 /* compile with -Dlocal if your debugger can't find static symbols */
34 # define VERSIONMADEBY (0x0) /* platform depedent */
38 #define Z_BUFSIZE (16384)
41 #ifndef Z_MAXFILENAMEINZIP
42 #define Z_MAXFILENAMEINZIP (256)
46 # define ALLOC(size) (malloc(size))
49 # define TRYFREE(p) {if (p) free(p);}
53 #define SIZECENTRALDIRITEM (0x2e)
54 #define SIZEZIPLOCALHEADER (0x1e)
57 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
71 const char zip_copyright[] =
72 " zip 0.15 Copyright 1998 Gilles Vollant ";
75 #define SIZEDATA_INDATABLOCK (4096-(4*4))
77 #define LOCALHEADERMAGIC (0x04034b50)
78 #define CENTRALHEADERMAGIC (0x02014b50)
79 #define ENDHEADERMAGIC (0x06054b50)
81 #define FLAG_LOCALHEADER_OFFSET (0x06)
82 #define CRC_LOCALHEADER_OFFSET (0x0e)
84 #define SIZECENTRALHEADER (0x2e) /* 46 */
86 typedef struct linkedlist_datablock_internal_s
88 struct linkedlist_datablock_internal_s* next_datablock;
89 uLong avail_in_this_block;
90 uLong filled_in_this_block;
91 uLong unused; /* for future use and alignement */
92 unsigned char data[SIZEDATA_INDATABLOCK];
93 } linkedlist_datablock_internal;
95 typedef struct linkedlist_data_s
97 linkedlist_datablock_internal* first_block;
98 linkedlist_datablock_internal* last_block;
104 z_stream stream; /* zLib stream structure for inflate */
105 int stream_initialised; /* 1 is stream is initialised */
106 uInt pos_in_buffered_data; /* last written byte in buffered_data */
108 uLong pos_local_header; /* offset of the local header of the file
110 char* central_header; /* central header data for the current file */
111 uLong size_centralheader; /* size of the central header for cur file */
112 uLong flag; /* flag of the file currently writing */
114 int method; /* compression method of file currenty wr.*/
115 Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
123 linkedlist_data central_dir;/* datablock with central dir in construction*/
124 int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/
125 curfile_info ci; /* info on the file curretly writing */
127 uLong begin_pos; /* position of the beginning of the zipfile */
131 local linkedlist_datablock_internal* allocate_new_datablock()
133 linkedlist_datablock_internal* ldi;
134 ldi = (linkedlist_datablock_internal*)
135 ALLOC(sizeof(linkedlist_datablock_internal));
138 ldi->next_datablock = NULL ;
139 ldi->filled_in_this_block = 0 ;
140 ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
145 local void free_datablock(ldi)
146 linkedlist_datablock_internal* ldi;
150 linkedlist_datablock_internal* ldinext = ldi->next_datablock;
156 local void init_linkedlist(ll)
159 ll->first_block = ll->last_block = NULL;
162 local void free_linkedlist(ll)
165 free_datablock(ll->first_block);
166 ll->first_block = ll->last_block = NULL;
170 local int add_data_in_datablock(ll,buf,len)
175 linkedlist_datablock_internal* ldi;
176 const unsigned char* from_copy;
179 return ZIP_INTERNALERROR;
181 if (ll->last_block == NULL)
183 ll->first_block = ll->last_block = allocate_new_datablock();
184 if (ll->first_block == NULL)
185 return ZIP_INTERNALERROR;
188 ldi = ll->last_block;
189 from_copy = (unsigned char*)buf;
195 unsigned char* to_copy;
197 if (ldi->avail_in_this_block==0)
199 ldi->next_datablock = allocate_new_datablock();
200 if (ldi->next_datablock == NULL)
201 return ZIP_INTERNALERROR;
202 ldi = ldi->next_datablock ;
203 ll->last_block = ldi;
206 if (ldi->avail_in_this_block < len)
207 copy_this = (uInt)ldi->avail_in_this_block;
209 copy_this = (uInt)len;
211 to_copy = &(ldi->data[ldi->filled_in_this_block]);
213 for (i=0;i<copy_this;i++)
214 *(to_copy+i)=*(from_copy+i);
216 ldi->filled_in_this_block += copy_this;
217 ldi->avail_in_this_block -= copy_this;
218 from_copy += copy_this ;
225 local int write_datablock(fout,ll)
229 linkedlist_datablock_internal* ldi;
230 ldi = ll->first_block;
233 if (ldi->filled_in_this_block > 0)
234 if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block,1,fout)!=1)
236 ldi = ldi->next_datablock;
241 /****************************************************************************/
243 /* ===========================================================================
244 Outputs a long in LSB order to the given file
245 nbByte == 1, 2 or 4 (byte, short or long)
248 local int ziplocal_putValue OF((FILE *file, uLong x, int nbByte));
249 local int ziplocal_putValue (file, x, nbByte)
254 unsigned char buf[4];
256 for (n = 0; n < nbByte; n++) {
257 buf[n] = (unsigned char)(x & 0xff);
260 if (fwrite(buf,nbByte,1,file)!=1)
266 local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte));
267 local void ziplocal_putValue_inmemory (dest, x, nbByte)
272 unsigned char* buf=(unsigned char*)dest;
274 for (n = 0; n < nbByte; n++) {
275 buf[n] = (unsigned char)(x & 0xff);
279 /****************************************************************************/
282 local uLong ziplocal_TmzDateToDosDate(ptm,dosDate)
286 uLong year = (uLong)ptm->tm_year;
292 (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
293 ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
297 /****************************************************************************/
299 extern zipFile ZEXPORT zipOpen (pathname, append)
300 const char *pathname;
306 ziinit.filezip = fopen(pathname,(append == 0) ? "wb" : "ab");
307 if (ziinit.filezip == NULL)
309 ziinit.begin_pos = ftell(ziinit.filezip);
310 ziinit.in_opened_file_inzip = 0;
311 ziinit.ci.stream_initialised = 0;
312 ziinit.number_entry = 0;
313 init_linkedlist(&(ziinit.central_dir));
316 zi = (zip_internal*)ALLOC(sizeof(zip_internal));
319 fclose(ziinit.filezip);
327 extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi,
328 extrafield_local, size_extrafield_local,
329 extrafield_global, size_extrafield_global,
330 comment, method, level)
332 const char* filename;
333 const zip_fileinfo* zipfi;
334 const void* extrafield_local;
335 uInt size_extrafield_local;
336 const void* extrafield_global;
337 uInt size_extrafield_global;
349 return ZIP_PARAMERROR;
350 if ((method!=0) && (method!=Z_DEFLATED))
351 return ZIP_PARAMERROR;
353 zi = (zip_internal*)file;
355 if (zi->in_opened_file_inzip == 1)
357 err = zipCloseFileInZip (file);
369 size_comment = strlen(comment);
371 size_filename = strlen(filename);
377 if (zipfi->dosDate != 0)
378 zi->ci.dosDate = zipfi->dosDate;
379 else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate);
383 if ((level==8) || (level==9))
391 zi->ci.method = method;
392 zi->ci.stream_initialised = 0;
393 zi->ci.pos_in_buffered_data = 0;
394 zi->ci.pos_local_header = ftell(zi->filezip);
395 zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename +
396 size_extrafield_global + size_comment;
397 zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader);
399 ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
401 ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2);
402 ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
403 ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
404 ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
405 ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
406 ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
407 ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
408 ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
409 ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
410 ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
411 ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
412 ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
415 ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2);
417 ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2);
420 ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4);
422 ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
424 ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header,4);
426 for (i=0;i<size_filename;i++)
427 *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
429 for (i=0;i<size_extrafield_global;i++)
430 *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
431 *(((const char*)extrafield_global)+i);
433 for (i=0;i<size_comment;i++)
434 *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
435 size_extrafield_global+i) = *(filename+i);
436 if (zi->ci.central_header == NULL)
437 return ZIP_INTERNALERROR;
439 /* write the local header */
440 err = ziplocal_putValue(zi->filezip,(uLong)LOCALHEADERMAGIC,4);
443 err = ziplocal_putValue(zi->filezip,(uLong)20,2);/* version needed to extract */
445 err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.flag,2);
448 err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.method,2);
451 err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.dosDate,4);
454 err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* crc 32, unknown */
456 err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* compressed size, unknown */
458 err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* uncompressed size, unknown */
461 err = ziplocal_putValue(zi->filezip,(uLong)size_filename,2);
464 err = ziplocal_putValue(zi->filezip,(uLong)size_extrafield_local,2);
466 if ((err==ZIP_OK) && (size_filename>0))
467 if (fwrite(filename,(uInt)size_filename,1,zi->filezip)!=1)
470 if ((err==ZIP_OK) && (size_extrafield_local>0))
471 if (fwrite(extrafield_local,(uInt)size_extrafield_local,1,zi->filezip)
475 zi->ci.stream.avail_in = (uInt)0;
476 zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
477 zi->ci.stream.next_out = zi->ci.buffered_data;
478 zi->ci.stream.total_in = 0;
479 zi->ci.stream.total_out = 0;
481 if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED))
483 zi->ci.stream.zalloc = (alloc_func)0;
484 zi->ci.stream.zfree = (free_func)0;
485 zi->ci.stream.opaque = (voidpf)0;
487 err = deflateInit2(&zi->ci.stream, level,
488 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
491 zi->ci.stream_initialised = 1;
496 zi->in_opened_file_inzip = 1;
500 extern int ZEXPORT zipWriteInFileInZip (file, buf, len)
509 return ZIP_PARAMERROR;
510 zi = (zip_internal*)file;
512 if (zi->in_opened_file_inzip == 0)
513 return ZIP_PARAMERROR;
515 zi->ci.stream.next_in = buf;
516 zi->ci.stream.avail_in = len;
517 zi->ci.crc32 = crc32(zi->ci.crc32,buf,len);
519 while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
521 if (zi->ci.stream.avail_out == 0)
523 if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
526 zi->ci.pos_in_buffered_data = 0;
527 zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
528 zi->ci.stream.next_out = zi->ci.buffered_data;
531 if (zi->ci.method == Z_DEFLATED)
533 uLong uTotalOutBefore = zi->ci.stream.total_out;
534 err=deflate(&zi->ci.stream, Z_NO_FLUSH);
535 zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
541 if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
542 copy_this = zi->ci.stream.avail_in;
544 copy_this = zi->ci.stream.avail_out;
545 for (i=0;i<copy_this;i++)
546 *(((char*)zi->ci.stream.next_out)+i) =
547 *(((const char*)zi->ci.stream.next_in)+i);
549 zi->ci.stream.avail_in -= copy_this;
550 zi->ci.stream.avail_out-= copy_this;
551 zi->ci.stream.next_in+= copy_this;
552 zi->ci.stream.next_out+= copy_this;
553 zi->ci.stream.total_in+= copy_this;
554 zi->ci.stream.total_out+= copy_this;
555 zi->ci.pos_in_buffered_data += copy_this;
563 extern int ZEXPORT zipCloseFileInZip (file)
570 return ZIP_PARAMERROR;
571 zi = (zip_internal*)file;
573 if (zi->in_opened_file_inzip == 0)
574 return ZIP_PARAMERROR;
575 zi->ci.stream.avail_in = 0;
577 if (zi->ci.method == Z_DEFLATED)
580 uLong uTotalOutBefore;
581 if (zi->ci.stream.avail_out == 0)
583 if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
586 zi->ci.pos_in_buffered_data = 0;
587 zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
588 zi->ci.stream.next_out = zi->ci.buffered_data;
590 uTotalOutBefore = zi->ci.stream.total_out;
591 err=deflate(&zi->ci.stream, Z_FINISH);
592 zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
595 if (err==Z_STREAM_END)
596 err=ZIP_OK; /* this is normal */
598 if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
599 if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
603 if ((zi->ci.method == Z_DEFLATED) && (err==ZIP_OK))
605 err=deflateEnd(&zi->ci.stream);
606 zi->ci.stream_initialised = 0;
609 ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)zi->ci.crc32,4); /*crc*/
610 ziplocal_putValue_inmemory(zi->ci.central_header+20,
611 (uLong)zi->ci.stream.total_out,4); /*compr size*/
612 ziplocal_putValue_inmemory(zi->ci.central_header+24,
613 (uLong)zi->ci.stream.total_in,4); /*uncompr size*/
616 err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header,
617 (uLong)zi->ci.size_centralheader);
618 free(zi->ci.central_header);
622 long cur_pos_inzip = ftell(zi->filezip);
623 if (fseek(zi->filezip,
624 zi->ci.pos_local_header + 14,SEEK_SET)!=0)
628 err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.crc32,4); /* crc 32, unknown */
630 if (err==ZIP_OK) /* compressed size, unknown */
631 err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_out,4);
633 if (err==ZIP_OK) /* uncompressed size, unknown */
634 err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_in,4);
636 if (fseek(zi->filezip,
637 cur_pos_inzip,SEEK_SET)!=0)
642 zi->in_opened_file_inzip = 0;
647 extern int ZEXPORT zipClose (file, global_comment)
649 const char* global_comment;
653 uLong size_centraldir = 0;
654 uLong centraldir_pos_inzip ;
655 uInt size_global_comment;
657 return ZIP_PARAMERROR;
658 zi = (zip_internal*)file;
660 if (zi->in_opened_file_inzip == 1)
662 err = zipCloseFileInZip (file);
665 if (global_comment==NULL)
666 size_global_comment = 0;
668 size_global_comment = strlen(global_comment);
671 centraldir_pos_inzip = ftell(zi->filezip);
674 linkedlist_datablock_internal* ldi = zi->central_dir.first_block ;
677 if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
678 if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block,
682 size_centraldir += ldi->filled_in_this_block;
683 ldi = ldi->next_datablock;
686 free_datablock(zi->central_dir.first_block);
688 if (err==ZIP_OK) /* Magic End */
689 err = ziplocal_putValue(zi->filezip,(uLong)ENDHEADERMAGIC,4);
691 if (err==ZIP_OK) /* number of this disk */
692 err = ziplocal_putValue(zi->filezip,(uLong)0,2);
694 if (err==ZIP_OK) /* number of the disk with the start of the central directory */
695 err = ziplocal_putValue(zi->filezip,(uLong)0,2);
697 if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
698 err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2);
700 if (err==ZIP_OK) /* total number of entries in the central dir */
701 err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2);
703 if (err==ZIP_OK) /* size of the central directory */
704 err = ziplocal_putValue(zi->filezip,(uLong)size_centraldir,4);
706 if (err==ZIP_OK) /* offset of start of central directory with respect to the
707 starting disk number */
708 err = ziplocal_putValue(zi->filezip,(uLong)centraldir_pos_inzip ,4);
710 if (err==ZIP_OK) /* zipfile comment length */
711 err = ziplocal_putValue(zi->filezip,(uLong)size_global_comment,2);
713 if ((err==ZIP_OK) && (size_global_comment>0))
714 if (fwrite(global_comment,(uInt)size_global_comment,1,zi->filezip) !=1 )