/* zip.c -- IO on .zip files using zlib
Version 1.1, February 14h, 2010
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
For more info read MiniZip_info.txt
Changes
Oct-2009 - Mathias Svensson - Remove old C style function prototypes
Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives
Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions.
Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data
It is used when recreting zip archive with RAW when deleting items from a zip.
ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed.
Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required)
Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
*/
#define NOCRYPT
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "zlib.h"
#include "zip.h"
#ifdef STDC
# include <stddef.h>
# include <string.h>
# include <stdlib.h>
#endif
#ifdef NO_ERRNO_H
extern int errno;
#else
# include <errno.h>
#endif
#ifndef local
# define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */
#ifndef VERSIONMADEBY
#ifdef _WIN32
#else
#endif
#endif
#ifndef Z_BUFSIZE
#endif
#ifndef Z_MAXFILENAMEINZIP
#endif
#ifndef ALLOC
#endif
#ifndef TRYFREE
#endif
/*
#define SIZECENTRALDIRITEM (0x2e)
#define SIZEZIPLOCALHEADER (0x1e)
*/
/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
// NOT sure that this work on ALL platform
#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32))
#ifndef SEEK_CUR
#endif
#ifndef SEEK_END
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef DEF_MEM_LEVEL
#if MAX_MEM_LEVEL >= 8
#else
#endif
#endif
const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
typedef struct linkedlist_datablock_internal_s
{
typedef struct linkedlist_data_s
{
typedef struct
{
#ifdef HAVE_BZIP2
#endif
currenty writing */
int encrypt;
#ifndef NOCRYPT
int crypt_header_size;
#endif
typedef struct
{
#ifndef NO_ADDFILEINEXISTINGZIP
char *globalcomment;
#endif
#ifndef NOCRYPT
#include "crypt.h"
#endif
{
ALLOC(sizeof(linkedlist_datablock_internal));
{
ldi->filled_in_this_block = 0 ;
}
return ldi;
}
{
{
}
}
{
}
{
}
{
const unsigned char* from_copy;
return ZIP_INTERNALERROR;
{
return ZIP_INTERNALERROR;
}
while (len>0)
{
uInt i;
unsigned char* to_copy;
if (ldi->avail_in_this_block==0)
{
return ZIP_INTERNALERROR;
}
else
for (i=0;i<copy_this;i++)
}
return ZIP_OK;
}
/****************************************************************************/
#ifndef NO_ADDFILEINEXISTINGZIP
/* ===========================================================================
Inputs a long in LSB order to the given file
nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T)
*/
local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte));
local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)
{
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;
}
}
return ZIP_ERRNO;
else
return ZIP_OK;
}
{
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;
}
}
}
/****************************************************************************/
{
if (year>=1980)
year-=1980;
else if (year>=80)
year-=80;
return
}
/****************************************************************************/
local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi));
local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi)
{
unsigned char c;
if (err==1)
{
*pi = (int)c;
return ZIP_OK;
}
else
{
return ZIP_ERRNO;
else
return ZIP_EOF;
}
}
/* ===========================================================================
Reads a long in LSB order from the given gz_stream. Sets
*/
local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)
{
uLong x ;
int i = 0;
int err;
x = (uLong)i;
x += ((uLong)i)<<8;
*pX = x;
else
*pX = 0;
return err;
}
local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)
{
uLong x ;
int i = 0;
int err;
x = (uLong)i;
x += ((uLong)i)<<8;
x += ((uLong)i)<<16;
x += ((uLong)i)<<24;
*pX = x;
else
*pX = 0;
return err;
}
local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX));
local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)
{
ZPOS64_T x;
int i = 0;
int err;
x = (ZPOS64_T)i;
x += ((ZPOS64_T)i)<<8;
x += ((ZPOS64_T)i)<<16;
x += ((ZPOS64_T)i)<<24;
x += ((ZPOS64_T)i)<<32;
x += ((ZPOS64_T)i)<<40;
x += ((ZPOS64_T)i)<<48;
x += ((ZPOS64_T)i)<<56;
*pX = x;
else
*pX = 0;
return err;
}
#ifndef BUFREADCOMMENT
#endif
/*
Locate the Central directory of a zipfile (at the end, just before
the global comment)
*/
local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
{
unsigned char* buf;
return 0;
return 0;
uBackRead = 4;
{
int i;
else
break;
break;
for (i=(int)uReadSize-3; (i--)>0;)
{
break;
}
if (uPosFound!=0)
break;
}
return uPosFound;
}
/*
Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before
the global comment)
*/
local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
{
unsigned char* buf;
return 0;
return 0;
uBackRead = 4;
{
int i;
else
break;
break;
for (i=(int)uReadSize-3; (i--)>0;)
{
// Signature "0x07064b50" Zip64 end of central directory locater
{
break;
}
}
if (uPosFound!=0)
break;
}
if (uPosFound == 0)
return 0;
/* Zip64 end of central directory locator */
return 0;
/* the signature, already checked */
return 0;
/* number of the disk with the start of the zip64 end of central directory */
return 0;
if (uL != 0)
return 0;
/* relative offset of the zip64 end of central directory record */
return 0;
/* total number of disks */
return 0;
if (uL != 1)
return 0;
/* Goto Zip64 end of central directory record */
return 0;
/* the signature */
return 0;
return 0;
return relativeOffset;
}
{
spaning ZIP, unsupported, always 0*/
for spaning ZIP, unsupported, always 0*/
the central dir
(same than number_entry on nospan) */
int hasZIP64Record = 0;
// check first if we find a ZIP64 record
if(central_pos > 0)
{
hasZIP64Record = 1;
}
else if(central_pos == 0)
{
}
/* disable to allow appending to empty ZIP archive
if (central_pos==0)
err=ZIP_ERRNO;
*/
if(hasZIP64Record)
{
/* the signature, already checked */
/* size of zip64 end of central directory record */
if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK)
/* version made by */
/* version needed to extract */
/* number of this disk */
/* number of the disk with the start of the central directory */
/* total number of entries in the central directory on this disk */
/* total number of entries in the central directory */
/* size of the central directory */
/* offset of start of central directory with respect to the
starting disk number */
// TODO..
// read the comment from the standard central header.
size_comment = 0;
}
else
{
// Read End of central Directory info
/* the signature, already checked */
/* number of this disk */
/* number of the disk with the start of the central directory */
/* total number of entries in the central dir on this disk */
number_entry = 0;
else
number_entry = uL;
/* total number of entries in the central dir */
number_entry_CD = 0;
else
/* size of the central directory */
size_central_dir = 0;
else
/* offset of start of central directory with respect to the starting disk number */
offset_central_dir = 0;
else
/* zipfile global comment length */
}
{
return ZIP_ERRNO;
}
if (size_comment>0)
{
if (pziinit->globalcomment)
{
size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment);
}
}
{
if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
{
}
}
if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0)
return err;
}
#endif /* !NO_ADDFILEINEXISTINGZIP*/
/************************************************************/
extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def)
{
if (pzlib_filefunc64_32_def==NULL)
else
(append == APPEND_STATUS_CREATE) ?
return NULL;
if (append == APPEND_STATUS_CREATEAFTER)
ziinit.number_entry = 0;
{
return NULL;
}
/* now we add file in a zipfile */
# ifndef NO_ADDFILEINEXISTINGZIP
if (append == APPEND_STATUS_ADDINZIP)
{
// Read and Cache Central Directory Records
}
if (globalcomment)
{
}
# endif /* !NO_ADDFILEINEXISTINGZIP*/
{
# ifndef NO_ADDFILEINEXISTINGZIP
# endif /* !NO_ADDFILEINEXISTINGZIP*/
return NULL;
}
else
{
}
}
extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def)
{
if (pzlib_filefunc32_def != NULL)
{
}
else
}
extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)
{
if (pzlib_filefunc_def != NULL)
{
}
else
}
{
}
{
}
int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local)
{
/* write the local header */
int err;
{
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */
}
// CRC / Compressed size / Uncompressed size will be filled in later and rewritten later
{
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */
}
{
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */
}
{
size_extrafield += 20;
}
{
}
{
if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local)
}
{
// write the Zip64 extended info
// Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file)
}
return err;
}
/*
NOTE.
When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped
before calling this function it can be done with zipRemoveExtraInfoBlock
It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize
unnecessary allocations.
*/
extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
{
uInt i;
# ifdef NOCRYPT
/*(crcForCrypting);*/
return ZIP_PARAMERROR;
# endif
return ZIP_PARAMERROR;
#ifdef HAVE_BZIP2
return ZIP_PARAMERROR;
#else
return ZIP_PARAMERROR;
#endif
{
return err;
}
filename="-";
size_comment = 0;
else
else
{
else
}
if (level==2)
if (level==1)
zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment;
zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data
zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree);
/* version info */
else
else
else
zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4);
for (i=0;i<size_filename;i++)
for (i=0;i<size_extrafield_global;i++)
*(((const char*)extrafield_global)+i);
for (i=0;i<size_comment;i++)
size_extrafield_global+i) = *(comment+i);
return ZIP_INTERNALERROR;
#ifdef HAVE_BZIP2
#endif
#ifdef HAVE_BZIP2
#else
#endif
{
{
if (windowBits>0)
windowBits = -windowBits;
}
{
#ifdef HAVE_BZIP2
// Init BZip stuff here
#endif
}
}
# ifndef NOCRYPT
{
unsigned int sizeHead;
/*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
}
# endif
return err;
}
extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
{
}
extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
{
}
extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
{
}
extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi,
{
NULL, 0, VERSIONMADEBY, 0, 0);
}
extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
{
}
extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
{
}
extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi,
{
NULL, 0, VERSIONMADEBY, 0, 0);
}
{
{
#ifndef NOCRYPT
uInt i;
int t;
#endif
}
if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data)
#ifdef HAVE_BZIP2
{
}
else
#endif
{
}
return err;
}
{
return ZIP_PARAMERROR;
if (zi->in_opened_file_inzip == 0)
return ZIP_PARAMERROR;
#ifdef HAVE_BZIP2
{
{
{
}
break;
{
// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32;
}
}
}
else
#endif
{
{
{
}
break;
{
{
int bBreak = 0;
bBreak++;
}
}
else
{
else
for (i = 0; i < copy_this; i++)
{
}
}
}// while(...)
}
return err;
}
{
}
{
short datasize = 0;
return ZIP_PARAMERROR;
if (zi->in_opened_file_inzip == 0)
return ZIP_PARAMERROR;
{
{
{
}
}
}
{
#ifdef HAVE_BZIP2
err = BZ_FINISH_OK;
while (err==BZ_FINISH_OK)
{
{
}
if(err == BZ_STREAM_END)
err = Z_STREAM_END;
}
if(err == BZ_FINISH_OK)
#endif
}
if (err==Z_STREAM_END)
{
}
{
}
#ifdef HAVE_BZIP2
{
}
#endif
{
}
# ifndef NOCRYPT
# endif
// update Current Item crc and sizes,
if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff)
{
/*version Made by*/
/*version needed*/
}
if(compressed_size >= 0xffffffff)
else
/// set internal file attributes field
if(uncompressed_size >= 0xffffffff)
else
// Add ZIP64 extra info field for uncompressed size
if(uncompressed_size >= 0xffffffff)
datasize += 8;
// Add ZIP64 extra info field for compressed size
if(compressed_size >= 0xffffffff)
datasize += 8;
// Add ZIP64 extra info field for relative offset to local file header of current file
datasize += 8;
if(datasize > 0)
{
char* p = NULL;
{
// we can not write more data to the buffer that we have room for.
return ZIP_BADZIPFILE;
}
// Add Extra Information Header for 'ZIP64 information'
p += 2;
p += 2;
if(uncompressed_size >= 0xffffffff)
{
p += 8;
}
if(compressed_size >= 0xffffffff)
{
p += 8;
}
{
p += 8;
}
// Update how much extra free space we got in the memory buffer
// and increase the centralheader size so the new ZIP64 fields are included
// ( 4 below is the size of HeaderID and DataSize field )
// Update the extra info size field
}
err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader);
{
// Update the LocalFileHeader with the new values.
{
{
// Update the size in the ZIP64 extended field.
if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0)
}
else
}
else
{
}
}
zi->number_entry ++;
zi->in_opened_file_inzip = 0;
return err;
}
{
return zipCloseFileInZipRaw (file,0,0);
}
{
/*num disks*/
/*relative offset*/
/*total disks*/ /* Do not support spawning of disk so always say 1 here*/
return err;
}
int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
{
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ?
if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
{
}
return err;
}
int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
{
/*signature*/
{
{
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record
else
}
}
{
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record
else
}
if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
{
if(pos >= 0xffffffff)
{
}
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4);
}
return err;
}
{
if(global_comment != NULL)
{
if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment)
}
return err;
}
{
int err = 0;
return ZIP_PARAMERROR;
{
}
#ifndef NO_ADDFILEINEXISTINGZIP
if (global_comment==NULL)
#endif
{
{
{
if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block)
}
}
}
{
}
#ifndef NO_ADDFILEINEXISTINGZIP
#endif
return err;
}
{
char* p = pData;
int size = 0;
char* pNewHeader;
char* pTmp;
short header;
short dataSize;
return ZIP_PARAMERROR;
pTmp = pNewHeader;
{
header = *(short*)p;
dataSize = *(((short*)p)+1);
{
}
else
{
// Extra Info block should not be removed, So copy it to the temp buffer.
p += dataSize + 4;
}
}
{
// clean old extra info block.
// copy the new extra info block over the old
if(size > 0)
// set the new extra info size
}
else
return retVal;
}