mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 08:12:40 +01:00
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;
|
||
|
}
|