diff --git a/source/utils/unzip/crypt.h b/source/utils/unzip/crypt.h new file mode 100644 index 00000000..e80f3b9b --- /dev/null +++ b/source/utils/unzip/crypt.h @@ -0,0 +1,132 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. + */ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned) (*(pkeys + 2)) & 0xffff) | 2; + return (int) (((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys, const unsigned long* pcrc_32_tab, int c) +{ + (*(pkeys + 0)) = CRC32( ( *( pkeys + 0 ) ), c ); + (*(pkeys + 1)) += (*(pkeys + 0)) & 0xff; + (*(pkeys + 1)) = (*(pkeys + 1)) * 134775813L + 1; + { + register int keyshift = (int) ((*(pkeys + 1)) >> 24); + (*(pkeys + 2)) = CRC32( ( *( pkeys + 2 ) ), keyshift ); + } + return c; +} + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd, unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + *(pkeys + 0) = 305419896L; + *(pkeys + 1) = 591751049L; + *(pkeys + 2) = 878082192L; + while (*passwd != '\0') + { + update_keys(pkeys, pcrc_32_tab, (int) *passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 +/* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead( passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting ) +const char *passwd; /* password string */ +unsigned char *buf; /* where to write header */ +int bufSize; +unsigned long* pkeys; +const unsigned long* pcrc_32_tab; +unsigned long crcForCrypting; +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if ( bufSize < RAND_HEAD_LEN ) + return 0; + + /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the + * output of rand() to get less predictability, since rand() is + * often poorly implemented. + */ + if ( ++calls == 1 ) + { + srand( ( unsigned )( time( NULL ) ^ ZCR_SEED2 ) ); + } + init_keys( passwd, pkeys, pcrc_32_tab ); + for ( n = 0; n < RAND_HEAD_LEN - 2; n++ ) + { + c = ( rand() >> 7 ) & 0xff; + header[n] = ( unsigned char )zencode( pkeys, pcrc_32_tab, c, t ); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys( passwd, pkeys, pcrc_32_tab ); + for ( n = 0; n < RAND_HEAD_LEN - 2; n++ ) + { + buf[n] = ( unsigned char )zencode( pkeys, pcrc_32_tab, header[n], t ); + } + buf[n++] = zencode( pkeys, pcrc_32_tab, ( int )( crcForCrypting >> 16 ) & 0xff, t ); + buf[n++] = zencode( pkeys, pcrc_32_tab, ( int )( crcForCrypting >> 24 ) & 0xff, t ); + return n; +} + +#endif diff --git a/source/utils/unzip/inflate.c b/source/utils/unzip/inflate.c new file mode 100644 index 00000000..3b71bede --- /dev/null +++ b/source/utils/unzip/inflate.c @@ -0,0 +1,64 @@ +#include "inflate.h" + +#define CHUNK 1024 + +int inflateFile(FILE *source, FILE *dest) +{ + int ret; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit( &strm ); + if (ret != Z_OK) return ret; + + /* decompress until deflate stream ends or end of file */ + do + { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror( source )) + { + (void) inflateEnd(&strm); + return Z_ERRNO; + } + if (strm.avail_in == 0) break; + strm.next_in = in; + + /* run inflate() on input until output buffer not full */ + do + { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + switch (ret) + { + case Z_NEED_DICT: + (void) inflateEnd(&strm); + return -20; + case Z_DATA_ERROR: + (void) inflateEnd(&strm); + return -21; + case Z_MEM_ERROR: + (void) inflateEnd(&strm); + return -22; + } + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror( dest )) + { + (void) inflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + /* clean up and return */ + (void) inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} diff --git a/source/utils/unzip/inflate.h b/source/utils/unzip/inflate.h new file mode 100644 index 00000000..6aa2ccbe --- /dev/null +++ b/source/utils/unzip/inflate.h @@ -0,0 +1,18 @@ +#ifndef _INFLATE_H +#define _INFLATE_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + int inflateFile(FILE *source, FILE *dest); + +#ifdef __cplusplus +} +#endif + +#endif //_INFLATE_H diff --git a/source/utils/unzip/ioapi.c b/source/utils/unzip/ioapi.c new file mode 100644 index 00000000..2e514696 --- /dev/null +++ b/source/utils/unzip/ioapi.c @@ -0,0 +1,176 @@ +/* ioapi.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant +*/ + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +voidpf ZCALLBACK fopen_file_func OF( ( + voidpf opaque, + const char* filename, + int mode ) ); + +uLong ZCALLBACK fread_file_func OF( ( + voidpf opaque, + voidpf stream, + void* buf, + uLong size ) ); + +uLong ZCALLBACK fwrite_file_func OF( ( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size ) ); + +long ZCALLBACK ftell_file_func OF( ( + voidpf opaque, + voidpf stream ) ); + +long ZCALLBACK fseek_file_func OF( ( + voidpf opaque, + voidpf stream, + uLong offset, + int origin ) ); + +int ZCALLBACK fclose_file_func OF( ( + voidpf opaque, + voidpf stream ) ); + +int ZCALLBACK ferror_file_func OF( ( + voidpf opaque, + voidpf stream ) ); + + +voidpf ZCALLBACK fopen_file_func ( opaque, filename, mode ) +voidpf opaque; +const char* filename; +int mode; +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ( ( mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER ) == ZLIB_FILEFUNC_MODE_READ ) + mode_fopen = "rb"; + else if ( mode & ZLIB_FILEFUNC_MODE_EXISTING ) + mode_fopen = "r+b"; + else if ( mode & ZLIB_FILEFUNC_MODE_CREATE ) + mode_fopen = "wb"; + + if ( ( filename != NULL ) && ( mode_fopen != NULL ) ) + file = fopen( filename, mode_fopen ); + return file; +} + + +uLong ZCALLBACK fread_file_func ( opaque, stream, buf, size ) +voidpf opaque; +voidpf stream; +void* buf; +uLong size; +{ + uLong ret; + ret = ( uLong )fread( buf, 1, ( size_t )size, ( FILE * )stream ); + return ret; +} + + +uLong ZCALLBACK fwrite_file_func ( opaque, stream, buf, size ) +voidpf opaque; +voidpf stream; +const void* buf; +uLong size; +{ + uLong ret; + ret = ( uLong )fwrite( buf, 1, ( size_t )size, ( FILE * )stream ); + return ret; +} + +long ZCALLBACK ftell_file_func ( opaque, stream ) +voidpf opaque; +voidpf stream; +{ + long ret; + ret = ftell( ( FILE * )stream ); + return ret; +} + +long ZCALLBACK fseek_file_func ( opaque, stream, offset, origin ) +voidpf opaque; +voidpf stream; +uLong offset; +int origin; +{ + int fseek_origin = 0; + long ret; + switch ( origin ) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: + return -1; + } + ret = 0; + fseek( ( FILE * )stream, offset, fseek_origin ); + return ret; +} + +int ZCALLBACK fclose_file_func ( opaque, stream ) +voidpf opaque; +voidpf stream; +{ + int ret; + ret = fclose( ( FILE * )stream ); + return ret; +} + +int ZCALLBACK ferror_file_func ( opaque, stream ) +voidpf opaque; +voidpf stream; +{ + int ret; + ret = ferror( ( FILE * )stream ); + return ret; +} + +void fill_fopen_filefunc ( pzlib_filefunc_def ) +zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/source/utils/unzip/ioapi.h b/source/utils/unzip/ioapi.h new file mode 100644 index 00000000..255ff03f --- /dev/null +++ b/source/utils/unzip/ioapi.h @@ -0,0 +1,71 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + */ + +#ifndef _ZLIBIOAPI_H +#define _ZLIBIOAPI_H + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + +#ifndef ZCALLBACK + +#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +#define ZCALLBACK CALLBACK +#else +#define ZCALLBACK +#endif +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef voidpf ( ZCALLBACK *open_file_func ) OF( ( voidpf opaque, const char* filename, int mode ) ); + typedef uLong ( ZCALLBACK *read_file_func ) OF( ( voidpf opaque, voidpf stream, void* buf, uLong size ) ); + typedef uLong ( ZCALLBACK *write_file_func ) OF( ( voidpf opaque, voidpf stream, const void* buf, uLong size ) ); + typedef long ( ZCALLBACK *tell_file_func ) OF( ( voidpf opaque, voidpf stream ) ); + typedef long ( ZCALLBACK *seek_file_func ) OF( ( voidpf opaque, voidpf stream, uLong offset, int origin ) ); + typedef int ( ZCALLBACK *close_file_func ) OF( ( voidpf opaque, voidpf stream ) ); + typedef int ( ZCALLBACK *testerror_file_func ) OF( ( voidpf opaque, voidpf stream ) ); + + typedef struct zlib_filefunc_def_s + { + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; + } zlib_filefunc_def; + +void fill_fopen_filefunc OF( ( zlib_filefunc_def* pzlib_filefunc_def ) ); + +#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) +#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) +#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) +#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) +#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/utils/unzip/miniunz.c b/source/utils/unzip/miniunz.c new file mode 100644 index 00000000..9acf4c64 --- /dev/null +++ b/source/utils/unzip/miniunz.c @@ -0,0 +1,299 @@ +/* + miniunz.c + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + */ + +#include +#include +#include +#include +#include +#include +# include +# include + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +static int mymkdir(const char* dirname) +{ + int ret = 0; + ret = mkdir(dirname, 0775); + return ret; +} + +int makedir(char *newdir) +{ + char *buffer; + char *p; + int len = (int) strlen(newdir); + + if (len <= 0) return 0; + + buffer = (char*) malloc(len + 1); + strcpy(buffer, newdir); + + if (buffer[len - 1] == '/') + { + buffer[len - 1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer + 1; + while (1) + { + char hold; + + while (*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + // printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) break; + *p++ = hold; + } + free(buffer); + return 1; +} + +static char *fullfilename(const char *basedir, char *filename) +{ + char *file = (char *) malloc(strlen(basedir) + strlen(filename) + 1); + if (basedir == NULL) + { + strcpy(file, filename); + } + else + { + if (basedir[strlen(basedir) - 1] == '/') + { + sprintf(file, "%s%s", basedir, filename); + } + else + { + sprintf(file, "%s/%s", basedir, filename); + } + } + return file; +} + +static int do_extract_currentfile(unzFile uf, const int* popt_extract_without_path, int* popt_overwrite, + const char* password, const char *basedir) +{ + char filename_inzip[256]; + char* filename_withoutpath; + char* filename_withpath; + char* p; + int err = UNZ_OK; + FILE *fout = NULL; + void* buf; + uInt size_buf; + + unz_file_info file_info; + err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + + if (err != UNZ_OK) + { + // printf("error %d with zipfile in unzGetCurrentFileInfo\n",err); + return err; + } + + size_buf = WRITEBUFFERSIZE; + buf = (void*) malloc(size_buf); + if (buf == NULL) + { + // printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + + p = filename_withoutpath = filename_inzip; + filename_withpath = fullfilename(basedir, filename_inzip); + while ((*p) != '\0') + { + if (((*p) == '/') || ((*p) == '\\')) filename_withoutpath = p + 1; + p++; + } + + if ((*filename_withoutpath) == '\0') + { + if ((*popt_extract_without_path) == 0) + { + + // Fix the path, this will fail if the directoryname is the same as the first filename in the zip + char *path = (char *) malloc(strlen(filename_withpath)); + strcpy(path, filename_withpath); + char *ptr = strstr(path, filename_withoutpath); + *ptr = '\0'; + + // printf("creating directory: %s\n",path); + mymkdir(path); + + free(path); + } + } + else + { + char* write_filename; + int skip = 0; + + if ((*popt_extract_without_path) == 0) + write_filename = filename_withpath; + else write_filename = filename_withoutpath; + + err = unzOpenCurrentFilePassword(uf, password); + if (err != UNZ_OK) + { + // printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err); + } + + if (((*popt_overwrite) == 0) && (err == UNZ_OK)) + { + char rep = 0; + FILE* ftestexist; + ftestexist = fopen(write_filename, "rb"); + if (ftestexist != NULL) + { + fclose(ftestexist); + do + { + char answer[128]; + int ret; + + // printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename); + ret = scanf("%1s", answer); + if (ret != 1) + { + exit(EXIT_FAILURE); + } + rep = answer[0]; + if ((rep >= 'a') && (rep <= 'z')) rep -= 0x20; + } while ((rep != 'Y') && (rep != 'N') && (rep != 'A')); + } + + if (rep == 'N') skip = 1; + + if (rep == 'A') *popt_overwrite = 1; + } + + if ((skip == 0) && (err == UNZ_OK)) + { + fout = fopen(write_filename, "wb"); + + /* some zipfile don't contain directory alone before file */ + if ((fout == NULL) && ((*popt_extract_without_path) == 0) && (filename_withoutpath + != (char*) filename_inzip)) + { + char c = *(filename_withoutpath - 1); + *(filename_withoutpath - 1) = '\0'; + + // Fix the path, this will fail if the directoryname is the same as the first filename in the zip + char *path = (char *) malloc(strlen(write_filename)); + strcpy(path, write_filename); + char *ptr = strstr(path, filename_withoutpath); + *ptr = '\0'; + makedir(path); + free(path); + + *(filename_withoutpath - 1) = c; + fout = fopen(write_filename, "wb"); + } + + if (fout == NULL) + { + // printf("error opening %s\n",write_filename); + } + } + + if (fout != NULL) + { + // printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf, buf, size_buf); + if (err < 0) + { + // printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err > 0) if (fwrite(buf, err, 1, fout) != 1) + { + // printf("error in writing extracted file\n"); + err = UNZ_ERRNO; + break; + } + } while (err > 0); + if (fout) fclose(fout); + + } + + if (err == UNZ_OK) + { + err = unzCloseCurrentFile(uf); + if (err != UNZ_OK) + { + // printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else unzCloseCurrentFile(uf); /* don't lose the error */ + } + free(filename_withpath); + free(buf); + return err; +} + +int extractZip(unzFile uf, int opt_extract_without_path, int opt_overwrite, const char* password, const char *basedir) +{ + uLong i; + unz_global_info gi; + int err; + + err = unzGetGlobalInfo(uf, &gi); + if (err != UNZ_OK) + // printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i = 0; i < gi.number_entry; i++) + { + if (do_extract_currentfile(uf, &opt_extract_without_path, &opt_overwrite, password, basedir) != UNZ_OK) break; + + if ((i + 1) < gi.number_entry) + { + err = unzGoToNextFile(uf); + if (err != UNZ_OK) + { + // printf("error %d with zipfile in unzGoToNextFile\n",err); + break; + } + } + } + + return 0; +} + +int extractZipOnefile(unzFile uf, const char* filename, int opt_extract_without_path, int opt_overwrite, + const char* password) +{ + if (unzLocateFile(uf, filename, CASESENSITIVITY) != UNZ_OK) + { + // printf("file %s not found in the zipfile\n",filename); + return 2; + } + + if (do_extract_currentfile(uf, &opt_extract_without_path, &opt_overwrite, password, NULL) == UNZ_OK) + return 0; + else return 1; +} diff --git a/source/utils/unzip/miniunz.h b/source/utils/unzip/miniunz.h new file mode 100644 index 00000000..ef32fb3c --- /dev/null +++ b/source/utils/unzip/miniunz.h @@ -0,0 +1,19 @@ +#ifndef _miniunz_H +#define _miniunz_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + int extractZip(unzFile uf, int opt_extract_without_path, int opt_overwrite, const char* password, + const char *basedir); + int extractZipOnefile(unzFile uf, const char* filename, int opt_extract_without_path, int opt_overwrite, + const char* password); + int makedir(char *newdir); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/utils/unzip/mztools.c b/source/utils/unzip/mztools.c new file mode 100644 index 00000000..2a79c3c6 --- /dev/null +++ b/source/utils/unzip/mztools.c @@ -0,0 +1,344 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) + */ + +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) + const char* file;const char* fileOut;const char* fileOutTmp;uLong* nRecovered;uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) + { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[256]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while (fread(header, 1, 30, fpZip) == 30) + { + int currentOffset = offset; + + /* File entry */ + if (READ_32( header ) == 0x04034b50) + { + unsigned int version = READ_16( header + 4 ); + unsigned int gpflag = READ_16( header + 6 ); + unsigned int method = READ_16( header + 8 ); + unsigned int filetime = READ_16( header + 10 ); + unsigned int filedate = READ_16( header + 12 ); + unsigned int crc = READ_32( header + 14 ); /* crc */ + unsigned int cpsize = READ_32( header + 18 ); /* compressed size */ + unsigned int uncpsize = READ_32( header + 22 ); /* uncompressed sz */ + unsigned int fnsize = READ_16( header + 26 ); /* file name length */ + unsigned int extsize = READ_16( header + 28 ); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) + { + offset += 30; + } + else + { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) + { + if (fread(filename, 1, fnsize, fpZip) == fnsize) + { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) + { + offset += fnsize; + } + else + { + err = Z_ERRNO; + break; + } + } + else + { + err = Z_ERRNO; + break; + } + } + else + { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) + { + if (fread(extra, 1, extsize, fpZip) == extsize) + { + if (fwrite(extra, 1, extsize, fpOut) == extsize) + { + offset += extsize; + } + else + { + err = Z_ERRNO; + break; + } + } + else + { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) + { + dataSize = uncpsize; + } + if (dataSize > 0) + { + char* data = malloc(dataSize); + if (data != NULL) + { + if ((int) fread(data, 1, dataSize, fpZip) == dataSize) + { + if ((int) fwrite(data, 1, dataSize, fpOut) == dataSize) + { + offset += dataSize; + totalBytes += dataSize; + } + else + { + err = Z_ERRNO; + } + } + else + { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) + { + break; + } + } + else + { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char header[46]; + char* comment = ""; + int comsize = (int) strlen(comment); + WRITE_32( header, 0x02014b50 ); + WRITE_16( header + 4, version ); + WRITE_16( header + 6, version ); + WRITE_16( header + 8, gpflag ); + WRITE_16( header + 10, method ); + WRITE_16( header + 12, filetime ); + WRITE_16( header + 14, filedate ); + WRITE_32( header + 16, crc ); + WRITE_32( header + 20, cpsize ); + WRITE_32( header + 24, uncpsize ); + WRITE_16( header + 28, fnsize ); + WRITE_16( header + 30, extsize ); + WRITE_16( header + 32, comsize ); + WRITE_16( header + 34, 0 ); /* disk # */ + WRITE_16( header + 36, 0 ); /* int attrb */ + WRITE_32( header + 38, 0 ); /* ext attrb */ + WRITE_32( header + 42, currentOffset ); + /* Header */ + if (fwrite(header, 1, 46, fpOutCD) == 46) + { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) + { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) + { + offsetCD += fnsize; + } + else + { + err = Z_ERRNO; + break; + } + } + else + { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) + { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) + { + offsetCD += extsize; + } + else + { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + if (comsize > 0) + { + if ((int) fwrite(comment, 1, comsize, fpOutCD) == comsize) + { + offsetCD += comsize; + } + else + { + err = Z_ERRNO; + break; + } + } + + } + else + { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + + } + else + { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char header[22]; + char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) + { + entriesZip = 0xffff; + } + WRITE_32( header, 0x06054b50 ); + WRITE_16( header + 4, 0 ); /* disk # */ + WRITE_16( header + 6, 0 ); /* disk # */ + WRITE_16( header + 8, entriesZip ); /* hack */ + WRITE_16( header + 10, entriesZip ); /* hack */ + WRITE_32( header + 12, offsetCD ); /* size of CD */ + WRITE_32( header + 16, offset ); /* offset to CD */ + WRITE_16( header + 20, comsize ); /* comment */ + + /* Header */ + if (fwrite(header, 1, 22, fpOutCD) == 22) + { + + /* Comment field */ + if (comsize > 0) + { + if ((int) fwrite(comment, 1, comsize, fpOutCD) != comsize) + { + err = Z_ERRNO; + } + } + + } + else + { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) + { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) + { + int nRead; + char buffer[8192]; + while ((nRead = (int) fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) + { + if ((int) fwrite(buffer, 1, nRead, fpOut) != nRead) + { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void) remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) + { + if (nRecovered != NULL) + { + *nRecovered = entries; + } + if (bytesRecovered != NULL) + { + *bytesRecovered = totalBytes; + } + } + } + else + { + err = Z_STREAM_ERROR; + } + return err; +} diff --git a/source/utils/unzip/mztools.h b/source/utils/unzip/mztools.h new file mode 100644 index 00000000..dc1d30c9 --- /dev/null +++ b/source/utils/unzip/mztools.h @@ -0,0 +1,29 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) + */ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + + /* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery + */ + extern int ZEXPORT unzRepair(const char* file, const char* fileOut, const char* fileOutTmp, uLong* nRecovered, + uLong* bytesRecovered); + +#endif diff --git a/source/utils/unzip/unzip.c b/source/utils/unzip/unzip.c new file mode 100644 index 00000000..2b366307 --- /dev/null +++ b/source/utils/unzip/unzip.c @@ -0,0 +1,1332 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + Read unzip.h for more info + */ + +/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. Code + woven in by Terry Thorsen 1/2003. + */ +/* + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + */ +/* + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + */ + +/* + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + */ + +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H +extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + +const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip_read_info_s; + +/* unz_s contain internal information about the zipfile + */ +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz_s; + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. + */ + +local int unzlocal_getByte OF( ( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi ) ); + +local int unzlocal_getByte(pzlib_filefunc_def, filestream, pi) + const zlib_filefunc_def* pzlib_filefunc_def;voidpf filestream;int *pi; +{ + unsigned char c; + int err = (int) ZREAD( *pzlib_filefunc_def, filestream, &c, 1 ); + if (err == 1) + { + *pi = (int) c; + return UNZ_OK; + } + else + { + if (ZERROR( *pzlib_filefunc_def, filestream )) + return UNZ_ERRNO; + else return UNZ_EOF; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets + */ +local int unzlocal_getShort OF( ( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX ) ); + +local int unzlocal_getShort(pzlib_filefunc_def, filestream, pX) + const zlib_filefunc_def* pzlib_filefunc_def;voidpf filestream;uLong *pX; +{ + uLong x; + int i = 0; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i); + x = (uLong) i; + + if (err == UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong) i) << 8; + + if (err == UNZ_OK) + *pX = x; + else *pX = 0; + return err; +} + +local int unzlocal_getLong OF( ( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX ) ); + +local int unzlocal_getLong(pzlib_filefunc_def, filestream, pX) + const zlib_filefunc_def* pzlib_filefunc_def;voidpf filestream;uLong *pX; +{ + uLong x; + int i = 0; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i); + x = (uLong) i; + + if (err == UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong) i) << 8; + + if (err == UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong) i) << 16; + + if (err == UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong) i) << 24; + + if (err == UNZ_OK) + *pX = x; + else *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal(fileName1, fileName2) + const char* fileName1;const char* fileName2; +{ + for (;;) + { + char c1 = *(fileName1++); + char c2 = *(fileName2++); + if ((c1 >= 'a') && (c1 <= 'z')) c1 -= 0x20; + if ((c2 >= 'a') && (c2 <= 'z')) c2 -= 0x20; + if (c1 == '\0') return ((c2 == '\0') ? 0 : -1); + if (c2 == '\0') return 1; + if (c1 < c2) return -1; + if (c1 > c2) return 1; + } +} + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + + */ +extern int ZEXPORT unzStringFileNameCompare(fileName1, fileName2, iCaseSensitivity) + const char* fileName1;const char* fileName2;int iCaseSensitivity; +{ + if (iCaseSensitivity == 0) iCaseSensitivity = CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity == 1) return strcmp(fileName1, fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1, fileName2); +} +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) + */ +local uLong unzlocal_SearchCentralDir OF( ( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream ) ); + +local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def, filestream) + const zlib_filefunc_def* pzlib_filefunc_def;voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack = 0xffff; /* maximum size of global comment */ + uLong uPosFound = 0; + + if (ZSEEK( *pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END ) != 0) return 0; + + uSizeFile = ZTELL( *pzlib_filefunc_def, filestream ); + + if (uMaxBack > uSizeFile) uMaxBack = uSizeFile; + + buf = (unsigned char*) ALLOC( BUFREADCOMMENT + 4 ); + if (buf == NULL) return 0; + + uBackRead = 4; + while (uBackRead < uMaxBack) + { + uLong uReadSize, uReadPos; + int i; + if (uBackRead + BUFREADCOMMENT > uMaxBack) + uBackRead = uMaxBack; + else uBackRead += BUFREADCOMMENT; + uReadPos = uSizeFile - uBackRead; + + uReadSize = ((BUFREADCOMMENT + 4) < (uSizeFile - uReadPos)) ? (BUFREADCOMMENT + 4) : (uSizeFile - uReadPos); + if (ZSEEK( *pzlib_filefunc_def, filestream, uReadPos, ZLIB_FILEFUNC_SEEK_SET ) != 0) break; + + if (ZREAD( *pzlib_filefunc_def, filestream, buf, uReadSize ) != uReadSize) break; + + for (i = (int) uReadSize - 3; (i--) > 0;) + if (((*(buf + i)) == 0x50) && ((*(buf + i + 1)) == 0x4b) && ((*(buf + i + 2)) == 0x05) && ((*(buf + i + 3)) + == 0x06)) + { + uPosFound = uReadPos + i; + break; + } + + if (uPosFound != 0) break; + } + TRYFREE( buf ); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + */ +extern unzFile ZEXPORT unzOpen2(path, pzlib_filefunc_def) + const char *path;zlib_filefunc_def* pzlib_filefunc_def; +{ + unz_s us; + unz_s *s; + uLong central_pos, uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err = UNZ_OK; + + if (unz_copyright[0] != ' ') return NULL; + + if (pzlib_filefunc_def == NULL) + fill_fopen_filefunc(&us.z_filefunc); + else us.z_filefunc = *pzlib_filefunc_def; + + us.filestream = (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, path, ZLIB_FILEFUNC_MODE_READ + | ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream == NULL) return NULL; + + central_pos = unzlocal_SearchCentralDir(&us.z_filefunc, us.filestream); + if (central_pos == 0) err = UNZ_ERRNO; + + if (ZSEEK( us.z_filefunc, us.filestream, + central_pos, ZLIB_FILEFUNC_SEEK_SET ) != 0) err = UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) err = UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream, &number_disk) != UNZ_OK) err = UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream, &number_disk_with_CD) != UNZ_OK) err = UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK) err = UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream, &number_entry_CD) != UNZ_OK) err = UNZ_ERRNO; + + if ((number_entry_CD != us.gi.number_entry) || (number_disk_with_CD != 0) || (number_disk != 0)) err + = UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream, &us.size_central_dir) != UNZ_OK) err = UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK) err = UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream, &us.gi.size_comment) != UNZ_OK) err = UNZ_ERRNO; + + if ((central_pos < us.offset_central_dir + us.size_central_dir) && (err == UNZ_OK)) err = UNZ_BADZIPFILE; + + if (err != UNZ_OK) + { + ZCLOSE( us.z_filefunc, us.filestream ); + return NULL; + } + + us.byte_before_the_zipfile = central_pos - (us.offset_central_dir + us.size_central_dir); + us.central_pos = central_pos; + us.pfile_in_zip_read = NULL; + us.encrypted = 0; + + s = (unz_s*) ALLOC( sizeof( unz_s ) ); + *s = us; + unzGoToFirstFile((unzFile) s); + return (unzFile) s; +} + +extern unzFile ZEXPORT unzOpen(path) + const char *path; +{ + return unzOpen2(path, NULL); +} + +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzClose(file) + unzFile file; +{ + unz_s* s; + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + + if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); + + ZCLOSE( s->z_filefunc, s->filestream ); + TRYFREE( s ); + return UNZ_OK; +} + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo(file, pglobal_info) + unzFile file;unz_global_info *pglobal_info; +{ + unz_s* s; + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + *pglobal_info = s->gi; + return UNZ_OK; +} + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) + */ +local void unzlocal_DosDateToTmuDate(ulDosDate, ptm) + uLong ulDosDate;tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong) (ulDosDate >> 16); + ptm->tm_mday = (uInt) (uDate & 0x1f); + ptm->tm_mon = (uInt) ((((uDate) & 0x1E0) / 0x20) - 1); + ptm->tm_year = (uInt) (((uDate & 0x0FE00) / 0x0200) + 1980); + + ptm->tm_hour = (uInt) ((ulDosDate & 0xF800) / 0x800); + ptm->tm_min = (uInt) ((ulDosDate & 0x7E0) / 0x20); + ptm->tm_sec = (uInt) (2 * (ulDosDate & 0x1f)); +} + +/* + Get Info about the current file in the zipfile, with internal only info + */ +local int unzlocal_GetCurrentFileInfoInternal OF( ( unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize ) ); + +local int unzlocal_GetCurrentFileInfoInternal(file, pfile_info, pfile_info_internal, szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, szComment, commentBufferSize) + unzFile file;unz_file_info *pfile_info;unz_file_info_internal *pfile_info_internal;char *szFileName;uLong + fileNameBufferSize;void *extraField;uLong extraFieldBufferSize;char *szComment;uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err = UNZ_OK; + uLong uMagic; + long lSeek = 0; + + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + if (ZSEEK( s->z_filefunc, s->filestream, + s->pos_in_central_dir + s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET ) != 0) err = UNZ_ERRNO; + + /* we check the magic */ + if (err == UNZ_OK) + { + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &uMagic) != UNZ_OK) + err = UNZ_ERRNO; + else if (uMagic != 0x02014b50) err = UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &file_info.version) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &file_info.version_needed) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &file_info.flag) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &file_info.compression_method) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &file_info.dosDate) != UNZ_OK) err = UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate, &file_info.tmu_date); + + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &file_info.crc) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &file_info.compressed_size) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &file_info.uncompressed_size) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &file_info.size_filename) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &file_info.size_file_extra) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &file_info.size_file_comment) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &file_info.disk_num_start) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &file_info.internal_fa) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &file_info.external_fa) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &file_info_internal.offset_curfile) != UNZ_OK) err = UNZ_ERRNO; + + lSeek += file_info.size_filename; + if ((err == UNZ_OK) && (szFileName != NULL)) + { + uLong uSizeRead; + if (file_info.size_filename < fileNameBufferSize) + { + *(szFileName + file_info.size_filename) = '\0'; + uSizeRead = file_info.size_filename; + } + else uSizeRead = fileNameBufferSize; + + if ((file_info.size_filename > 0) && (fileNameBufferSize > 0)) if (ZREAD( s->z_filefunc, s->filestream, szFileName, uSizeRead ) + != uSizeRead) err = UNZ_ERRNO; + lSeek -= uSizeRead; + } + + if ((err == UNZ_OK) && (extraField != NULL)) + { + uLong uSizeRead; + if (file_info.size_file_extra < extraFieldBufferSize) + uSizeRead = file_info.size_file_extra; + else uSizeRead = extraFieldBufferSize; + + if (lSeek != 0) + { + if (ZSEEK( s->z_filefunc, s->filestream, lSeek, ZLIB_FILEFUNC_SEEK_CUR ) == 0) + lSeek = 0; + else err = UNZ_ERRNO; + } + + if ((file_info.size_file_extra > 0) && (extraFieldBufferSize > 0)) if (ZREAD( s->z_filefunc, s->filestream, extraField, uSizeRead ) + != uSizeRead) err = UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else lSeek += file_info.size_file_extra; + + if ((err == UNZ_OK) && (szComment != NULL)) + { + uLong uSizeRead; + if (file_info.size_file_comment < commentBufferSize) + { + *(szComment + file_info.size_file_comment) = '\0'; + uSizeRead = file_info.size_file_comment; + } + else uSizeRead = commentBufferSize; + + if (lSeek != 0) + { + if (ZSEEK( s->z_filefunc, s->filestream, lSeek, ZLIB_FILEFUNC_SEEK_CUR ) == 0) + lSeek = 0; + else err = UNZ_ERRNO; + } + + if ((file_info.size_file_comment > 0) && (commentBufferSize > 0)) if (ZREAD( s->z_filefunc, s->filestream, szComment, uSizeRead ) + != uSizeRead) err = UNZ_ERRNO; + lSeek += file_info.size_file_comment - uSizeRead; + } + else lSeek += file_info.size_file_comment; + + if ((err == UNZ_OK) && (pfile_info != NULL)) *pfile_info = file_info; + + if ((err == UNZ_OK) && (pfile_info_internal != NULL)) *pfile_info_internal = file_info_internal; + + return err; +} + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. + */ +extern int ZEXPORT unzGetCurrentFileInfo(file, pfile_info, szFileName, fileNameBufferSize, extraField, + extraFieldBufferSize, szComment, commentBufferSize) + unzFile file;unz_file_info *pfile_info;char *szFileName;uLong fileNameBufferSize;void *extraField;uLong + extraFieldBufferSize;char *szComment;uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file, pfile_info, NULL, szFileName, fileNameBufferSize, extraField, + extraFieldBufferSize, szComment, commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem + */ +extern int ZEXPORT unzGoToFirstFile(file) + unzFile file; +{ + int err = UNZ_OK; + unz_s* s; + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + s->pos_in_central_dir = s->offset_central_dir; + s->num_file = 0; + err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, + NULL, 0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. + */ +extern int ZEXPORT unzGoToNextFile(file) + unzFile file; +{ + unz_s* s; + int err; + + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file + 1 == s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + + s->cur_file_info.size_file_comment; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, + NULL, 0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found + */ +extern int ZEXPORT unzLocateFile(file, szFileName, iCaseSensitivity) + unzFile file;const char *szFileName;int iCaseSensitivity; +{ + unz_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info cur_file_infoSaved; + unz_file_info_internal cur_file_info_internalSaved; + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + if (file == NULL) return UNZ_PARAMERROR; + + if (strlen(szFileName) >= UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; + + s = (unz_s*) file; + if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP + 1]; + err = unzGetCurrentFileInfo(file, NULL, szCurrentFileName, sizeof(szCurrentFileName) - 1, NULL, 0, NULL, 0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, szFileName, iCaseSensitivity) == 0) return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved; + s->pos_in_central_dir = pos_in_central_dirSaved; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + +/* + /////////////////////////////////////////// + // Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) + // I need random access + // + // Further optimization could be realized by adding an ability + // to cache the directory in memory. The goal being a single + // comprehensive file read to put the file I need in a memory. + */ + +/* + typedef struct unz_file_pos_s + { + uLong pos_in_zip_directory; // offset in file + uLong num_of_file; // # of file + } unz_file_pos; + */ + +extern int ZEXPORT unzGetFilePos(file, file_pos) + unzFile file;unz_file_pos* file_pos; +{ + unz_s* s; + + if (file == NULL || file_pos == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGoToFilePos(file, file_pos) + unzFile file;unz_file_pos* file_pos; +{ + unz_s* s; + int err; + + if (file == NULL || file_pos == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, + NULL, 0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + // Unzip Helper Functions - should be here? + /////////////////////////////////////////// + */ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) + */ +local int unzlocal_CheckCurrentFileCoherencyHeader(s, piSizeVar, poffset_local_extrafield, psize_local_extrafield) + unz_s* s;uInt* piSizeVar;uLong *poffset_local_extrafield;uInt *psize_local_extrafield; +{ + uLong uMagic, uData, uFlags; + uLong size_filename; + uLong size_extra_field; + int err = UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK( s->z_filefunc, s->filestream, s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET ) != 0) return UNZ_ERRNO; + + if (err == UNZ_OK) + { + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &uMagic) != UNZ_OK) + err = UNZ_ERRNO; + else if (uMagic != 0x04034b50) err = UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &uData) != UNZ_OK) err = UNZ_ERRNO; + /* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; + */ + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &uFlags) != UNZ_OK) err = UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &uData) != UNZ_OK) + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (uData != s->cur_file_info.compression_method)) err = UNZ_BADZIPFILE; + + if ((err == UNZ_OK) && (s->cur_file_info.compression_method != 0) && (s->cur_file_info.compression_method + != Z_DEFLATED)) err = UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &uData) != UNZ_OK) /* date/time */ + err = UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &uData) != UNZ_OK) /* crc */ + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (uData != s->cur_file_info.crc) && ((uFlags & 8) == 0)) err = UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &uData) != UNZ_OK) /* size compr */ + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (uData != s->cur_file_info.compressed_size) && ((uFlags & 8) == 0)) err + = UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream, &uData) != UNZ_OK) /* size uncompr */ + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (uData != s->cur_file_info.uncompressed_size) && ((uFlags & 8) == 0)) err + = UNZ_BADZIPFILE; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &size_filename) != UNZ_OK) + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename)) err = UNZ_BADZIPFILE; + + *piSizeVar += (uInt) size_filename; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream, &size_extra_field) != UNZ_OK) err = UNZ_ERRNO; + *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt) size_extra_field; + + *piSizeVar += (uInt) size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. + */ +extern int ZEXPORT unzOpenCurrentFile3(file, method, level, raw, password) + unzFile file;int* method;int* level;int raw;const char* password; +{ + int err = UNZ_OK; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if ( password != NULL ) + return UNZ_PARAMERROR; +# endif + + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + if (!s->current_file_ok) return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s, &iSizeVar, &offset_local_extrafield, &size_local_extrafield) + != UNZ_OK) return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) ALLOC( sizeof( file_in_zip_read_info_s ) ); + if (pfile_in_zip_read_info == NULL) return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer = (char*) ALLOC( UNZ_BUFSIZE ); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield = 0; + pfile_in_zip_read_info->raw = raw; + + if (pfile_in_zip_read_info->read_buffer == NULL) + { + TRYFREE( pfile_in_zip_read_info ); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised = 0; + + if (method != NULL) *method = (int) s->cur_file_info.compression_method; + + if (level != NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6: + *level = 1; + break; + case 4: + *level = 2; + break; + case 2: + *level = 9; + break; + } + } + + if ((s->cur_file_info.compression_method != 0) && (s->cur_file_info.compression_method != Z_DEFLATED)) err + = UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait = s->cur_file_info.crc; + pfile_in_zip_read_info->crc32 = 0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream = s->filestream; + pfile_in_zip_read_info->z_filefunc = s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method == Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func) 0; + pfile_in_zip_read_info->stream.zfree = (free_func) 0; + pfile_in_zip_read_info->stream.opaque = (voidpf) 0; + pfile_in_zip_read_info->stream.next_in = (voidpf) 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err = inflateInit2( &pfile_in_zip_read_info->stream, -MAX_WBITS ); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised = 1; + else + { + TRYFREE( pfile_in_zip_read_info ); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size; + pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size; + + pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt) 0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password, s->keys, s->pcrc_32_tab); + if (ZSEEK( s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET ) != 0) return UNZ_INTERNALERROR; + if (ZREAD( s->z_filefunc, s->filestream, source, 12 ) < 12) return UNZ_INTERNALERROR; + + for (i = 0; i < 12; i++) + zdecode( s->keys, s->pcrc_32_tab, source[i] ); + + s->pfile_in_zip_read->pos_in_zipfile += 12; + s->encrypted = 1; + } +# endif + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile(file) + unzFile file; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword(file, password) + unzFile file;const char* password; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2(file, method, level, raw) + unzFile file;int* method;int* level;int raw; +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) + */ +extern int ZEXPORT unzReadCurrentFile(file, buf, len) + unzFile file;voidp buf;unsigned len; +{ + int err = UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + pfile_in_zip_read_info = s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; + + if ((pfile_in_zip_read_info->read_buffer == NULL)) return UNZ_END_OF_LIST_OF_FILE; + if (len == 0) return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*) buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt) len; + + if ((len > pfile_in_zip_read_info->rest_read_uncompressed) && (!(pfile_in_zip_read_info->raw))) pfile_in_zip_read_info->stream.avail_out + = (uInt) pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len > pfile_in_zip_read_info->rest_read_compressed + pfile_in_zip_read_info->stream.avail_in) + && (pfile_in_zip_read_info->raw)) pfile_in_zip_read_info->stream.avail_out + = (uInt) pfile_in_zip_read_info->rest_read_compressed + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out > 0) + { + if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed > 0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressed < uReadThis) uReadThis + = (uInt) pfile_in_zip_read_info->rest_read_compressed; + if (uReadThis == 0) return UNZ_EOF; + if (ZSEEK( pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET ) != 0) return UNZ_ERRNO; + if (ZREAD( pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis ) != uReadThis) return UNZ_ERRNO; + +# ifndef NOUNCRYPT + if (s->encrypted) + { + uInt i; + for (i = 0; i < uReadThis; i++) + pfile_in_zip_read_info->read_buffer[i] = zdecode( s->keys, s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i] ); + } +# endif + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed -= uReadThis; + + pfile_in_zip_read_info->stream.next_in = (Bytef*) pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt) uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method == 0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy, i; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) return (iRead + == 0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out; + else uDoCopy = pfile_in_zip_read_info->stream.avail_in; + + for (i = 0; i < uDoCopy; i++) + *(pfile_in_zip_read_info->stream.next_out + i) = *(pfile_in_zip_read_info->stream.next_in + i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed -= uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore, uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush = Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err = inflate(&pfile_in_zip_read_info->stream, flush); + + if ((err >= 0) && (pfile_in_zip_read_info->stream.msg != NULL)) err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter - uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, bufBefore, (uInt) (uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + + iRead += (uInt) (uTotalOutAfter - uTotalOutBefore); + + if (err == Z_STREAM_END) return (iRead == 0) ? UNZ_EOF : iRead; + if (err != Z_OK) break; + } + } + + if (err == Z_OK) return iRead; + return err; +} + +/* + Give the current position in uncompressed data + */ +extern z_off_t ZEXPORT unztell(file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + pfile_in_zip_read_info = s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; + + return (z_off_t ) pfile_in_zip_read_info->stream.total_out; +} + +/* + return 1 if the end of file was reached, 0 elsewhere + */ +extern int ZEXPORT unzeof(file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + pfile_in_zip_read_info = s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else return 0; +} + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code + */ +extern int ZEXPORT unzGetLocalExtrafield(file, buf, len) + unzFile file;voidp buf;unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + pfile_in_zip_read_info = s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); + + if (buf == NULL) return (int) size_to_read; + + if (len > size_to_read) + read_now = (uInt) size_to_read; + else read_now = (uInt) len; + + if (read_now == 0) return 0; + + if (ZSEEK( pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET ) != 0) return UNZ_ERRNO; + + if (ZREAD( pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf, read_now ) != read_now) return UNZ_ERRNO; + + return (int) read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good + */ +extern int ZEXPORT unzCloseCurrentFile(file) + unzFile file; +{ + int err = UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + pfile_in_zip_read_info = s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err = UNZ_CRCERROR; + } + + TRYFREE( pfile_in_zip_read_info->read_buffer ); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE( pfile_in_zip_read_info ); + + s->pfile_in_zip_read = NULL; + + return err; +} + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 + */ +extern int ZEXPORT unzGetGlobalComment(file, szComment, uSizeBuf) + unzFile file;char *szComment;uLong uSizeBuf; +{ + unz_s* s; + uLong uReadThis; + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + + uReadThis = uSizeBuf; + if (uReadThis > s->gi.size_comment) uReadThis = s->gi.size_comment; + + if (ZSEEK( s->z_filefunc, s->filestream, s->central_pos + 22, ZLIB_FILEFUNC_SEEK_SET ) != 0) return UNZ_ERRNO; + + if (uReadThis > 0) + { + *szComment = '\0'; + if (ZREAD( s->z_filefunc, s->filestream, szComment, uReadThis ) != uReadThis) return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment + s->gi.size_comment) = '\0'; + return (int) uReadThis; +} + +/* Additions by RX '2004 */ +extern uLong ZEXPORT unzGetOffset(file) + unzFile file; +{ + unz_s* s; + + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + if (!s->current_file_ok) return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) if (s->num_file == s->gi.number_entry) return 0; + return s->pos_in_central_dir; +} + +extern int ZEXPORT unzSetOffset(file, pos) + unzFile file;uLong pos; +{ + unz_s* s; + int err; + + if (file == NULL) return UNZ_PARAMERROR; + s = (unz_s*) file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, + NULL, 0); + s->current_file_ok = (err == UNZ_OK); + return err; +} diff --git a/source/utils/unzip/unzip.h b/source/utils/unzip/unzip.h new file mode 100644 index 00000000..feffed58 --- /dev/null +++ b/source/utils/unzip/unzip.h @@ -0,0 +1,349 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + + Multi volume ZipFile (span) are not supported. + Encryption compatible with pkzip 2.04g only supported + Old compressions used by old PKZip 1.x are not supported + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + + */ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip + */ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) + /* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ + typedef struct TagunzFile__ + { + int unused; + }unzFile__; + typedef unzFile__ *unzFile; +#else + typedef voidp unzFile; +#endif + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + + /* tm_unz contain date/time info */ + typedef struct tm_unz_s + { + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ + } tm_unz; + + /* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ + typedef struct unz_global_info_s + { + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ + } unz_global_info; + + /* unz_file_info contain information about a file in the zipfile */ + typedef struct unz_file_info_s + { + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; + } unz_file_info; + + extern int ZEXPORT unzStringFileNameCompare OF ( ( const char* fileName1, + const char* fileName2, + int iCaseSensitivity ) ); + /* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + */ + + extern unzFile ZEXPORT unzOpen OF( ( const char *path ) ); + /* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + */ + + extern unzFile ZEXPORT unzOpen2 OF( ( const char *path, + zlib_filefunc_def* pzlib_filefunc_def ) ); + /* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) + */ + + extern int ZEXPORT unzClose OF( ( unzFile file ) ); + /* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + + extern int ZEXPORT unzGetGlobalInfo OF( ( unzFile file, + unz_global_info *pglobal_info ) ); + /* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + extern int ZEXPORT unzGetGlobalComment OF( ( unzFile file, + char *szComment, + uLong uSizeBuf ) ); + /* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 + */ + + /***************************************************************************/ + /* Unzip package allow you browse the directory of the zipfile */ + + extern int ZEXPORT unzGoToFirstFile OF( ( unzFile file ) ); + /* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem + */ + + extern int ZEXPORT unzGoToNextFile OF( ( unzFile file ) ); + /* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. + */ + + extern int ZEXPORT unzLocateFile OF( ( unzFile file, + const char *szFileName, + int iCaseSensitivity ) ); + /* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found + */ + + /* ****************************************** */ + /* Ryan supplied functions */ + /* unz_file_info contain information about a file in the zipfile */ + typedef struct unz_file_pos_s + { + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ + }unz_file_pos; + + extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos ); + + extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos ); + + /* ****************************************** */ + + extern int ZEXPORT unzGetCurrentFileInfo OF( ( unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize ) ); + /* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) + */ + + /***************************************************************************/ + /* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + + extern int ZEXPORT unzOpenCurrentFile OF( ( unzFile file ) ); + /* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. + */ + + extern int ZEXPORT unzOpenCurrentFilePassword OF( ( unzFile file, + const char* password ) ); + /* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. + */ + + extern int ZEXPORT unzOpenCurrentFile2 OF( ( unzFile file, + int* method, + int* level, + int raw ) ); + /* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL + */ + + extern int ZEXPORT unzOpenCurrentFile3 OF( ( unzFile file, + int* method, + int* level, + int raw, + const char* password ) ); + /* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL + */ + + extern int ZEXPORT unzCloseCurrentFile OF( ( unzFile file ) ); + /* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good + */ + + extern int ZEXPORT unzReadCurrentFile OF( ( unzFile file, + voidp buf, + unsigned len ) ); + /* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) + */ + + extern z_off_t ZEXPORT unztell OF( ( unzFile file ) ); + /* + Give the current position in uncompressed data + */ + + extern int ZEXPORT unzeof OF( ( unzFile file ) ); + /* + return 1 if the end of file was reached, 0 elsewhere + */ + + extern int ZEXPORT unzGetLocalExtrafield OF( ( unzFile file, + voidp buf, + unsigned len ) ); + /* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code + */ + + /***************************************************************************/ + + /* Get the current file offset */ + extern uLong ZEXPORT unzGetOffset ( unzFile file ); + + /* Set the current file offset */ + extern int ZEXPORT unzSetOffset ( unzFile file, uLong pos ); + +#ifdef __cplusplus + } +#endif + +#endif /* _unz_H */