Provide missing "AlmanacInterfaceTransactionQuery"
[phabricator.git] / externals / figlet / zipio.c
blobf7406d952a3e6d90176428af1cbbef2c4dbaf013
1 /*
2 * zipio.c - stdio emulation library for reading zip files
4 * Version 1.1.2
5 */
7 /*
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
26 * OF THIS SOFTWARE.
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
51 * method is 8).
53 * The crc-32 field is the crc on the uncompressed data.
55 * .zip file header:
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
63 * crc-32 4 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.
76 #include <stdlib.h>
77 #ifdef MEMCPY
78 #include <mem.h>
79 #endif
81 #include "zipio.h"
82 #include "inflate.h"
83 #include "crc.h"
86 * Macros for constants
89 #ifndef NULL
90 #define NULL ((void *) 0)
91 #endif
93 #ifndef TRUE
94 #define TRUE 1
95 #endif
97 #ifndef FALSE
98 #define FALSE 0
99 #endif
101 #ifndef ZIPSIGNATURE
102 #define ZIPSIGNATURE 0x04034b50L
103 #endif
105 #ifndef SEEK_SET
106 #define SEEK_SET 0
107 #endif
109 #ifndef SEEK_CUR
110 #define SEEK_CUR 1
111 #endif
113 #ifndef SEEK_END
114 #define SEEK_END 2
115 #endif
119 * Buffer size macros
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.
128 * Assumptions:
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)
141 #endif
143 #ifndef INPBUFSIZE
144 #define INPBUFSIZE ( 8 * 1024 )
145 #endif
147 #ifndef PTRBUFSIZE
148 #define PTRBUFSIZE ( 2 * 1024 )
149 #endif
151 #ifndef OUTBUFSIZE
152 #define OUTBUFSIZE ((unsigned int) ( 32 * 1024L))
153 #endif
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
167 #define CACHEINIT \
168 zs->ptr = NULL; \
169 zs->len = 0;
171 #define CACHEUPDATE \
172 if (ZS->ptr) \
174 ZS->fileposition &= ~((long) (OUTBUFSIZE-1)); \
175 ZS->fileposition += ZS->ptr - ZS->getbuf; \
176 ZS->ptr = NULL; \
178 ZS->len = 0;
181 * Macros for run-time type identification
184 #ifndef RUNTIMEENABLE
185 #define RUNTIMEENABLE 0
186 #endif
188 #if RUNTIMEENABLE
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;
197 #else
198 #define RUNTIMEINIT
199 #define RUNTIMECHECK
200 #endif
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 */
221 struct ZipioState {
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,
277 int doinflate
280 zs->getoff = -1;
281 zs->tmpfil = NULL;
284 * If not inflating, use the input file
287 if (!doinflate)
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 */
301 if (!zs->tmpfil)
303 if (zs->usiz >= BUFFERTHRESHOLD)
304 zs->tmpfil = tmpfile();
307 /* If there's no file open, then use memory buffering */
308 if (!zs->tmpfil)
310 int i;
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)
320 size_t inplen, ret;
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);
331 else
332 inplen = INPBUFSIZE;
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;
347 return FALSE;
350 /* Read from the buffer */
351 static int BufferRead(
352 struct ZipioState *zs,
353 long offset,
354 unsigned char *buffer,
355 long length
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 */
367 if (zs->tmpfil)
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 */
373 else
375 unsigned int i;
376 unsigned int off, len;
377 unsigned char *ptr;
379 long tmpoff;
380 unsigned char *tmpbuf;
381 long tmplen;
383 /* Save copies of offset, buffer and length for the loop */
384 tmpoff = offset;
385 tmpbuf = buffer;
386 tmplen = length;
388 /* Validate the transfer */
389 if (tmpoff+tmplen > MAXFILESIZE) return TRUE;
391 /* Loop till done */
392 while (tmplen)
394 /* Get a pointer to the next block */
395 i = (unsigned int) (tmpoff / OUTBUFSIZE);
396 ptr = zs->ptrbuf[i];
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 */
405 ptr += off;
407 /* Copy the data for this block */
408 #ifdef MEMCPY
409 memcpy(tmpbuf, ptr, len);
410 #else
411 for (i=0; i<len; i++)
412 tmpbuf[i] = ptr[i];
413 #endif
415 /* Update the offset, buffer, and length */
416 tmpoff += len;
417 tmpbuf += len;
418 tmplen -= len;
422 /* return success */
423 return FALSE;
426 /* Append to the buffer */
427 static int BufferAppend(
428 struct ZipioState *zs,
429 unsigned char *buffer,
430 long length
433 /* If using file buffering, just append the data from the file */
434 if (zs->tmpfil)
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 */
440 else
442 unsigned int i;
443 unsigned int off, len;
444 unsigned char *ptr;
446 long tmpoff;
447 unsigned char *tmpbuf;
448 long tmplen;
450 /* Save copies of outinf, buffer and length for the loop */
451 tmpoff = zs->outinf;
452 tmpbuf = buffer;
453 tmplen = length;
455 /* Validate the transfer */
456 if (tmpoff+tmplen > MAXFILESIZE) return TRUE;
458 /* Loop till done */
459 while (tmplen)
461 /* Get a pointer to the next block */
462 i = (unsigned int) (tmpoff / OUTBUFSIZE);
463 ptr = zs->ptrbuf[i];
464 if (!ptr)
466 ptr = (unsigned char *) malloc(OUTBUFSIZE);
467 if (!ptr) return TRUE;
468 zs->ptrbuf[i] = ptr;
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 */
477 ptr += off;
479 /* Copy the data for this block */
480 #ifdef MEMCPY
481 memcpy(ptr, tmpbuf, len);
482 #else
483 for (i=0; i<len; i++)
484 ptr[i] = tmpbuf[i];
485 #endif
487 /* Update the offset, buffer, and length */
488 tmpoff += len;
489 tmpbuf += len;
490 tmplen -= len;
494 /* Update the output buffer length */
495 zs->outinf += length;
497 /* return success */
498 return FALSE;
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)
509 zs->tmpfil = NULL;
511 /* If using the a temporary file, close it */
512 else if (zs->tmpfil)
514 fclose(zs->tmpfil);
515 zs->tmpfil = NULL;
517 /* If doing memory buffering, free the buffers */
518 else
520 int i;
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 */
537 RUNTIMECHECK;
539 /* If the write will go past the end of file, return an error */
540 if (ZS->outinf + length > ZS->usiz) return TRUE;
542 /* Update the CRC */
543 ZS->filecrc = CrcUpdate(ZS->filecrc, buffer, length);
545 /* Append to the buffer */
546 if (BufferAppend(ZS, buffer, length)) return TRUE;
548 /* Return success */
549 return FALSE;
552 static void *inflate_malloc(long length)
554 return malloc((size_t) length);
557 static void inflate_free(void *buffer)
559 free(buffer);
562 ZFILE *Zopen(const char *path, const char *mode)
564 struct ZipioState *zs;
566 long inplen;
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 */
574 CACHEINIT;
576 RUNTIMEINIT;
578 zs->errorencountered = FALSE;
580 zs->inpinf = 0;
581 zs->outinf = 0;
583 zs->fileposition = 0;
585 zs->filecrc = 0xffffffffL;
587 /* Open the real file */
588 zs->OpenFile = fopen(path, mode);
589 if (!zs->OpenFile)
591 free(zs);
592 return NULL;
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);
622 #endif
624 else
626 zs->sign = 0;
630 * If the file isn't a zip file, set up to read it normally
632 if ((zs->sign != ZIPSIGNATURE) ||
633 (zs->flag & 1) ||
634 (zs->comp != 8) ||
635 (inplen <= 30 + zs->flen + zs->elen) )
637 /* Initialize buffering */
638 BufferInitialize(zs, FALSE);
640 zs->inflatestate = NULL;
642 else
644 /* Initialize buffering */
645 BufferInitialize(zs, TRUE);
647 zs->inflatestate = InflateInitialize(
648 (void *) zs,
649 inflate_putbuffer,
650 inflate_malloc,
651 inflate_free
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 */
665 return (ZFILE *) zs;
668 int _Zgetc(ZFILE *stream)
670 long offset, length;
672 int off;
674 RUNTIMECHECK;
676 if (ZS->errorencountered) return -1;
678 CACHEUPDATE;
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;
692 ZS->getoff = offset;
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 */
701 ZS->len--;
702 return *(ZS->ptr++);
705 size_t Zread(void *ptr, size_t size, size_t n, ZFILE *stream)
707 long length;
709 RUNTIMECHECK;
711 if (ZS->errorencountered) return 0;
713 CACHEUPDATE;
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 */
726 length /= size;
727 length *= 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))
734 return 0;
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)
745 long newoffset;
747 RUNTIMECHECK;
749 if (ZS->errorencountered) return -1;
751 CACHEUPDATE;
753 if (whence == SEEK_SET)
755 newoffset = offset;
757 else if (whence == SEEK_CUR)
759 newoffset = ZS->fileposition + offset;
761 else if (whence == SEEK_END)
763 newoffset = ZS->fileposition + ZS->usiz;
765 else
767 return -1;
770 if ((newoffset < 0) || (newoffset > ZS->usiz)) return -1;
772 ZS->fileposition = newoffset;
774 return 0;
777 long Ztell(ZFILE *stream)
779 RUNTIMECHECK;
781 if (ZS->errorencountered) return -1;
783 CACHEUPDATE;
785 return ZS->fileposition;
788 int Zclose(ZFILE *stream)
790 int ret;
792 RUNTIMECHECK;
794 CACHEUPDATE;
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 */
811 BufferTerminate(ZS);
813 /* free the ZipioState structure */
814 free(ZS);
816 /* return the final error status */
817 return ret;