]> git.saurik.com Git - wxWidgets.git/blob - src/common/unzip.c
a base for geometry operations
[wxWidgets.git] / src / common / unzip.c
1 /* unzip.c -- IO on .zip files using zlib
2 Version 0.15 beta, Mar 19th, 1998,
3
4 Read unzip.h for more info
5 */
6
7 #if 0
8 for what compiler ?
9 #if !defined(__VISAGECPP__)
10 # pragma warning(disable:4001) /* non standard extension used: single line comment */
11 #endif
12 #endif
13
14
15 #include "wx/setup.h"
16
17 #if wxUSE_ZLIB && wxUSE_ZIPSTREAM
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "zlib.h"
23
24 /* Not the right solution (paths in makefiles) but... */
25 #ifdef __BORLANDC__
26 #include "../common/unzip.h"
27 #else
28 #include "unzip.h"
29 #endif
30
31 #ifdef STDC
32 # include <stddef.h>
33 # include <string.h>
34 # include <stdlib.h>
35 #endif
36 #ifdef NO_ERRNO_H
37 extern int errno;
38 #else
39 # include <errno.h>
40 #endif
41
42
43 #ifndef local
44 # define local static
45 #endif
46 /* compile with -Dlocal if your debugger can't find static symbols */
47
48
49
50 #if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
51 !defined(CASESENSITIVITYDEFAULT_NO)
52 #define CASESENSITIVITYDEFAULT_NO
53 #endif
54
55
56 #ifndef UNZ_BUFSIZE
57 #define UNZ_BUFSIZE (16384)
58 #endif
59
60 #ifndef UNZ_MAXFILENAMEINZIP
61 #define UNZ_MAXFILENAMEINZIP (256)
62 #endif
63
64 #ifndef ALLOC
65 # define ALLOC(size) (malloc(size))
66 #endif
67 #ifndef TRYFREE
68 # define TRYFREE(p) {if (p) free(p);}
69 #endif
70
71 #define SIZECENTRALDIRITEM (0x2e)
72 #define SIZEZIPLOCALHEADER (0x1e)
73
74
75 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
76
77 #ifndef SEEK_CUR
78 #define SEEK_CUR 1
79 #endif
80
81 #ifndef SEEK_END
82 #define SEEK_END 2
83 #endif
84
85 #ifndef SEEK_SET
86 #define SEEK_SET 0
87 #endif
88
89 const char unz_copyright[] =
90 " unzip 0.15 Copyright 1998 Gilles Vollant ";
91
92 /* unz_file_info_interntal contain internal info about a file in zipfile*/
93 typedef struct unz_file_info_internal_s
94 {
95 uLong offset_curfile;/* relative offset of local header 4 bytes */
96 } unz_file_info_internal;
97
98
99 /* file_in_zip_read_info_s contain internal information about a file in zipfile,
100 when reading and decompress it */
101 typedef struct
102 {
103 char *read_buffer; /* internal buffer for compressed data */
104 z_stream stream; /* zLib stream structure for inflate */
105
106 uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
107 uLong stream_initialised; /* flag set if stream structure is initialised*/
108
109 uLong offset_local_extrafield;/* offset of the local extra field */
110 uInt size_local_extrafield;/* size of the local extra field */
111 uLong pos_local_extrafield; /* position in the local extra field in read*/
112
113 uLong crc32; /* crc32 of all data uncompressed */
114 uLong crc32_wait; /* crc32 we must obtain after decompress all */
115 uLong rest_read_compressed; /* number of byte to be decompressed */
116 uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
117 FILE* file; /* io structore of the zipfile */
118 uLong compression_method; /* compression method (0==store) */
119 uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
120 } file_in_zip_read_info_s;
121
122
123 /* unz_s contain internal information about the zipfile
124 */
125 typedef struct
126 {
127 FILE* file; /* io structore of the zipfile */
128 unz_global_info gi; /* public global information */
129 uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
130 uLong num_file; /* number of the current file in the zipfile*/
131 uLong pos_in_central_dir; /* pos of the current file in the central dir*/
132 uLong current_file_ok; /* flag about the usability of the current file*/
133 uLong central_pos; /* position of the beginning of the central dir*/
134
135 uLong size_central_dir; /* size of the central directory */
136 uLong offset_central_dir; /* offset of start of central directory with
137 respect to the starting disk number */
138
139 unz_file_info cur_file_info; /* public info about the current file in zip*/
140 unz_file_info_internal cur_file_info_internal; /* private info about it*/
141 file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
142 file if we are decompressing it */
143 } unz_s;
144
145 #if defined (__VISAGECPP__)
146 /* VA always requires prototypes */
147 int unzlocal_CheckCurrentFileCoherencyHeader (unz_s*, uInt*, uLong*, uInt*);
148 #endif
149
150 /* ===========================================================================
151 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
152 for end of file.
153 IN assertion: the stream s has been sucessfully opened for reading.
154 */
155
156
157 local int unzlocal_getByte(fin,pi)
158 FILE *fin;
159 int *pi;
160 {
161 unsigned char c;
162 int err = fread(&c, 1, 1, fin);
163 if (err==1)
164 {
165 *pi = (int)c;
166 return UNZ_OK;
167 }
168 else
169 {
170 if (ferror(fin))
171 return UNZ_ERRNO;
172 else
173 return UNZ_EOF;
174 }
175 }
176
177
178 /* ===========================================================================
179 Reads a long in LSB order from the given gz_stream. Sets
180 */
181 local int unzlocal_getShort (fin,pX)
182 FILE* fin;
183 uLong *pX;
184 {
185 uLong x ;
186 int i;
187 int err;
188
189 err = unzlocal_getByte(fin,&i);
190 x = (uLong)i;
191
192 if (err==UNZ_OK)
193 err = unzlocal_getByte(fin,&i);
194 x += ((uLong)i)<<8;
195
196 if (err==UNZ_OK)
197 *pX = x;
198 else
199 *pX = 0;
200 return err;
201 }
202
203 local int unzlocal_getLong (fin,pX)
204 FILE* fin;
205 uLong *pX;
206 {
207 uLong x ;
208 int i;
209 int err;
210
211 err = unzlocal_getByte(fin,&i);
212 x = (uLong)i;
213
214 if (err==UNZ_OK)
215 err = unzlocal_getByte(fin,&i);
216 x += ((uLong)i)<<8;
217
218 if (err==UNZ_OK)
219 err = unzlocal_getByte(fin,&i);
220 x += ((uLong)i)<<16;
221
222 if (err==UNZ_OK)
223 err = unzlocal_getByte(fin,&i);
224 x += ((uLong)i)<<24;
225
226 if (err==UNZ_OK)
227 *pX = x;
228 else
229 *pX = 0;
230 return err;
231 }
232
233
234 /* My own strcmpi / strcasecmp */
235 local int strcmpcasenosensitive_internal (fileName1,fileName2)
236 const char* fileName1;
237 const char* fileName2;
238 {
239 for (;;)
240 {
241 char c1=*(fileName1++);
242 char c2=*(fileName2++);
243 if ((c1>='a') && (c1<='z'))
244 c1 -= 0x20;
245 if ((c2>='a') && (c2<='z'))
246 c2 -= 0x20;
247 if (c1=='\0')
248 return ((c2=='\0') ? 0 : -1);
249 if (c2=='\0')
250 return 1;
251 if (c1<c2)
252 return -1;
253 if (c1>c2)
254 return 1;
255 }
256 }
257
258
259 #ifdef CASESENSITIVITYDEFAULT_NO
260 #define CASESENSITIVITYDEFAULTVALUE 2
261 #else
262 #define CASESENSITIVITYDEFAULTVALUE 1
263 #endif
264
265 #ifndef STRCMPCASENOSENTIVEFUNCTION
266 #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
267 #endif
268
269 /*
270 Compare two filename (fileName1,fileName2).
271 If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
272 If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
273 or strcasecmp)
274 If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
275 (like 1 on Unix, 2 on Windows)
276
277 */
278 extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity)
279 const char* fileName1;
280 const char* fileName2;
281 int iCaseSensitivity;
282 {
283 if (iCaseSensitivity==0)
284 iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
285
286 if (iCaseSensitivity==1)
287 return strcmp(fileName1,fileName2);
288
289 return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
290 }
291
292 #define BUFREADCOMMENT (0x400)
293
294 /*
295 Locate the Central directory of a zipfile (at the end, just before
296 the global comment)
297 */
298 local uLong unzlocal_SearchCentralDir(fin)
299 FILE *fin;
300 {
301 unsigned char* buf;
302 uLong uSizeFile;
303 uLong uBackRead;
304 uLong uMaxBack=0xffff; /* maximum size of global comment */
305 uLong uPosFound=0;
306
307 if (fseek(fin,0,SEEK_END) != 0)
308 return 0;
309
310
311 uSizeFile = ftell( fin );
312
313 if (uMaxBack>uSizeFile)
314 uMaxBack = uSizeFile;
315
316 buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
317 if (buf==NULL)
318 return 0;
319
320 uBackRead = 4;
321 while (uBackRead<uMaxBack)
322 {
323 uLong uReadSize,uReadPos ;
324 int i;
325 if (uBackRead+BUFREADCOMMENT>uMaxBack)
326 uBackRead = uMaxBack;
327 else
328 uBackRead+=BUFREADCOMMENT;
329 uReadPos = uSizeFile-uBackRead ;
330
331 uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
332 (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
333 if (fseek(fin,uReadPos,SEEK_SET)!=0)
334 break;
335
336 if (fread(buf,(uInt)uReadSize,1,fin)!=1)
337 break;
338
339 for (i=(int)uReadSize-3; (i--)>0;)
340 if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
341 ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
342 {
343 uPosFound = uReadPos+i;
344 break;
345 }
346
347 if (uPosFound!=0)
348 break;
349 }
350 TRYFREE(buf);
351 return uPosFound;
352 }
353
354 #ifdef __WXMAC__
355 void wxUnix2MacFilename (char *s) ;
356 void
357 wxUnix2MacFilename (char *s)
358 {
359 if (s)
360 {
361 if ( *s == '.' )
362 {
363 // relative path , since it goes on with slash which is translated to a :
364 memmove( s , s+1 ,strlen( s ) ) ;
365 }
366 else if ( *s == '/' )
367 {
368 // absolute path -> on mac just start with the drive name
369 memmove( s , s+1 ,strlen( s ) ) ;
370 }
371 else
372 {
373 // wxASSERT_MSG( 1 , "unkown path beginning" ) ;
374 }
375 while (*s)
376 {
377 if (*s == '/' || *s == '\\')
378 {
379 // convert any back-directory situations
380 if ( *(s+1) == '.' && *(s+2) == '.' && ( (*(s+3) == '/' || *(s+3) == '\\') ) )
381 {
382 *s = ':';
383 memmove( s+1 , s+3 ,strlen( s+3 ) + 1 ) ;
384 }
385 else
386 *s = ':';
387 }
388
389 s++ ;
390 }
391 }
392 }
393 extern char * wxBuffer ;
394 #endif
395
396 /*
397 Open a Zip file. path contain the full pathname (by example,
398 on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
399 "zlib/zlib109.zip".
400 If the zipfile cannot be opened (file don't exist or in not valid), the
401 return value is NULL.
402 Else, the return value is a unzFile Handle, usable with other function
403 of this unzip package.
404 */
405 extern unzFile ZEXPORT unzOpen (path)
406 const char *path;
407 {
408 unz_s us;
409 unz_s *s;
410 uLong central_pos,uL;
411 FILE * fin ;
412
413 uLong number_disk; /* number of the current dist, used for
414 spaning ZIP, unsupported, always 0*/
415 uLong number_disk_with_CD; /* number the the disk with central dir, used
416 for spaning ZIP, unsupported, always 0*/
417 uLong number_entry_CD; /* total number of entries in
418 the central dir
419 (same than number_entry on nospan) */
420
421 int err=UNZ_OK;
422
423 if (unz_copyright[0]!=' ')
424 return NULL;
425
426 #ifdef __WXMAC__
427 strcpy( wxBuffer , path ) ;
428 wxUnix2MacFilename( wxBuffer ) ;
429 fin=fopen(wxBuffer,"rb");
430 #else
431 fin=fopen(path,"rb");
432 #endif
433 if (fin==NULL)
434 return NULL;
435
436 central_pos = unzlocal_SearchCentralDir(fin);
437 if (central_pos==0)
438 err=UNZ_ERRNO;
439
440 if (fseek(fin,central_pos,SEEK_SET)!=0)
441 err=UNZ_ERRNO;
442
443 /* the signature, already checked */
444 if (unzlocal_getLong(fin,&uL)!=UNZ_OK)
445 err=UNZ_ERRNO;
446
447 /* number of this disk */
448 if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK)
449 err=UNZ_ERRNO;
450
451 /* number of the disk with the start of the central directory */
452 if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK)
453 err=UNZ_ERRNO;
454
455 /* total number of entries in the central dir on this disk */
456 if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK)
457 err=UNZ_ERRNO;
458
459 /* total number of entries in the central dir */
460 if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK)
461 err=UNZ_ERRNO;
462
463 if ((number_entry_CD!=us.gi.number_entry) ||
464 (number_disk_with_CD!=0) ||
465 (number_disk!=0))
466 err=UNZ_BADZIPFILE;
467
468 /* size of the central directory */
469 if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK)
470 err=UNZ_ERRNO;
471
472 /* offset of start of central directory with respect to the
473 starting disk number */
474 if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK)
475 err=UNZ_ERRNO;
476
477 /* zipfile comment length */
478 if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK)
479 err=UNZ_ERRNO;
480
481 if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
482 (err==UNZ_OK))
483 err=UNZ_BADZIPFILE;
484
485 if (err!=UNZ_OK)
486 {
487 fclose(fin);
488 return NULL;
489 }
490 us.file=fin;
491 us.byte_before_the_zipfile = central_pos -
492 (us.offset_central_dir+us.size_central_dir);
493 us.central_pos = central_pos;
494 us.pfile_in_zip_read = NULL;
495
496
497 s=(unz_s*)ALLOC(sizeof(unz_s));
498 *s=us;
499 unzGoToFirstFile((unzFile)s);
500 return (unzFile)s;
501 }
502
503
504 /*
505 Close a ZipFile opened with unzipOpen.
506 If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
507 these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
508 return UNZ_OK if there is no problem. */
509 extern int ZEXPORT unzClose (file)
510 unzFile file;
511 {
512 unz_s* s;
513 if (file==NULL)
514 return UNZ_PARAMERROR;
515 s=(unz_s*)file;
516
517 if (s->pfile_in_zip_read!=NULL)
518 unzCloseCurrentFile(file);
519
520 fclose(s->file);
521 TRYFREE(s);
522 return UNZ_OK;
523 }
524
525
526 /*
527 Write info about the ZipFile in the *pglobal_info structure.
528 No preparation of the structure is needed
529 return UNZ_OK if there is no problem. */
530 extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info)
531 unzFile file;
532 unz_global_info *pglobal_info;
533 {
534 unz_s* s;
535 if (file==NULL)
536 return UNZ_PARAMERROR;
537 s=(unz_s*)file;
538 *pglobal_info=s->gi;
539 return UNZ_OK;
540 }
541
542
543 /*
544 Translate date/time from Dos format to tm_unz (readable more easilty)
545 */
546 local void unzlocal_DosDateToTmuDate (ulDosDate, ptm)
547 uLong ulDosDate;
548 tm_unz* ptm;
549 {
550 uLong uDate;
551 uDate = (uLong)(ulDosDate>>16);
552 ptm->tm_mday = (uInt)(uDate&0x1f) ;
553 ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ;
554 ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
555
556 ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
557 ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ;
558 ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ;
559 }
560
561 /*
562 Get Info about the current file in the zipfile, with internal only info
563 */
564 local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
565 unz_file_info *pfile_info,
566 unz_file_info_internal
567 *pfile_info_internal,
568 char *szFileName,
569 uLong fileNameBufferSize,
570 void *extraField,
571 uLong extraFieldBufferSize,
572 char *szComment,
573 uLong commentBufferSize));
574
575 local int unzlocal_GetCurrentFileInfoInternal (file,
576 pfile_info,
577 pfile_info_internal,
578 szFileName, fileNameBufferSize,
579 extraField, extraFieldBufferSize,
580 szComment, commentBufferSize)
581 unzFile file;
582 unz_file_info *pfile_info;
583 unz_file_info_internal *pfile_info_internal;
584 char *szFileName;
585 uLong fileNameBufferSize;
586 void *extraField;
587 uLong extraFieldBufferSize;
588 char *szComment;
589 uLong commentBufferSize;
590 {
591 unz_s* s;
592 unz_file_info file_info;
593 unz_file_info_internal file_info_internal;
594 int err=UNZ_OK;
595 uLong uMagic;
596 long lSeek=0;
597
598 if (file==NULL)
599 return UNZ_PARAMERROR;
600 s=(unz_s*)file;
601 if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0)
602 err=UNZ_ERRNO;
603
604
605 /* we check the magic */
606 if (err==UNZ_OK)
607 if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
608 err=UNZ_ERRNO;
609 else if (uMagic!=0x02014b50)
610 err=UNZ_BADZIPFILE;
611
612 if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)
613 err=UNZ_ERRNO;
614
615 if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)
616 err=UNZ_ERRNO;
617
618 if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)
619 err=UNZ_ERRNO;
620
621 if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)
622 err=UNZ_ERRNO;
623
624 if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)
625 err=UNZ_ERRNO;
626
627 unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
628
629 if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK)
630 err=UNZ_ERRNO;
631
632 if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK)
633 err=UNZ_ERRNO;
634
635 if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK)
636 err=UNZ_ERRNO;
637
638 if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK)
639 err=UNZ_ERRNO;
640
641 if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK)
642 err=UNZ_ERRNO;
643
644 if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK)
645 err=UNZ_ERRNO;
646
647 if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK)
648 err=UNZ_ERRNO;
649
650 if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK)
651 err=UNZ_ERRNO;
652
653 if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK)
654 err=UNZ_ERRNO;
655
656 if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK)
657 err=UNZ_ERRNO;
658
659 lSeek+=file_info.size_filename;
660 if ((err==UNZ_OK) && (szFileName!=NULL))
661 {
662 uLong uSizeRead ;
663 if (file_info.size_filename<fileNameBufferSize)
664 {
665 *(szFileName+file_info.size_filename)='\0';
666 uSizeRead = file_info.size_filename;
667 }
668 else
669 uSizeRead = fileNameBufferSize;
670
671 if ((file_info.size_filename>0) && (fileNameBufferSize>0))
672 if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1)
673 err=UNZ_ERRNO;
674 lSeek -= uSizeRead;
675 }
676
677
678 if ((err==UNZ_OK) && (extraField!=NULL))
679 {
680 uLong uSizeRead ;
681 if (file_info.size_file_extra<extraFieldBufferSize)
682 uSizeRead = file_info.size_file_extra;
683 else
684 uSizeRead = extraFieldBufferSize;
685
686 if (lSeek!=0)
687 if (fseek(s->file,lSeek,SEEK_CUR)==0)
688 lSeek=0;
689 else
690 err=UNZ_ERRNO;
691 if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
692 if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1)
693 err=UNZ_ERRNO;
694 lSeek += file_info.size_file_extra - uSizeRead;
695 }
696 else
697 lSeek+=file_info.size_file_extra;
698
699
700 if ((err==UNZ_OK) && (szComment!=NULL))
701 {
702 uLong uSizeRead ;
703 if (file_info.size_file_comment<commentBufferSize)
704 {
705 *(szComment+file_info.size_file_comment)='\0';
706 uSizeRead = file_info.size_file_comment;
707 }
708 else
709 uSizeRead = commentBufferSize;
710
711 if (lSeek!=0)
712 if (fseek(s->file,lSeek,SEEK_CUR)==0)
713 lSeek=0;
714 else
715 err=UNZ_ERRNO;
716 if ((file_info.size_file_comment>0) && (commentBufferSize>0))
717 if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1)
718 err=UNZ_ERRNO;
719 lSeek+=file_info.size_file_comment - uSizeRead;
720 }
721 else
722 lSeek+=file_info.size_file_comment;
723
724 if ((err==UNZ_OK) && (pfile_info!=NULL))
725 *pfile_info=file_info;
726
727 if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
728 *pfile_info_internal=file_info_internal;
729
730 return err;
731 }
732
733
734
735 /*
736 Write info about the ZipFile in the *pglobal_info structure.
737 No preparation of the structure is needed
738 return UNZ_OK if there is no problem.
739 */
740 extern int ZEXPORT unzGetCurrentFileInfo (file,
741 pfile_info,
742 szFileName, fileNameBufferSize,
743 extraField, extraFieldBufferSize,
744 szComment, commentBufferSize)
745 unzFile file;
746 unz_file_info *pfile_info;
747 char *szFileName;
748 uLong fileNameBufferSize;
749 void *extraField;
750 uLong extraFieldBufferSize;
751 char *szComment;
752 uLong commentBufferSize;
753 {
754 return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
755 szFileName,fileNameBufferSize,
756 extraField,extraFieldBufferSize,
757 szComment,commentBufferSize);
758 }
759
760 /*
761 Set the current file of the zipfile to the first file.
762 return UNZ_OK if there is no problem
763 */
764 extern int ZEXPORT unzGoToFirstFile (file)
765 unzFile file;
766 {
767 int err=UNZ_OK;
768 unz_s* s;
769 if (file==NULL)
770 return UNZ_PARAMERROR;
771 s=(unz_s*)file;
772 s->pos_in_central_dir=s->offset_central_dir;
773 s->num_file=0;
774 err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
775 &s->cur_file_info_internal,
776 NULL,0,NULL,0,NULL,0);
777 s->current_file_ok = (err == UNZ_OK);
778 return err;
779 }
780
781
782 /*
783 Set the current file of the zipfile to the next file.
784 return UNZ_OK if there is no problem
785 return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
786 */
787 extern int ZEXPORT unzGoToNextFile (file)
788 unzFile file;
789 {
790 unz_s* s;
791 int err;
792
793 if (file==NULL)
794 return UNZ_PARAMERROR;
795 s=(unz_s*)file;
796 if (!s->current_file_ok)
797 return UNZ_END_OF_LIST_OF_FILE;
798 if (s->num_file+1==s->gi.number_entry)
799 return UNZ_END_OF_LIST_OF_FILE;
800
801 s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
802 s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
803 s->num_file++;
804 err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
805 &s->cur_file_info_internal,
806 NULL,0,NULL,0,NULL,0);
807 s->current_file_ok = (err == UNZ_OK);
808 return err;
809 }
810
811
812 /*
813 Try locate the file szFileName in the zipfile.
814 For the iCaseSensitivity signification, see unzipStringFileNameCompare
815
816 return value :
817 UNZ_OK if the file is found. It becomes the current file.
818 UNZ_END_OF_LIST_OF_FILE if the file is not found
819 */
820 extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)
821 unzFile file;
822 const char *szFileName;
823 int iCaseSensitivity;
824 {
825 unz_s* s;
826 int err;
827
828
829 uLong num_fileSaved;
830 uLong pos_in_central_dirSaved;
831
832
833 if (file==NULL)
834 return UNZ_PARAMERROR;
835
836 if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
837 return UNZ_PARAMERROR;
838
839 s=(unz_s*)file;
840 if (!s->current_file_ok)
841 return UNZ_END_OF_LIST_OF_FILE;
842
843 num_fileSaved = s->num_file;
844 pos_in_central_dirSaved = s->pos_in_central_dir;
845
846 err = unzGoToFirstFile(file);
847
848 while (err == UNZ_OK)
849 {
850 char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
851 unzGetCurrentFileInfo(file,NULL,
852 szCurrentFileName,sizeof(szCurrentFileName)-1,
853 NULL,0,NULL,0);
854 if (unzStringFileNameCompare(szCurrentFileName,
855 szFileName,iCaseSensitivity)==0)
856 return UNZ_OK;
857 err = unzGoToNextFile(file);
858 }
859
860 s->num_file = num_fileSaved ;
861 s->pos_in_central_dir = pos_in_central_dirSaved ;
862 return err;
863 }
864
865
866 /*
867 Read the local header of the current zipfile
868 Check the coherency of the local header and info in the end of central
869 directory about this file
870 store in *piSizeVar the size of extra info in local header
871 (filename and size of extra field data)
872 */
873 local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
874 poffset_local_extrafield,
875 psize_local_extrafield)
876 unz_s* s;
877 uInt* piSizeVar;
878 uLong *poffset_local_extrafield;
879 uInt *psize_local_extrafield;
880 {
881 uLong uMagic,uData,uFlags;
882 uLong size_filename;
883 uLong size_extra_field;
884 int err=UNZ_OK;
885
886 *piSizeVar = 0;
887 *poffset_local_extrafield = 0;
888 *psize_local_extrafield = 0;
889
890 if (fseek(s->file,s->cur_file_info_internal.offset_curfile +
891 s->byte_before_the_zipfile,SEEK_SET)!=0)
892 return UNZ_ERRNO;
893
894
895 if (err==UNZ_OK)
896 if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
897 err=UNZ_ERRNO;
898 else if (uMagic!=0x04034b50)
899 err=UNZ_BADZIPFILE;
900
901 if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
902 err=UNZ_ERRNO;
903 /*
904 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
905 err=UNZ_BADZIPFILE;
906 */
907 if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK)
908 err=UNZ_ERRNO;
909
910 if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
911 err=UNZ_ERRNO;
912 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
913 err=UNZ_BADZIPFILE;
914
915 if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
916 (s->cur_file_info.compression_method!=Z_DEFLATED))
917 err=UNZ_BADZIPFILE;
918
919 if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */
920 err=UNZ_ERRNO;
921
922 if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */
923 err=UNZ_ERRNO;
924 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
925 ((uFlags & 8)==0))
926 err=UNZ_BADZIPFILE;
927
928 if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */
929 err=UNZ_ERRNO;
930 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
931 ((uFlags & 8)==0))
932 err=UNZ_BADZIPFILE;
933
934 if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */
935 err=UNZ_ERRNO;
936 else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) &&
937 ((uFlags & 8)==0))
938 err=UNZ_BADZIPFILE;
939
940
941 if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK)
942 err=UNZ_ERRNO;
943 else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
944 err=UNZ_BADZIPFILE;
945
946 *piSizeVar += (uInt)size_filename;
947
948 if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK)
949 err=UNZ_ERRNO;
950 *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
951 SIZEZIPLOCALHEADER + size_filename;
952 *psize_local_extrafield = (uInt)size_extra_field;
953
954 *piSizeVar += (uInt)size_extra_field;
955
956 return err;
957 }
958
959 /*
960 Open for reading data the current file in the zipfile.
961 If there is no error and the file is opened, the return value is UNZ_OK.
962 */
963 extern int ZEXPORT unzOpenCurrentFile (file)
964 unzFile file;
965 {
966 int err=UNZ_OK;
967 int Store;
968 uInt iSizeVar;
969 unz_s* s;
970 file_in_zip_read_info_s* pfile_in_zip_read_info;
971 uLong offset_local_extrafield; /* offset of the local extra field */
972 uInt size_local_extrafield; /* size of the local extra field */
973
974 if (file==NULL)
975 return UNZ_PARAMERROR;
976 s=(unz_s*)file;
977 if (!s->current_file_ok)
978 return UNZ_PARAMERROR;
979
980 if (s->pfile_in_zip_read != NULL)
981 unzCloseCurrentFile(file);
982
983 if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
984 &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
985 return UNZ_BADZIPFILE;
986
987 pfile_in_zip_read_info = (file_in_zip_read_info_s*)
988 ALLOC(sizeof(file_in_zip_read_info_s));
989 if (pfile_in_zip_read_info==NULL)
990 return UNZ_INTERNALERROR;
991
992 pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
993 pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
994 pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
995 pfile_in_zip_read_info->pos_local_extrafield=0;
996
997 if (pfile_in_zip_read_info->read_buffer==NULL)
998 {
999 TRYFREE(pfile_in_zip_read_info);
1000 return UNZ_INTERNALERROR;
1001 }
1002
1003 pfile_in_zip_read_info->stream_initialised=0;
1004
1005 if ((s->cur_file_info.compression_method!=0) &&
1006 (s->cur_file_info.compression_method!=Z_DEFLATED))
1007 err=UNZ_BADZIPFILE;
1008 Store = s->cur_file_info.compression_method==0;
1009
1010 pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
1011 pfile_in_zip_read_info->crc32=0;
1012 pfile_in_zip_read_info->compression_method =
1013 s->cur_file_info.compression_method;
1014 pfile_in_zip_read_info->file=s->file;
1015 pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
1016
1017 pfile_in_zip_read_info->stream.total_out = 0;
1018
1019 if (!Store)
1020 {
1021 pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
1022 pfile_in_zip_read_info->stream.zfree = (free_func)0;
1023 pfile_in_zip_read_info->stream.opaque = (voidpf)0;
1024
1025 err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
1026 if (err == Z_OK)
1027 pfile_in_zip_read_info->stream_initialised=1;
1028 /* windowBits is passed < 0 to tell that there is no zlib header.
1029 * Note that in this case inflate *requires* an extra "dummy" byte
1030 * after the compressed stream in order to complete decompression and
1031 * return Z_STREAM_END.
1032 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1033 * size of both compressed and uncompressed data
1034 */
1035 }
1036 pfile_in_zip_read_info->rest_read_compressed =
1037 s->cur_file_info.compressed_size ;
1038 pfile_in_zip_read_info->rest_read_uncompressed =
1039 s->cur_file_info.uncompressed_size ;
1040
1041
1042 pfile_in_zip_read_info->pos_in_zipfile =
1043 s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
1044 iSizeVar;
1045
1046 pfile_in_zip_read_info->stream.avail_in = (uInt)0;
1047
1048
1049 s->pfile_in_zip_read = pfile_in_zip_read_info;
1050 return UNZ_OK;
1051 }
1052
1053
1054 /*
1055 Read bytes from the current file.
1056 buf contain buffer where data must be copied
1057 len the size of buf.
1058
1059 return the number of byte copied if somes bytes are copied
1060 return 0 if the end of file was reached
1061 return <0 with error code if there is an error
1062 (UNZ_ERRNO for IO error, or zLib error for uncompress error)
1063 */
1064 extern int ZEXPORT unzReadCurrentFile (file, buf, len)
1065 unzFile file;
1066 voidp buf;
1067 unsigned len;
1068 {
1069 int err=UNZ_OK;
1070 uInt iRead = 0;
1071 unz_s* s;
1072 file_in_zip_read_info_s* pfile_in_zip_read_info;
1073 if (file==NULL)
1074 return UNZ_PARAMERROR;
1075 s=(unz_s*)file;
1076 pfile_in_zip_read_info=s->pfile_in_zip_read;
1077
1078 if (pfile_in_zip_read_info==NULL)
1079 return UNZ_PARAMERROR;
1080
1081
1082 if ((pfile_in_zip_read_info->read_buffer == NULL))
1083 return UNZ_END_OF_LIST_OF_FILE;
1084 if (len==0)
1085 return 0;
1086
1087 pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
1088
1089 pfile_in_zip_read_info->stream.avail_out = (uInt)len;
1090
1091 if (len>pfile_in_zip_read_info->rest_read_uncompressed)
1092 pfile_in_zip_read_info->stream.avail_out =
1093 (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
1094
1095 while (pfile_in_zip_read_info->stream.avail_out>0)
1096 {
1097 if ((pfile_in_zip_read_info->stream.avail_in==0) &&
1098 (pfile_in_zip_read_info->rest_read_compressed>0))
1099 {
1100 uInt uReadThis = UNZ_BUFSIZE;
1101 if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
1102 uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
1103 if (uReadThis == 0)
1104 return UNZ_EOF;
1105 if (fseek(pfile_in_zip_read_info->file,
1106 pfile_in_zip_read_info->pos_in_zipfile +
1107 pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0)
1108 return UNZ_ERRNO;
1109 if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1,
1110 pfile_in_zip_read_info->file)!=1)
1111 return UNZ_ERRNO;
1112 pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
1113
1114 pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
1115
1116 pfile_in_zip_read_info->stream.next_in =
1117 (Bytef*)pfile_in_zip_read_info->read_buffer;
1118 pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
1119 }
1120
1121 if (pfile_in_zip_read_info->compression_method==0)
1122 {
1123 uInt uDoCopy,i ;
1124 if (pfile_in_zip_read_info->stream.avail_out <
1125 pfile_in_zip_read_info->stream.avail_in)
1126 uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
1127 else
1128 uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
1129
1130 for (i=0;i<uDoCopy;i++)
1131 *(pfile_in_zip_read_info->stream.next_out+i) =
1132 *(pfile_in_zip_read_info->stream.next_in+i);
1133
1134 pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
1135 pfile_in_zip_read_info->stream.next_out,
1136 uDoCopy);
1137 pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
1138 pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
1139 pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
1140 pfile_in_zip_read_info->stream.next_out += uDoCopy;
1141 pfile_in_zip_read_info->stream.next_in += uDoCopy;
1142 pfile_in_zip_read_info->stream.total_out += uDoCopy;
1143 iRead += uDoCopy;
1144 }
1145 else
1146 {
1147 uLong uTotalOutBefore,uTotalOutAfter;
1148 const Bytef *bufBefore;
1149 uLong uOutThis;
1150 int flush=Z_SYNC_FLUSH;
1151
1152 uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
1153 bufBefore = pfile_in_zip_read_info->stream.next_out;
1154
1155 /*
1156 if ((pfile_in_zip_read_info->rest_read_uncompressed ==
1157 pfile_in_zip_read_info->stream.avail_out) &&
1158 (pfile_in_zip_read_info->rest_read_compressed == 0))
1159 flush = Z_FINISH;
1160 */
1161 err=inflate(&pfile_in_zip_read_info->stream,flush);
1162
1163 uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
1164 uOutThis = uTotalOutAfter-uTotalOutBefore;
1165
1166 pfile_in_zip_read_info->crc32 =
1167 crc32(pfile_in_zip_read_info->crc32,bufBefore,
1168 (uInt)(uOutThis));
1169
1170 pfile_in_zip_read_info->rest_read_uncompressed -=
1171 uOutThis;
1172
1173 iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
1174
1175 if (err==Z_STREAM_END)
1176 return (iRead==0) ? UNZ_EOF : iRead;
1177 if (err!=Z_OK)
1178 break;
1179 }
1180 }
1181
1182 if (err==Z_OK)
1183 return iRead;
1184 return err;
1185 }
1186
1187
1188 /*
1189 Give the current position in uncompressed data
1190 */
1191 extern z_off_t ZEXPORT unztell (file)
1192 unzFile file;
1193 {
1194 unz_s* s;
1195 file_in_zip_read_info_s* pfile_in_zip_read_info;
1196 if (file==NULL)
1197 return UNZ_PARAMERROR;
1198 s=(unz_s*)file;
1199 pfile_in_zip_read_info=s->pfile_in_zip_read;
1200
1201 if (pfile_in_zip_read_info==NULL)
1202 return UNZ_PARAMERROR;
1203
1204 return (z_off_t)pfile_in_zip_read_info->stream.total_out;
1205 }
1206
1207
1208 /*
1209 return 1 if the end of file was reached, 0 elsewhere
1210 */
1211 extern int ZEXPORT unzeof (file)
1212 unzFile file;
1213 {
1214 unz_s* s;
1215 file_in_zip_read_info_s* pfile_in_zip_read_info;
1216 if (file==NULL)
1217 return UNZ_PARAMERROR;
1218 s=(unz_s*)file;
1219 pfile_in_zip_read_info=s->pfile_in_zip_read;
1220
1221 if (pfile_in_zip_read_info==NULL)
1222 return UNZ_PARAMERROR;
1223
1224 if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1225 return 1;
1226 else
1227 return 0;
1228 }
1229
1230
1231
1232 /*
1233 Read extra field from the current file (opened by unzOpenCurrentFile)
1234 This is the local-header version of the extra field (sometimes, there is
1235 more info in the local-header version than in the central-header)
1236
1237 if buf==NULL, it return the size of the local extra field that can be read
1238
1239 if buf!=NULL, len is the size of the buffer, the extra header is copied in
1240 buf.
1241 the return value is the number of bytes copied in buf, or (if <0)
1242 the error code
1243 */
1244 extern int ZEXPORT unzGetLocalExtrafield (file,buf,len)
1245 unzFile file;
1246 voidp buf;
1247 unsigned len;
1248 {
1249 unz_s* s;
1250 file_in_zip_read_info_s* pfile_in_zip_read_info;
1251 uInt read_now;
1252 uLong size_to_read;
1253
1254 if (file==NULL)
1255 return UNZ_PARAMERROR;
1256 s=(unz_s*)file;
1257 pfile_in_zip_read_info=s->pfile_in_zip_read;
1258
1259 if (pfile_in_zip_read_info==NULL)
1260 return UNZ_PARAMERROR;
1261
1262 size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
1263 pfile_in_zip_read_info->pos_local_extrafield);
1264
1265 if (buf==NULL)
1266 return (int)size_to_read;
1267
1268 if (len>size_to_read)
1269 read_now = (uInt)size_to_read;
1270 else
1271 read_now = (uInt)len ;
1272
1273 if (read_now==0)
1274 return 0;
1275
1276 if (fseek(pfile_in_zip_read_info->file,
1277 pfile_in_zip_read_info->offset_local_extrafield +
1278 pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0)
1279 return UNZ_ERRNO;
1280
1281 if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1)
1282 return UNZ_ERRNO;
1283
1284 return (int)read_now;
1285 }
1286
1287 /*
1288 Close the file in zip opened with unzipOpenCurrentFile
1289 Return UNZ_CRCERROR if all the file was read but the CRC is not good
1290 */
1291 extern int ZEXPORT unzCloseCurrentFile (file)
1292 unzFile file;
1293 {
1294 int err=UNZ_OK;
1295
1296 unz_s* s;
1297 file_in_zip_read_info_s* pfile_in_zip_read_info;
1298 if (file==NULL)
1299 return UNZ_PARAMERROR;
1300 s=(unz_s*)file;
1301 pfile_in_zip_read_info=s->pfile_in_zip_read;
1302
1303 if (pfile_in_zip_read_info==NULL)
1304 return UNZ_PARAMERROR;
1305
1306
1307 if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1308 {
1309 if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
1310 err=UNZ_CRCERROR;
1311 }
1312
1313
1314 TRYFREE(pfile_in_zip_read_info->read_buffer);
1315 pfile_in_zip_read_info->read_buffer = NULL;
1316 if (pfile_in_zip_read_info->stream_initialised)
1317 inflateEnd(&pfile_in_zip_read_info->stream);
1318
1319 pfile_in_zip_read_info->stream_initialised = 0;
1320 TRYFREE(pfile_in_zip_read_info);
1321
1322 s->pfile_in_zip_read=NULL;
1323
1324 return err;
1325 }
1326
1327
1328 /*
1329 Get the global comment string of the ZipFile, in the szComment buffer.
1330 uSizeBuf is the size of the szComment buffer.
1331 return the number of byte copied or an error code <0
1332 */
1333 extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
1334 unzFile file;
1335 char *szComment;
1336 uLong uSizeBuf;
1337 {
1338 int err=UNZ_OK;
1339 unz_s* s;
1340 uLong uReadThis ;
1341 if (file==NULL)
1342 return UNZ_PARAMERROR;
1343 s=(unz_s*)file;
1344
1345 uReadThis = uSizeBuf;
1346 if (uReadThis>s->gi.size_comment)
1347 uReadThis = s->gi.size_comment;
1348
1349 if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0)
1350 return UNZ_ERRNO;
1351
1352 if (uReadThis>0)
1353 {
1354 *szComment='\0';
1355 if (fread(szComment,(uInt)uReadThis,1,s->file)!=1)
1356 return UNZ_ERRNO;
1357 }
1358
1359 if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
1360 *(szComment+s->gi.size_comment)='\0';
1361 return (int)uReadThis;
1362 }
1363
1364 #else
1365
1366 /* the file shouldn't be empty, som compilers don't like it */
1367 static const int dummyVariableInUnzip = 17;
1368
1369 #endif /* wxUSE_ZLIB && wxUSE_ZIPSTREAM */