From be5aeddb21292ffe0693808cdee1f22617429da9 Mon Sep 17 00:00:00 2001 From: Rtch90 Date: Sat, 8 Sep 2012 17:23:51 +0100 Subject: [PATCH] [Add] Zippy zappy tools. -- I have included MiniZip in the project as it is a complete pain in the ass. --- Bin/LibD.pro | 5 +- Libs/MiniZip/Makefile | 27 + Libs/MiniZip/crypt.h | 132 ++ Libs/MiniZip/ioapi.c | 178 +++ Libs/MiniZip/ioapi.h | 75 ++ Libs/MiniZip/iowin32.c | 270 ++++ Libs/MiniZip/iowin32.h | 21 + Libs/MiniZip/miniunz.c | 597 +++++++++ Libs/MiniZip/minizip.c | 463 +++++++ Libs/MiniZip/mztools.c | 281 +++++ Libs/MiniZip/mztools.h | 31 + Libs/MiniZip/test.zip | Bin 0 -> 120 bytes Libs/MiniZip/unzip.c | 1700 ++++++++++++++++++++++++++ Libs/MiniZip/unzip.h | 360 ++++++ Libs/MiniZip/zip.c | 1263 +++++++++++++++++++ Libs/MiniZip/zip.h | 257 ++++ Libs/minizip.a | Bin 0 -> 253062 bytes src/System/Filesystem/IOapi.h | 2 +- src/System/Filesystem/ZipPackage.cpp | 375 ++++++ src/System/Filesystem/ZipPackage.h | 22 + 20 files changed, 6057 insertions(+), 2 deletions(-) create mode 100644 Libs/MiniZip/Makefile create mode 100644 Libs/MiniZip/crypt.h create mode 100644 Libs/MiniZip/ioapi.c create mode 100644 Libs/MiniZip/ioapi.h create mode 100644 Libs/MiniZip/iowin32.c create mode 100644 Libs/MiniZip/iowin32.h create mode 100644 Libs/MiniZip/miniunz.c create mode 100644 Libs/MiniZip/minizip.c create mode 100644 Libs/MiniZip/mztools.c create mode 100644 Libs/MiniZip/mztools.h create mode 100644 Libs/MiniZip/test.zip create mode 100644 Libs/MiniZip/unzip.c create mode 100644 Libs/MiniZip/unzip.h create mode 100644 Libs/MiniZip/zip.c create mode 100644 Libs/MiniZip/zip.h create mode 100644 Libs/minizip.a create mode 100644 src/System/Filesystem/ZipPackage.cpp create mode 100644 src/System/Filesystem/ZipPackage.h diff --git a/Bin/LibD.pro b/Bin/LibD.pro index f27f96d..2fd6b9f 100644 --- a/Bin/LibD.pro +++ b/Bin/LibD.pro @@ -16,7 +16,8 @@ win32: { -lgdi32 \ -lopengl32 \ -lglu32 \ - -lSDL_mixer + -lSDL_mixer \ + -lminizip } HEADERS += ../src/Actor/Player.h \ ../src/Collision/AABB.h \ @@ -43,6 +44,7 @@ HEADERS += ../src/Actor/Player.h \ ../src/System/Convert/ConvertType.h \ ../src/System/Filesystem/OutputCompressedFileStream.h \ ../src/System/Filesystem/InputCompressedFileStream.h \ + ../src/System/Filesystem/ZipPackage.h \ ../src/System/Filesystem/InputStream.h \ ../src/System/Filesystem/OutputStream.h \ ../src/System/Filesystem/EmptyBuffer.h \ @@ -109,6 +111,7 @@ SOURCES += ../src/Actor/Player.cpp \ ../src/System/Filesystem/FileTimestampChecker.cpp \ ../src/System/Filesystem/OutputCompressedFileStream.cpp \ ../src/System/Filesystem/InputCompressedFileStream.cpp \ + ../src/System/Filesystem/ZipPackage.cpp \ ../src/System/Filesystem/InputStream.cpp \ ../src/System/Filesystem/OutputStream.cpp \ ../src/System/Filesystem/FileList.cpp \ diff --git a/Libs/MiniZip/Makefile b/Libs/MiniZip/Makefile new file mode 100644 index 0000000..254f63b --- /dev/null +++ b/Libs/MiniZip/Makefile @@ -0,0 +1,27 @@ +CC=cc +CFLAGS=-O -I../..i -c +#LDFLAGS += -lz + +UNZ_OBJS = miniunz.o unzip.o ioapi.o #libz.a +ZIP_OBJS = minizip.o zip.o ioapi.o #libz.a + +.c.o: + $(CC) -c $(CFLAGS) $*.c + +all: miniunz minizip + +miniunz: $(UNZ_OBJS) + #$(CC) $(CFLAGS) $(UNZ_OBJS) #$(LDFLAGS) + +minizip: $(ZIP_OBJS) + $(AR) -cvq ../minizip.a $(UNZ_OBJS) $(ZIP_OBJS) + #$(CC) $(CFLAGS) $(ZIP_OBJS) #$(LDFLAGS) + +test: miniunz minizip + ./minizip test readme.txt + ./miniunz -l test.zip + mv readme.txt readme.old + ./miniunz test.zip + +clean: + /bin/rm -f *.o minizip miniunz diff --git a/Libs/MiniZip/crypt.h b/Libs/MiniZip/crypt.h new file mode 100644 index 0000000..2d69da4 --- /dev/null +++ b/Libs/MiniZip/crypt.h @@ -0,0 +1,132 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 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> 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/Libs/MiniZip/ioapi.c b/Libs/MiniZip/ioapi.c new file mode 100644 index 0000000..51a9058 --- /dev/null +++ b/Libs/MiniZip/ioapi.c @@ -0,0 +1,178 @@ +/* ioapi.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 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; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + 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/Libs/MiniZip/ioapi.h b/Libs/MiniZip/ioapi.h new file mode 100644 index 0000000..1dba776 --- /dev/null +++ b/Libs/MiniZip/ioapi.h @@ -0,0 +1,75 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 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/Libs/MiniZip/iowin32.c b/Libs/MiniZip/iowin32.c new file mode 100644 index 0000000..e502139 --- /dev/null +++ b/Libs/MiniZip/iowin32.c @@ -0,0 +1,270 @@ +/* iowin32.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + This IO API version uses the Win32 API (for Microsoft Windows) + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant +*/ + +#include + +#include "zlib.h" +#include "ioapi.h" +#include "iowin32.h" + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE (0xFFFFFFFF) +#endif + +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + +voidpf ZCALLBACK win32_open_file_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK win32_read_file_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK win32_write_file_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK win32_tell_file_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK win32_seek_file_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK win32_close_file_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK win32_error_file_func OF(( + voidpf opaque, + voidpf stream)); + +typedef struct +{ + HANDLE hf; + int error; +} WIN32FILE_IOWIN; + +voidpf ZCALLBACK win32_open_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = 0; + voidpf ret=NULL; + + dwDesiredAccess = dwShareMode = dwFlagsAndAttributes = 0; + + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + { + dwDesiredAccess = GENERIC_READ; + dwCreationDisposition = OPEN_EXISTING; + dwShareMode = FILE_SHARE_READ; + } + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + { + dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + dwCreationDisposition = OPEN_EXISTING; + } + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + { + dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + dwCreationDisposition = CREATE_ALWAYS; + } + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, + dwCreationDisposition, dwFlagsAndAttributes, NULL); + + if (hFile == INVALID_HANDLE_VALUE) + hFile = NULL; + + if (hFile != NULL) + { + WIN32FILE_IOWIN w32fiow; + w32fiow.hf = hFile; + w32fiow.error = 0; + ret = malloc(sizeof(WIN32FILE_IOWIN)); + if (ret==NULL) + CloseHandle(hFile); + else *((WIN32FILE_IOWIN*)ret) = w32fiow; + } + return ret; +} + + +uLong ZCALLBACK win32_read_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + if (!ReadFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + + return ret; +} + + +uLong ZCALLBACK win32_write_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile !=NULL) + if (!WriteFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + + return ret; +} + +long ZCALLBACK win32_tell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + long ret=-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=(long)dwSet; + } + return ret; +} + +long ZCALLBACK win32_seek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + + long ret=-1; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +int ZCALLBACK win32_close_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret=-1; + + if (stream!=NULL) + { + HANDLE hFile; + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + CloseHandle(hFile); + ret=0; + } + free(stream); + } + return ret; +} + +int ZCALLBACK win32_error_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret=-1; + if (stream!=NULL) + { + ret = ((WIN32FILE_IOWIN*)stream) -> error; + } + return ret; +} + +void fill_win32_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = win32_open_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell_file = win32_tell_file_func; + pzlib_filefunc_def->zseek_file = win32_seek_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque=NULL; +} diff --git a/Libs/MiniZip/iowin32.h b/Libs/MiniZip/iowin32.h new file mode 100644 index 0000000..c128770 --- /dev/null +++ b/Libs/MiniZip/iowin32.h @@ -0,0 +1,21 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + This IO API version uses the Win32 API (for Microsoft Windows) + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant +*/ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif diff --git a/Libs/MiniZip/miniunz.c b/Libs/MiniZip/miniunz.c new file mode 100644 index 0000000..b5bc8b5 --- /dev/null +++ b/Libs/MiniZip/miniunz.c @@ -0,0 +1,597 @@ +/* + miniunz.c + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant +*/ + + +#include +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +#else +# include +# include +#endif + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#ifdef WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif +/* + mini unzip, demo of unzip package + + usage : + Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] + + list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT + if it exists +*/ + + +/* change_file_date : change the date/time of a file + filename : the filename of the file where date/time must be modified + dosdate : the new date at the MSDos format (4 bytes) + tmu_date : the SAME new date at the tm_unz format */ +void change_file_date(filename,dosdate,tmu_date) + const char *filename; + uLong dosdate; + tm_unz tmu_date; +{ +#ifdef WIN32 + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +#else +#ifdef unix + struct utimbuf ut; + struct tm newdate; + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min=tmu_date.tm_min; + newdate.tm_hour=tmu_date.tm_hour; + newdate.tm_mday=tmu_date.tm_mday; + newdate.tm_mon=tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year=tmu_date.tm_year - 1900; + else + newdate.tm_year=tmu_date.tm_year ; + newdate.tm_isdst=-1; + + ut.actime=ut.modtime=mktime(&newdate); + utime(filename,&ut); +#endif +#endif +} + + +/* mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#ifdef WIN32 + ret = mkdir(dirname); +#else +#ifdef unix + ret = mkdir (dirname,0775); +#endif +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)malloc(len+1); + if (buffer==NULL) + { + printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + 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; +} + +void do_banner() +{ + printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); + printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); +} + +void do_help() +{ + printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ + " -e Extract without pathname (junk paths)\n" \ + " -x Extract with pathname\n" \ + " -v list files\n" \ + " -l list files\n" \ + " -d directory to extract into\n" \ + " -o overwrite files without prompting\n" \ + " -p extract crypted file using password\n\n"); +} + + +int do_list(uf) + unzFile uf; +{ + 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); + printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); + printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); + for (i=0;i0) + ratio = (file_info.compressed_size*100)/file_info.uncompressed_size; + + /* display a '*' if the file is crypted */ + if ((file_info.flag & 1) != 0) + charCrypt='*'; + + if (file_info.compression_method==0) + string_method="Stored"; + else + if (file_info.compression_method==Z_DEFLATED) + { + uInt iLevel=(uInt)((file_info.flag & 0x6)/2); + if (iLevel==0) + string_method="Defl:N"; + else if (iLevel==1) + string_method="Defl:X"; + else if ((iLevel==2) || (iLevel==3)) + string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ + } + else + if (file_info.compression_method==Z_BZIP2ED) + { + string_method="BZip2 "; + } + else + string_method="Unkn. "; + + printf("%7lu %6s%c%7lu %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", + file_info.uncompressed_size,string_method, + charCrypt, + file_info.compressed_size, + ratio, + (uLong)file_info.tmu_date.tm_mon + 1, + (uLong)file_info.tmu_date.tm_mday, + (uLong)file_info.tmu_date.tm_year % 100, + (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, + (uLong)file_info.crc,filename_inzip); + if ((i+1)='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'; + makedir(write_filename); + *(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==0) + change_file_date(write_filename,file_info.dosDate, + file_info.tmu_date); + } + + 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(buf); + return err; +} + + +int do_extract(uf,opt_extract_without_path,opt_overwrite,password) + unzFile uf; + int opt_extract_without_path; + int opt_overwrite; + const char* password; +{ + uLong i; + unz_global_info gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo (uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +# include +# include +#else +# include +# include +#endif + +#include "zip.h" + +#ifdef WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif + + + +#define WRITEBUFFERSIZE (16384) +#define MAXFILENAME (256) + +#ifdef WIN32 +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret = 0; + { + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATAA ff32; + + hFind = FindFirstFileA(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + } + return ret; +} +#else +#ifdef unix +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret=0; + struct stat s; /* results of stat() */ + struct tm* filedate; + time_t tm_t=0; + + if (strcmp(f,"-")!=0) + { + char name[MAXFILENAME+1]; + int len = strlen(f); + if (len > MAXFILENAME) + len = MAXFILENAME; + + strncpy(name, f,MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, of the string is too long. */ + name[ MAXFILENAME ] = '\0'; + + if (name[len - 1] == '/') + name[len - 1] = '\0'; + /* not all systems allow stat'ing a file with / appended */ + if (stat(name,&s)==0) + { + tm_t = s.st_mtime; + ret = 1; + } + } + filedate = localtime(&tm_t); + + tmzip->tm_sec = filedate->tm_sec; + tmzip->tm_min = filedate->tm_min; + tmzip->tm_hour = filedate->tm_hour; + tmzip->tm_mday = filedate->tm_mday; + tmzip->tm_mon = filedate->tm_mon ; + tmzip->tm_year = filedate->tm_year; + + return ret; +} +#else +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + return 0; +} +#endif +#endif + + + + +int check_exist_file(filename) + const char* filename; +{ + FILE* ftestexist; + int ret = 1; + ftestexist = fopen(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +void do_banner() +{ + printf("MiniZip 1.01e-jg, demo of zLib + Zip package written by Gilles Vollant\n"); + printf("minor updates, jg.\n"); + printf("more info at http://www.winimage.com/zLibDll/minizip.html\n\n"); +} + +void do_help() +{ + printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ + " -o Overwrite existing file.zip\n" \ + " -a Append to existing file.zip\n" \ + " -0 Store only\n" \ + " -1 Compress faster\n" \ + " -9 Compress better\n" \ + " -j exclude path. store only the file name.\n\n"); +} + +/* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ +int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = fopen(filenameinzip,"rb"); + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %lx\n",filenameinzip,calculate_crc); + return err; +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i; + int opt_overwrite=0; + int opt_compress_level=Z_DEFAULT_COMPRESSION; + int opt_exclude_path=0; + int zipfilenamearg = 0; + char filename_try[MAXFILENAME+16]; + int zipok; + int err=0; + int size_buf=0; + void* buf=NULL; + const char* password=NULL; + + + do_banner(); + if (argc==1) + { + do_help(); + return 0; + } + else + { + for (i=1;i='0') && (c<='9')) + opt_compress_level = c-'0'; + if ((c=='j') || (c=='J')) + opt_exclude_path = 1; + + if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + if (rep=='N') + zipok = 0; + if (rep=='A') + opt_overwrite = 2; + } + } + + if (zipok==1) + { + zipFile zf; + int errclose; +# ifdef USEWIN32IOAPI + zlib_filefunc_def ffunc; + fill_win32_filefunc(&ffunc); + zf = zipOpen2(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); +# else + zf = zipOpen(filename_try,(opt_overwrite==2) ? 2 : 0); +# endif + + if (zf == NULL) + { + printf("error opening %s\n",filename_try); + err= ZIP_ERRNO; + } + else + printf("creating %s\n",filename_try); + + for (i=zipfilenamearg+1;(i='0') || (argv[i][1]<='9'))) && + (strlen(argv[i]) == 2))) + { + FILE * fin; + int size_read; + const char* filenameinzip = argv[i]; + const char *savefilenameinzip; + zip_fileinfo zi; + unsigned long crcFile=0; + + zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = + zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; + zi.dosDate = 0; + zi.internal_fa = 0; + zi.external_fa = 0; + filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); + +/* + err = zipOpenNewFileInZip(zf,filenameinzip,&zi, + NULL,0,NULL,0,NULL / * comment * /, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level); +*/ + if ((password != NULL) && (err==ZIP_OK)) + err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); + + /*the path name saved, should not include a leading slash. */ + /*if it did, windows/xp and dynazip couldn't read the zip file. */ + savefilenameinzip = filenameinzip; + while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) + { + savefilenameinzip++; + } + + /*should the zip file contain any path at all?*/ + if( opt_exclude_path ) + { + const char *tmpptr; + const char *lastslash = 0; + for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) + { + if( *tmpptr == '\\' || *tmpptr == '/') + { + lastslash = tmpptr; + } + } + if( lastslash != NULL ) + { + savefilenameinzip = lastslash+1; // base filename follows last slash. + } + } + + /**/ + err = zipOpenNewFileInZip3(zf,savefilenameinzip,&zi, + NULL,0,NULL,0,NULL /* comment*/, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level,0, + /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + password,crcFile); + + if (err != ZIP_OK) + printf("error in opening %s in zipfile\n",filenameinzip); + else + { + fin = fopen(filenameinzip,"rb"); + if (fin==NULL) + { + err=ZIP_ERRNO; + printf("error in opening %s for reading\n",filenameinzip); + } + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + { + err = zipWriteInFileInZip (zf,buf,size_read); + if (err<0) + { + printf("error in writing %s in the zipfile\n", + filenameinzip); + } + + } + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + if (err<0) + err=ZIP_ERRNO; + else + { + err = zipCloseFileInZip(zf); + if (err!=ZIP_OK) + printf("error in closing %s in the zipfile\n", + filenameinzip); + } + } + } + errclose = zipClose(zf,NULL); + if (errclose != ZIP_OK) + printf("error in closing %s\n",filename_try); + } + else + { + do_help(); + } + + free(buf); + return 0; +} diff --git a/Libs/MiniZip/mztools.c b/Libs/MiniZip/mztools.c new file mode 100644 index 0000000..8a50ee4 --- /dev/null +++ b/Libs/MiniZip/mztools.c @@ -0,0 +1,281 @@ +/* + 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/Libs/MiniZip/mztools.h b/Libs/MiniZip/mztools.h new file mode 100644 index 0000000..eee78dc --- /dev/null +++ b/Libs/MiniZip/mztools.h @@ -0,0 +1,31 @@ +/* + 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/Libs/MiniZip/test.zip b/Libs/MiniZip/test.zip new file mode 100644 index 0000000000000000000000000000000000000000..d7e89abfc8f6d4f95d6d1045b3f4452adab006a6 GIT binary patch literal 120 zcmWIWW@Zs#U|`??BE=pcgMkS|009>e7o{eq +#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 */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + 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 (c1c2) + 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 (uBackReaduMaxBack) + 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_pospfile_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_filename0) && (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_extraz_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_commentz_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) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (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) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (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_BZIP2ED) && + (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + 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=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else + 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=Z_DEFLATED; + 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; + + s->encrypted = 0; + +# 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_compressedrest_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;iread_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;istream.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 + if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + 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); + + pfile_in_zip_read_info->stream.next_in = pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } + 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 == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + 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 0; + 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/Libs/MiniZip/unzip.h b/Libs/MiniZip/unzip.h new file mode 100644 index 0000000..94c1b69 --- /dev/null +++ b/Libs/MiniZip/unzip.h @@ -0,0 +1,360 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 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 + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#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 */ diff --git a/Libs/MiniZip/zip.c b/Libs/MiniZip/zip.c new file mode 100644 index 0000000..1451d61 --- /dev/null +++ b/Libs/MiniZip/zip.c @@ -0,0 +1,1263 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.01h, December 28th, 2009 + + 27 Dec 2004 Rolf Kalbermatter + Modification to zipOpen2 to support globalComment retrieval. + + Copyright (C) 1998-2009 Gilles Vollant + + Read zip.h for more info +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.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 VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_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) +*/ + +/* 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 + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] = + " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + uLong pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralheader; /* size of the central header for cur file */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile_info; + +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile_info ci; /* info on the file curretly writing */ + + uLong begin_pos; /* position of the beginning of the zipfile */ + uLong add_position_when_writting_offset; + uLong number_entry; +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif +} zip_internal; + + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(ldi) + linkedlist_datablock_internal* ldi; +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(ll) + linkedlist_data* ll; +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(ll) + linkedlist_data* ll; +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(ll,buf,len) + linkedlist_data* ll; + const void* buf; + uLong len; +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 or 4 (byte, short or long) +*/ + +local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, uLong x, int nbByte)); +local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong x; + int nbByte; +{ + unsigned char buf[4]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); +local void ziplocal_putValue_inmemory (dest, x, nbByte) + void* dest; + uLong x; + int nbByte; +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong ziplocal_TmzDateToDosDate(ptm,dosDate) + const tm_zip* ptm; + uLong dosDate; +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int ziplocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int ziplocal_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 ZIP_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int ziplocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int ziplocal_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 = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int ziplocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int ziplocal_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 = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) + Fix from Riccardo Cohen +*/ +local uLong ziplocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong ziplocal_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 (uBackReaduMaxBack) + 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; +} + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + +/************************************************************/ +extern zipFile ZEXPORT zipOpen2 (pathname, append, globalcomment, pzlib_filefunc_def) + const char *pathname; + int append; + zipcharpc* globalcomment; + zlib_filefunc_def* pzlib_filefunc_def; +{ + zip_internal ziinit; + zip_internal* zi; + int err=ZIP_OK; + + + if (pzlib_filefunc_def==NULL) + fill_fopen_filefunc(&ziinit.z_filefunc); + else + ziinit.z_filefunc = *pzlib_filefunc_def; + + ziinit.filestream = (*(ziinit.z_filefunc.zopen_file)) + (ziinit.z_filefunc.opaque, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + zi = (zip_internal*)ALLOC(sizeof(zip_internal)); + if (zi==NULL) + { + ZCLOSE(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory */ + 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; + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong size_comment; + + central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* zipfile global comment length */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((central_pos0) + { + ziinit.globalcomment = (char*)ALLOC(size_comment+1); + if (ziinit.globalcomment) + { + size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment); + ziinit.globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - + (offset_central_dir+size_central_dir); + ziinit.add_position_when_writting_offset = byte_before_the_zipfile; + + { + uLong size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + offset_central_dir + byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + uLong read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&ziinit.central_dir,buf_read, + (uLong)read_this); + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + ziinit.begin_pos = byte_before_the_zipfile; + ziinit.number_entry = number_entry_CD; + + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen (pathname, append) + const char *pathname; + int append; +{ + return zipOpen2(pathname,append,NULL,NULL); +} + +extern int ZEXPORT zipOpenNewFileInZip4 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; + int windowBits; + int memLevel; + int strategy; + const char* password; + uLong crcForCrypting; + uLong versionMadeBy; + uLong flagBase; +{ + zip_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; + + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); + } + + zi->ci.flag = flagBase; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if ((level==2)) + zi->ci.flag |= 4; + if ((level==1)) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ; + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + + size_extrafield_global + size_comment; + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); + + ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + /* write the local header */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2); + + if ((err==ZIP_OK) && (size_filename>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + + if ((err==ZIP_OK) && (size_extrafield_local>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local) + !=size_extrafield_local) + err = ZIP_ERRNO; + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, + Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = 1; + } +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; +{ + return zipOpenNewFileInZip4 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; + int windowBits; + int memLevel; + int strategy; + const char* password; + uLong crcForCrypting; +{ + return zipOpenNewFileInZip4 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0); +} + + +extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; +{ + return zipOpenNewFileInZip4 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0); +} + +local int zipFlushWriteBuffer(zi) + zip_internal* zi; +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, + zi->ci.buffered_data[i],t); +#endif + } + if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) + !=zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + zi->ci.pos_in_buffered_data = 0; + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (file, buf, len) + zipFile file; + const void* buf; + unsigned len; +{ + zip_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + for (i=0;ici.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32) + zipFile file; + uLong uncompressed_size; + uLong crc32; +{ + zip_internal* zi; + uLong compressed_size; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + if (zipFlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err=deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = (uLong)zi->ci.stream.total_in; + } + compressed_size = (uLong)zi->ci.stream.total_out; +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20, + compressed_size,4); /*compr size*/ + if (zi->ci.stream.data_type == Z_ASCII) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + ziplocal_putValue_inmemory(zi->ci.central_header+24, + uncompressed_size,4); /*uncompr size*/ + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header, + (uLong)zi->ci.size_centralheader); + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + long cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); + if (ZSEEK(zi->z_filefunc,zi->filestream, + zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if (err==ZIP_OK) /* compressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + + if (ZSEEK(zi->z_filefunc,zi->filestream, + cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (file) + zipFile file; +{ + return zipCloseFileInZipRaw (file,0,0); +} + +extern int ZEXPORT zipClose (file, global_comment) + zipFile file; + const char* global_comment; +{ + zip_internal* zi; + int err = 0; + uLong size_centraldir = 0; + uLong centraldir_pos_inzip; + uInt size_global_comment; + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + if (global_comment==NULL) + size_global_comment = 0; + else + size_global_comment = (uInt)strlen(global_comment); + + centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block ; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream, + ldi->data,ldi->filled_in_this_block) + !=ldi->filled_in_this_block ) + err = ZIP_ERRNO; + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + if (err==ZIP_OK) /* Magic End */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* size of the central directory */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the + starting disk number */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream, + (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + + if (err==ZIP_OK) /* zipfile comment length */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if ((err==ZIP_OK) && (size_global_comment>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream, + global_comment,size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + + if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} diff --git a/Libs/MiniZip/zip.h b/Libs/MiniZip/zip.h new file mode 100644 index 0000000..39215ca --- /dev/null +++ b/Libs/MiniZip/zip.h @@ -0,0 +1,257 @@ +/* zip.h -- IO for compress .zip files using zlib + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant + + This unzip package allow creates .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 + + For uncompress .zip file, look at unzip.h + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.html 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 _zip_H +#define _zip_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_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_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCtypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase)); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); +/* + Close the current file in the zipfile, for fiel opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip_H */ diff --git a/Libs/minizip.a b/Libs/minizip.a new file mode 100644 index 0000000000000000000000000000000000000000..e651787e135d3ba2e28e5e972bc7fd1363028193 GIT binary patch literal 253062 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

UQ!+cZENQQXhYqLh`S82>P8XZ@ci zT1NUQZRc57G4~lZOYZ$^BV!mI*xWN!xzn@YlYo-6ewp~+ zodv%?3qAmx^1P!exs1WUewKy)%`EuAEI41gGs#(u^kl+WZkg~ivfz`m;6dO_*Vj}P zmH7Z<2`hY>s_LtN(JaiuXPKh^fufgr0O-52(BF^+zcmZa`A4SoT6z<$(UM7KWTCw1 zL2V>rEn6yD6*2i=wsP50yy*dy|AwUz&la5#sJC>>y{AwM5fzbz3o&7C?^r0BD6Jjs zRwr&sjW%0N9SaxZhWhh24z}?adb6AVd=18-Ud;Z<6HdpUWEp7|w+q z?GY_USd?*QQ>tYRt?kUFcB;=P5s~f8NX=R*3I48B4vs18>-1iIn}Ks^*La_SQw>7n z+YOxMukpPK=U7yr+_ZkG+>DoM4VwNH1Lu&aaq6zoke+H88b98^*~e)75(78s&Ao2E z4`})ZMX%-5{qs_T&#?x5w}G4S_GiJrWAHaet9uQ4Gav5v(L0EnhC6*U{(Rf+qhIZj zS$ne3zi!~B?!$XNK016JBZQ%4=0l;vnQu(jK^6W;gWgQn(LVYr^?ZC5`f7uo^@rmb z4exKJ(dAX^Jz8Hh_?!Stm+wsmJ>^`Xo^Lbg&2;g@>ol7G=epY~wuZw#FBY*g`WP&gk=c{Uk1-$8V`w)*&JosJ(G^d_I#YVu0{X8z1oxGqPX zKMM?clTVw0o9+E81|PG%f8C%r>%$8^`bCh7X2_s74Rku*gu#c-yHvidH|R}1KQQpq4L$=tKKkDMod&&G4}WCfW;q_E=3C4k=7pAX zyn&Y)_!$b<^=(keUun>r@?U7+CZ8DwZjLWk8~j+qwA81yFp6$Wmm>mdU-`~PhQ ze`bm9|DQJKP5!SLINynM{^YCqCG*YfuL26!`J?-*@dmxg|5^h-)8K!dk58%U7orBe z$!EQRn{o~sIA5W){6&Ti?C}O(PQhWAF22)g`U?&GECc^y7W_7a(_%S(8$X)02E8f& zJwEy^9=Y|sEc62g&bf@1^H~Ew+rVEi__N%xA1G$Xpf}}t%fQY4=NL{RVVFM?@ze26 zGw?GE{4)m5wJl9=!%agz{Ap9892(c})AN0}es9+8L(}W`)cbt&`aN}r57+OhC2C%y z`RMmc|NYzg{cMeoUcaB+=fm}T80O{JO4AyK#{JJ##?8-_;`Z);K5yC|tYcWo4n~<8 zvHu+RKWEfN(APoZW|N1RBUFY6;OmS~8i|!qsU{G_rut?InZ(siH{$-2*N5j;QiW{b z-MyJ~4zhee5&>0Q&;a0zj6_v5*o>X#THNbcgzfQ3j2&7SuXD?|4jy%luQ`o`w!Tyt z%K0fs#?-mzlqCy8O6PzAl=3^zHox;M7dlo#yRS-AFZNOOVn0MtdL5O~3u=Zh48HSGrcm?g^?XLJMf95O zW5|nxaUmw|NP#k2{KX0G8l@8W%&Hgnqq;gvA!mShWzt_IvxQRKpHbjWdacjswSrzZWbj&7 z)%zSm~--KczbW$@+2wh-xF@e1_u zeKnl8r>qA-pfH0kybecavU!!(RlnLjcIK}9GogCcgh$+1CEs)3Z>tIGAL>{ zbZkVQDjcYNNpq)mE}2--Np#Bi5j{l*=9RI~*Dirf;p#yhrf$-!yz@8DE0N?8#slT- z12^(2Wse!Xf!V>b314)NsM2-gOSZk@Ib&D8Z6)yydd~yb+(&U`g(0>lvyPTL$;gVH zL8mS3Qvu`-*>%EKq}?C82*Ruzfc}%Gi*z)#fNCD*Y+CMvearbaF7v;fx2Dul6R{F^ zxF%?uZd|`AI8`3s#a*dGzr>#|ZSfiUEt;rk^6W!2h9(a+ z)seh{`1?7r!v~p&=C#SWflat!csF!VaarH4oc>F`QQJR*3Yx*d?7h&|tnIH+PXoQr z#tNs)pprZpQXg5h?WU5O2R1Vc@D*UO)K`E-pBuIASnpfCV_>1nnO(?sZEcskS*h<` z&LpF&R~Pf35<{sm>=u>Pxm!c-9&{*DRR;eKiN=soKH^)z3!TL6tTc{02lw{OSwz-O z|5sSxPX9yF5JxMrX+1dUYmF~74_+)+L3^sFjytzAX?_xTgpM9pZP~N)(i`fERZ31K zadQnWj6n%HykHTIDmY5$Kfu0X%6-SPCDn_7NJg|gQXpyi6{|XAB{?WQ$ldMDMY{cV5z63GI_0G6CJS9R^ zsCs9hk6#K4#$U_hwc$HI_S$e<^&QIDiO<^OKG$IXEZ!RawEn*OYtfU2W`I+j`+K=9 zJQN?!58OTjjbwb?UsK%&JlE<7kPxNM9+? z#kd1>q%S(ilc)QXLx zZCm$$6<0qeiyr+d`-cLtsK$Oj%P}3-*GF;#fefo@f*VH>^o->26Wld@9Jl z84sSszZ8U8%WT`e4)Y1d<4MO}O=&TE_ay%E-cKt#{3Eyb#7HwCt?P}_~ z){KLd`Wdx0?{(ehoSBm+Gk&z&?!Nz@=l7d=&U2mn+~@l|_j8_e?wfvhN~05>GB?lZ z+Nfr*`#$9i#`4`D?PX13$1B_H#oPW~dWu{ykp`}^6+f>z%(+{pG>E7_!PtqoZ#h|1 zcsY>coHg&ET7CXoe*n72$kvJ9*n(p<-{F{})%hFe)+SmZ)W)R%m_pFQdutdB_-K>)vZd3xn2B)&sw6bkPA9Y5oJ{2~lXhCmD&fg194KI8AW9&4t?D2~nyq&+z_@J%}ul&Is@iLrOtnMFS}vo}@dzf1`9#8~}o<`nSL*6o0G&7hhBf z2DOPXk-Wo^!~+gM9%2~-y~d#lIGnJqupG9vtdLO*0m{RZp_uhhc@ z2f3ych20xD)p6F~Q|uUBWB!gfl1(fw#j6-3ZK()f?0oPjMdn8&Uj%((N(IEE>Al$a zpH}@}q*eb1jOzcrEASrF8bF0?0Ympyjw-aJjAV4}N*S(|i%TmPS0Hl%{Fuq=yr%Nf zB!>$Q6&CwD*3y?)j7b(Gti8uklRzL}2t(!x-ESRdc}(q-(1JVQ#k^h(Lm83E!#aH` zRD~#E&Q3@!YAe6H4YZ-k*TZ=@qXAiEL|*KebV=Vv7%{MXmEIdG;Cl`aUja$xpNiC_ zR-OO>JJ%hQ=eFB7KhigR_9XvN-{9g)^4*ki5YV6G)M0K?t5Di%k!Yz;e+z=JWZ})d zQ+YRY&q&Bqe=1UoYMS95{zPRC7oeI$m9K^Inym`%?;Oi~{1LJUiU!GTPsMG5ppVgHIIJeyd6Hzrspe!=%pYoC<22GFA1&;e9#241;z~N>OOm~+^)HD@$ z!BqFzrib`Wjv>a`dOSQ zS9GB|=ZaA#8IPS|W;L9kQBS;!Ob!bbAz2=j3G&3DY$>%8Si#J7 zy_#M*i23!RVnJcprG*Sb2m#>5-WQ;`IsJZ<4w}TE-C2Vq)>aAfcbOZs zxQbNm?>r7@@6(GFVXBa@2JJ-x=Hg+S6{*E6EWN>Wq+lB!SwhiJF9>7OsMM-mIoUTf3agTR`LUC+7_eW|dtm(SAIhgyY8X8H=!j^n zEywNL%FF)FEx6F>R1hGK70B?`- zVhn9!r8tS1=uMlBC@)6EratAJ4X?;9`=?d|!AR~ajvbFj8{XSj?(bwBab8F*K|oP# zp$eD_Rm6@^@1I(yue0^Fh}Zp7OXarf=AwsN;FEQq#~~uBvwvt-)cY~Ik{Kg)jA?`< zWh7KYH&9f>y}Xz=s7|T2giIpn9?-8G&PQ*V+Gf&o@8*=VKQ1y8VwyD=nDpb3M%DzF z?uGav0#w(1BL3}<^P;Sl#wWq6441}(@X~fEY$A*(@4yPH|8dB+SY~>+cPF$LN8)?( zbWjXWjX0Bb5*w5xSO-Z^FUK-bndR8KWR@E*lscH7thkg@$JOh2-_icHYXxa4ucIdV zZ@}n~WL6oUoPdNUO!cjs>QkmvnVE^eDCX7HycT=fWF#JJD^?YO#B@a@S$`pUt4RJ! z#!GQTjYu)CrH27uT(ox$yfULChhW)O#%}Thu5NM!_rQ~Ujd%96_3y|NLtDAn8^+&& z(1&#B|7K{j6^ai3V(;+?mE_1^8%Z|eFAQlhzNgWaMzAs*Vv($s4z3nQ+#~XQSG{g< zxQdgLWG0?&e6Svyeu9-q$4L#7hkdHdv~2%Oc|>Rl3_Kc+j*7q|`u zBW-vk80uU!eJ<^_O>f*Sbn5?2dsQild1OVS#B~3h*T`n*^hT>^UL)-VZJ3y-noz}k z^IjK_kL!Ou4cqc!icEOV!g1E)-V-|RHK8L`Ek3lPzLF-a{R?@`oa3VUX5lekhjTW_ zrvJJ_hacoMi~eh-wN=yHiKpzxo>SX^vtWg}bu7Q7c{THjb9MQPN{U!EE^W{SGk$=#Ey%dFFnK`-At>B+NCs>`|BIg8|-`P6650BuF&2M)>!LM_it7H4zrFn60 z74yq;fXu^ojUOPM&cn`h9)7LEi#|ynjuaFe&T)Q@bwe!%bQ9FY7r=G0##RxVR#F(oN`rbX7*BML?j``}=*g1lzcKU_JULZEF zq&hxiZQ=TYuKfIOmlW;Z_ta0PWuU8n`qVzjEbFtF^#u1M|7KD<{Mv%``S}mBFl^Iv zbolK19ZSexqMH06*LMDvfW|^kX!B4e&DfyET3h zap?mqnO*50zt&;*Gi-LI(D{F-`uiVr_=OCI3*cAE@dekyzjU8kBz=m|f6-aWzuFK1_#oPsg^QV_zk%$q0!n8fAO~ zuimuSugUXIjXxf7nZ6mf@QO3(d+UX?bmkh=em$fZBrc%y{}lrm+;h)yLtfP${CXYV zoWU}|CS7wSf8#eayxx|h{=BpcbbN3AH|Y4)o(ebZXVRJnkB3Bpj<90kwrR#}f4&i! z_@@1j1?Fu#K)&uV{Lk2%PgzVn$RNBDH}~vcbffVjevRDud?Jg$f1bwoYJ9D}LKGGHFX zYWzx#pRDUe9xSp=@gFFxbXXd$cHJ-0CD>4egY08g$+BGh63GlA~&sMHkIdGm? zBp*i};A);{`U^GQtZ_Zee9aoaL*pWwfWAZHZ6`3cmOXIY3_M$YzN_gk(E~ta5zs%B zgMM!g{O6j_vlM*bbhdo2X#7=;2P70@1>=F`9j+&AJ$?C3(D*owiyVSD+z>+gMvdRE z`ApFGDf+o;!^(pE!j-FlC6D(&Qpnw55P#Ev#JNnsn7E|BOAQF3n*ZAJ?gH8jm9I_T)9 zW zh1>OTwT0XH2_P*x^5@UEiP~duUA^gbC4*n1=^8!sMxI;e!Hqn3j|VsMT%QLwauwIQ z=}fvtek%9iMt+*?!HxXnJ!50!r>!1(BlmQBa3lBhcyJ^4oTDqz|Ipo2O98;=aE*Q+8kz=YoxRF_BlP=|!HxW}Xz9F`MW5n~(}bD}aQcaE?(o%9Yp3Ps=>|ldxvHrN;P*jz;U0Azn2$1HvV3I^dy++^e^y_3gZ*h z7}0K- z>j$=%7m)?7A`|1vIfnNEeXY>fYJHu=>u%@@xz@Mr>}#pR(l>p|lnVnD;f8A$&1()! ztonS__;C{|m50O`8Q8lP&PR)$K1CMbx?HVZmoxJi-}7y}miKU%@elO*mnwUG^LY>F zrN2qRDjm?z()@4Ff-^5>eyd~n%_XJNONy`p8{=JzS$a6$Rke^sq3m%#K5*6^as z)V0z0mNhiZtBOKxh_8y~aeP(Rwzm4JmM!ItQhYZ4f6SVl(U)P0CVj%(;F@dAF33d% zIKEra@i|Mc^etSaPvOevBXMhZ;tuEAvkv0H>qF;&mOTH|_~Q|mNtt(9c*U9YDI?g< zWXoKG2&7-ef<^ehG=Y9pr$bCUbB*ZuX#(xJ&k%S5yfB~H#5kwgZks0Tu|fDv{Tuje z@aSpTKyp2#3*N0!wjbk~_@@0hw!C%ED4TVL8hK+mZ~n98o#a9NP7u_5ih;39dDADB zE&X;)_!z=%=S|-Zv;Cy|ORl*wt=wx|dLhWpkkFgb4-Cj=laBSmH38#f4#W*bS??Go z&FT1&-q4vV$3-^!8cjbMS2~${ab~+ z-wd4e|3G3mL*E5|Hu{agNiUCW`0Mba`!0Uj=>Hiw>4)no4dPy$5?<V1tQ%@Tm`SUx0apzk&!;Jfag>%dr7tkK&pFiV7*20a!O`c5uHTY;9p;2EA ze!aeL_u#ka`^_HQjHi1&xEVJGJ-8VkRO@DIE*O8_#Ltf(e?fJ14!s4RpK$&Kl;}T= zOuyBt;GpC~=`Dcyg*Auy5*Xp8d6*aIC@<30+|75_itm&0p^Mp z^@|q$TAVo4Mk}B}A7dX!x6;m9D5w8%a#_qRJp-Am4r znCutCag9d64i3yPJHZEV0BXBWbW%MTxp%cV=;-uGF1bnh1_? zr;I>iIJd=uU3ImX5PF;mNMxKEQ{{kwKU@$I0MaiJJJOWdd|Aj8gpElDxiRSwHzxIP zV-mI~MY%=kCfTCoIPT=~hzpB8zn~d|B0EDg>=dn6_7@yCi8IUca$}5WIQ56rKD$WG zua^hRK0Z{`h_nF!DMv_cN`(cEu`Ui$Mu}^+dEzSpEN9i8N-oCu%@FWbOko!mMRL-yo#s8QWJ(~Zk zM*?8#v%id@p>IH&Qtv`NSD|l&H4eBLmH;-xo;~ z?{BXe7n|e2>_e)K|L(5%OE0#+e_8aX_V+{BUVaGYBiZk|+71TW`;S^N%>Q_IxNG*o z_V+K1j%ojg_OBY}bb%5CU9wdhEX9HVX8S2 z`#pBzFKYtf@%{%1?_5T0B(1vNReV1vK&Aa0V+;ZFvX z$&qB7+nndJ+D{yiB?(KOhbRN!Oir=W6T`PLRP#IkZN(syo+3Sx6-+u#OzUtByZ4uO z;L1VXHp6|zsSoo^ADj)IjI>KY#Yt<#4Wz)Nlw># z$=V~nAh=<~&o-vHq->MVg}th8#74jf9F+t>R{)T=Va4kAsRCe7gwW0uqtyt3W`Ih^ zedA#QIv$Qkp-a-vRXzq3?5BnDoX#g;o$3gZZxW3H@tz_FnPv6Rj*G*(ZJ{rS8DSE6 z;aXj!t`*$>jQap_5YnVynQV0jNE%<(6PCdFINHK1=Cip{3n6zO`tnJG&D(|DHM@?1$`Kyt~ z##dF3Zy0yo!a?R`82Aay%X})^GDfhptjpN8Wgv4JJ2LZVC8nC@S;p0P?aEv=?mDk= znO0htfstxuOJ-@nGUFkJJy>#9s~FmW;gflRK&S6RpvWC{yz=CwUI;4eZ z+NO%HKH@%|Es}XxtK450(9tsuo#_g+3W6$SVpd16!WW=B>W-JrN4mopTP5g-*{qAC z=`tN_Fx|(lB5^;B=%UY%@387#S5mFbQk15Us47nlwQYmbVZ!SE7pY@ z^t$j|jq{rz@oP2Srg3>+1kSy}0bm<6?!yG>ySAh*K5XsK^+UP}Z!7p_e*S-y6x9MY z55(KJ&h^pzTc?*CDJ)o)V}Gk8_2;fN+e^>?gKTa*S0trN|COeF%9CsDxlzB^&(&*) zT)$vb7}wP%z5dW6}Iv~=bg)P8UL ztvdhadnDt~nevsxIk&6VF^{BgFXAMDSGV_%=qrmv)K9@R%Fm zs!e=P1e1S5+z5}iO&E579RtpcL$YI)nE0msxpv}hJ3zi_y{@o=HPJIO2b zqKw(EOm>_cz3DSg+0t*}f*9Pp>XQEVrk@V*cu4o(w|1=uohMI!37Z=-rz0I!mv?Sp z@|^p#;pI8-D&Sn>HGJhc01Ps0Rz6d6;I*2MUpJUMH-K^NG+TbI()1T-db9pmukna! zcztco!6%vn=h|$xblY>_Yk{*KBD!Or>!+QFY1%+jS^Dd*igS1Mjs&X$s+qegAN%36JnFX zSed}S$Z23bWf_uCi}c*;r;Spm?SNvOVTo9t%xV?_8N7^^BlPvl4J*ho(){&BE$0!O zMPq}J<}^r5whRtNl#LAEmr);dY-X-Wn>BKmARKYdod*9`f^ft+ry2ZJf^eMUhKNu7 zy{`SF=Nh@8&(r;wIQyl+sa%MTeC%0dq(y%m!VLXs7CqB7bLp5I^c5C8`8)X0nKgUn z$L4>Lhkl(<`+UJ1{BN}A?Rsdp=61J67YY2b~+jr6Bkc)7;OgHaFadaJVN?Q}1)=es+TDuG_UFukY8DCwkw5Y3p zrAvLn1ru=#_sRDe21e_|aS4j|uc1plM3eJIp}DhvsM1O?tw^b)m{v-C6#fT?VYzyw zQUJlPWUIN#7~hSR>H@4(zrvM9Ih32)GzTpt@NthozJW~R~Q7> zO&sRz{GH;vYxR*-$-cs2isi1=Z@sB>1yJp5FE%FPBUG=~Z2f17;@P>V0i?M1{}Dy; zqGRL3_>R&LavuF^e8(?XglNR+`VL+;)YsA4u7}DHJR|YFYFwZNlAnvaG0}wF{r(4! z*T7x?;p&UKc?hMpPP z-zn)6#{O4pot^t*ca&m+?nRiWw>#0o*Pke<|dj@(U+1wG`h$hXkPAdW6J)?!1C^#ZV@M@wjWn@1g22?}}2V@(O6g`+21D z7qL5qDs_^4oJ}3CF2xEQB6pbz82HKi0NMc4O2~Z+iu~~vODTa?A4yU(okX7c7?}tm zkMfN$1l2-ReVGWA(F1KZp#VQCwzEbOp$hYf5q>BZQkpH{$K;_^S>n^oT&Q64cl;0! zsz>--bX=&1-Yy@@`mq;5eMm+1`8!sCBozNcUhEW)mS|0VyG~Ypp-nTvcT8b}vRPjh z;jPX?a&Y{>crQYYf2-xcSHVKFRr`0$1%c`-qFE|-ij(l9slH4mzkwXfr%cW9QF1^L z^8KBQA>-AeoLhioic{AXFu<3SCj*x_<&#r}yZHOIZExc5CTL2w|!HwO{mE3lnJ^B{t{fdn%K z5}@fE2O2=@VrBf!9mK4|>m;96JvT^&_T|uwJ0Qhd1~NpcD+UtG8$^K5wRWB#>0_y( z84Z~UIMB;hQCrg^%Ck>T6Plr{MuhA?NKS=(M(u~QXJA85DAILvo*qs3=#P=Yx$J<)+3P6;g=%8nnnDsALxW79B6NoTl9$B}!sX;NIBzJwzmv-moxh5mi?PGq z21QQS_Hxc0YPx?6wd(GkQTZ|wDMli(JF$xgT^7R7P58b~C33i`45MB#!D0$zt>C7P zH=L@Z6ixw}>|@FyN}Zrko%-mYn@LqL>@eV~I`&;{*Y({Wy-5;G#UA0@=5$4A_(bii z5@lbi-MUZ+<%`4j2w%l>&eok#jG5Ha14kg$b|I24c|9KJYE!{bmRu(#yi;cln!`FK zgIqLBQ{9xB0g~fBV8mX0Hs@2z^Ej7Uk&Q#DBJsfAoq296&0YSE(mXT@m0!hI&xWQ% zZWV=os<|%B*6b((R~6Zf(;vUF5j6kFGI!lg`K7k2ey-A^>5Gj+$yD?H0ea`-ef|DT z)M2VMXa>o5aT|mXf9F;*h>P0aqS(2$iM!VU(AzLxk@ON9DW@oPq~Xd}UAe`OxIDEq zF{LqaUpqo;_W7qDL6fEx>dw^)b=!Ojc{X=Pvtv*aXOOo$)GvtH?lKMw<0)m=4wN~h=k>5VGxjy_zWp!gdIa=LD1 zmB|cV+qE=ZZ-I2Z?SXoCtGdwHA!AIz4y5l&1#!|h`&6LqF)mdkN({)kJUDw+HEqkrHfc64px zJ~loy1h>@Ie|HkS1(G8t@n{byU|pp25tX@jdQ09!mrUa$H2&M(ciun_L~CmvjHRRr z%H`~s?4;@aIY=@gWjg8~dmjakyosV|=#OSzp?OwP?z+)YU2ZW7NRd%8WJ=SyR!EgX zxc-@C5mIbCBw5~7Vl>6cIDytdz2~w!c7BqBoWT#PQoY16`z-b(i84lLpi76m&yejB zGJu_^o(o_S*K-f_@x|*3zeZhV$*8A%*8pw8$*K6Wi;{xE>vWQD zFv*C{jKAXwblX&1;_H_Se@B2!Xd?kr12ocl<^`D&WVA^=DS3WY=*slm&=_$stJIcH z3gam=k;bj?WYHELsK$0%5kAwYJ#Da~(eLm4R{)OtHsoat1lTMSzEChs5otO;_&J@g zNh>+%UwousGnRJ`-MdeRyXN&9DFu_Eim-nt66k;9ht9iCJ6&Jv$4hYlvv};7$o^Y> zs7|TMr4gE6!Q^mM#1%Akbto}yg!6?*AxbYVa>mgPRSKqD>h6VjQ|I`nz?xOhQK7_@ zrP#8z^Q9r7f-8%iJb*9Zo$1SkJAX4IloaF5U>)F&%!9U z^$-cxmv13KSGc$e@<5<#GS)zLu<4}vK-B}k48q6jzLb|w8y(|c$J<ygAmq{_rD5`x|r7*_uf%ajQluEKVycx>rRSg~ZO_xloN zvZCf6)v4DH2vIYT3RyNFL`^U%WHv(L|HmrZDXMJl3%y@Jkgh8Zin2^jPSZ61);kh3 zVfVM0pnxhs-hc#03#bx&Txi$}$8z-GY=u@En#cQqBK0!RBrQYoOorq+ zk|e&R`likfx%?JV zFJe4TOb0VpBhz7{RV$y&V9p4#g!wAw1zE!Eyc}d%PI1I`|xDSKwAg+%T;SX~a z6Ys^3=2besDkYHl6TO0Yqj*D?o{aq+4(p_c{{wWsr>62dg&D@f)%UG8|&XeGIhMfx=ObTzss9``!H{~Oi?G@ z5xTfV)C&8j_DHw-8MCl|`fRqCdI1wF6H2jv^2dVmwI}&~@ouK~?^K*dT-f04yaw6A zBDjBie-3S@w2~^oOl0+>B+tA2Im1M=y@%!o;$F4RFpY<$0OpjQI^%JSCrA%MCh2ST zE%w?H50=6(TG~O%)iAzoW7!bn3Z53XP#PEmV^1RwVr5GhkvY5=$DtU+LCc#U{96^* zN$_q_-fDO^D{lq78goE^D=`%f3jNmbJ8AQt_Sagv{->1@0`=zcT~RohK{;mg)<$i)VXL%X?kqb7A!`)o{U(rCy|1@H-J0Xh%v`eybkF_ z^`qThBvlFu>~*i2D%B~Yi_cIdVV=T6U>foD-us}9Tt9^=bP54#LY+4z!QW;GewCHr z`V0YIQ=G&mzBQ#8k;j)aB;U$Ga<(CfVKH83k{0U_yEGkiHP?@doU=Dk9!isu<}fsC zOEF?KVZ7v%14|+E=YrwgkUG_rdtT;z<8o^GW(1#)yV(DFn!a=I zNiRiSPLUjC_8kzb)|m7w_$%-WYb?Sm_K2_N-u1NwA!_4(HNAHeKTXslyNQnnjm5^Uss6bocS^qxZRo zOM>}#WYZ*0!L?5FIhTB}*Zw*bd?LJ!8vi%q;NO*hNlDpy*3sI+P)S962-RdiR#E`~ zH3kCI80&b8j`z$^74MsjcU!?FC4sKOOG+x%4+)i2uN@jHnG_#3y`;S(ui(M#8}OO8 z!Iv*K{}WkMt{4 zyG%0pCo6Y-u5$nXO?UR3Q&~|N$1!a??mH{A0qsAeH}UcF7ac`Kc1KJb;-pW&cLsjM zHJOC*Z;K~g6W~qj90ZVOuJ~Sh@BMhhW%?8FvzFb-FJ?T@5N0#gD=qWz4@=!@!LHW>#dJ@i0`da z@@|v~)935c39|h;+)aGb{@lOmNdgFTU!N|Q^z%jCW$N9&_vW2pTgEDiNjh`K;FkOC zyy-Jf+0s8$sp7xqsW8v2BFgely1(RE2yRixraPO@g>1UB0~)^uSGtJ0_|C$W^#7#q z^mC2 zTQ`dCM!p9%{!5L^a~Bw0Hho4<0nf8~rrk%g=`B)xOz+@b#uZ4<&D0 zNqOf;hQ5Fw&o*q;8Ik8duvhTQM*l$$oRdX1dRiqX{~P!<6wZtHO4d{0ABr82}`0Iryy2f#043|8@@i zJ2`OLU19yq8>#Xsas<5FH2zDCiyQ&`ry5^)lA;$m0^XN2{(lUv`*jMqt=sxC6%7MJ z&VA(6Yz;LwQKjP=gmMUE4i0u)Ij?XrYv_z&_e4$-C8wq!UYqI z4r{RFnUU;zu0_E$@>|~``89`22Av~O$5ZAvC~ehXIq+1;SLdyOVsHthCh9@qM9AAd zurkrah-6bvtq$NUn+I<4mxVz#rg93#o6>}IhUgijdfNAZp2yft>^!j$!OL z5ceBd(&St{kp5=AN5FaUbNOJ)f`2my9^__kP0ucG(*1D`e6NMG%NzQUdY)l^Y(CXF z@Q{Vu_263gi5CBT7Eam7qBWDU13!i@8gQhy z>+@j?x7%xs7Mw|M(d!rSC_mi+qjXdqC%aaH*(eO9^A-PTRpgu zs}6W@BUkl$a3fb4yJjYzMy|RX&mTI28@Z~ z*n=CnfjW8y(Ccxs)q@-P;4Kesp3}wF{7Dk?oG$m^<~cptgPZ5{XF8xAH;0~Q>@3e2 z_L&Z7thMo7t5$mRXF8yDHGHZ|0Mwjrv6z*<*C0aZuTE1a z&u2QIRXsF%>c!NXfqAbVF9wopPgG2U3to4yq^z)QNn zSNZTc^#Oa4ad3NrJr!LQeNyS^Iy7Ja|jga3oRzt@ACadXgvoAE(aeXtIeK69;f zK!5)8pFcmxdF$#4lRoWv>$>B0;~)~&n(2X z5!WJIsZ6sN*A`q$ztDt^w*2UEykK|9h*Tl}v2`ZE-fdJts|`Ke$irhXLGD0jve=JM z2TSgd)gS*5)5A7mCSc%MlMf}#-r|DY+=4*^?QOqAysjIeSGr$fbDKU61`SfN%Vm1* zn!`q9rsUNBD$*4`wZDDRxv_$M++3+PjVm5qOY(Uv%bb_slBzF-L#Noo<{tJxcy)jK z2j7Su1r@17+CMlq_6khFm-i23f%6ivvxQlFQhw}oqr)>($~150CRGMr!$Rx6QQn{W zb~=QqqL%bYTdArYq!zXrA4xoc0$IC@)*S8yvj{dAb=_Zn5ME({y(P!G`-D*@Um3m` zAGb3y7Ix5bJL99wgwu78?2J_Vj6#nKhNdr4oE^udWn~G0EJOS<}YjL^?+iSau+b``Zlx1xhPtLp0rj0`mH}P~=U%UsWQ*aLP ziTH2ciSInC7SV7@t~+{OB;HpP3&dX;>OB2AcF&w0@6U@?#b3|IRq|KspVpHa1FGT~ z?prhbQ(sAaPM^Ih8F&WE|M(L;TaOctJi&{8&HZQhqqOvM0~*=UUxpo;d*FX$RA=fd zZr{5v?R<5};%DYpKF1RhH;ZM$!g6N21t%>%jl;v+&P9JOjnO*F zs>I_5Rbr~dsZoUfTj%36hm;X#z1R_~GaUmuiGz6!yU-$X8YANVOiqj;SLtoBgWI#~ z_VOTG3;l|do%AazqRrNQAk*7MKYbd zP^eX2gaI@V@02Fx@m#%+N{Tjk&`3XY4~32%>hGkCq(%ex&kApr^M>@ygN_{-l$~gK zwFeud5gQtg2dcx49t&OA$3PeMJ^oQaUowvJO#ZU}_FbYBJ600fFH3c>u!S7?j{2p) z^HxxJvKE2Le(q(Si6AL;tj_7u4T8h5710p8c?C8QH}>xf_G4J0P?=g&f$JJG3V~IL z4ck8;WsYQTfs+h)#24Vi`&+wmS7wt39%NW&QXA|{W>OcMCP>~S z2eGo0y$}yaY`pw#YM04s=dTuQh~1z33Ig0i7^EDC_8_IQlK9~O#wKhD6!TFWai8Ku zs!mIxdkyZBGE1i%9=63sXPlu$OyoAxc6h>#R};!N%1c{EnUa86mf2*Oa}lVP{a8&S z@jU@%FT0|V5249{QUZo!(F}Kw^gd}Qa2|;*+@5~E4Q2JEMt@X3)mc!QA3!@b;lw?* zrw8zitFTX1!rlNHGvxjO$#dcgfGvhUPBuS$I((AxH=VmBCscwE9l`(AqtlaIas}dN zsz=^|lNFp5jJ|Mz><69zqFJ9@$|Oa2N{y#TJoR`ujo96O;ka0gdd^b|_#f|iadK^R z=;SM-$E1clhLnAir)IpDMFZGiD<>N#hjHYQEW*3d+X~A=LYz81Bo;F!*TqhR!gQQ- zS><=?pKubjKLHg^8o4`_KJ|^Mv-G*>Q(^rfb}Da5eNgJr(Tx*z5aOsty)-q1mm-)* z2-Q60|7L{Z8whclxxqdLie<9FfWQ5g#Z8Adn> z!Dy$e?X>Q*p1vVPP2RFsImcR;#PWY=fErKlqpHQ4igVSFaOaJKJ~uP4 ^$wgr{e=%x6gY;=)BQFe6Myn5>2R>V{0H8(Gf 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 oo^1cM^dptd&c7DFTJbg?pIh|)P9OeFy +#include +#include +// Minizip! -- Included this in libs as it is a bit of a pain. +#include "../../../Libs/MiniZip/unzip.h" + +#include "EmptyBuffer.h" +#include "IFileList.h" +#include "../Convert/str2int.h" +#include "../Debug.h" +#include "ZipPackage.h" + +namespace saracraft { +namespace filesystem { +namespace { + +static const int BUFFER_SIZE = 100*1024; + +// -- + +void ConvertLower(std::string& str) { + for(unsigned int i = 0; i < str.size(); ++i) { + str[i] = tolower(str[i]); + if(str[i] == '\\') + str[i] = '/'; + } +} + +int FindTokenIndex(const std::string& str, const std::string& token, std::string::size_type start) { + if(token.size() >= str.size() - start) + return str.npos; + + for(std::string::size_type i = start; i <= str.size() - token.size(); ++i) { + bool found = true; + for(std::string::size_type j = 0; j < token.size(); ++j) { + if(token[j] != str[i+j]) { + found = false; + break; + } + } + if(found) + return i; + } + return str.npos; +} + +bool ContainsToken(const std::string& string, const std::string& token, std::string::size_type start) { + if(start + token.size() >= string.size()) + return false; + + for(unsigned int i = 0; i < token.size(); ++i) { + if(token[i] != string[i+start]) + return false; + } + return true; +} + +void FindTokens(const std::string& string, std::vector& result, const std::string& seperator) { + std::string::size_type start = string.find_first_of(seperator); + if(start == string.npos) { + result.push_back(string); + return; + } + + for(;;) { + std::string::size_type end = string.find_first_of(seperator, start + 1); + if(end == string.npos) { + std::string token = string.substr(start+1, string.size() - start - 1); + result.push_back(token); + break; + } + std::string token = string.substr(start,end-start); + result.push_back(token); + + start = end; + } +} + +/*void AddFile(std::string& file, IFileList& result) { + std::vector dirs; + FindTokens(file, dirs, "/"); + + std::stack dirsStack; + dirStack.push(&result.root); + + for(unsigned int i = 0; i < dirs.size() - 1; ++i) { + const std::string& dirName = dirs[i]; + + FileList::Dir* current = dirStack.top(); + int index = current->FindDirIndex(dirName); + if(index == -1) { + FileList::Dir newDir; + newDir.name = dirName; + current->dirs.push_back(newDir); + index = current->dirs.size() - 1; + } + dirStack.push(¤t->dirs[index]); + } + FileList::Dir* final = dirStack.top(); + final->files.puch_back(dirs[dirs.size() - 1]); +}*/ + +struct ZipFileData { + int size; + unz_file_pos filePosition; + + ZipFileData(void) : size(0) { + } +}; + +typedef std::map ZipFileList; + +struct ZipData { + unzFile fileId; + ZipFileList fileList; + + ZipData(const std::string& archive) : fileId(0) { + fileId = unzOpen(archive.c_str()); + if(fileId) + FindFiles(); + } + + ~ZipData(void) { + if(fileId) + unzClose(fileId); + } + + void FindFiles(void) { + unz_global_info globalInfo = { 0 }; + if(unzGetGlobalInfo(fileId, &globalInfo) != UNZ_OK) + return; + + char file[1024] = { 0 }; + for(unsigned int i = 0; i < globalInfo.number_entry; ++i) { + if(i != 0 && unzGoToNextFile(fileId) != UNZ_OK) + break; + unz_file_info fileInfo = { 0 }; + if(unzGetCurrentFileInfo(fileId, &fileInfo, file, sizeof(file) - 1, 0, 0, 0, 0) != UNZ_OK) + return; + if(fileInfo.uncompressed_size <= 0) + continue; + + ZipFileData zipFile; + zipFile.size = fileInfo.uncompressed_size; + unzGetFilePos(fileId, &zipFile.filePosition); + + std::string filename = file; + ConvertLower(filename); + fileList[filename] = zipFile; + } + } + + void FindFiles(std::string dir, std::string extension, IFileList& result) { + ConvertLower(dir); + ConvertLower(extension); + + if(extension.empty()) + return; + + std::vector tokens; + FindTokens(extension, tokens, "*"); + if(tokens.empty() || tokens.size() > 1) + return; + + ZipFileList::iterator it = fileList.begin(); + for(; it != fileList.end(); ++it) { + const std::string& file = it->first; + if(!ContainsToken(file, dir, 0)) + continue; + //if(ContainsToken(....) + + std::string::size_type fileStart = file.find_last_of("/"); + std::string::size_type index = FindTokenIndex(file, tokens[0], fileStart); + + // This will only detect search tokens begining with "*" -- FIXME + if(index == file.size() - tokens[0].size()) + result.AddFile(file); + + /* Eh.. Just find each token index (if there is one..) and move those forward + // hierarchically if needed. + if(!ContainsToken(file, dir, 0)) + continue; + if*/ + } + } + + bool FindFile(std::string file, ZipFileList::iterator& it) { + ConvertLower(file); + + it = fileList.find(file); + if(it == fileList.end()) + return false; + return true; + } +}; + +#if READ_CHUNKS +class ZipInputBuffer: public IInputStreamBuffer { + boost::shared_ptr zipData; + unsigned char buffer[BUFFER_SIZE]; + int currentPosition; + int readBytes; + unsigned long offset; + + ZipFileData fileData; + + /*void Release(void) const { + + }*/ + void FillBuffer(void) { + beginTime(); + int readSize = BUFFER_SIZE; + if(readBytes + readSize >= fileData.size) + readSize = fileData.size - readBytes; + + currentPossition = 0; + int id = unzGoToFilePos(zipData->fileId, &fileData.filePosition); + if(id != UNZ_OK) + return; + if(unzOpenCurrentFile(zipData->fileId) != UNZ_OK) + return; + + if(offset > 0 && if(unzSetOffset(zipData->fileId, readBytes) != UNZ_OK) + return; + + unzReadCurrentFile(fileData->fileId, buffer, readSize); + //offset = unzGetOffser(zipData->fileId); + unzCloseCurrentFile(zipData->fileId); + + endTime("fileBuffer"); + } + public: + ZipInputBuffer(boost::shared_ptr& zipData_, const ZipFileData& fileData_) : + zipData(zipData_), + fileData(fileData_) { + + currentPosition = -1; + readBytes = 0; + offset = 0; + } + + ~ZipInputBuffer(void) { + } + + unsigned char PopByte(void) { + if(!zipData->fileId || readBytes >= fileData.size) + FillBuffer(); + + ++readBytes; + return buffer[currentPosition++]; + } + + bool IsEof(void) const { + if(!zipData->fileId || readBytes >= fileData.size) + return true; + return false; + } + + int GetSize(void) const { + return fileData.size; + } + + void PopBytes(char* buffer, int bytes) { + for(int i = 0; i < bytes; ++i) + buffer[i] = PopByte(); + } +}; + +#else + +class ZipInputBuffer : public IInputStreamBuffer { + boost::shared_ptr zipData; + std::vector buffer; + int position; + + ZipFileData fileData; + + void FillBuffer(void) { + int readSize = fileData.size; + + if(unzGoToFilePos(zipData->fileId, &fileData.filePosition) != UNZ_OK) + return; + if(unzOpenCurrentFile(zipData->fileId) != UNZ_OK) + return; + + int bytes = unzReadCurrentFile(zipData->fileId, &buffer[0], readSize); + assert(bytes == readSize); + + unzCloseCurrentFile(zipData->fileId); + } +public: + ZipInputBuffer(boost::shared_ptr& zipData_, const ZipFileData& fileData_) : + zipData(zipData_), + fileData(fileData_) { + + position = 0; + } + + ~ZipInputBuffer(void) { + + } + + unsigned char PopByte(void) { + if(position >= fileData.size) + return 0; + if(position == 0) { + buffer.reserve(fileData.size); + FillBuffer(); + } + return buffer[position++]; + } + + bool IsEof(void) const { + if(position >= fileData.size) + return true; + return false; + } + + int GetSize(void) const { + return fileData.size; + } + + void PopBytes(char* buffer, int bytes) { + for(int i = 0; i < bytes; ++i) + buffer[i] = PopByte(); + } +}; +#endif + +} // Namespace unamed. + +struct ZipPackageData { + std::string archiveName; + boost::shared_ptr zipData; + + ZipPackageData(void) { + } + + void Load(void) { + zipData.reset(new ZipData(archiveName)); + } +}; + +ZipPackage::ZipPackage(const std::string& archiveName) { + boost::scoped_ptr tempData(new ZipPackageData()); + tempData->archiveName = archiveName; + tempData->Load(); + _data.swap(tempData); +} + +ZipPackage::~ZipPackage(void) { + +} + +void ZipPackage::FindFiles(const std::string& dir, const std::string& extension, IFileList& result) { + _data->zipData->FindFiles(dir, extension, result); +} + +InputStream ZipPackage::GetFile(const std::string& filename) { + InputStream inputStream; + + ZipFileList::iterator it; + if(_data->zipData->FindFile(filename, it)) { + boost::shared_ptr inputBuffer(new ZipInputBuffer(_data->zipData, it->second)); + inputStream.SetBuffer(inputBuffer); + } else { + boost::shared_ptr inputBuffer(new EmptyBuffer()); + inputStream.SetBuffer(inputBuffer); + } + return inputStream; +} + +} // Namespace filesystem. +} // Namespace saracraft. + diff --git a/src/System/Filesystem/ZipPackage.h b/src/System/Filesystem/ZipPackage.h new file mode 100644 index 0000000..5f0160c --- /dev/null +++ b/src/System/Filesystem/ZipPackage.h @@ -0,0 +1,22 @@ +#include +#include "IFilePackage.h" + +namespace saracraft { +namespace filesystem { + +class IFilePackage; +struct ZipPackageData; + +class ZipPackage : public IFilePackage { + boost::scoped_ptr _data; +public: + ZipPackage(const std::string& archiveName); + ~ZipPackage(void); + + void FindFiles(const std::string& dir, const std::string& extension, IFileList& result); + InputStream GetFile(const std::string& filename); +}; + +} // Namespace saracraft. +} // Namespace filesystme. +