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;
 | 
						|
}
 |