├── .gitignore ├── Classes ├── LZMASDK │ ├── 7z.h │ ├── 7zBuf.c │ ├── 7zBuf.h │ ├── 7zBuf2.c │ ├── 7zDec.c │ ├── 7zFile.c │ ├── 7zFile.h │ ├── 7zIn.c │ ├── 7zStream.c │ ├── 7zVersion.h │ ├── Alloc.c │ ├── Alloc.h │ ├── CpuArch.c │ ├── CpuArch.h │ ├── Delta.c │ ├── Delta.h │ ├── LZMAExtractor.h │ ├── LZMAExtractor.m │ ├── LzHash.h │ ├── Lzma2Dec.c │ ├── Lzma2Dec.h │ ├── LzmaDec.c │ ├── LzmaDec.h │ ├── Ppmd.h │ ├── Ppmd7.c │ ├── Ppmd7.h │ ├── Ppmd7Dec.c │ ├── Ppmd8.c │ ├── Ppmd8.h │ ├── Ppmd8Dec.c │ ├── RotateDefs.h │ ├── Types.h │ └── Util │ │ └── 7z │ │ ├── 7zAlloc.c │ │ ├── 7zAlloc.h │ │ └── 7zMain.c ├── lzmaSDKAppDelegate.h └── lzmaSDKAppDelegate.m ├── LICENSE.txt ├── MainWindow.xib ├── README.txt ├── files_dirs.7z ├── halfgig.7z ├── lzmaApp-Info.plist ├── lzmaApp_Prefix.pch ├── lzmaSDK.xcodeproj └── project.pbxproj ├── lzmaSDK ├── lzmaSDK-Info.plist └── lzmaSDK.h ├── lzmaSDKTests ├── Info.plist └── LZMAExtractorTests.m ├── main.m ├── onegig.7z ├── sixfiftymeg_2blocks.7z ├── test.7z ├── update.tcl └── writebig.tcl /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | xcuserdata 3 | *.pbxuser 4 | *.mode1v3 5 | *.xcworkspace 6 | -------------------------------------------------------------------------------- /Classes/LZMASDK/7z.h: -------------------------------------------------------------------------------- 1 | /* 7z.h -- 7z interface 2 | 2010-03-11 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __7Z_H 5 | #define __7Z_H 6 | 7 | #include "7zBuf.h" 8 | 9 | #include "stdio.h" 10 | 11 | EXTERN_C_BEGIN 12 | 13 | //#define _7ZIP_CRC_SUPPORT 14 | 15 | #define k7zStartHeaderSize 0x20 16 | #define k7zSignatureSize 6 17 | extern Byte k7zSignature[k7zSignatureSize]; 18 | #define k7zMajorVersion 0 19 | 20 | // 1024K = 1 Meg 21 | #define k7zUnpackMapDictionaryInMemoryMaxNumBytes 1024*1024 22 | 23 | enum EIdEnum 24 | { 25 | k7zIdEnd, 26 | k7zIdHeader, 27 | k7zIdArchiveProperties, 28 | k7zIdAdditionalStreamsInfo, 29 | k7zIdMainStreamsInfo, 30 | k7zIdFilesInfo, 31 | k7zIdPackInfo, 32 | k7zIdUnpackInfo, 33 | k7zIdSubStreamsInfo, 34 | k7zIdSize, 35 | k7zIdCRC, 36 | k7zIdFolder, 37 | k7zIdCodersUnpackSize, 38 | k7zIdNumUnpackStream, 39 | k7zIdEmptyStream, 40 | k7zIdEmptyFile, 41 | k7zIdAnti, 42 | k7zIdName, 43 | k7zIdCTime, 44 | k7zIdATime, 45 | k7zIdMTime, 46 | k7zIdWinAttributes, 47 | k7zIdComment, 48 | k7zIdEncodedHeader, 49 | k7zIdStartPos, 50 | k7zIdDummy 51 | }; 52 | 53 | typedef struct 54 | { 55 | UInt32 NumInStreams; 56 | UInt32 NumOutStreams; 57 | UInt64 MethodID; 58 | CBuf Props; 59 | } CSzCoderInfo; 60 | 61 | void SzCoderInfo_Init(CSzCoderInfo *p); 62 | void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc); 63 | 64 | typedef struct 65 | { 66 | UInt32 InIndex; 67 | UInt32 OutIndex; 68 | } CSzBindPair; 69 | 70 | typedef struct 71 | { 72 | CSzCoderInfo *Coders; 73 | CSzBindPair *BindPairs; 74 | UInt32 *PackStreams; 75 | UInt64 *UnpackSizes; 76 | UInt32 NumCoders; 77 | UInt32 NumBindPairs; 78 | UInt32 NumPackStreams; 79 | int UnpackCRCDefined; 80 | UInt32 UnpackCRC; 81 | 82 | UInt32 NumUnpackStreams; 83 | } CSzFolder; 84 | 85 | void SzFolder_Init(CSzFolder *p); 86 | UInt64 SzFolder_GetUnpackSize(CSzFolder *p); 87 | int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex); 88 | UInt32 SzFolder_GetNumOutStreams(CSzFolder *p); 89 | UInt64 SzFolder_GetUnpackSize(CSzFolder *p); 90 | 91 | SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, 92 | ILookInStream *stream, UInt64 startPos, 93 | Byte *outBuffer, size_t outSize, ISzAlloc *allocMain); 94 | 95 | typedef struct 96 | { 97 | UInt32 Low; 98 | UInt32 High; 99 | } CNtfsFileTime; 100 | 101 | typedef struct 102 | { 103 | CNtfsFileTime MTime; 104 | UInt64 Size; 105 | UInt32 Crc; 106 | UInt32 Attrib; 107 | Byte HasStream; 108 | Byte IsDir; 109 | Byte IsAnti; 110 | Byte CrcDefined; 111 | Byte MTimeDefined; 112 | Byte AttribDefined; 113 | } CSzFileItem; 114 | 115 | void SzFile_Init(CSzFileItem *p); 116 | 117 | typedef struct 118 | { 119 | UInt64 *PackSizes; 120 | Byte *PackCRCsDefined; 121 | UInt32 *PackCRCs; 122 | CSzFolder *Folders; 123 | CSzFileItem *Files; 124 | UInt32 NumPackStreams; 125 | UInt32 NumFolders; 126 | UInt32 NumFiles; 127 | } CSzAr; 128 | 129 | void SzAr_Init(CSzAr *p); 130 | void SzAr_Free(CSzAr *p, ISzAlloc *alloc); 131 | 132 | 133 | /* 134 | SzExtract extracts file from archive 135 | 136 | Pass an initialized pointer to a SzArEx_DictCache object, this record will 137 | contain the allocated/mapped buffer that holds decompressed data. 138 | 139 | *outBuffer must be 0 before first call for each new archive. 140 | 141 | Extracting cache: 142 | If you need to decompress more than one file, you can send 143 | these values from previous call: 144 | *blockIndex, 145 | *outBuffer, 146 | *outBufferSize 147 | You can consider "*outBuffer" as cache of solid block. If your archive is solid, 148 | it will increase decompression speed. 149 | 150 | If you use external function, you can declare these 3 cache variables 151 | (blockIndex, outBuffer, outBufferSize) as static in that external function. 152 | 153 | To flush the cache, invoke SzArEx_DictCache_free(). 154 | */ 155 | 156 | typedef struct 157 | { 158 | /* Ref to malloc implementation */ 159 | ISzAlloc *allocMain; 160 | /* Default to 0xFFFFFFFF, can have any value before first call (if outBuffer = 0) */ 161 | UInt32 blockIndex; 162 | /* must be 0 (NULL) before first call for each new archive */ 163 | Byte *outBuffer; 164 | /* init to 0, can have any value before first call */ 165 | size_t outBufferSize; 166 | /* byte offset in outBuffer where decoded entry begins */ 167 | size_t entryOffset; 168 | /* The size in bytes of a specific entry extracted from an archive */ 169 | size_t outSizeProcessed; 170 | 171 | /* If dictionary memory is being paged to disk via a writable mmap region, then 172 | * the mapFilename is non-NULL. */ 173 | char *mapFilename; 174 | 175 | /* If dictionary memory is being paged to disk and the file is currently open, 176 | * then this file pointer if non-NULL. */ 177 | FILE *mapFile; 178 | size_t mapSize; 179 | } SzArEx_DictCache; 180 | 181 | void 182 | SzArEx_DictCache_init(SzArEx_DictCache *dictCache, ISzAlloc *allocMain); 183 | 184 | void 185 | SzArEx_DictCache_free(SzArEx_DictCache *dictCache); 186 | 187 | int 188 | SzArEx_DictCache_mmap(SzArEx_DictCache *dictCache); 189 | 190 | void 191 | SzArEx_DictCache_munmap(SzArEx_DictCache *dictCache); 192 | 193 | typedef struct 194 | { 195 | CSzAr db; 196 | 197 | UInt64 startPosAfterHeader; 198 | UInt64 dataPos; 199 | 200 | UInt32 *FolderStartPackStreamIndex; 201 | UInt64 *PackStreamStartPositions; 202 | UInt32 *FolderStartFileIndex; 203 | UInt32 *FileIndexToFolderIndexMap; 204 | 205 | size_t *FileNameOffsets; /* in 2-byte steps */ 206 | CBuf FileNames; /* UTF-16-LE */ 207 | } CSzArEx; 208 | 209 | void SzArEx_Init(CSzArEx *p); 210 | void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); 211 | UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); 212 | int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); 213 | 214 | /* 215 | if dest == NULL, the return value specifies the required size of the buffer, 216 | in 16-bit characters, including the null-terminating character. 217 | if dest != NULL, the return value specifies the number of 16-bit characters that 218 | are written to the dest, including the null-terminating character. */ 219 | 220 | size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); 221 | 222 | SRes SzArEx_Extract( 223 | const CSzArEx *db, 224 | ILookInStream *inStream, 225 | UInt32 fileIndex, /* index of file */ 226 | SzArEx_DictCache *dictCache, 227 | ISzAlloc *allocMain, 228 | ISzAlloc *allocTemp); 229 | 230 | 231 | /* 232 | SzArEx_Open Errors: 233 | SZ_ERROR_NO_ARCHIVE 234 | SZ_ERROR_ARCHIVE 235 | SZ_ERROR_UNSUPPORTED 236 | SZ_ERROR_MEM 237 | SZ_ERROR_CRC 238 | SZ_ERROR_INPUT_EOF 239 | SZ_ERROR_FAIL 240 | */ 241 | 242 | SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp); 243 | 244 | EXTERN_C_END 245 | 246 | #endif 247 | -------------------------------------------------------------------------------- /Classes/LZMASDK/7zBuf.c: -------------------------------------------------------------------------------- 1 | /* 7zBuf.c -- Byte Buffer 2 | 2008-03-28 3 | Igor Pavlov 4 | Public domain */ 5 | 6 | #include "7zBuf.h" 7 | 8 | void Buf_Init(CBuf *p) 9 | { 10 | p->data = 0; 11 | p->size = 0; 12 | } 13 | 14 | int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc) 15 | { 16 | p->size = 0; 17 | if (size == 0) 18 | { 19 | p->data = 0; 20 | return 1; 21 | } 22 | p->data = (Byte *)alloc->Alloc(alloc, size); 23 | if (p->data != 0) 24 | { 25 | p->size = size; 26 | return 1; 27 | } 28 | return 0; 29 | } 30 | 31 | void Buf_Free(CBuf *p, ISzAlloc *alloc) 32 | { 33 | alloc->Free(alloc, p->data); 34 | p->data = 0; 35 | p->size = 0; 36 | } 37 | -------------------------------------------------------------------------------- /Classes/LZMASDK/7zBuf.h: -------------------------------------------------------------------------------- 1 | /* 7zBuf.h -- Byte Buffer 2 | 2009-02-07 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __7Z_BUF_H 5 | #define __7Z_BUF_H 6 | 7 | #include "Types.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | typedef struct 14 | { 15 | Byte *data; 16 | size_t size; 17 | } CBuf; 18 | 19 | void Buf_Init(CBuf *p); 20 | int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc); 21 | void Buf_Free(CBuf *p, ISzAlloc *alloc); 22 | 23 | typedef struct 24 | { 25 | Byte *data; 26 | size_t size; 27 | size_t pos; 28 | } CDynBuf; 29 | 30 | void DynBuf_Construct(CDynBuf *p); 31 | void DynBuf_SeekToBeg(CDynBuf *p); 32 | int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc); 33 | void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc); 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /Classes/LZMASDK/7zBuf2.c: -------------------------------------------------------------------------------- 1 | /* 7zBuf2.c -- Byte Buffer 2 | 2008-10-04 : Igor Pavlov : Public domain */ 3 | 4 | #include 5 | #include "7zBuf.h" 6 | 7 | void DynBuf_Construct(CDynBuf *p) 8 | { 9 | p->data = 0; 10 | p->size = 0; 11 | p->pos = 0; 12 | } 13 | 14 | void DynBuf_SeekToBeg(CDynBuf *p) 15 | { 16 | p->pos = 0; 17 | } 18 | 19 | int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc) 20 | { 21 | if (size > p->size - p->pos) 22 | { 23 | size_t newSize = p->pos + size; 24 | Byte *data; 25 | newSize += newSize / 4; 26 | data = (Byte *)alloc->Alloc(alloc, newSize); 27 | if (data == 0) 28 | return 0; 29 | p->size = newSize; 30 | memcpy(data, p->data, p->pos); 31 | alloc->Free(alloc, p->data); 32 | p->data = data; 33 | } 34 | memcpy(p->data + p->pos, buf, size); 35 | p->pos += size; 36 | return 1; 37 | } 38 | 39 | void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc) 40 | { 41 | alloc->Free(alloc, p->data); 42 | p->data = 0; 43 | p->size = 0; 44 | p->pos = 0; 45 | } 46 | -------------------------------------------------------------------------------- /Classes/LZMASDK/7zDec.c: -------------------------------------------------------------------------------- 1 | /* 7zDec.c -- Decoding from 7z folder 2 | 2010-11-02 : Igor Pavlov : Public domain */ 3 | 4 | #include 5 | 6 | /* #define _7ZIP_PPMD_SUPPPORT */ 7 | 8 | #include "7z.h" 9 | 10 | #ifdef _7ZIP_BRANCH_SUPPORT 11 | #include "Bcj2.h" 12 | #include "Bra.h" 13 | #endif 14 | #ifdef _7ZIP_CRC_SUPPORT 15 | #include "CpuArch.h" 16 | #endif 17 | #include "LzmaDec.h" 18 | #include "Lzma2Dec.h" 19 | #ifdef _7ZIP_PPMD_SUPPPORT 20 | #include "Ppmd7.h" 21 | #endif 22 | 23 | #define k_Copy 0 24 | #define k_LZMA2 0x21 25 | #define k_LZMA 0x30101 26 | #define k_BCJ 0x03030103 27 | #define k_PPC 0x03030205 28 | #define k_ARM 0x03030501 29 | #define k_ARMT 0x03030701 30 | #define k_SPARC 0x03030805 31 | #define k_BCJ2 0x0303011B 32 | 33 | #ifdef _7ZIP_PPMD_SUPPPORT 34 | 35 | #define k_PPMD 0x30401 36 | 37 | typedef struct 38 | { 39 | IByteIn p; 40 | const Byte *cur; 41 | const Byte *end; 42 | const Byte *begin; 43 | UInt64 processed; 44 | Bool extra; 45 | SRes res; 46 | ILookInStream *inStream; 47 | } CByteInToLook; 48 | 49 | static Byte ReadByte(void *pp) 50 | { 51 | CByteInToLook *p = (CByteInToLook *)pp; 52 | if (p->cur != p->end) 53 | return *p->cur++; 54 | if (p->res == SZ_OK) 55 | { 56 | size_t size = p->cur - p->begin; 57 | p->processed += size; 58 | p->res = p->inStream->Skip(p->inStream, size); 59 | size = (1 << 25); 60 | p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size); 61 | p->cur = p->begin; 62 | p->end = p->begin + size; 63 | if (size != 0) 64 | return *p->cur++;; 65 | } 66 | p->extra = True; 67 | return 0; 68 | } 69 | 70 | static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, 71 | Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) 72 | { 73 | CPpmd7 ppmd; 74 | CByteInToLook s; 75 | SRes res = SZ_OK; 76 | 77 | s.p.Read = ReadByte; 78 | s.inStream = inStream; 79 | s.begin = s.end = s.cur = NULL; 80 | s.extra = False; 81 | s.res = SZ_OK; 82 | s.processed = 0; 83 | 84 | if (coder->Props.size != 5) 85 | return SZ_ERROR_UNSUPPORTED; 86 | 87 | { 88 | unsigned order = coder->Props.data[0]; 89 | UInt32 memSize = GetUi32(coder->Props.data + 1); 90 | if (order < PPMD7_MIN_ORDER || 91 | order > PPMD7_MAX_ORDER || 92 | memSize < PPMD7_MIN_MEM_SIZE || 93 | memSize > PPMD7_MAX_MEM_SIZE) 94 | return SZ_ERROR_UNSUPPORTED; 95 | Ppmd7_Construct(&ppmd); 96 | if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) 97 | return SZ_ERROR_MEM; 98 | Ppmd7_Init(&ppmd, order); 99 | } 100 | { 101 | CPpmd7z_RangeDec rc; 102 | Ppmd7z_RangeDec_CreateVTable(&rc); 103 | rc.Stream = &s.p; 104 | if (!Ppmd7z_RangeDec_Init(&rc)) 105 | res = SZ_ERROR_DATA; 106 | else if (s.extra) 107 | res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); 108 | else 109 | { 110 | SizeT i; 111 | for (i = 0; i < outSize; i++) 112 | { 113 | int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p); 114 | if (s.extra || sym < 0) 115 | break; 116 | outBuffer[i] = (Byte)sym; 117 | } 118 | if (i != outSize) 119 | res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); 120 | else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc)) 121 | res = SZ_ERROR_DATA; 122 | } 123 | } 124 | Ppmd7_Free(&ppmd, allocMain); 125 | return res; 126 | } 127 | 128 | #endif 129 | 130 | 131 | static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, 132 | Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) 133 | { 134 | CLzmaDec state; 135 | SRes res = SZ_OK; 136 | 137 | LzmaDec_Construct(&state); 138 | RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain)); 139 | state.dic = outBuffer; 140 | state.dicBufSize = outSize; 141 | LzmaDec_Init(&state); 142 | 143 | for (;;) 144 | { 145 | Byte *inBuf = NULL; 146 | size_t lookahead = (1 << 18); 147 | if (lookahead > inSize) 148 | lookahead = (size_t)inSize; 149 | res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); 150 | if (res != SZ_OK) 151 | break; 152 | 153 | { 154 | SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; 155 | ELzmaStatus status; 156 | res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); 157 | lookahead -= inProcessed; 158 | inSize -= inProcessed; 159 | if (res != SZ_OK) 160 | break; 161 | if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos)) 162 | { 163 | if (state.dicBufSize != outSize || lookahead != 0 || 164 | (status != LZMA_STATUS_FINISHED_WITH_MARK && 165 | status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) 166 | res = SZ_ERROR_DATA; 167 | break; 168 | } 169 | res = inStream->Skip((void *)inStream, inProcessed); 170 | if (res != SZ_OK) 171 | break; 172 | } 173 | } 174 | 175 | LzmaDec_FreeProbs(&state, allocMain); 176 | return res; 177 | } 178 | 179 | static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, 180 | Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) 181 | { 182 | CLzma2Dec state; 183 | SRes res = SZ_OK; 184 | 185 | Lzma2Dec_Construct(&state); 186 | if (coder->Props.size != 1) 187 | return SZ_ERROR_DATA; 188 | RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain)); 189 | state.decoder.dic = outBuffer; 190 | state.decoder.dicBufSize = outSize; 191 | Lzma2Dec_Init(&state); 192 | 193 | for (;;) 194 | { 195 | Byte *inBuf = NULL; 196 | size_t lookahead = (1 << 18); 197 | if (lookahead > inSize) 198 | lookahead = (size_t)inSize; 199 | res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); 200 | if (res != SZ_OK) 201 | break; 202 | 203 | { 204 | SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; 205 | ELzmaStatus status; 206 | res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); 207 | lookahead -= inProcessed; 208 | inSize -= inProcessed; 209 | if (res != SZ_OK) 210 | break; 211 | if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos)) 212 | { 213 | if (state.decoder.dicBufSize != outSize || lookahead != 0 || 214 | (status != LZMA_STATUS_FINISHED_WITH_MARK)) 215 | res = SZ_ERROR_DATA; 216 | break; 217 | } 218 | res = inStream->Skip((void *)inStream, inProcessed); 219 | if (res != SZ_OK) 220 | break; 221 | } 222 | } 223 | 224 | Lzma2Dec_FreeProbs(&state, allocMain); 225 | return res; 226 | } 227 | 228 | static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) 229 | { 230 | while (inSize > 0) 231 | { 232 | void *inBuf; 233 | size_t curSize = (1 << 18); 234 | if (curSize > inSize) 235 | curSize = (size_t)inSize; 236 | RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize)); 237 | if (curSize == 0) 238 | return SZ_ERROR_INPUT_EOF; 239 | memcpy(outBuffer, inBuf, curSize); 240 | outBuffer += curSize; 241 | inSize -= curSize; 242 | RINOK(inStream->Skip((void *)inStream, curSize)); 243 | } 244 | return SZ_OK; 245 | } 246 | 247 | static Bool IS_MAIN_METHOD(UInt32 m) 248 | { 249 | switch(m) 250 | { 251 | case k_Copy: 252 | case k_LZMA: 253 | case k_LZMA2: 254 | #ifdef _7ZIP_PPMD_SUPPPORT 255 | case k_PPMD: 256 | #endif 257 | return True; 258 | } 259 | return False; 260 | } 261 | 262 | static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c) 263 | { 264 | return 265 | c->NumInStreams == 1 && 266 | c->NumOutStreams == 1 && 267 | c->MethodID <= (UInt32)0xFFFFFFFF && 268 | IS_MAIN_METHOD((UInt32)c->MethodID); 269 | } 270 | 271 | #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1) 272 | 273 | static SRes CheckSupportedFolder(const CSzFolder *f) 274 | { 275 | if (f->NumCoders < 1 || f->NumCoders > 4) 276 | return SZ_ERROR_UNSUPPORTED; 277 | if (!IS_SUPPORTED_CODER(&f->Coders[0])) 278 | return SZ_ERROR_UNSUPPORTED; 279 | if (f->NumCoders == 1) 280 | { 281 | if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0) 282 | return SZ_ERROR_UNSUPPORTED; 283 | return SZ_OK; 284 | } 285 | if (f->NumCoders == 2) 286 | { 287 | CSzCoderInfo *c = &f->Coders[1]; 288 | if (c->MethodID > (UInt32)0xFFFFFFFF || 289 | c->NumInStreams != 1 || 290 | c->NumOutStreams != 1 || 291 | f->NumPackStreams != 1 || 292 | f->PackStreams[0] != 0 || 293 | f->NumBindPairs != 1 || 294 | f->BindPairs[0].InIndex != 1 || 295 | f->BindPairs[0].OutIndex != 0) 296 | return SZ_ERROR_UNSUPPORTED; 297 | switch ((UInt32)c->MethodID) 298 | { 299 | case k_BCJ: 300 | case k_ARM: 301 | break; 302 | default: 303 | return SZ_ERROR_UNSUPPORTED; 304 | } 305 | return SZ_OK; 306 | } 307 | if (f->NumCoders == 4) 308 | { 309 | if (!IS_SUPPORTED_CODER(&f->Coders[1]) || 310 | !IS_SUPPORTED_CODER(&f->Coders[2]) || 311 | !IS_BCJ2(&f->Coders[3])) 312 | return SZ_ERROR_UNSUPPORTED; 313 | if (f->NumPackStreams != 4 || 314 | f->PackStreams[0] != 2 || 315 | f->PackStreams[1] != 6 || 316 | f->PackStreams[2] != 1 || 317 | f->PackStreams[3] != 0 || 318 | f->NumBindPairs != 3 || 319 | f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || 320 | f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || 321 | f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) 322 | return SZ_ERROR_UNSUPPORTED; 323 | return SZ_OK; 324 | } 325 | return SZ_ERROR_UNSUPPORTED; 326 | } 327 | 328 | static UInt64 GetSum(const UInt64 *values, UInt32 index) 329 | { 330 | UInt64 sum = 0; 331 | UInt32 i; 332 | for (i = 0; i < index; i++) 333 | sum += values[i]; 334 | return sum; 335 | } 336 | 337 | #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; 338 | 339 | static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, 340 | ILookInStream *inStream, UInt64 startPos, 341 | Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, 342 | Byte *tempBuf[]) 343 | { 344 | UInt32 ci; 345 | SizeT tempSizes[3] = { 0, 0, 0}; 346 | #ifdef _7ZIP_BRANCH_SUPPORT 347 | SizeT tempSize3 = 0; 348 | Byte *tempBuf3 = 0; 349 | #endif 350 | 351 | RINOK(CheckSupportedFolder(folder)); 352 | 353 | for (ci = 0; ci < folder->NumCoders; ci++) 354 | { 355 | CSzCoderInfo *coder = &folder->Coders[ci]; 356 | 357 | if (IS_MAIN_METHOD((UInt32)coder->MethodID)) 358 | { 359 | UInt32 si = 0; 360 | UInt64 offset; 361 | UInt64 inSize; 362 | Byte *outBufCur = outBuffer; 363 | SizeT outSizeCur = outSize; 364 | if (folder->NumCoders == 4) 365 | { 366 | UInt32 indices[] = { 3, 2, 0 }; 367 | UInt64 unpackSize = folder->UnpackSizes[ci]; 368 | si = indices[ci]; 369 | if (ci < 2) 370 | { 371 | Byte *temp; 372 | outSizeCur = (SizeT)unpackSize; 373 | if (outSizeCur != unpackSize) 374 | return SZ_ERROR_MEM; 375 | temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); 376 | if (temp == 0 && outSizeCur != 0) 377 | return SZ_ERROR_MEM; 378 | outBufCur = tempBuf[1 - ci] = temp; 379 | tempSizes[1 - ci] = outSizeCur; 380 | } 381 | else if (ci == 2) 382 | { 383 | if (unpackSize > outSize) /* check it */ 384 | return SZ_ERROR_PARAM; 385 | #ifdef _7ZIP_BRANCH_SUPPORT 386 | tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); 387 | tempSize3 = outSizeCur = (SizeT)unpackSize; 388 | #endif 389 | } 390 | else 391 | return SZ_ERROR_UNSUPPORTED; 392 | } 393 | offset = GetSum(packSizes, si); 394 | inSize = packSizes[si]; 395 | RINOK(LookInStream_SeekTo(inStream, startPos + offset)); 396 | 397 | if (coder->MethodID == k_Copy) 398 | { 399 | if (inSize != outSizeCur) /* check it */ 400 | return SZ_ERROR_DATA; 401 | RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); 402 | } 403 | else if (coder->MethodID == k_LZMA) 404 | { 405 | RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); 406 | } 407 | else if (coder->MethodID == k_LZMA2) 408 | { 409 | RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); 410 | } 411 | else 412 | { 413 | #ifdef _7ZIP_PPMD_SUPPPORT 414 | RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); 415 | #else 416 | return SZ_ERROR_UNSUPPORTED; 417 | #endif 418 | } 419 | } 420 | else if (coder->MethodID == k_BCJ2) 421 | { 422 | #ifdef _7ZIP_BRANCH_SUPPORT 423 | UInt64 offset = GetSum(packSizes, 1); 424 | UInt64 s3Size = packSizes[1]; 425 | SRes res; 426 | if (ci != 3) 427 | return SZ_ERROR_UNSUPPORTED; 428 | RINOK(LookInStream_SeekTo(inStream, startPos + offset)); 429 | tempSizes[2] = (SizeT)s3Size; 430 | if (tempSizes[2] != s3Size) 431 | return SZ_ERROR_MEM; 432 | tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); 433 | if (tempBuf[2] == 0 && tempSizes[2] != 0) 434 | return SZ_ERROR_MEM; 435 | res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); 436 | RINOK(res) 437 | 438 | res = Bcj2_Decode( 439 | tempBuf3, tempSize3, 440 | tempBuf[0], tempSizes[0], 441 | tempBuf[1], tempSizes[1], 442 | tempBuf[2], tempSizes[2], 443 | outBuffer, outSize); 444 | RINOK(res) 445 | #else 446 | return SZ_ERROR_UNSUPPORTED; 447 | #endif 448 | } 449 | else 450 | { 451 | #ifdef _7ZIP_BRANCH_SUPPORT 452 | if (ci != 1) 453 | return SZ_ERROR_UNSUPPORTED; 454 | switch(coder->MethodID) 455 | { 456 | case k_BCJ: 457 | { 458 | UInt32 state; 459 | x86_Convert_Init(state); 460 | x86_Convert(outBuffer, outSize, 0, &state, 0); 461 | break; 462 | } 463 | CASE_BRA_CONV(ARM) 464 | default: 465 | return SZ_ERROR_UNSUPPORTED; 466 | } 467 | #else 468 | return SZ_ERROR_UNSUPPORTED; 469 | #endif 470 | } 471 | } 472 | return SZ_OK; 473 | } 474 | 475 | SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, 476 | ILookInStream *inStream, UInt64 startPos, 477 | Byte *outBuffer, size_t outSize, ISzAlloc *allocMain) 478 | { 479 | Byte *tempBuf[3] = { 0, 0, 0}; 480 | int i; 481 | SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos, 482 | outBuffer, (SizeT)outSize, allocMain, tempBuf); 483 | for (i = 0; i < 3; i++) 484 | IAlloc_Free(allocMain, tempBuf[i]); 485 | return res; 486 | } 487 | -------------------------------------------------------------------------------- /Classes/LZMASDK/7zFile.c: -------------------------------------------------------------------------------- 1 | /* 7zFile.c -- File IO 2 | 2009-11-24 : Igor Pavlov : Public domain */ 3 | 4 | #include "7zFile.h" 5 | 6 | #include 7 | #include 8 | 9 | #ifndef USE_WINDOWS_FILE 10 | 11 | #ifndef UNDER_CE 12 | #include 13 | #endif 14 | 15 | #else 16 | 17 | /* 18 | ReadFile and WriteFile functions in Windows have BUG: 19 | If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) 20 | from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES 21 | (Insufficient system resources exist to complete the requested service). 22 | Probably in some version of Windows there are problems with other sizes: 23 | for 32 MB (maybe also for 16 MB). 24 | And message can be "Network connection was lost" 25 | */ 26 | 27 | #define kChunkSizeMax (1 << 22) 28 | 29 | #endif 30 | 31 | void File_Construct(CSzFile *p) 32 | { 33 | #ifdef USE_WINDOWS_FILE 34 | p->handle = INVALID_HANDLE_VALUE; 35 | #else 36 | p->file = NULL; 37 | #endif 38 | } 39 | 40 | #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) 41 | static WRes File_Open(CSzFile *p, const char *name, int writeMode, const char* threadCwd) 42 | { 43 | char *qualName = (char*) name; 44 | if (threadCwd != NULL) { 45 | qualName = (char *) malloc(strlen(threadCwd) + strlen(name) + 1); 46 | strcpy(qualName, threadCwd); 47 | strcat(qualName, (char*)name); 48 | } 49 | #ifdef USE_WINDOWS_FILE 50 | p->handle = CreateFileA(qualName, 51 | writeMode ? GENERIC_WRITE : GENERIC_READ, 52 | FILE_SHARE_READ, NULL, 53 | writeMode ? CREATE_ALWAYS : OPEN_EXISTING, 54 | FILE_ATTRIBUTE_NORMAL, NULL); 55 | if (qualName != name) { 56 | free(qualName); 57 | } 58 | return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); 59 | #else 60 | p->file = fopen(qualName, writeMode ? "wb+" : "rb"); 61 | if (qualName != name) { 62 | free(qualName); 63 | } 64 | return (p->file != 0) ? 0 : 65 | #ifdef UNDER_CE 66 | 2; /* ENOENT */ 67 | #else 68 | errno; 69 | #endif 70 | #endif 71 | } 72 | 73 | WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0, NULL); } 74 | WRes OutFile_Open(CSzFile *p, const char *name, const char *threadCwd) { return File_Open(p, name, 1, threadCwd); } 75 | #endif 76 | 77 | #ifdef USE_WINDOWS_FILE 78 | static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) 79 | { 80 | p->handle = CreateFileW(name, 81 | writeMode ? GENERIC_WRITE : GENERIC_READ, 82 | FILE_SHARE_READ, NULL, 83 | writeMode ? CREATE_ALWAYS : OPEN_EXISTING, 84 | FILE_ATTRIBUTE_NORMAL, NULL); 85 | return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); 86 | } 87 | WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } 88 | WRes OutFile_OpenW(CSzFile *p, const WCHAR *name, const WCHAR *threadCwd) { return File_OpenW(p, name, 1, threadCwd); } 89 | #endif 90 | 91 | WRes File_Close(CSzFile *p) 92 | { 93 | #ifdef USE_WINDOWS_FILE 94 | if (p->handle != INVALID_HANDLE_VALUE) 95 | { 96 | if (!CloseHandle(p->handle)) 97 | return GetLastError(); 98 | p->handle = INVALID_HANDLE_VALUE; 99 | } 100 | #else 101 | if (p->file != NULL) 102 | { 103 | int res = fclose(p->file); 104 | if (res != 0) 105 | return res; 106 | p->file = NULL; 107 | } 108 | #endif 109 | return 0; 110 | } 111 | 112 | WRes File_Read(CSzFile *p, void *data, size_t *size) 113 | { 114 | size_t originalSize = *size; 115 | if (originalSize == 0) 116 | return 0; 117 | 118 | #ifdef USE_WINDOWS_FILE 119 | 120 | *size = 0; 121 | do 122 | { 123 | DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; 124 | DWORD processed = 0; 125 | BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); 126 | data = (void *)((Byte *)data + processed); 127 | originalSize -= processed; 128 | *size += processed; 129 | if (!res) 130 | return GetLastError(); 131 | if (processed == 0) 132 | break; 133 | } 134 | while (originalSize > 0); 135 | return 0; 136 | 137 | #else 138 | 139 | *size = fread(data, 1, originalSize, p->file); 140 | if (*size == originalSize) 141 | return 0; 142 | return ferror(p->file); 143 | 144 | #endif 145 | } 146 | 147 | WRes File_Write(CSzFile *p, const void *data, size_t *size) 148 | { 149 | size_t originalSize = *size; 150 | if (originalSize == 0) 151 | return 0; 152 | 153 | #ifdef USE_WINDOWS_FILE 154 | 155 | *size = 0; 156 | do 157 | { 158 | DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; 159 | DWORD processed = 0; 160 | BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); 161 | data = (void *)((Byte *)data + processed); 162 | originalSize -= processed; 163 | *size += processed; 164 | if (!res) 165 | return GetLastError(); 166 | if (processed == 0) 167 | break; 168 | } 169 | while (originalSize > 0); 170 | return 0; 171 | 172 | #else 173 | 174 | *size = fwrite(data, 1, originalSize, p->file); 175 | if (*size == originalSize) 176 | return 0; 177 | return ferror(p->file); 178 | 179 | #endif 180 | } 181 | 182 | WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) 183 | { 184 | #ifdef USE_WINDOWS_FILE 185 | 186 | LARGE_INTEGER value; 187 | DWORD moveMethod; 188 | value.LowPart = (DWORD)*pos; 189 | value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ 190 | switch (origin) 191 | { 192 | case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; 193 | case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; 194 | case SZ_SEEK_END: moveMethod = FILE_END; break; 195 | default: return ERROR_INVALID_PARAMETER; 196 | } 197 | value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); 198 | if (value.LowPart == 0xFFFFFFFF) 199 | { 200 | WRes res = GetLastError(); 201 | if (res != NO_ERROR) 202 | return res; 203 | } 204 | *pos = ((Int64)value.HighPart << 32) | value.LowPart; 205 | return 0; 206 | 207 | #else 208 | 209 | int moveMethod; 210 | int res; 211 | switch (origin) 212 | { 213 | case SZ_SEEK_SET: moveMethod = SEEK_SET; break; 214 | case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; 215 | case SZ_SEEK_END: moveMethod = SEEK_END; break; 216 | default: return 1; 217 | } 218 | res = fseek(p->file, (long)*pos, moveMethod); 219 | *pos = ftell(p->file); 220 | return res; 221 | 222 | #endif 223 | } 224 | 225 | WRes File_GetLength(CSzFile *p, UInt64 *length) 226 | { 227 | #ifdef USE_WINDOWS_FILE 228 | 229 | DWORD sizeHigh; 230 | DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); 231 | if (sizeLow == 0xFFFFFFFF) 232 | { 233 | DWORD res = GetLastError(); 234 | if (res != NO_ERROR) 235 | return res; 236 | } 237 | *length = (((UInt64)sizeHigh) << 32) + sizeLow; 238 | return 0; 239 | 240 | #else 241 | 242 | long pos = ftell(p->file); 243 | int res = fseek(p->file, 0, SEEK_END); 244 | *length = ftell(p->file); 245 | fseek(p->file, pos, SEEK_SET); 246 | return res; 247 | 248 | #endif 249 | } 250 | 251 | 252 | /* ---------- FileSeqInStream ---------- */ 253 | 254 | static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size) 255 | { 256 | CFileSeqInStream *p = (CFileSeqInStream *)pp; 257 | return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; 258 | } 259 | 260 | void FileSeqInStream_CreateVTable(CFileSeqInStream *p) 261 | { 262 | p->s.Read = FileSeqInStream_Read; 263 | } 264 | 265 | 266 | /* ---------- FileInStream ---------- */ 267 | 268 | static SRes FileInStream_Read(void *pp, void *buf, size_t *size) 269 | { 270 | CFileInStream *p = (CFileInStream *)pp; 271 | return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; 272 | } 273 | 274 | static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin) 275 | { 276 | CFileInStream *p = (CFileInStream *)pp; 277 | return File_Seek(&p->file, pos, origin); 278 | } 279 | 280 | void FileInStream_CreateVTable(CFileInStream *p) 281 | { 282 | p->s.Read = FileInStream_Read; 283 | p->s.Seek = FileInStream_Seek; 284 | } 285 | 286 | 287 | /* ---------- FileOutStream ---------- */ 288 | 289 | static size_t FileOutStream_Write(void *pp, const void *data, size_t size) 290 | { 291 | CFileOutStream *p = (CFileOutStream *)pp; 292 | File_Write(&p->file, data, &size); 293 | return size; 294 | } 295 | 296 | void FileOutStream_CreateVTable(CFileOutStream *p) 297 | { 298 | p->s.Write = FileOutStream_Write; 299 | } 300 | -------------------------------------------------------------------------------- /Classes/LZMASDK/7zFile.h: -------------------------------------------------------------------------------- 1 | /* 7zFile.h -- File IO 2 | 2009-11-24 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __7Z_FILE_H 5 | #define __7Z_FILE_H 6 | 7 | #ifdef _WIN32 8 | #define USE_WINDOWS_FILE 9 | #endif 10 | 11 | #ifdef USE_WINDOWS_FILE 12 | #include 13 | #else 14 | #include 15 | #endif 16 | 17 | #include "Types.h" 18 | 19 | EXTERN_C_BEGIN 20 | 21 | /* ---------- File ---------- */ 22 | 23 | typedef struct 24 | { 25 | #ifdef USE_WINDOWS_FILE 26 | HANDLE handle; 27 | #else 28 | FILE *file; 29 | #endif 30 | } CSzFile; 31 | 32 | void File_Construct(CSzFile *p); 33 | #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) 34 | WRes InFile_Open(CSzFile *p, const char *name); 35 | WRes OutFile_Open(CSzFile *p, const char *name, const char *threadCwd); 36 | #endif 37 | #ifdef USE_WINDOWS_FILE 38 | WRes InFile_OpenW(CSzFile *p, const WCHAR *name); 39 | WRes OutFile_OpenW(CSzFile *p, const WCHAR *name, const WCHAR *threadCwd); 40 | #endif 41 | WRes File_Close(CSzFile *p); 42 | 43 | /* reads max(*size, remain file's size) bytes */ 44 | WRes File_Read(CSzFile *p, void *data, size_t *size); 45 | 46 | /* writes *size bytes */ 47 | WRes File_Write(CSzFile *p, const void *data, size_t *size); 48 | 49 | WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); 50 | WRes File_GetLength(CSzFile *p, UInt64 *length); 51 | 52 | 53 | /* ---------- FileInStream ---------- */ 54 | 55 | typedef struct 56 | { 57 | ISeqInStream s; 58 | CSzFile file; 59 | } CFileSeqInStream; 60 | 61 | void FileSeqInStream_CreateVTable(CFileSeqInStream *p); 62 | 63 | 64 | typedef struct 65 | { 66 | ISeekInStream s; 67 | CSzFile file; 68 | } CFileInStream; 69 | 70 | void FileInStream_CreateVTable(CFileInStream *p); 71 | 72 | 73 | typedef struct 74 | { 75 | ISeqOutStream s; 76 | CSzFile file; 77 | } CFileOutStream; 78 | 79 | void FileOutStream_CreateVTable(CFileOutStream *p); 80 | 81 | EXTERN_C_END 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /Classes/LZMASDK/7zStream.c: -------------------------------------------------------------------------------- 1 | /* 7zStream.c -- 7z Stream functions 2 | 2010-03-11 : Igor Pavlov : Public domain */ 3 | 4 | #include 5 | 6 | #include "Types.h" 7 | 8 | SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType) 9 | { 10 | while (size != 0) 11 | { 12 | size_t processed = size; 13 | RINOK(stream->Read(stream, buf, &processed)); 14 | if (processed == 0) 15 | return errorType; 16 | buf = (void *)((Byte *)buf + processed); 17 | size -= processed; 18 | } 19 | return SZ_OK; 20 | } 21 | 22 | SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size) 23 | { 24 | return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); 25 | } 26 | 27 | SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf) 28 | { 29 | size_t processed = 1; 30 | RINOK(stream->Read(stream, buf, &processed)); 31 | return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; 32 | } 33 | 34 | SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset) 35 | { 36 | Int64 t = offset; 37 | return stream->Seek(stream, &t, SZ_SEEK_SET); 38 | } 39 | 40 | SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size) 41 | { 42 | const void *lookBuf; 43 | if (*size == 0) 44 | return SZ_OK; 45 | RINOK(stream->Look(stream, &lookBuf, size)); 46 | memcpy(buf, lookBuf, *size); 47 | return stream->Skip(stream, *size); 48 | } 49 | 50 | SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType) 51 | { 52 | while (size != 0) 53 | { 54 | size_t processed = size; 55 | RINOK(stream->Read(stream, buf, &processed)); 56 | if (processed == 0) 57 | return errorType; 58 | buf = (void *)((Byte *)buf + processed); 59 | size -= processed; 60 | } 61 | return SZ_OK; 62 | } 63 | 64 | SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size) 65 | { 66 | return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); 67 | } 68 | 69 | static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size) 70 | { 71 | SRes res = SZ_OK; 72 | CLookToRead *p = (CLookToRead *)pp; 73 | size_t size2 = p->size - p->pos; 74 | if (size2 == 0 && *size > 0) 75 | { 76 | p->pos = 0; 77 | size2 = LookToRead_BUF_SIZE; 78 | res = p->realStream->Read(p->realStream, p->buf, &size2); 79 | p->size = size2; 80 | } 81 | if (size2 < *size) 82 | *size = size2; 83 | *buf = p->buf + p->pos; 84 | return res; 85 | } 86 | 87 | static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size) 88 | { 89 | SRes res = SZ_OK; 90 | CLookToRead *p = (CLookToRead *)pp; 91 | size_t size2 = p->size - p->pos; 92 | if (size2 == 0 && *size > 0) 93 | { 94 | p->pos = 0; 95 | if (*size > LookToRead_BUF_SIZE) 96 | *size = LookToRead_BUF_SIZE; 97 | res = p->realStream->Read(p->realStream, p->buf, size); 98 | size2 = p->size = *size; 99 | } 100 | if (size2 < *size) 101 | *size = size2; 102 | *buf = p->buf + p->pos; 103 | return res; 104 | } 105 | 106 | static SRes LookToRead_Skip(void *pp, size_t offset) 107 | { 108 | CLookToRead *p = (CLookToRead *)pp; 109 | p->pos += offset; 110 | return SZ_OK; 111 | } 112 | 113 | static SRes LookToRead_Read(void *pp, void *buf, size_t *size) 114 | { 115 | CLookToRead *p = (CLookToRead *)pp; 116 | size_t rem = p->size - p->pos; 117 | if (rem == 0) 118 | return p->realStream->Read(p->realStream, buf, size); 119 | if (rem > *size) 120 | rem = *size; 121 | memcpy(buf, p->buf + p->pos, rem); 122 | p->pos += rem; 123 | *size = rem; 124 | return SZ_OK; 125 | } 126 | 127 | static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin) 128 | { 129 | CLookToRead *p = (CLookToRead *)pp; 130 | p->pos = p->size = 0; 131 | return p->realStream->Seek(p->realStream, pos, origin); 132 | } 133 | 134 | void LookToRead_CreateVTable(CLookToRead *p, int lookahead) 135 | { 136 | p->s.Look = lookahead ? 137 | LookToRead_Look_Lookahead : 138 | LookToRead_Look_Exact; 139 | p->s.Skip = LookToRead_Skip; 140 | p->s.Read = LookToRead_Read; 141 | p->s.Seek = LookToRead_Seek; 142 | } 143 | 144 | void LookToRead_Init(CLookToRead *p) 145 | { 146 | p->pos = p->size = 0; 147 | } 148 | 149 | static SRes SecToLook_Read(void *pp, void *buf, size_t *size) 150 | { 151 | CSecToLook *p = (CSecToLook *)pp; 152 | return LookInStream_LookRead(p->realStream, buf, size); 153 | } 154 | 155 | void SecToLook_CreateVTable(CSecToLook *p) 156 | { 157 | p->s.Read = SecToLook_Read; 158 | } 159 | 160 | static SRes SecToRead_Read(void *pp, void *buf, size_t *size) 161 | { 162 | CSecToRead *p = (CSecToRead *)pp; 163 | return p->realStream->Read(p->realStream, buf, size); 164 | } 165 | 166 | void SecToRead_CreateVTable(CSecToRead *p) 167 | { 168 | p->s.Read = SecToRead_Read; 169 | } 170 | -------------------------------------------------------------------------------- /Classes/LZMASDK/7zVersion.h: -------------------------------------------------------------------------------- 1 | #define MY_VER_MAJOR 9 2 | #define MY_VER_MINOR 22 3 | #define MY_VER_BUILD 00 4 | #define MY_VERSION "9.22 beta" 5 | #define MY_7ZIP_VERSION "9.22 beta" 6 | #define MY_DATE "2011-04-18" 7 | #define MY_COPYRIGHT ": Igor Pavlov : Public domain" 8 | #define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE 9 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Alloc.c: -------------------------------------------------------------------------------- 1 | /* Alloc.c -- Memory allocation functions 2 | 2008-09-24 3 | Igor Pavlov 4 | Public domain */ 5 | 6 | #ifdef _WIN32 7 | #include 8 | #endif 9 | #include 10 | 11 | #include "Alloc.h" 12 | 13 | /* #define _SZ_ALLOC_DEBUG */ 14 | 15 | /* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ 16 | #ifdef _SZ_ALLOC_DEBUG 17 | #include 18 | int g_allocCount = 0; 19 | int g_allocCountMid = 0; 20 | int g_allocCountBig = 0; 21 | #endif 22 | 23 | void *MyAlloc(size_t size) 24 | { 25 | if (size == 0) 26 | return 0; 27 | #ifdef _SZ_ALLOC_DEBUG 28 | { 29 | void *p = malloc(size); 30 | fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p); 31 | return p; 32 | } 33 | #else 34 | return malloc(size); 35 | #endif 36 | } 37 | 38 | void MyFree(void *address) 39 | { 40 | #ifdef _SZ_ALLOC_DEBUG 41 | if (address != 0) 42 | fprintf(stderr, "\nFree; count = %10d, addr = %8X", --g_allocCount, (unsigned)address); 43 | #endif 44 | free(address); 45 | } 46 | 47 | #ifdef _WIN32 48 | 49 | void *MidAlloc(size_t size) 50 | { 51 | if (size == 0) 52 | return 0; 53 | #ifdef _SZ_ALLOC_DEBUG 54 | fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++); 55 | #endif 56 | return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); 57 | } 58 | 59 | void MidFree(void *address) 60 | { 61 | #ifdef _SZ_ALLOC_DEBUG 62 | if (address != 0) 63 | fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid); 64 | #endif 65 | if (address == 0) 66 | return; 67 | VirtualFree(address, 0, MEM_RELEASE); 68 | } 69 | 70 | #ifndef MEM_LARGE_PAGES 71 | #undef _7ZIP_LARGE_PAGES 72 | #endif 73 | 74 | #ifdef _7ZIP_LARGE_PAGES 75 | SIZE_T g_LargePageSize = 0; 76 | typedef SIZE_T (WINAPI *GetLargePageMinimumP)(); 77 | #endif 78 | 79 | void SetLargePageSize() 80 | { 81 | #ifdef _7ZIP_LARGE_PAGES 82 | SIZE_T size = 0; 83 | GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP) 84 | GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum"); 85 | if (largePageMinimum == 0) 86 | return; 87 | size = largePageMinimum(); 88 | if (size == 0 || (size & (size - 1)) != 0) 89 | return; 90 | g_LargePageSize = size; 91 | #endif 92 | } 93 | 94 | 95 | void *BigAlloc(size_t size) 96 | { 97 | if (size == 0) 98 | return 0; 99 | #ifdef _SZ_ALLOC_DEBUG 100 | fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++); 101 | #endif 102 | 103 | #ifdef _7ZIP_LARGE_PAGES 104 | if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18)) 105 | { 106 | void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)), 107 | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); 108 | if (res != 0) 109 | return res; 110 | } 111 | #endif 112 | return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); 113 | } 114 | 115 | void BigFree(void *address) 116 | { 117 | #ifdef _SZ_ALLOC_DEBUG 118 | if (address != 0) 119 | fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig); 120 | #endif 121 | 122 | if (address == 0) 123 | return; 124 | VirtualFree(address, 0, MEM_RELEASE); 125 | } 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Alloc.h: -------------------------------------------------------------------------------- 1 | /* Alloc.h -- Memory allocation functions 2 | 2009-02-07 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __COMMON_ALLOC_H 5 | #define __COMMON_ALLOC_H 6 | 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | void *MyAlloc(size_t size); 14 | void MyFree(void *address); 15 | 16 | #ifdef _WIN32 17 | 18 | void SetLargePageSize(); 19 | 20 | void *MidAlloc(size_t size); 21 | void MidFree(void *address); 22 | void *BigAlloc(size_t size); 23 | void BigFree(void *address); 24 | 25 | #else 26 | 27 | #define MidAlloc(size) MyAlloc(size) 28 | #define MidFree(address) MyFree(address) 29 | #define BigAlloc(size) MyAlloc(size) 30 | #define BigFree(address) MyFree(address) 31 | 32 | #endif 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Classes/LZMASDK/CpuArch.c: -------------------------------------------------------------------------------- 1 | /* CpuArch.c -- CPU specific code 2 | 2009-12-12: Igor Pavlov : Public domain */ 3 | 4 | #pragma clang diagnostic ignored "-Wmissing-prototypes" 5 | 6 | #include "CpuArch.h" 7 | 8 | -------------------------------------------------------------------------------- /Classes/LZMASDK/CpuArch.h: -------------------------------------------------------------------------------- 1 | /* CpuArch.h -- CPU specific code 2 | 2010-12-01: Igor Pavlov : Public domain */ 3 | 4 | #ifndef __CPU_ARCH_H 5 | #define __CPU_ARCH_H 6 | 7 | #include "Types.h" 8 | 9 | EXTERN_C_BEGIN 10 | 11 | /* 12 | MY_CPU_LE means that CPU is LITTLE ENDIAN. 13 | If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). 14 | 15 | MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. 16 | If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. 17 | */ 18 | 19 | #if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) 20 | #define MY_CPU_AMD64 21 | #endif 22 | 23 | #if defined(MY_CPU_AMD64) || defined(_M_IA64) 24 | #define MY_CPU_64BIT 25 | #endif 26 | 27 | #if defined(_M_IX86) || defined(__i386__) 28 | #define MY_CPU_X86 29 | #endif 30 | 31 | #if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) 32 | #define MY_CPU_X86_OR_AMD64 33 | #endif 34 | 35 | #if defined(MY_CPU_X86) || defined(_M_ARM) 36 | #define MY_CPU_32BIT 37 | #endif 38 | 39 | #if defined(_WIN32) && defined(_M_ARM) 40 | #define MY_CPU_ARM_LE 41 | #endif 42 | 43 | #if defined(_WIN32) && defined(_M_IA64) 44 | #define MY_CPU_IA64_LE 45 | #endif 46 | 47 | #if defined(MY_CPU_X86_OR_AMD64) 48 | #define MY_CPU_LE_UNALIGN 49 | #endif 50 | 51 | #if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__) 52 | #define MY_CPU_LE 53 | #endif 54 | 55 | #if defined(__BIG_ENDIAN__) || defined(__m68k__) || defined(__ARMEB__) || defined(__MIPSEB__) 56 | #define MY_CPU_BE 57 | #endif 58 | 59 | #if defined(MY_CPU_LE) && defined(MY_CPU_BE) 60 | Stop_Compiling_Bad_Endian 61 | #endif 62 | 63 | #ifdef MY_CPU_LE_UNALIGN 64 | 65 | #define GetUi16(p) (*(const UInt16 *)(p)) 66 | #define GetUi32(p) (*(const UInt32 *)(p)) 67 | #define GetUi64(p) (*(const UInt64 *)(p)) 68 | #define SetUi16(p, d) *(UInt16 *)(p) = (d); 69 | #define SetUi32(p, d) *(UInt32 *)(p) = (d); 70 | #define SetUi64(p, d) *(UInt64 *)(p) = (d); 71 | 72 | #else 73 | 74 | #define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) 75 | 76 | #define GetUi32(p) ( \ 77 | ((const Byte *)(p))[0] | \ 78 | ((UInt32)((const Byte *)(p))[1] << 8) | \ 79 | ((UInt32)((const Byte *)(p))[2] << 16) | \ 80 | ((UInt32)((const Byte *)(p))[3] << 24)) 81 | 82 | #define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) 83 | 84 | #define SetUi16(p, d) { UInt32 _x_ = (d); \ 85 | ((Byte *)(p))[0] = (Byte)_x_; \ 86 | ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } 87 | 88 | #define SetUi32(p, d) { UInt32 _x_ = (d); \ 89 | ((Byte *)(p))[0] = (Byte)_x_; \ 90 | ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ 91 | ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ 92 | ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } 93 | 94 | #define SetUi64(p, d) { UInt64 _x64_ = (d); \ 95 | SetUi32(p, (UInt32)_x64_); \ 96 | SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); } 97 | 98 | #endif 99 | 100 | #if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) 101 | 102 | #pragma intrinsic(_byteswap_ulong) 103 | #pragma intrinsic(_byteswap_uint64) 104 | #define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) 105 | #define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) 106 | 107 | #else 108 | 109 | #define GetBe32(p) ( \ 110 | ((UInt32)((const Byte *)(p))[0] << 24) | \ 111 | ((UInt32)((const Byte *)(p))[1] << 16) | \ 112 | ((UInt32)((const Byte *)(p))[2] << 8) | \ 113 | ((const Byte *)(p))[3] ) 114 | 115 | #define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) 116 | 117 | #endif 118 | 119 | #define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1]) 120 | 121 | EXTERN_C_END 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Delta.c: -------------------------------------------------------------------------------- 1 | /* Delta.c -- Delta converter 2 | 2009-05-26 : Igor Pavlov : Public domain */ 3 | 4 | #include "Delta.h" 5 | 6 | void Delta_Init(Byte *state) 7 | { 8 | unsigned i; 9 | for (i = 0; i < DELTA_STATE_SIZE; i++) 10 | state[i] = 0; 11 | } 12 | 13 | static void MyMemCpy(Byte *dest, const Byte *src, unsigned size) 14 | { 15 | unsigned i; 16 | for (i = 0; i < size; i++) 17 | dest[i] = src[i]; 18 | } 19 | 20 | void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) 21 | { 22 | Byte buf[DELTA_STATE_SIZE]; 23 | unsigned j = 0; 24 | MyMemCpy(buf, state, delta); 25 | { 26 | SizeT i; 27 | for (i = 0; i < size;) 28 | { 29 | for (j = 0; j < delta && i < size; i++, j++) 30 | { 31 | Byte b = data[i]; 32 | data[i] = (Byte)(b - buf[j]); 33 | buf[j] = b; 34 | } 35 | } 36 | } 37 | if (j == delta) 38 | j = 0; 39 | MyMemCpy(state, buf + j, delta - j); 40 | MyMemCpy(state + delta - j, buf, j); 41 | } 42 | 43 | void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) 44 | { 45 | Byte buf[DELTA_STATE_SIZE]; 46 | unsigned j = 0; 47 | MyMemCpy(buf, state, delta); 48 | { 49 | SizeT i; 50 | for (i = 0; i < size;) 51 | { 52 | for (j = 0; j < delta && i < size; i++, j++) 53 | { 54 | buf[j] = data[i] = (Byte)(buf[j] + data[i]); 55 | } 56 | } 57 | } 58 | if (j == delta) 59 | j = 0; 60 | MyMemCpy(state, buf + j, delta - j); 61 | MyMemCpy(state + delta - j, buf, j); 62 | } 63 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Delta.h: -------------------------------------------------------------------------------- 1 | /* Delta.h -- Delta converter 2 | 2009-04-15 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __DELTA_H 5 | #define __DELTA_H 6 | 7 | #include "Types.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #define DELTA_STATE_SIZE 256 14 | 15 | void Delta_Init(Byte *state); 16 | void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); 17 | void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /Classes/LZMASDK/LZMAExtractor.h: -------------------------------------------------------------------------------- 1 | // 2 | // LZMAExtractor.h 3 | // lzmaSDK 4 | // 5 | // Created by Brian Chaikelson on 11/19/09. 6 | // Copyright 2009 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LZMAExtractor : NSObject { 12 | } 13 | 14 | // Extract all the contents of a .7z archive directly into the indicated dir. 15 | // Directory structure is ignored if preserveDir is false. 16 | 17 | + (NSArray*) extract7zArchive:(NSString*)archivePath 18 | dirName:(NSString*)dirName 19 | preserveDir:(BOOL)preserveDir; 20 | 21 | // Extract all the contents of a .7z archive into the indicated temp dir 22 | // and return an array of the fully qualified filenames. This API 23 | // implicitly passes preserveDir as FALSE, so directory elements in the 24 | // entry name are always ignored as files are extracted. If multiple 25 | // entries have duplicated filenames in different directories, then 26 | // this API would would overwrite the duplicate entry file. 27 | 28 | + (NSArray*) extract7zArchive:(NSString*)archivePath 29 | tmpDirName:(NSString*)tmpDirName; 30 | 31 | // Extract just one entry from an archive and save it at the 32 | // path indicated by outPath. 33 | 34 | + (BOOL) extractArchiveEntry:(NSString*)archivePath 35 | archiveEntry:(NSString*)archiveEntry 36 | outPath:(NSString*)outPath; 37 | 38 | @end 39 | 40 | -------------------------------------------------------------------------------- /Classes/LZMASDK/LZMAExtractor.m: -------------------------------------------------------------------------------- 1 | // 2 | // LZMAExtractor.m 3 | // lzmaSDK 4 | // 5 | // Created by Mo DeJong on 11/19/09. 6 | // Copyright 2009 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "LZMAExtractor.h" 10 | 11 | int do7z_extract_entry(char *archivePath, char *archiveCachePath, char *threadCwd, char *entryName, char *entryPath, int fullPaths); 12 | 13 | @implementation LZMAExtractor 14 | 15 | // Return a fully qualified random filename in the tmp dir. The filename is based on the 16 | // exact time offset since 1970 so it should be unique. 17 | 18 | + (NSString*) generateUniqueTmpCachePath 19 | { 20 | NSString *tmpDir = NSTemporaryDirectory(); 21 | 22 | NSDate *nowDate = [NSDate date]; 23 | NSTimeInterval ti = [nowDate timeIntervalSinceReferenceDate]; 24 | 25 | // Format number of seconds as a string with a decimal separator 26 | NSString *doubleString = [NSString stringWithFormat:@"%f", ti]; 27 | 28 | // Remove the decimal point so that the file name consists of 29 | // numeric characters only. 30 | 31 | NSRange range; 32 | range = NSMakeRange(0, [doubleString length]); 33 | NSString *noDecimalString = [doubleString stringByReplacingOccurrencesOfString:@"." 34 | withString:@"" 35 | options:0 36 | range:range]; 37 | 38 | range = NSMakeRange(0, [noDecimalString length]); 39 | NSString *noMinusString = [noDecimalString stringByReplacingOccurrencesOfString:@"-" 40 | withString:@"" 41 | options:0 42 | range:range]; 43 | 44 | NSString *filename = [NSString stringWithFormat:@"%@%@", noMinusString, @".cache"]; 45 | 46 | NSString *tmpPath = [tmpDir stringByAppendingPathComponent:filename]; 47 | 48 | return tmpPath; 49 | } 50 | 51 | // Recurse into directories to determine the full paths of elements extracted 52 | // from a archive. 53 | 54 | + (void) recurseIntoDirectories:(NSMutableArray*)fullPathContents 55 | dirName:(NSString*)dirName 56 | entryPrefix:(NSString*)entryPrefix 57 | { 58 | NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dirName error:nil]; 59 | NSAssert(contents, @"contentsOfDirectoryAtPath failed"); 60 | 61 | for (NSString *path in contents) { 62 | //NSLog(@"found dir path: %@", path); 63 | NSString *fullPath = [dirName stringByAppendingPathComponent:path]; 64 | //NSLog(@"found full path: %@", fullPath); 65 | 66 | BOOL isDirectory = FALSE; 67 | BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDirectory]; 68 | assert(exists); 69 | 70 | NSString *combinedEntryPrefix; 71 | if ([entryPrefix length] == 0) { 72 | combinedEntryPrefix = path; 73 | } else { 74 | combinedEntryPrefix = [NSString stringWithFormat:@"%@/%@", entryPrefix, path]; 75 | } 76 | 77 | //NSLog(@"found entry path: %@", combinedEntryPrefix); 78 | 79 | if (isDirectory) { 80 | // Recurse into this directory and add the files in the directory 81 | 82 | [self recurseIntoDirectories:fullPathContents dirName:fullPath entryPrefix:combinedEntryPrefix]; 83 | } else { 84 | // A plain file path, append the entry name portion of the path. 85 | 86 | [fullPathContents addObject:fullPath]; 87 | } 88 | } 89 | 90 | return; 91 | } 92 | 93 | // Extract all the contents of a .7z archive directly into the indicated dir 94 | 95 | + (NSArray*) extract7zArchive:(NSString*)archivePath 96 | dirName:(NSString*)dirName 97 | preserveDir:(BOOL)preserveDir 98 | { 99 | NSAssert(archivePath, @"archivePath"); 100 | NSAssert(dirName, @"dirName"); 101 | 102 | BOOL worked, isDir, existsAlready; 103 | 104 | NSString *myTmpDir = dirName; 105 | existsAlready = [[NSFileManager defaultManager] fileExistsAtPath:myTmpDir isDirectory:&isDir]; 106 | 107 | if (existsAlready && !isDir) { 108 | worked = [[NSFileManager defaultManager] removeItemAtPath:myTmpDir error:nil]; 109 | NSAssert(worked, @"could not remove existing file with same name as tmp dir"); 110 | // create the directory below 111 | } 112 | 113 | if (existsAlready && isDir) { 114 | // Remove all the files in the named tmp dir 115 | NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:myTmpDir error:nil]; 116 | NSAssert(contents, @"contentsOfDirectoryAtPath failed"); 117 | for (NSString *path in contents) { 118 | NSLog(@"found existing dir path: %@", path); 119 | NSString *myTmpDirPath = [myTmpDir stringByAppendingPathComponent:path]; 120 | worked = [[NSFileManager defaultManager] removeItemAtPath:myTmpDirPath error:nil]; 121 | NSAssert(worked, @"could not remove existing file"); 122 | } 123 | } else { 124 | worked = [[NSFileManager defaultManager] createDirectoryAtPath:myTmpDir withIntermediateDirectories:YES attributes:nil error:nil]; 125 | NSAssert(worked, @"could not create tmp dir"); 126 | } 127 | 128 | // Create dir str that has a '/' character at the end so that strcat() can be used to 129 | // create a path string without using Cocoa path join logic. 130 | 131 | NSMutableString *dirQualMStr = [NSMutableString stringWithString:dirName]; 132 | if ([dirQualMStr hasSuffix:@"/"] == FALSE) { 133 | [dirQualMStr appendString:@"/"]; 134 | } 135 | 136 | char *archivePathPtr = (char*) [archivePath UTF8String]; 137 | NSString *archiveCachePath = [self generateUniqueTmpCachePath]; 138 | char *archiveCachePathPtr = (char*) [archiveCachePath UTF8String]; 139 | char *threadCwd = (char*) [dirQualMStr UTF8String]; 140 | char *entryNamePtr = NULL; // Extract all entries by passing NULL 141 | char *entryPathPtr = NULL; 142 | 143 | int result = do7z_extract_entry(archivePathPtr, archiveCachePathPtr, threadCwd, entryNamePtr, entryPathPtr, preserveDir ? 1 : 0); 144 | NSAssert(result == 0, @"could not extract files from 7z archive"); 145 | 146 | // Examine the contents of the current directory to see what was extracted 147 | 148 | NSMutableArray *fullPathContents = [NSMutableArray array]; 149 | 150 | [self recurseIntoDirectories:fullPathContents dirName:myTmpDir entryPrefix:@""]; 151 | 152 | return [NSArray arrayWithArray:fullPathContents]; 153 | } 154 | 155 | // Extract all the contents of a .7z archive into the indicated temp dir 156 | // and return an array of the fully qualified filenames. 157 | 158 | + (NSArray*) extract7zArchive:(NSString*)archivePath 159 | tmpDirName:(NSString*)tmpDirName 160 | { 161 | NSAssert(archivePath, @"archivePath"); 162 | NSAssert(tmpDirName, @"tmpDirName"); 163 | NSString *tmpDir = NSTemporaryDirectory(); 164 | NSString *fullTmpDir = [tmpDir stringByAppendingPathComponent:tmpDirName]; 165 | return [self extract7zArchive:archivePath dirName:fullTmpDir preserveDir:FALSE]; 166 | } 167 | 168 | // Extract just one entry from an archive and save it at the 169 | // path indicated by outPath. 170 | 171 | + (BOOL) extractArchiveEntry:(NSString*)archivePath 172 | archiveEntry:(NSString*)archiveEntry 173 | outPath:(NSString*)outPath 174 | { 175 | NSAssert(archivePath, @"archivePath"); 176 | NSAssert(archiveEntry, @"archiveEntry"); 177 | NSAssert(outPath, @"outPath"); 178 | 179 | char *archivePathPtr = (char*) [archivePath UTF8String]; 180 | NSString *archiveCachePath = [self generateUniqueTmpCachePath]; 181 | char *archiveCachePathPtr = (char*) [archiveCachePath UTF8String]; 182 | char *archiveEntryPtr = (char*) [archiveEntry UTF8String]; 183 | char *outPathPtr = (char*) [outPath UTF8String]; 184 | 185 | int result = do7z_extract_entry(archivePathPtr, archiveCachePathPtr, NULL, archiveEntryPtr, outPathPtr, 0); 186 | return (result == 0); 187 | } 188 | 189 | @end 190 | -------------------------------------------------------------------------------- /Classes/LZMASDK/LzHash.h: -------------------------------------------------------------------------------- 1 | /* LzHash.h -- HASH functions for LZ algorithms 2 | 2009-02-07 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __LZ_HASH_H 5 | #define __LZ_HASH_H 6 | 7 | #define kHash2Size (1 << 10) 8 | #define kHash3Size (1 << 16) 9 | #define kHash4Size (1 << 20) 10 | 11 | #define kFix3HashSize (kHash2Size) 12 | #define kFix4HashSize (kHash2Size + kHash3Size) 13 | #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) 14 | 15 | #define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); 16 | 17 | #define HASH3_CALC { \ 18 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ 19 | hash2Value = temp & (kHash2Size - 1); \ 20 | hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } 21 | 22 | #define HASH4_CALC { \ 23 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ 24 | hash2Value = temp & (kHash2Size - 1); \ 25 | hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ 26 | hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } 27 | 28 | #define HASH5_CALC { \ 29 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ 30 | hash2Value = temp & (kHash2Size - 1); \ 31 | hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ 32 | hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ 33 | hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ 34 | hash4Value &= (kHash4Size - 1); } 35 | 36 | /* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ 37 | #define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; 38 | 39 | 40 | #define MT_HASH2_CALC \ 41 | hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); 42 | 43 | #define MT_HASH3_CALC { \ 44 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ 45 | hash2Value = temp & (kHash2Size - 1); \ 46 | hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } 47 | 48 | #define MT_HASH4_CALC { \ 49 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ 50 | hash2Value = temp & (kHash2Size - 1); \ 51 | hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ 52 | hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Lzma2Dec.c: -------------------------------------------------------------------------------- 1 | /* Lzma2Dec.c -- LZMA2 Decoder 2 | 2010-12-15 : Igor Pavlov : Public domain */ 3 | 4 | /* #define SHOW_DEBUG_INFO */ 5 | 6 | #ifdef SHOW_DEBUG_INFO 7 | #include 8 | #endif 9 | 10 | #include 11 | 12 | #include "Lzma2Dec.h" 13 | 14 | /* 15 | 00000000 - EOS 16 | 00000001 U U - Uncompressed Reset Dic 17 | 00000010 U U - Uncompressed No Reset 18 | 100uuuuu U U P P - LZMA no reset 19 | 101uuuuu U U P P - LZMA reset state 20 | 110uuuuu U U P P S - LZMA reset state + new prop 21 | 111uuuuu U U P P S - LZMA reset state + new prop + reset dic 22 | 23 | u, U - Unpack Size 24 | P - Pack Size 25 | S - Props 26 | */ 27 | 28 | #define LZMA2_CONTROL_LZMA (1 << 7) 29 | #define LZMA2_CONTROL_COPY_NO_RESET 2 30 | #define LZMA2_CONTROL_COPY_RESET_DIC 1 31 | #define LZMA2_CONTROL_EOF 0 32 | 33 | #define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0) 34 | 35 | #define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3) 36 | #define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2) 37 | 38 | #define LZMA2_LCLP_MAX 4 39 | #define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) 40 | 41 | #ifdef SHOW_DEBUG_INFO 42 | #define PRF(x) x 43 | #else 44 | #define PRF(x) 45 | #endif 46 | 47 | typedef enum 48 | { 49 | LZMA2_STATE_CONTROL, 50 | LZMA2_STATE_UNPACK0, 51 | LZMA2_STATE_UNPACK1, 52 | LZMA2_STATE_PACK0, 53 | LZMA2_STATE_PACK1, 54 | LZMA2_STATE_PROP, 55 | LZMA2_STATE_DATA, 56 | LZMA2_STATE_DATA_CONT, 57 | LZMA2_STATE_FINISHED, 58 | LZMA2_STATE_ERROR 59 | } ELzma2State; 60 | 61 | static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) 62 | { 63 | UInt32 dicSize; 64 | if (prop > 40) 65 | return SZ_ERROR_UNSUPPORTED; 66 | dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); 67 | props[0] = (Byte)LZMA2_LCLP_MAX; 68 | props[1] = (Byte)(dicSize); 69 | props[2] = (Byte)(dicSize >> 8); 70 | props[3] = (Byte)(dicSize >> 16); 71 | props[4] = (Byte)(dicSize >> 24); 72 | return SZ_OK; 73 | } 74 | 75 | SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) 76 | { 77 | Byte props[LZMA_PROPS_SIZE]; 78 | RINOK(Lzma2Dec_GetOldProps(prop, props)); 79 | return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); 80 | } 81 | 82 | SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) 83 | { 84 | Byte props[LZMA_PROPS_SIZE]; 85 | RINOK(Lzma2Dec_GetOldProps(prop, props)); 86 | return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); 87 | } 88 | 89 | void Lzma2Dec_Init(CLzma2Dec *p) 90 | { 91 | p->state = LZMA2_STATE_CONTROL; 92 | p->needInitDic = True; 93 | p->needInitState = True; 94 | p->needInitProp = True; 95 | LzmaDec_Init(&p->decoder); 96 | } 97 | 98 | static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) 99 | { 100 | switch(p->state) 101 | { 102 | case LZMA2_STATE_CONTROL: 103 | p->control = b; 104 | PRF(printf("\n %4X ", p->decoder.dicPos)); 105 | PRF(printf(" %2X", b)); 106 | if (p->control == 0) 107 | return LZMA2_STATE_FINISHED; 108 | if (LZMA2_IS_UNCOMPRESSED_STATE(p)) 109 | { 110 | if ((p->control & 0x7F) > 2) 111 | return LZMA2_STATE_ERROR; 112 | p->unpackSize = 0; 113 | } 114 | else 115 | p->unpackSize = (UInt32)(p->control & 0x1F) << 16; 116 | return LZMA2_STATE_UNPACK0; 117 | 118 | case LZMA2_STATE_UNPACK0: 119 | p->unpackSize |= (UInt32)b << 8; 120 | return LZMA2_STATE_UNPACK1; 121 | 122 | case LZMA2_STATE_UNPACK1: 123 | p->unpackSize |= (UInt32)b; 124 | p->unpackSize++; 125 | PRF(printf(" %8d", p->unpackSize)); 126 | return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; 127 | 128 | case LZMA2_STATE_PACK0: 129 | p->packSize = (UInt32)b << 8; 130 | return LZMA2_STATE_PACK1; 131 | 132 | case LZMA2_STATE_PACK1: 133 | p->packSize |= (UInt32)b; 134 | p->packSize++; 135 | PRF(printf(" %8d", p->packSize)); 136 | return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: 137 | (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); 138 | 139 | case LZMA2_STATE_PROP: 140 | { 141 | int lc, lp; 142 | if (b >= (9 * 5 * 5)) 143 | return LZMA2_STATE_ERROR; 144 | lc = b % 9; 145 | b /= 9; 146 | p->decoder.prop.pb = b / 5; 147 | lp = b % 5; 148 | if (lc + lp > LZMA2_LCLP_MAX) 149 | return LZMA2_STATE_ERROR; 150 | p->decoder.prop.lc = lc; 151 | p->decoder.prop.lp = lp; 152 | p->needInitProp = False; 153 | return LZMA2_STATE_DATA; 154 | } 155 | } 156 | return LZMA2_STATE_ERROR; 157 | } 158 | 159 | static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) 160 | { 161 | memcpy(p->dic + p->dicPos, src, size); 162 | p->dicPos += size; 163 | if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) 164 | p->checkDicSize = p->prop.dicSize; 165 | p->processedPos += (UInt32)size; 166 | } 167 | 168 | void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState); 169 | 170 | SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, 171 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) 172 | { 173 | SizeT inSize = *srcLen; 174 | *srcLen = 0; 175 | *status = LZMA_STATUS_NOT_SPECIFIED; 176 | 177 | while (p->state != LZMA2_STATE_FINISHED) 178 | { 179 | SizeT dicPos = p->decoder.dicPos; 180 | if (p->state == LZMA2_STATE_ERROR) 181 | return SZ_ERROR_DATA; 182 | if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) 183 | { 184 | *status = LZMA_STATUS_NOT_FINISHED; 185 | return SZ_OK; 186 | } 187 | if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) 188 | { 189 | if (*srcLen == inSize) 190 | { 191 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; 192 | return SZ_OK; 193 | } 194 | (*srcLen)++; 195 | p->state = Lzma2Dec_UpdateState(p, *src++); 196 | continue; 197 | } 198 | { 199 | SizeT destSizeCur = dicLimit - dicPos; 200 | SizeT srcSizeCur = inSize - *srcLen; 201 | ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; 202 | 203 | if (p->unpackSize <= destSizeCur) 204 | { 205 | destSizeCur = (SizeT)p->unpackSize; 206 | curFinishMode = LZMA_FINISH_END; 207 | } 208 | 209 | if (LZMA2_IS_UNCOMPRESSED_STATE(p)) 210 | { 211 | if (*srcLen == inSize) 212 | { 213 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; 214 | return SZ_OK; 215 | } 216 | 217 | if (p->state == LZMA2_STATE_DATA) 218 | { 219 | Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); 220 | if (initDic) 221 | p->needInitProp = p->needInitState = True; 222 | else if (p->needInitDic) 223 | return SZ_ERROR_DATA; 224 | p->needInitDic = False; 225 | LzmaDec_InitDicAndState(&p->decoder, initDic, False); 226 | } 227 | 228 | if (srcSizeCur > destSizeCur) 229 | srcSizeCur = destSizeCur; 230 | 231 | if (srcSizeCur == 0) 232 | return SZ_ERROR_DATA; 233 | 234 | LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); 235 | 236 | src += srcSizeCur; 237 | *srcLen += srcSizeCur; 238 | p->unpackSize -= (UInt32)srcSizeCur; 239 | p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; 240 | } 241 | else 242 | { 243 | SizeT outSizeProcessed; 244 | SRes res; 245 | 246 | if (p->state == LZMA2_STATE_DATA) 247 | { 248 | int mode = LZMA2_GET_LZMA_MODE(p); 249 | Bool initDic = (mode == 3); 250 | Bool initState = (mode > 0); 251 | if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) 252 | return SZ_ERROR_DATA; 253 | 254 | LzmaDec_InitDicAndState(&p->decoder, initDic, initState); 255 | p->needInitDic = False; 256 | p->needInitState = False; 257 | p->state = LZMA2_STATE_DATA_CONT; 258 | } 259 | if (srcSizeCur > p->packSize) 260 | srcSizeCur = (SizeT)p->packSize; 261 | 262 | res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status); 263 | 264 | src += srcSizeCur; 265 | *srcLen += srcSizeCur; 266 | p->packSize -= (UInt32)srcSizeCur; 267 | 268 | outSizeProcessed = p->decoder.dicPos - dicPos; 269 | p->unpackSize -= (UInt32)outSizeProcessed; 270 | 271 | RINOK(res); 272 | if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) 273 | return res; 274 | 275 | if (srcSizeCur == 0 && outSizeProcessed == 0) 276 | { 277 | if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || 278 | p->unpackSize != 0 || p->packSize != 0) 279 | return SZ_ERROR_DATA; 280 | p->state = LZMA2_STATE_CONTROL; 281 | } 282 | if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) 283 | *status = LZMA_STATUS_NOT_FINISHED; 284 | } 285 | } 286 | } 287 | *status = LZMA_STATUS_FINISHED_WITH_MARK; 288 | return SZ_OK; 289 | } 290 | 291 | SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) 292 | { 293 | SizeT outSize = *destLen, inSize = *srcLen; 294 | *srcLen = *destLen = 0; 295 | for (;;) 296 | { 297 | SizeT srcSizeCur = inSize, outSizeCur, dicPos; 298 | ELzmaFinishMode curFinishMode; 299 | SRes res; 300 | if (p->decoder.dicPos == p->decoder.dicBufSize) 301 | p->decoder.dicPos = 0; 302 | dicPos = p->decoder.dicPos; 303 | if (outSize > p->decoder.dicBufSize - dicPos) 304 | { 305 | outSizeCur = p->decoder.dicBufSize; 306 | curFinishMode = LZMA_FINISH_ANY; 307 | } 308 | else 309 | { 310 | outSizeCur = dicPos + outSize; 311 | curFinishMode = finishMode; 312 | } 313 | 314 | res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status); 315 | src += srcSizeCur; 316 | inSize -= srcSizeCur; 317 | *srcLen += srcSizeCur; 318 | outSizeCur = p->decoder.dicPos - dicPos; 319 | memcpy(dest, p->decoder.dic + dicPos, outSizeCur); 320 | dest += outSizeCur; 321 | outSize -= outSizeCur; 322 | *destLen += outSizeCur; 323 | if (res != 0) 324 | return res; 325 | if (outSizeCur == 0 || outSize == 0) 326 | return SZ_OK; 327 | } 328 | } 329 | 330 | SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, 331 | Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) 332 | { 333 | CLzma2Dec p; 334 | SRes res; 335 | SizeT outSize = *destLen, inSize = *srcLen; 336 | *destLen = *srcLen = 0; 337 | *status = LZMA_STATUS_NOT_SPECIFIED; 338 | Lzma2Dec_Construct(&p); 339 | RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)); 340 | p.decoder.dic = dest; 341 | p.decoder.dicBufSize = outSize; 342 | Lzma2Dec_Init(&p); 343 | *srcLen = inSize; 344 | res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); 345 | *destLen = p.decoder.dicPos; 346 | if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) 347 | res = SZ_ERROR_INPUT_EOF; 348 | Lzma2Dec_FreeProbs(&p, alloc); 349 | return res; 350 | } 351 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Lzma2Dec.h: -------------------------------------------------------------------------------- 1 | /* Lzma2Dec.h -- LZMA2 Decoder 2 | 2009-05-03 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __LZMA2_DEC_H 5 | #define __LZMA2_DEC_H 6 | 7 | #include "LzmaDec.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /* ---------- State Interface ---------- */ 14 | 15 | typedef struct 16 | { 17 | CLzmaDec decoder; 18 | UInt32 packSize; 19 | UInt32 unpackSize; 20 | int state; 21 | Byte control; 22 | Bool needInitDic; 23 | Bool needInitState; 24 | Bool needInitProp; 25 | } CLzma2Dec; 26 | 27 | #define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) 28 | #define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc); 29 | #define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc); 30 | 31 | SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); 32 | SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); 33 | void Lzma2Dec_Init(CLzma2Dec *p); 34 | 35 | 36 | /* 37 | finishMode: 38 | It has meaning only if the decoding reaches output limit (*destLen or dicLimit). 39 | LZMA_FINISH_ANY - use smallest number of input bytes 40 | LZMA_FINISH_END - read EndOfStream marker after decoding 41 | 42 | Returns: 43 | SZ_OK 44 | status: 45 | LZMA_STATUS_FINISHED_WITH_MARK 46 | LZMA_STATUS_NOT_FINISHED 47 | LZMA_STATUS_NEEDS_MORE_INPUT 48 | SZ_ERROR_DATA - Data error 49 | */ 50 | 51 | SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, 52 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); 53 | 54 | SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, 55 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); 56 | 57 | 58 | /* ---------- One Call Interface ---------- */ 59 | 60 | /* 61 | finishMode: 62 | It has meaning only if the decoding reaches output limit (*destLen). 63 | LZMA_FINISH_ANY - use smallest number of input bytes 64 | LZMA_FINISH_END - read EndOfStream marker after decoding 65 | 66 | Returns: 67 | SZ_OK 68 | status: 69 | LZMA_STATUS_FINISHED_WITH_MARK 70 | LZMA_STATUS_NOT_FINISHED 71 | SZ_ERROR_DATA - Data error 72 | SZ_ERROR_MEM - Memory allocation error 73 | SZ_ERROR_UNSUPPORTED - Unsupported properties 74 | SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). 75 | */ 76 | 77 | SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, 78 | Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /Classes/LZMASDK/LzmaDec.h: -------------------------------------------------------------------------------- 1 | /* LzmaDec.h -- LZMA Decoder 2 | 2009-02-07 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __LZMA_DEC_H 5 | #define __LZMA_DEC_H 6 | 7 | #include "Types.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /* #define _LZMA_PROB32 */ 14 | /* _LZMA_PROB32 can increase the speed on some CPUs, 15 | but memory usage for CLzmaDec::probs will be doubled in that case */ 16 | 17 | #ifdef _LZMA_PROB32 18 | #define CLzmaProb UInt32 19 | #else 20 | #define CLzmaProb UInt16 21 | #endif 22 | 23 | 24 | /* ---------- LZMA Properties ---------- */ 25 | 26 | #define LZMA_PROPS_SIZE 5 27 | 28 | typedef struct _CLzmaProps 29 | { 30 | unsigned lc, lp, pb; 31 | UInt32 dicSize; 32 | } CLzmaProps; 33 | 34 | /* LzmaProps_Decode - decodes properties 35 | Returns: 36 | SZ_OK 37 | SZ_ERROR_UNSUPPORTED - Unsupported properties 38 | */ 39 | 40 | SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); 41 | 42 | 43 | /* ---------- LZMA Decoder state ---------- */ 44 | 45 | /* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. 46 | Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ 47 | 48 | #define LZMA_REQUIRED_INPUT_MAX 20 49 | 50 | typedef struct 51 | { 52 | CLzmaProps prop; 53 | CLzmaProb *probs; 54 | Byte *dic; 55 | const Byte *buf; 56 | UInt32 range, code; 57 | SizeT dicPos; 58 | SizeT dicBufSize; 59 | UInt32 processedPos; 60 | UInt32 checkDicSize; 61 | unsigned state; 62 | UInt32 reps[4]; 63 | unsigned remainLen; 64 | int needFlush; 65 | int needInitState; 66 | UInt32 numProbs; 67 | unsigned tempBufSize; 68 | Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; 69 | } CLzmaDec; 70 | 71 | #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } 72 | 73 | void LzmaDec_Init(CLzmaDec *p); 74 | 75 | /* There are two types of LZMA streams: 76 | 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. 77 | 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ 78 | 79 | typedef enum 80 | { 81 | LZMA_FINISH_ANY, /* finish at any point */ 82 | LZMA_FINISH_END /* block must be finished at the end */ 83 | } ELzmaFinishMode; 84 | 85 | /* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! 86 | 87 | You must use LZMA_FINISH_END, when you know that current output buffer 88 | covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. 89 | 90 | If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, 91 | and output value of destLen will be less than output buffer size limit. 92 | You can check status result also. 93 | 94 | You can use multiple checks to test data integrity after full decompression: 95 | 1) Check Result and "status" variable. 96 | 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. 97 | 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. 98 | You must use correct finish mode in that case. */ 99 | 100 | typedef enum 101 | { 102 | LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ 103 | LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ 104 | LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ 105 | LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ 106 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ 107 | } ELzmaStatus; 108 | 109 | /* ELzmaStatus is used only as output value for function call */ 110 | 111 | 112 | /* ---------- Interfaces ---------- */ 113 | 114 | /* There are 3 levels of interfaces: 115 | 1) Dictionary Interface 116 | 2) Buffer Interface 117 | 3) One Call Interface 118 | You can select any of these interfaces, but don't mix functions from different 119 | groups for same object. */ 120 | 121 | 122 | /* There are two variants to allocate state for Dictionary Interface: 123 | 1) LzmaDec_Allocate / LzmaDec_Free 124 | 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs 125 | You can use variant 2, if you set dictionary buffer manually. 126 | For Buffer Interface you must always use variant 1. 127 | 128 | LzmaDec_Allocate* can return: 129 | SZ_OK 130 | SZ_ERROR_MEM - Memory allocation error 131 | SZ_ERROR_UNSUPPORTED - Unsupported properties 132 | */ 133 | 134 | SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); 135 | void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); 136 | 137 | SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); 138 | void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); 139 | 140 | /* ---------- Dictionary Interface ---------- */ 141 | 142 | /* You can use it, if you want to eliminate the overhead for data copying from 143 | dictionary to some other external buffer. 144 | You must work with CLzmaDec variables directly in this interface. 145 | 146 | STEPS: 147 | LzmaDec_Constr() 148 | LzmaDec_Allocate() 149 | for (each new stream) 150 | { 151 | LzmaDec_Init() 152 | while (it needs more decompression) 153 | { 154 | LzmaDec_DecodeToDic() 155 | use data from CLzmaDec::dic and update CLzmaDec::dicPos 156 | } 157 | } 158 | LzmaDec_Free() 159 | */ 160 | 161 | /* LzmaDec_DecodeToDic 162 | 163 | The decoding to internal dictionary buffer (CLzmaDec::dic). 164 | You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! 165 | 166 | finishMode: 167 | It has meaning only if the decoding reaches output limit (dicLimit). 168 | LZMA_FINISH_ANY - Decode just dicLimit bytes. 169 | LZMA_FINISH_END - Stream must be finished after dicLimit. 170 | 171 | Returns: 172 | SZ_OK 173 | status: 174 | LZMA_STATUS_FINISHED_WITH_MARK 175 | LZMA_STATUS_NOT_FINISHED 176 | LZMA_STATUS_NEEDS_MORE_INPUT 177 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK 178 | SZ_ERROR_DATA - Data error 179 | */ 180 | 181 | SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, 182 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); 183 | 184 | 185 | /* ---------- Buffer Interface ---------- */ 186 | 187 | /* It's zlib-like interface. 188 | See LzmaDec_DecodeToDic description for information about STEPS and return results, 189 | but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need 190 | to work with CLzmaDec variables manually. 191 | 192 | finishMode: 193 | It has meaning only if the decoding reaches output limit (*destLen). 194 | LZMA_FINISH_ANY - Decode just destLen bytes. 195 | LZMA_FINISH_END - Stream must be finished after (*destLen). 196 | */ 197 | 198 | SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, 199 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); 200 | 201 | 202 | /* ---------- One Call Interface ---------- */ 203 | 204 | /* LzmaDecode 205 | 206 | finishMode: 207 | It has meaning only if the decoding reaches output limit (*destLen). 208 | LZMA_FINISH_ANY - Decode just destLen bytes. 209 | LZMA_FINISH_END - Stream must be finished after (*destLen). 210 | 211 | Returns: 212 | SZ_OK 213 | status: 214 | LZMA_STATUS_FINISHED_WITH_MARK 215 | LZMA_STATUS_NOT_FINISHED 216 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK 217 | SZ_ERROR_DATA - Data error 218 | SZ_ERROR_MEM - Memory allocation error 219 | SZ_ERROR_UNSUPPORTED - Unsupported properties 220 | SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). 221 | */ 222 | 223 | SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, 224 | const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 225 | ELzmaStatus *status, ISzAlloc *alloc); 226 | 227 | #ifdef __cplusplus 228 | } 229 | #endif 230 | 231 | #endif 232 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Ppmd.h: -------------------------------------------------------------------------------- 1 | /* Ppmd.h -- PPMD codec common code 2 | 2011-01-27 : Igor Pavlov : Public domain 3 | This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ 4 | 5 | #ifndef __PPMD_H 6 | #define __PPMD_H 7 | 8 | #include "Types.h" 9 | #include "CpuArch.h" 10 | 11 | EXTERN_C_BEGIN 12 | 13 | #ifdef MY_CPU_32BIT 14 | #define PPMD_32BIT 15 | #endif 16 | 17 | #define PPMD_INT_BITS 7 18 | #define PPMD_PERIOD_BITS 7 19 | #define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) 20 | 21 | #define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) 22 | #define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) 23 | #define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) 24 | #define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) 25 | 26 | #define PPMD_N1 4 27 | #define PPMD_N2 4 28 | #define PPMD_N3 4 29 | #define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) 30 | #define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) 31 | 32 | #pragma pack(push, 1) 33 | /* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ 34 | 35 | /* SEE-contexts for PPM-contexts with masked symbols */ 36 | typedef struct 37 | { 38 | UInt16 Summ; /* Freq */ 39 | Byte Shift; /* Speed of Freq change; low Shift is for fast change */ 40 | Byte Count; /* Count to next change of Shift */ 41 | } CPpmd_See; 42 | 43 | #define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ 44 | { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } 45 | 46 | typedef struct 47 | { 48 | Byte Symbol; 49 | Byte Freq; 50 | UInt16 SuccessorLow; 51 | UInt16 SuccessorHigh; 52 | } CPpmd_State; 53 | 54 | #pragma pack(pop) 55 | 56 | typedef 57 | #ifdef PPMD_32BIT 58 | CPpmd_State * 59 | #else 60 | UInt32 61 | #endif 62 | CPpmd_State_Ref; 63 | 64 | typedef 65 | #ifdef PPMD_32BIT 66 | void * 67 | #else 68 | UInt32 69 | #endif 70 | CPpmd_Void_Ref; 71 | 72 | typedef 73 | #ifdef PPMD_32BIT 74 | Byte * 75 | #else 76 | UInt32 77 | #endif 78 | CPpmd_Byte_Ref; 79 | 80 | #define PPMD_SetAllBitsIn256Bytes(p) \ 81 | { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \ 82 | p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }} 83 | 84 | EXTERN_C_END 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Ppmd7.c: -------------------------------------------------------------------------------- 1 | /* Ppmd7.c -- PPMdH codec 2 | 2010-03-12 : Igor Pavlov : Public domain 3 | This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ 4 | 5 | #include 6 | 7 | #include "Ppmd7.h" 8 | 9 | const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; 10 | static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; 11 | 12 | #define MAX_FREQ 124 13 | #define UNIT_SIZE 12 14 | 15 | #define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) 16 | #define U2I(nu) (p->Units2Indx[(nu) - 1]) 17 | #define I2U(indx) (p->Indx2Units[indx]) 18 | 19 | #ifdef PPMD_32BIT 20 | #define REF(ptr) (ptr) 21 | #else 22 | #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) 23 | #endif 24 | 25 | #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) 26 | 27 | #define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) 28 | #define STATS(ctx) Ppmd7_GetStats(p, ctx) 29 | #define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) 30 | #define SUFFIX(ctx) CTX((ctx)->Suffix) 31 | 32 | typedef CPpmd7_Context * CTX_PTR; 33 | 34 | struct CPpmd7_Node_; 35 | 36 | typedef 37 | #ifdef PPMD_32BIT 38 | struct CPpmd7_Node_ * 39 | #else 40 | UInt32 41 | #endif 42 | CPpmd7_Node_Ref; 43 | 44 | typedef struct CPpmd7_Node_ 45 | { 46 | UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ 47 | UInt16 NU; 48 | CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ 49 | CPpmd7_Node_Ref Prev; 50 | } CPpmd7_Node; 51 | 52 | #ifdef PPMD_32BIT 53 | #define NODE(ptr) (ptr) 54 | #else 55 | #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) 56 | #endif 57 | 58 | void Ppmd7_Construct(CPpmd7 *p) 59 | { 60 | unsigned i, k, m; 61 | 62 | p->Base = 0; 63 | 64 | for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) 65 | { 66 | unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); 67 | do { p->Units2Indx[k++] = (Byte)i; } while(--step); 68 | p->Indx2Units[i] = (Byte)k; 69 | } 70 | 71 | p->NS2BSIndx[0] = (0 << 1); 72 | p->NS2BSIndx[1] = (1 << 1); 73 | memset(p->NS2BSIndx + 2, (2 << 1), 9); 74 | memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); 75 | 76 | for (i = 0; i < 3; i++) 77 | p->NS2Indx[i] = (Byte)i; 78 | for (m = i, k = 1; i < 256; i++) 79 | { 80 | p->NS2Indx[i] = (Byte)m; 81 | if (--k == 0) 82 | k = (++m) - 2; 83 | } 84 | 85 | memset(p->HB2Flag, 0, 0x40); 86 | memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); 87 | } 88 | 89 | void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc) 90 | { 91 | alloc->Free(alloc, p->Base); 92 | p->Size = 0; 93 | p->Base = 0; 94 | } 95 | 96 | Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc) 97 | { 98 | if (p->Base == 0 || p->Size != size) 99 | { 100 | Ppmd7_Free(p, alloc); 101 | p->AlignOffset = 102 | #ifdef PPMD_32BIT 103 | (4 - size) & 3; 104 | #else 105 | 4 - (size & 3); 106 | #endif 107 | if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size 108 | #ifndef PPMD_32BIT 109 | + UNIT_SIZE 110 | #endif 111 | )) == 0) 112 | return False; 113 | p->Size = size; 114 | } 115 | return True; 116 | } 117 | 118 | static void InsertNode(CPpmd7 *p, void *node, unsigned indx) 119 | { 120 | *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; 121 | p->FreeList[indx] = REF(node); 122 | } 123 | 124 | static void *RemoveNode(CPpmd7 *p, unsigned indx) 125 | { 126 | CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); 127 | p->FreeList[indx] = *node; 128 | return node; 129 | } 130 | 131 | static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) 132 | { 133 | unsigned i, nu = I2U(oldIndx) - I2U(newIndx); 134 | ptr = (Byte *)ptr + U2B(I2U(newIndx)); 135 | if (I2U(i = U2I(nu)) != nu) 136 | { 137 | unsigned k = I2U(--i); 138 | InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); 139 | } 140 | InsertNode(p, ptr, i); 141 | } 142 | 143 | static void GlueFreeBlocks(CPpmd7 *p) 144 | { 145 | #ifdef PPMD_32BIT 146 | CPpmd7_Node headItem; 147 | CPpmd7_Node_Ref head = &headItem; 148 | #else 149 | CPpmd7_Node_Ref head = p->AlignOffset + p->Size; 150 | #endif 151 | 152 | CPpmd7_Node_Ref n = head; 153 | unsigned i; 154 | 155 | p->GlueCount = 255; 156 | 157 | /* create doubly-linked list of free blocks */ 158 | for (i = 0; i < PPMD_NUM_INDEXES; i++) 159 | { 160 | UInt16 nu = I2U(i); 161 | CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; 162 | p->FreeList[i] = 0; 163 | while (next != 0) 164 | { 165 | CPpmd7_Node *node = NODE(next); 166 | node->Next = n; 167 | n = NODE(n)->Prev = next; 168 | next = *(const CPpmd7_Node_Ref *)node; 169 | node->Stamp = 0; 170 | node->NU = (UInt16)nu; 171 | } 172 | } 173 | NODE(head)->Stamp = 1; 174 | NODE(head)->Next = n; 175 | NODE(n)->Prev = head; 176 | if (p->LoUnit != p->HiUnit) 177 | ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; 178 | 179 | /* Glue free blocks */ 180 | while (n != head) 181 | { 182 | CPpmd7_Node *node = NODE(n); 183 | UInt32 nu = (UInt32)node->NU; 184 | for (;;) 185 | { 186 | CPpmd7_Node *node2 = NODE(n) + nu; 187 | nu += node2->NU; 188 | if (node2->Stamp != 0 || nu >= 0x10000) 189 | break; 190 | NODE(node2->Prev)->Next = node2->Next; 191 | NODE(node2->Next)->Prev = node2->Prev; 192 | node->NU = (UInt16)nu; 193 | } 194 | n = node->Next; 195 | } 196 | 197 | /* Fill lists of free blocks */ 198 | for (n = NODE(head)->Next; n != head;) 199 | { 200 | CPpmd7_Node *node = NODE(n); 201 | unsigned nu; 202 | CPpmd7_Node_Ref next = node->Next; 203 | for (nu = node->NU; nu > 128; nu -= 128, node += 128) 204 | InsertNode(p, node, PPMD_NUM_INDEXES - 1); 205 | if (I2U(i = U2I(nu)) != nu) 206 | { 207 | unsigned k = I2U(--i); 208 | InsertNode(p, node + k, nu - k - 1); 209 | } 210 | InsertNode(p, node, i); 211 | n = next; 212 | } 213 | } 214 | 215 | static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) 216 | { 217 | unsigned i; 218 | void *retVal; 219 | if (p->GlueCount == 0) 220 | { 221 | GlueFreeBlocks(p); 222 | if (p->FreeList[indx] != 0) 223 | return RemoveNode(p, indx); 224 | } 225 | i = indx; 226 | do 227 | { 228 | if (++i == PPMD_NUM_INDEXES) 229 | { 230 | UInt32 numBytes = U2B(I2U(indx)); 231 | p->GlueCount--; 232 | return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); 233 | } 234 | } 235 | while (p->FreeList[i] == 0); 236 | retVal = RemoveNode(p, i); 237 | SplitBlock(p, retVal, i, indx); 238 | return retVal; 239 | } 240 | 241 | static void *AllocUnits(CPpmd7 *p, unsigned indx) 242 | { 243 | UInt32 numBytes; 244 | if (p->FreeList[indx] != 0) 245 | return RemoveNode(p, indx); 246 | numBytes = U2B(I2U(indx)); 247 | if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) 248 | { 249 | void *retVal = p->LoUnit; 250 | p->LoUnit += numBytes; 251 | return retVal; 252 | } 253 | return AllocUnitsRare(p, indx); 254 | } 255 | 256 | #define MyMem12Cpy(dest, src, num) \ 257 | { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ 258 | do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } 259 | 260 | static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) 261 | { 262 | unsigned i0 = U2I(oldNU); 263 | unsigned i1 = U2I(newNU); 264 | if (i0 == i1) 265 | return oldPtr; 266 | if (p->FreeList[i1] != 0) 267 | { 268 | void *ptr = RemoveNode(p, i1); 269 | MyMem12Cpy(ptr, oldPtr, newNU); 270 | InsertNode(p, oldPtr, i0); 271 | return ptr; 272 | } 273 | SplitBlock(p, oldPtr, i0, i1); 274 | return oldPtr; 275 | } 276 | 277 | #define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) 278 | 279 | static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) 280 | { 281 | (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); 282 | (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); 283 | } 284 | 285 | static void RestartModel(CPpmd7 *p) 286 | { 287 | unsigned i, k, m; 288 | 289 | memset(p->FreeList, 0, sizeof(p->FreeList)); 290 | p->Text = p->Base + p->AlignOffset; 291 | p->HiUnit = p->Text + p->Size; 292 | p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; 293 | p->GlueCount = 0; 294 | 295 | p->OrderFall = p->MaxOrder; 296 | p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; 297 | p->PrevSuccess = 0; 298 | 299 | p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ 300 | p->MinContext->Suffix = 0; 301 | p->MinContext->NumStats = 256; 302 | p->MinContext->SummFreq = 256 + 1; 303 | p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ 304 | p->LoUnit += U2B(256 / 2); 305 | p->MinContext->Stats = REF(p->FoundState); 306 | for (i = 0; i < 256; i++) 307 | { 308 | CPpmd_State *s = &p->FoundState[i]; 309 | s->Symbol = (Byte)i; 310 | s->Freq = 1; 311 | SetSuccessor(s, 0); 312 | } 313 | 314 | for (i = 0; i < 128; i++) 315 | for (k = 0; k < 8; k++) 316 | { 317 | UInt16 *dest = p->BinSumm[i] + k; 318 | UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); 319 | for (m = 0; m < 64; m += 8) 320 | dest[m] = val; 321 | } 322 | 323 | for (i = 0; i < 25; i++) 324 | for (k = 0; k < 16; k++) 325 | { 326 | CPpmd_See *s = &p->See[i][k]; 327 | s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); 328 | s->Count = 4; 329 | } 330 | } 331 | 332 | void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) 333 | { 334 | p->MaxOrder = maxOrder; 335 | RestartModel(p); 336 | p->DummySee.Shift = PPMD_PERIOD_BITS; 337 | p->DummySee.Summ = 0; /* unused */ 338 | p->DummySee.Count = 64; /* unused */ 339 | } 340 | 341 | static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) 342 | { 343 | CPpmd_State upState; 344 | CTX_PTR c = p->MinContext; 345 | CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); 346 | CPpmd_State *ps[PPMD7_MAX_ORDER]; 347 | unsigned numPs = 0; 348 | 349 | if (!skip) 350 | ps[numPs++] = p->FoundState; 351 | 352 | while (c->Suffix) 353 | { 354 | CPpmd_Void_Ref successor; 355 | CPpmd_State *s; 356 | c = SUFFIX(c); 357 | if (c->NumStats != 1) 358 | { 359 | for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); 360 | } 361 | else 362 | s = ONE_STATE(c); 363 | successor = SUCCESSOR(s); 364 | if (successor != upBranch) 365 | { 366 | c = CTX(successor); 367 | if (numPs == 0) 368 | return c; 369 | break; 370 | } 371 | ps[numPs++] = s; 372 | } 373 | 374 | upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); 375 | SetSuccessor(&upState, upBranch + 1); 376 | 377 | if (c->NumStats == 1) 378 | upState.Freq = ONE_STATE(c)->Freq; 379 | else 380 | { 381 | UInt32 cf, s0; 382 | CPpmd_State *s; 383 | for (s = STATS(c); s->Symbol != upState.Symbol; s++); 384 | cf = s->Freq - 1; 385 | s0 = c->SummFreq - c->NumStats - cf; 386 | upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); 387 | } 388 | 389 | do 390 | { 391 | /* Create Child */ 392 | CTX_PTR c1; /* = AllocContext(p); */ 393 | if (p->HiUnit != p->LoUnit) 394 | c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); 395 | else if (p->FreeList[0] != 0) 396 | c1 = (CTX_PTR)RemoveNode(p, 0); 397 | else 398 | { 399 | c1 = (CTX_PTR)AllocUnitsRare(p, 0); 400 | if (!c1) 401 | return NULL; 402 | } 403 | c1->NumStats = 1; 404 | *ONE_STATE(c1) = upState; 405 | c1->Suffix = REF(c); 406 | SetSuccessor(ps[--numPs], REF(c1)); 407 | c = c1; 408 | } 409 | while (numPs != 0); 410 | 411 | return c; 412 | } 413 | 414 | static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) 415 | { 416 | CPpmd_State tmp = *t1; 417 | *t1 = *t2; 418 | *t2 = tmp; 419 | } 420 | 421 | static void UpdateModel(CPpmd7 *p) 422 | { 423 | CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); 424 | CTX_PTR c; 425 | unsigned s0, ns; 426 | 427 | if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) 428 | { 429 | c = SUFFIX(p->MinContext); 430 | 431 | if (c->NumStats == 1) 432 | { 433 | CPpmd_State *s = ONE_STATE(c); 434 | if (s->Freq < 32) 435 | s->Freq++; 436 | } 437 | else 438 | { 439 | CPpmd_State *s = STATS(c); 440 | if (s->Symbol != p->FoundState->Symbol) 441 | { 442 | do { s++; } while (s->Symbol != p->FoundState->Symbol); 443 | if (s[0].Freq >= s[-1].Freq) 444 | { 445 | SwapStates(&s[0], &s[-1]); 446 | s--; 447 | } 448 | } 449 | if (s->Freq < MAX_FREQ - 9) 450 | { 451 | s->Freq += 2; 452 | c->SummFreq += 2; 453 | } 454 | } 455 | } 456 | 457 | if (p->OrderFall == 0) 458 | { 459 | p->MinContext = p->MaxContext = CreateSuccessors(p, True); 460 | if (p->MinContext == 0) 461 | { 462 | RestartModel(p); 463 | return; 464 | } 465 | SetSuccessor(p->FoundState, REF(p->MinContext)); 466 | return; 467 | } 468 | 469 | *p->Text++ = p->FoundState->Symbol; 470 | successor = REF(p->Text); 471 | if (p->Text >= p->UnitsStart) 472 | { 473 | RestartModel(p); 474 | return; 475 | } 476 | 477 | if (fSuccessor) 478 | { 479 | if (fSuccessor <= successor) 480 | { 481 | CTX_PTR cs = CreateSuccessors(p, False); 482 | if (cs == NULL) 483 | { 484 | RestartModel(p); 485 | return; 486 | } 487 | fSuccessor = REF(cs); 488 | } 489 | if (--p->OrderFall == 0) 490 | { 491 | successor = fSuccessor; 492 | p->Text -= (p->MaxContext != p->MinContext); 493 | } 494 | } 495 | else 496 | { 497 | SetSuccessor(p->FoundState, successor); 498 | fSuccessor = REF(p->MinContext); 499 | } 500 | 501 | s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); 502 | 503 | for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) 504 | { 505 | unsigned ns1; 506 | UInt32 cf, sf; 507 | if ((ns1 = c->NumStats) != 1) 508 | { 509 | if ((ns1 & 1) == 0) 510 | { 511 | /* Expand for one UNIT */ 512 | unsigned oldNU = ns1 >> 1; 513 | unsigned i = U2I(oldNU); 514 | if (i != U2I(oldNU + 1)) 515 | { 516 | void *ptr = AllocUnits(p, i + 1); 517 | void *oldPtr; 518 | if (!ptr) 519 | { 520 | RestartModel(p); 521 | return; 522 | } 523 | oldPtr = STATS(c); 524 | MyMem12Cpy(ptr, oldPtr, oldNU); 525 | InsertNode(p, oldPtr, i); 526 | c->Stats = STATS_REF(ptr); 527 | } 528 | } 529 | c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); 530 | } 531 | else 532 | { 533 | CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); 534 | if (!s) 535 | { 536 | RestartModel(p); 537 | return; 538 | } 539 | *s = *ONE_STATE(c); 540 | c->Stats = REF(s); 541 | if (s->Freq < MAX_FREQ / 4 - 1) 542 | s->Freq <<= 1; 543 | else 544 | s->Freq = MAX_FREQ - 4; 545 | c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); 546 | } 547 | cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); 548 | sf = (UInt32)s0 + c->SummFreq; 549 | if (cf < 6 * sf) 550 | { 551 | cf = 1 + (cf > sf) + (cf >= 4 * sf); 552 | c->SummFreq += 3; 553 | } 554 | else 555 | { 556 | cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); 557 | c->SummFreq = (UInt16)(c->SummFreq + cf); 558 | } 559 | { 560 | CPpmd_State *s = STATS(c) + ns1; 561 | SetSuccessor(s, successor); 562 | s->Symbol = p->FoundState->Symbol; 563 | s->Freq = (Byte)cf; 564 | c->NumStats = (UInt16)(ns1 + 1); 565 | } 566 | } 567 | p->MaxContext = p->MinContext = CTX(fSuccessor); 568 | } 569 | 570 | static void Rescale(CPpmd7 *p) 571 | { 572 | unsigned i, adder, sumFreq, escFreq; 573 | CPpmd_State *stats = STATS(p->MinContext); 574 | CPpmd_State *s = p->FoundState; 575 | { 576 | CPpmd_State tmp = *s; 577 | for (; s != stats; s--) 578 | s[0] = s[-1]; 579 | *s = tmp; 580 | } 581 | escFreq = p->MinContext->SummFreq - s->Freq; 582 | s->Freq += 4; 583 | adder = (p->OrderFall != 0); 584 | s->Freq = (Byte)((s->Freq + adder) >> 1); 585 | sumFreq = s->Freq; 586 | 587 | i = p->MinContext->NumStats - 1; 588 | do 589 | { 590 | escFreq -= (++s)->Freq; 591 | s->Freq = (Byte)((s->Freq + adder) >> 1); 592 | sumFreq += s->Freq; 593 | if (s[0].Freq > s[-1].Freq) 594 | { 595 | CPpmd_State *s1 = s; 596 | CPpmd_State tmp = *s1; 597 | do 598 | s1[0] = s1[-1]; 599 | while (--s1 != stats && tmp.Freq > s1[-1].Freq); 600 | *s1 = tmp; 601 | } 602 | } 603 | while (--i); 604 | 605 | if (s->Freq == 0) 606 | { 607 | unsigned numStats = p->MinContext->NumStats; 608 | unsigned n0, n1; 609 | do { i++; } while ((--s)->Freq == 0); 610 | escFreq += i; 611 | p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); 612 | if (p->MinContext->NumStats == 1) 613 | { 614 | CPpmd_State tmp = *stats; 615 | do 616 | { 617 | tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); 618 | escFreq >>= 1; 619 | } 620 | while (escFreq > 1); 621 | InsertNode(p, stats, U2I(((numStats + 1) >> 1))); 622 | *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; 623 | return; 624 | } 625 | n0 = (numStats + 1) >> 1; 626 | n1 = (p->MinContext->NumStats + 1) >> 1; 627 | if (n0 != n1) 628 | p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); 629 | } 630 | p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); 631 | p->FoundState = STATS(p->MinContext); 632 | } 633 | 634 | CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) 635 | { 636 | CPpmd_See *see; 637 | unsigned nonMasked = p->MinContext->NumStats - numMasked; 638 | if (p->MinContext->NumStats != 256) 639 | { 640 | see = p->See[p->NS2Indx[nonMasked - 1]] + 641 | (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + 642 | 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + 643 | 4 * (numMasked > nonMasked) + 644 | p->HiBitsFlag; 645 | { 646 | unsigned r = (see->Summ >> see->Shift); 647 | see->Summ = (UInt16)(see->Summ - r); 648 | *escFreq = r + (r == 0); 649 | } 650 | } 651 | else 652 | { 653 | see = &p->DummySee; 654 | *escFreq = 1; 655 | } 656 | return see; 657 | } 658 | 659 | static void NextContext(CPpmd7 *p) 660 | { 661 | CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); 662 | if (p->OrderFall == 0 && (Byte *)c > p->Text) 663 | p->MinContext = p->MaxContext = c; 664 | else 665 | UpdateModel(p); 666 | } 667 | 668 | void Ppmd7_Update1(CPpmd7 *p) 669 | { 670 | CPpmd_State *s = p->FoundState; 671 | s->Freq += 4; 672 | p->MinContext->SummFreq += 4; 673 | if (s[0].Freq > s[-1].Freq) 674 | { 675 | SwapStates(&s[0], &s[-1]); 676 | p->FoundState = --s; 677 | if (s->Freq > MAX_FREQ) 678 | Rescale(p); 679 | } 680 | NextContext(p); 681 | } 682 | 683 | void Ppmd7_Update1_0(CPpmd7 *p) 684 | { 685 | p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); 686 | p->RunLength += p->PrevSuccess; 687 | p->MinContext->SummFreq += 4; 688 | if ((p->FoundState->Freq += 4) > MAX_FREQ) 689 | Rescale(p); 690 | NextContext(p); 691 | } 692 | 693 | void Ppmd7_UpdateBin(CPpmd7 *p) 694 | { 695 | p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); 696 | p->PrevSuccess = 1; 697 | p->RunLength++; 698 | NextContext(p); 699 | } 700 | 701 | void Ppmd7_Update2(CPpmd7 *p) 702 | { 703 | p->MinContext->SummFreq += 4; 704 | if ((p->FoundState->Freq += 4) > MAX_FREQ) 705 | Rescale(p); 706 | p->RunLength = p->InitRL; 707 | UpdateModel(p); 708 | } 709 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Ppmd7.h: -------------------------------------------------------------------------------- 1 | /* Ppmd7.h -- PPMdH compression codec 2 | 2010-03-12 : Igor Pavlov : Public domain 3 | This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ 4 | 5 | /* This code supports virtual RangeDecoder and includes the implementation 6 | of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. 7 | If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ 8 | 9 | #ifndef __PPMD7_H 10 | #define __PPMD7_H 11 | 12 | #include "Ppmd.h" 13 | 14 | EXTERN_C_BEGIN 15 | 16 | #define PPMD7_MIN_ORDER 2 17 | #define PPMD7_MAX_ORDER 64 18 | 19 | #define PPMD7_MIN_MEM_SIZE (1 << 11) 20 | #define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) 21 | 22 | struct CPpmd7_Context_; 23 | 24 | typedef 25 | #ifdef PPMD_32BIT 26 | struct CPpmd7_Context_ * 27 | #else 28 | UInt32 29 | #endif 30 | CPpmd7_Context_Ref; 31 | 32 | typedef struct CPpmd7_Context_ 33 | { 34 | UInt16 NumStats; 35 | UInt16 SummFreq; 36 | CPpmd_State_Ref Stats; 37 | CPpmd7_Context_Ref Suffix; 38 | } CPpmd7_Context; 39 | 40 | #define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) 41 | 42 | typedef struct 43 | { 44 | CPpmd7_Context *MinContext, *MaxContext; 45 | CPpmd_State *FoundState; 46 | unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; 47 | Int32 RunLength, InitRL; /* must be 32-bit at least */ 48 | 49 | UInt32 Size; 50 | UInt32 GlueCount; 51 | Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; 52 | UInt32 AlignOffset; 53 | 54 | Byte Indx2Units[PPMD_NUM_INDEXES]; 55 | Byte Units2Indx[128]; 56 | CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; 57 | Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; 58 | CPpmd_See DummySee, See[25][16]; 59 | UInt16 BinSumm[128][64]; 60 | } CPpmd7; 61 | 62 | void Ppmd7_Construct(CPpmd7 *p); 63 | Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc); 64 | void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc); 65 | void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); 66 | #define Ppmd7_WasAllocated(p) ((p)->Base != NULL) 67 | 68 | 69 | /* ---------- Internal Functions ---------- */ 70 | 71 | extern const Byte PPMD7_kExpEscape[16]; 72 | 73 | #ifdef PPMD_32BIT 74 | #define Ppmd7_GetPtr(p, ptr) (ptr) 75 | #define Ppmd7_GetContext(p, ptr) (ptr) 76 | #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) 77 | #else 78 | #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) 79 | #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) 80 | #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) 81 | #endif 82 | 83 | void Ppmd7_Update1(CPpmd7 *p); 84 | void Ppmd7_Update1_0(CPpmd7 *p); 85 | void Ppmd7_Update2(CPpmd7 *p); 86 | void Ppmd7_UpdateBin(CPpmd7 *p); 87 | 88 | #define Ppmd7_GetBinSumm(p) \ 89 | &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ 90 | p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ 91 | (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ 92 | 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \ 93 | ((p->RunLength >> 26) & 0x20)] 94 | 95 | CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); 96 | 97 | 98 | /* ---------- Decode ---------- */ 99 | 100 | typedef struct 101 | { 102 | UInt32 (*GetThreshold)(void *p, UInt32 total); 103 | void (*Decode)(void *p, UInt32 start, UInt32 size); 104 | UInt32 (*DecodeBit)(void *p, UInt32 size0); 105 | } IPpmd7_RangeDec; 106 | 107 | typedef struct 108 | { 109 | IPpmd7_RangeDec p; 110 | UInt32 Range; 111 | UInt32 Code; 112 | IByteIn *Stream; 113 | } CPpmd7z_RangeDec; 114 | 115 | void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p); 116 | Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p); 117 | #define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) 118 | 119 | int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc); 120 | 121 | 122 | /* ---------- Encode ---------- */ 123 | 124 | typedef struct 125 | { 126 | UInt64 Low; 127 | UInt32 Range; 128 | Byte Cache; 129 | UInt64 CacheSize; 130 | IByteOut *Stream; 131 | } CPpmd7z_RangeEnc; 132 | 133 | void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p); 134 | void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p); 135 | 136 | void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); 137 | 138 | EXTERN_C_END 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Ppmd7Dec.c: -------------------------------------------------------------------------------- 1 | /* Ppmd7Dec.c -- PPMdH Decoder 2 | 2010-03-12 : Igor Pavlov : Public domain 3 | This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ 4 | 5 | #include "Ppmd7.h" 6 | 7 | #define kTopValue (1 << 24) 8 | 9 | Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) 10 | { 11 | unsigned i; 12 | p->Code = 0; 13 | p->Range = 0xFFFFFFFF; 14 | if (p->Stream->Read((void *)p->Stream) != 0) 15 | return False; 16 | for (i = 0; i < 4; i++) 17 | p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); 18 | return (p->Code < 0xFFFFFFFF); 19 | } 20 | 21 | static UInt32 Range_GetThreshold(void *pp, UInt32 total) 22 | { 23 | CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; 24 | return (p->Code) / (p->Range /= total); 25 | } 26 | 27 | static void Range_Normalize(CPpmd7z_RangeDec *p) 28 | { 29 | if (p->Range < kTopValue) 30 | { 31 | p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); 32 | p->Range <<= 8; 33 | if (p->Range < kTopValue) 34 | { 35 | p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); 36 | p->Range <<= 8; 37 | } 38 | } 39 | } 40 | 41 | static void Range_Decode(void *pp, UInt32 start, UInt32 size) 42 | { 43 | CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; 44 | p->Code -= start * p->Range; 45 | p->Range *= size; 46 | Range_Normalize(p); 47 | } 48 | 49 | static UInt32 Range_DecodeBit(void *pp, UInt32 size0) 50 | { 51 | CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; 52 | UInt32 newBound = (p->Range >> 14) * size0; 53 | UInt32 symbol; 54 | if (p->Code < newBound) 55 | { 56 | symbol = 0; 57 | p->Range = newBound; 58 | } 59 | else 60 | { 61 | symbol = 1; 62 | p->Code -= newBound; 63 | p->Range -= newBound; 64 | } 65 | Range_Normalize(p); 66 | return symbol; 67 | } 68 | 69 | void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) 70 | { 71 | p->p.GetThreshold = Range_GetThreshold; 72 | p->p.Decode = Range_Decode; 73 | p->p.DecodeBit = Range_DecodeBit; 74 | } 75 | 76 | 77 | #define MASK(sym) ((signed char *)charMask)[sym] 78 | 79 | int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc) 80 | { 81 | size_t charMask[256 / sizeof(size_t)]; 82 | if (p->MinContext->NumStats != 1) 83 | { 84 | CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); 85 | unsigned i; 86 | UInt32 count, hiCnt; 87 | if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) 88 | { 89 | Byte symbol; 90 | rc->Decode(rc, 0, s->Freq); 91 | p->FoundState = s; 92 | symbol = s->Symbol; 93 | Ppmd7_Update1_0(p); 94 | return symbol; 95 | } 96 | p->PrevSuccess = 0; 97 | i = p->MinContext->NumStats - 1; 98 | do 99 | { 100 | if ((hiCnt += (++s)->Freq) > count) 101 | { 102 | Byte symbol; 103 | rc->Decode(rc, hiCnt - s->Freq, s->Freq); 104 | p->FoundState = s; 105 | symbol = s->Symbol; 106 | Ppmd7_Update1(p); 107 | return symbol; 108 | } 109 | } 110 | while (--i); 111 | if (count >= p->MinContext->SummFreq) 112 | return -2; 113 | p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; 114 | rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); 115 | PPMD_SetAllBitsIn256Bytes(charMask); 116 | MASK(s->Symbol) = 0; 117 | i = p->MinContext->NumStats - 1; 118 | do { MASK((--s)->Symbol) = 0; } while (--i); 119 | } 120 | else 121 | { 122 | UInt16 *prob = Ppmd7_GetBinSumm(p); 123 | if (rc->DecodeBit(rc, *prob) == 0) 124 | { 125 | Byte symbol; 126 | *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); 127 | symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; 128 | Ppmd7_UpdateBin(p); 129 | return symbol; 130 | } 131 | *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); 132 | p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; 133 | PPMD_SetAllBitsIn256Bytes(charMask); 134 | MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; 135 | p->PrevSuccess = 0; 136 | } 137 | for (;;) 138 | { 139 | CPpmd_State *ps[256], *s; 140 | UInt32 freqSum, count, hiCnt; 141 | CPpmd_See *see; 142 | unsigned i, num, numMasked = p->MinContext->NumStats; 143 | do 144 | { 145 | p->OrderFall++; 146 | if (!p->MinContext->Suffix) 147 | return -1; 148 | p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); 149 | } 150 | while (p->MinContext->NumStats == numMasked); 151 | hiCnt = 0; 152 | s = Ppmd7_GetStats(p, p->MinContext); 153 | i = 0; 154 | num = p->MinContext->NumStats - numMasked; 155 | do 156 | { 157 | int k = (int)(MASK(s->Symbol)); 158 | hiCnt += (s->Freq & k); 159 | ps[i] = s++; 160 | i -= k; 161 | } 162 | while (i != num); 163 | 164 | see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); 165 | freqSum += hiCnt; 166 | count = rc->GetThreshold(rc, freqSum); 167 | 168 | if (count < hiCnt) 169 | { 170 | Byte symbol; 171 | CPpmd_State **pps = ps; 172 | for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); 173 | s = *pps; 174 | rc->Decode(rc, hiCnt - s->Freq, s->Freq); 175 | Ppmd_See_Update(see); 176 | p->FoundState = s; 177 | symbol = s->Symbol; 178 | Ppmd7_Update2(p); 179 | return symbol; 180 | } 181 | if (count >= freqSum) 182 | return -2; 183 | rc->Decode(rc, hiCnt, freqSum - hiCnt); 184 | see->Summ = (UInt16)(see->Summ + freqSum); 185 | do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Ppmd8.h: -------------------------------------------------------------------------------- 1 | /* Ppmd8.h -- PPMdI codec 2 | 2010-03-24 : Igor Pavlov : Public domain 3 | This code is based on: 4 | PPMd var.I (2002): Dmitry Shkarin : Public domain 5 | Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ 6 | 7 | #ifndef __PPMD8_H 8 | #define __PPMD8_H 9 | 10 | #include "Ppmd.h" 11 | 12 | EXTERN_C_BEGIN 13 | 14 | #define PPMD8_MIN_ORDER 2 15 | #define PPMD8_MAX_ORDER 16 16 | 17 | struct CPpmd8_Context_; 18 | 19 | typedef 20 | #ifdef PPMD_32BIT 21 | struct CPpmd8_Context_ * 22 | #else 23 | UInt32 24 | #endif 25 | CPpmd8_Context_Ref; 26 | 27 | typedef struct CPpmd8_Context_ 28 | { 29 | Byte NumStats; 30 | Byte Flags; 31 | UInt16 SummFreq; 32 | CPpmd_State_Ref Stats; 33 | CPpmd8_Context_Ref Suffix; 34 | } CPpmd8_Context; 35 | 36 | #define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) 37 | 38 | /* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed 39 | code is not compatible with original code for some files compressed 40 | in FREEZE mode. So we disable FREEZE mode support. */ 41 | 42 | enum 43 | { 44 | PPMD8_RESTORE_METHOD_RESTART, 45 | PPMD8_RESTORE_METHOD_CUT_OFF 46 | #ifdef PPMD8_FREEZE_SUPPORT 47 | , PPMD8_RESTORE_METHOD_FREEZE 48 | #endif 49 | }; 50 | 51 | typedef struct 52 | { 53 | CPpmd8_Context *MinContext, *MaxContext; 54 | CPpmd_State *FoundState; 55 | unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder; 56 | Int32 RunLength, InitRL; /* must be 32-bit at least */ 57 | 58 | UInt32 Size; 59 | UInt32 GlueCount; 60 | Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; 61 | UInt32 AlignOffset; 62 | unsigned RestoreMethod; 63 | 64 | /* Range Coder */ 65 | UInt32 Range; 66 | UInt32 Code; 67 | UInt32 Low; 68 | union 69 | { 70 | IByteIn *In; 71 | IByteOut *Out; 72 | } Stream; 73 | 74 | Byte Indx2Units[PPMD_NUM_INDEXES]; 75 | Byte Units2Indx[128]; 76 | CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; 77 | UInt32 Stamps[PPMD_NUM_INDEXES]; 78 | 79 | Byte NS2BSIndx[256], NS2Indx[260]; 80 | CPpmd_See DummySee, See[24][32]; 81 | UInt16 BinSumm[25][64]; 82 | } CPpmd8; 83 | 84 | void Ppmd8_Construct(CPpmd8 *p); 85 | Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc); 86 | void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc); 87 | void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod); 88 | #define Ppmd8_WasAllocated(p) ((p)->Base != NULL) 89 | 90 | 91 | /* ---------- Internal Functions ---------- */ 92 | 93 | extern const Byte PPMD8_kExpEscape[16]; 94 | 95 | #ifdef PPMD_32BIT 96 | #define Ppmd8_GetPtr(p, ptr) (ptr) 97 | #define Ppmd8_GetContext(p, ptr) (ptr) 98 | #define Ppmd8_GetStats(p, ctx) ((ctx)->Stats) 99 | #else 100 | #define Ppmd8_GetPtr(p, offs) ((void *)((p)->Base + (offs))) 101 | #define Ppmd8_GetContext(p, offs) ((CPpmd8_Context *)Ppmd8_GetPtr((p), (offs))) 102 | #define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats))) 103 | #endif 104 | 105 | void Ppmd8_Update1(CPpmd8 *p); 106 | void Ppmd8_Update1_0(CPpmd8 *p); 107 | void Ppmd8_Update2(CPpmd8 *p); 108 | void Ppmd8_UpdateBin(CPpmd8 *p); 109 | 110 | #define Ppmd8_GetBinSumm(p) \ 111 | &p->BinSumm[p->NS2Indx[Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \ 112 | p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \ 113 | p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)] 114 | 115 | CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale); 116 | 117 | 118 | /* ---------- Decode ---------- */ 119 | 120 | Bool Ppmd8_RangeDec_Init(CPpmd8 *p); 121 | #define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0) 122 | int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */ 123 | 124 | 125 | /* ---------- Encode ---------- */ 126 | 127 | #define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; } 128 | void Ppmd8_RangeEnc_FlushData(CPpmd8 *p); 129 | void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */ 130 | 131 | EXTERN_C_END 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Ppmd8Dec.c: -------------------------------------------------------------------------------- 1 | /* Ppmd8Dec.c -- PPMdI Decoder 2 | 2010-04-16 : Igor Pavlov : Public domain 3 | This code is based on: 4 | PPMd var.I (2002): Dmitry Shkarin : Public domain 5 | Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ 6 | 7 | #include "Ppmd8.h" 8 | 9 | #define kTop (1 << 24) 10 | #define kBot (1 << 15) 11 | 12 | Bool Ppmd8_RangeDec_Init(CPpmd8 *p) 13 | { 14 | unsigned i; 15 | p->Low = 0; 16 | p->Range = 0xFFFFFFFF; 17 | p->Code = 0; 18 | for (i = 0; i < 4; i++) 19 | p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); 20 | return (p->Code < 0xFFFFFFFF); 21 | } 22 | 23 | static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total) 24 | { 25 | return p->Code / (p->Range /= total); 26 | } 27 | 28 | static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size) 29 | { 30 | start *= p->Range; 31 | p->Low += start; 32 | p->Code -= start; 33 | p->Range *= size; 34 | 35 | while ((p->Low ^ (p->Low + p->Range)) < kTop || 36 | (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) 37 | { 38 | p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); 39 | p->Range <<= 8; 40 | p->Low <<= 8; 41 | } 42 | } 43 | 44 | #define MASK(sym) ((signed char *)charMask)[sym] 45 | 46 | int Ppmd8_DecodeSymbol(CPpmd8 *p) 47 | { 48 | size_t charMask[256 / sizeof(size_t)]; 49 | if (p->MinContext->NumStats != 0) 50 | { 51 | CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); 52 | unsigned i; 53 | UInt32 count, hiCnt; 54 | if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) 55 | { 56 | Byte symbol; 57 | RangeDec_Decode(p, 0, s->Freq); 58 | p->FoundState = s; 59 | symbol = s->Symbol; 60 | Ppmd8_Update1_0(p); 61 | return symbol; 62 | } 63 | p->PrevSuccess = 0; 64 | i = p->MinContext->NumStats; 65 | do 66 | { 67 | if ((hiCnt += (++s)->Freq) > count) 68 | { 69 | Byte symbol; 70 | RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); 71 | p->FoundState = s; 72 | symbol = s->Symbol; 73 | Ppmd8_Update1(p); 74 | return symbol; 75 | } 76 | } 77 | while (--i); 78 | if (count >= p->MinContext->SummFreq) 79 | return -2; 80 | RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt); 81 | PPMD_SetAllBitsIn256Bytes(charMask); 82 | MASK(s->Symbol) = 0; 83 | i = p->MinContext->NumStats; 84 | do { MASK((--s)->Symbol) = 0; } while (--i); 85 | } 86 | else 87 | { 88 | UInt16 *prob = Ppmd8_GetBinSumm(p); 89 | if (((p->Code / (p->Range >>= 14)) < *prob)) 90 | { 91 | Byte symbol; 92 | RangeDec_Decode(p, 0, *prob); 93 | *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); 94 | symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; 95 | Ppmd8_UpdateBin(p); 96 | return symbol; 97 | } 98 | RangeDec_Decode(p, *prob, (1 << 14) - *prob); 99 | *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); 100 | p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; 101 | PPMD_SetAllBitsIn256Bytes(charMask); 102 | MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; 103 | p->PrevSuccess = 0; 104 | } 105 | for (;;) 106 | { 107 | CPpmd_State *ps[256], *s; 108 | UInt32 freqSum, count, hiCnt; 109 | CPpmd_See *see; 110 | unsigned i, num, numMasked = p->MinContext->NumStats; 111 | do 112 | { 113 | p->OrderFall++; 114 | if (!p->MinContext->Suffix) 115 | return -1; 116 | p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); 117 | } 118 | while (p->MinContext->NumStats == numMasked); 119 | hiCnt = 0; 120 | s = Ppmd8_GetStats(p, p->MinContext); 121 | i = 0; 122 | num = p->MinContext->NumStats - numMasked; 123 | do 124 | { 125 | int k = (int)(MASK(s->Symbol)); 126 | hiCnt += (s->Freq & k); 127 | ps[i] = s++; 128 | i -= k; 129 | } 130 | while (i != num); 131 | 132 | see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); 133 | freqSum += hiCnt; 134 | count = RangeDec_GetThreshold(p, freqSum); 135 | 136 | if (count < hiCnt) 137 | { 138 | Byte symbol; 139 | CPpmd_State **pps = ps; 140 | for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); 141 | s = *pps; 142 | RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); 143 | Ppmd_See_Update(see); 144 | p->FoundState = s; 145 | symbol = s->Symbol; 146 | Ppmd8_Update2(p); 147 | return symbol; 148 | } 149 | if (count >= freqSum) 150 | return -2; 151 | RangeDec_Decode(p, hiCnt, freqSum - hiCnt); 152 | see->Summ = (UInt16)(see->Summ + freqSum); 153 | do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /Classes/LZMASDK/RotateDefs.h: -------------------------------------------------------------------------------- 1 | /* RotateDefs.h -- Rotate functions 2 | 2009-02-07 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __ROTATE_DEFS_H 5 | #define __ROTATE_DEFS_H 6 | 7 | #ifdef _MSC_VER 8 | 9 | #include 10 | #define rotlFixed(x, n) _rotl((x), (n)) 11 | #define rotrFixed(x, n) _rotr((x), (n)) 12 | 13 | #else 14 | 15 | #define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) 16 | #define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) 17 | 18 | #endif 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Types.h: -------------------------------------------------------------------------------- 1 | /* Types.h -- Basic types 2 | 2010-10-09 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __7Z_TYPES_H 5 | #define __7Z_TYPES_H 6 | 7 | #include 8 | 9 | #ifdef _WIN32 10 | #include 11 | #endif 12 | 13 | #ifndef EXTERN_C_BEGIN 14 | #ifdef __cplusplus 15 | #define EXTERN_C_BEGIN extern "C" { 16 | #define EXTERN_C_END } 17 | #else 18 | #define EXTERN_C_BEGIN 19 | #define EXTERN_C_END 20 | #endif 21 | #endif 22 | 23 | EXTERN_C_BEGIN 24 | 25 | #define SZ_OK 0 26 | 27 | #define SZ_ERROR_DATA 1 28 | #define SZ_ERROR_MEM 2 29 | #define SZ_ERROR_CRC 3 30 | #define SZ_ERROR_UNSUPPORTED 4 31 | #define SZ_ERROR_PARAM 5 32 | #define SZ_ERROR_INPUT_EOF 6 33 | #define SZ_ERROR_OUTPUT_EOF 7 34 | #define SZ_ERROR_READ 8 35 | #define SZ_ERROR_WRITE 9 36 | #define SZ_ERROR_PROGRESS 10 37 | #define SZ_ERROR_FAIL 11 38 | #define SZ_ERROR_THREAD 12 39 | 40 | #define SZ_ERROR_ARCHIVE 16 41 | #define SZ_ERROR_NO_ARCHIVE 17 42 | 43 | typedef int SRes; 44 | 45 | #ifdef _WIN32 46 | typedef DWORD WRes; 47 | #else 48 | typedef int WRes; 49 | #endif 50 | 51 | #ifndef RINOK 52 | #define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } 53 | #endif 54 | 55 | typedef unsigned char Byte; 56 | typedef short Int16; 57 | typedef unsigned short UInt16; 58 | 59 | #ifdef _LZMA_UINT32_IS_ULONG 60 | typedef long Int32; 61 | typedef unsigned long UInt32; 62 | #else 63 | typedef int Int32; 64 | typedef unsigned int UInt32; 65 | #endif 66 | 67 | #ifdef _SZ_NO_INT_64 68 | 69 | /* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. 70 | NOTES: Some code will work incorrectly in that case! */ 71 | 72 | typedef long Int64; 73 | typedef unsigned long UInt64; 74 | 75 | #else 76 | 77 | #if defined(_MSC_VER) || defined(__BORLANDC__) 78 | typedef __int64 Int64; 79 | typedef unsigned __int64 UInt64; 80 | #define UINT64_CONST(n) n 81 | #else 82 | typedef long long int Int64; 83 | typedef unsigned long long int UInt64; 84 | #define UINT64_CONST(n) n ## ULL 85 | #endif 86 | 87 | #endif 88 | 89 | #ifdef _LZMA_NO_SYSTEM_SIZE_T 90 | typedef UInt32 SizeT; 91 | #else 92 | typedef size_t SizeT; 93 | #endif 94 | 95 | typedef int Bool; 96 | #define True 1 97 | #define False 0 98 | 99 | 100 | #ifdef _WIN32 101 | #define MY_STD_CALL __stdcall 102 | #else 103 | #define MY_STD_CALL 104 | #endif 105 | 106 | #ifdef _MSC_VER 107 | 108 | #if _MSC_VER >= 1300 109 | #define MY_NO_INLINE __declspec(noinline) 110 | #else 111 | #define MY_NO_INLINE 112 | #endif 113 | 114 | #define MY_CDECL __cdecl 115 | #define MY_FAST_CALL __fastcall 116 | 117 | #else 118 | 119 | #define MY_CDECL 120 | #define MY_FAST_CALL 121 | 122 | #endif 123 | 124 | 125 | /* The following interfaces use first parameter as pointer to structure */ 126 | 127 | typedef struct 128 | { 129 | Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ 130 | } IByteIn; 131 | 132 | typedef struct 133 | { 134 | void (*Write)(void *p, Byte b); 135 | } IByteOut; 136 | 137 | typedef struct 138 | { 139 | SRes (*Read)(void *p, void *buf, size_t *size); 140 | /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. 141 | (output(*size) < input(*size)) is allowed */ 142 | } ISeqInStream; 143 | 144 | /* it can return SZ_ERROR_INPUT_EOF */ 145 | SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); 146 | SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); 147 | SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); 148 | 149 | typedef struct 150 | { 151 | size_t (*Write)(void *p, const void *buf, size_t size); 152 | /* Returns: result - the number of actually written bytes. 153 | (result < size) means error */ 154 | } ISeqOutStream; 155 | 156 | typedef enum 157 | { 158 | SZ_SEEK_SET = 0, 159 | SZ_SEEK_CUR = 1, 160 | SZ_SEEK_END = 2 161 | } ESzSeek; 162 | 163 | typedef struct 164 | { 165 | SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ 166 | SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); 167 | } ISeekInStream; 168 | 169 | typedef struct 170 | { 171 | SRes (*Look)(void *p, const void **buf, size_t *size); 172 | /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. 173 | (output(*size) > input(*size)) is not allowed 174 | (output(*size) < input(*size)) is allowed */ 175 | SRes (*Skip)(void *p, size_t offset); 176 | /* offset must be <= output(*size) of Look */ 177 | 178 | SRes (*Read)(void *p, void *buf, size_t *size); 179 | /* reads directly (without buffer). It's same as ISeqInStream::Read */ 180 | SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); 181 | } ILookInStream; 182 | 183 | SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); 184 | SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); 185 | 186 | /* reads via ILookInStream::Read */ 187 | SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); 188 | SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); 189 | 190 | #define LookToRead_BUF_SIZE (1 << 14) 191 | 192 | typedef struct 193 | { 194 | ILookInStream s; 195 | ISeekInStream *realStream; 196 | size_t pos; 197 | size_t size; 198 | Byte buf[LookToRead_BUF_SIZE]; 199 | } CLookToRead; 200 | 201 | void LookToRead_CreateVTable(CLookToRead *p, int lookahead); 202 | void LookToRead_Init(CLookToRead *p); 203 | 204 | typedef struct 205 | { 206 | ISeqInStream s; 207 | ILookInStream *realStream; 208 | } CSecToLook; 209 | 210 | void SecToLook_CreateVTable(CSecToLook *p); 211 | 212 | typedef struct 213 | { 214 | ISeqInStream s; 215 | ILookInStream *realStream; 216 | } CSecToRead; 217 | 218 | void SecToRead_CreateVTable(CSecToRead *p); 219 | 220 | typedef struct 221 | { 222 | SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); 223 | /* Returns: result. (result != SZ_OK) means break. 224 | Value (UInt64)(Int64)-1 for size means unknown value. */ 225 | } ICompressProgress; 226 | 227 | typedef struct 228 | { 229 | void *(*Alloc)(void *p, size_t size); 230 | void (*Free)(void *p, void *address); /* address can be 0 */ 231 | } ISzAlloc; 232 | 233 | #define IAlloc_Alloc(p, size) (p)->Alloc((p), size) 234 | #define IAlloc_Free(p, a) (p)->Free((p), a) 235 | 236 | #ifdef _WIN32 237 | 238 | #define CHAR_PATH_SEPARATOR '\\' 239 | #define WCHAR_PATH_SEPARATOR L'\\' 240 | #define STRING_PATH_SEPARATOR "\\" 241 | #define WSTRING_PATH_SEPARATOR L"\\" 242 | 243 | #else 244 | 245 | #define CHAR_PATH_SEPARATOR '/' 246 | #define WCHAR_PATH_SEPARATOR L'/' 247 | #define STRING_PATH_SEPARATOR "/" 248 | #define WSTRING_PATH_SEPARATOR L"/" 249 | 250 | #endif 251 | 252 | EXTERN_C_END 253 | 254 | #endif 255 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Util/7z/7zAlloc.c: -------------------------------------------------------------------------------- 1 | /* 7zAlloc.c -- Allocation functions 2 | 2010-10-29 : Igor Pavlov : Public domain */ 3 | 4 | #include "7zAlloc.h" 5 | 6 | /* #define _SZ_ALLOC_DEBUG */ 7 | /* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ 8 | 9 | #ifdef _SZ_ALLOC_DEBUG 10 | 11 | #ifdef _WIN32 12 | #include 13 | #endif 14 | 15 | #include 16 | int g_allocCount = 0; 17 | int g_allocCountTemp = 0; 18 | 19 | #endif 20 | 21 | void *SzAlloc(void *p, size_t size) 22 | { 23 | p = p; 24 | if (size == 0) 25 | return 0; 26 | #ifdef _SZ_ALLOC_DEBUG 27 | fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount); 28 | g_allocCount++; 29 | #endif 30 | return malloc(size); 31 | } 32 | 33 | void SzFree(void *p, void *address) 34 | { 35 | p = p; 36 | #ifdef _SZ_ALLOC_DEBUG 37 | if (address != 0) 38 | { 39 | g_allocCount--; 40 | fprintf(stderr, "\nFree; count = %10d", g_allocCount); 41 | } 42 | #endif 43 | free(address); 44 | } 45 | 46 | void *SzAllocTemp(void *p, size_t size) 47 | { 48 | p = p; 49 | if (size == 0) 50 | return 0; 51 | #ifdef _SZ_ALLOC_DEBUG 52 | fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp); 53 | g_allocCountTemp++; 54 | #ifdef _WIN32 55 | return HeapAlloc(GetProcessHeap(), 0, size); 56 | #endif 57 | #endif 58 | return malloc(size); 59 | } 60 | 61 | void SzFreeTemp(void *p, void *address) 62 | { 63 | p = p; 64 | #ifdef _SZ_ALLOC_DEBUG 65 | if (address != 0) 66 | { 67 | g_allocCountTemp--; 68 | fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp); 69 | } 70 | #ifdef _WIN32 71 | HeapFree(GetProcessHeap(), 0, address); 72 | return; 73 | #endif 74 | #endif 75 | free(address); 76 | } 77 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Util/7z/7zAlloc.h: -------------------------------------------------------------------------------- 1 | /* 7zAlloc.h -- Allocation functions 2 | 2010-10-29 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __7Z_ALLOC_H 5 | #define __7Z_ALLOC_H 6 | 7 | #include 8 | 9 | void *SzAlloc(void *p, size_t size); 10 | void SzFree(void *p, void *address); 11 | 12 | void *SzAllocTemp(void *p, size_t size); 13 | void SzFreeTemp(void *p, void *address); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /Classes/LZMASDK/Util/7z/7zMain.c: -------------------------------------------------------------------------------- 1 | /* 7zMain.c - Test application for 7z Decoder 2 | 2010-03-12 : Igor Pavlov : Public domain */ 3 | 4 | #pragma clang diagnostic ignored "-Wmissing-prototypes" 5 | 6 | #include 7 | #include 8 | 9 | #include "../../7z.h" 10 | #ifdef _7ZIP_CRC_SUPPORT 11 | #include "../../7zCrc.h" 12 | #endif 13 | #include "../../7zFile.h" 14 | #include "../../7zVersion.h" 15 | 16 | #include "7zAlloc.h" 17 | 18 | #ifndef USE_WINDOWS_FILE 19 | /* for mkdir */ 20 | #ifdef _WIN32 21 | #include 22 | #else 23 | #include 24 | #include 25 | #endif 26 | #endif 27 | 28 | #ifdef _WIN32 29 | #define CHAR_PATH_SEPARATOR '\\' 30 | #else 31 | #define CHAR_PATH_SEPARATOR '/' 32 | #endif 33 | 34 | #include 35 | #include 36 | 37 | static ISzAlloc g_Alloc = { SzAlloc, SzFree }; 38 | 39 | static int Buf_EnsureSize(CBuf *dest, size_t size) 40 | { 41 | if (dest->size >= size) 42 | return 1; 43 | Buf_Free(dest, &g_Alloc); 44 | return Buf_Create(dest, size, &g_Alloc); 45 | } 46 | 47 | #ifndef _WIN32 48 | 49 | static Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 50 | 51 | static Bool Utf16_To_Utf8(Byte *dest, size_t *destLen, const UInt16 *src, size_t srcLen) 52 | { 53 | size_t destPos = 0, srcPos = 0; 54 | for (;;) 55 | { 56 | unsigned numAdds; 57 | UInt32 value; 58 | if (srcPos == srcLen) 59 | { 60 | *destLen = destPos; 61 | return True; 62 | } 63 | value = src[srcPos++]; 64 | if (value < 0x80) 65 | { 66 | if (dest) 67 | dest[destPos] = (char)value; 68 | destPos++; 69 | continue; 70 | } 71 | if (value >= 0xD800 && value < 0xE000) 72 | { 73 | UInt32 c2; 74 | if (value >= 0xDC00 || srcPos == srcLen) 75 | break; 76 | c2 = src[srcPos++]; 77 | if (c2 < 0xDC00 || c2 >= 0xE000) 78 | break; 79 | value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; 80 | } 81 | for (numAdds = 1; numAdds < 5; numAdds++) 82 | if (value < (((UInt32)1) << (numAdds * 5 + 6))) 83 | break; 84 | if (dest) 85 | dest[destPos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); 86 | destPos++; 87 | do 88 | { 89 | numAdds--; 90 | if (dest) 91 | dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); 92 | destPos++; 93 | } 94 | while (numAdds != 0); 95 | } 96 | *destLen = destPos; 97 | return False; 98 | } 99 | 100 | static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen) 101 | { 102 | size_t destLen = 0; 103 | Bool res; 104 | Utf16_To_Utf8(NULL, &destLen, src, srcLen); 105 | destLen += 1; 106 | if (!Buf_EnsureSize(dest, destLen)) 107 | return SZ_ERROR_MEM; 108 | res = Utf16_To_Utf8(dest->data, &destLen, src, srcLen); 109 | dest->data[destLen] = 0; 110 | return res ? SZ_OK : SZ_ERROR_FAIL; 111 | } 112 | #endif 113 | 114 | static WRes Utf16_To_Char(CBuf *buf, const UInt16 *s, int fileMode) 115 | { 116 | int len = 0; 117 | for (len = 0; s[len] != '\0'; len++); 118 | 119 | #ifdef _WIN32 120 | { 121 | int size = len * 3 + 100; 122 | if (!Buf_EnsureSize(buf, size)) 123 | return SZ_ERROR_MEM; 124 | { 125 | char defaultChar = '_'; 126 | BOOL defUsed; 127 | int numChars = WideCharToMultiByte(fileMode ? (AreFileApisANSI() ? CP_ACP : CP_OEMCP) : CP_OEMCP, 128 | 0, s, len, (char *)buf->data, size, &defaultChar, &defUsed); 129 | if (numChars == 0 || numChars >= size) 130 | return SZ_ERROR_FAIL; 131 | buf->data[numChars] = 0; 132 | return SZ_OK; 133 | } 134 | } 135 | #else 136 | fileMode = fileMode; 137 | return Utf16_To_Utf8Buf(buf, s, len); 138 | #endif 139 | } 140 | 141 | static WRes MyCreateDir(const UInt16 *name, const char *threadCwd) 142 | { 143 | #ifdef USE_WINDOWS_FILE 144 | /* FIXME: windows lacks threadCwd support */ 145 | 146 | return CreateDirectoryW(name, NULL) ? 0 : GetLastError(); 147 | 148 | #else 149 | 150 | CBuf buf; 151 | WRes res; 152 | Buf_Init(&buf); 153 | RINOK(Utf16_To_Char(&buf, name, 1)); 154 | 155 | char *qualName = (char*) buf.data; 156 | if (threadCwd != NULL) { 157 | qualName = (char *) malloc(strlen(threadCwd) + strlen(qualName) + 1); 158 | strcpy(qualName, threadCwd); 159 | strcat(qualName, (char*) buf.data); 160 | } 161 | 162 | res = 163 | #ifdef _WIN32 164 | _mkdir((const char *)qualName) 165 | #else 166 | mkdir((const char *)qualName, 0777) 167 | #endif 168 | == 0 ? 0 : errno; 169 | Buf_Free(&buf, &g_Alloc); 170 | if (qualName != (char*)buf.data) { 171 | free(qualName); 172 | } 173 | return res; 174 | 175 | #endif 176 | } 177 | 178 | static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name, const char *threadCwd) 179 | { 180 | #ifdef USE_WINDOWS_FILE 181 | return OutFile_OpenW(p, name); 182 | #else 183 | CBuf buf; 184 | WRes res; 185 | Buf_Init(&buf); 186 | RINOK(Utf16_To_Char(&buf, name, 1)); 187 | res = OutFile_Open(p, (const char *)buf.data, threadCwd); 188 | Buf_Free(&buf, &g_Alloc); 189 | return res; 190 | #endif 191 | } 192 | 193 | //static void PrintString(const UInt16 *s) 194 | //{ 195 | // CBuf buf; 196 | // Buf_Init(&buf); 197 | // if (Utf16_To_Char(&buf, s, 0) == 0) 198 | // { 199 | // printf("%s", buf.data); 200 | // } 201 | // Buf_Free(&buf, &g_Alloc); 202 | //} 203 | 204 | //static void UInt64ToStr(UInt64 value, char *s) 205 | //{ 206 | // char temp[32]; 207 | // int pos = 0; 208 | // do 209 | // { 210 | // temp[pos++] = (char)('0' + (unsigned)(value % 10)); 211 | // value /= 10; 212 | // } 213 | // while (value != 0); 214 | // do 215 | // *s++ = temp[--pos]; 216 | // while (pos); 217 | // *s = '\0'; 218 | //} 219 | 220 | //static char *UIntToStr(char *s, unsigned value, int numDigits) 221 | //{ 222 | // char temp[16]; 223 | // int pos = 0; 224 | // do 225 | // temp[pos++] = (char)('0' + (value % 10)); 226 | // while (value /= 10); 227 | // for (numDigits -= pos; numDigits > 0; numDigits--) 228 | // *s++ = '0'; 229 | // do 230 | // *s++ = temp[--pos]; 231 | // while (pos); 232 | // *s = '\0'; 233 | // return s; 234 | //} 235 | 236 | #define PERIOD_4 (4 * 365 + 1) 237 | #define PERIOD_100 (PERIOD_4 * 25 - 1) 238 | #define PERIOD_400 (PERIOD_100 * 4 + 1) 239 | 240 | //static void ConvertFileTimeToString(const CNtfsFileTime *ft, char *s) 241 | //{ 242 | // unsigned year, mon, day, hour, min, sec; 243 | // UInt64 v64 = (ft->Low | ((UInt64)ft->High << 32)) / 10000000; 244 | // Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 245 | // unsigned t; 246 | // UInt32 v; 247 | // sec = (unsigned)(v64 % 60); v64 /= 60; 248 | // min = (unsigned)(v64 % 60); v64 /= 60; 249 | // hour = (unsigned)(v64 % 24); v64 /= 24; 250 | // 251 | // v = (UInt32)v64; 252 | // 253 | // year = (unsigned)(1601 + v / PERIOD_400 * 400); 254 | // v %= PERIOD_400; 255 | // 256 | // t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100; 257 | // t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4; 258 | // t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365; 259 | // 260 | // if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) 261 | // ms[1] = 29; 262 | // for (mon = 1; mon <= 12; mon++) 263 | // { 264 | // unsigned s = ms[mon - 1]; 265 | // if (v < s) 266 | // break; 267 | // v -= s; 268 | // } 269 | // day = (unsigned)v + 1; 270 | // s = UIntToStr(s, year, 4); *s++ = '-'; 271 | // s = UIntToStr(s, mon, 2); *s++ = '-'; 272 | // s = UIntToStr(s, day, 2); *s++ = ' '; 273 | // s = UIntToStr(s, hour, 2); *s++ = ':'; 274 | // s = UIntToStr(s, min, 2); *s++ = ':'; 275 | // s = UIntToStr(s, sec, 2); 276 | // s = s; // Avoids clang analyzer error about s value not being read 277 | //} 278 | 279 | void PrintError(char *sz) 280 | { 281 | printf("\nERROR: %s\n", sz); 282 | } 283 | 284 | //#ifdef USE_WINDOWS_FILE 285 | //#define kEmptyAttribChar '.' 286 | //static void GetAttribString(UInt32 wa, Bool isDir, char *s) 287 | //{ 288 | // s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : kEmptyAttribChar); 289 | // s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar); 290 | // s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar); 291 | // s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar); 292 | // s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar); 293 | // s[5] = '\0'; 294 | //} 295 | //#else 296 | //static void GetAttribString(UInt32 wa, Bool isDir, char *s) 297 | //{ 298 | // s[0] = '\0'; 299 | //} 300 | //#endif 301 | 302 | //int MY_CDECL unused_main(int numargs, char *args[]) 303 | //{ 304 | // CFileInStream archiveStream; 305 | // CLookToRead lookStream; 306 | // CSzArEx db; 307 | // SRes res; 308 | // ISzAlloc allocImp; 309 | // ISzAlloc allocTempImp; 310 | // UInt16 *temp = NULL; 311 | // size_t tempSize = 0; 312 | // 313 | // printf("\n7z ANSI-C Decoder " MY_VERSION_COPYRIGHT_DATE "\n\n"); 314 | // if (numargs == 1) 315 | // { 316 | // printf( 317 | // "Usage: 7zDec \n\n" 318 | // "\n" 319 | // " e: Extract files from archive (without using directory names)\n" 320 | // " l: List contents of archive\n" 321 | // " t: Test integrity of archive\n" 322 | // " x: eXtract files with full paths\n"); 323 | // return 0; 324 | // } 325 | // if (numargs < 3) 326 | // { 327 | // PrintError("incorrect command"); 328 | // return 1; 329 | // } 330 | // 331 | // allocImp.Alloc = SzAlloc; 332 | // allocImp.Free = SzFree; 333 | // 334 | // allocTempImp.Alloc = SzAllocTemp; 335 | // allocTempImp.Free = SzFreeTemp; 336 | // 337 | // if (InFile_Open(&archiveStream.file, args[2])) 338 | // { 339 | // PrintError("can not open input file"); 340 | // return 1; 341 | // } 342 | // 343 | // FileInStream_CreateVTable(&archiveStream); 344 | // LookToRead_CreateVTable(&lookStream, False); 345 | // 346 | // lookStream.realStream = &archiveStream.s; 347 | // LookToRead_Init(&lookStream); 348 | // 349 | //#ifdef _7ZIP_CRC_SUPPORT 350 | // CrcGenerateTable(); 351 | //#endif 352 | // 353 | // SzArEx_Init(&db); 354 | // res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp); 355 | // if (res == SZ_OK) 356 | // { 357 | // char *command = args[1]; 358 | // int listCommand = 0, testCommand = 0, /*extractCommand = 0,*/ fullPaths = 0; 359 | // if (strcmp(command, "l") == 0) listCommand = 1; 360 | // else if (strcmp(command, "t") == 0) testCommand = 1; 361 | // else if (strcmp(command, "e") == 0) { /*extractCommand = 1;*/ } 362 | // else if (strcmp(command, "x") == 0) { /*extractCommand = 1;*/ fullPaths = 1; } 363 | // else 364 | // { 365 | // PrintError("incorrect command"); 366 | // res = SZ_ERROR_FAIL; 367 | // } 368 | // 369 | // if (res == SZ_OK) 370 | // { 371 | // UInt32 i; 372 | // 373 | // /* 374 | // if you need cache, use these 3 variables. 375 | // if you use external function, you can make these variable as static. 376 | // */ 377 | // UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */ 378 | // Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */ 379 | // size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */ 380 | // 381 | // for (i = 0; i < db.db.NumFiles; i++) 382 | // { 383 | // size_t offset = 0; 384 | // size_t outSizeProcessed = 0; 385 | // const CSzFileItem *f = db.db.Files + i; 386 | // size_t len; 387 | // if (listCommand == 0 && f->IsDir && !fullPaths) 388 | // continue; 389 | // len = SzArEx_GetFileNameUtf16(&db, i, NULL); 390 | // 391 | // if (len > tempSize) 392 | // { 393 | // SzFree(NULL, temp); 394 | // tempSize = len; 395 | // temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0])); 396 | // if (temp == 0) 397 | // { 398 | // res = SZ_ERROR_MEM; 399 | // break; 400 | // } 401 | // } 402 | // 403 | // SzArEx_GetFileNameUtf16(&db, i, temp); 404 | // if (listCommand) 405 | // { 406 | // char attr[8], s[32], t[32]; 407 | // 408 | // GetAttribString(f->AttribDefined ? f->Attrib : 0, f->IsDir, attr); 409 | // 410 | // UInt64ToStr(f->Size, s); 411 | // if (f->MTimeDefined) 412 | // ConvertFileTimeToString(&f->MTime, t); 413 | // else 414 | // { 415 | // size_t j; 416 | // for (j = 0; j < 19; j++) 417 | // t[j] = ' '; 418 | // t[j] = '\0'; 419 | // } 420 | // 421 | // printf("%s %s %10s ", t, attr, s); 422 | // PrintString(temp); 423 | // if (f->IsDir) 424 | // printf("/"); 425 | // printf("\n"); 426 | // continue; 427 | // } 428 | // printf(testCommand ? 429 | // "Testing ": 430 | // "Extracting "); 431 | // PrintString(temp); 432 | // if (f->IsDir) 433 | // printf("/"); 434 | // else 435 | // { 436 | // res = SzArEx_Extract(&db, &lookStream.s, i, 437 | // &blockIndex, &outBuffer, &outBufferSize, 438 | // &offset, &outSizeProcessed, 439 | // &allocImp, &allocTempImp); 440 | // if (res != SZ_OK) 441 | // break; 442 | // } 443 | // if (!testCommand) 444 | // { 445 | // CSzFile outFile; 446 | // size_t processedSize; 447 | // size_t j; 448 | // UInt16 *name = (UInt16 *)temp; 449 | // const UInt16 *destPath = (const UInt16 *)name; 450 | // for (j = 0; (name != NULL) && (name[j] != 0); j++) 451 | // if (name[j] == '/') 452 | // { 453 | // if (fullPaths) 454 | // { 455 | // name[j] = 0; 456 | // MyCreateDir(name); 457 | // name[j] = CHAR_PATH_SEPARATOR; 458 | // } 459 | // else 460 | // destPath = name + j + 1; 461 | // } 462 | // 463 | // if (f->IsDir) 464 | // { 465 | // MyCreateDir(destPath); 466 | // printf("\n"); 467 | // continue; 468 | // } 469 | // else if (OutFile_OpenUtf16(&outFile, destPath)) 470 | // { 471 | // PrintError("can not open output file"); 472 | // res = SZ_ERROR_FAIL; 473 | // break; 474 | // } 475 | // processedSize = outSizeProcessed; 476 | // if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed) 477 | // { 478 | // PrintError("can not write output file"); 479 | // res = SZ_ERROR_FAIL; 480 | // break; 481 | // } 482 | // if (File_Close(&outFile)) 483 | // { 484 | // PrintError("can not close output file"); 485 | // res = SZ_ERROR_FAIL; 486 | // break; 487 | // } 488 | // #ifdef USE_WINDOWS_FILE 489 | // if (f->AttribDefined) 490 | // SetFileAttributesW(destPath, f->Attrib); 491 | // #endif 492 | // } 493 | // printf("\n"); 494 | // } 495 | // IAlloc_Free(&allocImp, outBuffer); 496 | // } 497 | // } 498 | // SzArEx_Free(&db, &allocImp); 499 | // SzFree(NULL, temp); 500 | // 501 | // File_Close(&archiveStream.file); 502 | // if (res == SZ_OK) 503 | // { 504 | // printf("\nEverything is Ok\n"); 505 | // return 0; 506 | // } 507 | // if (res == SZ_ERROR_UNSUPPORTED) 508 | // PrintError("decoder doesn't support this archive"); 509 | // else if (res == SZ_ERROR_MEM) 510 | // PrintError("can not allocate memory"); 511 | // else if (res == SZ_ERROR_CRC) 512 | // PrintError("CRC error"); 513 | // else 514 | // printf("\nERROR #%d\n", res); 515 | // return 1; 516 | //} 517 | 518 | // This entry point will extract all the contents of a .7z file 519 | // into the current directory when entryName is NULL. If 520 | // entryName is not NULL, then this method will extract a single 521 | // entry that has the name indicated in entryName. When extracting 522 | // all files, the files are created in the current directory. If 523 | // a single file is extracted by passing a non-NULL entryName, 524 | // then the file data is written to the path indicated by entryPath. 525 | 526 | //#define DEBUG_OUTPUT 527 | 528 | int do7z_extract_entry(char *archivePath, char *archiveCachePath, char *threadCwd, char *entryName, char *entryPath, int fullPaths) 529 | { 530 | CFileInStream archiveStream; 531 | CLookToRead lookStream; 532 | CSzArEx db; 533 | SRes res; 534 | ISzAlloc allocImp; 535 | ISzAlloc allocTempImp; 536 | UInt16 *temp = NULL; 537 | size_t tempSize = 0; 538 | int foundMatchingEntryName = 0; 539 | int extractAllFiles = 0; 540 | 541 | /* 542 | printf("\n7z ANSI-C Decoder " MY_VERSION_COPYRIGHT_DATE "\n\n"); 543 | if (numargs == 1) 544 | { 545 | printf( 546 | "Usage: 7zDec \n\n" 547 | "\n" 548 | " e: Extract files from archive (without using directory names)\n" 549 | " l: List contents of archive\n" 550 | " t: Test integrity of archive\n" 551 | " x: eXtract files with full paths\n"); 552 | return 0; 553 | } 554 | if (numargs < 3) 555 | { 556 | PrintError("incorrect command"); 557 | return 1; 558 | } 559 | */ 560 | 561 | allocImp.Alloc = SzAlloc; 562 | allocImp.Free = SzFree; 563 | 564 | allocTempImp.Alloc = SzAllocTemp; 565 | allocTempImp.Free = SzFreeTemp; 566 | 567 | if (InFile_Open(&archiveStream.file, archivePath)) 568 | { 569 | PrintError("can not open input file"); 570 | return 1; 571 | } 572 | 573 | FileInStream_CreateVTable(&archiveStream); 574 | LookToRead_CreateVTable(&lookStream, False); 575 | 576 | lookStream.realStream = &archiveStream.s; 577 | LookToRead_Init(&lookStream); 578 | 579 | #ifdef _7ZIP_CRC_SUPPORT 580 | CrcGenerateTable(); 581 | #else 582 | //CPU_Is_InOrder(); // Not needed currently 583 | #endif 584 | 585 | SzArEx_Init(&db); 586 | res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp); 587 | if (res == SZ_OK) 588 | { 589 | const int extractCommand = 1; 590 | 591 | assert(archiveCachePath); 592 | 593 | if (entryName == NULL) { 594 | extractAllFiles = 1; 595 | } else { 596 | assert(strlen(entryName) > 0); 597 | assert(entryPath != NULL); 598 | assert(strlen(entryPath) > 0); 599 | } 600 | 601 | if (extractCommand) 602 | { 603 | UInt32 i; 604 | 605 | // The dictionary cache contains data decompressed from the archive. It is managed by 606 | // the library and must be freed when done with processing of a specific archive. 607 | // Note that the cache cannot be saved from one execution to the next, it must 608 | // not exist after this function is done executing. 609 | 610 | SzArEx_DictCache dictCache; 611 | SzArEx_DictCache_init(&dictCache, &allocImp); 612 | 613 | // Enable mmap to file if the archive would be larger than 1/2 meg 614 | dictCache.mapFilename = archiveCachePath; 615 | 616 | for (i = 0; i < db.db.NumFiles; i++) 617 | { 618 | const CSzFileItem *f = db.db.Files + i; 619 | size_t len; 620 | if (f->IsDir && !fullPaths) 621 | continue; 622 | len = SzArEx_GetFileNameUtf16(&db, i, NULL); 623 | 624 | if (len > tempSize) 625 | { 626 | SzFree(NULL, temp); 627 | tempSize = len; 628 | temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0])); 629 | if (temp == 0) 630 | { 631 | res = SZ_ERROR_MEM; 632 | break; 633 | } 634 | } 635 | 636 | SzArEx_GetFileNameUtf16(&db, i, temp); 637 | 638 | #ifdef DEBUG_OUTPUT 639 | printf(testCommand ? 640 | "Testing ": 641 | "Extracting "); 642 | PrintString(temp); 643 | #endif 644 | if (f->IsDir) { 645 | #ifdef DEBUG_OUTPUT 646 | printf("/"); 647 | #endif 648 | } 649 | else 650 | { 651 | // When extracting a specific entry, skip extraction if the 652 | // entry name does not match exatly. 653 | 654 | if (!extractAllFiles) { 655 | CBuf buf; 656 | Buf_Init(&buf); 657 | if (temp && (Utf16_To_Char(&buf, temp, 0) == 0)) 658 | { 659 | if (strcmp((char*)buf.data, entryName) != 0) { 660 | // This is not the entry we are interested in extracting 661 | Buf_Free(&buf, &g_Alloc); 662 | continue; 663 | } 664 | } 665 | Buf_Free(&buf, &g_Alloc); 666 | } 667 | 668 | // if (0) { 669 | // printf("Extracting "); 670 | // PrintString(temp); 671 | // printf("\n"); 672 | // } 673 | 674 | foundMatchingEntryName = 1; 675 | 676 | res = SzArEx_Extract(&db, 677 | &lookStream.s, 678 | i, // archive entry offset 679 | &dictCache, 680 | &allocImp, &allocTempImp); 681 | if (res != SZ_OK) 682 | break; 683 | } 684 | 685 | { 686 | CSzFile outFile; 687 | size_t processedSize; 688 | size_t j; 689 | UInt16 *name = (UInt16 *)temp; 690 | const UInt16 *destPath; 691 | 692 | if (extractAllFiles) { 693 | // Extract to current dir, path is based on the entry path 694 | 695 | destPath = (const UInt16 *)name; 696 | 697 | for (j = 0; name[j] != 0; j++) 698 | { 699 | if (name[j] == '/') 700 | { 701 | if (fullPaths) 702 | { 703 | name[j] = 0; 704 | MyCreateDir(name, threadCwd); 705 | name[j] = CHAR_PATH_SEPARATOR; 706 | } 707 | else { 708 | destPath = name + j + 1; 709 | } 710 | } 711 | } 712 | } else { 713 | // Extract to specific fully qualified path 714 | 715 | SzFree(NULL, temp); 716 | temp = (UInt16 *)SzAlloc(NULL, (strlen(entryPath) + 1) * sizeof(UInt16)); 717 | int i = 0; 718 | for (i = 0; i < strlen(entryPath); i++) { 719 | temp[i] = entryPath[i]; 720 | } 721 | temp[i] = '\0'; 722 | destPath = (const UInt16 *) temp; 723 | } 724 | 725 | if (f->IsDir) 726 | { 727 | MyCreateDir(destPath, threadCwd); 728 | #ifdef DEBUG_OUTPUT 729 | printf("\n"); 730 | #endif 731 | continue; 732 | } 733 | else if (OutFile_OpenUtf16(&outFile, destPath, threadCwd)) 734 | { 735 | PrintError("can not open output file"); 736 | res = SZ_ERROR_FAIL; 737 | break; 738 | } 739 | processedSize = dictCache.outSizeProcessed; 740 | void *entryPtr = dictCache.outBuffer + dictCache.entryOffset; 741 | if (File_Write(&outFile, entryPtr, &processedSize) != 0 || processedSize != dictCache.outSizeProcessed) 742 | { 743 | PrintError("can not write output file"); 744 | res = SZ_ERROR_FAIL; 745 | break; 746 | } 747 | if (File_Close(&outFile)) 748 | { 749 | PrintError("can not close output file"); 750 | res = SZ_ERROR_FAIL; 751 | break; 752 | } 753 | } 754 | #ifdef DEBUG_OUTPUT 755 | printf("\n"); 756 | #endif 757 | } 758 | SzArEx_DictCache_free(&dictCache); 759 | } 760 | } 761 | SzArEx_Free(&db, &allocImp); 762 | SzFree(NULL, temp); 763 | 764 | File_Close(&archiveStream.file); 765 | if (!extractAllFiles && (foundMatchingEntryName == 0)) { 766 | // Did not find a matching entry in the archive 767 | #ifdef DEBUG_OUTPUT 768 | printf("\nCould not find matching entry in archive\n"); 769 | #endif 770 | return 1; 771 | } 772 | 773 | if (archiveCachePath) { 774 | // remove cache file if it exists 775 | unlink(archiveCachePath); 776 | } 777 | 778 | if (res == SZ_OK) 779 | { 780 | #ifdef DEBUG_OUTPUT 781 | printf("\nEverything is Ok\n"); 782 | #endif 783 | return 0; 784 | } 785 | if (res == SZ_ERROR_UNSUPPORTED) 786 | PrintError("decoder doesn't support this archive"); 787 | else if (res == SZ_ERROR_MEM) 788 | PrintError("can not allocate memory"); 789 | else if (res == SZ_ERROR_CRC) 790 | PrintError("CRC error"); 791 | else 792 | printf("\nERROR #%d\n", res); 793 | return 1; 794 | } 795 | -------------------------------------------------------------------------------- /Classes/lzmaSDKAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // lzmaSDKAppDelegate.h 3 | // lzmaSDK 4 | // 5 | // Created by Moses DeJong on 11/30/09. 6 | // Copyright __MyCompanyName__ 2009. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface lzmaSDKAppDelegate : NSObject { 12 | UIWindow *window; 13 | } 14 | 15 | @property (nonatomic, retain) IBOutlet UIWindow *window; 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /Classes/lzmaSDKAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // lzmaSDKAppDelegate.m 3 | // lzmaSDK 4 | // 5 | // Created by Moses DeJong on 11/30/09. 6 | // 7 | 8 | #import "lzmaSDKAppDelegate.h" 9 | 10 | #import "LZMAExtractor.h" 11 | 12 | 13 | // Return TRUE if file exists, FALSE otherwise 14 | 15 | BOOL fileExists(NSString *filePath) { 16 | if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { 17 | return TRUE; 18 | } else { 19 | return FALSE; 20 | } 21 | } 22 | 23 | // Query open file size, then rewind to start 24 | 25 | static 26 | uint32_t filesize(char *filepath) { 27 | int retcode; 28 | FILE *fp = fopen(filepath, "r"); 29 | retcode = fseek(fp, 0, SEEK_END); 30 | assert(retcode == 0); 31 | uint32_t size = (uint32_t) ftell(fp); 32 | fclose(fp); 33 | return size; 34 | } 35 | 36 | @implementation lzmaSDKAppDelegate 37 | 38 | @synthesize window; 39 | 40 | // This test decodes a small text file from the attached resource test.7z 41 | // This is a basic sanity check of the logic to decode an entry to a .7z archive. 42 | // Because the input archive and output files are small, this test case will 43 | // not use up much memory or emit large files. Note that because this dictionary 44 | // size is smaller than the 1 meg k7zUnpackMapDictionaryInMemoryMaxNumBytes limit, 45 | // this unpack operaiton will be done entirely in memory as opposed to using 46 | // mapped memory that is paged to disk. 47 | 48 | - (void) testSmallInMem 49 | { 50 | NSLog(@"START testSmallInMem"); 51 | 52 | BOOL worked; 53 | 54 | // Extract files from archive into named dir in the temp dir 55 | 56 | NSString *tmpDirname = @"Extract7z"; 57 | NSString *archiveFilename = @"test.7z"; 58 | NSString *archiveResPath = [[NSBundle mainBundle] pathForResource:archiveFilename ofType:nil]; 59 | NSAssert(archiveResPath, @"can't find test.7z"); 60 | 61 | NSArray *contents = [LZMAExtractor extract7zArchive:archiveResPath 62 | tmpDirName:tmpDirname]; 63 | 64 | for (NSString *entryPath in contents) { 65 | NSData *outputData = [NSData dataWithContentsOfFile:entryPath]; 66 | NSString *outStr = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; 67 | [outStr autorelease]; 68 | 69 | NSLog(@"%@", entryPath); 70 | NSLog(@"%@", outStr); 71 | } 72 | 73 | // Extract single entry "make.out" and save it as "tmp/make.out.txt" in the tmp dir. 74 | 75 | NSString *entryFilename = @"make.out"; 76 | NSString *makeTmpFilename = @"make.out.txt"; 77 | NSString *makeTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:makeTmpFilename]; 78 | 79 | worked = [LZMAExtractor extractArchiveEntry:archiveResPath 80 | archiveEntry:entryFilename 81 | outPath:makeTmpPath]; 82 | 83 | if (worked) { 84 | NSData *outputData = [NSData dataWithContentsOfFile:makeTmpPath]; 85 | NSString *outStr = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; 86 | [outStr autorelease]; 87 | 88 | NSLog(@"%@", makeTmpFilename); 89 | NSLog(@"%@", outStr); 90 | } 91 | 92 | NSLog(@"DONE testSmallInMem"); 93 | } 94 | 95 | // This test decodes a small text file from the attached resource test.7z 96 | // This is a basic sanity check of the logic to decode an entry to a .7z archive. 97 | // Because the input archive and output files are small, this test case will 98 | // not use up much memory or emit large files. Note that because this dictionary 99 | // size is smaller than the 1 meg k7zUnpackMapDictionaryInMemoryMaxNumBytes limit, 100 | // this unpack operaiton will be done entirely in memory as opposed to using 101 | // mapped memory that is paged to disk. 102 | 103 | - (void) testFilesAndDirs 104 | { 105 | NSLog(@"START testFilesAndDirs"); 106 | 107 | BOOL worked; 108 | 109 | // Extract dirs files 110 | 111 | NSString *archiveFilename = @"files_dirs.7z"; 112 | NSString *archiveResPath = [[NSBundle mainBundle] pathForResource:archiveFilename ofType:nil]; 113 | NSAssert(archiveResPath, @"can't find %@", archiveFilename); 114 | 115 | NSArray *contents = [LZMAExtractor extract7zArchive:archiveResPath 116 | dirName:NSTemporaryDirectory() 117 | preserveDir:TRUE]; 118 | 119 | for (NSString *entryPath in contents) { 120 | NSData *outputData = [NSData dataWithContentsOfFile:entryPath]; 121 | NSString *outStr = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; 122 | [outStr autorelease]; 123 | 124 | NSLog(@"%@", entryPath); 125 | NSLog(@"%@", outStr); 126 | } 127 | 128 | // Extract single entry "d2/f_2_1" and save it as "d2_f_2_1" in the tmp dir. 129 | 130 | NSString *entryFilename = @"d2/f_2_1"; 131 | NSString *makeTmpFilename = @"d2_f_2_1"; 132 | NSString *makeTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:makeTmpFilename]; 133 | 134 | worked = [LZMAExtractor extractArchiveEntry:archiveResPath 135 | archiveEntry:entryFilename 136 | outPath:makeTmpPath]; 137 | 138 | if (worked) { 139 | NSData *outputData = [NSData dataWithContentsOfFile:makeTmpPath]; 140 | NSString *outStr = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; 141 | [outStr autorelease]; 142 | 143 | NSLog(@"%@", makeTmpFilename); 144 | NSLog(@"%@", outStr); 145 | } 146 | 147 | NSLog(@"DONE testFilesAndDirs"); 148 | } 149 | 150 | // This test will extract a 500 meg file from a solid archive, this 500 meg file is way too large 151 | // to fit into regular memory, but it is smaller than the 700 meg limit on mapped memory 152 | // in iOS. This test will pass as long as the modification to the lzma SDK is implemented 153 | // so that memory is paged to disk when the dictionary size is large. 154 | // 155 | // Create: 156 | // 157 | // 7za a -mx=9 halfgig.7z halfgig.data 158 | // 159 | // The output of: 160 | // 161 | // 7za l -slt halfgig.7z 162 | // 163 | // Shows that the entire 500 meg file is stored as one large block. 164 | 165 | - (void) testHalfGig 166 | { 167 | NSLog(@"START testHalfGig"); 168 | 169 | // Extract files from archive into named dir in the temp dir 170 | 171 | NSString *archiveFilename = @"halfgig.7z"; 172 | NSString *archiveResPath = [[NSBundle mainBundle] pathForResource:archiveFilename ofType:nil]; 173 | NSAssert(archiveResPath, @"can't find %@", archiveFilename); 174 | 175 | NSString *tmpFilename = @"halfgig.data"; 176 | NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:tmpFilename]; 177 | 178 | BOOL worked = [LZMAExtractor extractArchiveEntry:archiveResPath archiveEntry:tmpFilename outPath:tmpPath]; 179 | NSAssert(worked, @"worked"); 180 | 181 | // Note that it will not be possible to hold this massive file in memory or even map the whole file. 182 | // It can only be streamed from disk. 183 | 184 | BOOL exists = fileExists(tmpPath); 185 | NSAssert(exists, @"exists"); 186 | 187 | uint32_t size = filesize((char*)[tmpPath UTF8String]); 188 | 189 | NSLog(@"%@ : size %d", tmpFilename, size); 190 | 191 | // 500 megs 192 | 193 | NSAssert(size == 1073741824/2, @"size"); 194 | 195 | // Make sure to delete this massive file 196 | 197 | worked = [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:nil]; 198 | NSAssert(worked, @"worked"); 199 | 200 | NSLog(@"DONE testHalfGig"); 201 | 202 | return; 203 | } 204 | 205 | // This test attempts to extract a massive 1 gig file out of an archive, the file 206 | // is so large that it cannot be held in regular memory on iOS. It also it too big 207 | // to be held in virtual memory as a memory mapped file, so the only way that this 208 | // file can be written to the disk is by streaming one buffer at a time. This test 209 | // case basically checks the implementation of the SDK to verify that data is decoded 210 | // and streamed to the disk as opposed to one massive malloc call that will fail 211 | // on an embedded system. This test will pass on the Simulator, because MacOSX will 212 | // automatically switch to virtual memory for a very large malloc. 213 | 214 | - (void) testOneGigFailTooBig 215 | { 216 | NSLog(@"START testOneGigFailTooBig"); 217 | 218 | // This archive contains a 1 gigabyte file created like so: 219 | // 7za a -mx=9 onegig.7z onegig.data 220 | // 221 | // This should fail to decompress on an iOS device because the size of the vmem 222 | // mapping is larger than the maximum size allowed by the OS. 223 | // 224 | // The output of: 225 | // 226 | // 7za l -slt onegig.7z 227 | // 228 | // Shows that the entire one gig file was compressed down into 1 single block, so 229 | // there is no way for iOS to allocate a buffer that large. 230 | 231 | NSString *archiveFilename = @"onegig.7z"; 232 | NSString *archiveResPath = [[NSBundle mainBundle] pathForResource:archiveFilename ofType:nil]; 233 | NSAssert(archiveResPath, @"can't find %@", archiveFilename); 234 | 235 | // Extract single entry "onegig.data" into the tmp dir 236 | 237 | NSString *tmpFilename = @"onegig.data"; 238 | NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:tmpFilename]; 239 | 240 | // Make sure file does not exist from some previous run at this point 241 | [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:nil]; 242 | 243 | BOOL worked = [LZMAExtractor extractArchiveEntry:archiveResPath archiveEntry:tmpFilename outPath:tmpPath]; 244 | 245 | if (TARGET_IPHONE_SIMULATOR) { 246 | NSAssert(worked == TRUE, @"worked"); 247 | } else { 248 | // Device, should fail 249 | NSAssert(worked == FALSE, @"worked"); 250 | 251 | BOOL exists = fileExists(tmpPath); 252 | NSAssert(exists == FALSE, @"exists"); 253 | } 254 | 255 | // Note that it will not be possible to hold this massive file in memory or even map the whole file. 256 | // It can only be streamed from disk. 257 | 258 | BOOL exists = fileExists(tmpPath); 259 | if (exists) { 260 | uint32_t size = filesize((char*)[tmpPath UTF8String]); 261 | 262 | NSLog(@"%@ : size %d", tmpFilename, size); 263 | 264 | // 1 gig 265 | 266 | NSAssert(size == 1073741824, @"size"); 267 | 268 | // Make sure to delete this massive file 269 | 270 | worked = [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:nil]; 271 | NSAssert(worked, @"worked"); 272 | } 273 | 274 | NSLog(@"DONE testOneGigFailTooBig"); 275 | return; 276 | } 277 | 278 | // This test will extract a pair of huge 650 meg files from a single archive. 279 | // If both files were stored into 1 block, the mapping operation would fail 280 | // on the device because the mapped size would be too large. But, one can work 281 | // around the upper limit if absolutely required by encoding the archive 282 | // with multiple blocks. 283 | // 284 | // Each block is decoded one at a time, so each file is able to fit into 285 | // memory only one at a time. The key here is to pass these 680m arguments 286 | // when encoding to define the upper limit of a block size, the result is 287 | // that each file is contained in its own block. 288 | // 289 | // Create: 290 | // 291 | // 7za a -mx=9 -md=680m -ms=680m sixfiftymeg_2blocks.7z sixfiftymeg1.data sixfiftymeg2.data 292 | // 293 | // The output of: 294 | // 295 | // 7za l -slt sixfiftymeg_2blocks.7z 296 | // 297 | // Shows that two blocks are defined in the archive, each one contains one of the 650 meg files. 298 | 299 | - (void) decodeSixFifty:(NSString*)entryName 300 | { 301 | // Extract files from archive into named dir in the temp dir 302 | 303 | NSString *archiveFilename = @"sixfiftymeg_2blocks.7z"; 304 | NSString *archiveResPath = [[NSBundle mainBundle] pathForResource:archiveFilename ofType:nil]; 305 | NSAssert(archiveResPath, @"can't find %@", archiveFilename); 306 | 307 | NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:entryName]; 308 | 309 | BOOL worked = [LZMAExtractor extractArchiveEntry:archiveResPath archiveEntry:entryName outPath:tmpPath]; 310 | NSAssert(worked, @"worked"); 311 | 312 | // Note that it will not be possible to hold this massive file in memory or even map the whole file. 313 | // It can only be streamed from disk. 314 | 315 | BOOL exists = fileExists(tmpPath); 316 | NSAssert(exists, @"exists"); 317 | 318 | uint32_t size = filesize((char*)[tmpPath UTF8String]); 319 | 320 | NSLog(@"%@ : size %d", entryName, size); 321 | 322 | // 650 megs 323 | 324 | NSAssert(size == (1024 * 1024 * 650), @"size"); 325 | 326 | // Delete the file on disk 327 | 328 | worked = [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:nil]; 329 | NSAssert(worked, @"worked"); 330 | 331 | return; 332 | } 333 | 334 | - (void) testTwoSixFiftyInTwoBlocks 335 | { 336 | NSLog(@"START testTwoSixFiftyInTwoBlocks"); 337 | 338 | NSString *makeTmpFilename; 339 | makeTmpFilename = @"sixfiftymeg1.data"; 340 | [self decodeSixFifty:makeTmpFilename]; 341 | 342 | makeTmpFilename = @"sixfiftymeg2.data"; 343 | [self decodeSixFifty:makeTmpFilename]; 344 | 345 | NSLog(@"DONE testTwoSixFiftyInTwoBlocks"); 346 | 347 | return; 348 | } 349 | 350 | 351 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 352 | { 353 | // Override point for customization after application launch 354 | UIViewController *viewController = [[UIViewController alloc] init]; 355 | [viewController autorelease]; 356 | window.rootViewController = viewController; 357 | [window makeKeyAndVisible]; 358 | 359 | NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 360 | target:self 361 | selector:@selector(startupTimer:) 362 | userInfo:nil 363 | repeats:FALSE]; 364 | 365 | 366 | [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; 367 | 368 | return TRUE; 369 | } 370 | 371 | // This callback timer runs after the app has started. If we left this blocking logic in 372 | // didFinishLaunchingWithOptions then the OS would think the app did not start and it could 373 | // be killed. 374 | 375 | - (void) startupTimer:(NSTimer*)timer 376 | { 377 | NSLog(@"START"); 378 | 379 | [self testSmallInMem]; 380 | 381 | [self testFilesAndDirs]; 382 | 383 | [self testHalfGig]; 384 | 385 | [self testTwoSixFiftyInTwoBlocks]; 386 | 387 | //[self testOneGigFailTooBig]; 388 | 389 | NSLog(@"DONE"); 390 | 391 | window.backgroundColor = [UIColor greenColor]; 392 | } 393 | 394 | - (void)dealloc { 395 | [window release]; 396 | [super dealloc]; 397 | } 398 | 399 | @end 400 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | This LZMA SDK source code is public domain. This code is based on public domain code from http://www.7-zip.org/sdk.html 2 | 3 | -------------------------------------------------------------------------------- /MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 768 5 | 10A288 6 | 715 7 | 1010 8 | 411.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 46 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | 35 | 36 | IBFirstResponder 37 | 38 | 39 | 40 | 41 | 1316 42 | 43 | {320, 480} 44 | 45 | 46 | 1 47 | MSAxIDEAA 48 | 49 | NO 50 | NO 51 | 52 | 53 | 54 | 55 | 56 | YES 57 | 58 | 59 | delegate 60 | 61 | 62 | 63 | 4 64 | 65 | 66 | 67 | window 68 | 69 | 70 | 71 | 5 72 | 73 | 74 | 75 | 76 | YES 77 | 78 | 0 79 | 80 | 81 | 82 | 83 | 84 | 2 85 | 86 | 87 | YES 88 | 89 | 90 | 91 | 92 | -1 93 | 94 | 95 | File's Owner 96 | 97 | 98 | 3 99 | 100 | 101 | 102 | 103 | -2 104 | 105 | 106 | 107 | 108 | 109 | 110 | YES 111 | 112 | YES 113 | -1.CustomClassName 114 | -2.CustomClassName 115 | 2.IBAttributePlaceholdersKey 116 | 2.IBEditorWindowLastContentRect 117 | 2.IBPluginDependency 118 | 3.CustomClassName 119 | 3.IBPluginDependency 120 | 121 | 122 | YES 123 | UIApplication 124 | UIResponder 125 | 126 | YES 127 | 128 | 129 | YES 130 | 131 | 132 | {{438, 320}, {320, 480}} 133 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 134 | lzmaSDKAppDelegate 135 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 136 | 137 | 138 | 139 | YES 140 | 141 | 142 | YES 143 | 144 | 145 | 146 | 147 | YES 148 | 149 | 150 | YES 151 | 152 | 153 | 154 | 9 155 | 156 | 157 | 158 | YES 159 | 160 | lzmaSDKAppDelegate 161 | NSObject 162 | 163 | window 164 | UIWindow 165 | 166 | 167 | IBProjectSource 168 | Classes/lzmaSDKAppDelegate.h 169 | 170 | 171 | 172 | lzmaSDKAppDelegate 173 | NSObject 174 | 175 | IBUserSource 176 | 177 | 178 | 179 | 180 | 181 | 0 182 | 183 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 184 | 185 | 186 | YES 187 | lzmaSDK.xcodeproj 188 | 3 189 | 190 | 191 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | This directory contains the LZMA SDK customized for an embedded system (iPhone/iOS) 2 | Only the file extraction logic was included, all code related to creating 3 | compressed streams was removed. CRC validation was removed to 4 | improve performance. In addition, large file support was added so that iOS 5 | is able to decompress files as large as 650 megs using memory mapped IO. 6 | This code is based on lzma release 9.22 beta. 7 | 8 | Note that when incorporating the code into a new project, copy only the 9 | LZMASDK directory in the Classes subdir into your iOS project. All of the 10 | other files in this example iOS app exist just to illustrate how to use 11 | the SDK code in the LZMASDK directory. 12 | 13 | The code was modified as follows: 14 | 15 | Embedded version does not need exe branch predictors. 16 | 17 | Bra.c 18 | Bcj2.c 19 | Bra86.c 20 | 21 | File List: 22 | 23 | 7zBuf.c 24 | 7zCrc.c 25 | 7zFile.c 26 | 7zStream.c 27 | LzHash.h 28 | LzmaDec.h 29 | 7zBuf.h 30 | 7zCrc.h 31 | 7zFile.h 32 | 7zVersion.h 33 | CpuArch.h 34 | LzmaDec.c 35 | Types.h 36 | 37 | Removed: 38 | 39 | (XZ file format support) 40 | Xz.* 41 | 42 | MtCoder.c 43 | 44 | Ppmd7Enc.c 45 | 46 | Sha256.* 47 | 48 | lzma Search (encode) functions 49 | 50 | rm LzFind* 51 | 52 | rm Threads.* 53 | 54 | rm Bra* 55 | 56 | rm Bcj2.* 57 | 58 | rm lzmaEnc* lzma2Enc.* 59 | 60 | The 7z.h and 7zIn.c files were modified to support memory mapping the dictionary 61 | cache file so that large files can be decompressed without having to break archives 62 | up into blocks. While splitting into blocks makes it possible to create an archive 63 | with lots of little files in different blocks, it makes compression much worse. 64 | Large file support makes it possible to get maximum compression by putting all 65 | the files into 1 block, but the downside is that the decode process is slower 66 | due to the use of memory mapped IO writes. See the k7zUnpackMapDictionaryInMemoryMaxNumBytes 67 | define in 7z.h if you want to change the size at which memory mapped IO kicks in, 68 | currently archives larger than 1 meg will use memory mapped IO. 69 | 70 | To update to a new version of the LZMA SDK, use the update.tcl to copy over those 71 | files that were used in this version. Note that updating is not trivial since files 72 | that have been modified would need to be merged. 73 | 74 | The example iOS application shows how to decode a small file and how some very large 75 | files can be decoded without using up all the memory in an iOS application. Previously, 76 | an archive with a dictionary around 30 to 40 megs would crash an iOS device, with 77 | the mmap logic files as large as 650 megs can be decoded without going over the 78 | virtual memory limits on iOS. Note that this large file support depends on how large 79 | a memory space a single process can map under iOS, so keeping a very large single 80 | archive under 400 megs is likely to be a good idea. 81 | 82 | See LICENSE.txt for license details. 83 | 84 | -------------------------------------------------------------------------------- /files_dirs.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdejong/lzmaSDK/43ef67638ff739999b2ec2790c1f09fe4135a543/files_dirs.7z -------------------------------------------------------------------------------- /halfgig.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdejong/lzmaSDK/43ef67638ff739999b2ec2790c1f09fe4135a543/halfgig.7z -------------------------------------------------------------------------------- /lzmaApp-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | com.helpurock.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | NSMainNibFile 28 | MainWindow 29 | 30 | 31 | -------------------------------------------------------------------------------- /lzmaApp_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'lzmaApp' target in the 'lzmaSDK' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /lzmaSDK/lzmaSDK-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | comp.helpurock.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /lzmaSDK/lzmaSDK.h: -------------------------------------------------------------------------------- 1 | // 2 | // lzmaSDK.h 3 | // lzmaSDK 4 | // 5 | // Created by Mo DeJong on 7/9/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for lzmaSDK. 12 | FOUNDATION_EXPORT double lzmaSDKVersionNumber; 13 | 14 | //! Project version string for lzmaSDK. 15 | FOUNDATION_EXPORT const unsigned char lzmaSDKVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | #import "LZMAExtractor.h" 20 | -------------------------------------------------------------------------------- /lzmaSDKTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | comp.helpurock.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /lzmaSDKTests/LZMAExtractorTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | 5 | @interface LZMAExtractorTests : XCTestCase 6 | @end 7 | 8 | @implementation LZMAExtractorTests 9 | 10 | // Return TRUE if file exists, FALSE otherwise 11 | BOOL fileExists(NSString *filePath) { 12 | if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { 13 | return TRUE; 14 | } else { 15 | return FALSE; 16 | } 17 | } 18 | 19 | // Query open file size, then rewind to start 20 | static uint32_t filesize(char *filepath) { 21 | int retcode; 22 | FILE *fp = fopen(filepath, "r"); 23 | retcode = fseek(fp, 0, SEEK_END); 24 | assert(retcode == 0); 25 | uint32_t size = (uint32_t) ftell(fp); 26 | fclose(fp); 27 | return size; 28 | } 29 | 30 | - (void) testSmallInMem 31 | { 32 | NSLog(@"START testSmallInMem"); 33 | 34 | BOOL worked; 35 | 36 | // Extract files from archive into named dir in the temp dir 37 | 38 | NSString *tmpDirname = @"Extract7z"; 39 | NSString *archiveFilename = @"test.7z"; 40 | NSString *archiveResPath = [[NSBundle bundleForClass:LZMAExtractorTests.class] pathForResource:archiveFilename ofType:nil]; 41 | XCTAssert(archiveResPath, @"can't find test.7z"); 42 | 43 | NSArray *contents = [LZMAExtractor extract7zArchive:archiveResPath 44 | tmpDirName:tmpDirname]; 45 | 46 | for (NSString *entryPath in contents) { 47 | NSData *outputData = [NSData dataWithContentsOfFile:entryPath]; 48 | NSString *outStr = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; 49 | 50 | 51 | NSLog(@"%@", entryPath); 52 | NSLog(@"%@", outStr); 53 | } 54 | 55 | // Extract single entry "make.out" and save it as "tmp/make.out.txt" in the tmp dir. 56 | 57 | NSString *entryFilename = @"make.out"; 58 | NSString *makeTmpFilename = @"make.out.txt"; 59 | NSString *makeTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:makeTmpFilename]; 60 | 61 | worked = [LZMAExtractor extractArchiveEntry:archiveResPath 62 | archiveEntry:entryFilename 63 | outPath:makeTmpPath]; 64 | 65 | 66 | XCTAssert(worked); 67 | if (worked) { 68 | NSData *outputData = [NSData dataWithContentsOfFile:makeTmpPath]; 69 | NSString *outStr = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; 70 | 71 | NSLog(@"%@", makeTmpFilename); 72 | NSLog(@"%@", outStr); 73 | } 74 | 75 | NSLog(@"DONE testSmallInMem"); 76 | } 77 | 78 | // This test decodes a small text file from the attached resource test.7z 79 | // This is a basic sanity check of the logic to decode an entry to a .7z archive. 80 | // Because the input archive and output files are small, this test case will 81 | // not use up much memory or emit large files. Note that because this dictionary 82 | // size is smaller than the 1 meg k7zUnpackMapDictionaryInMemoryMaxNumBytes limit, 83 | // this unpack operaiton will be done entirely in memory as opposed to using 84 | // mapped memory that is paged to disk. 85 | 86 | - (void) testFilesAndDirs 87 | { 88 | NSLog(@"START testFilesAndDirs"); 89 | 90 | BOOL worked; 91 | 92 | // Extract dirs files 93 | 94 | NSString *archiveFilename = @"files_dirs.7z"; 95 | NSString *archiveResPath = [[NSBundle bundleForClass:LZMAExtractorTests.class] pathForResource:archiveFilename ofType:nil]; 96 | NSAssert(archiveResPath, @"can't find %@", archiveFilename); 97 | 98 | NSArray *contents = [LZMAExtractor extract7zArchive:archiveResPath 99 | dirName:NSTemporaryDirectory() 100 | preserveDir:TRUE]; 101 | 102 | if ((0)) { 103 | for (NSString *entryPath in contents) { 104 | NSData *outputData = [NSData dataWithContentsOfFile:entryPath]; 105 | NSString *outStr = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; 106 | 107 | NSLog(@"%@", entryPath); 108 | NSLog(@"%@", outStr); 109 | } 110 | } 111 | 112 | XCTAssert(contents.count == 4); 113 | 114 | NSString *content; 115 | 116 | // .../d1/f1 117 | content = contents[0]; 118 | XCTAssert([content hasSuffix:@"d1/f1"]); 119 | 120 | // .../d1/f2 121 | content = contents[1]; 122 | XCTAssert([content hasSuffix:@"d1/f2"]); 123 | 124 | // .../d2/f_2_1 125 | content = contents[2]; 126 | XCTAssert([content hasSuffix:@"d2/f_2_1"]); 127 | 128 | // .../d2/f_2_2 129 | content = contents[3]; 130 | XCTAssert([content hasSuffix:@"d2/f_2_2"]); 131 | 132 | // Extract single entry "d2/f_2_1" and save it as "d2_f_2_1" in the tmp dir. 133 | 134 | NSString *entryFilename = @"d2/f_2_1"; 135 | NSString *makeTmpFilename = @"d2_f_2_1"; 136 | NSString *makeTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:makeTmpFilename]; 137 | 138 | worked = [LZMAExtractor extractArchiveEntry:archiveResPath 139 | archiveEntry:entryFilename 140 | outPath:makeTmpPath]; 141 | 142 | XCTAssert(worked); 143 | 144 | if (worked) { 145 | NSData *outputData = [NSData dataWithContentsOfFile:makeTmpPath]; 146 | NSString *outStr = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; 147 | XCTAssert([outStr hasSuffix:@"12\n"]); 148 | } 149 | 150 | NSLog(@"DONE testFilesAndDirs"); 151 | } 152 | 153 | // This test will extract a 500 meg file from a solid archive, this 500 meg file is way too large 154 | // to fit into regular memory, but it is smaller than the 700 meg limit on mapped memory 155 | // in iOS. This test will pass as long as the modification to the lzma SDK is implemented 156 | // so that memory is paged to disk when the dictionary size is large. 157 | // 158 | // Create: 159 | // 160 | // 7za a -mx=9 halfgig.7z halfgig.data 161 | // 162 | // The output of: 163 | // 164 | // 7za l -slt halfgig.7z 165 | // 166 | // Shows that the entire 500 meg file is stored as one large block. 167 | 168 | - (void) testHalfGig 169 | { 170 | NSLog(@"START testHalfGig"); 171 | 172 | // Extract files from archive into named dir in the temp dir 173 | 174 | NSString *archiveFilename = @"halfgig.7z"; 175 | NSString *archiveResPath = [[NSBundle bundleForClass:LZMAExtractorTests.class] pathForResource:archiveFilename ofType:nil]; 176 | XCTAssert(archiveResPath, @"can't find %@", archiveFilename); 177 | 178 | NSString *tmpFilename = @"halfgig.data"; 179 | NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:tmpFilename]; 180 | 181 | BOOL worked = [LZMAExtractor extractArchiveEntry:archiveResPath archiveEntry:tmpFilename outPath:tmpPath]; 182 | XCTAssert(worked, @"worked"); 183 | 184 | // Note that it will not be possible to hold this massive file in memory or even map the whole file. 185 | // It can only be streamed from disk. 186 | 187 | BOOL exists = fileExists(tmpPath); 188 | XCTAssert(exists, @"exists"); 189 | 190 | uint32_t size = filesize((char*)[tmpPath UTF8String]); 191 | 192 | NSLog(@"%@ : size %d", tmpFilename, size); 193 | 194 | // 500 megs 195 | 196 | XCTAssert(size == 1073741824/2, @"size"); 197 | 198 | // Make sure to delete this massive file 199 | 200 | worked = [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:nil]; 201 | XCTAssert(worked, @"worked"); 202 | 203 | NSLog(@"DONE testHalfGig"); 204 | 205 | return; 206 | } 207 | 208 | // This test attempts to extract a massive 1 gig file out of an archive, the file 209 | // is so large that it cannot be held in regular memory on iOS. It also it too big 210 | // to be held in virtual memory as a memory mapped file, so the only way that this 211 | // file can be written to the disk is by streaming one buffer at a time. This test 212 | // case basically checks the implementation of the SDK to verify that data is decoded 213 | // and streamed to the disk as opposed to one massive malloc call that will fail 214 | // on an embedded system. This test will pass on the Simulator, because MacOSX will 215 | // automatically switch to virtual memory for a very large malloc. 216 | 217 | - (void) testOneGigFailTooBig 218 | { 219 | NSLog(@"START testOneGigFailTooBig"); 220 | 221 | // This archive contains a 1 gigabyte file created like so: 222 | // 7za a -mx=9 onegig.7z onegig.data 223 | // 224 | // This should fail to decompress on an iOS device because the size of the vmem 225 | // mapping is larger than the maximum size allowed by the OS. 226 | // 227 | // The output of: 228 | // 229 | // 7za l -slt onegig.7z 230 | // 231 | // Shows that the entire one gig file was compressed down into 1 single block, so 232 | // there is no way for iOS to allocate a buffer that large. 233 | 234 | NSString *archiveFilename = @"onegig.7z"; 235 | NSString *archiveResPath = [[NSBundle bundleForClass:LZMAExtractorTests.class] pathForResource:archiveFilename ofType:nil]; 236 | XCTAssert(archiveResPath, @"can't find %@", archiveFilename); 237 | 238 | // Extract single entry "onegig.data" into the tmp dir 239 | 240 | NSString *tmpFilename = @"onegig.data"; 241 | NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:tmpFilename]; 242 | 243 | // Make sure file does not exist from some previous run at this point 244 | [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:nil]; 245 | 246 | BOOL worked = [LZMAExtractor extractArchiveEntry:archiveResPath archiveEntry:tmpFilename outPath:tmpPath]; 247 | 248 | if (TARGET_IPHONE_SIMULATOR) { 249 | XCTAssert(worked == TRUE, @"worked"); 250 | } else { 251 | // Device, should fail 252 | XCTAssert(worked == FALSE, @"worked"); 253 | 254 | BOOL exists = fileExists(tmpPath); 255 | XCTAssert(exists == FALSE, @"exists"); 256 | } 257 | 258 | // Note that it will not be possible to hold this massive file in memory or even map the whole file. 259 | // It can only be streamed from disk. 260 | 261 | BOOL exists = fileExists(tmpPath); 262 | if (exists) { 263 | uint32_t size = filesize((char*)[tmpPath UTF8String]); 264 | 265 | NSLog(@"%@ : size %d", tmpFilename, size); 266 | 267 | // 1 gig 268 | 269 | XCTAssert(size == 1073741824, @"size"); 270 | 271 | // Make sure to delete this massive file 272 | 273 | worked = [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:nil]; 274 | XCTAssert(worked, @"worked"); 275 | } 276 | 277 | NSLog(@"DONE testOneGigFailTooBig"); 278 | return; 279 | } 280 | 281 | // This test will extract a pair of huge 650 meg files from a single archive. 282 | // If both files were stored into 1 block, the mapping operation would fail 283 | // on the device because the mapped size would be too large. But, one can work 284 | // around the upper limit if absolutely required by encoding the archive 285 | // with multiple blocks. 286 | // 287 | // Each block is decoded one at a time, so each file is able to fit into 288 | // memory only one at a time. The key here is to pass these 680m arguments 289 | // when encoding to define the upper limit of a block size, the result is 290 | // that each file is contained in its own block. 291 | // 292 | // Create: 293 | // 294 | // 7za a -mx=9 -md=680m -ms=680m sixfiftymeg_2blocks.7z sixfiftymeg1.data sixfiftymeg2.data 295 | // 296 | // The output of: 297 | // 298 | // 7za l -slt sixfiftymeg_2blocks.7z 299 | // 300 | // Shows that two blocks are defined in the archive, each one contains one of the 650 meg files. 301 | 302 | - (void) decodeSixFifty:(NSString*)entryName 303 | { 304 | // Extract files from archive into named dir in the temp dir 305 | 306 | NSString *archiveFilename = @"sixfiftymeg_2blocks.7z"; 307 | NSString *archiveResPath = [[NSBundle bundleForClass:LZMAExtractorTests.class] pathForResource:archiveFilename ofType:nil]; 308 | XCTAssert(archiveResPath, @"can't find %@", archiveFilename); 309 | 310 | NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:entryName]; 311 | 312 | BOOL worked = [LZMAExtractor extractArchiveEntry:archiveResPath archiveEntry:entryName outPath:tmpPath]; 313 | XCTAssert(worked, @"worked"); 314 | 315 | // Note that it will not be possible to hold this massive file in memory or even map the whole file. 316 | // It can only be streamed from disk. 317 | 318 | BOOL exists = fileExists(tmpPath); 319 | XCTAssert(exists, @"exists"); 320 | 321 | uint32_t size = filesize((char*)[tmpPath UTF8String]); 322 | 323 | NSLog(@"%@ : size %d", entryName, size); 324 | 325 | // 650 megs 326 | 327 | XCTAssert(size == (1024 * 1024 * 650), @"size"); 328 | 329 | // Delete the file on disk 330 | 331 | worked = [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:nil]; 332 | XCTAssert(worked, @"worked"); 333 | 334 | return; 335 | } 336 | 337 | - (void) testTwoSixFiftyInTwoBlocks 338 | { 339 | NSLog(@"START testTwoSixFiftyInTwoBlocks"); 340 | 341 | NSString *makeTmpFilename; 342 | makeTmpFilename = @"sixfiftymeg1.data"; 343 | [self decodeSixFifty:makeTmpFilename]; 344 | 345 | makeTmpFilename = @"sixfiftymeg2.data"; 346 | [self decodeSixFifty:makeTmpFilename]; 347 | 348 | NSLog(@"DONE testTwoSixFiftyInTwoBlocks"); 349 | } 350 | 351 | 352 | @end 353 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // lzmaSDK 4 | // 5 | // 6 | 7 | #import 8 | 9 | int main(int argc, char *argv[]) { 10 | 11 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 12 | int retVal = UIApplicationMain(argc, argv, nil, nil); 13 | [pool release]; 14 | return retVal; 15 | } 16 | -------------------------------------------------------------------------------- /onegig.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdejong/lzmaSDK/43ef67638ff739999b2ec2790c1f09fe4135a543/onegig.7z -------------------------------------------------------------------------------- /sixfiftymeg_2blocks.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdejong/lzmaSDK/43ef67638ff739999b2ec2790c1f09fe4135a543/sixfiftymeg_2blocks.7z -------------------------------------------------------------------------------- /test.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdejong/lzmaSDK/43ef67638ff739999b2ec2790c1f09fe4135a543/test.7z -------------------------------------------------------------------------------- /update.tcl: -------------------------------------------------------------------------------- 1 | # Find all the .h or .c files in C/ and subdirs and copy over only those files 2 | # that already exist in ../Classes/LZMASDK/ 3 | 4 | set cfiles [glob -type f -nocomplain C/*.{h,c} C/*/*.{h,c}] 5 | 6 | foreach file $cfiles { 7 | #puts "file = $file" 8 | 9 | set tail [file tail $file] 10 | 11 | set path [file join .. Classes LZMASDK $tail] 12 | 13 | set copied 0 14 | 15 | if {[file exists $path]} { 16 | #puts "EXISTS $path" 17 | puts "cp $file $path" 18 | file copy -force $file $path 19 | set copied 1 20 | } 21 | 22 | # Also check ../Classes/LZMASDK/Util/7z 23 | set path [file join .. Classes LZMASDK Util 7z $tail] 24 | 25 | if {[file exists $path]} { 26 | #puts "EXISTS $path" 27 | puts "cp $file $path" 28 | file copy -force $file $path 29 | set copied 1 30 | } 31 | 32 | 33 | if {!$copied} { 34 | puts "IGNORE $file" 35 | } 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /writebig.tcl: -------------------------------------------------------------------------------- 1 | # Write a really massive 1024 megabyte file (1 gigabyte) that contains all zero bytes. 2 | # This file size was chosen because it is larger than the 700 megabyte 3 | # mapped file size limit in iOS. 4 | 5 | #set outfilename "onegig.data" 6 | #set numMegs 1024 7 | 8 | #set outfilename "halfgig.data" 9 | #set numMegs 512 10 | 11 | set outfilename "sixfiftymeg.data" 12 | set numMegs 650 13 | 14 | set oneK "" 15 | for {set i 0} {$i < 1024} {incr i} { 16 | append oneK "\0" 17 | } 18 | set oneMeg [string repeat $oneK 1024] 19 | if {[string length $oneMeg] != (1024 * 1024)} { 20 | puts "len is [string length $oneMeg], not one meg" 21 | exit 0 22 | } 23 | 24 | set fd [open $outfilename w] 25 | fconfigure $fd -encoding binary -translation binary 26 | for {set i 0} {$i < $numMegs} {incr i} { 27 | puts -nonewline $fd $oneMeg 28 | } 29 | close $fd 30 | 31 | set len [file size $outfilename] 32 | set expected_len [expr {1024 * 1024 * $numMegs}] 33 | if {$len != $expected_len} { 34 | puts "expected len = $expected_len, len was $len" 35 | exit 0 36 | } 37 | 38 | puts "wrote $outfilename" 39 | puts "$numMegs megs" 40 | 41 | --------------------------------------------------------------------------------