 935ced1edd
			
		
	
	935ced1edd
	
	
	
		
			
			Summary: Ref T7785. This prepares for (but does not yet use) a pure PHP implementation of Figlet parsing and rendering. Figlet is somewhat complex, but a parser already exists in PEAR. I'll make sure it's suitable and hook it up in the next diff. Test Plan: N/A, code not reachable Reviewers: chad Reviewed By: chad Maniphest Tasks: T9408, T7785 Differential Revision: https://secure.phabricator.com/D14101
		
			
				
	
	
		
			819 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			819 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * zipio.c - stdio emulation library for reading zip files
 | |
|  *
 | |
|  * Version 1.1.2
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Copyright (C) 1995, Edward B. Hamrick
 | |
|  *
 | |
|  * Permission to use, copy, modify, and distribute this software and
 | |
|  * its documentation for any purpose and without fee is hereby granted,
 | |
|  * provided that the above copyright notice appear in all copies and
 | |
|  * that both that copyright notice and this permission notice appear in
 | |
|  * supporting documentation, and that the name of the copyright holders
 | |
|  * not be used in advertising or publicity pertaining to distribution of
 | |
|  * the software without specific, written prior permission. The copyright
 | |
|  * holders makes no representations about the suitability of this software
 | |
|  * for any purpose. It is provided "as is" without express or implied warranty.
 | |
|  *
 | |
|  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | |
|  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
 | |
|  * IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT
 | |
|  * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 | |
|  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | |
|  * OF THIS SOFTWARE.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Changes from 1.1 to 1.1.1:
 | |
|  * Changed "z*" functions to "Z*" to avoid namespace pollution.
 | |
|  * Added "zungetc" macro.
 | |
|  * Added definitions of SEEK_SET, SEEK_CUR, SEEK_END for the Posixly challenged
 | |
|  * John Cowan <cowan@ccil.org>
 | |
|  *
 | |
|  * Changes from 1.1.1 to 1.1.2:
 | |
|  * Relicensed under the MIT license, with consent of the copyright holders.
 | |
|  * Avoid usage of unitialized "length" variable in _Zgetc
 | |
|  * Claudio Matsuoka (Jan 11 2011)
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Refer to zipio.h for a description of this package.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * The .zip file header is described below.  It consists of
 | |
|  * 30 fixed bytes, followed by two variable length fields
 | |
|  * whose length is contained in the first 30 bytes.  After this
 | |
|  * header, the data is stored (in deflate format if the compression
 | |
|  * method is 8).
 | |
|  *
 | |
|  * The crc-32 field is the crc on the uncompressed data.
 | |
|  *
 | |
|  * .zip file header:
 | |
|  *
 | |
|  *      local file header signature     4 bytes  (0x04034b50)
 | |
|  *      version needed to extract       2 bytes
 | |
|  *      general purpose bit flag        2 bytes
 | |
|  *      compression method              2 bytes
 | |
|  *      last mod file time              2 bytes
 | |
|  *      last mod file date              2 bytes
 | |
|  *      crc-32                          4 bytes
 | |
|  *      compressed size                 4 bytes
 | |
|  *      uncompressed size               4 bytes
 | |
|  *      filename length                 2 bytes
 | |
|  *      extra field length              2 bytes
 | |
|  *
 | |
|  *      filename (variable size)
 | |
|  *      extra field (variable size)
 | |
|  *
 | |
|  * These fields are described in more detail in appnote.txt
 | |
|  * in the pkzip 1.93 distribution.
 | |
|  */
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #ifdef MEMCPY
 | |
| #include <mem.h>
 | |
| #endif
 | |
| 
 | |
| #include "zipio.h"
 | |
| #include "inflate.h"
 | |
| #include "crc.h"
 | |
| 
 | |
| /*
 | |
|  * Macros for constants
 | |
|  */
 | |
| 
 | |
| #ifndef NULL
 | |
| #define NULL ((void *) 0)
 | |
| #endif
 | |
| 
 | |
| #ifndef TRUE
 | |
| #define TRUE 1
 | |
| #endif
 | |
| 
 | |
| #ifndef FALSE
 | |
| #define FALSE 0
 | |
| #endif
 | |
| 
 | |
| #ifndef ZIPSIGNATURE
 | |
| #define ZIPSIGNATURE     0x04034b50L
 | |
| #endif
 | |
| 
 | |
| #ifndef SEEK_SET
 | |
| #define SEEK_SET	0
 | |
| #endif
 | |
| 
 | |
| #ifndef SEEK_CUR
 | |
| #define SEEK_CUR	1
 | |
| #endif
 | |
| 
 | |
| #ifndef SEEK_END
 | |
| #define SEEK_END	2
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /* 
 | |
|  * Buffer size macros
 | |
|  *
 | |
|  * The following constants are optimized for large-model
 | |
|  * (but not flat model) Windows with virtual memory.  It 
 | |
|  * will work fine on unix and flat model Windows as well.  
 | |
|  *
 | |
|  * The constant BUFFERTHRESHOLD determines when memory
 | |
|  * buffering changes to file buffering.
 | |
|  *
 | |
|  * Assumptions:
 | |
|  *
 | |
|  *   1) INPBUFSIZE + OUTBUFSIZE + sizeof(void *) * PTRBUFSIZE + delta < 64K
 | |
|  *
 | |
|  *   2) OUTBUFSIZE = 32K * N (related to inflate's 32K window size)
 | |
|  *
 | |
|  *   2) Max in-memory file size is OUTBUFSIZE * PTRBUFSIZE
 | |
|  *      which is 64 MBytes by default (32K * 2K).
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #ifndef BUFFERTHRESHOLD
 | |
| #define BUFFERTHRESHOLD            (256 * 1024L)
 | |
| #endif
 | |
| 
 | |
| #ifndef INPBUFSIZE
 | |
| #define INPBUFSIZE                 (  8 * 1024 )
 | |
| #endif
 | |
| 
 | |
| #ifndef PTRBUFSIZE
 | |
| #define PTRBUFSIZE                 (  2 * 1024 )
 | |
| #endif
 | |
| 
 | |
| #ifndef OUTBUFSIZE
 | |
| #define OUTBUFSIZE ((unsigned int) ( 32 * 1024L))
 | |
| #endif
 | |
| 
 | |
| #define MAXFILESIZE (OUTBUFSIZE * (long) PTRBUFSIZE)
 | |
| 
 | |
| /*
 | |
|  * Macro for short-hand reference to ZipioState (from ZFILE *)
 | |
|  */
 | |
| 
 | |
| #define ZS ((struct ZipioState *) stream)
 | |
| 
 | |
| /*
 | |
|  * Macro to manipulate Zgetc() cache
 | |
|  */
 | |
| 
 | |
| #define CACHEINIT                                 \
 | |
|   zs->ptr = NULL;                                 \
 | |
|   zs->len = 0;
 | |
| 
 | |
| #define CACHEUPDATE                               \
 | |
|   if (ZS->ptr)                                    \
 | |
|   {                                               \
 | |
|     ZS->fileposition &= ~((long) (OUTBUFSIZE-1)); \
 | |
|     ZS->fileposition += ZS->ptr - ZS->getbuf;     \
 | |
|     ZS->ptr = NULL;                               \
 | |
|   }                                               \
 | |
|   ZS->len = 0;
 | |
| 
 | |
| /*
 | |
|  * Macros for run-time type identification
 | |
|  */
 | |
| 
 | |
| #ifndef RUNTIMEENABLE
 | |
| #define RUNTIMEENABLE 0
 | |
| #endif
 | |
| 
 | |
| #if RUNTIMEENABLE
 | |
| #define ZIPIOSTATETYPE   0x0110f00fL
 | |
| #define RUNTIMEINIT                                             \
 | |
|   zs->runtimetypeid1   = ZIPIOSTATETYPE;                        \
 | |
|   zs->runtimetypeid2   = ZIPIOSTATETYPE;
 | |
| 
 | |
| #define RUNTIMECHECK                                            \
 | |
|   if (!ZS || (ZS->runtimetypeid1 != ZIPIOSTATETYPE)             \
 | |
|           || (ZS->runtimetypeid2 != ZIPIOSTATETYPE)) return -1;
 | |
| #else
 | |
| #define RUNTIMEINIT
 | |
| #define RUNTIMECHECK
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * Macros for converting bytes to unsigned integers
 | |
|  */
 | |
| 
 | |
| #define GETUINT4(ptr, i4)                                               \
 | |
|   {                                                                     \
 | |
|     i4 = (((unsigned long) *(((unsigned char *) (ptr)) + 0))      ) |   \
 | |
|          (((unsigned long) *(((unsigned char *) (ptr)) + 1)) <<  8) |   \
 | |
|          (((unsigned long) *(((unsigned char *) (ptr)) + 2)) << 16) |   \
 | |
|          (((unsigned long) *(((unsigned char *) (ptr)) + 3)) << 24)   ; \
 | |
|   }
 | |
| 
 | |
| #define GETUINT2(ptr, i2)                                               \
 | |
|   {                                                                     \
 | |
|     i2 = (((unsigned  int) *(((unsigned char *) (ptr)) + 0))      ) |   \
 | |
|          (((unsigned  int) *(((unsigned char *) (ptr)) + 1)) <<  8)   ; \
 | |
|   }
 | |
| 
 | |
| /* Structure to hold state for decoding zip files */
 | |
| struct ZipioState {
 | |
| 
 | |
|   /* Fields overlaid with ZFILE structure */
 | |
|   int            len;                        /* length of Zgetc cache      */
 | |
|   unsigned char *ptr;                        /* pointer to Zgetc cache     */
 | |
| 
 | |
|   /* Fields invisible to users of ZFILE structure */
 | |
| 
 | |
|   unsigned long  runtimetypeid1;             /* to detect run-time errors  */
 | |
|   int            errorencountered;           /* error encountered flag     */
 | |
| 
 | |
|   /* Buffering state */
 | |
|   unsigned char  inpbuf[INPBUFSIZE];         /* inp buffer from zip file   */
 | |
|   unsigned char *ptrbuf[PTRBUFSIZE];         /* pointers to in-memory bufs */
 | |
| 
 | |
|   unsigned char  getbuf[OUTBUFSIZE];         /* buffer for use by Zgetc    */
 | |
|   long           getoff;                     /* starting offset of getbuf  */
 | |
| 
 | |
|   FILE          *tmpfil;                     /* file ptr to temp file      */
 | |
| 
 | |
|   /* Amount of input data inflated */
 | |
|   unsigned long  inpinf;
 | |
|   unsigned long  outinf;
 | |
| 
 | |
|   /* Zip file header */
 | |
|   unsigned long  sign;     /* local file header signature (0x04034b50) */
 | |
|   unsigned int   vers;     /* version needed to extract       2 bytes  */
 | |
|   unsigned int   flag;     /* general purpose bit flag        2 bytes  */
 | |
|   unsigned int   comp;     /* compression method              2 bytes  */
 | |
|   unsigned int   mtim;     /* last mod file time              2 bytes  */
 | |
|   unsigned int   mdat;     /* last mod file date              2 bytes  */
 | |
|   unsigned long  crc3;     /* crc-32                          4 bytes  */
 | |
|   unsigned long  csiz;     /* compressed size                 4 bytes  */
 | |
|   unsigned long  usiz;     /* uncompressed size               4 bytes  */
 | |
|   unsigned int   flen;     /* filename length                 2 bytes  */
 | |
|   unsigned int   elen;     /* extra field length              2 bytes  */
 | |
| 
 | |
|   /* Application state */
 | |
|   FILE          *OpenFile;                   /* currently open file        */
 | |
| 
 | |
|   void          *inflatestate;               /* current state for inflate  */
 | |
| 
 | |
|   unsigned long  fileposition;               /* current file position      */
 | |
| 
 | |
|   unsigned long  filecrc;                    /* current crc                */
 | |
| 
 | |
|   unsigned long  runtimetypeid2;             /* to detect run-time errors  */
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Utility routines to handle uncompressed file buffers
 | |
|  */
 | |
| 
 | |
| /* Initialize buffering */
 | |
| static void BufferInitialize(
 | |
|   struct ZipioState *zs,
 | |
|   int doinflate
 | |
| )
 | |
| {
 | |
|   zs->getoff = -1;
 | |
|   zs->tmpfil = NULL;
 | |
| 
 | |
|   /*
 | |
|    * If not inflating, use the input file
 | |
|    */
 | |
| 
 | |
|   if (!doinflate)
 | |
|   {
 | |
|     zs->tmpfil = zs->OpenFile;
 | |
| 
 | |
|     /* Get the uncompressed file size */
 | |
|     fseek(zs->tmpfil, 0, SEEK_END);
 | |
|     zs->usiz = ftell(zs->tmpfil);
 | |
|     zs->outinf = zs->usiz;
 | |
| 
 | |
|     /* Start at the beginning */
 | |
|     fseek(zs->tmpfil, 0, SEEK_SET);
 | |
|   }
 | |
| 
 | |
|   /* If there's no file open, see if it's big enough for temp file */
 | |
|   if (!zs->tmpfil)
 | |
|   {
 | |
|     if (zs->usiz >= BUFFERTHRESHOLD)
 | |
|       zs->tmpfil = tmpfile();
 | |
|   }
 | |
| 
 | |
|   /* If there's no file open, then use memory buffering */
 | |
|   if (!zs->tmpfil)
 | |
|   {
 | |
|     int i;
 | |
| 
 | |
|     for (i=0; i<PTRBUFSIZE; i++)
 | |
|       zs->ptrbuf[i] = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* pump data till length bytes of file are inflated or error encountered */
 | |
| static int BufferPump(struct ZipioState *zs, long length)
 | |
| {
 | |
|   size_t inplen, ret;
 | |
| 
 | |
|   /* Check to see if the length is valid */
 | |
|   if (length > zs->usiz) return TRUE;
 | |
| 
 | |
|   /* Loop till enough data is pumped */
 | |
|   while (!zs->errorencountered && (zs->outinf < length))
 | |
|   {
 | |
|     /* Compute how much data to read */
 | |
|     if ((zs->csiz - zs->inpinf) < INPBUFSIZE)
 | |
|       inplen = (size_t) (zs->csiz - zs->inpinf);
 | |
|     else
 | |
|       inplen = INPBUFSIZE;
 | |
| 
 | |
|     if (inplen <= 0) return TRUE;
 | |
| 
 | |
|     /* Read some data from the file */
 | |
|     ret = fread(zs->inpbuf, 1, inplen, zs->OpenFile);
 | |
|     if (ret != inplen) return TRUE;
 | |
| 
 | |
|     /* Update how much data has been read from the file */
 | |
|     zs->inpinf += inplen;
 | |
| 
 | |
|     /* Pump this data into the decompressor */
 | |
|     if (InflatePutBuffer(zs->inflatestate, zs->inpbuf, inplen)) return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* Read from the buffer */
 | |
| static int BufferRead(
 | |
|   struct ZipioState *zs,
 | |
|   long offset,
 | |
|   unsigned char *buffer,
 | |
|   long length
 | |
| )
 | |
| {
 | |
|   /*
 | |
|    * Make sure enough bytes have been inflated
 | |
|    * Note that the correction for reading past EOF has to
 | |
|    * be done before calling this routine
 | |
|    */
 | |
| 
 | |
|   if (BufferPump(zs, offset+length)) return TRUE;
 | |
| 
 | |
|   /* If using file buffering, just get the data from the file */
 | |
|   if (zs->tmpfil)
 | |
|   {
 | |
|     if (fseek(zs->tmpfil, offset, SEEK_SET)) return TRUE;
 | |
|     if (fread(buffer, 1, (size_t) length, zs->tmpfil) != length) return TRUE;
 | |
|   }
 | |
|   /* If no temp file, use memory buffering */
 | |
|   else
 | |
|   {
 | |
|     unsigned int i;
 | |
|     unsigned int off, len;
 | |
|     unsigned char *ptr;
 | |
| 
 | |
|     long           tmpoff;
 | |
|     unsigned char *tmpbuf;
 | |
|     long           tmplen;
 | |
| 
 | |
|     /* Save copies of offset, buffer and length for the loop */
 | |
|     tmpoff = offset;
 | |
|     tmpbuf = buffer;
 | |
|     tmplen = length;
 | |
| 
 | |
|     /* Validate the transfer */
 | |
|     if (tmpoff+tmplen > MAXFILESIZE) return TRUE;
 | |
| 
 | |
|     /* Loop till done */
 | |
|     while (tmplen)
 | |
|     {
 | |
|       /* Get a pointer to the next block */
 | |
|       i = (unsigned int) (tmpoff / OUTBUFSIZE);
 | |
|       ptr = zs->ptrbuf[i];
 | |
|       if (!ptr) return TRUE;
 | |
| 
 | |
|       /* Get the offset,length for this block */
 | |
|       off = (unsigned int) (tmpoff & (OUTBUFSIZE-1));
 | |
|       len = OUTBUFSIZE - off;
 | |
|       if (len > tmplen) len = (unsigned int) tmplen;
 | |
| 
 | |
|       /* Get the starting pointer for the transfer */
 | |
|       ptr += off;
 | |
| 
 | |
|       /* Copy the data for this block */
 | |
| #ifdef MEMCPY
 | |
|       memcpy(tmpbuf, ptr, len);
 | |
| #else
 | |
|       for (i=0; i<len; i++)
 | |
|         tmpbuf[i] = ptr[i];
 | |
| #endif
 | |
| 
 | |
|       /* Update the offset, buffer, and length */
 | |
|       tmpoff += len;
 | |
|       tmpbuf += len;
 | |
|       tmplen -= len;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* return success */
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* Append to the buffer */
 | |
| static int BufferAppend(
 | |
|   struct ZipioState *zs,
 | |
|   unsigned char *buffer,
 | |
|   long length
 | |
| )
 | |
| {
 | |
|   /* If using file buffering, just append the data from the file */
 | |
|   if (zs->tmpfil)
 | |
|   {
 | |
|     if (fseek(zs->tmpfil, zs->outinf, SEEK_SET)) return TRUE;
 | |
|     if (fwrite(buffer, 1, (size_t) length, zs->tmpfil) != length) return TRUE;
 | |
|   }
 | |
|   /* If no temp file, use memory buffering */
 | |
|   else
 | |
|   {
 | |
|     unsigned int i;
 | |
|     unsigned int off, len;
 | |
|     unsigned char *ptr;
 | |
| 
 | |
|     long           tmpoff;
 | |
|     unsigned char *tmpbuf;
 | |
|     long           tmplen;
 | |
| 
 | |
|     /* Save copies of outinf, buffer and length for the loop */
 | |
|     tmpoff = zs->outinf;
 | |
|     tmpbuf = buffer;
 | |
|     tmplen = length;
 | |
| 
 | |
|     /* Validate the transfer */
 | |
|     if (tmpoff+tmplen > MAXFILESIZE) return TRUE;
 | |
| 
 | |
|     /* Loop till done */
 | |
|     while (tmplen)
 | |
|     {
 | |
|       /* Get a pointer to the next block */
 | |
|       i = (unsigned int) (tmpoff / OUTBUFSIZE);
 | |
|       ptr = zs->ptrbuf[i];
 | |
|       if (!ptr)
 | |
|       {
 | |
|         ptr = (unsigned char *) malloc(OUTBUFSIZE);
 | |
|         if (!ptr) return TRUE;
 | |
|         zs->ptrbuf[i] = ptr;
 | |
|       }
 | |
| 
 | |
|       /* Get the offset,length for this block */
 | |
|       off = (unsigned int) (tmpoff & (OUTBUFSIZE-1));
 | |
|       len = OUTBUFSIZE - off;
 | |
|       if (len > tmplen) len = (unsigned int) tmplen;
 | |
| 
 | |
|       /* Get the starting pointer for the transfer */
 | |
|       ptr += off;
 | |
| 
 | |
|       /* Copy the data for this block */
 | |
| #ifdef MEMCPY
 | |
|       memcpy(ptr, tmpbuf, len);
 | |
| #else
 | |
|       for (i=0; i<len; i++)
 | |
|         ptr[i] = tmpbuf[i];
 | |
| #endif
 | |
| 
 | |
|       /* Update the offset, buffer, and length */
 | |
|       tmpoff += len;
 | |
|       tmpbuf += len;
 | |
|       tmplen -= len;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Update the output buffer length */
 | |
|   zs->outinf += length;
 | |
| 
 | |
|   /* return success */
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* Terminate buffering */
 | |
| static void BufferTerminate(
 | |
|   struct ZipioState *zs
 | |
| )
 | |
| {
 | |
|   /* If reading directly from the uncompressed file, just mark with NULL */
 | |
|   if (zs->tmpfil == zs->OpenFile)
 | |
|   {
 | |
|     zs->tmpfil = NULL;
 | |
|   }
 | |
|   /* If using the a temporary file, close it */
 | |
|   else if (zs->tmpfil)
 | |
|   {
 | |
|     fclose(zs->tmpfil);
 | |
|     zs->tmpfil = NULL;
 | |
|   }
 | |
|   /* If doing memory buffering, free the buffers */
 | |
|   else
 | |
|   {
 | |
|     int i;
 | |
| 
 | |
|     for (i=0; i<PTRBUFSIZE; i++)
 | |
|       if (zs->ptrbuf[i]) free(zs->ptrbuf[i]);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * callout routines for InflateInitialize
 | |
|  */
 | |
| 
 | |
| static int inflate_putbuffer(             /* returns 0 on success       */
 | |
|     void *stream,                         /* opaque ptr from Initialize */
 | |
|     unsigned char *buffer,                /* buffer to put              */
 | |
|     long length                           /* length of buffer           */
 | |
| )
 | |
| {
 | |
|   RUNTIMECHECK;
 | |
| 
 | |
|   /* If the write will go past the end of file, return an error */
 | |
|   if (ZS->outinf + length > ZS->usiz) return TRUE;
 | |
| 
 | |
|   /* Update the CRC */
 | |
|   ZS->filecrc = CrcUpdate(ZS->filecrc, buffer, length);
 | |
| 
 | |
|   /* Append to the buffer */
 | |
|   if (BufferAppend(ZS, buffer, length)) return TRUE;
 | |
| 
 | |
|   /* Return success */
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| static void *inflate_malloc(long length)
 | |
| {
 | |
|   return malloc((size_t) length);
 | |
| }
 | |
| 
 | |
| static void inflate_free(void *buffer)
 | |
| {
 | |
|   free(buffer);
 | |
| }
 | |
| 
 | |
| ZFILE *Zopen(const char *path, const char *mode)
 | |
| {
 | |
|   struct ZipioState *zs;
 | |
| 
 | |
|   long inplen;
 | |
| 
 | |
|   /* Allocate the ZipioState memory area */
 | |
|   zs = (struct ZipioState *) malloc(sizeof(struct ZipioState));
 | |
|   if (!zs) return NULL;
 | |
| 
 | |
|   /* Set up the initial values of the inflate state */
 | |
| 
 | |
|   CACHEINIT;
 | |
| 
 | |
|   RUNTIMEINIT;
 | |
| 
 | |
|   zs->errorencountered = FALSE;
 | |
| 
 | |
|   zs->inpinf           = 0;
 | |
|   zs->outinf           = 0;
 | |
| 
 | |
|   zs->fileposition     = 0;
 | |
| 
 | |
|   zs->filecrc          = 0xffffffffL;
 | |
| 
 | |
|   /* Open the real file */
 | |
|   zs->OpenFile = fopen(path, mode);
 | |
|   if (!zs->OpenFile)
 | |
|   {
 | |
|     free(zs);
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   /* Read the first input buffer */
 | |
|   if ((inplen = (long) fread(zs->inpbuf, 1, INPBUFSIZE, zs->OpenFile)) >= 30)
 | |
|   {
 | |
|     GETUINT4(zs->inpbuf+ 0, zs->sign);
 | |
|     GETUINT2(zs->inpbuf+ 4, zs->vers);
 | |
|     GETUINT2(zs->inpbuf+ 6, zs->flag);
 | |
|     GETUINT2(zs->inpbuf+ 8, zs->comp);
 | |
|     GETUINT2(zs->inpbuf+10, zs->mtim);
 | |
|     GETUINT2(zs->inpbuf+12, zs->mdat);
 | |
|     GETUINT4(zs->inpbuf+14, zs->crc3);
 | |
|     GETUINT4(zs->inpbuf+18, zs->csiz);
 | |
|     GETUINT4(zs->inpbuf+22, zs->usiz);
 | |
|     GETUINT2(zs->inpbuf+26, zs->flen);
 | |
|     GETUINT2(zs->inpbuf+28, zs->elen);
 | |
| 
 | |
| #ifdef PRINTZIPHEADER
 | |
|     fprintf(stderr, "local file header signature  hex %8lx\n", zs->sign);
 | |
|     fprintf(stderr, "version needed to extract        %8d\n" , zs->vers);
 | |
|     fprintf(stderr, "general purpose bit flag     hex %8x\n" , zs->flag);
 | |
|     fprintf(stderr, "compression method               %8d\n" , zs->comp);
 | |
|     fprintf(stderr, "last mod file time               %8d\n" , zs->mtim);
 | |
|     fprintf(stderr, "last mod file date               %8d\n" , zs->mdat);
 | |
|     fprintf(stderr, "crc-32                       hex %8lx\n", zs->crc3);
 | |
|     fprintf(stderr, "compressed size                  %8ld\n", zs->csiz);
 | |
|     fprintf(stderr, "uncompressed size                %8ld\n", zs->usiz);
 | |
|     fprintf(stderr, "filename length                  %8d\n" , zs->flen);
 | |
|     fprintf(stderr, "extra field length               %8d\n" , zs->elen);
 | |
| #endif
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     zs->sign = 0;
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|    * If the file isn't a zip file, set up to read it normally
 | |
|    */
 | |
|   if ((zs->sign   !=             ZIPSIGNATURE) ||
 | |
|       (zs->flag   &                         1) ||
 | |
|       (zs->comp   !=                        8) ||
 | |
|       (inplen     <= 30 + zs->flen + zs->elen)    )
 | |
|   {
 | |
|     /* Initialize buffering */
 | |
|     BufferInitialize(zs, FALSE);
 | |
| 
 | |
|     zs->inflatestate = NULL;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Initialize buffering */
 | |
|     BufferInitialize(zs, TRUE);
 | |
| 
 | |
|     zs->inflatestate = InflateInitialize(
 | |
|                          (void *) zs,
 | |
|                          inflate_putbuffer,
 | |
|                          inflate_malloc,
 | |
|                          inflate_free
 | |
|                        );
 | |
| 
 | |
|     if (InflatePutBuffer(zs->inflatestate,
 | |
|                          zs->inpbuf+30+zs->flen+zs->elen,
 | |
|                              inplen-30-zs->flen-zs->elen
 | |
|                         )
 | |
|        )
 | |
|       zs->errorencountered = TRUE;
 | |
| 
 | |
|     zs->inpinf += inplen-30-zs->flen-zs->elen;
 | |
|   }
 | |
| 
 | |
|   /* Return this state info to the caller */
 | |
|   return (ZFILE *) zs;
 | |
| }
 | |
| 
 | |
| int _Zgetc(ZFILE *stream)
 | |
| {
 | |
|   long offset, length;
 | |
| 
 | |
|   int off;
 | |
| 
 | |
|   RUNTIMECHECK;
 | |
| 
 | |
|   if (ZS->errorencountered) return -1;
 | |
| 
 | |
|   CACHEUPDATE;
 | |
| 
 | |
|   /* If already at EOF, return */
 | |
|   if (ZS->fileposition >= ZS->usiz) return -1;
 | |
| 
 | |
|   /* If data isn't in current outbuf, get it */
 | |
|   offset = ZS->fileposition & ~((long) (OUTBUFSIZE-1));
 | |
|   length = ZS->usiz - offset;
 | |
|   if (length > OUTBUFSIZE) length = OUTBUFSIZE;
 | |
| 
 | |
|   if (ZS->getoff != offset)
 | |
|   {
 | |
|     if (BufferRead(ZS, offset, ZS->getbuf, length)) return -1;
 | |
| 
 | |
|     ZS->getoff = offset;
 | |
|   }
 | |
| 
 | |
|   /* Set up the cache */
 | |
|   off = (int) (ZS->fileposition & (OUTBUFSIZE-1));
 | |
|   ZS->len = (int) (length - off);
 | |
|   ZS->ptr = ZS->getbuf    + off;
 | |
| 
 | |
|   /* Return the character */
 | |
|            ZS->len--;
 | |
|   return *(ZS->ptr++);
 | |
| }
 | |
| 
 | |
| size_t Zread(void *ptr, size_t size, size_t n, ZFILE *stream)
 | |
| {
 | |
|   long           length;
 | |
| 
 | |
|   RUNTIMECHECK;
 | |
| 
 | |
|   if (ZS->errorencountered) return 0;
 | |
| 
 | |
|   CACHEUPDATE;
 | |
| 
 | |
|   /* Compute the length requested */
 | |
|   length = size * (long) n;
 | |
| 
 | |
|   /* Adjust the length to account for premature EOF */
 | |
|   if (ZS->fileposition+length > ZS->usiz)
 | |
|     length = ZS->usiz - ZS->fileposition;
 | |
| 
 | |
|   /* If the length is zero, then just return an EOF error */
 | |
|   if (length <= 0) return 0;
 | |
| 
 | |
|   /* Make the length a multiple of size */
 | |
|   length /= size;
 | |
|   length *= size;
 | |
| 
 | |
|   /* If the length is zero, then just return an EOF error */
 | |
|   if (length <= 0) return 0;
 | |
| 
 | |
|   /* Read from the buffer */
 | |
|   if (BufferRead(ZS, ZS->fileposition, (unsigned char *) ptr, length))
 | |
|     return 0;
 | |
| 
 | |
|   /* Update the file position */
 | |
|   ZS->fileposition += length;
 | |
| 
 | |
|   /* Return the number of items transferred */
 | |
|   return (size_t) (length / size);
 | |
| }
 | |
| 
 | |
| int Zseek(ZFILE *stream, long offset, int whence)
 | |
| {
 | |
|   long newoffset;
 | |
| 
 | |
|   RUNTIMECHECK;
 | |
| 
 | |
|   if (ZS->errorencountered) return -1;
 | |
| 
 | |
|   CACHEUPDATE;
 | |
| 
 | |
|   if (whence == SEEK_SET)
 | |
|   {
 | |
|     newoffset = offset;
 | |
|   }
 | |
|   else if (whence == SEEK_CUR)
 | |
|   {
 | |
|     newoffset = ZS->fileposition + offset;
 | |
|   }
 | |
|   else if (whence == SEEK_END)
 | |
|   {
 | |
|     newoffset = ZS->fileposition + ZS->usiz;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     return -1;
 | |
|   }
 | |
| 
 | |
|   if ((newoffset < 0) || (newoffset > ZS->usiz)) return -1;
 | |
| 
 | |
|   ZS->fileposition = newoffset;
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| long Ztell(ZFILE *stream)
 | |
| {
 | |
|   RUNTIMECHECK;
 | |
| 
 | |
|   if (ZS->errorencountered) return -1;
 | |
| 
 | |
|   CACHEUPDATE;
 | |
| 
 | |
|   return ZS->fileposition;
 | |
| }
 | |
| 
 | |
| int Zclose(ZFILE *stream)
 | |
| {
 | |
|   int ret;
 | |
| 
 | |
|   RUNTIMECHECK;
 | |
| 
 | |
|   CACHEUPDATE;
 | |
| 
 | |
|   /* terminate the inflate routines, and check for errors */
 | |
|   if (ZS->inflatestate)
 | |
|   {
 | |
|     if (InflateTerminate(ZS->inflatestate))
 | |
|       ZS->errorencountered = TRUE;
 | |
| 
 | |
|     /* Check that the CRC is OK */
 | |
|     if (ZS->filecrc != (ZS->crc3 ^ 0xffffffffL))
 | |
|       ZS->errorencountered = TRUE;
 | |
|   }
 | |
| 
 | |
|   /* save the final error status */
 | |
|   ret = ZS->errorencountered;
 | |
| 
 | |
|   /* terminate the buffering */
 | |
|   BufferTerminate(ZS);
 | |
| 
 | |
|   /* free the ZipioState structure */
 | |
|   free(ZS);
 | |
| 
 | |
|   /* return the final error status */
 | |
|   return ret;
 | |
| }
 |