This is the DOSBox-Savestates-Patch by gandhig (based on Patches from ZenJu & tikalat with ykhwong's Slot-Load/Save-Code) for DOSBox-SVN-r4019 from https://www.vogons.org/viewtopic.php?f=32&t=53116&p=573451 modified by APic to also work on the 64Bit-Linux-Platform and merged to apply against DOSBox-SVN-r4132. Everything is still to be considered unstable Alpha. Gameblaster-State is currently broken. Contains Crash-Fix for Mixer-State. Patch only tested under Linux. diff --git a/include/cpu.h b/include/cpu.h index 69557d0..f844b19 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -20,6 +20,8 @@ #ifndef DOSBOX_CPU_H #define DOSBOX_CPU_H +#include + #ifndef DOSBOX_DOSBOX_H #include "dosbox.h" #endif @@ -377,6 +379,10 @@ public: desc.Load(table_base+(selector)); return true; } + + virtual void SaveState( std::ostream& stream ); + virtual void LoadState( std::istream& stream ); + protected: PhysPt table_base; Bitu table_limit; @@ -427,6 +433,10 @@ public: ldt_value=value; return true; } + + virtual void SaveState( std::ostream& stream ); + virtual void LoadState( std::istream& stream ); + private: PhysPt ldt_base; Bitu ldt_limit; diff --git a/include/crypt.h b/include/crypt.h new file mode 100644 index 0000000..8d818ac --- /dev/null +++ b/include/crypt.h @@ -0,0 +1,131 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(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++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/include/dma.h b/include/dma.h index a062432..f2db786 100644 --- a/include/dma.h +++ b/include/dma.h @@ -20,6 +20,8 @@ #ifndef DOSBOX_DMA_H #define DOSBOX_DMA_H +#include + enum DMAEvent { DMA_REACHED_TC, DMA_MASKED, @@ -78,6 +80,10 @@ public: } Bitu Read(Bitu size, Bit8u * buffer); Bitu Write(Bitu size, Bit8u * buffer); + + void SaveState( std::ostream& stream ); + void LoadState( std::istream& stream ); + }; class DmaController { @@ -106,6 +112,10 @@ public: } void WriteControllerReg(Bitu reg,Bitu val,Bitu len); Bitu ReadControllerReg(Bitu reg,Bitu len); + + void SaveState( std::ostream& stream ); + void LoadState( std::istream& stream ); + }; DmaChannel * GetDMAChannel(Bit8u chan); diff --git a/include/dos_system.h b/include/dos_system.h index 0147cbd..b50984d 100644 --- a/include/dos_system.h +++ b/include/dos_system.h @@ -78,8 +78,15 @@ public: virtual void AddRef() { refCtr++; }; virtual Bits RemoveRef() { return --refCtr; }; virtual bool UpdateDateTimeFromHost() { return true; } + + virtual Bit32u GetSeekPos() { return 0xffffffff; } + void SetDrive(Bit8u drv) { hdrive=drv;} Bit8u GetDrive(void) { return hdrive;} + + virtual void SaveState( std::ostream& stream ); + virtual void LoadState( std::istream& stream ); + Bit32u flags; Bit16u time; Bit16u date; @@ -128,6 +135,7 @@ public: bool UpdateDateTimeFromHost(void); void FlagReadOnlyMedium(void); void Flush(void); + Bit32u GetSeekPos(void); private: FILE * fhandle; bool read_only_medium; @@ -264,6 +272,10 @@ public: // disk cycling functionality (request resources) virtual void Activate(void) {}; + + virtual void SaveState( std::ostream& stream ); + virtual void LoadState( std::istream& stream ); + }; enum { OPEN_READ=0, OPEN_WRITE=1, OPEN_READWRITE=2, OPEN_READ_NO_MOD=4, DOS_NOT_INHERIT=128}; diff --git a/include/ioapi.h b/include/ioapi.h new file mode 100644 index 0000000..27f415c --- /dev/null +++ b/include/ioapi.h @@ -0,0 +1,200 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + 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 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include "zlib.h" + +#if defined(__APPLE__) || defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#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(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#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 int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +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)); + + +/* here is the "old" 32 bits structure structure */ +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; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/mixer.h b/include/mixer.h index a8e1aaa..2cf5f76 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -20,6 +20,8 @@ #ifndef DOSBOX_MIXER_H #define DOSBOX_MIXER_H +#include + #ifndef DOSBOX_DOSBOX_H #include "dosbox.h" #endif @@ -77,6 +79,10 @@ public: void FillUp(void); void Enable(bool _yesno); + + void SaveState( std::ostream& stream ); + void LoadState( std::istream& stream ); + MIXER_Handler handler; float volmain[2]; float scale; diff --git a/include/render.h b/include/render.h index c25ed82..ac17783 100644 --- a/include/render.h +++ b/include/render.h @@ -56,6 +56,9 @@ typedef struct { bool dblw,dblh; double ratio; float fps; + + double scrn_ratio; + } src; struct { Bitu count; diff --git a/include/unzip.h b/include/unzip.h new file mode 100644 index 0000000..f34d6ac --- /dev/null +++ b/include/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .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 of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + 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. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_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_info64_s +{ + ZPOS64_T 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_info64; + +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_info64_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 */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 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_info64; + +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)); +extern unzFile ZEXPORT unzOpen64 OF((const void *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. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +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 unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, 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)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *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); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +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) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* 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)); + +extern ZPOS64_T ZEXPORT unztell64 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 ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/include/zip.h b/include/zip.h new file mode 100644 index 0000000..ca9aaff --- /dev/null +++ b/include/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- 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 + + --------------------------------------------------------------------------- + + 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. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#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(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)); +extern zipFile ZEXPORT zipOpen64 OF((const void *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 zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_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)); + +extern int ZEXPORT zipOpenNewFileInZip64 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 zip64)); + +/* + 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) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +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)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 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 zip64)); +/* + 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)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 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, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : 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 + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 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, + int zip64 + )); +/* + 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)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file 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 +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/src/Makefile.am b/src/Makefile.am index a4029e8..7e48e1f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,7 +11,7 @@ endif .rc.o: $(WINDRES) -o $@ $< -dosbox_SOURCES = dosbox.cpp $(ico_stuff) +dosbox_SOURCES = dosbox.cpp save_state.cpp save_state.h miniunz.c minizip.c unzip.c zip.c ioapi.c mztools.c $(ico_stuff) dosbox_LDADD = cpu/libcpu.a debug/libdebug.a dos/libdos.a fpu/libfpu.a hardware/libhardware.a gui/libgui.a \ ints/libints.a misc/libmisc.a shell/libshell.a hardware/mame/libmame.a \ hardware/serialport/libserial.a libs/gui_tk/libgui_tk.a diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index 659d4a8..5a2ba27 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -23,6 +23,9 @@ #include "dosbox.h" #include "cpu.h" #include "memory.h" + +#include "../save_state.h" + #include "debug.h" #include "mapper.h" #include "setup.h" @@ -331,6 +334,10 @@ public: is386=desc.Is386(); return true; } + + void SaveState( std::ostream& stream ); + void LoadState( std::istream& stream ); + TSS_Descriptor desc; Bitu selector; PhysPt base; @@ -2404,6 +2411,10 @@ public: if(CPU_CycleDown <= 0) CPU_CycleDown = 20; if (CPU_CycleAutoAdjust) GFX_SetTitle(CPU_CyclePercUsed,-1,false); else GFX_SetTitle(CPU_CycleMax,-1,false); + + // savestate support + cpu.hlt.old_decoder=cpudecoder; + return true; } ~CPU(){ /* empty */}; @@ -2426,3 +2437,311 @@ void CPU_Init(Section* sec) { } //initialize static members bool CPU::inited=false; + +//save state support +void DescriptorTable::SaveState( std::ostream& stream ) +{ + WRITE_POD( &table_base, table_base ); + WRITE_POD( &table_limit, table_limit ); +} + + +void DescriptorTable::LoadState( std::istream& stream ) +{ + READ_POD( &table_base, table_base ); + READ_POD( &table_limit, table_limit ); +} + + +void GDTDescriptorTable::SaveState(std::ostream& stream) +{ + this->DescriptorTable::SaveState(stream); + + + WRITE_POD( &ldt_base, ldt_base ); + WRITE_POD( &ldt_limit, ldt_limit ); + WRITE_POD( &ldt_value, ldt_value ); +} + + +void GDTDescriptorTable::LoadState(std::istream& stream) +{ + this->DescriptorTable::LoadState(stream); + + + READ_POD( &ldt_base, ldt_base ); + READ_POD( &ldt_limit, ldt_limit ); + READ_POD( &ldt_value, ldt_value ); +} + + +void TaskStateSegment::SaveState( std::ostream& stream ) +{ + WRITE_POD( &desc.saved, desc.saved ); + WRITE_POD( &selector, selector ); + WRITE_POD( &base, base ); + WRITE_POD( &limit, limit ); + WRITE_POD( &is386, is386 ); + WRITE_POD( &valid, valid ); +} + + +void TaskStateSegment::LoadState( std::istream& stream ) +{ + READ_POD( &desc.saved, desc.saved ); + READ_POD( &selector, selector ); + READ_POD( &base, base ); + READ_POD( &limit, limit ); + READ_POD( &is386, is386 ); + READ_POD( &valid, valid ); +} + + +Bit16u CPU_FindDecoderType( CPU_Decoder *decoder ) +{ + Bit16u decoder_idx; + + decoder_idx = 0xffff; + + + if(0) {} + else if( cpudecoder == &CPU_Core_Normal_Run ) decoder_idx = 0; + else if( cpudecoder == &CPU_Core_Prefetch_Run ) decoder_idx = 1; + else if( cpudecoder == &CPU_Core_Simple_Run ) decoder_idx = 2; + else if( cpudecoder == &CPU_Core_Full_Run ) decoder_idx = 3; +#if (C_DYNAMIC_X86) + else if( cpudecoder == &CPU_Core_Dyn_X86_Run ) decoder_idx = 4; +#endif +#if (C_DYNREC) + else if( cpudecoder == &CPU_Core_Dynrec_Run ) decoder_idx = 5; +#endif + + else if( cpudecoder == &CPU_Core_Normal_Trap_Run ) decoder_idx = 100; +#if (C_DYNAMIC_X86) + else if( cpudecoder == &CPU_Core_Dyn_X86_Trap_Run ) decoder_idx = 101; +#endif +#if(C_DYNREC) + else if( cpudecoder == &CPU_Core_Dynrec_Trap_Run ) decoder_idx = 102; +#endif + + else if( cpudecoder == &HLT_Decode ) decoder_idx = 200; + + + return decoder_idx; +} + + +CPU_Decoder *CPU_IndexDecoderType( Bit16u decoder_idx ) +{ + CPU_Decoder *cpudecoder; + + + cpudecoder = 0; + switch( decoder_idx ) { + case 0: cpudecoder = &CPU_Core_Normal_Run; break; + case 1: cpudecoder = &CPU_Core_Prefetch_Run; break; + case 2: cpudecoder = &CPU_Core_Simple_Run; break; + case 3: cpudecoder = &CPU_Core_Full_Run; break; +#if (C_DYNAMIC_X86) + case 4: cpudecoder = &CPU_Core_Dyn_X86_Run; break; +#endif +#if (C_DYNREC) + case 5: cpudecoder = &CPU_Core_Dynrec_Run; break; +#endif + + case 100: cpudecoder = &CPU_Core_Normal_Trap_Run; break; +#if (C_DYNAMIC_X86) + case 101: cpudecoder = &CPU_Core_Dyn_X86_Trap_Run; break; +#endif +#if (C_DYNREC) + case 102: cpudecoder = &CPU_Core_Dynrec_Trap_Run; break; +#endif + + case 200: cpudecoder = &HLT_Decode; break; + } + + + return cpudecoder; +} + +extern void POD_Save_CPU_Flags( std::ostream& stream ); +extern void POD_Load_CPU_Flags( std::istream& stream ); +extern void CPU_Core_Dyn_X86_Cache_Reset(void); + +namespace +{ +class SerializeCPU : public SerializeGlobalPOD +{ +public: + SerializeCPU() : SerializeGlobalPOD("CPU") + {} + +private: + virtual void getBytes(std::ostream& stream) + { + Bit16u decoder_idx; + + extern Bits PageFaultCore(void); + extern Bits IOFaultCore(void); + + + + decoder_idx = CPU_FindDecoderType( cpudecoder ); + + //******************************************** + //******************************************** + //******************************************** + + SerializeGlobalPOD::getBytes(stream); + + + // - pure data + WRITE_POD( &cpu_regs, cpu_regs ); + + WRITE_POD( &cpu.cpl, cpu.cpl ); + WRITE_POD( &cpu.mpl, cpu.mpl ); + WRITE_POD( &cpu.cr0, cpu.cr0 ); + WRITE_POD( &cpu.pmode, cpu.pmode ); + cpu.gdt.SaveState(stream); + cpu.idt.SaveState(stream); + WRITE_POD( &cpu.stack, cpu.stack ); + WRITE_POD( &cpu.code, cpu.code ); + WRITE_POD( &cpu.hlt.cs, cpu.hlt.cs ); + WRITE_POD( &cpu.hlt.eip, cpu.hlt.eip ); + WRITE_POD( &cpu.exception, cpu.exception ); + WRITE_POD( &cpu.direction, cpu.direction ); + WRITE_POD( &cpu.trap_skip, cpu.trap_skip ); + WRITE_POD( &cpu.drx, cpu.drx ); + WRITE_POD( &cpu.trx, cpu.trx ); + + WRITE_POD( &Segs, Segs ); + WRITE_POD( &CPU_Cycles, CPU_Cycles ); + WRITE_POD( &CPU_CycleLeft, CPU_CycleLeft ); + WRITE_POD( &CPU_IODelayRemoved, CPU_IODelayRemoved ); + cpu_tss.SaveState(stream); + WRITE_POD( &lastint, lastint ); + + //******************************************** + //******************************************** + //******************************************** + + // - reloc func ptr + WRITE_POD( &decoder_idx, decoder_idx ); + + + + POD_Save_CPU_Flags(stream); + } + + virtual void setBytes(std::istream& stream) + { + Bit16u decoder_idx; + Bit16u decoder_old; + + + + + + decoder_old = CPU_FindDecoderType( cpudecoder ); + + //******************************************** + //******************************************** + //******************************************** + + SerializeGlobalPOD::setBytes(stream); + + + // - pure data + READ_POD( &cpu_regs, cpu_regs ); + + READ_POD( &cpu.cpl, cpu.cpl ); + READ_POD( &cpu.mpl, cpu.mpl ); + READ_POD( &cpu.cr0, cpu.cr0 ); + READ_POD( &cpu.pmode, cpu.pmode ); + cpu.gdt.LoadState(stream); + cpu.idt.LoadState(stream); + READ_POD( &cpu.stack, cpu.stack ); + READ_POD( &cpu.code, cpu.code ); + READ_POD( &cpu.hlt.cs, cpu.hlt.cs ); + READ_POD( &cpu.hlt.eip, cpu.hlt.eip ); + READ_POD( &cpu.exception, cpu.exception ); + READ_POD( &cpu.direction, cpu.direction ); + READ_POD( &cpu.trap_skip, cpu.trap_skip ); + READ_POD( &cpu.drx, cpu.drx ); + READ_POD( &cpu.trx, cpu.trx ); + + READ_POD( &Segs, Segs ); + READ_POD( &CPU_Cycles, CPU_Cycles ); + READ_POD( &CPU_CycleLeft, CPU_CycleLeft ); + READ_POD( &CPU_IODelayRemoved, CPU_IODelayRemoved ); + cpu_tss.LoadState(stream); + READ_POD( &lastint, lastint ); + + //******************************************** + //******************************************** + //******************************************** + + // - reloc func ptr + READ_POD( &decoder_idx, decoder_idx ); + + + + POD_Load_CPU_Flags(stream); + + //******************************************* + //******************************************* + //******************************************* + + // switch to running core + if( decoder_idx < 100 ) { + switch( decoder_old ) { + // run -> run (0-99) + + // trap -> run + case 100: cpudecoder = CPU_IndexDecoderType(0); break; + case 101: cpudecoder = CPU_IndexDecoderType(4); break; + case 102: cpudecoder = CPU_IndexDecoderType(5); break; + + // hlt -> run + case 200: cpudecoder = cpu.hlt.old_decoder; break; + } + } + + // switch to trap core + else if( decoder_idx < 200 ) { + switch( decoder_old ) { + // run -> trap + case 0: + case 1: + case 2: + case 3: cpudecoder = CPU_IndexDecoderType(100); break; + case 4: cpudecoder = CPU_IndexDecoderType(101); break; + case 5: cpudecoder = CPU_IndexDecoderType(102); break; + + // trap -> trap (100-199) + + // hlt -> trap + case 200: { + switch( CPU_FindDecoderType(cpu.hlt.old_decoder) ) { + case 0: + case 1: + case 2: + case 3: cpudecoder = CPU_IndexDecoderType(100); break; + case 4: cpudecoder = CPU_IndexDecoderType(101); break; + case 5: cpudecoder = CPU_IndexDecoderType(102); break; + } + } + } + } + + // switch to hlt core + else if( decoder_idx < 300 ) { + cpudecoder = CPU_IndexDecoderType(200); + } + +#if (C_DYNAMIC_X86) + CPU_Core_Dyn_X86_Cache_Reset(); +#endif + } +} dummy; +} diff --git a/src/cpu/flags.cpp b/src/cpu/flags.cpp index 63b7b45..6bb0904 100644 --- a/src/cpu/flags.cpp +++ b/src/cpu/flags.cpp @@ -26,6 +26,8 @@ #include "lazyflags.h" #include "pic.h" +#include "../save_state.h" + LazyFlags lflags; /* CF Carry Flag -- Set on high-order bit carry or borrow; cleared @@ -1186,3 +1188,16 @@ void DestroyConditionFlags(void) { } #endif + +// save state support +void POD_Save_CPU_Flags( std::ostream& stream ) +{ + // - pure data + WRITE_POD( &lflags, lflags ); +} + +void POD_Load_CPU_Flags( std::istream& stream ) +{ + // - pure data + READ_POD( &lflags, lflags ); +} \ No newline at end of file diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index d5cb2b8..6a1c69d 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -30,6 +30,8 @@ #include "support.h" #include "serialport.h" +#include "../save_state.h" + DOS_Block dos; DOS_InfoBlock dos_infoblock; @@ -1274,3 +1276,85 @@ void DOS_Init(Section* sec) { /* shutdown function */ sec->AddDestroyFunction(&DOS_ShutDown,false); } + +//save state support + +extern void POD_Save_DOS_Files( std::ostream& stream ); +extern void POD_Save_DOS_DriveManager( std::ostream& stream ); +extern void POD_Load_DOS_Files( std::istream& stream ); +extern void POD_Load_DOS_DriveManager( std::istream& stream ); + +namespace +{ +class SerializeDos : public SerializeGlobalPOD +{ +public: + SerializeDos() : SerializeGlobalPOD("Dos") + {} + +private: + virtual void getBytes(std::ostream& stream) + { + SerializeGlobalPOD::getBytes(stream); + + + + //*********************************************** + //*********************************************** + //*********************************************** + + // - pure data + WRITE_POD( &dos.firstMCB, dos.firstMCB ); + WRITE_POD( &dos.errorcode, dos.errorcode ); + WRITE_POD( &dos.env, dos.env ); + WRITE_POD( &dos.cpmentry, dos.cpmentry ); + WRITE_POD( &dos.return_code, dos.return_code ); + WRITE_POD( &dos.return_mode, dos.return_mode ); + + WRITE_POD( &dos.current_drive, dos.current_drive ); + WRITE_POD( &dos.verify, dos.verify ); + WRITE_POD( &dos.breakcheck, dos.breakcheck ); + WRITE_POD( &dos.echo, dos.echo ); + + WRITE_POD( &dos.loaded_codepage, dos.loaded_codepage ); + + + + + POD_Save_DOS_Files(stream); + POD_Save_DOS_DriveManager(stream); + } + + virtual void setBytes(std::istream& stream) + { + SerializeGlobalPOD::setBytes(stream); + + + + //*********************************************** + //*********************************************** + //*********************************************** + + // - pure data + READ_POD( &dos.firstMCB, dos.firstMCB ); + READ_POD( &dos.errorcode, dos.errorcode ); + READ_POD( &dos.env, dos.env ); + READ_POD( &dos.cpmentry, dos.cpmentry ); + READ_POD( &dos.return_code, dos.return_code ); + READ_POD( &dos.return_mode, dos.return_mode ); + + READ_POD( &dos.current_drive, dos.current_drive ); + READ_POD( &dos.verify, dos.verify ); + READ_POD( &dos.breakcheck, dos.breakcheck ); + READ_POD( &dos.echo, dos.echo ); + + READ_POD( &dos.loaded_codepage, dos.loaded_codepage ); + + + + + POD_Load_DOS_Files(stream); + POD_Load_DOS_DriveManager(stream); + } +} dummy; +} \ No newline at end of file diff --git a/src/dos/dos_files.cpp b/src/dos/dos_files.cpp index 49d7eee..54e447d 100644 --- a/src/dos/dos_files.cpp +++ b/src/dos/dos_files.cpp @@ -25,6 +25,9 @@ #include "dosbox.h" #include "bios.h" #include "mem.h" + +#include "../save_state.h" + #include "regs.h" #include "dos_inc.h" #include "drives.h" @@ -1332,3 +1335,212 @@ void DOS_SetupFiles (void) { } Drives[25]=new Virtual_Drive(); } + +// save state support +void DOS_File::SaveState( std::ostream& stream ) +{ + Bit32u file_namelen, seek_pos; + + + file_namelen = strlen( name )+1; + seek_pos = GetSeekPos(); + + //****************************************** + //****************************************** + //****************************************** + + // - pure data + WRITE_POD( &file_namelen, file_namelen ); + WRITE_POD_SIZE( name, file_namelen ); + + WRITE_POD( &flags, flags ); + WRITE_POD( &open, open ); + + WRITE_POD( &attr, attr ); + WRITE_POD( &time, time ); + WRITE_POD( &date, date ); + WRITE_POD( &refCtr, refCtr ); + WRITE_POD( &hdrive, hdrive ); + + //****************************************** + //****************************************** + //****************************************** + + // - reloc ptr + WRITE_POD( &seek_pos, seek_pos ); +} + + +void DOS_File::LoadState( std::istream& stream ) +{ + Bit32u file_namelen, seek_pos; + char *file_name; + + //****************************************** + //****************************************** + //****************************************** + + // - pure data + READ_POD( &file_namelen, file_namelen ); + file_name = (char*)alloca( file_namelen * sizeof(char) ); + READ_POD_SIZE( file_name, file_namelen ); + + READ_POD( &flags, flags ); + READ_POD( &open, open ); + + READ_POD( &attr, attr ); + READ_POD( &time, time ); + READ_POD( &date, date ); + READ_POD( &refCtr, refCtr ); + READ_POD( &hdrive, hdrive ); + + //****************************************** + //****************************************** + //****************************************** + + // - reloc ptr + READ_POD( &seek_pos, seek_pos ); + + + if( open ) Seek( &seek_pos, DOS_SEEK_SET ); + else Close(); +} + + +void POD_Save_DOS_Files( std::ostream& stream ) +{ + // 1. Do drives first (directories -> files) + // 2. Then files next + + for( int lcv=0; lcvSaveState(stream); + } + + + for( int lcv=0; lcvGetName(), "CON" ) == 0 ) file_valid = 0xfe; + if( strcmp( Files[lcv]->GetName(), "LPT1" ) == 0 ) file_valid = 0xfe; + if( strcmp( Files[lcv]->GetName(), "PRN" ) == 0 ) file_valid = 0xfe; + if( strcmp( Files[lcv]->GetName(), "AUX" ) == 0 ) file_valid = 0xfe; + } + + + // - reloc ptr + WRITE_POD( &file_valid, file_valid ); + if( file_valid >= 0xfe ) continue; + + //********************************************** + //********************************************** + //********************************************** + + file_namelen = strlen( Files[lcv]->name ) + 1; + file_name = (char *) alloca( file_namelen ); + strcpy( file_name, Files[lcv]->name ); + + file_drive = Files[lcv]->GetDrive(); + file_flags = Files[lcv]->flags; + + + // - Drives->FileOpen vars (repeat copy) + WRITE_POD( &file_namelen, file_namelen ); + WRITE_POD_SIZE( file_name, file_namelen ); + + WRITE_POD( &file_drive, file_drive ); + WRITE_POD( &file_flags, file_flags ); + + + Files[lcv]->SaveState(stream); + } +} + + +void POD_Load_DOS_Files( std::istream& stream ) +{ + // 1. Do drives first (directories -> files) + // 2. Then files next + + for( int lcv=0; lcvLoadState(stream); + } + + + for( int lcv=0; lcvGetName(), "CON" ) == 0 ) break; + if( strcmp( Files[lcv]->GetName(), "LPT1" ) == 0 ) break; + if( strcmp( Files[lcv]->GetName(), "PRN" ) == 0 ) break; + if( strcmp( Files[lcv]->GetName(), "AUX" ) == 0 ) break; + + + while( Files[lcv]->IsOpen() ) Files[lcv]->Close(); + + delete Files[lcv]; + Files[lcv]=0; + } + + + // ignore NULL file + if( file_valid == 0xff ) continue; + + //********************************************** + //********************************************** + //********************************************** + + // - Drives->FileOpen vars (repeat copy) + + READ_POD( &file_namelen, file_namelen ); + file_name = (char *) alloca( file_namelen ); + READ_POD_SIZE( file_name, file_namelen ); + + READ_POD( &file_drive, file_drive ); + READ_POD( &file_flags, file_flags ); + + + // NOTE: Must open regardless to get 'new' DOS_File class + Drives[file_drive]->FileOpen( &Files[lcv], file_name, file_flags ); + + if( Files[lcv] ) Files[lcv]->LoadState(stream); + } +} \ No newline at end of file diff --git a/src/dos/dos_mscdex.cpp b/src/dos/dos_mscdex.cpp index 73fbabd..30bded8 100644 --- a/src/dos/dos_mscdex.cpp +++ b/src/dos/dos_mscdex.cpp @@ -30,6 +30,8 @@ #include "cdrom.h" +#include "../save_state.h" + #define MSCDEX_LOG LOG(LOG_MISC,LOG_ERROR) //#define MSCDEX_LOG @@ -1355,3 +1357,79 @@ void MSCDEX_Init(Section* sec) { /* Create MSCDEX */ mscdex = new CMscdex; } + +//save state support +namespace +{ +class SerializeCdrom : public SerializeGlobalPOD +{ +public: + SerializeCdrom() : SerializeGlobalPOD("Cdrom") + { + } + +private: + virtual void getBytes(std::ostream& stream) + { + //writePOD(stream, xms_callback); + + SerializeGlobalPOD::getBytes(stream); + + + for (Bit8u drive_unit=0; drive_unitGetNumDrives(); drive_unit++) { + TMSF pos, start, end; + bool playing, pause; + + mscdex->GetAudioStatus(drive_unit, playing, pause, start, end); + mscdex->GetCurrentPos(drive_unit,pos); + + stream.write(reinterpret_cast( &playing ), sizeof(playing) ); + stream.write(reinterpret_cast( &pause ), sizeof(pause) ); + stream.write(reinterpret_cast( &pos ), sizeof(pos) ); + stream.write(reinterpret_cast( &start ), sizeof(start) ); + stream.write(reinterpret_cast( &end ), sizeof(end) ); + } + } + + + virtual void setBytes(std::istream& stream) + { + //readPOD(stream, xms_callback); + + + SerializeGlobalPOD::setBytes(stream); + + + for (Bit8u drive_unit=0; drive_unitGetNumDrives(); drive_unit++) { + TMSF pos, start, end; + Bit32u msf_time, play_len; + bool playing, pause; + + + + mscdex->StopAudio(drive_unit); + + + stream.read(reinterpret_cast( &playing ), sizeof(playing) ); + stream.read(reinterpret_cast( &pause ), sizeof(pause) ); + stream.read(reinterpret_cast( &pos ), sizeof(pos) ); + stream.read(reinterpret_cast( &start ), sizeof(start) ); + stream.read(reinterpret_cast( &end ), sizeof(end) ); + + + msf_time = ( pos.min << 16 ) + ( pos.sec << 8 ) + ( pos.fr ); + + // end = total play time (GetAudioStatus adds +150) + // pos = current play cursor + // start = start play cursor + play_len = end.min * 75 * 60 + ( end.sec * 75 ) + end.fr - 150; + play_len -= ( pos.min - start.min ) * 75 * 60 + ( pos.sec - start.sec ) * 75 + ( pos.fr - start.fr ); + + + // first play, then simulate pause + if( playing ) mscdex->PlayAudioMSF(drive_unit, msf_time, play_len); + if( pause ) mscdex->PlayAudioMSF(drive_unit, msf_time, 0); + } + } +} dummy; +} \ No newline at end of file diff --git a/src/dos/drive_fat.cpp b/src/dos/drive_fat.cpp index a58ae1e..a262efc 100644 --- a/src/dos/drive_fat.cpp +++ b/src/dos/drive_fat.cpp @@ -46,6 +46,9 @@ public: bool Close(); Bit16u GetInformation(void); bool UpdateDateTimeFromHost(void); + + Bit32u GetSeekPos(void); + public: Bit32u firstCluster; Bit32u seekpos; @@ -299,6 +302,10 @@ bool fatFile::UpdateDateTimeFromHost(void) { return true; } +Bit32u fatFile::GetSeekPos() { + return seekpos; +} + Bit32u fatDrive::getClustFirstSect(Bit32u clustNum) { return ((clustNum - 2) * bootbuffer.sectorspercluster) + firstDataSector; } diff --git a/src/dos/drive_iso.cpp b/src/dos/drive_iso.cpp index 2faa8ac..efbfd65 100644 --- a/src/dos/drive_iso.cpp +++ b/src/dos/drive_iso.cpp @@ -38,6 +38,9 @@ public: bool Seek(Bit32u *pos, Bit32u type); bool Close(); Bit16u GetInformation(void); + + Bit32u GetSeekPos(void); + private: isoDrive *drive; Bit8u buffer[ISO_FRAMESIZE]; @@ -133,6 +136,10 @@ Bit16u isoFile::GetInformation(void) { return 0x40; // read-only drive } +Bit32u isoFile::GetSeekPos() { + return filePos - fileBegin; +} + int MSCDEX_RemoveDrive(char driveLetter); int MSCDEX_AddDrive(char driveLetter, const char* physicalPath, Bit8u& subUnit); void MSCDEX_ReplaceDrive(CDROM_Interface* cdrom, Bit8u subUnit); diff --git a/src/dos/drive_local.cpp b/src/dos/drive_local.cpp index 46ebb7d..178719d 100644 --- a/src/dos/drive_local.cpp +++ b/src/dos/drive_local.cpp @@ -30,7 +30,6 @@ #include "cross.h" #include "inout.h" - bool localDrive::FileCreate(DOS_File * * file,char * name,Bit16u /*attributes*/) { //TODO Maybe care for attributes but not likely char newname[CROSS_LEN]; @@ -507,6 +506,9 @@ Bit16u localFile::GetInformation(void) { return read_only_medium?0x40:0; } +Bit32u localFile::GetSeekPos() { + return ftell( fhandle ); +} localFile::localFile(const char* _name, FILE * handle) { fhandle=handle; diff --git a/src/dos/drives.cpp b/src/dos/drives.cpp index 832eb91..e0c8344 100644 --- a/src/dos/drives.cpp +++ b/src/dos/drives.cpp @@ -23,6 +23,8 @@ #include "mapper.h" #include "support.h" +#include "../save_state.h" + bool WildFileCmp(const char * file, const char * wild) { char file_name[9]; @@ -109,8 +111,8 @@ void Set_Label(char const * const input, char * const output, bool cdrom) { DOS_Drive::DOS_Drive() { - curdir[0]=0; - info[0]=0; + ::memset(curdir, 0, sizeof(curdir)); + ::memset(info, 0, sizeof(info)); } char * DOS_Drive::GetInfo(void) { @@ -228,3 +230,45 @@ void DriveManager::Init(Section* /* sec */) { void DRIVES_Init(Section* sec) { DriveManager::Init(sec); } + +// save state support +void DOS_Drive::SaveState( std::ostream& stream ) +{ + // - pure data + WRITE_POD( &curdir, curdir ); + WRITE_POD( &info, info ); +} + + +void DOS_Drive::LoadState( std::istream& stream ) +{ + // - pure data + READ_POD( &curdir, curdir ); + READ_POD( &info, info ); +} + + +void DriveManager::SaveState( std::ostream& stream ) +{ + // - pure data + WRITE_POD( ¤tDrive, currentDrive ); +} + + +void DriveManager::LoadState( std::istream& stream ) +{ + // - pure data + READ_POD( ¤tDrive, currentDrive ); +} + + +void POD_Save_DOS_DriveManager( std::ostream& stream ) +{ + DriveManager::SaveState(stream); +} + + +void POD_Load_DOS_DriveManager( std::istream& stream ) +{ + DriveManager::LoadState(stream); +} diff --git a/src/dos/drives.h b/src/dos/drives.h index 14f3831..6ff929e 100644 --- a/src/dos/drives.h +++ b/src/dos/drives.h @@ -39,6 +39,9 @@ public: static void CycleAllDisks(void); static void Init(Section* sec); + static void SaveState( std::ostream& stream ); + static void LoadState( std::istream& stream ); + private: static struct DriveInfo { std::vector disks; diff --git a/src/dosbox.cpp b/src/dosbox.cpp index a501266..5bae9fd 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -22,6 +22,9 @@ #include #include #include + +#include + #include "dosbox.h" #include "debug.h" #include "cpu.h" @@ -43,6 +46,8 @@ #include "render.h" #include "pci_bus.h" +#include "save_state.h" + Config * control; MachineType machine; SVGACards svgaCard; @@ -342,6 +347,125 @@ static void DOSBOX_UnlockSpeed( bool pressed ) { } } +static void DOSBOX_UnlockSpeed2( bool pressed ) { + if (pressed) { + ticksLocked =! ticksLocked; + DOSBOX_UnlockSpeed(ticksLocked?true:false); + } +} + +namespace +{ +std::string getTime() +{ + const time_t current = time(NULL); + tm* timeinfo; + timeinfo = localtime(¤t); //convert to local time + char buffer[50]; + ::strftime(buffer, 50, "%H:%M:%S", timeinfo); + return buffer; +} + +class SlotPos +{ +public: + SlotPos() : slot(0) {} + + void next() + { + ++slot; + slot %= SaveState::SLOT_COUNT; + } + + void previous() + { + slot += SaveState::SLOT_COUNT - 1; + slot %= SaveState::SLOT_COUNT; + } + + void set(int value) + { + slot = value; + } + + operator size_t() const + { + return slot; + } +private: + size_t slot; +} currentSlot; + +void notifyError(const std::string& message) +{ +#ifdef WIN32 + ::MessageBox(0, message.c_str(), "Error", 0); +#endif + LOG_MSG(message.c_str()); +} + +void SetGameState(int value) { + currentSlot.set(value); +} + +void SaveGameState(bool pressed) { + if (!pressed) return; + + try + { + SaveState::instance().save(currentSlot); + LOG_MSG("[%s]: State %d saved!", getTime().c_str(), currentSlot + 1); + } + catch (const SaveState::Error& err) + { + notifyError(err); + } +} + +void LoadGameState(bool pressed) { + if (!pressed) return; + +// if (SaveState::instance().isEmpty(currentSlot)) +// { +// LOG_MSG("[%s]: State %d is empty!", getTime().c_str(), currentSlot + 1); +// return; +// } + try + { + SaveState::instance().load(currentSlot); + LOG_MSG("[%s]: State %d loaded!", getTime().c_str(), currentSlot + 1); + } + catch (const SaveState::Error& err) + { + notifyError(err); + } +} + +void NextSaveSlot(bool pressed) { + if (!pressed) return; + + currentSlot.next(); + + const bool emptySlot = SaveState::instance().isEmpty(currentSlot); + LOG_MSG("Active save slot: %d %s", currentSlot + 1, emptySlot ? "[Empty]" : ""); +} + + +void PreviousSaveSlot(bool pressed) { + if (!pressed) return; + + currentSlot.previous(); + + const bool emptySlot = SaveState::instance().isEmpty(currentSlot); + LOG_MSG("Active save slot: %d %s", currentSlot + 1, emptySlot ? "[Empty]" : ""); +} +} +void SetGameState_Run(int value) { SetGameState(value); } +void SaveGameState_Run(void) { SaveGameState(true); } +void LoadGameState_Run(void) { LoadGameState(true); } +void NextSaveSlot_Run(void) { NextSaveSlot(true); } +void PreviousSaveSlot_Run(void) { PreviousSaveSlot(true); } + static void DOSBOX_RealInit(Section * sec) { Section_prop * section=static_cast(sec); /* Initialize some dosbox internals */ @@ -353,13 +477,22 @@ static void DOSBOX_RealInit(Section * sec) { MSG_Init(section); MAPPER_AddHandler(DOSBOX_UnlockSpeed, MK_f12, MMOD2,"speedlock","Speedlock"); + + MAPPER_AddHandler(DOSBOX_UnlockSpeed2, MK_f12, MMOD1|MMOD2,"speedlock2","Speedlock2"); + std::string cmd_machine; if (control->cmdline->FindString("-machine",cmd_machine,true)){ //update value in config (else no matching against suggested values section->HandleInputline(std::string("machine=") + cmd_machine); } - std::string mtype(section->Get_string("machine")); + //add support for loading/saving game states + MAPPER_AddHandler(SaveGameState, MK_f5, MMOD2,"savestate","Save State"); + MAPPER_AddHandler(LoadGameState, MK_f9, MMOD2,"loadstate","Load State"); + MAPPER_AddHandler(PreviousSaveSlot, MK_f6, MMOD2,"prevslot","Prev. Slot"); + MAPPER_AddHandler(NextSaveSlot, MK_f7, MMOD2,"nextslot","Next Slot"); + + std::string mtype(section->Get_string("machine")); svgaCard = SVGA_None; machine = MCH_VGA; int10.vesa_nolfb = false; @@ -789,3 +922,62 @@ void DOSBOX_Init(void) { control->SetStartUp(&SHELL_Init); } + +extern void POD_Save_Sdlmain( std::ostream& stream ); +extern void POD_Load_Sdlmain( std::istream& stream ); + +// save state support + +namespace +{ +class SerializeDosbox : public SerializeGlobalPOD +{ +public: + SerializeDosbox() : SerializeGlobalPOD("Dosbox") + {} + +private: + virtual void getBytes(std::ostream& stream) + { + + //****************************************** + //****************************************** + //****************************************** + + SerializeGlobalPOD::getBytes(stream); + + //****************************************** + //****************************************** + //****************************************** + + POD_Save_Sdlmain(stream); + } + + virtual void setBytes(std::istream& stream) + { + + //****************************************** + //****************************************** + //****************************************** + + SerializeGlobalPOD::setBytes(stream); + + //****************************************** + //****************************************** + //****************************************** + + POD_Load_Sdlmain(stream); + + //******************************************* + //******************************************* + //******************************************* + + // Reset any auto cycle guessing for this frame + ticksRemain=5; + ticksLast = GetTicks(); + ticksAdded = 0; + ticksDone = 0; + ticksScheduled = 0; + } +} dummy; +} \ No newline at end of file diff --git a/src/fpu/fpu.cpp b/src/fpu/fpu.cpp index 86131b5..ea85953 100644 --- a/src/fpu/fpu.cpp +++ b/src/fpu/fpu.cpp @@ -27,6 +27,8 @@ #include "fpu.h" #include "cpu.h" +#include "../save_state.h" + FPU_rec fpu; void FPU_FLDCW(PhysPt addr){ @@ -628,3 +630,16 @@ void FPU_Init(Section*) { } #endif + +//save state support +namespace +{ +class SerializeFpu : public SerializeGlobalPOD +{ +public: + SerializeFpu() : SerializeGlobalPOD("FPU") + { + registerPOD(fpu); + } +} dummy; +} \ No newline at end of file diff --git a/src/gui/midi.cpp b/src/gui/midi.cpp index d17963e..b3aa1e6 100644 --- a/src/gui/midi.cpp +++ b/src/gui/midi.cpp @@ -34,6 +34,8 @@ #include "hardware.h" #include "timer.h" +#include "../save_state.h" + #define RAWBUF 1024 Bit8u MIDI_evt_len[256] = { @@ -68,6 +70,24 @@ MidiHandler::MidiHandler(){ MidiHandler Midi_none; +static struct { + bool init; + bool ignore; + + // NOTE: 16-bit ($ffff = not used, $00-ff = data value) + Bit16u code_80[0x80]; // note off (w/ velocity) + Bit16u code_90[0x80]; // note on (w/ velocity) + Bit16u code_a0[0x80]; // aftertouch (polyphonic key pressure) + Bit16u code_b0[0x80]; // Continuous controller (GM 1.0 + GS) + Bit16u code_c0[1]; // patch change + Bit16u code_d0[1]; // channel pressure (after-touch) + Bit16u code_e0[2]; // pitch bend + //Bit16u code_f0-ff // system messages + + Bit16u code_rpn_coarse[3]; // registered parameter numbers (GM 1.0) + Bit16u code_rpn_fine[3]; // registered parameter numbers (GM 1.0) +} midi_state[16]; + /* Include different midi drivers, lowest ones get checked first for default */ #if defined(MACOSX) @@ -93,6 +113,424 @@ MidiHandler Midi_none; DB_Midi midi; +//#define WIN32_MIDI_STATE_DEBUG + +void MIDI_State_Reset() +{ + memset( &midi_state, 0xff, sizeof(midi_state) ); + + midi_state[0].init = true; + midi_state[0].ignore = false; +} + + +void MIDI_State_SaveMessage() +{ + Bit8u channel, command, arg1, arg2; + + if( midi_state[0].init == false ) { + MIDI_State_Reset(); + } + + if( midi_state[0].ignore == true ) return; + + + channel = midi.cmd_buf[0] & 0xf; + command = midi.cmd_buf[0] >> 4; + arg1 = midi.cmd_buf[1]; + arg2 = midi.cmd_buf[2]; + + switch( command ) { + case 0x8: // Note off + // - arg1 = note, arg2 = velocity off + midi_state[channel].code_80[arg1] = arg2; + + memset( &midi_state[channel].code_90[arg1], 0xff, sizeof(midi_state[channel].code_90[arg1]) ); + memset( &midi_state[channel].code_a0[arg1], 0xff, sizeof(midi_state[channel].code_a0[arg1]) ); + memset( midi_state[channel].code_d0, 0xff, sizeof(midi_state[channel].code_d0) ); + break; + + + case 0x9: // Note on + if( arg2 > 0 ) { + // - arg1 = note, arg2 = velocity on + midi_state[channel].code_90[arg1] = arg2; + + memset( &midi_state[channel].code_80[arg1], 0xff, sizeof(midi_state[channel].code_80[arg1]) ); + } + else { + // velocity = 0 (note off) + midi_state[channel].code_80[arg1] = arg2; + + memset( &midi_state[channel].code_90[arg1], 0xff, sizeof(midi_state[channel].code_90[arg1]) ); + memset( &midi_state[channel].code_a0[arg1], 0xff, sizeof(midi_state[channel].code_a0[arg1]) ); + memset( midi_state[channel].code_d0, 0xff, sizeof(midi_state[channel].code_d0) ); + } + break; + + + case 0xA: // Aftertouch (polyphonic pressure) + midi_state[channel].code_a0[arg1] = arg2; + break; + + + case 0xB: // Controller #s + midi_state[channel].code_b0[arg1] = arg2; + + switch( arg1 ) { + // General Midi 1.0 + case 0x01: break; // Modulation + + case 0x07: break; // Volume + case 0x0A: break; // Pan + case 0x0B: break; // Expression + + case 0x40: break; // Sustain pedal + + case 0x64: break; // Registered Parameter Number (RPN) LSB + case 0x65: break; // Registered Parameter Number (RPN) MSB + + case 0x79: // All controllers off + /* + (likely GM1+GM2) + Set Expression (#11) to 127 + Set Modulation (#1) to 0 + Set Pedals (#64, #65, #66, #67) to 0 + Set Registered and Non-registered parameter number LSB and MSB (#98-#101) to null value (127) + Set pitch bender to center (64/0) + Reset channel pressure to 0 + Reset polyphonic pressure for all notes to 0. + */ + memset( midi_state[channel].code_a0, 0xff, sizeof(midi_state[channel].code_a0) ); + memset( midi_state[channel].code_c0, 0xff, sizeof(midi_state[channel].code_c0) ); + memset( midi_state[channel].code_d0, 0xff, sizeof(midi_state[channel].code_d0) ); + memset( midi_state[channel].code_e0, 0xff, sizeof(midi_state[channel].code_e0) ); + + memset( midi_state[channel].code_b0+0x01, 0xff, sizeof(midi_state[channel].code_b0[0x01]) ); + memset( midi_state[channel].code_b0+0x0b, 0xff, sizeof(midi_state[channel].code_b0[0x0b]) ); + memset( midi_state[channel].code_b0+0x40, 0xff, sizeof(midi_state[channel].code_b0[0x40]) ); + + memset( midi_state[channel].code_rpn_coarse, 0xff, sizeof(midi_state[channel].code_rpn_coarse) ); + memset( midi_state[channel].code_rpn_fine, 0xff, sizeof(midi_state[channel].code_rpn_fine) ); + + /* + (likely GM1+GM2) + Do NOT reset Bank Select (#0/#32) + Do NOT reset Volume (#7) + Do NOT reset Pan (#10) + Do NOT reset Program Change + Do NOT reset Effect Controllers (#91-#95) (5B-5F) + Do NOT reset Sound Controllers (#70-#79) (46-4F) + Do NOT reset other channel mode messages (#120-#127) (78-7F) + Do NOT reset registered or non-registered parameters. + */ + //Intentional fall-through + + case 0x7b: // All notes off + memset( midi_state[channel].code_80, 0xff, sizeof(midi_state[channel].code_80) ); + memset( midi_state[channel].code_90, 0xff, sizeof(midi_state[channel].code_90) ); + break; + + //****************************************** + //****************************************** + //****************************************** + + // Roland GS + case 0x00: break; // Bank select MSB + case 0x05: break; // Portamento time + case 0x20: break; // Bank select LSB + case 0x41: break; // Portamento + case 0x42: break; // Sostenuto + case 0x43: break; // Soft pedal + case 0x54: break; // Portamento control + case 0x5B: break; // Effect 1 (Reverb) send level + case 0x5D: break; // Effect 3 (Chorus) send level + case 0x5E: break; // Effect 4 (Variation) send level + + // TODO: Add more as needed + case 0x62: // NRPN LSB +#ifdef WIN32_MIDI_STATE_DEBUG + { + char str[512]; + + sprintf( str, "GS NRPN %x = %x", arg1, arg2 ); + MessageBox( 0, str, "MIDI State", 0 ); + } +#endif + break; + //case 0x63: break; // NRPN MSB + //case 0x78: break; // All sounds off (TODO) + + + /* + // Roland MT-32 + case 0x64: + parts[part]->setRPNLSB(velocity); + break; + case 0x65: + parts[part]->setRPNMSB(velocity); + break; + + case 0x7B: // All notes off + //printDebug("All notes off"); + parts[part]->allNotesOff(); + break; + + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + // CONFIRMED:Mok: A real LAPC-I responds to these controllers as follows: + parts[part]->setHoldPedal(false); + parts[part]->allNotesOff(); + break; + */ + + //****************************************** + //****************************************** + //****************************************** + + /* + (LSB,MSB) RPN + + GM 1.0 + 00,00 = Pitch bend range (fine + coarse) + 01,00 = Channel Fine tuning + 02,00 = Channel Coarse tuning + 7F,7F = None + */ + + case 0x06: // Data entry (coarse) + { + int rpn; + + rpn = midi_state[channel].code_b0[0x64]; + rpn |= (midi_state[channel].code_b0[0x65]) << 8; + + + // GM 1.0 = 0-2 + if( rpn >= 3 ) { +#ifdef WIN32_MIDI_STATE_DEBUG + char str[512]; + + sprintf( str, "RPN coarse %x = %x", rpn, arg2 ); + MessageBox( 0, str, "MIDI State", 0 ); +#endif + break; + } + if( rpn == 0x7f7f ) break; + + midi_state[channel].code_rpn_coarse[rpn] = arg2; + } + break; + + + case 0x26: // Data entry (fine) + { + int rpn; + + rpn = midi_state[channel].code_b0[0x64]; + rpn |= (midi_state[channel].code_b0[0x65]) << 8; + + + // GM 1.0 = 0-2 + if( rpn >= 3 ) { +#ifdef WIN32_MIDI_STATE_DEBUG + char str[512]; + + sprintf( str, "RPN fine %x = %x", rpn, arg2 ); + MessageBox( 0, str, "MIDI State", 0 ); +#endif + break; + } + if( rpn == 0x7f7f ) break; + + midi_state[channel].code_rpn_fine[rpn] = arg2; + } + break; + + + default: // unsupported +#ifdef WIN32_MIDI_STATE_DEBUG + { + char str[512]; + + // Ignore 'illegal' modes for now + if( arg1 != 0x70 && arg1 != 0x72 ) { + sprintf( str, "Control %x = %x", arg1, arg2 ); + //MessageBox( 0, str, "MIDI State", 0 ); + } + } +#endif + + //__asm int 3 + break; + } + break; + + + case 0xC: // Patch change + midi_state[channel].code_c0[0] = arg1; + break; + + case 0xD: // Channel pressure (aftertouch) + midi_state[channel].code_d0[0] = arg1; + break; + + case 0xE: // Pitch bend + midi_state[channel].code_e0[0] = arg1; + midi_state[channel].code_e0[1] = arg2; + break; + + case 0xF: // System messages + // TODO: General Midi 1.0 says 'Master Volume' SysEx + break; + + // unhandled case + default: + break; + } +} + + +void MIDI_RawOutByte(Bit8u); +void MIDI_State_LoadMessage() +{ + if( midi_state[0].init == false ) { + MIDI_State_Reset(); + } + + + // flush data buffer + if( midi.status < 0xf0 ) { + // throw invalid midi message - start new cmd + MIDI_RawOutByte(0x80); + } + else if( midi.status == 0xf0 ) { + // SysEx - throw invalid midi message + MIDI_RawOutByte(0xf7); + } + + + midi_state[0].ignore = true; + + // shutdown sound + for( int lcv=0; lcv<16; lcv++ ) { + MIDI_RawOutByte( 0xb0+lcv ); + MIDI_RawOutByte( 0x78 ); + MIDI_RawOutByte( 0x00 ); + + MIDI_RawOutByte( 0x79 ); + MIDI_RawOutByte( 0x00 ); + + // GS-way + MIDI_RawOutByte( 0x7b ); + MIDI_RawOutByte( 0x00 ); + } + + + for( int lcv=0; lcv<16; lcv++ ) { + // control states (bx - 00-5F) + MIDI_RawOutByte( 0xb0+lcv ); + + + for( int lcv2=0; lcv2<0x80; lcv2++ ) { + if( lcv2 >= 0x60 ) break; + if( midi_state[lcv].code_b0[lcv2] == 0xffff ) continue; + + // RPN data - coarse / fine + if( lcv2 == 0x06 ) continue; + if( lcv2 == 0x26 ) continue; + + + //MIDI_RawOutByte( 0xb0+lcv ); + MIDI_RawOutByte( lcv2 ); + MIDI_RawOutByte( midi_state[lcv].code_b0[lcv2] & 0xff ); + } + + + // control states - RPN data (GM 1.0) + for( int lcv2=0; lcv2<3; lcv2++ ) { + if( midi_state[lcv].code_rpn_coarse[lcv2] == 0xffff && + midi_state[lcv].code_rpn_fine[lcv2] == 0xffff ) continue; + + + //MIDI_RawOutByte( 0xb0+lcv ); + MIDI_RawOutByte( 0x64 ); + MIDI_RawOutByte( lcv2 ); + MIDI_RawOutByte( 0x65 ); + MIDI_RawOutByte( 0x00 ); + + + //MIDI_RawOutByte( 0xb0+lcv ); + MIDI_RawOutByte( 0x06 ); + MIDI_RawOutByte( midi_state[lcv].code_rpn_coarse[lcv2] & 0xff ); + MIDI_RawOutByte( 0x26 ); + MIDI_RawOutByte( midi_state[lcv].code_rpn_fine[lcv2] & 0xff ); + + + //MIDI_RawOutByte( 0xb0+lcv ); + MIDI_RawOutByte( 0x64 ); + MIDI_RawOutByte( 0x7f ); + MIDI_RawOutByte( 0x65 ); + MIDI_RawOutByte( 0x7f ); + } + + + // program change + if( midi_state[lcv].code_c0[0] != 0xffff ) { + MIDI_RawOutByte( 0xc0+lcv ); + MIDI_RawOutByte( midi_state[lcv].code_c0[0]&0xff ); + } + + + // pitch wheel change + if( midi_state[lcv].code_e0[0] != 0xffff ) { + MIDI_RawOutByte( 0xe0+lcv ); + MIDI_RawOutByte( midi_state[lcv].code_e0[0]&0xff ); + MIDI_RawOutByte( midi_state[lcv].code_e0[1]&0xff ); + } + + //****************************************** + //****************************************** + //****************************************** + + // note on + MIDI_RawOutByte( 0x90+lcv ); + + for( int lcv2=0; lcv2<0x80; lcv2++ ) { + if( midi_state[lcv].code_90[lcv2] == 0xffff ) continue; + + + //MIDI_RawOutByte( 0x90+lcv ); + MIDI_RawOutByte( lcv2 ); + MIDI_RawOutByte( midi_state[lcv].code_90[lcv2]&0xff ); + } + + + // polyphonic aftertouch + MIDI_RawOutByte( 0xa0+lcv ); + + for( int lcv2=0; lcv2<0x80; lcv2++ ) { + if( midi_state[lcv].code_a0[lcv2] == 0xffff ) continue; + + + //MIDI_RawOutByte( 0xa0+lcv ); + MIDI_RawOutByte( lcv2 ); + MIDI_RawOutByte( midi_state[lcv].code_a0[lcv2]&0xff ); + } + + + // channel aftertouch + if( midi_state[lcv].code_d0[0] != 0xffff ) { + MIDI_RawOutByte( 0xd0+lcv ); + MIDI_RawOutByte( midi_state[lcv].code_d0[0]&0xff ); + } + } + + midi_state[0].ignore = false; +} + void MIDI_RawOutByte(Bit8u data) { if (midi.sysex.start) { Bit32u passed_ticks = GetTicks() - midi.sysex.start; @@ -151,6 +589,9 @@ void MIDI_RawOutByte(Bit8u data) { if (CaptureState & CAPTURE_MIDI) { CAPTURE_AddMidi(false, midi.cmd_len, midi.cmd_buf); } + + MIDI_State_SaveMessage(); + midi.handler->PlayMsg(midi.cmd_buf); midi.cmd_pos=1; //Use Running status } @@ -205,6 +646,12 @@ getdefault: midi.available=true; midi.handler=handler; LOG_MSG("MIDI: Opened device:%s",handler->GetName()); + + // force reset to prevent crashes (when not properly shutdown) + // ex. Roland VSC = unexpected hard system crash + midi_state[0].init = false; + MIDI_State_LoadMessage(); + return; } handler=handler->next; @@ -212,6 +659,16 @@ getdefault: /* This shouldn't be possible */ } ~MIDI(){ + + if( midi.status < 0xf0 ) { + // throw invalid midi message - start new cmd + MIDI_RawOutByte(0x80); + } + else if( midi.status == 0xf0 ) { + // SysEx - throw invalid midi message + MIDI_RawOutByte(0xf7); + } + if(midi.available) midi.handler->Close(); midi.available = false; midi.handler = 0; @@ -227,3 +684,110 @@ void MIDI_Init(Section * sec) { test = new MIDI(sec); sec->AddDestroyFunction(&MIDI_Destroy,true); } + +//save state support +namespace { +class SerializeMidi : public SerializeGlobalPOD { +public: + SerializeMidi() : SerializeGlobalPOD("Midi") + {} + +private: + virtual void getBytes(std::ostream& stream) + { + if( !test ) return; + + //****************************************** + //****************************************** + //****************************************** + + SerializeGlobalPOD::getBytes(stream); + + + // - pure data + WRITE_POD( &midi.status, midi.status ); + WRITE_POD( &midi.cmd_len, midi.cmd_len ); + WRITE_POD( &midi.cmd_pos, midi.cmd_pos ); + WRITE_POD( &midi.cmd_buf, midi.cmd_buf ); + WRITE_POD( &midi.rt_buf, midi.rt_buf ); + WRITE_POD( &midi.sysex, midi.sysex ); + + //******************************************* + //******************************************* + //******************************************* + + // Supports MT-32 MUNT only!! + if(0) { + } + + // external MIDI + else if( midi.available ) { + const char pod_name[32] = "External"; + + + WRITE_POD( &pod_name, pod_name ); + + //******************************************* + //******************************************* + //******************************************* + + // - pure data + WRITE_POD( &midi_state, midi_state ); + } + } + + virtual void setBytes(std::istream& stream) + { + if( !test ) return; + + //****************************************** + //****************************************** + //****************************************** + + SerializeGlobalPOD::setBytes(stream); + + + // - pure data + READ_POD( &midi.status, midi.status ); + READ_POD( &midi.cmd_len, midi.cmd_len ); + READ_POD( &midi.cmd_pos, midi.cmd_pos ); + READ_POD( &midi.cmd_buf, midi.cmd_buf ); + READ_POD( &midi.rt_buf, midi.rt_buf ); + READ_POD( &midi.sysex, midi.sysex ); + + //******************************************* + //******************************************* + //******************************************* + + // Supports MT-32 MUNT only!! + if(0) { + } + + // external MIDI + else if( midi.available ) { + char pod_name[32] = {0}; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "External" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + // - pure data + READ_POD( &midi_state, midi_state ); + + //************************************************ + //************************************************ + //************************************************ + + MIDI_State_LoadMessage(); + } + } +} dummy; +} \ No newline at end of file diff --git a/src/gui/render.cpp b/src/gui/render.cpp index d6be555..1ebeca9 100644 --- a/src/gui/render.cpp +++ b/src/gui/render.cpp @@ -31,12 +31,14 @@ #include "hardware.h" #include "support.h" +#include "../save_state.h" + #include "render_scalers.h" Render_t render; ScalerLineHandler_t RENDER_DrawLine; -static void RENDER_CallBack( GFX_CallBackFunctions_t function ); +void RENDER_CallBack( GFX_CallBackFunctions_t function ); static void Check_Palette(void) { /* Clean up any previous changed palette data */ @@ -498,7 +500,7 @@ forcenormal: render.active=true; } -static void RENDER_CallBack( GFX_CallBackFunctions_t function ) { +void RENDER_CallBack( GFX_CallBackFunctions_t function ) { if (function == GFX_CallBackStop) { RENDER_Halt( ); return; @@ -513,11 +515,17 @@ static void RENDER_CallBack( GFX_CallBackFunctions_t function ) { } } -void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool dblw,bool dblh) { +void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double scrn_ratio,bool dblw,bool dblh) { + + double ratio; + RENDER_Halt( ); if (!width || !height || width > SCALER_MAXWIDTH || height > SCALER_MAXHEIGHT) { return; } + + ratio = scrn_ratio; + if ( ratio > 1 ) { double target = height * ratio + 0.025; ratio = target / height; @@ -531,6 +539,9 @@ void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool render.src.dblh=dblh; render.src.fps=fps; render.src.ratio=ratio; + + render.src.scrn_ratio=scrn_ratio; + RENDER_Reset( ); } @@ -631,3 +642,53 @@ void RENDER_Init(Section * sec) { GFX_SetTitle(-1,render.frameskip.max,false); } +//save state support +namespace +{ +class SerializeRender : public SerializeGlobalPOD +{ +public: + SerializeRender() : SerializeGlobalPOD("Render") + {} + +private: + virtual void getBytes(std::ostream& stream) + { + SerializeGlobalPOD::getBytes(stream); + + + // - pure data + WRITE_POD( &render.src, render.src ); + + WRITE_POD( &render.pal, render.pal ); + WRITE_POD( &render.updating, render.updating ); + WRITE_POD( &render.active, render.active ); + WRITE_POD( &render.fullFrame, render.fullFrame ); + } + + virtual void setBytes(std::istream& stream) + { + SerializeGlobalPOD::setBytes(stream); + + + // - pure data + READ_POD( &render.src, render.src ); + + READ_POD( &render.pal, render.pal ); + READ_POD( &render.updating, render.updating ); + READ_POD( &render.active, render.active ); + READ_POD( &render.fullFrame, render.fullFrame ); + + //*************************************** + //*************************************** + + // reset screen + memset( &render.frameskip, 0, sizeof(render.frameskip) ); + + render.scale.clearCache = true; + if( render.scale.outWrite ) { GFX_EndUpdate(NULL); } + + RENDER_SetSize( render.src.width, render.src.height, render.src.bpp, render.src.fps, render.src.scrn_ratio, render.src.dblw, render.src.dblh ); + } +} dummy; +} \ No newline at end of file diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp index 3213f1c..811ac21 100644 --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -50,6 +50,8 @@ #include "cross.h" #include "control.h" +#include "../save_state.h" + #define MAPPERFILE "mapper-" VERSION ".map" //#define DISABLE_JOYSTICK @@ -2168,3 +2170,29 @@ void GFX_GetSize(int &width, int &height, bool &fullscreen) { height = sdl.draw.height; fullscreen = sdl.desktop.fullscreen; } + +bool Get_Custom_SaveDir(std::string& savedir) { + std::string custom_savedir; + if (control->cmdline->FindString("-savedir",custom_savedir,false)) { + savedir=custom_savedir; + return true; + } else { + return false; + } +} + +// save state support +void POD_Save_Sdlmain( std::ostream& stream ) +{ + // - pure data + WRITE_POD( &sdl.mouse.autolock, sdl.mouse.autolock ); + WRITE_POD( &sdl.mouse.requestlock, sdl.mouse.requestlock ); +} + + +void POD_Load_Sdlmain( std::istream& stream ) +{ + // - pure data + READ_POD( &sdl.mouse.autolock, sdl.mouse.autolock ); + READ_POD( &sdl.mouse.requestlock, sdl.mouse.requestlock ); +} \ No newline at end of file diff --git a/src/hardware/adlib.cpp b/src/hardware/adlib.cpp index e0b4c59..daad81e 100644 --- a/src/hardware/adlib.cpp +++ b/src/hardware/adlib.cpp @@ -28,6 +28,8 @@ #include "mem.h" #include "dbopl.h" +#include "../save_state.h" + #include "mame/emu.h" #include "mame/fmopl.h" #include "mame/ymf262.h" @@ -58,6 +60,42 @@ namespace OPL2 { virtual void Init( Bitu rate ) { adlib_init(rate); } + + virtual void SaveState( std::ostream& stream ) { + const char pod_name[32] = "OPL2"; + + if( stream.fail() ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //************************************************ + //************************************************ + //************************************************ + + adlib_savestate(stream); + } + + virtual void LoadState( std::istream& stream ) { + char pod_name[32] = {0}; + + if( stream.fail() ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "OPL2" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + adlib_loadstate(stream); + } + ~Handler() { } }; @@ -87,6 +125,42 @@ namespace OPL3 { virtual void Init( Bitu rate ) { adlib_init(rate); } + + virtual void SaveState( std::ostream& stream ) { + const char pod_name[32] = "OPL3"; + + if( stream.fail() ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //************************************************ + //************************************************ + //************************************************ + + adlib_savestate(stream); + } + + virtual void LoadState( std::istream& stream ) { + char pod_name[32] = {0}; + + if( stream.fail() ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "OPL3" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + adlib_loadstate(stream); + } + ~Handler() { } }; @@ -866,3 +940,80 @@ void OPL_ShutDown(Section* sec){ module = 0; } + +// savestate support +void Adlib::Module::SaveState( std::ostream& stream ) +{ + // - pure data + WRITE_POD( &mode, mode ); + WRITE_POD( ®, reg ); + WRITE_POD( &ctrl, ctrl ); + WRITE_POD( &oplmode, oplmode ); + WRITE_POD( &lastUsed, lastUsed ); + + handler->SaveState(stream); + + WRITE_POD( &cache, cache ); + WRITE_POD( &chip, chip ); +} + + +void Adlib::Module::LoadState( std::istream& stream ) +{ + // - pure data + READ_POD( &mode, mode ); + READ_POD( ®, reg ); + READ_POD( &ctrl, ctrl ); + READ_POD( &oplmode, oplmode ); + READ_POD( &lastUsed, lastUsed ); + + handler->LoadState(stream); + + READ_POD( &cache, cache ); + READ_POD( &chip, chip ); +} + + +void POD_Save_Adlib(std::ostream& stream) +{ + const char pod_name[32] = "Adlib"; + + if( stream.fail() ) return; + if( !module ) return; + if( !module->mixerChan ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //************************************************ + //************************************************ + //************************************************ + + module->SaveState(stream); + module->mixerChan->SaveState(stream); +} + + +void POD_Load_Adlib(std::istream& stream) +{ + char pod_name[32] = {0}; + + if( stream.fail() ) return; + if( !module ) return; + if( !module->mixerChan ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "Adlib" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + module->LoadState(stream); + module->mixerChan->LoadState(stream); +} diff --git a/src/hardware/adlib.h b/src/hardware/adlib.h index 5d5065a..1961dc1 100644 --- a/src/hardware/adlib.h +++ b/src/hardware/adlib.h @@ -104,6 +104,10 @@ public: virtual void Generate( MixerChannel* chan, Bitu samples ) = 0; //Initialize at a specific sample rate and mode virtual void Init( Bitu rate ) = 0; + + virtual void SaveState( std::ostream& stream ) {} + virtual void LoadState( std::istream& stream ) {} + virtual ~Handler() { } }; @@ -152,6 +156,9 @@ public: Bitu PortRead( Bitu port, Bitu iolen ); void Init( Mode m ); + virtual void SaveState( std::ostream& stream ); + virtual void LoadState( std::istream& stream ); + Module( Section* configuration); ~Module(); }; diff --git a/src/hardware/cmos.cpp b/src/hardware/cmos.cpp index 362aa54..3e7b3d8 100644 --- a/src/hardware/cmos.cpp +++ b/src/hardware/cmos.cpp @@ -29,6 +29,8 @@ #include "setup.h" #include "cross.h" //fmod on certain platforms +#include "../save_state.h" + static struct { Bit8u regs[0x40]; bool nmi; @@ -328,3 +330,28 @@ void CMOS_Init(Section* sec) { test = new CMOS(sec); sec->AddDestroyFunction(&CMOS_Destroy,true); } + +// save state support +void *cmos_timerevent_PIC_Event = (void*)cmos_timerevent; + +namespace +{ +class SerializeCmos : public SerializeGlobalPOD +{ +public: + SerializeCmos() : SerializeGlobalPOD("CMOS") + { + registerPOD(cmos.regs); + registerPOD(cmos.nmi); + registerPOD(cmos.reg); + registerPOD(cmos.timer.enabled); + registerPOD(cmos.timer.div); + registerPOD(cmos.timer.delay); + registerPOD(cmos.timer.acknowledged); + registerPOD(cmos.last.timer); + registerPOD(cmos.last.ended); + registerPOD(cmos.last.alarm); + registerPOD(cmos.update_ended); + } +} dummy; +} \ No newline at end of file diff --git a/src/hardware/dbopl.cpp b/src/hardware/dbopl.cpp index 4416c50..6c86864 100644 --- a/src/hardware/dbopl.cpp +++ b/src/hardware/dbopl.cpp @@ -40,6 +40,8 @@ #include "dosbox.h" #include "dbopl.h" +#include "../save_state.h" + #ifndef PI #define PI 3.14159265358979323846 @@ -1517,5 +1519,156 @@ void Handler::Init( Bitu rate ) { chip.Setup( rate ); } +// save state support +void Handler::SaveState( std::ostream& stream ) +{ + const char pod_name[32] = "DBOPL"; + + if( stream.fail() ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //************************************************ + //************************************************ + //************************************************ + + Bit8u volhandler_idx[18][2]; + Bit32u wavebase_idx[18][2]; + Bit8u synthhandler_idx[18]; + + + for( int lcv1=0; lcv1<18; lcv1++ ) { + for( int lcv2=0; lcv2<2; lcv2++ ) { + volhandler_idx[lcv1][lcv2] = 0xff; + + for( int lcv3=0; lcv3<5; lcv3++ ) { + if( chip.chan[lcv1].op[lcv2].volHandler == VolumeHandlerTable[lcv3] ) { + volhandler_idx[lcv1][lcv2] = lcv3; + break; + } + } + + wavebase_idx[lcv1][lcv2] = (intptr_t) chip.chan[lcv1].op[lcv2].waveBase - (intptr_t) &WaveTable; + } + + + synthhandler_idx[lcv1] = 0xff; + if(0) {} + else if( chip.chan[lcv1].synthHandler == &Channel::BlockTemplate< sm3FMFM > ) synthhandler_idx[lcv1] = 0x00; + else if( chip.chan[lcv1].synthHandler == &Channel::BlockTemplate< sm3AMFM > ) synthhandler_idx[lcv1] = 0x01; + else if( chip.chan[lcv1].synthHandler == &Channel::BlockTemplate< sm3FMAM > ) synthhandler_idx[lcv1] = 0x02; + else if( chip.chan[lcv1].synthHandler == &Channel::BlockTemplate< sm3AMAM > ) synthhandler_idx[lcv1] = 0x03; + else if( chip.chan[lcv1].synthHandler == &Channel::BlockTemplate< sm3AM > ) synthhandler_idx[lcv1] = 0x04; + else if( chip.chan[lcv1].synthHandler == &Channel::BlockTemplate< sm3FM > ) synthhandler_idx[lcv1] = 0x05; + else if( chip.chan[lcv1].synthHandler == &Channel::BlockTemplate< sm2AM > ) synthhandler_idx[lcv1] = 0x06; + else if( chip.chan[lcv1].synthHandler == &Channel::BlockTemplate< sm2FM > ) synthhandler_idx[lcv1] = 0x07; + else if( chip.chan[lcv1].synthHandler == &Channel::BlockTemplate< sm3Percussion > ) synthhandler_idx[lcv1] = 0x08; + else if( chip.chan[lcv1].synthHandler == &Channel::BlockTemplate< sm2Percussion > ) synthhandler_idx[lcv1] = 0x09; + } + + //*************************************************** + //*************************************************** + //*************************************************** + + // dbopl.cpp + + // - pure data + WRITE_POD( &WaveTable, WaveTable ); + WRITE_POD( &doneTables, doneTables ); + + //*************************************************** + //*************************************************** + //*************************************************** + + // dbopl.h + + // - near-pure data + WRITE_POD( &chip, chip ); + + + + + // - reloc ptr (!!!) + WRITE_POD( &volhandler_idx, volhandler_idx ); + WRITE_POD( &wavebase_idx, wavebase_idx ); + WRITE_POD( &synthhandler_idx, synthhandler_idx ); +} + +void Handler::LoadState( std::istream& stream ) +{ + char pod_name[32] = {0}; + + if( stream.fail() ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "DBOPL" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + Bit8u volhandler_idx[18][2]; + Bit32u wavebase_idx[18][2]; + Bit8u synthhandler_idx[18]; + + //*************************************************** + //*************************************************** + //*************************************************** + + // dbopl.cpp + + // - pure data + READ_POD( &WaveTable, WaveTable ); + READ_POD( &doneTables, doneTables ); + + //*************************************************** + //*************************************************** + //*************************************************** + + // dbopl.h + + // - near-pure data + READ_POD( &chip, chip ); + + + + + // - reloc ptr (!!!) + READ_POD( &volhandler_idx, volhandler_idx ); + READ_POD( &wavebase_idx, wavebase_idx ); + READ_POD( &synthhandler_idx, synthhandler_idx ); + + //*************************************************** + //*************************************************** + //*************************************************** + + for( int lcv1=0; lcv1<18; lcv1++ ) { + for( int lcv2=0; lcv2<2; lcv2++ ) { + chip.chan[lcv1].op[lcv2].volHandler = VolumeHandlerTable[ volhandler_idx[lcv1][lcv2] ]; + + chip.chan[lcv1].op[lcv2].waveBase = (Bit16s *) ((intptr_t) wavebase_idx[lcv1][lcv2] + (intptr_t) &WaveTable); + } + + + switch( synthhandler_idx[lcv1] ) { + case 0x00: chip.chan[lcv1].synthHandler = &Channel::BlockTemplate< sm3FMFM >; break; + case 0x01: chip.chan[lcv1].synthHandler = &Channel::BlockTemplate< sm3AMFM >; break; + case 0x02: chip.chan[lcv1].synthHandler = &Channel::BlockTemplate< sm3FMAM >; break; + case 0x03: chip.chan[lcv1].synthHandler = &Channel::BlockTemplate< sm3AMAM >; break; + case 0x04: chip.chan[lcv1].synthHandler = &Channel::BlockTemplate< sm3AM >; break; + case 0x05: chip.chan[lcv1].synthHandler = &Channel::BlockTemplate< sm3FM >; break; + case 0x06: chip.chan[lcv1].synthHandler = &Channel::BlockTemplate< sm2AM >; break; + case 0x07: chip.chan[lcv1].synthHandler = &Channel::BlockTemplate< sm2FM >; break; + case 0x08: chip.chan[lcv1].synthHandler = &Channel::BlockTemplate< sm3Percussion >; break; + case 0x09: chip.chan[lcv1].synthHandler = &Channel::BlockTemplate< sm2Percussion >; break; + } + } +} }; //Namespace DBOPL diff --git a/src/hardware/dbopl.h b/src/hardware/dbopl.h index 4e61b11..e7dc6e5 100644 --- a/src/hardware/dbopl.h +++ b/src/hardware/dbopl.h @@ -253,6 +253,10 @@ struct Handler : public Adlib::Handler { virtual void WriteReg( Bit32u addr, Bit8u val ); virtual void Generate( MixerChannel* chan, Bitu samples ); virtual void Init( Bitu rate ); + + virtual void SaveState( std::ostream& stream ); + virtual void LoadState( std::istream& stream ); + }; diff --git a/src/hardware/disney.cpp b/src/hardware/disney.cpp index 671487c..b205922 100644 --- a/src/hardware/disney.cpp +++ b/src/hardware/disney.cpp @@ -24,6 +24,8 @@ #include "pic.h" #include "setup.h" +#include "../save_state.h" + #define DISNEY_BASE 0x0378 #define DISNEY_SIZE 128 @@ -397,3 +399,111 @@ void DISNEY_Init(Section* sec) { test = new DISNEY(sec); sec->AddDestroyFunction(&DISNEY_ShutDown,true); } + +// save state support +void *DISNEY_disable_PIC_Event = (void*)DISNEY_disable; + + +void POD_Save_Disney( std::ostream& stream ) +{ + const char pod_name[32] = "Disney"; + + if( stream.fail() ) return; + if( !test ) return; + if( !disney.chan ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //************************************************ + //************************************************ + //************************************************ + + Bit8u dac_leader_idx; + + + dac_leader_idx = 0xff; + for( int lcv=0; lcv<2; lcv++ ) { + if( disney.leader == &disney.da[lcv] ) { dac_leader_idx = lcv; break; } + } + + // ******************************************* + // ******************************************* + // ******************************************* + + // - near-pure struct data + WRITE_POD( &disney, disney ); + + + + + // - reloc ptr + WRITE_POD( &dac_leader_idx, dac_leader_idx ); + + //******************************************* + //******************************************* + //******************************************* + + disney.chan->SaveState(stream); +} + + +void POD_Load_Disney( std::istream& stream ) +{ + char pod_name[32] = {0}; + + if( stream.fail() ) return; + if( !test ) return; + if( !disney.chan ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "Disney" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + Bit8u dac_leader_idx; + MixerObject *mo_old; + MixerChannel *chan_old; + + + // save old ptrs + mo_old = disney.mo; + chan_old = disney.chan; + + //******************************************* + //******************************************* + //******************************************* + + // - near-pure struct data + READ_POD( &disney, disney ); + + + + // - reloc ptr + READ_POD( &dac_leader_idx, dac_leader_idx ); + + //******************************************* + //******************************************* + //******************************************* + + disney.leader = NULL; + if( dac_leader_idx != 0xff ) disney.leader = &disney.da[dac_leader_idx]; + + //******************************************* + //******************************************* + //******************************************* + + // restore old ptrs + disney.mo = mo_old; + disney.chan = chan_old; + + + disney.chan->LoadState(stream); +} \ No newline at end of file diff --git a/src/hardware/dma.cpp b/src/hardware/dma.cpp index f310c58..5b4596e 100644 --- a/src/hardware/dma.cpp +++ b/src/hardware/dma.cpp @@ -26,6 +26,8 @@ #include "paging.h" #include "setup.h" +#include "../save_state.h" + DmaController *DmaControllers[2]; #define EMM_PAGEFRAME4K ((0xE000*16)/4096) @@ -402,3 +404,194 @@ void DMA_Init(Section* sec) { ems_board_mapping[i]=i; } } + +//save state support +extern void *GUS_DMA_Callback_Func; +extern void *SB_DSP_DMA_CallBack_Func; +extern void *SB_DSP_ADC_CallBack_Func; +extern void *SB_DSP_E2_DMA_CallBack_Func; +extern void *TandyDAC_DMA_CallBack_Func; + + +const void *dma_state_callback_table[] = { + NULL, + GUS_DMA_Callback_Func, + SB_DSP_DMA_CallBack_Func, + SB_DSP_ADC_CallBack_Func, + SB_DSP_E2_DMA_CallBack_Func, + TandyDAC_DMA_CallBack_Func +}; + + +Bit8u POD_State_Find_DMA_Callback( Bit32u addr ) +{ + Bit8u size; + + size = sizeof(dma_state_callback_table) / sizeof(Bit32u); + for( int lcv=0; lcvSaveState(stream); + } +} + + +void DmaController::LoadState( std::istream& stream ) +{ + // - pure data + READ_POD( &ctrlnum, ctrlnum ); + READ_POD( &flipflop, flipflop ); + + for( int lcv=0; lcv<4; lcv++ ) { + DmaChannels[lcv]->LoadState(stream); + } +} + + +namespace +{ +class SerializeDMA : public SerializeGlobalPOD +{ +public: + SerializeDMA() : SerializeGlobalPOD("DMA") + {} + +private: + virtual void getBytes(std::ostream& stream) + { + SerializeGlobalPOD::getBytes(stream); + + + // - pure data + WRITE_POD( &dma_wrapping, dma_wrapping ); + + + for( int lcv=0; lcv<2; lcv++ ) { + // cga, tandy, pcjr = no 2nd controller + if( !DmaControllers[lcv] ) continue; + + DmaControllers[lcv]->SaveState(stream); + } + + + // - pure data + WRITE_POD( &ems_board_mapping, ems_board_mapping ); + } + + virtual void setBytes(std::istream& stream) + { + SerializeGlobalPOD::setBytes(stream); + + + // - pure data + READ_POD( &dma_wrapping, dma_wrapping ); + + + for( int lcv=0; lcv<2; lcv++ ) { + // cga, tandy, pcjr = no 2nd controller + if( !DmaControllers[lcv] ) continue; + + DmaControllers[lcv]->LoadState(stream); + } + + + // - pure data + READ_POD( &ems_board_mapping, ems_board_mapping ); + } +} dummy; +} diff --git a/src/hardware/gameblaster.cpp b/src/hardware/gameblaster.cpp index 0047962..70a2cdb 100644 --- a/src/hardware/gameblaster.cpp +++ b/src/hardware/gameblaster.cpp @@ -27,6 +27,8 @@ #include #include +#include "../save_state.h" + #include "mame/emu.h" #include "mame/saa1099.h" @@ -171,3 +173,74 @@ void CMS_Init(Section* sec) { void CMS_ShutDown(Section* sec) { delete test; } + +// save state support +void POD_Save_Gameblaster( std::ostream& stream ) +{ + const char pod_name[32] = "CMS"; + + if( stream.fail() ) return; + if( !test ) return; + if( !cms_chan ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //******************************************* + //******************************************* + //******************************************* + + // - pure data (?) - untested since MAME SAA1099 is used + WRITE_POD( &device, device ); +// WRITE_POD( &sampleRate, sampleRate ); +// WRITE_POD( &saa1099, saa1099 ); +// +// WRITE_POD( &cms_buffer, cms_buffer ); +// WRITE_POD( &last_command, last_command ); +// WRITE_POD( &base_port, base_port ); +// WRITE_POD( &cms_detect_register, cms_detect_register ); + + //************************************************ + //************************************************ + //************************************************ + + cms_chan->SaveState(stream); +} + + +void POD_Load_Gameblaster( std::istream& stream ) +{ + char pod_name[32] = {0}; + + if( stream.fail() ) return; + if( !test ) return; + if( !cms_chan ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "CMS" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //******************************************* + //******************************************* + //******************************************* + + // - pure data (?) - untested since MAME SAA1099 is used + READ_POD( &device, device ); +// READ_POD( &sampleRate, sampleRate ); +// READ_POD( &saa1099, saa1099 ); +// +// READ_POD( &cms_buffer, cms_buffer ); +// READ_POD( &last_command, last_command ); +// READ_POD( &base_port, base_port ); +// READ_POD( &cms_detect_register, cms_detect_register ); + + //************************************************ + //************************************************ + //************************************************ + + cms_chan->LoadState(stream); +} diff --git a/src/hardware/gus.cpp b/src/hardware/gus.cpp index a539b13..e8f8961 100644 --- a/src/hardware/gus.cpp +++ b/src/hardware/gus.cpp @@ -29,6 +29,9 @@ #include "shell.h" #include "math.h" #include "regs.h" + +#include "../save_state.h" + using namespace std; //Extra bits of precision over normal gus @@ -921,3 +924,124 @@ void GUS_Init(Section* sec) { test = new GUS(sec); sec->AddDestroyFunction(&GUS_ShutDown,true); } + +// save state support +void *GUS_TimerEvent_PIC_Event = (void*)GUS_TimerEvent; +void *GUS_DMA_Callback_Func = (void*)GUS_DMA_Callback; + + +void POD_Save_GUS( std::ostream& stream ) +{ + const char pod_name[32] = "GUS"; + + if( stream.fail() ) return; + if( !test ) return; + if( !gus_chan ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //******************************************* + //******************************************* + //******************************************* + + Bit8u curchan_idx; + + + curchan_idx = 0xff; + for( int lcv=0; lcv<32; lcv++ ) { + if( curchan == guschan[lcv] ) { curchan_idx = lcv; break; } + } + + // ******************************************* + // ******************************************* + // ******************************************* + + // - pure data + WRITE_POD( &adlib_commandreg, adlib_commandreg ); + WRITE_POD( &GUSRam, GUSRam ); + WRITE_POD( &vol16bit, vol16bit ); + WRITE_POD( &pantable, pantable ); + + // - pure struct data + WRITE_POD( &myGUS, myGUS ); + + + // - pure data + for( int lcv=0; lcv<32; lcv++ ) { + WRITE_POD( guschan[lcv], *guschan[lcv] ); + } + + // ******************************************* + // ******************************************* + // ******************************************* + + // - reloc ptr + WRITE_POD( &curchan_idx, curchan_idx ); + + // ******************************************* + // ******************************************* + // ******************************************* + + gus_chan->SaveState(stream); +} + + +void POD_Load_GUS( std::istream& stream ) +{ + char pod_name[32] = {0}; + + if( stream.fail() ) return; + if( !test ) return; + if( !gus_chan ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "GUS" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + Bit8u curchan_idx; + + //******************************************* + //******************************************* + //******************************************* + + // - pure data + READ_POD( &adlib_commandreg, adlib_commandreg ); + READ_POD( &GUSRam, GUSRam ); + READ_POD( &vol16bit, vol16bit ); + READ_POD( &pantable, pantable ); + + READ_POD( &myGUS, myGUS ); + + for( int lcv=0; lcv<32; lcv++ ) { + if( !guschan[lcv] ) continue; + + READ_POD( guschan[lcv], *guschan[lcv] ); + } + + + + // - reloc ptr + READ_POD( &curchan_idx, curchan_idx ); + + //******************************************* + //******************************************* + //******************************************* + + curchan = NULL; + if( curchan_idx != 0xff ) curchan = guschan[curchan_idx]; + + //******************************************* + //******************************************* + //******************************************* + + gus_chan->LoadState(stream); +} \ No newline at end of file diff --git a/src/hardware/hardware.cpp b/src/hardware/hardware.cpp index d66143f..ef5e44e 100644 --- a/src/hardware/hardware.cpp +++ b/src/hardware/hardware.cpp @@ -35,7 +35,7 @@ #include "../libs/zmbv/zmbv.cpp" #endif -static std::string capturedir; +std::string capturedir; extern const char* RunningProgram; Bitu CaptureState; diff --git a/src/hardware/iohandler.cpp b/src/hardware/iohandler.cpp index 816e3c4..302386f 100644 --- a/src/hardware/iohandler.cpp +++ b/src/hardware/iohandler.cpp @@ -25,6 +25,8 @@ #include "../src/cpu/lazyflags.h" #include "callback.h" +#include "../save_state.h" + //#define ENABLE_PORTLOG IO_WriteHandler * io_writehandlers[3][IO_MAX]; @@ -527,3 +529,19 @@ void IO_Init(Section * sect) { test = new IO(sect); sect->AddDestroyFunction(&IO_Destroy); } + +//save state support +namespace +{ +class SerializeIO : public SerializeGlobalPOD +{ +public: + SerializeIO() : SerializeGlobalPOD("IO handler") + { + //io_writehandlers -> quasi constant + //io_readhandlers -> quasi constant + + registerPOD(iof_queue.used); registerPOD(iof_queue.entries); + } +} dummy; +} \ No newline at end of file diff --git a/src/hardware/ipx.cpp b/src/hardware/ipx.cpp index 58317cd..f051e78 100644 --- a/src/hardware/ipx.cpp +++ b/src/hardware/ipx.cpp @@ -1197,4 +1197,8 @@ void IPX_Init(Section* sec) { //Initialize static members; Bit16u IPX::dospage = 0; +// save state support +void *IPX_AES_EventHandler_PIC_Event = (void*)IPX_AES_EventHandler; +void *IPX_ClientLoop_PIC_Timer = (void*)IPX_ClientLoop; + #endif diff --git a/src/hardware/ipxserver.cpp b/src/hardware/ipxserver.cpp index 1f4554e..e9ff5e2 100644 --- a/src/hardware/ipxserver.cpp +++ b/src/hardware/ipxserver.cpp @@ -228,5 +228,7 @@ bool IPX_StartServer(Bit16u portnum) { return false; } +// save state support +void *IPX_ServerLoop_PIC_Timer = (void*)IPX_ServerLoop; #endif diff --git a/src/hardware/joystick.cpp b/src/hardware/joystick.cpp index e2318bf..e54085e 100644 --- a/src/hardware/joystick.cpp +++ b/src/hardware/joystick.cpp @@ -26,6 +26,7 @@ #include "pic.h" #include "support.h" +#include "../save_state.h" //TODO: higher axis can't be mapped. Find out why again @@ -335,3 +336,22 @@ void JOYSTICK_Init(Section* sec) { test = new JOYSTICK(sec); sec->AddDestroyFunction(&JOYSTICK_Destroy,true); } + +//save state support +namespace +{ +class SerializeStick : public SerializeGlobalPOD +{ +public: + SerializeStick() : SerializeGlobalPOD("Joystick") + { + registerPOD(joytype); + registerPOD(stick); + registerPOD(last_write); + registerPOD(write_active); + registerPOD(swap34); + registerPOD(button_wrapping_enabled); + registerPOD(autofire); + } +} dummy; +} diff --git a/src/hardware/keyboard.cpp b/src/hardware/keyboard.cpp index 0a0a5c1..26e369a 100644 --- a/src/hardware/keyboard.cpp +++ b/src/hardware/keyboard.cpp @@ -25,6 +25,8 @@ #include "mixer.h" #include "timer.h" +#include "../save_state.h" + #define KEYBUFSIZE 32 #define KEYDELAY 0.300f //Considering 20-30 khz serial clock and 11 bits/char @@ -392,3 +394,32 @@ void KEYBOARD_Init(Section* sec) { keyb.repeat.wait=0; KEYBOARD_ClrBuffer(); } + +//save state support +void *KEYBOARD_TransferBuffer_PIC_Event = (void*)KEYBOARD_TransferBuffer; +void *KEYBOARD_TickHandler_PIC_Timer = (void*)KEYBOARD_TickHandler; + +namespace +{ +class SerializeKeyboard : public SerializeGlobalPOD +{ +public: + SerializeKeyboard() : SerializeGlobalPOD("Keyboard") + { + registerPOD(keyb.buffer); + registerPOD(keyb.used); + registerPOD(keyb.pos); + registerPOD(keyb.repeat.key); + registerPOD(keyb.repeat.wait); + registerPOD(keyb.repeat.pause); + registerPOD(keyb.repeat.rate); + registerPOD(keyb.command); + registerPOD(keyb.p60data); + registerPOD(keyb.p60changed); + registerPOD(keyb.active); + registerPOD(keyb.scanning); + registerPOD(keyb.scheduled); + registerPOD(port_61_data); + } +} dummy; +} \ No newline at end of file diff --git a/src/hardware/memory.cpp b/src/hardware/memory.cpp index a8357b1..a59e07c 100644 --- a/src/hardware/memory.cpp +++ b/src/hardware/memory.cpp @@ -24,6 +24,8 @@ #include "paging.h" #include "regs.h" +#include "../save_state.h" + #include #define PAGES_IN_BLOCK ((1024*1024)/MEM_PAGE_SIZE) @@ -612,3 +614,121 @@ void MEM_Init(Section * sec) { test = new MEMORY(sec); sec->AddDestroyFunction(&MEM_ShutDown); } + +//save state support +extern void* VGA_PageHandler_Func[16]; + +intptr_t Memory_PageHandler_table[] = +{ + 0, + (intptr_t) &ram_page_handler, + (intptr_t) &rom_page_handler, + + (intptr_t) VGA_PageHandler_Func[0], + (intptr_t) VGA_PageHandler_Func[1], + (intptr_t) VGA_PageHandler_Func[2], + (intptr_t) VGA_PageHandler_Func[3], + (intptr_t) VGA_PageHandler_Func[4], + (intptr_t) VGA_PageHandler_Func[5], + (intptr_t) VGA_PageHandler_Func[6], + (intptr_t) VGA_PageHandler_Func[7], + (intptr_t) VGA_PageHandler_Func[8], + (intptr_t) VGA_PageHandler_Func[9], + (intptr_t) VGA_PageHandler_Func[10], + (intptr_t) VGA_PageHandler_Func[11], + (intptr_t) VGA_PageHandler_Func[12], + (intptr_t) VGA_PageHandler_Func[13], + (intptr_t) VGA_PageHandler_Func[14], + (intptr_t) VGA_PageHandler_Func[15], +}; + + +namespace +{ +class SerializeMemory : public SerializeGlobalPOD +{ +public: + SerializeMemory() : SerializeGlobalPOD("Memory") + {} + +private: + virtual void getBytes(std::ostream& stream) + { + Bit8u pagehandler_idx[0x10000]; + int size_table; + + + // assume 256MB max memory + size_table = sizeof(Memory_PageHandler_table) / sizeof(intptr_t); + for( int lcv=0; lcvAddDestroyFunction(&MPU401_Destroy,true); } + +// save state support +void *MPU401_Event_PIC_Event = (void*)MPU401_Event; + + +void POD_Save_MPU401( std::ostream& stream ) +{ + const char pod_name[32] = "MPU401"; + + if( stream.fail() ) return; + if( !test ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //******************************************* + //******************************************* + //******************************************* + + // - pure data + WRITE_POD( &mpu, mpu ); +} + + +void POD_Load_MPU401( std::istream& stream ) +{ + char pod_name[32] = {0}; + + if( stream.fail() ) return; + if( !test ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "MPU401" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + // - pure data + READ_POD( &mpu, mpu ); +} \ No newline at end of file diff --git a/src/hardware/opl.cpp b/src/hardware/opl.cpp index 54155c5..a745e7c 100644 --- a/src/hardware/opl.cpp +++ b/src/hardware/opl.cpp @@ -1459,3 +1459,116 @@ void adlib_getsample(Bit16s* sndptr, Bits numsamples) { } } + +// save state support +void adlib_savestate( std::ostream& stream ) +{ + Bit32u cur_wform_idx[MAXOPERATORS]; + + + for( int lcv=0; lcvAddDestroyFunction(&PCSPEAKER_ShutDown,true); } + +// save state support +void POD_Save_PCSpeaker( std::ostream& stream ) +{ + const char pod_name[32] = "PCSpeaker"; + + if( stream.fail() ) return; + if( !test ) return; + if( !spkr.chan ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //******************************************* + //******************************************* + //******************************************* + + // - near-pure data + WRITE_POD( &spkr, spkr ); + + //******************************************* + //******************************************* + //******************************************* + + spkr.chan->SaveState(stream); +} + + +void POD_Load_PCSpeaker( std::istream& stream ) +{ + char pod_name[32] = {0}; + + if( stream.fail() ) return; + if( !test ) return; + if( !spkr.chan ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "PCSpeaker" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + MixerChannel *chan_old; + + + // - save static ptrs + chan_old = spkr.chan; + + //******************************************* + //******************************************* + //******************************************* + + // - near-pure data + READ_POD( &spkr, spkr ); + + //******************************************* + //******************************************* + //******************************************* + + // - restore static ptrs + spkr.chan = chan_old; + + + spkr.chan->LoadState(stream); +} \ No newline at end of file diff --git a/src/hardware/pic.cpp b/src/hardware/pic.cpp index 0bdba54..0c5aa4b 100644 --- a/src/hardware/pic.cpp +++ b/src/hardware/pic.cpp @@ -24,6 +24,8 @@ #include "timer.h" #include "setup.h" +#include "../save_state.h" + #define PIC_QUEUESIZE 512 struct PIC_Controller { @@ -622,3 +624,362 @@ void PIC_Init(Section* sec) { test = new PIC_8259A(sec); sec->AddDestroyFunction(&PIC_Destroy); } + +// PIC_EventHandlers +extern void *cmos_timerevent_PIC_Event; // Cmos.cpp +extern void *DISNEY_disable_PIC_Event; // Disney.cpp +extern void *GUS_TimerEvent_PIC_Event; // Gus.cpp +extern void *IPX_AES_EventHandler_PIC_Event; // Ipx.cpp +extern void *KEYBOARD_TransferBuffer_PIC_Event; // Keyboard.cpp +extern void *MOUSE_Limit_Events_PIC_Event; // Mouse.cpp +extern void *MPU401_Event_PIC_Event; // Mpu401.cpp +extern void *DMA_Silent_Event_PIC_Event; // Sblaster.cpp +extern void *DSP_FinishReset_PIC_Event; +extern void *DSP_RaiseIRQEvent_PIC_Event; +extern void *END_DMA_Event_PIC_Event; +extern void *Serial_EventHandler_PIC_Event; // Serialport.cpp +extern void *PIT0_Event_PIC_Event; // Timer.cpp +extern void *VGA_DisplayStartLatch_PIC_Event; // Vga.cpp +extern void *VGA_DrawEGASingleLine_PIC_Event; +extern void *VGA_DrawPart_PIC_Event; +extern void *VGA_DrawSingleLine_PIC_Event; +extern void *VGA_Other_VertInterrupt_PIC_Event; +extern void *VGA_PanningLatch_PIC_Event; +extern void *VGA_SetupDrawing_PIC_Event; +extern void *VGA_VertInterrupt_PIC_Event; +extern void *VGA_VerticalTimer_PIC_Event; + +#if C_NE2000 +extern void *NE2000_TX_Event_PIC_Event; // Ne2000.cpp +#endif + + +// PIC_TimerHandlers +extern void *IPX_ClientLoop_PIC_Timer; // Ipx.cpp +extern void *IPX_ServerLoop_PIC_Timer; // Ipxserver.cpp +extern void *KEYBOARD_TickHandler_PIC_Timer; // Keyboard.cpp +extern void *KEYBOARD_TickHandler_PIC_Timer; // Keyboard.cpp +extern void *MIXER_Mix_NoSound_PIC_Timer; // Mixer.cpp +extern void *MIXER_Mix_PIC_Timer; + +#if C_NE2000 +extern void *NE2000_Poller_PIC_Event; // Ne2000.cpp +#endif + + +const void *pic_state_event_table[] = { + NULL, + cmos_timerevent_PIC_Event, + DISNEY_disable_PIC_Event, + GUS_TimerEvent_PIC_Event, +#if C_IPX + IPX_AES_EventHandler_PIC_Event, +#endif + KEYBOARD_TransferBuffer_PIC_Event, + MOUSE_Limit_Events_PIC_Event, + MPU401_Event_PIC_Event, + DMA_Silent_Event_PIC_Event, + DSP_FinishReset_PIC_Event, + DSP_RaiseIRQEvent_PIC_Event, + END_DMA_Event_PIC_Event, + END_DMA_Event_PIC_Event, + Serial_EventHandler_PIC_Event, + PIT0_Event_PIC_Event, + VGA_DisplayStartLatch_PIC_Event, + VGA_DrawEGASingleLine_PIC_Event, + VGA_DrawPart_PIC_Event, + VGA_DrawSingleLine_PIC_Event, + VGA_Other_VertInterrupt_PIC_Event, + VGA_PanningLatch_PIC_Event, + VGA_SetupDrawing_PIC_Event, + VGA_VertInterrupt_PIC_Event, + VGA_VerticalTimer_PIC_Event, + +#if C_NE2000 + NE2000_TX_Event_PIC_Event, +#endif +}; + + +const void *pic_state_timer_table[] = { + NULL, +#if C_IPX + IPX_ClientLoop_PIC_Timer, + IPX_ServerLoop_PIC_Timer, +#endif + KEYBOARD_TickHandler_PIC_Timer, + KEYBOARD_TickHandler_PIC_Timer, + MIXER_Mix_NoSound_PIC_Timer, + MIXER_Mix_PIC_Timer, + +#if C_NE2000 + NE2000_Poller_PIC_Event, +#endif +}; + + + +//#include +Bit16u PIC_State_FindEvent( intptr_t addr ) { + int size; + + size = sizeof(pic_state_event_table) / sizeof(intptr_t); + for( int lcv=0; lcvnext; + ticker_size++; + } + + // *************************************************** + // *************************************************** + // *************************************************** + + SerializeGlobalPOD::getBytes(stream); + + + // - data + stream.write(reinterpret_cast(&PIC_Ticks), sizeof(PIC_Ticks) ); + stream.write(reinterpret_cast(&PIC_IRQCheck), sizeof(PIC_IRQCheck) ); + + // - data structs + stream.write(reinterpret_cast(&pics), sizeof(pics) ); + + + pic_free_idx = 0xffff; + pic_next_idx = 0xffff; + for( int lcv=0; lcv(&pic_queue.entries[lcv].index), sizeof(pic_queue.entries[lcv].index) ); + stream.write(reinterpret_cast(&pic_queue.entries[lcv].value), sizeof(pic_queue.entries[lcv].value) ); + + // - function ptr + event_idx = PIC_State_FindEvent( (intptr_t) (pic_queue.entries[lcv].pic_event) ); + stream.write(reinterpret_cast(&event_idx), sizeof(event_idx) ); + + // - reloc ptr + stream.write(reinterpret_cast(&pic_next_ptr[lcv]), sizeof(pic_next_ptr[lcv]) ); + + + if( &pic_queue.entries[lcv] == pic_queue.free_entry ) pic_free_idx = lcv; + if( &pic_queue.entries[lcv] == pic_queue.next_entry ) pic_next_idx = lcv; + } + + // - reloc ptrs + stream.write(reinterpret_cast(&pic_free_idx), sizeof(pic_free_idx) ); + stream.write(reinterpret_cast(&pic_next_idx), sizeof(pic_next_idx) ); + + + // - data + stream.write(reinterpret_cast(&InEventService), sizeof(InEventService) ); + stream.write(reinterpret_cast(&srv_lag), sizeof(srv_lag) ); + + + // - reloc ptr + stream.write(reinterpret_cast(&ticker_size), sizeof(ticker_size) ); + + ticker_ptr = firstticker; + for( int lcv=0; lcvhandler) ); + stream.write(reinterpret_cast(&ticker_handler_idx), sizeof(ticker_handler_idx) ); + + // - reloc new ptr (leave alone) + //stream.write(reinterpret_cast(&ticker_ptr->next), sizeof(ticker_ptr->next) ); + + ticker_ptr = ticker_ptr->next; + } + + + // - system (leave alone) + //stream.write(reinterpret_cast(&PIC_benchstart), sizeof(PIC_benchstart) ); + //stream.write(reinterpret_cast(&PIC_tickstart), sizeof(PIC_tickstart) ); + + // - static (leave alone) + //test->saveState(stream); + } + + virtual void setBytes(std::istream& stream) + { + Bit16u free_idx, next_idx; + Bit16u ticker_size; + + + SerializeGlobalPOD::setBytes(stream); + + + // - data + stream.read(reinterpret_cast(&PIC_Ticks), sizeof(PIC_Ticks) ); + stream.read(reinterpret_cast(&PIC_IRQCheck), sizeof(PIC_IRQCheck) ); + + // - data structs + stream.read(reinterpret_cast(&pics), sizeof(pics) ); + + + for( int lcv=0; lcv(&pic_queue.entries[lcv].index), sizeof(pic_queue.entries[lcv].index) ); + stream.read(reinterpret_cast(&pic_queue.entries[lcv].value), sizeof(pic_queue.entries[lcv].value) ); + + + // - function ptr + stream.read(reinterpret_cast(&event_idx), sizeof(event_idx) ); + pic_queue.entries[lcv].pic_event = (PIC_EventHandler) PIC_State_IndexEvent( event_idx ); + + + // - reloc ptr + stream.read(reinterpret_cast(&next_idx), sizeof(next_idx) ); + + pic_queue.entries[lcv].next = NULL; + if( next_idx != 0xffff ) + pic_queue.entries[lcv].next = &pic_queue.entries[next_idx]; + } + + // - reloc ptrs + stream.read(reinterpret_cast(&free_idx), sizeof(free_idx) ); + stream.read(reinterpret_cast(&next_idx), sizeof(next_idx) ); + + pic_queue.free_entry = NULL; + if( free_idx != 0xffff ) + pic_queue.free_entry = &pic_queue.entries[free_idx]; + + pic_queue.next_entry = NULL; + if( next_idx != 0xffff ) + pic_queue.next_entry = &pic_queue.entries[next_idx]; + + + // - data + stream.read(reinterpret_cast(&InEventService), sizeof(InEventService) ); + stream.read(reinterpret_cast(&srv_lag), sizeof(srv_lag) ); + + + // 1- wipe old data + // 2- insert new data + while( firstticker != NULL ) { + TickerBlock *ticker_ptr; + + ticker_ptr = firstticker; + firstticker = firstticker->next; + + delete ticker_ptr; + } + + + // - reloc ptr + stream.read(reinterpret_cast(&ticker_size), sizeof(ticker_size) ); + + firstticker = NULL; + if( ticker_size ) { + TickerBlock *ticker_ptr; + + for( int lcv = 0; lcvnext = new TickerBlock; + ticker_ptr = ticker_ptr->next; + } + + + // - function ptr + stream.read(reinterpret_cast(&ticker_idx), sizeof(ticker_idx) ); + ticker_ptr->handler = (TIMER_TickHandler) PIC_State_IndexTimer( ticker_idx ); + + // - reloc new ptr (linked list) + ticker_ptr->next = NULL; + } + } + + + // - system (leave alone) + //stream.read(reinterpret_cast(&PIC_benchstart), sizeof(PIC_benchstart) ); + //stream.read(reinterpret_cast(&PIC_tickstart), sizeof(PIC_tickstart) ); + + // - static (leave alone) + //test->loadState(stream); + } +} dummy; +} diff --git a/src/hardware/sblaster.cpp b/src/hardware/sblaster.cpp index 9058df0..a636f17 100644 --- a/src/hardware/sblaster.cpp +++ b/src/hardware/sblaster.cpp @@ -29,6 +29,9 @@ #include "hardware.h" #include "setup.h" #include "support.h" + +#include "../save_state.h" + #include "shell.h" using namespace std; @@ -1730,3 +1733,123 @@ void SBLASTER_Init(Section* sec) { test = new SBLASTER(sec); sec->AddDestroyFunction(&SBLASTER_ShutDown,true); } + +// save state support +void *DMA_Silent_Event_PIC_Event = (void*)DMA_Silent_Event; +void *DSP_FinishReset_PIC_Event = (void*)DSP_FinishReset; +void *DSP_RaiseIRQEvent_PIC_Event = (void*)DSP_RaiseIRQEvent; +void *END_DMA_Event_PIC_Event = (void*)END_DMA_Event; + +void *SB_DSP_DMA_CallBack_Func = (void*)DSP_DMA_CallBack; +void *SB_DSP_ADC_CallBack_Func = (void*)DSP_ADC_CallBack; +void *SB_DSP_E2_DMA_CallBack_Func = (void*)DSP_E2_DMA_CallBack; + + +void POD_Save_Sblaster( std::ostream& stream ) +{ + const char pod_name[32] = "SBlaster"; + + if( stream.fail() ) return; + if( !test ) return; + if( !sb.chan ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //******************************************* + //******************************************* + //******************************************* + + Bit8u dma_idx; + + + dma_idx = 0xff; + for( int lcv=0; lcv<8; lcv++ ) { + if( sb.dma.chan == GetDMAChannel(lcv) ) { dma_idx = lcv; break; } + } + + // ******************************************* + // ******************************************* + // ******************************************* + + // - near-pure data + WRITE_POD( &sb, sb ); + + // - pure data + WRITE_POD( &ASP_regs, ASP_regs ); + WRITE_POD( &ASP_init_in_progress, ASP_init_in_progress ); + + + + // - reloc ptr + WRITE_POD( &dma_idx, dma_idx ); + + // ******************************************* + // ******************************************* + // ******************************************* + + sb.chan->SaveState(stream); +} + + +void POD_Load_Sblaster( std::istream& stream ) +{ + char pod_name[32] = {0}; + + if( stream.fail() ) return; + if( !test ) return; + if( !sb.chan ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "SBlaster" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + Bit8u dma_idx; + MixerChannel *mixer_old; + + + // save static ptr + mixer_old = sb.chan; + + //******************************************* + //******************************************* + //******************************************* + + // - near-pure data + READ_POD( &sb, sb ); + + // - pure data + READ_POD( &ASP_regs, ASP_regs ); + READ_POD( &ASP_init_in_progress, ASP_init_in_progress ); + + + + + // - reloc ptr + READ_POD( &dma_idx, dma_idx ); + + //******************************************* + //******************************************* + //******************************************* + + sb.dma.chan = NULL; + if( dma_idx != 0xff ) sb.dma.chan = GetDMAChannel(dma_idx); + + //******************************************* + //******************************************* + //******************************************* + + // restore static ptr + sb.chan = mixer_old; + + + sb.chan->LoadState(stream); +} \ No newline at end of file diff --git a/src/hardware/serialport/serialport.cpp b/src/hardware/serialport/serialport.cpp index e74bfcc..614978c 100644 --- a/src/hardware/serialport/serialport.cpp +++ b/src/hardware/serialport/serialport.cpp @@ -1296,3 +1296,6 @@ void SERIAL_Init (Section * sec) { testSerialPortsBaseclass = new SERIALPORTS (sec); sec->AddDestroyFunction (&SERIAL_Destroy, true); } + +// save state support +void *Serial_EventHandler_PIC_Event = (void*)Serial_EventHandler; \ No newline at end of file diff --git a/src/hardware/tandy_sound.cpp b/src/hardware/tandy_sound.cpp index 99cc79b..924713f 100644 --- a/src/hardware/tandy_sound.cpp +++ b/src/hardware/tandy_sound.cpp @@ -33,6 +33,10 @@ #include "mame/emu.h" #include "mame/sn76496.h" +#include "../save_state.h" + +#define MAX_OUTPUT 0x7fff +#define STEP 0x10000 #define SOUND_CLOCK (14318180 / 4) @@ -346,3 +350,119 @@ void TANDYSOUND_Init(Section* sec) { test = new TANDYSOUND(sec); sec->AddDestroyFunction(&TANDYSOUND_ShutDown,true); } + +// save state support +void *TandyDAC_DMA_CallBack_Func = (void*)TandyDAC_DMA_CallBack; + + +void POD_Save_Tandy_Sound( std::ostream& stream ) +{ + const char pod_name[32] = "Tandy"; + + if( stream.fail() ) return; + if( !test ) return; + if( !tandy.chan ) return; + + + WRITE_POD( &pod_name, pod_name ); + + //******************************************* + //******************************************* + //******************************************* + + Bit8u dma_idx; + + + dma_idx = 0xff; + for( int lcv=0; lcv<8; lcv++ ) { + if( tandy.dac.dma.chan == GetDMAChannel(lcv) ) { dma_idx = lcv; break; } + } + + // ******************************************* + // ******************************************* + // ******************************************* + + // - pure data +// WRITE_POD( &sn, sn ); + + // - near-pure data + WRITE_POD( &tandy, tandy ); + + + + + // - reloc ptr + WRITE_POD( &dma_idx, dma_idx ); + + // ******************************************* + // ******************************************* + // ******************************************* + + tandy.chan->SaveState(stream); + tandy.dac.chan->SaveState(stream); +} + + +void POD_Load_Tandy_Sound( std::istream& stream ) +{ + char pod_name[32] = {0}; + + if( stream.fail() ) return; + if( !test ) return; + if( !tandy.chan ) return; + + + // error checking + READ_POD( &pod_name, pod_name ); + if( strcmp( pod_name, "Tandy" ) ) { + stream.clear( std::istream::failbit | std::istream::badbit ); + return; + } + + //************************************************ + //************************************************ + //************************************************ + + Bit8u dma_idx; + MixerChannel *chan_old, *dac_chan_old; + + + // - save static ptrs + chan_old = tandy.chan; + dac_chan_old = tandy.dac.chan; + + // ******************************************* + // ******************************************* + // ******************************************* + + // - pure data +// READ_POD( &sn, sn ); + + // - near-pure data + READ_POD( &tandy, tandy ); + + + + + // - reloc ptr + READ_POD( &dma_idx, dma_idx ); + + // ******************************************* + // ******************************************* + // ******************************************* + + tandy.dac.dma.chan = NULL; + if( dma_idx != 0xff ) tandy.dac.dma.chan = GetDMAChannel(dma_idx); + + // ******************************************* + // ******************************************* + // ******************************************* + + // - restore static ptrs + tandy.chan = chan_old; + tandy.dac.chan = dac_chan_old; + + + tandy.chan->LoadState(stream); + tandy.dac.chan->LoadState(stream); +} diff --git a/src/hardware/timer.cpp b/src/hardware/timer.cpp index 0173f99..ee2584e 100644 --- a/src/hardware/timer.cpp +++ b/src/hardware/timer.cpp @@ -26,6 +26,8 @@ #include "timer.h" #include "setup.h" +#include "../save_state.h" + static INLINE void BIN2BCD(Bit16u& val) { Bit16u temp=val%10 + (((val/10)%10)<<4)+ (((val/100)%10)<<8) + (((val/1000)%10)<<12); val=temp; @@ -467,3 +469,22 @@ void TIMER_Init(Section* sec) { test = new TIMER(sec); sec->AddDestroyFunction(&TIMER_Destroy); } + +//save state support +void *PIT0_Event_PIC_Event = (void*)PIT0_Event; + + +namespace +{ +class SerializeTimer : public SerializeGlobalPOD +{ +public: + SerializeTimer() : SerializeGlobalPOD("IntTimer10") + { + registerPOD(pit); + registerPOD(gate2); + registerPOD(latched_timerstatus); + registerPOD(latched_timerstatus_locked); + } +} dummy; +} \ No newline at end of file diff --git a/src/hardware/vga.cpp b/src/hardware/vga.cpp index 3d45384..5273f16 100644 --- a/src/hardware/vga.cpp +++ b/src/hardware/vga.cpp @@ -23,6 +23,9 @@ #include "pic.h" #include "vga.h" +#include "../save_state.h" +#include "mem.h" + #include VGA_Type vga; @@ -261,3 +264,279 @@ void SVGA_Setup_Driver(void) { break; } } + +extern void POD_Save_VGA_Draw( std::ostream & ); +extern void POD_Save_VGA_Seq( std::ostream & ); +extern void POD_Save_VGA_Attr( std::ostream & ); +extern void POD_Save_VGA_Crtc( std::ostream & ); +extern void POD_Save_VGA_Gfx( std::ostream & ); +extern void POD_Save_VGA_Dac( std::ostream & ); +extern void POD_Save_VGA_S3( std::ostream & ); +extern void POD_Save_VGA_Other( std::ostream & ); +extern void POD_Save_VGA_Memory( std::ostream & ); +extern void POD_Save_VGA_Paradise( std::ostream & ); +extern void POD_Save_VGA_Tseng( std::ostream & ); +extern void POD_Save_VGA_XGA( std::ostream & ); +extern void POD_Load_VGA_Draw( std::istream & ); +extern void POD_Load_VGA_Seq( std::istream & ); +extern void POD_Load_VGA_Attr( std::istream & ); +extern void POD_Load_VGA_Crtc( std::istream & ); +extern void POD_Load_VGA_Gfx( std::istream & ); +extern void POD_Load_VGA_Dac( std::istream & ); +extern void POD_Load_VGA_S3( std::istream & ); +extern void POD_Load_VGA_Other( std::istream & ); +extern void POD_Load_VGA_Memory( std::istream & ); +extern void POD_Load_VGA_Paradise( std::istream & ); +extern void POD_Load_VGA_Tseng( std::istream & ); +extern void POD_Load_VGA_XGA( std::istream & ); + +//save state support +void *VGA_SetupDrawing_PIC_Event = (void*)VGA_SetupDrawing; + + +namespace { +class SerializeVga : public SerializeGlobalPOD { +public: + SerializeVga() : SerializeGlobalPOD("Vga") + {} + +private: + virtual void getBytes(std::ostream& stream) + { + Bit32u tandy_drawbase_idx, tandy_membase_idx; + + + + + if( vga.tandy.draw_base == vga.mem.linear ) tandy_drawbase_idx=0xffffffff; + else tandy_drawbase_idx = vga.tandy.draw_base - MemBase; + + if( vga.tandy.mem_base == vga.mem.linear ) tandy_membase_idx=0xffffffff; + else tandy_membase_idx = vga.tandy.mem_base - MemBase; + + //******************************** + //******************************** + + SerializeGlobalPOD::getBytes(stream); + + + // - pure data + WRITE_POD( &vga.mode, vga.mode ); + WRITE_POD( &vga.misc_output, vga.misc_output ); + + + // VGA_Draw.cpp + POD_Save_VGA_Draw(stream); + + + // - pure struct data + WRITE_POD( &vga.config, vga.config ); + WRITE_POD( &vga.internal, vga.internal ); + + + // VGA_Seq.cpp / VGA_Attr.cpp / (..) + POD_Save_VGA_Seq(stream); + POD_Save_VGA_Attr(stream); + POD_Save_VGA_Crtc(stream); + POD_Save_VGA_Gfx(stream); + POD_Save_VGA_Dac(stream); + + + // - pure data + WRITE_POD( &vga.latch, vga.latch ); + + + // VGA_S3.cpp + POD_Save_VGA_S3(stream); + + + // - pure struct data + WRITE_POD( &vga.svga, vga.svga ); + WRITE_POD( &vga.herc, vga.herc ); + + + // - near-pure struct data + WRITE_POD( &vga.tandy, vga.tandy ); + + // - reloc data + WRITE_POD( &tandy_drawbase_idx, tandy_drawbase_idx ); + WRITE_POD( &tandy_membase_idx, tandy_membase_idx ); + + + // vga_other.cpp / vga_memory.cpp + POD_Save_VGA_Other(stream); + POD_Save_VGA_Memory(stream); + + + // - pure data + WRITE_POD( &vga.vmemwrap, vga.vmemwrap ); + + + // - static ptrs + 'new' data + //Bit8u* fastmem; + //Bit8u* fastmem_orgptr; + + // - 'new' data + WRITE_POD_SIZE( vga.fastmem_orgptr, sizeof(Bit8u) * ((vga.vmemsize << 1) + 4096 + 16) ); + + + // - pure data (variable on S3 card) + WRITE_POD( &vga.vmemsize, vga.vmemsize ); + + +#ifdef VGA_KEEP_CHANGES + // - static ptr + //Bit8u* map; + + // - 'new' data + WRITE_POD_SIZE( vga.changes.map, sizeof(Bit8u) * (VGA_MEMORY >> VGA_CHANGE_SHIFT) + 32 ); + + + // - pure data + WRITE_POD( &vga.changes.checkMask, vga.changes.checkMask ); + WRITE_POD( &vga.changes.frame, vga.changes.frame ); + WRITE_POD( &vga.changes.writeMask, vga.changes.writeMask ); + WRITE_POD( &vga.changes.active, vga.changes.active ); + WRITE_POD( &vga.changes.clearMask, vga.changes.clearMask ); + WRITE_POD( &vga.changes.start, vga.changes.start ); + WRITE_POD( &vga.changes.last, vga.changes.last ); + WRITE_POD( &vga.changes.lastAddress, vga.changes.lastAddress ); +#endif + + + // - pure data + WRITE_POD( &vga.lfb.page, vga.lfb.page ); + WRITE_POD( &vga.lfb.addr, vga.lfb.addr ); + WRITE_POD( &vga.lfb.mask, vga.lfb.mask ); + + // - static ptr + //PageHandler *handler; + + + // VGA_paradise.cpp / VGA_tseng.cpp / VGA_xga.cpp + POD_Save_VGA_Paradise(stream); + POD_Save_VGA_Tseng(stream); + POD_Save_VGA_XGA(stream); + } + + virtual void setBytes(std::istream& stream) + { + Bit32u tandy_drawbase_idx, tandy_membase_idx; + + + + //******************************** + //******************************** + + SerializeGlobalPOD::setBytes(stream); + + + // - pure data + READ_POD( &vga.mode, vga.mode ); + READ_POD( &vga.misc_output, vga.misc_output ); + + + // VGA_Draw.cpp + POD_Load_VGA_Draw(stream); + + + // - pure struct data + READ_POD( &vga.config, vga.config ); + READ_POD( &vga.internal, vga.internal ); + + + // VGA_Seq.cpp / VGA_Attr.cpp / (..) + POD_Load_VGA_Seq(stream); + POD_Load_VGA_Attr(stream); + POD_Load_VGA_Crtc(stream); + POD_Load_VGA_Gfx(stream); + POD_Load_VGA_Dac(stream); + + + // - pure data + READ_POD( &vga.latch, vga.latch ); + + + // VGA_S3.cpp + POD_Load_VGA_S3(stream); + + + // - pure struct data + READ_POD( &vga.svga, vga.svga ); + READ_POD( &vga.herc, vga.herc ); + + + // - near-pure struct data + READ_POD( &vga.tandy, vga.tandy ); + + // - reloc data + READ_POD( &tandy_drawbase_idx, tandy_drawbase_idx ); + READ_POD( &tandy_membase_idx, tandy_membase_idx ); + + + // vga_other.cpp / vga_memory.cpp + POD_Load_VGA_Other(stream); + POD_Load_VGA_Memory(stream); + + + // - pure data + READ_POD( &vga.vmemwrap, vga.vmemwrap ); + + + // - static ptrs + 'new' data + //Bit8u* fastmem; + //Bit8u* fastmem_orgptr; + + // - 'new' data + READ_POD_SIZE( vga.fastmem_orgptr, sizeof(Bit8u) * ((vga.vmemsize << 1) + 4096 + 16) ); + + + // - pure data (variable on S3 card) + READ_POD( &vga.vmemsize, vga.vmemsize ); + + +#ifdef VGA_KEEP_CHANGES + // - static ptr + //Bit8u* map; + + // - 'new' data + READ_POD_SIZE( vga.changes.map, sizeof(Bit8u) * (VGA_MEMORY >> VGA_CHANGE_SHIFT) + 32 ); + + + // - pure data + READ_POD( &vga.changes.checkMask, vga.changes.checkMask ); + READ_POD( &vga.changes.frame, vga.changes.frame ); + READ_POD( &vga.changes.writeMask, vga.changes.writeMask ); + READ_POD( &vga.changes.active, vga.changes.active ); + READ_POD( &vga.changes.clearMask, vga.changes.clearMask ); + READ_POD( &vga.changes.start, vga.changes.start ); + READ_POD( &vga.changes.last, vga.changes.last ); + READ_POD( &vga.changes.lastAddress, vga.changes.lastAddress ); +#endif + + + // - pure data + READ_POD( &vga.lfb.page, vga.lfb.page ); + READ_POD( &vga.lfb.addr, vga.lfb.addr ); + READ_POD( &vga.lfb.mask, vga.lfb.mask ); + + // - static ptr + //PageHandler *handler; + + + // VGA_paradise.cpp / VGA_tseng.cpp / VGA_xga.cpp + POD_Load_VGA_Paradise(stream); + POD_Load_VGA_Tseng(stream); + POD_Load_VGA_XGA(stream); + + //******************************** + //******************************** + + if( tandy_drawbase_idx == 0xffffffff ) vga.tandy.draw_base = vga.mem.linear; + else vga.tandy.draw_base = MemBase + tandy_drawbase_idx; + + if( tandy_membase_idx == 0xffffffff ) vga.tandy.mem_base = vga.mem.linear; + else vga.tandy.mem_base = MemBase + tandy_membase_idx; + } +} dummy; +} \ No newline at end of file diff --git a/src/hardware/vga_attr.cpp b/src/hardware/vga_attr.cpp index 3d48d8e..27cca0f 100644 --- a/src/hardware/vga_attr.cpp +++ b/src/hardware/vga_attr.cpp @@ -21,6 +21,8 @@ #include "inout.h" #include "vga.h" +#include "../save_state.h" + #define attr(blah) vga.attr.blah void VGA_ATTR_SetEGAMonitorPalette(EGAMonitorMode m) { @@ -294,3 +296,23 @@ void VGA_SetupAttr(void) { } } } + +// save state support +void POD_Save_VGA_Attr( std::ostream& stream ) +{ + // - pure struct data + WRITE_POD( &vga.attr, vga.attr ); + + + // no static globals found +} + + +void POD_Load_VGA_Attr( std::istream& stream ) +{ + // - pure struct data + READ_POD( &vga.attr, vga.attr ); + + + // no static globals found +} \ No newline at end of file diff --git a/src/hardware/vga_crtc.cpp b/src/hardware/vga_crtc.cpp index 47e2368..bfd6eab 100644 --- a/src/hardware/vga_crtc.cpp +++ b/src/hardware/vga_crtc.cpp @@ -26,6 +26,8 @@ #include "video.h" #include "pic.h" +#include "../save_state.h" + #define crtc(blah) vga.crtc.blah @@ -430,6 +432,23 @@ Bitu vga_read_p3d5(Bitu port,Bitu iolen) { } } +// save state support + +void POD_Save_VGA_Crtc( std::ostream& stream ) +{ + // - pure struct data + WRITE_POD( &vga.crtc, vga.crtc ); + + + // no static globals found +} + +void POD_Load_VGA_Crtc( std::istream& stream ) +{ + // - pure struct data + READ_POD( &vga.crtc, vga.crtc ); + // no static globals found +} \ No newline at end of file diff --git a/src/hardware/vga_dac.cpp b/src/hardware/vga_dac.cpp index f5cd529..e572e35 100644 --- a/src/hardware/vga_dac.cpp +++ b/src/hardware/vga_dac.cpp @@ -21,6 +21,8 @@ #include "render.h" #include "vga.h" +#include "../save_state.h" + /* 3C6h (R/W): PEL Mask bit 0-7 This register is anded with the palette index sent for each dot. @@ -216,3 +218,24 @@ void VGA_SetupDAC(void) { IO_RegisterReadHandler(0x3c9,read_p3c9,IO_MB); } } + +// save state support + +void POD_Save_VGA_Dac( std::ostream& stream ) +{ + // - pure struct data + WRITE_POD( &vga.dac, vga.dac ); + + + // no static globals found +} + + +void POD_Load_VGA_Dac( std::istream& stream ) +{ + // - pure struct data + READ_POD( &vga.dac, vga.dac ); + + + // no static globals found +} \ No newline at end of file diff --git a/src/hardware/vga_draw.cpp b/src/hardware/vga_draw.cpp index 9a93997..f2f91fd 100644 --- a/src/hardware/vga_draw.cpp +++ b/src/hardware/vga_draw.cpp @@ -26,6 +26,8 @@ #include "vga.h" #include "pic.h" +#include "../save_state.h" + //#undef C_DEBUG //#define C_DEBUG 1 //#define LOG(X,Y) LOG_MSG @@ -1620,3 +1622,172 @@ void VGA_SetOverride(bool vga_override) { } } } + +// save state support +void *VGA_DisplayStartLatch_PIC_Event = (void*)VGA_DisplayStartLatch; +void *VGA_DrawEGASingleLine_PIC_Event = (void*)VGA_DrawEGASingleLine; +void *VGA_DrawPart_PIC_Event = (void*)VGA_DrawPart; +void *VGA_DrawSingleLine_PIC_Event = (void*)VGA_DrawSingleLine; +void *VGA_Other_VertInterrupt_PIC_Event = (void*)VGA_Other_VertInterrupt; +void *VGA_PanningLatch_PIC_Event = (void*)VGA_PanningLatch; +void *VGA_VertInterrupt_PIC_Event = (void*)VGA_VertInterrupt; +void *VGA_VerticalTimer_PIC_Event = (void*)VGA_VerticalTimer; + + +void POD_Save_VGA_Draw( std::ostream& stream ) +{ + Bit8u linear_base_idx; + Bit8u font_tables_idx[2]; + Bit8u drawline_idx; + + + if(0) {} + else if( vga.draw.linear_base == vga.mem.linear ) linear_base_idx = 0; + else if( vga.draw.linear_base == vga.fastmem ) linear_base_idx = 1; + + + for( int lcv=0; lcv<2; lcv++ ) { + if(0) {} + else if( vga.draw.font_tables[lcv] == &(vga.draw.font[0*1024]) ) font_tables_idx[lcv] = 0; + else if( vga.draw.font_tables[lcv] == &(vga.draw.font[8*1024]) ) font_tables_idx[lcv] = 1; + else if( vga.draw.font_tables[lcv] == &(vga.draw.font[16*1024]) ) font_tables_idx[lcv] = 2; + else if( vga.draw.font_tables[lcv] == &(vga.draw.font[24*1024]) ) font_tables_idx[lcv] = 3; + else if( vga.draw.font_tables[lcv] == &(vga.draw.font[32*1024]) ) font_tables_idx[lcv] = 4; + else if( vga.draw.font_tables[lcv] == &(vga.draw.font[40*1024]) ) font_tables_idx[lcv] = 5; + else if( vga.draw.font_tables[lcv] == &(vga.draw.font[48*1024]) ) font_tables_idx[lcv] = 6; + else if( vga.draw.font_tables[lcv] == &(vga.draw.font[56*1024]) ) font_tables_idx[lcv] = 7; + } + + + if(0) {} + else if( VGA_DrawLine == VGA_Draw_1BPP_Line ) drawline_idx = 1; + else if( VGA_DrawLine == VGA_Draw_2BPP_Line ) drawline_idx = 3; + else if( VGA_DrawLine == VGA_Draw_2BPPHiRes_Line ) drawline_idx = 4; + else if( VGA_DrawLine == VGA_Draw_CGA16_Line ) drawline_idx = 5; + else if( VGA_DrawLine == VGA_Draw_4BPP_Line ) drawline_idx = 6; + else if( VGA_DrawLine == VGA_Draw_4BPP_Line_Double ) drawline_idx = 7; + else if( VGA_DrawLine == VGA_Draw_Linear_Line ) drawline_idx = 8; + else if( VGA_DrawLine == VGA_Draw_Xlat16_Linear_Line ) drawline_idx = 9; + else if( VGA_DrawLine == VGA_Draw_VGA_Line_HWMouse ) drawline_idx = 11; + else if( VGA_DrawLine == VGA_Draw_LIN16_Line_HWMouse ) drawline_idx = 12; + else if( VGA_DrawLine == VGA_Draw_LIN32_Line_HWMouse ) drawline_idx = 13; + else if( VGA_DrawLine == VGA_TEXT_Draw_Line ) drawline_idx = 14; + else if( VGA_DrawLine == VGA_TEXT_Herc_Draw_Line ) drawline_idx = 15; + else if( VGA_DrawLine == VGA_TEXT_Xlat16_Draw_Line ) drawline_idx = 17; + + //********************************************** + //********************************************** + + // - near-pure (struct) data + WRITE_POD( &vga.draw, vga.draw ); + + + // - reloc ptr + WRITE_POD( &linear_base_idx, linear_base_idx ); + WRITE_POD( &font_tables_idx, font_tables_idx ); + + //********************************************** + //********************************************** + + // static globals + + // - reloc function ptr + WRITE_POD( &drawline_idx, drawline_idx ); + + + // - pure data + WRITE_POD( &TempLine, TempLine ); + + + // - system data + //WRITE_POD( &vsync, vsync ); + //WRITE_POD( &uservsyncjolt, uservsyncjolt ); + + + // - pure data + WRITE_POD( &temp, temp ); + WRITE_POD( &FontMask, FontMask ); + WRITE_POD( &bg_color_index, bg_color_index ); +} + + +void POD_Load_VGA_Draw( std::istream& stream ) +{ + Bit8u linear_base_idx; + Bit8u font_tables_idx[2]; + Bit8u drawline_idx; + + //********************************************** + //********************************************** + + // - near-pure (struct) data + READ_POD( &vga.draw, vga.draw ); + + + // - reloc ptr + READ_POD( &linear_base_idx, linear_base_idx ); + READ_POD( &font_tables_idx, font_tables_idx ); + + //********************************************** + //********************************************** + + // static globals + + // - reloc function ptr + READ_POD( &drawline_idx, drawline_idx ); + + + // - pure data + READ_POD( &TempLine, TempLine ); + + + // - system data + //READ_POD( &vsync, vsync ); + //READ_POD( &uservsyncjolt, uservsyncjolt ); + + + // - pure data + READ_POD( &temp, temp ); + READ_POD( &FontMask, FontMask ); + READ_POD( &bg_color_index, bg_color_index ); + + //********************************************** + //********************************************** + + switch( linear_base_idx ) { + case 0: vga.draw.linear_base = vga.mem.linear; break; + case 1: vga.draw.linear_base = vga.fastmem; break; + } + + + for( int lcv=0; lcv<2; lcv++ ) { + switch( font_tables_idx[lcv] ) { + case 0: vga.draw.font_tables[lcv] = &(vga.draw.font[0*1024]); break; + case 1: vga.draw.font_tables[lcv] = &(vga.draw.font[8*1024]); break; + case 2: vga.draw.font_tables[lcv] = &(vga.draw.font[16*1024]); break; + case 3: vga.draw.font_tables[lcv] = &(vga.draw.font[24*1024]); break; + case 4: vga.draw.font_tables[lcv] = &(vga.draw.font[32*1024]); break; + case 5: vga.draw.font_tables[lcv] = &(vga.draw.font[40*1024]); break; + case 6: vga.draw.font_tables[lcv] = &(vga.draw.font[48*1024]); break; + case 7: vga.draw.font_tables[lcv] = &(vga.draw.font[56*1024]); break; + } + } + + + switch( drawline_idx ) { + case 1: VGA_DrawLine = VGA_Draw_1BPP_Line; break; + case 3: VGA_DrawLine = VGA_Draw_2BPP_Line; break; + case 4: VGA_DrawLine = VGA_Draw_2BPPHiRes_Line; break; + case 5: VGA_DrawLine = VGA_Draw_CGA16_Line; break; + case 6: VGA_DrawLine = VGA_Draw_4BPP_Line; break; + case 7: VGA_DrawLine = VGA_Draw_4BPP_Line_Double; break; + case 8: VGA_DrawLine = VGA_Draw_Linear_Line; break; + case 9: VGA_DrawLine = VGA_Draw_Xlat16_Linear_Line; break; + case 11: VGA_DrawLine = VGA_Draw_VGA_Line_HWMouse; break; + case 12: VGA_DrawLine = VGA_Draw_LIN16_Line_HWMouse; break; + case 13: VGA_DrawLine = VGA_Draw_LIN32_Line_HWMouse; break; + case 14: VGA_DrawLine = VGA_TEXT_Draw_Line; break; + case 15: VGA_DrawLine = VGA_TEXT_Herc_Draw_Line; break; + case 17: VGA_DrawLine = VGA_TEXT_Xlat16_Draw_Line; break; + } +} \ No newline at end of file diff --git a/src/hardware/vga_gfx.cpp b/src/hardware/vga_gfx.cpp index 40e0420..e87be74 100644 --- a/src/hardware/vga_gfx.cpp +++ b/src/hardware/vga_gfx.cpp @@ -21,6 +21,8 @@ #include "inout.h" #include "vga.h" +#include "../save_state.h" + #define gfx(blah) vga.gfx.blah static bool index9warned=false; @@ -232,4 +234,29 @@ void VGA_SetupGFX(void) { } } +// save state support + +void POD_Save_VGA_Gfx( std::ostream& stream ) +{ + // - pure struct data + WRITE_POD( &vga.gfx, vga.gfx ); + + //******************************************* + //******************************************* + + // - system data + //WRITE_POD( &index9warned, index9warned ); +} + + +void POD_Load_VGA_Gfx( std::istream& stream ) +{ + // - pure struct data + READ_POD( &vga.gfx, vga.gfx ); + + //******************************************* + //******************************************* + // - system data + //READ_POD( &index9warned, index9warned ); +} \ No newline at end of file diff --git a/src/hardware/vga_memory.cpp b/src/hardware/vga_memory.cpp index dcd5e47..a3a2103 100644 --- a/src/hardware/vga_memory.cpp +++ b/src/hardware/vga_memory.cpp @@ -27,6 +27,8 @@ #include "inout.h" #include "setup.h" +#include "../save_state.h" + #ifndef C_VGARAM_CHECKED #define C_VGARAM_CHECKED 1 @@ -986,3 +988,69 @@ void VGA_SetupMemory(Section* sec) { //TODO map? } } + +// save state support +void *VGA_PageHandler_Func[16] = +{ + (void *) &vgaph.map, + (void *) &vgaph.changes, + (void *) &vgaph.text, + (void *) &vgaph.tandy, + (void *) &vgaph.cega, + (void *) &vgaph.cvga, + (void *) &vgaph.uega, + (void *) &vgaph.uvga, + (void *) &vgaph.pcjr, + (void *) &vgaph.herc, + (void *) &vgaph.lin4, + (void *) &vgaph.lfb, + (void *) &vgaph.lfbchanges, + (void *) &vgaph.mmio, + (void *) &vgaph.empty, +}; + + +void POD_Save_VGA_Memory( std::ostream& stream ) +{ + // - static ptrs + //Bit8u* linear; + //Bit8u* linear_orgptr; + + + // - pure data + WRITE_POD_SIZE( vga.mem.linear_orgptr, sizeof(Bit8u) * (std::max(vga.vmemsize, 512 * 1024U) + 2048 + 16) ); + + //*************************************************** + //*************************************************** + + // static globals + + // - pure struct data + WRITE_POD( &vgapages, vgapages ); + + // - static classes + //WRITE_POD( &vgaph, vgaph ); +} + + +void POD_Load_VGA_Memory( std::istream& stream ) +{ + // - static ptrs + //Bit8u* linear; + //Bit8u* linear_orgptr; + + + // - pure data + READ_POD_SIZE( vga.mem.linear_orgptr, sizeof(Bit8u) * (std::max(vga.vmemsize, 512 * 1024U) + 2048 + 16) ); + + //*************************************************** + //*************************************************** + + // static globals + + // - pure struct data + READ_POD( &vgapages, vgapages ); + + // - static classes + //READ_POD( &vgaph, vgaph ); +} \ No newline at end of file diff --git a/src/hardware/vga_other.cpp b/src/hardware/vga_other.cpp index 1e0f91d..52636ca 100644 --- a/src/hardware/vga_other.cpp +++ b/src/hardware/vga_other.cpp @@ -27,6 +27,8 @@ #include "render.h" #include "mapper.h" +#include "../save_state.h" + static void write_crtc_index_other(Bitu /*port*/,Bitu val,Bitu /*iolen*/) { vga.other.index=(Bit8u)val; } @@ -865,3 +867,38 @@ void VGA_SetupOther(void) { } } + +// save state support + +void POD_Save_VGA_Other( std::ostream& stream ) +{ + // - pure struct data + WRITE_POD( &vga.other, vga.other ); + + //**************************************** + //**************************************** + + // static globals + + // - system + user data + WRITE_POD( &hue_offset, hue_offset ); + WRITE_POD( &cga16_val, cga16_val ); + WRITE_POD( &herc_pal, herc_pal ); +} + + +void POD_Load_VGA_Other( std::istream& stream ) +{ + // - pure struct data + READ_POD( &vga.other, vga.other ); + + //**************************************** + //**************************************** + + // static globals + + // - system + user data + READ_POD( &hue_offset, hue_offset ); + READ_POD( &cga16_val, cga16_val ); + READ_POD( &herc_pal, herc_pal ); +} \ No newline at end of file diff --git a/src/hardware/vga_paradise.cpp b/src/hardware/vga_paradise.cpp index 59b5642..78a85ec 100644 --- a/src/hardware/vga_paradise.cpp +++ b/src/hardware/vga_paradise.cpp @@ -23,6 +23,8 @@ #include "inout.h" #include "mem.h" +#include "../save_state.h" + typedef struct { Bitu PR0A; Bitu PR0B; @@ -239,3 +241,24 @@ void SVGA_Setup_ParadisePVGA1A(void) { IO_Write(0x3cf, 0x05); // Enable! } + +// save state support + +void POD_Save_VGA_Paradise( std::ostream& stream ) +{ + // static globals + + + // - pure struct data + WRITE_POD( &pvga1a, pvga1a ); +} + + +void POD_Load_VGA_Paradise( std::istream& stream ) +{ + // static globals + + + // - pure struct data + READ_POD( &pvga1a, pvga1a ); +} \ No newline at end of file diff --git a/src/hardware/vga_s3.cpp b/src/hardware/vga_s3.cpp index 87bbbed..7c1e1ad 100644 --- a/src/hardware/vga_s3.cpp +++ b/src/hardware/vga_s3.cpp @@ -22,6 +22,8 @@ #include "vga.h" #include "mem.h" +#include "../save_state.h" + void SVGA_S3_WriteCRTC(Bitu reg,Bitu val,Bitu iolen) { switch (reg) { case 0x31: /* CR31 Memory Configuration */ @@ -563,3 +565,28 @@ void SVGA_Setup_S3Trio(void) { phys_writeb(rom_base+0x0046,'6'); phys_writeb(rom_base+0x0047,'4'); } + +// save state support + +void POD_Save_VGA_S3( std::ostream& stream ) +{ + // - pure struct data + WRITE_POD( &vga.s3, vga.s3 ); + + //***************************************** + //***************************************** + + // static globals +} + + +void POD_Load_VGA_S3( std::istream& stream ) +{ + // - pure struct data + READ_POD( &vga.s3, vga.s3 ); + + //***************************************** + //***************************************** + + // static globals +} \ No newline at end of file diff --git a/src/hardware/vga_seq.cpp b/src/hardware/vga_seq.cpp index 7cd711c..68290a3 100644 --- a/src/hardware/vga_seq.cpp +++ b/src/hardware/vga_seq.cpp @@ -21,6 +21,8 @@ #include "inout.h" #include "vga.h" +#include "../save_state.h" + #define seq(blah) vga.seq.blah Bitu read_p3c4(Bitu /*port*/,Bitu /*iolen*/) { @@ -158,3 +160,22 @@ void VGA_SetupSEQ(void) { } } +// save state support + +void POD_Save_VGA_Seq( std::ostream& stream ) +{ + // - pure struct data + WRITE_POD( &vga.seq, vga.seq ); + + + // no static globals found +} + + +void POD_Load_VGA_Seq( std::istream& stream ) +{ + // - pure struct data + READ_POD( &vga.seq, vga.seq ); + + // no static globals found +} \ No newline at end of file diff --git a/src/hardware/vga_tseng.cpp b/src/hardware/vga_tseng.cpp index 576346a..0205705 100644 --- a/src/hardware/vga_tseng.cpp +++ b/src/hardware/vga_tseng.cpp @@ -24,6 +24,9 @@ #include "inout.h" #include "mem.h" #include + +#include "../save_state.h" + // Tseng ET4K data typedef struct { Bit8u extensionsEnabled; @@ -805,3 +808,26 @@ void SVGA_Setup_TsengET3K(void) { phys_writeb(rom_base+0x007a,'g'); phys_writeb(rom_base+0x007b,' '); } + +// save state support + +void POD_Save_VGA_Tseng( std::ostream& stream ) +{ + // static globals + + + // - pure struct data + WRITE_POD( &et4k, et4k ); + WRITE_POD( &et3k, et3k ); +} + + +void POD_Load_VGA_Tseng( std::istream& stream ) +{ + // static globals + + + // - pure struct data + READ_POD( &et4k, et4k ); + READ_POD( &et3k, et3k ); +} \ No newline at end of file diff --git a/src/hardware/vga_xga.cpp b/src/hardware/vga_xga.cpp index def606d..f942c5f 100644 --- a/src/hardware/vga_xga.cpp +++ b/src/hardware/vga_xga.cpp @@ -26,6 +26,8 @@ #include "callback.h" #include "cpu.h" // for 0x3da delay +#include "../save_state.h" + #define XGA_SCREEN_WIDTH vga.s3.xga_screen_width #define XGA_COLOR_MODE vga.s3.xga_color_mode @@ -1317,3 +1319,24 @@ void VGA_SetupXGA(void) { IO_RegisterWriteHandler(0xe2ea,&XGA_Write,IO_MB | IO_MW | IO_MD); IO_RegisterReadHandler(0xe2ea,&XGA_Read,IO_MB | IO_MW | IO_MD); } + +// save state support + +void POD_Save_VGA_XGA( std::ostream& stream ) +{ + // static globals + + + // - pure struct data + WRITE_POD( &xga, xga ); +} + + +void POD_Load_VGA_XGA( std::istream& stream ) +{ + // static globals + + + // - pure struct data + READ_POD( &xga, xga ); +} \ No newline at end of file diff --git a/src/ints/ems.cpp b/src/ints/ems.cpp index c835706..ddbc089 100644 --- a/src/ints/ems.cpp +++ b/src/ints/ems.cpp @@ -31,6 +31,9 @@ #include "setup.h" #include "support.h" #include "cpu.h" + +#include "../save_state.h" + #include "dma.h" #define EMM_PAGEFRAME 0xE000 @@ -1469,3 +1472,25 @@ void EMS_Init(Section* sec) { //Initialize static members Bit16u EMS::ems_baseseg = 0; + +//save state support +namespace +{ +class SerializeEMS : public SerializeGlobalPOD +{ +public: + SerializeEMS() : SerializeGlobalPOD("EMS") + { + registerPOD(emm_handles); + registerPOD(emm_mappings); + registerPOD(emm_segmentmappings); + registerPOD(GEMMIS_seg); + registerPOD(vcpi.enabled); + registerPOD(vcpi.ems_handle); + registerPOD(vcpi.pm_interface); + registerPOD(vcpi.private_area); + registerPOD(vcpi.pic1_remapping); + registerPOD(vcpi.pic2_remapping); + } +} dummy; +} \ No newline at end of file diff --git a/src/ints/int10.cpp b/src/ints/int10.cpp index 2a8f996..9c0455f 100644 --- a/src/ints/int10.cpp +++ b/src/ints/int10.cpp @@ -26,6 +26,8 @@ #include "mouse.h" #include "setup.h" +#include "../save_state.h" + Int10Data int10; static Bitu call_10; static bool warned_ff=false; @@ -767,3 +769,24 @@ void INT10_Init(Section* /*sec*/) { INT10_Seg40Init(); INT10_SetVideoMode(0x3); } + +//save state support +namespace +{ +class SerializeInt10 : public SerializeGlobalPOD +{ +public: + SerializeInt10() : SerializeGlobalPOD("Int10") + { + registerPOD(int10); + //registerPOD(CurMode); + //registerPOD(call_10); + //registerPOD(warned_ff); + } + + // virtual void setBytes(std::istream& stream) + //{ + // SerializeGlobalPOD::setBytes(stream); + //} +} dummy; +} \ No newline at end of file diff --git a/src/ints/mouse.cpp b/src/ints/mouse.cpp index 2d0d5d7..c932c52 100644 --- a/src/ints/mouse.cpp +++ b/src/ints/mouse.cpp @@ -33,6 +33,8 @@ #include "bios.h" #include "dos_inc.h" +#include "../save_state.h" + static Bitu call_int33,call_int74,int74_ret_callback,call_mouse_bd; static Bit16u ps2cbseg,ps2cbofs; static bool useps2callback,ps2callbackinit; @@ -1143,3 +1145,118 @@ void MOUSE_Init(Section* /*sec*/) { Mouse_Reset(); Mouse_SetSensitivity(50,50,50); } + +//save state support +void *MOUSE_Limit_Events_PIC_Event = (void*)MOUSE_Limit_Events; + + +namespace +{ +class SerializeMouse : public SerializeGlobalPOD +{ +public: + SerializeMouse() : SerializeGlobalPOD("Mouse") + {} + +private: + virtual void getBytes(std::ostream& stream) + { + Bit8u screenMask_idx, cursorMask_idx; + + + if( mouse.screenMask == defaultScreenMask ) screenMask_idx = 0x00; + else if( mouse.screenMask == userdefScreenMask ) screenMask_idx = 0x01; + + if( mouse.cursorMask == defaultCursorMask ) cursorMask_idx = 0x00; + else if( mouse.cursorMask == userdefCursorMask ) cursorMask_idx = 0x01; + + //******************************************* + //******************************************* + //******************************************* + + SerializeGlobalPOD::getBytes(stream); + + + // - pure data + WRITE_POD( &ps2cbseg, ps2cbseg ); + WRITE_POD( &ps2cbofs, ps2cbofs ); + WRITE_POD( &useps2callback, useps2callback ); + WRITE_POD( &ps2callbackinit, ps2callbackinit ); + + WRITE_POD( &userdefScreenMask, userdefScreenMask ); + WRITE_POD( &userdefCursorMask, userdefCursorMask ); + + + // - near-pure data + WRITE_POD( &mouse, mouse ); + + + // - pure data + WRITE_POD( &gfxReg3CE, gfxReg3CE ); + WRITE_POD( &index3C4, index3C4 ); + WRITE_POD( &gfxReg3C5, gfxReg3C5 ); + + //******************************************* + //******************************************* + //******************************************* + + // - reloc ptr + WRITE_POD( &screenMask_idx, screenMask_idx ); + WRITE_POD( &cursorMask_idx, cursorMask_idx ); + } + + virtual void setBytes(std::istream& stream) + { + Bit8u screenMask_idx, cursorMask_idx; + + //******************************************* + //******************************************* + //******************************************* + + SerializeGlobalPOD::setBytes(stream); + + + // - pure data + READ_POD( &ps2cbseg, ps2cbseg ); + READ_POD( &ps2cbofs, ps2cbofs ); + READ_POD( &useps2callback, useps2callback ); + READ_POD( &ps2callbackinit, ps2callbackinit ); + + READ_POD( &userdefScreenMask, userdefScreenMask ); + READ_POD( &userdefCursorMask, userdefCursorMask ); + + + // - near-pure data + READ_POD( &mouse, mouse ); + + + // - pure data + READ_POD( &gfxReg3CE, gfxReg3CE ); + READ_POD( &index3C4, index3C4 ); + READ_POD( &gfxReg3C5, gfxReg3C5 ); + + //******************************************* + //******************************************* + //******************************************* + + // - reloc ptr + READ_POD( &screenMask_idx, screenMask_idx ); + READ_POD( &cursorMask_idx, cursorMask_idx ); + + + if( screenMask_idx == 0x00 ) mouse.screenMask = defaultScreenMask; + else if( screenMask_idx == 0x01 ) mouse.screenMask = userdefScreenMask; + + if( cursorMask_idx == 0x00 ) mouse.cursorMask = defaultCursorMask; + else if( cursorMask_idx == 0x01 ) mouse.cursorMask = userdefCursorMask; + + //******************************************* + //******************************************* + //******************************************* + + // reset + oldmouseX = static_cast(mouse.x); + oldmouseY = static_cast(mouse.y); + } +} dummy; +} \ No newline at end of file diff --git a/src/ints/xms.cpp b/src/ints/xms.cpp index 60b84a1..ad2cc1d 100644 --- a/src/ints/xms.cpp +++ b/src/ints/xms.cpp @@ -30,6 +30,8 @@ #include "xms.h" #include "bios.h" +#include "../save_state.h" + #define XMS_HANDLES 50 /* 50 XMS Memory Blocks */ #define XMS_VERSION 0x0300 /* version 3.00 */ #define XMS_DRIVER_VERSION 0x0301 /* my driver version 3.01 */ @@ -483,3 +485,16 @@ void XMS_Init(Section* sec) { test = new XMS(sec); sec->AddDestroyFunction(&XMS_ShutDown,true); } + +//save state support + namespace +{ +class SerializeXMS : public SerializeGlobalPOD +{ +public: + SerializeXMS() : SerializeGlobalPOD("XMS") + { + registerPOD(xms_handles); + } +} dummy; +} \ No newline at end of file diff --git a/src/ioapi.c b/src/ioapi.c new file mode 100644 index 0000000..34f764a --- /dev/null +++ b/src/ioapi.c @@ -0,0 +1,235 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + 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 + +*/ + +#if (defined(_WIN32)) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == ((uLong)-1)) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (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; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* 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 = fopen64((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = ftello64((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (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; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T 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(fseeko64((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (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; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_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/src/miniunz.c b/src/miniunz.c new file mode 100644 index 0000000..283edab --- /dev/null +++ b/src/miniunz.c @@ -0,0 +1,514 @@ +/* + miniunz.c + Version 1.1, February 14h, 2010 + sample 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 of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) +*/ + +#ifndef _WIN32 + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +#elif __APPLE__ +#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 = CreateFileA(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_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"); +} +*/ +void Display64BitsSize(ZPOS64_T n, int size_char) +{ + /* to avoid compatibility problem , we do here the conversion */ + char number[21]; + int offset=19; + int pos_string = 19; + number[20]=0; + for (;;) { + number[offset]=(char)((n%10)+'0'); + if (number[offset] != '0') + pos_string=offset; + n/=10; + if (offset==0) + break; + offset--; + } + { + int size_display_string = 19-pos_string; + while (size_char > size_display_string) + { + size_char--; + //printf(" "); + } + } + + //printf("%s",&number[pos_string]); +} + +int do_extract_currentfile(uf,popt_extract_without_path,popt_overwrite,password) + unzFile uf; + const int* popt_extract_without_path; + int* popt_overwrite; + const char* password; +{ + char filename_inzip[256]; + char* filename_withoutpath; + char* p; + int err=UNZ_OK; + FILE *fout=NULL; + void* buf; + uInt size_buf; + + unz_file_info64 file_info; + uLong ratio=0; + err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0); + + if (err!=UNZ_OK) + { + //printf("error %d with zipfile in unzGetCurrentFileInfo\n",err); + return err; + } + + size_buf = WRITEBUFFERSIZE; + buf = (void*)malloc(size_buf); + if (buf==NULL) + { + //printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + + p = filename_withoutpath = filename_inzip; + while ((*p) != '\0') + { + if (((*p)=='/') || ((*p)=='\\')) + filename_withoutpath = p+1; + p++; + } + + if ((*filename_withoutpath)=='\0') + { + if ((*popt_extract_without_path)==0) + { + //printf("creating directory: %s\n",filename_inzip); + mymkdir(filename_inzip); + } + } + else + { + const char* write_filename; + int skip=0; + + if ((*popt_extract_without_path)==0) + write_filename = filename_inzip; + else + write_filename = filename_withoutpath; + + err = unzOpenCurrentFilePassword(uf,password); + if (err!=UNZ_OK) + { + //printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err); + } + + if (((*popt_overwrite)==0) && (err==UNZ_OK)) + { + char rep=0; + FILE* ftestexist; + ftestexist = fopen64(write_filename,"rb"); + if (ftestexist!=NULL) + { + fclose(ftestexist); + do + { + char answer[128]; + int ret; + + //printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename); + ret = scanf("%1s",answer); + if (ret != 1) + { + exit(EXIT_FAILURE); + } + rep = answer[0] ; + if ((rep>='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + } + + if (rep == 'N') + skip = 1; + + if (rep == 'A') + *popt_overwrite=1; + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=fopen64(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=fopen64(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_info64 gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) { + //printf("error %d with zipfile in unzGetGlobalInfo \n",err); + } + + for (i=0;i + #define GetCurrentDir _getcwd +#else + #include + #define GetCurrentDir getcwd + #endif + +int my_miniunz( + char ** savefile, + const char * savefile2, + const char * savedir) { + const char *zipfilename=NULL; + const char *filename_to_extract=NULL; + const char *password=NULL; + char filename_try[MAXFILENAME+16] = ""; + int i; + int ret_value=0; + int opt_do_extract=1; + int opt_do_extract_withoutpath=0; + int opt_overwrite=0; + int opt_extractdir=0; + const char *dirname=NULL; + unzFile uf=NULL; + + opt_do_extract = opt_do_extract_withoutpath = 1; + opt_overwrite=1; + opt_extractdir=1; + dirname=savedir; + zipfilename = savefile; + filename_to_extract = savefile2; + + if (zipfilename!=NULL) + { + +# ifdef USEWIN32IOAPI + zlib_filefunc64_def ffunc; +# endif + + strncpy(filename_try, zipfilename,MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, of the string is too long. */ + filename_try[ MAXFILENAME ] = '\0'; + +# ifdef USEWIN32IOAPI + fill_win32_filefunc64A(&ffunc); + uf = unzOpen2_64(zipfilename,&ffunc); +# else + uf = unzOpen64(zipfilename); +# endif + } + + if (uf==NULL) + { + //printf("Cannot open %s\n",zipfilename,zipfilename); + return 1; + } + //printf("%s opened\n",filename_try); + + if (opt_do_extract==1) + { + char cCurrentPath[FILENAME_MAX]; + GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)); +#ifdef _WIN32 + _chdir(dirname); +#else + chdir(dirname); +#endif + ret_value = do_extract_onefile(uf, filename_to_extract, opt_do_extract_withoutpath, opt_overwrite, password); + chdir(cCurrentPath); + } + + unzClose(uf); + + return ret_value; +} diff --git a/src/minizip.c b/src/minizip.c new file mode 100644 index 0000000..b2716d3 --- /dev/null +++ b/src/minizip.c @@ -0,0 +1,377 @@ +/* + minizip.c + Version 1.1, February 14h, 2010 + sample 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 of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) +*/ + +#ifndef _WIN32 + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +# include +# include +#elif __APPLE__ +#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 = fopen64(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +/* 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 = fopen64(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 isLargeFile(const char* filename) +{ + int largeFile = 0; + ZPOS64_T pos = 0; + FILE* pFile = fopen64(filename, "rb"); + + if(pFile != NULL) + { + int n = fseeko64(pFile, 0, SEEK_END); + + pos = ftello64(pFile); + + //printf("File : %s is %lld bytes\n", filename, pos); + + if(pos >= 0xffffffff) + largeFile = 1; + + fclose(pFile); + } + + return largeFile; +} + +int my_minizip( + char ** savefile, + char ** savefile2) { + 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; + + opt_overwrite = 2; + opt_compress_level = 9; + opt_exclude_path = 1; + + size_buf = WRITEBUFFERSIZE; + buf = (void*)malloc(size_buf); + if (buf==NULL) + { + //printf("Error allocating memory\n"); + return ZIP_INTERNALERROR; + } + + { + zipFile zf; + int errclose; +# ifdef USEWIN32IOAPI + zlib_filefunc64_def ffunc; + fill_win32_filefunc64A(&ffunc); + zf = zipOpen2_64(savefile,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); +# else + zf = zipOpen64(savefile,(opt_overwrite==2) ? 2 : 0); +# endif + + if (zf == NULL) + { + //printf("error opening %s\n",savefile); + err= ZIP_ERRNO; + } + else + //printf("creating %s\n",savefile); + + { + FILE * fin; + int size_read; + const char* filenameinzip = savefile2; + const char *savefilenameinzip; + zip_fileinfo zi; + unsigned long crcFile=0; + int zip64 = 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); + + if ((password != NULL) && (err==ZIP_OK)) + err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); + + zip64 = isLargeFile(filenameinzip); + + /* 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_64(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, zip64); + + if (err != ZIP_OK) { + //printf("error in opening %s in zipfile\n",filenameinzip); + } + else + { + fin = fopen64(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",savefile); + } + } + + free(buf); + return 0; +} diff --git a/src/mztools.c b/src/mztools.c new file mode 100644 index 0000000..5fecc4e --- /dev/null +++ b/src/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/src/save_state.cpp b/src/save_state.cpp new file mode 100644 index 0000000..1489a5d --- /dev/null +++ b/src/save_state.cpp @@ -0,0 +1,394 @@ +#include "save_state.h" +#include "zlib.h" +#ifdef WIN32 +#include "direct.h" +#endif +#include "cross.h" +#include "logging.h" +#if defined (__APPLE__) +#else +#include +#endif +#include +#include + +#include +#include +#include +#include +#include +#include "SDL.h" + +#ifndef WIN32 +char* itoa(int value, char* str, int radix) { + /** + * C++ version 0.4 char* style "itoa": + * Written by Lukás Chmela + * Released under GPLv3. + */ + // check that the radix if valid + if (radix < 2 || radix > 36) { *str = '\0'; return str; } + + char* ptr = str, *ptr1 = str, tmp_char; + int tmp_value; + + do { + tmp_value = value; + value /= radix; + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * radix)]; + } while ( value ); + + // Apply negative sign + if (tmp_value < 0) *ptr++ = '-'; + *ptr-- = '\0'; + while(ptr1 < ptr) { + tmp_char = *ptr; + *ptr--= *ptr1; + *ptr1++ = tmp_char; + } + return str; +} +#endif + +SaveState& SaveState::instance() { + static SaveState singleton; + return singleton; +} + +void SaveState::registerComponent(const std::string& uniqueName, Component& comp) { + components.insert(std::make_pair(uniqueName, CompData(comp))); +} + +namespace Util { +std::string compress(const std::string& input) { //throw (SaveState::Error) + if (input.empty()) + return input; + + const uLong bufferSize = ::compressBound(input.size()); + + std::string output; + output.resize(bufferSize); + + uLongf actualSize = bufferSize; + if (::compress2(reinterpret_cast(&output[0]), &actualSize, + reinterpret_cast(input.c_str()), input.size(), Z_BEST_SPEED) != Z_OK) + throw SaveState::Error("Compression failed!"); + + output.resize(actualSize); + + //save size of uncompressed data + const size_t uncompressedSize = input.size(); //save size of uncompressed data + output.resize(output.size() + sizeof(uncompressedSize)); //won't trigger a reallocation + ::memcpy(&output[0] + output.size() - sizeof(uncompressedSize), &uncompressedSize, sizeof(uncompressedSize)); + + return std::string(&output[0], output.size()); //strip reserved space +} + +std::string decompress(const std::string& input) { //throw (SaveState::Error) + if (input.empty()) + return input; + + //retrieve size of uncompressed data + size_t uncompressedSize = 0; + ::memcpy(&uncompressedSize, &input[0] + input.size() - sizeof(uncompressedSize), sizeof(uncompressedSize)); + + std::string output; + output.resize(uncompressedSize); + + uLongf actualSize = uncompressedSize; + if (::uncompress(reinterpret_cast(&output[0]), &actualSize, + reinterpret_cast(input.c_str()), input.size() - sizeof(uncompressedSize)) != Z_OK) + throw SaveState::Error("Decompression failed!"); + + output.resize(actualSize); //should be superfluous! + + return output; +} +} + +inline void SaveState::RawBytes::set(const std::string& stream) { + bytes = stream; + isCompressed = false; + dataExists = true; +} + +inline std::string SaveState::RawBytes::get() const { //throw (Error){ + if (isCompressed) + (Util::decompress(bytes)).swap(bytes); + isCompressed = false; + return bytes; +} + +inline void SaveState::RawBytes::compress() const { //throw (Error) + if (!isCompressed) + (Util::compress(bytes)).swap(bytes); + isCompressed = true; +} + +inline bool SaveState::RawBytes::dataAvailable() const { + return dataExists; +} + +extern "C" { + int my_minizip(char ** savefile,char ** savefile2); + int my_miniunz(char ** savefile, const char * savefile2, const char * savedir); +} + +void SaveState::save(size_t slot) { //throw (Error) + if (slot >= SLOT_COUNT) return; + SDL_PauseAudio(0); + bool save_err=false; + extern unsigned int MEM_TotalPages(void); + if((MEM_TotalPages()*4096/1024/1024)>200) { + LOG_MSG("Stopped. 200 MB is the maximum memory size for saving/loading states."); + return; + } + bool create_title=false; + bool create_memorysize=false; + extern const char* RunningProgram; + std::string path; + bool Get_Custom_SaveDir(std::string& savedir); + if(Get_Custom_SaveDir(path)) { + path+=CROSS_FILESPLIT; + } else { + extern std::string capturedir; + const size_t last_slash_idx = capturedir.find_last_of("\\/"); + if (std::string::npos != last_slash_idx) { + path = capturedir.substr(0, last_slash_idx); + } else { + path = "."; + } + path+=CROSS_FILESPLIT; + path+="save"; + Cross::CreateDir(path); + path+=CROSS_FILESPLIT; + } + + std::string temp, save2; + std::stringstream slotname; + slotname << slot+1; + temp=path; + std::string save=temp+slotname.str()+".sav"; + remove(save.c_str()); + std::ofstream file (save.c_str()); + file << ""; + file.close(); + try { + for (CompEntry::iterator i = components.begin(); i != components.end(); ++i) { + std::ostringstream ss; + i->second.comp.getBytes(ss); + i->second.rawBytes[slot].set(ss.str()); + + //LOG_MSG("Component is %s",i->first.c_str()); + + if(!create_title) { + std::string tempname = temp+"Program_Name"; + std::ofstream programname (tempname.c_str(), std::ofstream::binary); + programname << RunningProgram; + create_title=true; + programname.close(); + } + + if(!create_memorysize) { + std::string tempname = temp+"Memory_Size"; + std::ofstream memorysize (tempname.c_str(), std::ofstream::binary); + memorysize << MEM_TotalPages(); + create_memorysize=true; + memorysize.close(); + } + std::string realtemp; + realtemp = temp + i->first; + std::ofstream outfile (realtemp.c_str(), std::ofstream::binary); + outfile << (Util::compress(ss.str())); + //compress all other saved states except position "slot" + //const std::vector& rb = i->second.rawBytes; + //std::for_each(rb.begin(), rb.begin() + slot, std::mem_fun_ref(&RawBytes::compress)); + //std::for_each(rb.begin() + slot + 1, rb.end(), std::mem_fun_ref(&RawBytes::compress)); + outfile.close(); + ss.clear(); + if(outfile.fail()) { + LOG_MSG("Save failed! - %s", realtemp.c_str()); + save_err=true; + remove(save.c_str()); + goto delete_all; + } + } + } + catch (const std::bad_alloc&) { + LOG_MSG("Save failed! Out of Memory!"); + save_err=true; + remove(save.c_str()); + goto delete_all; + } + + for (CompEntry::iterator i = components.begin(); i != components.end(); ++i) { + save2=temp+i->first; + my_minizip((char **)save.c_str(), (char **)save2.c_str()); + } + save2=temp+"Program_Name"; + my_minizip((char **)save.c_str(), (char **)save2.c_str()); + save2=temp+"Memory_Size"; + my_minizip((char **)save.c_str(), (char **)save2.c_str()); + +delete_all: + for (CompEntry::iterator i = components.begin(); i != components.end(); ++i) { + save2=temp+i->first; + remove(save2.c_str()); + } + save2=temp+"Program_Name"; + remove(save2.c_str()); + save2=temp+"Memory_Size"; + remove(save2.c_str()); + if (!save_err) LOG_MSG("Saved. (Slot %d)",slot+1); +} + +void SaveState::load(size_t slot) const { //throw (Error) +// if (isEmpty(slot)) return; + extern unsigned int MEM_TotalPages(void); + bool load_err=false; + if((MEM_TotalPages()*4096/1024/1024)>200) { + LOG_MSG("Stopped. 200 MB is the maximum memory size for saving/loading states."); + return; + } + SDL_PauseAudio(0); + extern const char* RunningProgram; + bool read_title=false; + bool read_memorysize=false; + std::string path; + bool Get_Custom_SaveDir(std::string& savedir); + if(Get_Custom_SaveDir(path)) { + path+=CROSS_FILESPLIT; + } else { + extern std::string capturedir; + const size_t last_slash_idx = capturedir.find_last_of("\\/"); + if (std::string::npos != last_slash_idx) { + path = capturedir.substr(0, last_slash_idx); + } else { + path = "."; + } + path += CROSS_FILESPLIT; + path +="save"; + path += CROSS_FILESPLIT; + } + std::string temp; + temp = path; + std::stringstream slotname; + slotname << slot+1; + std::string save=temp+slotname.str()+".sav"; + std::ifstream check_slot; + check_slot.open(save.c_str(), std::ifstream::in); + if(check_slot.fail()) { + LOG_MSG("No saved slot - %d (%s)",slot+1,save.c_str()); + load_err=true; + return; + } + + for (CompEntry::const_iterator i = components.begin(); i != components.end(); ++i) { + std::filebuf * fb; + std::ifstream ss; + std::ifstream check_file; + fb = ss.rdbuf(); + + //LOG_MSG("Component is %s",i->first.c_str()); + + my_miniunz((char **)save.c_str(),i->first.c_str(),temp.c_str()); + + if(!read_title) { + my_miniunz((char **)save.c_str(),"Program_Name",temp.c_str()); + std::ifstream check_title; + int length = 8; + + std::string tempname = temp+"Program_Name"; + check_title.open(tempname.c_str(), std::ifstream::in); + if(check_title.fail()) { + LOG_MSG("Save state corrupted! Program in inconsistent state! - Program_Name"); + load_err=true; + goto delete_all; + } + check_title.seekg (0, std::ios::end); + length = check_title.tellg(); + check_title.seekg (0, std::ios::beg); + + char * const buffer = (char*)alloca( (length+1) * sizeof(char)); // char buffer[length]; + check_title.read (buffer, length); + check_title.close(); + if(strncmp(buffer,RunningProgram,length)) { + buffer[length]='\0'; + LOG_MSG("Aborted. Check your program name: %s",buffer); + load_err=true; + goto delete_all; + } + read_title=true; + } + + if(!read_memorysize) { + my_miniunz((char **)save.c_str(),"Memory_Size",temp.c_str()); + std::fstream check_memorysize; + int length = 8; + + std::string tempname = temp+"Memory_Size"; + check_memorysize.open(tempname.c_str(), std::ifstream::in); + if(check_memorysize.fail()) { + LOG_MSG("Save state corrupted! Program in inconsistent state! - Memory_Size"); + load_err=true; + goto delete_all; + } + check_memorysize.seekg (0, std::ios::end); + length = check_memorysize.tellg(); + check_memorysize.seekg (0, std::ios::beg); + + char * const buffer = (char*)alloca( (length+1) * sizeof(char)); // char buffer[length]; + check_memorysize.read (buffer, length); + check_memorysize.close(); + char str[10]; + itoa(MEM_TotalPages(), str, 10); + if(strncmp(buffer,str,length)) { + buffer[length]='\0'; + LOG_MSG("WARNING: Check your memory size."); + } + read_memorysize=true; + } + std::string realtemp; + realtemp = temp + i->first; + check_file.open(realtemp.c_str(), std::ifstream::in); + check_file.close(); + if(check_file.fail()) { + LOG_MSG("Save state corrupted! Program in inconsistent state! - %s",i->first.c_str()); + load_err=true; + goto delete_all; + } + + fb->open(realtemp.c_str(),std::ios::in | std::ios::binary); + std::string str((std::istreambuf_iterator(ss)), std::istreambuf_iterator()); + std::stringstream mystream; + mystream << (Util::decompress(str)); + i->second.comp.setBytes(mystream); + if (mystream.rdbuf()->in_avail() != 0 || mystream.eof()) { //basic consistency check + LOG_MSG("Save state corrupted! Program in inconsistent state! - %s",i->first.c_str()); + load_err=true; + goto delete_all; + } + //compress all other saved states except position "slot" + //const std::vector& rb = i->second.rawBytes; + //std::for_each(rb.begin(), rb.begin() + slot, std::mem_fun_ref(&RawBytes::compress)); + //std::for_each(rb.begin() + slot + 1, rb.end(), std::mem_fun_ref(&RawBytes::compress)); + fb->close(); + mystream.clear(); + } +delete_all: + std::string save2; + for (CompEntry::const_iterator i = components.begin(); i != components.end(); ++i) { + save2=temp+i->first; + remove(save2.c_str()); + } + save2=temp+"Program_Name"; + remove(save2.c_str()); + save2=temp+"Memory_Size"; + remove(save2.c_str()); + if (!load_err) LOG_MSG("Loaded. (Slot %d)",slot+1); +} + +bool SaveState::isEmpty(size_t slot) const { + if (slot >= SLOT_COUNT) return true; + return (components.empty() || !components.begin()->second.rawBytes[slot].dataAvailable()); +} diff --git a/src/save_state.h b/src/save_state.h new file mode 100644 index 0000000..9c7fb51 --- /dev/null +++ b/src/save_state.h @@ -0,0 +1,177 @@ +#ifndef SAVE_STATE_H_INCLUDED +#define SAVE_STATE_H_INCLUDED + +#include +#include +#include +#include +#include + + +#define WRITE_POD(x,y) \ + stream.write(reinterpret_cast( (x) ), sizeof( (y) ) ); + +#define WRITE_POD_SIZE(x,y) \ + stream.write(reinterpret_cast( (x) ), (y) ); + +#define READ_POD(x,y) \ + stream.read(reinterpret_cast( (x) ), sizeof( (y) ) ); + +#define READ_POD_SIZE(x,y) \ + stream.read(reinterpret_cast( (x) ), (y) ); + + + +class SaveState +{ +public: + static SaveState& instance(); + + typedef std::string Error; + static const size_t SLOT_COUNT = 10; //slot: [0,...,SLOT_COUNT - 1] + + void save (size_t slot); //throw (Error) + void load (size_t slot) const; //throw (Error) + bool isEmpty(size_t slot) const; + + //initialization: register relevant components on program startup + struct Component + { + virtual void getBytes(std::ostream& stream) = 0; + virtual void setBytes(std::istream& stream) = 0; + }; + + void registerComponent(const std::string& uniqueName, Component& comp); //comp must have global lifetime! + +private: + SaveState() {} + SaveState(const SaveState&); + SaveState& operator=(const SaveState&); + + class RawBytes + { + public: + RawBytes() : dataExists(false), isCompressed(false) {} + void set(const std::string& stream); + std::string get() const; //throw (Error) + void compress() const; //throw (Error) + bool dataAvailable() const; + private: + bool dataExists; //determine whether set method (even with empty string) was called + mutable bool isCompressed; //design for logical not binary const + mutable std::string bytes; // + }; + + struct CompData + { + CompData(Component& cmp) : comp(cmp), rawBytes(SLOT_COUNT) {} + Component& comp; + std::vector rawBytes; + }; + + typedef std::map CompEntry; + CompEntry components; +}; + + +//some helper functions +template +void writePOD(std::ostream& stream, const T& data); + +template +void readPOD(std::istream& stream, T& data); + +void writeString(std::ostream& stream, const std::string& data); +void readString(std::istream& stream, std::string& data); + + +//Implementation of SaveState::Component for saving POD types only +class SerializeGlobalPOD : public SaveState::Component +{ +public: + SerializeGlobalPOD(const std::string& compName) + { + SaveState::instance().registerComponent(compName, *this); + } + + template + void registerPOD(T& pod) //register POD for serializatioin + { + podRef.push_back(POD(pod)); + } + +protected: + virtual void getBytes(std::ostream& stream) + { + std::for_each(podRef.begin(), podRef.end(), std::bind1st(WriteGlobalPOD(), &stream)); + } + + virtual void setBytes(std::istream& stream) + { + std::for_each(podRef.begin(), podRef.end(), std::bind1st(ReadGlobalPOD(), &stream)); + } + +private: + struct POD + { + template + POD(T& pod) : address(&pod), size(sizeof(T)) {} + void* address; + size_t size; + }; + + struct WriteGlobalPOD : public std::binary_function + { + void operator()(std::ostream* stream, const POD& data) const + { + stream->write(static_cast(data.address), data.size); + } + }; + + struct ReadGlobalPOD : public std::binary_function + { + void operator()(std::istream* stream, const POD& data) const + { + stream->read(static_cast(data.address), data.size); + } + }; + + std::vector podRef; +}; + +//---------------- inline implementation ------------------------- +template +inline +void writePOD(std::ostream& stream, const T& data) +{ + stream.write(reinterpret_cast(&data), sizeof(T)); +} + + +template +inline +void readPOD(std::istream& stream, T& data) +{ + stream.read(reinterpret_cast(&data), sizeof(T)); +} + + +inline +void writeString(std::ostream& stream, const std::string& data) +{ + const size_t stringSize = data.size(); + writePOD(stream, stringSize); + stream.write(data.c_str(), stringSize * sizeof(std::string::value_type)); +} + + +inline +void readString(std::istream& stream, std::string& data) +{ + size_t stringSize = 0; + readPOD(stream, stringSize); + data.resize(stringSize); + stream.read(&data[0], stringSize * sizeof(std::string::value_type)); +} + +#endif //SAVE_STATE_H_INCLUDED diff --git a/src/unzip.c b/src/unzip.c new file mode 100644 index 0000000..c4585c4 --- /dev/null +++ b/src/unzip.c @@ -0,0 +1,2125 @@ +/* unzip.c -- IO for uncompress .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 of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#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_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_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 + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz64_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 unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*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 unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (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 (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 ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*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) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*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; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*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) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*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))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + 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. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong 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*/ + ZPOS64_T 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; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&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 (unz64local_getLong64(&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 (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_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 (unz64local_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 (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + 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 (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(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 unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(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 unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(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 (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T 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 (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == (unsigned long)-1) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + 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 (ZREAD64(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 unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if (err==UNZ_OK) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_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 (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_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 = unz64local_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 (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_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 = unzGetCurrentFileInfo64(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 +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_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 unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_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 = unz64local_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; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// 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 unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * 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 (ZSEEK64(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 (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_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 (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_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 (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_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 (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_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 (unz64local_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 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T 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=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_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->total_out_64=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 = 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 (ZSEEK64(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(ZREAD64(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 (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + 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 (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_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 (ZSEEK64(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 (ZREAD64(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->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + 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 = (char*)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 = (char*)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 = (const Bytef *)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->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + 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 = (Bytef*)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 = (Bytef*)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 + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T 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->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + 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 (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_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; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_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 (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_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 (ZSEEK64(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 (ZREAD64(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 (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_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 (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(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 ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_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 uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_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; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} diff --git a/src/zip.c b/src/zip.c new file mode 100644 index 0000000..d45bf69 --- /dev/null +++ b/src/zip.c @@ -0,0 +1,2004 @@ +/* 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 + +*/ + + +#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 (64*1024) //(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.... */ + + +// 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 +#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 ZIP64ENDHEADERMAGIC (0x6064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) + +#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 */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T 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_centralExtra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ + 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; + int zip64; /* Add ZIP64 extened information in the extra field */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T totalCompressedData; + ZPOS64_T totalUncompressedData; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_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.*/ + curfile64_info ci; /* info on the file curretly writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writting_offset; + ZPOS64_T number_entry; + +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif + +} zip64_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(linkedlist_datablock_internal* ldi) +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(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 ,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) +{ + unsigned char buf[8]; + 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 (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T 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 zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + 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 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; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR64(*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 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; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *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; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *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; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<24; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<32; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<40; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<48; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<56; + + 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) +*/ +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; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*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) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*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; +} + +/* +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; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*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) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + { + // Signature "0x07064b50" Zip64 end of central directory locater + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + } + + if (uPosFound!=0) + break; + } + + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) + return 0; + + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto Zip64 end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' + return 0; + + return relativeOffset; +} + +int LoadCentralDirectoryRecord(zip64_internal* pziinit) +{ + int err=ZIP_OK; + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T central_pos; + uLong 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*/ + ZPOS64_T number_entry; + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong VersionMadeBy; + uLong VersionNeeded; + uLong size_comment; + + int hasZIP64Record = 0; + + // check first if we find a ZIP64 record + central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); + if(central_pos > 0) + { + hasZIP64Record = 1; + } + else if(central_pos == 0) + { + central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); + } + +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + + if(hasZIP64Record) + { + ZPOS64_T sizeEndOfCentralDirectory; + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version made by */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version needed to extract */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->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 (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + // TODO.. + // read the comment from the standard central header. + size_comment = 0; + } + else + { + // Read End of central Directory info + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry = uL; + + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry_CD = uL; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + size_central_dir = uL; + + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + offset_central_dir = uL; + + + /* zipfile global comment length */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + } + + if ((central_posz_filefunc, pziinit->filestream); + return ZIP_ERRNO; + } + + if (size_comment>0) + { + pziinit->globalcomment = (char*)ALLOC(size_comment+1); + if (pziinit->globalcomment) + { + size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); + pziinit->globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + pziinit->add_position_when_writting_offset = byte_before_the_zipfile; + + { + ZPOS64_T size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK64(pziinit->z_filefunc, pziinit->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)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); + + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + pziinit->begin_pos = byte_before_the_zipfile; + pziinit->number_entry = number_entry_CD; + + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + return err; +} + + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + + +/************************************************************/ +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; + int err=ZIP_OK; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, + 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) + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + + ziinit.begin_pos = ZTELL64(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 = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi==NULL) + { + ZCLOSE64(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) + { + // Read and Cache Central Directory Records + err = LoadCentralDirectoryRecord(&ziinit); + } + + 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 zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + + + +extern zipFile ZEXPORT zipOpen (const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) +{ + return zipOpen3(pathname,append,NULL,NULL); +} + +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) +{ + /* write the local header */ + int err; + uInt size_filename = (uInt)strlen(filename); + uInt size_extrafield = size_extrafield_local; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); + + if (err==ZIP_OK) + { + if(zi->ci.zip64) + 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 */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + { + if(zi->ci.zip64) + 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 */ + } + if (err==ZIP_OK) + { + if(zi->ci.zip64) + 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 */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if(zi->ci.zip64) + { + size_extrafield += 20; + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); + + if ((err==ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + + if ((err==ZIP_OK) && (zi->ci.zip64)) + { + // write the Zip64 extended info + short HeaderID = 1; + short DataSize = 16; + ZPOS64_T CompressedSize = 0; + ZPOS64_T UncompressedSize = 0; + + // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); + } + + 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, + 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, int zip64) +{ + zip64_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; + +#ifdef HAVE_BZIP2 + if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) + return ZIP_PARAMERROR; +#else + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; +#endif + + zi = (zip64_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 = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + 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 = ZTELL64(zi->z_filefunc,zi->filestream); + + 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); + + zi->ci.size_centralExtra = size_extrafield_global; + zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + if(zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); + 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;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; + + zi->ci.zip64 = zip64; + zi->ci.totalCompressedData = 0; + zi->ci.totalUncompressedData = 0; + zi->ci.pos_zip64extrainfo = 0; + + err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + 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; + +#ifdef HAVE_BZIP2 + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) +#else + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) +#endif + { + if(zi->ci.method == Z_DEFLATED) + { + 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 = Z_DEFLATED; + } + else if(zi->ci.method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + // Init BZip stuff here + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); + if(err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + + } + +# 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 (ZWRITE64(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 zipOpenNewFileInZip4 (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) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (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_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(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, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(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_64 (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, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(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 zip64) +{ + return zipOpenNewFileInZip4_64 (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, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64 (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 zip64) +{ + return zipOpenNewFileInZip4_64 (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, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip (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_64 (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, 0); +} + +local int zip64FlushWriteBuffer(zip64_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 (ZWRITE64(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.totalCompressedData += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED) + { + zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.totalUncompressedData += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + + + if(err != BZ_RUN_OK) + break; + + if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; +// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; + } + } + + if(err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(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); + if(uTotalOutBefore > zi->ci.stream.total_out) + { + int bBreak = 0; + bBreak++; + } + + 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; i < copy_this; i++) + *(((char*)zi->ci.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; + } + } + }// while(...) + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + short datasize = 0; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_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 (zip64FlushWriteBuffer(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) ; + } + } + else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err==BZ_FINISH_OK) + { + uLong uTotalOutBefore; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.bstream.total_out_lo32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if(err == BZ_STREAM_END) + err = Z_STREAM_END; + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); + } + + if(err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + { + if (zip64FlushWriteBuffer(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; + } +#ifdef HAVE_BZIP2 + else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err==ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.totalUncompressedData; + } + compressed_size = zi->ci.totalCompressedData; + +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + // update Current Item crc and sizes, + if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /*version Made by*/ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); + /*version needed*/ + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); + + } + + zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + + + if(compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ + + /// set internal file attributes field + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + + if(uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ + + // 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 + if(zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + if(datasize > 0) + { + char* p = NULL; + + if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) + { + // we can not write more data to the buffer that we have room for. + return ZIP_BADZIPFILE; + } + + p = zi->ci.central_header + zi->ci.size_centralheader; + + // Add Extra Information Header for 'ZIP64 information' + zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); // DataSize + p += 2; + + if(uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + + if(compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + + if(zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 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 ) + zi->ci.size_centralExtraFree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + + // Update the extra info size field + zi->ci.size_centralExtra += datasize + 4; + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); + } + + 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) + { + // Update the LocalFileHeader with the new values. + + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if(uncompressed_size >= 0xffffffff) + { + if(zi->ci.pos_zip64extrainfo > 0) + { + // 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) + err = ZIP_ERRNO; + + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + } + else + { + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + if (ZSEEK64(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 (zipFile file) +{ + return zipCloseFileInZipRaw (file,0,0); +} + +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) +{ + int err = ZIP_OK; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); + + /*num disks*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + /*relative offset*/ + if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); + + /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); + + return err; +} + +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + uLong Zip64DataSize = 44; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? + + if (err==ZIP_OK) /* version made by */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* version needed */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); + } + return err; +} +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + /*signature*/ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_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 = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + { + { + if(zi->number_entry >= 0xFFFF) + 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)zi->number_entry,2); + } + } + + if (err==ZIP_OK) /* total number of entries in the central dir */ + { + if(zi->number_entry >= 0xFFFF) + 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)zi->number_entry,2); + } + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_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 */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); + } + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + } + + return err; +} + +int Write_GlobalComment(zip64_internal* zi, const char* global_comment) +{ + int err = ZIP_OK; + uInt size_global_comment = 0; + + if(global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + return err; +} + +extern int ZEXPORT zipClose (zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + + centraldir_pos_inzip = ZTELL64(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 (ZWRITE64(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)); + + pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); + Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); + } + + if (err==ZIP_OK) + err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + if(err == ZIP_OK) + err = Write_GlobalComment(zi, global_comment); + + if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) +{ + char* p = pData; + int size = 0; + char* pNewHeader; + char* pTmp; + short header; + short dataSize; + + int retVal = ZIP_OK; + + if(pData == NULL || *dataLen < 4) + return ZIP_PARAMERROR; + + pNewHeader = (char*)ALLOC(*dataLen); + pTmp = pNewHeader; + + while(p < (pData + *dataLen)) + { + header = *(short*)p; + dataSize = *(((short*)p)+1); + + if( header == sHeader ) // Header found. + { + p += dataSize + 4; // skip it. do not copy to temp buffer + } + else + { + // Extra Info block should not be removed, So copy it to the temp buffer. + memcpy(pTmp, p, dataSize + 4); + p += dataSize + 4; + size += dataSize + 4; + } + + } + + if(size < *dataLen) + { + // clean old extra info block. + memset(pData,0, *dataLen); + + // copy the new extra info block over the old + if(size > 0) + memcpy(pData, pNewHeader, size); + + // set the new extra info size + *dataLen = size; + + retVal = ZIP_OK; + } + else + retVal = ZIP_ERRNO; + + TRYFREE(pNewHeader); + + return retVal; +}