diff --git a/fex/7z_C/7z.h b/fex/7z_C/7z.h index b7edd3ba..01c4cac6 100644 --- a/fex/7z_C/7z.h +++ b/fex/7z_C/7z.h @@ -1,203 +1,203 @@ -/* 7z.h -- 7z interface -2010-03-11 : Igor Pavlov : Public domain */ - -#ifndef __7Z_H -#define __7Z_H - -#include "7zBuf.h" - -EXTERN_C_BEGIN - -#define k7zStartHeaderSize 0x20 -#define k7zSignatureSize 6 -extern Byte k7zSignature[k7zSignatureSize]; -#define k7zMajorVersion 0 - -enum EIdEnum -{ - k7zIdEnd, - k7zIdHeader, - k7zIdArchiveProperties, - k7zIdAdditionalStreamsInfo, - k7zIdMainStreamsInfo, - k7zIdFilesInfo, - k7zIdPackInfo, - k7zIdUnpackInfo, - k7zIdSubStreamsInfo, - k7zIdSize, - k7zIdCRC, - k7zIdFolder, - k7zIdCodersUnpackSize, - k7zIdNumUnpackStream, - k7zIdEmptyStream, - k7zIdEmptyFile, - k7zIdAnti, - k7zIdName, - k7zIdCTime, - k7zIdATime, - k7zIdMTime, - k7zIdWinAttributes, - k7zIdComment, - k7zIdEncodedHeader, - k7zIdStartPos, - k7zIdDummy -}; - -typedef struct -{ - UInt32 NumInStreams; - UInt32 NumOutStreams; - UInt64 MethodID; - CBuf Props; -} CSzCoderInfo; - -void SzCoderInfo_Init(CSzCoderInfo *p); -void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc); - -typedef struct -{ - UInt32 InIndex; - UInt32 OutIndex; -} CSzBindPair; - -typedef struct -{ - CSzCoderInfo *Coders; - CSzBindPair *BindPairs; - UInt32 *PackStreams; - UInt64 *UnpackSizes; - UInt32 NumCoders; - UInt32 NumBindPairs; - UInt32 NumPackStreams; - int UnpackCRCDefined; - UInt32 UnpackCRC; - - UInt32 NumUnpackStreams; -} CSzFolder; - -void SzFolder_Init(CSzFolder *p); -UInt64 SzFolder_GetUnpackSize(CSzFolder *p); -int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex); -UInt32 SzFolder_GetNumOutStreams(CSzFolder *p); -UInt64 SzFolder_GetUnpackSize(CSzFolder *p); - -SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, - ILookInStream *stream, UInt64 startPos, - Byte *outBuffer, size_t outSize, ISzAlloc *allocMain); - -typedef struct -{ - UInt32 Low; - UInt32 High; -} CNtfsFileTime; - -typedef struct -{ - CNtfsFileTime MTime; - UInt64 Size; - UInt32 Crc; - UInt32 Attrib; - Byte HasStream; - Byte IsDir; - Byte IsAnti; - Byte CrcDefined; - Byte MTimeDefined; - Byte AttribDefined; -} CSzFileItem; - -void SzFile_Init(CSzFileItem *p); - -typedef struct -{ - UInt64 *PackSizes; - Byte *PackCRCsDefined; - UInt32 *PackCRCs; - CSzFolder *Folders; - CSzFileItem *Files; - UInt32 NumPackStreams; - UInt32 NumFolders; - UInt32 NumFiles; -} CSzAr; - -void SzAr_Init(CSzAr *p); -void SzAr_Free(CSzAr *p, ISzAlloc *alloc); - - -/* - SzExtract extracts file from archive - - *outBuffer must be 0 before first call for each new archive. - - Extracting cache: - If you need to decompress more than one file, you can send - these values from previous call: - *blockIndex, - *outBuffer, - *outBufferSize - You can consider "*outBuffer" as cache of solid block. If your archive is solid, - it will increase decompression speed. - - If you use external function, you can declare these 3 cache variables - (blockIndex, outBuffer, outBufferSize) as static in that external function. - - Free *outBuffer and set *outBuffer to 0, if you want to flush cache. -*/ - -typedef struct -{ - CSzAr db; - - UInt64 startPosAfterHeader; - UInt64 dataPos; - - UInt32 *FolderStartPackStreamIndex; - UInt64 *PackStreamStartPositions; - UInt32 *FolderStartFileIndex; - UInt32 *FileIndexToFolderIndexMap; - - size_t *FileNameOffsets; /* in 2-byte steps */ - CBuf FileNames; /* UTF-16-LE */ -} CSzArEx; - -void SzArEx_Init(CSzArEx *p); -void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); -UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); -int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); - -/* -if dest == NULL, the return value specifies the required size of the buffer, - in 16-bit characters, including the null-terminating character. -if dest != NULL, the return value specifies the number of 16-bit characters that - are written to the dest, including the null-terminating character. */ - -size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); - -SRes SzArEx_Extract( - const CSzArEx *db, - ILookInStream *inStream, - UInt32 fileIndex, /* index of file */ - UInt32 *blockIndex, /* index of solid block */ - Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ - size_t *outBufferSize, /* buffer size for output buffer */ - size_t *offset, /* offset of stream for required file in *outBuffer */ - size_t *outSizeProcessed, /* size of file in *outBuffer */ - ISzAlloc *allocMain, - ISzAlloc *allocTemp); - - -/* -SzArEx_Open Errors: -SZ_ERROR_NO_ARCHIVE -SZ_ERROR_ARCHIVE -SZ_ERROR_UNSUPPORTED -SZ_ERROR_MEM -SZ_ERROR_CRC -SZ_ERROR_INPUT_EOF -SZ_ERROR_FAIL -*/ - -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp); - -EXTERN_C_END - -#endif +/* 7z.h -- 7z interface +2010-03-11 : Igor Pavlov : Public domain */ + +#ifndef __7Z_H +#define __7Z_H + +#include "7zBuf.h" + +EXTERN_C_BEGIN + +#define k7zStartHeaderSize 0x20 +#define k7zSignatureSize 6 +extern Byte k7zSignature[k7zSignatureSize]; +#define k7zMajorVersion 0 + +enum EIdEnum +{ + k7zIdEnd, + k7zIdHeader, + k7zIdArchiveProperties, + k7zIdAdditionalStreamsInfo, + k7zIdMainStreamsInfo, + k7zIdFilesInfo, + k7zIdPackInfo, + k7zIdUnpackInfo, + k7zIdSubStreamsInfo, + k7zIdSize, + k7zIdCRC, + k7zIdFolder, + k7zIdCodersUnpackSize, + k7zIdNumUnpackStream, + k7zIdEmptyStream, + k7zIdEmptyFile, + k7zIdAnti, + k7zIdName, + k7zIdCTime, + k7zIdATime, + k7zIdMTime, + k7zIdWinAttributes, + k7zIdComment, + k7zIdEncodedHeader, + k7zIdStartPos, + k7zIdDummy +}; + +typedef struct +{ + UInt32 NumInStreams; + UInt32 NumOutStreams; + UInt64 MethodID; + CBuf Props; +} CSzCoderInfo; + +void SzCoderInfo_Init(CSzCoderInfo *p); +void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc); + +typedef struct +{ + UInt32 InIndex; + UInt32 OutIndex; +} CSzBindPair; + +typedef struct +{ + CSzCoderInfo *Coders; + CSzBindPair *BindPairs; + UInt32 *PackStreams; + UInt64 *UnpackSizes; + UInt32 NumCoders; + UInt32 NumBindPairs; + UInt32 NumPackStreams; + int UnpackCRCDefined; + UInt32 UnpackCRC; + + UInt32 NumUnpackStreams; +} CSzFolder; + +void SzFolder_Init(CSzFolder *p); +UInt64 SzFolder_GetUnpackSize(CSzFolder *p); +int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex); +UInt32 SzFolder_GetNumOutStreams(CSzFolder *p); +UInt64 SzFolder_GetUnpackSize(CSzFolder *p); + +SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, + ILookInStream *stream, UInt64 startPos, + Byte *outBuffer, size_t outSize, ISzAlloc *allocMain); + +typedef struct +{ + UInt32 Low; + UInt32 High; +} CNtfsFileTime; + +typedef struct +{ + CNtfsFileTime MTime; + UInt64 Size; + UInt32 Crc; + UInt32 Attrib; + Byte HasStream; + Byte IsDir; + Byte IsAnti; + Byte CrcDefined; + Byte MTimeDefined; + Byte AttribDefined; +} CSzFileItem; + +void SzFile_Init(CSzFileItem *p); + +typedef struct +{ + UInt64 *PackSizes; + Byte *PackCRCsDefined; + UInt32 *PackCRCs; + CSzFolder *Folders; + CSzFileItem *Files; + UInt32 NumPackStreams; + UInt32 NumFolders; + UInt32 NumFiles; +} CSzAr; + +void SzAr_Init(CSzAr *p); +void SzAr_Free(CSzAr *p, ISzAlloc *alloc); + + +/* + SzExtract extracts file from archive + + *outBuffer must be 0 before first call for each new archive. + + Extracting cache: + If you need to decompress more than one file, you can send + these values from previous call: + *blockIndex, + *outBuffer, + *outBufferSize + You can consider "*outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + If you use external function, you can declare these 3 cache variables + (blockIndex, outBuffer, outBufferSize) as static in that external function. + + Free *outBuffer and set *outBuffer to 0, if you want to flush cache. +*/ + +typedef struct +{ + CSzAr db; + + UInt64 startPosAfterHeader; + UInt64 dataPos; + + UInt32 *FolderStartPackStreamIndex; + UInt64 *PackStreamStartPositions; + UInt32 *FolderStartFileIndex; + UInt32 *FileIndexToFolderIndexMap; + + size_t *FileNameOffsets; /* in 2-byte steps */ + CBuf FileNames; /* UTF-16-LE */ +} CSzArEx; + +void SzArEx_Init(CSzArEx *p); +void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); +UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); +int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); + +/* +if dest == NULL, the return value specifies the required size of the buffer, + in 16-bit characters, including the null-terminating character. +if dest != NULL, the return value specifies the number of 16-bit characters that + are written to the dest, including the null-terminating character. */ + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); + +SRes SzArEx_Extract( + const CSzArEx *db, + ILookInStream *inStream, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAlloc *allocMain, + ISzAlloc *allocTemp); + + +/* +SzArEx_Open Errors: +SZ_ERROR_NO_ARCHIVE +SZ_ERROR_ARCHIVE +SZ_ERROR_UNSUPPORTED +SZ_ERROR_MEM +SZ_ERROR_CRC +SZ_ERROR_INPUT_EOF +SZ_ERROR_FAIL +*/ + +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp); + +EXTERN_C_END + +#endif diff --git a/fex/7z_C/7zAlloc.c b/fex/7z_C/7zAlloc.c index 8874496d..964b28db 100644 --- a/fex/7z_C/7zAlloc.c +++ b/fex/7z_C/7zAlloc.c @@ -1,76 +1,76 @@ -/* 7zAlloc.c -- Allocation functions -2010-10-29 : Igor Pavlov : Public domain */ - -#include "7zAlloc.h" - -/* #define _SZ_ALLOC_DEBUG */ -/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ - -#ifdef _SZ_ALLOC_DEBUG - -#ifdef _WIN32 -#include -#endif - -#include -int g_allocCount = 0; -int g_allocCountTemp = 0; - -#endif - -void *SzAlloc(void *p, size_t size) -{ - p = p; - if (size == 0) - return 0; - #ifdef _SZ_ALLOC_DEBUG - fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount); - g_allocCount++; - #endif - return malloc(size); -} - -void SzFree(void *p, void *address) -{ - p = p; - #ifdef _SZ_ALLOC_DEBUG - if (address != 0) - { - g_allocCount--; - fprintf(stderr, "\nFree; count = %10d", g_allocCount); - } - #endif - free(address); -} - -void *SzAllocTemp(void *p, size_t size) -{ - p = p; - if (size == 0) - return 0; - #ifdef _SZ_ALLOC_DEBUG - fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp); - g_allocCountTemp++; - #ifdef _WIN32 - return HeapAlloc(GetProcessHeap(), 0, size); - #endif - #endif - return malloc(size); -} - -void SzFreeTemp(void *p, void *address) -{ - p = p; - #ifdef _SZ_ALLOC_DEBUG - if (address != 0) - { - g_allocCountTemp--; - fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp); - } - #ifdef _WIN32 - HeapFree(GetProcessHeap(), 0, address); - return; - #endif - #endif - free(address); -} +/* 7zAlloc.c -- Allocation functions +2010-10-29 : Igor Pavlov : Public domain */ + +#include "7zAlloc.h" + +/* #define _SZ_ALLOC_DEBUG */ +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ + +#ifdef _SZ_ALLOC_DEBUG + +#ifdef _WIN32 +#include +#endif + +#include +int g_allocCount = 0; +int g_allocCountTemp = 0; + +#endif + +void *SzAlloc(void *p, size_t size) +{ + p = p; + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount); + g_allocCount++; + #endif + return malloc(size); +} + +void SzFree(void *p, void *address) +{ + p = p; + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + { + g_allocCount--; + fprintf(stderr, "\nFree; count = %10d", g_allocCount); + } + #endif + free(address); +} + +void *SzAllocTemp(void *p, size_t size) +{ + p = p; + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp); + g_allocCountTemp++; + #ifdef _WIN32 + return HeapAlloc(GetProcessHeap(), 0, size); + #endif + #endif + return malloc(size); +} + +void SzFreeTemp(void *p, void *address) +{ + p = p; + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + { + g_allocCountTemp--; + fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp); + } + #ifdef _WIN32 + HeapFree(GetProcessHeap(), 0, address); + return; + #endif + #endif + free(address); +} diff --git a/fex/7z_C/7zAlloc.h b/fex/7z_C/7zAlloc.h index 860f116a..3344e937 100644 --- a/fex/7z_C/7zAlloc.h +++ b/fex/7z_C/7zAlloc.h @@ -1,15 +1,15 @@ -/* 7zAlloc.h -- Allocation functions -2010-10-29 : Igor Pavlov : Public domain */ - -#ifndef __7Z_ALLOC_H -#define __7Z_ALLOC_H - -#include - -void *SzAlloc(void *p, size_t size); -void SzFree(void *p, void *address); - -void *SzAllocTemp(void *p, size_t size); -void SzFreeTemp(void *p, void *address); - -#endif +/* 7zAlloc.h -- Allocation functions +2010-10-29 : Igor Pavlov : Public domain */ + +#ifndef __7Z_ALLOC_H +#define __7Z_ALLOC_H + +#include + +void *SzAlloc(void *p, size_t size); +void SzFree(void *p, void *address); + +void *SzAllocTemp(void *p, size_t size); +void SzFreeTemp(void *p, void *address); + +#endif diff --git a/fex/7z_C/7zBuf.c b/fex/7z_C/7zBuf.c index a35fa2f9..14e7f4e2 100644 --- a/fex/7z_C/7zBuf.c +++ b/fex/7z_C/7zBuf.c @@ -1,36 +1,36 @@ -/* 7zBuf.c -- Byte Buffer -2008-03-28 -Igor Pavlov -Public domain */ - -#include "7zBuf.h" - -void Buf_Init(CBuf *p) -{ - p->data = 0; - p->size = 0; -} - -int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc) -{ - p->size = 0; - if (size == 0) - { - p->data = 0; - return 1; - } - p->data = (Byte *)alloc->Alloc(alloc, size); - if (p->data != 0) - { - p->size = size; - return 1; - } - return 0; -} - -void Buf_Free(CBuf *p, ISzAlloc *alloc) -{ - alloc->Free(alloc, p->data); - p->data = 0; - p->size = 0; -} +/* 7zBuf.c -- Byte Buffer +2008-03-28 +Igor Pavlov +Public domain */ + +#include "7zBuf.h" + +void Buf_Init(CBuf *p) +{ + p->data = 0; + p->size = 0; +} + +int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc) +{ + p->size = 0; + if (size == 0) + { + p->data = 0; + return 1; + } + p->data = (Byte *)alloc->Alloc(alloc, size); + if (p->data != 0) + { + p->size = size; + return 1; + } + return 0; +} + +void Buf_Free(CBuf *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->data); + p->data = 0; + p->size = 0; +} diff --git a/fex/7z_C/7zBuf.h b/fex/7z_C/7zBuf.h index 88ff0c2f..e9f2f316 100644 --- a/fex/7z_C/7zBuf.h +++ b/fex/7z_C/7zBuf.h @@ -1,39 +1,39 @@ -/* 7zBuf.h -- Byte Buffer -2009-02-07 : Igor Pavlov : Public domain */ - -#ifndef __7Z_BUF_H -#define __7Z_BUF_H - -#include "Types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct -{ - Byte *data; - size_t size; -} CBuf; - -void Buf_Init(CBuf *p); -int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc); -void Buf_Free(CBuf *p, ISzAlloc *alloc); - -typedef struct -{ - Byte *data; - size_t size; - size_t pos; -} CDynBuf; - -void DynBuf_Construct(CDynBuf *p); -void DynBuf_SeekToBeg(CDynBuf *p); -int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc); -void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc); - -#ifdef __cplusplus -} -#endif - -#endif +/* 7zBuf.h -- Byte Buffer +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __7Z_BUF_H +#define __7Z_BUF_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + Byte *data; + size_t size; +} CBuf; + +void Buf_Init(CBuf *p); +int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc); +void Buf_Free(CBuf *p, ISzAlloc *alloc); + +typedef struct +{ + Byte *data; + size_t size; + size_t pos; +} CDynBuf; + +void DynBuf_Construct(CDynBuf *p); +void DynBuf_SeekToBeg(CDynBuf *p); +int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc); +void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/fex/7z_C/7zC.txt b/fex/7z_C/7zC.txt index 4ff63250..5d5d06d7 100644 --- a/fex/7z_C/7zC.txt +++ b/fex/7z_C/7zC.txt @@ -1,194 +1,194 @@ -7z ANSI-C Decoder 4.62 ----------------------- - -7z ANSI-C provides 7z/LZMA decoding. -7z ANSI-C version is simplified version ported from C++ code. - -LZMA is default and general compression method of 7z format -in 7-Zip compression program (www.7-zip.org). LZMA provides high -compression ratio and very fast decompression. - - -LICENSE -------- - -7z ANSI-C Decoder is part of the LZMA SDK. -LZMA SDK is written and placed in the public domain by Igor Pavlov. - -Files ---------------------- - -7zDecode.* - Low level 7z decoding -7zExtract.* - High level 7z decoding -7zHeader.* - .7z format constants -7zIn.* - .7z archive opening -7zItem.* - .7z structures -7zMain.c - Test application - - -How To Use ----------- - -You must download 7-Zip program from www.7-zip.org. - -You can create .7z archive with 7z.exe or 7za.exe: - - 7za.exe a archive.7z *.htm -r -mx -m0fb=255 - -If you have big number of files in archive, and you need fast extracting, -you can use partly-solid archives: - - 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K - -In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only -512KB for extracting one file from such archive. - - -Limitations of current version of 7z ANSI-C Decoder ---------------------------------------------------- - - - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive. - - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters. - - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names. - -These limitations will be fixed in future versions. - - -Using 7z ANSI-C Decoder Test application: ------------------------------------------ - -Usage: 7zDec - -: - e: Extract files from archive - l: List contents of archive - t: Test integrity of archive - -Example: - - 7zDec l archive.7z - -lists contents of archive.7z - - 7zDec e archive.7z - -extracts files from archive.7z to current folder. - - -How to use .7z Decoder ----------------------- - -Memory allocation -~~~~~~~~~~~~~~~~~ - -7z Decoder uses two memory pools: -1) Temporary pool -2) Main pool -Such scheme can allow you to avoid fragmentation of allocated blocks. - - -Steps for using 7z decoder --------------------------- - -Use code at 7zMain.c as example. - -1) Declare variables: - inStream /* implements ILookInStream interface */ - CSzArEx db; /* 7z archive database structure */ - ISzAlloc allocImp; /* memory functions for main pool */ - ISzAlloc allocTempImp; /* memory functions for temporary pool */ - -2) call CrcGenerateTable(); function to initialize CRC structures. - -3) call SzArEx_Init(&db); function to initialize db structures. - -4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive - -This function opens archive "inStream" and reads headers to "db". -All items in "db" will be allocated with "allocMain" functions. -SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions. - -5) List items or Extract items - - Listing code: - ~~~~~~~~~~~~~ - { - UInt32 i; - for (i = 0; i < db.db.NumFiles; i++) - { - CFileItem *f = db.db.Files + i; - printf("%10d %s\n", (int)f->Size, f->Name); - } - } - - Extracting code: - ~~~~~~~~~~~~~~~~ - - SZ_RESULT SzAr_Extract( - CArchiveDatabaseEx *db, - ILookInStream *inStream, - UInt32 fileIndex, /* index of file */ - UInt32 *blockIndex, /* index of solid block */ - Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ - size_t *outBufferSize, /* buffer size for output buffer */ - size_t *offset, /* offset of stream for required file in *outBuffer */ - size_t *outSizeProcessed, /* size of file in *outBuffer */ - ISzAlloc *allocMain, - ISzAlloc *allocTemp); - - If you need to decompress more than one file, you can send these values from previous call: - blockIndex, - outBuffer, - outBufferSize, - You can consider "outBuffer" as cache of solid block. If your archive is solid, - it will increase decompression speed. - - After decompressing you must free "outBuffer": - allocImp.Free(outBuffer); - -6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db". - - - - -Memory requirements for .7z decoding ------------------------------------- - -Memory usage for Archive opening: - - Temporary pool: - - Memory for uncompressed .7z headers - - some other temporary blocks - - Main pool: - - Memory for database: - Estimated size of one file structures in solid archive: - - Size (4 or 8 Bytes) - - CRC32 (4 bytes) - - LastWriteTime (8 bytes) - - Some file information (4 bytes) - - File Name (variable length) + pointer + allocation structures - -Memory usage for archive Decompressing: - - Temporary pool: - - Memory for LZMA decompressing structures - - Main pool: - - Memory for decompressed solid block - - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these - temprorary buffers can be about 15% of solid block size. - - -7z Decoder doesn't allocate memory for compressed blocks. -Instead of this, you must allocate buffer with desired -size before calling 7z Decoder. Use 7zMain.c as example. - - -Defines -------- - -_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr. - - ---- - -http://www.7-zip.org -http://www.7-zip.org/sdk.html -http://www.7-zip.org/support.html +7z ANSI-C Decoder 4.62 +---------------------- + +7z ANSI-C provides 7z/LZMA decoding. +7z ANSI-C version is simplified version ported from C++ code. + +LZMA is default and general compression method of 7z format +in 7-Zip compression program (www.7-zip.org). LZMA provides high +compression ratio and very fast decompression. + + +LICENSE +------- + +7z ANSI-C Decoder is part of the LZMA SDK. +LZMA SDK is written and placed in the public domain by Igor Pavlov. + +Files +--------------------- + +7zDecode.* - Low level 7z decoding +7zExtract.* - High level 7z decoding +7zHeader.* - .7z format constants +7zIn.* - .7z archive opening +7zItem.* - .7z structures +7zMain.c - Test application + + +How To Use +---------- + +You must download 7-Zip program from www.7-zip.org. + +You can create .7z archive with 7z.exe or 7za.exe: + + 7za.exe a archive.7z *.htm -r -mx -m0fb=255 + +If you have big number of files in archive, and you need fast extracting, +you can use partly-solid archives: + + 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K + +In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only +512KB for extracting one file from such archive. + + +Limitations of current version of 7z ANSI-C Decoder +--------------------------------------------------- + + - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive. + - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters. + - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names. + +These limitations will be fixed in future versions. + + +Using 7z ANSI-C Decoder Test application: +----------------------------------------- + +Usage: 7zDec + +: + e: Extract files from archive + l: List contents of archive + t: Test integrity of archive + +Example: + + 7zDec l archive.7z + +lists contents of archive.7z + + 7zDec e archive.7z + +extracts files from archive.7z to current folder. + + +How to use .7z Decoder +---------------------- + +Memory allocation +~~~~~~~~~~~~~~~~~ + +7z Decoder uses two memory pools: +1) Temporary pool +2) Main pool +Such scheme can allow you to avoid fragmentation of allocated blocks. + + +Steps for using 7z decoder +-------------------------- + +Use code at 7zMain.c as example. + +1) Declare variables: + inStream /* implements ILookInStream interface */ + CSzArEx db; /* 7z archive database structure */ + ISzAlloc allocImp; /* memory functions for main pool */ + ISzAlloc allocTempImp; /* memory functions for temporary pool */ + +2) call CrcGenerateTable(); function to initialize CRC structures. + +3) call SzArEx_Init(&db); function to initialize db structures. + +4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive + +This function opens archive "inStream" and reads headers to "db". +All items in "db" will be allocated with "allocMain" functions. +SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions. + +5) List items or Extract items + + Listing code: + ~~~~~~~~~~~~~ + { + UInt32 i; + for (i = 0; i < db.db.NumFiles; i++) + { + CFileItem *f = db.db.Files + i; + printf("%10d %s\n", (int)f->Size, f->Name); + } + } + + Extracting code: + ~~~~~~~~~~~~~~~~ + + SZ_RESULT SzAr_Extract( + CArchiveDatabaseEx *db, + ILookInStream *inStream, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAlloc *allocMain, + ISzAlloc *allocTemp); + + If you need to decompress more than one file, you can send these values from previous call: + blockIndex, + outBuffer, + outBufferSize, + You can consider "outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + After decompressing you must free "outBuffer": + allocImp.Free(outBuffer); + +6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db". + + + + +Memory requirements for .7z decoding +------------------------------------ + +Memory usage for Archive opening: + - Temporary pool: + - Memory for uncompressed .7z headers + - some other temporary blocks + - Main pool: + - Memory for database: + Estimated size of one file structures in solid archive: + - Size (4 or 8 Bytes) + - CRC32 (4 bytes) + - LastWriteTime (8 bytes) + - Some file information (4 bytes) + - File Name (variable length) + pointer + allocation structures + +Memory usage for archive Decompressing: + - Temporary pool: + - Memory for LZMA decompressing structures + - Main pool: + - Memory for decompressed solid block + - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these + temprorary buffers can be about 15% of solid block size. + + +7z Decoder doesn't allocate memory for compressed blocks. +Instead of this, you must allocate buffer with desired +size before calling 7z Decoder. Use 7zMain.c as example. + + +Defines +------- + +_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr. + + +--- + +http://www.7-zip.org +http://www.7-zip.org/sdk.html +http://www.7-zip.org/support.html diff --git a/fex/7z_C/7zCrc.c b/fex/7z_C/7zCrc.c index 5801dabf..a9208496 100644 --- a/fex/7z_C/7zCrc.c +++ b/fex/7z_C/7zCrc.c @@ -1,74 +1,74 @@ -/* 7zCrc.c -- CRC32 calculation -2009-11-23 : Igor Pavlov : Public domain */ - -#include "7zCrc.h" -#include "CpuArch.h" - -#define kCrcPoly 0xEDB88320 - -#ifdef MY_CPU_LE -#define CRC_NUM_TABLES 8 -#else -#define CRC_NUM_TABLES 1 -#endif - -typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); - -static CRC_FUNC g_CrcUpdate; -UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; - -#if CRC_NUM_TABLES == 1 - -#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -static UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) -{ - const Byte *p = (const Byte *)data; - for (; size > 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; -} - -#else - -UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); -UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); - -#endif - -UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) -{ - return g_CrcUpdate(v, data, size, g_CrcTable); -} - -UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) -{ - return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; -} - -void MY_FAST_CALL CrcGenerateTable() -{ - UInt32 i; - for (i = 0; i < 256; i++) - { - UInt32 r = i; - unsigned j; - for (j = 0; j < 8; j++) - r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); - g_CrcTable[i] = r; - } - #if CRC_NUM_TABLES == 1 - g_CrcUpdate = CrcUpdateT1; - #else - for (; i < 256 * CRC_NUM_TABLES; i++) - { - UInt32 r = g_CrcTable[i - 256]; - g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); - } - g_CrcUpdate = CrcUpdateT4; - #ifdef MY_CPU_X86_OR_AMD64 - if (!CPU_Is_InOrder()) - g_CrcUpdate = CrcUpdateT8; - #endif - #endif -} +/* 7zCrc.c -- CRC32 calculation +2009-11-23 : Igor Pavlov : Public domain */ + +#include "7zCrc.h" +#include "CpuArch.h" + +#define kCrcPoly 0xEDB88320 + +#ifdef MY_CPU_LE +#define CRC_NUM_TABLES 8 +#else +#define CRC_NUM_TABLES 1 +#endif + +typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); + +static CRC_FUNC g_CrcUpdate; +UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; + +#if CRC_NUM_TABLES == 1 + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +static UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +#else + +UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); +UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); + +#endif + +UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) +{ + return g_CrcUpdate(v, data, size, g_CrcTable); +} + +UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) +{ + return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; +} + +void MY_FAST_CALL CrcGenerateTable() +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt32 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); + g_CrcTable[i] = r; + } + #if CRC_NUM_TABLES == 1 + g_CrcUpdate = CrcUpdateT1; + #else + for (; i < 256 * CRC_NUM_TABLES; i++) + { + UInt32 r = g_CrcTable[i - 256]; + g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); + } + g_CrcUpdate = CrcUpdateT4; + #ifdef MY_CPU_X86_OR_AMD64 + if (!CPU_Is_InOrder()) + g_CrcUpdate = CrcUpdateT8; + #endif + #endif +} diff --git a/fex/7z_C/7zCrc.h b/fex/7z_C/7zCrc.h index 4a1ec38c..38e3e5fb 100644 --- a/fex/7z_C/7zCrc.h +++ b/fex/7z_C/7zCrc.h @@ -1,25 +1,25 @@ -/* 7zCrc.h -- CRC32 calculation -2009-11-21 : Igor Pavlov : Public domain */ - -#ifndef __7Z_CRC_H -#define __7Z_CRC_H - -#include "Types.h" - -EXTERN_C_BEGIN - -extern UInt32 g_CrcTable[]; - -/* Call CrcGenerateTable one time before other CRC functions */ -void MY_FAST_CALL CrcGenerateTable(void); - -#define CRC_INIT_VAL 0xFFFFFFFF -#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) -#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); -UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); - -EXTERN_C_END - -#endif +/* 7zCrc.h -- CRC32 calculation +2009-11-21 : Igor Pavlov : Public domain */ + +#ifndef __7Z_CRC_H +#define __7Z_CRC_H + +#include "Types.h" + +EXTERN_C_BEGIN + +extern UInt32 g_CrcTable[]; + +/* Call CrcGenerateTable one time before other CRC functions */ +void MY_FAST_CALL CrcGenerateTable(void); + +#define CRC_INIT_VAL 0xFFFFFFFF +#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) +#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); +UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); + +EXTERN_C_END + +#endif diff --git a/fex/7z_C/7zCrcOpt.c b/fex/7z_C/7zCrcOpt.c index 6205d716..6c766a20 100644 --- a/fex/7z_C/7zCrcOpt.c +++ b/fex/7z_C/7zCrcOpt.c @@ -1,34 +1,34 @@ -/* 7zCrcOpt.c -- CRC32 calculation : optimized version -2009-11-23 : Igor Pavlov : Public domain */ - -#include "CpuArch.h" - -#ifdef MY_CPU_LE - -#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) -{ - const Byte *p = (const Byte *)data; - for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - for (; size >= 4; size -= 4, p += 4) - { - v ^= *(const UInt32 *)p; - v = - table[0x300 + (v & 0xFF)] ^ - table[0x200 + ((v >> 8) & 0xFF)] ^ - table[0x100 + ((v >> 16) & 0xFF)] ^ - table[0x000 + ((v >> 24))]; - } - for (; size > 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; -} - -UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) -{ - return CrcUpdateT4(v, data, size, table); -} - -#endif +/* 7zCrcOpt.c -- CRC32 calculation : optimized version +2009-11-23 : Igor Pavlov : Public domain */ + +#include "CpuArch.h" + +#ifdef MY_CPU_LE + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + v ^= *(const UInt32 *)p; + v = + table[0x300 + (v & 0xFF)] ^ + table[0x200 + ((v >> 8) & 0xFF)] ^ + table[0x100 + ((v >> 16) & 0xFF)] ^ + table[0x000 + ((v >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + return CrcUpdateT4(v, data, size, table); +} + +#endif diff --git a/fex/7z_C/7zDecode.c b/fex/7z_C/7zDecode.c index 33868074..b6d80995 100644 --- a/fex/7z_C/7zDecode.c +++ b/fex/7z_C/7zDecode.c @@ -1,470 +1,470 @@ -/* 7zDec.c -- Decoding from 7z folder -2010-11-02 : Igor Pavlov : Public domain */ - -#include - -/* #define _7ZIP_PPMD_SUPPPORT */ - -#include "7z.h" - -#include "Bcj2.h" -#include "Bra.h" -#include "CpuArch.h" -#include "LzmaDec.h" -#include "Lzma2Dec.h" -#ifdef _7ZIP_PPMD_SUPPPORT -#include "Ppmd7.h" -#endif - -#define k_Copy 0 -#define k_LZMA2 0x21 -#define k_LZMA 0x30101 -#define k_BCJ 0x03030103 -#define k_PPC 0x03030205 -#define k_ARM 0x03030501 -#define k_ARMT 0x03030701 -#define k_SPARC 0x03030805 -#define k_BCJ2 0x0303011B - -#ifdef _7ZIP_PPMD_SUPPPORT - -#define k_PPMD 0x30401 - -typedef struct -{ - IByteIn p; - const Byte *cur; - const Byte *end; - const Byte *begin; - UInt64 processed; - Bool extra; - SRes res; - ILookInStream *inStream; -} CByteInToLook; - -static Byte ReadByte(void *pp) -{ - CByteInToLook *p = (CByteInToLook *)pp; - if (p->cur != p->end) - return *p->cur++; - if (p->res == SZ_OK) - { - size_t size = p->cur - p->begin; - p->processed += size; - p->res = p->inStream->Skip(p->inStream, size); - size = (1 << 25); - p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size); - p->cur = p->begin; - p->end = p->begin + size; - if (size != 0) - return *p->cur++;; - } - p->extra = True; - return 0; -} - -static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, - Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) -{ - CPpmd7 ppmd; - CByteInToLook s; - SRes res = SZ_OK; - - s.p.Read = ReadByte; - s.inStream = inStream; - s.begin = s.end = s.cur = NULL; - s.extra = False; - s.res = SZ_OK; - s.processed = 0; - - if (coder->Props.size != 5) - return SZ_ERROR_UNSUPPORTED; - - { - unsigned order = coder->Props.data[0]; - UInt32 memSize = GetUi32(coder->Props.data + 1); - if (order < PPMD7_MIN_ORDER || - order > PPMD7_MAX_ORDER || - memSize < PPMD7_MIN_MEM_SIZE || - memSize > PPMD7_MAX_MEM_SIZE) - return SZ_ERROR_UNSUPPORTED; - Ppmd7_Construct(&ppmd); - if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) - return SZ_ERROR_MEM; - Ppmd7_Init(&ppmd, order); - } - { - CPpmd7z_RangeDec rc; - Ppmd7z_RangeDec_CreateVTable(&rc); - rc.Stream = &s.p; - if (!Ppmd7z_RangeDec_Init(&rc)) - res = SZ_ERROR_DATA; - else if (s.extra) - res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); - else - { - SizeT i; - for (i = 0; i < outSize; i++) - { - int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p); - if (s.extra || sym < 0) - break; - outBuffer[i] = (Byte)sym; - } - if (i != outSize) - res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); - else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc)) - res = SZ_ERROR_DATA; - } - } - Ppmd7_Free(&ppmd, allocMain); - return res; -} - -#endif - - -static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, - Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) -{ - CLzmaDec state; - SRes res = SZ_OK; - - LzmaDec_Construct(&state); - RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain)); - state.dic = outBuffer; - state.dicBufSize = outSize; - LzmaDec_Init(&state); - - for (;;) - { - Byte *inBuf = NULL; - size_t lookahead = (1 << 18); - if (lookahead > inSize) - lookahead = (size_t)inSize; - res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); - if (res != SZ_OK) - break; - - { - SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; - ELzmaStatus status; - res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); - lookahead -= inProcessed; - inSize -= inProcessed; - if (res != SZ_OK) - break; - if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos)) - { - if (state.dicBufSize != outSize || lookahead != 0 || - (status != LZMA_STATUS_FINISHED_WITH_MARK && - status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) - res = SZ_ERROR_DATA; - break; - } - res = inStream->Skip((void *)inStream, inProcessed); - if (res != SZ_OK) - break; - } - } - - LzmaDec_FreeProbs(&state, allocMain); - return res; -} - -static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, - Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) -{ - CLzma2Dec state; - SRes res = SZ_OK; - - Lzma2Dec_Construct(&state); - if (coder->Props.size != 1) - return SZ_ERROR_DATA; - RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain)); - state.decoder.dic = outBuffer; - state.decoder.dicBufSize = outSize; - Lzma2Dec_Init(&state); - - for (;;) - { - Byte *inBuf = NULL; - size_t lookahead = (1 << 18); - if (lookahead > inSize) - lookahead = (size_t)inSize; - res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); - if (res != SZ_OK) - break; - - { - SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; - ELzmaStatus status; - res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); - lookahead -= inProcessed; - inSize -= inProcessed; - if (res != SZ_OK) - break; - if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos)) - { - if (state.decoder.dicBufSize != outSize || lookahead != 0 || - (status != LZMA_STATUS_FINISHED_WITH_MARK)) - res = SZ_ERROR_DATA; - break; - } - res = inStream->Skip((void *)inStream, inProcessed); - if (res != SZ_OK) - break; - } - } - - Lzma2Dec_FreeProbs(&state, allocMain); - return res; -} - -static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) -{ - while (inSize > 0) - { - void *inBuf; - size_t curSize = (1 << 18); - if (curSize > inSize) - curSize = (size_t)inSize; - RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize)); - if (curSize == 0) - return SZ_ERROR_INPUT_EOF; - memcpy(outBuffer, inBuf, curSize); - outBuffer += curSize; - inSize -= curSize; - RINOK(inStream->Skip((void *)inStream, curSize)); - } - return SZ_OK; -} - -static Bool IS_MAIN_METHOD(UInt32 m) -{ - switch(m) - { - case k_Copy: - case k_LZMA: - case k_LZMA2: - #ifdef _7ZIP_PPMD_SUPPPORT - case k_PPMD: - #endif - return True; - } - return False; -} - -static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c) -{ - return - c->NumInStreams == 1 && - c->NumOutStreams == 1 && - c->MethodID <= (UInt32)0xFFFFFFFF && - IS_MAIN_METHOD((UInt32)c->MethodID); -} - -#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1) - -static SRes CheckSupportedFolder(const CSzFolder *f) -{ - if (f->NumCoders < 1 || f->NumCoders > 4) - return SZ_ERROR_UNSUPPORTED; - if (!IS_SUPPORTED_CODER(&f->Coders[0])) - return SZ_ERROR_UNSUPPORTED; - if (f->NumCoders == 1) - { - if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0) - return SZ_ERROR_UNSUPPORTED; - return SZ_OK; - } - if (f->NumCoders == 2) - { - CSzCoderInfo *c = &f->Coders[1]; - if (c->MethodID > (UInt32)0xFFFFFFFF || - c->NumInStreams != 1 || - c->NumOutStreams != 1 || - f->NumPackStreams != 1 || - f->PackStreams[0] != 0 || - f->NumBindPairs != 1 || - f->BindPairs[0].InIndex != 1 || - f->BindPairs[0].OutIndex != 0) - return SZ_ERROR_UNSUPPORTED; - switch ((UInt32)c->MethodID) - { - case k_BCJ: - case k_ARM: - break; - default: - return SZ_ERROR_UNSUPPORTED; - } - return SZ_OK; - } - if (f->NumCoders == 4) - { - if (!IS_SUPPORTED_CODER(&f->Coders[1]) || - !IS_SUPPORTED_CODER(&f->Coders[2]) || - !IS_BCJ2(&f->Coders[3])) - return SZ_ERROR_UNSUPPORTED; - if (f->NumPackStreams != 4 || - f->PackStreams[0] != 2 || - f->PackStreams[1] != 6 || - f->PackStreams[2] != 1 || - f->PackStreams[3] != 0 || - f->NumBindPairs != 3 || - f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || - f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || - f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) - return SZ_ERROR_UNSUPPORTED; - return SZ_OK; - } - return SZ_ERROR_UNSUPPORTED; -} - -static UInt64 GetSum(const UInt64 *values, UInt32 index) -{ - UInt64 sum = 0; - UInt32 i; - for (i = 0; i < index; i++) - sum += values[i]; - return sum; -} - -#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; - -static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, - ILookInStream *inStream, UInt64 startPos, - Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, - Byte *tempBuf[]) -{ - UInt32 ci; - SizeT tempSizes[3] = { 0, 0, 0}; - SizeT tempSize3 = 0; - Byte *tempBuf3 = 0; - - RINOK(CheckSupportedFolder(folder)); - - for (ci = 0; ci < folder->NumCoders; ci++) - { - CSzCoderInfo *coder = &folder->Coders[ci]; - - if (IS_MAIN_METHOD((UInt32)coder->MethodID)) - { - UInt32 si = 0; - UInt64 offset; - UInt64 inSize; - Byte *outBufCur = outBuffer; - SizeT outSizeCur = outSize; - if (folder->NumCoders == 4) - { - UInt32 indices[] = { 3, 2, 0 }; - UInt64 unpackSize = folder->UnpackSizes[ci]; - si = indices[ci]; - if (ci < 2) - { - Byte *temp; - outSizeCur = (SizeT)unpackSize; - if (outSizeCur != unpackSize) - return SZ_ERROR_MEM; - temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); - if (temp == 0 && outSizeCur != 0) - return SZ_ERROR_MEM; - outBufCur = tempBuf[1 - ci] = temp; - tempSizes[1 - ci] = outSizeCur; - } - else if (ci == 2) - { - if (unpackSize > outSize) /* check it */ - return SZ_ERROR_PARAM; - tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); - tempSize3 = outSizeCur = (SizeT)unpackSize; - } - else - return SZ_ERROR_UNSUPPORTED; - } - offset = GetSum(packSizes, si); - inSize = packSizes[si]; - RINOK(LookInStream_SeekTo(inStream, startPos + offset)); - - if (coder->MethodID == k_Copy) - { - if (inSize != outSizeCur) /* check it */ - return SZ_ERROR_DATA; - RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); - } - else if (coder->MethodID == k_LZMA) - { - RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); - } - else if (coder->MethodID == k_LZMA2) - { - RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); - } - else - { - #ifdef _7ZIP_PPMD_SUPPPORT - RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); - #else - return SZ_ERROR_UNSUPPORTED; - #endif - } - } - else if (coder->MethodID == k_BCJ2) - { - UInt64 offset = GetSum(packSizes, 1); - UInt64 s3Size = packSizes[1]; - SRes res; - if (ci != 3) - return SZ_ERROR_UNSUPPORTED; - RINOK(LookInStream_SeekTo(inStream, startPos + offset)); - tempSizes[2] = (SizeT)s3Size; - if (tempSizes[2] != s3Size) - return SZ_ERROR_MEM; - tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); - if (tempBuf[2] == 0 && tempSizes[2] != 0) - return SZ_ERROR_MEM; - res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); - RINOK(res) - - res = Bcj2_Decode( - tempBuf3, tempSize3, - tempBuf[0], tempSizes[0], - tempBuf[1], tempSizes[1], - tempBuf[2], tempSizes[2], - outBuffer, outSize); - RINOK(res) - } - else - { - if (ci != 1) - return SZ_ERROR_UNSUPPORTED; - switch(coder->MethodID) - { - case k_BCJ: - { - UInt32 state; - x86_Convert_Init(state); - x86_Convert(outBuffer, outSize, 0, &state, 0); - break; - } - CASE_BRA_CONV(ARM) - default: - return SZ_ERROR_UNSUPPORTED; - } - } - } - return SZ_OK; -} - -SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, - ILookInStream *inStream, UInt64 startPos, - Byte *outBuffer, size_t outSize, ISzAlloc *allocMain) -{ - Byte *tempBuf[3] = { 0, 0, 0}; - int i; - SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos, - outBuffer, (SizeT)outSize, allocMain, tempBuf); - for (i = 0; i < 3; i++) - IAlloc_Free(allocMain, tempBuf[i]); - return res; -} +/* 7zDec.c -- Decoding from 7z folder +2010-11-02 : Igor Pavlov : Public domain */ + +#include + +/* #define _7ZIP_PPMD_SUPPPORT */ + +#include "7z.h" + +#include "Bcj2.h" +#include "Bra.h" +#include "CpuArch.h" +#include "LzmaDec.h" +#include "Lzma2Dec.h" +#ifdef _7ZIP_PPMD_SUPPPORT +#include "Ppmd7.h" +#endif + +#define k_Copy 0 +#define k_LZMA2 0x21 +#define k_LZMA 0x30101 +#define k_BCJ 0x03030103 +#define k_PPC 0x03030205 +#define k_ARM 0x03030501 +#define k_ARMT 0x03030701 +#define k_SPARC 0x03030805 +#define k_BCJ2 0x0303011B + +#ifdef _7ZIP_PPMD_SUPPPORT + +#define k_PPMD 0x30401 + +typedef struct +{ + IByteIn p; + const Byte *cur; + const Byte *end; + const Byte *begin; + UInt64 processed; + Bool extra; + SRes res; + ILookInStream *inStream; +} CByteInToLook; + +static Byte ReadByte(void *pp) +{ + CByteInToLook *p = (CByteInToLook *)pp; + if (p->cur != p->end) + return *p->cur++; + if (p->res == SZ_OK) + { + size_t size = p->cur - p->begin; + p->processed += size; + p->res = p->inStream->Skip(p->inStream, size); + size = (1 << 25); + p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size); + p->cur = p->begin; + p->end = p->begin + size; + if (size != 0) + return *p->cur++;; + } + p->extra = True; + return 0; +} + +static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) +{ + CPpmd7 ppmd; + CByteInToLook s; + SRes res = SZ_OK; + + s.p.Read = ReadByte; + s.inStream = inStream; + s.begin = s.end = s.cur = NULL; + s.extra = False; + s.res = SZ_OK; + s.processed = 0; + + if (coder->Props.size != 5) + return SZ_ERROR_UNSUPPORTED; + + { + unsigned order = coder->Props.data[0]; + UInt32 memSize = GetUi32(coder->Props.data + 1); + if (order < PPMD7_MIN_ORDER || + order > PPMD7_MAX_ORDER || + memSize < PPMD7_MIN_MEM_SIZE || + memSize > PPMD7_MAX_MEM_SIZE) + return SZ_ERROR_UNSUPPORTED; + Ppmd7_Construct(&ppmd); + if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) + return SZ_ERROR_MEM; + Ppmd7_Init(&ppmd, order); + } + { + CPpmd7z_RangeDec rc; + Ppmd7z_RangeDec_CreateVTable(&rc); + rc.Stream = &s.p; + if (!Ppmd7z_RangeDec_Init(&rc)) + res = SZ_ERROR_DATA; + else if (s.extra) + res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); + else + { + SizeT i; + for (i = 0; i < outSize; i++) + { + int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p); + if (s.extra || sym < 0) + break; + outBuffer[i] = (Byte)sym; + } + if (i != outSize) + res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); + else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc)) + res = SZ_ERROR_DATA; + } + } + Ppmd7_Free(&ppmd, allocMain); + return res; +} + +#endif + + +static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) +{ + CLzmaDec state; + SRes res = SZ_OK; + + LzmaDec_Construct(&state); + RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain)); + state.dic = outBuffer; + state.dicBufSize = outSize; + LzmaDec_Init(&state); + + for (;;) + { + Byte *inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); + if (res != SZ_OK) + break; + + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; + ELzmaStatus status; + res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; + if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos)) + { + if (state.dicBufSize != outSize || lookahead != 0 || + (status != LZMA_STATUS_FINISHED_WITH_MARK && + status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) + res = SZ_ERROR_DATA; + break; + } + res = inStream->Skip((void *)inStream, inProcessed); + if (res != SZ_OK) + break; + } + } + + LzmaDec_FreeProbs(&state, allocMain); + return res; +} + +static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) +{ + CLzma2Dec state; + SRes res = SZ_OK; + + Lzma2Dec_Construct(&state); + if (coder->Props.size != 1) + return SZ_ERROR_DATA; + RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain)); + state.decoder.dic = outBuffer; + state.decoder.dicBufSize = outSize; + Lzma2Dec_Init(&state); + + for (;;) + { + Byte *inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); + if (res != SZ_OK) + break; + + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; + ELzmaStatus status; + res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; + if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos)) + { + if (state.decoder.dicBufSize != outSize || lookahead != 0 || + (status != LZMA_STATUS_FINISHED_WITH_MARK)) + res = SZ_ERROR_DATA; + break; + } + res = inStream->Skip((void *)inStream, inProcessed); + if (res != SZ_OK) + break; + } + } + + Lzma2Dec_FreeProbs(&state, allocMain); + return res; +} + +static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) +{ + while (inSize > 0) + { + void *inBuf; + size_t curSize = (1 << 18); + if (curSize > inSize) + curSize = (size_t)inSize; + RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize)); + if (curSize == 0) + return SZ_ERROR_INPUT_EOF; + memcpy(outBuffer, inBuf, curSize); + outBuffer += curSize; + inSize -= curSize; + RINOK(inStream->Skip((void *)inStream, curSize)); + } + return SZ_OK; +} + +static Bool IS_MAIN_METHOD(UInt32 m) +{ + switch(m) + { + case k_Copy: + case k_LZMA: + case k_LZMA2: + #ifdef _7ZIP_PPMD_SUPPPORT + case k_PPMD: + #endif + return True; + } + return False; +} + +static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c) +{ + return + c->NumInStreams == 1 && + c->NumOutStreams == 1 && + c->MethodID <= (UInt32)0xFFFFFFFF && + IS_MAIN_METHOD((UInt32)c->MethodID); +} + +#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1) + +static SRes CheckSupportedFolder(const CSzFolder *f) +{ + if (f->NumCoders < 1 || f->NumCoders > 4) + return SZ_ERROR_UNSUPPORTED; + if (!IS_SUPPORTED_CODER(&f->Coders[0])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumCoders == 1) + { + if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + if (f->NumCoders == 2) + { + CSzCoderInfo *c = &f->Coders[1]; + if (c->MethodID > (UInt32)0xFFFFFFFF || + c->NumInStreams != 1 || + c->NumOutStreams != 1 || + f->NumPackStreams != 1 || + f->PackStreams[0] != 0 || + f->NumBindPairs != 1 || + f->BindPairs[0].InIndex != 1 || + f->BindPairs[0].OutIndex != 0) + return SZ_ERROR_UNSUPPORTED; + switch ((UInt32)c->MethodID) + { + case k_BCJ: + case k_ARM: + break; + default: + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; + } + if (f->NumCoders == 4) + { + if (!IS_SUPPORTED_CODER(&f->Coders[1]) || + !IS_SUPPORTED_CODER(&f->Coders[2]) || + !IS_BCJ2(&f->Coders[3])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumPackStreams != 4 || + f->PackStreams[0] != 2 || + f->PackStreams[1] != 6 || + f->PackStreams[2] != 1 || + f->PackStreams[3] != 0 || + f->NumBindPairs != 3 || + f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || + f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || + f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + return SZ_ERROR_UNSUPPORTED; +} + +static UInt64 GetSum(const UInt64 *values, UInt32 index) +{ + UInt64 sum = 0; + UInt32 i; + for (i = 0; i < index; i++) + sum += values[i]; + return sum; +} + +#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; + +static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, + ILookInStream *inStream, UInt64 startPos, + Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, + Byte *tempBuf[]) +{ + UInt32 ci; + SizeT tempSizes[3] = { 0, 0, 0}; + SizeT tempSize3 = 0; + Byte *tempBuf3 = 0; + + RINOK(CheckSupportedFolder(folder)); + + for (ci = 0; ci < folder->NumCoders; ci++) + { + CSzCoderInfo *coder = &folder->Coders[ci]; + + if (IS_MAIN_METHOD((UInt32)coder->MethodID)) + { + UInt32 si = 0; + UInt64 offset; + UInt64 inSize; + Byte *outBufCur = outBuffer; + SizeT outSizeCur = outSize; + if (folder->NumCoders == 4) + { + UInt32 indices[] = { 3, 2, 0 }; + UInt64 unpackSize = folder->UnpackSizes[ci]; + si = indices[ci]; + if (ci < 2) + { + Byte *temp; + outSizeCur = (SizeT)unpackSize; + if (outSizeCur != unpackSize) + return SZ_ERROR_MEM; + temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); + if (temp == 0 && outSizeCur != 0) + return SZ_ERROR_MEM; + outBufCur = tempBuf[1 - ci] = temp; + tempSizes[1 - ci] = outSizeCur; + } + else if (ci == 2) + { + if (unpackSize > outSize) /* check it */ + return SZ_ERROR_PARAM; + tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); + tempSize3 = outSizeCur = (SizeT)unpackSize; + } + else + return SZ_ERROR_UNSUPPORTED; + } + offset = GetSum(packSizes, si); + inSize = packSizes[si]; + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + + if (coder->MethodID == k_Copy) + { + if (inSize != outSizeCur) /* check it */ + return SZ_ERROR_DATA; + RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); + } + else if (coder->MethodID == k_LZMA) + { + RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); + } + else if (coder->MethodID == k_LZMA2) + { + RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); + } + else + { + #ifdef _7ZIP_PPMD_SUPPPORT + RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); + #else + return SZ_ERROR_UNSUPPORTED; + #endif + } + } + else if (coder->MethodID == k_BCJ2) + { + UInt64 offset = GetSum(packSizes, 1); + UInt64 s3Size = packSizes[1]; + SRes res; + if (ci != 3) + return SZ_ERROR_UNSUPPORTED; + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + tempSizes[2] = (SizeT)s3Size; + if (tempSizes[2] != s3Size) + return SZ_ERROR_MEM; + tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); + if (tempBuf[2] == 0 && tempSizes[2] != 0) + return SZ_ERROR_MEM; + res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); + RINOK(res) + + res = Bcj2_Decode( + tempBuf3, tempSize3, + tempBuf[0], tempSizes[0], + tempBuf[1], tempSizes[1], + tempBuf[2], tempSizes[2], + outBuffer, outSize); + RINOK(res) + } + else + { + if (ci != 1) + return SZ_ERROR_UNSUPPORTED; + switch(coder->MethodID) + { + case k_BCJ: + { + UInt32 state; + x86_Convert_Init(state); + x86_Convert(outBuffer, outSize, 0, &state, 0); + break; + } + CASE_BRA_CONV(ARM) + default: + return SZ_ERROR_UNSUPPORTED; + } + } + } + return SZ_OK; +} + +SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, + ILookInStream *inStream, UInt64 startPos, + Byte *outBuffer, size_t outSize, ISzAlloc *allocMain) +{ + Byte *tempBuf[3] = { 0, 0, 0}; + int i; + SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos, + outBuffer, (SizeT)outSize, allocMain, tempBuf); + for (i = 0; i < 3; i++) + IAlloc_Free(allocMain, tempBuf[i]); + return res; +} diff --git a/fex/7z_C/7zDecode.h b/fex/7z_C/7zDecode.h index 9607915b..e19fe387 100644 --- a/fex/7z_C/7zDecode.h +++ b/fex/7z_C/7zDecode.h @@ -1,13 +1,13 @@ -/* 7zDecode.h -- Decoding from 7z folder -2008-11-23 : Igor Pavlov : Public domain */ - -#ifndef __7Z_DECODE_H -#define __7Z_DECODE_H - -#include "7zItem.h" - -SRes SzDecode(const UInt64 *packSizes, const CSzFolder *folder, - ILookInStream *stream, UInt64 startPos, - Byte *outBuffer, size_t outSize, ISzAlloc *allocMain); - -#endif +/* 7zDecode.h -- Decoding from 7z folder +2008-11-23 : Igor Pavlov : Public domain */ + +#ifndef __7Z_DECODE_H +#define __7Z_DECODE_H + +#include "7zItem.h" + +SRes SzDecode(const UInt64 *packSizes, const CSzFolder *folder, + ILookInStream *stream, UInt64 startPos, + Byte *outBuffer, size_t outSize, ISzAlloc *allocMain); + +#endif diff --git a/fex/7z_C/7zExtract.c b/fex/7z_C/7zExtract.c index e6630855..99ef3654 100644 --- a/fex/7z_C/7zExtract.c +++ b/fex/7z_C/7zExtract.c @@ -1,93 +1,93 @@ -/* 7zExtract.c -- Extracting from 7z archive -2008-11-23 : Igor Pavlov : Public domain */ - -#include "7zCrc.h" -#include "7zDecode.h" -#include "7zExtract.h" - -SRes SzAr_Extract( - const CSzArEx *p, - ILookInStream *inStream, - UInt32 fileIndex, - UInt32 *blockIndex, - Byte **outBuffer, - size_t *outBufferSize, - size_t *offset, - size_t *outSizeProcessed, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; - SRes res = SZ_OK; - *offset = 0; - *outSizeProcessed = 0; - if (folderIndex == (UInt32)-1) - { - IAlloc_Free(allocMain, *outBuffer); - *blockIndex = folderIndex; - *outBuffer = 0; - *outBufferSize = 0; - return SZ_OK; - } - - if (*outBuffer == 0 || *blockIndex != folderIndex) - { - CSzFolder *folder = p->db.Folders + folderIndex; - UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); - size_t unpackSize = (size_t)unpackSizeSpec; - UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); - - if (unpackSize != unpackSizeSpec) - return SZ_ERROR_MEM; - *blockIndex = folderIndex; - IAlloc_Free(allocMain, *outBuffer); - *outBuffer = 0; - - RINOK(LookInStream_SeekTo(inStream, startOffset)); - - if (res == SZ_OK) - { - *outBufferSize = unpackSize; - if (unpackSize != 0) - { - *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); - if (*outBuffer == 0) - res = SZ_ERROR_MEM; - } - if (res == SZ_OK) - { - res = SzDecode(p->db.PackSizes + - p->FolderStartPackStreamIndex[folderIndex], folder, - inStream, startOffset, - *outBuffer, unpackSize, allocTemp); - if (res == SZ_OK) - { - if (folder->UnpackCRCDefined) - { - if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) - res = SZ_ERROR_CRC; - } - } - } - } - } - if (res == SZ_OK) - { - UInt32 i; - CSzFileItem *fileItem = p->db.Files + fileIndex; - *offset = 0; - for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) - *offset += (UInt32)p->db.Files[i].Size; - *outSizeProcessed = (size_t)fileItem->Size; - if (*offset + *outSizeProcessed > *outBufferSize) - return SZ_ERROR_FAIL; - { - if (fileItem->FileCRCDefined) - { - if (CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->FileCRC) - res = SZ_ERROR_CRC; - } - } - } - return res; -} +/* 7zExtract.c -- Extracting from 7z archive +2008-11-23 : Igor Pavlov : Public domain */ + +#include "7zCrc.h" +#include "7zDecode.h" +#include "7zExtract.h" + +SRes SzAr_Extract( + const CSzArEx *p, + ILookInStream *inStream, + UInt32 fileIndex, + UInt32 *blockIndex, + Byte **outBuffer, + size_t *outBufferSize, + size_t *offset, + size_t *outSizeProcessed, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; + SRes res = SZ_OK; + *offset = 0; + *outSizeProcessed = 0; + if (folderIndex == (UInt32)-1) + { + IAlloc_Free(allocMain, *outBuffer); + *blockIndex = folderIndex; + *outBuffer = 0; + *outBufferSize = 0; + return SZ_OK; + } + + if (*outBuffer == 0 || *blockIndex != folderIndex) + { + CSzFolder *folder = p->db.Folders + folderIndex; + UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); + size_t unpackSize = (size_t)unpackSizeSpec; + UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); + + if (unpackSize != unpackSizeSpec) + return SZ_ERROR_MEM; + *blockIndex = folderIndex; + IAlloc_Free(allocMain, *outBuffer); + *outBuffer = 0; + + RINOK(LookInStream_SeekTo(inStream, startOffset)); + + if (res == SZ_OK) + { + *outBufferSize = unpackSize; + if (unpackSize != 0) + { + *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); + if (*outBuffer == 0) + res = SZ_ERROR_MEM; + } + if (res == SZ_OK) + { + res = SzDecode(p->db.PackSizes + + p->FolderStartPackStreamIndex[folderIndex], folder, + inStream, startOffset, + *outBuffer, unpackSize, allocTemp); + if (res == SZ_OK) + { + if (folder->UnpackCRCDefined) + { + if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) + res = SZ_ERROR_CRC; + } + } + } + } + } + if (res == SZ_OK) + { + UInt32 i; + CSzFileItem *fileItem = p->db.Files + fileIndex; + *offset = 0; + for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) + *offset += (UInt32)p->db.Files[i].Size; + *outSizeProcessed = (size_t)fileItem->Size; + if (*offset + *outSizeProcessed > *outBufferSize) + return SZ_ERROR_FAIL; + { + if (fileItem->FileCRCDefined) + { + if (CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->FileCRC) + res = SZ_ERROR_CRC; + } + } + } + return res; +} diff --git a/fex/7z_C/7zExtract.h b/fex/7z_C/7zExtract.h index 4f956bee..1ca110c6 100644 --- a/fex/7z_C/7zExtract.h +++ b/fex/7z_C/7zExtract.h @@ -1,49 +1,49 @@ -/* 7zExtract.h -- Extracting from 7z archive -2008-11-23 : Igor Pavlov : Public domain */ - -#ifndef __7Z_EXTRACT_H -#define __7Z_EXTRACT_H - -#include "7zIn.h" - -#ifdef __cplusplus - extern "C" { -#endif - -/* - SzExtract extracts file from archive - - *outBuffer must be 0 before first call for each new archive. - - Extracting cache: - If you need to decompress more than one file, you can send - these values from previous call: - *blockIndex, - *outBuffer, - *outBufferSize - You can consider "*outBuffer" as cache of solid block. If your archive is solid, - it will increase decompression speed. - - If you use external function, you can declare these 3 cache variables - (blockIndex, outBuffer, outBufferSize) as static in that external function. - - Free *outBuffer and set *outBuffer to 0, if you want to flush cache. -*/ - -SRes SzAr_Extract( - const CSzArEx *db, - ILookInStream *inStream, - UInt32 fileIndex, /* index of file */ - UInt32 *blockIndex, /* index of solid block */ - Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ - size_t *outBufferSize, /* buffer size for output buffer */ - size_t *offset, /* offset of stream for required file in *outBuffer */ - size_t *outSizeProcessed, /* size of file in *outBuffer */ - ISzAlloc *allocMain, - ISzAlloc *allocTemp); - -#ifdef __cplusplus - } -#endif - -#endif +/* 7zExtract.h -- Extracting from 7z archive +2008-11-23 : Igor Pavlov : Public domain */ + +#ifndef __7Z_EXTRACT_H +#define __7Z_EXTRACT_H + +#include "7zIn.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* + SzExtract extracts file from archive + + *outBuffer must be 0 before first call for each new archive. + + Extracting cache: + If you need to decompress more than one file, you can send + these values from previous call: + *blockIndex, + *outBuffer, + *outBufferSize + You can consider "*outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + If you use external function, you can declare these 3 cache variables + (blockIndex, outBuffer, outBufferSize) as static in that external function. + + Free *outBuffer and set *outBuffer to 0, if you want to flush cache. +*/ + +SRes SzAr_Extract( + const CSzArEx *db, + ILookInStream *inStream, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAlloc *allocMain, + ISzAlloc *allocTemp); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/fex/7z_C/7zHeader.c b/fex/7z_C/7zHeader.c index c44ff4a4..e48faa48 100644 --- a/fex/7z_C/7zHeader.c +++ b/fex/7z_C/7zHeader.c @@ -1,6 +1,6 @@ -/* 7zHeader.c -- 7z Headers -2008-10-04 : Igor Pavlov : Public domain */ - -#include "7zHeader.h" - -Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; +/* 7zHeader.c -- 7z Headers +2008-10-04 : Igor Pavlov : Public domain */ + +#include "7zHeader.h" + +Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; diff --git a/fex/7z_C/7zHeader.h b/fex/7z_C/7zHeader.h index a8c85e8d..ad095df4 100644 --- a/fex/7z_C/7zHeader.h +++ b/fex/7z_C/7zHeader.h @@ -1,57 +1,57 @@ -/* 7zHeader.h -- 7z Headers -2008-10-04 : Igor Pavlov : Public domain */ - -#ifndef __7Z_HEADER_H -#define __7Z_HEADER_H - -#include "Types.h" - -#define k7zSignatureSize 6 -extern Byte k7zSignature[k7zSignatureSize]; - -#define k7zMajorVersion 0 - -#define k7zStartHeaderSize 0x20 - -enum EIdEnum -{ - k7zIdEnd, - - k7zIdHeader, - - k7zIdArchiveProperties, - - k7zIdAdditionalStreamsInfo, - k7zIdMainStreamsInfo, - k7zIdFilesInfo, - - k7zIdPackInfo, - k7zIdUnpackInfo, - k7zIdSubStreamsInfo, - - k7zIdSize, - k7zIdCRC, - - k7zIdFolder, - - k7zIdCodersUnpackSize, - k7zIdNumUnpackStream, - - k7zIdEmptyStream, - k7zIdEmptyFile, - k7zIdAnti, - - k7zIdName, - k7zIdCTime, - k7zIdATime, - k7zIdMTime, - k7zIdWinAttributes, - k7zIdComment, - - k7zIdEncodedHeader, - - k7zIdStartPos, - k7zIdDummy -}; - -#endif +/* 7zHeader.h -- 7z Headers +2008-10-04 : Igor Pavlov : Public domain */ + +#ifndef __7Z_HEADER_H +#define __7Z_HEADER_H + +#include "Types.h" + +#define k7zSignatureSize 6 +extern Byte k7zSignature[k7zSignatureSize]; + +#define k7zMajorVersion 0 + +#define k7zStartHeaderSize 0x20 + +enum EIdEnum +{ + k7zIdEnd, + + k7zIdHeader, + + k7zIdArchiveProperties, + + k7zIdAdditionalStreamsInfo, + k7zIdMainStreamsInfo, + k7zIdFilesInfo, + + k7zIdPackInfo, + k7zIdUnpackInfo, + k7zIdSubStreamsInfo, + + k7zIdSize, + k7zIdCRC, + + k7zIdFolder, + + k7zIdCodersUnpackSize, + k7zIdNumUnpackStream, + + k7zIdEmptyStream, + k7zIdEmptyFile, + k7zIdAnti, + + k7zIdName, + k7zIdCTime, + k7zIdATime, + k7zIdMTime, + k7zIdWinAttributes, + k7zIdComment, + + k7zIdEncodedHeader, + + k7zIdStartPos, + k7zIdDummy +}; + +#endif diff --git a/fex/7z_C/7zIn.c b/fex/7z_C/7zIn.c index f1a44928..ec93a43f 100644 --- a/fex/7z_C/7zIn.c +++ b/fex/7z_C/7zIn.c @@ -1,1402 +1,1402 @@ -/* 7zIn.c -- 7z Input functions -2010-10-29 : Igor Pavlov : Public domain */ - -#include - -#include "7z.h" -#include "7zCrc.h" -#include "CpuArch.h" - -Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; - -#define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; } - -#define NUM_FOLDER_CODERS_MAX 32 -#define NUM_CODER_STREAMS_MAX 32 - -void SzCoderInfo_Init(CSzCoderInfo *p) -{ - Buf_Init(&p->Props); -} - -void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc) -{ - Buf_Free(&p->Props, alloc); - SzCoderInfo_Init(p); -} - -void SzFolder_Init(CSzFolder *p) -{ - p->Coders = 0; - p->BindPairs = 0; - p->PackStreams = 0; - p->UnpackSizes = 0; - p->NumCoders = 0; - p->NumBindPairs = 0; - p->NumPackStreams = 0; - p->UnpackCRCDefined = 0; - p->UnpackCRC = 0; - p->NumUnpackStreams = 0; -} - -void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc) -{ - UInt32 i; - if (p->Coders) - for (i = 0; i < p->NumCoders; i++) - SzCoderInfo_Free(&p->Coders[i], alloc); - IAlloc_Free(alloc, p->Coders); - IAlloc_Free(alloc, p->BindPairs); - IAlloc_Free(alloc, p->PackStreams); - IAlloc_Free(alloc, p->UnpackSizes); - SzFolder_Init(p); -} - -UInt32 SzFolder_GetNumOutStreams(CSzFolder *p) -{ - UInt32 result = 0; - UInt32 i; - for (i = 0; i < p->NumCoders; i++) - result += p->Coders[i].NumOutStreams; - return result; -} - -int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex) -{ - UInt32 i; - for (i = 0; i < p->NumBindPairs; i++) - if (p->BindPairs[i].InIndex == inStreamIndex) - return i; - return -1; -} - - -int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex) -{ - UInt32 i; - for (i = 0; i < p->NumBindPairs; i++) - if (p->BindPairs[i].OutIndex == outStreamIndex) - return i; - return -1; -} - -UInt64 SzFolder_GetUnpackSize(CSzFolder *p) -{ - int i = (int)SzFolder_GetNumOutStreams(p); - if (i == 0) - return 0; - for (i--; i >= 0; i--) - if (SzFolder_FindBindPairForOutStream(p, i) < 0) - return p->UnpackSizes[i]; - /* throw 1; */ - return 0; -} - -void SzFile_Init(CSzFileItem *p) -{ - p->HasStream = 1; - p->IsDir = 0; - p->IsAnti = 0; - p->CrcDefined = 0; - p->MTimeDefined = 0; -} - -void SzAr_Init(CSzAr *p) -{ - p->PackSizes = 0; - p->PackCRCsDefined = 0; - p->PackCRCs = 0; - p->Folders = 0; - p->Files = 0; - p->NumPackStreams = 0; - p->NumFolders = 0; - p->NumFiles = 0; -} - -void SzAr_Free(CSzAr *p, ISzAlloc *alloc) -{ - UInt32 i; - if (p->Folders) - for (i = 0; i < p->NumFolders; i++) - SzFolder_Free(&p->Folders[i], alloc); - - IAlloc_Free(alloc, p->PackSizes); - IAlloc_Free(alloc, p->PackCRCsDefined); - IAlloc_Free(alloc, p->PackCRCs); - IAlloc_Free(alloc, p->Folders); - IAlloc_Free(alloc, p->Files); - SzAr_Init(p); -} - - -void SzArEx_Init(CSzArEx *p) -{ - SzAr_Init(&p->db); - p->FolderStartPackStreamIndex = 0; - p->PackStreamStartPositions = 0; - p->FolderStartFileIndex = 0; - p->FileIndexToFolderIndexMap = 0; - p->FileNameOffsets = 0; - Buf_Init(&p->FileNames); -} - -void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) -{ - IAlloc_Free(alloc, p->FolderStartPackStreamIndex); - IAlloc_Free(alloc, p->PackStreamStartPositions); - IAlloc_Free(alloc, p->FolderStartFileIndex); - IAlloc_Free(alloc, p->FileIndexToFolderIndexMap); - - IAlloc_Free(alloc, p->FileNameOffsets); - Buf_Free(&p->FileNames, alloc); - - SzAr_Free(&p->db, alloc); - SzArEx_Init(p); -} - -/* -UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const -{ - return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex]; -} - -UInt64 GetFilePackSize(int fileIndex) const -{ - int folderIndex = FileIndexToFolderIndexMap[fileIndex]; - if (folderIndex >= 0) - { - const CSzFolder &folderInfo = Folders[folderIndex]; - if (FolderStartFileIndex[folderIndex] == fileIndex) - return GetFolderFullPackSize(folderIndex); - } - return 0; -} -*/ - -#define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \ - if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; } - -static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc) -{ - UInt32 startPos = 0; - UInt64 startPosSize = 0; - UInt32 i; - UInt32 folderIndex = 0; - UInt32 indexInFolder = 0; - MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc); - for (i = 0; i < p->db.NumFolders; i++) - { - p->FolderStartPackStreamIndex[i] = startPos; - startPos += p->db.Folders[i].NumPackStreams; - } - - MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc); - - for (i = 0; i < p->db.NumPackStreams; i++) - { - p->PackStreamStartPositions[i] = startPosSize; - startPosSize += p->db.PackSizes[i]; - } - - MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc); - MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc); - - for (i = 0; i < p->db.NumFiles; i++) - { - CSzFileItem *file = p->db.Files + i; - int emptyStream = !file->HasStream; - if (emptyStream && indexInFolder == 0) - { - p->FileIndexToFolderIndexMap[i] = (UInt32)-1; - continue; - } - if (indexInFolder == 0) - { - /* - v3.13 incorrectly worked with empty folders - v4.07: Loop for skipping empty folders - */ - for (;;) - { - if (folderIndex >= p->db.NumFolders) - return SZ_ERROR_ARCHIVE; - p->FolderStartFileIndex[folderIndex] = i; - if (p->db.Folders[folderIndex].NumUnpackStreams != 0) - break; - folderIndex++; - } - } - p->FileIndexToFolderIndexMap[i] = folderIndex; - if (emptyStream) - continue; - indexInFolder++; - if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams) - { - folderIndex++; - indexInFolder = 0; - } - } - return SZ_OK; -} - - -UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder) -{ - return p->dataPos + - p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder]; -} - -int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize) -{ - UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex]; - CSzFolder *folder = p->db.Folders + folderIndex; - UInt64 size = 0; - UInt32 i; - for (i = 0; i < folder->NumPackStreams; i++) - { - UInt64 t = size + p->db.PackSizes[packStreamIndex + i]; - if (t < size) /* check it */ - return SZ_ERROR_FAIL; - size = t; - } - *resSize = size; - return SZ_OK; -} - - -/* -SRes SzReadTime(const CObjectVector &dataVector, - CObjectVector &files, UInt64 type) -{ - CBoolVector boolVector; - RINOK(ReadBoolVector2(files.Size(), boolVector)) - - CStreamSwitch streamSwitch; - RINOK(streamSwitch.Set(this, &dataVector)); - - for (int i = 0; i < files.Size(); i++) - { - CSzFileItem &file = files[i]; - CArchiveFileTime fileTime; - bool defined = boolVector[i]; - if (defined) - { - UInt32 low, high; - RINOK(SzReadUInt32(low)); - RINOK(SzReadUInt32(high)); - fileTime.dwLowDateTime = low; - fileTime.dwHighDateTime = high; - } - switch(type) - { - case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break; - case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break; - case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break; - } - } - return SZ_OK; -} -*/ - -static int TestSignatureCandidate(Byte *testBytes) -{ - size_t i; - for (i = 0; i < k7zSignatureSize; i++) - if (testBytes[i] != k7zSignature[i]) - return 0; - return 1; -} - -typedef struct _CSzState -{ - Byte *Data; - size_t Size; -}CSzData; - -static SRes SzReadByte(CSzData *sd, Byte *b) -{ - if (sd->Size == 0) - return SZ_ERROR_ARCHIVE; - sd->Size--; - *b = *sd->Data++; - return SZ_OK; -} - -static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size) -{ - size_t i; - for (i = 0; i < size; i++) - { - RINOK(SzReadByte(sd, data + i)); - } - return SZ_OK; -} - -static SRes SzReadUInt32(CSzData *sd, UInt32 *value) -{ - int i; - *value = 0; - for (i = 0; i < 4; i++) - { - Byte b; - RINOK(SzReadByte(sd, &b)); - *value |= ((UInt32)(b) << (8 * i)); - } - return SZ_OK; -} - -static SRes SzReadNumber(CSzData *sd, UInt64 *value) -{ - Byte firstByte; - Byte mask = 0x80; - int i; - RINOK(SzReadByte(sd, &firstByte)); - *value = 0; - for (i = 0; i < 8; i++) - { - Byte b; - if ((firstByte & mask) == 0) - { - UInt64 highPart = firstByte & (mask - 1); - *value += (highPart << (8 * i)); - return SZ_OK; - } - RINOK(SzReadByte(sd, &b)); - *value |= ((UInt64)b << (8 * i)); - mask >>= 1; - } - return SZ_OK; -} - -static SRes SzReadNumber32(CSzData *sd, UInt32 *value) -{ - UInt64 value64; - RINOK(SzReadNumber(sd, &value64)); - if (value64 >= 0x80000000) - return SZ_ERROR_UNSUPPORTED; - if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2))) - return SZ_ERROR_UNSUPPORTED; - *value = (UInt32)value64; - return SZ_OK; -} - -static SRes SzReadID(CSzData *sd, UInt64 *value) -{ - return SzReadNumber(sd, value); -} - -static SRes SzSkeepDataSize(CSzData *sd, UInt64 size) -{ - if (size > sd->Size) - return SZ_ERROR_ARCHIVE; - sd->Size -= (size_t)size; - sd->Data += (size_t)size; - return SZ_OK; -} - -static SRes SzSkeepData(CSzData *sd) -{ - UInt64 size; - RINOK(SzReadNumber(sd, &size)); - return SzSkeepDataSize(sd, size); -} - -static SRes SzReadArchiveProperties(CSzData *sd) -{ - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - break; - SzSkeepData(sd); - } - return SZ_OK; -} - -static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute) -{ - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == attribute) - return SZ_OK; - if (type == k7zIdEnd) - return SZ_ERROR_ARCHIVE; - RINOK(SzSkeepData(sd)); - } -} - -static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) -{ - Byte b = 0; - Byte mask = 0; - size_t i; - MY_ALLOC(Byte, *v, numItems, alloc); - for (i = 0; i < numItems; i++) - { - if (mask == 0) - { - RINOK(SzReadByte(sd, &b)); - mask = 0x80; - } - (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0); - mask >>= 1; - } - return SZ_OK; -} - -static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) -{ - Byte allAreDefined; - size_t i; - RINOK(SzReadByte(sd, &allAreDefined)); - if (allAreDefined == 0) - return SzReadBoolVector(sd, numItems, v, alloc); - MY_ALLOC(Byte, *v, numItems, alloc); - for (i = 0; i < numItems; i++) - (*v)[i] = 1; - return SZ_OK; -} - -static SRes SzReadHashDigests( - CSzData *sd, - size_t numItems, - Byte **digestsDefined, - UInt32 **digests, - ISzAlloc *alloc) -{ - size_t i; - RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc)); - MY_ALLOC(UInt32, *digests, numItems, alloc); - for (i = 0; i < numItems; i++) - if ((*digestsDefined)[i]) - { - RINOK(SzReadUInt32(sd, (*digests) + i)); - } - return SZ_OK; -} - -static SRes SzReadPackInfo( - CSzData *sd, - UInt64 *dataOffset, - UInt32 *numPackStreams, - UInt64 **packSizes, - Byte **packCRCsDefined, - UInt32 **packCRCs, - ISzAlloc *alloc) -{ - UInt32 i; - RINOK(SzReadNumber(sd, dataOffset)); - RINOK(SzReadNumber32(sd, numPackStreams)); - - RINOK(SzWaitAttribute(sd, k7zIdSize)); - - MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc); - - for (i = 0; i < *numPackStreams; i++) - { - RINOK(SzReadNumber(sd, (*packSizes) + i)); - } - - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - break; - if (type == k7zIdCRC) - { - RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc)); - continue; - } - RINOK(SzSkeepData(sd)); - } - if (*packCRCsDefined == 0) - { - MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc); - MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc); - for (i = 0; i < *numPackStreams; i++) - { - (*packCRCsDefined)[i] = 0; - (*packCRCs)[i] = 0; - } - } - return SZ_OK; -} - -static SRes SzReadSwitch(CSzData *sd) -{ - Byte external; - RINOK(SzReadByte(sd, &external)); - return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; -} - -static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc) -{ - UInt32 numCoders, numBindPairs, numPackStreams, i; - UInt32 numInStreams = 0, numOutStreams = 0; - - RINOK(SzReadNumber32(sd, &numCoders)); - if (numCoders > NUM_FOLDER_CODERS_MAX) - return SZ_ERROR_UNSUPPORTED; - folder->NumCoders = numCoders; - - MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc); - - for (i = 0; i < numCoders; i++) - SzCoderInfo_Init(folder->Coders + i); - - for (i = 0; i < numCoders; i++) - { - Byte mainByte; - CSzCoderInfo *coder = folder->Coders + i; - { - unsigned idSize, j; - Byte longID[15]; - RINOK(SzReadByte(sd, &mainByte)); - idSize = (unsigned)(mainByte & 0xF); - RINOK(SzReadBytes(sd, longID, idSize)); - if (idSize > sizeof(coder->MethodID)) - return SZ_ERROR_UNSUPPORTED; - coder->MethodID = 0; - for (j = 0; j < idSize; j++) - coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j); - - if ((mainByte & 0x10) != 0) - { - RINOK(SzReadNumber32(sd, &coder->NumInStreams)); - RINOK(SzReadNumber32(sd, &coder->NumOutStreams)); - if (coder->NumInStreams > NUM_CODER_STREAMS_MAX || - coder->NumOutStreams > NUM_CODER_STREAMS_MAX) - return SZ_ERROR_UNSUPPORTED; - } - else - { - coder->NumInStreams = 1; - coder->NumOutStreams = 1; - } - if ((mainByte & 0x20) != 0) - { - UInt64 propertiesSize = 0; - RINOK(SzReadNumber(sd, &propertiesSize)); - if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc)) - return SZ_ERROR_MEM; - RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize)); - } - } - while ((mainByte & 0x80) != 0) - { - RINOK(SzReadByte(sd, &mainByte)); - RINOK(SzSkeepDataSize(sd, (mainByte & 0xF))); - if ((mainByte & 0x10) != 0) - { - UInt32 n; - RINOK(SzReadNumber32(sd, &n)); - RINOK(SzReadNumber32(sd, &n)); - } - if ((mainByte & 0x20) != 0) - { - UInt64 propertiesSize = 0; - RINOK(SzReadNumber(sd, &propertiesSize)); - RINOK(SzSkeepDataSize(sd, propertiesSize)); - } - } - numInStreams += coder->NumInStreams; - numOutStreams += coder->NumOutStreams; - } - - if (numOutStreams == 0) - return SZ_ERROR_UNSUPPORTED; - - folder->NumBindPairs = numBindPairs = numOutStreams - 1; - MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc); - - for (i = 0; i < numBindPairs; i++) - { - CSzBindPair *bp = folder->BindPairs + i; - RINOK(SzReadNumber32(sd, &bp->InIndex)); - RINOK(SzReadNumber32(sd, &bp->OutIndex)); - } - - if (numInStreams < numBindPairs) - return SZ_ERROR_UNSUPPORTED; - - folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs; - MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc); - - if (numPackStreams == 1) - { - for (i = 0; i < numInStreams ; i++) - if (SzFolder_FindBindPairForInStream(folder, i) < 0) - break; - if (i == numInStreams) - return SZ_ERROR_UNSUPPORTED; - folder->PackStreams[0] = i; - } - else - for (i = 0; i < numPackStreams; i++) - { - RINOK(SzReadNumber32(sd, folder->PackStreams + i)); - } - return SZ_OK; -} - -static SRes SzReadUnpackInfo( - CSzData *sd, - UInt32 *numFolders, - CSzFolder **folders, /* for alloc */ - ISzAlloc *alloc, - ISzAlloc *allocTemp) -{ - UInt32 i; - RINOK(SzWaitAttribute(sd, k7zIdFolder)); - RINOK(SzReadNumber32(sd, numFolders)); - { - RINOK(SzReadSwitch(sd)); - - MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc); - - for (i = 0; i < *numFolders; i++) - SzFolder_Init((*folders) + i); - - for (i = 0; i < *numFolders; i++) - { - RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc)); - } - } - - RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize)); - - for (i = 0; i < *numFolders; i++) - { - UInt32 j; - CSzFolder *folder = (*folders) + i; - UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder); - - MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc); - - for (j = 0; j < numOutStreams; j++) - { - RINOK(SzReadNumber(sd, folder->UnpackSizes + j)); - } - } - - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - return SZ_OK; - if (type == k7zIdCRC) - { - SRes res; - Byte *crcsDefined = 0; - UInt32 *crcs = 0; - res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp); - if (res == SZ_OK) - { - for (i = 0; i < *numFolders; i++) - { - CSzFolder *folder = (*folders) + i; - folder->UnpackCRCDefined = crcsDefined[i]; - folder->UnpackCRC = crcs[i]; - } - } - IAlloc_Free(allocTemp, crcs); - IAlloc_Free(allocTemp, crcsDefined); - RINOK(res); - continue; - } - RINOK(SzSkeepData(sd)); - } -} - -static SRes SzReadSubStreamsInfo( - CSzData *sd, - UInt32 numFolders, - CSzFolder *folders, - UInt32 *numUnpackStreams, - UInt64 **unpackSizes, - Byte **digestsDefined, - UInt32 **digests, - ISzAlloc *allocTemp) -{ - UInt64 type = 0; - UInt32 i; - UInt32 si = 0; - UInt32 numDigests = 0; - - for (i = 0; i < numFolders; i++) - folders[i].NumUnpackStreams = 1; - *numUnpackStreams = numFolders; - - for (;;) - { - RINOK(SzReadID(sd, &type)); - if (type == k7zIdNumUnpackStream) - { - *numUnpackStreams = 0; - for (i = 0; i < numFolders; i++) - { - UInt32 numStreams; - RINOK(SzReadNumber32(sd, &numStreams)); - folders[i].NumUnpackStreams = numStreams; - *numUnpackStreams += numStreams; - } - continue; - } - if (type == k7zIdCRC || type == k7zIdSize) - break; - if (type == k7zIdEnd) - break; - RINOK(SzSkeepData(sd)); - } - - if (*numUnpackStreams == 0) - { - *unpackSizes = 0; - *digestsDefined = 0; - *digests = 0; - } - else - { - *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64)); - RINOM(*unpackSizes); - *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte)); - RINOM(*digestsDefined); - *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32)); - RINOM(*digests); - } - - for (i = 0; i < numFolders; i++) - { - /* - v3.13 incorrectly worked with empty folders - v4.07: we check that folder is empty - */ - UInt64 sum = 0; - UInt32 j; - UInt32 numSubstreams = folders[i].NumUnpackStreams; - if (numSubstreams == 0) - continue; - if (type == k7zIdSize) - for (j = 1; j < numSubstreams; j++) - { - UInt64 size; - RINOK(SzReadNumber(sd, &size)); - (*unpackSizes)[si++] = size; - sum += size; - } - (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum; - } - if (type == k7zIdSize) - { - RINOK(SzReadID(sd, &type)); - } - - for (i = 0; i < *numUnpackStreams; i++) - { - (*digestsDefined)[i] = 0; - (*digests)[i] = 0; - } - - - for (i = 0; i < numFolders; i++) - { - UInt32 numSubstreams = folders[i].NumUnpackStreams; - if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) - numDigests += numSubstreams; - } - - - si = 0; - for (;;) - { - if (type == k7zIdCRC) - { - int digestIndex = 0; - Byte *digestsDefined2 = 0; - UInt32 *digests2 = 0; - SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp); - if (res == SZ_OK) - { - for (i = 0; i < numFolders; i++) - { - CSzFolder *folder = folders + i; - UInt32 numSubstreams = folder->NumUnpackStreams; - if (numSubstreams == 1 && folder->UnpackCRCDefined) - { - (*digestsDefined)[si] = 1; - (*digests)[si] = folder->UnpackCRC; - si++; - } - else - { - UInt32 j; - for (j = 0; j < numSubstreams; j++, digestIndex++) - { - (*digestsDefined)[si] = digestsDefined2[digestIndex]; - (*digests)[si] = digests2[digestIndex]; - si++; - } - } - } - } - IAlloc_Free(allocTemp, digestsDefined2); - IAlloc_Free(allocTemp, digests2); - RINOK(res); - } - else if (type == k7zIdEnd) - return SZ_OK; - else - { - RINOK(SzSkeepData(sd)); - } - RINOK(SzReadID(sd, &type)); - } -} - - -static SRes SzReadStreamsInfo( - CSzData *sd, - UInt64 *dataOffset, - CSzAr *p, - UInt32 *numUnpackStreams, - UInt64 **unpackSizes, /* allocTemp */ - Byte **digestsDefined, /* allocTemp */ - UInt32 **digests, /* allocTemp */ - ISzAlloc *alloc, - ISzAlloc *allocTemp) -{ - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if ((UInt64)(int)type != type) - return SZ_ERROR_UNSUPPORTED; - switch((int)type) - { - case k7zIdEnd: - return SZ_OK; - case k7zIdPackInfo: - { - RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams, - &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc)); - break; - } - case k7zIdUnpackInfo: - { - RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp)); - break; - } - case k7zIdSubStreamsInfo: - { - RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders, - numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp)); - break; - } - default: - return SZ_ERROR_UNSUPPORTED; - } - } -} - -size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) -{ - size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; - if (dest != 0) - { - size_t i; - const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2); - for (i = 0; i < len; i++) - dest[i] = GetUi16(src + i * 2); - } - return len; -} - -static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes) -{ - UInt32 i; - size_t pos = 0; - for (i = 0; i < numFiles; i++) - { - sizes[i] = pos; - for (;;) - { - if (pos >= size) - return SZ_ERROR_ARCHIVE; - if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0) - break; - pos++; - } - pos++; - } - sizes[i] = pos; - return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; -} - -static SRes SzReadHeader2( - CSzArEx *p, /* allocMain */ - CSzData *sd, - UInt64 **unpackSizes, /* allocTemp */ - Byte **digestsDefined, /* allocTemp */ - UInt32 **digests, /* allocTemp */ - Byte **emptyStreamVector, /* allocTemp */ - Byte **emptyFileVector, /* allocTemp */ - Byte **lwtVector, /* allocTemp */ - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - UInt64 type; - UInt32 numUnpackStreams = 0; - UInt32 numFiles = 0; - CSzFileItem *files = 0; - UInt32 numEmptyStreams = 0; - UInt32 i; - - RINOK(SzReadID(sd, &type)); - - if (type == k7zIdArchiveProperties) - { - RINOK(SzReadArchiveProperties(sd)); - RINOK(SzReadID(sd, &type)); - } - - - if (type == k7zIdMainStreamsInfo) - { - RINOK(SzReadStreamsInfo(sd, - &p->dataPos, - &p->db, - &numUnpackStreams, - unpackSizes, - digestsDefined, - digests, allocMain, allocTemp)); - p->dataPos += p->startPosAfterHeader; - RINOK(SzReadID(sd, &type)); - } - - if (type == k7zIdEnd) - return SZ_OK; - if (type != k7zIdFilesInfo) - return SZ_ERROR_ARCHIVE; - - RINOK(SzReadNumber32(sd, &numFiles)); - p->db.NumFiles = numFiles; - - MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain); - - p->db.Files = files; - for (i = 0; i < numFiles; i++) - SzFile_Init(files + i); - - for (;;) - { - UInt64 type; - UInt64 size; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - break; - RINOK(SzReadNumber(sd, &size)); - if (size > sd->Size) - return SZ_ERROR_ARCHIVE; - if ((UInt64)(int)type != type) - { - RINOK(SzSkeepDataSize(sd, size)); - } - else - switch((int)type) - { - case k7zIdName: - { - size_t namesSize; - RINOK(SzReadSwitch(sd)); - namesSize = (size_t)size - 1; - if ((namesSize & 1) != 0) - return SZ_ERROR_ARCHIVE; - if (!Buf_Create(&p->FileNames, namesSize, allocMain)) - return SZ_ERROR_MEM; - MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); - memcpy(p->FileNames.data, sd->Data, namesSize); - RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets)) - RINOK(SzSkeepDataSize(sd, namesSize)); - break; - } - case k7zIdEmptyStream: - { - RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp)); - numEmptyStreams = 0; - for (i = 0; i < numFiles; i++) - if ((*emptyStreamVector)[i]) - numEmptyStreams++; - break; - } - case k7zIdEmptyFile: - { - RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp)); - break; - } - case k7zIdWinAttributes: - { - RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); - RINOK(SzReadSwitch(sd)); - for (i = 0; i < numFiles; i++) - { - CSzFileItem *f = &files[i]; - Byte defined = (*lwtVector)[i]; - f->AttribDefined = defined; - f->Attrib = 0; - if (defined) - { - RINOK(SzReadUInt32(sd, &f->Attrib)); - } - } - IAlloc_Free(allocTemp, *lwtVector); - *lwtVector = NULL; - break; - } - case k7zIdMTime: - { - RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); - RINOK(SzReadSwitch(sd)); - for (i = 0; i < numFiles; i++) - { - CSzFileItem *f = &files[i]; - Byte defined = (*lwtVector)[i]; - f->MTimeDefined = defined; - f->MTime.Low = f->MTime.High = 0; - if (defined) - { - RINOK(SzReadUInt32(sd, &f->MTime.Low)); - RINOK(SzReadUInt32(sd, &f->MTime.High)); - } - } - IAlloc_Free(allocTemp, *lwtVector); - *lwtVector = NULL; - break; - } - default: - { - RINOK(SzSkeepDataSize(sd, size)); - } - } - } - - { - UInt32 emptyFileIndex = 0; - UInt32 sizeIndex = 0; - for (i = 0; i < numFiles; i++) - { - CSzFileItem *file = files + i; - file->IsAnti = 0; - if (*emptyStreamVector == 0) - file->HasStream = 1; - else - file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1); - if (file->HasStream) - { - file->IsDir = 0; - file->Size = (*unpackSizes)[sizeIndex]; - file->Crc = (*digests)[sizeIndex]; - file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex]; - sizeIndex++; - } - else - { - if (*emptyFileVector == 0) - file->IsDir = 1; - else - file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1); - emptyFileIndex++; - file->Size = 0; - file->Crc = 0; - file->CrcDefined = 0; - } - } - } - return SzArEx_Fill(p, allocMain); -} - -static SRes SzReadHeader( - CSzArEx *p, - CSzData *sd, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - UInt64 *unpackSizes = 0; - Byte *digestsDefined = 0; - UInt32 *digests = 0; - Byte *emptyStreamVector = 0; - Byte *emptyFileVector = 0; - Byte *lwtVector = 0; - SRes res = SzReadHeader2(p, sd, - &unpackSizes, &digestsDefined, &digests, - &emptyStreamVector, &emptyFileVector, &lwtVector, - allocMain, allocTemp); - IAlloc_Free(allocTemp, unpackSizes); - IAlloc_Free(allocTemp, digestsDefined); - IAlloc_Free(allocTemp, digests); - IAlloc_Free(allocTemp, emptyStreamVector); - IAlloc_Free(allocTemp, emptyFileVector); - IAlloc_Free(allocTemp, lwtVector); - return res; -} - -static SRes SzReadAndDecodePackedStreams2( - ILookInStream *inStream, - CSzData *sd, - CBuf *outBuffer, - UInt64 baseOffset, - CSzAr *p, - UInt64 **unpackSizes, - Byte **digestsDefined, - UInt32 **digests, - ISzAlloc *allocTemp) -{ - - UInt32 numUnpackStreams = 0; - UInt64 dataStartPos; - CSzFolder *folder; - UInt64 unpackSize; - SRes res; - - RINOK(SzReadStreamsInfo(sd, &dataStartPos, p, - &numUnpackStreams, unpackSizes, digestsDefined, digests, - allocTemp, allocTemp)); - - dataStartPos += baseOffset; - if (p->NumFolders != 1) - return SZ_ERROR_ARCHIVE; - - folder = p->Folders; - unpackSize = SzFolder_GetUnpackSize(folder); - - RINOK(LookInStream_SeekTo(inStream, dataStartPos)); - - if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp)) - return SZ_ERROR_MEM; - - res = SzFolder_Decode(folder, p->PackSizes, - inStream, dataStartPos, - outBuffer->data, (size_t)unpackSize, allocTemp); - RINOK(res); - if (folder->UnpackCRCDefined) - if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC) - return SZ_ERROR_CRC; - return SZ_OK; -} - -static SRes SzReadAndDecodePackedStreams( - ILookInStream *inStream, - CSzData *sd, - CBuf *outBuffer, - UInt64 baseOffset, - ISzAlloc *allocTemp) -{ - CSzAr p; - UInt64 *unpackSizes = 0; - Byte *digestsDefined = 0; - UInt32 *digests = 0; - SRes res; - SzAr_Init(&p); - res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset, - &p, &unpackSizes, &digestsDefined, &digests, - allocTemp); - SzAr_Free(&p, allocTemp); - IAlloc_Free(allocTemp, unpackSizes); - IAlloc_Free(allocTemp, digestsDefined); - IAlloc_Free(allocTemp, digests); - return res; -} - -static SRes SzArEx_Open2( - CSzArEx *p, - ILookInStream *inStream, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - Byte header[k7zStartHeaderSize]; - Int64 startArcPos; - UInt64 nextHeaderOffset, nextHeaderSize; - size_t nextHeaderSizeT; - UInt32 nextHeaderCRC; - CBuf buffer; - SRes res; - - startArcPos = 0; - RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); - - RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); - - if (!TestSignatureCandidate(header)) - return SZ_ERROR_NO_ARCHIVE; - if (header[6] != k7zMajorVersion) - return SZ_ERROR_UNSUPPORTED; - - nextHeaderOffset = GetUi64(header + 12); - nextHeaderSize = GetUi64(header + 20); - nextHeaderCRC = GetUi32(header + 28); - - p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; - - if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) - return SZ_ERROR_CRC; - - nextHeaderSizeT = (size_t)nextHeaderSize; - if (nextHeaderSizeT != nextHeaderSize) - return SZ_ERROR_MEM; - if (nextHeaderSizeT == 0) - return SZ_OK; - if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || - nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) - return SZ_ERROR_NO_ARCHIVE; - - { - Int64 pos = 0; - RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); - if ((UInt64)pos < startArcPos + nextHeaderOffset || - (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || - (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) - return SZ_ERROR_INPUT_EOF; - } - - RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); - - if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) - return SZ_ERROR_MEM; - - res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT); - if (res == SZ_OK) - { - res = SZ_ERROR_ARCHIVE; - if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC) - { - CSzData sd; - UInt64 type; - sd.Data = buffer.data; - sd.Size = buffer.size; - res = SzReadID(&sd, &type); - if (res == SZ_OK) - { - if (type == k7zIdEncodedHeader) - { - CBuf outBuffer; - Buf_Init(&outBuffer); - res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp); - if (res != SZ_OK) - Buf_Free(&outBuffer, allocTemp); - else - { - Buf_Free(&buffer, allocTemp); - buffer.data = outBuffer.data; - buffer.size = outBuffer.size; - sd.Data = buffer.data; - sd.Size = buffer.size; - res = SzReadID(&sd, &type); - } - } - } - if (res == SZ_OK) - { - if (type == k7zIdHeader) - res = SzReadHeader(p, &sd, allocMain, allocTemp); - else - res = SZ_ERROR_UNSUPPORTED; - } - } - } - Buf_Free(&buffer, allocTemp); - return res; -} - -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp) -{ - SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); - if (res != SZ_OK) - SzArEx_Free(p, allocMain); - return res; -} - -SRes SzArEx_Extract( - const CSzArEx *p, - ILookInStream *inStream, - UInt32 fileIndex, - UInt32 *blockIndex, - Byte **outBuffer, - size_t *outBufferSize, - size_t *offset, - size_t *outSizeProcessed, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; - SRes res = SZ_OK; - *offset = 0; - *outSizeProcessed = 0; - if (folderIndex == (UInt32)-1) - { - IAlloc_Free(allocMain, *outBuffer); - *blockIndex = folderIndex; - *outBuffer = 0; - *outBufferSize = 0; - return SZ_OK; - } - - if (*outBuffer == 0 || *blockIndex != folderIndex) - { - CSzFolder *folder = p->db.Folders + folderIndex; - UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); - size_t unpackSize = (size_t)unpackSizeSpec; - UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); - - if (unpackSize != unpackSizeSpec) - return SZ_ERROR_MEM; - *blockIndex = folderIndex; - IAlloc_Free(allocMain, *outBuffer); - *outBuffer = 0; - - RINOK(LookInStream_SeekTo(inStream, startOffset)); - - if (res == SZ_OK) - { - *outBufferSize = unpackSize; - if (unpackSize != 0) - { - *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); - if (*outBuffer == 0) - res = SZ_ERROR_MEM; - } - if (res == SZ_OK) - { - res = SzFolder_Decode(folder, - p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], - inStream, startOffset, - *outBuffer, unpackSize, allocTemp); - if (res == SZ_OK) - { - if (folder->UnpackCRCDefined) - { - if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) - res = SZ_ERROR_CRC; - } - } - } - } - } - if (res == SZ_OK) - { - UInt32 i; - CSzFileItem *fileItem = p->db.Files + fileIndex; - *offset = 0; - for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) - *offset += (UInt32)p->db.Files[i].Size; - *outSizeProcessed = (size_t)fileItem->Size; - if (*offset + *outSizeProcessed > *outBufferSize) - return SZ_ERROR_FAIL; - if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc) - res = SZ_ERROR_CRC; - } - return res; -} +/* 7zIn.c -- 7z Input functions +2010-10-29 : Igor Pavlov : Public domain */ + +#include + +#include "7z.h" +#include "7zCrc.h" +#include "CpuArch.h" + +Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; + +#define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; } + +#define NUM_FOLDER_CODERS_MAX 32 +#define NUM_CODER_STREAMS_MAX 32 + +void SzCoderInfo_Init(CSzCoderInfo *p) +{ + Buf_Init(&p->Props); +} + +void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc) +{ + Buf_Free(&p->Props, alloc); + SzCoderInfo_Init(p); +} + +void SzFolder_Init(CSzFolder *p) +{ + p->Coders = 0; + p->BindPairs = 0; + p->PackStreams = 0; + p->UnpackSizes = 0; + p->NumCoders = 0; + p->NumBindPairs = 0; + p->NumPackStreams = 0; + p->UnpackCRCDefined = 0; + p->UnpackCRC = 0; + p->NumUnpackStreams = 0; +} + +void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc) +{ + UInt32 i; + if (p->Coders) + for (i = 0; i < p->NumCoders; i++) + SzCoderInfo_Free(&p->Coders[i], alloc); + IAlloc_Free(alloc, p->Coders); + IAlloc_Free(alloc, p->BindPairs); + IAlloc_Free(alloc, p->PackStreams); + IAlloc_Free(alloc, p->UnpackSizes); + SzFolder_Init(p); +} + +UInt32 SzFolder_GetNumOutStreams(CSzFolder *p) +{ + UInt32 result = 0; + UInt32 i; + for (i = 0; i < p->NumCoders; i++) + result += p->Coders[i].NumOutStreams; + return result; +} + +int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex) +{ + UInt32 i; + for (i = 0; i < p->NumBindPairs; i++) + if (p->BindPairs[i].InIndex == inStreamIndex) + return i; + return -1; +} + + +int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex) +{ + UInt32 i; + for (i = 0; i < p->NumBindPairs; i++) + if (p->BindPairs[i].OutIndex == outStreamIndex) + return i; + return -1; +} + +UInt64 SzFolder_GetUnpackSize(CSzFolder *p) +{ + int i = (int)SzFolder_GetNumOutStreams(p); + if (i == 0) + return 0; + for (i--; i >= 0; i--) + if (SzFolder_FindBindPairForOutStream(p, i) < 0) + return p->UnpackSizes[i]; + /* throw 1; */ + return 0; +} + +void SzFile_Init(CSzFileItem *p) +{ + p->HasStream = 1; + p->IsDir = 0; + p->IsAnti = 0; + p->CrcDefined = 0; + p->MTimeDefined = 0; +} + +void SzAr_Init(CSzAr *p) +{ + p->PackSizes = 0; + p->PackCRCsDefined = 0; + p->PackCRCs = 0; + p->Folders = 0; + p->Files = 0; + p->NumPackStreams = 0; + p->NumFolders = 0; + p->NumFiles = 0; +} + +void SzAr_Free(CSzAr *p, ISzAlloc *alloc) +{ + UInt32 i; + if (p->Folders) + for (i = 0; i < p->NumFolders; i++) + SzFolder_Free(&p->Folders[i], alloc); + + IAlloc_Free(alloc, p->PackSizes); + IAlloc_Free(alloc, p->PackCRCsDefined); + IAlloc_Free(alloc, p->PackCRCs); + IAlloc_Free(alloc, p->Folders); + IAlloc_Free(alloc, p->Files); + SzAr_Init(p); +} + + +void SzArEx_Init(CSzArEx *p) +{ + SzAr_Init(&p->db); + p->FolderStartPackStreamIndex = 0; + p->PackStreamStartPositions = 0; + p->FolderStartFileIndex = 0; + p->FileIndexToFolderIndexMap = 0; + p->FileNameOffsets = 0; + Buf_Init(&p->FileNames); +} + +void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->FolderStartPackStreamIndex); + IAlloc_Free(alloc, p->PackStreamStartPositions); + IAlloc_Free(alloc, p->FolderStartFileIndex); + IAlloc_Free(alloc, p->FileIndexToFolderIndexMap); + + IAlloc_Free(alloc, p->FileNameOffsets); + Buf_Free(&p->FileNames, alloc); + + SzAr_Free(&p->db, alloc); + SzArEx_Init(p); +} + +/* +UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const +{ + return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex]; +} + +UInt64 GetFilePackSize(int fileIndex) const +{ + int folderIndex = FileIndexToFolderIndexMap[fileIndex]; + if (folderIndex >= 0) + { + const CSzFolder &folderInfo = Folders[folderIndex]; + if (FolderStartFileIndex[folderIndex] == fileIndex) + return GetFolderFullPackSize(folderIndex); + } + return 0; +} +*/ + +#define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \ + if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; } + +static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc) +{ + UInt32 startPos = 0; + UInt64 startPosSize = 0; + UInt32 i; + UInt32 folderIndex = 0; + UInt32 indexInFolder = 0; + MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc); + for (i = 0; i < p->db.NumFolders; i++) + { + p->FolderStartPackStreamIndex[i] = startPos; + startPos += p->db.Folders[i].NumPackStreams; + } + + MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc); + + for (i = 0; i < p->db.NumPackStreams; i++) + { + p->PackStreamStartPositions[i] = startPosSize; + startPosSize += p->db.PackSizes[i]; + } + + MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc); + MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc); + + for (i = 0; i < p->db.NumFiles; i++) + { + CSzFileItem *file = p->db.Files + i; + int emptyStream = !file->HasStream; + if (emptyStream && indexInFolder == 0) + { + p->FileIndexToFolderIndexMap[i] = (UInt32)-1; + continue; + } + if (indexInFolder == 0) + { + /* + v3.13 incorrectly worked with empty folders + v4.07: Loop for skipping empty folders + */ + for (;;) + { + if (folderIndex >= p->db.NumFolders) + return SZ_ERROR_ARCHIVE; + p->FolderStartFileIndex[folderIndex] = i; + if (p->db.Folders[folderIndex].NumUnpackStreams != 0) + break; + folderIndex++; + } + } + p->FileIndexToFolderIndexMap[i] = folderIndex; + if (emptyStream) + continue; + indexInFolder++; + if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams) + { + folderIndex++; + indexInFolder = 0; + } + } + return SZ_OK; +} + + +UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder) +{ + return p->dataPos + + p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder]; +} + +int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize) +{ + UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex]; + CSzFolder *folder = p->db.Folders + folderIndex; + UInt64 size = 0; + UInt32 i; + for (i = 0; i < folder->NumPackStreams; i++) + { + UInt64 t = size + p->db.PackSizes[packStreamIndex + i]; + if (t < size) /* check it */ + return SZ_ERROR_FAIL; + size = t; + } + *resSize = size; + return SZ_OK; +} + + +/* +SRes SzReadTime(const CObjectVector &dataVector, + CObjectVector &files, UInt64 type) +{ + CBoolVector boolVector; + RINOK(ReadBoolVector2(files.Size(), boolVector)) + + CStreamSwitch streamSwitch; + RINOK(streamSwitch.Set(this, &dataVector)); + + for (int i = 0; i < files.Size(); i++) + { + CSzFileItem &file = files[i]; + CArchiveFileTime fileTime; + bool defined = boolVector[i]; + if (defined) + { + UInt32 low, high; + RINOK(SzReadUInt32(low)); + RINOK(SzReadUInt32(high)); + fileTime.dwLowDateTime = low; + fileTime.dwHighDateTime = high; + } + switch(type) + { + case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break; + case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break; + case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break; + } + } + return SZ_OK; +} +*/ + +static int TestSignatureCandidate(Byte *testBytes) +{ + size_t i; + for (i = 0; i < k7zSignatureSize; i++) + if (testBytes[i] != k7zSignature[i]) + return 0; + return 1; +} + +typedef struct _CSzState +{ + Byte *Data; + size_t Size; +}CSzData; + +static SRes SzReadByte(CSzData *sd, Byte *b) +{ + if (sd->Size == 0) + return SZ_ERROR_ARCHIVE; + sd->Size--; + *b = *sd->Data++; + return SZ_OK; +} + +static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size) +{ + size_t i; + for (i = 0; i < size; i++) + { + RINOK(SzReadByte(sd, data + i)); + } + return SZ_OK; +} + +static SRes SzReadUInt32(CSzData *sd, UInt32 *value) +{ + int i; + *value = 0; + for (i = 0; i < 4; i++) + { + Byte b; + RINOK(SzReadByte(sd, &b)); + *value |= ((UInt32)(b) << (8 * i)); + } + return SZ_OK; +} + +static SRes SzReadNumber(CSzData *sd, UInt64 *value) +{ + Byte firstByte; + Byte mask = 0x80; + int i; + RINOK(SzReadByte(sd, &firstByte)); + *value = 0; + for (i = 0; i < 8; i++) + { + Byte b; + if ((firstByte & mask) == 0) + { + UInt64 highPart = firstByte & (mask - 1); + *value += (highPart << (8 * i)); + return SZ_OK; + } + RINOK(SzReadByte(sd, &b)); + *value |= ((UInt64)b << (8 * i)); + mask >>= 1; + } + return SZ_OK; +} + +static SRes SzReadNumber32(CSzData *sd, UInt32 *value) +{ + UInt64 value64; + RINOK(SzReadNumber(sd, &value64)); + if (value64 >= 0x80000000) + return SZ_ERROR_UNSUPPORTED; + if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2))) + return SZ_ERROR_UNSUPPORTED; + *value = (UInt32)value64; + return SZ_OK; +} + +static SRes SzReadID(CSzData *sd, UInt64 *value) +{ + return SzReadNumber(sd, value); +} + +static SRes SzSkeepDataSize(CSzData *sd, UInt64 size) +{ + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + sd->Size -= (size_t)size; + sd->Data += (size_t)size; + return SZ_OK; +} + +static SRes SzSkeepData(CSzData *sd) +{ + UInt64 size; + RINOK(SzReadNumber(sd, &size)); + return SzSkeepDataSize(sd, size); +} + +static SRes SzReadArchiveProperties(CSzData *sd) +{ + for (;;) + { + UInt64 type; + RINOK(SzReadID(sd, &type)); + if (type == k7zIdEnd) + break; + SzSkeepData(sd); + } + return SZ_OK; +} + +static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute) +{ + for (;;) + { + UInt64 type; + RINOK(SzReadID(sd, &type)); + if (type == attribute) + return SZ_OK; + if (type == k7zIdEnd) + return SZ_ERROR_ARCHIVE; + RINOK(SzSkeepData(sd)); + } +} + +static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) +{ + Byte b = 0; + Byte mask = 0; + size_t i; + MY_ALLOC(Byte, *v, numItems, alloc); + for (i = 0; i < numItems; i++) + { + if (mask == 0) + { + RINOK(SzReadByte(sd, &b)); + mask = 0x80; + } + (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0); + mask >>= 1; + } + return SZ_OK; +} + +static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) +{ + Byte allAreDefined; + size_t i; + RINOK(SzReadByte(sd, &allAreDefined)); + if (allAreDefined == 0) + return SzReadBoolVector(sd, numItems, v, alloc); + MY_ALLOC(Byte, *v, numItems, alloc); + for (i = 0; i < numItems; i++) + (*v)[i] = 1; + return SZ_OK; +} + +static SRes SzReadHashDigests( + CSzData *sd, + size_t numItems, + Byte **digestsDefined, + UInt32 **digests, + ISzAlloc *alloc) +{ + size_t i; + RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc)); + MY_ALLOC(UInt32, *digests, numItems, alloc); + for (i = 0; i < numItems; i++) + if ((*digestsDefined)[i]) + { + RINOK(SzReadUInt32(sd, (*digests) + i)); + } + return SZ_OK; +} + +static SRes SzReadPackInfo( + CSzData *sd, + UInt64 *dataOffset, + UInt32 *numPackStreams, + UInt64 **packSizes, + Byte **packCRCsDefined, + UInt32 **packCRCs, + ISzAlloc *alloc) +{ + UInt32 i; + RINOK(SzReadNumber(sd, dataOffset)); + RINOK(SzReadNumber32(sd, numPackStreams)); + + RINOK(SzWaitAttribute(sd, k7zIdSize)); + + MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc); + + for (i = 0; i < *numPackStreams; i++) + { + RINOK(SzReadNumber(sd, (*packSizes) + i)); + } + + for (;;) + { + UInt64 type; + RINOK(SzReadID(sd, &type)); + if (type == k7zIdEnd) + break; + if (type == k7zIdCRC) + { + RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc)); + continue; + } + RINOK(SzSkeepData(sd)); + } + if (*packCRCsDefined == 0) + { + MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc); + MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc); + for (i = 0; i < *numPackStreams; i++) + { + (*packCRCsDefined)[i] = 0; + (*packCRCs)[i] = 0; + } + } + return SZ_OK; +} + +static SRes SzReadSwitch(CSzData *sd) +{ + Byte external; + RINOK(SzReadByte(sd, &external)); + return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; +} + +static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc) +{ + UInt32 numCoders, numBindPairs, numPackStreams, i; + UInt32 numInStreams = 0, numOutStreams = 0; + + RINOK(SzReadNumber32(sd, &numCoders)); + if (numCoders > NUM_FOLDER_CODERS_MAX) + return SZ_ERROR_UNSUPPORTED; + folder->NumCoders = numCoders; + + MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc); + + for (i = 0; i < numCoders; i++) + SzCoderInfo_Init(folder->Coders + i); + + for (i = 0; i < numCoders; i++) + { + Byte mainByte; + CSzCoderInfo *coder = folder->Coders + i; + { + unsigned idSize, j; + Byte longID[15]; + RINOK(SzReadByte(sd, &mainByte)); + idSize = (unsigned)(mainByte & 0xF); + RINOK(SzReadBytes(sd, longID, idSize)); + if (idSize > sizeof(coder->MethodID)) + return SZ_ERROR_UNSUPPORTED; + coder->MethodID = 0; + for (j = 0; j < idSize; j++) + coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j); + + if ((mainByte & 0x10) != 0) + { + RINOK(SzReadNumber32(sd, &coder->NumInStreams)); + RINOK(SzReadNumber32(sd, &coder->NumOutStreams)); + if (coder->NumInStreams > NUM_CODER_STREAMS_MAX || + coder->NumOutStreams > NUM_CODER_STREAMS_MAX) + return SZ_ERROR_UNSUPPORTED; + } + else + { + coder->NumInStreams = 1; + coder->NumOutStreams = 1; + } + if ((mainByte & 0x20) != 0) + { + UInt64 propertiesSize = 0; + RINOK(SzReadNumber(sd, &propertiesSize)); + if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc)) + return SZ_ERROR_MEM; + RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize)); + } + } + while ((mainByte & 0x80) != 0) + { + RINOK(SzReadByte(sd, &mainByte)); + RINOK(SzSkeepDataSize(sd, (mainByte & 0xF))); + if ((mainByte & 0x10) != 0) + { + UInt32 n; + RINOK(SzReadNumber32(sd, &n)); + RINOK(SzReadNumber32(sd, &n)); + } + if ((mainByte & 0x20) != 0) + { + UInt64 propertiesSize = 0; + RINOK(SzReadNumber(sd, &propertiesSize)); + RINOK(SzSkeepDataSize(sd, propertiesSize)); + } + } + numInStreams += coder->NumInStreams; + numOutStreams += coder->NumOutStreams; + } + + if (numOutStreams == 0) + return SZ_ERROR_UNSUPPORTED; + + folder->NumBindPairs = numBindPairs = numOutStreams - 1; + MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc); + + for (i = 0; i < numBindPairs; i++) + { + CSzBindPair *bp = folder->BindPairs + i; + RINOK(SzReadNumber32(sd, &bp->InIndex)); + RINOK(SzReadNumber32(sd, &bp->OutIndex)); + } + + if (numInStreams < numBindPairs) + return SZ_ERROR_UNSUPPORTED; + + folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs; + MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc); + + if (numPackStreams == 1) + { + for (i = 0; i < numInStreams ; i++) + if (SzFolder_FindBindPairForInStream(folder, i) < 0) + break; + if (i == numInStreams) + return SZ_ERROR_UNSUPPORTED; + folder->PackStreams[0] = i; + } + else + for (i = 0; i < numPackStreams; i++) + { + RINOK(SzReadNumber32(sd, folder->PackStreams + i)); + } + return SZ_OK; +} + +static SRes SzReadUnpackInfo( + CSzData *sd, + UInt32 *numFolders, + CSzFolder **folders, /* for alloc */ + ISzAlloc *alloc, + ISzAlloc *allocTemp) +{ + UInt32 i; + RINOK(SzWaitAttribute(sd, k7zIdFolder)); + RINOK(SzReadNumber32(sd, numFolders)); + { + RINOK(SzReadSwitch(sd)); + + MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc); + + for (i = 0; i < *numFolders; i++) + SzFolder_Init((*folders) + i); + + for (i = 0; i < *numFolders; i++) + { + RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc)); + } + } + + RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize)); + + for (i = 0; i < *numFolders; i++) + { + UInt32 j; + CSzFolder *folder = (*folders) + i; + UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder); + + MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc); + + for (j = 0; j < numOutStreams; j++) + { + RINOK(SzReadNumber(sd, folder->UnpackSizes + j)); + } + } + + for (;;) + { + UInt64 type; + RINOK(SzReadID(sd, &type)); + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + SRes res; + Byte *crcsDefined = 0; + UInt32 *crcs = 0; + res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp); + if (res == SZ_OK) + { + for (i = 0; i < *numFolders; i++) + { + CSzFolder *folder = (*folders) + i; + folder->UnpackCRCDefined = crcsDefined[i]; + folder->UnpackCRC = crcs[i]; + } + } + IAlloc_Free(allocTemp, crcs); + IAlloc_Free(allocTemp, crcsDefined); + RINOK(res); + continue; + } + RINOK(SzSkeepData(sd)); + } +} + +static SRes SzReadSubStreamsInfo( + CSzData *sd, + UInt32 numFolders, + CSzFolder *folders, + UInt32 *numUnpackStreams, + UInt64 **unpackSizes, + Byte **digestsDefined, + UInt32 **digests, + ISzAlloc *allocTemp) +{ + UInt64 type = 0; + UInt32 i; + UInt32 si = 0; + UInt32 numDigests = 0; + + for (i = 0; i < numFolders; i++) + folders[i].NumUnpackStreams = 1; + *numUnpackStreams = numFolders; + + for (;;) + { + RINOK(SzReadID(sd, &type)); + if (type == k7zIdNumUnpackStream) + { + *numUnpackStreams = 0; + for (i = 0; i < numFolders; i++) + { + UInt32 numStreams; + RINOK(SzReadNumber32(sd, &numStreams)); + folders[i].NumUnpackStreams = numStreams; + *numUnpackStreams += numStreams; + } + continue; + } + if (type == k7zIdCRC || type == k7zIdSize) + break; + if (type == k7zIdEnd) + break; + RINOK(SzSkeepData(sd)); + } + + if (*numUnpackStreams == 0) + { + *unpackSizes = 0; + *digestsDefined = 0; + *digests = 0; + } + else + { + *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64)); + RINOM(*unpackSizes); + *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte)); + RINOM(*digestsDefined); + *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32)); + RINOM(*digests); + } + + for (i = 0; i < numFolders; i++) + { + /* + v3.13 incorrectly worked with empty folders + v4.07: we check that folder is empty + */ + UInt64 sum = 0; + UInt32 j; + UInt32 numSubstreams = folders[i].NumUnpackStreams; + if (numSubstreams == 0) + continue; + if (type == k7zIdSize) + for (j = 1; j < numSubstreams; j++) + { + UInt64 size; + RINOK(SzReadNumber(sd, &size)); + (*unpackSizes)[si++] = size; + sum += size; + } + (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum; + } + if (type == k7zIdSize) + { + RINOK(SzReadID(sd, &type)); + } + + for (i = 0; i < *numUnpackStreams; i++) + { + (*digestsDefined)[i] = 0; + (*digests)[i] = 0; + } + + + for (i = 0; i < numFolders; i++) + { + UInt32 numSubstreams = folders[i].NumUnpackStreams; + if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) + numDigests += numSubstreams; + } + + + si = 0; + for (;;) + { + if (type == k7zIdCRC) + { + int digestIndex = 0; + Byte *digestsDefined2 = 0; + UInt32 *digests2 = 0; + SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp); + if (res == SZ_OK) + { + for (i = 0; i < numFolders; i++) + { + CSzFolder *folder = folders + i; + UInt32 numSubstreams = folder->NumUnpackStreams; + if (numSubstreams == 1 && folder->UnpackCRCDefined) + { + (*digestsDefined)[si] = 1; + (*digests)[si] = folder->UnpackCRC; + si++; + } + else + { + UInt32 j; + for (j = 0; j < numSubstreams; j++, digestIndex++) + { + (*digestsDefined)[si] = digestsDefined2[digestIndex]; + (*digests)[si] = digests2[digestIndex]; + si++; + } + } + } + } + IAlloc_Free(allocTemp, digestsDefined2); + IAlloc_Free(allocTemp, digests2); + RINOK(res); + } + else if (type == k7zIdEnd) + return SZ_OK; + else + { + RINOK(SzSkeepData(sd)); + } + RINOK(SzReadID(sd, &type)); + } +} + + +static SRes SzReadStreamsInfo( + CSzData *sd, + UInt64 *dataOffset, + CSzAr *p, + UInt32 *numUnpackStreams, + UInt64 **unpackSizes, /* allocTemp */ + Byte **digestsDefined, /* allocTemp */ + UInt32 **digests, /* allocTemp */ + ISzAlloc *alloc, + ISzAlloc *allocTemp) +{ + for (;;) + { + UInt64 type; + RINOK(SzReadID(sd, &type)); + if ((UInt64)(int)type != type) + return SZ_ERROR_UNSUPPORTED; + switch((int)type) + { + case k7zIdEnd: + return SZ_OK; + case k7zIdPackInfo: + { + RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams, + &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc)); + break; + } + case k7zIdUnpackInfo: + { + RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp)); + break; + } + case k7zIdSubStreamsInfo: + { + RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders, + numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp)); + break; + } + default: + return SZ_ERROR_UNSUPPORTED; + } + } +} + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + if (dest != 0) + { + size_t i; + const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2); + for (i = 0; i < len; i++) + dest[i] = GetUi16(src + i * 2); + } + return len; +} + +static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes) +{ + UInt32 i; + size_t pos = 0; + for (i = 0; i < numFiles; i++) + { + sizes[i] = pos; + for (;;) + { + if (pos >= size) + return SZ_ERROR_ARCHIVE; + if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0) + break; + pos++; + } + pos++; + } + sizes[i] = pos; + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static SRes SzReadHeader2( + CSzArEx *p, /* allocMain */ + CSzData *sd, + UInt64 **unpackSizes, /* allocTemp */ + Byte **digestsDefined, /* allocTemp */ + UInt32 **digests, /* allocTemp */ + Byte **emptyStreamVector, /* allocTemp */ + Byte **emptyFileVector, /* allocTemp */ + Byte **lwtVector, /* allocTemp */ + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt64 type; + UInt32 numUnpackStreams = 0; + UInt32 numFiles = 0; + CSzFileItem *files = 0; + UInt32 numEmptyStreams = 0; + UInt32 i; + + RINOK(SzReadID(sd, &type)); + + if (type == k7zIdArchiveProperties) + { + RINOK(SzReadArchiveProperties(sd)); + RINOK(SzReadID(sd, &type)); + } + + + if (type == k7zIdMainStreamsInfo) + { + RINOK(SzReadStreamsInfo(sd, + &p->dataPos, + &p->db, + &numUnpackStreams, + unpackSizes, + digestsDefined, + digests, allocMain, allocTemp)); + p->dataPos += p->startPosAfterHeader; + RINOK(SzReadID(sd, &type)); + } + + if (type == k7zIdEnd) + return SZ_OK; + if (type != k7zIdFilesInfo) + return SZ_ERROR_ARCHIVE; + + RINOK(SzReadNumber32(sd, &numFiles)); + p->db.NumFiles = numFiles; + + MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain); + + p->db.Files = files; + for (i = 0; i < numFiles; i++) + SzFile_Init(files + i); + + for (;;) + { + UInt64 type; + UInt64 size; + RINOK(SzReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(SzReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + if ((UInt64)(int)type != type) + { + RINOK(SzSkeepDataSize(sd, size)); + } + else + switch((int)type) + { + case k7zIdName: + { + size_t namesSize; + RINOK(SzReadSwitch(sd)); + namesSize = (size_t)size - 1; + if ((namesSize & 1) != 0) + return SZ_ERROR_ARCHIVE; + if (!Buf_Create(&p->FileNames, namesSize, allocMain)) + return SZ_ERROR_MEM; + MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); + memcpy(p->FileNames.data, sd->Data, namesSize); + RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets)) + RINOK(SzSkeepDataSize(sd, namesSize)); + break; + } + case k7zIdEmptyStream: + { + RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp)); + numEmptyStreams = 0; + for (i = 0; i < numFiles; i++) + if ((*emptyStreamVector)[i]) + numEmptyStreams++; + break; + } + case k7zIdEmptyFile: + { + RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp)); + break; + } + case k7zIdWinAttributes: + { + RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); + RINOK(SzReadSwitch(sd)); + for (i = 0; i < numFiles; i++) + { + CSzFileItem *f = &files[i]; + Byte defined = (*lwtVector)[i]; + f->AttribDefined = defined; + f->Attrib = 0; + if (defined) + { + RINOK(SzReadUInt32(sd, &f->Attrib)); + } + } + IAlloc_Free(allocTemp, *lwtVector); + *lwtVector = NULL; + break; + } + case k7zIdMTime: + { + RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); + RINOK(SzReadSwitch(sd)); + for (i = 0; i < numFiles; i++) + { + CSzFileItem *f = &files[i]; + Byte defined = (*lwtVector)[i]; + f->MTimeDefined = defined; + f->MTime.Low = f->MTime.High = 0; + if (defined) + { + RINOK(SzReadUInt32(sd, &f->MTime.Low)); + RINOK(SzReadUInt32(sd, &f->MTime.High)); + } + } + IAlloc_Free(allocTemp, *lwtVector); + *lwtVector = NULL; + break; + } + default: + { + RINOK(SzSkeepDataSize(sd, size)); + } + } + } + + { + UInt32 emptyFileIndex = 0; + UInt32 sizeIndex = 0; + for (i = 0; i < numFiles; i++) + { + CSzFileItem *file = files + i; + file->IsAnti = 0; + if (*emptyStreamVector == 0) + file->HasStream = 1; + else + file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1); + if (file->HasStream) + { + file->IsDir = 0; + file->Size = (*unpackSizes)[sizeIndex]; + file->Crc = (*digests)[sizeIndex]; + file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex]; + sizeIndex++; + } + else + { + if (*emptyFileVector == 0) + file->IsDir = 1; + else + file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1); + emptyFileIndex++; + file->Size = 0; + file->Crc = 0; + file->CrcDefined = 0; + } + } + } + return SzArEx_Fill(p, allocMain); +} + +static SRes SzReadHeader( + CSzArEx *p, + CSzData *sd, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt64 *unpackSizes = 0; + Byte *digestsDefined = 0; + UInt32 *digests = 0; + Byte *emptyStreamVector = 0; + Byte *emptyFileVector = 0; + Byte *lwtVector = 0; + SRes res = SzReadHeader2(p, sd, + &unpackSizes, &digestsDefined, &digests, + &emptyStreamVector, &emptyFileVector, &lwtVector, + allocMain, allocTemp); + IAlloc_Free(allocTemp, unpackSizes); + IAlloc_Free(allocTemp, digestsDefined); + IAlloc_Free(allocTemp, digests); + IAlloc_Free(allocTemp, emptyStreamVector); + IAlloc_Free(allocTemp, emptyFileVector); + IAlloc_Free(allocTemp, lwtVector); + return res; +} + +static SRes SzReadAndDecodePackedStreams2( + ILookInStream *inStream, + CSzData *sd, + CBuf *outBuffer, + UInt64 baseOffset, + CSzAr *p, + UInt64 **unpackSizes, + Byte **digestsDefined, + UInt32 **digests, + ISzAlloc *allocTemp) +{ + + UInt32 numUnpackStreams = 0; + UInt64 dataStartPos; + CSzFolder *folder; + UInt64 unpackSize; + SRes res; + + RINOK(SzReadStreamsInfo(sd, &dataStartPos, p, + &numUnpackStreams, unpackSizes, digestsDefined, digests, + allocTemp, allocTemp)); + + dataStartPos += baseOffset; + if (p->NumFolders != 1) + return SZ_ERROR_ARCHIVE; + + folder = p->Folders; + unpackSize = SzFolder_GetUnpackSize(folder); + + RINOK(LookInStream_SeekTo(inStream, dataStartPos)); + + if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp)) + return SZ_ERROR_MEM; + + res = SzFolder_Decode(folder, p->PackSizes, + inStream, dataStartPos, + outBuffer->data, (size_t)unpackSize, allocTemp); + RINOK(res); + if (folder->UnpackCRCDefined) + if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC) + return SZ_ERROR_CRC; + return SZ_OK; +} + +static SRes SzReadAndDecodePackedStreams( + ILookInStream *inStream, + CSzData *sd, + CBuf *outBuffer, + UInt64 baseOffset, + ISzAlloc *allocTemp) +{ + CSzAr p; + UInt64 *unpackSizes = 0; + Byte *digestsDefined = 0; + UInt32 *digests = 0; + SRes res; + SzAr_Init(&p); + res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset, + &p, &unpackSizes, &digestsDefined, &digests, + allocTemp); + SzAr_Free(&p, allocTemp); + IAlloc_Free(allocTemp, unpackSizes); + IAlloc_Free(allocTemp, digestsDefined); + IAlloc_Free(allocTemp, digests); + return res; +} + +static SRes SzArEx_Open2( + CSzArEx *p, + ILookInStream *inStream, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + Byte header[k7zStartHeaderSize]; + Int64 startArcPos; + UInt64 nextHeaderOffset, nextHeaderSize; + size_t nextHeaderSizeT; + UInt32 nextHeaderCRC; + CBuf buffer; + SRes res; + + startArcPos = 0; + RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); + + RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); + + if (!TestSignatureCandidate(header)) + return SZ_ERROR_NO_ARCHIVE; + if (header[6] != k7zMajorVersion) + return SZ_ERROR_UNSUPPORTED; + + nextHeaderOffset = GetUi64(header + 12); + nextHeaderSize = GetUi64(header + 20); + nextHeaderCRC = GetUi32(header + 28); + + p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; + + if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) + return SZ_ERROR_CRC; + + nextHeaderSizeT = (size_t)nextHeaderSize; + if (nextHeaderSizeT != nextHeaderSize) + return SZ_ERROR_MEM; + if (nextHeaderSizeT == 0) + return SZ_OK; + if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || + nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) + return SZ_ERROR_NO_ARCHIVE; + + { + Int64 pos = 0; + RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); + if ((UInt64)pos < startArcPos + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) + return SZ_ERROR_INPUT_EOF; + } + + RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); + + if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) + return SZ_ERROR_MEM; + + res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT); + if (res == SZ_OK) + { + res = SZ_ERROR_ARCHIVE; + if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC) + { + CSzData sd; + UInt64 type; + sd.Data = buffer.data; + sd.Size = buffer.size; + res = SzReadID(&sd, &type); + if (res == SZ_OK) + { + if (type == k7zIdEncodedHeader) + { + CBuf outBuffer; + Buf_Init(&outBuffer); + res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp); + if (res != SZ_OK) + Buf_Free(&outBuffer, allocTemp); + else + { + Buf_Free(&buffer, allocTemp); + buffer.data = outBuffer.data; + buffer.size = outBuffer.size; + sd.Data = buffer.data; + sd.Size = buffer.size; + res = SzReadID(&sd, &type); + } + } + } + if (res == SZ_OK) + { + if (type == k7zIdHeader) + res = SzReadHeader(p, &sd, allocMain, allocTemp); + else + res = SZ_ERROR_UNSUPPORTED; + } + } + } + Buf_Free(&buffer, allocTemp); + return res; +} + +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp) +{ + SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); + if (res != SZ_OK) + SzArEx_Free(p, allocMain); + return res; +} + +SRes SzArEx_Extract( + const CSzArEx *p, + ILookInStream *inStream, + UInt32 fileIndex, + UInt32 *blockIndex, + Byte **outBuffer, + size_t *outBufferSize, + size_t *offset, + size_t *outSizeProcessed, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; + SRes res = SZ_OK; + *offset = 0; + *outSizeProcessed = 0; + if (folderIndex == (UInt32)-1) + { + IAlloc_Free(allocMain, *outBuffer); + *blockIndex = folderIndex; + *outBuffer = 0; + *outBufferSize = 0; + return SZ_OK; + } + + if (*outBuffer == 0 || *blockIndex != folderIndex) + { + CSzFolder *folder = p->db.Folders + folderIndex; + UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); + size_t unpackSize = (size_t)unpackSizeSpec; + UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); + + if (unpackSize != unpackSizeSpec) + return SZ_ERROR_MEM; + *blockIndex = folderIndex; + IAlloc_Free(allocMain, *outBuffer); + *outBuffer = 0; + + RINOK(LookInStream_SeekTo(inStream, startOffset)); + + if (res == SZ_OK) + { + *outBufferSize = unpackSize; + if (unpackSize != 0) + { + *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); + if (*outBuffer == 0) + res = SZ_ERROR_MEM; + } + if (res == SZ_OK) + { + res = SzFolder_Decode(folder, + p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], + inStream, startOffset, + *outBuffer, unpackSize, allocTemp); + if (res == SZ_OK) + { + if (folder->UnpackCRCDefined) + { + if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) + res = SZ_ERROR_CRC; + } + } + } + } + } + if (res == SZ_OK) + { + UInt32 i; + CSzFileItem *fileItem = p->db.Files + fileIndex; + *offset = 0; + for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) + *offset += (UInt32)p->db.Files[i].Size; + *outSizeProcessed = (size_t)fileItem->Size; + if (*offset + *outSizeProcessed > *outBufferSize) + return SZ_ERROR_FAIL; + if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc) + res = SZ_ERROR_CRC; + } + return res; +} diff --git a/fex/7z_C/7zIn.h b/fex/7z_C/7zIn.h index 278a8450..89e0fb85 100644 --- a/fex/7z_C/7zIn.h +++ b/fex/7z_C/7zIn.h @@ -1,49 +1,49 @@ -/* 7zIn.h -- 7z Input functions -2008-11-23 : Igor Pavlov : Public domain */ - -#ifndef __7Z_IN_H -#define __7Z_IN_H - -#include "7zHeader.h" -#include "7zItem.h" - -#ifdef __cplusplus - extern "C" { -#endif - -typedef struct -{ - CSzAr db; - - UInt64 startPosAfterHeader; - UInt64 dataPos; - - UInt32 *FolderStartPackStreamIndex; - UInt64 *PackStreamStartPositions; - UInt32 *FolderStartFileIndex; - UInt32 *FileIndexToFolderIndexMap; -} CSzArEx; - -void SzArEx_Init(CSzArEx *p); -void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); -UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); -int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); - -/* -Errors: -SZ_ERROR_NO_ARCHIVE -SZ_ERROR_ARCHIVE -SZ_ERROR_UNSUPPORTED -SZ_ERROR_MEM -SZ_ERROR_CRC -SZ_ERROR_INPUT_EOF -SZ_ERROR_FAIL -*/ - -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp); - -#ifdef __cplusplus - } -#endif - -#endif +/* 7zIn.h -- 7z Input functions +2008-11-23 : Igor Pavlov : Public domain */ + +#ifndef __7Z_IN_H +#define __7Z_IN_H + +#include "7zHeader.h" +#include "7zItem.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct +{ + CSzAr db; + + UInt64 startPosAfterHeader; + UInt64 dataPos; + + UInt32 *FolderStartPackStreamIndex; + UInt64 *PackStreamStartPositions; + UInt32 *FolderStartFileIndex; + UInt32 *FileIndexToFolderIndexMap; +} CSzArEx; + +void SzArEx_Init(CSzArEx *p); +void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); +UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); +int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); + +/* +Errors: +SZ_ERROR_NO_ARCHIVE +SZ_ERROR_ARCHIVE +SZ_ERROR_UNSUPPORTED +SZ_ERROR_MEM +SZ_ERROR_CRC +SZ_ERROR_INPUT_EOF +SZ_ERROR_FAIL +*/ + +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/fex/7z_C/7zItem.c b/fex/7z_C/7zItem.c index ffe1cd77..4a092614 100644 --- a/fex/7z_C/7zItem.c +++ b/fex/7z_C/7zItem.c @@ -1,129 +1,129 @@ -/* 7zItem.c -- 7z Items -2008-10-04 : Igor Pavlov : Public domain */ - -#include "7zItem.h" - -void SzCoderInfo_Init(CSzCoderInfo *p) -{ - Buf_Init(&p->Props); -} - -void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc) -{ - Buf_Free(&p->Props, alloc); - SzCoderInfo_Init(p); -} - -void SzFolder_Init(CSzFolder *p) -{ - p->Coders = 0; - p->BindPairs = 0; - p->PackStreams = 0; - p->UnpackSizes = 0; - p->NumCoders = 0; - p->NumBindPairs = 0; - p->NumPackStreams = 0; - p->UnpackCRCDefined = 0; - p->UnpackCRC = 0; - p->NumUnpackStreams = 0; -} - -static -void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc) -{ - UInt32 i; - if (p->Coders) - for (i = 0; i < p->NumCoders; i++) - SzCoderInfo_Free(&p->Coders[i], alloc); - IAlloc_Free(alloc, p->Coders); - IAlloc_Free(alloc, p->BindPairs); - IAlloc_Free(alloc, p->PackStreams); - IAlloc_Free(alloc, p->UnpackSizes); - SzFolder_Init(p); -} - -UInt32 SzFolder_GetNumOutStreams(CSzFolder *p) -{ - UInt32 result = 0; - UInt32 i; - for (i = 0; i < p->NumCoders; i++) - result += p->Coders[i].NumOutStreams; - return result; -} - -int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex) -{ - UInt32 i; - for (i = 0; i < p->NumBindPairs; i++) - if (p->BindPairs[i].InIndex == inStreamIndex) - return i; - return -1; -} - - -static -int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex) -{ - UInt32 i; - for (i = 0; i < p->NumBindPairs; i++) - if (p->BindPairs[i].OutIndex == outStreamIndex) - return i; - return -1; -} - -UInt64 SzFolder_GetUnpackSize(CSzFolder *p) -{ - int i = (int)SzFolder_GetNumOutStreams(p); - if (i == 0) - return 0; - for (i--; i >= 0; i--) - if (SzFolder_FindBindPairForOutStream(p, i) < 0) - return p->UnpackSizes[i]; - /* throw 1; */ - return 0; -} - -void SzFile_Init(CSzFileItem *p) -{ - p->HasStream = 1; - p->IsDir = 0; - p->IsAnti = 0; - p->FileCRCDefined = 0; - p->MTimeDefined = 0; - p->Name = 0; -} - -static void SzFile_Free(CSzFileItem *p, ISzAlloc *alloc) -{ - IAlloc_Free(alloc, p->Name); - SzFile_Init(p); -} - -void SzAr_Init(CSzAr *p) -{ - p->PackSizes = 0; - p->PackCRCsDefined = 0; - p->PackCRCs = 0; - p->Folders = 0; - p->Files = 0; - p->NumPackStreams = 0; - p->NumFolders = 0; - p->NumFiles = 0; -} - -void SzAr_Free(CSzAr *p, ISzAlloc *alloc) -{ - UInt32 i; - if (p->Folders) - for (i = 0; i < p->NumFolders; i++) - SzFolder_Free(&p->Folders[i], alloc); - if (p->Files) - for (i = 0; i < p->NumFiles; i++) - SzFile_Free(&p->Files[i], alloc); - IAlloc_Free(alloc, p->PackSizes); - IAlloc_Free(alloc, p->PackCRCsDefined); - IAlloc_Free(alloc, p->PackCRCs); - IAlloc_Free(alloc, p->Folders); - IAlloc_Free(alloc, p->Files); - SzAr_Init(p); -} +/* 7zItem.c -- 7z Items +2008-10-04 : Igor Pavlov : Public domain */ + +#include "7zItem.h" + +void SzCoderInfo_Init(CSzCoderInfo *p) +{ + Buf_Init(&p->Props); +} + +void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc) +{ + Buf_Free(&p->Props, alloc); + SzCoderInfo_Init(p); +} + +void SzFolder_Init(CSzFolder *p) +{ + p->Coders = 0; + p->BindPairs = 0; + p->PackStreams = 0; + p->UnpackSizes = 0; + p->NumCoders = 0; + p->NumBindPairs = 0; + p->NumPackStreams = 0; + p->UnpackCRCDefined = 0; + p->UnpackCRC = 0; + p->NumUnpackStreams = 0; +} + +static +void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc) +{ + UInt32 i; + if (p->Coders) + for (i = 0; i < p->NumCoders; i++) + SzCoderInfo_Free(&p->Coders[i], alloc); + IAlloc_Free(alloc, p->Coders); + IAlloc_Free(alloc, p->BindPairs); + IAlloc_Free(alloc, p->PackStreams); + IAlloc_Free(alloc, p->UnpackSizes); + SzFolder_Init(p); +} + +UInt32 SzFolder_GetNumOutStreams(CSzFolder *p) +{ + UInt32 result = 0; + UInt32 i; + for (i = 0; i < p->NumCoders; i++) + result += p->Coders[i].NumOutStreams; + return result; +} + +int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex) +{ + UInt32 i; + for (i = 0; i < p->NumBindPairs; i++) + if (p->BindPairs[i].InIndex == inStreamIndex) + return i; + return -1; +} + + +static +int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex) +{ + UInt32 i; + for (i = 0; i < p->NumBindPairs; i++) + if (p->BindPairs[i].OutIndex == outStreamIndex) + return i; + return -1; +} + +UInt64 SzFolder_GetUnpackSize(CSzFolder *p) +{ + int i = (int)SzFolder_GetNumOutStreams(p); + if (i == 0) + return 0; + for (i--; i >= 0; i--) + if (SzFolder_FindBindPairForOutStream(p, i) < 0) + return p->UnpackSizes[i]; + /* throw 1; */ + return 0; +} + +void SzFile_Init(CSzFileItem *p) +{ + p->HasStream = 1; + p->IsDir = 0; + p->IsAnti = 0; + p->FileCRCDefined = 0; + p->MTimeDefined = 0; + p->Name = 0; +} + +static void SzFile_Free(CSzFileItem *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->Name); + SzFile_Init(p); +} + +void SzAr_Init(CSzAr *p) +{ + p->PackSizes = 0; + p->PackCRCsDefined = 0; + p->PackCRCs = 0; + p->Folders = 0; + p->Files = 0; + p->NumPackStreams = 0; + p->NumFolders = 0; + p->NumFiles = 0; +} + +void SzAr_Free(CSzAr *p, ISzAlloc *alloc) +{ + UInt32 i; + if (p->Folders) + for (i = 0; i < p->NumFolders; i++) + SzFolder_Free(&p->Folders[i], alloc); + if (p->Files) + for (i = 0; i < p->NumFiles; i++) + SzFile_Free(&p->Files[i], alloc); + IAlloc_Free(alloc, p->PackSizes); + IAlloc_Free(alloc, p->PackCRCsDefined); + IAlloc_Free(alloc, p->PackCRCs); + IAlloc_Free(alloc, p->Folders); + IAlloc_Free(alloc, p->Files); + SzAr_Init(p); +} diff --git a/fex/7z_C/7zItem.h b/fex/7z_C/7zItem.h index dbd21b81..7ef24731 100644 --- a/fex/7z_C/7zItem.h +++ b/fex/7z_C/7zItem.h @@ -1,83 +1,83 @@ -/* 7zItem.h -- 7z Items -2008-10-04 : Igor Pavlov : Public domain */ - -#ifndef __7Z_ITEM_H -#define __7Z_ITEM_H - -#include "7zBuf.h" - -typedef struct -{ - UInt32 NumInStreams; - UInt32 NumOutStreams; - UInt64 MethodID; - CBuf Props; -} CSzCoderInfo; - -void SzCoderInfo_Init(CSzCoderInfo *p); -void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc); - -typedef struct -{ - UInt32 InIndex; - UInt32 OutIndex; -} CBindPair; - -typedef struct -{ - CSzCoderInfo *Coders; - CBindPair *BindPairs; - UInt32 *PackStreams; - UInt64 *UnpackSizes; - UInt32 NumCoders; - UInt32 NumBindPairs; - UInt32 NumPackStreams; - int UnpackCRCDefined; - UInt32 UnpackCRC; - - UInt32 NumUnpackStreams; -} CSzFolder; - -void SzFolder_Init(CSzFolder *p); -UInt64 SzFolder_GetUnpackSize(CSzFolder *p); -int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex); -UInt32 SzFolder_GetNumOutStreams(CSzFolder *p); - -typedef struct -{ - UInt32 Low; - UInt32 High; -} CNtfsFileTime; - -typedef struct -{ - CNtfsFileTime MTime; - UInt64 Size; - char *Name; - UInt32 FileCRC; - - Byte HasStream; - Byte IsDir; - Byte IsAnti; - Byte FileCRCDefined; - Byte MTimeDefined; -} CSzFileItem; - -void SzFile_Init(CSzFileItem *p); - -typedef struct -{ - UInt64 *PackSizes; - Byte *PackCRCsDefined; - UInt32 *PackCRCs; - CSzFolder *Folders; - CSzFileItem *Files; - UInt32 NumPackStreams; - UInt32 NumFolders; - UInt32 NumFiles; -} CSzAr; - -void SzAr_Init(CSzAr *p); -void SzAr_Free(CSzAr *p, ISzAlloc *alloc); - -#endif +/* 7zItem.h -- 7z Items +2008-10-04 : Igor Pavlov : Public domain */ + +#ifndef __7Z_ITEM_H +#define __7Z_ITEM_H + +#include "7zBuf.h" + +typedef struct +{ + UInt32 NumInStreams; + UInt32 NumOutStreams; + UInt64 MethodID; + CBuf Props; +} CSzCoderInfo; + +void SzCoderInfo_Init(CSzCoderInfo *p); +void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc); + +typedef struct +{ + UInt32 InIndex; + UInt32 OutIndex; +} CBindPair; + +typedef struct +{ + CSzCoderInfo *Coders; + CBindPair *BindPairs; + UInt32 *PackStreams; + UInt64 *UnpackSizes; + UInt32 NumCoders; + UInt32 NumBindPairs; + UInt32 NumPackStreams; + int UnpackCRCDefined; + UInt32 UnpackCRC; + + UInt32 NumUnpackStreams; +} CSzFolder; + +void SzFolder_Init(CSzFolder *p); +UInt64 SzFolder_GetUnpackSize(CSzFolder *p); +int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex); +UInt32 SzFolder_GetNumOutStreams(CSzFolder *p); + +typedef struct +{ + UInt32 Low; + UInt32 High; +} CNtfsFileTime; + +typedef struct +{ + CNtfsFileTime MTime; + UInt64 Size; + char *Name; + UInt32 FileCRC; + + Byte HasStream; + Byte IsDir; + Byte IsAnti; + Byte FileCRCDefined; + Byte MTimeDefined; +} CSzFileItem; + +void SzFile_Init(CSzFileItem *p); + +typedef struct +{ + UInt64 *PackSizes; + Byte *PackCRCsDefined; + UInt32 *PackCRCs; + CSzFolder *Folders; + CSzFileItem *Files; + UInt32 NumPackStreams; + UInt32 NumFolders; + UInt32 NumFiles; +} CSzAr; + +void SzAr_Init(CSzAr *p); +void SzAr_Free(CSzAr *p, ISzAlloc *alloc); + +#endif diff --git a/fex/7z_C/7zStream.c b/fex/7z_C/7zStream.c index f0959fb0..0ebb7b5f 100644 --- a/fex/7z_C/7zStream.c +++ b/fex/7z_C/7zStream.c @@ -1,169 +1,169 @@ -/* 7zStream.c -- 7z Stream functions -2010-03-11 : Igor Pavlov : Public domain */ - -#include - -#include "Types.h" - -SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType) -{ - while (size != 0) - { - size_t processed = size; - RINOK(stream->Read(stream, buf, &processed)); - if (processed == 0) - return errorType; - buf = (void *)((Byte *)buf + processed); - size -= processed; - } - return SZ_OK; -} - -SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size) -{ - return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); -} - -SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf) -{ - size_t processed = 1; - RINOK(stream->Read(stream, buf, &processed)); - return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; -} - -SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset) -{ - Int64 t = offset; - return stream->Seek(stream, &t, SZ_SEEK_SET); -} - -SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size) -{ - const void *lookBuf; - if (*size == 0) - return SZ_OK; - RINOK(stream->Look(stream, &lookBuf, size)); - memcpy(buf, lookBuf, *size); - return stream->Skip(stream, *size); -} - -SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType) -{ - while (size != 0) - { - size_t processed = size; - RINOK(stream->Read(stream, buf, &processed)); - if (processed == 0) - return errorType; - buf = (void *)((Byte *)buf + processed); - size -= processed; - } - return SZ_OK; -} - -SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size) -{ - return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); -} - -static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size) -{ - SRes res = SZ_OK; - CLookToRead *p = (CLookToRead *)pp; - size_t size2 = p->size - p->pos; - if (size2 == 0 && *size > 0) - { - p->pos = 0; - size2 = LookToRead_BUF_SIZE; - res = p->realStream->Read(p->realStream, p->buf, &size2); - p->size = size2; - } - if (size2 < *size) - *size = size2; - *buf = p->buf + p->pos; - return res; -} - -static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size) -{ - SRes res = SZ_OK; - CLookToRead *p = (CLookToRead *)pp; - size_t size2 = p->size - p->pos; - if (size2 == 0 && *size > 0) - { - p->pos = 0; - if (*size > LookToRead_BUF_SIZE) - *size = LookToRead_BUF_SIZE; - res = p->realStream->Read(p->realStream, p->buf, size); - size2 = p->size = *size; - } - if (size2 < *size) - *size = size2; - *buf = p->buf + p->pos; - return res; -} - -static SRes LookToRead_Skip(void *pp, size_t offset) -{ - CLookToRead *p = (CLookToRead *)pp; - p->pos += offset; - return SZ_OK; -} - -static SRes LookToRead_Read(void *pp, void *buf, size_t *size) -{ - CLookToRead *p = (CLookToRead *)pp; - size_t rem = p->size - p->pos; - if (rem == 0) - return p->realStream->Read(p->realStream, buf, size); - if (rem > *size) - rem = *size; - memcpy(buf, p->buf + p->pos, rem); - p->pos += rem; - *size = rem; - return SZ_OK; -} - -static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin) -{ - CLookToRead *p = (CLookToRead *)pp; - p->pos = p->size = 0; - return p->realStream->Seek(p->realStream, pos, origin); -} - -void LookToRead_CreateVTable(CLookToRead *p, int lookahead) -{ - p->s.Look = lookahead ? - LookToRead_Look_Lookahead : - LookToRead_Look_Exact; - p->s.Skip = LookToRead_Skip; - p->s.Read = LookToRead_Read; - p->s.Seek = LookToRead_Seek; -} - -void LookToRead_Init(CLookToRead *p) -{ - p->pos = p->size = 0; -} - -static SRes SecToLook_Read(void *pp, void *buf, size_t *size) -{ - CSecToLook *p = (CSecToLook *)pp; - return LookInStream_LookRead(p->realStream, buf, size); -} - -void SecToLook_CreateVTable(CSecToLook *p) -{ - p->s.Read = SecToLook_Read; -} - -static SRes SecToRead_Read(void *pp, void *buf, size_t *size) -{ - CSecToRead *p = (CSecToRead *)pp; - return p->realStream->Read(p->realStream, buf, size); -} - -void SecToRead_CreateVTable(CSecToRead *p) -{ - p->s.Read = SecToRead_Read; -} +/* 7zStream.c -- 7z Stream functions +2010-03-11 : Igor Pavlov : Public domain */ + +#include + +#include "Types.h" + +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType) +{ + while (size != 0) + { + size_t processed = size; + RINOK(stream->Read(stream, buf, &processed)); + if (processed == 0) + return errorType; + buf = (void *)((Byte *)buf + processed); + size -= processed; + } + return SZ_OK; +} + +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size) +{ + return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); +} + +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf) +{ + size_t processed = 1; + RINOK(stream->Read(stream, buf, &processed)); + return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; +} + +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset) +{ + Int64 t = offset; + return stream->Seek(stream, &t, SZ_SEEK_SET); +} + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size) +{ + const void *lookBuf; + if (*size == 0) + return SZ_OK; + RINOK(stream->Look(stream, &lookBuf, size)); + memcpy(buf, lookBuf, *size); + return stream->Skip(stream, *size); +} + +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType) +{ + while (size != 0) + { + size_t processed = size; + RINOK(stream->Read(stream, buf, &processed)); + if (processed == 0) + return errorType; + buf = (void *)((Byte *)buf + processed); + size -= processed; + } + return SZ_OK; +} + +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size) +{ + return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); +} + +static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size) +{ + SRes res = SZ_OK; + CLookToRead *p = (CLookToRead *)pp; + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size > 0) + { + p->pos = 0; + size2 = LookToRead_BUF_SIZE; + res = p->realStream->Read(p->realStream, p->buf, &size2); + p->size = size2; + } + if (size2 < *size) + *size = size2; + *buf = p->buf + p->pos; + return res; +} + +static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size) +{ + SRes res = SZ_OK; + CLookToRead *p = (CLookToRead *)pp; + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size > 0) + { + p->pos = 0; + if (*size > LookToRead_BUF_SIZE) + *size = LookToRead_BUF_SIZE; + res = p->realStream->Read(p->realStream, p->buf, size); + size2 = p->size = *size; + } + if (size2 < *size) + *size = size2; + *buf = p->buf + p->pos; + return res; +} + +static SRes LookToRead_Skip(void *pp, size_t offset) +{ + CLookToRead *p = (CLookToRead *)pp; + p->pos += offset; + return SZ_OK; +} + +static SRes LookToRead_Read(void *pp, void *buf, size_t *size) +{ + CLookToRead *p = (CLookToRead *)pp; + size_t rem = p->size - p->pos; + if (rem == 0) + return p->realStream->Read(p->realStream, buf, size); + if (rem > *size) + rem = *size; + memcpy(buf, p->buf + p->pos, rem); + p->pos += rem; + *size = rem; + return SZ_OK; +} + +static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin) +{ + CLookToRead *p = (CLookToRead *)pp; + p->pos = p->size = 0; + return p->realStream->Seek(p->realStream, pos, origin); +} + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead) +{ + p->s.Look = lookahead ? + LookToRead_Look_Lookahead : + LookToRead_Look_Exact; + p->s.Skip = LookToRead_Skip; + p->s.Read = LookToRead_Read; + p->s.Seek = LookToRead_Seek; +} + +void LookToRead_Init(CLookToRead *p) +{ + p->pos = p->size = 0; +} + +static SRes SecToLook_Read(void *pp, void *buf, size_t *size) +{ + CSecToLook *p = (CSecToLook *)pp; + return LookInStream_LookRead(p->realStream, buf, size); +} + +void SecToLook_CreateVTable(CSecToLook *p) +{ + p->s.Read = SecToLook_Read; +} + +static SRes SecToRead_Read(void *pp, void *buf, size_t *size) +{ + CSecToRead *p = (CSecToRead *)pp; + return p->realStream->Read(p->realStream, buf, size); +} + +void SecToRead_CreateVTable(CSecToRead *p) +{ + p->s.Read = SecToRead_Read; +} diff --git a/fex/7z_C/Bcj2.c b/fex/7z_C/Bcj2.c index 474bdd45..20199ce5 100644 --- a/fex/7z_C/Bcj2.c +++ b/fex/7z_C/Bcj2.c @@ -1,132 +1,132 @@ -/* Bcj2.c -- Converter for x86 code (BCJ2) -2008-10-04 : Igor Pavlov : Public domain */ - -#include "Bcj2.h" - -#ifdef _LZMA_PROB32 -#define CProb UInt32 -#else -#define CProb UInt16 -#endif - -#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80) -#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)) - -#define kNumTopBits 24 -#define kTopValue ((UInt32)1 << kNumTopBits) - -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) -#define kNumMoveBits 5 - -#define RC_READ_BYTE (*buffer++) -#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; } -#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \ - { int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }} - -#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; } - -#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) -#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE; -#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE; - -int Bcj2_Decode( - const Byte *buf0, SizeT size0, - const Byte *buf1, SizeT size1, - const Byte *buf2, SizeT size2, - const Byte *buf3, SizeT size3, - Byte *outBuf, SizeT outSize) -{ - CProb p[256 + 2]; - SizeT inPos = 0, outPos = 0; - - const Byte *buffer, *bufferLim; - UInt32 range, code; - Byte prevByte = 0; - - unsigned int i; - for (i = 0; i < sizeof(p) / sizeof(p[0]); i++) - p[i] = kBitModelTotal >> 1; - - buffer = buf3; - bufferLim = buffer + size3; - RC_INIT2 - - if (outSize == 0) - return SZ_OK; - - for (;;) - { - Byte b; - CProb *prob; - UInt32 bound; - UInt32 ttt; - - SizeT limit = size0 - inPos; - if (outSize - outPos < limit) - limit = outSize - outPos; - while (limit != 0) - { - Byte b = buf0[inPos]; - outBuf[outPos++] = b; - if (IsJ(prevByte, b)) - break; - inPos++; - prevByte = b; - limit--; - } - - if (limit == 0 || outPos == outSize) - break; - - b = buf0[inPos++]; - - if (b == 0xE8) - prob = p + prevByte; - else if (b == 0xE9) - prob = p + 256; - else - prob = p + 257; - - IF_BIT_0(prob) - { - UPDATE_0(prob) - prevByte = b; - } - else - { - UInt32 dest; - const Byte *v; - UPDATE_1(prob) - if (b == 0xE8) - { - v = buf1; - if (size1 < 4) - return SZ_ERROR_DATA; - buf1 += 4; - size1 -= 4; - } - else - { - v = buf2; - if (size2 < 4) - return SZ_ERROR_DATA; - buf2 += 4; - size2 -= 4; - } - dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) | - ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4); - outBuf[outPos++] = (Byte)dest; - if (outPos == outSize) - break; - outBuf[outPos++] = (Byte)(dest >> 8); - if (outPos == outSize) - break; - outBuf[outPos++] = (Byte)(dest >> 16); - if (outPos == outSize) - break; - outBuf[outPos++] = prevByte = (Byte)(dest >> 24); - } - } - return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA; -} +/* Bcj2.c -- Converter for x86 code (BCJ2) +2008-10-04 : Igor Pavlov : Public domain */ + +#include "Bcj2.h" + +#ifdef _LZMA_PROB32 +#define CProb UInt32 +#else +#define CProb UInt16 +#endif + +#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80) +#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)) + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_READ_BYTE (*buffer++) +#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; } +#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \ + { int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }} + +#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; } + +#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE; +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE; + +int Bcj2_Decode( + const Byte *buf0, SizeT size0, + const Byte *buf1, SizeT size1, + const Byte *buf2, SizeT size2, + const Byte *buf3, SizeT size3, + Byte *outBuf, SizeT outSize) +{ + CProb p[256 + 2]; + SizeT inPos = 0, outPos = 0; + + const Byte *buffer, *bufferLim; + UInt32 range, code; + Byte prevByte = 0; + + unsigned int i; + for (i = 0; i < sizeof(p) / sizeof(p[0]); i++) + p[i] = kBitModelTotal >> 1; + + buffer = buf3; + bufferLim = buffer + size3; + RC_INIT2 + + if (outSize == 0) + return SZ_OK; + + for (;;) + { + Byte b; + CProb *prob; + UInt32 bound; + UInt32 ttt; + + SizeT limit = size0 - inPos; + if (outSize - outPos < limit) + limit = outSize - outPos; + while (limit != 0) + { + Byte b = buf0[inPos]; + outBuf[outPos++] = b; + if (IsJ(prevByte, b)) + break; + inPos++; + prevByte = b; + limit--; + } + + if (limit == 0 || outPos == outSize) + break; + + b = buf0[inPos++]; + + if (b == 0xE8) + prob = p + prevByte; + else if (b == 0xE9) + prob = p + 256; + else + prob = p + 257; + + IF_BIT_0(prob) + { + UPDATE_0(prob) + prevByte = b; + } + else + { + UInt32 dest; + const Byte *v; + UPDATE_1(prob) + if (b == 0xE8) + { + v = buf1; + if (size1 < 4) + return SZ_ERROR_DATA; + buf1 += 4; + size1 -= 4; + } + else + { + v = buf2; + if (size2 < 4) + return SZ_ERROR_DATA; + buf2 += 4; + size2 -= 4; + } + dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) | + ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4); + outBuf[outPos++] = (Byte)dest; + if (outPos == outSize) + break; + outBuf[outPos++] = (Byte)(dest >> 8); + if (outPos == outSize) + break; + outBuf[outPos++] = (Byte)(dest >> 16); + if (outPos == outSize) + break; + outBuf[outPos++] = prevByte = (Byte)(dest >> 24); + } + } + return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA; +} diff --git a/fex/7z_C/Bcj2.h b/fex/7z_C/Bcj2.h index d9d857bc..dbc05414 100644 --- a/fex/7z_C/Bcj2.h +++ b/fex/7z_C/Bcj2.h @@ -1,38 +1,38 @@ -/* Bcj2.h -- Converter for x86 code (BCJ2) -2009-02-07 : Igor Pavlov : Public domain */ - -#ifndef __BCJ2_H -#define __BCJ2_H - -#include "Types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* -Conditions: - outSize <= FullOutputSize, - where FullOutputSize is full size of output stream of x86_2 filter. - -If buf0 overlaps outBuf, there are two required conditions: - 1) (buf0 >= outBuf) - 2) (buf0 + size0 >= outBuf + FullOutputSize). - -Returns: - SZ_OK - SZ_ERROR_DATA - Data error -*/ - -int Bcj2_Decode( - const Byte *buf0, SizeT size0, - const Byte *buf1, SizeT size1, - const Byte *buf2, SizeT size2, - const Byte *buf3, SizeT size3, - Byte *outBuf, SizeT outSize); - -#ifdef __cplusplus -} -#endif - -#endif +/* Bcj2.h -- Converter for x86 code (BCJ2) +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __BCJ2_H +#define __BCJ2_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +Conditions: + outSize <= FullOutputSize, + where FullOutputSize is full size of output stream of x86_2 filter. + +If buf0 overlaps outBuf, there are two required conditions: + 1) (buf0 >= outBuf) + 2) (buf0 + size0 >= outBuf + FullOutputSize). + +Returns: + SZ_OK + SZ_ERROR_DATA - Data error +*/ + +int Bcj2_Decode( + const Byte *buf0, SizeT size0, + const Byte *buf1, SizeT size1, + const Byte *buf2, SizeT size2, + const Byte *buf3, SizeT size3, + Byte *outBuf, SizeT outSize); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/fex/7z_C/Bra.c b/fex/7z_C/Bra.c index 2a0f147b..2e47b141 100644 --- a/fex/7z_C/Bra.c +++ b/fex/7z_C/Bra.c @@ -1,133 +1,133 @@ -/* Bra.c -- Converters for RISC code -2010-04-16 : Igor Pavlov : Public domain */ - -#include "Bra.h" - -SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) -{ - SizeT i; - if (size < 4) - return 0; - size -= 4; - ip += 8; - for (i = 0; i <= size; i += 4) - { - if (data[i + 3] == 0xEB) - { - UInt32 dest; - UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]); - src <<= 2; - if (encoding) - dest = ip + (UInt32)i + src; - else - dest = src - (ip + (UInt32)i); - dest >>= 2; - data[i + 2] = (Byte)(dest >> 16); - data[i + 1] = (Byte)(dest >> 8); - data[i + 0] = (Byte)dest; - } - } - return i; -} - -SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) -{ - SizeT i; - if (size < 4) - return 0; - size -= 4; - ip += 4; - for (i = 0; i <= size; i += 2) - { - if ((data[i + 1] & 0xF8) == 0xF0 && - (data[i + 3] & 0xF8) == 0xF8) - { - UInt32 dest; - UInt32 src = - (((UInt32)data[i + 1] & 0x7) << 19) | - ((UInt32)data[i + 0] << 11) | - (((UInt32)data[i + 3] & 0x7) << 8) | - (data[i + 2]); - - src <<= 1; - if (encoding) - dest = ip + (UInt32)i + src; - else - dest = src - (ip + (UInt32)i); - dest >>= 1; - - data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7)); - data[i + 0] = (Byte)(dest >> 11); - data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7)); - data[i + 2] = (Byte)dest; - i += 2; - } - } - return i; -} - -SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) -{ - SizeT i; - if (size < 4) - return 0; - size -= 4; - for (i = 0; i <= size; i += 4) - { - if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1) - { - UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) | - ((UInt32)data[i + 1] << 16) | - ((UInt32)data[i + 2] << 8) | - ((UInt32)data[i + 3] & (~3)); - - UInt32 dest; - if (encoding) - dest = ip + (UInt32)i + src; - else - dest = src - (ip + (UInt32)i); - data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3)); - data[i + 1] = (Byte)(dest >> 16); - data[i + 2] = (Byte)(dest >> 8); - data[i + 3] &= 0x3; - data[i + 3] |= dest; - } - } - return i; -} - -SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) -{ - UInt32 i; - if (size < 4) - return 0; - size -= 4; - for (i = 0; i <= size; i += 4) - { - if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) || - (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)) - { - UInt32 src = - ((UInt32)data[i + 0] << 24) | - ((UInt32)data[i + 1] << 16) | - ((UInt32)data[i + 2] << 8) | - ((UInt32)data[i + 3]); - UInt32 dest; - - src <<= 2; - if (encoding) - dest = ip + i + src; - else - dest = src - (ip + i); - dest >>= 2; - - dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000; - - data[i + 0] = (Byte)(dest >> 24); - data[i + 1] = (Byte)(dest >> 16); - data[i + 2] = (Byte)(dest >> 8); - data[i + 3] = (Byte)dest; - } - } - return i; -} +/* Bra.c -- Converters for RISC code +2010-04-16 : Igor Pavlov : Public domain */ + +#include "Bra.h" + +SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 4) + return 0; + size -= 4; + ip += 8; + for (i = 0; i <= size; i += 4) + { + if (data[i + 3] == 0xEB) + { + UInt32 dest; + UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]); + src <<= 2; + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + dest >>= 2; + data[i + 2] = (Byte)(dest >> 16); + data[i + 1] = (Byte)(dest >> 8); + data[i + 0] = (Byte)dest; + } + } + return i; +} + +SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 4) + return 0; + size -= 4; + ip += 4; + for (i = 0; i <= size; i += 2) + { + if ((data[i + 1] & 0xF8) == 0xF0 && + (data[i + 3] & 0xF8) == 0xF8) + { + UInt32 dest; + UInt32 src = + (((UInt32)data[i + 1] & 0x7) << 19) | + ((UInt32)data[i + 0] << 11) | + (((UInt32)data[i + 3] & 0x7) << 8) | + (data[i + 2]); + + src <<= 1; + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + dest >>= 1; + + data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7)); + data[i + 0] = (Byte)(dest >> 11); + data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7)); + data[i + 2] = (Byte)dest; + i += 2; + } + } + return i; +} + +SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 4) + return 0; + size -= 4; + for (i = 0; i <= size; i += 4) + { + if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1) + { + UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) | + ((UInt32)data[i + 1] << 16) | + ((UInt32)data[i + 2] << 8) | + ((UInt32)data[i + 3] & (~3)); + + UInt32 dest; + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3)); + data[i + 1] = (Byte)(dest >> 16); + data[i + 2] = (Byte)(dest >> 8); + data[i + 3] &= 0x3; + data[i + 3] |= dest; + } + } + return i; +} + +SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + UInt32 i; + if (size < 4) + return 0; + size -= 4; + for (i = 0; i <= size; i += 4) + { + if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) || + (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)) + { + UInt32 src = + ((UInt32)data[i + 0] << 24) | + ((UInt32)data[i + 1] << 16) | + ((UInt32)data[i + 2] << 8) | + ((UInt32)data[i + 3]); + UInt32 dest; + + src <<= 2; + if (encoding) + dest = ip + i + src; + else + dest = src - (ip + i); + dest >>= 2; + + dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000; + + data[i + 0] = (Byte)(dest >> 24); + data[i + 1] = (Byte)(dest >> 16); + data[i + 2] = (Byte)(dest >> 8); + data[i + 3] = (Byte)dest; + } + } + return i; +} diff --git a/fex/7z_C/Bra.h b/fex/7z_C/Bra.h index 9c91e332..5748c1c0 100644 --- a/fex/7z_C/Bra.h +++ b/fex/7z_C/Bra.h @@ -1,68 +1,68 @@ -/* Bra.h -- Branch converters for executables -2009-02-07 : Igor Pavlov : Public domain */ - -#ifndef __BRA_H -#define __BRA_H - -#include "Types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* -These functions convert relative addresses to absolute addresses -in CALL instructions to increase the compression ratio. - - In: - data - data buffer - size - size of data - ip - current virtual Instruction Pinter (IP) value - state - state variable for x86 converter - encoding - 0 (for decoding), 1 (for encoding) - - Out: - state - state variable for x86 converter - - Returns: - The number of processed bytes. If you call these functions with multiple calls, - you must start next call with first byte after block of processed bytes. - - Type Endian Alignment LookAhead - - x86 little 1 4 - ARMT little 2 2 - ARM little 4 0 - PPC big 4 0 - SPARC big 4 0 - IA64 little 16 0 - - size must be >= Alignment + LookAhead, if it's not last block. - If (size < Alignment + LookAhead), converter returns 0. - - Example: - - UInt32 ip = 0; - for () - { - ; size must be >= Alignment + LookAhead, if it's not last block - SizeT processed = Convert(data, size, ip, 1); - data += processed; - size -= processed; - ip += processed; - } -*/ - -#define x86_Convert_Init(state) { state = 0; } -SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); -SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); - -#ifdef __cplusplus -} -#endif - -#endif +/* Bra.h -- Branch converters for executables +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __BRA_H +#define __BRA_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +These functions convert relative addresses to absolute addresses +in CALL instructions to increase the compression ratio. + + In: + data - data buffer + size - size of data + ip - current virtual Instruction Pinter (IP) value + state - state variable for x86 converter + encoding - 0 (for decoding), 1 (for encoding) + + Out: + state - state variable for x86 converter + + Returns: + The number of processed bytes. If you call these functions with multiple calls, + you must start next call with first byte after block of processed bytes. + + Type Endian Alignment LookAhead + + x86 little 1 4 + ARMT little 2 2 + ARM little 4 0 + PPC big 4 0 + SPARC big 4 0 + IA64 little 16 0 + + size must be >= Alignment + LookAhead, if it's not last block. + If (size < Alignment + LookAhead), converter returns 0. + + Example: + + UInt32 ip = 0; + for () + { + ; size must be >= Alignment + LookAhead, if it's not last block + SizeT processed = Convert(data, size, ip, 1); + data += processed; + size -= processed; + ip += processed; + } +*/ + +#define x86_Convert_Init(state) { state = 0; } +SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); +SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/fex/7z_C/Bra86.c b/fex/7z_C/Bra86.c index 93566cb2..1ee0e709 100644 --- a/fex/7z_C/Bra86.c +++ b/fex/7z_C/Bra86.c @@ -1,85 +1,85 @@ -/* Bra86.c -- Converter for x86 code (BCJ) -2008-10-04 : Igor Pavlov : Public domain */ - -#include "Bra.h" - -#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF) - -const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0}; -const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3}; - -SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) -{ - SizeT bufferPos = 0, prevPosT; - UInt32 prevMask = *state & 0x7; - if (size < 5) - return 0; - ip += 5; - prevPosT = (SizeT)0 - 1; - - for (;;) - { - Byte *p = data + bufferPos; - Byte *limit = data + size - 4; - for (; p < limit; p++) - if ((*p & 0xFE) == 0xE8) - break; - bufferPos = (SizeT)(p - data); - if (p >= limit) - break; - prevPosT = bufferPos - prevPosT; - if (prevPosT > 3) - prevMask = 0; - else - { - prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7; - if (prevMask != 0) - { - Byte b = p[4 - kMaskToBitNumber[prevMask]]; - if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b)) - { - prevPosT = bufferPos; - prevMask = ((prevMask << 1) & 0x7) | 1; - bufferPos++; - continue; - } - } - } - prevPosT = bufferPos; - - if (Test86MSByte(p[4])) - { - UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); - UInt32 dest; - for (;;) - { - Byte b; - int index; - if (encoding) - dest = (ip + (UInt32)bufferPos) + src; - else - dest = src - (ip + (UInt32)bufferPos); - if (prevMask == 0) - break; - index = kMaskToBitNumber[prevMask] * 8; - b = (Byte)(dest >> (24 - index)); - if (!Test86MSByte(b)) - break; - src = dest ^ ((1 << (32 - index)) - 1); - } - p[4] = (Byte)(~(((dest >> 24) & 1) - 1)); - p[3] = (Byte)(dest >> 16); - p[2] = (Byte)(dest >> 8); - p[1] = (Byte)dest; - bufferPos += 5; - } - else - { - prevMask = ((prevMask << 1) & 0x7) | 1; - bufferPos++; - } - } - prevPosT = bufferPos - prevPosT; - *state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7)); - return bufferPos; -} +/* Bra86.c -- Converter for x86 code (BCJ) +2008-10-04 : Igor Pavlov : Public domain */ + +#include "Bra.h" + +#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF) + +const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0}; +const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3}; + +SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) +{ + SizeT bufferPos = 0, prevPosT; + UInt32 prevMask = *state & 0x7; + if (size < 5) + return 0; + ip += 5; + prevPosT = (SizeT)0 - 1; + + for (;;) + { + Byte *p = data + bufferPos; + Byte *limit = data + size - 4; + for (; p < limit; p++) + if ((*p & 0xFE) == 0xE8) + break; + bufferPos = (SizeT)(p - data); + if (p >= limit) + break; + prevPosT = bufferPos - prevPosT; + if (prevPosT > 3) + prevMask = 0; + else + { + prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7; + if (prevMask != 0) + { + Byte b = p[4 - kMaskToBitNumber[prevMask]]; + if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b)) + { + prevPosT = bufferPos; + prevMask = ((prevMask << 1) & 0x7) | 1; + bufferPos++; + continue; + } + } + } + prevPosT = bufferPos; + + if (Test86MSByte(p[4])) + { + UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); + UInt32 dest; + for (;;) + { + Byte b; + int index; + if (encoding) + dest = (ip + (UInt32)bufferPos) + src; + else + dest = src - (ip + (UInt32)bufferPos); + if (prevMask == 0) + break; + index = kMaskToBitNumber[prevMask] * 8; + b = (Byte)(dest >> (24 - index)); + if (!Test86MSByte(b)) + break; + src = dest ^ ((1 << (32 - index)) - 1); + } + p[4] = (Byte)(~(((dest >> 24) & 1) - 1)); + p[3] = (Byte)(dest >> 16); + p[2] = (Byte)(dest >> 8); + p[1] = (Byte)dest; + bufferPos += 5; + } + else + { + prevMask = ((prevMask << 1) & 0x7) | 1; + bufferPos++; + } + } + prevPosT = bufferPos - prevPosT; + *state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7)); + return bufferPos; +} diff --git a/fex/7z_C/CpuArch.c b/fex/7z_C/CpuArch.c index a411dda0..e7d7ad2d 100644 --- a/fex/7z_C/CpuArch.c +++ b/fex/7z_C/CpuArch.c @@ -1,173 +1,173 @@ -/* CpuArch.c -- CPU specific code -2010-10-26: Igor Pavlov : Public domain */ - -#include "CpuArch.h" - -#ifdef MY_CPU_X86_OR_AMD64 - -#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) -#define USE_ASM -#endif - -#if defined(USE_ASM) && !defined(MY_CPU_AMD64) -static UInt32 CheckFlag(UInt32 flag) -{ - #ifdef _MSC_VER - __asm pushfd; - __asm pop EAX; - __asm mov EDX, EAX; - __asm xor EAX, flag; - __asm push EAX; - __asm popfd; - __asm pushfd; - __asm pop EAX; - __asm xor EAX, EDX; - __asm push EDX; - __asm popfd; - __asm and flag, EAX; - #else - __asm__ __volatile__ ( - "pushf\n\t" - "pop %%EAX\n\t" - "movl %%EAX,%%EDX\n\t" - "xorl %0,%%EAX\n\t" - "push %%EAX\n\t" - "popf\n\t" - "pushf\n\t" - "pop %%EAX\n\t" - "xorl %%EDX,%%EAX\n\t" - "push %%EDX\n\t" - "popf\n\t" - "andl %%EAX, %0\n\t": - "=c" (flag) : "c" (flag)); - #endif - return flag; -} -#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; -#else -#define CHECK_CPUID_IS_SUPPORTED -#endif - -static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) -{ - #ifdef USE_ASM - - #ifdef _MSC_VER - - UInt32 a2, b2, c2, d2; - __asm xor EBX, EBX; - __asm xor ECX, ECX; - __asm xor EDX, EDX; - __asm mov EAX, function; - __asm cpuid; - __asm mov a2, EAX; - __asm mov b2, EBX; - __asm mov c2, ECX; - __asm mov d2, EDX; - - *a = a2; - *b = b2; - *c = c2; - *d = d2; - - #else - - // Mac cross-compile compiler: - // can't find register in class 'BREG' while reloading 'asm' - // so use class 'r' and register var binding - register _b asm("%bx"); - __asm__ __volatile__ ( - "cpuid" - : "=a" (*a) , - "=r" (_b) , - "=c" (*c) , - "=d" (*d) - : "0" (function)) ; - *b = _b; - - #endif - - #else - - int CPUInfo[4]; - __cpuid(CPUInfo, function); - *a = CPUInfo[0]; - *b = CPUInfo[1]; - *c = CPUInfo[2]; - *d = CPUInfo[3]; - - #endif -} - -Bool x86cpuid_CheckAndRead(Cx86cpuid *p) -{ - CHECK_CPUID_IS_SUPPORTED - MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); - MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); - return True; -} - -static UInt32 kVendors[][3] = -{ - { 0x756E6547, 0x49656E69, 0x6C65746E}, - { 0x68747541, 0x69746E65, 0x444D4163}, - { 0x746E6543, 0x48727561, 0x736C7561} -}; - -int x86cpuid_GetFirm(const Cx86cpuid *p) -{ - unsigned i; - for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) - { - const UInt32 *v = kVendors[i]; - if (v[0] == p->vendor[0] && - v[1] == p->vendor[1] && - v[2] == p->vendor[2]) - return (int)i; - } - return -1; -} - -Bool CPU_Is_InOrder() -{ - Cx86cpuid p; - int firm; - UInt32 family, model; - if (!x86cpuid_CheckAndRead(&p)) - return True; - family = x86cpuid_GetFamily(&p); - model = x86cpuid_GetModel(&p); - firm = x86cpuid_GetFirm(&p); - switch (firm) - { - case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C)); - case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); - case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); - } - return True; -} - -#if !defined(MY_CPU_AMD64) && defined(_WIN32) -static Bool CPU_Sys_Is_SSE_Supported() -{ - OSVERSIONINFO vi; - vi.dwOSVersionInfoSize = sizeof(vi); - if (!GetVersionEx(&vi)) - return False; - return (vi.dwMajorVersion >= 5); -} -#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; -#else -#define CHECK_SYS_SSE_SUPPORT -#endif - -Bool CPU_Is_Aes_Supported() -{ - Cx86cpuid p; - CHECK_SYS_SSE_SUPPORT - if (!x86cpuid_CheckAndRead(&p)) - return False; - return (p.c >> 25) & 1; -} - -#endif +/* CpuArch.c -- CPU specific code +2010-10-26: Igor Pavlov : Public domain */ + +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 + +#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) +#define USE_ASM +#endif + +#if defined(USE_ASM) && !defined(MY_CPU_AMD64) +static UInt32 CheckFlag(UInt32 flag) +{ + #ifdef _MSC_VER + __asm pushfd; + __asm pop EAX; + __asm mov EDX, EAX; + __asm xor EAX, flag; + __asm push EAX; + __asm popfd; + __asm pushfd; + __asm pop EAX; + __asm xor EAX, EDX; + __asm push EDX; + __asm popfd; + __asm and flag, EAX; + #else + __asm__ __volatile__ ( + "pushf\n\t" + "pop %%EAX\n\t" + "movl %%EAX,%%EDX\n\t" + "xorl %0,%%EAX\n\t" + "push %%EAX\n\t" + "popf\n\t" + "pushf\n\t" + "pop %%EAX\n\t" + "xorl %%EDX,%%EAX\n\t" + "push %%EDX\n\t" + "popf\n\t" + "andl %%EAX, %0\n\t": + "=c" (flag) : "c" (flag)); + #endif + return flag; +} +#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; +#else +#define CHECK_CPUID_IS_SUPPORTED +#endif + +static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) +{ + #ifdef USE_ASM + + #ifdef _MSC_VER + + UInt32 a2, b2, c2, d2; + __asm xor EBX, EBX; + __asm xor ECX, ECX; + __asm xor EDX, EDX; + __asm mov EAX, function; + __asm cpuid; + __asm mov a2, EAX; + __asm mov b2, EBX; + __asm mov c2, ECX; + __asm mov d2, EDX; + + *a = a2; + *b = b2; + *c = c2; + *d = d2; + + #else + + // Mac cross-compile compiler: + // can't find register in class 'BREG' while reloading 'asm' + // so use class 'r' and register var binding + register _b asm("%bx"); + __asm__ __volatile__ ( + "cpuid" + : "=a" (*a) , + "=r" (_b) , + "=c" (*c) , + "=d" (*d) + : "0" (function)) ; + *b = _b; + + #endif + + #else + + int CPUInfo[4]; + __cpuid(CPUInfo, function); + *a = CPUInfo[0]; + *b = CPUInfo[1]; + *c = CPUInfo[2]; + *d = CPUInfo[3]; + + #endif +} + +Bool x86cpuid_CheckAndRead(Cx86cpuid *p) +{ + CHECK_CPUID_IS_SUPPORTED + MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); + MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); + return True; +} + +static UInt32 kVendors[][3] = +{ + { 0x756E6547, 0x49656E69, 0x6C65746E}, + { 0x68747541, 0x69746E65, 0x444D4163}, + { 0x746E6543, 0x48727561, 0x736C7561} +}; + +int x86cpuid_GetFirm(const Cx86cpuid *p) +{ + unsigned i; + for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) + { + const UInt32 *v = kVendors[i]; + if (v[0] == p->vendor[0] && + v[1] == p->vendor[1] && + v[2] == p->vendor[2]) + return (int)i; + } + return -1; +} + +Bool CPU_Is_InOrder() +{ + Cx86cpuid p; + int firm; + UInt32 family, model; + if (!x86cpuid_CheckAndRead(&p)) + return True; + family = x86cpuid_GetFamily(&p); + model = x86cpuid_GetModel(&p); + firm = x86cpuid_GetFirm(&p); + switch (firm) + { + case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C)); + case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); + case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); + } + return True; +} + +#if !defined(MY_CPU_AMD64) && defined(_WIN32) +static Bool CPU_Sys_Is_SSE_Supported() +{ + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (!GetVersionEx(&vi)) + return False; + return (vi.dwMajorVersion >= 5); +} +#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; +#else +#define CHECK_SYS_SSE_SUPPORT +#endif + +Bool CPU_Is_Aes_Supported() +{ + Cx86cpuid p; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_CheckAndRead(&p)) + return False; + return (p.c >> 25) & 1; +} + +#endif diff --git a/fex/7z_C/CpuArch.h b/fex/7z_C/CpuArch.h index 0a709bb2..01930c7e 100644 --- a/fex/7z_C/CpuArch.h +++ b/fex/7z_C/CpuArch.h @@ -1,155 +1,155 @@ -/* CpuArch.h -- CPU specific code -2010-10-26: Igor Pavlov : Public domain */ - -#ifndef __CPU_ARCH_H -#define __CPU_ARCH_H - -#include "Types.h" - -EXTERN_C_BEGIN - -/* -MY_CPU_LE means that CPU is LITTLE ENDIAN. -If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). - -MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. -If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. -*/ - -#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) -#define MY_CPU_AMD64 -#endif - -#if defined(MY_CPU_AMD64) || defined(_M_IA64) -#define MY_CPU_64BIT -#endif - -#if defined(_M_IX86) || defined(__i386__) -#define MY_CPU_X86 -#endif - -#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) -#define MY_CPU_X86_OR_AMD64 -#endif - -#if defined(MY_CPU_X86) || defined(_M_ARM) -#define MY_CPU_32BIT -#endif - -#if defined(_WIN32) && defined(_M_ARM) -#define MY_CPU_ARM_LE -#endif - -#if defined(_WIN32) && defined(_M_IA64) -#define MY_CPU_IA64_LE -#endif - -#if defined(MY_CPU_X86_OR_AMD64) -#define MY_CPU_LE_UNALIGN -#endif - -#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__) -#define MY_CPU_LE -#endif - -#if defined(__BIG_ENDIAN__) -#define MY_CPU_BE -#endif - -#if defined(MY_CPU_LE) && defined(MY_CPU_BE) -Stop_Compiling_Bad_Endian -#endif - -#ifdef MY_CPU_LE_UNALIGN - -#define GetUi16(p) (*(const UInt16 *)(p)) -#define GetUi32(p) (*(const UInt32 *)(p)) -#define GetUi64(p) (*(const UInt64 *)(p)) -#define SetUi16(p, d) *(UInt16 *)(p) = (d); -#define SetUi32(p, d) *(UInt32 *)(p) = (d); -#define SetUi64(p, d) *(UInt64 *)(p) = (d); - -#else - -#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) - -#define GetUi32(p) ( \ - ((const Byte *)(p))[0] | \ - ((UInt32)((const Byte *)(p))[1] << 8) | \ - ((UInt32)((const Byte *)(p))[2] << 16) | \ - ((UInt32)((const Byte *)(p))[3] << 24)) - -#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) - -#define SetUi16(p, d) { UInt32 _x_ = (d); \ - ((Byte *)(p))[0] = (Byte)_x_; \ - ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } - -#define SetUi32(p, d) { UInt32 _x_ = (d); \ - ((Byte *)(p))[0] = (Byte)_x_; \ - ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ - ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ - ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } - -#define SetUi64(p, d) { UInt64 _x64_ = (d); \ - SetUi32(p, (UInt32)_x64_); \ - SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); } - -#endif - -#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) - -#pragma intrinsic(_byteswap_ulong) -#pragma intrinsic(_byteswap_uint64) -#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) -#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) - -#else - -#define GetBe32(p) ( \ - ((UInt32)((const Byte *)(p))[0] << 24) | \ - ((UInt32)((const Byte *)(p))[1] << 16) | \ - ((UInt32)((const Byte *)(p))[2] << 8) | \ - ((const Byte *)(p))[3] ) - -#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) - -#endif - -#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1]) - - -#ifdef MY_CPU_X86_OR_AMD64 - -typedef struct -{ - UInt32 maxFunc; - UInt32 vendor[3]; - UInt32 ver; - UInt32 b; - UInt32 c; - UInt32 d; -} Cx86cpuid; - -enum -{ - CPU_FIRM_INTEL, - CPU_FIRM_AMD, - CPU_FIRM_VIA -}; - -Bool x86cpuid_CheckAndRead(Cx86cpuid *p); -int x86cpuid_GetFirm(const Cx86cpuid *p); - -#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F) -#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) -#define x86cpuid_GetStepping(p) ((p)->ver & 0xF) - -Bool CPU_Is_InOrder(); -Bool CPU_Is_Aes_Supported(); - -#endif - -EXTERN_C_END - -#endif +/* CpuArch.h -- CPU specific code +2010-10-26: Igor Pavlov : Public domain */ + +#ifndef __CPU_ARCH_H +#define __CPU_ARCH_H + +#include "Types.h" + +EXTERN_C_BEGIN + +/* +MY_CPU_LE means that CPU is LITTLE ENDIAN. +If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). + +MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. +If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. +*/ + +#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) +#define MY_CPU_AMD64 +#endif + +#if defined(MY_CPU_AMD64) || defined(_M_IA64) +#define MY_CPU_64BIT +#endif + +#if defined(_M_IX86) || defined(__i386__) +#define MY_CPU_X86 +#endif + +#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) +#define MY_CPU_X86_OR_AMD64 +#endif + +#if defined(MY_CPU_X86) || defined(_M_ARM) +#define MY_CPU_32BIT +#endif + +#if defined(_WIN32) && defined(_M_ARM) +#define MY_CPU_ARM_LE +#endif + +#if defined(_WIN32) && defined(_M_IA64) +#define MY_CPU_IA64_LE +#endif + +#if defined(MY_CPU_X86_OR_AMD64) +#define MY_CPU_LE_UNALIGN +#endif + +#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__) +#define MY_CPU_LE +#endif + +#if defined(__BIG_ENDIAN__) +#define MY_CPU_BE +#endif + +#if defined(MY_CPU_LE) && defined(MY_CPU_BE) +Stop_Compiling_Bad_Endian +#endif + +#ifdef MY_CPU_LE_UNALIGN + +#define GetUi16(p) (*(const UInt16 *)(p)) +#define GetUi32(p) (*(const UInt32 *)(p)) +#define GetUi64(p) (*(const UInt64 *)(p)) +#define SetUi16(p, d) *(UInt16 *)(p) = (d); +#define SetUi32(p, d) *(UInt32 *)(p) = (d); +#define SetUi64(p, d) *(UInt64 *)(p) = (d); + +#else + +#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) + +#define GetUi32(p) ( \ + ((const Byte *)(p))[0] | \ + ((UInt32)((const Byte *)(p))[1] << 8) | \ + ((UInt32)((const Byte *)(p))[2] << 16) | \ + ((UInt32)((const Byte *)(p))[3] << 24)) + +#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) + +#define SetUi16(p, d) { UInt32 _x_ = (d); \ + ((Byte *)(p))[0] = (Byte)_x_; \ + ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } + +#define SetUi32(p, d) { UInt32 _x_ = (d); \ + ((Byte *)(p))[0] = (Byte)_x_; \ + ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ + ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ + ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } + +#define SetUi64(p, d) { UInt64 _x64_ = (d); \ + SetUi32(p, (UInt32)_x64_); \ + SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); } + +#endif + +#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) + +#pragma intrinsic(_byteswap_ulong) +#pragma intrinsic(_byteswap_uint64) +#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) +#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) + +#else + +#define GetBe32(p) ( \ + ((UInt32)((const Byte *)(p))[0] << 24) | \ + ((UInt32)((const Byte *)(p))[1] << 16) | \ + ((UInt32)((const Byte *)(p))[2] << 8) | \ + ((const Byte *)(p))[3] ) + +#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) + +#endif + +#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1]) + + +#ifdef MY_CPU_X86_OR_AMD64 + +typedef struct +{ + UInt32 maxFunc; + UInt32 vendor[3]; + UInt32 ver; + UInt32 b; + UInt32 c; + UInt32 d; +} Cx86cpuid; + +enum +{ + CPU_FIRM_INTEL, + CPU_FIRM_AMD, + CPU_FIRM_VIA +}; + +Bool x86cpuid_CheckAndRead(Cx86cpuid *p); +int x86cpuid_GetFirm(const Cx86cpuid *p); + +#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F) +#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) +#define x86cpuid_GetStepping(p) ((p)->ver & 0xF) + +Bool CPU_Is_InOrder(); +Bool CPU_Is_Aes_Supported(); + +#endif + +EXTERN_C_END + +#endif diff --git a/fex/7z_C/Lzma2Dec.c b/fex/7z_C/Lzma2Dec.c index 838631d4..f38a5d48 100644 --- a/fex/7z_C/Lzma2Dec.c +++ b/fex/7z_C/Lzma2Dec.c @@ -1,371 +1,371 @@ -/* Lzma2Dec.c -- LZMA2 Decoder -2009-05-03 : Igor Pavlov : Public domain */ - -/* #define SHOW_DEBUG_INFO */ - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#include - -#include "Lzma2Dec.h" - -/* -00000000 - EOS -00000001 U U - Uncompressed Reset Dic -00000010 U U - Uncompressed No Reset -100uuuuu U U P P - LZMA no reset -101uuuuu U U P P - LZMA reset state -110uuuuu U U P P S - LZMA reset state + new prop -111uuuuu U U P P S - LZMA reset state + new prop + reset dic - - u, U - Unpack Size - P - Pack Size - S - Props -*/ - -#define LZMA2_CONTROL_LZMA (1 << 7) -#define LZMA2_CONTROL_COPY_NO_RESET 2 -#define LZMA2_CONTROL_COPY_RESET_DIC 1 -#define LZMA2_CONTROL_EOF 0 - -#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0) - -#define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3) -#define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2) - -#define LZMA2_LCLP_MAX 4 -#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) - -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif - -typedef enum -{ - LZMA2_STATE_CONTROL, - LZMA2_STATE_UNPACK0, - LZMA2_STATE_UNPACK1, - LZMA2_STATE_PACK0, - LZMA2_STATE_PACK1, - LZMA2_STATE_PROP, - LZMA2_STATE_DATA, - LZMA2_STATE_DATA_CONT, - LZMA2_STATE_FINISHED, - LZMA2_STATE_ERROR -} ELzma2State; - -static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) -{ - UInt32 dicSize; - if (prop > 40) - return SZ_ERROR_UNSUPPORTED; - dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); - props[0] = (Byte)LZMA2_LCLP_MAX; - props[1] = (Byte)(dicSize); - props[2] = (Byte)(dicSize >> 8); - props[3] = (Byte)(dicSize >> 16); - props[4] = (Byte)(dicSize >> 24); - return SZ_OK; -} - -SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) -{ - Byte props[LZMA_PROPS_SIZE]; - RINOK(Lzma2Dec_GetOldProps(prop, props)); - return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); -} - -SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) -{ - Byte props[LZMA_PROPS_SIZE]; - RINOK(Lzma2Dec_GetOldProps(prop, props)); - return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); -} - -void Lzma2Dec_Init(CLzma2Dec *p) -{ - p->state = LZMA2_STATE_CONTROL; - p->needInitDic = True; - p->needInitState = True; - p->needInitProp = True; - LzmaDec_Init(&p->decoder); -} - -static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) -{ - switch(p->state) - { - case LZMA2_STATE_CONTROL: - p->control = b; - PRF(printf("\n %4X ", p->decoder.dicPos)); - PRF(printf(" %2X", b)); - if (p->control == 0) - return LZMA2_STATE_FINISHED; - if (LZMA2_IS_UNCOMPRESSED_STATE(p)) - { - if ((p->control & 0x7F) > 2) - return LZMA2_STATE_ERROR; - p->unpackSize = 0; - } - else - p->unpackSize = (UInt32)(p->control & 0x1F) << 16; - return LZMA2_STATE_UNPACK0; - - case LZMA2_STATE_UNPACK0: - p->unpackSize |= (UInt32)b << 8; - return LZMA2_STATE_UNPACK1; - - case LZMA2_STATE_UNPACK1: - p->unpackSize |= (UInt32)b; - p->unpackSize++; - PRF(printf(" %8d", p->unpackSize)); - return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; - - case LZMA2_STATE_PACK0: - p->packSize = (UInt32)b << 8; - return LZMA2_STATE_PACK1; - - case LZMA2_STATE_PACK1: - p->packSize |= (UInt32)b; - p->packSize++; - PRF(printf(" %8d", p->packSize)); - return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: - (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); - - case LZMA2_STATE_PROP: - { - int lc, lp; - if (b >= (9 * 5 * 5)) - return LZMA2_STATE_ERROR; - lc = b % 9; - b /= 9; - p->decoder.prop.pb = b / 5; - lp = b % 5; - if (lc + lp > LZMA2_LCLP_MAX) - return LZMA2_STATE_ERROR; - p->decoder.prop.lc = lc; - p->decoder.prop.lp = lp; - p->needInitProp = False; - return LZMA2_STATE_DATA; - } - } - return LZMA2_STATE_ERROR; -} - -static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) -{ - memcpy(p->dic + p->dicPos, src, size); - p->dicPos += size; - if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) - p->checkDicSize = p->prop.dicSize; - p->processedPos += (UInt32)size; -} - -static -void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) -{ - p->needFlush = 1; - p->remainLen = 0; - p->tempBufSize = 0; - - if (initDic) - { - p->processedPos = 0; - p->checkDicSize = 0; - p->needInitState = 1; - } - if (initState) - p->needInitState = 1; -} - -SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) -{ - SizeT inSize = *srcLen; - *srcLen = 0; - *status = LZMA_STATUS_NOT_SPECIFIED; - - while (p->state != LZMA2_STATE_FINISHED) - { - SizeT dicPos = p->decoder.dicPos; - if (p->state == LZMA2_STATE_ERROR) - return SZ_ERROR_DATA; - if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_OK; - } - if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) - { - if (*srcLen == inSize) - { - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - (*srcLen)++; - p->state = Lzma2Dec_UpdateState(p, *src++); - continue; - } - { - SizeT destSizeCur = dicLimit - dicPos; - SizeT srcSizeCur = inSize - *srcLen; - ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; - - if (p->unpackSize <= destSizeCur) - { - destSizeCur = (SizeT)p->unpackSize; - curFinishMode = LZMA_FINISH_END; - } - - if (LZMA2_IS_UNCOMPRESSED_STATE(p)) - { - if (*srcLen == inSize) - { - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - - if (p->state == LZMA2_STATE_DATA) - { - Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); - if (initDic) - p->needInitProp = p->needInitState = True; - else if (p->needInitDic) - return SZ_ERROR_DATA; - p->needInitDic = False; - LzmaDec_InitDicAndState(&p->decoder, initDic, False); - } - - if (srcSizeCur > destSizeCur) - srcSizeCur = destSizeCur; - - if (srcSizeCur == 0) - return SZ_ERROR_DATA; - - LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); - - src += srcSizeCur; - *srcLen += srcSizeCur; - p->unpackSize -= (UInt32)srcSizeCur; - p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; - } - else - { - SizeT outSizeProcessed; - SRes res; - - if (p->state == LZMA2_STATE_DATA) - { - int mode = LZMA2_GET_LZMA_MODE(p); - Bool initDic = (mode == 3); - Bool initState = (mode > 0); - if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) - return SZ_ERROR_DATA; - - LzmaDec_InitDicAndState(&p->decoder, initDic, initState); - p->needInitDic = False; - p->needInitState = False; - p->state = LZMA2_STATE_DATA_CONT; - } - if (srcSizeCur > p->packSize) - srcSizeCur = (SizeT)p->packSize; - - res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status); - - src += srcSizeCur; - *srcLen += srcSizeCur; - p->packSize -= (UInt32)srcSizeCur; - - outSizeProcessed = p->decoder.dicPos - dicPos; - p->unpackSize -= (UInt32)outSizeProcessed; - - RINOK(res); - if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) - return res; - - if (srcSizeCur == 0 && outSizeProcessed == 0) - { - if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || - p->unpackSize != 0 || p->packSize != 0) - return SZ_ERROR_DATA; - p->state = LZMA2_STATE_CONTROL; - } - if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) - *status = LZMA_STATUS_NOT_FINISHED; - } - } - } - *status = LZMA_STATUS_FINISHED_WITH_MARK; - return SZ_OK; -} - -SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) -{ - SizeT outSize = *destLen, inSize = *srcLen; - *srcLen = *destLen = 0; - for (;;) - { - SizeT srcSizeCur = inSize, outSizeCur, dicPos; - ELzmaFinishMode curFinishMode; - SRes res; - if (p->decoder.dicPos == p->decoder.dicBufSize) - p->decoder.dicPos = 0; - dicPos = p->decoder.dicPos; - if (outSize > p->decoder.dicBufSize - dicPos) - { - outSizeCur = p->decoder.dicBufSize; - curFinishMode = LZMA_FINISH_ANY; - } - else - { - outSizeCur = dicPos + outSize; - curFinishMode = finishMode; - } - - res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status); - src += srcSizeCur; - inSize -= srcSizeCur; - *srcLen += srcSizeCur; - outSizeCur = p->decoder.dicPos - dicPos; - memcpy(dest, p->decoder.dic + dicPos, outSizeCur); - dest += outSizeCur; - outSize -= outSizeCur; - *destLen += outSizeCur; - if (res != 0) - return res; - if (outSizeCur == 0 || outSize == 0) - return SZ_OK; - } -} - -SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) -{ - CLzma2Dec decoder; - SRes res; - SizeT outSize = *destLen, inSize = *srcLen; - Byte props[LZMA_PROPS_SIZE]; - - Lzma2Dec_Construct(&decoder); - - *destLen = *srcLen = 0; - *status = LZMA_STATUS_NOT_SPECIFIED; - decoder.decoder.dic = dest; - decoder.decoder.dicBufSize = outSize; - - RINOK(Lzma2Dec_GetOldProps(prop, props)); - RINOK(LzmaDec_AllocateProbs(&decoder.decoder, props, LZMA_PROPS_SIZE, alloc)); - - *srcLen = inSize; - res = Lzma2Dec_DecodeToDic(&decoder, outSize, src, srcLen, finishMode, status); - *destLen = decoder.decoder.dicPos; - if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) - res = SZ_ERROR_INPUT_EOF; - - LzmaDec_FreeProbs(&decoder.decoder, alloc); - return res; -} +/* Lzma2Dec.c -- LZMA2 Decoder +2009-05-03 : Igor Pavlov : Public domain */ + +/* #define SHOW_DEBUG_INFO */ + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include + +#include "Lzma2Dec.h" + +/* +00000000 - EOS +00000001 U U - Uncompressed Reset Dic +00000010 U U - Uncompressed No Reset +100uuuuu U U P P - LZMA no reset +101uuuuu U U P P - LZMA reset state +110uuuuu U U P P S - LZMA reset state + new prop +111uuuuu U U P P S - LZMA reset state + new prop + reset dic + + u, U - Unpack Size + P - Pack Size + S - Props +*/ + +#define LZMA2_CONTROL_LZMA (1 << 7) +#define LZMA2_CONTROL_COPY_NO_RESET 2 +#define LZMA2_CONTROL_COPY_RESET_DIC 1 +#define LZMA2_CONTROL_EOF 0 + +#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0) + +#define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3) +#define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2) + +#define LZMA2_LCLP_MAX 4 +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +typedef enum +{ + LZMA2_STATE_CONTROL, + LZMA2_STATE_UNPACK0, + LZMA2_STATE_UNPACK1, + LZMA2_STATE_PACK0, + LZMA2_STATE_PACK1, + LZMA2_STATE_PROP, + LZMA2_STATE_DATA, + LZMA2_STATE_DATA_CONT, + LZMA2_STATE_FINISHED, + LZMA2_STATE_ERROR +} ELzma2State; + +static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) +{ + UInt32 dicSize; + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); + props[0] = (Byte)LZMA2_LCLP_MAX; + props[1] = (Byte)(dicSize); + props[2] = (Byte)(dicSize >> 8); + props[3] = (Byte)(dicSize >> 16); + props[4] = (Byte)(dicSize >> 24); + return SZ_OK; +} + +SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) +{ + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)); + return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); +} + +SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) +{ + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)); + return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); +} + +void Lzma2Dec_Init(CLzma2Dec *p) +{ + p->state = LZMA2_STATE_CONTROL; + p->needInitDic = True; + p->needInitState = True; + p->needInitProp = True; + LzmaDec_Init(&p->decoder); +} + +static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) +{ + switch(p->state) + { + case LZMA2_STATE_CONTROL: + p->control = b; + PRF(printf("\n %4X ", p->decoder.dicPos)); + PRF(printf(" %2X", b)); + if (p->control == 0) + return LZMA2_STATE_FINISHED; + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if ((p->control & 0x7F) > 2) + return LZMA2_STATE_ERROR; + p->unpackSize = 0; + } + else + p->unpackSize = (UInt32)(p->control & 0x1F) << 16; + return LZMA2_STATE_UNPACK0; + + case LZMA2_STATE_UNPACK0: + p->unpackSize |= (UInt32)b << 8; + return LZMA2_STATE_UNPACK1; + + case LZMA2_STATE_UNPACK1: + p->unpackSize |= (UInt32)b; + p->unpackSize++; + PRF(printf(" %8d", p->unpackSize)); + return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; + + case LZMA2_STATE_PACK0: + p->packSize = (UInt32)b << 8; + return LZMA2_STATE_PACK1; + + case LZMA2_STATE_PACK1: + p->packSize |= (UInt32)b; + p->packSize++; + PRF(printf(" %8d", p->packSize)); + return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: + (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); + + case LZMA2_STATE_PROP: + { + int lc, lp; + if (b >= (9 * 5 * 5)) + return LZMA2_STATE_ERROR; + lc = b % 9; + b /= 9; + p->decoder.prop.pb = b / 5; + lp = b % 5; + if (lc + lp > LZMA2_LCLP_MAX) + return LZMA2_STATE_ERROR; + p->decoder.prop.lc = lc; + p->decoder.prop.lp = lp; + p->needInitProp = False; + return LZMA2_STATE_DATA; + } + } + return LZMA2_STATE_ERROR; +} + +static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) +{ + memcpy(p->dic + p->dicPos, src, size); + p->dicPos += size; + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) + p->checkDicSize = p->prop.dicSize; + p->processedPos += (UInt32)size; +} + +static +void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; +} + +SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->state != LZMA2_STATE_FINISHED) + { + SizeT dicPos = p->decoder.dicPos; + if (p->state == LZMA2_STATE_ERROR) + return SZ_ERROR_DATA; + if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) + { + if (*srcLen == inSize) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + (*srcLen)++; + p->state = Lzma2Dec_UpdateState(p, *src++); + continue; + } + { + SizeT destSizeCur = dicLimit - dicPos; + SizeT srcSizeCur = inSize - *srcLen; + ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; + + if (p->unpackSize <= destSizeCur) + { + destSizeCur = (SizeT)p->unpackSize; + curFinishMode = LZMA_FINISH_END; + } + + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (*srcLen == inSize) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + if (p->state == LZMA2_STATE_DATA) + { + Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); + if (initDic) + p->needInitProp = p->needInitState = True; + else if (p->needInitDic) + return SZ_ERROR_DATA; + p->needInitDic = False; + LzmaDec_InitDicAndState(&p->decoder, initDic, False); + } + + if (srcSizeCur > destSizeCur) + srcSizeCur = destSizeCur; + + if (srcSizeCur == 0) + return SZ_ERROR_DATA; + + LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); + + src += srcSizeCur; + *srcLen += srcSizeCur; + p->unpackSize -= (UInt32)srcSizeCur; + p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; + } + else + { + SizeT outSizeProcessed; + SRes res; + + if (p->state == LZMA2_STATE_DATA) + { + int mode = LZMA2_GET_LZMA_MODE(p); + Bool initDic = (mode == 3); + Bool initState = (mode > 0); + if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) + return SZ_ERROR_DATA; + + LzmaDec_InitDicAndState(&p->decoder, initDic, initState); + p->needInitDic = False; + p->needInitState = False; + p->state = LZMA2_STATE_DATA_CONT; + } + if (srcSizeCur > p->packSize) + srcSizeCur = (SizeT)p->packSize; + + res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status); + + src += srcSizeCur; + *srcLen += srcSizeCur; + p->packSize -= (UInt32)srcSizeCur; + + outSizeProcessed = p->decoder.dicPos - dicPos; + p->unpackSize -= (UInt32)outSizeProcessed; + + RINOK(res); + if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) + return res; + + if (srcSizeCur == 0 && outSizeProcessed == 0) + { + if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || + p->unpackSize != 0 || p->packSize != 0) + return SZ_ERROR_DATA; + p->state = LZMA2_STATE_CONTROL; + } + if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + *status = LZMA_STATUS_NOT_FINISHED; + } + } + } + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return SZ_OK; +} + +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen, inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT srcSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->decoder.dicPos == p->decoder.dicBufSize) + p->decoder.dicPos = 0; + dicPos = p->decoder.dicPos; + if (outSize > p->decoder.dicBufSize - dicPos) + { + outSizeCur = p->decoder.dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status); + src += srcSizeCur; + inSize -= srcSizeCur; + *srcLen += srcSizeCur; + outSizeCur = p->decoder.dicPos - dicPos; + memcpy(dest, p->decoder.dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzma2Dec decoder; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + Byte props[LZMA_PROPS_SIZE]; + + Lzma2Dec_Construct(&decoder); + + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + decoder.decoder.dic = dest; + decoder.decoder.dicBufSize = outSize; + + RINOK(Lzma2Dec_GetOldProps(prop, props)); + RINOK(LzmaDec_AllocateProbs(&decoder.decoder, props, LZMA_PROPS_SIZE, alloc)); + + *srcLen = inSize; + res = Lzma2Dec_DecodeToDic(&decoder, outSize, src, srcLen, finishMode, status); + *destLen = decoder.decoder.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + + LzmaDec_FreeProbs(&decoder.decoder, alloc); + return res; +} diff --git a/fex/7z_C/Lzma2Dec.h b/fex/7z_C/Lzma2Dec.h index 827698de..6bc07bbc 100644 --- a/fex/7z_C/Lzma2Dec.h +++ b/fex/7z_C/Lzma2Dec.h @@ -1,84 +1,84 @@ -/* Lzma2Dec.h -- LZMA2 Decoder -2009-05-03 : Igor Pavlov : Public domain */ - -#ifndef __LZMA2_DEC_H -#define __LZMA2_DEC_H - -#include "LzmaDec.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* ---------- State Interface ---------- */ - -typedef struct -{ - CLzmaDec decoder; - UInt32 packSize; - UInt32 unpackSize; - int state; - Byte control; - Bool needInitDic; - Bool needInitState; - Bool needInitProp; -} CLzma2Dec; - -#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) -#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc); -#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc); - -SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); -SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); -void Lzma2Dec_Init(CLzma2Dec *p); - - -/* -finishMode: - It has meaning only if the decoding reaches output limit (*destLen or dicLimit). - LZMA_FINISH_ANY - use smallest number of input bytes - LZMA_FINISH_END - read EndOfStream marker after decoding - -Returns: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_NEEDS_MORE_INPUT - SZ_ERROR_DATA - Data error -*/ - -SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); - -SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); - - -/* ---------- One Call Interface ---------- */ - -/* -finishMode: - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - use smallest number of input bytes - LZMA_FINISH_END - read EndOfStream marker after decoding - -Returns: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties - SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). -*/ - -SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); - -#ifdef __cplusplus -} -#endif - -#endif +/* Lzma2Dec.h -- LZMA2 Decoder +2009-05-03 : Igor Pavlov : Public domain */ + +#ifndef __LZMA2_DEC_H +#define __LZMA2_DEC_H + +#include "LzmaDec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------- State Interface ---------- */ + +typedef struct +{ + CLzmaDec decoder; + UInt32 packSize; + UInt32 unpackSize; + int state; + Byte control; + Bool needInitDic; + Bool needInitState; + Bool needInitProp; +} CLzma2Dec; + +#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) +#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc); +#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc); + +SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); +SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); +void Lzma2Dec_Init(CLzma2Dec *p); + + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen or dicLimit). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + SZ_ERROR_DATA - Data error +*/ + +SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/fex/7z_C/LzmaDec.c b/fex/7z_C/LzmaDec.c index 876a1d86..08966d5e 100644 --- a/fex/7z_C/LzmaDec.c +++ b/fex/7z_C/LzmaDec.c @@ -1,1000 +1,1000 @@ -/* LzmaDec.c -- LZMA Decoder -2009-09-20 : Igor Pavlov : Public domain */ - -#include "LzmaDec.h" - -#include - -#define kNumTopBits 24 -#define kTopValue ((UInt32)1 << kNumTopBits) - -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) -#define kNumMoveBits 5 - -#define RC_INIT_SIZE 5 - -#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } - -#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) -#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); -#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); -#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ - { UPDATE_0(p); i = (i + i); A0; } else \ - { UPDATE_1(p); i = (i + i) + 1; A1; } -#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) - -#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } -#define TREE_DECODE(probs, limit, i) \ - { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } - -/* #define _LZMA_SIZE_OPT */ - -#ifdef _LZMA_SIZE_OPT -#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) -#else -#define TREE_6_DECODE(probs, i) \ - { i = 1; \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - i -= 0x40; } -#endif - -#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } - -#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) -#define UPDATE_0_CHECK range = bound; -#define UPDATE_1_CHECK range -= bound; code -= bound; -#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ - { UPDATE_0_CHECK; i = (i + i); A0; } else \ - { UPDATE_1_CHECK; i = (i + i) + 1; A1; } -#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) -#define TREE_DECODE_CHECK(probs, limit, i) \ - { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } - - -#define kNumPosBitsMax 4 -#define kNumPosStatesMax (1 << kNumPosBitsMax) - -#define kLenNumLowBits 3 -#define kLenNumLowSymbols (1 << kLenNumLowBits) -#define kLenNumMidBits 3 -#define kLenNumMidSymbols (1 << kLenNumMidBits) -#define kLenNumHighBits 8 -#define kLenNumHighSymbols (1 << kLenNumHighBits) - -#define LenChoice 0 -#define LenChoice2 (LenChoice + 1) -#define LenLow (LenChoice2 + 1) -#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) -#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) -#define kNumLenProbs (LenHigh + kLenNumHighSymbols) - - -#define kNumStates 12 -#define kNumLitStates 7 - -#define kStartPosModelIndex 4 -#define kEndPosModelIndex 14 -#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) - -#define kNumPosSlotBits 6 -#define kNumLenToPosStates 4 - -#define kNumAlignBits 4 -#define kAlignTableSize (1 << kNumAlignBits) - -#define kMatchMinLen 2 -#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) - -#define IsMatch 0 -#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) -#define IsRepG0 (IsRep + kNumStates) -#define IsRepG1 (IsRepG0 + kNumStates) -#define IsRepG2 (IsRepG1 + kNumStates) -#define IsRep0Long (IsRepG2 + kNumStates) -#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) -#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) -#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) -#define LenCoder (Align + kAlignTableSize) -#define RepLenCoder (LenCoder + kNumLenProbs) -#define Literal (RepLenCoder + kNumLenProbs) - -#define LZMA_BASE_SIZE 1846 -#define LZMA_LIT_SIZE 768 - -#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) - -#if Literal != LZMA_BASE_SIZE -StopCompilingDueBUG -#endif - -#define LZMA_DIC_MIN (1 << 12) - -/* First LZMA-symbol is always decoded. -And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization -Out: - Result: - SZ_OK - OK - SZ_ERROR_DATA - Error - p->remainLen: - < kMatchSpecLenStart : normal remain - = kMatchSpecLenStart : finished - = kMatchSpecLenStart + 1 : Flush marker - = kMatchSpecLenStart + 2 : State Init Marker -*/ - -static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) -{ - CLzmaProb *probs = p->probs; - - unsigned state = p->state; - UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; - unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; - unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; - unsigned lc = p->prop.lc; - - Byte *dic = p->dic; - SizeT dicBufSize = p->dicBufSize; - SizeT dicPos = p->dicPos; - - UInt32 processedPos = p->processedPos; - UInt32 checkDicSize = p->checkDicSize; - unsigned len = 0; - - const Byte *buf = p->buf; - UInt32 range = p->range; - UInt32 code = p->code; - - do - { - CLzmaProb *prob; - UInt32 bound; - unsigned ttt; - unsigned posState = processedPos & pbMask; - - prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; - IF_BIT_0(prob) - { - unsigned symbol; - UPDATE_0(prob); - prob = probs + Literal; - if (checkDicSize != 0 || processedPos != 0) - prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + - (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); - - if (state < kNumLitStates) - { - state -= (state < 4) ? state : 3; - symbol = 1; - do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); - } - else - { - unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; - unsigned offs = 0x100; - state -= (state < 10) ? 3 : 6; - symbol = 1; - do - { - unsigned bit; - CLzmaProb *probLit; - matchByte <<= 1; - bit = (matchByte & offs); - probLit = prob + offs + bit + symbol; - GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) - } - while (symbol < 0x100); - } - dic[dicPos++] = (Byte)symbol; - processedPos++; - continue; - } - else - { - UPDATE_1(prob); - prob = probs + IsRep + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - state += kNumStates; - prob = probs + LenCoder; - } - else - { - UPDATE_1(prob); - if (checkDicSize == 0 && processedPos == 0) - return SZ_ERROR_DATA; - prob = probs + IsRepG0 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; - IF_BIT_0(prob) - { - UPDATE_0(prob); - dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; - dicPos++; - processedPos++; - state = state < kNumLitStates ? 9 : 11; - continue; - } - UPDATE_1(prob); - } - else - { - UInt32 distance; - UPDATE_1(prob); - prob = probs + IsRepG1 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - distance = rep1; - } - else - { - UPDATE_1(prob); - prob = probs + IsRepG2 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - distance = rep2; - } - else - { - UPDATE_1(prob); - distance = rep3; - rep3 = rep2; - } - rep2 = rep1; - } - rep1 = rep0; - rep0 = distance; - } - state = state < kNumLitStates ? 8 : 11; - prob = probs + RepLenCoder; - } - { - unsigned limit, offset; - CLzmaProb *probLen = prob + LenChoice; - IF_BIT_0(probLen) - { - UPDATE_0(probLen); - probLen = prob + LenLow + (posState << kLenNumLowBits); - offset = 0; - limit = (1 << kLenNumLowBits); - } - else - { - UPDATE_1(probLen); - probLen = prob + LenChoice2; - IF_BIT_0(probLen) - { - UPDATE_0(probLen); - probLen = prob + LenMid + (posState << kLenNumMidBits); - offset = kLenNumLowSymbols; - limit = (1 << kLenNumMidBits); - } - else - { - UPDATE_1(probLen); - probLen = prob + LenHigh; - offset = kLenNumLowSymbols + kLenNumMidSymbols; - limit = (1 << kLenNumHighBits); - } - } - TREE_DECODE(probLen, limit, len); - len += offset; - } - - if (state >= kNumStates) - { - UInt32 distance; - prob = probs + PosSlot + - ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); - TREE_6_DECODE(prob, distance); - if (distance >= kStartPosModelIndex) - { - unsigned posSlot = (unsigned)distance; - int numDirectBits = (int)(((distance >> 1) - 1)); - distance = (2 | (distance & 1)); - if (posSlot < kEndPosModelIndex) - { - distance <<= numDirectBits; - prob = probs + SpecPos + distance - posSlot - 1; - { - UInt32 mask = 1; - unsigned i = 1; - do - { - GET_BIT2(prob + i, i, ; , distance |= mask); - mask <<= 1; - } - while (--numDirectBits != 0); - } - } - else - { - numDirectBits -= kNumAlignBits; - do - { - NORMALIZE - range >>= 1; - - { - UInt32 t; - code -= range; - t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ - distance = (distance << 1) + (t + 1); - code += range & t; - } - /* - distance <<= 1; - if (code >= range) - { - code -= range; - distance |= 1; - } - */ - } - while (--numDirectBits != 0); - prob = probs + Align; - distance <<= kNumAlignBits; - { - unsigned i = 1; - GET_BIT2(prob + i, i, ; , distance |= 1); - GET_BIT2(prob + i, i, ; , distance |= 2); - GET_BIT2(prob + i, i, ; , distance |= 4); - GET_BIT2(prob + i, i, ; , distance |= 8); - } - if (distance == (UInt32)0xFFFFFFFF) - { - len += kMatchSpecLenStart; - state -= kNumStates; - break; - } - } - } - rep3 = rep2; - rep2 = rep1; - rep1 = rep0; - rep0 = distance + 1; - if (checkDicSize == 0) - { - if (distance >= processedPos) - return SZ_ERROR_DATA; - } - else if (distance >= checkDicSize) - return SZ_ERROR_DATA; - state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; - } - - len += kMatchMinLen; - - if (limit == dicPos) - return SZ_ERROR_DATA; - { - SizeT rem = limit - dicPos; - unsigned curLen = ((rem < len) ? (unsigned)rem : len); - SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); - - processedPos += curLen; - - len -= curLen; - if (pos + curLen <= dicBufSize) - { - Byte *dest = dic + dicPos; - ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; - const Byte *lim = dest + curLen; - dicPos += curLen; - do - *(dest) = (Byte)*(dest + src); - while (++dest != lim); - } - else - { - do - { - dic[dicPos++] = dic[pos]; - if (++pos == dicBufSize) - pos = 0; - } - while (--curLen != 0); - } - } - } - } - while (dicPos < limit && buf < bufLimit); - NORMALIZE; - p->buf = buf; - p->range = range; - p->code = code; - p->remainLen = len; - p->dicPos = dicPos; - p->processedPos = processedPos; - p->reps[0] = rep0; - p->reps[1] = rep1; - p->reps[2] = rep2; - p->reps[3] = rep3; - p->state = state; - - return SZ_OK; -} - -static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) -{ - if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) - { - Byte *dic = p->dic; - SizeT dicPos = p->dicPos; - SizeT dicBufSize = p->dicBufSize; - unsigned len = p->remainLen; - UInt32 rep0 = p->reps[0]; - if (limit - dicPos < len) - len = (unsigned)(limit - dicPos); - - if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) - p->checkDicSize = p->prop.dicSize; - - p->processedPos += len; - p->remainLen -= len; - while (len-- != 0) - { - dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; - dicPos++; - } - p->dicPos = dicPos; - } -} - -static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) -{ - do - { - SizeT limit2 = limit; - if (p->checkDicSize == 0) - { - UInt32 rem = p->prop.dicSize - p->processedPos; - if (limit - p->dicPos > rem) - limit2 = p->dicPos + rem; - } - RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); - if (p->processedPos >= p->prop.dicSize) - p->checkDicSize = p->prop.dicSize; - LzmaDec_WriteRem(p, limit); - } - while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); - - if (p->remainLen > kMatchSpecLenStart) - { - p->remainLen = kMatchSpecLenStart; - } - return 0; -} - -typedef enum -{ - DUMMY_ERROR, /* unexpected end of input stream */ - DUMMY_LIT, - DUMMY_MATCH, - DUMMY_REP -} ELzmaDummy; - -static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) -{ - UInt32 range = p->range; - UInt32 code = p->code; - const Byte *bufLimit = buf + inSize; - CLzmaProb *probs = p->probs; - unsigned state = p->state; - ELzmaDummy res; - - { - CLzmaProb *prob; - UInt32 bound; - unsigned ttt; - unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); - - prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK - - /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ - - prob = probs + Literal; - if (p->checkDicSize != 0 || p->processedPos != 0) - prob += (LZMA_LIT_SIZE * - ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + - (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); - - if (state < kNumLitStates) - { - unsigned symbol = 1; - do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); - } - else - { - unsigned matchByte = p->dic[p->dicPos - p->reps[0] + - ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; - unsigned offs = 0x100; - unsigned symbol = 1; - do - { - unsigned bit; - CLzmaProb *probLit; - matchByte <<= 1; - bit = (matchByte & offs); - probLit = prob + offs + bit + symbol; - GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) - } - while (symbol < 0x100); - } - res = DUMMY_LIT; - } - else - { - unsigned len; - UPDATE_1_CHECK; - - prob = probs + IsRep + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - state = 0; - prob = probs + LenCoder; - res = DUMMY_MATCH; - } - else - { - UPDATE_1_CHECK; - res = DUMMY_REP; - prob = probs + IsRepG0 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - NORMALIZE_CHECK; - return DUMMY_REP; - } - else - { - UPDATE_1_CHECK; - } - } - else - { - UPDATE_1_CHECK; - prob = probs + IsRepG1 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - } - else - { - UPDATE_1_CHECK; - prob = probs + IsRepG2 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - } - else - { - UPDATE_1_CHECK; - } - } - } - state = kNumStates; - prob = probs + RepLenCoder; - } - { - unsigned limit, offset; - CLzmaProb *probLen = prob + LenChoice; - IF_BIT_0_CHECK(probLen) - { - UPDATE_0_CHECK; - probLen = prob + LenLow + (posState << kLenNumLowBits); - offset = 0; - limit = 1 << kLenNumLowBits; - } - else - { - UPDATE_1_CHECK; - probLen = prob + LenChoice2; - IF_BIT_0_CHECK(probLen) - { - UPDATE_0_CHECK; - probLen = prob + LenMid + (posState << kLenNumMidBits); - offset = kLenNumLowSymbols; - limit = 1 << kLenNumMidBits; - } - else - { - UPDATE_1_CHECK; - probLen = prob + LenHigh; - offset = kLenNumLowSymbols + kLenNumMidSymbols; - limit = 1 << kLenNumHighBits; - } - } - TREE_DECODE_CHECK(probLen, limit, len); - len += offset; - } - - if (state < 4) - { - unsigned posSlot; - prob = probs + PosSlot + - ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << - kNumPosSlotBits); - TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); - if (posSlot >= kStartPosModelIndex) - { - int numDirectBits = ((posSlot >> 1) - 1); - - /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ - - if (posSlot < kEndPosModelIndex) - { - prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; - } - else - { - numDirectBits -= kNumAlignBits; - do - { - NORMALIZE_CHECK - range >>= 1; - code -= range & (((code - range) >> 31) - 1); - /* if (code >= range) code -= range; */ - } - while (--numDirectBits != 0); - prob = probs + Align; - numDirectBits = kNumAlignBits; - } - { - unsigned i = 1; - do - { - GET_BIT_CHECK(prob + i, i); - } - while (--numDirectBits != 0); - } - } - } - } - } - NORMALIZE_CHECK; - return res; -} - - -static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) -{ - p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); - p->range = 0xFFFFFFFF; - p->needFlush = 0; -} - -static -void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) -{ - p->needFlush = 1; - p->remainLen = 0; - p->tempBufSize = 0; - - if (initDic) - { - p->processedPos = 0; - p->checkDicSize = 0; - p->needInitState = 1; - } - if (initState) - p->needInitState = 1; -} - -void LzmaDec_Init(CLzmaDec *p) -{ - p->dicPos = 0; - LzmaDec_InitDicAndState(p, True, True); -} - -static void LzmaDec_InitStateReal(CLzmaDec *p) -{ - UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); - UInt32 i; - CLzmaProb *probs = p->probs; - for (i = 0; i < numProbs; i++) - probs[i] = kBitModelTotal >> 1; - p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; - p->state = 0; - p->needInitState = 0; -} - -SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, - ELzmaFinishMode finishMode, ELzmaStatus *status) -{ - SizeT inSize = *srcLen; - (*srcLen) = 0; - LzmaDec_WriteRem(p, dicLimit); - - *status = LZMA_STATUS_NOT_SPECIFIED; - - while (p->remainLen != kMatchSpecLenStart) - { - int checkEndMarkNow; - - if (p->needFlush != 0) - { - for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) - p->tempBuf[p->tempBufSize++] = *src++; - if (p->tempBufSize < RC_INIT_SIZE) - { - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - if (p->tempBuf[0] != 0) - return SZ_ERROR_DATA; - - LzmaDec_InitRc(p, p->tempBuf); - p->tempBufSize = 0; - } - - checkEndMarkNow = 0; - if (p->dicPos >= dicLimit) - { - if (p->remainLen == 0 && p->code == 0) - { - *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; - return SZ_OK; - } - if (finishMode == LZMA_FINISH_ANY) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_OK; - } - if (p->remainLen != 0) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; - } - checkEndMarkNow = 1; - } - - if (p->needInitState) - LzmaDec_InitStateReal(p); - - if (p->tempBufSize == 0) - { - SizeT processed; - const Byte *bufLimit; - if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) - { - int dummyRes = LzmaDec_TryDummy(p, src, inSize); - if (dummyRes == DUMMY_ERROR) - { - memcpy(p->tempBuf, src, inSize); - p->tempBufSize = (unsigned)inSize; - (*srcLen) += inSize; - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - if (checkEndMarkNow && dummyRes != DUMMY_MATCH) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; - } - bufLimit = src; - } - else - bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; - p->buf = src; - if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) - return SZ_ERROR_DATA; - processed = (SizeT)(p->buf - src); - (*srcLen) += processed; - src += processed; - inSize -= processed; - } - else - { - unsigned rem = p->tempBufSize, lookAhead = 0; - while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) - p->tempBuf[rem++] = src[lookAhead++]; - p->tempBufSize = rem; - if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) - { - int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); - if (dummyRes == DUMMY_ERROR) - { - (*srcLen) += lookAhead; - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - if (checkEndMarkNow && dummyRes != DUMMY_MATCH) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; - } - } - p->buf = p->tempBuf; - if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) - return SZ_ERROR_DATA; - lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); - (*srcLen) += lookAhead; - src += lookAhead; - inSize -= lookAhead; - p->tempBufSize = 0; - } - } - if (p->code == 0) - *status = LZMA_STATUS_FINISHED_WITH_MARK; - return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; -} - -SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) -{ - SizeT outSize = *destLen; - SizeT inSize = *srcLen; - *srcLen = *destLen = 0; - for (;;) - { - SizeT inSizeCur = inSize, outSizeCur, dicPos; - ELzmaFinishMode curFinishMode; - SRes res; - if (p->dicPos == p->dicBufSize) - p->dicPos = 0; - dicPos = p->dicPos; - if (outSize > p->dicBufSize - dicPos) - { - outSizeCur = p->dicBufSize; - curFinishMode = LZMA_FINISH_ANY; - } - else - { - outSizeCur = dicPos + outSize; - curFinishMode = finishMode; - } - - res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); - src += inSizeCur; - inSize -= inSizeCur; - *srcLen += inSizeCur; - outSizeCur = p->dicPos - dicPos; - memcpy(dest, p->dic + dicPos, outSizeCur); - dest += outSizeCur; - outSize -= outSizeCur; - *destLen += outSizeCur; - if (res != 0) - return res; - if (outSizeCur == 0 || outSize == 0) - return SZ_OK; - } -} - -void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) -{ - alloc->Free(alloc, p->probs); - p->probs = 0; -} - -static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) -{ - alloc->Free(alloc, p->dic); - p->dic = 0; -} - -void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) -{ - LzmaDec_FreeProbs(p, alloc); - LzmaDec_FreeDict(p, alloc); -} - -SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) -{ - UInt32 dicSize; - Byte d; - - if (size < LZMA_PROPS_SIZE) - return SZ_ERROR_UNSUPPORTED; - else - dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); - - if (dicSize < LZMA_DIC_MIN) - dicSize = LZMA_DIC_MIN; - p->dicSize = dicSize; - - d = data[0]; - if (d >= (9 * 5 * 5)) - return SZ_ERROR_UNSUPPORTED; - - p->lc = d % 9; - d /= 9; - p->pb = d / 5; - p->lp = d % 5; - - return SZ_OK; -} - -static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) -{ - UInt32 numProbs = LzmaProps_GetNumProbs(propNew); - if (p->probs == 0 || numProbs != p->numProbs) - { - LzmaDec_FreeProbs(p, alloc); - p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); - p->numProbs = numProbs; - if (p->probs == 0) - return SZ_ERROR_MEM; - } - return SZ_OK; -} - -SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) -{ - CLzmaProps propNew; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)); - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); - p->prop = propNew; - return SZ_OK; -} - -SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) -{ - CLzmaProps propNew; - SizeT dicBufSize; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)); - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); - dicBufSize = propNew.dicSize; - if (p->dic == 0 || dicBufSize != p->dicBufSize) - { - LzmaDec_FreeDict(p, alloc); - p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); - if (p->dic == 0) - { - LzmaDec_FreeProbs(p, alloc); - return SZ_ERROR_MEM; - } - } - p->dicBufSize = dicBufSize; - p->prop = propNew; - return SZ_OK; -} - -SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAlloc *alloc) -{ - CLzmaDec p; - SRes res; - SizeT inSize = *srcLen; - SizeT outSize = *destLen; - *srcLen = *destLen = 0; - if (inSize < RC_INIT_SIZE) - return SZ_ERROR_INPUT_EOF; - - LzmaDec_Construct(&p); - res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); - if (res != 0) - return res; - p.dic = dest; - p.dicBufSize = outSize; - - LzmaDec_Init(&p); - - *srcLen = inSize; - res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); - - if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) - res = SZ_ERROR_INPUT_EOF; - - (*destLen) = p.dicPos; - LzmaDec_FreeProbs(&p, alloc); - return res; -} +/* LzmaDec.c -- LZMA Decoder +2009-09-20 : Igor Pavlov : Public domain */ + +#include "LzmaDec.h" + +#include + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } +#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) + +#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +#define LZMA_DIC_MIN (1 << 12) + +/* First LZMA-symbol is always decoded. +And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization +Out: + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : Flush marker + = kMatchSpecLenStart + 2 : State Init Marker +*/ + +static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = p->probs; + + unsigned state = p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; + unsigned lc = p->prop.lc; + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = processedPos & pbMask; + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (checkDicSize != 0 || processedPos != 0) + prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + + if (state < kNumLitStates) + { + state -= (state < 4) ? state : 3; + symbol = 1; + do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; + symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + dic[dicPos++] = (Byte)symbol; + processedPos++; + continue; + } + else + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = (1 << kLenNumMidBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, limit, len); + len += offset; + } + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + int numDirectBits = (int)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos + distance - posSlot - 1; + { + UInt32 mask = 1; + unsigned i = 1; + do + { + GET_BIT2(prob + i, i, ; , distance |= mask); + mask <<= 1; + } + while (--numDirectBits != 0); + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits != 0); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + GET_BIT2(prob + i, i, ; , distance |= 1); + GET_BIT2(prob + i, i, ; , distance |= 2); + GET_BIT2(prob + i, i, ; , distance |= 4); + GET_BIT2(prob + i, i, ; , distance |= 8); + } + if (distance == (UInt32)0xFFFFFFFF) + { + len += kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + if (checkDicSize == 0) + { + if (distance >= processedPos) + return SZ_ERROR_DATA; + } + else if (distance >= checkDicSize) + return SZ_ERROR_DATA; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + } + + len += kMatchMinLen; + + if (limit == dicPos) + return SZ_ERROR_DATA; + { + SizeT rem = limit - dicPos; + unsigned curLen = ((rem < len) ? (unsigned)rem : len); + SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + + processedPos += curLen; + + len -= curLen; + if (pos + curLen <= dicBufSize) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = state; + + return SZ_OK; +} + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = p->remainLen; + UInt32 rep0 = p->reps[0]; + if (limit - dicPos < len) + len = (unsigned)(limit - dicPos); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += len; + p->remainLen -= len; + while (len-- != 0) + { + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); + if (p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + if (p->remainLen > kMatchSpecLenStart) + { + p->remainLen = kMatchSpecLenStart; + } + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + CLzmaProb *probs = p->probs; + unsigned state = p->state; + ELzmaDummy res; + + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += (LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumMidBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits != 0); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + do + { + GET_BIT_CHECK(prob + i, i); + } + while (--numDirectBits != 0); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) +{ + p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; +} + +static +void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + +static void LzmaDec_InitStateReal(CLzmaDec *p) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); + UInt32 i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + p->needInitState = 0; +} + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + LzmaDec_WriteRem(p, dicLimit); + + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow; + + if (p->needFlush != 0) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + + LzmaDec_InitRc(p, p->tempBuf); + p->tempBufSize = 0; + } + + checkEndMarkNow = 0; + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->needInitState) + LzmaDec_InitStateReal(p); + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + (*srcLen) += lookAhead; + src += lookAhead; + inSize -= lookAhead; + p->tempBufSize = 0; + } + } + if (p->code == 0) + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; +} + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->probs); + p->probs = 0; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->dic); + p->dic = 0; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = d % 9; + d /= 9; + p->pb = d / 5; + p->lp = d % 5; + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (p->probs == 0 || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); + p->numProbs = numProbs; + if (p->probs == 0) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + dicBufSize = propNew.dicSize; + if (p->dic == 0 || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); + if (p->dic == 0) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzmaDec p; + SRes res; + SizeT inSize = *srcLen; + SizeT outSize = *destLen; + *srcLen = *destLen = 0; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + + LzmaDec_Construct(&p); + res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); + if (res != 0) + return res; + p.dic = dest; + p.dicBufSize = outSize; + + LzmaDec_Init(&p); + + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + + (*destLen) = p.dicPos; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/fex/7z_C/LzmaDec.h b/fex/7z_C/LzmaDec.h index 6741a644..bf7f084b 100644 --- a/fex/7z_C/LzmaDec.h +++ b/fex/7z_C/LzmaDec.h @@ -1,231 +1,231 @@ -/* LzmaDec.h -- LZMA Decoder -2009-02-07 : Igor Pavlov : Public domain */ - -#ifndef __LZMA_DEC_H -#define __LZMA_DEC_H - -#include "Types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* #define _LZMA_PROB32 */ -/* _LZMA_PROB32 can increase the speed on some CPUs, - but memory usage for CLzmaDec::probs will be doubled in that case */ - -#ifdef _LZMA_PROB32 -#define CLzmaProb UInt32 -#else -#define CLzmaProb UInt16 -#endif - - -/* ---------- LZMA Properties ---------- */ - -#define LZMA_PROPS_SIZE 5 - -typedef struct _CLzmaProps -{ - unsigned lc, lp, pb; - UInt32 dicSize; -} CLzmaProps; - -/* LzmaProps_Decode - decodes properties -Returns: - SZ_OK - SZ_ERROR_UNSUPPORTED - Unsupported properties -*/ - -SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); - - -/* ---------- LZMA Decoder state ---------- */ - -/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. - Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ - -#define LZMA_REQUIRED_INPUT_MAX 20 - -typedef struct -{ - CLzmaProps prop; - CLzmaProb *probs; - Byte *dic; - const Byte *buf; - UInt32 range, code; - SizeT dicPos; - SizeT dicBufSize; - UInt32 processedPos; - UInt32 checkDicSize; - unsigned state; - UInt32 reps[4]; - unsigned remainLen; - int needFlush; - int needInitState; - UInt32 numProbs; - unsigned tempBufSize; - Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; -} CLzmaDec; - -#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } - -void LzmaDec_Init(CLzmaDec *p); - -/* There are two types of LZMA streams: - 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. - 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ - -typedef enum -{ - LZMA_FINISH_ANY, /* finish at any point */ - LZMA_FINISH_END /* block must be finished at the end */ -} ELzmaFinishMode; - -/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! - - You must use LZMA_FINISH_END, when you know that current output buffer - covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. - - If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, - and output value of destLen will be less than output buffer size limit. - You can check status result also. - - You can use multiple checks to test data integrity after full decompression: - 1) Check Result and "status" variable. - 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. - 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. - You must use correct finish mode in that case. */ - -typedef enum -{ - LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ - LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ - LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ - LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ -} ELzmaStatus; - -/* ELzmaStatus is used only as output value for function call */ - - -/* ---------- Interfaces ---------- */ - -/* There are 3 levels of interfaces: - 1) Dictionary Interface - 2) Buffer Interface - 3) One Call Interface - You can select any of these interfaces, but don't mix functions from different - groups for same object. */ - - -/* There are two variants to allocate state for Dictionary Interface: - 1) LzmaDec_Allocate / LzmaDec_Free - 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs - You can use variant 2, if you set dictionary buffer manually. - For Buffer Interface you must always use variant 1. - -LzmaDec_Allocate* can return: - SZ_OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties -*/ - -SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); -void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); - -SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); -void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); - -/* ---------- Dictionary Interface ---------- */ - -/* You can use it, if you want to eliminate the overhead for data copying from - dictionary to some other external buffer. - You must work with CLzmaDec variables directly in this interface. - - STEPS: - LzmaDec_Constr() - LzmaDec_Allocate() - for (each new stream) - { - LzmaDec_Init() - while (it needs more decompression) - { - LzmaDec_DecodeToDic() - use data from CLzmaDec::dic and update CLzmaDec::dicPos - } - } - LzmaDec_Free() -*/ - -/* LzmaDec_DecodeToDic - - The decoding to internal dictionary buffer (CLzmaDec::dic). - You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! - -finishMode: - It has meaning only if the decoding reaches output limit (dicLimit). - LZMA_FINISH_ANY - Decode just dicLimit bytes. - LZMA_FINISH_END - Stream must be finished after dicLimit. - -Returns: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_NEEDS_MORE_INPUT - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - SZ_ERROR_DATA - Data error -*/ - -SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); - - -/* ---------- Buffer Interface ---------- */ - -/* It's zlib-like interface. - See LzmaDec_DecodeToDic description for information about STEPS and return results, - but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need - to work with CLzmaDec variables manually. - -finishMode: - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). -*/ - -SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); - - -/* ---------- One Call Interface ---------- */ - -/* LzmaDecode - -finishMode: - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). - -Returns: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties - SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). -*/ - -SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAlloc *alloc); - -#ifdef __cplusplus -} -#endif - -#endif +/* LzmaDec.h -- LZMA Decoder +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_DEC_H +#define __LZMA_DEC_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* #define _LZMA_PROB32 */ +/* _LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + unsigned lc, lp, pb; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + CLzmaProps prop; + CLzmaProb *probs; + Byte *dic; + const Byte *buf; + UInt32 range, code; + SizeT dicPos; + SizeT dicBufSize; + UInt32 processedPos; + UInt32 checkDicSize; + unsigned state; + UInt32 reps[4]; + unsigned remainLen; + int needFlush; + int needInitState; + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); + +SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Constr() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/fex/7z_C/Types.h b/fex/7z_C/Types.h index f193ce2f..7732c240 100644 --- a/fex/7z_C/Types.h +++ b/fex/7z_C/Types.h @@ -1,254 +1,254 @@ -/* Types.h -- Basic types -2010-10-09 : Igor Pavlov : Public domain */ - -#ifndef __7Z_TYPES_H -#define __7Z_TYPES_H - -#include - -#ifdef _WIN32 -#include -#endif - -#ifndef EXTERN_C_BEGIN -#ifdef __cplusplus -#define EXTERN_C_BEGIN extern "C" { -#define EXTERN_C_END } -#else -#define EXTERN_C_BEGIN -#define EXTERN_C_END -#endif -#endif - -EXTERN_C_BEGIN - -#define SZ_OK 0 - -#define SZ_ERROR_DATA 1 -#define SZ_ERROR_MEM 2 -#define SZ_ERROR_CRC 3 -#define SZ_ERROR_UNSUPPORTED 4 -#define SZ_ERROR_PARAM 5 -#define SZ_ERROR_INPUT_EOF 6 -#define SZ_ERROR_OUTPUT_EOF 7 -#define SZ_ERROR_READ 8 -#define SZ_ERROR_WRITE 9 -#define SZ_ERROR_PROGRESS 10 -#define SZ_ERROR_FAIL 11 -#define SZ_ERROR_THREAD 12 - -#define SZ_ERROR_ARCHIVE 16 -#define SZ_ERROR_NO_ARCHIVE 17 - -typedef int SRes; - -#ifdef _WIN32 -typedef DWORD WRes; -#else -typedef int WRes; -#endif - -#ifndef RINOK -#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } -#endif - -typedef unsigned char Byte; -typedef short Int16; -typedef unsigned short UInt16; - -#ifdef _LZMA_UINT32_IS_ULONG -typedef long Int32; -typedef unsigned long UInt32; -#else -typedef int Int32; -typedef unsigned int UInt32; -#endif - -#ifdef _SZ_NO_INT_64 - -/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. - NOTES: Some code will work incorrectly in that case! */ - -typedef long Int64; -typedef unsigned long UInt64; - -#else - -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef __int64 Int64; -typedef unsigned __int64 UInt64; -#define UINT64_CONST(n) n -#else -typedef long long int Int64; -typedef unsigned long long int UInt64; -#define UINT64_CONST(n) n ## ULL -#endif - -#endif - -#ifdef _LZMA_NO_SYSTEM_SIZE_T -typedef UInt32 SizeT; -#else -typedef size_t SizeT; -#endif - -typedef int Bool; -#define True 1 -#define False 0 - - -#ifdef _WIN32 -#define MY_STD_CALL __stdcall -#else -#define MY_STD_CALL -#endif - -#ifdef _MSC_VER - -#if _MSC_VER >= 1300 -#define MY_NO_INLINE __declspec(noinline) -#else -#define MY_NO_INLINE -#endif - -#define MY_CDECL __cdecl -#define MY_FAST_CALL __fastcall - -#else - -#define MY_CDECL -#define MY_FAST_CALL - -#endif - - -/* The following interfaces use first parameter as pointer to structure */ - -typedef struct -{ - Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ -} IByteIn; - -typedef struct -{ - void (*Write)(void *p, Byte b); -} IByteOut; - -typedef struct -{ - SRes (*Read)(void *p, void *buf, size_t *size); - /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. - (output(*size) < input(*size)) is allowed */ -} ISeqInStream; - -/* it can return SZ_ERROR_INPUT_EOF */ -SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); -SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); -SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); - -typedef struct -{ - size_t (*Write)(void *p, const void *buf, size_t size); - /* Returns: result - the number of actually written bytes. - (result < size) means error */ -} ISeqOutStream; - -typedef enum -{ - SZ_SEEK_SET = 0, - SZ_SEEK_CUR = 1, - SZ_SEEK_END = 2 -} ESzSeek; - -typedef struct -{ - SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ - SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); -} ISeekInStream; - -typedef struct -{ - SRes (*Look)(void *p, const void **buf, size_t *size); - /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. - (output(*size) > input(*size)) is not allowed - (output(*size) < input(*size)) is allowed */ - SRes (*Skip)(void *p, size_t offset); - /* offset must be <= output(*size) of Look */ - - SRes (*Read)(void *p, void *buf, size_t *size); - /* reads directly (without buffer). It's same as ISeqInStream::Read */ - SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); -} ILookInStream; - -SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); -SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); - -/* reads via ILookInStream::Read */ -SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); -SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); - -#define LookToRead_BUF_SIZE (1 << 14) - -typedef struct -{ - ILookInStream s; - ISeekInStream *realStream; - size_t pos; - size_t size; - Byte buf[LookToRead_BUF_SIZE]; -} CLookToRead; - -void LookToRead_CreateVTable(CLookToRead *p, int lookahead); -void LookToRead_Init(CLookToRead *p); - -typedef struct -{ - ISeqInStream s; - ILookInStream *realStream; -} CSecToLook; - -void SecToLook_CreateVTable(CSecToLook *p); - -typedef struct -{ - ISeqInStream s; - ILookInStream *realStream; -} CSecToRead; - -void SecToRead_CreateVTable(CSecToRead *p); - -typedef struct -{ - SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); - /* Returns: result. (result != SZ_OK) means break. - Value (UInt64)(Int64)-1 for size means unknown value. */ -} ICompressProgress; - -typedef struct -{ - void *(*Alloc)(void *p, size_t size); - void (*Free)(void *p, void *address); /* address can be 0 */ -} ISzAlloc; - -#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) -#define IAlloc_Free(p, a) (p)->Free((p), a) - -#ifdef _WIN32 - -#define CHAR_PATH_SEPARATOR '\\' -#define WCHAR_PATH_SEPARATOR L'\\' -#define STRING_PATH_SEPARATOR "\\" -#define WSTRING_PATH_SEPARATOR L"\\" - -#else - -#define CHAR_PATH_SEPARATOR '/' -#define WCHAR_PATH_SEPARATOR L'/' -#define STRING_PATH_SEPARATOR "/" -#define WSTRING_PATH_SEPARATOR L"/" - -#endif - -EXTERN_C_END - -#endif +/* Types.h -- Basic types +2010-10-09 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#include + +#ifdef _WIN32 +#include +#endif + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + +#ifdef _WIN32 +typedef DWORD WRes; +#else +typedef int WRes; +#endif + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#define UINT64_CONST(n) n +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#define UINT64_CONST(n) n ## ULL +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int Bool; +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define MY_STD_CALL __stdcall +#else +#define MY_STD_CALL +#endif + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_CDECL __cdecl +#define MY_FAST_CALL __fastcall + +#else + +#define MY_CDECL +#define MY_FAST_CALL + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ +} IByteIn; + +typedef struct +{ + void (*Write)(void *p, Byte b); +} IByteOut; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +} ISeqInStream; + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); + +typedef struct +{ + size_t (*Write)(void *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +} ISeqOutStream; + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ISeekInStream; + +typedef struct +{ + SRes (*Look)(void *p, const void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(void *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ILookInStream; + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); + +#define LookToRead_BUF_SIZE (1 << 14) + +typedef struct +{ + ILookInStream s; + ISeekInStream *realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; +} CLookToRead; + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead); +void LookToRead_Init(CLookToRead *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + +typedef struct +{ + SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +} ICompressProgress; + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) +#define IAlloc_Free(p, a) (p)->Free((p), a) + +#ifdef _WIN32 + +#define CHAR_PATH_SEPARATOR '\\' +#define WCHAR_PATH_SEPARATOR L'\\' +#define STRING_PATH_SEPARATOR "\\" +#define WSTRING_PATH_SEPARATOR L"\\" + +#else + +#define CHAR_PATH_SEPARATOR '/' +#define WCHAR_PATH_SEPARATOR L'/' +#define STRING_PATH_SEPARATOR "/" +#define WSTRING_PATH_SEPARATOR L"/" + +#endif + +EXTERN_C_END + +#endif diff --git a/fex/7z_C/lzma.txt b/fex/7z_C/lzma.txt index d4f4af92..715792d6 100644 --- a/fex/7z_C/lzma.txt +++ b/fex/7z_C/lzma.txt @@ -1,594 +1,594 @@ -LZMA SDK 4.65 -------------- - -LZMA SDK provides the documentation, samples, header files, libraries, -and tools you need to develop applications that use LZMA compression. - -LZMA is default and general compression method of 7z format -in 7-Zip compression program (www.7-zip.org). LZMA provides high -compression ratio and very fast decompression. - -LZMA is an improved version of famous LZ77 compression algorithm. -It was improved in way of maximum increasing of compression ratio, -keeping high decompression speed and low memory requirements for -decompressing. - - - -LICENSE -------- - -LZMA SDK is written and placed in the public domain by Igor Pavlov. - - -LZMA SDK Contents ------------------ - -LZMA SDK includes: - - - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing - - Compiled file->file LZMA compressing/decompressing program for Windows system - - -UNIX/Linux version ------------------- -To compile C++ version of file->file LZMA encoding, go to directory -C++/7zip/Compress/LZMA_Alone -and call make to recompile it: - make -f makefile.gcc clean all - -In some UNIX/Linux versions you must compile LZMA with static libraries. -To compile with static libraries, you can use -LIB = -lm -static - - -Files ---------------------- -lzma.txt - LZMA SDK description (this file) -7zFormat.txt - 7z Format description -7zC.txt - 7z ANSI-C Decoder description -methods.txt - Compression method IDs for .7z -lzma.exe - Compiled file->file LZMA encoder/decoder for Windows -history.txt - history of the LZMA SDK - - -Source code structure ---------------------- - -C/ - C files - 7zCrc*.* - CRC code - Alloc.* - Memory allocation functions - Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code - LzFind.* - Match finder for LZ (LZMA) encoders - LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding - LzHash.h - Additional file for LZ match finder - LzmaDec.* - LZMA decoding - LzmaEnc.* - LZMA encoding - LzmaLib.* - LZMA Library for DLL calling - Types.h - Basic types for another .c files - Threads.* - The code for multithreading. - - LzmaLib - LZMA Library (.DLL for Windows) - - LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder). - - Archive - files related to archiving - 7z - 7z ANSI-C Decoder - -CPP/ -- CPP files - - Common - common files for C++ projects - Windows - common files for Windows related code - - 7zip - files related to 7-Zip Project - - Common - common files for 7-Zip - - Compress - files related to compression/decompression - - Copy - Copy coder - RangeCoder - Range Coder (special code of compression/decompression) - LZMA - LZMA compression/decompression on C++ - LZMA_Alone - file->file LZMA compression/decompression - Branch - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code - - Archive - files related to archiving - - Common - common files for archive handling - 7z - 7z C++ Encoder/Decoder - - Bundles - Modules that are bundles of other modules - - Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2 - Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2 - Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2. - - UI - User Interface files - - Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll - Common - Common UI files - Console - Code for console archiver - - - -CS/ - C# files - 7zip - Common - some common files for 7-Zip - Compress - files related to compression/decompression - LZ - files related to LZ (Lempel-Ziv) compression algorithm - LZMA - LZMA compression/decompression - LzmaAlone - file->file LZMA compression/decompression - RangeCoder - Range Coder (special code of compression/decompression) - -Java/ - Java files - SevenZip - Compression - files related to compression/decompression - LZ - files related to LZ (Lempel-Ziv) compression algorithm - LZMA - LZMA compression/decompression - RangeCoder - Range Coder (special code of compression/decompression) - - -C/C++ source code of LZMA SDK is part of 7-Zip project. -7-Zip source code can be downloaded from 7-Zip's SourceForge page: - - http://sourceforge.net/projects/sevenzip/ - - - -LZMA features -------------- - - Variable dictionary size (up to 1 GB) - - Estimated compressing speed: about 2 MB/s on 2 GHz CPU - - Estimated decompressing speed: - - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64 - - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC - - Small memory requirements for decompressing (16 KB + DictionarySize) - - Small code size for decompressing: 5-8 KB - -LZMA decoder uses only integer operations and can be -implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions). - -Some critical operations that affect the speed of LZMA decompression: - 1) 32*16 bit integer multiply - 2) Misspredicted branches (penalty mostly depends from pipeline length) - 3) 32-bit shift and arithmetic operations - -The speed of LZMA decompressing mostly depends from CPU speed. -Memory speed has no big meaning. But if your CPU has small data cache, -overall weight of memory speed will slightly increase. - - -How To Use ----------- - -Using LZMA encoder/decoder executable --------------------------------------- - -Usage: LZMA inputFile outputFile [...] - - e: encode file - - d: decode file - - b: Benchmark. There are two tests: compressing and decompressing - with LZMA method. Benchmark shows rating in MIPS (million - instructions per second). Rating value is calculated from - measured speed and it is normalized with Intel's Core 2 results. - Also Benchmark checks possible hardware errors (RAM - errors in most cases). Benchmark uses these settings: - (-a1, -d21, -fb32, -mfbt4). You can change only -d parameter. - Also you can change the number of iterations. Example for 30 iterations: - LZMA b 30 - Default number of iterations is 10. - - - - - -a{N}: set compression mode 0 = fast, 1 = normal - default: 1 (normal) - - d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB) - The maximum value for dictionary size is 1 GB = 2^30 bytes. - Dictionary size is calculated as DictionarySize = 2^N bytes. - For decompressing file compressed by LZMA method with dictionary - size D = 2^N you need about D bytes of memory (RAM). - - -fb{N}: set number of fast bytes - [5, 273], default: 128 - Usually big number gives a little bit better compression ratio - and slower compression process. - - -lc{N}: set number of literal context bits - [0, 8], default: 3 - Sometimes lc=4 gives gain for big files. - - -lp{N}: set number of literal pos bits - [0, 4], default: 0 - lp switch is intended for periodical data when period is - equal 2^N. For example, for 32-bit (4 bytes) - periodical data you can use lp=2. Often it's better to set lc0, - if you change lp switch. - - -pb{N}: set number of pos bits - [0, 4], default: 2 - pb switch is intended for periodical data - when period is equal 2^N. - - -mf{MF_ID}: set Match Finder. Default: bt4. - Algorithms from hc* group doesn't provide good compression - ratio, but they often works pretty fast in combination with - fast mode (-a0). - - Memory requirements depend from dictionary size - (parameter "d" in table below). - - MF_ID Memory Description - - bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing. - bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing. - bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing. - hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing. - - -eos: write End Of Stream marker. By default LZMA doesn't write - eos marker, since LZMA decoder knows uncompressed size - stored in .lzma file header. - - -si: Read data from stdin (it will write End Of Stream marker). - -so: Write data to stdout - - -Examples: - -1) LZMA e file.bin file.lzma -d16 -lc0 - -compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K) -and 0 literal context bits. -lc0 allows to reduce memory requirements -for decompression. - - -2) LZMA e file.bin file.lzma -lc0 -lp2 - -compresses file.bin to file.lzma with settings suitable -for 32-bit periodical data (for example, ARM or MIPS code). - -3) LZMA d file.lzma file.bin - -decompresses file.lzma to file.bin. - - -Compression ratio hints ------------------------ - -Recommendations ---------------- - -To increase the compression ratio for LZMA compressing it's desirable -to have aligned data (if it's possible) and also it's desirable to locate -data in such order, where code is grouped in one place and data is -grouped in other place (it's better than such mixing: code, data, code, -data, ...). - - -Filters -------- -You can increase the compression ratio for some data types, using -special filters before compressing. For example, it's possible to -increase the compression ratio on 5-10% for code for those CPU ISAs: -x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC. - -You can find C source code of such filters in C/Bra*.* files - -You can check the compression ratio gain of these filters with such -7-Zip commands (example for ARM code): -No filter: - 7z a a1.7z a.bin -m0=lzma - -With filter for little-endian ARM code: - 7z a a2.7z a.bin -m0=arm -m1=lzma - -It works in such manner: -Compressing = Filter_encoding + LZMA_encoding -Decompressing = LZMA_decoding + Filter_decoding - -Compressing and decompressing speed of such filters is very high, -so it will not increase decompressing time too much. -Moreover, it reduces decompression time for LZMA_decoding, -since compression ratio with filtering is higher. - -These filters convert CALL (calling procedure) instructions -from relative offsets to absolute addresses, so such data becomes more -compressible. - -For some ISAs (for example, for MIPS) it's impossible to get gain from such filter. - - -LZMA compressed file format ---------------------------- -Offset Size Description - 0 1 Special LZMA properties (lc,lp, pb in encoded form) - 1 4 Dictionary size (little endian) - 5 8 Uncompressed size (little endian). -1 means unknown size - 13 Compressed data - - -ANSI-C LZMA Decoder -~~~~~~~~~~~~~~~~~~~ - -Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58. -If you want to use old interfaces you can download previous version of LZMA SDK -from sourceforge.net site. - -To use ANSI-C LZMA Decoder you need the following files: -1) LzmaDec.h + LzmaDec.c + Types.h -LzmaUtil/LzmaUtil.c is example application that uses these files. - - -Memory requirements for LZMA decoding -------------------------------------- - -Stack usage of LZMA decoding function for local variables is not -larger than 200-400 bytes. - -LZMA Decoder uses dictionary buffer and internal state structure. -Internal state structure consumes - state_size = (4 + (1.5 << (lc + lp))) KB -by default (lc=3, lp=0), state_size = 16 KB. - - -How To decompress data ----------------------- - -LZMA Decoder (ANSI-C version) now supports 2 interfaces: -1) Single-call Decompressing -2) Multi-call State Decompressing (zlib-like interface) - -You must use external allocator: -Example: -void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } -void SzFree(void *p, void *address) { p = p; free(address); } -ISzAlloc alloc = { SzAlloc, SzFree }; - -You can use p = p; operator to disable compiler warnings. - - -Single-call Decompressing -------------------------- -When to use: RAM->RAM decompressing -Compile files: LzmaDec.h + LzmaDec.c + Types.h -Compile defines: no defines -Memory Requirements: - - Input buffer: compressed size - - Output buffer: uncompressed size - - LZMA Internal Structures: state_size (16 KB for default settings) - -Interface: - int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAlloc *alloc); - In: - dest - output data - destLen - output data size - src - input data - srcLen - input data size - propData - LZMA properties (5 bytes) - propSize - size of propData buffer (5 bytes) - finishMode - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). - You can use LZMA_FINISH_END, when you know that - current output buffer covers last bytes of stream. - alloc - Memory allocator. - - Out: - destLen - processed output size - srcLen - processed input size - - Output: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties - SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). - - If LZMA decoder sees end_marker before reaching output limit, it returns OK result, - and output value of destLen will be less than output buffer size limit. - - You can use multiple checks to test data integrity after full decompression: - 1) Check Result and "status" variable. - 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. - 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. - You must use correct finish mode in that case. */ - - -Multi-call State Decompressing (zlib-like interface) ----------------------------------------------------- - -When to use: file->file decompressing -Compile files: LzmaDec.h + LzmaDec.c + Types.h - -Memory Requirements: - - Buffer for input stream: any size (for example, 16 KB) - - Buffer for output stream: any size (for example, 16 KB) - - LZMA Internal Structures: state_size (16 KB for default settings) - - LZMA dictionary (dictionary size is encoded in LZMA properties header) - -1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header: - unsigned char header[LZMA_PROPS_SIZE + 8]; - ReadFile(inFile, header, sizeof(header) - -2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties - - CLzmaDec state; - LzmaDec_Constr(&state); - res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc); - if (res != SZ_OK) - return res; - -3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop - - LzmaDec_Init(&state); - for (;;) - { - ... - int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode); - ... - } - - -4) Free all allocated structures - LzmaDec_Free(&state, &g_Alloc); - -For full code example, look at C/LzmaUtil/LzmaUtil.c code. - - -How To compress data --------------------- - -Compile files: LzmaEnc.h + LzmaEnc.c + Types.h + -LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h - -Memory Requirements: - - (dictSize * 11.5 + 6 MB) + state_size - -Lzma Encoder can use two memory allocators: -1) alloc - for small arrays. -2) allocBig - for big arrays. - -For example, you can use Large RAM Pages (2 MB) in allocBig allocator for -better compression speed. Note that Windows has bad implementation for -Large RAM Pages. -It's OK to use same allocator for alloc and allocBig. - - -Single-call Compression with callbacks --------------------------------------- - -Check C/LzmaUtil/LzmaUtil.c as example, - -When to use: file->file decompressing - -1) you must implement callback structures for interfaces: -ISeqInStream -ISeqOutStream -ICompressProgress -ISzAlloc - -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; - - CFileSeqInStream inStream; - CFileSeqOutStream outStream; - - inStream.funcTable.Read = MyRead; - inStream.file = inFile; - outStream.funcTable.Write = MyWrite; - outStream.file = outFile; - - -2) Create CLzmaEncHandle object; - - CLzmaEncHandle enc; - - enc = LzmaEnc_Create(&g_Alloc); - if (enc == 0) - return SZ_ERROR_MEM; - - -3) initialize CLzmaEncProps properties; - - LzmaEncProps_Init(&props); - - Then you can change some properties in that structure. - -4) Send LZMA properties to LZMA Encoder - - res = LzmaEnc_SetProps(enc, &props); - -5) Write encoded properties to header - - Byte header[LZMA_PROPS_SIZE + 8]; - size_t headerSize = LZMA_PROPS_SIZE; - UInt64 fileSize; - int i; - - res = LzmaEnc_WriteProperties(enc, header, &headerSize); - fileSize = MyGetFileLength(inFile); - for (i = 0; i < 8; i++) - header[headerSize++] = (Byte)(fileSize >> (8 * i)); - MyWriteFileAndCheck(outFile, header, headerSize) - -6) Call encoding function: - res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable, - NULL, &g_Alloc, &g_Alloc); - -7) Destroy LZMA Encoder Object - LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); - - -If callback function return some error code, LzmaEnc_Encode also returns that code. - - -Single-call RAM->RAM Compression --------------------------------- - -Single-call RAM->RAM Compression is similar to Compression with callbacks, -but you provide pointers to buffers instead of pointers to stream callbacks: - -HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, - CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, - ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); - -Return code: - SZ_OK - OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_PARAM - Incorrect paramater - SZ_ERROR_OUTPUT_EOF - output buffer overflow - SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) - - - -LZMA Defines ------------- - -_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code. - -_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for - some structures will be doubled in that case. - -_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit. - -_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type. - - -C++ LZMA Encoder/Decoder -~~~~~~~~~~~~~~~~~~~~~~~~ -C++ LZMA code use COM-like interfaces. So if you want to use it, -you can study basics of COM/OLE. -C++ LZMA code is just wrapper over ANSI-C code. - - -C++ Notes -~~~~~~~~~~~~~~~~~~~~~~~~ -If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling), -you must check that you correctly work with "new" operator. -7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator. -So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator: -operator new(size_t size) -{ - void *p = ::malloc(size); - if (p == 0) - throw CNewException(); - return p; -} -If you use MSCV that throws exception for "new" operator, you can compile without -"NewHandler.cpp". So standard exception will be used. Actually some code of -7-Zip catches any exception in internal code and converts it to HRESULT code. -So you don't need to catch CNewException, if you call COM interfaces of 7-Zip. - ---- - -http://www.7-zip.org -http://www.7-zip.org/sdk.html -http://www.7-zip.org/support.html +LZMA SDK 4.65 +------------- + +LZMA SDK provides the documentation, samples, header files, libraries, +and tools you need to develop applications that use LZMA compression. + +LZMA is default and general compression method of 7z format +in 7-Zip compression program (www.7-zip.org). LZMA provides high +compression ratio and very fast decompression. + +LZMA is an improved version of famous LZ77 compression algorithm. +It was improved in way of maximum increasing of compression ratio, +keeping high decompression speed and low memory requirements for +decompressing. + + + +LICENSE +------- + +LZMA SDK is written and placed in the public domain by Igor Pavlov. + + +LZMA SDK Contents +----------------- + +LZMA SDK includes: + + - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing + - Compiled file->file LZMA compressing/decompressing program for Windows system + + +UNIX/Linux version +------------------ +To compile C++ version of file->file LZMA encoding, go to directory +C++/7zip/Compress/LZMA_Alone +and call make to recompile it: + make -f makefile.gcc clean all + +In some UNIX/Linux versions you must compile LZMA with static libraries. +To compile with static libraries, you can use +LIB = -lm -static + + +Files +--------------------- +lzma.txt - LZMA SDK description (this file) +7zFormat.txt - 7z Format description +7zC.txt - 7z ANSI-C Decoder description +methods.txt - Compression method IDs for .7z +lzma.exe - Compiled file->file LZMA encoder/decoder for Windows +history.txt - history of the LZMA SDK + + +Source code structure +--------------------- + +C/ - C files + 7zCrc*.* - CRC code + Alloc.* - Memory allocation functions + Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code + LzFind.* - Match finder for LZ (LZMA) encoders + LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding + LzHash.h - Additional file for LZ match finder + LzmaDec.* - LZMA decoding + LzmaEnc.* - LZMA encoding + LzmaLib.* - LZMA Library for DLL calling + Types.h - Basic types for another .c files + Threads.* - The code for multithreading. + + LzmaLib - LZMA Library (.DLL for Windows) + + LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder). + + Archive - files related to archiving + 7z - 7z ANSI-C Decoder + +CPP/ -- CPP files + + Common - common files for C++ projects + Windows - common files for Windows related code + + 7zip - files related to 7-Zip Project + + Common - common files for 7-Zip + + Compress - files related to compression/decompression + + Copy - Copy coder + RangeCoder - Range Coder (special code of compression/decompression) + LZMA - LZMA compression/decompression on C++ + LZMA_Alone - file->file LZMA compression/decompression + Branch - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code + + Archive - files related to archiving + + Common - common files for archive handling + 7z - 7z C++ Encoder/Decoder + + Bundles - Modules that are bundles of other modules + + Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2 + Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2 + Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2. + + UI - User Interface files + + Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll + Common - Common UI files + Console - Code for console archiver + + + +CS/ - C# files + 7zip + Common - some common files for 7-Zip + Compress - files related to compression/decompression + LZ - files related to LZ (Lempel-Ziv) compression algorithm + LZMA - LZMA compression/decompression + LzmaAlone - file->file LZMA compression/decompression + RangeCoder - Range Coder (special code of compression/decompression) + +Java/ - Java files + SevenZip + Compression - files related to compression/decompression + LZ - files related to LZ (Lempel-Ziv) compression algorithm + LZMA - LZMA compression/decompression + RangeCoder - Range Coder (special code of compression/decompression) + + +C/C++ source code of LZMA SDK is part of 7-Zip project. +7-Zip source code can be downloaded from 7-Zip's SourceForge page: + + http://sourceforge.net/projects/sevenzip/ + + + +LZMA features +------------- + - Variable dictionary size (up to 1 GB) + - Estimated compressing speed: about 2 MB/s on 2 GHz CPU + - Estimated decompressing speed: + - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64 + - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC + - Small memory requirements for decompressing (16 KB + DictionarySize) + - Small code size for decompressing: 5-8 KB + +LZMA decoder uses only integer operations and can be +implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions). + +Some critical operations that affect the speed of LZMA decompression: + 1) 32*16 bit integer multiply + 2) Misspredicted branches (penalty mostly depends from pipeline length) + 3) 32-bit shift and arithmetic operations + +The speed of LZMA decompressing mostly depends from CPU speed. +Memory speed has no big meaning. But if your CPU has small data cache, +overall weight of memory speed will slightly increase. + + +How To Use +---------- + +Using LZMA encoder/decoder executable +-------------------------------------- + +Usage: LZMA inputFile outputFile [...] + + e: encode file + + d: decode file + + b: Benchmark. There are two tests: compressing and decompressing + with LZMA method. Benchmark shows rating in MIPS (million + instructions per second). Rating value is calculated from + measured speed and it is normalized with Intel's Core 2 results. + Also Benchmark checks possible hardware errors (RAM + errors in most cases). Benchmark uses these settings: + (-a1, -d21, -fb32, -mfbt4). You can change only -d parameter. + Also you can change the number of iterations. Example for 30 iterations: + LZMA b 30 + Default number of iterations is 10. + + + + + -a{N}: set compression mode 0 = fast, 1 = normal + default: 1 (normal) + + d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB) + The maximum value for dictionary size is 1 GB = 2^30 bytes. + Dictionary size is calculated as DictionarySize = 2^N bytes. + For decompressing file compressed by LZMA method with dictionary + size D = 2^N you need about D bytes of memory (RAM). + + -fb{N}: set number of fast bytes - [5, 273], default: 128 + Usually big number gives a little bit better compression ratio + and slower compression process. + + -lc{N}: set number of literal context bits - [0, 8], default: 3 + Sometimes lc=4 gives gain for big files. + + -lp{N}: set number of literal pos bits - [0, 4], default: 0 + lp switch is intended for periodical data when period is + equal 2^N. For example, for 32-bit (4 bytes) + periodical data you can use lp=2. Often it's better to set lc0, + if you change lp switch. + + -pb{N}: set number of pos bits - [0, 4], default: 2 + pb switch is intended for periodical data + when period is equal 2^N. + + -mf{MF_ID}: set Match Finder. Default: bt4. + Algorithms from hc* group doesn't provide good compression + ratio, but they often works pretty fast in combination with + fast mode (-a0). + + Memory requirements depend from dictionary size + (parameter "d" in table below). + + MF_ID Memory Description + + bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing. + bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing. + bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing. + hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing. + + -eos: write End Of Stream marker. By default LZMA doesn't write + eos marker, since LZMA decoder knows uncompressed size + stored in .lzma file header. + + -si: Read data from stdin (it will write End Of Stream marker). + -so: Write data to stdout + + +Examples: + +1) LZMA e file.bin file.lzma -d16 -lc0 + +compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K) +and 0 literal context bits. -lc0 allows to reduce memory requirements +for decompression. + + +2) LZMA e file.bin file.lzma -lc0 -lp2 + +compresses file.bin to file.lzma with settings suitable +for 32-bit periodical data (for example, ARM or MIPS code). + +3) LZMA d file.lzma file.bin + +decompresses file.lzma to file.bin. + + +Compression ratio hints +----------------------- + +Recommendations +--------------- + +To increase the compression ratio for LZMA compressing it's desirable +to have aligned data (if it's possible) and also it's desirable to locate +data in such order, where code is grouped in one place and data is +grouped in other place (it's better than such mixing: code, data, code, +data, ...). + + +Filters +------- +You can increase the compression ratio for some data types, using +special filters before compressing. For example, it's possible to +increase the compression ratio on 5-10% for code for those CPU ISAs: +x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC. + +You can find C source code of such filters in C/Bra*.* files + +You can check the compression ratio gain of these filters with such +7-Zip commands (example for ARM code): +No filter: + 7z a a1.7z a.bin -m0=lzma + +With filter for little-endian ARM code: + 7z a a2.7z a.bin -m0=arm -m1=lzma + +It works in such manner: +Compressing = Filter_encoding + LZMA_encoding +Decompressing = LZMA_decoding + Filter_decoding + +Compressing and decompressing speed of such filters is very high, +so it will not increase decompressing time too much. +Moreover, it reduces decompression time for LZMA_decoding, +since compression ratio with filtering is higher. + +These filters convert CALL (calling procedure) instructions +from relative offsets to absolute addresses, so such data becomes more +compressible. + +For some ISAs (for example, for MIPS) it's impossible to get gain from such filter. + + +LZMA compressed file format +--------------------------- +Offset Size Description + 0 1 Special LZMA properties (lc,lp, pb in encoded form) + 1 4 Dictionary size (little endian) + 5 8 Uncompressed size (little endian). -1 means unknown size + 13 Compressed data + + +ANSI-C LZMA Decoder +~~~~~~~~~~~~~~~~~~~ + +Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58. +If you want to use old interfaces you can download previous version of LZMA SDK +from sourceforge.net site. + +To use ANSI-C LZMA Decoder you need the following files: +1) LzmaDec.h + LzmaDec.c + Types.h +LzmaUtil/LzmaUtil.c is example application that uses these files. + + +Memory requirements for LZMA decoding +------------------------------------- + +Stack usage of LZMA decoding function for local variables is not +larger than 200-400 bytes. + +LZMA Decoder uses dictionary buffer and internal state structure. +Internal state structure consumes + state_size = (4 + (1.5 << (lc + lp))) KB +by default (lc=3, lp=0), state_size = 16 KB. + + +How To decompress data +---------------------- + +LZMA Decoder (ANSI-C version) now supports 2 interfaces: +1) Single-call Decompressing +2) Multi-call State Decompressing (zlib-like interface) + +You must use external allocator: +Example: +void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } +void SzFree(void *p, void *address) { p = p; free(address); } +ISzAlloc alloc = { SzAlloc, SzFree }; + +You can use p = p; operator to disable compiler warnings. + + +Single-call Decompressing +------------------------- +When to use: RAM->RAM decompressing +Compile files: LzmaDec.h + LzmaDec.c + Types.h +Compile defines: no defines +Memory Requirements: + - Input buffer: compressed size + - Output buffer: uncompressed size + - LZMA Internal Structures: state_size (16 KB for default settings) + +Interface: + int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size + propData - LZMA properties (5 bytes) + propSize - size of propData buffer (5 bytes) + finishMode - It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + You can use LZMA_FINISH_END, when you know that + current output buffer covers last bytes of stream. + alloc - Memory allocator. + + Out: + destLen - processed output size + srcLen - processed input size + + Output: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). + + If LZMA decoder sees end_marker before reaching output limit, it returns OK result, + and output value of destLen will be less than output buffer size limit. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + + +Multi-call State Decompressing (zlib-like interface) +---------------------------------------------------- + +When to use: file->file decompressing +Compile files: LzmaDec.h + LzmaDec.c + Types.h + +Memory Requirements: + - Buffer for input stream: any size (for example, 16 KB) + - Buffer for output stream: any size (for example, 16 KB) + - LZMA Internal Structures: state_size (16 KB for default settings) + - LZMA dictionary (dictionary size is encoded in LZMA properties header) + +1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header: + unsigned char header[LZMA_PROPS_SIZE + 8]; + ReadFile(inFile, header, sizeof(header) + +2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties + + CLzmaDec state; + LzmaDec_Constr(&state); + res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc); + if (res != SZ_OK) + return res; + +3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop + + LzmaDec_Init(&state); + for (;;) + { + ... + int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode); + ... + } + + +4) Free all allocated structures + LzmaDec_Free(&state, &g_Alloc); + +For full code example, look at C/LzmaUtil/LzmaUtil.c code. + + +How To compress data +-------------------- + +Compile files: LzmaEnc.h + LzmaEnc.c + Types.h + +LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h + +Memory Requirements: + - (dictSize * 11.5 + 6 MB) + state_size + +Lzma Encoder can use two memory allocators: +1) alloc - for small arrays. +2) allocBig - for big arrays. + +For example, you can use Large RAM Pages (2 MB) in allocBig allocator for +better compression speed. Note that Windows has bad implementation for +Large RAM Pages. +It's OK to use same allocator for alloc and allocBig. + + +Single-call Compression with callbacks +-------------------------------------- + +Check C/LzmaUtil/LzmaUtil.c as example, + +When to use: file->file decompressing + +1) you must implement callback structures for interfaces: +ISeqInStream +ISeqOutStream +ICompressProgress +ISzAlloc + +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + + CFileSeqInStream inStream; + CFileSeqOutStream outStream; + + inStream.funcTable.Read = MyRead; + inStream.file = inFile; + outStream.funcTable.Write = MyWrite; + outStream.file = outFile; + + +2) Create CLzmaEncHandle object; + + CLzmaEncHandle enc; + + enc = LzmaEnc_Create(&g_Alloc); + if (enc == 0) + return SZ_ERROR_MEM; + + +3) initialize CLzmaEncProps properties; + + LzmaEncProps_Init(&props); + + Then you can change some properties in that structure. + +4) Send LZMA properties to LZMA Encoder + + res = LzmaEnc_SetProps(enc, &props); + +5) Write encoded properties to header + + Byte header[LZMA_PROPS_SIZE + 8]; + size_t headerSize = LZMA_PROPS_SIZE; + UInt64 fileSize; + int i; + + res = LzmaEnc_WriteProperties(enc, header, &headerSize); + fileSize = MyGetFileLength(inFile); + for (i = 0; i < 8; i++) + header[headerSize++] = (Byte)(fileSize >> (8 * i)); + MyWriteFileAndCheck(outFile, header, headerSize) + +6) Call encoding function: + res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable, + NULL, &g_Alloc, &g_Alloc); + +7) Destroy LZMA Encoder Object + LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); + + +If callback function return some error code, LzmaEnc_Encode also returns that code. + + +Single-call RAM->RAM Compression +-------------------------------- + +Single-call RAM->RAM Compression is similar to Compression with callbacks, +but you provide pointers to buffers instead of pointers to stream callbacks: + +HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) + + + +LZMA Defines +------------ + +_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code. + +_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for + some structures will be doubled in that case. + +_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit. + +_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type. + + +C++ LZMA Encoder/Decoder +~~~~~~~~~~~~~~~~~~~~~~~~ +C++ LZMA code use COM-like interfaces. So if you want to use it, +you can study basics of COM/OLE. +C++ LZMA code is just wrapper over ANSI-C code. + + +C++ Notes +~~~~~~~~~~~~~~~~~~~~~~~~ +If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling), +you must check that you correctly work with "new" operator. +7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator. +So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator: +operator new(size_t size) +{ + void *p = ::malloc(size); + if (p == 0) + throw CNewException(); + return p; +} +If you use MSCV that throws exception for "new" operator, you can compile without +"NewHandler.cpp". So standard exception will be used. Actually some code of +7-Zip catches any exception in internal code and converts it to HRESULT code. +So you don't need to catch CNewException, if you call COM interfaces of 7-Zip. + +--- + +http://www.7-zip.org +http://www.7-zip.org/sdk.html +http://www.7-zip.org/support.html diff --git a/fex/changes.txt b/fex/changes.txt index 446f0415..924b8984 100644 --- a/fex/changes.txt +++ b/fex/changes.txt @@ -1,71 +1,71 @@ -File_Extractor Change Log -------------------------- -- Change that might break code. -+ Improvement that is unlikely to break any code. -* Other changes. - - -File_Extractor 1.0.0 (2009-10-12) --------------------- -- Added fex_stat() which MUST be called before getting current file -information beyond name, like fex_size(). - -- Changed fex_*() functions to always report error via return value, -rather than sometimes via a parameter. This will break user code that -uses fex_data(), fex_open(), fex_open_type(), and fex_identify_file(). -See demos for usage. - -- Deprecated C++ interface. Use fex.h and nothing else to access library -from user code. - -- Removed archive types (fex_zip_type, etc.) from interface. Use -fex_identify_extension() to get particular type. - -- Removed fex_mini.c, unzip.h, and unrarlib.h for now, as maintaining -them was too taxing. If others express desire for them, I can re-add -them. - -- Removed fex_scan_only() and fex_read_once(), as they don't improve -performance anymore. Use fex_read() in place of fex_read_once(). - -- Removed fex_remain(). Use fex_size()-fex_tell() to find number of -bytes remaining. - -- Removed fex_set_user_data() and related functions, as they didn't seem -useful to anyone. - -- Removed fex_type_t structure from interface and added accessors -instead (fex_type_name(), fex_type_extension()). - -+ Improved archive file type determination to reject other archive types -not handled by the library, rather than opening them as binary files. - -+ Added Doxygen compatibility to fex.h. - -+ Added fex_crc32() to quickly get CRC-32 of current file from archive -header, without having to read entire file to calculate it. - -+ Added fex_err_code() to get numeric error code, along with other -helpful error-related functions. Also added more documentation on how to -handle library errors in user code. - -+ Added fex_init() for use in multi-threaded programs. - -+ Added fex_seek_arc() to seek to particular file in archive. - -+ Added fex_wname() to get Unicode name of current file. - -+ Added support for building as DLL. - -+ Added support for wide-character file paths on Windows, enabled with -BLARGG_UTF8_PATHS (thanks to byuu for the idea). This is necessary to -support file paths on non-English Windows systems. - -+ Started using unit testing during development. - -+ Updated to 7-zip 4.65, unrar_core 3.8.5. - - -File_Extractor 0.4.3 (2008-12-08) --------------------- -* Limited release +File_Extractor Change Log +------------------------- +- Change that might break code. ++ Improvement that is unlikely to break any code. +* Other changes. + + +File_Extractor 1.0.0 (2009-10-12) +-------------------- +- Added fex_stat() which MUST be called before getting current file +information beyond name, like fex_size(). + +- Changed fex_*() functions to always report error via return value, +rather than sometimes via a parameter. This will break user code that +uses fex_data(), fex_open(), fex_open_type(), and fex_identify_file(). +See demos for usage. + +- Deprecated C++ interface. Use fex.h and nothing else to access library +from user code. + +- Removed archive types (fex_zip_type, etc.) from interface. Use +fex_identify_extension() to get particular type. + +- Removed fex_mini.c, unzip.h, and unrarlib.h for now, as maintaining +them was too taxing. If others express desire for them, I can re-add +them. + +- Removed fex_scan_only() and fex_read_once(), as they don't improve +performance anymore. Use fex_read() in place of fex_read_once(). + +- Removed fex_remain(). Use fex_size()-fex_tell() to find number of +bytes remaining. + +- Removed fex_set_user_data() and related functions, as they didn't seem +useful to anyone. + +- Removed fex_type_t structure from interface and added accessors +instead (fex_type_name(), fex_type_extension()). + ++ Improved archive file type determination to reject other archive types +not handled by the library, rather than opening them as binary files. + ++ Added Doxygen compatibility to fex.h. + ++ Added fex_crc32() to quickly get CRC-32 of current file from archive +header, without having to read entire file to calculate it. + ++ Added fex_err_code() to get numeric error code, along with other +helpful error-related functions. Also added more documentation on how to +handle library errors in user code. + ++ Added fex_init() for use in multi-threaded programs. + ++ Added fex_seek_arc() to seek to particular file in archive. + ++ Added fex_wname() to get Unicode name of current file. + ++ Added support for building as DLL. + ++ Added support for wide-character file paths on Windows, enabled with +BLARGG_UTF8_PATHS (thanks to byuu for the idea). This is necessary to +support file paths on non-English Windows systems. + ++ Started using unit testing during development. + ++ Updated to 7-zip 4.65, unrar_core 3.8.5. + + +File_Extractor 0.4.3 (2008-12-08) +-------------------- +* Limited release diff --git a/fex/fex.txt b/fex/fex.txt index e94e641d..533df884 100644 --- a/fex/fex.txt +++ b/fex/fex.txt @@ -1,330 +1,330 @@ -File_Extractor 1.0.0 --------------------- -Author : Shay Green -Website : http://code.google.com/p/file-extractor/ -License : GNU LGPL 2.1 or later for all except unrar -Language: C interface, C++ implementation - - -Contents --------- -* Overview -* Limitations -* Extracting file data -* Archive file type handling -* Using in multiple threads -* Error handling -* Solving problems -* Thanks - - -Overview --------- -File_Exactor (fex) allows you to write one version of file-opening code -that handles normal files and archives of files. It presents each as a -series of files that you can scan and optionally extract; a single file -is made to act like an archive of just one file, so your code doesn't -need to do anything special to handle it. - -Basic steps for scanning and extracting from an archive: - - * Open an archive or normal file using fex_open(). - * Scanning/extraction loop: - - Exit loop if fex_done() returns true. - - Get current file's name with fex_name(). - - If more file information is needed, call fex_stat() first. - - If extracting, use fex_data() or fex_read(). - - Go to next file in archive with fex_next(). - * Close archive and free memory with fex_close(). - -You can stop scanning an archive at any point, for example once you've -found the file you're looking for. If you need to go back to the first -file, call fex_rewind() at any time. Be sure to check error codes -returned by most functions. - - -Limitations ------------ -All archives: -* A file's checksum is verified only after ALL its data is extracted. -* Encryption, segmentation, files larger than 2GB, and other extra -features are not supported. - -GZ archives: -* Only gzip archives of a single file are supported. If it has multiple -files, the reported size will be wrong. Multi-file gzip archives are -very rare. - -ZIP archives: -* Supports files compressed using either deflation or store -(uncompressed). Other compression schemes like BZip2 and Deflate64 are -not supported. -* Archive must have a valid directory structure at the end. - -RAR archives: -* Support for really old 1.x archives might not work. If you have some -of these old archives, send them to me so I can test them. - -7-zip: -* Solid archives can currently use lots of memory when open. - - -Extracting file data --------------------- -A file's data can be extracted with one or more calls to fex_read(), as -you would read from a normal file. Use fex_tell() to find out how much -has already been read. Use this if you need the data read into your own -structure in memory. - -File data can also be extracted to memory by the library with -fex_data(). The pointer returned is valid only until you go to another -file or close the archive, so this is only useful if you need to examine -or process the data immediately and not keep it around for later. -Archive extractors naturally keep a copy of the extracted data in memory -already for solid archive types (currently 7-zip and RAR), so this -function is optimized to avoid making a second copy of it in those -cases. - -Use fex_size() to find the size of the extracted data. Remember that -fex_stat() or fex_data() must be called BEFORE calling fex_size(). - - -Archive file type handling --------------------------- -By default, fex uses the filename extension and header to determine -archive type. If the filename extension is unrecognized or it lacks an -extension, fex examines the first few bytes of the file. If still -unrecognized, fex opens it as binary. Fex also checks for common archive -types that it doesn't support, so that it can reject as unsupported them -rather than unhelpfully opening them as binary. - -Your file format might itself be an archive, for example your files end -in ".rsn" yet are normal RAR archives, or they end in ".vgz" and are -gzipped. This is why fex checks the headers of files with unknown -filename extensions, rather than treating them as binary or rejecting -them. - -Type identification can be customized by using the various -identification functions and fex_open_type(). For example, you could -avoid the header check: - - fex_t* fex; - fex_type_t type = fex_identify_extension( path ); - if ( type == NULL ) - error( "Unsupported archive type" ); - - error( fex_open_type( &fex, path, type ) ); - -Note that you'll only get a NULL type for known archive type that fex -doesn't handle; you won't get it for your own files, for example -fex_identify_extension("myfile.foo") won't return NULL (unless for some -reason you've disabled binary file support). - -Use fex_type_list() to get a list of the types fex supports, for example -to tell the user what archive types your program supports: - - const fex_type_t* t; - for ( t = fex_type_list(); *t; t++ ) - printf( "%s\n", fex_type_name( *t ) ); - -To get the fex_type_t for a particular archive type, use -fex_identify_extension(): - - fex_type_t zip_type = fex_identify_extension( ".zip" ); - if ( zip_type == NULL ) - error( "ZIP isn't supported" ); - -Be sure to check the result as shown, rather than assuming the library -supports a particular archive type. Use an extension of "" to get the -type for binary files: - - fex_type_t bin_type = fex_identify_extension( "" ); - if ( bin_type == NULL ) - error( "Binary files aren't supported?!?" ); - - -Using in multiple threads -------------------------- -Fex supports multi-threaded programs. If only one thread at a time is -using the library, nothing special needs to be done. If more than one -thread is using the library, the following must be done: - -* Call fex_init() from the main thread and ensure it completes before -any other threads use any fex functions. This initializes shared data -tables used by the extractors. - -* For each archive opened, only access it from one thread at a time. -Different archives can be accessed from different threads without any -synchronization, since fex uses no global variables. If the same archive -must be accessed from multiple threads, all calls to any fex functions -must be in critical section(s). - - -Unicode file paths on Windows ------------------------------ -If using Windows and your program supports Unicode file paths, enable -BLARGG_UTF8_PATHS in blargg_config.h, and convert your wide-character -paths to UTF-8 before passing them to fex.h functions: - - /* Wide-character path that could have come from system */ - wchar_t wide_path [] = L"demo.zip"; - - /* Convert from wide path and check for error */ - char* path = fex_wide_to_path( wide_path ); - if ( path == NULL ) - error( "Out of memory" ); - - /* Use converted path for fex call */ - error( fex_open( &fex, path ) ); - - /* Free memory used by path */ - fex_free_path( path ); - -The converted path can be used with any of the fex functions that take -paths, for example fex_identify_extension() or fex_has_extension(). - - -Error handling --------------- -Most functions that can fail return fex_err_t, a pointer type. On -failure they return a pointer to an error object, and on success they -return NULL. Use fex_err_code() to get a conventional error code, or -fex_err_str() to get a string suitable for reporting to the user. - -There are two basic approches that your code can use to handle library -errors. It can return errors, or report them and exit the function via -some other means. - -Your code can return errors as the library does, using fex_err_t: - - #define RETURN_ERR( expr ) \ - do {\ - fex_err_t err = (expr);\ - if ( err != NULL )\ - return err;\ - } while ( 0 ) - - fex_err_t my_func() - { - RETURN_ERR( fex_foo() ); - RETURN_ERR( fex_bar() ); - return NULL; - } - -If you have your own error codes, you can convert fex's errors to them: - - // error codes that differ from library's - enum { - my_ok = 0, - my_generic_error = 123, - my_out_of_memory = 456, - my_file_not_found = 789 - // ... - }; - - int convert_error( fex_err_t err ) - { - switch ( fex_err_code( err ) ) - { - case fex_ok: return my_ok; - case fex_err_generic: return my_generic_error; - case fex_err_memory: return my_out_of_memory; - case fex_err_file_missing: return my_file_not_found; - // ... - default: return my_generic_error; - } - } - - #define RETURN_ERR( expr ) \ - do {\ - fex_err_t err = (expr);\ - if ( err != NULL )\ - return convert_error( err );\ - } while ( 0 ) - - int my_func() - { - RETURN_ERR( fex_foo() ); - RETURN_ERR( fex_bar() ); - return my_ok; - } - -The other approach is to pass all errors to an error handler function -that never returns if passed a non-success error value: - - // never returns if err != NULL - void handle_error( fex_err_t err ); - - void my_func() - { - handle_error( fex_foo() ); - handle_error( fex_bar() ); - } - -handle_error() could print the error and exit the program: - - void handle_error( fex_err_t err ) - { - if ( err != NULL ) - { - const char* str = fex_err_str( err ); - printf( "Error: %s\n", str ); - exit( EXIT_FAILURE ); - } - } - -handle_error() could also throw a C++ exception (or equivalently in C, -longmp() back to a setjmp() done inside caller()): - - void handle_error( fex_err_t err ) - { - switch ( fex_err_code( err ) ) - { - case fex_ok: return; - case fex_err_memory: throw std::bad_alloc(); - // ... - case fex_err_generic: - default: - throw std::runtime_error( fex_err_str( err ) ); - } - } - - void caller() - { - try - { - my_func(); - } - catch ( const std::exception& e ) - { - printf( "Error: %s\n", e.what() ); - } - } - - -Solving problems ----------------- -If you're having problems, try the following: - -* Enable debugging support in your environment. This enables assertions -and other run-time checks. In particular, be sure NDEBUG isn't defined. - -* Turn the compiler's optimizer is off. Sometimes an optimizer generates -bad code. - -* If multiple threads are being used, ensure that only one at a time is -accessing a given set of objects from the library. This library is not -in general thread-safe, though independent objects can be used in -separate threads. - -* If all else fails, see if the demo works. - - -Thanks ------- -Thanks to Richard Bannister, Kode54, byuu, Cless, and DJRobX for testing -and giving feedback for the library. Thanks to the authors of zlib, -unrar, and 7-zip. - --- -Shay Green +File_Extractor 1.0.0 +-------------------- +Author : Shay Green +Website : http://code.google.com/p/file-extractor/ +License : GNU LGPL 2.1 or later for all except unrar +Language: C interface, C++ implementation + + +Contents +-------- +* Overview +* Limitations +* Extracting file data +* Archive file type handling +* Using in multiple threads +* Error handling +* Solving problems +* Thanks + + +Overview +-------- +File_Exactor (fex) allows you to write one version of file-opening code +that handles normal files and archives of files. It presents each as a +series of files that you can scan and optionally extract; a single file +is made to act like an archive of just one file, so your code doesn't +need to do anything special to handle it. + +Basic steps for scanning and extracting from an archive: + + * Open an archive or normal file using fex_open(). + * Scanning/extraction loop: + - Exit loop if fex_done() returns true. + - Get current file's name with fex_name(). + - If more file information is needed, call fex_stat() first. + - If extracting, use fex_data() or fex_read(). + - Go to next file in archive with fex_next(). + * Close archive and free memory with fex_close(). + +You can stop scanning an archive at any point, for example once you've +found the file you're looking for. If you need to go back to the first +file, call fex_rewind() at any time. Be sure to check error codes +returned by most functions. + + +Limitations +----------- +All archives: +* A file's checksum is verified only after ALL its data is extracted. +* Encryption, segmentation, files larger than 2GB, and other extra +features are not supported. + +GZ archives: +* Only gzip archives of a single file are supported. If it has multiple +files, the reported size will be wrong. Multi-file gzip archives are +very rare. + +ZIP archives: +* Supports files compressed using either deflation or store +(uncompressed). Other compression schemes like BZip2 and Deflate64 are +not supported. +* Archive must have a valid directory structure at the end. + +RAR archives: +* Support for really old 1.x archives might not work. If you have some +of these old archives, send them to me so I can test them. + +7-zip: +* Solid archives can currently use lots of memory when open. + + +Extracting file data +-------------------- +A file's data can be extracted with one or more calls to fex_read(), as +you would read from a normal file. Use fex_tell() to find out how much +has already been read. Use this if you need the data read into your own +structure in memory. + +File data can also be extracted to memory by the library with +fex_data(). The pointer returned is valid only until you go to another +file or close the archive, so this is only useful if you need to examine +or process the data immediately and not keep it around for later. +Archive extractors naturally keep a copy of the extracted data in memory +already for solid archive types (currently 7-zip and RAR), so this +function is optimized to avoid making a second copy of it in those +cases. + +Use fex_size() to find the size of the extracted data. Remember that +fex_stat() or fex_data() must be called BEFORE calling fex_size(). + + +Archive file type handling +-------------------------- +By default, fex uses the filename extension and header to determine +archive type. If the filename extension is unrecognized or it lacks an +extension, fex examines the first few bytes of the file. If still +unrecognized, fex opens it as binary. Fex also checks for common archive +types that it doesn't support, so that it can reject as unsupported them +rather than unhelpfully opening them as binary. + +Your file format might itself be an archive, for example your files end +in ".rsn" yet are normal RAR archives, or they end in ".vgz" and are +gzipped. This is why fex checks the headers of files with unknown +filename extensions, rather than treating them as binary or rejecting +them. + +Type identification can be customized by using the various +identification functions and fex_open_type(). For example, you could +avoid the header check: + + fex_t* fex; + fex_type_t type = fex_identify_extension( path ); + if ( type == NULL ) + error( "Unsupported archive type" ); + + error( fex_open_type( &fex, path, type ) ); + +Note that you'll only get a NULL type for known archive type that fex +doesn't handle; you won't get it for your own files, for example +fex_identify_extension("myfile.foo") won't return NULL (unless for some +reason you've disabled binary file support). + +Use fex_type_list() to get a list of the types fex supports, for example +to tell the user what archive types your program supports: + + const fex_type_t* t; + for ( t = fex_type_list(); *t; t++ ) + printf( "%s\n", fex_type_name( *t ) ); + +To get the fex_type_t for a particular archive type, use +fex_identify_extension(): + + fex_type_t zip_type = fex_identify_extension( ".zip" ); + if ( zip_type == NULL ) + error( "ZIP isn't supported" ); + +Be sure to check the result as shown, rather than assuming the library +supports a particular archive type. Use an extension of "" to get the +type for binary files: + + fex_type_t bin_type = fex_identify_extension( "" ); + if ( bin_type == NULL ) + error( "Binary files aren't supported?!?" ); + + +Using in multiple threads +------------------------- +Fex supports multi-threaded programs. If only one thread at a time is +using the library, nothing special needs to be done. If more than one +thread is using the library, the following must be done: + +* Call fex_init() from the main thread and ensure it completes before +any other threads use any fex functions. This initializes shared data +tables used by the extractors. + +* For each archive opened, only access it from one thread at a time. +Different archives can be accessed from different threads without any +synchronization, since fex uses no global variables. If the same archive +must be accessed from multiple threads, all calls to any fex functions +must be in critical section(s). + + +Unicode file paths on Windows +----------------------------- +If using Windows and your program supports Unicode file paths, enable +BLARGG_UTF8_PATHS in blargg_config.h, and convert your wide-character +paths to UTF-8 before passing them to fex.h functions: + + /* Wide-character path that could have come from system */ + wchar_t wide_path [] = L"demo.zip"; + + /* Convert from wide path and check for error */ + char* path = fex_wide_to_path( wide_path ); + if ( path == NULL ) + error( "Out of memory" ); + + /* Use converted path for fex call */ + error( fex_open( &fex, path ) ); + + /* Free memory used by path */ + fex_free_path( path ); + +The converted path can be used with any of the fex functions that take +paths, for example fex_identify_extension() or fex_has_extension(). + + +Error handling +-------------- +Most functions that can fail return fex_err_t, a pointer type. On +failure they return a pointer to an error object, and on success they +return NULL. Use fex_err_code() to get a conventional error code, or +fex_err_str() to get a string suitable for reporting to the user. + +There are two basic approches that your code can use to handle library +errors. It can return errors, or report them and exit the function via +some other means. + +Your code can return errors as the library does, using fex_err_t: + + #define RETURN_ERR( expr ) \ + do {\ + fex_err_t err = (expr);\ + if ( err != NULL )\ + return err;\ + } while ( 0 ) + + fex_err_t my_func() + { + RETURN_ERR( fex_foo() ); + RETURN_ERR( fex_bar() ); + return NULL; + } + +If you have your own error codes, you can convert fex's errors to them: + + // error codes that differ from library's + enum { + my_ok = 0, + my_generic_error = 123, + my_out_of_memory = 456, + my_file_not_found = 789 + // ... + }; + + int convert_error( fex_err_t err ) + { + switch ( fex_err_code( err ) ) + { + case fex_ok: return my_ok; + case fex_err_generic: return my_generic_error; + case fex_err_memory: return my_out_of_memory; + case fex_err_file_missing: return my_file_not_found; + // ... + default: return my_generic_error; + } + } + + #define RETURN_ERR( expr ) \ + do {\ + fex_err_t err = (expr);\ + if ( err != NULL )\ + return convert_error( err );\ + } while ( 0 ) + + int my_func() + { + RETURN_ERR( fex_foo() ); + RETURN_ERR( fex_bar() ); + return my_ok; + } + +The other approach is to pass all errors to an error handler function +that never returns if passed a non-success error value: + + // never returns if err != NULL + void handle_error( fex_err_t err ); + + void my_func() + { + handle_error( fex_foo() ); + handle_error( fex_bar() ); + } + +handle_error() could print the error and exit the program: + + void handle_error( fex_err_t err ) + { + if ( err != NULL ) + { + const char* str = fex_err_str( err ); + printf( "Error: %s\n", str ); + exit( EXIT_FAILURE ); + } + } + +handle_error() could also throw a C++ exception (or equivalently in C, +longmp() back to a setjmp() done inside caller()): + + void handle_error( fex_err_t err ) + { + switch ( fex_err_code( err ) ) + { + case fex_ok: return; + case fex_err_memory: throw std::bad_alloc(); + // ... + case fex_err_generic: + default: + throw std::runtime_error( fex_err_str( err ) ); + } + } + + void caller() + { + try + { + my_func(); + } + catch ( const std::exception& e ) + { + printf( "Error: %s\n", e.what() ); + } + } + + +Solving problems +---------------- +If you're having problems, try the following: + +* Enable debugging support in your environment. This enables assertions +and other run-time checks. In particular, be sure NDEBUG isn't defined. + +* Turn the compiler's optimizer is off. Sometimes an optimizer generates +bad code. + +* If multiple threads are being used, ensure that only one at a time is +accessing a given set of objects from the library. This library is not +in general thread-safe, though independent objects can be used in +separate threads. + +* If all else fails, see if the demo works. + + +Thanks +------ +Thanks to Richard Bannister, Kode54, byuu, Cless, and DJRobX for testing +and giving feedback for the library. Thanks to the authors of zlib, +unrar, and 7-zip. + +-- +Shay Green diff --git a/fex/fex/Binary_Extractor.cpp b/fex/fex/Binary_Extractor.cpp index 7940c0a0..8c85b992 100644 --- a/fex/fex/Binary_Extractor.cpp +++ b/fex/fex/Binary_Extractor.cpp @@ -1,77 +1,77 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "Binary_Extractor.h" - -/* Copyright (C) 2005-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -// TODO: could close file once data has been read into memory - -static File_Extractor* new_binary() -{ - return BLARGG_NEW Binary_Extractor; -} - -fex_type_t_ const fex_bin_type [1] = {{ - "", - &new_binary, - "file", - NULL -}}; - -Binary_Extractor::Binary_Extractor() : - File_Extractor( fex_bin_type ) -{ } - -Binary_Extractor::~Binary_Extractor() -{ - close(); -} - -blargg_err_t Binary_Extractor::open_path_v() -{ - set_name( arc_path() ); - return blargg_ok; -} - -blargg_err_t Binary_Extractor::open_v() -{ - set_name( arc_path() ); - set_info( arc().remain(), 0, 0 ); - return blargg_ok; -} - -void Binary_Extractor::close_v() -{ } - -blargg_err_t Binary_Extractor::next_v() -{ - return blargg_ok; -} - -blargg_err_t Binary_Extractor::rewind_v() -{ - return open_path_v(); -} - -blargg_err_t Binary_Extractor::stat_v() -{ - RETURN_ERR( open_arc_file() ); - RETURN_ERR( arc().seek( 0 ) ); - return open_v(); -} - -blargg_err_t Binary_Extractor::extract_v( void* p, int n ) -{ - return arc().read( p, n ); -} +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "Binary_Extractor.h" + +/* Copyright (C) 2005-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +// TODO: could close file once data has been read into memory + +static File_Extractor* new_binary() +{ + return BLARGG_NEW Binary_Extractor; +} + +fex_type_t_ const fex_bin_type [1] = {{ + "", + &new_binary, + "file", + NULL +}}; + +Binary_Extractor::Binary_Extractor() : + File_Extractor( fex_bin_type ) +{ } + +Binary_Extractor::~Binary_Extractor() +{ + close(); +} + +blargg_err_t Binary_Extractor::open_path_v() +{ + set_name( arc_path() ); + return blargg_ok; +} + +blargg_err_t Binary_Extractor::open_v() +{ + set_name( arc_path() ); + set_info( arc().remain(), 0, 0 ); + return blargg_ok; +} + +void Binary_Extractor::close_v() +{ } + +blargg_err_t Binary_Extractor::next_v() +{ + return blargg_ok; +} + +blargg_err_t Binary_Extractor::rewind_v() +{ + return open_path_v(); +} + +blargg_err_t Binary_Extractor::stat_v() +{ + RETURN_ERR( open_arc_file() ); + RETURN_ERR( arc().seek( 0 ) ); + return open_v(); +} + +blargg_err_t Binary_Extractor::extract_v( void* p, int n ) +{ + return arc().read( p, n ); +} diff --git a/fex/fex/Binary_Extractor.h b/fex/fex/Binary_Extractor.h index d8cca642..339a0873 100644 --- a/fex/fex/Binary_Extractor.h +++ b/fex/fex/Binary_Extractor.h @@ -1,26 +1,26 @@ -// Presents a single file as an "archive" of just that file. - -// File_Extractor 1.0.0 -#ifndef BINARY_EXTRACTOR_H -#define BINARY_EXTRACTOR_H - -#include "File_Extractor.h" - -class Binary_Extractor : public File_Extractor { -public: - Binary_Extractor(); - virtual ~Binary_Extractor(); - -protected: - virtual blargg_err_t open_path_v(); - virtual blargg_err_t open_v(); - virtual void close_v(); - - virtual blargg_err_t next_v(); - virtual blargg_err_t rewind_v(); - - virtual blargg_err_t stat_v(); - virtual blargg_err_t extract_v( void*, int ); -}; - -#endif +// Presents a single file as an "archive" of just that file. + +// File_Extractor 1.0.0 +#ifndef BINARY_EXTRACTOR_H +#define BINARY_EXTRACTOR_H + +#include "File_Extractor.h" + +class Binary_Extractor : public File_Extractor { +public: + Binary_Extractor(); + virtual ~Binary_Extractor(); + +protected: + virtual blargg_err_t open_path_v(); + virtual blargg_err_t open_v(); + virtual void close_v(); + + virtual blargg_err_t next_v(); + virtual blargg_err_t rewind_v(); + + virtual blargg_err_t stat_v(); + virtual blargg_err_t extract_v( void*, int ); +}; + +#endif diff --git a/fex/fex/Data_Reader.cpp b/fex/fex/Data_Reader.cpp index e5a8d49a..83b09e2f 100644 --- a/fex/fex/Data_Reader.cpp +++ b/fex/fex/Data_Reader.cpp @@ -1,765 +1,765 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "Data_Reader.h" - -#include "blargg_endian.h" -#include -#include -#include - -#if BLARGG_UTF8_PATHS - #include -#endif - -/* Copyright (C) 2005-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -// Data_Reader - -blargg_err_t Data_Reader::read( void* p, int n ) -{ - assert( n >= 0 ); - - if ( n < 0 ) - return blargg_err_caller; - - if ( n <= 0 ) - return blargg_ok; - - if ( n > remain() ) - return blargg_err_file_eof; - - blargg_err_t err = read_v( p, n ); - if ( !err ) - remain_ -= n; - - return err; -} - -blargg_err_t Data_Reader::read_avail( void* p, int* n_ ) -{ - assert( *n_ >= 0 ); - - int n = min( *n_, remain() ); - *n_ = 0; - - if ( n < 0 ) - return blargg_err_caller; - - if ( n <= 0 ) - return blargg_ok; - - blargg_err_t err = read_v( p, n ); - if ( !err ) - { - remain_ -= n; - *n_ = n; - } - - return err; -} - -blargg_err_t Data_Reader::read_avail( void* p, long* n ) -{ - int i = STATIC_CAST(int, *n); - blargg_err_t err = read_avail( p, &i ); - *n = i; - return err; -} - -blargg_err_t Data_Reader::skip_v( int count ) -{ - char buf [512]; - while ( count ) - { - int n = min( count, (int) sizeof buf ); - count -= n; - RETURN_ERR( read_v( buf, n ) ); - } - return blargg_ok; -} - -blargg_err_t Data_Reader::skip( int n ) -{ - assert( n >= 0 ); - - if ( n < 0 ) - return blargg_err_caller; - - if ( n <= 0 ) - return blargg_ok; - - if ( n > remain() ) - return blargg_err_file_eof; - - blargg_err_t err = skip_v( n ); - if ( !err ) - remain_ -= n; - - return err; -} - - -// File_Reader - -blargg_err_t File_Reader::seek( int n ) -{ - assert( n >= 0 ); - - if ( n < 0 ) - return blargg_err_caller; - - if ( n == tell() ) - return blargg_ok; - - if ( n > size() ) - return blargg_err_file_eof; - - blargg_err_t err = seek_v( n ); - if ( !err ) - set_tell( n ); - - return err; -} - -blargg_err_t File_Reader::skip_v( int n ) -{ - return seek_v( tell() + n ); -} - - -// Subset_Reader - -Subset_Reader::Subset_Reader( Data_Reader* dr, int size ) : - in( dr ) -{ - set_remain( min( size, dr->remain() ) ); -} - -blargg_err_t Subset_Reader::read_v( void* p, int s ) -{ - return in->read( p, s ); -} - - -// Remaining_Reader - -Remaining_Reader::Remaining_Reader( void const* h, int size, Data_Reader* r ) : - in( r ) -{ - header = h; - header_remain = size; - - set_remain( size + r->remain() ); -} - -blargg_err_t Remaining_Reader::read_v( void* out, int count ) -{ - int first = min( count, header_remain ); - if ( first ) - { - memcpy( out, header, first ); - header = STATIC_CAST(char const*, header) + first; - header_remain -= first; - } - - return in->read( STATIC_CAST(char*, out) + first, count - first ); -} - - -// Mem_File_Reader - -Mem_File_Reader::Mem_File_Reader( const void* p, long s ) : - begin( STATIC_CAST(const char*, p) ) -{ - set_size( s ); -} - -blargg_err_t Mem_File_Reader::read_v( void* p, int s ) -{ - memcpy( p, begin + tell(), s ); - return blargg_ok; -} - -blargg_err_t Mem_File_Reader::seek_v( int ) -{ - return blargg_ok; -} - - -// Callback_Reader - -Callback_Reader::Callback_Reader( callback_t c, long s, void* d ) : - callback( c ), - user_data( d ) -{ - set_remain( s ); -} - -blargg_err_t Callback_Reader::read_v( void* out, int count ) -{ - return callback( user_data, out, count ); -} - - -// Callback_File_Reader - -Callback_File_Reader::Callback_File_Reader( callback_t c, long s, void* d ) : - callback( c ), - user_data( d ) -{ - set_size( s ); -} - -blargg_err_t Callback_File_Reader::read_v( void* out, int count ) -{ - return callback( user_data, out, count, tell() ); -} - -blargg_err_t Callback_File_Reader::seek_v( int ) -{ - return blargg_ok; -} - -static const BOOST::uint8_t mask_tab[6]={0x80,0xE0,0xF0,0xF8,0xFC,0xFE}; - -static const BOOST::uint8_t val_tab[6]={0,0xC0,0xE0,0xF0,0xF8,0xFC}; - -size_t utf8_char_len_from_header( char p_c ) -{ - BOOST::uint8_t c = (BOOST::uint8_t)p_c; - - size_t cnt = 0; - for(;;) - { - if ( ( p_c & mask_tab[cnt] ) == val_tab[cnt] ) break; - if ( ++cnt >= 6 ) return 0; - } - - return cnt + 1; -} - -size_t utf8_decode_char( const char *p_utf8, unsigned & wide, size_t mmax ) -{ - const BOOST::uint8_t * utf8 = ( const BOOST::uint8_t* )p_utf8; - - if ( mmax == 0 ) - { - wide = 0; - return 0; - } - - if ( utf8[0] < 0x80 ) - { - wide = utf8[0]; - return utf8[0]>0 ? 1 : 0; - } - if ( mmax > 6 ) mmax = 6; - wide = 0; - - unsigned res=0; - unsigned n; - unsigned cnt=0; - for(;;) - { - if ( ( *utf8 & mask_tab[cnt] ) == val_tab[cnt] ) break; - if ( ++cnt >= mmax ) return 0; - } - cnt++; - - if ( cnt==2 && !( *utf8 & 0x1E ) ) return 0; - - if ( cnt == 1 ) - res = *utf8; - else - res = ( 0xFF >> ( cnt + 1 ) ) & *utf8; - - for ( n = 1; n < cnt; n++ ) - { - if ( ( utf8[n] & 0xC0 ) != 0x80 ) - return 0; - if ( !res && n == 2 && !( ( utf8[n] & 0x7F ) >> ( 7 - cnt ) ) ) - return 0; - - res = ( res << 6 ) | ( utf8[n] & 0x3F ); - } - - wide = res; - - return cnt; -} - -size_t utf8_encode_char( unsigned wide, char * target ) -{ - size_t count; - - if ( wide < 0x80 ) - count = 1; - else if ( wide < 0x800 ) - count = 2; - else if ( wide < 0x10000 ) - count = 3; - else if ( wide < 0x200000 ) - count = 4; - else if ( wide < 0x4000000 ) - count = 5; - else if ( wide <= 0x7FFFFFFF ) - count = 6; - else - return 0; - - if ( target == 0 ) - return count; - - switch ( count ) - { - case 6: - target[5] = 0x80 | ( wide & 0x3F ); - wide = wide >> 6; - wide |= 0x4000000; - case 5: - target[4] = 0x80 | ( wide & 0x3F ); - wide = wide >> 6; - wide |= 0x200000; - case 4: - target[3] = 0x80 | ( wide & 0x3F ); - wide = wide >> 6; - wide |= 0x10000; - case 3: - target[2] = 0x80 | ( wide & 0x3F ); - wide = wide >> 6; - wide |= 0x800; - case 2: - target[1] = 0x80 | ( wide & 0x3F ); - wide = wide >> 6; - wide |= 0xC0; - case 1: - target[0] = wide; - } - - return count; -} - -size_t utf16_encode_char( unsigned cur_wchar, wchar_t * out ) -{ - if ( cur_wchar < 0x10000 ) - { - if ( out ) *out = (wchar_t) cur_wchar; return 1; - } - else if ( cur_wchar < ( 1 << 20 ) ) - { - unsigned c = cur_wchar - 0x10000; - //MSDN: - //The first (high) surrogate is a 16-bit code value in the range U+D800 to U+DBFF. The second (low) surrogate is a 16-bit code value in the range U+DC00 to U+DFFF. Using surrogates, Unicode can support over one million characters. For more details about surrogates, refer to The Unicode Standard, version 2.0. - if ( out ) - { - out[0] = ( wchar_t )( 0xD800 | ( 0x3FF & ( c >> 10 ) ) ); - out[1] = ( wchar_t )( 0xDC00 | ( 0x3FF & c ) ) ; - } - return 2; - } - else - { - if ( out ) *out = '?'; return 1; - } -} - -size_t utf16_decode_char( const wchar_t * p_source, unsigned * p_out, size_t p_source_length ) -{ - if ( p_source_length == 0 ) return 0; - else if ( p_source_length == 1 ) - { - *p_out = p_source[0]; - return 1; - } - else - { - size_t retval = 0; - unsigned decoded = p_source[0]; - if ( decoded != 0 ) - { - retval = 1; - if ( ( decoded & 0xFC00 ) == 0xD800 ) - { - unsigned low = p_source[1]; - if ( ( low & 0xFC00 ) == 0xDC00 ) - { - decoded = 0x10000 + ( ( ( decoded & 0x3FF ) << 10 ) | ( low & 0x3FF ) ); - retval = 2; - } - } - } - *p_out = decoded; - return retval; - } -} - -// Converts wide-character path to UTF-8. Free result with free(). Only supported on Windows. -char* blargg_to_utf8( const wchar_t* wpath ) -{ - if ( wpath == NULL ) - return NULL; - - size_t needed = 0; - size_t mmax = wcslen( wpath ); - if ( mmax <= 0 ) - return NULL; - - size_t ptr = 0; - while ( ptr < mmax ) - { - unsigned wide = 0; - size_t char_len = utf16_decode_char( wpath + ptr, &wide, mmax - ptr ); - if ( !char_len ) break; - ptr += char_len; - needed += utf8_encode_char( wide, 0 ); - } - if ( needed <= 0 ) - return NULL; - - char* path = (char*) calloc( needed + 1, 1 ); - if ( path == NULL ) - return NULL; - - ptr = 0; - size_t actual = 0; - while ( ptr < mmax && actual < needed ) - { - unsigned wide = 0; - size_t char_len = utf16_decode_char( wpath + ptr, &wide, mmax - ptr ); - if ( !char_len ) break; - ptr += char_len; - actual += utf8_encode_char( wide, path + actual ); - } - - if ( actual == 0 ) - { - free( path ); - return NULL; - } - - assert( actual == needed ); - return path; -} - -// Converts UTF-8 path to wide-character. Free result with free() Only supported on Windows. -wchar_t* blargg_to_wide( const char* path ) -{ - if ( path == NULL ) - return NULL; - - size_t mmax = strlen( path ); - if ( mmax <= 0 ) - return NULL; - - size_t needed = 0; - size_t ptr = 0; - while ( ptr < mmax ) - { - unsigned wide = 0; - size_t char_len = utf8_decode_char( path + ptr, wide, mmax - ptr ); - if ( !char_len ) break; - ptr += char_len; - needed += utf16_encode_char( wide, 0 ); - } - if ( needed <= 0 ) - return NULL; - - wchar_t* wpath = (wchar_t*) calloc( needed + 1, sizeof *wpath ); - if ( wpath == NULL ) - return NULL; - - ptr = 0; - size_t actual = 0; - while ( ptr < mmax && actual < needed ) - { - unsigned wide = 0; - size_t char_len = utf8_decode_char( path + ptr, wide, mmax - ptr ); - if ( !char_len ) break; - ptr += char_len; - actual += utf16_encode_char( wide, wpath + actual ); - } - if ( actual == 0 ) - { - free( wpath ); - return NULL; - } - - assert( actual == needed ); - return wpath; -} - -#ifdef _WIN32 - -static FILE* blargg_fopen( const char path [], const char mode [] ) -{ - FILE* file = NULL; - wchar_t* wmode = NULL; - wchar_t* wpath = NULL; - - wpath = blargg_to_wide( path ); - if ( wpath ) - { - wmode = blargg_to_wide( mode ); - if ( wmode ) - file = _wfopen( wpath, wmode ); - } - - // Save and restore errno in case free() clears it - int saved_errno = errno; - free( wmode ); - free( wpath ); - errno = saved_errno; - - return file; -} - -#else - -static inline FILE* blargg_fopen( const char path [], const char mode [] ) -{ - return fopen( path, mode ); -} - -#endif - - -// Std_File_Reader - -Std_File_Reader::Std_File_Reader() -{ - file_ = NULL; -} - -Std_File_Reader::~Std_File_Reader() -{ - close(); -} - -static blargg_err_t blargg_fopen( FILE** out, const char path [] ) -{ - errno = 0; - *out = blargg_fopen( path, "rb" ); - if ( !*out ) - { - #ifdef ENOENT - if ( errno == ENOENT ) - return blargg_err_file_missing; - #endif - #ifdef ENOMEM - if ( errno == ENOMEM ) - return blargg_err_memory; - #endif - return blargg_err_file_read; - } - - return blargg_ok; -} - -static blargg_err_t blargg_fsize( FILE* f, long* out ) -{ - if ( fseek( f, 0, SEEK_END ) ) - return blargg_err_file_io; - - *out = ftell( f ); - if ( *out < 0 ) - return blargg_err_file_io; - - if ( fseek( f, 0, SEEK_SET ) ) - return blargg_err_file_io; - - return blargg_ok; -} - -blargg_err_t Std_File_Reader::open( const char path [] ) -{ - close(); - - FILE* f; - RETURN_ERR( blargg_fopen( &f, path ) ); - - long s; - blargg_err_t err = blargg_fsize( f, &s ); - if ( err ) - { - fclose( f ); - return err; - } - - file_ = f; - set_size( s ); - - return blargg_ok; -} - -void Std_File_Reader::make_unbuffered() -{ - if ( setvbuf( STATIC_CAST(FILE*, file_), NULL, _IONBF, 0 ) ) - check( false ); // shouldn't fail, but OK if it does -} - -blargg_err_t Std_File_Reader::read_v( void* p, int s ) -{ - if ( (size_t) s != fread( p, 1, s, STATIC_CAST(FILE*, file_) ) ) - { - // Data_Reader's wrapper should prevent EOF - check( !feof( STATIC_CAST(FILE*, file_) ) ); - - return blargg_err_file_io; - } - - return blargg_ok; -} - -blargg_err_t Std_File_Reader::seek_v( int n ) -{ - if ( fseek( STATIC_CAST(FILE*, file_), n, SEEK_SET ) ) - { - // Data_Reader's wrapper should prevent EOF - check( !feof( STATIC_CAST(FILE*, file_) ) ); - - return blargg_err_file_io; - } - - return blargg_ok; -} - -void Std_File_Reader::close() -{ - if ( file_ ) - { - fclose( STATIC_CAST(FILE*, file_) ); - file_ = NULL; - } -} - - -// Gzip_File_Reader - -#ifdef HAVE_ZLIB_H - -#include "zlib.h" - -static const char* get_gzip_eof( const char path [], long* eof ) -{ - FILE* file; - RETURN_ERR( blargg_fopen( &file, path ) ); - - int const h_size = 4; - unsigned char h [h_size]; - - // read four bytes to ensure that we can seek to -4 later - if ( fread( h, 1, h_size, file ) != (size_t) h_size || h[0] != 0x1F || h[1] != 0x8B ) - { - // Not gzipped - if ( ferror( file ) ) - return blargg_err_file_io; - - if ( fseek( file, 0, SEEK_END ) ) - return blargg_err_file_io; - - *eof = ftell( file ); - if ( *eof < 0 ) - return blargg_err_file_io; - } - else - { - // Gzipped; get uncompressed size from end - if ( fseek( file, -h_size, SEEK_END ) ) - return blargg_err_file_io; - - if ( fread( h, 1, h_size, file ) != (size_t) h_size ) - return blargg_err_file_io; - - *eof = get_le32( h ); - } - - if ( fclose( file ) ) - check( false ); - - return blargg_ok; -} - -Gzip_File_Reader::Gzip_File_Reader() -{ - file_ = NULL; -} - -Gzip_File_Reader::~Gzip_File_Reader() -{ - close(); -} - -blargg_err_t Gzip_File_Reader::open( const char path [] ) -{ - close(); - - long s; - RETURN_ERR( get_gzip_eof( path, &s ) ); - - file_ = gzopen( path, "rb" ); - if ( !file_ ) - return blargg_err_file_read; - - set_size( s ); - return blargg_ok; -} - -static blargg_err_t convert_gz_error( gzFile file ) -{ - int err; - gzerror( file, &err ); - - switch ( err ) - { - case Z_STREAM_ERROR: break; - case Z_DATA_ERROR: return blargg_err_file_corrupt; - case Z_MEM_ERROR: return blargg_err_memory; - case Z_BUF_ERROR: break; - } - return blargg_err_internal; -} - -blargg_err_t Gzip_File_Reader::read_v( void* p, int s ) -{ - int result = gzread( file_, p, s ); - if ( result != s ) - { - if ( result < 0 ) - return convert_gz_error( file_ ); - - return blargg_err_file_corrupt; - } - - return blargg_ok; -} - -blargg_err_t Gzip_File_Reader::seek_v( int n ) -{ - if ( gzseek( file_, n, SEEK_SET ) < 0 ) - return convert_gz_error( file_ ); - - return blargg_ok; -} - -void Gzip_File_Reader::close() -{ - if ( file_ ) - { - if ( gzclose( file_ ) ) - check( false ); - file_ = NULL; - } -} - -#endif +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "Data_Reader.h" + +#include "blargg_endian.h" +#include +#include +#include + +#if BLARGG_UTF8_PATHS + #include +#endif + +/* Copyright (C) 2005-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +// Data_Reader + +blargg_err_t Data_Reader::read( void* p, int n ) +{ + assert( n >= 0 ); + + if ( n < 0 ) + return blargg_err_caller; + + if ( n <= 0 ) + return blargg_ok; + + if ( n > remain() ) + return blargg_err_file_eof; + + blargg_err_t err = read_v( p, n ); + if ( !err ) + remain_ -= n; + + return err; +} + +blargg_err_t Data_Reader::read_avail( void* p, int* n_ ) +{ + assert( *n_ >= 0 ); + + int n = min( *n_, remain() ); + *n_ = 0; + + if ( n < 0 ) + return blargg_err_caller; + + if ( n <= 0 ) + return blargg_ok; + + blargg_err_t err = read_v( p, n ); + if ( !err ) + { + remain_ -= n; + *n_ = n; + } + + return err; +} + +blargg_err_t Data_Reader::read_avail( void* p, long* n ) +{ + int i = STATIC_CAST(int, *n); + blargg_err_t err = read_avail( p, &i ); + *n = i; + return err; +} + +blargg_err_t Data_Reader::skip_v( int count ) +{ + char buf [512]; + while ( count ) + { + int n = min( count, (int) sizeof buf ); + count -= n; + RETURN_ERR( read_v( buf, n ) ); + } + return blargg_ok; +} + +blargg_err_t Data_Reader::skip( int n ) +{ + assert( n >= 0 ); + + if ( n < 0 ) + return blargg_err_caller; + + if ( n <= 0 ) + return blargg_ok; + + if ( n > remain() ) + return blargg_err_file_eof; + + blargg_err_t err = skip_v( n ); + if ( !err ) + remain_ -= n; + + return err; +} + + +// File_Reader + +blargg_err_t File_Reader::seek( int n ) +{ + assert( n >= 0 ); + + if ( n < 0 ) + return blargg_err_caller; + + if ( n == tell() ) + return blargg_ok; + + if ( n > size() ) + return blargg_err_file_eof; + + blargg_err_t err = seek_v( n ); + if ( !err ) + set_tell( n ); + + return err; +} + +blargg_err_t File_Reader::skip_v( int n ) +{ + return seek_v( tell() + n ); +} + + +// Subset_Reader + +Subset_Reader::Subset_Reader( Data_Reader* dr, int size ) : + in( dr ) +{ + set_remain( min( size, dr->remain() ) ); +} + +blargg_err_t Subset_Reader::read_v( void* p, int s ) +{ + return in->read( p, s ); +} + + +// Remaining_Reader + +Remaining_Reader::Remaining_Reader( void const* h, int size, Data_Reader* r ) : + in( r ) +{ + header = h; + header_remain = size; + + set_remain( size + r->remain() ); +} + +blargg_err_t Remaining_Reader::read_v( void* out, int count ) +{ + int first = min( count, header_remain ); + if ( first ) + { + memcpy( out, header, first ); + header = STATIC_CAST(char const*, header) + first; + header_remain -= first; + } + + return in->read( STATIC_CAST(char*, out) + first, count - first ); +} + + +// Mem_File_Reader + +Mem_File_Reader::Mem_File_Reader( const void* p, long s ) : + begin( STATIC_CAST(const char*, p) ) +{ + set_size( s ); +} + +blargg_err_t Mem_File_Reader::read_v( void* p, int s ) +{ + memcpy( p, begin + tell(), s ); + return blargg_ok; +} + +blargg_err_t Mem_File_Reader::seek_v( int ) +{ + return blargg_ok; +} + + +// Callback_Reader + +Callback_Reader::Callback_Reader( callback_t c, long s, void* d ) : + callback( c ), + user_data( d ) +{ + set_remain( s ); +} + +blargg_err_t Callback_Reader::read_v( void* out, int count ) +{ + return callback( user_data, out, count ); +} + + +// Callback_File_Reader + +Callback_File_Reader::Callback_File_Reader( callback_t c, long s, void* d ) : + callback( c ), + user_data( d ) +{ + set_size( s ); +} + +blargg_err_t Callback_File_Reader::read_v( void* out, int count ) +{ + return callback( user_data, out, count, tell() ); +} + +blargg_err_t Callback_File_Reader::seek_v( int ) +{ + return blargg_ok; +} + +static const BOOST::uint8_t mask_tab[6]={0x80,0xE0,0xF0,0xF8,0xFC,0xFE}; + +static const BOOST::uint8_t val_tab[6]={0,0xC0,0xE0,0xF0,0xF8,0xFC}; + +size_t utf8_char_len_from_header( char p_c ) +{ + BOOST::uint8_t c = (BOOST::uint8_t)p_c; + + size_t cnt = 0; + for(;;) + { + if ( ( p_c & mask_tab[cnt] ) == val_tab[cnt] ) break; + if ( ++cnt >= 6 ) return 0; + } + + return cnt + 1; +} + +size_t utf8_decode_char( const char *p_utf8, unsigned & wide, size_t mmax ) +{ + const BOOST::uint8_t * utf8 = ( const BOOST::uint8_t* )p_utf8; + + if ( mmax == 0 ) + { + wide = 0; + return 0; + } + + if ( utf8[0] < 0x80 ) + { + wide = utf8[0]; + return utf8[0]>0 ? 1 : 0; + } + if ( mmax > 6 ) mmax = 6; + wide = 0; + + unsigned res=0; + unsigned n; + unsigned cnt=0; + for(;;) + { + if ( ( *utf8 & mask_tab[cnt] ) == val_tab[cnt] ) break; + if ( ++cnt >= mmax ) return 0; + } + cnt++; + + if ( cnt==2 && !( *utf8 & 0x1E ) ) return 0; + + if ( cnt == 1 ) + res = *utf8; + else + res = ( 0xFF >> ( cnt + 1 ) ) & *utf8; + + for ( n = 1; n < cnt; n++ ) + { + if ( ( utf8[n] & 0xC0 ) != 0x80 ) + return 0; + if ( !res && n == 2 && !( ( utf8[n] & 0x7F ) >> ( 7 - cnt ) ) ) + return 0; + + res = ( res << 6 ) | ( utf8[n] & 0x3F ); + } + + wide = res; + + return cnt; +} + +size_t utf8_encode_char( unsigned wide, char * target ) +{ + size_t count; + + if ( wide < 0x80 ) + count = 1; + else if ( wide < 0x800 ) + count = 2; + else if ( wide < 0x10000 ) + count = 3; + else if ( wide < 0x200000 ) + count = 4; + else if ( wide < 0x4000000 ) + count = 5; + else if ( wide <= 0x7FFFFFFF ) + count = 6; + else + return 0; + + if ( target == 0 ) + return count; + + switch ( count ) + { + case 6: + target[5] = 0x80 | ( wide & 0x3F ); + wide = wide >> 6; + wide |= 0x4000000; + case 5: + target[4] = 0x80 | ( wide & 0x3F ); + wide = wide >> 6; + wide |= 0x200000; + case 4: + target[3] = 0x80 | ( wide & 0x3F ); + wide = wide >> 6; + wide |= 0x10000; + case 3: + target[2] = 0x80 | ( wide & 0x3F ); + wide = wide >> 6; + wide |= 0x800; + case 2: + target[1] = 0x80 | ( wide & 0x3F ); + wide = wide >> 6; + wide |= 0xC0; + case 1: + target[0] = wide; + } + + return count; +} + +size_t utf16_encode_char( unsigned cur_wchar, wchar_t * out ) +{ + if ( cur_wchar < 0x10000 ) + { + if ( out ) *out = (wchar_t) cur_wchar; return 1; + } + else if ( cur_wchar < ( 1 << 20 ) ) + { + unsigned c = cur_wchar - 0x10000; + //MSDN: + //The first (high) surrogate is a 16-bit code value in the range U+D800 to U+DBFF. The second (low) surrogate is a 16-bit code value in the range U+DC00 to U+DFFF. Using surrogates, Unicode can support over one million characters. For more details about surrogates, refer to The Unicode Standard, version 2.0. + if ( out ) + { + out[0] = ( wchar_t )( 0xD800 | ( 0x3FF & ( c >> 10 ) ) ); + out[1] = ( wchar_t )( 0xDC00 | ( 0x3FF & c ) ) ; + } + return 2; + } + else + { + if ( out ) *out = '?'; return 1; + } +} + +size_t utf16_decode_char( const wchar_t * p_source, unsigned * p_out, size_t p_source_length ) +{ + if ( p_source_length == 0 ) return 0; + else if ( p_source_length == 1 ) + { + *p_out = p_source[0]; + return 1; + } + else + { + size_t retval = 0; + unsigned decoded = p_source[0]; + if ( decoded != 0 ) + { + retval = 1; + if ( ( decoded & 0xFC00 ) == 0xD800 ) + { + unsigned low = p_source[1]; + if ( ( low & 0xFC00 ) == 0xDC00 ) + { + decoded = 0x10000 + ( ( ( decoded & 0x3FF ) << 10 ) | ( low & 0x3FF ) ); + retval = 2; + } + } + } + *p_out = decoded; + return retval; + } +} + +// Converts wide-character path to UTF-8. Free result with free(). Only supported on Windows. +char* blargg_to_utf8( const wchar_t* wpath ) +{ + if ( wpath == NULL ) + return NULL; + + size_t needed = 0; + size_t mmax = wcslen( wpath ); + if ( mmax <= 0 ) + return NULL; + + size_t ptr = 0; + while ( ptr < mmax ) + { + unsigned wide = 0; + size_t char_len = utf16_decode_char( wpath + ptr, &wide, mmax - ptr ); + if ( !char_len ) break; + ptr += char_len; + needed += utf8_encode_char( wide, 0 ); + } + if ( needed <= 0 ) + return NULL; + + char* path = (char*) calloc( needed + 1, 1 ); + if ( path == NULL ) + return NULL; + + ptr = 0; + size_t actual = 0; + while ( ptr < mmax && actual < needed ) + { + unsigned wide = 0; + size_t char_len = utf16_decode_char( wpath + ptr, &wide, mmax - ptr ); + if ( !char_len ) break; + ptr += char_len; + actual += utf8_encode_char( wide, path + actual ); + } + + if ( actual == 0 ) + { + free( path ); + return NULL; + } + + assert( actual == needed ); + return path; +} + +// Converts UTF-8 path to wide-character. Free result with free() Only supported on Windows. +wchar_t* blargg_to_wide( const char* path ) +{ + if ( path == NULL ) + return NULL; + + size_t mmax = strlen( path ); + if ( mmax <= 0 ) + return NULL; + + size_t needed = 0; + size_t ptr = 0; + while ( ptr < mmax ) + { + unsigned wide = 0; + size_t char_len = utf8_decode_char( path + ptr, wide, mmax - ptr ); + if ( !char_len ) break; + ptr += char_len; + needed += utf16_encode_char( wide, 0 ); + } + if ( needed <= 0 ) + return NULL; + + wchar_t* wpath = (wchar_t*) calloc( needed + 1, sizeof *wpath ); + if ( wpath == NULL ) + return NULL; + + ptr = 0; + size_t actual = 0; + while ( ptr < mmax && actual < needed ) + { + unsigned wide = 0; + size_t char_len = utf8_decode_char( path + ptr, wide, mmax - ptr ); + if ( !char_len ) break; + ptr += char_len; + actual += utf16_encode_char( wide, wpath + actual ); + } + if ( actual == 0 ) + { + free( wpath ); + return NULL; + } + + assert( actual == needed ); + return wpath; +} + +#ifdef _WIN32 + +static FILE* blargg_fopen( const char path [], const char mode [] ) +{ + FILE* file = NULL; + wchar_t* wmode = NULL; + wchar_t* wpath = NULL; + + wpath = blargg_to_wide( path ); + if ( wpath ) + { + wmode = blargg_to_wide( mode ); + if ( wmode ) + file = _wfopen( wpath, wmode ); + } + + // Save and restore errno in case free() clears it + int saved_errno = errno; + free( wmode ); + free( wpath ); + errno = saved_errno; + + return file; +} + +#else + +static inline FILE* blargg_fopen( const char path [], const char mode [] ) +{ + return fopen( path, mode ); +} + +#endif + + +// Std_File_Reader + +Std_File_Reader::Std_File_Reader() +{ + file_ = NULL; +} + +Std_File_Reader::~Std_File_Reader() +{ + close(); +} + +static blargg_err_t blargg_fopen( FILE** out, const char path [] ) +{ + errno = 0; + *out = blargg_fopen( path, "rb" ); + if ( !*out ) + { + #ifdef ENOENT + if ( errno == ENOENT ) + return blargg_err_file_missing; + #endif + #ifdef ENOMEM + if ( errno == ENOMEM ) + return blargg_err_memory; + #endif + return blargg_err_file_read; + } + + return blargg_ok; +} + +static blargg_err_t blargg_fsize( FILE* f, long* out ) +{ + if ( fseek( f, 0, SEEK_END ) ) + return blargg_err_file_io; + + *out = ftell( f ); + if ( *out < 0 ) + return blargg_err_file_io; + + if ( fseek( f, 0, SEEK_SET ) ) + return blargg_err_file_io; + + return blargg_ok; +} + +blargg_err_t Std_File_Reader::open( const char path [] ) +{ + close(); + + FILE* f; + RETURN_ERR( blargg_fopen( &f, path ) ); + + long s; + blargg_err_t err = blargg_fsize( f, &s ); + if ( err ) + { + fclose( f ); + return err; + } + + file_ = f; + set_size( s ); + + return blargg_ok; +} + +void Std_File_Reader::make_unbuffered() +{ + if ( setvbuf( STATIC_CAST(FILE*, file_), NULL, _IONBF, 0 ) ) + check( false ); // shouldn't fail, but OK if it does +} + +blargg_err_t Std_File_Reader::read_v( void* p, int s ) +{ + if ( (size_t) s != fread( p, 1, s, STATIC_CAST(FILE*, file_) ) ) + { + // Data_Reader's wrapper should prevent EOF + check( !feof( STATIC_CAST(FILE*, file_) ) ); + + return blargg_err_file_io; + } + + return blargg_ok; +} + +blargg_err_t Std_File_Reader::seek_v( int n ) +{ + if ( fseek( STATIC_CAST(FILE*, file_), n, SEEK_SET ) ) + { + // Data_Reader's wrapper should prevent EOF + check( !feof( STATIC_CAST(FILE*, file_) ) ); + + return blargg_err_file_io; + } + + return blargg_ok; +} + +void Std_File_Reader::close() +{ + if ( file_ ) + { + fclose( STATIC_CAST(FILE*, file_) ); + file_ = NULL; + } +} + + +// Gzip_File_Reader + +#ifdef HAVE_ZLIB_H + +#include "zlib.h" + +static const char* get_gzip_eof( const char path [], long* eof ) +{ + FILE* file; + RETURN_ERR( blargg_fopen( &file, path ) ); + + int const h_size = 4; + unsigned char h [h_size]; + + // read four bytes to ensure that we can seek to -4 later + if ( fread( h, 1, h_size, file ) != (size_t) h_size || h[0] != 0x1F || h[1] != 0x8B ) + { + // Not gzipped + if ( ferror( file ) ) + return blargg_err_file_io; + + if ( fseek( file, 0, SEEK_END ) ) + return blargg_err_file_io; + + *eof = ftell( file ); + if ( *eof < 0 ) + return blargg_err_file_io; + } + else + { + // Gzipped; get uncompressed size from end + if ( fseek( file, -h_size, SEEK_END ) ) + return blargg_err_file_io; + + if ( fread( h, 1, h_size, file ) != (size_t) h_size ) + return blargg_err_file_io; + + *eof = get_le32( h ); + } + + if ( fclose( file ) ) + check( false ); + + return blargg_ok; +} + +Gzip_File_Reader::Gzip_File_Reader() +{ + file_ = NULL; +} + +Gzip_File_Reader::~Gzip_File_Reader() +{ + close(); +} + +blargg_err_t Gzip_File_Reader::open( const char path [] ) +{ + close(); + + long s; + RETURN_ERR( get_gzip_eof( path, &s ) ); + + file_ = gzopen( path, "rb" ); + if ( !file_ ) + return blargg_err_file_read; + + set_size( s ); + return blargg_ok; +} + +static blargg_err_t convert_gz_error( gzFile file ) +{ + int err; + gzerror( file, &err ); + + switch ( err ) + { + case Z_STREAM_ERROR: break; + case Z_DATA_ERROR: return blargg_err_file_corrupt; + case Z_MEM_ERROR: return blargg_err_memory; + case Z_BUF_ERROR: break; + } + return blargg_err_internal; +} + +blargg_err_t Gzip_File_Reader::read_v( void* p, int s ) +{ + int result = gzread( file_, p, s ); + if ( result != s ) + { + if ( result < 0 ) + return convert_gz_error( file_ ); + + return blargg_err_file_corrupt; + } + + return blargg_ok; +} + +blargg_err_t Gzip_File_Reader::seek_v( int n ) +{ + if ( gzseek( file_, n, SEEK_SET ) < 0 ) + return convert_gz_error( file_ ); + + return blargg_ok; +} + +void Gzip_File_Reader::close() +{ + if ( file_ ) + { + if ( gzclose( file_ ) ) + check( false ); + file_ = NULL; + } +} + +#endif diff --git a/fex/fex/Data_Reader.h b/fex/fex/Data_Reader.h index ad58f522..be206f7b 100644 --- a/fex/fex/Data_Reader.h +++ b/fex/fex/Data_Reader.h @@ -1,264 +1,264 @@ -// Lightweight interface for reading data from byte stream - -// File_Extractor 1.0.0 -#ifndef DATA_READER_H -#define DATA_READER_H - -#include "blargg_common.h" - -/* Some functions accept a long instead of int for convenience where caller has -a long due to some other interface, and would otherwise have to get a warning, -or cast it (and verify that it wasn't outside the range of an int). - -To really support huge (>2GB) files, long isn't a solution, since there's no -guarantee it's more than 32 bits. We'd need to use long long (if available), or -something compiler-specific, and change all places file sizes or offsets are -used. */ - -// Supports reading and finding out how many bytes are remaining -class Data_Reader { -public: - - // Reads min(*n,remain()) bytes and sets *n to this number, thus trying to read more - // tham remain() bytes doesn't result in error, just *n being set to remain(). - blargg_err_t read_avail( void* p, int* n ); - blargg_err_t read_avail( void* p, long* n ); - - // Reads exactly n bytes, or returns error if they couldn't ALL be read. - // Reading past end of file results in blargg_err_file_eof. - blargg_err_t read( void* p, int n ); - - // Number of bytes remaining until end of file - int remain() const { return remain_; } - - // Reads and discards n bytes. Skipping past end of file results in blargg_err_file_eof. - blargg_err_t skip( int n ); - - virtual ~Data_Reader() { } - -private: - // noncopyable - Data_Reader( const Data_Reader& ); - Data_Reader& operator = ( const Data_Reader& ); - -// Derived interface -protected: - Data_Reader() : remain_( 0 ) { } - - // Sets remain - void set_remain( int n ) { assert( n >= 0 ); remain_ = n; } - - // Do same as read(). Guaranteed that 0 < n <= remain(). Value of remain() is updated - // AFTER this call succeeds, not before. set_remain() should NOT be called from this. - virtual blargg_err_t read_v( void*, int n ) BLARGG_PURE( { (void)n; return blargg_ok; } ) - - // Do same as skip(). Guaranteed that 0 < n <= remain(). Default just reads data - // and discards it. Value of remain() is updated AFTER this call succeeds, not - // before. set_remain() should NOT be called from this. - virtual blargg_err_t skip_v( int n ); - -// Implementation -public: - BLARGG_DISABLE_NOTHROW - -private: - int remain_; -}; - - -// Supports seeking in addition to Data_Reader operations -class File_Reader : public Data_Reader { -public: - - // Size of file - int size() const { return size_; } - - // Current position in file - int tell() const { return size_ - remain(); } - - // Goes to new position - blargg_err_t seek( int ); - -// Derived interface -protected: - // Sets size and resets position - void set_size( int n ) { size_ = n; Data_Reader::set_remain( n ); } - void set_size( long n ) { set_size( STATIC_CAST(int, n) ); } - - // Sets reported position - void set_tell( int i ) { assert( 0 <= i && i <= size_ ); Data_Reader::set_remain( size_ - i ); } - - // Do same as seek(). Guaranteed that 0 <= n <= size(). Value of tell() is updated - // AFTER this call succeeds, not before. set_* functions should NOT be called from this. - virtual blargg_err_t seek_v( int n ) BLARGG_PURE( { (void)n; return blargg_ok; } ) - -// Implementation -protected: - File_Reader() : size_( 0 ) { } - - virtual blargg_err_t skip_v( int ); - -private: - int size_; - - void set_remain(); // avoid accidental use of set_remain -}; - - -// Reads from file on disk -class Std_File_Reader : public File_Reader { -public: - - // Opens file - blargg_err_t open( const char path [] ); - - // Closes file if one was open - void close(); - - // Switches to unbuffered mode. Useful if buffering is already being - // done at a higher level. - void make_unbuffered(); - -// Implementation -public: - Std_File_Reader(); - virtual ~Std_File_Reader(); - -protected: - virtual blargg_err_t read_v( void*, int ); - virtual blargg_err_t seek_v( int ); - -private: - void* file_; -}; - - -// Treats range of memory as a file -class Mem_File_Reader : public File_Reader { -public: - - Mem_File_Reader( const void* begin, long size ); - -// Implementation -protected: - virtual blargg_err_t read_v( void*, int ); - virtual blargg_err_t seek_v( int ); - -private: - const char* const begin; -}; - - -// Allows only count bytes to be read from reader passed -class Subset_Reader : public Data_Reader { -public: - - Subset_Reader( Data_Reader*, int count ); - -// Implementation -protected: - virtual blargg_err_t read_v( void*, int ); - -private: - Data_Reader* const in; -}; - - -// Joins already-read header and remaining data into original file. -// Meant for cases where you've already read header and don't want -// to seek and re-read data (for efficiency). -class Remaining_Reader : public Data_Reader { -public: - - Remaining_Reader( void const* header, int header_size, Data_Reader* ); - -// Implementation -protected: - virtual blargg_err_t read_v( void*, int ); - -private: - Data_Reader* const in; - void const* header; - int header_remain; -}; - - -// Invokes callback function to read data -extern "C" { // necessary to be usable from C - typedef const char* (*callback_reader_func_t)( - void* user_data, // Same value passed to constructor - void* out, // Buffer to place data into - int count // Number of bytes to read - ); -} -class Callback_Reader : public Data_Reader { -public: - typedef callback_reader_func_t callback_t; - Callback_Reader( callback_t, long size, void* user_data ); - -// Implementation -protected: - virtual blargg_err_t read_v( void*, int ); - -private: - callback_t const callback; - void* const user_data; -}; - - -// Invokes callback function to read data -extern "C" { // necessary to be usable from C - typedef const char* (*callback_file_reader_func_t)( - void* user_data, // Same value passed to constructor - void* out, // Buffer to place data into - int count, // Number of bytes to read - int pos // Position in file to read from - ); -} -class Callback_File_Reader : public File_Reader { -public: - typedef callback_file_reader_func_t callback_t; - Callback_File_Reader( callback_t, long size, void* user_data ); - -// Implementation -protected: - virtual blargg_err_t read_v( void*, int ); - virtual blargg_err_t seek_v( int ); - -private: - callback_t const callback; - void* const user_data; -}; - - -#ifdef HAVE_ZLIB_H - -// Reads file compressed with gzip (or uncompressed) -class Gzip_File_Reader : public File_Reader { -public: - - // Opens possibly gzipped file - blargg_err_t open( const char path [] ); - - // Closes file if one was open - void close(); - -// Implementation -public: - Gzip_File_Reader(); - ~Gzip_File_Reader(); - -protected: - virtual blargg_err_t read_v( void*, int ); - virtual blargg_err_t seek_v( int ); - -private: - // void* so "zlib.h" doesn't have to be included here - void* file_; -}; -#endif - -char* blargg_to_utf8( const wchar_t* ); -wchar_t* blargg_to_wide( const char* ); - -#endif +// Lightweight interface for reading data from byte stream + +// File_Extractor 1.0.0 +#ifndef DATA_READER_H +#define DATA_READER_H + +#include "blargg_common.h" + +/* Some functions accept a long instead of int for convenience where caller has +a long due to some other interface, and would otherwise have to get a warning, +or cast it (and verify that it wasn't outside the range of an int). + +To really support huge (>2GB) files, long isn't a solution, since there's no +guarantee it's more than 32 bits. We'd need to use long long (if available), or +something compiler-specific, and change all places file sizes or offsets are +used. */ + +// Supports reading and finding out how many bytes are remaining +class Data_Reader { +public: + + // Reads min(*n,remain()) bytes and sets *n to this number, thus trying to read more + // tham remain() bytes doesn't result in error, just *n being set to remain(). + blargg_err_t read_avail( void* p, int* n ); + blargg_err_t read_avail( void* p, long* n ); + + // Reads exactly n bytes, or returns error if they couldn't ALL be read. + // Reading past end of file results in blargg_err_file_eof. + blargg_err_t read( void* p, int n ); + + // Number of bytes remaining until end of file + int remain() const { return remain_; } + + // Reads and discards n bytes. Skipping past end of file results in blargg_err_file_eof. + blargg_err_t skip( int n ); + + virtual ~Data_Reader() { } + +private: + // noncopyable + Data_Reader( const Data_Reader& ); + Data_Reader& operator = ( const Data_Reader& ); + +// Derived interface +protected: + Data_Reader() : remain_( 0 ) { } + + // Sets remain + void set_remain( int n ) { assert( n >= 0 ); remain_ = n; } + + // Do same as read(). Guaranteed that 0 < n <= remain(). Value of remain() is updated + // AFTER this call succeeds, not before. set_remain() should NOT be called from this. + virtual blargg_err_t read_v( void*, int n ) BLARGG_PURE( { (void)n; return blargg_ok; } ) + + // Do same as skip(). Guaranteed that 0 < n <= remain(). Default just reads data + // and discards it. Value of remain() is updated AFTER this call succeeds, not + // before. set_remain() should NOT be called from this. + virtual blargg_err_t skip_v( int n ); + +// Implementation +public: + BLARGG_DISABLE_NOTHROW + +private: + int remain_; +}; + + +// Supports seeking in addition to Data_Reader operations +class File_Reader : public Data_Reader { +public: + + // Size of file + int size() const { return size_; } + + // Current position in file + int tell() const { return size_ - remain(); } + + // Goes to new position + blargg_err_t seek( int ); + +// Derived interface +protected: + // Sets size and resets position + void set_size( int n ) { size_ = n; Data_Reader::set_remain( n ); } + void set_size( long n ) { set_size( STATIC_CAST(int, n) ); } + + // Sets reported position + void set_tell( int i ) { assert( 0 <= i && i <= size_ ); Data_Reader::set_remain( size_ - i ); } + + // Do same as seek(). Guaranteed that 0 <= n <= size(). Value of tell() is updated + // AFTER this call succeeds, not before. set_* functions should NOT be called from this. + virtual blargg_err_t seek_v( int n ) BLARGG_PURE( { (void)n; return blargg_ok; } ) + +// Implementation +protected: + File_Reader() : size_( 0 ) { } + + virtual blargg_err_t skip_v( int ); + +private: + int size_; + + void set_remain(); // avoid accidental use of set_remain +}; + + +// Reads from file on disk +class Std_File_Reader : public File_Reader { +public: + + // Opens file + blargg_err_t open( const char path [] ); + + // Closes file if one was open + void close(); + + // Switches to unbuffered mode. Useful if buffering is already being + // done at a higher level. + void make_unbuffered(); + +// Implementation +public: + Std_File_Reader(); + virtual ~Std_File_Reader(); + +protected: + virtual blargg_err_t read_v( void*, int ); + virtual blargg_err_t seek_v( int ); + +private: + void* file_; +}; + + +// Treats range of memory as a file +class Mem_File_Reader : public File_Reader { +public: + + Mem_File_Reader( const void* begin, long size ); + +// Implementation +protected: + virtual blargg_err_t read_v( void*, int ); + virtual blargg_err_t seek_v( int ); + +private: + const char* const begin; +}; + + +// Allows only count bytes to be read from reader passed +class Subset_Reader : public Data_Reader { +public: + + Subset_Reader( Data_Reader*, int count ); + +// Implementation +protected: + virtual blargg_err_t read_v( void*, int ); + +private: + Data_Reader* const in; +}; + + +// Joins already-read header and remaining data into original file. +// Meant for cases where you've already read header and don't want +// to seek and re-read data (for efficiency). +class Remaining_Reader : public Data_Reader { +public: + + Remaining_Reader( void const* header, int header_size, Data_Reader* ); + +// Implementation +protected: + virtual blargg_err_t read_v( void*, int ); + +private: + Data_Reader* const in; + void const* header; + int header_remain; +}; + + +// Invokes callback function to read data +extern "C" { // necessary to be usable from C + typedef const char* (*callback_reader_func_t)( + void* user_data, // Same value passed to constructor + void* out, // Buffer to place data into + int count // Number of bytes to read + ); +} +class Callback_Reader : public Data_Reader { +public: + typedef callback_reader_func_t callback_t; + Callback_Reader( callback_t, long size, void* user_data ); + +// Implementation +protected: + virtual blargg_err_t read_v( void*, int ); + +private: + callback_t const callback; + void* const user_data; +}; + + +// Invokes callback function to read data +extern "C" { // necessary to be usable from C + typedef const char* (*callback_file_reader_func_t)( + void* user_data, // Same value passed to constructor + void* out, // Buffer to place data into + int count, // Number of bytes to read + int pos // Position in file to read from + ); +} +class Callback_File_Reader : public File_Reader { +public: + typedef callback_file_reader_func_t callback_t; + Callback_File_Reader( callback_t, long size, void* user_data ); + +// Implementation +protected: + virtual blargg_err_t read_v( void*, int ); + virtual blargg_err_t seek_v( int ); + +private: + callback_t const callback; + void* const user_data; +}; + + +#ifdef HAVE_ZLIB_H + +// Reads file compressed with gzip (or uncompressed) +class Gzip_File_Reader : public File_Reader { +public: + + // Opens possibly gzipped file + blargg_err_t open( const char path [] ); + + // Closes file if one was open + void close(); + +// Implementation +public: + Gzip_File_Reader(); + ~Gzip_File_Reader(); + +protected: + virtual blargg_err_t read_v( void*, int ); + virtual blargg_err_t seek_v( int ); + +private: + // void* so "zlib.h" doesn't have to be included here + void* file_; +}; +#endif + +char* blargg_to_utf8( const wchar_t* ); +wchar_t* blargg_to_wide( const char* ); + +#endif diff --git a/fex/fex/File_Extractor.cpp b/fex/fex/File_Extractor.cpp index 4b27d921..e060e095 100644 --- a/fex/fex/File_Extractor.cpp +++ b/fex/fex/File_Extractor.cpp @@ -1,341 +1,341 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "File_Extractor.h" - -/* Copyright (C) 2005-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -File_Extractor::fex_t( fex_type_t t ) : - type_( t ) -{ - own_file_ = NULL; - - close_(); -} - -// Open - -blargg_err_t File_Extractor::set_path( const char* path ) -{ - if ( !path ) - path = ""; - - RETURN_ERR( path_.resize( strlen( path ) + 1 ) ); - memcpy( path_.begin(), path, path_.size() ); - return blargg_ok; -} - -blargg_err_t File_Extractor::open( const char path [] ) -{ - close(); - - RETURN_ERR( set_path( path ) ); - - blargg_err_t err = open_path_v(); - if ( err ) - close(); - else - opened_ = true; - - return err; -} - -blargg_err_t File_Extractor::open_path_v() -{ - RETURN_ERR( open_arc_file() ); - - return open_v(); -} - -inline -static void make_unbuffered( Std_File_Reader* r ) -{ - r->make_unbuffered(); -} - -inline -static void make_unbuffered( void* ) -{ } - -blargg_err_t File_Extractor::open_arc_file( bool unbuffered ) -{ - if ( reader_ ) - return blargg_ok; - - FEX_FILE_READER* in = BLARGG_NEW FEX_FILE_READER; - CHECK_ALLOC( in ); - - blargg_err_t err = in->open( arc_path() ); - if ( err ) - { - delete in; - } - else - { - reader_ = in; - own_file(); - if ( unbuffered ) - make_unbuffered( in ); - } - - return err; -} - -blargg_err_t File_Extractor::open( File_Reader* input, const char* path ) -{ - close(); - - RETURN_ERR( set_path( path ) ); - - RETURN_ERR( input->seek( 0 ) ); - - reader_ = input; - blargg_err_t err = open_v(); - if ( err ) - close(); - else - opened_ = true; - - return err; -} - -// Close - -void File_Extractor::close() -{ - close_v(); - close_(); -} - -void File_Extractor::close_() -{ - delete own_file_; - own_file_ = NULL; - - tell_ = 0; - reader_ = NULL; - opened_ = false; - - path_.clear(); - clear_file(); -} - -File_Extractor::~fex_t() -{ - check( !opened() ); // fails if derived destructor didn't call close() - - delete own_file_; -} - -// Scanning - -void File_Extractor::clear_file() -{ - name_ = NULL; - wname_ = NULL; - done_ = true; - stat_called = false; - data_ptr_ = NULL; - - set_info( 0 ); - own_data_.clear(); - clear_file_v(); -} - -void File_Extractor::set_name( const char new_name [], const wchar_t* new_wname ) -{ - name_ = new_name; - wname_ = new_wname; - done_ = false; -} - -void File_Extractor::set_info( int new_size, unsigned date, unsigned crc ) -{ - size_ = new_size; - date_ = (date != 0xFFFFFFFF ? date : 0); - crc32_ = crc; - set_remain( new_size ); -} - -blargg_err_t File_Extractor::next_() -{ - tell_++; - clear_file(); - - blargg_err_t err = next_v(); - if ( err ) - clear_file(); - - return err; -} - -blargg_err_t File_Extractor::next() -{ - assert( !done() ); - return next_(); -} - -blargg_err_t File_Extractor::rewind() -{ - assert( opened() ); - - tell_ = 0; - clear_file(); - - blargg_err_t err = rewind_v(); - if ( err ) - clear_file(); - - return err; -} - -blargg_err_t File_Extractor::stat() -{ - assert( !done() ); - - if ( !stat_called ) - { - RETURN_ERR( stat_v() ); - stat_called = true; - } - return blargg_ok; -} - -// Tell/seek - -int const pos_offset = 1; - -fex_pos_t File_Extractor::tell_arc() const -{ - assert( opened() ); - - fex_pos_t pos = tell_arc_v(); - assert( pos >= 0 ); - - return pos + pos_offset; -} - -blargg_err_t File_Extractor::seek_arc( fex_pos_t pos ) -{ - assert( opened() ); - assert( pos != 0 ); - - clear_file(); - - blargg_err_t err = seek_arc_v( pos - pos_offset ); - if ( err ) - clear_file(); - - return err; -} - -fex_pos_t File_Extractor::tell_arc_v() const -{ - return tell_; -} - -blargg_err_t File_Extractor::seek_arc_v( fex_pos_t pos ) -{ - // >= because seeking to current file should always reset read pointer etc. - if ( tell_ >= pos ) - RETURN_ERR( rewind() ); - - while ( tell_ < pos ) - { - RETURN_ERR( next_() ); - - if ( done() ) - { - assert( false ); - return blargg_err_caller; - } - } - - assert( tell_ == pos ); - - return blargg_ok; -} - -// Extraction - -blargg_err_t File_Extractor::rewind_file() -{ - RETURN_ERR( stat() ); - - if ( tell() > 0 ) - { - if ( data_ptr_ ) - { - set_remain( size() ); - } - else - { - RETURN_ERR( seek_arc( tell_arc() ) ); - RETURN_ERR( stat() ); - } - } - - return blargg_ok; -} - -blargg_err_t File_Extractor::data( const void** data_out ) -{ - assert( !done() ); - - *data_out = NULL; - if ( !data_ptr_ ) - { - int old_tell = tell(); - - RETURN_ERR( rewind_file() ); - - void const* ptr; - RETURN_ERR( data_v( &ptr ) ); - data_ptr_ = ptr; - - // Now that data is in memory, we can seek by simply setting remain - set_remain( size() - old_tell ); - } - - *data_out = data_ptr_; - return blargg_ok; -} - -blargg_err_t File_Extractor::data_v( void const** out ) -{ - RETURN_ERR( own_data_.resize( size() ) ); - *out = own_data_.begin(); - - blargg_err_t err = extract_v( own_data_.begin(), own_data_.size() ); - if ( err ) - own_data_.clear(); - - return err; -} - -blargg_err_t File_Extractor::extract_v( void* out, int count ) -{ - void const* p; - RETURN_ERR( data( &p ) ); - memcpy( out, STATIC_CAST(char const*,p) + (size() - remain()), count ); - - return blargg_ok; -} - -blargg_err_t File_Extractor::read_v( void* out, int count ) -{ - if ( data_ptr_ ) - return File_Extractor::extract_v( out, count ); - - return extract_v( out, count ); -} +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "File_Extractor.h" + +/* Copyright (C) 2005-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +File_Extractor::fex_t( fex_type_t t ) : + type_( t ) +{ + own_file_ = NULL; + + close_(); +} + +// Open + +blargg_err_t File_Extractor::set_path( const char* path ) +{ + if ( !path ) + path = ""; + + RETURN_ERR( path_.resize( strlen( path ) + 1 ) ); + memcpy( path_.begin(), path, path_.size() ); + return blargg_ok; +} + +blargg_err_t File_Extractor::open( const char path [] ) +{ + close(); + + RETURN_ERR( set_path( path ) ); + + blargg_err_t err = open_path_v(); + if ( err ) + close(); + else + opened_ = true; + + return err; +} + +blargg_err_t File_Extractor::open_path_v() +{ + RETURN_ERR( open_arc_file() ); + + return open_v(); +} + +inline +static void make_unbuffered( Std_File_Reader* r ) +{ + r->make_unbuffered(); +} + +inline +static void make_unbuffered( void* ) +{ } + +blargg_err_t File_Extractor::open_arc_file( bool unbuffered ) +{ + if ( reader_ ) + return blargg_ok; + + FEX_FILE_READER* in = BLARGG_NEW FEX_FILE_READER; + CHECK_ALLOC( in ); + + blargg_err_t err = in->open( arc_path() ); + if ( err ) + { + delete in; + } + else + { + reader_ = in; + own_file(); + if ( unbuffered ) + make_unbuffered( in ); + } + + return err; +} + +blargg_err_t File_Extractor::open( File_Reader* input, const char* path ) +{ + close(); + + RETURN_ERR( set_path( path ) ); + + RETURN_ERR( input->seek( 0 ) ); + + reader_ = input; + blargg_err_t err = open_v(); + if ( err ) + close(); + else + opened_ = true; + + return err; +} + +// Close + +void File_Extractor::close() +{ + close_v(); + close_(); +} + +void File_Extractor::close_() +{ + delete own_file_; + own_file_ = NULL; + + tell_ = 0; + reader_ = NULL; + opened_ = false; + + path_.clear(); + clear_file(); +} + +File_Extractor::~fex_t() +{ + check( !opened() ); // fails if derived destructor didn't call close() + + delete own_file_; +} + +// Scanning + +void File_Extractor::clear_file() +{ + name_ = NULL; + wname_ = NULL; + done_ = true; + stat_called = false; + data_ptr_ = NULL; + + set_info( 0 ); + own_data_.clear(); + clear_file_v(); +} + +void File_Extractor::set_name( const char new_name [], const wchar_t* new_wname ) +{ + name_ = new_name; + wname_ = new_wname; + done_ = false; +} + +void File_Extractor::set_info( int new_size, unsigned date, unsigned crc ) +{ + size_ = new_size; + date_ = (date != 0xFFFFFFFF ? date : 0); + crc32_ = crc; + set_remain( new_size ); +} + +blargg_err_t File_Extractor::next_() +{ + tell_++; + clear_file(); + + blargg_err_t err = next_v(); + if ( err ) + clear_file(); + + return err; +} + +blargg_err_t File_Extractor::next() +{ + assert( !done() ); + return next_(); +} + +blargg_err_t File_Extractor::rewind() +{ + assert( opened() ); + + tell_ = 0; + clear_file(); + + blargg_err_t err = rewind_v(); + if ( err ) + clear_file(); + + return err; +} + +blargg_err_t File_Extractor::stat() +{ + assert( !done() ); + + if ( !stat_called ) + { + RETURN_ERR( stat_v() ); + stat_called = true; + } + return blargg_ok; +} + +// Tell/seek + +int const pos_offset = 1; + +fex_pos_t File_Extractor::tell_arc() const +{ + assert( opened() ); + + fex_pos_t pos = tell_arc_v(); + assert( pos >= 0 ); + + return pos + pos_offset; +} + +blargg_err_t File_Extractor::seek_arc( fex_pos_t pos ) +{ + assert( opened() ); + assert( pos != 0 ); + + clear_file(); + + blargg_err_t err = seek_arc_v( pos - pos_offset ); + if ( err ) + clear_file(); + + return err; +} + +fex_pos_t File_Extractor::tell_arc_v() const +{ + return tell_; +} + +blargg_err_t File_Extractor::seek_arc_v( fex_pos_t pos ) +{ + // >= because seeking to current file should always reset read pointer etc. + if ( tell_ >= pos ) + RETURN_ERR( rewind() ); + + while ( tell_ < pos ) + { + RETURN_ERR( next_() ); + + if ( done() ) + { + assert( false ); + return blargg_err_caller; + } + } + + assert( tell_ == pos ); + + return blargg_ok; +} + +// Extraction + +blargg_err_t File_Extractor::rewind_file() +{ + RETURN_ERR( stat() ); + + if ( tell() > 0 ) + { + if ( data_ptr_ ) + { + set_remain( size() ); + } + else + { + RETURN_ERR( seek_arc( tell_arc() ) ); + RETURN_ERR( stat() ); + } + } + + return blargg_ok; +} + +blargg_err_t File_Extractor::data( const void** data_out ) +{ + assert( !done() ); + + *data_out = NULL; + if ( !data_ptr_ ) + { + int old_tell = tell(); + + RETURN_ERR( rewind_file() ); + + void const* ptr; + RETURN_ERR( data_v( &ptr ) ); + data_ptr_ = ptr; + + // Now that data is in memory, we can seek by simply setting remain + set_remain( size() - old_tell ); + } + + *data_out = data_ptr_; + return blargg_ok; +} + +blargg_err_t File_Extractor::data_v( void const** out ) +{ + RETURN_ERR( own_data_.resize( size() ) ); + *out = own_data_.begin(); + + blargg_err_t err = extract_v( own_data_.begin(), own_data_.size() ); + if ( err ) + own_data_.clear(); + + return err; +} + +blargg_err_t File_Extractor::extract_v( void* out, int count ) +{ + void const* p; + RETURN_ERR( data( &p ) ); + memcpy( out, STATIC_CAST(char const*,p) + (size() - remain()), count ); + + return blargg_ok; +} + +blargg_err_t File_Extractor::read_v( void* out, int count ) +{ + if ( data_ptr_ ) + return File_Extractor::extract_v( out, count ); + + return extract_v( out, count ); +} diff --git a/fex/fex/File_Extractor.h b/fex/fex/File_Extractor.h index 44080ca2..ad25d5f8 100644 --- a/fex/fex/File_Extractor.h +++ b/fex/fex/File_Extractor.h @@ -1,191 +1,191 @@ -// Compressed file archive interface - -// File_Extractor 1.0.0 -#ifndef FILE_EXTRACTOR_H -#define FILE_EXTRACTOR_H - -#include "blargg_common.h" -#include "Data_Reader.h" -#include "fex.h" - -struct fex_t : private Data_Reader { -public: - virtual ~fex_t(); - -// Open/close - - // Opens archive from custom data source. Keeps pointer until close(). - blargg_err_t open( File_Reader* input, const char* path = NULL ); - - // Takes ownership of File_Reader* passed to open(), so that close() - // will delete it. - void own_file() { own_file_ = reader_; } - - // See fex.h - blargg_err_t open( const char path [] ); - fex_type_t type() const { return type_; } - void close(); - -// Scanning - - // See fex.h - bool done() const { return done_; } - blargg_err_t next(); - blargg_err_t rewind(); - fex_pos_t tell_arc() const; - blargg_err_t seek_arc( fex_pos_t ); - -// Info - - // See fex.h - const char* name() const { return name_; } - const wchar_t* wname() const { return wname_; } - blargg_err_t stat(); - int size() const { assert( stat_called ); return size_; } - unsigned int dos_date() const { return date_; } - unsigned int crc32() const { return crc32_; } - -// Extraction - - // Data_Reader to current file's data, so standard Data_Reader interface can - // be used, rather than having to treat archives specially. stat() must have - // been called. - Data_Reader& reader() { assert( stat_called ); return *this; } - - // See fex.h - blargg_err_t data( const void** data_out ); - int tell() const { return size_ - remain(); } - -// Derived interface -protected: - - // Sets type of object - fex_t( fex_type_t ); - - // Path to archive file, or "" if none supplied - const char* arc_path() const { return path_.begin(); } - - // Opens archive file if it's not already. If unbuffered is true, opens file - // without any buffering. - blargg_err_t open_arc_file( bool unbuffered = false ); - - // Archive file - File_Reader& arc() const { return *reader_; } - - // Sets current file name - void set_name( const char name [], const wchar_t* wname = NULL ); - - // Sets current file information - void set_info( int size, unsigned date = 0, unsigned crc = 0 ); - -// User overrides - - // Overrides must do indicated task. Non-pure functions have reasonable default - // implementation. Overrides should avoid calling public functions like - // next() and rewind(). - - // Open archive using file_path(). OK to delay actual file opening until later. - // Default just calls open_arc_file(), then open_v(). - virtual blargg_err_t open_path_v(); - - // Open archive using file() for source data. If unsupported, return error. - virtual blargg_err_t open_v() BLARGG_PURE( ; ) - - // Go to next file in archive and call set_name() and optionally set_info() - virtual blargg_err_t next_v() BLARGG_PURE( ; ) - - // Go back to first file in archive - virtual blargg_err_t rewind_v() BLARGG_PURE( ; ) - - // Close archive. Called even if open_path_v() or open_v() return unsuccessfully. - virtual void close_v() BLARGG_PURE( ; ) - - // Clear any fields related to current file - virtual void clear_file_v() { } - - // Call set_info() if not already called by next_v() - virtual blargg_err_t stat_v() { return blargg_ok; } - - // Return value that allows later return to this file. Result must be >= 0. - virtual fex_pos_t tell_arc_v() const; - - // Return to previously saved position - virtual blargg_err_t seek_arc_v( fex_pos_t ); - - // One or both of the following must be overridden - - // Provide pointer to data for current file in archive - virtual blargg_err_t data_v( const void** out ); - - // Extract next n bytes - virtual blargg_err_t extract_v( void* out, int n ); - -// Implementation -public: - BLARGG_DISABLE_NOTHROW - -private: - fex_type_t const type_; - - // Archive file - blargg_vector path_; - File_Reader* reader_; - File_Reader* own_file_; - bool opened_; - - // Position in archive - fex_pos_t tell_; // only used by default implementation of tell/seek - bool done_; - - // Info for current file in archive - const char* name_; - const wchar_t* wname_; - unsigned date_; - unsigned crc32_; - int size_; - bool stat_called; - - // Current file contents - void const* data_ptr_; // NULL if not read into memory - blargg_vector own_data_; - - bool opened() const { return opened_; } - void clear_file(); - void close_(); - blargg_err_t set_path( const char* path ); - blargg_err_t rewind_file(); - blargg_err_t next_(); - - // Data_Reader overrides - // TODO: override skip_v? - virtual blargg_err_t read_v( void* out, int n ); -}; - -struct fex_type_t_ -{ - const char* extension; - File_Extractor* (*new_fex)(); - const char* name; - blargg_err_t (*init)(); // Called by fex_init(). Can be NULL. -}; - -extern const fex_type_t_ - fex_7z_type [1], - fex_gz_type [1], - fex_rar_type [1], - fex_zip_type [1], - fex_bin_type [1]; - -inline blargg_err_t File_Extractor::open_v() { return blargg_ok; } -inline blargg_err_t File_Extractor::next_v() { return blargg_ok; } -inline blargg_err_t File_Extractor::rewind_v() { return blargg_ok; } -inline void File_Extractor::close_v() { } - -// Default to Std_File_Reader for archive access -#ifndef FEX_FILE_READER - #define FEX_FILE_READER Std_File_Reader -#elif defined (FEX_FILE_READER_INCLUDE) - #include FEX_FILE_READER_INCLUDE -#endif - -#endif +// Compressed file archive interface + +// File_Extractor 1.0.0 +#ifndef FILE_EXTRACTOR_H +#define FILE_EXTRACTOR_H + +#include "blargg_common.h" +#include "Data_Reader.h" +#include "fex.h" + +struct fex_t : private Data_Reader { +public: + virtual ~fex_t(); + +// Open/close + + // Opens archive from custom data source. Keeps pointer until close(). + blargg_err_t open( File_Reader* input, const char* path = NULL ); + + // Takes ownership of File_Reader* passed to open(), so that close() + // will delete it. + void own_file() { own_file_ = reader_; } + + // See fex.h + blargg_err_t open( const char path [] ); + fex_type_t type() const { return type_; } + void close(); + +// Scanning + + // See fex.h + bool done() const { return done_; } + blargg_err_t next(); + blargg_err_t rewind(); + fex_pos_t tell_arc() const; + blargg_err_t seek_arc( fex_pos_t ); + +// Info + + // See fex.h + const char* name() const { return name_; } + const wchar_t* wname() const { return wname_; } + blargg_err_t stat(); + int size() const { assert( stat_called ); return size_; } + unsigned int dos_date() const { return date_; } + unsigned int crc32() const { return crc32_; } + +// Extraction + + // Data_Reader to current file's data, so standard Data_Reader interface can + // be used, rather than having to treat archives specially. stat() must have + // been called. + Data_Reader& reader() { assert( stat_called ); return *this; } + + // See fex.h + blargg_err_t data( const void** data_out ); + int tell() const { return size_ - remain(); } + +// Derived interface +protected: + + // Sets type of object + fex_t( fex_type_t ); + + // Path to archive file, or "" if none supplied + const char* arc_path() const { return path_.begin(); } + + // Opens archive file if it's not already. If unbuffered is true, opens file + // without any buffering. + blargg_err_t open_arc_file( bool unbuffered = false ); + + // Archive file + File_Reader& arc() const { return *reader_; } + + // Sets current file name + void set_name( const char name [], const wchar_t* wname = NULL ); + + // Sets current file information + void set_info( int size, unsigned date = 0, unsigned crc = 0 ); + +// User overrides + + // Overrides must do indicated task. Non-pure functions have reasonable default + // implementation. Overrides should avoid calling public functions like + // next() and rewind(). + + // Open archive using file_path(). OK to delay actual file opening until later. + // Default just calls open_arc_file(), then open_v(). + virtual blargg_err_t open_path_v(); + + // Open archive using file() for source data. If unsupported, return error. + virtual blargg_err_t open_v() BLARGG_PURE( ; ) + + // Go to next file in archive and call set_name() and optionally set_info() + virtual blargg_err_t next_v() BLARGG_PURE( ; ) + + // Go back to first file in archive + virtual blargg_err_t rewind_v() BLARGG_PURE( ; ) + + // Close archive. Called even if open_path_v() or open_v() return unsuccessfully. + virtual void close_v() BLARGG_PURE( ; ) + + // Clear any fields related to current file + virtual void clear_file_v() { } + + // Call set_info() if not already called by next_v() + virtual blargg_err_t stat_v() { return blargg_ok; } + + // Return value that allows later return to this file. Result must be >= 0. + virtual fex_pos_t tell_arc_v() const; + + // Return to previously saved position + virtual blargg_err_t seek_arc_v( fex_pos_t ); + + // One or both of the following must be overridden + + // Provide pointer to data for current file in archive + virtual blargg_err_t data_v( const void** out ); + + // Extract next n bytes + virtual blargg_err_t extract_v( void* out, int n ); + +// Implementation +public: + BLARGG_DISABLE_NOTHROW + +private: + fex_type_t const type_; + + // Archive file + blargg_vector path_; + File_Reader* reader_; + File_Reader* own_file_; + bool opened_; + + // Position in archive + fex_pos_t tell_; // only used by default implementation of tell/seek + bool done_; + + // Info for current file in archive + const char* name_; + const wchar_t* wname_; + unsigned date_; + unsigned crc32_; + int size_; + bool stat_called; + + // Current file contents + void const* data_ptr_; // NULL if not read into memory + blargg_vector own_data_; + + bool opened() const { return opened_; } + void clear_file(); + void close_(); + blargg_err_t set_path( const char* path ); + blargg_err_t rewind_file(); + blargg_err_t next_(); + + // Data_Reader overrides + // TODO: override skip_v? + virtual blargg_err_t read_v( void* out, int n ); +}; + +struct fex_type_t_ +{ + const char* extension; + File_Extractor* (*new_fex)(); + const char* name; + blargg_err_t (*init)(); // Called by fex_init(). Can be NULL. +}; + +extern const fex_type_t_ + fex_7z_type [1], + fex_gz_type [1], + fex_rar_type [1], + fex_zip_type [1], + fex_bin_type [1]; + +inline blargg_err_t File_Extractor::open_v() { return blargg_ok; } +inline blargg_err_t File_Extractor::next_v() { return blargg_ok; } +inline blargg_err_t File_Extractor::rewind_v() { return blargg_ok; } +inline void File_Extractor::close_v() { } + +// Default to Std_File_Reader for archive access +#ifndef FEX_FILE_READER + #define FEX_FILE_READER Std_File_Reader +#elif defined (FEX_FILE_READER_INCLUDE) + #include FEX_FILE_READER_INCLUDE +#endif + +#endif diff --git a/fex/fex/Gzip_Extractor.cpp b/fex/fex/Gzip_Extractor.cpp index 6946de27..f169fed9 100644 --- a/fex/fex/Gzip_Extractor.cpp +++ b/fex/fex/Gzip_Extractor.cpp @@ -1,98 +1,98 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "Gzip_Extractor.h" - -/* Copyright (C) 2005-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -// TODO: could close file once data has been read into memory - -static blargg_err_t init_gzip_file() -{ - get_crc_table(); // initialize zlib's CRC-32 tables - return blargg_ok; -} - -static File_Extractor* new_gzip() -{ - return BLARGG_NEW Gzip_Extractor; -} - -fex_type_t_ const fex_gz_type [1] = {{ - ".gz", - &new_gzip, - "gzipped file", - &init_gzip_file -}}; - -Gzip_Extractor::Gzip_Extractor() : - File_Extractor( fex_gz_type ) -{ } - -Gzip_Extractor::~Gzip_Extractor() -{ - close(); -} - -blargg_err_t Gzip_Extractor::open_path_v() -{ - // skip opening file - return open_v(); -} - -blargg_err_t Gzip_Extractor::stat_v() -{ - RETURN_ERR( open_arc_file( true ) ); - if ( !gr.opened() || gr.tell() != 0 ) - RETURN_ERR( gr.open( &arc() ) ); - - set_info( gr.remain(), 0, gr.crc32() ); - return blargg_ok; -} - -blargg_err_t Gzip_Extractor::open_v() -{ - // Remove .gz suffix - size_t len = strlen( arc_path() ); - if ( fex_has_extension( arc_path(), ".gz" ) ) - len -= 3; - - RETURN_ERR( name.resize( len + 1 ) ); - memcpy( name.begin(), arc_path(), name.size() ); - name [name.size() - 1] = '\0'; - - set_name( name.begin() ); - return blargg_ok; -} - -void Gzip_Extractor::close_v() -{ - name.clear(); - gr.close(); -} - -blargg_err_t Gzip_Extractor::next_v() -{ - return blargg_ok; -} - -blargg_err_t Gzip_Extractor::rewind_v() -{ - set_name( name.begin() ); - return blargg_ok; -} - -blargg_err_t Gzip_Extractor::extract_v( void* p, int n ) -{ - return gr.read( p, n ); -} +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "Gzip_Extractor.h" + +/* Copyright (C) 2005-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +// TODO: could close file once data has been read into memory + +static blargg_err_t init_gzip_file() +{ + get_crc_table(); // initialize zlib's CRC-32 tables + return blargg_ok; +} + +static File_Extractor* new_gzip() +{ + return BLARGG_NEW Gzip_Extractor; +} + +fex_type_t_ const fex_gz_type [1] = {{ + ".gz", + &new_gzip, + "gzipped file", + &init_gzip_file +}}; + +Gzip_Extractor::Gzip_Extractor() : + File_Extractor( fex_gz_type ) +{ } + +Gzip_Extractor::~Gzip_Extractor() +{ + close(); +} + +blargg_err_t Gzip_Extractor::open_path_v() +{ + // skip opening file + return open_v(); +} + +blargg_err_t Gzip_Extractor::stat_v() +{ + RETURN_ERR( open_arc_file( true ) ); + if ( !gr.opened() || gr.tell() != 0 ) + RETURN_ERR( gr.open( &arc() ) ); + + set_info( gr.remain(), 0, gr.crc32() ); + return blargg_ok; +} + +blargg_err_t Gzip_Extractor::open_v() +{ + // Remove .gz suffix + size_t len = strlen( arc_path() ); + if ( fex_has_extension( arc_path(), ".gz" ) ) + len -= 3; + + RETURN_ERR( name.resize( len + 1 ) ); + memcpy( name.begin(), arc_path(), name.size() ); + name [name.size() - 1] = '\0'; + + set_name( name.begin() ); + return blargg_ok; +} + +void Gzip_Extractor::close_v() +{ + name.clear(); + gr.close(); +} + +blargg_err_t Gzip_Extractor::next_v() +{ + return blargg_ok; +} + +blargg_err_t Gzip_Extractor::rewind_v() +{ + set_name( name.begin() ); + return blargg_ok; +} + +blargg_err_t Gzip_Extractor::extract_v( void* p, int n ) +{ + return gr.read( p, n ); +} diff --git a/fex/fex/Gzip_Extractor.h b/fex/fex/Gzip_Extractor.h index 02044d0c..814dc9b3 100644 --- a/fex/fex/Gzip_Extractor.h +++ b/fex/fex/Gzip_Extractor.h @@ -1,34 +1,34 @@ -// Presents a gzipped file as an "archive" of just that file. -// Also handles non-gzipped files. - -// File_Extractor 1.0.0 -#ifndef GZIP_EXTRACTOR_H -#define GZIP_EXTRACTOR_H - -#include "File_Extractor.h" -#include "Gzip_Reader.h" - -class Gzip_Extractor : public File_Extractor { -public: - Gzip_Extractor(); - virtual ~Gzip_Extractor(); - -protected: - virtual blargg_err_t open_path_v(); - virtual blargg_err_t open_v(); - virtual void close_v(); - - virtual blargg_err_t next_v(); - virtual blargg_err_t rewind_v(); - - virtual blargg_err_t stat_v(); - virtual blargg_err_t extract_v( void*, int ); - -private: - Gzip_Reader gr; - blargg_vector name; - - void set_info_(); -}; - -#endif +// Presents a gzipped file as an "archive" of just that file. +// Also handles non-gzipped files. + +// File_Extractor 1.0.0 +#ifndef GZIP_EXTRACTOR_H +#define GZIP_EXTRACTOR_H + +#include "File_Extractor.h" +#include "Gzip_Reader.h" + +class Gzip_Extractor : public File_Extractor { +public: + Gzip_Extractor(); + virtual ~Gzip_Extractor(); + +protected: + virtual blargg_err_t open_path_v(); + virtual blargg_err_t open_v(); + virtual void close_v(); + + virtual blargg_err_t next_v(); + virtual blargg_err_t rewind_v(); + + virtual blargg_err_t stat_v(); + virtual blargg_err_t extract_v( void*, int ); + +private: + Gzip_Reader gr; + blargg_vector name; + + void set_info_(); +}; + +#endif diff --git a/fex/fex/Gzip_Reader.cpp b/fex/fex/Gzip_Reader.cpp index 464beee7..2aad302c 100644 --- a/fex/fex/Gzip_Reader.cpp +++ b/fex/fex/Gzip_Reader.cpp @@ -1,85 +1,85 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "Gzip_Reader.h" - -#include "blargg_endian.h" - -/* Copyright (C) 2006-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -Gzip_Reader::Gzip_Reader() -{ - close(); -} - -Gzip_Reader::~Gzip_Reader() -{ } - -static blargg_err_t gzip_reader_read( void* file, void* out, int* count ) -{ - return STATIC_CAST(File_Reader*,file)->read_avail( out, count ); -} - -blargg_err_t Gzip_Reader::calc_size() -{ - size_ = in->size(); - crc32_ = 0; - if ( inflater.deflated() ) - { - byte trailer [8]; - int old_pos = in->tell(); - RETURN_ERR( in->seek( size_ - sizeof trailer ) ); - RETURN_ERR( in->read( trailer, sizeof trailer ) ); - RETURN_ERR( in->seek( old_pos ) ); - crc32_ = get_le32( trailer + 0 ); - - unsigned n = get_le32( trailer + 4 ); - if ( n > INT_MAX ) - return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "gzip larger than 2GB" ); - - size_ = n; - } - return blargg_ok; -} - -blargg_err_t Gzip_Reader::open( File_Reader* new_in ) -{ - close(); - - in = new_in; - RETURN_ERR( in->seek( 0 ) ); - RETURN_ERR( inflater.begin( gzip_reader_read, new_in ) ); - RETURN_ERR( inflater.set_mode( inflater.mode_auto ) ); - RETURN_ERR( calc_size() ); - set_remain( size_ ); - - return blargg_ok; -} - -void Gzip_Reader::close() -{ - in = NULL; - inflater.end(); -} - -blargg_err_t Gzip_Reader::read_v( void* out, int count ) -{ - assert( in ); - int actual = count; - RETURN_ERR( inflater.read( out, &actual ) ); - - if ( actual != count ) - return blargg_err_file_corrupt; - - return blargg_ok; -} +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "Gzip_Reader.h" + +#include "blargg_endian.h" + +/* Copyright (C) 2006-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +Gzip_Reader::Gzip_Reader() +{ + close(); +} + +Gzip_Reader::~Gzip_Reader() +{ } + +static blargg_err_t gzip_reader_read( void* file, void* out, int* count ) +{ + return STATIC_CAST(File_Reader*,file)->read_avail( out, count ); +} + +blargg_err_t Gzip_Reader::calc_size() +{ + size_ = in->size(); + crc32_ = 0; + if ( inflater.deflated() ) + { + byte trailer [8]; + int old_pos = in->tell(); + RETURN_ERR( in->seek( size_ - sizeof trailer ) ); + RETURN_ERR( in->read( trailer, sizeof trailer ) ); + RETURN_ERR( in->seek( old_pos ) ); + crc32_ = get_le32( trailer + 0 ); + + unsigned n = get_le32( trailer + 4 ); + if ( n > INT_MAX ) + return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "gzip larger than 2GB" ); + + size_ = n; + } + return blargg_ok; +} + +blargg_err_t Gzip_Reader::open( File_Reader* new_in ) +{ + close(); + + in = new_in; + RETURN_ERR( in->seek( 0 ) ); + RETURN_ERR( inflater.begin( gzip_reader_read, new_in ) ); + RETURN_ERR( inflater.set_mode( inflater.mode_auto ) ); + RETURN_ERR( calc_size() ); + set_remain( size_ ); + + return blargg_ok; +} + +void Gzip_Reader::close() +{ + in = NULL; + inflater.end(); +} + +blargg_err_t Gzip_Reader::read_v( void* out, int count ) +{ + assert( in ); + int actual = count; + RETURN_ERR( inflater.read( out, &actual ) ); + + if ( actual != count ) + return blargg_err_file_corrupt; + + return blargg_ok; +} diff --git a/fex/fex/Gzip_Reader.h b/fex/fex/Gzip_Reader.h index 72123ead..a9b2d6a9 100644 --- a/fex/fex/Gzip_Reader.h +++ b/fex/fex/Gzip_Reader.h @@ -1,46 +1,46 @@ -// Transparently decompresses gzip files, as well as uncompressed - -// File_Extractor 1.0.0 -#ifndef GZIP_READER_H -#define GZIP_READER_H - -#include "Data_Reader.h" -#include "Zlib_Inflater.h" - -class Gzip_Reader : public Data_Reader { -public: - // Keeps pointer to reader until close(). If - blargg_err_t open( File_Reader* ); - - // True if file is open - bool opened() const { return in != NULL; } - - // Frees memory - void close(); - - // True if file is compressed - bool deflated() const { return inflater.deflated(); } - - // CRC-32 of data, of 0 if unavailable - unsigned int crc32() const { return crc32_; } - - // Number of bytes read since opening - int tell() const { return size_ - remain(); } - -public: - Gzip_Reader(); - virtual ~Gzip_Reader(); - -protected: - virtual blargg_err_t read_v( void*, int ); - -private: - File_Reader* in; - unsigned crc32_; - int size_; - Zlib_Inflater inflater; - - blargg_err_t calc_size(); -}; - -#endif +// Transparently decompresses gzip files, as well as uncompressed + +// File_Extractor 1.0.0 +#ifndef GZIP_READER_H +#define GZIP_READER_H + +#include "Data_Reader.h" +#include "Zlib_Inflater.h" + +class Gzip_Reader : public Data_Reader { +public: + // Keeps pointer to reader until close(). If + blargg_err_t open( File_Reader* ); + + // True if file is open + bool opened() const { return in != NULL; } + + // Frees memory + void close(); + + // True if file is compressed + bool deflated() const { return inflater.deflated(); } + + // CRC-32 of data, of 0 if unavailable + unsigned int crc32() const { return crc32_; } + + // Number of bytes read since opening + int tell() const { return size_ - remain(); } + +public: + Gzip_Reader(); + virtual ~Gzip_Reader(); + +protected: + virtual blargg_err_t read_v( void*, int ); + +private: + File_Reader* in; + unsigned crc32_; + int size_; + Zlib_Inflater inflater; + + blargg_err_t calc_size(); +}; + +#endif diff --git a/fex/fex/Rar_Extractor.cpp b/fex/fex/Rar_Extractor.cpp index 41058646..afade7fa 100644 --- a/fex/fex/Rar_Extractor.cpp +++ b/fex/fex/Rar_Extractor.cpp @@ -1,197 +1,197 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "blargg_common.h" - -#if FEX_ENABLE_RAR - -#include "Rar_Extractor.h" - -/* Copyright (C) 2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -static blargg_err_t init_rar() -{ - unrar_init(); - return blargg_ok; -} - -static File_Extractor* new_rar() -{ - return BLARGG_NEW Rar_Extractor; -} - -fex_type_t_ const fex_rar_type [1] = {{ - ".rar", - &new_rar, - "RAR archive", - &init_rar -}}; - -blargg_err_t Rar_Extractor::convert_err( unrar_err_t err ) -{ - blargg_err_t reader_err = reader.err; - reader.err = blargg_ok; - if ( reader_err ) - check( err == unrar_next_err ); - - switch ( err ) - { - case unrar_ok: return blargg_ok; - case unrar_err_memory: return blargg_err_memory; - case unrar_err_open: return blargg_err_file_read; - case unrar_err_not_arc: return blargg_err_file_type; - case unrar_err_corrupt: return blargg_err_file_corrupt; - case unrar_err_io: return blargg_err_file_io; - case unrar_err_arc_eof: return blargg_err_internal; - case unrar_err_encrypted: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR encryption not supported" ); - case unrar_err_segmented: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR segmentation not supported" ); - case unrar_err_huge: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "Huge RAR files not supported" ); - case unrar_err_old_algo: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "Old RAR compression not supported" ); - case unrar_err_new_algo: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR uses unknown newer compression" ); - case unrar_next_err: break; - default: - check( false ); // unhandled RAR error - } - - if ( reader_err ) - return reader_err; - - check( false ); - return BLARGG_ERR( BLARGG_ERR_INTERNAL, "RAR archive" ); -} - -static inline unrar_err_t handle_err( Rar_Extractor::read_callback_t* h, blargg_err_t err ) -{ - if ( !err ) - return unrar_ok; - - h->err = err; - return unrar_next_err; -} - -extern "C" -{ - static unrar_err_t my_unrar_read( void* data, void* out, int* count, unrar_pos_t pos ) - { - // TODO: 64-bit file support - - Rar_Extractor::read_callback_t* h = STATIC_CAST(Rar_Extractor::read_callback_t*,data); - if ( h->pos != pos ) - { - blargg_err_t err = h->in->seek( pos ); - if ( err ) - return handle_err( h, err ); - - h->pos = pos; - } - - blargg_err_t err = h->in->read_avail( out, count ); - if ( err ) - return handle_err( h, err ); - - h->pos += *count; - - return unrar_ok; - } -} - -Rar_Extractor::Rar_Extractor() : - File_Extractor( fex_rar_type ) -{ - unrar = NULL; -} - -Rar_Extractor::~Rar_Extractor() -{ - close(); -} - -blargg_err_t Rar_Extractor::open_v() -{ - reader.pos = 0; - reader.in = &arc(); - reader.err = blargg_ok; - - RETURN_ERR( arc().seek( 0 ) ); - RETURN_ERR( convert_err( unrar_open_custom( &unrar, &my_unrar_read, &reader ) ) ); - return skip_unextractables(); -} - -void Rar_Extractor::close_v() -{ - unrar_close( unrar ); - - unrar = NULL; - reader.in = NULL; -} - -blargg_err_t Rar_Extractor::skip_unextractables() -{ - while ( !unrar_done( unrar ) && unrar_try_extract( unrar ) ) - RETURN_ERR( next_raw() ); - - if ( !unrar_done( unrar ) ) - { - unrar_info_t const* info = unrar_info( unrar ); - - set_name( info->name, (info->name_w && *info->name_w) ? info->name_w : NULL ); - set_info( info->size, info->dos_date, (info->is_crc32 ? info->crc : 0) ); - } - - return blargg_ok; -} - -blargg_err_t Rar_Extractor::next_raw() -{ - return convert_err( unrar_next( unrar ) ); -} - -blargg_err_t Rar_Extractor::next_v() -{ - RETURN_ERR( next_raw() ); - return skip_unextractables(); -} - -blargg_err_t Rar_Extractor::rewind_v() -{ - RETURN_ERR( convert_err( unrar_rewind( unrar ) ) ); - return skip_unextractables(); -} - -fex_pos_t Rar_Extractor::tell_arc_v() const -{ - return unrar_tell( unrar ); -} - -blargg_err_t Rar_Extractor::seek_arc_v( fex_pos_t pos ) -{ - RETURN_ERR( convert_err( unrar_seek( unrar, pos ) ) ); - return skip_unextractables(); -} - -blargg_err_t Rar_Extractor::data_v( void const** out ) -{ - return convert_err( unrar_extract_mem( unrar, out ) ); -} - -blargg_err_t Rar_Extractor::extract_v( void* out, int count ) -{ - // We can read entire file directly into user buffer - if ( count == size() ) - return convert_err( unrar_extract( unrar, out, count ) ); - - // This will call data_v() and copy from that buffer for us - return File_Extractor::extract_v( out, count ); -} - -#endif +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "blargg_common.h" + +#if FEX_ENABLE_RAR + +#include "Rar_Extractor.h" + +/* Copyright (C) 2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +static blargg_err_t init_rar() +{ + unrar_init(); + return blargg_ok; +} + +static File_Extractor* new_rar() +{ + return BLARGG_NEW Rar_Extractor; +} + +fex_type_t_ const fex_rar_type [1] = {{ + ".rar", + &new_rar, + "RAR archive", + &init_rar +}}; + +blargg_err_t Rar_Extractor::convert_err( unrar_err_t err ) +{ + blargg_err_t reader_err = reader.err; + reader.err = blargg_ok; + if ( reader_err ) + check( err == unrar_next_err ); + + switch ( err ) + { + case unrar_ok: return blargg_ok; + case unrar_err_memory: return blargg_err_memory; + case unrar_err_open: return blargg_err_file_read; + case unrar_err_not_arc: return blargg_err_file_type; + case unrar_err_corrupt: return blargg_err_file_corrupt; + case unrar_err_io: return blargg_err_file_io; + case unrar_err_arc_eof: return blargg_err_internal; + case unrar_err_encrypted: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR encryption not supported" ); + case unrar_err_segmented: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR segmentation not supported" ); + case unrar_err_huge: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "Huge RAR files not supported" ); + case unrar_err_old_algo: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "Old RAR compression not supported" ); + case unrar_err_new_algo: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR uses unknown newer compression" ); + case unrar_next_err: break; + default: + check( false ); // unhandled RAR error + } + + if ( reader_err ) + return reader_err; + + check( false ); + return BLARGG_ERR( BLARGG_ERR_INTERNAL, "RAR archive" ); +} + +static inline unrar_err_t handle_err( Rar_Extractor::read_callback_t* h, blargg_err_t err ) +{ + if ( !err ) + return unrar_ok; + + h->err = err; + return unrar_next_err; +} + +extern "C" +{ + static unrar_err_t my_unrar_read( void* data, void* out, int* count, unrar_pos_t pos ) + { + // TODO: 64-bit file support + + Rar_Extractor::read_callback_t* h = STATIC_CAST(Rar_Extractor::read_callback_t*,data); + if ( h->pos != pos ) + { + blargg_err_t err = h->in->seek( pos ); + if ( err ) + return handle_err( h, err ); + + h->pos = pos; + } + + blargg_err_t err = h->in->read_avail( out, count ); + if ( err ) + return handle_err( h, err ); + + h->pos += *count; + + return unrar_ok; + } +} + +Rar_Extractor::Rar_Extractor() : + File_Extractor( fex_rar_type ) +{ + unrar = NULL; +} + +Rar_Extractor::~Rar_Extractor() +{ + close(); +} + +blargg_err_t Rar_Extractor::open_v() +{ + reader.pos = 0; + reader.in = &arc(); + reader.err = blargg_ok; + + RETURN_ERR( arc().seek( 0 ) ); + RETURN_ERR( convert_err( unrar_open_custom( &unrar, &my_unrar_read, &reader ) ) ); + return skip_unextractables(); +} + +void Rar_Extractor::close_v() +{ + unrar_close( unrar ); + + unrar = NULL; + reader.in = NULL; +} + +blargg_err_t Rar_Extractor::skip_unextractables() +{ + while ( !unrar_done( unrar ) && unrar_try_extract( unrar ) ) + RETURN_ERR( next_raw() ); + + if ( !unrar_done( unrar ) ) + { + unrar_info_t const* info = unrar_info( unrar ); + + set_name( info->name, (info->name_w && *info->name_w) ? info->name_w : NULL ); + set_info( info->size, info->dos_date, (info->is_crc32 ? info->crc : 0) ); + } + + return blargg_ok; +} + +blargg_err_t Rar_Extractor::next_raw() +{ + return convert_err( unrar_next( unrar ) ); +} + +blargg_err_t Rar_Extractor::next_v() +{ + RETURN_ERR( next_raw() ); + return skip_unextractables(); +} + +blargg_err_t Rar_Extractor::rewind_v() +{ + RETURN_ERR( convert_err( unrar_rewind( unrar ) ) ); + return skip_unextractables(); +} + +fex_pos_t Rar_Extractor::tell_arc_v() const +{ + return unrar_tell( unrar ); +} + +blargg_err_t Rar_Extractor::seek_arc_v( fex_pos_t pos ) +{ + RETURN_ERR( convert_err( unrar_seek( unrar, pos ) ) ); + return skip_unextractables(); +} + +blargg_err_t Rar_Extractor::data_v( void const** out ) +{ + return convert_err( unrar_extract_mem( unrar, out ) ); +} + +blargg_err_t Rar_Extractor::extract_v( void* out, int count ) +{ + // We can read entire file directly into user buffer + if ( count == size() ) + return convert_err( unrar_extract( unrar, out, count ) ); + + // This will call data_v() and copy from that buffer for us + return File_Extractor::extract_v( out, count ); +} + +#endif diff --git a/fex/fex/Rar_Extractor.h b/fex/fex/Rar_Extractor.h index 0f0174d1..9a74dea3 100644 --- a/fex/fex/Rar_Extractor.h +++ b/fex/fex/Rar_Extractor.h @@ -1,43 +1,43 @@ -// RAR archive extractor - -// File_Extractor 1.0.0 -#ifndef RAR_EXTRACTOR_H -#define RAR_EXTRACTOR_H - -#include "File_Extractor.h" -#include "unrar/unrar.h" - -class Rar_Extractor : public File_Extractor { -public: - Rar_Extractor(); - virtual ~Rar_Extractor(); - - struct read_callback_t - { - const char* err; - int pos; - File_Reader* in; - }; - -protected: - virtual blargg_err_t open_v(); - virtual void close_v(); - - virtual blargg_err_t next_v(); - virtual blargg_err_t rewind_v(); - virtual fex_pos_t tell_arc_v() const; - virtual blargg_err_t seek_arc_v( fex_pos_t ); - - virtual blargg_err_t data_v( void const** ); - virtual blargg_err_t extract_v( void*, int ); - -private: - unrar_t* unrar; - read_callback_t reader; - - blargg_err_t convert_err( unrar_err_t ); - blargg_err_t skip_unextractables(); - blargg_err_t next_raw(); -}; - -#endif +// RAR archive extractor + +// File_Extractor 1.0.0 +#ifndef RAR_EXTRACTOR_H +#define RAR_EXTRACTOR_H + +#include "File_Extractor.h" +#include "unrar/unrar.h" + +class Rar_Extractor : public File_Extractor { +public: + Rar_Extractor(); + virtual ~Rar_Extractor(); + + struct read_callback_t + { + const char* err; + int pos; + File_Reader* in; + }; + +protected: + virtual blargg_err_t open_v(); + virtual void close_v(); + + virtual blargg_err_t next_v(); + virtual blargg_err_t rewind_v(); + virtual fex_pos_t tell_arc_v() const; + virtual blargg_err_t seek_arc_v( fex_pos_t ); + + virtual blargg_err_t data_v( void const** ); + virtual blargg_err_t extract_v( void*, int ); + +private: + unrar_t* unrar; + read_callback_t reader; + + blargg_err_t convert_err( unrar_err_t ); + blargg_err_t skip_unextractables(); + blargg_err_t next_raw(); +}; + +#endif diff --git a/fex/fex/Zip7_Extractor.cpp b/fex/fex/Zip7_Extractor.cpp index d1fcbf44..1b6071db 100644 --- a/fex/fex/Zip7_Extractor.cpp +++ b/fex/fex/Zip7_Extractor.cpp @@ -1,354 +1,354 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "Zip7_Extractor.h" - -extern "C" { -#include "7z_C/7z.h" -#include "7z_C/7zAlloc.h" -#include "7z_C/7zCrc.h" -} - -#include - -/* Copyright (C) 2005-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -static ISzAlloc zip7_alloc = { SzAlloc, SzFree }; -static ISzAlloc zip7_alloc_temp = { SzAllocTemp, SzFreeTemp }; - -struct Zip7_Extractor_Impl : - ISeekInStream -{ - CLookToRead look; - CSzArEx db; - - // SzExtract state - UInt32 block_index; - Byte* buf; - size_t buf_size; - - File_Reader* in; - const char* in_err; -}; - -extern "C" -{ - // 7-zip callbacks pass an ISeekInStream* for data, so we must cast it - // back to ISeekInStream* FIRST, then cast to our Impl structure - - static SRes zip7_read_( void* vstream, void* out, size_t* size ) - { - assert( out && size ); - ISeekInStream* stream = STATIC_CAST(ISeekInStream*,vstream); - Zip7_Extractor_Impl* impl = STATIC_CAST(Zip7_Extractor_Impl*,stream); - - long lsize = *size; - blargg_err_t err = impl->in->read_avail( out, &lsize ); - if ( err ) - { - *size = 0; - impl->in_err = err; - return SZ_ERROR_READ; - } - - *size = lsize; - return SZ_OK; - } - - static SRes zip7_seek_( void* vstream, Int64* pos, ESzSeek mode ) - { - ISeekInStream* stream = STATIC_CAST(ISeekInStream*,vstream); - Zip7_Extractor_Impl* impl = STATIC_CAST(Zip7_Extractor_Impl*,stream); - - // assert( mode != SZ_SEEK_CUR ); // never used - - if ( mode == SZ_SEEK_END ) - { - assert( *pos == 0 ); // only used to find file length - *pos = impl->in->size(); - return SZ_OK; - } - - // assert( mode == SZ_SEEK_SET ); - blargg_err_t err = impl->in->seek( *pos ); - if ( err ) - { - // don't set in_err in this case, since it might be benign - if ( err == blargg_err_file_eof ) - return SZ_ERROR_INPUT_EOF; - - impl->in_err = err; - return SZ_ERROR_READ; - } - - return SZ_OK; - } -} - -blargg_err_t Zip7_Extractor::zip7_err( int err ) -{ - // TODO: ignore in_err in some cases? unsure about which error to use - blargg_err_t in_err = impl->in_err; - impl->in_err = NULL; - if ( in_err ) - { - check( err != SZ_OK ); - return in_err; - } - - switch ( err ) - { - case SZ_OK: return blargg_ok; - case SZ_ERROR_MEM: return blargg_err_memory; - case SZ_ERROR_READ: return blargg_err_file_io; - case SZ_ERROR_CRC: - case SZ_ERROR_DATA: - case SZ_ERROR_INPUT_EOF: - case SZ_ERROR_ARCHIVE: return blargg_err_file_corrupt; - case SZ_ERROR_UNSUPPORTED: return blargg_err_file_feature; - case SZ_ERROR_NO_ARCHIVE: return blargg_err_file_type; - } - - return blargg_err_generic; -} - -static blargg_err_t init_7z() -{ - static bool inited; - if ( !inited ) - { - inited = true; - CrcGenerateTable(); - } - return blargg_ok; -} - -static File_Extractor* new_7z() -{ - return BLARGG_NEW Zip7_Extractor; -} - -fex_type_t_ const fex_7z_type [1] = {{ - ".7z", - &new_7z, - "7-zip archive", - &init_7z -}}; - -Zip7_Extractor::Zip7_Extractor() : - File_Extractor( fex_7z_type ) -{ - impl = NULL; -} - -Zip7_Extractor::~Zip7_Extractor() -{ - close(); -} - -blargg_err_t Zip7_Extractor::open_v() -{ - RETURN_ERR( init_7z() ); - - if ( !impl ) - { - impl = (Zip7_Extractor_Impl*) malloc( sizeof *impl ); - CHECK_ALLOC( impl ); - } - - impl->in = &arc(); - impl->block_index = (UInt32) -1; - impl->buf = NULL; - impl->buf_size = 0; - - LookToRead_CreateVTable( &impl->look, false ); - impl->ISeekInStream::Read = zip7_read_; - impl->ISeekInStream::Seek = zip7_seek_; - impl->look.realStream = impl; - LookToRead_Init( &impl->look ); - - SzArEx_Init( &impl->db ); - - impl->in_err = NULL; - RETURN_ERR( zip7_err( SzArEx_Open( &impl->db, &impl->look.s, - &zip7_alloc, &zip7_alloc_temp ) ) ); - - return seek_arc_v( 0 ); -} - -void Zip7_Extractor::close_v() -{ - if ( impl ) - { - if ( impl->in ) - { - impl->in = NULL; - SzArEx_Free( &impl->db, &zip7_alloc ); - } - IAlloc_Free( &zip7_alloc, impl->buf ); - free( impl ); - impl = NULL; - } -} - -// This method was taken from ogre-7z (thanks), and is thus LGPL -bool Zip7_Extractor::utf16ToUtf8( unsigned char* dest, size_t* destLen, const short* src, size_t srcLen ) -{ - static const unsigned char sUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - size_t destPos = 0, srcPos = 0; - for(;;) - { - unsigned int numAdds; - unsigned long value; - if( srcPos == srcLen ) - { - *destLen = destPos; - return true; - } - - value = src[srcPos++]; - if( value < 0x80 ) - { - if( dest ) - { - dest[destPos] = (char)value; - } - destPos++; - continue; - } - - if( value >= 0xD800 && value < 0xE000 ) - { - unsigned long c2; - if( value >= 0xDC00 || srcPos == srcLen ) - break; - - c2 = src[srcPos++]; - if( c2 < 0xDC00 || c2 >= 0xE000 ) - break; - - value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; - } - - for( numAdds = 1; numAdds < 5; numAdds++ ) - { - if( value < (((UInt32)1) << (numAdds * 5 + 6)) ) - break; - } - - if( dest ) - { - dest[destPos] = (char)(sUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); - } - - destPos++; - do - { - numAdds--; - if( dest ) - { - dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); - } - destPos++; - } - while( numAdds != 0 ); - } - - *destLen = destPos; - return false; -} - -blargg_err_t Zip7_Extractor::next_v() -{ - while ( ++index < (int) impl->db.db.NumFiles ) - { - CSzFileItem const& item = impl->db.db.Files [index]; - if ( !item.IsDir ) - { - unsigned long date = 0; - if ( item.MTimeDefined ) - { - const UInt64 epoch = ((UInt64)0x019db1de << 32) + 0xd53e8000; - /* 0x019db1ded53e8000ULL: 1970-01-01 00:00:00 (UTC) */ - struct tm tm; - - UInt64 time = ((UInt64)item.MTime.High << 32) + item.MTime.Low - epoch; - time /= 1000000; - - time_t _time = time; - - #ifdef _WIN32 - tm = *localtime( &_time ); - #else - localtime_r( &_time, &tm ); - #endif - - date = (( tm.tm_sec >> 1 ) & 0x1F) | - (( tm.tm_min & 0x3F ) << 5 ) | - (( tm.tm_hour & 0x1F ) << 11 ) | - (( tm.tm_mday & 0x1F ) << 16 ) | - (( ( tm.tm_mon + 1 ) & 0x0F ) << 21 ) | - (( ( tm.tm_year - 80 ) & 0x7F ) << 25 ); - } - - size_t name_length = SzArEx_GetFileNameUtf16( &impl->db, index, 0 ); - size_t utf8_length = 0; - name16.resize( name_length ); - SzArEx_GetFileNameUtf16( &impl->db, index, ( UInt16 * ) name16.begin() ); - unsigned char temp[1024]; - utf16ToUtf8( temp, &utf8_length, (const short*)name16.begin(), name_length - 1 ); - temp[utf8_length] = '\0'; - - name8.resize( utf8_length + 1 ); - memcpy( name8.begin(), temp, utf8_length + 1 ); - set_name( name8.begin(), name16.begin() ); - set_info( item.Size, 0, (item.CrcDefined ? item.Crc : 0) ); - break; - } - } - - return blargg_ok; -} - -blargg_err_t Zip7_Extractor::rewind_v() -{ - return seek_arc_v( 0 ); -} - -fex_pos_t Zip7_Extractor::tell_arc_v() const -{ - return index; -} - -blargg_err_t Zip7_Extractor::seek_arc_v( fex_pos_t pos ) -{ - assert( 0 <= pos && pos <= (int) impl->db.db.NumFiles ); - - index = pos - 1; - return next_v(); -} - -blargg_err_t Zip7_Extractor::data_v( void const** out ) -{ - impl->in_err = NULL; - size_t offset = 0; - size_t count = 0; - RETURN_ERR( zip7_err( SzArEx_Extract( &impl->db, &impl->look.s, index, - &impl->block_index, &impl->buf, &impl->buf_size, - &offset, &count, &zip7_alloc, &zip7_alloc_temp ) ) ); - assert( count == (size_t) size() ); - - *out = impl->buf + offset; - return blargg_ok; -} +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "Zip7_Extractor.h" + +extern "C" { +#include "7z_C/7z.h" +#include "7z_C/7zAlloc.h" +#include "7z_C/7zCrc.h" +} + +#include + +/* Copyright (C) 2005-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +static ISzAlloc zip7_alloc = { SzAlloc, SzFree }; +static ISzAlloc zip7_alloc_temp = { SzAllocTemp, SzFreeTemp }; + +struct Zip7_Extractor_Impl : + ISeekInStream +{ + CLookToRead look; + CSzArEx db; + + // SzExtract state + UInt32 block_index; + Byte* buf; + size_t buf_size; + + File_Reader* in; + const char* in_err; +}; + +extern "C" +{ + // 7-zip callbacks pass an ISeekInStream* for data, so we must cast it + // back to ISeekInStream* FIRST, then cast to our Impl structure + + static SRes zip7_read_( void* vstream, void* out, size_t* size ) + { + assert( out && size ); + ISeekInStream* stream = STATIC_CAST(ISeekInStream*,vstream); + Zip7_Extractor_Impl* impl = STATIC_CAST(Zip7_Extractor_Impl*,stream); + + long lsize = *size; + blargg_err_t err = impl->in->read_avail( out, &lsize ); + if ( err ) + { + *size = 0; + impl->in_err = err; + return SZ_ERROR_READ; + } + + *size = lsize; + return SZ_OK; + } + + static SRes zip7_seek_( void* vstream, Int64* pos, ESzSeek mode ) + { + ISeekInStream* stream = STATIC_CAST(ISeekInStream*,vstream); + Zip7_Extractor_Impl* impl = STATIC_CAST(Zip7_Extractor_Impl*,stream); + + // assert( mode != SZ_SEEK_CUR ); // never used + + if ( mode == SZ_SEEK_END ) + { + assert( *pos == 0 ); // only used to find file length + *pos = impl->in->size(); + return SZ_OK; + } + + // assert( mode == SZ_SEEK_SET ); + blargg_err_t err = impl->in->seek( *pos ); + if ( err ) + { + // don't set in_err in this case, since it might be benign + if ( err == blargg_err_file_eof ) + return SZ_ERROR_INPUT_EOF; + + impl->in_err = err; + return SZ_ERROR_READ; + } + + return SZ_OK; + } +} + +blargg_err_t Zip7_Extractor::zip7_err( int err ) +{ + // TODO: ignore in_err in some cases? unsure about which error to use + blargg_err_t in_err = impl->in_err; + impl->in_err = NULL; + if ( in_err ) + { + check( err != SZ_OK ); + return in_err; + } + + switch ( err ) + { + case SZ_OK: return blargg_ok; + case SZ_ERROR_MEM: return blargg_err_memory; + case SZ_ERROR_READ: return blargg_err_file_io; + case SZ_ERROR_CRC: + case SZ_ERROR_DATA: + case SZ_ERROR_INPUT_EOF: + case SZ_ERROR_ARCHIVE: return blargg_err_file_corrupt; + case SZ_ERROR_UNSUPPORTED: return blargg_err_file_feature; + case SZ_ERROR_NO_ARCHIVE: return blargg_err_file_type; + } + + return blargg_err_generic; +} + +static blargg_err_t init_7z() +{ + static bool inited; + if ( !inited ) + { + inited = true; + CrcGenerateTable(); + } + return blargg_ok; +} + +static File_Extractor* new_7z() +{ + return BLARGG_NEW Zip7_Extractor; +} + +fex_type_t_ const fex_7z_type [1] = {{ + ".7z", + &new_7z, + "7-zip archive", + &init_7z +}}; + +Zip7_Extractor::Zip7_Extractor() : + File_Extractor( fex_7z_type ) +{ + impl = NULL; +} + +Zip7_Extractor::~Zip7_Extractor() +{ + close(); +} + +blargg_err_t Zip7_Extractor::open_v() +{ + RETURN_ERR( init_7z() ); + + if ( !impl ) + { + impl = (Zip7_Extractor_Impl*) malloc( sizeof *impl ); + CHECK_ALLOC( impl ); + } + + impl->in = &arc(); + impl->block_index = (UInt32) -1; + impl->buf = NULL; + impl->buf_size = 0; + + LookToRead_CreateVTable( &impl->look, false ); + impl->ISeekInStream::Read = zip7_read_; + impl->ISeekInStream::Seek = zip7_seek_; + impl->look.realStream = impl; + LookToRead_Init( &impl->look ); + + SzArEx_Init( &impl->db ); + + impl->in_err = NULL; + RETURN_ERR( zip7_err( SzArEx_Open( &impl->db, &impl->look.s, + &zip7_alloc, &zip7_alloc_temp ) ) ); + + return seek_arc_v( 0 ); +} + +void Zip7_Extractor::close_v() +{ + if ( impl ) + { + if ( impl->in ) + { + impl->in = NULL; + SzArEx_Free( &impl->db, &zip7_alloc ); + } + IAlloc_Free( &zip7_alloc, impl->buf ); + free( impl ); + impl = NULL; + } +} + +// This method was taken from ogre-7z (thanks), and is thus LGPL +bool Zip7_Extractor::utf16ToUtf8( unsigned char* dest, size_t* destLen, const short* src, size_t srcLen ) +{ + static const unsigned char sUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + size_t destPos = 0, srcPos = 0; + for(;;) + { + unsigned int numAdds; + unsigned long value; + if( srcPos == srcLen ) + { + *destLen = destPos; + return true; + } + + value = src[srcPos++]; + if( value < 0x80 ) + { + if( dest ) + { + dest[destPos] = (char)value; + } + destPos++; + continue; + } + + if( value >= 0xD800 && value < 0xE000 ) + { + unsigned long c2; + if( value >= 0xDC00 || srcPos == srcLen ) + break; + + c2 = src[srcPos++]; + if( c2 < 0xDC00 || c2 >= 0xE000 ) + break; + + value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; + } + + for( numAdds = 1; numAdds < 5; numAdds++ ) + { + if( value < (((UInt32)1) << (numAdds * 5 + 6)) ) + break; + } + + if( dest ) + { + dest[destPos] = (char)(sUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); + } + + destPos++; + do + { + numAdds--; + if( dest ) + { + dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); + } + destPos++; + } + while( numAdds != 0 ); + } + + *destLen = destPos; + return false; +} + +blargg_err_t Zip7_Extractor::next_v() +{ + while ( ++index < (int) impl->db.db.NumFiles ) + { + CSzFileItem const& item = impl->db.db.Files [index]; + if ( !item.IsDir ) + { + unsigned long date = 0; + if ( item.MTimeDefined ) + { + const UInt64 epoch = ((UInt64)0x019db1de << 32) + 0xd53e8000; + /* 0x019db1ded53e8000ULL: 1970-01-01 00:00:00 (UTC) */ + struct tm tm; + + UInt64 time = ((UInt64)item.MTime.High << 32) + item.MTime.Low - epoch; + time /= 1000000; + + time_t _time = time; + + #ifdef _WIN32 + tm = *localtime( &_time ); + #else + localtime_r( &_time, &tm ); + #endif + + date = (( tm.tm_sec >> 1 ) & 0x1F) | + (( tm.tm_min & 0x3F ) << 5 ) | + (( tm.tm_hour & 0x1F ) << 11 ) | + (( tm.tm_mday & 0x1F ) << 16 ) | + (( ( tm.tm_mon + 1 ) & 0x0F ) << 21 ) | + (( ( tm.tm_year - 80 ) & 0x7F ) << 25 ); + } + + size_t name_length = SzArEx_GetFileNameUtf16( &impl->db, index, 0 ); + size_t utf8_length = 0; + name16.resize( name_length ); + SzArEx_GetFileNameUtf16( &impl->db, index, ( UInt16 * ) name16.begin() ); + unsigned char temp[1024]; + utf16ToUtf8( temp, &utf8_length, (const short*)name16.begin(), name_length - 1 ); + temp[utf8_length] = '\0'; + + name8.resize( utf8_length + 1 ); + memcpy( name8.begin(), temp, utf8_length + 1 ); + set_name( name8.begin(), name16.begin() ); + set_info( item.Size, 0, (item.CrcDefined ? item.Crc : 0) ); + break; + } + } + + return blargg_ok; +} + +blargg_err_t Zip7_Extractor::rewind_v() +{ + return seek_arc_v( 0 ); +} + +fex_pos_t Zip7_Extractor::tell_arc_v() const +{ + return index; +} + +blargg_err_t Zip7_Extractor::seek_arc_v( fex_pos_t pos ) +{ + assert( 0 <= pos && pos <= (int) impl->db.db.NumFiles ); + + index = pos - 1; + return next_v(); +} + +blargg_err_t Zip7_Extractor::data_v( void const** out ) +{ + impl->in_err = NULL; + size_t offset = 0; + size_t count = 0; + RETURN_ERR( zip7_err( SzArEx_Extract( &impl->db, &impl->look.s, index, + &impl->block_index, &impl->buf, &impl->buf_size, + &offset, &count, &zip7_alloc, &zip7_alloc_temp ) ) ); + assert( count == (size_t) size() ); + + *out = impl->buf + offset; + return blargg_ok; +} diff --git a/fex/fex/Zip7_Extractor.h b/fex/fex/Zip7_Extractor.h index 668f899f..a1d7e01c 100644 --- a/fex/fex/Zip7_Extractor.h +++ b/fex/fex/Zip7_Extractor.h @@ -1,38 +1,38 @@ -// 7-zip archive extractor - -// File_Extractor 1.0.0 -#ifndef ZIP7_EXTRACTOR_H -#define ZIP7_EXTRACTOR_H - -#include "File_Extractor.h" - -struct Zip7_Extractor_Impl; - -class Zip7_Extractor : public File_Extractor { -public: - Zip7_Extractor(); - virtual ~Zip7_Extractor(); - -protected: - virtual blargg_err_t open_v(); - virtual void close_v(); - - virtual blargg_err_t next_v(); - virtual blargg_err_t rewind_v(); - virtual fex_pos_t tell_arc_v() const; - virtual blargg_err_t seek_arc_v( fex_pos_t ); - - virtual blargg_err_t data_v( void const** out ); - - bool utf16ToUtf8( unsigned char* dest, size_t* destLen, const short* src, size_t srcLen ); - -private: - Zip7_Extractor_Impl* impl; - int index; - blargg_vector name8; - blargg_vector name16; - - blargg_err_t zip7_err( int err ); -}; - -#endif +// 7-zip archive extractor + +// File_Extractor 1.0.0 +#ifndef ZIP7_EXTRACTOR_H +#define ZIP7_EXTRACTOR_H + +#include "File_Extractor.h" + +struct Zip7_Extractor_Impl; + +class Zip7_Extractor : public File_Extractor { +public: + Zip7_Extractor(); + virtual ~Zip7_Extractor(); + +protected: + virtual blargg_err_t open_v(); + virtual void close_v(); + + virtual blargg_err_t next_v(); + virtual blargg_err_t rewind_v(); + virtual fex_pos_t tell_arc_v() const; + virtual blargg_err_t seek_arc_v( fex_pos_t ); + + virtual blargg_err_t data_v( void const** out ); + + bool utf16ToUtf8( unsigned char* dest, size_t* destLen, const short* src, size_t srcLen ); + +private: + Zip7_Extractor_Impl* impl; + int index; + blargg_vector name8; + blargg_vector name16; + + blargg_err_t zip7_err( int err ); +}; + +#endif diff --git a/fex/fex/Zip_Extractor.cpp b/fex/fex/Zip_Extractor.cpp index baeb8e32..8bcc61c3 100644 --- a/fex/fex/Zip_Extractor.cpp +++ b/fex/fex/Zip_Extractor.cpp @@ -1,390 +1,390 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "Zip_Extractor.h" - -#include "blargg_endian.h" - -/* Copyright (C) 2005-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -/* To avoid copying filename string from catalog, I terminate it by modifying -catalog data. This potentially requires moving the first byte of the type -of the next entry elsewhere; I move it to the first byte of made_by. Kind -of hacky, but I'd rather not have to allocate memory for a copy of it. */ - -#include "blargg_source.h" - -/* Reads this much from end of file when first opening. Only this much is -searched for the end catalog entry. If whole catalog is within this data, -nothing more needs to be read on open. */ -int const end_read_size = 8 * 1024; - -/* Reads are are made using file offset that's a multiple of this, -increasing performance. */ -int const disk_block_size = 4 * 1024; - -// Read buffer used for extracting file data -int const read_buf_size = 16 * 1024; - -struct header_t -{ - char type [4]; - byte vers [2]; - byte flags [2]; - byte method [2]; - byte date [4]; - byte crc [4]; - byte raw_size [4]; - byte size [4]; - byte filename_len [2]; - byte extra_len [2]; - char filename [2]; // [filename_len] - //char extra [extra_len]; -}; -int const header_size = 30; - -struct entry_t -{ - char type [4]; - byte made_by [2]; - byte vers [2]; - byte flags [2]; - byte method [2]; - byte date [4]; - byte crc [4]; - byte raw_size [4]; - byte size [4]; - byte filename_len [2]; - byte extra_len [2]; - byte comment_len [2]; - byte disk [2]; - byte int_attrib [2]; - byte ext_attrib [4]; - byte file_offset [4]; - char filename [2]; // [filename_len] - //char extra [extra_len]; - //char comment [comment_len]; -}; -int const entry_size = 46; - -struct end_entry_t -{ - char type [4]; - byte disk [2]; - byte first_disk [2]; - byte disk_entry_count [2]; - byte entry_count [2]; - byte dir_size [4]; - byte dir_offset [4]; - byte comment_len [2]; - char comment [2]; // [comment_len] -}; -int const end_entry_size = 22; - -static blargg_err_t init_zip() -{ - get_crc_table(); // initialize zlib's CRC-32 tables - return blargg_ok; -} - -static File_Extractor* new_zip() -{ - return BLARGG_NEW Zip_Extractor; -} - -fex_type_t_ const fex_zip_type [1] = {{ - ".zip", - &new_zip, - "ZIP archive", - &init_zip -}}; - -Zip_Extractor::Zip_Extractor() : - File_Extractor( fex_zip_type ) -{ - Zip_Extractor::clear_file_v(); - - // If these fail, structures had extra padding inserted by compiler - assert( offsetof (header_t,filename) == header_size ); - assert( offsetof (entry_t,filename) == entry_size ); - assert( offsetof (end_entry_t,comment) == end_entry_size ); -} - -Zip_Extractor::~Zip_Extractor() -{ - close(); -} - -blargg_err_t Zip_Extractor::open_path_v() -{ - RETURN_ERR( open_arc_file( true ) ); - return File_Extractor::open_path_v(); -} - -inline -void Zip_Extractor::reorder_entry_header( int offset ) -{ - catalog [offset + 0] = 0; - catalog [offset + 4] = 'P'; -} - -blargg_err_t Zip_Extractor::open_v() -{ - if ( arc().size() < end_entry_size ) - return blargg_err_file_type; - - // Read final end_read_size bytes of file - int file_pos = max( 0, arc().size() - end_read_size ); - file_pos -= file_pos % disk_block_size; - RETURN_ERR( catalog.resize( arc().size() - file_pos ) ); - RETURN_ERR( arc().seek( file_pos ) ); - RETURN_ERR( arc().read( catalog.begin(), catalog.size() ) ); - - // Find end-of-catalog entry - int end_pos = catalog.size() - end_entry_size; - while ( end_pos >= 0 && memcmp( &catalog [end_pos], "PK\5\6", 4 ) ) - end_pos--; - if ( end_pos < 0 ) - return blargg_err_file_type; - end_entry_t const& end_entry = (end_entry_t&) catalog [end_pos]; - end_pos += file_pos; - - // some idiotic zip compressors add data to end of zip without setting comment len -// check( arc().size() == end_pos + end_entry_size + get_le16( end_entry.comment_len ) ); - - // Find file offset of beginning of catalog - catalog_begin = get_le32( end_entry.dir_offset ); - int catalog_size = end_pos - catalog_begin; - if ( catalog_size < 0 ) - return blargg_err_file_corrupt; - catalog_size += end_entry_size; - - // See if catalog is entirely contained in bytes already read - int begin_offset = catalog_begin - file_pos; - if ( begin_offset >= 0 ) - memmove( catalog.begin(), &catalog [begin_offset], catalog_size ); - - RETURN_ERR( catalog.resize( catalog_size ) ); - if ( begin_offset < 0 ) - { - // Catalog begins before bytes read, so it needs to be read - RETURN_ERR( arc().seek( catalog_begin ) ); - RETURN_ERR( arc().read( catalog.begin(), catalog.size() ) ); - } - - // First entry in catalog should be a file or end of archive - if ( memcmp( catalog.begin(), "PK\1\2", 4 ) && memcmp( catalog.begin(), "PK\5\6", 4 ) ) - return blargg_err_file_type; - - reorder_entry_header( 0 ); - return rewind_v(); -} - -void Zip_Extractor::close_v() -{ - catalog.clear(); -} - -// Scanning - -inline -static bool is_normal_file( entry_t const& e, unsigned len ) -{ - int last_char = (len ? e.filename [len - 1] : '/'); - bool is_dir = (last_char == '/' || last_char == '\\'); - if ( is_dir && get_le32( e.size ) == 0 ) - return false; - check( !is_dir ); - - // Mac OS X puts meta-information in separate files with normal extensions, - // so they must be filtered out or caller will mistake them for normal files. - if ( e.made_by[1] == 3 ) - { - const char* dir = strrchr( e.filename, '/' ); - if ( dir ) - dir++; - else - dir = e.filename; - - if ( *dir == '.' ) - return false; - - if ( !strcmp( dir, "Icon\x0D" ) ) - return false; - } - - return true; -} - -blargg_err_t Zip_Extractor::update_info( bool advance_first ) -{ - while ( 1 ) - { - entry_t& e = (entry_t&) catalog [catalog_pos]; - - if ( memcmp( e.type, "\0K\1\2P", 5 ) && memcmp( e.type, "PK\1\2", 4 ) ) - { - check( !memcmp( e.type, "\0K\5\6P", 5 ) ); - break; - } - - unsigned len = get_le16( e.filename_len ); - int next_offset = catalog_pos + entry_size + len + get_le16( e.extra_len ) + - get_le16( e.comment_len ); - if ( (unsigned) next_offset > catalog.size() - end_entry_size ) - return blargg_err_file_corrupt; - - if ( catalog [next_offset] == 'P' ) - reorder_entry_header( next_offset ); - - if ( !advance_first ) - { - e.filename [len] = 0; // terminate name - - if ( is_normal_file( e, len ) ) - { - set_name( e.filename ); - set_info( get_le32( e.size ), get_le32( e.date ), get_le32( e.crc ) ); - break; - } - } - - catalog_pos = next_offset; - advance_first = false; - } - - return blargg_ok; -} - -blargg_err_t Zip_Extractor::next_v() -{ - return update_info( true ); -} - -blargg_err_t Zip_Extractor::rewind_v() -{ - return seek_arc_v( 0 ); -} - -fex_pos_t Zip_Extractor::tell_arc_v() const -{ - return catalog_pos; -} - -blargg_err_t Zip_Extractor::seek_arc_v( fex_pos_t pos ) -{ - assert( 0 <= pos && (size_t) pos <= catalog.size() - end_entry_size ); - - catalog_pos = pos; - return update_info( false ); -} - -// Reading - -void Zip_Extractor::clear_file_v() -{ - buf.end(); -} - -blargg_err_t Zip_Extractor::inflater_read( void* data, void* out, int* count ) -{ - Zip_Extractor& self = *STATIC_CAST(Zip_Extractor*,data); - - if ( *count > self.raw_remain ) - *count = self.raw_remain; - - self.raw_remain -= *count; - - return self.arc().read( out, *count ); -} - -blargg_err_t Zip_Extractor::fill_buf( int offset, int buf_size, int initial_read ) -{ - raw_remain = arc().size() - offset; - RETURN_ERR( arc().seek( offset ) ); - return buf.begin( inflater_read, this, buf_size, initial_read ); -} - -blargg_err_t Zip_Extractor::first_read( int count ) -{ - entry_t const& e = (entry_t&) catalog [catalog_pos]; - - // Determine compression - { - int method = get_le16( e.method ); - if ( (method && method != Z_DEFLATED) || get_le16( e.vers ) > 20 ) - return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "compression method" ); - file_deflated = (method != 0); - } - - int raw_size = get_le32( e.raw_size ); - - int file_offset = get_le32( e.file_offset ); - int align = file_offset % disk_block_size; - { - // read header - int buf_size = 3 * disk_block_size - 1 + raw_size; // space for all raw data - buf_size -= buf_size % disk_block_size; - int initial_read = buf_size; - if ( !file_deflated || count < size() ) - { - buf_size = read_buf_size; - initial_read = disk_block_size * 2; - } - // TODO: avoid re-reading if buffer already has data we want? - RETURN_ERR( fill_buf( file_offset - align, buf_size, initial_read ) ); - } - header_t const& h = (header_t&) buf.data() [align]; - if ( buf.filled() < align + header_size || memcmp( h.type, "PK\3\4", 4 ) ) - return blargg_err_file_corrupt; - - // CRCs of header and file data - correct_crc = get_le32( h.crc ); - if ( !correct_crc ) - correct_crc = get_le32( e.crc ); - check( correct_crc == get_le32( e.crc ) ); // catalog CRC should match - crc = ::crc32( 0, NULL, 0 ); - - // Data offset - int data_offset = file_offset + header_size + - get_le16( h.filename_len ) + get_le16( h.extra_len ); - if ( data_offset + raw_size > catalog_begin ) - return blargg_err_file_corrupt; - - // Refill buffer if there's lots of extra data after header - int buf_offset = data_offset - file_offset + align; - if ( buf_offset > buf.filled() ) - { - // TODO: this will almost never occur, making it a good place for bugs - buf_offset = data_offset % disk_block_size; - RETURN_ERR( fill_buf( data_offset - buf_offset, read_buf_size, disk_block_size ) ); - } - - raw_remain = raw_size - (buf.filled() - buf_offset); - return buf.set_mode( (file_deflated ? buf.mode_raw_deflate : buf.mode_copy), buf_offset ); -} - -blargg_err_t Zip_Extractor::extract_v( void* out, int count ) -{ - if ( tell() == 0 ) - RETURN_ERR( first_read( count ) ); - - int actual = count; - RETURN_ERR( buf.read( out, &actual ) ); - if ( actual < count ) - return blargg_err_file_corrupt; - - crc = ::crc32( crc, (byte const*) out, count ); - if ( count == reader().remain() && crc != correct_crc ) - return blargg_err_file_corrupt; - - return blargg_ok; -} +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "Zip_Extractor.h" + +#include "blargg_endian.h" + +/* Copyright (C) 2005-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +/* To avoid copying filename string from catalog, I terminate it by modifying +catalog data. This potentially requires moving the first byte of the type +of the next entry elsewhere; I move it to the first byte of made_by. Kind +of hacky, but I'd rather not have to allocate memory for a copy of it. */ + +#include "blargg_source.h" + +/* Reads this much from end of file when first opening. Only this much is +searched for the end catalog entry. If whole catalog is within this data, +nothing more needs to be read on open. */ +int const end_read_size = 8 * 1024; + +/* Reads are are made using file offset that's a multiple of this, +increasing performance. */ +int const disk_block_size = 4 * 1024; + +// Read buffer used for extracting file data +int const read_buf_size = 16 * 1024; + +struct header_t +{ + char type [4]; + byte vers [2]; + byte flags [2]; + byte method [2]; + byte date [4]; + byte crc [4]; + byte raw_size [4]; + byte size [4]; + byte filename_len [2]; + byte extra_len [2]; + char filename [2]; // [filename_len] + //char extra [extra_len]; +}; +int const header_size = 30; + +struct entry_t +{ + char type [4]; + byte made_by [2]; + byte vers [2]; + byte flags [2]; + byte method [2]; + byte date [4]; + byte crc [4]; + byte raw_size [4]; + byte size [4]; + byte filename_len [2]; + byte extra_len [2]; + byte comment_len [2]; + byte disk [2]; + byte int_attrib [2]; + byte ext_attrib [4]; + byte file_offset [4]; + char filename [2]; // [filename_len] + //char extra [extra_len]; + //char comment [comment_len]; +}; +int const entry_size = 46; + +struct end_entry_t +{ + char type [4]; + byte disk [2]; + byte first_disk [2]; + byte disk_entry_count [2]; + byte entry_count [2]; + byte dir_size [4]; + byte dir_offset [4]; + byte comment_len [2]; + char comment [2]; // [comment_len] +}; +int const end_entry_size = 22; + +static blargg_err_t init_zip() +{ + get_crc_table(); // initialize zlib's CRC-32 tables + return blargg_ok; +} + +static File_Extractor* new_zip() +{ + return BLARGG_NEW Zip_Extractor; +} + +fex_type_t_ const fex_zip_type [1] = {{ + ".zip", + &new_zip, + "ZIP archive", + &init_zip +}}; + +Zip_Extractor::Zip_Extractor() : + File_Extractor( fex_zip_type ) +{ + Zip_Extractor::clear_file_v(); + + // If these fail, structures had extra padding inserted by compiler + assert( offsetof (header_t,filename) == header_size ); + assert( offsetof (entry_t,filename) == entry_size ); + assert( offsetof (end_entry_t,comment) == end_entry_size ); +} + +Zip_Extractor::~Zip_Extractor() +{ + close(); +} + +blargg_err_t Zip_Extractor::open_path_v() +{ + RETURN_ERR( open_arc_file( true ) ); + return File_Extractor::open_path_v(); +} + +inline +void Zip_Extractor::reorder_entry_header( int offset ) +{ + catalog [offset + 0] = 0; + catalog [offset + 4] = 'P'; +} + +blargg_err_t Zip_Extractor::open_v() +{ + if ( arc().size() < end_entry_size ) + return blargg_err_file_type; + + // Read final end_read_size bytes of file + int file_pos = max( 0, arc().size() - end_read_size ); + file_pos -= file_pos % disk_block_size; + RETURN_ERR( catalog.resize( arc().size() - file_pos ) ); + RETURN_ERR( arc().seek( file_pos ) ); + RETURN_ERR( arc().read( catalog.begin(), catalog.size() ) ); + + // Find end-of-catalog entry + int end_pos = catalog.size() - end_entry_size; + while ( end_pos >= 0 && memcmp( &catalog [end_pos], "PK\5\6", 4 ) ) + end_pos--; + if ( end_pos < 0 ) + return blargg_err_file_type; + end_entry_t const& end_entry = (end_entry_t&) catalog [end_pos]; + end_pos += file_pos; + + // some idiotic zip compressors add data to end of zip without setting comment len +// check( arc().size() == end_pos + end_entry_size + get_le16( end_entry.comment_len ) ); + + // Find file offset of beginning of catalog + catalog_begin = get_le32( end_entry.dir_offset ); + int catalog_size = end_pos - catalog_begin; + if ( catalog_size < 0 ) + return blargg_err_file_corrupt; + catalog_size += end_entry_size; + + // See if catalog is entirely contained in bytes already read + int begin_offset = catalog_begin - file_pos; + if ( begin_offset >= 0 ) + memmove( catalog.begin(), &catalog [begin_offset], catalog_size ); + + RETURN_ERR( catalog.resize( catalog_size ) ); + if ( begin_offset < 0 ) + { + // Catalog begins before bytes read, so it needs to be read + RETURN_ERR( arc().seek( catalog_begin ) ); + RETURN_ERR( arc().read( catalog.begin(), catalog.size() ) ); + } + + // First entry in catalog should be a file or end of archive + if ( memcmp( catalog.begin(), "PK\1\2", 4 ) && memcmp( catalog.begin(), "PK\5\6", 4 ) ) + return blargg_err_file_type; + + reorder_entry_header( 0 ); + return rewind_v(); +} + +void Zip_Extractor::close_v() +{ + catalog.clear(); +} + +// Scanning + +inline +static bool is_normal_file( entry_t const& e, unsigned len ) +{ + int last_char = (len ? e.filename [len - 1] : '/'); + bool is_dir = (last_char == '/' || last_char == '\\'); + if ( is_dir && get_le32( e.size ) == 0 ) + return false; + check( !is_dir ); + + // Mac OS X puts meta-information in separate files with normal extensions, + // so they must be filtered out or caller will mistake them for normal files. + if ( e.made_by[1] == 3 ) + { + const char* dir = strrchr( e.filename, '/' ); + if ( dir ) + dir++; + else + dir = e.filename; + + if ( *dir == '.' ) + return false; + + if ( !strcmp( dir, "Icon\x0D" ) ) + return false; + } + + return true; +} + +blargg_err_t Zip_Extractor::update_info( bool advance_first ) +{ + while ( 1 ) + { + entry_t& e = (entry_t&) catalog [catalog_pos]; + + if ( memcmp( e.type, "\0K\1\2P", 5 ) && memcmp( e.type, "PK\1\2", 4 ) ) + { + check( !memcmp( e.type, "\0K\5\6P", 5 ) ); + break; + } + + unsigned len = get_le16( e.filename_len ); + int next_offset = catalog_pos + entry_size + len + get_le16( e.extra_len ) + + get_le16( e.comment_len ); + if ( (unsigned) next_offset > catalog.size() - end_entry_size ) + return blargg_err_file_corrupt; + + if ( catalog [next_offset] == 'P' ) + reorder_entry_header( next_offset ); + + if ( !advance_first ) + { + e.filename [len] = 0; // terminate name + + if ( is_normal_file( e, len ) ) + { + set_name( e.filename ); + set_info( get_le32( e.size ), get_le32( e.date ), get_le32( e.crc ) ); + break; + } + } + + catalog_pos = next_offset; + advance_first = false; + } + + return blargg_ok; +} + +blargg_err_t Zip_Extractor::next_v() +{ + return update_info( true ); +} + +blargg_err_t Zip_Extractor::rewind_v() +{ + return seek_arc_v( 0 ); +} + +fex_pos_t Zip_Extractor::tell_arc_v() const +{ + return catalog_pos; +} + +blargg_err_t Zip_Extractor::seek_arc_v( fex_pos_t pos ) +{ + assert( 0 <= pos && (size_t) pos <= catalog.size() - end_entry_size ); + + catalog_pos = pos; + return update_info( false ); +} + +// Reading + +void Zip_Extractor::clear_file_v() +{ + buf.end(); +} + +blargg_err_t Zip_Extractor::inflater_read( void* data, void* out, int* count ) +{ + Zip_Extractor& self = *STATIC_CAST(Zip_Extractor*,data); + + if ( *count > self.raw_remain ) + *count = self.raw_remain; + + self.raw_remain -= *count; + + return self.arc().read( out, *count ); +} + +blargg_err_t Zip_Extractor::fill_buf( int offset, int buf_size, int initial_read ) +{ + raw_remain = arc().size() - offset; + RETURN_ERR( arc().seek( offset ) ); + return buf.begin( inflater_read, this, buf_size, initial_read ); +} + +blargg_err_t Zip_Extractor::first_read( int count ) +{ + entry_t const& e = (entry_t&) catalog [catalog_pos]; + + // Determine compression + { + int method = get_le16( e.method ); + if ( (method && method != Z_DEFLATED) || get_le16( e.vers ) > 20 ) + return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "compression method" ); + file_deflated = (method != 0); + } + + int raw_size = get_le32( e.raw_size ); + + int file_offset = get_le32( e.file_offset ); + int align = file_offset % disk_block_size; + { + // read header + int buf_size = 3 * disk_block_size - 1 + raw_size; // space for all raw data + buf_size -= buf_size % disk_block_size; + int initial_read = buf_size; + if ( !file_deflated || count < size() ) + { + buf_size = read_buf_size; + initial_read = disk_block_size * 2; + } + // TODO: avoid re-reading if buffer already has data we want? + RETURN_ERR( fill_buf( file_offset - align, buf_size, initial_read ) ); + } + header_t const& h = (header_t&) buf.data() [align]; + if ( buf.filled() < align + header_size || memcmp( h.type, "PK\3\4", 4 ) ) + return blargg_err_file_corrupt; + + // CRCs of header and file data + correct_crc = get_le32( h.crc ); + if ( !correct_crc ) + correct_crc = get_le32( e.crc ); + check( correct_crc == get_le32( e.crc ) ); // catalog CRC should match + crc = ::crc32( 0, NULL, 0 ); + + // Data offset + int data_offset = file_offset + header_size + + get_le16( h.filename_len ) + get_le16( h.extra_len ); + if ( data_offset + raw_size > catalog_begin ) + return blargg_err_file_corrupt; + + // Refill buffer if there's lots of extra data after header + int buf_offset = data_offset - file_offset + align; + if ( buf_offset > buf.filled() ) + { + // TODO: this will almost never occur, making it a good place for bugs + buf_offset = data_offset % disk_block_size; + RETURN_ERR( fill_buf( data_offset - buf_offset, read_buf_size, disk_block_size ) ); + } + + raw_remain = raw_size - (buf.filled() - buf_offset); + return buf.set_mode( (file_deflated ? buf.mode_raw_deflate : buf.mode_copy), buf_offset ); +} + +blargg_err_t Zip_Extractor::extract_v( void* out, int count ) +{ + if ( tell() == 0 ) + RETURN_ERR( first_read( count ) ); + + int actual = count; + RETURN_ERR( buf.read( out, &actual ) ); + if ( actual < count ) + return blargg_err_file_corrupt; + + crc = ::crc32( crc, (byte const*) out, count ); + if ( count == reader().remain() && crc != correct_crc ) + return blargg_err_file_corrupt; + + return blargg_ok; +} diff --git a/fex/fex/Zip_Extractor.h b/fex/fex/Zip_Extractor.h index fc7c85cb..9742df99 100644 --- a/fex/fex/Zip_Extractor.h +++ b/fex/fex/Zip_Extractor.h @@ -1,45 +1,45 @@ -// ZIP archive extractor. Only supports deflation and store (no compression). - -// File_Extractor 1.0.0 -#ifndef ZIP_EXTRACTOR_H -#define ZIP_EXTRACTOR_H - -#include "File_Extractor.h" -#include "Zlib_Inflater.h" - -class Zip_Extractor : public File_Extractor { -public: - Zip_Extractor(); - virtual ~Zip_Extractor(); - -protected: - virtual blargg_err_t open_path_v(); - virtual blargg_err_t open_v(); - virtual void close_v(); - - virtual void clear_file_v(); - virtual blargg_err_t next_v(); - virtual blargg_err_t rewind_v(); - virtual fex_pos_t tell_arc_v() const; - virtual blargg_err_t seek_arc_v( fex_pos_t ); - - virtual blargg_err_t extract_v( void*, int ); - -private: - blargg_vector catalog; - int catalog_begin; // offset of first catalog entry in file (to detect corruption) - int catalog_pos; // position of current entry in catalog - int raw_remain; // bytes remaining to be read from zip file for current file - unsigned crc; // ongoing CRC of extracted bytes - unsigned correct_crc; - bool file_deflated; - Zlib_Inflater buf; - - blargg_err_t fill_buf( int offset, int buf_size, int initial_read ); - blargg_err_t update_info( bool advance_first ); - blargg_err_t first_read( int count ); - void reorder_entry_header( int offset ); - static blargg_err_t inflater_read( void* data, void* out, int* count ); -}; - -#endif +// ZIP archive extractor. Only supports deflation and store (no compression). + +// File_Extractor 1.0.0 +#ifndef ZIP_EXTRACTOR_H +#define ZIP_EXTRACTOR_H + +#include "File_Extractor.h" +#include "Zlib_Inflater.h" + +class Zip_Extractor : public File_Extractor { +public: + Zip_Extractor(); + virtual ~Zip_Extractor(); + +protected: + virtual blargg_err_t open_path_v(); + virtual blargg_err_t open_v(); + virtual void close_v(); + + virtual void clear_file_v(); + virtual blargg_err_t next_v(); + virtual blargg_err_t rewind_v(); + virtual fex_pos_t tell_arc_v() const; + virtual blargg_err_t seek_arc_v( fex_pos_t ); + + virtual blargg_err_t extract_v( void*, int ); + +private: + blargg_vector catalog; + int catalog_begin; // offset of first catalog entry in file (to detect corruption) + int catalog_pos; // position of current entry in catalog + int raw_remain; // bytes remaining to be read from zip file for current file + unsigned crc; // ongoing CRC of extracted bytes + unsigned correct_crc; + bool file_deflated; + Zlib_Inflater buf; + + blargg_err_t fill_buf( int offset, int buf_size, int initial_read ); + blargg_err_t update_info( bool advance_first ); + blargg_err_t first_read( int count ); + void reorder_entry_header( int offset ); + static blargg_err_t inflater_read( void* data, void* out, int* count ); +}; + +#endif diff --git a/fex/fex/Zlib_Inflater.cpp b/fex/fex/Zlib_Inflater.cpp index ac77ca51..8d31b514 100644 --- a/fex/fex/Zlib_Inflater.cpp +++ b/fex/fex/Zlib_Inflater.cpp @@ -1,257 +1,257 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "Zlib_Inflater.h" - -/* Copyright (C) 2006-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -int const block_size = 4096; - -static const char* get_zlib_err( int code ) -{ - assert( code != Z_OK ); - switch ( code ) - { - case Z_MEM_ERROR: return blargg_err_memory; - case Z_DATA_ERROR: return blargg_err_file_corrupt; - // TODO: handle more error codes - } - - const char* str = zError( code ); - if ( !str ) - str = BLARGG_ERR( BLARGG_ERR_GENERIC, "problem unzipping data" ); - - return str; -} - -void Zlib_Inflater::end() -{ - if ( deflated_ ) - { - deflated_ = false; - if ( inflateEnd( &zbuf ) ) - check( false ); - } - buf.clear(); - - static z_stream const empty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - memcpy( &zbuf, &empty, sizeof zbuf ); -} - -Zlib_Inflater::Zlib_Inflater() -{ - deflated_ = false; - end(); // initialize things -} - -Zlib_Inflater::~Zlib_Inflater() -{ - end(); -} - -blargg_err_t Zlib_Inflater::fill_buf( int count ) -{ - byte* out = buf.end() - count; - RETURN_ERR( callback( user_data, out, &count ) ); - zbuf.avail_in = count; - zbuf.next_in = out; - return blargg_ok; -} - -blargg_err_t Zlib_Inflater::begin( callback_t new_callback, void* new_user_data, - int new_buf_size, int initial_read ) -{ - callback = new_callback; - user_data = new_user_data; - - end(); - - // TODO: decide whether using different size on alloc failure is a good idea - //RETURN_ERR( buf.resize( new_buf_size ? new_buf_size : 4 * block_size ) ); - if ( new_buf_size && buf.resize( new_buf_size ) ) - { - ACK_FAILURE(); - new_buf_size = 0; - } - - if ( !new_buf_size ) - { - RETURN_ERR( buf.resize( 4 * block_size ) ); - initial_read = 0; - } - - // Fill buffer with some data, less than normal buffer size since caller might - // just be examining beginning of file. - return fill_buf( initial_read ? initial_read : block_size ); -} - -blargg_err_t Zlib_Inflater::set_mode( mode_t mode, int data_offset ) -{ - zbuf.next_in += data_offset; - zbuf.avail_in -= data_offset; - - if ( mode == mode_auto ) - { - // examine buffer for gzip header - mode = mode_copy; - unsigned const min_gzip_size = 2 + 8 + 8; - if ( zbuf.avail_in >= min_gzip_size && - zbuf.next_in [0] == 0x1F && zbuf.next_in [1] == 0x8B ) - mode = mode_ungz; - } - - if ( mode != mode_copy ) - { - int wb = MAX_WBITS + 16; // have zlib handle gzip header - if ( mode == mode_raw_deflate ) - wb = -MAX_WBITS; - - int zerr = inflateInit2( &zbuf, wb ); - if ( zerr ) - { - zbuf.next_in = NULL; - return get_zlib_err( zerr ); - } - - deflated_ = true; - } - return blargg_ok; -} - -/* -// Reads/inflates entire stream. All input must be in buffer, and count must be total -// of all output. -blargg_err_t read_all( void* out, int count ); - - -// zlib automatically applies this optimization (uses inflateFast) -// TODO: remove -blargg_err_t Zlib_Inflater::read_all( void* out, int count ) -{ - if ( deflated_ ) - { - zbuf.next_out = (Bytef*) out; - zbuf.avail_out = count; - - int err = inflate( &zbuf, Z_FINISH ); - - if ( zbuf.avail_out || err != Z_STREAM_END ) - return blargg_err_file_corrupt; - } - else - { - if ( zbuf.avail_in < count ) - return blargg_err_file_corrupt; - - memcpy( out, zbuf.next_in, count ); - - zbuf.next_in += count; - zbuf.avail_in -= count; - } - - return blargg_ok; -} -*/ - -blargg_err_t Zlib_Inflater::read( void* out, int* count_io ) -{ - int remain = *count_io; - if ( remain && zbuf.next_in ) - { - if ( deflated_ ) - { - zbuf.next_out = (Bytef*) out; - zbuf.avail_out = remain; - - while ( 1 ) - { - uInt old_avail_in = zbuf.avail_in; - int err = inflate( &zbuf, Z_NO_FLUSH ); - if ( err == Z_STREAM_END ) - { - remain = zbuf.avail_out; - end(); - break; // no more data to inflate - } - - if ( err && (err != Z_BUF_ERROR || old_avail_in) ) - return get_zlib_err( err ); - - if ( !zbuf.avail_out ) - { - remain = 0; - break; // requested number of bytes inflated - } - - if ( zbuf.avail_in ) - { - // inflate() should never leave input if there's still space for output - check( false ); - return blargg_err_file_corrupt; - } - - RETURN_ERR( fill_buf( buf.size() ) ); - if ( !zbuf.avail_in ) - return blargg_err_file_corrupt; // stream didn't end but there's no more data - } - } - else - { - while ( 1 ) - { - // copy buffered data - if ( zbuf.avail_in ) - { - long count = zbuf.avail_in; - if ( count > remain ) - count = remain; - memcpy( out, zbuf.next_in, count ); - zbuf.total_out += count; - out = (char*) out + count; - remain -= count; - zbuf.next_in += count; - zbuf.avail_in -= count; - } - - if ( !zbuf.avail_in && zbuf.next_in < buf.end() ) - { - end(); - break; - } - - // read large request directly - if ( remain + zbuf.total_out % block_size >= buf.size() ) - { - int count = remain; - RETURN_ERR( callback( user_data, out, &count ) ); - zbuf.total_out += count; - out = (char*) out + count; - remain -= count; - - if ( remain ) - { - end(); - break; - } - } - - if ( !remain ) - break; - - RETURN_ERR( fill_buf( buf.size() - zbuf.total_out % block_size ) ); - } - } - } - *count_io -= remain; - return blargg_ok; -} +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "Zlib_Inflater.h" + +/* Copyright (C) 2006-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +int const block_size = 4096; + +static const char* get_zlib_err( int code ) +{ + assert( code != Z_OK ); + switch ( code ) + { + case Z_MEM_ERROR: return blargg_err_memory; + case Z_DATA_ERROR: return blargg_err_file_corrupt; + // TODO: handle more error codes + } + + const char* str = zError( code ); + if ( !str ) + str = BLARGG_ERR( BLARGG_ERR_GENERIC, "problem unzipping data" ); + + return str; +} + +void Zlib_Inflater::end() +{ + if ( deflated_ ) + { + deflated_ = false; + if ( inflateEnd( &zbuf ) ) + check( false ); + } + buf.clear(); + + static z_stream const empty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + memcpy( &zbuf, &empty, sizeof zbuf ); +} + +Zlib_Inflater::Zlib_Inflater() +{ + deflated_ = false; + end(); // initialize things +} + +Zlib_Inflater::~Zlib_Inflater() +{ + end(); +} + +blargg_err_t Zlib_Inflater::fill_buf( int count ) +{ + byte* out = buf.end() - count; + RETURN_ERR( callback( user_data, out, &count ) ); + zbuf.avail_in = count; + zbuf.next_in = out; + return blargg_ok; +} + +blargg_err_t Zlib_Inflater::begin( callback_t new_callback, void* new_user_data, + int new_buf_size, int initial_read ) +{ + callback = new_callback; + user_data = new_user_data; + + end(); + + // TODO: decide whether using different size on alloc failure is a good idea + //RETURN_ERR( buf.resize( new_buf_size ? new_buf_size : 4 * block_size ) ); + if ( new_buf_size && buf.resize( new_buf_size ) ) + { + ACK_FAILURE(); + new_buf_size = 0; + } + + if ( !new_buf_size ) + { + RETURN_ERR( buf.resize( 4 * block_size ) ); + initial_read = 0; + } + + // Fill buffer with some data, less than normal buffer size since caller might + // just be examining beginning of file. + return fill_buf( initial_read ? initial_read : block_size ); +} + +blargg_err_t Zlib_Inflater::set_mode( mode_t mode, int data_offset ) +{ + zbuf.next_in += data_offset; + zbuf.avail_in -= data_offset; + + if ( mode == mode_auto ) + { + // examine buffer for gzip header + mode = mode_copy; + unsigned const min_gzip_size = 2 + 8 + 8; + if ( zbuf.avail_in >= min_gzip_size && + zbuf.next_in [0] == 0x1F && zbuf.next_in [1] == 0x8B ) + mode = mode_ungz; + } + + if ( mode != mode_copy ) + { + int wb = MAX_WBITS + 16; // have zlib handle gzip header + if ( mode == mode_raw_deflate ) + wb = -MAX_WBITS; + + int zerr = inflateInit2( &zbuf, wb ); + if ( zerr ) + { + zbuf.next_in = NULL; + return get_zlib_err( zerr ); + } + + deflated_ = true; + } + return blargg_ok; +} + +/* +// Reads/inflates entire stream. All input must be in buffer, and count must be total +// of all output. +blargg_err_t read_all( void* out, int count ); + + +// zlib automatically applies this optimization (uses inflateFast) +// TODO: remove +blargg_err_t Zlib_Inflater::read_all( void* out, int count ) +{ + if ( deflated_ ) + { + zbuf.next_out = (Bytef*) out; + zbuf.avail_out = count; + + int err = inflate( &zbuf, Z_FINISH ); + + if ( zbuf.avail_out || err != Z_STREAM_END ) + return blargg_err_file_corrupt; + } + else + { + if ( zbuf.avail_in < count ) + return blargg_err_file_corrupt; + + memcpy( out, zbuf.next_in, count ); + + zbuf.next_in += count; + zbuf.avail_in -= count; + } + + return blargg_ok; +} +*/ + +blargg_err_t Zlib_Inflater::read( void* out, int* count_io ) +{ + int remain = *count_io; + if ( remain && zbuf.next_in ) + { + if ( deflated_ ) + { + zbuf.next_out = (Bytef*) out; + zbuf.avail_out = remain; + + while ( 1 ) + { + uInt old_avail_in = zbuf.avail_in; + int err = inflate( &zbuf, Z_NO_FLUSH ); + if ( err == Z_STREAM_END ) + { + remain = zbuf.avail_out; + end(); + break; // no more data to inflate + } + + if ( err && (err != Z_BUF_ERROR || old_avail_in) ) + return get_zlib_err( err ); + + if ( !zbuf.avail_out ) + { + remain = 0; + break; // requested number of bytes inflated + } + + if ( zbuf.avail_in ) + { + // inflate() should never leave input if there's still space for output + check( false ); + return blargg_err_file_corrupt; + } + + RETURN_ERR( fill_buf( buf.size() ) ); + if ( !zbuf.avail_in ) + return blargg_err_file_corrupt; // stream didn't end but there's no more data + } + } + else + { + while ( 1 ) + { + // copy buffered data + if ( zbuf.avail_in ) + { + long count = zbuf.avail_in; + if ( count > remain ) + count = remain; + memcpy( out, zbuf.next_in, count ); + zbuf.total_out += count; + out = (char*) out + count; + remain -= count; + zbuf.next_in += count; + zbuf.avail_in -= count; + } + + if ( !zbuf.avail_in && zbuf.next_in < buf.end() ) + { + end(); + break; + } + + // read large request directly + if ( remain + zbuf.total_out % block_size >= buf.size() ) + { + int count = remain; + RETURN_ERR( callback( user_data, out, &count ) ); + zbuf.total_out += count; + out = (char*) out + count; + remain -= count; + + if ( remain ) + { + end(); + break; + } + } + + if ( !remain ) + break; + + RETURN_ERR( fill_buf( buf.size() - zbuf.total_out % block_size ) ); + } + } + } + *count_io -= remain; + return blargg_ok; +} diff --git a/fex/fex/Zlib_Inflater.h b/fex/fex/Zlib_Inflater.h index 8f0434fd..a585b080 100644 --- a/fex/fex/Zlib_Inflater.h +++ b/fex/fex/Zlib_Inflater.h @@ -1,70 +1,70 @@ -// Simplifies use of zlib for inflating data - -// File_Extractor 1.0.0 -#ifndef ZLIB_INFLATER_H -#define ZLIB_INFLATER_H - -#include "blargg_common.h" -#include "Data_Reader.h" -#include "zlib.h" - -class Zlib_Inflater { -public: - - // Reads at most min(*count,bytes_until_eof()) bytes into *out and set *count - // to that number, or returns error if that many can't be read. - typedef blargg_err_t (*callback_t)( void* user_data, void* out, int* count ); - - // Begins by setting callback and filling buffer. Default buffer is 16K and - // filled to 4K, or specify buf_size and initial_read for custom buffer size - // and how much to read initially. - blargg_err_t begin( callback_t, void* user_data, - int buf_size = 0, int initial_read = 0 ); - - // Data read into buffer by begin() - const unsigned char* data() const { return zbuf.next_in; } - int filled() const { return zbuf.avail_in; } - - // Begins inflation using specified mode. Using mode_auto selects between - // mode_copy and mode_ungz by examining first two bytes of buffer. Use - // buf_offset to specify where data begins in buffer, in case there is - // header data that should be skipped. - enum mode_t { mode_copy, mode_ungz, mode_raw_deflate, mode_auto }; - blargg_err_t set_mode( mode_t, int buf_offset = 0 ); - - // True if set_mode() has been called with mode_ungz or mode_raw_deflate - bool deflated() const { return deflated_; } - - // Reads/inflates at most *count_io bytes into *out and sets *count_io to actual - // number of bytes read (less than requested if end of data was reached). - // Buffers source data internally, even in copy mode, so input file can be - // unbuffered without sacrificing performance. - blargg_err_t read( void* out, int* count_io ); - - // Total number of bytes read since begin() - int tell() const { return zbuf.total_out; } - - // Ends inflation and frees memory - void end(); - -private: - // noncopyable - Zlib_Inflater( const Zlib_Inflater& ); - Zlib_Inflater& operator = ( const Zlib_Inflater& ); - -// Implementation -public: - Zlib_Inflater(); - ~Zlib_Inflater(); - -private: - z_stream_s zbuf; - blargg_vector buf; - bool deflated_; - callback_t callback; - void* user_data; - - blargg_err_t fill_buf( int count ); -}; - -#endif +// Simplifies use of zlib for inflating data + +// File_Extractor 1.0.0 +#ifndef ZLIB_INFLATER_H +#define ZLIB_INFLATER_H + +#include "blargg_common.h" +#include "Data_Reader.h" +#include "zlib.h" + +class Zlib_Inflater { +public: + + // Reads at most min(*count,bytes_until_eof()) bytes into *out and set *count + // to that number, or returns error if that many can't be read. + typedef blargg_err_t (*callback_t)( void* user_data, void* out, int* count ); + + // Begins by setting callback and filling buffer. Default buffer is 16K and + // filled to 4K, or specify buf_size and initial_read for custom buffer size + // and how much to read initially. + blargg_err_t begin( callback_t, void* user_data, + int buf_size = 0, int initial_read = 0 ); + + // Data read into buffer by begin() + const unsigned char* data() const { return zbuf.next_in; } + int filled() const { return zbuf.avail_in; } + + // Begins inflation using specified mode. Using mode_auto selects between + // mode_copy and mode_ungz by examining first two bytes of buffer. Use + // buf_offset to specify where data begins in buffer, in case there is + // header data that should be skipped. + enum mode_t { mode_copy, mode_ungz, mode_raw_deflate, mode_auto }; + blargg_err_t set_mode( mode_t, int buf_offset = 0 ); + + // True if set_mode() has been called with mode_ungz or mode_raw_deflate + bool deflated() const { return deflated_; } + + // Reads/inflates at most *count_io bytes into *out and sets *count_io to actual + // number of bytes read (less than requested if end of data was reached). + // Buffers source data internally, even in copy mode, so input file can be + // unbuffered without sacrificing performance. + blargg_err_t read( void* out, int* count_io ); + + // Total number of bytes read since begin() + int tell() const { return zbuf.total_out; } + + // Ends inflation and frees memory + void end(); + +private: + // noncopyable + Zlib_Inflater( const Zlib_Inflater& ); + Zlib_Inflater& operator = ( const Zlib_Inflater& ); + +// Implementation +public: + Zlib_Inflater(); + ~Zlib_Inflater(); + +private: + z_stream_s zbuf; + blargg_vector buf; + bool deflated_; + callback_t callback; + void* user_data; + + blargg_err_t fill_buf( int count ); +}; + +#endif diff --git a/fex/fex/blargg_common.cpp b/fex/fex/blargg_common.cpp index ab86e645..9f3e9ebd 100644 --- a/fex/fex/blargg_common.cpp +++ b/fex/fex/blargg_common.cpp @@ -1,51 +1,51 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "blargg_common.h" - -/* Copyright (C) 2008-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -void blargg_vector_::init() -{ - begin_ = NULL; - size_ = 0; -} - -void blargg_vector_::clear() -{ - void* p = begin_; - begin_ = NULL; - size_ = 0; - free( p ); -} - -blargg_err_t blargg_vector_::resize_( size_t n, size_t elem_size ) -{ - if ( n != size_ ) - { - if ( n == 0 ) - { - // Simpler to handle explicitly. Realloc will handle a size of 0, - // but then we have to avoid raising an error for a NULL return. - clear(); - } - else - { - void* p = realloc( begin_, n * elem_size ); - CHECK_ALLOC( p ); - begin_ = p; - size_ = n; - } - } - return blargg_ok; -} +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "blargg_common.h" + +/* Copyright (C) 2008-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +void blargg_vector_::init() +{ + begin_ = NULL; + size_ = 0; +} + +void blargg_vector_::clear() +{ + void* p = begin_; + begin_ = NULL; + size_ = 0; + free( p ); +} + +blargg_err_t blargg_vector_::resize_( size_t n, size_t elem_size ) +{ + if ( n != size_ ) + { + if ( n == 0 ) + { + // Simpler to handle explicitly. Realloc will handle a size of 0, + // but then we have to avoid raising an error for a NULL return. + clear(); + } + else + { + void* p = realloc( begin_, n * elem_size ); + CHECK_ALLOC( p ); + begin_ = p; + size_ = n; + } + } + return blargg_ok; +} diff --git a/fex/fex/blargg_common.h b/fex/fex/blargg_common.h index ca7a96ea..8c22fef9 100644 --- a/fex/fex/blargg_common.h +++ b/fex/fex/blargg_common.h @@ -1,201 +1,201 @@ -// Sets up common environment for Shay Green's libraries. -// To change configuration options, modify blargg_config.h, not this file. - -// File_Extractor 1.0.0 -#ifndef BLARGG_COMMON_H -#define BLARGG_COMMON_H - -#include -#include -#include - -typedef const char* blargg_err_t; // 0 on success, otherwise error string - -// Success; no error -int const blargg_ok = 0; - -// BLARGG_RESTRICT: equivalent to C99's restrict, where supported -#if __GNUC__ >= 3 || _MSC_VER >= 1100 - #define BLARGG_RESTRICT __restrict -#else - #define BLARGG_RESTRICT -#endif - -#if __cplusplus >= 199711 - #define BLARGG_MUTABLE mutable -#else - #define BLARGG_MUTABLE -#endif - -/* BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant). -I don't just use 'abcd' because that's implementation-dependent. */ -#define BLARGG_4CHAR( a, b, c, d ) \ - ((a&0xFF)*0x1000000 + (b&0xFF)*0x10000 + (c&0xFF)*0x100 + (d&0xFF)) - -/* BLARGG_STATIC_ASSERT( expr ): Generates compile error if expr is 0. -Can be used at file, function, or class scope. */ -#ifdef _MSC_VER - // MSVC6 (_MSC_VER < 1300) __LINE__ fails when /Zl is specified - #define BLARGG_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) -#else - // Others fail when declaring same function multiple times in class, - // so differentiate them by line - #define BLARGG_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) -#endif - -/* Pure virtual functions cause a vtable entry to a "called pure virtual" -error handler, requiring linkage to the C++ runtime library. This macro is -used in place of the "= 0", and simply expands to its argument. During -development, it expands to "= 0", allowing detection of missing overrides. */ -#define BLARGG_PURE( def ) def - -/* My code depends on ASCII anywhere a character or string constant is -compared with data read from a file, and anywhere file data is read and -treated as a string. */ -#if '\n'!=0x0A || ' '!=0x20 || '0'!=0x30 || 'A'!=0x41 || 'a'!=0x61 - #error "ASCII character set required" -#endif - -/* My code depends on int being at least 32 bits. Almost everything these days -uses at least 32-bit ints, so it's hard to even find a system with 16-bit ints -to test with. The issue can't be gotten around by using a suitable blargg_int -everywhere either, because int is often converted to implicitly when doing -arithmetic on smaller types. */ -#if UINT_MAX < 0xFFFFFFFF - #error "int must be at least 32 bits" -#endif - -// In case compiler doesn't support these properly. Used rarely. -#define STATIC_CAST(T,expr) static_cast (expr) -#define CONST_CAST( T,expr) const_cast (expr) - -// User configuration can override the above macros if necessary -#include "blargg_config.h" - -/* BLARGG_DEPRECATED [_TEXT] for any declarations/text to be removed in a -future version. In GCC, we can let the compiler warn. In other compilers, -we strip it out unless BLARGG_LEGACY is true. */ -#if BLARGG_LEGACY - // Allow old client code to work without warnings - #define BLARGG_DEPRECATED_TEXT( text ) text - #define BLARGG_DEPRECATED( text ) text -#elif __GNUC__ >= 4 - // In GCC, we can mark declarations and let the compiler warn - #define BLARGG_DEPRECATED_TEXT( text ) text - #define BLARGG_DEPRECATED( text ) __attribute__ ((deprecated)) text -#else - // By default, deprecated items are removed, to avoid use in new code - #define BLARGG_DEPRECATED_TEXT( text ) - #define BLARGG_DEPRECATED( text ) -#endif - -/* BOOST::int8_t, BOOST::int32_t, etc. -I used BOOST since I originally was going to allow use of the boost library -for prividing the definitions. If I'm defining them, they must be scoped or -else they could conflict with the standard ones at global scope. Even if -HAVE_STDINT_H isn't defined, I can't assume the typedefs won't exist at -global scope already. */ -#if defined (HAVE_STDINT_H) || \ - UCHAR_MAX != 0xFF || USHRT_MAX != 0xFFFF || UINT_MAX != 0xFFFFFFFF - #include - #define BOOST -#else - struct BOOST - { - typedef signed char int8_t; - typedef unsigned char uint8_t; - typedef short int16_t; - typedef unsigned short uint16_t; - typedef int int32_t; - typedef unsigned int uint32_t; - }; -#endif - -/* My code is not written with exceptions in mind, so either uses new (nothrow) -OR overrides operator new in my classes. The former is best since clients -creating objects will get standard exceptions on failure, but that causes it -to require the standard C++ library. So, when the client is using the C -interface, I override operator new to use malloc. */ - -// BLARGG_DISABLE_NOTHROW is put inside classes -#ifndef BLARGG_DISABLE_NOTHROW - // throw spec mandatory in ISO C++ if NULL can be returned - #if __cplusplus >= 199711 || __GNUC__ >= 3 || _MSC_VER >= 1300 - #define BLARGG_THROWS_NOTHING throw () - #else - #define BLARGG_THROWS_NOTHING - #endif - - #define BLARGG_DISABLE_NOTHROW \ - void* operator new ( size_t s ) BLARGG_THROWS_NOTHING { return malloc( s ); }\ - void operator delete( void* p ) BLARGG_THROWS_NOTHING { free( p ); } - - #define BLARGG_NEW new -#else - // BLARGG_NEW is used in place of new in library code - #include - #define BLARGG_NEW new (std::nothrow) -#endif - - class blargg_vector_ { - protected: - void* begin_; - size_t size_; - void init(); - blargg_err_t resize_( size_t n, size_t elem_size ); - public: - size_t size() const { return size_; } - void clear(); - }; - -// Very lightweight vector for POD types (no constructor/destructor) -template -class blargg_vector : public blargg_vector_ { - union T_must_be_pod { T t; }; // fails if T is not POD -public: - blargg_vector() { init(); } - ~blargg_vector() { clear(); } - - blargg_err_t resize( size_t n ) { return resize_( n, sizeof (T) ); } - - T* begin() { return static_cast (begin_); } - const T* begin() const { return static_cast (begin_); } - - T* end() { return static_cast (begin_) + size_; } - const T* end() const { return static_cast (begin_) + size_; } - - T& operator [] ( size_t n ) - { - assert( n < size_ ); - return static_cast (begin_) [n]; - } - - const T& operator [] ( size_t n ) const - { - assert( n < size_ ); - return static_cast (begin_) [n]; - } -}; - -// Callback function with user data. -// blargg_callback set_callback; // for user, this acts like... -// void set_callback( T func, void* user_data = NULL ); // ...this -// To call function, do set_callback.f( .. set_callback.data ... ); -template -struct blargg_callback -{ - T f; - void* data; - blargg_callback() { f = NULL; } - void operator () ( T callback, void* user_data = NULL ) { f = callback; data = user_data; } -}; - -BLARGG_DEPRECATED( typedef signed int blargg_long; ) -BLARGG_DEPRECATED( typedef unsigned int blargg_ulong; ) -#if BLARGG_LEGACY - #define BOOST_STATIC_ASSERT BLARGG_STATIC_ASSERT -#endif - -#endif +// Sets up common environment for Shay Green's libraries. +// To change configuration options, modify blargg_config.h, not this file. + +// File_Extractor 1.0.0 +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +#include +#include +#include + +typedef const char* blargg_err_t; // 0 on success, otherwise error string + +// Success; no error +int const blargg_ok = 0; + +// BLARGG_RESTRICT: equivalent to C99's restrict, where supported +#if __GNUC__ >= 3 || _MSC_VER >= 1100 + #define BLARGG_RESTRICT __restrict +#else + #define BLARGG_RESTRICT +#endif + +#if __cplusplus >= 199711 + #define BLARGG_MUTABLE mutable +#else + #define BLARGG_MUTABLE +#endif + +/* BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant). +I don't just use 'abcd' because that's implementation-dependent. */ +#define BLARGG_4CHAR( a, b, c, d ) \ + ((a&0xFF)*0x1000000 + (b&0xFF)*0x10000 + (c&0xFF)*0x100 + (d&0xFF)) + +/* BLARGG_STATIC_ASSERT( expr ): Generates compile error if expr is 0. +Can be used at file, function, or class scope. */ +#ifdef _MSC_VER + // MSVC6 (_MSC_VER < 1300) __LINE__ fails when /Zl is specified + #define BLARGG_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) +#else + // Others fail when declaring same function multiple times in class, + // so differentiate them by line + #define BLARGG_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) +#endif + +/* Pure virtual functions cause a vtable entry to a "called pure virtual" +error handler, requiring linkage to the C++ runtime library. This macro is +used in place of the "= 0", and simply expands to its argument. During +development, it expands to "= 0", allowing detection of missing overrides. */ +#define BLARGG_PURE( def ) def + +/* My code depends on ASCII anywhere a character or string constant is +compared with data read from a file, and anywhere file data is read and +treated as a string. */ +#if '\n'!=0x0A || ' '!=0x20 || '0'!=0x30 || 'A'!=0x41 || 'a'!=0x61 + #error "ASCII character set required" +#endif + +/* My code depends on int being at least 32 bits. Almost everything these days +uses at least 32-bit ints, so it's hard to even find a system with 16-bit ints +to test with. The issue can't be gotten around by using a suitable blargg_int +everywhere either, because int is often converted to implicitly when doing +arithmetic on smaller types. */ +#if UINT_MAX < 0xFFFFFFFF + #error "int must be at least 32 bits" +#endif + +// In case compiler doesn't support these properly. Used rarely. +#define STATIC_CAST(T,expr) static_cast (expr) +#define CONST_CAST( T,expr) const_cast (expr) + +// User configuration can override the above macros if necessary +#include "blargg_config.h" + +/* BLARGG_DEPRECATED [_TEXT] for any declarations/text to be removed in a +future version. In GCC, we can let the compiler warn. In other compilers, +we strip it out unless BLARGG_LEGACY is true. */ +#if BLARGG_LEGACY + // Allow old client code to work without warnings + #define BLARGG_DEPRECATED_TEXT( text ) text + #define BLARGG_DEPRECATED( text ) text +#elif __GNUC__ >= 4 + // In GCC, we can mark declarations and let the compiler warn + #define BLARGG_DEPRECATED_TEXT( text ) text + #define BLARGG_DEPRECATED( text ) __attribute__ ((deprecated)) text +#else + // By default, deprecated items are removed, to avoid use in new code + #define BLARGG_DEPRECATED_TEXT( text ) + #define BLARGG_DEPRECATED( text ) +#endif + +/* BOOST::int8_t, BOOST::int32_t, etc. +I used BOOST since I originally was going to allow use of the boost library +for prividing the definitions. If I'm defining them, they must be scoped or +else they could conflict with the standard ones at global scope. Even if +HAVE_STDINT_H isn't defined, I can't assume the typedefs won't exist at +global scope already. */ +#if defined (HAVE_STDINT_H) || \ + UCHAR_MAX != 0xFF || USHRT_MAX != 0xFFFF || UINT_MAX != 0xFFFFFFFF + #include + #define BOOST +#else + struct BOOST + { + typedef signed char int8_t; + typedef unsigned char uint8_t; + typedef short int16_t; + typedef unsigned short uint16_t; + typedef int int32_t; + typedef unsigned int uint32_t; + }; +#endif + +/* My code is not written with exceptions in mind, so either uses new (nothrow) +OR overrides operator new in my classes. The former is best since clients +creating objects will get standard exceptions on failure, but that causes it +to require the standard C++ library. So, when the client is using the C +interface, I override operator new to use malloc. */ + +// BLARGG_DISABLE_NOTHROW is put inside classes +#ifndef BLARGG_DISABLE_NOTHROW + // throw spec mandatory in ISO C++ if NULL can be returned + #if __cplusplus >= 199711 || __GNUC__ >= 3 || _MSC_VER >= 1300 + #define BLARGG_THROWS_NOTHING throw () + #else + #define BLARGG_THROWS_NOTHING + #endif + + #define BLARGG_DISABLE_NOTHROW \ + void* operator new ( size_t s ) BLARGG_THROWS_NOTHING { return malloc( s ); }\ + void operator delete( void* p ) BLARGG_THROWS_NOTHING { free( p ); } + + #define BLARGG_NEW new +#else + // BLARGG_NEW is used in place of new in library code + #include + #define BLARGG_NEW new (std::nothrow) +#endif + + class blargg_vector_ { + protected: + void* begin_; + size_t size_; + void init(); + blargg_err_t resize_( size_t n, size_t elem_size ); + public: + size_t size() const { return size_; } + void clear(); + }; + +// Very lightweight vector for POD types (no constructor/destructor) +template +class blargg_vector : public blargg_vector_ { + union T_must_be_pod { T t; }; // fails if T is not POD +public: + blargg_vector() { init(); } + ~blargg_vector() { clear(); } + + blargg_err_t resize( size_t n ) { return resize_( n, sizeof (T) ); } + + T* begin() { return static_cast (begin_); } + const T* begin() const { return static_cast (begin_); } + + T* end() { return static_cast (begin_) + size_; } + const T* end() const { return static_cast (begin_) + size_; } + + T& operator [] ( size_t n ) + { + assert( n < size_ ); + return static_cast (begin_) [n]; + } + + const T& operator [] ( size_t n ) const + { + assert( n < size_ ); + return static_cast (begin_) [n]; + } +}; + +// Callback function with user data. +// blargg_callback set_callback; // for user, this acts like... +// void set_callback( T func, void* user_data = NULL ); // ...this +// To call function, do set_callback.f( .. set_callback.data ... ); +template +struct blargg_callback +{ + T f; + void* data; + blargg_callback() { f = NULL; } + void operator () ( T callback, void* user_data = NULL ) { f = callback; data = user_data; } +}; + +BLARGG_DEPRECATED( typedef signed int blargg_long; ) +BLARGG_DEPRECATED( typedef unsigned int blargg_ulong; ) +#if BLARGG_LEGACY + #define BOOST_STATIC_ASSERT BLARGG_STATIC_ASSERT +#endif + +#endif diff --git a/fex/fex/blargg_config.h b/fex/fex/blargg_config.h index 5eb5d451..2282f1db 100644 --- a/fex/fex/blargg_config.h +++ b/fex/fex/blargg_config.h @@ -1,31 +1,31 @@ -// Library configuration. Modify this file as necessary. - -// File_Extractor 1.0.0 -#ifndef BLARGG_CONFIG_H -#define BLARGG_CONFIG_H - -// Uncomment a #define line below to have effect described. - -// Enable RAR archive support. Doing so adds extra licensing restrictions -// to this library (see unrar/readme.txt for more information). -//#define FEX_ENABLE_RAR 1 - -// Accept file paths encoded as UTF-8. Currently only affects Windows, -// as Unix/Linux/Mac OS X already use UTF-8 paths. -//#define BLARGG_UTF8_PATHS 1 - -// Enable support for as building DLL on Windows. -//#define BLARGG_BUILD_DLL 1 - -// Support only the listed archive types. Remove any you don't need. -#define FEX_TYPE_LIST \ - fex_7z_type,\ - fex_gz_type,\ - fex_zip_type, - -// Use standard config.h if present -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#endif +// Library configuration. Modify this file as necessary. + +// File_Extractor 1.0.0 +#ifndef BLARGG_CONFIG_H +#define BLARGG_CONFIG_H + +// Uncomment a #define line below to have effect described. + +// Enable RAR archive support. Doing so adds extra licensing restrictions +// to this library (see unrar/readme.txt for more information). +//#define FEX_ENABLE_RAR 1 + +// Accept file paths encoded as UTF-8. Currently only affects Windows, +// as Unix/Linux/Mac OS X already use UTF-8 paths. +//#define BLARGG_UTF8_PATHS 1 + +// Enable support for as building DLL on Windows. +//#define BLARGG_BUILD_DLL 1 + +// Support only the listed archive types. Remove any you don't need. +#define FEX_TYPE_LIST \ + fex_7z_type,\ + fex_gz_type,\ + fex_zip_type, + +// Use standard config.h if present +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#endif diff --git a/fex/fex/blargg_endian.h b/fex/fex/blargg_endian.h index d012871f..c32c12f5 100644 --- a/fex/fex/blargg_endian.h +++ b/fex/fex/blargg_endian.h @@ -1,185 +1,185 @@ -// CPU Byte Order Utilities - -// File_Extractor 1.0.0 -#ifndef BLARGG_ENDIAN_H -#define BLARGG_ENDIAN_H - -#include "blargg_common.h" - -// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) -#if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64) - #define BLARGG_CPU_X86 1 - #define BLARGG_CPU_CISC 1 -#endif - -#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) || \ - defined (__POWERPC__) || defined (__powerc) - #define BLARGG_CPU_POWERPC 1 - #define BLARGG_CPU_RISC 1 -#endif - -// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only -// one may be #defined to 1. Only needed if something actually depends on byte order. -#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) -#ifdef __GLIBC__ - // GCC handles this for us - #include - #if __BYTE_ORDER == __LITTLE_ENDIAN - #define BLARGG_LITTLE_ENDIAN 1 - #elif __BYTE_ORDER == __BIG_ENDIAN - #define BLARGG_BIG_ENDIAN 1 - #endif -#else - -#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ - (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) - #define BLARGG_LITTLE_ENDIAN 1 -#endif - -#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ - defined (__sparc__) || BLARGG_CPU_POWERPC || \ - (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) - #define BLARGG_BIG_ENDIAN 1 -#elif !defined (__mips__) - // No endian specified; assume little-endian, since it's most common - #define BLARGG_LITTLE_ENDIAN 1 -#endif -#endif -#endif - -#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN - #undef BLARGG_LITTLE_ENDIAN - #undef BLARGG_BIG_ENDIAN -#endif - -inline void blargg_verify_byte_order() -{ - #ifndef NDEBUG - #if BLARGG_BIG_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i == 0 ); - #elif BLARGG_LITTLE_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i != 0 ); - #endif - #endif -} - -inline unsigned get_le16( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [0]; -} - -inline unsigned get_be16( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [0] << 8 | - (unsigned) ((unsigned char const*) p) [1]; -} - -inline unsigned get_le32( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [3] << 24 | - (unsigned) ((unsigned char const*) p) [2] << 16 | - (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [0]; -} - -inline unsigned get_be32( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [0] << 24 | - (unsigned) ((unsigned char const*) p) [1] << 16 | - (unsigned) ((unsigned char const*) p) [2] << 8 | - (unsigned) ((unsigned char const*) p) [3]; -} - -inline void set_le16( void* p, unsigned n ) -{ - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [0] = (unsigned char) n; -} - -inline void set_be16( void* p, unsigned n ) -{ - ((unsigned char*) p) [0] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) n; -} - -inline void set_le32( void* p, unsigned n ) -{ - ((unsigned char*) p) [0] = (unsigned char) n; - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [2] = (unsigned char) (n >> 16); - ((unsigned char*) p) [3] = (unsigned char) (n >> 24); -} - -inline void set_be32( void* p, unsigned n ) -{ - ((unsigned char*) p) [3] = (unsigned char) n; - ((unsigned char*) p) [2] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) (n >> 16); - ((unsigned char*) p) [0] = (unsigned char) (n >> 24); -} - -#if BLARGG_NONPORTABLE - // Optimized implementation if byte order is known - #if BLARGG_LITTLE_ENDIAN - #define GET_LE16( addr ) (*(BOOST::uint16_t const*) (addr)) - #define GET_LE32( addr ) (*(BOOST::uint32_t const*) (addr)) - #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) - #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - #elif BLARGG_BIG_ENDIAN - #define GET_BE16( addr ) (*(BOOST::uint16_t const*) (addr)) - #define GET_BE32( addr ) (*(BOOST::uint32_t const*) (addr)) - #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) - #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - - #if BLARGG_CPU_POWERPC - // PowerPC has special byte-reversed instructions - #if defined (__MWERKS__) - #define GET_LE16( addr ) (__lhbrx( addr, 0 )) - #define GET_LE32( addr ) (__lwbrx( addr, 0 )) - #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) - #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) - #elif defined (__GNUC__) - #define GET_LE16( addr ) ({unsigned short ppc_lhbrx_; __asm__ volatile( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr) : "memory" ); ppc_lhbrx_;}) - #define GET_LE32( addr ) ({unsigned short ppc_lwbrx_; __asm__ volatile( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr) : "memory" ); ppc_lwbrx_;}) - #define SET_LE16( addr, in ) ({__asm__ volatile( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );}) - #define SET_LE32( addr, in ) ({__asm__ volatile( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );}) - #endif - #endif - #endif -#endif - -#ifndef GET_LE16 - #define GET_LE16( addr ) get_le16( addr ) - #define SET_LE16( addr, data ) set_le16( addr, data ) -#endif - -#ifndef GET_LE32 - #define GET_LE32( addr ) get_le32( addr ) - #define SET_LE32( addr, data ) set_le32( addr, data ) -#endif - -#ifndef GET_BE16 - #define GET_BE16( addr ) get_be16( addr ) - #define SET_BE16( addr, data ) set_be16( addr, data ) -#endif - -#ifndef GET_BE32 - #define GET_BE32( addr ) get_be32( addr ) - #define SET_BE32( addr, data ) set_be32( addr, data ) -#endif - -// auto-selecting versions - -inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } -inline void set_le( BOOST::uint32_t* p, unsigned n ) { SET_LE32( p, n ); } -inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } -inline void set_be( BOOST::uint32_t* p, unsigned n ) { SET_BE32( p, n ); } -inline unsigned get_le( BOOST::uint16_t const* p ) { return GET_LE16( p ); } -inline unsigned get_le( BOOST::uint32_t const* p ) { return GET_LE32( p ); } -inline unsigned get_be( BOOST::uint16_t const* p ) { return GET_BE16( p ); } -inline unsigned get_be( BOOST::uint32_t const* p ) { return GET_BE32( p ); } - -#endif +// CPU Byte Order Utilities + +// File_Extractor 1.0.0 +#ifndef BLARGG_ENDIAN_H +#define BLARGG_ENDIAN_H + +#include "blargg_common.h" + +// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) +#if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64) + #define BLARGG_CPU_X86 1 + #define BLARGG_CPU_CISC 1 +#endif + +#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) || \ + defined (__POWERPC__) || defined (__powerc) + #define BLARGG_CPU_POWERPC 1 + #define BLARGG_CPU_RISC 1 +#endif + +// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only +// one may be #defined to 1. Only needed if something actually depends on byte order. +#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) +#ifdef __GLIBC__ + // GCC handles this for us + #include + #if __BYTE_ORDER == __LITTLE_ENDIAN + #define BLARGG_LITTLE_ENDIAN 1 + #elif __BYTE_ORDER == __BIG_ENDIAN + #define BLARGG_BIG_ENDIAN 1 + #endif +#else + +#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ + (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) + #define BLARGG_LITTLE_ENDIAN 1 +#endif + +#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ + defined (__sparc__) || BLARGG_CPU_POWERPC || \ + (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) + #define BLARGG_BIG_ENDIAN 1 +#elif !defined (__mips__) + // No endian specified; assume little-endian, since it's most common + #define BLARGG_LITTLE_ENDIAN 1 +#endif +#endif +#endif + +#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN + #undef BLARGG_LITTLE_ENDIAN + #undef BLARGG_BIG_ENDIAN +#endif + +inline void blargg_verify_byte_order() +{ + #ifndef NDEBUG + #if BLARGG_BIG_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i == 0 ); + #elif BLARGG_LITTLE_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i != 0 ); + #endif + #endif +} + +inline unsigned get_le16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [1] << 8 | + (unsigned) ((unsigned char const*) p) [0]; +} + +inline unsigned get_be16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [0] << 8 | + (unsigned) ((unsigned char const*) p) [1]; +} + +inline unsigned get_le32( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [3] << 24 | + (unsigned) ((unsigned char const*) p) [2] << 16 | + (unsigned) ((unsigned char const*) p) [1] << 8 | + (unsigned) ((unsigned char const*) p) [0]; +} + +inline unsigned get_be32( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [0] << 24 | + (unsigned) ((unsigned char const*) p) [1] << 16 | + (unsigned) ((unsigned char const*) p) [2] << 8 | + (unsigned) ((unsigned char const*) p) [3]; +} + +inline void set_le16( void* p, unsigned n ) +{ + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [0] = (unsigned char) n; +} + +inline void set_be16( void* p, unsigned n ) +{ + ((unsigned char*) p) [0] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) n; +} + +inline void set_le32( void* p, unsigned n ) +{ + ((unsigned char*) p) [0] = (unsigned char) n; + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [2] = (unsigned char) (n >> 16); + ((unsigned char*) p) [3] = (unsigned char) (n >> 24); +} + +inline void set_be32( void* p, unsigned n ) +{ + ((unsigned char*) p) [3] = (unsigned char) n; + ((unsigned char*) p) [2] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) (n >> 16); + ((unsigned char*) p) [0] = (unsigned char) (n >> 24); +} + +#if BLARGG_NONPORTABLE + // Optimized implementation if byte order is known + #if BLARGG_LITTLE_ENDIAN + #define GET_LE16( addr ) (*(BOOST::uint16_t const*) (addr)) + #define GET_LE32( addr ) (*(BOOST::uint32_t const*) (addr)) + #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + #elif BLARGG_BIG_ENDIAN + #define GET_BE16( addr ) (*(BOOST::uint16_t const*) (addr)) + #define GET_BE32( addr ) (*(BOOST::uint32_t const*) (addr)) + #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + + #if BLARGG_CPU_POWERPC + // PowerPC has special byte-reversed instructions + #if defined (__MWERKS__) + #define GET_LE16( addr ) (__lhbrx( addr, 0 )) + #define GET_LE32( addr ) (__lwbrx( addr, 0 )) + #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) + #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) + #elif defined (__GNUC__) + #define GET_LE16( addr ) ({unsigned short ppc_lhbrx_; __asm__ volatile( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr) : "memory" ); ppc_lhbrx_;}) + #define GET_LE32( addr ) ({unsigned short ppc_lwbrx_; __asm__ volatile( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr) : "memory" ); ppc_lwbrx_;}) + #define SET_LE16( addr, in ) ({__asm__ volatile( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );}) + #define SET_LE32( addr, in ) ({__asm__ volatile( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );}) + #endif + #endif + #endif +#endif + +#ifndef GET_LE16 + #define GET_LE16( addr ) get_le16( addr ) + #define SET_LE16( addr, data ) set_le16( addr, data ) +#endif + +#ifndef GET_LE32 + #define GET_LE32( addr ) get_le32( addr ) + #define SET_LE32( addr, data ) set_le32( addr, data ) +#endif + +#ifndef GET_BE16 + #define GET_BE16( addr ) get_be16( addr ) + #define SET_BE16( addr, data ) set_be16( addr, data ) +#endif + +#ifndef GET_BE32 + #define GET_BE32( addr ) get_be32( addr ) + #define SET_BE32( addr, data ) set_be32( addr, data ) +#endif + +// auto-selecting versions + +inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } +inline void set_le( BOOST::uint32_t* p, unsigned n ) { SET_LE32( p, n ); } +inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } +inline void set_be( BOOST::uint32_t* p, unsigned n ) { SET_BE32( p, n ); } +inline unsigned get_le( BOOST::uint16_t const* p ) { return GET_LE16( p ); } +inline unsigned get_le( BOOST::uint32_t const* p ) { return GET_LE32( p ); } +inline unsigned get_be( BOOST::uint16_t const* p ) { return GET_BE16( p ); } +inline unsigned get_be( BOOST::uint32_t const* p ) { return GET_BE32( p ); } + +#endif diff --git a/fex/fex/blargg_errors.cpp b/fex/fex/blargg_errors.cpp index 025ea500..14076cdb 100644 --- a/fex/fex/blargg_errors.cpp +++ b/fex/fex/blargg_errors.cpp @@ -1,113 +1,113 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "blargg_errors.h" - -/* Copyright (C) 2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -blargg_err_def_t blargg_err_generic = BLARGG_ERR_GENERIC; -blargg_err_def_t blargg_err_memory = BLARGG_ERR_MEMORY; -blargg_err_def_t blargg_err_caller = BLARGG_ERR_CALLER; -blargg_err_def_t blargg_err_internal = BLARGG_ERR_INTERNAL; -blargg_err_def_t blargg_err_limitation = BLARGG_ERR_LIMITATION; - -blargg_err_def_t blargg_err_file_missing = BLARGG_ERR_FILE_MISSING; -blargg_err_def_t blargg_err_file_read = BLARGG_ERR_FILE_READ; -blargg_err_def_t blargg_err_file_write = BLARGG_ERR_FILE_WRITE; -blargg_err_def_t blargg_err_file_io = BLARGG_ERR_FILE_IO; -blargg_err_def_t blargg_err_file_full = BLARGG_ERR_FILE_FULL; -blargg_err_def_t blargg_err_file_eof = BLARGG_ERR_FILE_EOF; - -blargg_err_def_t blargg_err_file_type = BLARGG_ERR_FILE_TYPE; -blargg_err_def_t blargg_err_file_feature = BLARGG_ERR_FILE_FEATURE; -blargg_err_def_t blargg_err_file_corrupt = BLARGG_ERR_FILE_CORRUPT; - -const char* blargg_err_str( blargg_err_t err ) -{ - if ( !err ) - return ""; - - if ( *err == BLARGG_ERR_TYPE("")[0] ) - return err + 1; - - return err; -} - -bool blargg_is_err_type( blargg_err_t err, const char type [] ) -{ - if ( err ) - { - // True if first strlen(type) characters of err match type - char const* p = err; - while ( *type && *type == *p ) - { - type++; - p++; - } - - if ( !*type ) - return true; - } - - return false; -} - -const char* blargg_err_details( blargg_err_t err ) -{ - const char* p = err; - if ( !p ) - { - p = ""; - } - else if ( *p == BLARGG_ERR_TYPE("")[0] ) - { - while ( *p && *p != ';' ) - p++; - - // Skip ; and space after it - if ( *p ) - { - p++; - - check( *p == ' ' ); - if ( *p ) - p++; - } - } - return p; -} - -int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const codes [] ) -{ - if ( !err ) - return 0; - - while ( codes->str && !blargg_is_err_type( err, codes->str ) ) - codes++; - - return codes->code; -} - -blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const codes [] ) -{ - if ( !code ) - return blargg_ok; - - while ( codes->str && codes->code != code ) - codes++; - - if ( !codes->str ) - return blargg_err_generic; - - return codes->str; -} +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "blargg_errors.h" + +/* Copyright (C) 2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +blargg_err_def_t blargg_err_generic = BLARGG_ERR_GENERIC; +blargg_err_def_t blargg_err_memory = BLARGG_ERR_MEMORY; +blargg_err_def_t blargg_err_caller = BLARGG_ERR_CALLER; +blargg_err_def_t blargg_err_internal = BLARGG_ERR_INTERNAL; +blargg_err_def_t blargg_err_limitation = BLARGG_ERR_LIMITATION; + +blargg_err_def_t blargg_err_file_missing = BLARGG_ERR_FILE_MISSING; +blargg_err_def_t blargg_err_file_read = BLARGG_ERR_FILE_READ; +blargg_err_def_t blargg_err_file_write = BLARGG_ERR_FILE_WRITE; +blargg_err_def_t blargg_err_file_io = BLARGG_ERR_FILE_IO; +blargg_err_def_t blargg_err_file_full = BLARGG_ERR_FILE_FULL; +blargg_err_def_t blargg_err_file_eof = BLARGG_ERR_FILE_EOF; + +blargg_err_def_t blargg_err_file_type = BLARGG_ERR_FILE_TYPE; +blargg_err_def_t blargg_err_file_feature = BLARGG_ERR_FILE_FEATURE; +blargg_err_def_t blargg_err_file_corrupt = BLARGG_ERR_FILE_CORRUPT; + +const char* blargg_err_str( blargg_err_t err ) +{ + if ( !err ) + return ""; + + if ( *err == BLARGG_ERR_TYPE("")[0] ) + return err + 1; + + return err; +} + +bool blargg_is_err_type( blargg_err_t err, const char type [] ) +{ + if ( err ) + { + // True if first strlen(type) characters of err match type + char const* p = err; + while ( *type && *type == *p ) + { + type++; + p++; + } + + if ( !*type ) + return true; + } + + return false; +} + +const char* blargg_err_details( blargg_err_t err ) +{ + const char* p = err; + if ( !p ) + { + p = ""; + } + else if ( *p == BLARGG_ERR_TYPE("")[0] ) + { + while ( *p && *p != ';' ) + p++; + + // Skip ; and space after it + if ( *p ) + { + p++; + + check( *p == ' ' ); + if ( *p ) + p++; + } + } + return p; +} + +int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const codes [] ) +{ + if ( !err ) + return 0; + + while ( codes->str && !blargg_is_err_type( err, codes->str ) ) + codes++; + + return codes->code; +} + +blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const codes [] ) +{ + if ( !code ) + return blargg_ok; + + while ( codes->str && codes->code != code ) + codes++; + + if ( !codes->str ) + return blargg_err_generic; + + return codes->str; +} diff --git a/fex/fex/blargg_errors.h b/fex/fex/blargg_errors.h index 2b6dd3c0..9c5206d5 100644 --- a/fex/fex/blargg_errors.h +++ b/fex/fex/blargg_errors.h @@ -1,80 +1,80 @@ -// Error strings and conversion functions - -// File_Extractor 1.0.0 -#ifndef BLARGG_ERRORS_H -#define BLARGG_ERRORS_H - -#ifndef BLARGG_COMMON_H - #include "blargg_common.h" -#endif - -typedef const char blargg_err_def_t []; - -// Basic errors -extern blargg_err_def_t blargg_err_generic; -extern blargg_err_def_t blargg_err_memory; -extern blargg_err_def_t blargg_err_caller; -extern blargg_err_def_t blargg_err_internal; -extern blargg_err_def_t blargg_err_limitation; - -// File low-level -extern blargg_err_def_t blargg_err_file_missing; // not found -extern blargg_err_def_t blargg_err_file_read; -extern blargg_err_def_t blargg_err_file_write; -extern blargg_err_def_t blargg_err_file_io; -extern blargg_err_def_t blargg_err_file_full; -extern blargg_err_def_t blargg_err_file_eof; - -// File high-level -extern blargg_err_def_t blargg_err_file_type; // wrong file type -extern blargg_err_def_t blargg_err_file_feature; -extern blargg_err_def_t blargg_err_file_corrupt; - -// C string describing error, or "" if err == NULL -const char* blargg_err_str( blargg_err_t err ); - -// True iff error is of given type, or false if err == NULL -bool blargg_is_err_type( blargg_err_t, const char type [] ); - -// Details of error without describing main cause, or "" if err == NULL -const char* blargg_err_details( blargg_err_t err ); - -// Converts error string to integer code using mapping table. Calls blargg_is_err_type() -// for each str and returns code on first match. Returns 0 if err == NULL. -struct blargg_err_to_code_t { - const char* str; - int code; -}; -int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const [] ); - -// Converts error code back to string. If code == 0, returns NULL. If not in table, -// returns blargg_err_generic. -blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const [] ); - -// Generates error string literal with details of cause -#define BLARGG_ERR( type, str ) (type "; " str) - -// Extra space to make it clear when blargg_err_str() isn't called to get -// printable version of error. At some point, I might prefix error strings -// with a code, to speed conversion to a code. -#define BLARGG_ERR_TYPE( str ) " " str - -// Error types to pass to BLARGG_ERR macro -#define BLARGG_ERR_GENERIC BLARGG_ERR_TYPE( "operation failed" ) -#define BLARGG_ERR_MEMORY BLARGG_ERR_TYPE( "out of memory" ) -#define BLARGG_ERR_CALLER BLARGG_ERR_TYPE( "internal usage bug" ) -#define BLARGG_ERR_INTERNAL BLARGG_ERR_TYPE( "internal bug" ) -#define BLARGG_ERR_LIMITATION BLARGG_ERR_TYPE( "exceeded limitation" ) - -#define BLARGG_ERR_FILE_MISSING BLARGG_ERR_TYPE( "file not found" ) -#define BLARGG_ERR_FILE_READ BLARGG_ERR_TYPE( "couldn't open file" ) -#define BLARGG_ERR_FILE_WRITE BLARGG_ERR_TYPE( "couldn't modify file" ) -#define BLARGG_ERR_FILE_IO BLARGG_ERR_TYPE( "read/write error" ) -#define BLARGG_ERR_FILE_FULL BLARGG_ERR_TYPE( "disk full" ) -#define BLARGG_ERR_FILE_EOF BLARGG_ERR_TYPE( "truncated file" ) - -#define BLARGG_ERR_FILE_TYPE BLARGG_ERR_TYPE( "wrong file type" ) -#define BLARGG_ERR_FILE_FEATURE BLARGG_ERR_TYPE( "unsupported file feature" ) -#define BLARGG_ERR_FILE_CORRUPT BLARGG_ERR_TYPE( "corrupt file" ) - -#endif +// Error strings and conversion functions + +// File_Extractor 1.0.0 +#ifndef BLARGG_ERRORS_H +#define BLARGG_ERRORS_H + +#ifndef BLARGG_COMMON_H + #include "blargg_common.h" +#endif + +typedef const char blargg_err_def_t []; + +// Basic errors +extern blargg_err_def_t blargg_err_generic; +extern blargg_err_def_t blargg_err_memory; +extern blargg_err_def_t blargg_err_caller; +extern blargg_err_def_t blargg_err_internal; +extern blargg_err_def_t blargg_err_limitation; + +// File low-level +extern blargg_err_def_t blargg_err_file_missing; // not found +extern blargg_err_def_t blargg_err_file_read; +extern blargg_err_def_t blargg_err_file_write; +extern blargg_err_def_t blargg_err_file_io; +extern blargg_err_def_t blargg_err_file_full; +extern blargg_err_def_t blargg_err_file_eof; + +// File high-level +extern blargg_err_def_t blargg_err_file_type; // wrong file type +extern blargg_err_def_t blargg_err_file_feature; +extern blargg_err_def_t blargg_err_file_corrupt; + +// C string describing error, or "" if err == NULL +const char* blargg_err_str( blargg_err_t err ); + +// True iff error is of given type, or false if err == NULL +bool blargg_is_err_type( blargg_err_t, const char type [] ); + +// Details of error without describing main cause, or "" if err == NULL +const char* blargg_err_details( blargg_err_t err ); + +// Converts error string to integer code using mapping table. Calls blargg_is_err_type() +// for each str and returns code on first match. Returns 0 if err == NULL. +struct blargg_err_to_code_t { + const char* str; + int code; +}; +int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const [] ); + +// Converts error code back to string. If code == 0, returns NULL. If not in table, +// returns blargg_err_generic. +blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const [] ); + +// Generates error string literal with details of cause +#define BLARGG_ERR( type, str ) (type "; " str) + +// Extra space to make it clear when blargg_err_str() isn't called to get +// printable version of error. At some point, I might prefix error strings +// with a code, to speed conversion to a code. +#define BLARGG_ERR_TYPE( str ) " " str + +// Error types to pass to BLARGG_ERR macro +#define BLARGG_ERR_GENERIC BLARGG_ERR_TYPE( "operation failed" ) +#define BLARGG_ERR_MEMORY BLARGG_ERR_TYPE( "out of memory" ) +#define BLARGG_ERR_CALLER BLARGG_ERR_TYPE( "internal usage bug" ) +#define BLARGG_ERR_INTERNAL BLARGG_ERR_TYPE( "internal bug" ) +#define BLARGG_ERR_LIMITATION BLARGG_ERR_TYPE( "exceeded limitation" ) + +#define BLARGG_ERR_FILE_MISSING BLARGG_ERR_TYPE( "file not found" ) +#define BLARGG_ERR_FILE_READ BLARGG_ERR_TYPE( "couldn't open file" ) +#define BLARGG_ERR_FILE_WRITE BLARGG_ERR_TYPE( "couldn't modify file" ) +#define BLARGG_ERR_FILE_IO BLARGG_ERR_TYPE( "read/write error" ) +#define BLARGG_ERR_FILE_FULL BLARGG_ERR_TYPE( "disk full" ) +#define BLARGG_ERR_FILE_EOF BLARGG_ERR_TYPE( "truncated file" ) + +#define BLARGG_ERR_FILE_TYPE BLARGG_ERR_TYPE( "wrong file type" ) +#define BLARGG_ERR_FILE_FEATURE BLARGG_ERR_TYPE( "unsupported file feature" ) +#define BLARGG_ERR_FILE_CORRUPT BLARGG_ERR_TYPE( "corrupt file" ) + +#endif diff --git a/fex/fex/blargg_source.h b/fex/fex/blargg_source.h index f96087e7..659f34c5 100644 --- a/fex/fex/blargg_source.h +++ b/fex/fex/blargg_source.h @@ -1,125 +1,125 @@ -/* Included at the beginning of library source files, AFTER all other #include -lines. Sets up helpful macros and services used in my source code. Since this -is only "active" in my source code, I don't have to worry about polluting the -global namespace with unprefixed names. */ - -// File_Extractor 1.0.0 -#ifndef BLARGG_SOURCE_H -#define BLARGG_SOURCE_H - -#ifndef BLARGG_COMMON_H // optimization only - #include "blargg_common.h" -#endif -#include "blargg_errors.h" - -#include /* memcpy(), memset(), memmove() */ -#include /* offsetof() */ - -/* The following four macros are for debugging only. Some or all might be -defined to do nothing, depending on the circumstances. Described is what -happens when a particular macro is defined to do something. When defined to -do nothing, the macros do NOT evaluate their argument(s). */ - -/* If expr is false, prints file and line number, then aborts program. Meant -for checking internal state and consistency. A failed assertion indicates a bug -in MY code. - -void assert( bool expr ); */ -#include - -/* If expr is false, prints file and line number, then aborts program. Meant -for checking caller-supplied parameters and operations that are outside the -control of the module. A failed requirement probably indicates a bug in YOUR -code. - -void require( bool expr ); */ -#undef require -#define require( expr ) assert( expr ) - -/* Like printf() except output goes to debugging console/file. - -void dprintf( const char format [], ... ); */ -static inline void blargg_dprintf_( const char [], ... ) { } -#undef dprintf -#define dprintf (1) ? (void) 0 : blargg_dprintf_ - -/* If expr is false, prints file and line number to debug console/log, then -continues execution normally. Meant for flagging potential problems or things -that should be looked into, but that aren't serious problems. - -void check( bool expr ); */ -#undef check -#define check( expr ) ((void) 0) - -/* If expr yields non-NULL error string, returns it from current function, -otherwise continues normally. */ -#undef RETURN_ERR -#define RETURN_ERR( expr ) \ - do {\ - blargg_err_t blargg_return_err_ = (expr);\ - if ( blargg_return_err_ )\ - return blargg_return_err_;\ - } while ( 0 ) - -/* If ptr is NULL, returns out-of-memory error, otherwise continues normally. */ -#undef CHECK_ALLOC -#define CHECK_ALLOC( ptr ) \ - do {\ - if ( !(ptr) )\ - return blargg_err_memory;\ - } while ( 0 ) - -/* The usual min/max functions for built-in types. - -template T min( T x, T y ) { return x < y ? x : y; } -template T max( T x, T y ) { return x > y ? x : y; } */ -#define BLARGG_DEF_MIN_MAX( type ) \ - static inline type blargg_min( type x, type y ) { if ( y < x ) x = y; return x; }\ - static inline type blargg_max( type x, type y ) { if ( x < y ) x = y; return x; } - -BLARGG_DEF_MIN_MAX( int ) -BLARGG_DEF_MIN_MAX( unsigned ) -BLARGG_DEF_MIN_MAX( long ) -BLARGG_DEF_MIN_MAX( unsigned long ) -BLARGG_DEF_MIN_MAX( float ) -BLARGG_DEF_MIN_MAX( double ) - -#undef min -#define min blargg_min - -#undef max -#define max blargg_max - -// typedef unsigned char byte; -typedef unsigned char blargg_byte; -#undef byte -#define byte blargg_byte - -#ifndef BLARGG_EXPORT - #if defined (_WIN32) && BLARGG_BUILD_DLL - #define BLARGG_EXPORT __declspec(dllexport) - #elif defined (__GNUC__) - // can always set visibility, even when not building DLL - #define BLARGG_EXPORT __attribute__ ((visibility ("default"))) - #else - #define BLARGG_EXPORT - #endif -#endif - -#if BLARGG_LEGACY - #define BLARGG_CHECK_ALLOC CHECK_ALLOC - #define BLARGG_RETURN_ERR RETURN_ERR -#endif - -// Called after failed operation when overall operation may still complete OK. -// Only used by unit testing framework. -#undef ACK_FAILURE -#define ACK_FAILURE() ((void)0) - -/* BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf etc. -and check */ -#ifdef BLARGG_SOURCE_BEGIN - #include BLARGG_SOURCE_BEGIN -#endif - -#endif +/* Included at the beginning of library source files, AFTER all other #include +lines. Sets up helpful macros and services used in my source code. Since this +is only "active" in my source code, I don't have to worry about polluting the +global namespace with unprefixed names. */ + +// File_Extractor 1.0.0 +#ifndef BLARGG_SOURCE_H +#define BLARGG_SOURCE_H + +#ifndef BLARGG_COMMON_H // optimization only + #include "blargg_common.h" +#endif +#include "blargg_errors.h" + +#include /* memcpy(), memset(), memmove() */ +#include /* offsetof() */ + +/* The following four macros are for debugging only. Some or all might be +defined to do nothing, depending on the circumstances. Described is what +happens when a particular macro is defined to do something. When defined to +do nothing, the macros do NOT evaluate their argument(s). */ + +/* If expr is false, prints file and line number, then aborts program. Meant +for checking internal state and consistency. A failed assertion indicates a bug +in MY code. + +void assert( bool expr ); */ +#include + +/* If expr is false, prints file and line number, then aborts program. Meant +for checking caller-supplied parameters and operations that are outside the +control of the module. A failed requirement probably indicates a bug in YOUR +code. + +void require( bool expr ); */ +#undef require +#define require( expr ) assert( expr ) + +/* Like printf() except output goes to debugging console/file. + +void dprintf( const char format [], ... ); */ +static inline void blargg_dprintf_( const char [], ... ) { } +#undef dprintf +#define dprintf (1) ? (void) 0 : blargg_dprintf_ + +/* If expr is false, prints file and line number to debug console/log, then +continues execution normally. Meant for flagging potential problems or things +that should be looked into, but that aren't serious problems. + +void check( bool expr ); */ +#undef check +#define check( expr ) ((void) 0) + +/* If expr yields non-NULL error string, returns it from current function, +otherwise continues normally. */ +#undef RETURN_ERR +#define RETURN_ERR( expr ) \ + do {\ + blargg_err_t blargg_return_err_ = (expr);\ + if ( blargg_return_err_ )\ + return blargg_return_err_;\ + } while ( 0 ) + +/* If ptr is NULL, returns out-of-memory error, otherwise continues normally. */ +#undef CHECK_ALLOC +#define CHECK_ALLOC( ptr ) \ + do {\ + if ( !(ptr) )\ + return blargg_err_memory;\ + } while ( 0 ) + +/* The usual min/max functions for built-in types. + +template T min( T x, T y ) { return x < y ? x : y; } +template T max( T x, T y ) { return x > y ? x : y; } */ +#define BLARGG_DEF_MIN_MAX( type ) \ + static inline type blargg_min( type x, type y ) { if ( y < x ) x = y; return x; }\ + static inline type blargg_max( type x, type y ) { if ( x < y ) x = y; return x; } + +BLARGG_DEF_MIN_MAX( int ) +BLARGG_DEF_MIN_MAX( unsigned ) +BLARGG_DEF_MIN_MAX( long ) +BLARGG_DEF_MIN_MAX( unsigned long ) +BLARGG_DEF_MIN_MAX( float ) +BLARGG_DEF_MIN_MAX( double ) + +#undef min +#define min blargg_min + +#undef max +#define max blargg_max + +// typedef unsigned char byte; +typedef unsigned char blargg_byte; +#undef byte +#define byte blargg_byte + +#ifndef BLARGG_EXPORT + #if defined (_WIN32) && BLARGG_BUILD_DLL + #define BLARGG_EXPORT __declspec(dllexport) + #elif defined (__GNUC__) + // can always set visibility, even when not building DLL + #define BLARGG_EXPORT __attribute__ ((visibility ("default"))) + #else + #define BLARGG_EXPORT + #endif +#endif + +#if BLARGG_LEGACY + #define BLARGG_CHECK_ALLOC CHECK_ALLOC + #define BLARGG_RETURN_ERR RETURN_ERR +#endif + +// Called after failed operation when overall operation may still complete OK. +// Only used by unit testing framework. +#undef ACK_FAILURE +#define ACK_FAILURE() ((void)0) + +/* BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf etc. +and check */ +#ifdef BLARGG_SOURCE_BEGIN + #include BLARGG_SOURCE_BEGIN +#endif + +#endif diff --git a/fex/fex/fex.cpp b/fex/fex/fex.cpp index 07a0ec07..ab3f153e 100644 --- a/fex/fex/fex.cpp +++ b/fex/fex/fex.cpp @@ -1,321 +1,321 @@ -// File_Extractor 1.0.0. http://www.slack.net/~ant/ - -#include "fex.h" - -#include "File_Extractor.h" -#include "blargg_endian.h" -#include -#include - -/* Copyright (C) 2005-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - - -//// Types - -BLARGG_EXPORT const fex_type_t* fex_type_list( void ) -{ - static fex_type_t const fex_type_list_ [] = - { - #ifdef FEX_TYPE_LIST - FEX_TYPE_LIST - #else - // Modify blargg_config.h to change type list, NOT this file - fex_7z_type, - fex_gz_type, - #if FEX_ENABLE_RAR - fex_rar_type, - #endif - fex_zip_type, - #endif - fex_bin_type, - NULL - }; - - return fex_type_list_; -} - -BLARGG_EXPORT fex_err_t fex_init( void ) -{ - static bool inited; - if ( !inited ) - { - for ( fex_type_t const* t = fex_type_list(); *t != NULL; ++t ) - { - if ( (*t)->init ) - RETURN_ERR( (*t)->init() ); - } - inited = true; - } - return blargg_ok; -} - -BLARGG_EXPORT const char* fex_identify_header( void const* header ) -{ - unsigned four = get_be32( header ); - switch ( four ) - { - case 0x52457E5E: - case 0x52617221: return ".rar"; - - case 0x377ABCAF: return ".7z"; - - case 0x504B0304: - case 0x504B0506: return ".zip"; - - case 0x53495421: return ".sit"; - case 0x41724301: return ".arc"; - case 0x4D534346: return ".cab"; - case 0x5A4F4F20: return ".zoo"; - } - - unsigned three = four >> 8; - switch ( three ) - { - case 0x425A68: return ".bz2"; - } - - unsigned two = four >> 16; - switch ( two ) - { - case 0x1F8B: return ".gz"; - case 0x60EA: return ".arj"; - } - - unsigned skip_first_two = four & 0xFFFF; - if ( skip_first_two == 0x2D6C ) - return ".lha"; - - return ""; -} - -static int fex_has_extension_( const char str [], const char suffix [], size_t str_len ) -{ - size_t suffix_len = strlen( suffix ); - if ( str_len >= suffix_len ) - { - str += str_len - suffix_len; - while ( *str && tolower( (unsigned char) *str ) == *suffix ) - { - str++; - suffix++; - } - } - return *suffix == 0; -} - -BLARGG_EXPORT int fex_has_extension( const char str [], const char suffix [] ) -{ - return fex_has_extension_( str, suffix, strlen( str ) ); -} - -static int is_archive_extension( const char str [] ) -{ - static const char exts [] [6] = { - ".7z", - ".arc", - ".arj", - ".bz2", - ".cab", - ".dmg", - ".gz", - ".lha", - ".lz", - ".lzh", - ".lzma", - ".lzo", - ".lzx", - ".pea", - ".rar", - ".sit", - ".sitx", - ".tgz", - ".tlz", - ".z", - ".zip", - ".zoo", - "" - }; - - size_t str_len = strlen( str ); - const char (*ext) [6] = exts; - for ( ; **ext; ext++ ) - { - if ( fex_has_extension_( str, *ext, str_len ) ) - return 1; - } - return 0; -} - -BLARGG_EXPORT fex_type_t fex_identify_extension( const char str [] ) -{ - size_t str_len = strlen( str ); - for ( fex_type_t const* types = fex_type_list(); *types; types++ ) - { - if ( fex_has_extension_( str, (*types)->extension, str_len ) ) - { - // Avoid treating known archive type as binary - if ( *(*types)->extension || !is_archive_extension( str ) ) - return *types; - } - } - return NULL; -} - -BLARGG_EXPORT fex_err_t fex_identify_file( fex_type_t* type_out, const char path [] ) -{ - *type_out = NULL; - - fex_type_t type = fex_identify_extension( path ); - - // Unsupported extension? - if ( !type ) - return blargg_ok; // reject - - // Unknown/no extension? - if ( !*(type->extension) ) - { - // Examine header - FEX_FILE_READER in; - RETURN_ERR( in.open( path ) ); - if ( in.remain() >= fex_identify_header_size ) - { - char h [fex_identify_header_size]; - RETURN_ERR( in.read( h, sizeof h ) ); - - type = fex_identify_extension( fex_identify_header( h ) ); - } - } - - *type_out = type; - return blargg_ok; -} - -BLARGG_EXPORT fex_err_t fex_open_type( fex_t** fe_out, const char path [], fex_type_t type ) -{ - *fe_out = NULL; - - if ( !type ) - return blargg_err_file_type; - - fex_t* fe = type->new_fex(); - CHECK_ALLOC( fe ); - - fex_err_t err = fe->open( path ); - if ( err ) - { - delete fe; - return err; - } - - *fe_out = fe; - return blargg_ok; -} - -BLARGG_EXPORT fex_err_t fex_open( fex_t** fe_out, const char path [] ) -{ - *fe_out = NULL; - - fex_type_t type; - RETURN_ERR( fex_identify_file( &type, path ) ); - - return fex_open_type( fe_out, path, type ); -} - - -//// Wide paths - -char* fex_wide_to_path( const wchar_t* wide ) -{ - return blargg_to_utf8( wide ); -} - -void fex_free_path( char* path ) -{ - free( path ); -} - - -//// Errors - -#define ENTRY( name ) { blargg_err_##name, fex_err_##name } -static blargg_err_to_code_t const fex_codes [] = -{ - ENTRY( generic ), - ENTRY( memory ), - ENTRY( caller ), - ENTRY( internal ), - ENTRY( limitation ), - - ENTRY( file_missing ), - ENTRY( file_read ), - ENTRY( file_io ), - ENTRY( file_eof ), - - ENTRY( file_type ), - ENTRY( file_feature ), - ENTRY( file_corrupt ), - - { 0, -1 } -}; -#undef ENTRY - -static int err_code( fex_err_t err ) -{ - return blargg_err_to_code( err, fex_codes ); -} - -BLARGG_EXPORT int fex_err_code( fex_err_t err ) -{ - int code = err_code( err ); - return (code >= 0 ? code : fex_err_generic); -} - -BLARGG_EXPORT fex_err_t fex_code_to_err( int code ) -{ - return blargg_code_to_err( code, fex_codes ); -} - -BLARGG_EXPORT const char* fex_err_details( fex_err_t err ) -{ - // If we don't have error code assigned, return entire string - return (err_code( err ) >= 0 ? blargg_err_details( err ) : blargg_err_str( err )); -} - - -//// Wrappers - -BLARGG_EXPORT fex_err_t fex_read( fex_t* fe, void* out, int count ) -{ - RETURN_ERR( fe->stat() ); - return fe->reader().read( out, count ); -} - -BLARGG_EXPORT void fex_close ( fex_t* fe ) { delete fe; } -BLARGG_EXPORT fex_type_t fex_type ( const fex_t* fe ) { return fe->type(); } -BLARGG_EXPORT int fex_done ( const fex_t* fe ) { return fe->done(); } -BLARGG_EXPORT const char* fex_name ( const fex_t* fe ) { return fe->name(); } -BLARGG_EXPORT const wchar_t* fex_wname ( const fex_t* fe ) { return fe->wname(); } -BLARGG_EXPORT int fex_size ( const fex_t* fe ) { return fe->size(); } -BLARGG_EXPORT unsigned fex_dos_date ( const fex_t* fe ) { return fe->dos_date(); } -BLARGG_EXPORT unsigned fex_crc32 ( const fex_t* fe ) { return fe->crc32(); } -BLARGG_EXPORT fex_err_t fex_stat ( fex_t* fe ) { return fe->stat(); } -BLARGG_EXPORT fex_err_t fex_next ( fex_t* fe ) { return fe->next(); } -BLARGG_EXPORT fex_err_t fex_rewind ( fex_t* fe ) { return fe->rewind(); } -BLARGG_EXPORT int fex_tell ( const fex_t* fe ) { return fe->tell(); } -BLARGG_EXPORT fex_pos_t fex_tell_arc ( const fex_t* fe ) { return fe->tell_arc(); } -BLARGG_EXPORT fex_err_t fex_seek_arc ( fex_t* fe, fex_pos_t pos ) { return fe->seek_arc( pos ); } -BLARGG_EXPORT const char* fex_type_extension ( fex_type_t t ) { return t->extension; } -BLARGG_EXPORT const char* fex_type_name ( fex_type_t t ) { return t->name; } -BLARGG_EXPORT fex_err_t fex_data ( fex_t* fe, const void** data_out ) { return fe->data( data_out ); } -BLARGG_EXPORT const char* fex_err_str ( fex_err_t err ) { return blargg_err_str( err ); } +// File_Extractor 1.0.0. http://www.slack.net/~ant/ + +#include "fex.h" + +#include "File_Extractor.h" +#include "blargg_endian.h" +#include +#include + +/* Copyright (C) 2005-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + + +//// Types + +BLARGG_EXPORT const fex_type_t* fex_type_list( void ) +{ + static fex_type_t const fex_type_list_ [] = + { + #ifdef FEX_TYPE_LIST + FEX_TYPE_LIST + #else + // Modify blargg_config.h to change type list, NOT this file + fex_7z_type, + fex_gz_type, + #if FEX_ENABLE_RAR + fex_rar_type, + #endif + fex_zip_type, + #endif + fex_bin_type, + NULL + }; + + return fex_type_list_; +} + +BLARGG_EXPORT fex_err_t fex_init( void ) +{ + static bool inited; + if ( !inited ) + { + for ( fex_type_t const* t = fex_type_list(); *t != NULL; ++t ) + { + if ( (*t)->init ) + RETURN_ERR( (*t)->init() ); + } + inited = true; + } + return blargg_ok; +} + +BLARGG_EXPORT const char* fex_identify_header( void const* header ) +{ + unsigned four = get_be32( header ); + switch ( four ) + { + case 0x52457E5E: + case 0x52617221: return ".rar"; + + case 0x377ABCAF: return ".7z"; + + case 0x504B0304: + case 0x504B0506: return ".zip"; + + case 0x53495421: return ".sit"; + case 0x41724301: return ".arc"; + case 0x4D534346: return ".cab"; + case 0x5A4F4F20: return ".zoo"; + } + + unsigned three = four >> 8; + switch ( three ) + { + case 0x425A68: return ".bz2"; + } + + unsigned two = four >> 16; + switch ( two ) + { + case 0x1F8B: return ".gz"; + case 0x60EA: return ".arj"; + } + + unsigned skip_first_two = four & 0xFFFF; + if ( skip_first_two == 0x2D6C ) + return ".lha"; + + return ""; +} + +static int fex_has_extension_( const char str [], const char suffix [], size_t str_len ) +{ + size_t suffix_len = strlen( suffix ); + if ( str_len >= suffix_len ) + { + str += str_len - suffix_len; + while ( *str && tolower( (unsigned char) *str ) == *suffix ) + { + str++; + suffix++; + } + } + return *suffix == 0; +} + +BLARGG_EXPORT int fex_has_extension( const char str [], const char suffix [] ) +{ + return fex_has_extension_( str, suffix, strlen( str ) ); +} + +static int is_archive_extension( const char str [] ) +{ + static const char exts [] [6] = { + ".7z", + ".arc", + ".arj", + ".bz2", + ".cab", + ".dmg", + ".gz", + ".lha", + ".lz", + ".lzh", + ".lzma", + ".lzo", + ".lzx", + ".pea", + ".rar", + ".sit", + ".sitx", + ".tgz", + ".tlz", + ".z", + ".zip", + ".zoo", + "" + }; + + size_t str_len = strlen( str ); + const char (*ext) [6] = exts; + for ( ; **ext; ext++ ) + { + if ( fex_has_extension_( str, *ext, str_len ) ) + return 1; + } + return 0; +} + +BLARGG_EXPORT fex_type_t fex_identify_extension( const char str [] ) +{ + size_t str_len = strlen( str ); + for ( fex_type_t const* types = fex_type_list(); *types; types++ ) + { + if ( fex_has_extension_( str, (*types)->extension, str_len ) ) + { + // Avoid treating known archive type as binary + if ( *(*types)->extension || !is_archive_extension( str ) ) + return *types; + } + } + return NULL; +} + +BLARGG_EXPORT fex_err_t fex_identify_file( fex_type_t* type_out, const char path [] ) +{ + *type_out = NULL; + + fex_type_t type = fex_identify_extension( path ); + + // Unsupported extension? + if ( !type ) + return blargg_ok; // reject + + // Unknown/no extension? + if ( !*(type->extension) ) + { + // Examine header + FEX_FILE_READER in; + RETURN_ERR( in.open( path ) ); + if ( in.remain() >= fex_identify_header_size ) + { + char h [fex_identify_header_size]; + RETURN_ERR( in.read( h, sizeof h ) ); + + type = fex_identify_extension( fex_identify_header( h ) ); + } + } + + *type_out = type; + return blargg_ok; +} + +BLARGG_EXPORT fex_err_t fex_open_type( fex_t** fe_out, const char path [], fex_type_t type ) +{ + *fe_out = NULL; + + if ( !type ) + return blargg_err_file_type; + + fex_t* fe = type->new_fex(); + CHECK_ALLOC( fe ); + + fex_err_t err = fe->open( path ); + if ( err ) + { + delete fe; + return err; + } + + *fe_out = fe; + return blargg_ok; +} + +BLARGG_EXPORT fex_err_t fex_open( fex_t** fe_out, const char path [] ) +{ + *fe_out = NULL; + + fex_type_t type; + RETURN_ERR( fex_identify_file( &type, path ) ); + + return fex_open_type( fe_out, path, type ); +} + + +//// Wide paths + +char* fex_wide_to_path( const wchar_t* wide ) +{ + return blargg_to_utf8( wide ); +} + +void fex_free_path( char* path ) +{ + free( path ); +} + + +//// Errors + +#define ENTRY( name ) { blargg_err_##name, fex_err_##name } +static blargg_err_to_code_t const fex_codes [] = +{ + ENTRY( generic ), + ENTRY( memory ), + ENTRY( caller ), + ENTRY( internal ), + ENTRY( limitation ), + + ENTRY( file_missing ), + ENTRY( file_read ), + ENTRY( file_io ), + ENTRY( file_eof ), + + ENTRY( file_type ), + ENTRY( file_feature ), + ENTRY( file_corrupt ), + + { 0, -1 } +}; +#undef ENTRY + +static int err_code( fex_err_t err ) +{ + return blargg_err_to_code( err, fex_codes ); +} + +BLARGG_EXPORT int fex_err_code( fex_err_t err ) +{ + int code = err_code( err ); + return (code >= 0 ? code : fex_err_generic); +} + +BLARGG_EXPORT fex_err_t fex_code_to_err( int code ) +{ + return blargg_code_to_err( code, fex_codes ); +} + +BLARGG_EXPORT const char* fex_err_details( fex_err_t err ) +{ + // If we don't have error code assigned, return entire string + return (err_code( err ) >= 0 ? blargg_err_details( err ) : blargg_err_str( err )); +} + + +//// Wrappers + +BLARGG_EXPORT fex_err_t fex_read( fex_t* fe, void* out, int count ) +{ + RETURN_ERR( fe->stat() ); + return fe->reader().read( out, count ); +} + +BLARGG_EXPORT void fex_close ( fex_t* fe ) { delete fe; } +BLARGG_EXPORT fex_type_t fex_type ( const fex_t* fe ) { return fe->type(); } +BLARGG_EXPORT int fex_done ( const fex_t* fe ) { return fe->done(); } +BLARGG_EXPORT const char* fex_name ( const fex_t* fe ) { return fe->name(); } +BLARGG_EXPORT const wchar_t* fex_wname ( const fex_t* fe ) { return fe->wname(); } +BLARGG_EXPORT int fex_size ( const fex_t* fe ) { return fe->size(); } +BLARGG_EXPORT unsigned fex_dos_date ( const fex_t* fe ) { return fe->dos_date(); } +BLARGG_EXPORT unsigned fex_crc32 ( const fex_t* fe ) { return fe->crc32(); } +BLARGG_EXPORT fex_err_t fex_stat ( fex_t* fe ) { return fe->stat(); } +BLARGG_EXPORT fex_err_t fex_next ( fex_t* fe ) { return fe->next(); } +BLARGG_EXPORT fex_err_t fex_rewind ( fex_t* fe ) { return fe->rewind(); } +BLARGG_EXPORT int fex_tell ( const fex_t* fe ) { return fe->tell(); } +BLARGG_EXPORT fex_pos_t fex_tell_arc ( const fex_t* fe ) { return fe->tell_arc(); } +BLARGG_EXPORT fex_err_t fex_seek_arc ( fex_t* fe, fex_pos_t pos ) { return fe->seek_arc( pos ); } +BLARGG_EXPORT const char* fex_type_extension ( fex_type_t t ) { return t->extension; } +BLARGG_EXPORT const char* fex_type_name ( fex_type_t t ) { return t->name; } +BLARGG_EXPORT fex_err_t fex_data ( fex_t* fe, const void** data_out ) { return fe->data( data_out ); } +BLARGG_EXPORT const char* fex_err_str ( fex_err_t err ) { return blargg_err_str( err ); } diff --git a/fex/fex/fex.h b/fex/fex/fex.h index 503a495a..8b6173ae 100644 --- a/fex/fex/fex.h +++ b/fex/fex/fex.h @@ -1,204 +1,204 @@ -/** Uniform access to zip, gzip, 7-zip, and RAR compressed archives \file */ - -/* File_Extractor 1.0.0 */ -#ifndef FEX_H -#define FEX_H - -#include - -#ifdef __cplusplus - extern "C" { -#endif - - -/** First parameter of most functions is fex_t*, or const fex_t* if nothing is -changed. Once one of these functions returns an error, the archive should not -be used any further, other than to close it. One exception is -fex_error_file_eof; the archive may still be used after this. */ -typedef struct fex_t fex_t; - -/** Pointer to error, or NULL if function was successful. See error functions -below. */ -#ifndef fex_err_t /* (#ifndef allows better testing of library) */ - typedef const char* fex_err_t; -#endif - - -/**** File types ****/ - -/** Archive file type identifier. Can also hold NULL. */ -typedef const struct fex_type_t_* fex_type_t; - -/** Array of supported types, with NULL at end */ -const fex_type_t* fex_type_list( void ); - -/** Name of this archive type, e.g. "ZIP archive", "file" */ -const char* fex_type_name( fex_type_t ); - -/** Usual file extension for type, e.g. ".zip", ".7z". For binary file type, -returns "", since it can open any file. */ -const char* fex_type_extension( fex_type_t ); - - -/**** Wide-character file paths ****/ - -/** Converts wide-character path to form suitable for use with fex functions. */ -char* fex_wide_to_path( const wchar_t* wide ); - -/** Frees converted path. OK to pass NULL. */ -void fex_free_path( char* ); - - -/**** Identification ****/ - -/** True if str ends in extension. If extension is "", always returns true. -Converts str to lowercase before comparison, so extension should ALREADY be -lowercase (i.e. pass ".zip", NOT ".ZIP"). */ -int fex_has_extension( const char str [], const char extension [] ); - -/** Determines type based on first fex_identify_header_size bytes of file. -Returns usual file extension this should have (e.g. ".zip", ".gz", etc.). -Returns "" if file header is not recognized. */ -const char* fex_identify_header( const void* header ); -enum { fex_identify_header_size = 16 }; - -/** Determines type based on extension of a file path, or just a lone extension -(must include '.', e.g. ".zip", NOT just "zip"). Returns NULL if extension is -for an unsupported type (e.g. ".lzh"). */ -fex_type_t fex_identify_extension( const char path_or_extension [] ); - -/** Determines type based on filename extension and/or file header. Sets *out -to determined type, or NULL if type is not supported. */ -fex_err_t fex_identify_file( fex_type_t* out, const char path [] ); - -/** Type of an already-opened archive */ -fex_type_t fex_type( const fex_t* ); - - -/**** Open/close ****/ - -/** Initializes static tables used by library. Automatically called by -fex_open(). OK to call more than once. */ -fex_err_t fex_init( void ); - -/** Opens archive and points *out at it. If error, sets *out to NULL. */ -fex_err_t fex_open( fex_t** out, const char path [] ); - -/** Opens archive of specified type and sets *out. Returns error if file is not -of that archive type. If error, sets *out to NULL. */ -fex_err_t fex_open_type( fex_t** out, const char path [], fex_type_t ); - -/** Closes archive and frees memory. OK to pass NULL. */ -void fex_close( fex_t* ); - - -/**** Scanning ****/ - -/** True if at end of archive. Must be called after fex_open() or fex_rewind(), -as an archive might contain no files. */ -int fex_done( const fex_t* ); - -/** Goes to next file in archive. If there are no more files, fex_done() will -now return true. */ -fex_err_t fex_next( fex_t* ); - -/** Goes back to first file in archive, as if it were just opened with -fex_open() */ -fex_err_t fex_rewind( fex_t* ); - -/** Saved position in archive. Can also store zero. */ -typedef int fex_pos_t; - -/** Position of current file in archive. Never returns zero. */ -fex_pos_t fex_tell_arc( const fex_t* ); - -/** Returns to file at previously-saved position */ -fex_err_t fex_seek_arc( fex_t*, fex_pos_t ); - - -/**** Info ****/ - -/** Name of current file */ -const char* fex_name( const fex_t* ); - -/** Wide-character name of current file, or NULL if unavailable */ -const wchar_t* fex_wname( const fex_t* ); - -/** Makes further information available for file */ -fex_err_t fex_stat( fex_t* ); - -/** Size of current file. fex_stat() or fex_data() must have been called. */ -int fex_size( const fex_t* ); - -/** Modification date of current file (MS-DOS format), or 0 if unavailable. -fex_stat() must have been called. */ -unsigned int fex_dos_date( const fex_t* ); - -/** CRC-32 checksum of current file's contents, or 0 if unavailable. Doesn't -require calculation; simply gets it from file's header. fex_stat() must have -been called. */ -unsigned int fex_crc32( const fex_t* ); - - -/**** Extraction ****/ - -/** Reads n bytes from current file. Reading past end of file results in -fex_err_file_eof. */ -fex_err_t fex_read( fex_t*, void* out, int n ); - -/** Number of bytes read from current file */ -int fex_tell( const fex_t* ); - -/** Points *out at current file's data in memory. Pointer is valid until -fex_next(), fex_rewind(), fex_seek_arc(), or fex_close() is called. Pointer -must NOT be freed(); library frees it automatically. If error, sets *out to -NULL. */ -fex_err_t fex_data( fex_t*, const void** out ); - - -/**** Errors ****/ - -/** Error string associated with err. Returns "" if err is NULL. Returns err -unchanged if it isn't a fex_err_t returned by library. */ -const char* fex_err_str( fex_err_t err ); - -/** Details of error beyond main cause, or "" if none or err is NULL. Returns -err unchanged if it isn't a fex_err_t returned by library. */ -const char* fex_err_details( fex_err_t err ); - -/** Numeric code corresponding to err. Returns fex_ok if err is NULL. Returns -fex_err_generic if err isn't a fex_err_t returned by library. */ -int fex_err_code( fex_err_t err ); - -enum { - fex_ok = 0,/**< Successful call. Guaranteed to be zero. */ - fex_err_generic = 0x01,/**< Error of unspecified type */ - fex_err_memory = 0x02,/**< Out of memory */ - fex_err_caller = 0x03,/**< Caller called function with bad args */ - fex_err_internal = 0x04,/**< Internal problem, bug, etc. */ - fex_err_limitation = 0x05,/**< Exceeded program limit */ - - fex_err_file_missing = 0x20,/**< File not found at specified path */ - fex_err_file_read = 0x21,/**< Couldn't open file for reading */ - fex_err_file_io = 0x23,/**< Read/write error */ - fex_err_file_eof = 0x25,/**< Tried to read past end of file */ - - fex_err_file_type = 0x30,/**< File is of wrong type */ - fex_err_file_feature = 0x32,/**< File requires unsupported feature */ - fex_err_file_corrupt = 0x33 /**< File is corrupt */ -}; - -/** fex_err_t corresponding to numeric code. Note that this might not recover -the original fex_err_t before it was converted to a numeric code; in -particular, fex_err_details(fex_code_to_err(code)) will be "" in most cases. */ -fex_err_t fex_code_to_err( int code ); - - -/* Deprecated */ -typedef fex_t File_Extractor; - -#ifdef __cplusplus - } -#endif - -#endif +/** Uniform access to zip, gzip, 7-zip, and RAR compressed archives \file */ + +/* File_Extractor 1.0.0 */ +#ifndef FEX_H +#define FEX_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + +/** First parameter of most functions is fex_t*, or const fex_t* if nothing is +changed. Once one of these functions returns an error, the archive should not +be used any further, other than to close it. One exception is +fex_error_file_eof; the archive may still be used after this. */ +typedef struct fex_t fex_t; + +/** Pointer to error, or NULL if function was successful. See error functions +below. */ +#ifndef fex_err_t /* (#ifndef allows better testing of library) */ + typedef const char* fex_err_t; +#endif + + +/**** File types ****/ + +/** Archive file type identifier. Can also hold NULL. */ +typedef const struct fex_type_t_* fex_type_t; + +/** Array of supported types, with NULL at end */ +const fex_type_t* fex_type_list( void ); + +/** Name of this archive type, e.g. "ZIP archive", "file" */ +const char* fex_type_name( fex_type_t ); + +/** Usual file extension for type, e.g. ".zip", ".7z". For binary file type, +returns "", since it can open any file. */ +const char* fex_type_extension( fex_type_t ); + + +/**** Wide-character file paths ****/ + +/** Converts wide-character path to form suitable for use with fex functions. */ +char* fex_wide_to_path( const wchar_t* wide ); + +/** Frees converted path. OK to pass NULL. */ +void fex_free_path( char* ); + + +/**** Identification ****/ + +/** True if str ends in extension. If extension is "", always returns true. +Converts str to lowercase before comparison, so extension should ALREADY be +lowercase (i.e. pass ".zip", NOT ".ZIP"). */ +int fex_has_extension( const char str [], const char extension [] ); + +/** Determines type based on first fex_identify_header_size bytes of file. +Returns usual file extension this should have (e.g. ".zip", ".gz", etc.). +Returns "" if file header is not recognized. */ +const char* fex_identify_header( const void* header ); +enum { fex_identify_header_size = 16 }; + +/** Determines type based on extension of a file path, or just a lone extension +(must include '.', e.g. ".zip", NOT just "zip"). Returns NULL if extension is +for an unsupported type (e.g. ".lzh"). */ +fex_type_t fex_identify_extension( const char path_or_extension [] ); + +/** Determines type based on filename extension and/or file header. Sets *out +to determined type, or NULL if type is not supported. */ +fex_err_t fex_identify_file( fex_type_t* out, const char path [] ); + +/** Type of an already-opened archive */ +fex_type_t fex_type( const fex_t* ); + + +/**** Open/close ****/ + +/** Initializes static tables used by library. Automatically called by +fex_open(). OK to call more than once. */ +fex_err_t fex_init( void ); + +/** Opens archive and points *out at it. If error, sets *out to NULL. */ +fex_err_t fex_open( fex_t** out, const char path [] ); + +/** Opens archive of specified type and sets *out. Returns error if file is not +of that archive type. If error, sets *out to NULL. */ +fex_err_t fex_open_type( fex_t** out, const char path [], fex_type_t ); + +/** Closes archive and frees memory. OK to pass NULL. */ +void fex_close( fex_t* ); + + +/**** Scanning ****/ + +/** True if at end of archive. Must be called after fex_open() or fex_rewind(), +as an archive might contain no files. */ +int fex_done( const fex_t* ); + +/** Goes to next file in archive. If there are no more files, fex_done() will +now return true. */ +fex_err_t fex_next( fex_t* ); + +/** Goes back to first file in archive, as if it were just opened with +fex_open() */ +fex_err_t fex_rewind( fex_t* ); + +/** Saved position in archive. Can also store zero. */ +typedef int fex_pos_t; + +/** Position of current file in archive. Never returns zero. */ +fex_pos_t fex_tell_arc( const fex_t* ); + +/** Returns to file at previously-saved position */ +fex_err_t fex_seek_arc( fex_t*, fex_pos_t ); + + +/**** Info ****/ + +/** Name of current file */ +const char* fex_name( const fex_t* ); + +/** Wide-character name of current file, or NULL if unavailable */ +const wchar_t* fex_wname( const fex_t* ); + +/** Makes further information available for file */ +fex_err_t fex_stat( fex_t* ); + +/** Size of current file. fex_stat() or fex_data() must have been called. */ +int fex_size( const fex_t* ); + +/** Modification date of current file (MS-DOS format), or 0 if unavailable. +fex_stat() must have been called. */ +unsigned int fex_dos_date( const fex_t* ); + +/** CRC-32 checksum of current file's contents, or 0 if unavailable. Doesn't +require calculation; simply gets it from file's header. fex_stat() must have +been called. */ +unsigned int fex_crc32( const fex_t* ); + + +/**** Extraction ****/ + +/** Reads n bytes from current file. Reading past end of file results in +fex_err_file_eof. */ +fex_err_t fex_read( fex_t*, void* out, int n ); + +/** Number of bytes read from current file */ +int fex_tell( const fex_t* ); + +/** Points *out at current file's data in memory. Pointer is valid until +fex_next(), fex_rewind(), fex_seek_arc(), or fex_close() is called. Pointer +must NOT be freed(); library frees it automatically. If error, sets *out to +NULL. */ +fex_err_t fex_data( fex_t*, const void** out ); + + +/**** Errors ****/ + +/** Error string associated with err. Returns "" if err is NULL. Returns err +unchanged if it isn't a fex_err_t returned by library. */ +const char* fex_err_str( fex_err_t err ); + +/** Details of error beyond main cause, or "" if none or err is NULL. Returns +err unchanged if it isn't a fex_err_t returned by library. */ +const char* fex_err_details( fex_err_t err ); + +/** Numeric code corresponding to err. Returns fex_ok if err is NULL. Returns +fex_err_generic if err isn't a fex_err_t returned by library. */ +int fex_err_code( fex_err_t err ); + +enum { + fex_ok = 0,/**< Successful call. Guaranteed to be zero. */ + fex_err_generic = 0x01,/**< Error of unspecified type */ + fex_err_memory = 0x02,/**< Out of memory */ + fex_err_caller = 0x03,/**< Caller called function with bad args */ + fex_err_internal = 0x04,/**< Internal problem, bug, etc. */ + fex_err_limitation = 0x05,/**< Exceeded program limit */ + + fex_err_file_missing = 0x20,/**< File not found at specified path */ + fex_err_file_read = 0x21,/**< Couldn't open file for reading */ + fex_err_file_io = 0x23,/**< Read/write error */ + fex_err_file_eof = 0x25,/**< Tried to read past end of file */ + + fex_err_file_type = 0x30,/**< File is of wrong type */ + fex_err_file_feature = 0x32,/**< File requires unsupported feature */ + fex_err_file_corrupt = 0x33 /**< File is corrupt */ +}; + +/** fex_err_t corresponding to numeric code. Note that this might not recover +the original fex_err_t before it was converted to a numeric code; in +particular, fex_err_details(fex_code_to_err(code)) will be "" in most cases. */ +fex_err_t fex_code_to_err( int code ); + + +/* Deprecated */ +typedef fex_t File_Extractor; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/fex/internals.txt b/fex/internals.txt index 7269f9d1..92a6bca7 100644 --- a/fex/internals.txt +++ b/fex/internals.txt @@ -1,91 +1,91 @@ -File_Extractor library internals --------------------------------- -This describes the implementation and design. - -Contents --------- -* Framework -* Archive abstraction -* 7-ZIP -* ZIP -* RAR -* GZIP -* Binary - - -Framework ---------- -This library is essentially: - -* Several archive readers -* Wrappers to provide common interface -* File type detection - -The File_Extractor base class implements the common aspects of the -interface and filters out invalid calls. It also provides default -implementations for some operations. Each derived *_Extractor class then -wraps the particular library. - -Then fex.h provides a stable, C-compatible wrapper over File_Extractor, -and does file type identification. - - -Archive abstraction -------------------- -An extractor is abstracted to these fundamental operations: - -* Open (either from path or custom reader) -* Iterate over each file -* Extract file's data (either gradually, or all at once into memory) -* Seek to particular file in archive -* Close - -The extractor can choose whether to open a file path immediately, or -defer until the first stat() call. When extracting data, it can -implement one or both of normal read and "give me a pointer to the data -already in memory". If it only implements one, File_Extractor will -implement the other in terms of it. - - -7-ZIP ------ -A fairly simple wrapper over a slightly-modified LZMA library. -Unfortunately you probably won't be able to drop a later version of the -LZMA library sources in and recompile, as the interface and file -arrangement tends to change with every release. The main change I've -made is to declare functions extern "C" in headers, so C++ code can call -them. - - -ZIP ---- -A complete implementation I wrote. Has nifty optimization that makes all -disk reads begin and end on a multiple of 4K. Also minimizes number of -accesses when initially reading catalog, and extracting file data. -Correctly handles empty zip archives, unlike the popular unzip library -which reports it as a bad archive. - - -RAR ---- -Wrapper over heavily-modified UnRAR extraction library based on the -official UnRAR sources. The library is available separately with -documentation and demos, in case you want to use it without the -File_Extractor front-end (see unrar/changes.txt for more). - - -GZIP ----- -Uses zlib's built-in parsing. Also works with non-gzipped files, based -on absence of two-byte Gzip header. Defers opening of file until -fex_stat(), speeding mere scanning of filenames. Gzip_Reader and -Zlib_Reader further divide the implementation into more manageable and -reusable components. - - -Binary ------- -Just a minimal wrapper over C-style FILE. - --- -Shay Green +File_Extractor library internals +-------------------------------- +This describes the implementation and design. + +Contents +-------- +* Framework +* Archive abstraction +* 7-ZIP +* ZIP +* RAR +* GZIP +* Binary + + +Framework +--------- +This library is essentially: + +* Several archive readers +* Wrappers to provide common interface +* File type detection + +The File_Extractor base class implements the common aspects of the +interface and filters out invalid calls. It also provides default +implementations for some operations. Each derived *_Extractor class then +wraps the particular library. + +Then fex.h provides a stable, C-compatible wrapper over File_Extractor, +and does file type identification. + + +Archive abstraction +------------------- +An extractor is abstracted to these fundamental operations: + +* Open (either from path or custom reader) +* Iterate over each file +* Extract file's data (either gradually, or all at once into memory) +* Seek to particular file in archive +* Close + +The extractor can choose whether to open a file path immediately, or +defer until the first stat() call. When extracting data, it can +implement one or both of normal read and "give me a pointer to the data +already in memory". If it only implements one, File_Extractor will +implement the other in terms of it. + + +7-ZIP +----- +A fairly simple wrapper over a slightly-modified LZMA library. +Unfortunately you probably won't be able to drop a later version of the +LZMA library sources in and recompile, as the interface and file +arrangement tends to change with every release. The main change I've +made is to declare functions extern "C" in headers, so C++ code can call +them. + + +ZIP +--- +A complete implementation I wrote. Has nifty optimization that makes all +disk reads begin and end on a multiple of 4K. Also minimizes number of +accesses when initially reading catalog, and extracting file data. +Correctly handles empty zip archives, unlike the popular unzip library +which reports it as a bad archive. + + +RAR +--- +Wrapper over heavily-modified UnRAR extraction library based on the +official UnRAR sources. The library is available separately with +documentation and demos, in case you want to use it without the +File_Extractor front-end (see unrar/changes.txt for more). + + +GZIP +---- +Uses zlib's built-in parsing. Also works with non-gzipped files, based +on absence of two-byte Gzip header. Defers opening of file until +fex_stat(), speeding mere scanning of filenames. Gzip_Reader and +Zlib_Reader further divide the implementation into more manageable and +reusable components. + + +Binary +------ +Just a minimal wrapper over C-style FILE. + +-- +Shay Green diff --git a/fex/license.txt b/fex/license.txt index 5faba9d4..5ab7695a 100644 --- a/fex/license.txt +++ b/fex/license.txt @@ -1,504 +1,504 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/fex/readme.txt b/fex/readme.txt index 47a83ace..74566479 100644 --- a/fex/readme.txt +++ b/fex/readme.txt @@ -1,59 +1,59 @@ -File_Extractor 1.0.0 --------------------- -File_Extractor is a modular archive scanning and extraction library that -supports several popular compressed file formats. It gives a common -interface to the supported formats, allowing one version of user code. - -Features: -* Simple C interface. -* Supports ZIP, GZIP, 7-Zip (7Z), and RAR[1] archive formats. -* Non-archive files act like archive of that one file, simplifying code. -* Modular design allows removal of support for unneeded archive formats. -* Optionally supports wide-character paths on Windows. -* Archive file type identification can be customized - -[1] RAR support must be enabled before use, due to its special -licensing. - -Author : Shay Green -Website : http://code.google.com/p/file-extractor/ -License : GNU LGPL 2.1 or later for all except unrar -Language: C interface, C++ implementation - - -Getting Started ---------------- -Build the demo by typing "make" at the command-line. If that doesn't -work, manually build a program from demo.c and all *.c and *.cpp files -in fex/, 7z_C/, and zlib/. Run demo with test.zip in the same directory. - -To enable RAR archive support, edit fex/blargg_config.h. - -See fex.h for reference and fex.txt for documentation. - - -Files ------ -fex.txt Manual -license.txt GNU LGPL 2.1 license - -makefile Builds libfex.a and demo - -demo.c Basic usage -demo_read.c Uses fex_read() to extract data -demo_rewind.c Uses fex_rewind() to re-scan archive -demo_seek.c Uses fex_seek_arc() to go back to files -demo_directory.c Recursively scans directory for archives -demo.zip Test archive used by demos - -fex/ - blargg_config.h Configuration (modify as needed) - fex.h C interface (also usable from C++) - (all other files) Library sources - -zlib/ Zip/Gzip (can use your system's instead) -7z_C/ 7-Zip -unrar/ RAR - --- -Shay Green +File_Extractor 1.0.0 +-------------------- +File_Extractor is a modular archive scanning and extraction library that +supports several popular compressed file formats. It gives a common +interface to the supported formats, allowing one version of user code. + +Features: +* Simple C interface. +* Supports ZIP, GZIP, 7-Zip (7Z), and RAR[1] archive formats. +* Non-archive files act like archive of that one file, simplifying code. +* Modular design allows removal of support for unneeded archive formats. +* Optionally supports wide-character paths on Windows. +* Archive file type identification can be customized + +[1] RAR support must be enabled before use, due to its special +licensing. + +Author : Shay Green +Website : http://code.google.com/p/file-extractor/ +License : GNU LGPL 2.1 or later for all except unrar +Language: C interface, C++ implementation + + +Getting Started +--------------- +Build the demo by typing "make" at the command-line. If that doesn't +work, manually build a program from demo.c and all *.c and *.cpp files +in fex/, 7z_C/, and zlib/. Run demo with test.zip in the same directory. + +To enable RAR archive support, edit fex/blargg_config.h. + +See fex.h for reference and fex.txt for documentation. + + +Files +----- +fex.txt Manual +license.txt GNU LGPL 2.1 license + +makefile Builds libfex.a and demo + +demo.c Basic usage +demo_read.c Uses fex_read() to extract data +demo_rewind.c Uses fex_rewind() to re-scan archive +demo_seek.c Uses fex_seek_arc() to go back to files +demo_directory.c Recursively scans directory for archives +demo.zip Test archive used by demos + +fex/ + blargg_config.h Configuration (modify as needed) + fex.h C interface (also usable from C++) + (all other files) Library sources + +zlib/ Zip/Gzip (can use your system's instead) +7z_C/ 7-Zip +unrar/ RAR + +-- +Shay Green