view src/common/unzip.cpp @ 43:629602cb5e8c

GPL v2, same as vba-rerecording.
author Robert McIntyre <rlm@mit.edu>
date Tue, 26 Feb 2013 10:08:20 +0000
parents f9f4f1b99eed
children
line wrap: on
line source
1 /* unzip.c -- IO on .zip files using zlib
2 Version 0.15 beta, Mar 19th, 1998,
4 Read unzip.h for more info
5 */
7 #include <cstdio>
8 #include <cstdlib>
9 #include <cstring>
10 #include "zlib.h"
11 #include "unzip.h"
13 #ifdef NO_ERRNO_H
14 extern int errno;
15 #else
16 # include <cerrno>
17 #endif
19 #ifndef local
20 # define local static
21 #endif
22 /* compile with -Dlocal if your debugger can't find static symbols */
24 #if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
25 !defined(CASESENSITIVITYDEFAULT_NO)
26 #define CASESENSITIVITYDEFAULT_NO
27 #endif
29 #ifndef UNZ_BUFSIZE
30 #define UNZ_BUFSIZE (16384)
31 #endif
33 #ifndef UNZ_MAXFILENAMEINZIP
34 #define UNZ_MAXFILENAMEINZIP (256)
35 #endif
37 #ifndef ALLOC
38 # define ALLOC(size) (malloc(size))
39 #endif
40 #ifndef TRYFREE
41 # define TRYFREE(p) {if (p) \
42 free(p);}
43 #endif
45 #define SIZECENTRALDIRITEM (0x2e)
46 #define SIZEZIPLOCALHEADER (0x1e)
48 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
50 #ifndef SEEK_CUR
51 #define SEEK_CUR 1
52 #endif
54 #ifndef SEEK_END
55 #define SEEK_END 2
56 #endif
58 #ifndef SEEK_SET
59 #define SEEK_SET 0
60 #endif
62 const char unz_copyright[] =
63 " unzip 0.15 Copyright 1998 Gilles Vollant ";
65 /* unz_file_info_interntal contain internal info about a file in zipfile*/
66 typedef struct unz_file_info_internal_s
67 {
68 uLong offset_curfile; /* relative offset of local header 4 bytes */
69 } unz_file_info_internal;
71 /* file_in_zip_read_info_s contain internal information about a file in zipfile,
72 when reading and decompress it */
73 typedef struct
74 {
75 char * read_buffer; /* internal buffer for compressed data */
76 z_stream stream; /* zLib stream structure for inflate */
78 uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
79 uLong stream_initialised; /* flag set if stream structure is initialised*/
81 uLong offset_local_extrafield; /* offset of the local extra field */
82 uInt size_local_extrafield; /* size of the local extra field */
83 uLong pos_local_extrafield; /* position in the local extra field in read*/
85 uLong crc32; /* crc32 of all data uncompressed */
86 uLong crc32_wait; /* crc32 we must obtain after decompress all */
87 uLong rest_read_compressed; /* number of byte to be decompressed */
88 uLong rest_read_uncompressed; /*number of byte to be obtained after decomp*/
89 FILE* file; /* io structore of the zipfile */
90 uLong compression_method; /* compression method (0==store) */
91 uLong byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/
92 } file_in_zip_read_info_s;
94 /* unz_s contain internal information about the zipfile
95 */
96 typedef struct
97 {
98 FILE*file; /* io structore of the zipfile */
99 unz_global_info gi; /* public global information */
100 uLong byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/
101 uLong num_file; /* number of the current file in the zipfile*/
102 uLong pos_in_central_dir; /* pos of the current file in the central dir*/
103 uLong current_file_ok; /* flag about the usability of the current file*/
104 uLong central_pos; /* position of the beginning of the central dir*/
106 uLong size_central_dir; /* size of the central directory */
107 uLong offset_central_dir; /* offset of start of central directory with
108 respect to the starting disk number */
110 unz_file_info cur_file_info; /* public info about the current file in zip*/
111 unz_file_info_internal cur_file_info_internal; /* private info about it*/
112 file_in_zip_read_info_s*pfile_in_zip_read; /* structure about the current
113 file if we are decompressing it */
114 } unz_s;
116 /* ===========================================================================
117 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
118 for end of file.
119 IN assertion: the stream s has been sucessfully opened for reading.
120 */
122 local int unzlocal_getByte(FILE *fin, int *pi)
123 {
124 unsigned char c;
125 int err = fread(&c, 1, 1, fin);
126 if (err == 1)
127 {
128 *pi = (int)c;
129 return UNZ_OK;
130 }
131 else
132 {
133 if (ferror(fin))
134 return UNZ_ERRNO;
135 else
136 return UNZ_EOF;
137 }
138 }
140 /* ===========================================================================
141 Reads a long in LSB order from the given gz_stream. Sets
142 */
143 local int unzlocal_getShort(FILE *fin, uLong *pX)
144 {
145 uLong x ;
146 int i;
147 int err;
149 err = unzlocal_getByte(fin, &i);
150 x = (uLong)i;
152 if (err == UNZ_OK)
153 err = unzlocal_getByte(fin, &i);
154 x += ((uLong)i)<<8;
156 if (err == UNZ_OK)
157 *pX = x;
158 else
159 *pX = 0;
160 return err;
161 }
163 local int unzlocal_getLong(FILE *fin, uLong *pX)
164 {
165 uLong x ;
166 int i;
167 int err;
169 err = unzlocal_getByte(fin, &i);
170 x = (uLong)i;
172 if (err == UNZ_OK)
173 err = unzlocal_getByte(fin, &i);
174 x += ((uLong)i)<<8;
176 if (err == UNZ_OK)
177 err = unzlocal_getByte(fin, &i);
178 x += ((uLong)i)<<16;
180 if (err == UNZ_OK)
181 err = unzlocal_getByte(fin, &i);
182 x += ((uLong)i)<<24;
184 if (err == UNZ_OK)
185 *pX = x;
186 else
187 *pX = 0;
188 return err;
189 }
191 /* My own strcmpi / strcasecmp */
192 local int strcmpcasenosensitive_internal(const char *fileName1,
193 const char *fileName2)
194 {
195 for (;;)
196 {
197 char c1 = *(fileName1++);
198 char c2 = *(fileName2++);
199 if ((c1 >= 'a') && (c1 <= 'z'))
200 c1 -= 0x20;
201 if ((c2 >= 'a') && (c2 <= 'z'))
202 c2 -= 0x20;
203 if (c1 == '\0')
204 return ((c2 == '\0') ? 0 : -1);
205 if (c2 == '\0')
206 return 1;
207 if (c1 < c2)
208 return -1;
209 if (c1 > c2)
210 return 1;
211 }
212 }
214 #ifdef CASESENSITIVITYDEFAULT_NO
215 #define CASESENSITIVITYDEFAULTVALUE 2
216 #else
217 #define CASESENSITIVITYDEFAULTVALUE 1
218 #endif
220 #ifndef STRCMPCASENOSENTIVEFUNCTION
221 #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
222 #endif
224 /*
225 Compare two filename (fileName1,fileName2).
226 If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
227 If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
228 or strcasecmp)
229 If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
230 (like 1 on Unix, 2 on Windows)
232 */
233 extern int ZEXPORT unzStringFileNameCompare(const char *fileName1,
234 const char *fileName2,
235 int iCaseSensitivity)
236 {
237 if (iCaseSensitivity == 0)
238 iCaseSensitivity = CASESENSITIVITYDEFAULTVALUE;
240 if (iCaseSensitivity == 1)
241 return strcmp(fileName1, fileName2);
243 return STRCMPCASENOSENTIVEFUNCTION(fileName1, fileName2);
244 }
246 #define BUFREADCOMMENT (0x400)
248 /*
249 Locate the Central directory of a zipfile (at the end, just before
250 the global comment)
251 */
252 local uLong unzlocal_SearchCentralDir(FILE *fin)
253 {
254 unsigned char*buf;
255 uLong uSizeFile;
256 uLong uBackRead;
257 uLong uMaxBack = 0xffff; /* maximum size of global comment */
258 uLong uPosFound = 0;
260 if (fseek(fin, 0, SEEK_END) != 0)
261 return 0;
263 uSizeFile = ftell(fin);
265 if (uMaxBack > uSizeFile)
266 uMaxBack = uSizeFile;
268 buf = (unsigned char *)ALLOC(BUFREADCOMMENT+4);
269 if (buf == NULL)
270 return 0;
272 uBackRead = 4;
273 while (uBackRead < uMaxBack)
274 {
275 uLong uReadSize, uReadPos ;
276 int i;
277 if (uBackRead+BUFREADCOMMENT > uMaxBack)
278 uBackRead = uMaxBack;
279 else
280 uBackRead += BUFREADCOMMENT;
281 uReadPos = uSizeFile-uBackRead ;
283 uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
284 (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
285 if (fseek(fin, uReadPos, SEEK_SET) != 0)
286 break;
288 if (fread(buf, (uInt)uReadSize, 1, fin) != 1)
289 break;
291 for (i = (int)uReadSize-3; (i--) > 0;)
292 if (((*(buf+i)) == 0x50) && ((*(buf+i+1)) == 0x4b) &&
293 ((*(buf+i+2)) == 0x05) && ((*(buf+i+3)) == 0x06))
294 {
295 uPosFound = uReadPos+i;
296 break;
297 }
299 if (uPosFound != 0)
300 break;
301 }
302 TRYFREE(buf);
303 return uPosFound;
304 }
306 /*
307 Open a Zip file. path contain the full pathname (by example,
308 on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
309 "zlib/zlib109.zip".
310 If the zipfile cannot be opened (file don't exist or in not valid), the
311 return value is NULL.
312 Else, the return value is a unzFile Handle, usable with other function
313 of this unzip package.
314 */
315 extern unzFile ZEXPORT unzOpen(const char *path)
316 {
317 unz_s us;
318 unz_s *s;
319 uLong central_pos, uL;
320 FILE * fin ;
322 uLong number_disk; /* number of the current dist, used for
323 spaning ZIP, unsupported, always 0*/
324 uLong number_disk_with_CD; /* number the the disk with central dir, used
325 for spaning ZIP, unsupported, always 0*/
326 uLong number_entry_CD; /* total number of entries in
327 the central dir
328 (same than number_entry on nospan) */
330 int err = UNZ_OK;
332 if (unz_copyright[0] != ' ')
333 return NULL;
335 fin = fopen(path, "rb");
336 if (fin == NULL)
337 return NULL;
339 central_pos = unzlocal_SearchCentralDir(fin);
340 if (central_pos == 0)
341 err = UNZ_ERRNO;
343 if (fseek(fin, central_pos, SEEK_SET) != 0)
344 err = UNZ_ERRNO;
346 /* the signature, already checked */
347 if (unzlocal_getLong(fin, &uL) != UNZ_OK)
348 err = UNZ_ERRNO;
350 /* number of this disk */
351 if (unzlocal_getShort(fin, &number_disk) != UNZ_OK)
352 err = UNZ_ERRNO;
354 /* number of the disk with the start of the central directory */
355 if (unzlocal_getShort(fin, &number_disk_with_CD) != UNZ_OK)
356 err = UNZ_ERRNO;
358 /* total number of entries in the central dir on this disk */
359 if (unzlocal_getShort(fin, &us.gi.number_entry) != UNZ_OK)
360 err = UNZ_ERRNO;
362 /* total number of entries in the central dir */
363 if (unzlocal_getShort(fin, &number_entry_CD) != UNZ_OK)
364 err = UNZ_ERRNO;
366 if ((number_entry_CD != us.gi.number_entry) ||
367 (number_disk_with_CD != 0) ||
368 (number_disk != 0))
369 err = UNZ_BADZIPFILE;
371 /* size of the central directory */
372 if (unzlocal_getLong(fin, &us.size_central_dir) != UNZ_OK)
373 err = UNZ_ERRNO;
375 /* offset of start of central directory with respect to the
376 starting disk number */
377 if (unzlocal_getLong(fin, &us.offset_central_dir) != UNZ_OK)
378 err = UNZ_ERRNO;
380 /* zipfile comment length */
381 if (unzlocal_getShort(fin, &us.gi.size_comment) != UNZ_OK)
382 err = UNZ_ERRNO;
384 if ((central_pos < us.offset_central_dir+us.size_central_dir) &&
385 (err == UNZ_OK))
386 err = UNZ_BADZIPFILE;
388 if (err != UNZ_OK)
389 {
390 fclose(fin);
391 return NULL;
392 }
394 us.file = fin;
395 us.byte_before_the_zipfile = central_pos -
396 (us.offset_central_dir+us.size_central_dir);
397 us.central_pos = central_pos;
398 us.pfile_in_zip_read = NULL;
400 s = (unz_s *)ALLOC(sizeof(unz_s));
401 *s = us;
402 unzGoToFirstFile((unzFile)s);
403 return (unzFile)s;
404 }
406 /*
407 Close a ZipFile opened with unzipOpen.
408 If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
409 these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
410 return UNZ_OK if there is no problem. */
411 extern int ZEXPORT unzClose(unzFile file)
412 {
413 unz_s*s;
414 if (file == NULL)
415 return UNZ_PARAMERROR;
416 s = (unz_s *)file;
418 if (s->pfile_in_zip_read != NULL)
419 unzCloseCurrentFile(file);
421 fclose(s->file);
422 TRYFREE(s);
423 return UNZ_OK;
424 }
426 /*
427 Write info about the ZipFile in the *pglobal_info structure.
428 No preparation of the structure is needed
429 return UNZ_OK if there is no problem. */
430 extern int ZEXPORT unzGetGlobalInfo(unzFile file,
431 unz_global_info *pglobal_info)
432 {
433 unz_s*s;
434 if (file == NULL)
435 return UNZ_PARAMERROR;
436 s = (unz_s *)file;
437 *pglobal_info = s->gi;
438 return UNZ_OK;
439 }
441 /*
442 Translate date/time from Dos format to tm_unz (readable more easilty)
443 */
444 local void unzlocal_DosDateToTmuDate(uLong ulDosDate, tm_unz *ptm)
445 {
446 uLong uDate;
447 uDate = (uLong)(ulDosDate>>16);
448 ptm->tm_mday = (uInt)(uDate&0x1f) ;
449 ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ;
450 ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
452 ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
453 ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ;
454 ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ;
455 }
457 /*
458 Get Info about the current file in the zipfile, with internal only info
459 */
460 local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
461 unz_file_info *pfile_info,
462 unz_file_info_internal
463 *pfile_info_internal,
464 char *szFileName,
465 uLong fileNameBufferSize,
466 void *extraField,
467 uLong extraFieldBufferSize,
468 char *szComment,
469 uLong commentBufferSize));
471 local int unzlocal_GetCurrentFileInfoInternal(unzFile file,
472 unz_file_info *pfile_info,
473 unz_file_info_internal *pfile_info_internal,
474 char *szFileName,
475 uLong fileNameBufferSize,
476 void *extraField,
477 uLong extraFieldBufferSize,
478 char *szComment,
479 uLong commentBufferSize)
480 {
481 unz_s* s;
482 unz_file_info file_info;
483 unz_file_info_internal file_info_internal;
484 int err = UNZ_OK;
485 uLong uMagic;
486 long lSeek = 0;
488 if (file == NULL)
489 return UNZ_PARAMERROR;
490 s = (unz_s *)file;
491 if (fseek(s->file, s->pos_in_central_dir+s->byte_before_the_zipfile, SEEK_SET) != 0)
492 err = UNZ_ERRNO;
494 /* we check the magic */
495 if (err == UNZ_OK)
496 if (unzlocal_getLong(s->file, &uMagic) != UNZ_OK)
497 err = UNZ_ERRNO;
498 else if (uMagic != 0x02014b50)
499 err = UNZ_BADZIPFILE;
501 if (unzlocal_getShort(s->file, &file_info.version) != UNZ_OK)
502 err = UNZ_ERRNO;
504 if (unzlocal_getShort(s->file, &file_info.version_needed) != UNZ_OK)
505 err = UNZ_ERRNO;
507 if (unzlocal_getShort(s->file, &file_info.flag) != UNZ_OK)
508 err = UNZ_ERRNO;
510 if (unzlocal_getShort(s->file, &file_info.compression_method) != UNZ_OK)
511 err = UNZ_ERRNO;
513 if (unzlocal_getLong(s->file, &file_info.dosDate) != UNZ_OK)
514 err = UNZ_ERRNO;
516 unzlocal_DosDateToTmuDate(file_info.dosDate, &file_info.tmu_date);
518 if (unzlocal_getLong(s->file, &file_info.crc) != UNZ_OK)
519 err = UNZ_ERRNO;
521 if (unzlocal_getLong(s->file, &file_info.compressed_size) != UNZ_OK)
522 err = UNZ_ERRNO;
524 if (unzlocal_getLong(s->file, &file_info.uncompressed_size) != UNZ_OK)
525 err = UNZ_ERRNO;
527 if (unzlocal_getShort(s->file, &file_info.size_filename) != UNZ_OK)
528 err = UNZ_ERRNO;
530 if (unzlocal_getShort(s->file, &file_info.size_file_extra) != UNZ_OK)
531 err = UNZ_ERRNO;
533 if (unzlocal_getShort(s->file, &file_info.size_file_comment) != UNZ_OK)
534 err = UNZ_ERRNO;
536 if (unzlocal_getShort(s->file, &file_info.disk_num_start) != UNZ_OK)
537 err = UNZ_ERRNO;
539 if (unzlocal_getShort(s->file, &file_info.internal_fa) != UNZ_OK)
540 err = UNZ_ERRNO;
542 if (unzlocal_getLong(s->file, &file_info.external_fa) != UNZ_OK)
543 err = UNZ_ERRNO;
545 if (unzlocal_getLong(s->file, &file_info_internal.offset_curfile) != UNZ_OK)
546 err = UNZ_ERRNO;
548 lSeek += file_info.size_filename;
549 if ((err == UNZ_OK) && (szFileName != NULL))
550 {
551 uLong uSizeRead ;
552 if (file_info.size_filename < fileNameBufferSize)
553 {
554 *(szFileName+file_info.size_filename) = '\0';
555 uSizeRead = file_info.size_filename;
556 }
557 else
558 uSizeRead = fileNameBufferSize;
560 if ((file_info.size_filename > 0) && (fileNameBufferSize > 0))
561 if (fread(szFileName, (uInt)uSizeRead, 1, s->file) != 1)
562 err = UNZ_ERRNO;
563 lSeek -= uSizeRead;
564 }
566 if ((err == UNZ_OK) && (extraField != NULL))
567 {
568 uLong uSizeRead ;
569 if (file_info.size_file_extra < extraFieldBufferSize)
570 uSizeRead = file_info.size_file_extra;
571 else
572 uSizeRead = extraFieldBufferSize;
574 if (lSeek != 0)
575 if (fseek(s->file, lSeek, SEEK_CUR) == 0)
576 lSeek = 0;
577 else
578 err = UNZ_ERRNO;
579 if ((file_info.size_file_extra > 0) && (extraFieldBufferSize > 0))
580 if (fread(extraField, (uInt)uSizeRead, 1, s->file) != 1)
581 err = UNZ_ERRNO;
582 lSeek += file_info.size_file_extra - uSizeRead;
583 }
584 else
585 lSeek += file_info.size_file_extra;
587 if ((err == UNZ_OK) && (szComment != NULL))
588 {
589 uLong uSizeRead ;
590 if (file_info.size_file_comment < commentBufferSize)
591 {
592 *(szComment+file_info.size_file_comment) = '\0';
593 uSizeRead = file_info.size_file_comment;
594 }
595 else
596 uSizeRead = commentBufferSize;
598 if (lSeek != 0)
599 if (fseek(s->file, lSeek, SEEK_CUR) == 0)
600 lSeek = 0;
601 else
602 err = UNZ_ERRNO;
603 if ((file_info.size_file_comment > 0) && (commentBufferSize > 0))
604 if (fread(szComment, (uInt)uSizeRead, 1, s->file) != 1)
605 err = UNZ_ERRNO;
606 lSeek += file_info.size_file_comment - uSizeRead;
607 }
608 else
609 lSeek += file_info.size_file_comment;
611 if ((err == UNZ_OK) && (pfile_info != NULL))
612 *pfile_info = file_info;
614 if ((err == UNZ_OK) && (pfile_info_internal != NULL))
615 *pfile_info_internal = file_info_internal;
617 return err;
618 }
620 /*
621 Write info about the ZipFile in the *pglobal_info structure.
622 No preparation of the structure is needed
623 return UNZ_OK if there is no problem.
624 */
625 extern int ZEXPORT unzGetCurrentFileInfo(unzFile file,
626 unz_file_info *pfile_info,
627 char *szFileName,
628 uLong fileNameBufferSize,
629 void *extraField,
630 uLong extraFieldBufferSize,
631 char *szComment,
632 uLong commentBufferSize)
633 {
634 return unzlocal_GetCurrentFileInfoInternal(file, pfile_info, NULL,
635 szFileName, fileNameBufferSize,
636 extraField, extraFieldBufferSize,
637 szComment, commentBufferSize);
638 }
640 /*
641 Set the current file of the zipfile to the first file.
642 return UNZ_OK if there is no problem
643 */
644 extern int ZEXPORT unzGoToFirstFile(unzFile file)
645 {
646 int err = UNZ_OK;
647 unz_s*s;
648 if (file == NULL)
649 return UNZ_PARAMERROR;
650 s = (unz_s *)file;
651 s->pos_in_central_dir = s->offset_central_dir;
652 s->num_file = 0;
653 err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info,
654 &s->cur_file_info_internal,
655 NULL, 0, NULL, 0, NULL, 0);
656 s->current_file_ok = (err == UNZ_OK);
657 return err;
658 }
660 /*
661 Set the current file of the zipfile to the next file.
662 return UNZ_OK if there is no problem
663 return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
664 */
665 extern int ZEXPORT unzGoToNextFile(unzFile file)
666 {
667 unz_s*s;
668 int err;
670 if (file == NULL)
671 return UNZ_PARAMERROR;
672 s = (unz_s *)file;
673 if (!s->current_file_ok)
674 return UNZ_END_OF_LIST_OF_FILE;
675 if (s->num_file+1 == s->gi.number_entry)
676 return UNZ_END_OF_LIST_OF_FILE;
678 s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
679 s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
680 s->num_file++;
681 err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info,
682 &s->cur_file_info_internal,
683 NULL, 0, NULL, 0, NULL, 0);
684 s->current_file_ok = (err == UNZ_OK);
685 return err;
686 }
688 /*
689 Try locate the file szFileName in the zipfile.
690 For the iCaseSensitivity signification, see unzipStringFileNameCompare
692 return value :
693 UNZ_OK if the file is found. It becomes the current file.
694 UNZ_END_OF_LIST_OF_FILE if the file is not found
695 */
696 extern int ZEXPORT unzLocateFile(unzFile file,
697 const char *szFileName,
698 int iCaseSensitivity)
699 {
700 unz_s*s;
701 int err;
703 uLong num_fileSaved;
704 uLong pos_in_central_dirSaved;
706 if (file == NULL)
707 return UNZ_PARAMERROR;
709 if (strlen(szFileName) >= UNZ_MAXFILENAMEINZIP)
710 return UNZ_PARAMERROR;
712 s = (unz_s *)file;
713 if (!s->current_file_ok)
714 return UNZ_END_OF_LIST_OF_FILE;
716 num_fileSaved = s->num_file;
717 pos_in_central_dirSaved = s->pos_in_central_dir;
719 err = unzGoToFirstFile(file);
721 while (err == UNZ_OK)
722 {
723 char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
724 unzGetCurrentFileInfo(file, NULL,
725 szCurrentFileName, sizeof(szCurrentFileName)-1,
726 NULL, 0, NULL, 0);
727 if (unzStringFileNameCompare(szCurrentFileName,
728 szFileName, iCaseSensitivity) == 0)
729 return UNZ_OK;
730 err = unzGoToNextFile(file);
731 }
733 s->num_file = num_fileSaved ;
734 s->pos_in_central_dir = pos_in_central_dirSaved ;
735 return err;
736 }
738 /*
739 Read the local header of the current zipfile
740 Check the coherency of the local header and info in the end of central
741 directory about this file
742 store in *piSizeVar the size of extra info in local header
743 (filename and size of extra field data)
744 */
745 local int unzlocal_CheckCurrentFileCoherencyHeader(unz_s *s,
746 uInt *piSizeVar,
747 uLong *poffset_local_extrafield,
748 uInt *psize_local_extrafield)
749 {
750 uLong uMagic, uData, uFlags;
751 uLong size_filename;
752 uLong size_extra_field;
753 int err = UNZ_OK;
755 *piSizeVar = 0;
756 *poffset_local_extrafield = 0;
757 *psize_local_extrafield = 0;
759 if (fseek(s->file, s->cur_file_info_internal.offset_curfile +
760 s->byte_before_the_zipfile, SEEK_SET) != 0)
761 return UNZ_ERRNO;
763 if (err == UNZ_OK)
764 if (unzlocal_getLong(s->file, &uMagic) != UNZ_OK)
765 err = UNZ_ERRNO;
766 else if (uMagic != 0x04034b50)
767 err = UNZ_BADZIPFILE;
769 if (unzlocal_getShort(s->file, &uData) != UNZ_OK)
770 err = UNZ_ERRNO;
771 /*
772 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
773 err=UNZ_BADZIPFILE;
774 */
775 if (unzlocal_getShort(s->file, &uFlags) != UNZ_OK)
776 err = UNZ_ERRNO;
778 if (unzlocal_getShort(s->file, &uData) != UNZ_OK)
779 err = UNZ_ERRNO;
780 else if ((err == UNZ_OK) && (uData != s->cur_file_info.compression_method))
781 err = UNZ_BADZIPFILE;
783 if ((err == UNZ_OK) && (s->cur_file_info.compression_method != 0) &&
784 (s->cur_file_info.compression_method != Z_DEFLATED))
785 err = UNZ_BADZIPFILE;
787 if (unzlocal_getLong(s->file, &uData) != UNZ_OK) /* date/time */
788 err = UNZ_ERRNO;
790 if (unzlocal_getLong(s->file, &uData) != UNZ_OK) /* crc */
791 err = UNZ_ERRNO;
792 else if ((err == UNZ_OK) && (uData != s->cur_file_info.crc) &&
793 ((uFlags & 8) == 0))
794 err = UNZ_BADZIPFILE;
796 if (unzlocal_getLong(s->file, &uData) != UNZ_OK) /* size compr */
797 err = UNZ_ERRNO;
798 else if ((err == UNZ_OK) && (uData != s->cur_file_info.compressed_size) &&
799 ((uFlags & 8) == 0))
800 err = UNZ_BADZIPFILE;
802 if (unzlocal_getLong(s->file, &uData) != UNZ_OK) /* size uncompr */
803 err = UNZ_ERRNO;
804 else if ((err == UNZ_OK) && (uData != s->cur_file_info.uncompressed_size) &&
805 ((uFlags & 8) == 0))
806 err = UNZ_BADZIPFILE;
808 if (unzlocal_getShort(s->file, &size_filename) != UNZ_OK)
809 err = UNZ_ERRNO;
810 else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename))
811 err = UNZ_BADZIPFILE;
813 *piSizeVar += (uInt)size_filename;
815 if (unzlocal_getShort(s->file, &size_extra_field) != UNZ_OK)
816 err = UNZ_ERRNO;
817 *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile +
818 SIZEZIPLOCALHEADER + size_filename;
819 *psize_local_extrafield = (uInt)size_extra_field;
821 *piSizeVar += (uInt)size_extra_field;
823 return err;
824 }
826 /*
827 Open for reading data the current file in the zipfile.
828 If there is no error and the file is opened, the return value is UNZ_OK.
829 */
830 extern int ZEXPORT unzOpenCurrentFile(unzFile file)
831 {
832 int err = UNZ_OK;
833 int Store;
834 uInt iSizeVar;
835 unz_s*s;
836 file_in_zip_read_info_s*pfile_in_zip_read_info;
837 uLong offset_local_extrafield; /* offset of the local extra field */
838 uInt size_local_extrafield; /* size of the local extra field */
840 if (file == NULL)
841 return UNZ_PARAMERROR;
842 s = (unz_s *)file;
843 if (!s->current_file_ok)
844 return UNZ_PARAMERROR;
846 if (s->pfile_in_zip_read != NULL)
847 unzCloseCurrentFile(file);
849 if (unzlocal_CheckCurrentFileCoherencyHeader(s, &iSizeVar,
850 &offset_local_extrafield, &size_local_extrafield) != UNZ_OK)
851 return UNZ_BADZIPFILE;
853 pfile_in_zip_read_info = (file_in_zip_read_info_s *)
854 ALLOC(sizeof(file_in_zip_read_info_s));
855 if (pfile_in_zip_read_info == NULL)
856 return UNZ_INTERNALERROR;
858 pfile_in_zip_read_info->read_buffer = (char *)ALLOC(UNZ_BUFSIZE);
859 pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
860 pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
861 pfile_in_zip_read_info->pos_local_extrafield = 0;
863 if (pfile_in_zip_read_info->read_buffer == NULL)
864 {
865 TRYFREE(pfile_in_zip_read_info);
866 return UNZ_INTERNALERROR;
867 }
869 pfile_in_zip_read_info->stream_initialised = 0;
871 if ((s->cur_file_info.compression_method != 0) &&
872 (s->cur_file_info.compression_method != Z_DEFLATED))
873 err = UNZ_BADZIPFILE;
874 Store = s->cur_file_info.compression_method == 0;
876 pfile_in_zip_read_info->crc32_wait = s->cur_file_info.crc;
877 pfile_in_zip_read_info->crc32 = 0;
878 pfile_in_zip_read_info->compression_method =
879 s->cur_file_info.compression_method;
880 pfile_in_zip_read_info->file = s->file;
881 pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile;
883 pfile_in_zip_read_info->stream.total_out = 0;
885 if (!Store)
886 {
887 pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
888 pfile_in_zip_read_info->stream.zfree = (free_func)0;
889 pfile_in_zip_read_info->stream.opaque = (voidpf)0;
891 err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
892 if (err == Z_OK)
893 pfile_in_zip_read_info->stream_initialised = 1;
894 /* windowBits is passed < 0 to tell that there is no zlib header.
895 * Note that in this case inflate *requires* an extra "dummy" byte
896 * after the compressed stream in order to complete decompression and
897 * return Z_STREAM_END.
898 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
899 * size of both compressed and uncompressed data
900 */
901 }
902 pfile_in_zip_read_info->rest_read_compressed =
903 s->cur_file_info.compressed_size ;
904 pfile_in_zip_read_info->rest_read_uncompressed =
905 s->cur_file_info.uncompressed_size ;
907 pfile_in_zip_read_info->pos_in_zipfile =
908 s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
909 iSizeVar;
911 pfile_in_zip_read_info->stream.avail_in = (uInt)0;
913 s->pfile_in_zip_read = pfile_in_zip_read_info;
914 return UNZ_OK;
915 }
917 /*
918 Read bytes from the current file.
919 buf contain buffer where data must be copied
920 len the size of buf.
922 return the number of byte copied if somes bytes are copied
923 return 0 if the end of file was reached
924 return <0 with error code if there is an error
925 (UNZ_ERRNO for IO error, or zLib error for uncompress error)
926 */
927 extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len)
928 {
929 int err = UNZ_OK;
930 uInt iRead = 0;
931 unz_s*s;
932 file_in_zip_read_info_s*pfile_in_zip_read_info;
933 if (file == NULL)
934 return UNZ_PARAMERROR;
935 s = (unz_s *)file;
936 pfile_in_zip_read_info = s->pfile_in_zip_read;
938 if (pfile_in_zip_read_info == NULL)
939 return UNZ_PARAMERROR;
941 if ((pfile_in_zip_read_info->read_buffer == NULL))
942 return UNZ_END_OF_LIST_OF_FILE;
943 if (len == 0)
944 return 0;
946 pfile_in_zip_read_info->stream.next_out = (Bytef *)buf;
948 pfile_in_zip_read_info->stream.avail_out = (uInt)len;
950 if (len > pfile_in_zip_read_info->rest_read_uncompressed)
951 pfile_in_zip_read_info->stream.avail_out =
952 (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
954 while (pfile_in_zip_read_info->stream.avail_out > 0)
955 {
956 if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
957 (pfile_in_zip_read_info->rest_read_compressed > 0))
958 {
959 uInt uReadThis = UNZ_BUFSIZE;
960 if (pfile_in_zip_read_info->rest_read_compressed < uReadThis)
961 uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
962 if (uReadThis == 0)
963 return UNZ_EOF;
964 if (fseek(pfile_in_zip_read_info->file,
965 pfile_in_zip_read_info->pos_in_zipfile +
966 pfile_in_zip_read_info->byte_before_the_zipfile, SEEK_SET) != 0)
967 return UNZ_ERRNO;
968 if (fread(pfile_in_zip_read_info->read_buffer, uReadThis, 1,
969 pfile_in_zip_read_info->file) != 1)
970 return UNZ_ERRNO;
971 pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
973 pfile_in_zip_read_info->rest_read_compressed -= uReadThis;
975 pfile_in_zip_read_info->stream.next_in =
976 (Bytef *)pfile_in_zip_read_info->read_buffer;
977 pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
978 }
980 if (pfile_in_zip_read_info->compression_method == 0)
981 {
982 uInt uDoCopy, i ;
983 if (pfile_in_zip_read_info->stream.avail_out <
984 pfile_in_zip_read_info->stream.avail_in)
985 uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
986 else
987 uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
989 for (i = 0; i < uDoCopy; i++)
990 *(pfile_in_zip_read_info->stream.next_out+i) =
991 *(pfile_in_zip_read_info->stream.next_in+i);
993 pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
994 pfile_in_zip_read_info->stream.next_out,
995 uDoCopy);
996 pfile_in_zip_read_info->rest_read_uncompressed -= uDoCopy;
997 pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
998 pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
999 pfile_in_zip_read_info->stream.next_out += uDoCopy;
1000 pfile_in_zip_read_info->stream.next_in += uDoCopy;
1001 pfile_in_zip_read_info->stream.total_out += uDoCopy;
1002 iRead += uDoCopy;
1004 else
1006 uLong uTotalOutBefore, uTotalOutAfter;
1007 const Bytef *bufBefore;
1008 uLong uOutThis;
1009 int flush = Z_SYNC_FLUSH;
1011 uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
1012 bufBefore = pfile_in_zip_read_info->stream.next_out;
1014 /*
1015 if ((pfile_in_zip_read_info->rest_read_uncompressed ==
1016 pfile_in_zip_read_info->stream.avail_out) &&
1017 (pfile_in_zip_read_info->rest_read_compressed == 0))
1018 flush = Z_FINISH;
1019 */
1020 err = inflate(&pfile_in_zip_read_info->stream, flush);
1022 uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
1023 uOutThis = uTotalOutAfter-uTotalOutBefore;
1025 pfile_in_zip_read_info->crc32 =
1026 crc32(pfile_in_zip_read_info->crc32, bufBefore,
1027 (uInt)(uOutThis));
1029 pfile_in_zip_read_info->rest_read_uncompressed -=
1030 uOutThis;
1032 iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
1034 if (err == Z_STREAM_END)
1035 return (iRead == 0) ? UNZ_EOF : iRead;
1036 if (err != Z_OK)
1037 break;
1041 if (err == Z_OK)
1042 return iRead;
1043 return err;
1046 /*
1047 Give the current position in uncompressed data
1048 */
1049 extern z_off_t ZEXPORT unztell(unzFile file)
1051 unz_s*s;
1052 file_in_zip_read_info_s*pfile_in_zip_read_info;
1053 if (file == NULL)
1054 return UNZ_PARAMERROR;
1055 s = (unz_s *)file;
1056 pfile_in_zip_read_info = s->pfile_in_zip_read;
1058 if (pfile_in_zip_read_info == NULL)
1059 return UNZ_PARAMERROR;
1061 return (z_off_t)pfile_in_zip_read_info->stream.total_out;
1064 /*
1065 return 1 if the end of file was reached, 0 elsewhere
1066 */
1067 extern int ZEXPORT unzeof(unzFile file)
1069 unz_s*s;
1070 file_in_zip_read_info_s*pfile_in_zip_read_info;
1071 if (file == NULL)
1072 return UNZ_PARAMERROR;
1073 s = (unz_s *)file;
1074 pfile_in_zip_read_info = s->pfile_in_zip_read;
1076 if (pfile_in_zip_read_info == NULL)
1077 return UNZ_PARAMERROR;
1079 if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1080 return 1;
1081 else
1082 return 0;
1085 /*
1086 Read extra field from the current file (opened by unzOpenCurrentFile)
1087 This is the local-header version of the extra field (sometimes, there is
1088 more info in the local-header version than in the central-header)
1090 if buf==NULL, it return the size of the local extra field that can be read
1092 if buf!=NULL, len is the size of the buffer, the extra header is copied in
1093 buf.
1094 the return value is the number of bytes copied in buf, or (if <0)
1095 the error code
1096 */
1097 extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len)
1099 unz_s*s;
1100 file_in_zip_read_info_s*pfile_in_zip_read_info;
1101 uInt read_now;
1102 uLong size_to_read;
1104 if (file == NULL)
1105 return UNZ_PARAMERROR;
1106 s = (unz_s *)file;
1107 pfile_in_zip_read_info = s->pfile_in_zip_read;
1109 if (pfile_in_zip_read_info == NULL)
1110 return UNZ_PARAMERROR;
1112 size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
1113 pfile_in_zip_read_info->pos_local_extrafield);
1115 if (buf == NULL)
1116 return (int)size_to_read;
1118 if (len > size_to_read)
1119 read_now = (uInt)size_to_read;
1120 else
1121 read_now = (uInt)len ;
1123 if (read_now == 0)
1124 return 0;
1126 if (fseek(pfile_in_zip_read_info->file,
1127 pfile_in_zip_read_info->offset_local_extrafield +
1128 pfile_in_zip_read_info->pos_local_extrafield, SEEK_SET) != 0)
1129 return UNZ_ERRNO;
1131 if (fread(buf, (uInt)size_to_read, 1, pfile_in_zip_read_info->file) != 1)
1132 return UNZ_ERRNO;
1134 return (int)read_now;
1137 /*
1138 Close the file in zip opened with unzipOpenCurrentFile
1139 Return UNZ_CRCERROR if all the file was read but the CRC is not good
1140 */
1141 extern int ZEXPORT unzCloseCurrentFile(unzFile file)
1143 int err = UNZ_OK;
1145 unz_s*s;
1146 file_in_zip_read_info_s*pfile_in_zip_read_info;
1147 if (file == NULL)
1148 return UNZ_PARAMERROR;
1149 s = (unz_s *)file;
1150 pfile_in_zip_read_info = s->pfile_in_zip_read;
1152 if (pfile_in_zip_read_info == NULL)
1153 return UNZ_PARAMERROR;
1155 if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1157 if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
1158 err = UNZ_CRCERROR;
1161 TRYFREE(pfile_in_zip_read_info->read_buffer);
1162 pfile_in_zip_read_info->read_buffer = NULL;
1163 if (pfile_in_zip_read_info->stream_initialised)
1164 inflateEnd(&pfile_in_zip_read_info->stream);
1166 pfile_in_zip_read_info->stream_initialised = 0;
1167 TRYFREE(pfile_in_zip_read_info);
1169 s->pfile_in_zip_read = NULL;
1171 return err;
1174 /*
1175 Get the global comment string of the ZipFile, in the szComment buffer.
1176 uSizeBuf is the size of the szComment buffer.
1177 return the number of byte copied or an error code <0
1178 */
1179 extern int ZEXPORT unzGetGlobalComment(unzFile file,
1180 char *szComment,
1181 uLong uSizeBuf)
1183 //int err=UNZ_OK;
1184 unz_s*s;
1185 uLong uReadThis ;
1186 if (file == NULL)
1187 return UNZ_PARAMERROR;
1188 s = (unz_s *)file;
1190 uReadThis = uSizeBuf;
1191 if (uReadThis > s->gi.size_comment)
1192 uReadThis = s->gi.size_comment;
1194 if (fseek(s->file, s->central_pos+22, SEEK_SET) != 0)
1195 return UNZ_ERRNO;
1197 if (uReadThis > 0)
1199 *szComment = '\0';
1200 if (fread(szComment, (uInt)uReadThis, 1, s->file) != 1)
1201 return UNZ_ERRNO;
1204 if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
1205 *(szComment+s->gi.size_comment) = '\0';
1206 return (int)uReadThis;