2 * zipio.c - stdio emulation library for reading zip files
8 * Copyright (C) 1995, Edward B. Hamrick
10 * Permission to use, copy, modify, and distribute this software and
11 * its documentation for any purpose and without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear in
14 * supporting documentation, and that the name of the copyright holders
15 * not be used in advertising or publicity pertaining to distribution of
16 * the software without specific, written prior permission. The copyright
17 * holders makes no representations about the suitability of this software
18 * for any purpose. It is provided "as is" without express or implied warranty.
20 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
21 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
22 * IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT
23 * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
24 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
25 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
30 * Changes from 1.1 to 1.1.1:
31 * Changed "z*" functions to "Z*" to avoid namespace pollution.
32 * Added "zungetc" macro.
33 * Added definitions of SEEK_SET, SEEK_CUR, SEEK_END for the Posixly challenged
34 * John Cowan <cowan@ccil.org>
36 * Changes from 1.1.1 to 1.1.2:
37 * Relicensed under the MIT license, with consent of the copyright holders.
38 * Avoid usage of unitialized "length" variable in _Zgetc
39 * Claudio Matsuoka (Jan 11 2011)
43 * Refer to zipio.h for a description of this package.
47 * The .zip file header is described below. It consists of
48 * 30 fixed bytes, followed by two variable length fields
49 * whose length is contained in the first 30 bytes. After this
50 * header, the data is stored (in deflate format if the compression
53 * The crc-32 field is the crc on the uncompressed data.
57 * local file header signature 4 bytes (0x04034b50)
58 * version needed to extract 2 bytes
59 * general purpose bit flag 2 bytes
60 * compression method 2 bytes
61 * last mod file time 2 bytes
62 * last mod file date 2 bytes
64 * compressed size 4 bytes
65 * uncompressed size 4 bytes
66 * filename length 2 bytes
67 * extra field length 2 bytes
69 * filename (variable size)
70 * extra field (variable size)
72 * These fields are described in more detail in appnote.txt
73 * in the pkzip 1.93 distribution.
86 * Macros for constants
90 #define NULL ((void *) 0)
102 #define ZIPSIGNATURE 0x04034b50L
121 * The following constants are optimized for large-model
122 * (but not flat model) Windows with virtual memory. It
123 * will work fine on unix and flat model Windows as well.
125 * The constant BUFFERTHRESHOLD determines when memory
126 * buffering changes to file buffering.
130 * 1) INPBUFSIZE + OUTBUFSIZE + sizeof(void *) * PTRBUFSIZE + delta < 64K
132 * 2) OUTBUFSIZE = 32K * N (related to inflate's 32K window size)
134 * 2) Max in-memory file size is OUTBUFSIZE * PTRBUFSIZE
135 * which is 64 MBytes by default (32K * 2K).
139 #ifndef BUFFERTHRESHOLD
140 #define BUFFERTHRESHOLD (256 * 1024L)
144 #define INPBUFSIZE ( 8 * 1024 )
148 #define PTRBUFSIZE ( 2 * 1024 )
152 #define OUTBUFSIZE ((unsigned int) ( 32 * 1024L))
155 #define MAXFILESIZE (OUTBUFSIZE * (long) PTRBUFSIZE)
158 * Macro for short-hand reference to ZipioState (from ZFILE *)
161 #define ZS ((struct ZipioState *) stream)
164 * Macro to manipulate Zgetc() cache
171 #define CACHEUPDATE \
174 ZS->fileposition &= ~((long) (OUTBUFSIZE-1)); \
175 ZS->fileposition += ZS->ptr - ZS->getbuf; \
181 * Macros for run-time type identification
184 #ifndef RUNTIMEENABLE
185 #define RUNTIMEENABLE 0
189 #define ZIPIOSTATETYPE 0x0110f00fL
190 #define RUNTIMEINIT \
191 zs->runtimetypeid1 = ZIPIOSTATETYPE; \
192 zs->runtimetypeid2 = ZIPIOSTATETYPE;
194 #define RUNTIMECHECK \
195 if (!ZS || (ZS->runtimetypeid1 != ZIPIOSTATETYPE) \
196 || (ZS->runtimetypeid2 != ZIPIOSTATETYPE)) return -1;
203 * Macros for converting bytes to unsigned integers
206 #define GETUINT4(ptr, i4) \
208 i4 = (((unsigned long) *(((unsigned char *) (ptr)) + 0)) ) | \
209 (((unsigned long) *(((unsigned char *) (ptr)) + 1)) << 8) | \
210 (((unsigned long) *(((unsigned char *) (ptr)) + 2)) << 16) | \
211 (((unsigned long) *(((unsigned char *) (ptr)) + 3)) << 24) ; \
214 #define GETUINT2(ptr, i2) \
216 i2 = (((unsigned int) *(((unsigned char *) (ptr)) + 0)) ) | \
217 (((unsigned int) *(((unsigned char *) (ptr)) + 1)) << 8) ; \
220 /* Structure to hold state for decoding zip files */
223 /* Fields overlaid with ZFILE structure */
224 int len
; /* length of Zgetc cache */
225 unsigned char *ptr
; /* pointer to Zgetc cache */
227 /* Fields invisible to users of ZFILE structure */
229 unsigned long runtimetypeid1
; /* to detect run-time errors */
230 int errorencountered
; /* error encountered flag */
232 /* Buffering state */
233 unsigned char inpbuf
[INPBUFSIZE
]; /* inp buffer from zip file */
234 unsigned char *ptrbuf
[PTRBUFSIZE
]; /* pointers to in-memory bufs */
236 unsigned char getbuf
[OUTBUFSIZE
]; /* buffer for use by Zgetc */
237 long getoff
; /* starting offset of getbuf */
239 FILE *tmpfil
; /* file ptr to temp file */
241 /* Amount of input data inflated */
242 unsigned long inpinf
;
243 unsigned long outinf
;
245 /* Zip file header */
246 unsigned long sign
; /* local file header signature (0x04034b50) */
247 unsigned int vers
; /* version needed to extract 2 bytes */
248 unsigned int flag
; /* general purpose bit flag 2 bytes */
249 unsigned int comp
; /* compression method 2 bytes */
250 unsigned int mtim
; /* last mod file time 2 bytes */
251 unsigned int mdat
; /* last mod file date 2 bytes */
252 unsigned long crc3
; /* crc-32 4 bytes */
253 unsigned long csiz
; /* compressed size 4 bytes */
254 unsigned long usiz
; /* uncompressed size 4 bytes */
255 unsigned int flen
; /* filename length 2 bytes */
256 unsigned int elen
; /* extra field length 2 bytes */
258 /* Application state */
259 FILE *OpenFile
; /* currently open file */
261 void *inflatestate
; /* current state for inflate */
263 unsigned long fileposition
; /* current file position */
265 unsigned long filecrc
; /* current crc */
267 unsigned long runtimetypeid2
; /* to detect run-time errors */
271 * Utility routines to handle uncompressed file buffers
274 /* Initialize buffering */
275 static void BufferInitialize(
276 struct ZipioState
*zs
,
284 * If not inflating, use the input file
289 zs
->tmpfil
= zs
->OpenFile
;
291 /* Get the uncompressed file size */
292 fseek(zs
->tmpfil
, 0, SEEK_END
);
293 zs
->usiz
= ftell(zs
->tmpfil
);
294 zs
->outinf
= zs
->usiz
;
296 /* Start at the beginning */
297 fseek(zs
->tmpfil
, 0, SEEK_SET
);
300 /* If there's no file open, see if it's big enough for temp file */
303 if (zs
->usiz
>= BUFFERTHRESHOLD
)
304 zs
->tmpfil
= tmpfile();
307 /* If there's no file open, then use memory buffering */
312 for (i
=0; i
<PTRBUFSIZE
; i
++)
313 zs
->ptrbuf
[i
] = NULL
;
317 /* pump data till length bytes of file are inflated or error encountered */
318 static int BufferPump(struct ZipioState
*zs
, long length
)
322 /* Check to see if the length is valid */
323 if (length
> zs
->usiz
) return TRUE
;
325 /* Loop till enough data is pumped */
326 while (!zs
->errorencountered
&& (zs
->outinf
< length
))
328 /* Compute how much data to read */
329 if ((zs
->csiz
- zs
->inpinf
) < INPBUFSIZE
)
330 inplen
= (size_t) (zs
->csiz
- zs
->inpinf
);
334 if (inplen
<= 0) return TRUE
;
336 /* Read some data from the file */
337 ret
= fread(zs
->inpbuf
, 1, inplen
, zs
->OpenFile
);
338 if (ret
!= inplen
) return TRUE
;
340 /* Update how much data has been read from the file */
341 zs
->inpinf
+= inplen
;
343 /* Pump this data into the decompressor */
344 if (InflatePutBuffer(zs
->inflatestate
, zs
->inpbuf
, inplen
)) return TRUE
;
350 /* Read from the buffer */
351 static int BufferRead(
352 struct ZipioState
*zs
,
354 unsigned char *buffer
,
359 * Make sure enough bytes have been inflated
360 * Note that the correction for reading past EOF has to
361 * be done before calling this routine
364 if (BufferPump(zs
, offset
+length
)) return TRUE
;
366 /* If using file buffering, just get the data from the file */
369 if (fseek(zs
->tmpfil
, offset
, SEEK_SET
)) return TRUE
;
370 if (fread(buffer
, 1, (size_t) length
, zs
->tmpfil
) != length
) return TRUE
;
372 /* If no temp file, use memory buffering */
376 unsigned int off
, len
;
380 unsigned char *tmpbuf
;
383 /* Save copies of offset, buffer and length for the loop */
388 /* Validate the transfer */
389 if (tmpoff
+tmplen
> MAXFILESIZE
) return TRUE
;
394 /* Get a pointer to the next block */
395 i
= (unsigned int) (tmpoff
/ OUTBUFSIZE
);
397 if (!ptr
) return TRUE
;
399 /* Get the offset,length for this block */
400 off
= (unsigned int) (tmpoff
& (OUTBUFSIZE
-1));
401 len
= OUTBUFSIZE
- off
;
402 if (len
> tmplen
) len
= (unsigned int) tmplen
;
404 /* Get the starting pointer for the transfer */
407 /* Copy the data for this block */
409 memcpy(tmpbuf
, ptr
, len
);
411 for (i
=0; i
<len
; i
++)
415 /* Update the offset, buffer, and length */
426 /* Append to the buffer */
427 static int BufferAppend(
428 struct ZipioState
*zs
,
429 unsigned char *buffer
,
433 /* If using file buffering, just append the data from the file */
436 if (fseek(zs
->tmpfil
, zs
->outinf
, SEEK_SET
)) return TRUE
;
437 if (fwrite(buffer
, 1, (size_t) length
, zs
->tmpfil
) != length
) return TRUE
;
439 /* If no temp file, use memory buffering */
443 unsigned int off
, len
;
447 unsigned char *tmpbuf
;
450 /* Save copies of outinf, buffer and length for the loop */
455 /* Validate the transfer */
456 if (tmpoff
+tmplen
> MAXFILESIZE
) return TRUE
;
461 /* Get a pointer to the next block */
462 i
= (unsigned int) (tmpoff
/ OUTBUFSIZE
);
466 ptr
= (unsigned char *) malloc(OUTBUFSIZE
);
467 if (!ptr
) return TRUE
;
471 /* Get the offset,length for this block */
472 off
= (unsigned int) (tmpoff
& (OUTBUFSIZE
-1));
473 len
= OUTBUFSIZE
- off
;
474 if (len
> tmplen
) len
= (unsigned int) tmplen
;
476 /* Get the starting pointer for the transfer */
479 /* Copy the data for this block */
481 memcpy(ptr
, tmpbuf
, len
);
483 for (i
=0; i
<len
; i
++)
487 /* Update the offset, buffer, and length */
494 /* Update the output buffer length */
495 zs
->outinf
+= length
;
501 /* Terminate buffering */
502 static void BufferTerminate(
503 struct ZipioState
*zs
506 /* If reading directly from the uncompressed file, just mark with NULL */
507 if (zs
->tmpfil
== zs
->OpenFile
)
511 /* If using the a temporary file, close it */
517 /* If doing memory buffering, free the buffers */
522 for (i
=0; i
<PTRBUFSIZE
; i
++)
523 if (zs
->ptrbuf
[i
]) free(zs
->ptrbuf
[i
]);
528 * callout routines for InflateInitialize
531 static int inflate_putbuffer( /* returns 0 on success */
532 void *stream
, /* opaque ptr from Initialize */
533 unsigned char *buffer
, /* buffer to put */
534 long length
/* length of buffer */
539 /* If the write will go past the end of file, return an error */
540 if (ZS
->outinf
+ length
> ZS
->usiz
) return TRUE
;
543 ZS
->filecrc
= CrcUpdate(ZS
->filecrc
, buffer
, length
);
545 /* Append to the buffer */
546 if (BufferAppend(ZS
, buffer
, length
)) return TRUE
;
552 static void *inflate_malloc(long length
)
554 return malloc((size_t) length
);
557 static void inflate_free(void *buffer
)
562 ZFILE
*Zopen(const char *path
, const char *mode
)
564 struct ZipioState
*zs
;
568 /* Allocate the ZipioState memory area */
569 zs
= (struct ZipioState
*) malloc(sizeof(struct ZipioState
));
570 if (!zs
) return NULL
;
572 /* Set up the initial values of the inflate state */
578 zs
->errorencountered
= FALSE
;
583 zs
->fileposition
= 0;
585 zs
->filecrc
= 0xffffffffL
;
587 /* Open the real file */
588 zs
->OpenFile
= fopen(path
, mode
);
595 /* Read the first input buffer */
596 if ((inplen
= (long) fread(zs
->inpbuf
, 1, INPBUFSIZE
, zs
->OpenFile
)) >= 30)
598 GETUINT4(zs
->inpbuf
+ 0, zs
->sign
);
599 GETUINT2(zs
->inpbuf
+ 4, zs
->vers
);
600 GETUINT2(zs
->inpbuf
+ 6, zs
->flag
);
601 GETUINT2(zs
->inpbuf
+ 8, zs
->comp
);
602 GETUINT2(zs
->inpbuf
+10, zs
->mtim
);
603 GETUINT2(zs
->inpbuf
+12, zs
->mdat
);
604 GETUINT4(zs
->inpbuf
+14, zs
->crc3
);
605 GETUINT4(zs
->inpbuf
+18, zs
->csiz
);
606 GETUINT4(zs
->inpbuf
+22, zs
->usiz
);
607 GETUINT2(zs
->inpbuf
+26, zs
->flen
);
608 GETUINT2(zs
->inpbuf
+28, zs
->elen
);
610 #ifdef PRINTZIPHEADER
611 fprintf(stderr
, "local file header signature hex %8lx\n", zs
->sign
);
612 fprintf(stderr
, "version needed to extract %8d\n" , zs
->vers
);
613 fprintf(stderr
, "general purpose bit flag hex %8x\n" , zs
->flag
);
614 fprintf(stderr
, "compression method %8d\n" , zs
->comp
);
615 fprintf(stderr
, "last mod file time %8d\n" , zs
->mtim
);
616 fprintf(stderr
, "last mod file date %8d\n" , zs
->mdat
);
617 fprintf(stderr
, "crc-32 hex %8lx\n", zs
->crc3
);
618 fprintf(stderr
, "compressed size %8ld\n", zs
->csiz
);
619 fprintf(stderr
, "uncompressed size %8ld\n", zs
->usiz
);
620 fprintf(stderr
, "filename length %8d\n" , zs
->flen
);
621 fprintf(stderr
, "extra field length %8d\n" , zs
->elen
);
630 * If the file isn't a zip file, set up to read it normally
632 if ((zs
->sign
!= ZIPSIGNATURE
) ||
635 (inplen
<= 30 + zs
->flen
+ zs
->elen
) )
637 /* Initialize buffering */
638 BufferInitialize(zs
, FALSE
);
640 zs
->inflatestate
= NULL
;
644 /* Initialize buffering */
645 BufferInitialize(zs
, TRUE
);
647 zs
->inflatestate
= InflateInitialize(
654 if (InflatePutBuffer(zs
->inflatestate
,
655 zs
->inpbuf
+30+zs
->flen
+zs
->elen
,
656 inplen
-30-zs
->flen
-zs
->elen
659 zs
->errorencountered
= TRUE
;
661 zs
->inpinf
+= inplen
-30-zs
->flen
-zs
->elen
;
664 /* Return this state info to the caller */
668 int _Zgetc(ZFILE
*stream
)
676 if (ZS
->errorencountered
) return -1;
680 /* If already at EOF, return */
681 if (ZS
->fileposition
>= ZS
->usiz
) return -1;
683 /* If data isn't in current outbuf, get it */
684 offset
= ZS
->fileposition
& ~((long) (OUTBUFSIZE
-1));
685 length
= ZS
->usiz
- offset
;
686 if (length
> OUTBUFSIZE
) length
= OUTBUFSIZE
;
688 if (ZS
->getoff
!= offset
)
690 if (BufferRead(ZS
, offset
, ZS
->getbuf
, length
)) return -1;
695 /* Set up the cache */
696 off
= (int) (ZS
->fileposition
& (OUTBUFSIZE
-1));
697 ZS
->len
= (int) (length
- off
);
698 ZS
->ptr
= ZS
->getbuf
+ off
;
700 /* Return the character */
705 size_t Zread(void *ptr
, size_t size
, size_t n
, ZFILE
*stream
)
711 if (ZS
->errorencountered
) return 0;
715 /* Compute the length requested */
716 length
= size
* (long) n
;
718 /* Adjust the length to account for premature EOF */
719 if (ZS
->fileposition
+length
> ZS
->usiz
)
720 length
= ZS
->usiz
- ZS
->fileposition
;
722 /* If the length is zero, then just return an EOF error */
723 if (length
<= 0) return 0;
725 /* Make the length a multiple of size */
729 /* If the length is zero, then just return an EOF error */
730 if (length
<= 0) return 0;
732 /* Read from the buffer */
733 if (BufferRead(ZS
, ZS
->fileposition
, (unsigned char *) ptr
, length
))
736 /* Update the file position */
737 ZS
->fileposition
+= length
;
739 /* Return the number of items transferred */
740 return (size_t) (length
/ size
);
743 int Zseek(ZFILE
*stream
, long offset
, int whence
)
749 if (ZS
->errorencountered
) return -1;
753 if (whence
== SEEK_SET
)
757 else if (whence
== SEEK_CUR
)
759 newoffset
= ZS
->fileposition
+ offset
;
761 else if (whence
== SEEK_END
)
763 newoffset
= ZS
->fileposition
+ ZS
->usiz
;
770 if ((newoffset
< 0) || (newoffset
> ZS
->usiz
)) return -1;
772 ZS
->fileposition
= newoffset
;
777 long Ztell(ZFILE
*stream
)
781 if (ZS
->errorencountered
) return -1;
785 return ZS
->fileposition
;
788 int Zclose(ZFILE
*stream
)
796 /* terminate the inflate routines, and check for errors */
797 if (ZS
->inflatestate
)
799 if (InflateTerminate(ZS
->inflatestate
))
800 ZS
->errorencountered
= TRUE
;
802 /* Check that the CRC is OK */
803 if (ZS
->filecrc
!= (ZS
->crc3
^ 0xffffffffL
))
804 ZS
->errorencountered
= TRUE
;
807 /* save the final error status */
808 ret
= ZS
->errorencountered
;
810 /* terminate the buffering */
813 /* free the ZipioState structure */
816 /* return the final error status */