diff options
| author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2021-12-27 00:00:00 +0000 |
|---|---|---|
| committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2022-03-18 15:35:13 +0500 |
| commit | f19f813537c7aea1c20749c914e756b54a9c3cf5 (patch) | |
| tree | 816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /C | |
| parent | 98e06a519b63b81986abe76d28887f6984a7732b (diff) | |
| download | 7zip-21.07.tar.gz 7zip-21.07.tar.bz2 7zip-21.07.zip | |
'21.07'21.07
Diffstat (limited to 'C')
159 files changed, 43570 insertions, 0 deletions
| @@ -0,0 +1,204 @@ | |||
| 1 | /* 7z.h -- 7z interface | ||
| 2 | 2018-07-02 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_H | ||
| 5 | #define __7Z_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define k7zStartHeaderSize 0x20 | ||
| 12 | #define k7zSignatureSize 6 | ||
| 13 | |||
| 14 | extern const Byte k7zSignature[k7zSignatureSize]; | ||
| 15 | |||
| 16 | typedef struct | ||
| 17 | { | ||
| 18 | const Byte *Data; | ||
| 19 | size_t Size; | ||
| 20 | } CSzData; | ||
| 21 | |||
| 22 | /* CSzCoderInfo & CSzFolder support only default methods */ | ||
| 23 | |||
| 24 | typedef struct | ||
| 25 | { | ||
| 26 | size_t PropsOffset; | ||
| 27 | UInt32 MethodID; | ||
| 28 | Byte NumStreams; | ||
| 29 | Byte PropsSize; | ||
| 30 | } CSzCoderInfo; | ||
| 31 | |||
| 32 | typedef struct | ||
| 33 | { | ||
| 34 | UInt32 InIndex; | ||
| 35 | UInt32 OutIndex; | ||
| 36 | } CSzBond; | ||
| 37 | |||
| 38 | #define SZ_NUM_CODERS_IN_FOLDER_MAX 4 | ||
| 39 | #define SZ_NUM_BONDS_IN_FOLDER_MAX 3 | ||
| 40 | #define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4 | ||
| 41 | |||
| 42 | typedef struct | ||
| 43 | { | ||
| 44 | UInt32 NumCoders; | ||
| 45 | UInt32 NumBonds; | ||
| 46 | UInt32 NumPackStreams; | ||
| 47 | UInt32 UnpackStream; | ||
| 48 | UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX]; | ||
| 49 | CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX]; | ||
| 50 | CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX]; | ||
| 51 | } CSzFolder; | ||
| 52 | |||
| 53 | |||
| 54 | SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd); | ||
| 55 | |||
| 56 | typedef struct | ||
| 57 | { | ||
| 58 | UInt32 Low; | ||
| 59 | UInt32 High; | ||
| 60 | } CNtfsFileTime; | ||
| 61 | |||
| 62 | typedef struct | ||
| 63 | { | ||
| 64 | Byte *Defs; /* MSB 0 bit numbering */ | ||
| 65 | UInt32 *Vals; | ||
| 66 | } CSzBitUi32s; | ||
| 67 | |||
| 68 | typedef struct | ||
| 69 | { | ||
| 70 | Byte *Defs; /* MSB 0 bit numbering */ | ||
| 71 | // UInt64 *Vals; | ||
| 72 | CNtfsFileTime *Vals; | ||
| 73 | } CSzBitUi64s; | ||
| 74 | |||
| 75 | #define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) | ||
| 76 | |||
| 77 | #define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) | ||
| 78 | |||
| 79 | typedef struct | ||
| 80 | { | ||
| 81 | UInt32 NumPackStreams; | ||
| 82 | UInt32 NumFolders; | ||
| 83 | |||
| 84 | UInt64 *PackPositions; // NumPackStreams + 1 | ||
| 85 | CSzBitUi32s FolderCRCs; // NumFolders | ||
| 86 | |||
| 87 | size_t *FoCodersOffsets; // NumFolders + 1 | ||
| 88 | UInt32 *FoStartPackStreamIndex; // NumFolders + 1 | ||
| 89 | UInt32 *FoToCoderUnpackSizes; // NumFolders + 1 | ||
| 90 | Byte *FoToMainUnpackSizeIndex; // NumFolders | ||
| 91 | UInt64 *CoderUnpackSizes; // for all coders in all folders | ||
| 92 | |||
| 93 | Byte *CodersData; | ||
| 94 | |||
| 95 | UInt64 RangeLimit; | ||
| 96 | } CSzAr; | ||
| 97 | |||
| 98 | UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex); | ||
| 99 | |||
| 100 | SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, | ||
| 101 | ILookInStream *stream, UInt64 startPos, | ||
| 102 | Byte *outBuffer, size_t outSize, | ||
| 103 | ISzAllocPtr allocMain); | ||
| 104 | |||
| 105 | typedef struct | ||
| 106 | { | ||
| 107 | CSzAr db; | ||
| 108 | |||
| 109 | UInt64 startPosAfterHeader; | ||
| 110 | UInt64 dataPos; | ||
| 111 | |||
| 112 | UInt32 NumFiles; | ||
| 113 | |||
| 114 | UInt64 *UnpackPositions; // NumFiles + 1 | ||
| 115 | // Byte *IsEmptyFiles; | ||
| 116 | Byte *IsDirs; | ||
| 117 | CSzBitUi32s CRCs; | ||
| 118 | |||
| 119 | CSzBitUi32s Attribs; | ||
| 120 | // CSzBitUi32s Parents; | ||
| 121 | CSzBitUi64s MTime; | ||
| 122 | CSzBitUi64s CTime; | ||
| 123 | |||
| 124 | UInt32 *FolderToFile; // NumFolders + 1 | ||
| 125 | UInt32 *FileToFolder; // NumFiles | ||
| 126 | |||
| 127 | size_t *FileNameOffsets; /* in 2-byte steps */ | ||
| 128 | Byte *FileNames; /* UTF-16-LE */ | ||
| 129 | } CSzArEx; | ||
| 130 | |||
| 131 | #define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i)) | ||
| 132 | |||
| 133 | #define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i]) | ||
| 134 | |||
| 135 | void SzArEx_Init(CSzArEx *p); | ||
| 136 | void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc); | ||
| 137 | UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); | ||
| 138 | int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); | ||
| 139 | |||
| 140 | /* | ||
| 141 | if dest == NULL, the return value specifies the required size of the buffer, | ||
| 142 | in 16-bit characters, including the null-terminating character. | ||
| 143 | if dest != NULL, the return value specifies the number of 16-bit characters that | ||
| 144 | are written to the dest, including the null-terminating character. */ | ||
| 145 | |||
| 146 | size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); | ||
| 147 | |||
| 148 | /* | ||
| 149 | size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex); | ||
| 150 | UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest); | ||
| 151 | */ | ||
| 152 | |||
| 153 | |||
| 154 | |||
| 155 | /* | ||
| 156 | SzArEx_Extract extracts file from archive | ||
| 157 | |||
| 158 | *outBuffer must be 0 before first call for each new archive. | ||
| 159 | |||
| 160 | Extracting cache: | ||
| 161 | If you need to decompress more than one file, you can send | ||
| 162 | these values from previous call: | ||
| 163 | *blockIndex, | ||
| 164 | *outBuffer, | ||
| 165 | *outBufferSize | ||
| 166 | You can consider "*outBuffer" as cache of solid block. If your archive is solid, | ||
| 167 | it will increase decompression speed. | ||
| 168 | |||
| 169 | If you use external function, you can declare these 3 cache variables | ||
| 170 | (blockIndex, outBuffer, outBufferSize) as static in that external function. | ||
| 171 | |||
| 172 | Free *outBuffer and set *outBuffer to 0, if you want to flush cache. | ||
| 173 | */ | ||
| 174 | |||
| 175 | SRes SzArEx_Extract( | ||
| 176 | const CSzArEx *db, | ||
| 177 | ILookInStream *inStream, | ||
| 178 | UInt32 fileIndex, /* index of file */ | ||
| 179 | UInt32 *blockIndex, /* index of solid block */ | ||
| 180 | Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ | ||
| 181 | size_t *outBufferSize, /* buffer size for output buffer */ | ||
| 182 | size_t *offset, /* offset of stream for required file in *outBuffer */ | ||
| 183 | size_t *outSizeProcessed, /* size of file in *outBuffer */ | ||
| 184 | ISzAllocPtr allocMain, | ||
| 185 | ISzAllocPtr allocTemp); | ||
| 186 | |||
| 187 | |||
| 188 | /* | ||
| 189 | SzArEx_Open Errors: | ||
| 190 | SZ_ERROR_NO_ARCHIVE | ||
| 191 | SZ_ERROR_ARCHIVE | ||
| 192 | SZ_ERROR_UNSUPPORTED | ||
| 193 | SZ_ERROR_MEM | ||
| 194 | SZ_ERROR_CRC | ||
| 195 | SZ_ERROR_INPUT_EOF | ||
| 196 | SZ_ERROR_FAIL | ||
| 197 | */ | ||
| 198 | |||
| 199 | SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, | ||
| 200 | ISzAllocPtr allocMain, ISzAllocPtr allocTemp); | ||
| 201 | |||
| 202 | EXTERN_C_END | ||
| 203 | |||
| 204 | #endif | ||
diff --git a/C/7zAlloc.c b/C/7zAlloc.c new file mode 100644 index 0000000..c924a52 --- /dev/null +++ b/C/7zAlloc.c | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | /* 7zAlloc.c -- Allocation functions | ||
| 2 | 2017-04-03 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <stdlib.h> | ||
| 7 | |||
| 8 | #include "7zAlloc.h" | ||
| 9 | |||
| 10 | /* #define _SZ_ALLOC_DEBUG */ | ||
| 11 | /* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ | ||
| 12 | |||
| 13 | #ifdef _SZ_ALLOC_DEBUG | ||
| 14 | |||
| 15 | #ifdef _WIN32 | ||
| 16 | #include <windows.h> | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #include <stdio.h> | ||
| 20 | int g_allocCount = 0; | ||
| 21 | int g_allocCountTemp = 0; | ||
| 22 | |||
| 23 | #endif | ||
| 24 | |||
| 25 | void *SzAlloc(ISzAllocPtr p, size_t size) | ||
| 26 | { | ||
| 27 | UNUSED_VAR(p); | ||
| 28 | if (size == 0) | ||
| 29 | return 0; | ||
| 30 | #ifdef _SZ_ALLOC_DEBUG | ||
| 31 | fprintf(stderr, "\nAlloc %10u bytes; count = %10d", (unsigned)size, g_allocCount); | ||
| 32 | g_allocCount++; | ||
| 33 | #endif | ||
| 34 | return malloc(size); | ||
| 35 | } | ||
| 36 | |||
| 37 | void SzFree(ISzAllocPtr p, void *address) | ||
| 38 | { | ||
| 39 | UNUSED_VAR(p); | ||
| 40 | #ifdef _SZ_ALLOC_DEBUG | ||
| 41 | if (address != 0) | ||
| 42 | { | ||
| 43 | g_allocCount--; | ||
| 44 | fprintf(stderr, "\nFree; count = %10d", g_allocCount); | ||
| 45 | } | ||
| 46 | #endif | ||
| 47 | free(address); | ||
| 48 | } | ||
| 49 | |||
| 50 | void *SzAllocTemp(ISzAllocPtr p, size_t size) | ||
| 51 | { | ||
| 52 | UNUSED_VAR(p); | ||
| 53 | if (size == 0) | ||
| 54 | return 0; | ||
| 55 | #ifdef _SZ_ALLOC_DEBUG | ||
| 56 | fprintf(stderr, "\nAlloc_temp %10u bytes; count = %10d", (unsigned)size, g_allocCountTemp); | ||
| 57 | g_allocCountTemp++; | ||
| 58 | #ifdef _WIN32 | ||
| 59 | return HeapAlloc(GetProcessHeap(), 0, size); | ||
| 60 | #endif | ||
| 61 | #endif | ||
| 62 | return malloc(size); | ||
| 63 | } | ||
| 64 | |||
| 65 | void SzFreeTemp(ISzAllocPtr p, void *address) | ||
| 66 | { | ||
| 67 | UNUSED_VAR(p); | ||
| 68 | #ifdef _SZ_ALLOC_DEBUG | ||
| 69 | if (address != 0) | ||
| 70 | { | ||
| 71 | g_allocCountTemp--; | ||
| 72 | fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp); | ||
| 73 | } | ||
| 74 | #ifdef _WIN32 | ||
| 75 | HeapFree(GetProcessHeap(), 0, address); | ||
| 76 | return; | ||
| 77 | #endif | ||
| 78 | #endif | ||
| 79 | free(address); | ||
| 80 | } | ||
diff --git a/C/7zAlloc.h b/C/7zAlloc.h new file mode 100644 index 0000000..44778f9 --- /dev/null +++ b/C/7zAlloc.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* 7zAlloc.h -- Allocation functions | ||
| 2 | 2017-04-03 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_ALLOC_H | ||
| 5 | #define __7Z_ALLOC_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | void *SzAlloc(ISzAllocPtr p, size_t size); | ||
| 12 | void SzFree(ISzAllocPtr p, void *address); | ||
| 13 | |||
| 14 | void *SzAllocTemp(ISzAllocPtr p, size_t size); | ||
| 15 | void SzFreeTemp(ISzAllocPtr p, void *address); | ||
| 16 | |||
| 17 | EXTERN_C_END | ||
| 18 | |||
| 19 | #endif | ||
diff --git a/C/7zArcIn.c b/C/7zArcIn.c new file mode 100644 index 0000000..0d9dec4 --- /dev/null +++ b/C/7zArcIn.c | |||
| @@ -0,0 +1,1783 @@ | |||
| 1 | /* 7zArcIn.c -- 7z Input functions | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | #include "7z.h" | ||
| 9 | #include "7zBuf.h" | ||
| 10 | #include "7zCrc.h" | ||
| 11 | #include "CpuArch.h" | ||
| 12 | |||
| 13 | #define MY_ALLOC(T, p, size, alloc) { \ | ||
| 14 | if ((p = (T *)ISzAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; } | ||
| 15 | |||
| 16 | #define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) } | ||
| 17 | |||
| 18 | #define MY_ALLOC_AND_CPY(to, size, from, alloc) \ | ||
| 19 | { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); } | ||
| 20 | |||
| 21 | #define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \ | ||
| 22 | { if ((size) == 0) to = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } } | ||
| 23 | |||
| 24 | #define k7zMajorVersion 0 | ||
| 25 | |||
| 26 | enum EIdEnum | ||
| 27 | { | ||
| 28 | k7zIdEnd, | ||
| 29 | k7zIdHeader, | ||
| 30 | k7zIdArchiveProperties, | ||
| 31 | k7zIdAdditionalStreamsInfo, | ||
| 32 | k7zIdMainStreamsInfo, | ||
| 33 | k7zIdFilesInfo, | ||
| 34 | k7zIdPackInfo, | ||
| 35 | k7zIdUnpackInfo, | ||
| 36 | k7zIdSubStreamsInfo, | ||
| 37 | k7zIdSize, | ||
| 38 | k7zIdCRC, | ||
| 39 | k7zIdFolder, | ||
| 40 | k7zIdCodersUnpackSize, | ||
| 41 | k7zIdNumUnpackStream, | ||
| 42 | k7zIdEmptyStream, | ||
| 43 | k7zIdEmptyFile, | ||
| 44 | k7zIdAnti, | ||
| 45 | k7zIdName, | ||
| 46 | k7zIdCTime, | ||
| 47 | k7zIdATime, | ||
| 48 | k7zIdMTime, | ||
| 49 | k7zIdWinAttrib, | ||
| 50 | k7zIdComment, | ||
| 51 | k7zIdEncodedHeader, | ||
| 52 | k7zIdStartPos, | ||
| 53 | k7zIdDummy | ||
| 54 | // k7zNtSecure, | ||
| 55 | // k7zParent, | ||
| 56 | // k7zIsReal | ||
| 57 | }; | ||
| 58 | |||
| 59 | const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; | ||
| 60 | |||
| 61 | #define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } | ||
| 62 | |||
| 63 | static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAllocPtr alloc) | ||
| 64 | { | ||
| 65 | if (num == 0) | ||
| 66 | { | ||
| 67 | p->Defs = NULL; | ||
| 68 | p->Vals = NULL; | ||
| 69 | } | ||
| 70 | else | ||
| 71 | { | ||
| 72 | MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc); | ||
| 73 | MY_ALLOC(UInt32, p->Vals, num, alloc); | ||
| 74 | } | ||
| 75 | return SZ_OK; | ||
| 76 | } | ||
| 77 | |||
| 78 | static void SzBitUi32s_Free(CSzBitUi32s *p, ISzAllocPtr alloc) | ||
| 79 | { | ||
| 80 | ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; | ||
| 81 | ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; | ||
| 82 | } | ||
| 83 | |||
| 84 | #define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } | ||
| 85 | |||
| 86 | static void SzBitUi64s_Free(CSzBitUi64s *p, ISzAllocPtr alloc) | ||
| 87 | { | ||
| 88 | ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; | ||
| 89 | ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; | ||
| 90 | } | ||
| 91 | |||
| 92 | |||
| 93 | static void SzAr_Init(CSzAr *p) | ||
| 94 | { | ||
| 95 | p->NumPackStreams = 0; | ||
| 96 | p->NumFolders = 0; | ||
| 97 | |||
| 98 | p->PackPositions = NULL; | ||
| 99 | SzBitUi32s_Init(&p->FolderCRCs); | ||
| 100 | |||
| 101 | p->FoCodersOffsets = NULL; | ||
| 102 | p->FoStartPackStreamIndex = NULL; | ||
| 103 | p->FoToCoderUnpackSizes = NULL; | ||
| 104 | p->FoToMainUnpackSizeIndex = NULL; | ||
| 105 | p->CoderUnpackSizes = NULL; | ||
| 106 | |||
| 107 | p->CodersData = NULL; | ||
| 108 | |||
| 109 | p->RangeLimit = 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | static void SzAr_Free(CSzAr *p, ISzAllocPtr alloc) | ||
| 113 | { | ||
| 114 | ISzAlloc_Free(alloc, p->PackPositions); | ||
| 115 | SzBitUi32s_Free(&p->FolderCRCs, alloc); | ||
| 116 | |||
| 117 | ISzAlloc_Free(alloc, p->FoCodersOffsets); | ||
| 118 | ISzAlloc_Free(alloc, p->FoStartPackStreamIndex); | ||
| 119 | ISzAlloc_Free(alloc, p->FoToCoderUnpackSizes); | ||
| 120 | ISzAlloc_Free(alloc, p->FoToMainUnpackSizeIndex); | ||
| 121 | ISzAlloc_Free(alloc, p->CoderUnpackSizes); | ||
| 122 | |||
| 123 | ISzAlloc_Free(alloc, p->CodersData); | ||
| 124 | |||
| 125 | SzAr_Init(p); | ||
| 126 | } | ||
| 127 | |||
| 128 | |||
| 129 | void SzArEx_Init(CSzArEx *p) | ||
| 130 | { | ||
| 131 | SzAr_Init(&p->db); | ||
| 132 | |||
| 133 | p->NumFiles = 0; | ||
| 134 | p->dataPos = 0; | ||
| 135 | |||
| 136 | p->UnpackPositions = NULL; | ||
| 137 | p->IsDirs = NULL; | ||
| 138 | |||
| 139 | p->FolderToFile = NULL; | ||
| 140 | p->FileToFolder = NULL; | ||
| 141 | |||
| 142 | p->FileNameOffsets = NULL; | ||
| 143 | p->FileNames = NULL; | ||
| 144 | |||
| 145 | SzBitUi32s_Init(&p->CRCs); | ||
| 146 | SzBitUi32s_Init(&p->Attribs); | ||
| 147 | // SzBitUi32s_Init(&p->Parents); | ||
| 148 | SzBitUi64s_Init(&p->MTime); | ||
| 149 | SzBitUi64s_Init(&p->CTime); | ||
| 150 | } | ||
| 151 | |||
| 152 | void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc) | ||
| 153 | { | ||
| 154 | ISzAlloc_Free(alloc, p->UnpackPositions); | ||
| 155 | ISzAlloc_Free(alloc, p->IsDirs); | ||
| 156 | |||
| 157 | ISzAlloc_Free(alloc, p->FolderToFile); | ||
| 158 | ISzAlloc_Free(alloc, p->FileToFolder); | ||
| 159 | |||
| 160 | ISzAlloc_Free(alloc, p->FileNameOffsets); | ||
| 161 | ISzAlloc_Free(alloc, p->FileNames); | ||
| 162 | |||
| 163 | SzBitUi32s_Free(&p->CRCs, alloc); | ||
| 164 | SzBitUi32s_Free(&p->Attribs, alloc); | ||
| 165 | // SzBitUi32s_Free(&p->Parents, alloc); | ||
| 166 | SzBitUi64s_Free(&p->MTime, alloc); | ||
| 167 | SzBitUi64s_Free(&p->CTime, alloc); | ||
| 168 | |||
| 169 | SzAr_Free(&p->db, alloc); | ||
| 170 | SzArEx_Init(p); | ||
| 171 | } | ||
| 172 | |||
| 173 | |||
| 174 | static int TestSignatureCandidate(const Byte *testBytes) | ||
| 175 | { | ||
| 176 | unsigned i; | ||
| 177 | for (i = 0; i < k7zSignatureSize; i++) | ||
| 178 | if (testBytes[i] != k7zSignature[i]) | ||
| 179 | return 0; | ||
| 180 | return 1; | ||
| 181 | } | ||
| 182 | |||
| 183 | #define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; } | ||
| 184 | |||
| 185 | #define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++; | ||
| 186 | #define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest) | ||
| 187 | #define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++; | ||
| 188 | |||
| 189 | #define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); } | ||
| 190 | #define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); } | ||
| 191 | |||
| 192 | #define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \ | ||
| 193 | dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4); | ||
| 194 | |||
| 195 | static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) | ||
| 196 | { | ||
| 197 | Byte firstByte, mask; | ||
| 198 | unsigned i; | ||
| 199 | UInt32 v; | ||
| 200 | |||
| 201 | SZ_READ_BYTE(firstByte); | ||
| 202 | if ((firstByte & 0x80) == 0) | ||
| 203 | { | ||
| 204 | *value = firstByte; | ||
| 205 | return SZ_OK; | ||
| 206 | } | ||
| 207 | SZ_READ_BYTE(v); | ||
| 208 | if ((firstByte & 0x40) == 0) | ||
| 209 | { | ||
| 210 | *value = (((UInt32)firstByte & 0x3F) << 8) | v; | ||
| 211 | return SZ_OK; | ||
| 212 | } | ||
| 213 | SZ_READ_BYTE(mask); | ||
| 214 | *value = v | ((UInt32)mask << 8); | ||
| 215 | mask = 0x20; | ||
| 216 | for (i = 2; i < 8; i++) | ||
| 217 | { | ||
| 218 | Byte b; | ||
| 219 | if ((firstByte & mask) == 0) | ||
| 220 | { | ||
| 221 | UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); | ||
| 222 | *value |= (highPart << (8 * i)); | ||
| 223 | return SZ_OK; | ||
| 224 | } | ||
| 225 | SZ_READ_BYTE(b); | ||
| 226 | *value |= ((UInt64)b << (8 * i)); | ||
| 227 | mask >>= 1; | ||
| 228 | } | ||
| 229 | return SZ_OK; | ||
| 230 | } | ||
| 231 | |||
| 232 | |||
| 233 | static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) | ||
| 234 | { | ||
| 235 | Byte firstByte; | ||
| 236 | UInt64 value64; | ||
| 237 | if (sd->Size == 0) | ||
| 238 | return SZ_ERROR_ARCHIVE; | ||
| 239 | firstByte = *sd->Data; | ||
| 240 | if ((firstByte & 0x80) == 0) | ||
| 241 | { | ||
| 242 | *value = firstByte; | ||
| 243 | sd->Data++; | ||
| 244 | sd->Size--; | ||
| 245 | return SZ_OK; | ||
| 246 | } | ||
| 247 | RINOK(ReadNumber(sd, &value64)); | ||
| 248 | if (value64 >= (UInt32)0x80000000 - 1) | ||
| 249 | return SZ_ERROR_UNSUPPORTED; | ||
| 250 | if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4))) | ||
| 251 | return SZ_ERROR_UNSUPPORTED; | ||
| 252 | *value = (UInt32)value64; | ||
| 253 | return SZ_OK; | ||
| 254 | } | ||
| 255 | |||
| 256 | #define ReadID(sd, value) ReadNumber(sd, value) | ||
| 257 | |||
| 258 | static SRes SkipData(CSzData *sd) | ||
| 259 | { | ||
| 260 | UInt64 size; | ||
| 261 | RINOK(ReadNumber(sd, &size)); | ||
| 262 | if (size > sd->Size) | ||
| 263 | return SZ_ERROR_ARCHIVE; | ||
| 264 | SKIP_DATA(sd, size); | ||
| 265 | return SZ_OK; | ||
| 266 | } | ||
| 267 | |||
| 268 | static SRes WaitId(CSzData *sd, UInt32 id) | ||
| 269 | { | ||
| 270 | for (;;) | ||
| 271 | { | ||
| 272 | UInt64 type; | ||
| 273 | RINOK(ReadID(sd, &type)); | ||
| 274 | if (type == id) | ||
| 275 | return SZ_OK; | ||
| 276 | if (type == k7zIdEnd) | ||
| 277 | return SZ_ERROR_ARCHIVE; | ||
| 278 | RINOK(SkipData(sd)); | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v) | ||
| 283 | { | ||
| 284 | UInt32 numBytes = (numItems + 7) >> 3; | ||
| 285 | if (numBytes > sd->Size) | ||
| 286 | return SZ_ERROR_ARCHIVE; | ||
| 287 | *v = sd->Data; | ||
| 288 | SKIP_DATA(sd, numBytes); | ||
| 289 | return SZ_OK; | ||
| 290 | } | ||
| 291 | |||
| 292 | static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems) | ||
| 293 | { | ||
| 294 | Byte b = 0; | ||
| 295 | unsigned m = 0; | ||
| 296 | UInt32 sum = 0; | ||
| 297 | for (; numItems != 0; numItems--) | ||
| 298 | { | ||
| 299 | if (m == 0) | ||
| 300 | { | ||
| 301 | b = *bits++; | ||
| 302 | m = 8; | ||
| 303 | } | ||
| 304 | m--; | ||
| 305 | sum += ((b >> m) & 1); | ||
| 306 | } | ||
| 307 | return sum; | ||
| 308 | } | ||
| 309 | |||
| 310 | static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc) | ||
| 311 | { | ||
| 312 | Byte allAreDefined; | ||
| 313 | Byte *v2; | ||
| 314 | UInt32 numBytes = (numItems + 7) >> 3; | ||
| 315 | *v = NULL; | ||
| 316 | SZ_READ_BYTE(allAreDefined); | ||
| 317 | if (numBytes == 0) | ||
| 318 | return SZ_OK; | ||
| 319 | if (allAreDefined == 0) | ||
| 320 | { | ||
| 321 | if (numBytes > sd->Size) | ||
| 322 | return SZ_ERROR_ARCHIVE; | ||
| 323 | MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc); | ||
| 324 | SKIP_DATA(sd, numBytes); | ||
| 325 | return SZ_OK; | ||
| 326 | } | ||
| 327 | MY_ALLOC(Byte, *v, numBytes, alloc); | ||
| 328 | v2 = *v; | ||
| 329 | memset(v2, 0xFF, (size_t)numBytes); | ||
| 330 | { | ||
| 331 | unsigned numBits = (unsigned)numItems & 7; | ||
| 332 | if (numBits != 0) | ||
| 333 | v2[(size_t)numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits)); | ||
| 334 | } | ||
| 335 | return SZ_OK; | ||
| 336 | } | ||
| 337 | |||
| 338 | static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) | ||
| 339 | { | ||
| 340 | UInt32 i; | ||
| 341 | CSzData sd; | ||
| 342 | UInt32 *vals; | ||
| 343 | const Byte *defs; | ||
| 344 | MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc); | ||
| 345 | sd = *sd2; | ||
| 346 | defs = crcs->Defs; | ||
| 347 | vals = crcs->Vals; | ||
| 348 | for (i = 0; i < numItems; i++) | ||
| 349 | if (SzBitArray_Check(defs, i)) | ||
| 350 | { | ||
| 351 | SZ_READ_32(vals[i]); | ||
| 352 | } | ||
| 353 | else | ||
| 354 | vals[i] = 0; | ||
| 355 | *sd2 = sd; | ||
| 356 | return SZ_OK; | ||
| 357 | } | ||
| 358 | |||
| 359 | static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) | ||
| 360 | { | ||
| 361 | SzBitUi32s_Free(crcs, alloc); | ||
| 362 | RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)); | ||
| 363 | return ReadUi32s(sd, numItems, crcs, alloc); | ||
| 364 | } | ||
| 365 | |||
| 366 | static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems) | ||
| 367 | { | ||
| 368 | Byte allAreDefined; | ||
| 369 | UInt32 numDefined = numItems; | ||
| 370 | SZ_READ_BYTE(allAreDefined); | ||
| 371 | if (!allAreDefined) | ||
| 372 | { | ||
| 373 | size_t numBytes = (numItems + 7) >> 3; | ||
| 374 | if (numBytes > sd->Size) | ||
| 375 | return SZ_ERROR_ARCHIVE; | ||
| 376 | numDefined = CountDefinedBits(sd->Data, numItems); | ||
| 377 | SKIP_DATA(sd, numBytes); | ||
| 378 | } | ||
| 379 | if (numDefined > (sd->Size >> 2)) | ||
| 380 | return SZ_ERROR_ARCHIVE; | ||
| 381 | SKIP_DATA(sd, (size_t)numDefined * 4); | ||
| 382 | return SZ_OK; | ||
| 383 | } | ||
| 384 | |||
| 385 | static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAllocPtr alloc) | ||
| 386 | { | ||
| 387 | RINOK(SzReadNumber32(sd, &p->NumPackStreams)); | ||
| 388 | |||
| 389 | RINOK(WaitId(sd, k7zIdSize)); | ||
| 390 | MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc); | ||
| 391 | { | ||
| 392 | UInt64 sum = 0; | ||
| 393 | UInt32 i; | ||
| 394 | UInt32 numPackStreams = p->NumPackStreams; | ||
| 395 | for (i = 0; i < numPackStreams; i++) | ||
| 396 | { | ||
| 397 | UInt64 packSize; | ||
| 398 | p->PackPositions[i] = sum; | ||
| 399 | RINOK(ReadNumber(sd, &packSize)); | ||
| 400 | sum += packSize; | ||
| 401 | if (sum < packSize) | ||
| 402 | return SZ_ERROR_ARCHIVE; | ||
| 403 | } | ||
| 404 | p->PackPositions[i] = sum; | ||
| 405 | } | ||
| 406 | |||
| 407 | for (;;) | ||
| 408 | { | ||
| 409 | UInt64 type; | ||
| 410 | RINOK(ReadID(sd, &type)); | ||
| 411 | if (type == k7zIdEnd) | ||
| 412 | return SZ_OK; | ||
| 413 | if (type == k7zIdCRC) | ||
| 414 | { | ||
| 415 | /* CRC of packed streams is unused now */ | ||
| 416 | RINOK(SkipBitUi32s(sd, p->NumPackStreams)); | ||
| 417 | continue; | ||
| 418 | } | ||
| 419 | RINOK(SkipData(sd)); | ||
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | /* | ||
| 424 | static SRes SzReadSwitch(CSzData *sd) | ||
| 425 | { | ||
| 426 | Byte external; | ||
| 427 | RINOK(SzReadByte(sd, &external)); | ||
| 428 | return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; | ||
| 429 | } | ||
| 430 | */ | ||
| 431 | |||
| 432 | #define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) | ||
| 433 | |||
| 434 | SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) | ||
| 435 | { | ||
| 436 | UInt32 numCoders, i; | ||
| 437 | UInt32 numInStreams = 0; | ||
| 438 | const Byte *dataStart = sd->Data; | ||
| 439 | |||
| 440 | f->NumCoders = 0; | ||
| 441 | f->NumBonds = 0; | ||
| 442 | f->NumPackStreams = 0; | ||
| 443 | f->UnpackStream = 0; | ||
| 444 | |||
| 445 | RINOK(SzReadNumber32(sd, &numCoders)); | ||
| 446 | if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) | ||
| 447 | return SZ_ERROR_UNSUPPORTED; | ||
| 448 | |||
| 449 | for (i = 0; i < numCoders; i++) | ||
| 450 | { | ||
| 451 | Byte mainByte; | ||
| 452 | CSzCoderInfo *coder = f->Coders + i; | ||
| 453 | unsigned idSize, j; | ||
| 454 | UInt64 id; | ||
| 455 | |||
| 456 | SZ_READ_BYTE(mainByte); | ||
| 457 | if ((mainByte & 0xC0) != 0) | ||
| 458 | return SZ_ERROR_UNSUPPORTED; | ||
| 459 | |||
| 460 | idSize = (unsigned)(mainByte & 0xF); | ||
| 461 | if (idSize > sizeof(id)) | ||
| 462 | return SZ_ERROR_UNSUPPORTED; | ||
| 463 | if (idSize > sd->Size) | ||
| 464 | return SZ_ERROR_ARCHIVE; | ||
| 465 | id = 0; | ||
| 466 | for (j = 0; j < idSize; j++) | ||
| 467 | { | ||
| 468 | id = ((id << 8) | *sd->Data); | ||
| 469 | sd->Data++; | ||
| 470 | sd->Size--; | ||
| 471 | } | ||
| 472 | if (id > (UInt32)0xFFFFFFFF) | ||
| 473 | return SZ_ERROR_UNSUPPORTED; | ||
| 474 | coder->MethodID = (UInt32)id; | ||
| 475 | |||
| 476 | coder->NumStreams = 1; | ||
| 477 | coder->PropsOffset = 0; | ||
| 478 | coder->PropsSize = 0; | ||
| 479 | |||
| 480 | if ((mainByte & 0x10) != 0) | ||
| 481 | { | ||
| 482 | UInt32 numStreams; | ||
| 483 | |||
| 484 | RINOK(SzReadNumber32(sd, &numStreams)); | ||
| 485 | if (numStreams > k_NumCodersStreams_in_Folder_MAX) | ||
| 486 | return SZ_ERROR_UNSUPPORTED; | ||
| 487 | coder->NumStreams = (Byte)numStreams; | ||
| 488 | |||
| 489 | RINOK(SzReadNumber32(sd, &numStreams)); | ||
| 490 | if (numStreams != 1) | ||
| 491 | return SZ_ERROR_UNSUPPORTED; | ||
| 492 | } | ||
| 493 | |||
| 494 | numInStreams += coder->NumStreams; | ||
| 495 | |||
| 496 | if (numInStreams > k_NumCodersStreams_in_Folder_MAX) | ||
| 497 | return SZ_ERROR_UNSUPPORTED; | ||
| 498 | |||
| 499 | if ((mainByte & 0x20) != 0) | ||
| 500 | { | ||
| 501 | UInt32 propsSize = 0; | ||
| 502 | RINOK(SzReadNumber32(sd, &propsSize)); | ||
| 503 | if (propsSize > sd->Size) | ||
| 504 | return SZ_ERROR_ARCHIVE; | ||
| 505 | if (propsSize >= 0x80) | ||
| 506 | return SZ_ERROR_UNSUPPORTED; | ||
| 507 | coder->PropsOffset = (size_t)(sd->Data - dataStart); | ||
| 508 | coder->PropsSize = (Byte)propsSize; | ||
| 509 | sd->Data += (size_t)propsSize; | ||
| 510 | sd->Size -= (size_t)propsSize; | ||
| 511 | } | ||
| 512 | } | ||
| 513 | |||
| 514 | /* | ||
| 515 | if (numInStreams == 1 && numCoders == 1) | ||
| 516 | { | ||
| 517 | f->NumPackStreams = 1; | ||
| 518 | f->PackStreams[0] = 0; | ||
| 519 | } | ||
| 520 | else | ||
| 521 | */ | ||
| 522 | { | ||
| 523 | Byte streamUsed[k_NumCodersStreams_in_Folder_MAX]; | ||
| 524 | UInt32 numBonds, numPackStreams; | ||
| 525 | |||
| 526 | numBonds = numCoders - 1; | ||
| 527 | if (numInStreams < numBonds) | ||
| 528 | return SZ_ERROR_ARCHIVE; | ||
| 529 | if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX) | ||
| 530 | return SZ_ERROR_UNSUPPORTED; | ||
| 531 | f->NumBonds = numBonds; | ||
| 532 | |||
| 533 | numPackStreams = numInStreams - numBonds; | ||
| 534 | if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) | ||
| 535 | return SZ_ERROR_UNSUPPORTED; | ||
| 536 | f->NumPackStreams = numPackStreams; | ||
| 537 | |||
| 538 | for (i = 0; i < numInStreams; i++) | ||
| 539 | streamUsed[i] = False; | ||
| 540 | |||
| 541 | if (numBonds != 0) | ||
| 542 | { | ||
| 543 | Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX]; | ||
| 544 | |||
| 545 | for (i = 0; i < numCoders; i++) | ||
| 546 | coderUsed[i] = False; | ||
| 547 | |||
| 548 | for (i = 0; i < numBonds; i++) | ||
| 549 | { | ||
| 550 | CSzBond *bp = f->Bonds + i; | ||
| 551 | |||
| 552 | RINOK(SzReadNumber32(sd, &bp->InIndex)); | ||
| 553 | if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) | ||
| 554 | return SZ_ERROR_ARCHIVE; | ||
| 555 | streamUsed[bp->InIndex] = True; | ||
| 556 | |||
| 557 | RINOK(SzReadNumber32(sd, &bp->OutIndex)); | ||
| 558 | if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) | ||
| 559 | return SZ_ERROR_ARCHIVE; | ||
| 560 | coderUsed[bp->OutIndex] = True; | ||
| 561 | } | ||
| 562 | |||
| 563 | for (i = 0; i < numCoders; i++) | ||
| 564 | if (!coderUsed[i]) | ||
| 565 | { | ||
| 566 | f->UnpackStream = i; | ||
| 567 | break; | ||
| 568 | } | ||
| 569 | |||
| 570 | if (i == numCoders) | ||
| 571 | return SZ_ERROR_ARCHIVE; | ||
| 572 | } | ||
| 573 | |||
| 574 | if (numPackStreams == 1) | ||
| 575 | { | ||
| 576 | for (i = 0; i < numInStreams; i++) | ||
| 577 | if (!streamUsed[i]) | ||
| 578 | break; | ||
| 579 | if (i == numInStreams) | ||
| 580 | return SZ_ERROR_ARCHIVE; | ||
| 581 | f->PackStreams[0] = i; | ||
| 582 | } | ||
| 583 | else | ||
| 584 | for (i = 0; i < numPackStreams; i++) | ||
| 585 | { | ||
| 586 | UInt32 index; | ||
| 587 | RINOK(SzReadNumber32(sd, &index)); | ||
| 588 | if (index >= numInStreams || streamUsed[index]) | ||
| 589 | return SZ_ERROR_ARCHIVE; | ||
| 590 | streamUsed[index] = True; | ||
| 591 | f->PackStreams[i] = index; | ||
| 592 | } | ||
| 593 | } | ||
| 594 | |||
| 595 | f->NumCoders = numCoders; | ||
| 596 | |||
| 597 | return SZ_OK; | ||
| 598 | } | ||
| 599 | |||
| 600 | |||
| 601 | static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) | ||
| 602 | { | ||
| 603 | CSzData sd; | ||
| 604 | sd = *sd2; | ||
| 605 | for (; num != 0; num--) | ||
| 606 | { | ||
| 607 | Byte firstByte, mask; | ||
| 608 | unsigned i; | ||
| 609 | SZ_READ_BYTE_2(firstByte); | ||
| 610 | if ((firstByte & 0x80) == 0) | ||
| 611 | continue; | ||
| 612 | if ((firstByte & 0x40) == 0) | ||
| 613 | { | ||
| 614 | if (sd.Size == 0) | ||
| 615 | return SZ_ERROR_ARCHIVE; | ||
| 616 | sd.Size--; | ||
| 617 | sd.Data++; | ||
| 618 | continue; | ||
| 619 | } | ||
| 620 | mask = 0x20; | ||
| 621 | for (i = 2; i < 8 && (firstByte & mask) != 0; i++) | ||
| 622 | mask >>= 1; | ||
| 623 | if (i > sd.Size) | ||
| 624 | return SZ_ERROR_ARCHIVE; | ||
| 625 | SKIP_DATA2(sd, i); | ||
| 626 | } | ||
| 627 | *sd2 = sd; | ||
| 628 | return SZ_OK; | ||
| 629 | } | ||
| 630 | |||
| 631 | |||
| 632 | #define k_Scan_NumCoders_MAX 64 | ||
| 633 | #define k_Scan_NumCodersStreams_in_Folder_MAX 64 | ||
| 634 | |||
| 635 | |||
| 636 | static SRes ReadUnpackInfo(CSzAr *p, | ||
| 637 | CSzData *sd2, | ||
| 638 | UInt32 numFoldersMax, | ||
| 639 | const CBuf *tempBufs, UInt32 numTempBufs, | ||
| 640 | ISzAllocPtr alloc) | ||
| 641 | { | ||
| 642 | CSzData sd; | ||
| 643 | |||
| 644 | UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex; | ||
| 645 | const Byte *startBufPtr; | ||
| 646 | Byte external; | ||
| 647 | |||
| 648 | RINOK(WaitId(sd2, k7zIdFolder)); | ||
| 649 | |||
| 650 | RINOK(SzReadNumber32(sd2, &numFolders)); | ||
| 651 | if (numFolders > numFoldersMax) | ||
| 652 | return SZ_ERROR_UNSUPPORTED; | ||
| 653 | p->NumFolders = numFolders; | ||
| 654 | |||
| 655 | SZ_READ_BYTE_SD(sd2, external); | ||
| 656 | if (external == 0) | ||
| 657 | sd = *sd2; | ||
| 658 | else | ||
| 659 | { | ||
| 660 | UInt32 index; | ||
| 661 | RINOK(SzReadNumber32(sd2, &index)); | ||
| 662 | if (index >= numTempBufs) | ||
| 663 | return SZ_ERROR_ARCHIVE; | ||
| 664 | sd.Data = tempBufs[index].data; | ||
| 665 | sd.Size = tempBufs[index].size; | ||
| 666 | } | ||
| 667 | |||
| 668 | MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc); | ||
| 669 | MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc); | ||
| 670 | MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc); | ||
| 671 | MY_ALLOC_ZE(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc); | ||
| 672 | |||
| 673 | startBufPtr = sd.Data; | ||
| 674 | |||
| 675 | packStreamIndex = 0; | ||
| 676 | numCodersOutStreams = 0; | ||
| 677 | |||
| 678 | for (fo = 0; fo < numFolders; fo++) | ||
| 679 | { | ||
| 680 | UInt32 numCoders, ci, numInStreams = 0; | ||
| 681 | |||
| 682 | p->FoCodersOffsets[fo] = (size_t)(sd.Data - startBufPtr); | ||
| 683 | |||
| 684 | RINOK(SzReadNumber32(&sd, &numCoders)); | ||
| 685 | if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) | ||
| 686 | return SZ_ERROR_UNSUPPORTED; | ||
| 687 | |||
| 688 | for (ci = 0; ci < numCoders; ci++) | ||
| 689 | { | ||
| 690 | Byte mainByte; | ||
| 691 | unsigned idSize; | ||
| 692 | UInt32 coderInStreams; | ||
| 693 | |||
| 694 | SZ_READ_BYTE_2(mainByte); | ||
| 695 | if ((mainByte & 0xC0) != 0) | ||
| 696 | return SZ_ERROR_UNSUPPORTED; | ||
| 697 | idSize = (mainByte & 0xF); | ||
| 698 | if (idSize > 8) | ||
| 699 | return SZ_ERROR_UNSUPPORTED; | ||
| 700 | if (idSize > sd.Size) | ||
| 701 | return SZ_ERROR_ARCHIVE; | ||
| 702 | SKIP_DATA2(sd, idSize); | ||
| 703 | |||
| 704 | coderInStreams = 1; | ||
| 705 | |||
| 706 | if ((mainByte & 0x10) != 0) | ||
| 707 | { | ||
| 708 | UInt32 coderOutStreams; | ||
| 709 | RINOK(SzReadNumber32(&sd, &coderInStreams)); | ||
| 710 | RINOK(SzReadNumber32(&sd, &coderOutStreams)); | ||
| 711 | if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) | ||
| 712 | return SZ_ERROR_UNSUPPORTED; | ||
| 713 | } | ||
| 714 | |||
| 715 | numInStreams += coderInStreams; | ||
| 716 | |||
| 717 | if ((mainByte & 0x20) != 0) | ||
| 718 | { | ||
| 719 | UInt32 propsSize; | ||
| 720 | RINOK(SzReadNumber32(&sd, &propsSize)); | ||
| 721 | if (propsSize > sd.Size) | ||
| 722 | return SZ_ERROR_ARCHIVE; | ||
| 723 | SKIP_DATA2(sd, propsSize); | ||
| 724 | } | ||
| 725 | } | ||
| 726 | |||
| 727 | { | ||
| 728 | UInt32 indexOfMainStream = 0; | ||
| 729 | UInt32 numPackStreams = 1; | ||
| 730 | |||
| 731 | if (numCoders != 1 || numInStreams != 1) | ||
| 732 | { | ||
| 733 | Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX]; | ||
| 734 | Byte coderUsed[k_Scan_NumCoders_MAX]; | ||
| 735 | |||
| 736 | UInt32 i; | ||
| 737 | UInt32 numBonds = numCoders - 1; | ||
| 738 | if (numInStreams < numBonds) | ||
| 739 | return SZ_ERROR_ARCHIVE; | ||
| 740 | |||
| 741 | if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) | ||
| 742 | return SZ_ERROR_UNSUPPORTED; | ||
| 743 | |||
| 744 | for (i = 0; i < numInStreams; i++) | ||
| 745 | streamUsed[i] = False; | ||
| 746 | for (i = 0; i < numCoders; i++) | ||
| 747 | coderUsed[i] = False; | ||
| 748 | |||
| 749 | for (i = 0; i < numBonds; i++) | ||
| 750 | { | ||
| 751 | UInt32 index; | ||
| 752 | |||
| 753 | RINOK(SzReadNumber32(&sd, &index)); | ||
| 754 | if (index >= numInStreams || streamUsed[index]) | ||
| 755 | return SZ_ERROR_ARCHIVE; | ||
| 756 | streamUsed[index] = True; | ||
| 757 | |||
| 758 | RINOK(SzReadNumber32(&sd, &index)); | ||
| 759 | if (index >= numCoders || coderUsed[index]) | ||
| 760 | return SZ_ERROR_ARCHIVE; | ||
| 761 | coderUsed[index] = True; | ||
| 762 | } | ||
| 763 | |||
| 764 | numPackStreams = numInStreams - numBonds; | ||
| 765 | |||
| 766 | if (numPackStreams != 1) | ||
| 767 | for (i = 0; i < numPackStreams; i++) | ||
| 768 | { | ||
| 769 | UInt32 index; | ||
| 770 | RINOK(SzReadNumber32(&sd, &index)); | ||
| 771 | if (index >= numInStreams || streamUsed[index]) | ||
| 772 | return SZ_ERROR_ARCHIVE; | ||
| 773 | streamUsed[index] = True; | ||
| 774 | } | ||
| 775 | |||
| 776 | for (i = 0; i < numCoders; i++) | ||
| 777 | if (!coderUsed[i]) | ||
| 778 | { | ||
| 779 | indexOfMainStream = i; | ||
| 780 | break; | ||
| 781 | } | ||
| 782 | |||
| 783 | if (i == numCoders) | ||
| 784 | return SZ_ERROR_ARCHIVE; | ||
| 785 | } | ||
| 786 | |||
| 787 | p->FoStartPackStreamIndex[fo] = packStreamIndex; | ||
| 788 | p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; | ||
| 789 | p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; | ||
| 790 | numCodersOutStreams += numCoders; | ||
| 791 | if (numCodersOutStreams < numCoders) | ||
| 792 | return SZ_ERROR_UNSUPPORTED; | ||
| 793 | if (numPackStreams > p->NumPackStreams - packStreamIndex) | ||
| 794 | return SZ_ERROR_ARCHIVE; | ||
| 795 | packStreamIndex += numPackStreams; | ||
| 796 | } | ||
| 797 | } | ||
| 798 | |||
| 799 | p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; | ||
| 800 | |||
| 801 | { | ||
| 802 | const size_t dataSize = (size_t)(sd.Data - startBufPtr); | ||
| 803 | p->FoStartPackStreamIndex[fo] = packStreamIndex; | ||
| 804 | p->FoCodersOffsets[fo] = dataSize; | ||
| 805 | MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc); | ||
| 806 | } | ||
| 807 | |||
| 808 | if (external != 0) | ||
| 809 | { | ||
| 810 | if (sd.Size != 0) | ||
| 811 | return SZ_ERROR_ARCHIVE; | ||
| 812 | sd = *sd2; | ||
| 813 | } | ||
| 814 | |||
| 815 | RINOK(WaitId(&sd, k7zIdCodersUnpackSize)); | ||
| 816 | |||
| 817 | MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc); | ||
| 818 | { | ||
| 819 | UInt32 i; | ||
| 820 | for (i = 0; i < numCodersOutStreams; i++) | ||
| 821 | { | ||
| 822 | RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)); | ||
| 823 | } | ||
| 824 | } | ||
| 825 | |||
| 826 | for (;;) | ||
| 827 | { | ||
| 828 | UInt64 type; | ||
| 829 | RINOK(ReadID(&sd, &type)); | ||
| 830 | if (type == k7zIdEnd) | ||
| 831 | { | ||
| 832 | *sd2 = sd; | ||
| 833 | return SZ_OK; | ||
| 834 | } | ||
| 835 | if (type == k7zIdCRC) | ||
| 836 | { | ||
| 837 | RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)); | ||
| 838 | continue; | ||
| 839 | } | ||
| 840 | RINOK(SkipData(&sd)); | ||
| 841 | } | ||
| 842 | } | ||
| 843 | |||
| 844 | |||
| 845 | UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex) | ||
| 846 | { | ||
| 847 | return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]]; | ||
| 848 | } | ||
| 849 | |||
| 850 | |||
| 851 | typedef struct | ||
| 852 | { | ||
| 853 | UInt32 NumTotalSubStreams; | ||
| 854 | UInt32 NumSubDigests; | ||
| 855 | CSzData sdNumSubStreams; | ||
| 856 | CSzData sdSizes; | ||
| 857 | CSzData sdCRCs; | ||
| 858 | } CSubStreamInfo; | ||
| 859 | |||
| 860 | |||
| 861 | static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) | ||
| 862 | { | ||
| 863 | UInt64 type = 0; | ||
| 864 | UInt32 numSubDigests = 0; | ||
| 865 | UInt32 numFolders = p->NumFolders; | ||
| 866 | UInt32 numUnpackStreams = numFolders; | ||
| 867 | UInt32 numUnpackSizesInData = 0; | ||
| 868 | |||
| 869 | for (;;) | ||
| 870 | { | ||
| 871 | RINOK(ReadID(sd, &type)); | ||
| 872 | if (type == k7zIdNumUnpackStream) | ||
| 873 | { | ||
| 874 | UInt32 i; | ||
| 875 | ssi->sdNumSubStreams.Data = sd->Data; | ||
| 876 | numUnpackStreams = 0; | ||
| 877 | numSubDigests = 0; | ||
| 878 | for (i = 0; i < numFolders; i++) | ||
| 879 | { | ||
| 880 | UInt32 numStreams; | ||
| 881 | RINOK(SzReadNumber32(sd, &numStreams)); | ||
| 882 | if (numUnpackStreams > numUnpackStreams + numStreams) | ||
| 883 | return SZ_ERROR_UNSUPPORTED; | ||
| 884 | numUnpackStreams += numStreams; | ||
| 885 | if (numStreams != 0) | ||
| 886 | numUnpackSizesInData += (numStreams - 1); | ||
| 887 | if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i)) | ||
| 888 | numSubDigests += numStreams; | ||
| 889 | } | ||
| 890 | ssi->sdNumSubStreams.Size = (size_t)(sd->Data - ssi->sdNumSubStreams.Data); | ||
| 891 | continue; | ||
| 892 | } | ||
| 893 | if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd) | ||
| 894 | break; | ||
| 895 | RINOK(SkipData(sd)); | ||
| 896 | } | ||
| 897 | |||
| 898 | if (!ssi->sdNumSubStreams.Data) | ||
| 899 | { | ||
| 900 | numSubDigests = numFolders; | ||
| 901 | if (p->FolderCRCs.Defs) | ||
| 902 | numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders); | ||
| 903 | } | ||
| 904 | |||
| 905 | ssi->NumTotalSubStreams = numUnpackStreams; | ||
| 906 | ssi->NumSubDigests = numSubDigests; | ||
| 907 | |||
| 908 | if (type == k7zIdSize) | ||
| 909 | { | ||
| 910 | ssi->sdSizes.Data = sd->Data; | ||
| 911 | RINOK(SkipNumbers(sd, numUnpackSizesInData)); | ||
| 912 | ssi->sdSizes.Size = (size_t)(sd->Data - ssi->sdSizes.Data); | ||
| 913 | RINOK(ReadID(sd, &type)); | ||
| 914 | } | ||
| 915 | |||
| 916 | for (;;) | ||
| 917 | { | ||
| 918 | if (type == k7zIdEnd) | ||
| 919 | return SZ_OK; | ||
| 920 | if (type == k7zIdCRC) | ||
| 921 | { | ||
| 922 | ssi->sdCRCs.Data = sd->Data; | ||
| 923 | RINOK(SkipBitUi32s(sd, numSubDigests)); | ||
| 924 | ssi->sdCRCs.Size = (size_t)(sd->Data - ssi->sdCRCs.Data); | ||
| 925 | } | ||
| 926 | else | ||
| 927 | { | ||
| 928 | RINOK(SkipData(sd)); | ||
| 929 | } | ||
| 930 | RINOK(ReadID(sd, &type)); | ||
| 931 | } | ||
| 932 | } | ||
| 933 | |||
| 934 | static SRes SzReadStreamsInfo(CSzAr *p, | ||
| 935 | CSzData *sd, | ||
| 936 | UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs, | ||
| 937 | UInt64 *dataOffset, | ||
| 938 | CSubStreamInfo *ssi, | ||
| 939 | ISzAllocPtr alloc) | ||
| 940 | { | ||
| 941 | UInt64 type; | ||
| 942 | |||
| 943 | SzData_Clear(&ssi->sdSizes); | ||
| 944 | SzData_Clear(&ssi->sdCRCs); | ||
| 945 | SzData_Clear(&ssi->sdNumSubStreams); | ||
| 946 | |||
| 947 | *dataOffset = 0; | ||
| 948 | RINOK(ReadID(sd, &type)); | ||
| 949 | if (type == k7zIdPackInfo) | ||
| 950 | { | ||
| 951 | RINOK(ReadNumber(sd, dataOffset)); | ||
| 952 | if (*dataOffset > p->RangeLimit) | ||
| 953 | return SZ_ERROR_ARCHIVE; | ||
| 954 | RINOK(ReadPackInfo(p, sd, alloc)); | ||
| 955 | if (p->PackPositions[p->NumPackStreams] > p->RangeLimit - *dataOffset) | ||
| 956 | return SZ_ERROR_ARCHIVE; | ||
| 957 | RINOK(ReadID(sd, &type)); | ||
| 958 | } | ||
| 959 | if (type == k7zIdUnpackInfo) | ||
| 960 | { | ||
| 961 | RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)); | ||
| 962 | RINOK(ReadID(sd, &type)); | ||
| 963 | } | ||
| 964 | if (type == k7zIdSubStreamsInfo) | ||
| 965 | { | ||
| 966 | RINOK(ReadSubStreamsInfo(p, sd, ssi)); | ||
| 967 | RINOK(ReadID(sd, &type)); | ||
| 968 | } | ||
| 969 | else | ||
| 970 | { | ||
| 971 | ssi->NumTotalSubStreams = p->NumFolders; | ||
| 972 | // ssi->NumSubDigests = 0; | ||
| 973 | } | ||
| 974 | |||
| 975 | return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED); | ||
| 976 | } | ||
| 977 | |||
| 978 | static SRes SzReadAndDecodePackedStreams( | ||
| 979 | ILookInStream *inStream, | ||
| 980 | CSzData *sd, | ||
| 981 | CBuf *tempBufs, | ||
| 982 | UInt32 numFoldersMax, | ||
| 983 | UInt64 baseOffset, | ||
| 984 | CSzAr *p, | ||
| 985 | ISzAllocPtr allocTemp) | ||
| 986 | { | ||
| 987 | UInt64 dataStartPos; | ||
| 988 | UInt32 fo; | ||
| 989 | CSubStreamInfo ssi; | ||
| 990 | |||
| 991 | RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)); | ||
| 992 | |||
| 993 | dataStartPos += baseOffset; | ||
| 994 | if (p->NumFolders == 0) | ||
| 995 | return SZ_ERROR_ARCHIVE; | ||
| 996 | |||
| 997 | for (fo = 0; fo < p->NumFolders; fo++) | ||
| 998 | Buf_Init(tempBufs + fo); | ||
| 999 | |||
| 1000 | for (fo = 0; fo < p->NumFolders; fo++) | ||
| 1001 | { | ||
| 1002 | CBuf *tempBuf = tempBufs + fo; | ||
| 1003 | UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); | ||
| 1004 | if ((size_t)unpackSize != unpackSize) | ||
| 1005 | return SZ_ERROR_MEM; | ||
| 1006 | if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) | ||
| 1007 | return SZ_ERROR_MEM; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | for (fo = 0; fo < p->NumFolders; fo++) | ||
| 1011 | { | ||
| 1012 | const CBuf *tempBuf = tempBufs + fo; | ||
| 1013 | RINOK(LookInStream_SeekTo(inStream, dataStartPos)); | ||
| 1014 | RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | return SZ_OK; | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets) | ||
| 1021 | { | ||
| 1022 | size_t pos = 0; | ||
| 1023 | *offsets++ = 0; | ||
| 1024 | if (numFiles == 0) | ||
| 1025 | return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE; | ||
| 1026 | if (size < 2) | ||
| 1027 | return SZ_ERROR_ARCHIVE; | ||
| 1028 | if (data[size - 2] != 0 || data[size - 1] != 0) | ||
| 1029 | return SZ_ERROR_ARCHIVE; | ||
| 1030 | do | ||
| 1031 | { | ||
| 1032 | const Byte *p; | ||
| 1033 | if (pos == size) | ||
| 1034 | return SZ_ERROR_ARCHIVE; | ||
| 1035 | for (p = data + pos; | ||
| 1036 | #ifdef _WIN32 | ||
| 1037 | *(const UInt16 *)(const void *)p != 0 | ||
| 1038 | #else | ||
| 1039 | p[0] != 0 || p[1] != 0 | ||
| 1040 | #endif | ||
| 1041 | ; p += 2); | ||
| 1042 | pos = (size_t)(p - data) + 2; | ||
| 1043 | *offsets++ = (pos >> 1); | ||
| 1044 | } | ||
| 1045 | while (--numFiles); | ||
| 1046 | return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, | ||
| 1050 | CSzData *sd2, | ||
| 1051 | const CBuf *tempBufs, UInt32 numTempBufs, | ||
| 1052 | ISzAllocPtr alloc) | ||
| 1053 | { | ||
| 1054 | CSzData sd; | ||
| 1055 | UInt32 i; | ||
| 1056 | CNtfsFileTime *vals; | ||
| 1057 | Byte *defs; | ||
| 1058 | Byte external; | ||
| 1059 | |||
| 1060 | RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)); | ||
| 1061 | |||
| 1062 | SZ_READ_BYTE_SD(sd2, external); | ||
| 1063 | if (external == 0) | ||
| 1064 | sd = *sd2; | ||
| 1065 | else | ||
| 1066 | { | ||
| 1067 | UInt32 index; | ||
| 1068 | RINOK(SzReadNumber32(sd2, &index)); | ||
| 1069 | if (index >= numTempBufs) | ||
| 1070 | return SZ_ERROR_ARCHIVE; | ||
| 1071 | sd.Data = tempBufs[index].data; | ||
| 1072 | sd.Size = tempBufs[index].size; | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc); | ||
| 1076 | vals = p->Vals; | ||
| 1077 | defs = p->Defs; | ||
| 1078 | for (i = 0; i < num; i++) | ||
| 1079 | if (SzBitArray_Check(defs, i)) | ||
| 1080 | { | ||
| 1081 | if (sd.Size < 8) | ||
| 1082 | return SZ_ERROR_ARCHIVE; | ||
| 1083 | vals[i].Low = GetUi32(sd.Data); | ||
| 1084 | vals[i].High = GetUi32(sd.Data + 4); | ||
| 1085 | SKIP_DATA2(sd, 8); | ||
| 1086 | } | ||
| 1087 | else | ||
| 1088 | vals[i].High = vals[i].Low = 0; | ||
| 1089 | |||
| 1090 | if (external == 0) | ||
| 1091 | *sd2 = sd; | ||
| 1092 | |||
| 1093 | return SZ_OK; | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | |||
| 1097 | #define NUM_ADDITIONAL_STREAMS_MAX 8 | ||
| 1098 | |||
| 1099 | |||
| 1100 | static SRes SzReadHeader2( | ||
| 1101 | CSzArEx *p, /* allocMain */ | ||
| 1102 | CSzData *sd, | ||
| 1103 | ILookInStream *inStream, | ||
| 1104 | CBuf *tempBufs, UInt32 *numTempBufs, | ||
| 1105 | ISzAllocPtr allocMain, | ||
| 1106 | ISzAllocPtr allocTemp | ||
| 1107 | ) | ||
| 1108 | { | ||
| 1109 | CSubStreamInfo ssi; | ||
| 1110 | |||
| 1111 | { | ||
| 1112 | UInt64 type; | ||
| 1113 | |||
| 1114 | SzData_Clear(&ssi.sdSizes); | ||
| 1115 | SzData_Clear(&ssi.sdCRCs); | ||
| 1116 | SzData_Clear(&ssi.sdNumSubStreams); | ||
| 1117 | |||
| 1118 | ssi.NumSubDigests = 0; | ||
| 1119 | ssi.NumTotalSubStreams = 0; | ||
| 1120 | |||
| 1121 | RINOK(ReadID(sd, &type)); | ||
| 1122 | |||
| 1123 | if (type == k7zIdArchiveProperties) | ||
| 1124 | { | ||
| 1125 | for (;;) | ||
| 1126 | { | ||
| 1127 | UInt64 type2; | ||
| 1128 | RINOK(ReadID(sd, &type2)); | ||
| 1129 | if (type2 == k7zIdEnd) | ||
| 1130 | break; | ||
| 1131 | RINOK(SkipData(sd)); | ||
| 1132 | } | ||
| 1133 | RINOK(ReadID(sd, &type)); | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | if (type == k7zIdAdditionalStreamsInfo) | ||
| 1137 | { | ||
| 1138 | CSzAr tempAr; | ||
| 1139 | SRes res; | ||
| 1140 | |||
| 1141 | SzAr_Init(&tempAr); | ||
| 1142 | tempAr.RangeLimit = p->db.RangeLimit; | ||
| 1143 | |||
| 1144 | res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, | ||
| 1145 | p->startPosAfterHeader, &tempAr, allocTemp); | ||
| 1146 | *numTempBufs = tempAr.NumFolders; | ||
| 1147 | SzAr_Free(&tempAr, allocTemp); | ||
| 1148 | |||
| 1149 | if (res != SZ_OK) | ||
| 1150 | return res; | ||
| 1151 | RINOK(ReadID(sd, &type)); | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | if (type == k7zIdMainStreamsInfo) | ||
| 1155 | { | ||
| 1156 | RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs, | ||
| 1157 | &p->dataPos, &ssi, allocMain)); | ||
| 1158 | p->dataPos += p->startPosAfterHeader; | ||
| 1159 | RINOK(ReadID(sd, &type)); | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | if (type == k7zIdEnd) | ||
| 1163 | { | ||
| 1164 | return SZ_OK; | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | if (type != k7zIdFilesInfo) | ||
| 1168 | return SZ_ERROR_ARCHIVE; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | { | ||
| 1172 | UInt32 numFiles = 0; | ||
| 1173 | UInt32 numEmptyStreams = 0; | ||
| 1174 | const Byte *emptyStreams = NULL; | ||
| 1175 | const Byte *emptyFiles = NULL; | ||
| 1176 | |||
| 1177 | RINOK(SzReadNumber32(sd, &numFiles)); | ||
| 1178 | p->NumFiles = numFiles; | ||
| 1179 | |||
| 1180 | for (;;) | ||
| 1181 | { | ||
| 1182 | UInt64 type; | ||
| 1183 | UInt64 size; | ||
| 1184 | RINOK(ReadID(sd, &type)); | ||
| 1185 | if (type == k7zIdEnd) | ||
| 1186 | break; | ||
| 1187 | RINOK(ReadNumber(sd, &size)); | ||
| 1188 | if (size > sd->Size) | ||
| 1189 | return SZ_ERROR_ARCHIVE; | ||
| 1190 | |||
| 1191 | if (type >= ((UInt32)1 << 8)) | ||
| 1192 | { | ||
| 1193 | SKIP_DATA(sd, size); | ||
| 1194 | } | ||
| 1195 | else switch ((unsigned)type) | ||
| 1196 | { | ||
| 1197 | case k7zIdName: | ||
| 1198 | { | ||
| 1199 | size_t namesSize; | ||
| 1200 | const Byte *namesData; | ||
| 1201 | Byte external; | ||
| 1202 | |||
| 1203 | SZ_READ_BYTE(external); | ||
| 1204 | if (external == 0) | ||
| 1205 | { | ||
| 1206 | namesSize = (size_t)size - 1; | ||
| 1207 | namesData = sd->Data; | ||
| 1208 | } | ||
| 1209 | else | ||
| 1210 | { | ||
| 1211 | UInt32 index; | ||
| 1212 | RINOK(SzReadNumber32(sd, &index)); | ||
| 1213 | if (index >= *numTempBufs) | ||
| 1214 | return SZ_ERROR_ARCHIVE; | ||
| 1215 | namesData = (tempBufs)[index].data; | ||
| 1216 | namesSize = (tempBufs)[index].size; | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | if ((namesSize & 1) != 0) | ||
| 1220 | return SZ_ERROR_ARCHIVE; | ||
| 1221 | MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); | ||
| 1222 | MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain); | ||
| 1223 | RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) | ||
| 1224 | if (external == 0) | ||
| 1225 | { | ||
| 1226 | SKIP_DATA(sd, namesSize); | ||
| 1227 | } | ||
| 1228 | break; | ||
| 1229 | } | ||
| 1230 | case k7zIdEmptyStream: | ||
| 1231 | { | ||
| 1232 | RINOK(RememberBitVector(sd, numFiles, &emptyStreams)); | ||
| 1233 | numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); | ||
| 1234 | emptyFiles = NULL; | ||
| 1235 | break; | ||
| 1236 | } | ||
| 1237 | case k7zIdEmptyFile: | ||
| 1238 | { | ||
| 1239 | RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)); | ||
| 1240 | break; | ||
| 1241 | } | ||
| 1242 | case k7zIdWinAttrib: | ||
| 1243 | { | ||
| 1244 | Byte external; | ||
| 1245 | CSzData sdSwitch; | ||
| 1246 | CSzData *sdPtr; | ||
| 1247 | SzBitUi32s_Free(&p->Attribs, allocMain); | ||
| 1248 | RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)); | ||
| 1249 | |||
| 1250 | SZ_READ_BYTE(external); | ||
| 1251 | if (external == 0) | ||
| 1252 | sdPtr = sd; | ||
| 1253 | else | ||
| 1254 | { | ||
| 1255 | UInt32 index; | ||
| 1256 | RINOK(SzReadNumber32(sd, &index)); | ||
| 1257 | if (index >= *numTempBufs) | ||
| 1258 | return SZ_ERROR_ARCHIVE; | ||
| 1259 | sdSwitch.Data = (tempBufs)[index].data; | ||
| 1260 | sdSwitch.Size = (tempBufs)[index].size; | ||
| 1261 | sdPtr = &sdSwitch; | ||
| 1262 | } | ||
| 1263 | RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)); | ||
| 1264 | break; | ||
| 1265 | } | ||
| 1266 | /* | ||
| 1267 | case k7zParent: | ||
| 1268 | { | ||
| 1269 | SzBitUi32s_Free(&p->Parents, allocMain); | ||
| 1270 | RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain)); | ||
| 1271 | RINOK(SzReadSwitch(sd)); | ||
| 1272 | RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain)); | ||
| 1273 | break; | ||
| 1274 | } | ||
| 1275 | */ | ||
| 1276 | case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; | ||
| 1277 | case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; | ||
| 1278 | default: | ||
| 1279 | { | ||
| 1280 | SKIP_DATA(sd, size); | ||
| 1281 | } | ||
| 1282 | } | ||
| 1283 | } | ||
| 1284 | |||
| 1285 | if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams) | ||
| 1286 | return SZ_ERROR_ARCHIVE; | ||
| 1287 | |||
| 1288 | for (;;) | ||
| 1289 | { | ||
| 1290 | UInt64 type; | ||
| 1291 | RINOK(ReadID(sd, &type)); | ||
| 1292 | if (type == k7zIdEnd) | ||
| 1293 | break; | ||
| 1294 | RINOK(SkipData(sd)); | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | { | ||
| 1298 | UInt32 i; | ||
| 1299 | UInt32 emptyFileIndex = 0; | ||
| 1300 | UInt32 folderIndex = 0; | ||
| 1301 | UInt32 remSubStreams = 0; | ||
| 1302 | UInt32 numSubStreams = 0; | ||
| 1303 | UInt64 unpackPos = 0; | ||
| 1304 | const Byte *digestsDefs = NULL; | ||
| 1305 | const Byte *digestsVals = NULL; | ||
| 1306 | UInt32 digestsValsIndex = 0; | ||
| 1307 | UInt32 digestIndex; | ||
| 1308 | Byte allDigestsDefined = 0; | ||
| 1309 | Byte isDirMask = 0; | ||
| 1310 | Byte crcMask = 0; | ||
| 1311 | Byte mask = 0x80; | ||
| 1312 | |||
| 1313 | MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain); | ||
| 1314 | MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain); | ||
| 1315 | MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain); | ||
| 1316 | MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain); | ||
| 1317 | |||
| 1318 | RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)); | ||
| 1319 | |||
| 1320 | if (ssi.sdCRCs.Size != 0) | ||
| 1321 | { | ||
| 1322 | SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined); | ||
| 1323 | if (allDigestsDefined) | ||
| 1324 | digestsVals = ssi.sdCRCs.Data; | ||
| 1325 | else | ||
| 1326 | { | ||
| 1327 | size_t numBytes = (ssi.NumSubDigests + 7) >> 3; | ||
| 1328 | digestsDefs = ssi.sdCRCs.Data; | ||
| 1329 | digestsVals = digestsDefs + numBytes; | ||
| 1330 | } | ||
| 1331 | } | ||
| 1332 | |||
| 1333 | digestIndex = 0; | ||
| 1334 | |||
| 1335 | for (i = 0; i < numFiles; i++, mask >>= 1) | ||
| 1336 | { | ||
| 1337 | if (mask == 0) | ||
| 1338 | { | ||
| 1339 | UInt32 byteIndex = (i - 1) >> 3; | ||
| 1340 | p->IsDirs[byteIndex] = isDirMask; | ||
| 1341 | p->CRCs.Defs[byteIndex] = crcMask; | ||
| 1342 | isDirMask = 0; | ||
| 1343 | crcMask = 0; | ||
| 1344 | mask = 0x80; | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | p->UnpackPositions[i] = unpackPos; | ||
| 1348 | p->CRCs.Vals[i] = 0; | ||
| 1349 | |||
| 1350 | if (emptyStreams && SzBitArray_Check(emptyStreams, i)) | ||
| 1351 | { | ||
| 1352 | if (emptyFiles) | ||
| 1353 | { | ||
| 1354 | if (!SzBitArray_Check(emptyFiles, emptyFileIndex)) | ||
| 1355 | isDirMask |= mask; | ||
| 1356 | emptyFileIndex++; | ||
| 1357 | } | ||
| 1358 | else | ||
| 1359 | isDirMask |= mask; | ||
| 1360 | if (remSubStreams == 0) | ||
| 1361 | { | ||
| 1362 | p->FileToFolder[i] = (UInt32)-1; | ||
| 1363 | continue; | ||
| 1364 | } | ||
| 1365 | } | ||
| 1366 | |||
| 1367 | if (remSubStreams == 0) | ||
| 1368 | { | ||
| 1369 | for (;;) | ||
| 1370 | { | ||
| 1371 | if (folderIndex >= p->db.NumFolders) | ||
| 1372 | return SZ_ERROR_ARCHIVE; | ||
| 1373 | p->FolderToFile[folderIndex] = i; | ||
| 1374 | numSubStreams = 1; | ||
| 1375 | if (ssi.sdNumSubStreams.Data) | ||
| 1376 | { | ||
| 1377 | RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); | ||
| 1378 | } | ||
| 1379 | remSubStreams = numSubStreams; | ||
| 1380 | if (numSubStreams != 0) | ||
| 1381 | break; | ||
| 1382 | { | ||
| 1383 | UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); | ||
| 1384 | unpackPos += folderUnpackSize; | ||
| 1385 | if (unpackPos < folderUnpackSize) | ||
| 1386 | return SZ_ERROR_ARCHIVE; | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | folderIndex++; | ||
| 1390 | } | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | p->FileToFolder[i] = folderIndex; | ||
| 1394 | |||
| 1395 | if (emptyStreams && SzBitArray_Check(emptyStreams, i)) | ||
| 1396 | continue; | ||
| 1397 | |||
| 1398 | if (--remSubStreams == 0) | ||
| 1399 | { | ||
| 1400 | UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); | ||
| 1401 | UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; | ||
| 1402 | if (folderUnpackSize < unpackPos - startFolderUnpackPos) | ||
| 1403 | return SZ_ERROR_ARCHIVE; | ||
| 1404 | unpackPos = startFolderUnpackPos + folderUnpackSize; | ||
| 1405 | if (unpackPos < folderUnpackSize) | ||
| 1406 | return SZ_ERROR_ARCHIVE; | ||
| 1407 | |||
| 1408 | if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i)) | ||
| 1409 | { | ||
| 1410 | p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; | ||
| 1411 | crcMask |= mask; | ||
| 1412 | } | ||
| 1413 | else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) | ||
| 1414 | { | ||
| 1415 | p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); | ||
| 1416 | digestsValsIndex++; | ||
| 1417 | crcMask |= mask; | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | folderIndex++; | ||
| 1421 | } | ||
| 1422 | else | ||
| 1423 | { | ||
| 1424 | UInt64 v; | ||
| 1425 | RINOK(ReadNumber(&ssi.sdSizes, &v)); | ||
| 1426 | unpackPos += v; | ||
| 1427 | if (unpackPos < v) | ||
| 1428 | return SZ_ERROR_ARCHIVE; | ||
| 1429 | if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) | ||
| 1430 | { | ||
| 1431 | p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); | ||
| 1432 | digestsValsIndex++; | ||
| 1433 | crcMask |= mask; | ||
| 1434 | } | ||
| 1435 | } | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | if (mask != 0x80) | ||
| 1439 | { | ||
| 1440 | UInt32 byteIndex = (i - 1) >> 3; | ||
| 1441 | p->IsDirs[byteIndex] = isDirMask; | ||
| 1442 | p->CRCs.Defs[byteIndex] = crcMask; | ||
| 1443 | } | ||
| 1444 | |||
| 1445 | p->UnpackPositions[i] = unpackPos; | ||
| 1446 | |||
| 1447 | if (remSubStreams != 0) | ||
| 1448 | return SZ_ERROR_ARCHIVE; | ||
| 1449 | |||
| 1450 | for (;;) | ||
| 1451 | { | ||
| 1452 | p->FolderToFile[folderIndex] = i; | ||
| 1453 | if (folderIndex >= p->db.NumFolders) | ||
| 1454 | break; | ||
| 1455 | if (!ssi.sdNumSubStreams.Data) | ||
| 1456 | return SZ_ERROR_ARCHIVE; | ||
| 1457 | RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); | ||
| 1458 | if (numSubStreams != 0) | ||
| 1459 | return SZ_ERROR_ARCHIVE; | ||
| 1460 | /* | ||
| 1461 | { | ||
| 1462 | UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); | ||
| 1463 | unpackPos += folderUnpackSize; | ||
| 1464 | if (unpackPos < folderUnpackSize) | ||
| 1465 | return SZ_ERROR_ARCHIVE; | ||
| 1466 | } | ||
| 1467 | */ | ||
| 1468 | folderIndex++; | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0) | ||
| 1472 | return SZ_ERROR_ARCHIVE; | ||
| 1473 | } | ||
| 1474 | } | ||
| 1475 | return SZ_OK; | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | |||
| 1479 | static SRes SzReadHeader( | ||
| 1480 | CSzArEx *p, | ||
| 1481 | CSzData *sd, | ||
| 1482 | ILookInStream *inStream, | ||
| 1483 | ISzAllocPtr allocMain, | ||
| 1484 | ISzAllocPtr allocTemp) | ||
| 1485 | { | ||
| 1486 | UInt32 i; | ||
| 1487 | UInt32 numTempBufs = 0; | ||
| 1488 | SRes res; | ||
| 1489 | CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX]; | ||
| 1490 | |||
| 1491 | for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) | ||
| 1492 | Buf_Init(tempBufs + i); | ||
| 1493 | |||
| 1494 | res = SzReadHeader2(p, sd, inStream, | ||
| 1495 | tempBufs, &numTempBufs, | ||
| 1496 | allocMain, allocTemp); | ||
| 1497 | |||
| 1498 | for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) | ||
| 1499 | Buf_Free(tempBufs + i, allocTemp); | ||
| 1500 | |||
| 1501 | RINOK(res); | ||
| 1502 | |||
| 1503 | if (sd->Size != 0) | ||
| 1504 | return SZ_ERROR_FAIL; | ||
| 1505 | |||
| 1506 | return res; | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | static SRes SzArEx_Open2( | ||
| 1510 | CSzArEx *p, | ||
| 1511 | ILookInStream *inStream, | ||
| 1512 | ISzAllocPtr allocMain, | ||
| 1513 | ISzAllocPtr allocTemp) | ||
| 1514 | { | ||
| 1515 | Byte header[k7zStartHeaderSize]; | ||
| 1516 | Int64 startArcPos; | ||
| 1517 | UInt64 nextHeaderOffset, nextHeaderSize; | ||
| 1518 | size_t nextHeaderSizeT; | ||
| 1519 | UInt32 nextHeaderCRC; | ||
| 1520 | CBuf buf; | ||
| 1521 | SRes res; | ||
| 1522 | |||
| 1523 | startArcPos = 0; | ||
| 1524 | RINOK(ILookInStream_Seek(inStream, &startArcPos, SZ_SEEK_CUR)); | ||
| 1525 | |||
| 1526 | RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); | ||
| 1527 | |||
| 1528 | if (!TestSignatureCandidate(header)) | ||
| 1529 | return SZ_ERROR_NO_ARCHIVE; | ||
| 1530 | if (header[6] != k7zMajorVersion) | ||
| 1531 | return SZ_ERROR_UNSUPPORTED; | ||
| 1532 | |||
| 1533 | nextHeaderOffset = GetUi64(header + 12); | ||
| 1534 | nextHeaderSize = GetUi64(header + 20); | ||
| 1535 | nextHeaderCRC = GetUi32(header + 28); | ||
| 1536 | |||
| 1537 | p->startPosAfterHeader = (UInt64)startArcPos + k7zStartHeaderSize; | ||
| 1538 | |||
| 1539 | if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) | ||
| 1540 | return SZ_ERROR_CRC; | ||
| 1541 | |||
| 1542 | p->db.RangeLimit = nextHeaderOffset; | ||
| 1543 | |||
| 1544 | nextHeaderSizeT = (size_t)nextHeaderSize; | ||
| 1545 | if (nextHeaderSizeT != nextHeaderSize) | ||
| 1546 | return SZ_ERROR_MEM; | ||
| 1547 | if (nextHeaderSizeT == 0) | ||
| 1548 | return SZ_OK; | ||
| 1549 | if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || | ||
| 1550 | nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) | ||
| 1551 | return SZ_ERROR_NO_ARCHIVE; | ||
| 1552 | |||
| 1553 | { | ||
| 1554 | Int64 pos = 0; | ||
| 1555 | RINOK(ILookInStream_Seek(inStream, &pos, SZ_SEEK_END)); | ||
| 1556 | if ((UInt64)pos < (UInt64)startArcPos + nextHeaderOffset || | ||
| 1557 | (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset || | ||
| 1558 | (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) | ||
| 1559 | return SZ_ERROR_INPUT_EOF; | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | RINOK(LookInStream_SeekTo(inStream, (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset)); | ||
| 1563 | |||
| 1564 | if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp)) | ||
| 1565 | return SZ_ERROR_MEM; | ||
| 1566 | |||
| 1567 | res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT); | ||
| 1568 | |||
| 1569 | if (res == SZ_OK) | ||
| 1570 | { | ||
| 1571 | res = SZ_ERROR_ARCHIVE; | ||
| 1572 | if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC) | ||
| 1573 | { | ||
| 1574 | CSzData sd; | ||
| 1575 | UInt64 type; | ||
| 1576 | sd.Data = buf.data; | ||
| 1577 | sd.Size = buf.size; | ||
| 1578 | |||
| 1579 | res = ReadID(&sd, &type); | ||
| 1580 | |||
| 1581 | if (res == SZ_OK && type == k7zIdEncodedHeader) | ||
| 1582 | { | ||
| 1583 | CSzAr tempAr; | ||
| 1584 | CBuf tempBuf; | ||
| 1585 | Buf_Init(&tempBuf); | ||
| 1586 | |||
| 1587 | SzAr_Init(&tempAr); | ||
| 1588 | tempAr.RangeLimit = p->db.RangeLimit; | ||
| 1589 | |||
| 1590 | res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp); | ||
| 1591 | SzAr_Free(&tempAr, allocTemp); | ||
| 1592 | |||
| 1593 | if (res != SZ_OK) | ||
| 1594 | { | ||
| 1595 | Buf_Free(&tempBuf, allocTemp); | ||
| 1596 | } | ||
| 1597 | else | ||
| 1598 | { | ||
| 1599 | Buf_Free(&buf, allocTemp); | ||
| 1600 | buf.data = tempBuf.data; | ||
| 1601 | buf.size = tempBuf.size; | ||
| 1602 | sd.Data = buf.data; | ||
| 1603 | sd.Size = buf.size; | ||
| 1604 | res = ReadID(&sd, &type); | ||
| 1605 | } | ||
| 1606 | } | ||
| 1607 | |||
| 1608 | if (res == SZ_OK) | ||
| 1609 | { | ||
| 1610 | if (type == k7zIdHeader) | ||
| 1611 | { | ||
| 1612 | /* | ||
| 1613 | CSzData sd2; | ||
| 1614 | unsigned ttt; | ||
| 1615 | for (ttt = 0; ttt < 40000; ttt++) | ||
| 1616 | { | ||
| 1617 | SzArEx_Free(p, allocMain); | ||
| 1618 | sd2 = sd; | ||
| 1619 | res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp); | ||
| 1620 | if (res != SZ_OK) | ||
| 1621 | break; | ||
| 1622 | } | ||
| 1623 | */ | ||
| 1624 | res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp); | ||
| 1625 | } | ||
| 1626 | else | ||
| 1627 | res = SZ_ERROR_UNSUPPORTED; | ||
| 1628 | } | ||
| 1629 | } | ||
| 1630 | } | ||
| 1631 | |||
| 1632 | Buf_Free(&buf, allocTemp); | ||
| 1633 | return res; | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | |||
| 1637 | SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, | ||
| 1638 | ISzAllocPtr allocMain, ISzAllocPtr allocTemp) | ||
| 1639 | { | ||
| 1640 | SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); | ||
| 1641 | if (res != SZ_OK) | ||
| 1642 | SzArEx_Free(p, allocMain); | ||
| 1643 | return res; | ||
| 1644 | } | ||
| 1645 | |||
| 1646 | |||
| 1647 | SRes SzArEx_Extract( | ||
| 1648 | const CSzArEx *p, | ||
| 1649 | ILookInStream *inStream, | ||
| 1650 | UInt32 fileIndex, | ||
| 1651 | UInt32 *blockIndex, | ||
| 1652 | Byte **tempBuf, | ||
| 1653 | size_t *outBufferSize, | ||
| 1654 | size_t *offset, | ||
| 1655 | size_t *outSizeProcessed, | ||
| 1656 | ISzAllocPtr allocMain, | ||
| 1657 | ISzAllocPtr allocTemp) | ||
| 1658 | { | ||
| 1659 | UInt32 folderIndex = p->FileToFolder[fileIndex]; | ||
| 1660 | SRes res = SZ_OK; | ||
| 1661 | |||
| 1662 | *offset = 0; | ||
| 1663 | *outSizeProcessed = 0; | ||
| 1664 | |||
| 1665 | if (folderIndex == (UInt32)-1) | ||
| 1666 | { | ||
| 1667 | ISzAlloc_Free(allocMain, *tempBuf); | ||
| 1668 | *blockIndex = folderIndex; | ||
| 1669 | *tempBuf = NULL; | ||
| 1670 | *outBufferSize = 0; | ||
| 1671 | return SZ_OK; | ||
| 1672 | } | ||
| 1673 | |||
| 1674 | if (*tempBuf == NULL || *blockIndex != folderIndex) | ||
| 1675 | { | ||
| 1676 | UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); | ||
| 1677 | /* | ||
| 1678 | UInt64 unpackSizeSpec = | ||
| 1679 | p->UnpackPositions[p->FolderToFile[(size_t)folderIndex + 1]] - | ||
| 1680 | p->UnpackPositions[p->FolderToFile[folderIndex]]; | ||
| 1681 | */ | ||
| 1682 | size_t unpackSize = (size_t)unpackSizeSpec; | ||
| 1683 | |||
| 1684 | if (unpackSize != unpackSizeSpec) | ||
| 1685 | return SZ_ERROR_MEM; | ||
| 1686 | *blockIndex = folderIndex; | ||
| 1687 | ISzAlloc_Free(allocMain, *tempBuf); | ||
| 1688 | *tempBuf = NULL; | ||
| 1689 | |||
| 1690 | if (res == SZ_OK) | ||
| 1691 | { | ||
| 1692 | *outBufferSize = unpackSize; | ||
| 1693 | if (unpackSize != 0) | ||
| 1694 | { | ||
| 1695 | *tempBuf = (Byte *)ISzAlloc_Alloc(allocMain, unpackSize); | ||
| 1696 | if (*tempBuf == NULL) | ||
| 1697 | res = SZ_ERROR_MEM; | ||
| 1698 | } | ||
| 1699 | |||
| 1700 | if (res == SZ_OK) | ||
| 1701 | { | ||
| 1702 | res = SzAr_DecodeFolder(&p->db, folderIndex, | ||
| 1703 | inStream, p->dataPos, *tempBuf, unpackSize, allocTemp); | ||
| 1704 | } | ||
| 1705 | } | ||
| 1706 | } | ||
| 1707 | |||
| 1708 | if (res == SZ_OK) | ||
| 1709 | { | ||
| 1710 | UInt64 unpackPos = p->UnpackPositions[fileIndex]; | ||
| 1711 | *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); | ||
| 1712 | *outSizeProcessed = (size_t)(p->UnpackPositions[(size_t)fileIndex + 1] - unpackPos); | ||
| 1713 | if (*offset + *outSizeProcessed > *outBufferSize) | ||
| 1714 | return SZ_ERROR_FAIL; | ||
| 1715 | if (SzBitWithVals_Check(&p->CRCs, fileIndex)) | ||
| 1716 | if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) | ||
| 1717 | res = SZ_ERROR_CRC; | ||
| 1718 | } | ||
| 1719 | |||
| 1720 | return res; | ||
| 1721 | } | ||
| 1722 | |||
| 1723 | |||
| 1724 | size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) | ||
| 1725 | { | ||
| 1726 | size_t offs = p->FileNameOffsets[fileIndex]; | ||
| 1727 | size_t len = p->FileNameOffsets[fileIndex + 1] - offs; | ||
| 1728 | if (dest != 0) | ||
| 1729 | { | ||
| 1730 | size_t i; | ||
| 1731 | const Byte *src = p->FileNames + offs * 2; | ||
| 1732 | for (i = 0; i < len; i++) | ||
| 1733 | dest[i] = GetUi16(src + i * 2); | ||
| 1734 | } | ||
| 1735 | return len; | ||
| 1736 | } | ||
| 1737 | |||
| 1738 | /* | ||
| 1739 | size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex) | ||
| 1740 | { | ||
| 1741 | size_t len; | ||
| 1742 | if (!p->FileNameOffsets) | ||
| 1743 | return 1; | ||
| 1744 | len = 0; | ||
| 1745 | for (;;) | ||
| 1746 | { | ||
| 1747 | UInt32 parent = (UInt32)(Int32)-1; | ||
| 1748 | len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; | ||
| 1749 | if SzBitWithVals_Check(&p->Parents, fileIndex) | ||
| 1750 | parent = p->Parents.Vals[fileIndex]; | ||
| 1751 | if (parent == (UInt32)(Int32)-1) | ||
| 1752 | return len; | ||
| 1753 | fileIndex = parent; | ||
| 1754 | } | ||
| 1755 | } | ||
| 1756 | |||
| 1757 | UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest) | ||
| 1758 | { | ||
| 1759 | BoolInt needSlash; | ||
| 1760 | if (!p->FileNameOffsets) | ||
| 1761 | { | ||
| 1762 | *(--dest) = 0; | ||
| 1763 | return dest; | ||
| 1764 | } | ||
| 1765 | needSlash = False; | ||
| 1766 | for (;;) | ||
| 1767 | { | ||
| 1768 | UInt32 parent = (UInt32)(Int32)-1; | ||
| 1769 | size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; | ||
| 1770 | SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen); | ||
| 1771 | if (needSlash) | ||
| 1772 | *(dest - 1) = '/'; | ||
| 1773 | needSlash = True; | ||
| 1774 | dest -= curLen; | ||
| 1775 | |||
| 1776 | if SzBitWithVals_Check(&p->Parents, fileIndex) | ||
| 1777 | parent = p->Parents.Vals[fileIndex]; | ||
| 1778 | if (parent == (UInt32)(Int32)-1) | ||
| 1779 | return dest; | ||
| 1780 | fileIndex = parent; | ||
| 1781 | } | ||
| 1782 | } | ||
| 1783 | */ | ||
diff --git a/C/7zBuf.c b/C/7zBuf.c new file mode 100644 index 0000000..8865c32 --- /dev/null +++ b/C/7zBuf.c | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* 7zBuf.c -- Byte Buffer | ||
| 2 | 2017-04-03 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 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, ISzAllocPtr alloc) | ||
| 15 | { | ||
| 16 | p->size = 0; | ||
| 17 | if (size == 0) | ||
| 18 | { | ||
| 19 | p->data = 0; | ||
| 20 | return 1; | ||
| 21 | } | ||
| 22 | p->data = (Byte *)ISzAlloc_Alloc(alloc, size); | ||
| 23 | if (p->data) | ||
| 24 | { | ||
| 25 | p->size = size; | ||
| 26 | return 1; | ||
| 27 | } | ||
| 28 | return 0; | ||
| 29 | } | ||
| 30 | |||
| 31 | void Buf_Free(CBuf *p, ISzAllocPtr alloc) | ||
| 32 | { | ||
| 33 | ISzAlloc_Free(alloc, p->data); | ||
| 34 | p->data = 0; | ||
| 35 | p->size = 0; | ||
| 36 | } | ||
diff --git a/C/7zBuf.h b/C/7zBuf.h new file mode 100644 index 0000000..81d1b5b --- /dev/null +++ b/C/7zBuf.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | /* 7zBuf.h -- Byte Buffer | ||
| 2 | 2017-04-03 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_BUF_H | ||
| 5 | #define __7Z_BUF_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | typedef struct | ||
| 12 | { | ||
| 13 | Byte *data; | ||
| 14 | size_t size; | ||
| 15 | } CBuf; | ||
| 16 | |||
| 17 | void Buf_Init(CBuf *p); | ||
| 18 | int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc); | ||
| 19 | void Buf_Free(CBuf *p, ISzAllocPtr alloc); | ||
| 20 | |||
| 21 | typedef struct | ||
| 22 | { | ||
| 23 | Byte *data; | ||
| 24 | size_t size; | ||
| 25 | size_t pos; | ||
| 26 | } CDynBuf; | ||
| 27 | |||
| 28 | void DynBuf_Construct(CDynBuf *p); | ||
| 29 | void DynBuf_SeekToBeg(CDynBuf *p); | ||
| 30 | int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc); | ||
| 31 | void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc); | ||
| 32 | |||
| 33 | EXTERN_C_END | ||
| 34 | |||
| 35 | #endif | ||
diff --git a/C/7zBuf2.c b/C/7zBuf2.c new file mode 100644 index 0000000..2083474 --- /dev/null +++ b/C/7zBuf2.c | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | /* 7zBuf2.c -- Byte Buffer | ||
| 2 | 2017-04-03 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | #include "7zBuf.h" | ||
| 9 | |||
| 10 | void DynBuf_Construct(CDynBuf *p) | ||
| 11 | { | ||
| 12 | p->data = 0; | ||
| 13 | p->size = 0; | ||
| 14 | p->pos = 0; | ||
| 15 | } | ||
| 16 | |||
| 17 | void DynBuf_SeekToBeg(CDynBuf *p) | ||
| 18 | { | ||
| 19 | p->pos = 0; | ||
| 20 | } | ||
| 21 | |||
| 22 | int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc) | ||
| 23 | { | ||
| 24 | if (size > p->size - p->pos) | ||
| 25 | { | ||
| 26 | size_t newSize = p->pos + size; | ||
| 27 | Byte *data; | ||
| 28 | newSize += newSize / 4; | ||
| 29 | data = (Byte *)ISzAlloc_Alloc(alloc, newSize); | ||
| 30 | if (!data) | ||
| 31 | return 0; | ||
| 32 | p->size = newSize; | ||
| 33 | if (p->pos != 0) | ||
| 34 | memcpy(data, p->data, p->pos); | ||
| 35 | ISzAlloc_Free(alloc, p->data); | ||
| 36 | p->data = data; | ||
| 37 | } | ||
| 38 | if (size != 0) | ||
| 39 | { | ||
| 40 | memcpy(p->data + p->pos, buf, size); | ||
| 41 | p->pos += size; | ||
| 42 | } | ||
| 43 | return 1; | ||
| 44 | } | ||
| 45 | |||
| 46 | void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc) | ||
| 47 | { | ||
| 48 | ISzAlloc_Free(alloc, p->data); | ||
| 49 | p->data = 0; | ||
| 50 | p->size = 0; | ||
| 51 | p->pos = 0; | ||
| 52 | } | ||
diff --git a/C/7zCrc.c b/C/7zCrc.c new file mode 100644 index 0000000..f186324 --- /dev/null +++ b/C/7zCrc.c | |||
| @@ -0,0 +1,322 @@ | |||
| 1 | /* 7zCrc.c -- CRC32 init | ||
| 2 | 2021-04-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "7zCrc.h" | ||
| 7 | #include "CpuArch.h" | ||
| 8 | |||
| 9 | #define kCrcPoly 0xEDB88320 | ||
| 10 | |||
| 11 | #ifdef MY_CPU_LE | ||
| 12 | #define CRC_NUM_TABLES 8 | ||
| 13 | #else | ||
| 14 | #define CRC_NUM_TABLES 9 | ||
| 15 | |||
| 16 | #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) | ||
| 17 | |||
| 18 | UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
| 19 | UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
| 20 | #endif | ||
| 21 | |||
| 22 | #ifndef MY_CPU_BE | ||
| 23 | UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
| 24 | UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
| 25 | #endif | ||
| 26 | |||
| 27 | typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
| 28 | |||
| 29 | extern | ||
| 30 | CRC_FUNC g_CrcUpdateT4; | ||
| 31 | CRC_FUNC g_CrcUpdateT4; | ||
| 32 | extern | ||
| 33 | CRC_FUNC g_CrcUpdateT8; | ||
| 34 | CRC_FUNC g_CrcUpdateT8; | ||
| 35 | extern | ||
| 36 | CRC_FUNC g_CrcUpdateT0_32; | ||
| 37 | CRC_FUNC g_CrcUpdateT0_32; | ||
| 38 | extern | ||
| 39 | CRC_FUNC g_CrcUpdateT0_64; | ||
| 40 | CRC_FUNC g_CrcUpdateT0_64; | ||
| 41 | extern | ||
| 42 | CRC_FUNC g_CrcUpdate; | ||
| 43 | CRC_FUNC g_CrcUpdate; | ||
| 44 | |||
| 45 | UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; | ||
| 46 | |||
| 47 | UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) | ||
| 48 | { | ||
| 49 | return g_CrcUpdate(v, data, size, g_CrcTable); | ||
| 50 | } | ||
| 51 | |||
| 52 | UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) | ||
| 53 | { | ||
| 54 | return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; | ||
| 55 | } | ||
| 56 | |||
| 57 | #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) | ||
| 58 | |||
| 59 | UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
| 60 | UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) | ||
| 61 | { | ||
| 62 | const Byte *p = (const Byte *)data; | ||
| 63 | const Byte *pEnd = p + size; | ||
| 64 | for (; p != pEnd; p++) | ||
| 65 | v = CRC_UPDATE_BYTE_2(v, *p); | ||
| 66 | return v; | ||
| 67 | } | ||
| 68 | |||
| 69 | |||
| 70 | /* ---------- hardware CRC ---------- */ | ||
| 71 | |||
| 72 | #ifdef MY_CPU_LE | ||
| 73 | |||
| 74 | #if defined(MY_CPU_ARM_OR_ARM64) | ||
| 75 | |||
| 76 | // #pragma message("ARM*") | ||
| 77 | |||
| 78 | #if defined(_MSC_VER) | ||
| 79 | #if defined(MY_CPU_ARM64) | ||
| 80 | #if (_MSC_VER >= 1910) | ||
| 81 | #define USE_ARM64_CRC | ||
| 82 | #endif | ||
| 83 | #endif | ||
| 84 | #elif (defined(__clang__) && (__clang_major__ >= 3)) \ | ||
| 85 | || (defined(__GNUC__) && (__GNUC__ > 4)) | ||
| 86 | #if !defined(__ARM_FEATURE_CRC32) | ||
| 87 | #define __ARM_FEATURE_CRC32 1 | ||
| 88 | #if (!defined(__clang__) || (__clang_major__ > 3)) // fix these numbers | ||
| 89 | #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc"))) | ||
| 90 | #endif | ||
| 91 | #endif | ||
| 92 | #if defined(__ARM_FEATURE_CRC32) | ||
| 93 | #define USE_ARM64_CRC | ||
| 94 | #include <arm_acle.h> | ||
| 95 | #endif | ||
| 96 | #endif | ||
| 97 | |||
| 98 | #else | ||
| 99 | |||
| 100 | // no hardware CRC | ||
| 101 | |||
| 102 | // #define USE_CRC_EMU | ||
| 103 | |||
| 104 | #ifdef USE_CRC_EMU | ||
| 105 | |||
| 106 | #pragma message("ARM64 CRC emulation") | ||
| 107 | |||
| 108 | MY_FORCE_INLINE | ||
| 109 | UInt32 __crc32b(UInt32 v, UInt32 data) | ||
| 110 | { | ||
| 111 | const UInt32 *table = g_CrcTable; | ||
| 112 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); | ||
| 113 | return v; | ||
| 114 | } | ||
| 115 | |||
| 116 | MY_FORCE_INLINE | ||
| 117 | UInt32 __crc32w(UInt32 v, UInt32 data) | ||
| 118 | { | ||
| 119 | const UInt32 *table = g_CrcTable; | ||
| 120 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 121 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 122 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 123 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 124 | return v; | ||
| 125 | } | ||
| 126 | |||
| 127 | MY_FORCE_INLINE | ||
| 128 | UInt32 __crc32d(UInt32 v, UInt64 data) | ||
| 129 | { | ||
| 130 | const UInt32 *table = g_CrcTable; | ||
| 131 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 132 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 133 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 134 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 135 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 136 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 137 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 138 | v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; | ||
| 139 | return v; | ||
| 140 | } | ||
| 141 | |||
| 142 | #endif // USE_CRC_EMU | ||
| 143 | |||
| 144 | #endif // defined(MY_CPU_ARM64) && defined(MY_CPU_LE) | ||
| 145 | |||
| 146 | |||
| 147 | |||
| 148 | #if defined(USE_ARM64_CRC) || defined(USE_CRC_EMU) | ||
| 149 | |||
| 150 | #define T0_32_UNROLL_BYTES (4 * 4) | ||
| 151 | #define T0_64_UNROLL_BYTES (4 * 8) | ||
| 152 | |||
| 153 | #ifndef ATTRIB_CRC | ||
| 154 | #define ATTRIB_CRC | ||
| 155 | #endif | ||
| 156 | // #pragma message("USE ARM HW CRC") | ||
| 157 | |||
| 158 | ATTRIB_CRC | ||
| 159 | UInt32 MY_FAST_CALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
| 160 | ATTRIB_CRC | ||
| 161 | UInt32 MY_FAST_CALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table) | ||
| 162 | { | ||
| 163 | const Byte *p = (const Byte *)data; | ||
| 164 | UNUSED_VAR(table); | ||
| 165 | |||
| 166 | for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_32_UNROLL_BYTES - 1)) != 0; size--) | ||
| 167 | v = __crc32b(v, *p++); | ||
| 168 | |||
| 169 | if (size >= T0_32_UNROLL_BYTES) | ||
| 170 | { | ||
| 171 | const Byte *lim = p + size; | ||
| 172 | size &= (T0_32_UNROLL_BYTES - 1); | ||
| 173 | lim -= size; | ||
| 174 | do | ||
| 175 | { | ||
| 176 | v = __crc32w(v, *(const UInt32 *)(const void *)(p)); | ||
| 177 | v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4; | ||
| 178 | v = __crc32w(v, *(const UInt32 *)(const void *)(p)); | ||
| 179 | v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4; | ||
| 180 | } | ||
| 181 | while (p != lim); | ||
| 182 | } | ||
| 183 | |||
| 184 | for (; size != 0; size--) | ||
| 185 | v = __crc32b(v, *p++); | ||
| 186 | |||
| 187 | return v; | ||
| 188 | } | ||
| 189 | |||
| 190 | ATTRIB_CRC | ||
| 191 | UInt32 MY_FAST_CALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
| 192 | ATTRIB_CRC | ||
| 193 | UInt32 MY_FAST_CALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table) | ||
| 194 | { | ||
| 195 | const Byte *p = (const Byte *)data; | ||
| 196 | UNUSED_VAR(table); | ||
| 197 | |||
| 198 | for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_64_UNROLL_BYTES - 1)) != 0; size--) | ||
| 199 | v = __crc32b(v, *p++); | ||
| 200 | |||
| 201 | if (size >= T0_64_UNROLL_BYTES) | ||
| 202 | { | ||
| 203 | const Byte *lim = p + size; | ||
| 204 | size &= (T0_64_UNROLL_BYTES - 1); | ||
| 205 | lim -= size; | ||
| 206 | do | ||
| 207 | { | ||
| 208 | v = __crc32d(v, *(const UInt64 *)(const void *)(p)); | ||
| 209 | v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8; | ||
| 210 | v = __crc32d(v, *(const UInt64 *)(const void *)(p)); | ||
| 211 | v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8; | ||
| 212 | } | ||
| 213 | while (p != lim); | ||
| 214 | } | ||
| 215 | |||
| 216 | for (; size != 0; size--) | ||
| 217 | v = __crc32b(v, *p++); | ||
| 218 | |||
| 219 | return v; | ||
| 220 | } | ||
| 221 | |||
| 222 | #endif // defined(USE_ARM64_CRC) || defined(USE_CRC_EMU) | ||
| 223 | |||
| 224 | #endif // MY_CPU_LE | ||
| 225 | |||
| 226 | |||
| 227 | |||
| 228 | |||
| 229 | void MY_FAST_CALL CrcGenerateTable() | ||
| 230 | { | ||
| 231 | UInt32 i; | ||
| 232 | for (i = 0; i < 256; i++) | ||
| 233 | { | ||
| 234 | UInt32 r = i; | ||
| 235 | unsigned j; | ||
| 236 | for (j = 0; j < 8; j++) | ||
| 237 | r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); | ||
| 238 | g_CrcTable[i] = r; | ||
| 239 | } | ||
| 240 | for (i = 256; i < 256 * CRC_NUM_TABLES; i++) | ||
| 241 | { | ||
| 242 | UInt32 r = g_CrcTable[(size_t)i - 256]; | ||
| 243 | g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); | ||
| 244 | } | ||
| 245 | |||
| 246 | #if CRC_NUM_TABLES < 4 | ||
| 247 | |||
| 248 | g_CrcUpdate = CrcUpdateT1; | ||
| 249 | |||
| 250 | #else | ||
| 251 | |||
| 252 | #ifdef MY_CPU_LE | ||
| 253 | |||
| 254 | g_CrcUpdateT4 = CrcUpdateT4; | ||
| 255 | g_CrcUpdate = CrcUpdateT4; | ||
| 256 | |||
| 257 | #if CRC_NUM_TABLES >= 8 | ||
| 258 | g_CrcUpdateT8 = CrcUpdateT8; | ||
| 259 | |||
| 260 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 261 | if (!CPU_Is_InOrder()) | ||
| 262 | #endif | ||
| 263 | g_CrcUpdate = CrcUpdateT8; | ||
| 264 | #endif | ||
| 265 | |||
| 266 | #else | ||
| 267 | { | ||
| 268 | #ifndef MY_CPU_BE | ||
| 269 | UInt32 k = 0x01020304; | ||
| 270 | const Byte *p = (const Byte *)&k; | ||
| 271 | if (p[0] == 4 && p[1] == 3) | ||
| 272 | { | ||
| 273 | g_CrcUpdateT4 = CrcUpdateT4; | ||
| 274 | g_CrcUpdate = CrcUpdateT4; | ||
| 275 | #if CRC_NUM_TABLES >= 8 | ||
| 276 | g_CrcUpdateT8 = CrcUpdateT8; | ||
| 277 | g_CrcUpdate = CrcUpdateT8; | ||
| 278 | #endif | ||
| 279 | } | ||
| 280 | else if (p[0] != 1 || p[1] != 2) | ||
| 281 | g_CrcUpdate = CrcUpdateT1; | ||
| 282 | else | ||
| 283 | #endif | ||
| 284 | { | ||
| 285 | for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) | ||
| 286 | { | ||
| 287 | UInt32 x = g_CrcTable[(size_t)i - 256]; | ||
| 288 | g_CrcTable[i] = CRC_UINT32_SWAP(x); | ||
| 289 | } | ||
| 290 | g_CrcUpdateT4 = CrcUpdateT1_BeT4; | ||
| 291 | g_CrcUpdate = CrcUpdateT1_BeT4; | ||
| 292 | #if CRC_NUM_TABLES >= 8 | ||
| 293 | g_CrcUpdateT8 = CrcUpdateT1_BeT8; | ||
| 294 | g_CrcUpdate = CrcUpdateT1_BeT8; | ||
| 295 | #endif | ||
| 296 | } | ||
| 297 | } | ||
| 298 | #endif | ||
| 299 | #endif | ||
| 300 | |||
| 301 | #ifdef MY_CPU_LE | ||
| 302 | #ifdef USE_ARM64_CRC | ||
| 303 | if (CPU_IsSupported_CRC32()) | ||
| 304 | { | ||
| 305 | g_CrcUpdateT0_32 = CrcUpdateT0_32; | ||
| 306 | g_CrcUpdateT0_64 = CrcUpdateT0_64; | ||
| 307 | g_CrcUpdate = | ||
| 308 | #if defined(MY_CPU_ARM) | ||
| 309 | CrcUpdateT0_32; | ||
| 310 | #else | ||
| 311 | CrcUpdateT0_64; | ||
| 312 | #endif | ||
| 313 | } | ||
| 314 | #endif | ||
| 315 | |||
| 316 | #ifdef USE_CRC_EMU | ||
| 317 | g_CrcUpdateT0_32 = CrcUpdateT0_32; | ||
| 318 | g_CrcUpdateT0_64 = CrcUpdateT0_64; | ||
| 319 | g_CrcUpdate = CrcUpdateT0_64; | ||
| 320 | #endif | ||
| 321 | #endif | ||
| 322 | } | ||
diff --git a/C/7zCrc.h b/C/7zCrc.h new file mode 100644 index 0000000..8fd5795 --- /dev/null +++ b/C/7zCrc.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* 7zCrc.h -- CRC32 calculation | ||
| 2 | 2013-01-18 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_CRC_H | ||
| 5 | #define __7Z_CRC_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | extern UInt32 g_CrcTable[]; | ||
| 12 | |||
| 13 | /* Call CrcGenerateTable one time before other CRC functions */ | ||
| 14 | void MY_FAST_CALL CrcGenerateTable(void); | ||
| 15 | |||
| 16 | #define CRC_INIT_VAL 0xFFFFFFFF | ||
| 17 | #define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) | ||
| 18 | #define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) | ||
| 19 | |||
| 20 | UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); | ||
| 21 | UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); | ||
| 22 | |||
| 23 | EXTERN_C_END | ||
| 24 | |||
| 25 | #endif | ||
diff --git a/C/7zCrcOpt.c b/C/7zCrcOpt.c new file mode 100644 index 0000000..69fad9c --- /dev/null +++ b/C/7zCrcOpt.c | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | /* 7zCrcOpt.c -- CRC32 calculation | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "CpuArch.h" | ||
| 7 | |||
| 8 | #ifndef MY_CPU_BE | ||
| 9 | |||
| 10 | #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) | ||
| 11 | |||
| 12 | UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
| 13 | UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) | ||
| 14 | { | ||
| 15 | const Byte *p = (const Byte *)data; | ||
| 16 | for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) | ||
| 17 | v = CRC_UPDATE_BYTE_2(v, *p); | ||
| 18 | for (; size >= 4; size -= 4, p += 4) | ||
| 19 | { | ||
| 20 | v ^= *(const UInt32 *)(const void *)p; | ||
| 21 | v = | ||
| 22 | (table + 0x300)[((v ) & 0xFF)] | ||
| 23 | ^ (table + 0x200)[((v >> 8) & 0xFF)] | ||
| 24 | ^ (table + 0x100)[((v >> 16) & 0xFF)] | ||
| 25 | ^ (table + 0x000)[((v >> 24))]; | ||
| 26 | } | ||
| 27 | for (; size > 0; size--, p++) | ||
| 28 | v = CRC_UPDATE_BYTE_2(v, *p); | ||
| 29 | return v; | ||
| 30 | } | ||
| 31 | |||
| 32 | UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
| 33 | UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) | ||
| 34 | { | ||
| 35 | const Byte *p = (const Byte *)data; | ||
| 36 | for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) | ||
| 37 | v = CRC_UPDATE_BYTE_2(v, *p); | ||
| 38 | for (; size >= 8; size -= 8, p += 8) | ||
| 39 | { | ||
| 40 | UInt32 d; | ||
| 41 | v ^= *(const UInt32 *)(const void *)p; | ||
| 42 | v = | ||
| 43 | (table + 0x700)[((v ) & 0xFF)] | ||
| 44 | ^ (table + 0x600)[((v >> 8) & 0xFF)] | ||
| 45 | ^ (table + 0x500)[((v >> 16) & 0xFF)] | ||
| 46 | ^ (table + 0x400)[((v >> 24))]; | ||
| 47 | d = *((const UInt32 *)(const void *)p + 1); | ||
| 48 | v ^= | ||
| 49 | (table + 0x300)[((d ) & 0xFF)] | ||
| 50 | ^ (table + 0x200)[((d >> 8) & 0xFF)] | ||
| 51 | ^ (table + 0x100)[((d >> 16) & 0xFF)] | ||
| 52 | ^ (table + 0x000)[((d >> 24))]; | ||
| 53 | } | ||
| 54 | for (; size > 0; size--, p++) | ||
| 55 | v = CRC_UPDATE_BYTE_2(v, *p); | ||
| 56 | return v; | ||
| 57 | } | ||
| 58 | |||
| 59 | #endif | ||
| 60 | |||
| 61 | |||
| 62 | #ifndef MY_CPU_LE | ||
| 63 | |||
| 64 | #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) | ||
| 65 | |||
| 66 | #define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8)) | ||
| 67 | |||
| 68 | UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table) | ||
| 69 | { | ||
| 70 | const Byte *p = (const Byte *)data; | ||
| 71 | table += 0x100; | ||
| 72 | v = CRC_UINT32_SWAP(v); | ||
| 73 | for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) | ||
| 74 | v = CRC_UPDATE_BYTE_2_BE(v, *p); | ||
| 75 | for (; size >= 4; size -= 4, p += 4) | ||
| 76 | { | ||
| 77 | v ^= *(const UInt32 *)(const void *)p; | ||
| 78 | v = | ||
| 79 | (table + 0x000)[((v ) & 0xFF)] | ||
| 80 | ^ (table + 0x100)[((v >> 8) & 0xFF)] | ||
| 81 | ^ (table + 0x200)[((v >> 16) & 0xFF)] | ||
| 82 | ^ (table + 0x300)[((v >> 24))]; | ||
| 83 | } | ||
| 84 | for (; size > 0; size--, p++) | ||
| 85 | v = CRC_UPDATE_BYTE_2_BE(v, *p); | ||
| 86 | return CRC_UINT32_SWAP(v); | ||
| 87 | } | ||
| 88 | |||
| 89 | UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table) | ||
| 90 | { | ||
| 91 | const Byte *p = (const Byte *)data; | ||
| 92 | table += 0x100; | ||
| 93 | v = CRC_UINT32_SWAP(v); | ||
| 94 | for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) | ||
| 95 | v = CRC_UPDATE_BYTE_2_BE(v, *p); | ||
| 96 | for (; size >= 8; size -= 8, p += 8) | ||
| 97 | { | ||
| 98 | UInt32 d; | ||
| 99 | v ^= *(const UInt32 *)(const void *)p; | ||
| 100 | v = | ||
| 101 | (table + 0x400)[((v ) & 0xFF)] | ||
| 102 | ^ (table + 0x500)[((v >> 8) & 0xFF)] | ||
| 103 | ^ (table + 0x600)[((v >> 16) & 0xFF)] | ||
| 104 | ^ (table + 0x700)[((v >> 24))]; | ||
| 105 | d = *((const UInt32 *)(const void *)p + 1); | ||
| 106 | v ^= | ||
| 107 | (table + 0x000)[((d ) & 0xFF)] | ||
| 108 | ^ (table + 0x100)[((d >> 8) & 0xFF)] | ||
| 109 | ^ (table + 0x200)[((d >> 16) & 0xFF)] | ||
| 110 | ^ (table + 0x300)[((d >> 24))]; | ||
| 111 | } | ||
| 112 | for (; size > 0; size--, p++) | ||
| 113 | v = CRC_UPDATE_BYTE_2_BE(v, *p); | ||
| 114 | return CRC_UINT32_SWAP(v); | ||
| 115 | } | ||
| 116 | |||
| 117 | #endif | ||
diff --git a/C/7zDec.c b/C/7zDec.c new file mode 100644 index 0000000..fbfd016 --- /dev/null +++ b/C/7zDec.c | |||
| @@ -0,0 +1,600 @@ | |||
| 1 | /* 7zDec.c -- Decoding from 7z folder | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | /* #define _7ZIP_PPMD_SUPPPORT */ | ||
| 9 | |||
| 10 | #include "7z.h" | ||
| 11 | #include "7zCrc.h" | ||
| 12 | |||
| 13 | #include "Bcj2.h" | ||
| 14 | #include "Bra.h" | ||
| 15 | #include "CpuArch.h" | ||
| 16 | #include "Delta.h" | ||
| 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 | #ifndef _7Z_NO_METHOD_LZMA2 | ||
| 25 | #define k_LZMA2 0x21 | ||
| 26 | #endif | ||
| 27 | #define k_LZMA 0x30101 | ||
| 28 | #define k_BCJ2 0x303011B | ||
| 29 | #ifndef _7Z_NO_METHODS_FILTERS | ||
| 30 | #define k_Delta 3 | ||
| 31 | #define k_BCJ 0x3030103 | ||
| 32 | #define k_PPC 0x3030205 | ||
| 33 | #define k_IA64 0x3030401 | ||
| 34 | #define k_ARM 0x3030501 | ||
| 35 | #define k_ARMT 0x3030701 | ||
| 36 | #define k_SPARC 0x3030805 | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #ifdef _7ZIP_PPMD_SUPPPORT | ||
| 40 | |||
| 41 | #define k_PPMD 0x30401 | ||
| 42 | |||
| 43 | typedef struct | ||
| 44 | { | ||
| 45 | IByteIn vt; | ||
| 46 | const Byte *cur; | ||
| 47 | const Byte *end; | ||
| 48 | const Byte *begin; | ||
| 49 | UInt64 processed; | ||
| 50 | BoolInt extra; | ||
| 51 | SRes res; | ||
| 52 | const ILookInStream *inStream; | ||
| 53 | } CByteInToLook; | ||
| 54 | |||
| 55 | static Byte ReadByte(const IByteIn *pp) | ||
| 56 | { | ||
| 57 | CByteInToLook *p = CONTAINER_FROM_VTBL(pp, CByteInToLook, vt); | ||
| 58 | if (p->cur != p->end) | ||
| 59 | return *p->cur++; | ||
| 60 | if (p->res == SZ_OK) | ||
| 61 | { | ||
| 62 | size_t size = (size_t)(p->cur - p->begin); | ||
| 63 | p->processed += size; | ||
| 64 | p->res = ILookInStream_Skip(p->inStream, size); | ||
| 65 | size = (1 << 25); | ||
| 66 | p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size); | ||
| 67 | p->cur = p->begin; | ||
| 68 | p->end = p->begin + size; | ||
| 69 | if (size != 0) | ||
| 70 | return *p->cur++;; | ||
| 71 | } | ||
| 72 | p->extra = True; | ||
| 73 | return 0; | ||
| 74 | } | ||
| 75 | |||
| 76 | static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, const ILookInStream *inStream, | ||
| 77 | Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) | ||
| 78 | { | ||
| 79 | CPpmd7 ppmd; | ||
| 80 | CByteInToLook s; | ||
| 81 | SRes res = SZ_OK; | ||
| 82 | |||
| 83 | s.vt.Read = ReadByte; | ||
| 84 | s.inStream = inStream; | ||
| 85 | s.begin = s.end = s.cur = NULL; | ||
| 86 | s.extra = False; | ||
| 87 | s.res = SZ_OK; | ||
| 88 | s.processed = 0; | ||
| 89 | |||
| 90 | if (propsSize != 5) | ||
| 91 | return SZ_ERROR_UNSUPPORTED; | ||
| 92 | |||
| 93 | { | ||
| 94 | unsigned order = props[0]; | ||
| 95 | UInt32 memSize = GetUi32(props + 1); | ||
| 96 | if (order < PPMD7_MIN_ORDER || | ||
| 97 | order > PPMD7_MAX_ORDER || | ||
| 98 | memSize < PPMD7_MIN_MEM_SIZE || | ||
| 99 | memSize > PPMD7_MAX_MEM_SIZE) | ||
| 100 | return SZ_ERROR_UNSUPPORTED; | ||
| 101 | Ppmd7_Construct(&ppmd); | ||
| 102 | if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) | ||
| 103 | return SZ_ERROR_MEM; | ||
| 104 | Ppmd7_Init(&ppmd, order); | ||
| 105 | } | ||
| 106 | { | ||
| 107 | ppmd.rc.dec.Stream = &s.vt; | ||
| 108 | if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec)) | ||
| 109 | res = SZ_ERROR_DATA; | ||
| 110 | else if (!s.extra) | ||
| 111 | { | ||
| 112 | Byte *buf = outBuffer; | ||
| 113 | const Byte *lim = buf + outSize; | ||
| 114 | for (; buf != lim; buf++) | ||
| 115 | { | ||
| 116 | int sym = Ppmd7z_DecodeSymbol(&ppmd); | ||
| 117 | if (s.extra || sym < 0) | ||
| 118 | break; | ||
| 119 | *buf = (Byte)sym; | ||
| 120 | } | ||
| 121 | if (buf != lim) | ||
| 122 | res = SZ_ERROR_DATA; | ||
| 123 | else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) | ||
| 124 | { | ||
| 125 | /* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */ | ||
| 126 | res = SZ_ERROR_DATA; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | if (s.extra) | ||
| 130 | res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); | ||
| 131 | else if (s.processed + (size_t)(s.cur - s.begin) != inSize) | ||
| 132 | res = SZ_ERROR_DATA; | ||
| 133 | } | ||
| 134 | Ppmd7_Free(&ppmd, allocMain); | ||
| 135 | return res; | ||
| 136 | } | ||
| 137 | |||
| 138 | #endif | ||
| 139 | |||
| 140 | |||
| 141 | static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, | ||
| 142 | Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) | ||
| 143 | { | ||
| 144 | CLzmaDec state; | ||
| 145 | SRes res = SZ_OK; | ||
| 146 | |||
| 147 | LzmaDec_Construct(&state); | ||
| 148 | RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)); | ||
| 149 | state.dic = outBuffer; | ||
| 150 | state.dicBufSize = outSize; | ||
| 151 | LzmaDec_Init(&state); | ||
| 152 | |||
| 153 | for (;;) | ||
| 154 | { | ||
| 155 | const void *inBuf = NULL; | ||
| 156 | size_t lookahead = (1 << 18); | ||
| 157 | if (lookahead > inSize) | ||
| 158 | lookahead = (size_t)inSize; | ||
| 159 | res = ILookInStream_Look(inStream, &inBuf, &lookahead); | ||
| 160 | if (res != SZ_OK) | ||
| 161 | break; | ||
| 162 | |||
| 163 | { | ||
| 164 | SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; | ||
| 165 | ELzmaStatus status; | ||
| 166 | res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status); | ||
| 167 | lookahead -= inProcessed; | ||
| 168 | inSize -= inProcessed; | ||
| 169 | if (res != SZ_OK) | ||
| 170 | break; | ||
| 171 | |||
| 172 | if (status == LZMA_STATUS_FINISHED_WITH_MARK) | ||
| 173 | { | ||
| 174 | if (outSize != state.dicPos || inSize != 0) | ||
| 175 | res = SZ_ERROR_DATA; | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | |||
| 179 | if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) | ||
| 180 | break; | ||
| 181 | |||
| 182 | if (inProcessed == 0 && dicPos == state.dicPos) | ||
| 183 | { | ||
| 184 | res = SZ_ERROR_DATA; | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | |||
| 188 | res = ILookInStream_Skip(inStream, inProcessed); | ||
| 189 | if (res != SZ_OK) | ||
| 190 | break; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | LzmaDec_FreeProbs(&state, allocMain); | ||
| 195 | return res; | ||
| 196 | } | ||
| 197 | |||
| 198 | |||
| 199 | #ifndef _7Z_NO_METHOD_LZMA2 | ||
| 200 | |||
| 201 | static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, | ||
| 202 | Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) | ||
| 203 | { | ||
| 204 | CLzma2Dec state; | ||
| 205 | SRes res = SZ_OK; | ||
| 206 | |||
| 207 | Lzma2Dec_Construct(&state); | ||
| 208 | if (propsSize != 1) | ||
| 209 | return SZ_ERROR_DATA; | ||
| 210 | RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)); | ||
| 211 | state.decoder.dic = outBuffer; | ||
| 212 | state.decoder.dicBufSize = outSize; | ||
| 213 | Lzma2Dec_Init(&state); | ||
| 214 | |||
| 215 | for (;;) | ||
| 216 | { | ||
| 217 | const void *inBuf = NULL; | ||
| 218 | size_t lookahead = (1 << 18); | ||
| 219 | if (lookahead > inSize) | ||
| 220 | lookahead = (size_t)inSize; | ||
| 221 | res = ILookInStream_Look(inStream, &inBuf, &lookahead); | ||
| 222 | if (res != SZ_OK) | ||
| 223 | break; | ||
| 224 | |||
| 225 | { | ||
| 226 | SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; | ||
| 227 | ELzmaStatus status; | ||
| 228 | res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status); | ||
| 229 | lookahead -= inProcessed; | ||
| 230 | inSize -= inProcessed; | ||
| 231 | if (res != SZ_OK) | ||
| 232 | break; | ||
| 233 | |||
| 234 | if (status == LZMA_STATUS_FINISHED_WITH_MARK) | ||
| 235 | { | ||
| 236 | if (outSize != state.decoder.dicPos || inSize != 0) | ||
| 237 | res = SZ_ERROR_DATA; | ||
| 238 | break; | ||
| 239 | } | ||
| 240 | |||
| 241 | if (inProcessed == 0 && dicPos == state.decoder.dicPos) | ||
| 242 | { | ||
| 243 | res = SZ_ERROR_DATA; | ||
| 244 | break; | ||
| 245 | } | ||
| 246 | |||
| 247 | res = ILookInStream_Skip(inStream, inProcessed); | ||
| 248 | if (res != SZ_OK) | ||
| 249 | break; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | Lzma2Dec_FreeProbs(&state, allocMain); | ||
| 254 | return res; | ||
| 255 | } | ||
| 256 | |||
| 257 | #endif | ||
| 258 | |||
| 259 | |||
| 260 | static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) | ||
| 261 | { | ||
| 262 | while (inSize > 0) | ||
| 263 | { | ||
| 264 | const void *inBuf; | ||
| 265 | size_t curSize = (1 << 18); | ||
| 266 | if (curSize > inSize) | ||
| 267 | curSize = (size_t)inSize; | ||
| 268 | RINOK(ILookInStream_Look(inStream, &inBuf, &curSize)); | ||
| 269 | if (curSize == 0) | ||
| 270 | return SZ_ERROR_INPUT_EOF; | ||
| 271 | memcpy(outBuffer, inBuf, curSize); | ||
| 272 | outBuffer += curSize; | ||
| 273 | inSize -= curSize; | ||
| 274 | RINOK(ILookInStream_Skip(inStream, curSize)); | ||
| 275 | } | ||
| 276 | return SZ_OK; | ||
| 277 | } | ||
| 278 | |||
| 279 | static BoolInt IS_MAIN_METHOD(UInt32 m) | ||
| 280 | { | ||
| 281 | switch (m) | ||
| 282 | { | ||
| 283 | case k_Copy: | ||
| 284 | case k_LZMA: | ||
| 285 | #ifndef _7Z_NO_METHOD_LZMA2 | ||
| 286 | case k_LZMA2: | ||
| 287 | #endif | ||
| 288 | #ifdef _7ZIP_PPMD_SUPPPORT | ||
| 289 | case k_PPMD: | ||
| 290 | #endif | ||
| 291 | return True; | ||
| 292 | } | ||
| 293 | return False; | ||
| 294 | } | ||
| 295 | |||
| 296 | static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c) | ||
| 297 | { | ||
| 298 | return | ||
| 299 | c->NumStreams == 1 | ||
| 300 | /* && c->MethodID <= (UInt32)0xFFFFFFFF */ | ||
| 301 | && IS_MAIN_METHOD((UInt32)c->MethodID); | ||
| 302 | } | ||
| 303 | |||
| 304 | #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4) | ||
| 305 | |||
| 306 | static SRes CheckSupportedFolder(const CSzFolder *f) | ||
| 307 | { | ||
| 308 | if (f->NumCoders < 1 || f->NumCoders > 4) | ||
| 309 | return SZ_ERROR_UNSUPPORTED; | ||
| 310 | if (!IS_SUPPORTED_CODER(&f->Coders[0])) | ||
| 311 | return SZ_ERROR_UNSUPPORTED; | ||
| 312 | if (f->NumCoders == 1) | ||
| 313 | { | ||
| 314 | if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0) | ||
| 315 | return SZ_ERROR_UNSUPPORTED; | ||
| 316 | return SZ_OK; | ||
| 317 | } | ||
| 318 | |||
| 319 | |||
| 320 | #ifndef _7Z_NO_METHODS_FILTERS | ||
| 321 | |||
| 322 | if (f->NumCoders == 2) | ||
| 323 | { | ||
| 324 | const CSzCoderInfo *c = &f->Coders[1]; | ||
| 325 | if ( | ||
| 326 | /* c->MethodID > (UInt32)0xFFFFFFFF || */ | ||
| 327 | c->NumStreams != 1 | ||
| 328 | || f->NumPackStreams != 1 | ||
| 329 | || f->PackStreams[0] != 0 | ||
| 330 | || f->NumBonds != 1 | ||
| 331 | || f->Bonds[0].InIndex != 1 | ||
| 332 | || f->Bonds[0].OutIndex != 0) | ||
| 333 | return SZ_ERROR_UNSUPPORTED; | ||
| 334 | switch ((UInt32)c->MethodID) | ||
| 335 | { | ||
| 336 | case k_Delta: | ||
| 337 | case k_BCJ: | ||
| 338 | case k_PPC: | ||
| 339 | case k_IA64: | ||
| 340 | case k_SPARC: | ||
| 341 | case k_ARM: | ||
| 342 | case k_ARMT: | ||
| 343 | break; | ||
| 344 | default: | ||
| 345 | return SZ_ERROR_UNSUPPORTED; | ||
| 346 | } | ||
| 347 | return SZ_OK; | ||
| 348 | } | ||
| 349 | |||
| 350 | #endif | ||
| 351 | |||
| 352 | |||
| 353 | if (f->NumCoders == 4) | ||
| 354 | { | ||
| 355 | if (!IS_SUPPORTED_CODER(&f->Coders[1]) | ||
| 356 | || !IS_SUPPORTED_CODER(&f->Coders[2]) | ||
| 357 | || !IS_BCJ2(&f->Coders[3])) | ||
| 358 | return SZ_ERROR_UNSUPPORTED; | ||
| 359 | if (f->NumPackStreams != 4 | ||
| 360 | || f->PackStreams[0] != 2 | ||
| 361 | || f->PackStreams[1] != 6 | ||
| 362 | || f->PackStreams[2] != 1 | ||
| 363 | || f->PackStreams[3] != 0 | ||
| 364 | || f->NumBonds != 3 | ||
| 365 | || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0 | ||
| 366 | || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1 | ||
| 367 | || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2) | ||
| 368 | return SZ_ERROR_UNSUPPORTED; | ||
| 369 | return SZ_OK; | ||
| 370 | } | ||
| 371 | |||
| 372 | return SZ_ERROR_UNSUPPORTED; | ||
| 373 | } | ||
| 374 | |||
| 375 | #ifndef _7Z_NO_METHODS_FILTERS | ||
| 376 | #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; | ||
| 377 | #endif | ||
| 378 | |||
| 379 | static SRes SzFolder_Decode2(const CSzFolder *folder, | ||
| 380 | const Byte *propsData, | ||
| 381 | const UInt64 *unpackSizes, | ||
| 382 | const UInt64 *packPositions, | ||
| 383 | ILookInStream *inStream, UInt64 startPos, | ||
| 384 | Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain, | ||
| 385 | Byte *tempBuf[]) | ||
| 386 | { | ||
| 387 | UInt32 ci; | ||
| 388 | SizeT tempSizes[3] = { 0, 0, 0}; | ||
| 389 | SizeT tempSize3 = 0; | ||
| 390 | Byte *tempBuf3 = 0; | ||
| 391 | |||
| 392 | RINOK(CheckSupportedFolder(folder)); | ||
| 393 | |||
| 394 | for (ci = 0; ci < folder->NumCoders; ci++) | ||
| 395 | { | ||
| 396 | const CSzCoderInfo *coder = &folder->Coders[ci]; | ||
| 397 | |||
| 398 | if (IS_MAIN_METHOD((UInt32)coder->MethodID)) | ||
| 399 | { | ||
| 400 | UInt32 si = 0; | ||
| 401 | UInt64 offset; | ||
| 402 | UInt64 inSize; | ||
| 403 | Byte *outBufCur = outBuffer; | ||
| 404 | SizeT outSizeCur = outSize; | ||
| 405 | if (folder->NumCoders == 4) | ||
| 406 | { | ||
| 407 | UInt32 indices[] = { 3, 2, 0 }; | ||
| 408 | UInt64 unpackSize = unpackSizes[ci]; | ||
| 409 | si = indices[ci]; | ||
| 410 | if (ci < 2) | ||
| 411 | { | ||
| 412 | Byte *temp; | ||
| 413 | outSizeCur = (SizeT)unpackSize; | ||
| 414 | if (outSizeCur != unpackSize) | ||
| 415 | return SZ_ERROR_MEM; | ||
| 416 | temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur); | ||
| 417 | if (!temp && outSizeCur != 0) | ||
| 418 | return SZ_ERROR_MEM; | ||
| 419 | outBufCur = tempBuf[1 - ci] = temp; | ||
| 420 | tempSizes[1 - ci] = outSizeCur; | ||
| 421 | } | ||
| 422 | else if (ci == 2) | ||
| 423 | { | ||
| 424 | if (unpackSize > outSize) /* check it */ | ||
| 425 | return SZ_ERROR_PARAM; | ||
| 426 | tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); | ||
| 427 | tempSize3 = outSizeCur = (SizeT)unpackSize; | ||
| 428 | } | ||
| 429 | else | ||
| 430 | return SZ_ERROR_UNSUPPORTED; | ||
| 431 | } | ||
| 432 | offset = packPositions[si]; | ||
| 433 | inSize = packPositions[(size_t)si + 1] - offset; | ||
| 434 | RINOK(LookInStream_SeekTo(inStream, startPos + offset)); | ||
| 435 | |||
| 436 | if (coder->MethodID == k_Copy) | ||
| 437 | { | ||
| 438 | if (inSize != outSizeCur) /* check it */ | ||
| 439 | return SZ_ERROR_DATA; | ||
| 440 | RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); | ||
| 441 | } | ||
| 442 | else if (coder->MethodID == k_LZMA) | ||
| 443 | { | ||
| 444 | RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); | ||
| 445 | } | ||
| 446 | #ifndef _7Z_NO_METHOD_LZMA2 | ||
| 447 | else if (coder->MethodID == k_LZMA2) | ||
| 448 | { | ||
| 449 | RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); | ||
| 450 | } | ||
| 451 | #endif | ||
| 452 | #ifdef _7ZIP_PPMD_SUPPPORT | ||
| 453 | else if (coder->MethodID == k_PPMD) | ||
| 454 | { | ||
| 455 | RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); | ||
| 456 | } | ||
| 457 | #endif | ||
| 458 | else | ||
| 459 | return SZ_ERROR_UNSUPPORTED; | ||
| 460 | } | ||
| 461 | else if (coder->MethodID == k_BCJ2) | ||
| 462 | { | ||
| 463 | UInt64 offset = packPositions[1]; | ||
| 464 | UInt64 s3Size = packPositions[2] - offset; | ||
| 465 | |||
| 466 | if (ci != 3) | ||
| 467 | return SZ_ERROR_UNSUPPORTED; | ||
| 468 | |||
| 469 | tempSizes[2] = (SizeT)s3Size; | ||
| 470 | if (tempSizes[2] != s3Size) | ||
| 471 | return SZ_ERROR_MEM; | ||
| 472 | tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]); | ||
| 473 | if (!tempBuf[2] && tempSizes[2] != 0) | ||
| 474 | return SZ_ERROR_MEM; | ||
| 475 | |||
| 476 | RINOK(LookInStream_SeekTo(inStream, startPos + offset)); | ||
| 477 | RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])); | ||
| 478 | |||
| 479 | if ((tempSizes[0] & 3) != 0 || | ||
| 480 | (tempSizes[1] & 3) != 0 || | ||
| 481 | tempSize3 + tempSizes[0] + tempSizes[1] != outSize) | ||
| 482 | return SZ_ERROR_DATA; | ||
| 483 | |||
| 484 | { | ||
| 485 | CBcj2Dec p; | ||
| 486 | |||
| 487 | p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3; | ||
| 488 | p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0]; | ||
| 489 | p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1]; | ||
| 490 | p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2]; | ||
| 491 | |||
| 492 | p.dest = outBuffer; | ||
| 493 | p.destLim = outBuffer + outSize; | ||
| 494 | |||
| 495 | Bcj2Dec_Init(&p); | ||
| 496 | RINOK(Bcj2Dec_Decode(&p)); | ||
| 497 | |||
| 498 | { | ||
| 499 | unsigned i; | ||
| 500 | for (i = 0; i < 4; i++) | ||
| 501 | if (p.bufs[i] != p.lims[i]) | ||
| 502 | return SZ_ERROR_DATA; | ||
| 503 | |||
| 504 | if (!Bcj2Dec_IsFinished(&p)) | ||
| 505 | return SZ_ERROR_DATA; | ||
| 506 | |||
| 507 | if (p.dest != p.destLim | ||
| 508 | || p.state != BCJ2_STREAM_MAIN) | ||
| 509 | return SZ_ERROR_DATA; | ||
| 510 | } | ||
| 511 | } | ||
| 512 | } | ||
| 513 | #ifndef _7Z_NO_METHODS_FILTERS | ||
| 514 | else if (ci == 1) | ||
| 515 | { | ||
| 516 | if (coder->MethodID == k_Delta) | ||
| 517 | { | ||
| 518 | if (coder->PropsSize != 1) | ||
| 519 | return SZ_ERROR_UNSUPPORTED; | ||
| 520 | { | ||
| 521 | Byte state[DELTA_STATE_SIZE]; | ||
| 522 | Delta_Init(state); | ||
| 523 | Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); | ||
| 524 | } | ||
| 525 | } | ||
| 526 | else | ||
| 527 | { | ||
| 528 | if (coder->PropsSize != 0) | ||
| 529 | return SZ_ERROR_UNSUPPORTED; | ||
| 530 | switch (coder->MethodID) | ||
| 531 | { | ||
| 532 | case k_BCJ: | ||
| 533 | { | ||
| 534 | UInt32 state; | ||
| 535 | x86_Convert_Init(state); | ||
| 536 | x86_Convert(outBuffer, outSize, 0, &state, 0); | ||
| 537 | break; | ||
| 538 | } | ||
| 539 | CASE_BRA_CONV(PPC) | ||
| 540 | CASE_BRA_CONV(IA64) | ||
| 541 | CASE_BRA_CONV(SPARC) | ||
| 542 | CASE_BRA_CONV(ARM) | ||
| 543 | CASE_BRA_CONV(ARMT) | ||
| 544 | default: | ||
| 545 | return SZ_ERROR_UNSUPPORTED; | ||
| 546 | } | ||
| 547 | } | ||
| 548 | } | ||
| 549 | #endif | ||
| 550 | else | ||
| 551 | return SZ_ERROR_UNSUPPORTED; | ||
| 552 | } | ||
| 553 | |||
| 554 | return SZ_OK; | ||
| 555 | } | ||
| 556 | |||
| 557 | |||
| 558 | SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, | ||
| 559 | ILookInStream *inStream, UInt64 startPos, | ||
| 560 | Byte *outBuffer, size_t outSize, | ||
| 561 | ISzAllocPtr allocMain) | ||
| 562 | { | ||
| 563 | SRes res; | ||
| 564 | CSzFolder folder; | ||
| 565 | CSzData sd; | ||
| 566 | |||
| 567 | const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex]; | ||
| 568 | sd.Data = data; | ||
| 569 | sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex]; | ||
| 570 | |||
| 571 | res = SzGetNextFolderItem(&folder, &sd); | ||
| 572 | |||
| 573 | if (res != SZ_OK) | ||
| 574 | return res; | ||
| 575 | |||
| 576 | if (sd.Size != 0 | ||
| 577 | || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex] | ||
| 578 | || outSize != SzAr_GetFolderUnpackSize(p, folderIndex)) | ||
| 579 | return SZ_ERROR_FAIL; | ||
| 580 | { | ||
| 581 | unsigned i; | ||
| 582 | Byte *tempBuf[3] = { 0, 0, 0}; | ||
| 583 | |||
| 584 | res = SzFolder_Decode2(&folder, data, | ||
| 585 | &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]], | ||
| 586 | p->PackPositions + p->FoStartPackStreamIndex[folderIndex], | ||
| 587 | inStream, startPos, | ||
| 588 | outBuffer, (SizeT)outSize, allocMain, tempBuf); | ||
| 589 | |||
| 590 | for (i = 0; i < 3; i++) | ||
| 591 | ISzAlloc_Free(allocMain, tempBuf[i]); | ||
| 592 | |||
| 593 | if (res == SZ_OK) | ||
| 594 | if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex)) | ||
| 595 | if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex]) | ||
| 596 | res = SZ_ERROR_CRC; | ||
| 597 | |||
| 598 | return res; | ||
| 599 | } | ||
| 600 | } | ||
diff --git a/C/7zFile.c b/C/7zFile.c new file mode 100644 index 0000000..13d2efa --- /dev/null +++ b/C/7zFile.c | |||
| @@ -0,0 +1,442 @@ | |||
| 1 | /* 7zFile.c -- File IO | ||
| 2 | 2021-04-29 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "7zFile.h" | ||
| 7 | |||
| 8 | #ifndef USE_WINDOWS_FILE | ||
| 9 | |||
| 10 | #include <errno.h> | ||
| 11 | |||
| 12 | #ifndef USE_FOPEN | ||
| 13 | #include <stdio.h> | ||
| 14 | #include <fcntl.h> | ||
| 15 | #ifdef _WIN32 | ||
| 16 | #include <io.h> | ||
| 17 | typedef int ssize_t; | ||
| 18 | typedef int off_t; | ||
| 19 | #else | ||
| 20 | #include <unistd.h> | ||
| 21 | #endif | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #else | ||
| 25 | |||
| 26 | /* | ||
| 27 | ReadFile and WriteFile functions in Windows have BUG: | ||
| 28 | If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) | ||
| 29 | from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES | ||
| 30 | (Insufficient system resources exist to complete the requested service). | ||
| 31 | Probably in some version of Windows there are problems with other sizes: | ||
| 32 | for 32 MB (maybe also for 16 MB). | ||
| 33 | And message can be "Network connection was lost" | ||
| 34 | */ | ||
| 35 | |||
| 36 | #endif | ||
| 37 | |||
| 38 | #define kChunkSizeMax (1 << 22) | ||
| 39 | |||
| 40 | void File_Construct(CSzFile *p) | ||
| 41 | { | ||
| 42 | #ifdef USE_WINDOWS_FILE | ||
| 43 | p->handle = INVALID_HANDLE_VALUE; | ||
| 44 | #elif defined(USE_FOPEN) | ||
| 45 | p->file = NULL; | ||
| 46 | #else | ||
| 47 | p->fd = -1; | ||
| 48 | #endif | ||
| 49 | } | ||
| 50 | |||
| 51 | #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) | ||
| 52 | |||
| 53 | static WRes File_Open(CSzFile *p, const char *name, int writeMode) | ||
| 54 | { | ||
| 55 | #ifdef USE_WINDOWS_FILE | ||
| 56 | |||
| 57 | p->handle = CreateFileA(name, | ||
| 58 | writeMode ? GENERIC_WRITE : GENERIC_READ, | ||
| 59 | FILE_SHARE_READ, NULL, | ||
| 60 | writeMode ? CREATE_ALWAYS : OPEN_EXISTING, | ||
| 61 | FILE_ATTRIBUTE_NORMAL, NULL); | ||
| 62 | return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); | ||
| 63 | |||
| 64 | #elif defined(USE_FOPEN) | ||
| 65 | |||
| 66 | p->file = fopen(name, writeMode ? "wb+" : "rb"); | ||
| 67 | return (p->file != 0) ? 0 : | ||
| 68 | #ifdef UNDER_CE | ||
| 69 | 2; /* ENOENT */ | ||
| 70 | #else | ||
| 71 | errno; | ||
| 72 | #endif | ||
| 73 | |||
| 74 | #else | ||
| 75 | |||
| 76 | int flags = (writeMode ? (O_CREAT | O_EXCL | O_WRONLY) : O_RDONLY); | ||
| 77 | #ifdef O_BINARY | ||
| 78 | flags |= O_BINARY; | ||
| 79 | #endif | ||
| 80 | p->fd = open(name, flags, 0666); | ||
| 81 | return (p->fd != -1) ? 0 : errno; | ||
| 82 | |||
| 83 | #endif | ||
| 84 | } | ||
| 85 | |||
| 86 | WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } | ||
| 87 | |||
| 88 | WRes OutFile_Open(CSzFile *p, const char *name) | ||
| 89 | { | ||
| 90 | #if defined(USE_WINDOWS_FILE) || defined(USE_FOPEN) | ||
| 91 | return File_Open(p, name, 1); | ||
| 92 | #else | ||
| 93 | p->fd = creat(name, 0666); | ||
| 94 | return (p->fd != -1) ? 0 : errno; | ||
| 95 | #endif | ||
| 96 | } | ||
| 97 | |||
| 98 | #endif | ||
| 99 | |||
| 100 | |||
| 101 | #ifdef USE_WINDOWS_FILE | ||
| 102 | static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) | ||
| 103 | { | ||
| 104 | p->handle = CreateFileW(name, | ||
| 105 | writeMode ? GENERIC_WRITE : GENERIC_READ, | ||
| 106 | FILE_SHARE_READ, NULL, | ||
| 107 | writeMode ? CREATE_ALWAYS : OPEN_EXISTING, | ||
| 108 | FILE_ATTRIBUTE_NORMAL, NULL); | ||
| 109 | return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); | ||
| 110 | } | ||
| 111 | WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } | ||
| 112 | WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } | ||
| 113 | #endif | ||
| 114 | |||
| 115 | WRes File_Close(CSzFile *p) | ||
| 116 | { | ||
| 117 | #ifdef USE_WINDOWS_FILE | ||
| 118 | |||
| 119 | if (p->handle != INVALID_HANDLE_VALUE) | ||
| 120 | { | ||
| 121 | if (!CloseHandle(p->handle)) | ||
| 122 | return GetLastError(); | ||
| 123 | p->handle = INVALID_HANDLE_VALUE; | ||
| 124 | } | ||
| 125 | |||
| 126 | #elif defined(USE_FOPEN) | ||
| 127 | |||
| 128 | if (p->file != NULL) | ||
| 129 | { | ||
| 130 | int res = fclose(p->file); | ||
| 131 | if (res != 0) | ||
| 132 | { | ||
| 133 | if (res == EOF) | ||
| 134 | return errno; | ||
| 135 | return res; | ||
| 136 | } | ||
| 137 | p->file = NULL; | ||
| 138 | } | ||
| 139 | |||
| 140 | #else | ||
| 141 | |||
| 142 | if (p->fd != -1) | ||
| 143 | { | ||
| 144 | if (close(p->fd) != 0) | ||
| 145 | return errno; | ||
| 146 | p->fd = -1; | ||
| 147 | } | ||
| 148 | |||
| 149 | #endif | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | |||
| 155 | WRes File_Read(CSzFile *p, void *data, size_t *size) | ||
| 156 | { | ||
| 157 | size_t originalSize = *size; | ||
| 158 | *size = 0; | ||
| 159 | if (originalSize == 0) | ||
| 160 | return 0; | ||
| 161 | |||
| 162 | #ifdef USE_WINDOWS_FILE | ||
| 163 | |||
| 164 | do | ||
| 165 | { | ||
| 166 | const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; | ||
| 167 | DWORD processed = 0; | ||
| 168 | const BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); | ||
| 169 | data = (void *)((Byte *)data + processed); | ||
| 170 | originalSize -= processed; | ||
| 171 | *size += processed; | ||
| 172 | if (!res) | ||
| 173 | return GetLastError(); | ||
| 174 | // debug : we can break here for partial reading mode | ||
| 175 | if (processed == 0) | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | while (originalSize > 0); | ||
| 179 | |||
| 180 | #elif defined(USE_FOPEN) | ||
| 181 | |||
| 182 | do | ||
| 183 | { | ||
| 184 | const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; | ||
| 185 | const size_t processed = fread(data, 1, curSize, p->file); | ||
| 186 | data = (void *)((Byte *)data + (size_t)processed); | ||
| 187 | originalSize -= processed; | ||
| 188 | *size += processed; | ||
| 189 | if (processed != curSize) | ||
| 190 | return ferror(p->file); | ||
| 191 | // debug : we can break here for partial reading mode | ||
| 192 | if (processed == 0) | ||
| 193 | break; | ||
| 194 | } | ||
| 195 | while (originalSize > 0); | ||
| 196 | |||
| 197 | #else | ||
| 198 | |||
| 199 | do | ||
| 200 | { | ||
| 201 | const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; | ||
| 202 | const ssize_t processed = read(p->fd, data, curSize); | ||
| 203 | if (processed == -1) | ||
| 204 | return errno; | ||
| 205 | if (processed == 0) | ||
| 206 | break; | ||
| 207 | data = (void *)((Byte *)data + (size_t)processed); | ||
| 208 | originalSize -= (size_t)processed; | ||
| 209 | *size += (size_t)processed; | ||
| 210 | // debug : we can break here for partial reading mode | ||
| 211 | // break; | ||
| 212 | } | ||
| 213 | while (originalSize > 0); | ||
| 214 | |||
| 215 | #endif | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | |||
| 221 | WRes File_Write(CSzFile *p, const void *data, size_t *size) | ||
| 222 | { | ||
| 223 | size_t originalSize = *size; | ||
| 224 | *size = 0; | ||
| 225 | if (originalSize == 0) | ||
| 226 | return 0; | ||
| 227 | |||
| 228 | #ifdef USE_WINDOWS_FILE | ||
| 229 | |||
| 230 | do | ||
| 231 | { | ||
| 232 | const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; | ||
| 233 | DWORD processed = 0; | ||
| 234 | const BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); | ||
| 235 | data = (const void *)((const Byte *)data + processed); | ||
| 236 | originalSize -= processed; | ||
| 237 | *size += processed; | ||
| 238 | if (!res) | ||
| 239 | return GetLastError(); | ||
| 240 | if (processed == 0) | ||
| 241 | break; | ||
| 242 | } | ||
| 243 | while (originalSize > 0); | ||
| 244 | |||
| 245 | #elif defined(USE_FOPEN) | ||
| 246 | |||
| 247 | do | ||
| 248 | { | ||
| 249 | const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; | ||
| 250 | const size_t processed = fwrite(data, 1, curSize, p->file); | ||
| 251 | data = (void *)((Byte *)data + (size_t)processed); | ||
| 252 | originalSize -= processed; | ||
| 253 | *size += processed; | ||
| 254 | if (processed != curSize) | ||
| 255 | return ferror(p->file); | ||
| 256 | if (processed == 0) | ||
| 257 | break; | ||
| 258 | } | ||
| 259 | while (originalSize > 0); | ||
| 260 | |||
| 261 | #else | ||
| 262 | |||
| 263 | do | ||
| 264 | { | ||
| 265 | const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; | ||
| 266 | const ssize_t processed = write(p->fd, data, curSize); | ||
| 267 | if (processed == -1) | ||
| 268 | return errno; | ||
| 269 | if (processed == 0) | ||
| 270 | break; | ||
| 271 | data = (void *)((Byte *)data + (size_t)processed); | ||
| 272 | originalSize -= (size_t)processed; | ||
| 273 | *size += (size_t)processed; | ||
| 274 | } | ||
| 275 | while (originalSize > 0); | ||
| 276 | |||
| 277 | #endif | ||
| 278 | |||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | |||
| 283 | WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) | ||
| 284 | { | ||
| 285 | #ifdef USE_WINDOWS_FILE | ||
| 286 | |||
| 287 | DWORD moveMethod; | ||
| 288 | UInt32 low = (UInt32)*pos; | ||
| 289 | LONG high = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ | ||
| 290 | switch (origin) | ||
| 291 | { | ||
| 292 | case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; | ||
| 293 | case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; | ||
| 294 | case SZ_SEEK_END: moveMethod = FILE_END; break; | ||
| 295 | default: return ERROR_INVALID_PARAMETER; | ||
| 296 | } | ||
| 297 | low = SetFilePointer(p->handle, (LONG)low, &high, moveMethod); | ||
| 298 | if (low == (UInt32)0xFFFFFFFF) | ||
| 299 | { | ||
| 300 | WRes res = GetLastError(); | ||
| 301 | if (res != NO_ERROR) | ||
| 302 | return res; | ||
| 303 | } | ||
| 304 | *pos = ((Int64)high << 32) | low; | ||
| 305 | return 0; | ||
| 306 | |||
| 307 | #else | ||
| 308 | |||
| 309 | int moveMethod; // = origin; | ||
| 310 | |||
| 311 | switch (origin) | ||
| 312 | { | ||
| 313 | case SZ_SEEK_SET: moveMethod = SEEK_SET; break; | ||
| 314 | case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; | ||
| 315 | case SZ_SEEK_END: moveMethod = SEEK_END; break; | ||
| 316 | default: return EINVAL; | ||
| 317 | } | ||
| 318 | |||
| 319 | #if defined(USE_FOPEN) | ||
| 320 | { | ||
| 321 | int res = fseek(p->file, (long)*pos, moveMethod); | ||
| 322 | if (res == -1) | ||
| 323 | return errno; | ||
| 324 | *pos = ftell(p->file); | ||
| 325 | if (*pos == -1) | ||
| 326 | return errno; | ||
| 327 | return 0; | ||
| 328 | } | ||
| 329 | #else | ||
| 330 | { | ||
| 331 | off_t res = lseek(p->fd, (off_t)*pos, moveMethod); | ||
| 332 | if (res == -1) | ||
| 333 | return errno; | ||
| 334 | *pos = res; | ||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | #endif // USE_FOPEN | ||
| 339 | #endif // USE_WINDOWS_FILE | ||
| 340 | } | ||
| 341 | |||
| 342 | |||
| 343 | WRes File_GetLength(CSzFile *p, UInt64 *length) | ||
| 344 | { | ||
| 345 | #ifdef USE_WINDOWS_FILE | ||
| 346 | |||
| 347 | DWORD sizeHigh; | ||
| 348 | DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); | ||
| 349 | if (sizeLow == 0xFFFFFFFF) | ||
| 350 | { | ||
| 351 | DWORD res = GetLastError(); | ||
| 352 | if (res != NO_ERROR) | ||
| 353 | return res; | ||
| 354 | } | ||
| 355 | *length = (((UInt64)sizeHigh) << 32) + sizeLow; | ||
| 356 | return 0; | ||
| 357 | |||
| 358 | #elif defined(USE_FOPEN) | ||
| 359 | |||
| 360 | long pos = ftell(p->file); | ||
| 361 | int res = fseek(p->file, 0, SEEK_END); | ||
| 362 | *length = ftell(p->file); | ||
| 363 | fseek(p->file, pos, SEEK_SET); | ||
| 364 | return res; | ||
| 365 | |||
| 366 | #else | ||
| 367 | |||
| 368 | off_t pos; | ||
| 369 | *length = 0; | ||
| 370 | pos = lseek(p->fd, 0, SEEK_CUR); | ||
| 371 | if (pos != -1) | ||
| 372 | { | ||
| 373 | const off_t len2 = lseek(p->fd, 0, SEEK_END); | ||
| 374 | const off_t res2 = lseek(p->fd, pos, SEEK_SET); | ||
| 375 | if (len2 != -1) | ||
| 376 | { | ||
| 377 | *length = (UInt64)len2; | ||
| 378 | if (res2 != -1) | ||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | return errno; | ||
| 383 | |||
| 384 | #endif | ||
| 385 | } | ||
| 386 | |||
| 387 | |||
| 388 | /* ---------- FileSeqInStream ---------- */ | ||
| 389 | |||
| 390 | static SRes FileSeqInStream_Read(const ISeqInStream *pp, void *buf, size_t *size) | ||
| 391 | { | ||
| 392 | CFileSeqInStream *p = CONTAINER_FROM_VTBL(pp, CFileSeqInStream, vt); | ||
| 393 | WRes wres = File_Read(&p->file, buf, size); | ||
| 394 | p->wres = wres; | ||
| 395 | return (wres == 0) ? SZ_OK : SZ_ERROR_READ; | ||
| 396 | } | ||
| 397 | |||
| 398 | void FileSeqInStream_CreateVTable(CFileSeqInStream *p) | ||
| 399 | { | ||
| 400 | p->vt.Read = FileSeqInStream_Read; | ||
| 401 | } | ||
| 402 | |||
| 403 | |||
| 404 | /* ---------- FileInStream ---------- */ | ||
| 405 | |||
| 406 | static SRes FileInStream_Read(const ISeekInStream *pp, void *buf, size_t *size) | ||
| 407 | { | ||
| 408 | CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); | ||
| 409 | WRes wres = File_Read(&p->file, buf, size); | ||
| 410 | p->wres = wres; | ||
| 411 | return (wres == 0) ? SZ_OK : SZ_ERROR_READ; | ||
| 412 | } | ||
| 413 | |||
| 414 | static SRes FileInStream_Seek(const ISeekInStream *pp, Int64 *pos, ESzSeek origin) | ||
| 415 | { | ||
| 416 | CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); | ||
| 417 | WRes wres = File_Seek(&p->file, pos, origin); | ||
| 418 | p->wres = wres; | ||
| 419 | return (wres == 0) ? SZ_OK : SZ_ERROR_READ; | ||
| 420 | } | ||
| 421 | |||
| 422 | void FileInStream_CreateVTable(CFileInStream *p) | ||
| 423 | { | ||
| 424 | p->vt.Read = FileInStream_Read; | ||
| 425 | p->vt.Seek = FileInStream_Seek; | ||
| 426 | } | ||
| 427 | |||
| 428 | |||
| 429 | /* ---------- FileOutStream ---------- */ | ||
| 430 | |||
| 431 | static size_t FileOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) | ||
| 432 | { | ||
| 433 | CFileOutStream *p = CONTAINER_FROM_VTBL(pp, CFileOutStream, vt); | ||
| 434 | WRes wres = File_Write(&p->file, data, &size); | ||
| 435 | p->wres = wres; | ||
| 436 | return size; | ||
| 437 | } | ||
| 438 | |||
| 439 | void FileOutStream_CreateVTable(CFileOutStream *p) | ||
| 440 | { | ||
| 441 | p->vt.Write = FileOutStream_Write; | ||
| 442 | } | ||
diff --git a/C/7zFile.h b/C/7zFile.h new file mode 100644 index 0000000..788abb6 --- /dev/null +++ b/C/7zFile.h | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | /* 7zFile.h -- File IO | ||
| 2 | 2021-02-15 : 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 | // #include <windows.h> | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #ifdef USE_WINDOWS_FILE | ||
| 13 | #include <windows.h> | ||
| 14 | #else | ||
| 15 | // note: USE_FOPEN mode is limited to 32-bit file size | ||
| 16 | // #define USE_FOPEN | ||
| 17 | // #include <stdio.h> | ||
| 18 | #endif | ||
| 19 | |||
| 20 | #include "7zTypes.h" | ||
| 21 | |||
| 22 | EXTERN_C_BEGIN | ||
| 23 | |||
| 24 | /* ---------- File ---------- */ | ||
| 25 | |||
| 26 | typedef struct | ||
| 27 | { | ||
| 28 | #ifdef USE_WINDOWS_FILE | ||
| 29 | HANDLE handle; | ||
| 30 | #elif defined(USE_FOPEN) | ||
| 31 | FILE *file; | ||
| 32 | #else | ||
| 33 | int fd; | ||
| 34 | #endif | ||
| 35 | } CSzFile; | ||
| 36 | |||
| 37 | void File_Construct(CSzFile *p); | ||
| 38 | #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) | ||
| 39 | WRes InFile_Open(CSzFile *p, const char *name); | ||
| 40 | WRes OutFile_Open(CSzFile *p, const char *name); | ||
| 41 | #endif | ||
| 42 | #ifdef USE_WINDOWS_FILE | ||
| 43 | WRes InFile_OpenW(CSzFile *p, const WCHAR *name); | ||
| 44 | WRes OutFile_OpenW(CSzFile *p, const WCHAR *name); | ||
| 45 | #endif | ||
| 46 | WRes File_Close(CSzFile *p); | ||
| 47 | |||
| 48 | /* reads max(*size, remain file's size) bytes */ | ||
| 49 | WRes File_Read(CSzFile *p, void *data, size_t *size); | ||
| 50 | |||
| 51 | /* writes *size bytes */ | ||
| 52 | WRes File_Write(CSzFile *p, const void *data, size_t *size); | ||
| 53 | |||
| 54 | WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); | ||
| 55 | WRes File_GetLength(CSzFile *p, UInt64 *length); | ||
| 56 | |||
| 57 | |||
| 58 | /* ---------- FileInStream ---------- */ | ||
| 59 | |||
| 60 | typedef struct | ||
| 61 | { | ||
| 62 | ISeqInStream vt; | ||
| 63 | CSzFile file; | ||
| 64 | WRes wres; | ||
| 65 | } CFileSeqInStream; | ||
| 66 | |||
| 67 | void FileSeqInStream_CreateVTable(CFileSeqInStream *p); | ||
| 68 | |||
| 69 | |||
| 70 | typedef struct | ||
| 71 | { | ||
| 72 | ISeekInStream vt; | ||
| 73 | CSzFile file; | ||
| 74 | WRes wres; | ||
| 75 | } CFileInStream; | ||
| 76 | |||
| 77 | void FileInStream_CreateVTable(CFileInStream *p); | ||
| 78 | |||
| 79 | |||
| 80 | typedef struct | ||
| 81 | { | ||
| 82 | ISeqOutStream vt; | ||
| 83 | CSzFile file; | ||
| 84 | WRes wres; | ||
| 85 | } CFileOutStream; | ||
| 86 | |||
| 87 | void FileOutStream_CreateVTable(CFileOutStream *p); | ||
| 88 | |||
| 89 | EXTERN_C_END | ||
| 90 | |||
| 91 | #endif | ||
diff --git a/C/7zStream.c b/C/7zStream.c new file mode 100644 index 0000000..28a1460 --- /dev/null +++ b/C/7zStream.c | |||
| @@ -0,0 +1,176 @@ | |||
| 1 | /* 7zStream.c -- 7z Stream functions | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | #include "7zTypes.h" | ||
| 9 | |||
| 10 | SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType) | ||
| 11 | { | ||
| 12 | while (size != 0) | ||
| 13 | { | ||
| 14 | size_t processed = size; | ||
| 15 | RINOK(ISeqInStream_Read(stream, buf, &processed)); | ||
| 16 | if (processed == 0) | ||
| 17 | return errorType; | ||
| 18 | buf = (void *)((Byte *)buf + processed); | ||
| 19 | size -= processed; | ||
| 20 | } | ||
| 21 | return SZ_OK; | ||
| 22 | } | ||
| 23 | |||
| 24 | SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size) | ||
| 25 | { | ||
| 26 | return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); | ||
| 27 | } | ||
| 28 | |||
| 29 | SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf) | ||
| 30 | { | ||
| 31 | size_t processed = 1; | ||
| 32 | RINOK(ISeqInStream_Read(stream, buf, &processed)); | ||
| 33 | return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; | ||
| 34 | } | ||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset) | ||
| 39 | { | ||
| 40 | Int64 t = (Int64)offset; | ||
| 41 | return ILookInStream_Seek(stream, &t, SZ_SEEK_SET); | ||
| 42 | } | ||
| 43 | |||
| 44 | SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size) | ||
| 45 | { | ||
| 46 | const void *lookBuf; | ||
| 47 | if (*size == 0) | ||
| 48 | return SZ_OK; | ||
| 49 | RINOK(ILookInStream_Look(stream, &lookBuf, size)); | ||
| 50 | memcpy(buf, lookBuf, *size); | ||
| 51 | return ILookInStream_Skip(stream, *size); | ||
| 52 | } | ||
| 53 | |||
| 54 | SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType) | ||
| 55 | { | ||
| 56 | while (size != 0) | ||
| 57 | { | ||
| 58 | size_t processed = size; | ||
| 59 | RINOK(ILookInStream_Read(stream, buf, &processed)); | ||
| 60 | if (processed == 0) | ||
| 61 | return errorType; | ||
| 62 | buf = (void *)((Byte *)buf + processed); | ||
| 63 | size -= processed; | ||
| 64 | } | ||
| 65 | return SZ_OK; | ||
| 66 | } | ||
| 67 | |||
| 68 | SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size) | ||
| 69 | { | ||
| 70 | return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); | ||
| 71 | } | ||
| 72 | |||
| 73 | |||
| 74 | |||
| 75 | #define GET_LookToRead2 CLookToRead2 *p = CONTAINER_FROM_VTBL(pp, CLookToRead2, vt); | ||
| 76 | |||
| 77 | static SRes LookToRead2_Look_Lookahead(const ILookInStream *pp, const void **buf, size_t *size) | ||
| 78 | { | ||
| 79 | SRes res = SZ_OK; | ||
| 80 | GET_LookToRead2 | ||
| 81 | size_t size2 = p->size - p->pos; | ||
| 82 | if (size2 == 0 && *size != 0) | ||
| 83 | { | ||
| 84 | p->pos = 0; | ||
| 85 | p->size = 0; | ||
| 86 | size2 = p->bufSize; | ||
| 87 | res = ISeekInStream_Read(p->realStream, p->buf, &size2); | ||
| 88 | p->size = size2; | ||
| 89 | } | ||
| 90 | if (*size > size2) | ||
| 91 | *size = size2; | ||
| 92 | *buf = p->buf + p->pos; | ||
| 93 | return res; | ||
| 94 | } | ||
| 95 | |||
| 96 | static SRes LookToRead2_Look_Exact(const ILookInStream *pp, const void **buf, size_t *size) | ||
| 97 | { | ||
| 98 | SRes res = SZ_OK; | ||
| 99 | GET_LookToRead2 | ||
| 100 | size_t size2 = p->size - p->pos; | ||
| 101 | if (size2 == 0 && *size != 0) | ||
| 102 | { | ||
| 103 | p->pos = 0; | ||
| 104 | p->size = 0; | ||
| 105 | if (*size > p->bufSize) | ||
| 106 | *size = p->bufSize; | ||
| 107 | res = ISeekInStream_Read(p->realStream, p->buf, size); | ||
| 108 | size2 = p->size = *size; | ||
| 109 | } | ||
| 110 | if (*size > size2) | ||
| 111 | *size = size2; | ||
| 112 | *buf = p->buf + p->pos; | ||
| 113 | return res; | ||
| 114 | } | ||
| 115 | |||
| 116 | static SRes LookToRead2_Skip(const ILookInStream *pp, size_t offset) | ||
| 117 | { | ||
| 118 | GET_LookToRead2 | ||
| 119 | p->pos += offset; | ||
| 120 | return SZ_OK; | ||
| 121 | } | ||
| 122 | |||
| 123 | static SRes LookToRead2_Read(const ILookInStream *pp, void *buf, size_t *size) | ||
| 124 | { | ||
| 125 | GET_LookToRead2 | ||
| 126 | size_t rem = p->size - p->pos; | ||
| 127 | if (rem == 0) | ||
| 128 | return ISeekInStream_Read(p->realStream, buf, size); | ||
| 129 | if (rem > *size) | ||
| 130 | rem = *size; | ||
| 131 | memcpy(buf, p->buf + p->pos, rem); | ||
| 132 | p->pos += rem; | ||
| 133 | *size = rem; | ||
| 134 | return SZ_OK; | ||
| 135 | } | ||
| 136 | |||
| 137 | static SRes LookToRead2_Seek(const ILookInStream *pp, Int64 *pos, ESzSeek origin) | ||
| 138 | { | ||
| 139 | GET_LookToRead2 | ||
| 140 | p->pos = p->size = 0; | ||
| 141 | return ISeekInStream_Seek(p->realStream, pos, origin); | ||
| 142 | } | ||
| 143 | |||
| 144 | void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead) | ||
| 145 | { | ||
| 146 | p->vt.Look = lookahead ? | ||
| 147 | LookToRead2_Look_Lookahead : | ||
| 148 | LookToRead2_Look_Exact; | ||
| 149 | p->vt.Skip = LookToRead2_Skip; | ||
| 150 | p->vt.Read = LookToRead2_Read; | ||
| 151 | p->vt.Seek = LookToRead2_Seek; | ||
| 152 | } | ||
| 153 | |||
| 154 | |||
| 155 | |||
| 156 | static SRes SecToLook_Read(const ISeqInStream *pp, void *buf, size_t *size) | ||
| 157 | { | ||
| 158 | CSecToLook *p = CONTAINER_FROM_VTBL(pp, CSecToLook, vt); | ||
| 159 | return LookInStream_LookRead(p->realStream, buf, size); | ||
| 160 | } | ||
| 161 | |||
| 162 | void SecToLook_CreateVTable(CSecToLook *p) | ||
| 163 | { | ||
| 164 | p->vt.Read = SecToLook_Read; | ||
| 165 | } | ||
| 166 | |||
| 167 | static SRes SecToRead_Read(const ISeqInStream *pp, void *buf, size_t *size) | ||
| 168 | { | ||
| 169 | CSecToRead *p = CONTAINER_FROM_VTBL(pp, CSecToRead, vt); | ||
| 170 | return ILookInStream_Read(p->realStream, buf, size); | ||
| 171 | } | ||
| 172 | |||
| 173 | void SecToRead_CreateVTable(CSecToRead *p) | ||
| 174 | { | ||
| 175 | p->vt.Read = SecToRead_Read; | ||
| 176 | } | ||
diff --git a/C/7zTypes.h b/C/7zTypes.h new file mode 100644 index 0000000..fe4fde3 --- /dev/null +++ b/C/7zTypes.h | |||
| @@ -0,0 +1,525 @@ | |||
| 1 | /* 7zTypes.h -- Basic types | ||
| 2 | 2021-12-25 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_TYPES_H | ||
| 5 | #define __7Z_TYPES_H | ||
| 6 | |||
| 7 | #ifdef _WIN32 | ||
| 8 | /* #include <windows.h> */ | ||
| 9 | #else | ||
| 10 | #include <errno.h> | ||
| 11 | #endif | ||
| 12 | |||
| 13 | #include <stddef.h> | ||
| 14 | |||
| 15 | #ifndef EXTERN_C_BEGIN | ||
| 16 | #ifdef __cplusplus | ||
| 17 | #define EXTERN_C_BEGIN extern "C" { | ||
| 18 | #define EXTERN_C_END } | ||
| 19 | #else | ||
| 20 | #define EXTERN_C_BEGIN | ||
| 21 | #define EXTERN_C_END | ||
| 22 | #endif | ||
| 23 | #endif | ||
| 24 | |||
| 25 | EXTERN_C_BEGIN | ||
| 26 | |||
| 27 | #define SZ_OK 0 | ||
| 28 | |||
| 29 | #define SZ_ERROR_DATA 1 | ||
| 30 | #define SZ_ERROR_MEM 2 | ||
| 31 | #define SZ_ERROR_CRC 3 | ||
| 32 | #define SZ_ERROR_UNSUPPORTED 4 | ||
| 33 | #define SZ_ERROR_PARAM 5 | ||
| 34 | #define SZ_ERROR_INPUT_EOF 6 | ||
| 35 | #define SZ_ERROR_OUTPUT_EOF 7 | ||
| 36 | #define SZ_ERROR_READ 8 | ||
| 37 | #define SZ_ERROR_WRITE 9 | ||
| 38 | #define SZ_ERROR_PROGRESS 10 | ||
| 39 | #define SZ_ERROR_FAIL 11 | ||
| 40 | #define SZ_ERROR_THREAD 12 | ||
| 41 | |||
| 42 | #define SZ_ERROR_ARCHIVE 16 | ||
| 43 | #define SZ_ERROR_NO_ARCHIVE 17 | ||
| 44 | |||
| 45 | typedef int SRes; | ||
| 46 | |||
| 47 | |||
| 48 | #ifdef _MSC_VER | ||
| 49 | #if _MSC_VER > 1200 | ||
| 50 | #define MY_ALIGN(n) __declspec(align(n)) | ||
| 51 | #else | ||
| 52 | #define MY_ALIGN(n) | ||
| 53 | #endif | ||
| 54 | #else | ||
| 55 | #define MY_ALIGN(n) __attribute__ ((aligned(n))) | ||
| 56 | #endif | ||
| 57 | |||
| 58 | |||
| 59 | #ifdef _WIN32 | ||
| 60 | |||
| 61 | /* typedef DWORD WRes; */ | ||
| 62 | typedef unsigned WRes; | ||
| 63 | #define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x) | ||
| 64 | |||
| 65 | // #define MY_HRES_ERROR__INTERNAL_ERROR MY_SRes_HRESULT_FROM_WRes(ERROR_INTERNAL_ERROR) | ||
| 66 | |||
| 67 | #else // _WIN32 | ||
| 68 | |||
| 69 | // #define ENV_HAVE_LSTAT | ||
| 70 | typedef int WRes; | ||
| 71 | |||
| 72 | // (FACILITY_ERRNO = 0x800) is 7zip's FACILITY constant to represent (errno) errors in HRESULT | ||
| 73 | #define MY__FACILITY_ERRNO 0x800 | ||
| 74 | #define MY__FACILITY_WIN32 7 | ||
| 75 | #define MY__FACILITY__WRes MY__FACILITY_ERRNO | ||
| 76 | |||
| 77 | #define MY_HRESULT_FROM_errno_CONST_ERROR(x) ((HRESULT)( \ | ||
| 78 | ( (HRESULT)(x) & 0x0000FFFF) \ | ||
| 79 | | (MY__FACILITY__WRes << 16) \ | ||
| 80 | | (HRESULT)0x80000000 )) | ||
| 81 | |||
| 82 | #define MY_SRes_HRESULT_FROM_WRes(x) \ | ||
| 83 | ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : MY_HRESULT_FROM_errno_CONST_ERROR(x)) | ||
| 84 | |||
| 85 | // we call macro HRESULT_FROM_WIN32 for system errors (WRes) that are (errno) | ||
| 86 | #define HRESULT_FROM_WIN32(x) MY_SRes_HRESULT_FROM_WRes(x) | ||
| 87 | |||
| 88 | /* | ||
| 89 | #define ERROR_FILE_NOT_FOUND 2L | ||
| 90 | #define ERROR_ACCESS_DENIED 5L | ||
| 91 | #define ERROR_NO_MORE_FILES 18L | ||
| 92 | #define ERROR_LOCK_VIOLATION 33L | ||
| 93 | #define ERROR_FILE_EXISTS 80L | ||
| 94 | #define ERROR_DISK_FULL 112L | ||
| 95 | #define ERROR_NEGATIVE_SEEK 131L | ||
| 96 | #define ERROR_ALREADY_EXISTS 183L | ||
| 97 | #define ERROR_DIRECTORY 267L | ||
| 98 | #define ERROR_TOO_MANY_POSTS 298L | ||
| 99 | |||
| 100 | #define ERROR_INTERNAL_ERROR 1359L | ||
| 101 | #define ERROR_INVALID_REPARSE_DATA 4392L | ||
| 102 | #define ERROR_REPARSE_TAG_INVALID 4393L | ||
| 103 | #define ERROR_REPARSE_TAG_MISMATCH 4394L | ||
| 104 | */ | ||
| 105 | |||
| 106 | // we use errno equivalents for some WIN32 errors: | ||
| 107 | |||
| 108 | #define ERROR_INVALID_PARAMETER EINVAL | ||
| 109 | #define ERROR_INVALID_FUNCTION EINVAL | ||
| 110 | #define ERROR_ALREADY_EXISTS EEXIST | ||
| 111 | #define ERROR_FILE_EXISTS EEXIST | ||
| 112 | #define ERROR_PATH_NOT_FOUND ENOENT | ||
| 113 | #define ERROR_FILE_NOT_FOUND ENOENT | ||
| 114 | #define ERROR_DISK_FULL ENOSPC | ||
| 115 | // #define ERROR_INVALID_HANDLE EBADF | ||
| 116 | |||
| 117 | // we use FACILITY_WIN32 for errors that has no errno equivalent | ||
| 118 | // Too many posts were made to a semaphore. | ||
| 119 | #define ERROR_TOO_MANY_POSTS ((HRESULT)0x8007012AL) | ||
| 120 | #define ERROR_INVALID_REPARSE_DATA ((HRESULT)0x80071128L) | ||
| 121 | #define ERROR_REPARSE_TAG_INVALID ((HRESULT)0x80071129L) | ||
| 122 | |||
| 123 | // if (MY__FACILITY__WRes != FACILITY_WIN32), | ||
| 124 | // we use FACILITY_WIN32 for COM errors: | ||
| 125 | #define E_OUTOFMEMORY ((HRESULT)0x8007000EL) | ||
| 126 | #define E_INVALIDARG ((HRESULT)0x80070057L) | ||
| 127 | #define MY__E_ERROR_NEGATIVE_SEEK ((HRESULT)0x80070083L) | ||
| 128 | |||
| 129 | /* | ||
| 130 | // we can use FACILITY_ERRNO for some COM errors, that have errno equivalents: | ||
| 131 | #define E_OUTOFMEMORY MY_HRESULT_FROM_errno_CONST_ERROR(ENOMEM) | ||
| 132 | #define E_INVALIDARG MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) | ||
| 133 | #define MY__E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) | ||
| 134 | */ | ||
| 135 | |||
| 136 | // gcc / clang : (sizeof(long) == sizeof(void*)) in 32/64 bits | ||
| 137 | typedef long INT_PTR; | ||
| 138 | typedef unsigned long UINT_PTR; | ||
| 139 | |||
| 140 | #define TEXT(quote) quote | ||
| 141 | |||
| 142 | #define FILE_ATTRIBUTE_READONLY 0x0001 | ||
| 143 | #define FILE_ATTRIBUTE_HIDDEN 0x0002 | ||
| 144 | #define FILE_ATTRIBUTE_SYSTEM 0x0004 | ||
| 145 | #define FILE_ATTRIBUTE_DIRECTORY 0x0010 | ||
| 146 | #define FILE_ATTRIBUTE_ARCHIVE 0x0020 | ||
| 147 | #define FILE_ATTRIBUTE_DEVICE 0x0040 | ||
| 148 | #define FILE_ATTRIBUTE_NORMAL 0x0080 | ||
| 149 | #define FILE_ATTRIBUTE_TEMPORARY 0x0100 | ||
| 150 | #define FILE_ATTRIBUTE_SPARSE_FILE 0x0200 | ||
| 151 | #define FILE_ATTRIBUTE_REPARSE_POINT 0x0400 | ||
| 152 | #define FILE_ATTRIBUTE_COMPRESSED 0x0800 | ||
| 153 | #define FILE_ATTRIBUTE_OFFLINE 0x1000 | ||
| 154 | #define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x2000 | ||
| 155 | #define FILE_ATTRIBUTE_ENCRYPTED 0x4000 | ||
| 156 | |||
| 157 | #define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */ | ||
| 158 | |||
| 159 | #endif | ||
| 160 | |||
| 161 | |||
| 162 | #ifndef RINOK | ||
| 163 | #define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } | ||
| 164 | #endif | ||
| 165 | |||
| 166 | #ifndef RINOK_WRes | ||
| 167 | #define RINOK_WRes(x) { WRes __result__ = (x); if (__result__ != 0) return __result__; } | ||
| 168 | #endif | ||
| 169 | |||
| 170 | typedef unsigned char Byte; | ||
| 171 | typedef short Int16; | ||
| 172 | typedef unsigned short UInt16; | ||
| 173 | |||
| 174 | #ifdef _LZMA_UINT32_IS_ULONG | ||
| 175 | typedef long Int32; | ||
| 176 | typedef unsigned long UInt32; | ||
| 177 | #else | ||
| 178 | typedef int Int32; | ||
| 179 | typedef unsigned int UInt32; | ||
| 180 | #endif | ||
| 181 | |||
| 182 | |||
| 183 | #ifndef _WIN32 | ||
| 184 | |||
| 185 | typedef int INT; | ||
| 186 | typedef Int32 INT32; | ||
| 187 | typedef unsigned int UINT; | ||
| 188 | typedef UInt32 UINT32; | ||
| 189 | typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit for _WIN32 compatibility | ||
| 190 | typedef UINT32 ULONG; | ||
| 191 | |||
| 192 | #undef DWORD | ||
| 193 | typedef UINT32 DWORD; | ||
| 194 | |||
| 195 | #define VOID void | ||
| 196 | |||
| 197 | #define HRESULT LONG | ||
| 198 | |||
| 199 | typedef void *LPVOID; | ||
| 200 | // typedef void VOID; | ||
| 201 | // typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; | ||
| 202 | // gcc / clang on Unix : sizeof(long==sizeof(void*) in 32 or 64 bits) | ||
| 203 | typedef long INT_PTR; | ||
| 204 | typedef unsigned long UINT_PTR; | ||
| 205 | typedef long LONG_PTR; | ||
| 206 | typedef unsigned long DWORD_PTR; | ||
| 207 | |||
| 208 | typedef size_t SIZE_T; | ||
| 209 | |||
| 210 | #endif // _WIN32 | ||
| 211 | |||
| 212 | |||
| 213 | #define MY_HRES_ERROR__INTERNAL_ERROR ((HRESULT)0x8007054FL) | ||
| 214 | |||
| 215 | |||
| 216 | #ifdef _SZ_NO_INT_64 | ||
| 217 | |||
| 218 | /* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. | ||
| 219 | NOTES: Some code will work incorrectly in that case! */ | ||
| 220 | |||
| 221 | typedef long Int64; | ||
| 222 | typedef unsigned long UInt64; | ||
| 223 | |||
| 224 | #else | ||
| 225 | |||
| 226 | #if defined(_MSC_VER) || defined(__BORLANDC__) | ||
| 227 | typedef __int64 Int64; | ||
| 228 | typedef unsigned __int64 UInt64; | ||
| 229 | #define UINT64_CONST(n) n | ||
| 230 | #else | ||
| 231 | typedef long long int Int64; | ||
| 232 | typedef unsigned long long int UInt64; | ||
| 233 | #define UINT64_CONST(n) n ## ULL | ||
| 234 | #endif | ||
| 235 | |||
| 236 | #endif | ||
| 237 | |||
| 238 | #ifdef _LZMA_NO_SYSTEM_SIZE_T | ||
| 239 | typedef UInt32 SizeT; | ||
| 240 | #else | ||
| 241 | typedef size_t SizeT; | ||
| 242 | #endif | ||
| 243 | |||
| 244 | typedef int BoolInt; | ||
| 245 | /* typedef BoolInt Bool; */ | ||
| 246 | #define True 1 | ||
| 247 | #define False 0 | ||
| 248 | |||
| 249 | |||
| 250 | #ifdef _WIN32 | ||
| 251 | #define MY_STD_CALL __stdcall | ||
| 252 | #else | ||
| 253 | #define MY_STD_CALL | ||
| 254 | #endif | ||
| 255 | |||
| 256 | #ifdef _MSC_VER | ||
| 257 | |||
| 258 | #if _MSC_VER >= 1300 | ||
| 259 | #define MY_NO_INLINE __declspec(noinline) | ||
| 260 | #else | ||
| 261 | #define MY_NO_INLINE | ||
| 262 | #endif | ||
| 263 | |||
| 264 | #define MY_FORCE_INLINE __forceinline | ||
| 265 | |||
| 266 | #define MY_CDECL __cdecl | ||
| 267 | #define MY_FAST_CALL __fastcall | ||
| 268 | |||
| 269 | #else // _MSC_VER | ||
| 270 | |||
| 271 | #if (defined(__GNUC__) && (__GNUC__ >= 4)) \ | ||
| 272 | || (defined(__clang__) && (__clang_major__ >= 4)) \ | ||
| 273 | || defined(__INTEL_COMPILER) \ | ||
| 274 | || defined(__xlC__) | ||
| 275 | #define MY_NO_INLINE __attribute__((noinline)) | ||
| 276 | // #define MY_FORCE_INLINE __attribute__((always_inline)) inline | ||
| 277 | #else | ||
| 278 | #define MY_NO_INLINE | ||
| 279 | #endif | ||
| 280 | |||
| 281 | #define MY_FORCE_INLINE | ||
| 282 | |||
| 283 | |||
| 284 | #define MY_CDECL | ||
| 285 | |||
| 286 | #if defined(_M_IX86) \ | ||
| 287 | || defined(__i386__) | ||
| 288 | // #define MY_FAST_CALL __attribute__((fastcall)) | ||
| 289 | // #define MY_FAST_CALL __attribute__((cdecl)) | ||
| 290 | #define MY_FAST_CALL | ||
| 291 | #elif defined(MY_CPU_AMD64) | ||
| 292 | // #define MY_FAST_CALL __attribute__((ms_abi)) | ||
| 293 | #define MY_FAST_CALL | ||
| 294 | #else | ||
| 295 | #define MY_FAST_CALL | ||
| 296 | #endif | ||
| 297 | |||
| 298 | #endif // _MSC_VER | ||
| 299 | |||
| 300 | |||
| 301 | /* The following interfaces use first parameter as pointer to structure */ | ||
| 302 | |||
| 303 | typedef struct IByteIn IByteIn; | ||
| 304 | struct IByteIn | ||
| 305 | { | ||
| 306 | Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */ | ||
| 307 | }; | ||
| 308 | #define IByteIn_Read(p) (p)->Read(p) | ||
| 309 | |||
| 310 | |||
| 311 | typedef struct IByteOut IByteOut; | ||
| 312 | struct IByteOut | ||
| 313 | { | ||
| 314 | void (*Write)(const IByteOut *p, Byte b); | ||
| 315 | }; | ||
| 316 | #define IByteOut_Write(p, b) (p)->Write(p, b) | ||
| 317 | |||
| 318 | |||
| 319 | typedef struct ISeqInStream ISeqInStream; | ||
| 320 | struct ISeqInStream | ||
| 321 | { | ||
| 322 | SRes (*Read)(const ISeqInStream *p, void *buf, size_t *size); | ||
| 323 | /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. | ||
| 324 | (output(*size) < input(*size)) is allowed */ | ||
| 325 | }; | ||
| 326 | #define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size) | ||
| 327 | |||
| 328 | /* it can return SZ_ERROR_INPUT_EOF */ | ||
| 329 | SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size); | ||
| 330 | SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType); | ||
| 331 | SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf); | ||
| 332 | |||
| 333 | |||
| 334 | typedef struct ISeqOutStream ISeqOutStream; | ||
| 335 | struct ISeqOutStream | ||
| 336 | { | ||
| 337 | size_t (*Write)(const ISeqOutStream *p, const void *buf, size_t size); | ||
| 338 | /* Returns: result - the number of actually written bytes. | ||
| 339 | (result < size) means error */ | ||
| 340 | }; | ||
| 341 | #define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size) | ||
| 342 | |||
| 343 | typedef enum | ||
| 344 | { | ||
| 345 | SZ_SEEK_SET = 0, | ||
| 346 | SZ_SEEK_CUR = 1, | ||
| 347 | SZ_SEEK_END = 2 | ||
| 348 | } ESzSeek; | ||
| 349 | |||
| 350 | |||
| 351 | typedef struct ISeekInStream ISeekInStream; | ||
| 352 | struct ISeekInStream | ||
| 353 | { | ||
| 354 | SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ | ||
| 355 | SRes (*Seek)(const ISeekInStream *p, Int64 *pos, ESzSeek origin); | ||
| 356 | }; | ||
| 357 | #define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size) | ||
| 358 | #define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) | ||
| 359 | |||
| 360 | |||
| 361 | typedef struct ILookInStream ILookInStream; | ||
| 362 | struct ILookInStream | ||
| 363 | { | ||
| 364 | SRes (*Look)(const ILookInStream *p, const void **buf, size_t *size); | ||
| 365 | /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. | ||
| 366 | (output(*size) > input(*size)) is not allowed | ||
| 367 | (output(*size) < input(*size)) is allowed */ | ||
| 368 | SRes (*Skip)(const ILookInStream *p, size_t offset); | ||
| 369 | /* offset must be <= output(*size) of Look */ | ||
| 370 | |||
| 371 | SRes (*Read)(const ILookInStream *p, void *buf, size_t *size); | ||
| 372 | /* reads directly (without buffer). It's same as ISeqInStream::Read */ | ||
| 373 | SRes (*Seek)(const ILookInStream *p, Int64 *pos, ESzSeek origin); | ||
| 374 | }; | ||
| 375 | |||
| 376 | #define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size) | ||
| 377 | #define ILookInStream_Skip(p, offset) (p)->Skip(p, offset) | ||
| 378 | #define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size) | ||
| 379 | #define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) | ||
| 380 | |||
| 381 | |||
| 382 | SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size); | ||
| 383 | SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset); | ||
| 384 | |||
| 385 | /* reads via ILookInStream::Read */ | ||
| 386 | SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType); | ||
| 387 | SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size); | ||
| 388 | |||
| 389 | |||
| 390 | |||
| 391 | typedef struct | ||
| 392 | { | ||
| 393 | ILookInStream vt; | ||
| 394 | const ISeekInStream *realStream; | ||
| 395 | |||
| 396 | size_t pos; | ||
| 397 | size_t size; /* it's data size */ | ||
| 398 | |||
| 399 | /* the following variables must be set outside */ | ||
| 400 | Byte *buf; | ||
| 401 | size_t bufSize; | ||
| 402 | } CLookToRead2; | ||
| 403 | |||
| 404 | void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead); | ||
| 405 | |||
| 406 | #define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; } | ||
| 407 | |||
| 408 | |||
| 409 | typedef struct | ||
| 410 | { | ||
| 411 | ISeqInStream vt; | ||
| 412 | const ILookInStream *realStream; | ||
| 413 | } CSecToLook; | ||
| 414 | |||
| 415 | void SecToLook_CreateVTable(CSecToLook *p); | ||
| 416 | |||
| 417 | |||
| 418 | |||
| 419 | typedef struct | ||
| 420 | { | ||
| 421 | ISeqInStream vt; | ||
| 422 | const ILookInStream *realStream; | ||
| 423 | } CSecToRead; | ||
| 424 | |||
| 425 | void SecToRead_CreateVTable(CSecToRead *p); | ||
| 426 | |||
| 427 | |||
| 428 | typedef struct ICompressProgress ICompressProgress; | ||
| 429 | |||
| 430 | struct ICompressProgress | ||
| 431 | { | ||
| 432 | SRes (*Progress)(const ICompressProgress *p, UInt64 inSize, UInt64 outSize); | ||
| 433 | /* Returns: result. (result != SZ_OK) means break. | ||
| 434 | Value (UInt64)(Int64)-1 for size means unknown value. */ | ||
| 435 | }; | ||
| 436 | #define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize) | ||
| 437 | |||
| 438 | |||
| 439 | |||
| 440 | typedef struct ISzAlloc ISzAlloc; | ||
| 441 | typedef const ISzAlloc * ISzAllocPtr; | ||
| 442 | |||
| 443 | struct ISzAlloc | ||
| 444 | { | ||
| 445 | void *(*Alloc)(ISzAllocPtr p, size_t size); | ||
| 446 | void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */ | ||
| 447 | }; | ||
| 448 | |||
| 449 | #define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size) | ||
| 450 | #define ISzAlloc_Free(p, a) (p)->Free(p, a) | ||
| 451 | |||
| 452 | /* deprecated */ | ||
| 453 | #define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size) | ||
| 454 | #define IAlloc_Free(p, a) ISzAlloc_Free(p, a) | ||
| 455 | |||
| 456 | |||
| 457 | |||
| 458 | |||
| 459 | |||
| 460 | #ifndef MY_offsetof | ||
| 461 | #ifdef offsetof | ||
| 462 | #define MY_offsetof(type, m) offsetof(type, m) | ||
| 463 | /* | ||
| 464 | #define MY_offsetof(type, m) FIELD_OFFSET(type, m) | ||
| 465 | */ | ||
| 466 | #else | ||
| 467 | #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m)) | ||
| 468 | #endif | ||
| 469 | #endif | ||
| 470 | |||
| 471 | |||
| 472 | |||
| 473 | #ifndef MY_container_of | ||
| 474 | |||
| 475 | /* | ||
| 476 | #define MY_container_of(ptr, type, m) container_of(ptr, type, m) | ||
| 477 | #define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m) | ||
| 478 | #define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m))) | ||
| 479 | #define MY_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m)))) | ||
| 480 | */ | ||
| 481 | |||
| 482 | /* | ||
| 483 | GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly" | ||
| 484 | GCC 3.4.4 : classes with constructor | ||
| 485 | GCC 4.8.1 : classes with non-public variable members" | ||
| 486 | */ | ||
| 487 | |||
| 488 | #define MY_container_of(ptr, type, m) ((type *)(void *)((char *)(void *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m))) | ||
| 489 | |||
| 490 | #endif | ||
| 491 | |||
| 492 | #define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(void *)(ptr)) | ||
| 493 | |||
| 494 | /* | ||
| 495 | #define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) | ||
| 496 | */ | ||
| 497 | #define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m) | ||
| 498 | |||
| 499 | #define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) | ||
| 500 | /* | ||
| 501 | #define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m) | ||
| 502 | */ | ||
| 503 | |||
| 504 | |||
| 505 | #define MY_memset_0_ARRAY(a) memset((a), 0, sizeof(a)) | ||
| 506 | |||
| 507 | #ifdef _WIN32 | ||
| 508 | |||
| 509 | #define CHAR_PATH_SEPARATOR '\\' | ||
| 510 | #define WCHAR_PATH_SEPARATOR L'\\' | ||
| 511 | #define STRING_PATH_SEPARATOR "\\" | ||
| 512 | #define WSTRING_PATH_SEPARATOR L"\\" | ||
| 513 | |||
| 514 | #else | ||
| 515 | |||
| 516 | #define CHAR_PATH_SEPARATOR '/' | ||
| 517 | #define WCHAR_PATH_SEPARATOR L'/' | ||
| 518 | #define STRING_PATH_SEPARATOR "/" | ||
| 519 | #define WSTRING_PATH_SEPARATOR L"/" | ||
| 520 | |||
| 521 | #endif | ||
| 522 | |||
| 523 | EXTERN_C_END | ||
| 524 | |||
| 525 | #endif | ||
diff --git a/C/7zVersion.h b/C/7zVersion.h new file mode 100644 index 0000000..e9363d3 --- /dev/null +++ b/C/7zVersion.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #define MY_VER_MAJOR 21 | ||
| 2 | #define MY_VER_MINOR 07 | ||
| 3 | #define MY_VER_BUILD 0 | ||
| 4 | #define MY_VERSION_NUMBERS "21.07" | ||
| 5 | #define MY_VERSION MY_VERSION_NUMBERS | ||
| 6 | |||
| 7 | #ifdef MY_CPU_NAME | ||
| 8 | #define MY_VERSION_CPU MY_VERSION " (" MY_CPU_NAME ")" | ||
| 9 | #else | ||
| 10 | #define MY_VERSION_CPU MY_VERSION | ||
| 11 | #endif | ||
| 12 | |||
| 13 | #define MY_DATE "2021-12-26" | ||
| 14 | #undef MY_COPYRIGHT | ||
| 15 | #undef MY_VERSION_COPYRIGHT_DATE | ||
| 16 | #define MY_AUTHOR_NAME "Igor Pavlov" | ||
| 17 | #define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" | ||
| 18 | #define MY_COPYRIGHT_CR "Copyright (c) 1999-2021 Igor Pavlov" | ||
| 19 | |||
| 20 | #ifdef USE_COPYRIGHT_CR | ||
| 21 | #define MY_COPYRIGHT MY_COPYRIGHT_CR | ||
| 22 | #else | ||
| 23 | #define MY_COPYRIGHT MY_COPYRIGHT_PD | ||
| 24 | #endif | ||
| 25 | |||
| 26 | #define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE | ||
| 27 | #define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE | ||
diff --git a/C/7zVersion.rc b/C/7zVersion.rc new file mode 100644 index 0000000..e520995 --- /dev/null +++ b/C/7zVersion.rc | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | #define MY_VS_FFI_FILEFLAGSMASK 0x0000003FL | ||
| 2 | #define MY_VOS_NT_WINDOWS32 0x00040004L | ||
| 3 | #define MY_VOS_CE_WINDOWS32 0x00050004L | ||
| 4 | |||
| 5 | #define MY_VFT_APP 0x00000001L | ||
| 6 | #define MY_VFT_DLL 0x00000002L | ||
| 7 | |||
| 8 | // #include <WinVer.h> | ||
| 9 | |||
| 10 | #ifndef MY_VERSION | ||
| 11 | #include "7zVersion.h" | ||
| 12 | #endif | ||
| 13 | |||
| 14 | #define MY_VER MY_VER_MAJOR,MY_VER_MINOR,MY_VER_BUILD,0 | ||
| 15 | |||
| 16 | #ifdef DEBUG | ||
| 17 | #define DBG_FL VS_FF_DEBUG | ||
| 18 | #else | ||
| 19 | #define DBG_FL 0 | ||
| 20 | #endif | ||
| 21 | |||
| 22 | #define MY_VERSION_INFO(fileType, descr, intName, origName) \ | ||
| 23 | LANGUAGE 9, 1 \ | ||
| 24 | 1 VERSIONINFO \ | ||
| 25 | FILEVERSION MY_VER \ | ||
| 26 | PRODUCTVERSION MY_VER \ | ||
| 27 | FILEFLAGSMASK MY_VS_FFI_FILEFLAGSMASK \ | ||
| 28 | FILEFLAGS DBG_FL \ | ||
| 29 | FILEOS MY_VOS_NT_WINDOWS32 \ | ||
| 30 | FILETYPE fileType \ | ||
| 31 | FILESUBTYPE 0x0L \ | ||
| 32 | BEGIN \ | ||
| 33 | BLOCK "StringFileInfo" \ | ||
| 34 | BEGIN \ | ||
| 35 | BLOCK "040904b0" \ | ||
| 36 | BEGIN \ | ||
| 37 | VALUE "CompanyName", "Igor Pavlov" \ | ||
| 38 | VALUE "FileDescription", descr \ | ||
| 39 | VALUE "FileVersion", MY_VERSION \ | ||
| 40 | VALUE "InternalName", intName \ | ||
| 41 | VALUE "LegalCopyright", MY_COPYRIGHT \ | ||
| 42 | VALUE "OriginalFilename", origName \ | ||
| 43 | VALUE "ProductName", "7-Zip" \ | ||
| 44 | VALUE "ProductVersion", MY_VERSION \ | ||
| 45 | END \ | ||
| 46 | END \ | ||
| 47 | BLOCK "VarFileInfo" \ | ||
| 48 | BEGIN \ | ||
| 49 | VALUE "Translation", 0x409, 1200 \ | ||
| 50 | END \ | ||
| 51 | END | ||
| 52 | |||
| 53 | #define MY_VERSION_INFO_APP(descr, intName) MY_VERSION_INFO(MY_VFT_APP, descr, intName, intName ".exe") | ||
| 54 | |||
| 55 | #define MY_VERSION_INFO_DLL(descr, intName) MY_VERSION_INFO(MY_VFT_DLL, descr, intName, intName ".dll") | ||
diff --git a/C/7zip_gcc_c.mak b/C/7zip_gcc_c.mak new file mode 100644 index 0000000..e884440 --- /dev/null +++ b/C/7zip_gcc_c.mak | |||
| @@ -0,0 +1,313 @@ | |||
| 1 | |||
| 2 | MY_ARCH_2 = $(MY_ARCH) | ||
| 3 | |||
| 4 | MY_ASM = jwasm | ||
| 5 | MY_ASM = asmc | ||
| 6 | |||
| 7 | PROGPATH = $(O)/$(PROG) | ||
| 8 | PROGPATH_STATIC = $(O)/$(PROG)s | ||
| 9 | |||
| 10 | |||
| 11 | # for object file | ||
| 12 | CFLAGS_BASE_LIST = -c | ||
| 13 | # for ASM file | ||
| 14 | # CFLAGS_BASE_LIST = -S | ||
| 15 | CFLAGS_BASE = $(MY_ARCH_2) -O2 $(CFLAGS_BASE_LIST) -Wall -Werror -Wextra $(CFLAGS_WARN) \ | ||
| 16 | -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE | ||
| 17 | |||
| 18 | |||
| 19 | LDFLAGS_STATIC = -DNDEBUG | ||
| 20 | # -static | ||
| 21 | |||
| 22 | ifdef SystemDrive | ||
| 23 | IS_MINGW = 1 | ||
| 24 | endif | ||
| 25 | |||
| 26 | ifdef DEF_FILE | ||
| 27 | |||
| 28 | |||
| 29 | ifdef IS_MINGW | ||
| 30 | SHARED_EXT=.dll | ||
| 31 | LDFLAGS = -shared -DEF $(DEF_FILE) $(LDFLAGS_STATIC) | ||
| 32 | else | ||
| 33 | SHARED_EXT=.so | ||
| 34 | LDFLAGS = -shared -fPIC $(LDFLAGS_STATIC) | ||
| 35 | CC_SHARED=-fPIC | ||
| 36 | endif | ||
| 37 | |||
| 38 | |||
| 39 | else | ||
| 40 | |||
| 41 | LDFLAGS = $(LDFLAGS_STATIC) | ||
| 42 | # -s is not required for clang, do we need it for GGC ??? | ||
| 43 | # -s | ||
| 44 | |||
| 45 | #-static -static-libgcc -static-libstdc++ | ||
| 46 | |||
| 47 | ifdef IS_MINGW | ||
| 48 | SHARED_EXT=.exe | ||
| 49 | else | ||
| 50 | SHARED_EXT= | ||
| 51 | endif | ||
| 52 | |||
| 53 | endif | ||
| 54 | |||
| 55 | |||
| 56 | PROGPATH = $(O)/$(PROG)$(SHARED_EXT) | ||
| 57 | PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT) | ||
| 58 | |||
| 59 | ifndef O | ||
| 60 | O=_o | ||
| 61 | endif | ||
| 62 | |||
| 63 | ifdef IS_MINGW | ||
| 64 | |||
| 65 | RM = del | ||
| 66 | MY_MKDIR=mkdir | ||
| 67 | LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 | ||
| 68 | |||
| 69 | |||
| 70 | CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE | ||
| 71 | # -Wno-delete-non-virtual-dtor | ||
| 72 | |||
| 73 | DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll | ||
| 74 | |||
| 75 | else | ||
| 76 | |||
| 77 | RM = rm -f | ||
| 78 | MY_MKDIR=mkdir -p | ||
| 79 | # CFLAGS_BASE := $(CFLAGS_BASE) -D_7ZIP_ST | ||
| 80 | # CXXFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE | ||
| 81 | |||
| 82 | # LOCAL_LIBS=-lpthread | ||
| 83 | # LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl | ||
| 84 | LIB2 = -lpthread -ldl | ||
| 85 | |||
| 86 | DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) | ||
| 87 | |||
| 88 | endif | ||
| 89 | |||
| 90 | |||
| 91 | |||
| 92 | CFLAGS = $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(CC_SHARED) -o $@ | ||
| 93 | |||
| 94 | |||
| 95 | ifdef IS_X64 | ||
| 96 | AFLAGS_ABI = -elf64 -DABI_LINUX | ||
| 97 | else | ||
| 98 | AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL | ||
| 99 | # -DABI_CDECL | ||
| 100 | # -DABI_LINUX | ||
| 101 | # -DABI_CDECL | ||
| 102 | endif | ||
| 103 | AFLAGS = $(AFLAGS_ABI) -Fo$(O)/ | ||
| 104 | |||
| 105 | |||
| 106 | CXX_WARN_FLAGS = | ||
| 107 | #-Wno-invalid-offsetof | ||
| 108 | #-Wno-reorder | ||
| 109 | |||
| 110 | CXXFLAGS = $(LOCAL_FLAGS) $(CXXFLAGS_BASE2) $(CFLAGS_BASE) $(CXXFLAGS_EXTRA) $(CC_SHARED) -o $@ $(CXX_WARN_FLAGS) | ||
| 111 | |||
| 112 | STATIC_TARGET= | ||
| 113 | ifdef COMPL_STATIC | ||
| 114 | STATIC_TARGET=$(PROGPATH_STATIC) | ||
| 115 | endif | ||
| 116 | |||
| 117 | |||
| 118 | all: $(O) $(PROGPATH) $(STATIC_TARGET) | ||
| 119 | |||
| 120 | $(O): | ||
| 121 | $(MY_MKDIR) $(O) | ||
| 122 | |||
| 123 | LFLAGS_ALL = -s $(MY_ARCH_2) $(LDFLAGS) $(LD_arch) $(OBJS) $(MY_LIBS) $(LIB2) | ||
| 124 | $(PROGPATH): $(OBJS) | ||
| 125 | $(CXX) -o $(PROGPATH) $(LFLAGS_ALL) | ||
| 126 | |||
| 127 | $(PROGPATH_STATIC): $(OBJS) | ||
| 128 | $(CXX) -static -o $(PROGPATH_STATIC) $(LFLAGS_ALL) | ||
| 129 | |||
| 130 | |||
| 131 | ifndef NO_DEFAULT_RES | ||
| 132 | $O/resource.o: resource.rc | ||
| 133 | windres.exe $(RFLAGS) resource.rc $O/resource.o | ||
| 134 | endif | ||
| 135 | |||
| 136 | |||
| 137 | |||
| 138 | $O/7zAlloc.o: ../../../C/7zAlloc.c | ||
| 139 | $(CC) $(CFLAGS) $< | ||
| 140 | $O/7zArcIn.o: ../../../C/7zArcIn.c | ||
| 141 | $(CC) $(CFLAGS) $< | ||
| 142 | $O/7zBuf.o: ../../../C/7zBuf.c | ||
| 143 | $(CC) $(CFLAGS) $< | ||
| 144 | $O/7zBuf2.o: ../../../C/7zBuf2.c | ||
| 145 | $(CC) $(CFLAGS) $< | ||
| 146 | $O/7zCrc.o: ../../../C/7zCrc.c | ||
| 147 | $(CC) $(CFLAGS) $< | ||
| 148 | $O/7zDec.o: ../../../C/7zDec.c | ||
| 149 | $(CC) $(CFLAGS) $< | ||
| 150 | $O/7zFile.o: ../../../C/7zFile.c | ||
| 151 | $(CC) $(CFLAGS) $< | ||
| 152 | $O/7zStream.o: ../../../C/7zStream.c | ||
| 153 | $(CC) $(CFLAGS) $< | ||
| 154 | $O/Aes.o: ../../../C/Aes.c | ||
| 155 | $(CC) $(CFLAGS) $< | ||
| 156 | $O/Alloc.o: ../../../C/Alloc.c | ||
| 157 | $(CC) $(CFLAGS) $< | ||
| 158 | $O/Bcj2.o: ../../../C/Bcj2.c | ||
| 159 | $(CC) $(CFLAGS) $< | ||
| 160 | $O/Bcj2Enc.o: ../../../C/Bcj2Enc.c | ||
| 161 | $(CC) $(CFLAGS) $< | ||
| 162 | $O/Blake2s.o: ../../../C/Blake2s.c | ||
| 163 | $(CC) $(CFLAGS) $< | ||
| 164 | $O/Bra.o: ../../../C/Bra.c | ||
| 165 | $(CC) $(CFLAGS) $< | ||
| 166 | $O/Bra86.o: ../../../C/Bra86.c | ||
| 167 | $(CC) $(CFLAGS) $< | ||
| 168 | $O/BraIA64.o: ../../../C/BraIA64.c | ||
| 169 | $(CC) $(CFLAGS) $< | ||
| 170 | $O/BwtSort.o: ../../../C/BwtSort.c | ||
| 171 | $(CC) $(CFLAGS) $< | ||
| 172 | |||
| 173 | $O/CpuArch.o: ../../../C/CpuArch.c | ||
| 174 | $(CC) $(CFLAGS) $< | ||
| 175 | $O/Delta.o: ../../../C/Delta.c | ||
| 176 | $(CC) $(CFLAGS) $< | ||
| 177 | $O/DllSecur.o: ../../../C/DllSecur.c | ||
| 178 | $(CC) $(CFLAGS) $< | ||
| 179 | $O/HuffEnc.o: ../../../C/HuffEnc.c | ||
| 180 | $(CC) $(CFLAGS) $< | ||
| 181 | $O/LzFind.o: ../../../C/LzFind.c | ||
| 182 | $(CC) $(CFLAGS) $< | ||
| 183 | |||
| 184 | # ifdef MT_FILES | ||
| 185 | $O/LzFindMt.o: ../../../C/LzFindMt.c | ||
| 186 | $(CC) $(CFLAGS) $< | ||
| 187 | $O/LzFindOpt.o: ../../../C/LzFindOpt.c | ||
| 188 | $(CC) $(CFLAGS) $< | ||
| 189 | |||
| 190 | $O/Threads.o: ../../../C/Threads.c | ||
| 191 | $(CC) $(CFLAGS) $< | ||
| 192 | # endif | ||
| 193 | |||
| 194 | $O/LzmaEnc.o: ../../../C/LzmaEnc.c | ||
| 195 | $(CC) $(CFLAGS) $< | ||
| 196 | $O/Lzma86Dec.o: ../../../C/Lzma86Dec.c | ||
| 197 | $(CC) $(CFLAGS) $< | ||
| 198 | $O/Lzma86Enc.o: ../../../C/Lzma86Enc.c | ||
| 199 | $(CC) $(CFLAGS) $< | ||
| 200 | $O/Lzma2Dec.o: ../../../C/Lzma2Dec.c | ||
| 201 | $(CC) $(CFLAGS) $< | ||
| 202 | $O/Lzma2DecMt.o: ../../../C/Lzma2DecMt.c | ||
| 203 | $(CC) $(CFLAGS) $< | ||
| 204 | $O/Lzma2Enc.o: ../../../C/Lzma2Enc.c | ||
| 205 | $(CC) $(CFLAGS) $< | ||
| 206 | $O/LzmaLib.o: ../../../C/LzmaLib.c | ||
| 207 | $(CC) $(CFLAGS) $< | ||
| 208 | $O/MtCoder.o: ../../../C/MtCoder.c | ||
| 209 | $(CC) $(CFLAGS) $< | ||
| 210 | $O/MtDec.o: ../../../C/MtDec.c | ||
| 211 | $(CC) $(CFLAGS) $< | ||
| 212 | $O/Ppmd7.o: ../../../C/Ppmd7.c | ||
| 213 | $(CC) $(CFLAGS) $< | ||
| 214 | $O/Ppmd7aDec.o: ../../../C/Ppmd7aDec.c | ||
| 215 | $(CC) $(CFLAGS) $< | ||
| 216 | $O/Ppmd7Dec.o: ../../../C/Ppmd7Dec.c | ||
| 217 | $(CC) $(CFLAGS) $< | ||
| 218 | $O/Ppmd7Enc.o: ../../../C/Ppmd7Enc.c | ||
| 219 | $(CC) $(CFLAGS) $< | ||
| 220 | $O/Ppmd8.o: ../../../C/Ppmd8.c | ||
| 221 | $(CC) $(CFLAGS) $< | ||
| 222 | $O/Ppmd8Dec.o: ../../../C/Ppmd8Dec.c | ||
| 223 | $(CC) $(CFLAGS) $< | ||
| 224 | $O/Ppmd8Enc.o: ../../../C/Ppmd8Enc.c | ||
| 225 | $(CC) $(CFLAGS) $< | ||
| 226 | $O/Sha1.o: ../../../C/Sha1.c | ||
| 227 | $(CC) $(CFLAGS) $< | ||
| 228 | $O/Sha256.o: ../../../C/Sha256.c | ||
| 229 | $(CC) $(CFLAGS) $< | ||
| 230 | $O/Sort.o: ../../../C/Sort.c | ||
| 231 | $(CC) $(CFLAGS) $< | ||
| 232 | $O/Xz.o: ../../../C/Xz.c | ||
| 233 | $(CC) $(CFLAGS) $< | ||
| 234 | $O/XzCrc64.o: ../../../C/XzCrc64.c | ||
| 235 | $(CC) $(CFLAGS) $< | ||
| 236 | |||
| 237 | |||
| 238 | ifdef USE_ASM | ||
| 239 | ifdef IS_X64 | ||
| 240 | USE_X86_ASM=1 | ||
| 241 | else | ||
| 242 | ifdef IS_X86 | ||
| 243 | USE_X86_ASM=1 | ||
| 244 | endif | ||
| 245 | endif | ||
| 246 | endif | ||
| 247 | |||
| 248 | ifdef USE_X86_ASM | ||
| 249 | $O/7zCrcOpt.o: ../../../Asm/x86/7zCrcOpt.asm | ||
| 250 | $(MY_ASM) $(AFLAGS) $< | ||
| 251 | $O/XzCrc64Opt.o: ../../../Asm/x86/XzCrc64Opt.asm | ||
| 252 | $(MY_ASM) $(AFLAGS) $< | ||
| 253 | $O/AesOpt.o: ../../../Asm/x86/AesOpt.asm | ||
| 254 | $(MY_ASM) $(AFLAGS) $< | ||
| 255 | $O/Sha1Opt.o: ../../../Asm/x86/Sha1Opt.asm | ||
| 256 | $(MY_ASM) $(AFLAGS) $< | ||
| 257 | $O/Sha256Opt.o: ../../../Asm/x86/Sha256Opt.asm | ||
| 258 | $(MY_ASM) $(AFLAGS) $< | ||
| 259 | else | ||
| 260 | $O/7zCrcOpt.o: ../../7zCrcOpt.c | ||
| 261 | $(CC) $(CFLAGS) $< | ||
| 262 | $O/XzCrc64Opt.o: ../../XzCrc64Opt.c | ||
| 263 | $(CC) $(CFLAGS) $< | ||
| 264 | $O/Sha1Opt.o: ../../Sha1Opt.c | ||
| 265 | $(CC) $(CFLAGS) $< | ||
| 266 | $O/Sha256Opt.o: ../../Sha256Opt.c | ||
| 267 | $(CC) $(CFLAGS) $< | ||
| 268 | $O/AesOpt.o: ../../AesOpt.c | ||
| 269 | $(CC) $(CFLAGS) $< | ||
| 270 | endif | ||
| 271 | |||
| 272 | |||
| 273 | ifdef USE_LZMA_DEC_ASM | ||
| 274 | |||
| 275 | ifdef IS_X64 | ||
| 276 | $O/LzmaDecOpt.o: ../../../Asm/x86/LzmaDecOpt.asm | ||
| 277 | $(MY_ASM) $(AFLAGS) $< | ||
| 278 | endif | ||
| 279 | |||
| 280 | ifdef IS_ARM64 | ||
| 281 | $O/LzmaDecOpt.o: ../../../Asm/arm64/LzmaDecOpt.S ../../../Asm/arm64/7zAsm.S | ||
| 282 | $(CC) $(CFLAGS) $< | ||
| 283 | endif | ||
| 284 | |||
| 285 | $O/LzmaDec.o: ../../LzmaDec.c | ||
| 286 | $(CC) $(CFLAGS) -D_LZMA_DEC_OPT $< | ||
| 287 | |||
| 288 | else | ||
| 289 | |||
| 290 | $O/LzmaDec.o: ../../LzmaDec.c | ||
| 291 | $(CC) $(CFLAGS) $< | ||
| 292 | |||
| 293 | endif | ||
| 294 | |||
| 295 | |||
| 296 | |||
| 297 | $O/XzDec.o: ../../../C/XzDec.c | ||
| 298 | $(CC) $(CFLAGS) $< | ||
| 299 | $O/XzEnc.o: ../../../C/XzEnc.c | ||
| 300 | $(CC) $(CFLAGS) $< | ||
| 301 | $O/XzIn.o: ../../../C/XzIn.c | ||
| 302 | $(CC) $(CFLAGS) $< | ||
| 303 | |||
| 304 | |||
| 305 | $O/7zMain.o: ../../../C/Util/7z/7zMain.c | ||
| 306 | $(CC) $(CFLAGS) $< | ||
| 307 | $O/LzmaUtil.o: ../../../C/Util/Lzma/LzmaUtil.c | ||
| 308 | $(CC) $(CFLAGS) $< | ||
| 309 | |||
| 310 | |||
| 311 | |||
| 312 | clean: | ||
| 313 | -$(DEL_OBJ_EXE) | ||
| @@ -0,0 +1,375 @@ | |||
| 1 | /* Aes.c -- AES encryption / decryption | ||
| 2 | 2021-05-13 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "CpuArch.h" | ||
| 7 | #include "Aes.h" | ||
| 8 | |||
| 9 | AES_CODE_FUNC g_AesCbc_Decode; | ||
| 10 | #ifndef _SFX | ||
| 11 | AES_CODE_FUNC g_AesCbc_Encode; | ||
| 12 | AES_CODE_FUNC g_AesCtr_Code; | ||
| 13 | UInt32 g_Aes_SupportedFunctions_Flags; | ||
| 14 | #endif | ||
| 15 | |||
| 16 | static UInt32 T[256 * 4]; | ||
| 17 | static const Byte Sbox[256] = { | ||
| 18 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, | ||
| 19 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, | ||
| 20 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, | ||
| 21 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, | ||
| 22 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, | ||
| 23 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, | ||
| 24 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, | ||
| 25 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, | ||
| 26 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, | ||
| 27 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, | ||
| 28 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, | ||
| 29 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, | ||
| 30 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, | ||
| 31 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, | ||
| 32 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, | ||
| 33 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; | ||
| 34 | |||
| 35 | |||
| 36 | static UInt32 D[256 * 4]; | ||
| 37 | static Byte InvS[256]; | ||
| 38 | |||
| 39 | #define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF) | ||
| 40 | |||
| 41 | #define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24)) | ||
| 42 | |||
| 43 | #define gb0(x) ( (x) & 0xFF) | ||
| 44 | #define gb1(x) (((x) >> ( 8)) & 0xFF) | ||
| 45 | #define gb2(x) (((x) >> (16)) & 0xFF) | ||
| 46 | #define gb3(x) (((x) >> (24))) | ||
| 47 | |||
| 48 | #define gb(n, x) gb ## n(x) | ||
| 49 | |||
| 50 | #define TT(x) (T + (x << 8)) | ||
| 51 | #define DD(x) (D + (x << 8)) | ||
| 52 | |||
| 53 | |||
| 54 | // #define _SHOW_AES_STATUS | ||
| 55 | |||
| 56 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 57 | #define USE_HW_AES | ||
| 58 | #elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) | ||
| 59 | #if defined(__clang__) | ||
| 60 | #if (__clang_major__ >= 8) // fix that check | ||
| 61 | #define USE_HW_AES | ||
| 62 | #endif | ||
| 63 | #elif defined(__GNUC__) | ||
| 64 | #if (__GNUC__ >= 6) // fix that check | ||
| 65 | #define USE_HW_AES | ||
| 66 | #endif | ||
| 67 | #elif defined(_MSC_VER) | ||
| 68 | #if _MSC_VER >= 1910 | ||
| 69 | #define USE_HW_AES | ||
| 70 | #endif | ||
| 71 | #endif | ||
| 72 | #endif | ||
| 73 | |||
| 74 | #ifdef USE_HW_AES | ||
| 75 | #ifdef _SHOW_AES_STATUS | ||
| 76 | #include <stdio.h> | ||
| 77 | #define _PRF(x) x | ||
| 78 | #else | ||
| 79 | #define _PRF(x) | ||
| 80 | #endif | ||
| 81 | #endif | ||
| 82 | |||
| 83 | |||
| 84 | void AesGenTables(void) | ||
| 85 | { | ||
| 86 | unsigned i; | ||
| 87 | for (i = 0; i < 256; i++) | ||
| 88 | InvS[Sbox[i]] = (Byte)i; | ||
| 89 | |||
| 90 | for (i = 0; i < 256; i++) | ||
| 91 | { | ||
| 92 | { | ||
| 93 | UInt32 a1 = Sbox[i]; | ||
| 94 | UInt32 a2 = xtime(a1); | ||
| 95 | UInt32 a3 = a2 ^ a1; | ||
| 96 | TT(0)[i] = Ui32(a2, a1, a1, a3); | ||
| 97 | TT(1)[i] = Ui32(a3, a2, a1, a1); | ||
| 98 | TT(2)[i] = Ui32(a1, a3, a2, a1); | ||
| 99 | TT(3)[i] = Ui32(a1, a1, a3, a2); | ||
| 100 | } | ||
| 101 | { | ||
| 102 | UInt32 a1 = InvS[i]; | ||
| 103 | UInt32 a2 = xtime(a1); | ||
| 104 | UInt32 a4 = xtime(a2); | ||
| 105 | UInt32 a8 = xtime(a4); | ||
| 106 | UInt32 a9 = a8 ^ a1; | ||
| 107 | UInt32 aB = a8 ^ a2 ^ a1; | ||
| 108 | UInt32 aD = a8 ^ a4 ^ a1; | ||
| 109 | UInt32 aE = a8 ^ a4 ^ a2; | ||
| 110 | DD(0)[i] = Ui32(aE, a9, aD, aB); | ||
| 111 | DD(1)[i] = Ui32(aB, aE, a9, aD); | ||
| 112 | DD(2)[i] = Ui32(aD, aB, aE, a9); | ||
| 113 | DD(3)[i] = Ui32(a9, aD, aB, aE); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | { | ||
| 118 | AES_CODE_FUNC d = AesCbc_Decode; | ||
| 119 | #ifndef _SFX | ||
| 120 | AES_CODE_FUNC e = AesCbc_Encode; | ||
| 121 | AES_CODE_FUNC c = AesCtr_Code; | ||
| 122 | UInt32 flags = 0; | ||
| 123 | #endif | ||
| 124 | |||
| 125 | #ifdef USE_HW_AES | ||
| 126 | if (CPU_IsSupported_AES()) | ||
| 127 | { | ||
| 128 | // #pragma message ("AES HW") | ||
| 129 | _PRF(printf("\n===AES HW\n")); | ||
| 130 | d = AesCbc_Decode_HW; | ||
| 131 | |||
| 132 | #ifndef _SFX | ||
| 133 | e = AesCbc_Encode_HW; | ||
| 134 | c = AesCtr_Code_HW; | ||
| 135 | flags = k_Aes_SupportedFunctions_HW; | ||
| 136 | #endif | ||
| 137 | |||
| 138 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 139 | if (CPU_IsSupported_VAES_AVX2()) | ||
| 140 | { | ||
| 141 | _PRF(printf("\n===vaes avx2\n")); | ||
| 142 | d = AesCbc_Decode_HW_256; | ||
| 143 | #ifndef _SFX | ||
| 144 | c = AesCtr_Code_HW_256; | ||
| 145 | flags |= k_Aes_SupportedFunctions_HW_256; | ||
| 146 | #endif | ||
| 147 | } | ||
| 148 | #endif | ||
| 149 | } | ||
| 150 | #endif | ||
| 151 | |||
| 152 | g_AesCbc_Decode = d; | ||
| 153 | #ifndef _SFX | ||
| 154 | g_AesCbc_Encode = e; | ||
| 155 | g_AesCtr_Code = c; | ||
| 156 | g_Aes_SupportedFunctions_Flags = flags; | ||
| 157 | #endif | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | |||
| 162 | #define HT(i, x, s) TT(x)[gb(x, s[(i + x) & 3])] | ||
| 163 | |||
| 164 | #define HT4(m, i, s, p) m[i] = \ | ||
| 165 | HT(i, 0, s) ^ \ | ||
| 166 | HT(i, 1, s) ^ \ | ||
| 167 | HT(i, 2, s) ^ \ | ||
| 168 | HT(i, 3, s) ^ w[p + i] | ||
| 169 | |||
| 170 | #define HT16(m, s, p) \ | ||
| 171 | HT4(m, 0, s, p); \ | ||
| 172 | HT4(m, 1, s, p); \ | ||
| 173 | HT4(m, 2, s, p); \ | ||
| 174 | HT4(m, 3, s, p); \ | ||
| 175 | |||
| 176 | #define FT(i, x) Sbox[gb(x, m[(i + x) & 3])] | ||
| 177 | #define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i]; | ||
| 178 | |||
| 179 | |||
| 180 | #define HD(i, x, s) DD(x)[gb(x, s[(i - x) & 3])] | ||
| 181 | |||
| 182 | #define HD4(m, i, s, p) m[i] = \ | ||
| 183 | HD(i, 0, s) ^ \ | ||
| 184 | HD(i, 1, s) ^ \ | ||
| 185 | HD(i, 2, s) ^ \ | ||
| 186 | HD(i, 3, s) ^ w[p + i]; | ||
| 187 | |||
| 188 | #define HD16(m, s, p) \ | ||
| 189 | HD4(m, 0, s, p); \ | ||
| 190 | HD4(m, 1, s, p); \ | ||
| 191 | HD4(m, 2, s, p); \ | ||
| 192 | HD4(m, 3, s, p); \ | ||
| 193 | |||
| 194 | #define FD(i, x) InvS[gb(x, m[(i - x) & 3])] | ||
| 195 | #define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i]; | ||
| 196 | |||
| 197 | void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize) | ||
| 198 | { | ||
| 199 | unsigned i, m; | ||
| 200 | const UInt32 *wLim; | ||
| 201 | UInt32 t; | ||
| 202 | UInt32 rcon = 1; | ||
| 203 | |||
| 204 | keySize /= 4; | ||
| 205 | w[0] = ((UInt32)keySize / 2) + 3; | ||
| 206 | w += 4; | ||
| 207 | |||
| 208 | for (i = 0; i < keySize; i++, key += 4) | ||
| 209 | w[i] = GetUi32(key); | ||
| 210 | |||
| 211 | t = w[(size_t)keySize - 1]; | ||
| 212 | wLim = w + (size_t)keySize * 3 + 28; | ||
| 213 | m = 0; | ||
| 214 | do | ||
| 215 | { | ||
| 216 | if (m == 0) | ||
| 217 | { | ||
| 218 | t = Ui32(Sbox[gb1(t)] ^ rcon, Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]); | ||
| 219 | rcon <<= 1; | ||
| 220 | if (rcon & 0x100) | ||
| 221 | rcon = 0x1b; | ||
| 222 | m = keySize; | ||
| 223 | } | ||
| 224 | else if (m == 4 && keySize > 6) | ||
| 225 | t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]); | ||
| 226 | m--; | ||
| 227 | t ^= w[0]; | ||
| 228 | w[keySize] = t; | ||
| 229 | } | ||
| 230 | while (++w != wLim); | ||
| 231 | } | ||
| 232 | |||
| 233 | void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *w, const Byte *key, unsigned keySize) | ||
| 234 | { | ||
| 235 | unsigned i, num; | ||
| 236 | Aes_SetKey_Enc(w, key, keySize); | ||
| 237 | num = keySize + 20; | ||
| 238 | w += 8; | ||
| 239 | for (i = 0; i < num; i++) | ||
| 240 | { | ||
| 241 | UInt32 r = w[i]; | ||
| 242 | w[i] = | ||
| 243 | DD(0)[Sbox[gb0(r)]] ^ | ||
| 244 | DD(1)[Sbox[gb1(r)]] ^ | ||
| 245 | DD(2)[Sbox[gb2(r)]] ^ | ||
| 246 | DD(3)[Sbox[gb3(r)]]; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | /* Aes_Encode and Aes_Decode functions work with little-endian words. | ||
| 251 | src and dest are pointers to 4 UInt32 words. | ||
| 252 | src and dest can point to same block */ | ||
| 253 | |||
| 254 | // MY_FORCE_INLINE | ||
| 255 | static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src) | ||
| 256 | { | ||
| 257 | UInt32 s[4]; | ||
| 258 | UInt32 m[4]; | ||
| 259 | UInt32 numRounds2 = w[0]; | ||
| 260 | w += 4; | ||
| 261 | s[0] = src[0] ^ w[0]; | ||
| 262 | s[1] = src[1] ^ w[1]; | ||
| 263 | s[2] = src[2] ^ w[2]; | ||
| 264 | s[3] = src[3] ^ w[3]; | ||
| 265 | w += 4; | ||
| 266 | for (;;) | ||
| 267 | { | ||
| 268 | HT16(m, s, 0); | ||
| 269 | if (--numRounds2 == 0) | ||
| 270 | break; | ||
| 271 | HT16(s, m, 4); | ||
| 272 | w += 8; | ||
| 273 | } | ||
| 274 | w += 4; | ||
| 275 | FT4(0); FT4(1); FT4(2); FT4(3); | ||
| 276 | } | ||
| 277 | |||
| 278 | MY_FORCE_INLINE | ||
| 279 | static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src) | ||
| 280 | { | ||
| 281 | UInt32 s[4]; | ||
| 282 | UInt32 m[4]; | ||
| 283 | UInt32 numRounds2 = w[0]; | ||
| 284 | w += 4 + numRounds2 * 8; | ||
| 285 | s[0] = src[0] ^ w[0]; | ||
| 286 | s[1] = src[1] ^ w[1]; | ||
| 287 | s[2] = src[2] ^ w[2]; | ||
| 288 | s[3] = src[3] ^ w[3]; | ||
| 289 | for (;;) | ||
| 290 | { | ||
| 291 | w -= 8; | ||
| 292 | HD16(m, s, 4); | ||
| 293 | if (--numRounds2 == 0) | ||
| 294 | break; | ||
| 295 | HD16(s, m, 0); | ||
| 296 | } | ||
| 297 | FD4(0); FD4(1); FD4(2); FD4(3); | ||
| 298 | } | ||
| 299 | |||
| 300 | void AesCbc_Init(UInt32 *p, const Byte *iv) | ||
| 301 | { | ||
| 302 | unsigned i; | ||
| 303 | for (i = 0; i < 4; i++) | ||
| 304 | p[i] = GetUi32(iv + i * 4); | ||
| 305 | } | ||
| 306 | |||
| 307 | void MY_FAST_CALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks) | ||
| 308 | { | ||
| 309 | for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE) | ||
| 310 | { | ||
| 311 | p[0] ^= GetUi32(data); | ||
| 312 | p[1] ^= GetUi32(data + 4); | ||
| 313 | p[2] ^= GetUi32(data + 8); | ||
| 314 | p[3] ^= GetUi32(data + 12); | ||
| 315 | |||
| 316 | Aes_Encode(p + 4, p, p); | ||
| 317 | |||
| 318 | SetUi32(data, p[0]); | ||
| 319 | SetUi32(data + 4, p[1]); | ||
| 320 | SetUi32(data + 8, p[2]); | ||
| 321 | SetUi32(data + 12, p[3]); | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | void MY_FAST_CALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks) | ||
| 326 | { | ||
| 327 | UInt32 in[4], out[4]; | ||
| 328 | for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE) | ||
| 329 | { | ||
| 330 | in[0] = GetUi32(data); | ||
| 331 | in[1] = GetUi32(data + 4); | ||
| 332 | in[2] = GetUi32(data + 8); | ||
| 333 | in[3] = GetUi32(data + 12); | ||
| 334 | |||
| 335 | Aes_Decode(p + 4, out, in); | ||
| 336 | |||
| 337 | SetUi32(data, p[0] ^ out[0]); | ||
| 338 | SetUi32(data + 4, p[1] ^ out[1]); | ||
| 339 | SetUi32(data + 8, p[2] ^ out[2]); | ||
| 340 | SetUi32(data + 12, p[3] ^ out[3]); | ||
| 341 | |||
| 342 | p[0] = in[0]; | ||
| 343 | p[1] = in[1]; | ||
| 344 | p[2] = in[2]; | ||
| 345 | p[3] = in[3]; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | void MY_FAST_CALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks) | ||
| 350 | { | ||
| 351 | for (; numBlocks != 0; numBlocks--) | ||
| 352 | { | ||
| 353 | UInt32 temp[4]; | ||
| 354 | unsigned i; | ||
| 355 | |||
| 356 | if (++p[0] == 0) | ||
| 357 | p[1]++; | ||
| 358 | |||
| 359 | Aes_Encode(p + 4, temp, p); | ||
| 360 | |||
| 361 | for (i = 0; i < 4; i++, data += 4) | ||
| 362 | { | ||
| 363 | UInt32 t = temp[i]; | ||
| 364 | |||
| 365 | #ifdef MY_CPU_LE_UNALIGN | ||
| 366 | *((UInt32 *)(void *)data) ^= t; | ||
| 367 | #else | ||
| 368 | data[0] = (Byte)(data[0] ^ (t & 0xFF)); | ||
| 369 | data[1] = (Byte)(data[1] ^ ((t >> 8) & 0xFF)); | ||
| 370 | data[2] = (Byte)(data[2] ^ ((t >> 16) & 0xFF)); | ||
| 371 | data[3] = (Byte)(data[3] ^ ((t >> 24))); | ||
| 372 | #endif | ||
| 373 | } | ||
| 374 | } | ||
| 375 | } | ||
| @@ -0,0 +1,60 @@ | |||
| 1 | /* Aes.h -- AES encryption / decryption | ||
| 2 | 2018-04-28 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __AES_H | ||
| 5 | #define __AES_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define AES_BLOCK_SIZE 16 | ||
| 12 | |||
| 13 | /* Call AesGenTables one time before other AES functions */ | ||
| 14 | void AesGenTables(void); | ||
| 15 | |||
| 16 | /* UInt32 pointers must be 16-byte aligned */ | ||
| 17 | |||
| 18 | /* 16-byte (4 * 32-bit words) blocks: 1 (IV) + 1 (keyMode) + 15 (AES-256 roundKeys) */ | ||
| 19 | #define AES_NUM_IVMRK_WORDS ((1 + 1 + 15) * 4) | ||
| 20 | |||
| 21 | /* aes - 16-byte aligned pointer to keyMode+roundKeys sequence */ | ||
| 22 | /* keySize = 16 or 24 or 32 (bytes) */ | ||
| 23 | typedef void (MY_FAST_CALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize); | ||
| 24 | void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize); | ||
| 25 | void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *aes, const Byte *key, unsigned keySize); | ||
| 26 | |||
| 27 | /* ivAes - 16-byte aligned pointer to iv+keyMode+roundKeys sequence: UInt32[AES_NUM_IVMRK_WORDS] */ | ||
| 28 | void AesCbc_Init(UInt32 *ivAes, const Byte *iv); /* iv size is AES_BLOCK_SIZE */ | ||
| 29 | |||
| 30 | /* data - 16-byte aligned pointer to data */ | ||
| 31 | /* numBlocks - the number of 16-byte blocks in data array */ | ||
| 32 | typedef void (MY_FAST_CALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks); | ||
| 33 | |||
| 34 | extern AES_CODE_FUNC g_AesCbc_Decode; | ||
| 35 | #ifndef _SFX | ||
| 36 | extern AES_CODE_FUNC g_AesCbc_Encode; | ||
| 37 | extern AES_CODE_FUNC g_AesCtr_Code; | ||
| 38 | #define k_Aes_SupportedFunctions_HW (1 << 2) | ||
| 39 | #define k_Aes_SupportedFunctions_HW_256 (1 << 3) | ||
| 40 | extern UInt32 g_Aes_SupportedFunctions_Flags; | ||
| 41 | #endif | ||
| 42 | |||
| 43 | |||
| 44 | #define DECLARE__AES_CODE_FUNC(funcName) \ | ||
| 45 | void MY_FAST_CALL funcName(UInt32 *ivAes, Byte *data, size_t numBlocks); | ||
| 46 | |||
| 47 | DECLARE__AES_CODE_FUNC (AesCbc_Encode) | ||
| 48 | DECLARE__AES_CODE_FUNC (AesCbc_Decode) | ||
| 49 | DECLARE__AES_CODE_FUNC (AesCtr_Code) | ||
| 50 | |||
| 51 | DECLARE__AES_CODE_FUNC (AesCbc_Encode_HW) | ||
| 52 | DECLARE__AES_CODE_FUNC (AesCbc_Decode_HW) | ||
| 53 | DECLARE__AES_CODE_FUNC (AesCtr_Code_HW) | ||
| 54 | |||
| 55 | DECLARE__AES_CODE_FUNC (AesCbc_Decode_HW_256) | ||
| 56 | DECLARE__AES_CODE_FUNC (AesCtr_Code_HW_256) | ||
| 57 | |||
| 58 | EXTERN_C_END | ||
| 59 | |||
| 60 | #endif | ||
diff --git a/C/AesOpt.c b/C/AesOpt.c new file mode 100644 index 0000000..8be8ff6 --- /dev/null +++ b/C/AesOpt.c | |||
| @@ -0,0 +1,776 @@ | |||
| 1 | /* AesOpt.c -- AES optimized code for x86 AES hardware instructions | ||
| 2 | 2021-04-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "CpuArch.h" | ||
| 7 | |||
| 8 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 9 | |||
| 10 | #if defined(__clang__) | ||
| 11 | #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 8) | ||
| 12 | #define USE_INTEL_AES | ||
| 13 | #define ATTRIB_AES __attribute__((__target__("aes"))) | ||
| 14 | #if (__clang_major__ >= 8) | ||
| 15 | #define USE_INTEL_VAES | ||
| 16 | #define ATTRIB_VAES __attribute__((__target__("aes,vaes,avx2"))) | ||
| 17 | #endif | ||
| 18 | #endif | ||
| 19 | #elif defined(__GNUC__) | ||
| 20 | #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) | ||
| 21 | #define USE_INTEL_AES | ||
| 22 | #ifndef __AES__ | ||
| 23 | #define ATTRIB_AES __attribute__((__target__("aes"))) | ||
| 24 | #endif | ||
| 25 | #if (__GNUC__ >= 8) | ||
| 26 | #define USE_INTEL_VAES | ||
| 27 | #define ATTRIB_VAES __attribute__((__target__("aes,vaes,avx2"))) | ||
| 28 | #endif | ||
| 29 | #endif | ||
| 30 | #elif defined(__INTEL_COMPILER) | ||
| 31 | #if (__INTEL_COMPILER >= 1110) | ||
| 32 | #define USE_INTEL_AES | ||
| 33 | #if (__INTEL_COMPILER >= 1900) | ||
| 34 | #define USE_INTEL_VAES | ||
| 35 | #endif | ||
| 36 | #endif | ||
| 37 | #elif defined(_MSC_VER) | ||
| 38 | #if (_MSC_VER > 1500) || (_MSC_FULL_VER >= 150030729) | ||
| 39 | #define USE_INTEL_AES | ||
| 40 | #if (_MSC_VER >= 1910) | ||
| 41 | #define USE_INTEL_VAES | ||
| 42 | #endif | ||
| 43 | #endif | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #ifndef ATTRIB_AES | ||
| 47 | #define ATTRIB_AES | ||
| 48 | #endif | ||
| 49 | #ifndef ATTRIB_VAES | ||
| 50 | #define ATTRIB_VAES | ||
| 51 | #endif | ||
| 52 | |||
| 53 | |||
| 54 | #ifdef USE_INTEL_AES | ||
| 55 | |||
| 56 | #include <wmmintrin.h> | ||
| 57 | |||
| 58 | #ifndef USE_INTEL_VAES | ||
| 59 | #define AES_TYPE_keys __m128i | ||
| 60 | #define AES_TYPE_data __m128i | ||
| 61 | #endif | ||
| 62 | |||
| 63 | #define AES_FUNC_START(name) \ | ||
| 64 | void MY_FAST_CALL name(__m128i *p, __m128i *data, size_t numBlocks) | ||
| 65 | |||
| 66 | #define AES_FUNC_START2(name) \ | ||
| 67 | AES_FUNC_START (name); \ | ||
| 68 | ATTRIB_AES \ | ||
| 69 | AES_FUNC_START (name) | ||
| 70 | |||
| 71 | #define MM_OP(op, dest, src) dest = op(dest, src); | ||
| 72 | #define MM_OP_m(op, src) MM_OP(op, m, src); | ||
| 73 | |||
| 74 | #define MM_XOR( dest, src) MM_OP(_mm_xor_si128, dest, src); | ||
| 75 | #define AVX_XOR(dest, src) MM_OP(_mm256_xor_si256, dest, src); | ||
| 76 | |||
| 77 | |||
| 78 | AES_FUNC_START2 (AesCbc_Encode_HW) | ||
| 79 | { | ||
| 80 | __m128i m = *p; | ||
| 81 | const __m128i k0 = p[2]; | ||
| 82 | const __m128i k1 = p[3]; | ||
| 83 | const UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; | ||
| 84 | for (; numBlocks != 0; numBlocks--, data++) | ||
| 85 | { | ||
| 86 | UInt32 r = numRounds2; | ||
| 87 | const __m128i *w = p + 4; | ||
| 88 | __m128i temp = *data; | ||
| 89 | MM_XOR (temp, k0); | ||
| 90 | MM_XOR (m, temp); | ||
| 91 | MM_OP_m (_mm_aesenc_si128, k1); | ||
| 92 | do | ||
| 93 | { | ||
| 94 | MM_OP_m (_mm_aesenc_si128, w[0]); | ||
| 95 | MM_OP_m (_mm_aesenc_si128, w[1]); | ||
| 96 | w += 2; | ||
| 97 | } | ||
| 98 | while (--r); | ||
| 99 | MM_OP_m (_mm_aesenclast_si128, w[0]); | ||
| 100 | *data = m; | ||
| 101 | } | ||
| 102 | *p = m; | ||
| 103 | } | ||
| 104 | |||
| 105 | |||
| 106 | #define WOP_1(op) | ||
| 107 | #define WOP_2(op) WOP_1 (op) op (m1, 1); | ||
| 108 | #define WOP_3(op) WOP_2 (op) op (m2, 2); | ||
| 109 | #define WOP_4(op) WOP_3 (op) op (m3, 3); | ||
| 110 | #ifdef MY_CPU_AMD64 | ||
| 111 | #define WOP_5(op) WOP_4 (op) op (m4, 4); | ||
| 112 | #define WOP_6(op) WOP_5 (op) op (m5, 5); | ||
| 113 | #define WOP_7(op) WOP_6 (op) op (m6, 6); | ||
| 114 | #define WOP_8(op) WOP_7 (op) op (m7, 7); | ||
| 115 | #endif | ||
| 116 | /* | ||
| 117 | #define WOP_9(op) WOP_8 (op) op (m8, 8); | ||
| 118 | #define WOP_10(op) WOP_9 (op) op (m9, 9); | ||
| 119 | #define WOP_11(op) WOP_10(op) op (m10, 10); | ||
| 120 | #define WOP_12(op) WOP_11(op) op (m11, 11); | ||
| 121 | #define WOP_13(op) WOP_12(op) op (m12, 12); | ||
| 122 | #define WOP_14(op) WOP_13(op) op (m13, 13); | ||
| 123 | */ | ||
| 124 | |||
| 125 | #ifdef MY_CPU_AMD64 | ||
| 126 | #define NUM_WAYS 8 | ||
| 127 | #define WOP_M1 WOP_8 | ||
| 128 | #else | ||
| 129 | #define NUM_WAYS 4 | ||
| 130 | #define WOP_M1 WOP_4 | ||
| 131 | #endif | ||
| 132 | |||
| 133 | #define WOP(op) op (m0, 0); WOP_M1(op) | ||
| 134 | |||
| 135 | |||
| 136 | #define DECLARE_VAR(reg, ii) __m128i reg | ||
| 137 | #define LOAD_data( reg, ii) reg = data[ii]; | ||
| 138 | #define STORE_data( reg, ii) data[ii] = reg; | ||
| 139 | #if (NUM_WAYS > 1) | ||
| 140 | #define XOR_data_M1(reg, ii) MM_XOR (reg, data[ii- 1]); | ||
| 141 | #endif | ||
| 142 | |||
| 143 | #define AVX__DECLARE_VAR(reg, ii) __m256i reg | ||
| 144 | #define AVX__LOAD_data( reg, ii) reg = ((const __m256i *)(const void *)data)[ii]; | ||
| 145 | #define AVX__STORE_data( reg, ii) ((__m256i *)(void *)data)[ii] = reg; | ||
| 146 | #define AVX__XOR_data_M1(reg, ii) AVX_XOR (reg, (((const __m256i *)(const void *)(data - 1))[ii])); | ||
| 147 | |||
| 148 | #define MM_OP_key(op, reg) MM_OP(op, reg, key); | ||
| 149 | |||
| 150 | #define AES_DEC( reg, ii) MM_OP_key (_mm_aesdec_si128, reg) | ||
| 151 | #define AES_DEC_LAST( reg, ii) MM_OP_key (_mm_aesdeclast_si128, reg) | ||
| 152 | #define AES_ENC( reg, ii) MM_OP_key (_mm_aesenc_si128, reg) | ||
| 153 | #define AES_ENC_LAST( reg, ii) MM_OP_key (_mm_aesenclast_si128, reg) | ||
| 154 | #define AES_XOR( reg, ii) MM_OP_key (_mm_xor_si128, reg) | ||
| 155 | |||
| 156 | |||
| 157 | #define AVX__AES_DEC( reg, ii) MM_OP_key (_mm256_aesdec_epi128, reg) | ||
| 158 | #define AVX__AES_DEC_LAST( reg, ii) MM_OP_key (_mm256_aesdeclast_epi128, reg) | ||
| 159 | #define AVX__AES_ENC( reg, ii) MM_OP_key (_mm256_aesenc_epi128, reg) | ||
| 160 | #define AVX__AES_ENC_LAST( reg, ii) MM_OP_key (_mm256_aesenclast_epi128, reg) | ||
| 161 | #define AVX__AES_XOR( reg, ii) MM_OP_key (_mm256_xor_si256, reg) | ||
| 162 | |||
| 163 | #define CTR_START(reg, ii) MM_OP (_mm_add_epi64, ctr, one); reg = ctr; | ||
| 164 | #define CTR_END( reg, ii) MM_XOR (data[ii], reg); | ||
| 165 | |||
| 166 | #define AVX__CTR_START(reg, ii) MM_OP (_mm256_add_epi64, ctr2, two); reg = _mm256_xor_si256(ctr2, key); | ||
| 167 | #define AVX__CTR_END( reg, ii) AVX_XOR (((__m256i *)(void *)data)[ii], reg); | ||
| 168 | |||
| 169 | #define WOP_KEY(op, n) { \ | ||
| 170 | const __m128i key = w[n]; \ | ||
| 171 | WOP(op); } | ||
| 172 | |||
| 173 | #define AVX__WOP_KEY(op, n) { \ | ||
| 174 | const __m256i key = w[n]; \ | ||
| 175 | WOP(op); } | ||
| 176 | |||
| 177 | |||
| 178 | #define WIDE_LOOP_START \ | ||
| 179 | dataEnd = data + numBlocks; \ | ||
| 180 | if (numBlocks >= NUM_WAYS) \ | ||
| 181 | { dataEnd -= NUM_WAYS; do { \ | ||
| 182 | |||
| 183 | |||
| 184 | #define WIDE_LOOP_END \ | ||
| 185 | data += NUM_WAYS; \ | ||
| 186 | } while (data <= dataEnd); \ | ||
| 187 | dataEnd += NUM_WAYS; } \ | ||
| 188 | |||
| 189 | |||
| 190 | #define SINGLE_LOOP \ | ||
| 191 | for (; data < dataEnd; data++) | ||
| 192 | |||
| 193 | |||
| 194 | #define NUM_AES_KEYS_MAX 15 | ||
| 195 | |||
| 196 | #define WIDE_LOOP_START_AVX(OP) \ | ||
| 197 | dataEnd = data + numBlocks; \ | ||
| 198 | if (numBlocks >= NUM_WAYS * 2) \ | ||
| 199 | { __m256i keys[NUM_AES_KEYS_MAX]; \ | ||
| 200 | UInt32 ii; \ | ||
| 201 | OP \ | ||
| 202 | for (ii = 0; ii < numRounds; ii++) \ | ||
| 203 | keys[ii] = _mm256_broadcastsi128_si256(p[ii]); \ | ||
| 204 | dataEnd -= NUM_WAYS * 2; do { \ | ||
| 205 | |||
| 206 | |||
| 207 | #define WIDE_LOOP_END_AVX(OP) \ | ||
| 208 | data += NUM_WAYS * 2; \ | ||
| 209 | } while (data <= dataEnd); \ | ||
| 210 | dataEnd += NUM_WAYS * 2; \ | ||
| 211 | OP \ | ||
| 212 | _mm256_zeroupper(); \ | ||
| 213 | } \ | ||
| 214 | |||
| 215 | /* MSVC for x86: If we don't call _mm256_zeroupper(), and -arch:IA32 is not specified, | ||
| 216 | MSVC still can insert vzeroupper instruction. */ | ||
| 217 | |||
| 218 | |||
| 219 | AES_FUNC_START2 (AesCbc_Decode_HW) | ||
| 220 | { | ||
| 221 | __m128i iv = *p; | ||
| 222 | const __m128i *wStart = p + *(const UInt32 *)(p + 1) * 2 + 2 - 1; | ||
| 223 | const __m128i *dataEnd; | ||
| 224 | p += 2; | ||
| 225 | |||
| 226 | WIDE_LOOP_START | ||
| 227 | { | ||
| 228 | const __m128i *w = wStart; | ||
| 229 | |||
| 230 | WOP (DECLARE_VAR) | ||
| 231 | WOP (LOAD_data); | ||
| 232 | WOP_KEY (AES_XOR, 1) | ||
| 233 | |||
| 234 | do | ||
| 235 | { | ||
| 236 | WOP_KEY (AES_DEC, 0) | ||
| 237 | w--; | ||
| 238 | } | ||
| 239 | while (w != p); | ||
| 240 | WOP_KEY (AES_DEC_LAST, 0) | ||
| 241 | |||
| 242 | MM_XOR (m0, iv); | ||
| 243 | WOP_M1 (XOR_data_M1) | ||
| 244 | iv = data[NUM_WAYS - 1]; | ||
| 245 | WOP (STORE_data); | ||
| 246 | } | ||
| 247 | WIDE_LOOP_END | ||
| 248 | |||
| 249 | SINGLE_LOOP | ||
| 250 | { | ||
| 251 | const __m128i *w = wStart - 1; | ||
| 252 | __m128i m = _mm_xor_si128 (w[2], *data); | ||
| 253 | do | ||
| 254 | { | ||
| 255 | MM_OP_m (_mm_aesdec_si128, w[1]); | ||
| 256 | MM_OP_m (_mm_aesdec_si128, w[0]); | ||
| 257 | w -= 2; | ||
| 258 | } | ||
| 259 | while (w != p); | ||
| 260 | MM_OP_m (_mm_aesdec_si128, w[1]); | ||
| 261 | MM_OP_m (_mm_aesdeclast_si128, w[0]); | ||
| 262 | |||
| 263 | MM_XOR (m, iv); | ||
| 264 | iv = *data; | ||
| 265 | *data = m; | ||
| 266 | } | ||
| 267 | |||
| 268 | p[-2] = iv; | ||
| 269 | } | ||
| 270 | |||
| 271 | |||
| 272 | AES_FUNC_START2 (AesCtr_Code_HW) | ||
| 273 | { | ||
| 274 | __m128i ctr = *p; | ||
| 275 | UInt32 numRoundsMinus2 = *(const UInt32 *)(p + 1) * 2 - 1; | ||
| 276 | const __m128i *dataEnd; | ||
| 277 | __m128i one = _mm_cvtsi32_si128(1); | ||
| 278 | |||
| 279 | p += 2; | ||
| 280 | |||
| 281 | WIDE_LOOP_START | ||
| 282 | { | ||
| 283 | const __m128i *w = p; | ||
| 284 | UInt32 r = numRoundsMinus2; | ||
| 285 | WOP (DECLARE_VAR) | ||
| 286 | WOP (CTR_START); | ||
| 287 | WOP_KEY (AES_XOR, 0) | ||
| 288 | w += 1; | ||
| 289 | do | ||
| 290 | { | ||
| 291 | WOP_KEY (AES_ENC, 0) | ||
| 292 | w += 1; | ||
| 293 | } | ||
| 294 | while (--r); | ||
| 295 | WOP_KEY (AES_ENC_LAST, 0) | ||
| 296 | |||
| 297 | WOP (CTR_END); | ||
| 298 | } | ||
| 299 | WIDE_LOOP_END | ||
| 300 | |||
| 301 | SINGLE_LOOP | ||
| 302 | { | ||
| 303 | UInt32 numRounds2 = *(const UInt32 *)(p - 2 + 1) - 1; | ||
| 304 | const __m128i *w = p; | ||
| 305 | __m128i m; | ||
| 306 | MM_OP (_mm_add_epi64, ctr, one); | ||
| 307 | m = _mm_xor_si128 (ctr, p[0]); | ||
| 308 | w += 1; | ||
| 309 | do | ||
| 310 | { | ||
| 311 | MM_OP_m (_mm_aesenc_si128, w[0]); | ||
| 312 | MM_OP_m (_mm_aesenc_si128, w[1]); | ||
| 313 | w += 2; | ||
| 314 | } | ||
| 315 | while (--numRounds2); | ||
| 316 | MM_OP_m (_mm_aesenc_si128, w[0]); | ||
| 317 | MM_OP_m (_mm_aesenclast_si128, w[1]); | ||
| 318 | MM_XOR (*data, m); | ||
| 319 | } | ||
| 320 | |||
| 321 | p[-2] = ctr; | ||
| 322 | } | ||
| 323 | |||
| 324 | |||
| 325 | |||
| 326 | #ifdef USE_INTEL_VAES | ||
| 327 | |||
| 328 | #if defined(__clang__) && defined(_MSC_VER) | ||
| 329 | #define __SSE4_2__ | ||
| 330 | #define __AES__ | ||
| 331 | #define __AVX__ | ||
| 332 | #define __AVX2__ | ||
| 333 | #define __VAES__ | ||
| 334 | #define __AVX512F__ | ||
| 335 | #define __AVX512VL__ | ||
| 336 | #endif | ||
| 337 | |||
| 338 | #include <immintrin.h> | ||
| 339 | |||
| 340 | #define VAES_FUNC_START2(name) \ | ||
| 341 | AES_FUNC_START (name); \ | ||
| 342 | ATTRIB_VAES \ | ||
| 343 | AES_FUNC_START (name) | ||
| 344 | |||
| 345 | VAES_FUNC_START2 (AesCbc_Decode_HW_256) | ||
| 346 | { | ||
| 347 | __m128i iv = *p; | ||
| 348 | const __m128i *dataEnd; | ||
| 349 | UInt32 numRounds = *(const UInt32 *)(p + 1) * 2 + 1; | ||
| 350 | p += 2; | ||
| 351 | |||
| 352 | WIDE_LOOP_START_AVX(;) | ||
| 353 | { | ||
| 354 | const __m256i *w = keys + numRounds - 2; | ||
| 355 | |||
| 356 | WOP (AVX__DECLARE_VAR) | ||
| 357 | WOP (AVX__LOAD_data); | ||
| 358 | AVX__WOP_KEY (AVX__AES_XOR, 1) | ||
| 359 | |||
| 360 | do | ||
| 361 | { | ||
| 362 | AVX__WOP_KEY (AVX__AES_DEC, 0) | ||
| 363 | w--; | ||
| 364 | } | ||
| 365 | while (w != keys); | ||
| 366 | AVX__WOP_KEY (AVX__AES_DEC_LAST, 0) | ||
| 367 | |||
| 368 | AVX_XOR (m0, _mm256_setr_m128i(iv, data[0])); | ||
| 369 | WOP_M1 (AVX__XOR_data_M1) | ||
| 370 | iv = data[NUM_WAYS * 2 - 1]; | ||
| 371 | WOP (AVX__STORE_data); | ||
| 372 | } | ||
| 373 | WIDE_LOOP_END_AVX(;) | ||
| 374 | |||
| 375 | SINGLE_LOOP | ||
| 376 | { | ||
| 377 | const __m128i *w = p + *(const UInt32 *)(p + 1 - 2) * 2 + 1 - 3; | ||
| 378 | __m128i m = _mm_xor_si128 (w[2], *data); | ||
| 379 | do | ||
| 380 | { | ||
| 381 | MM_OP_m (_mm_aesdec_si128, w[1]); | ||
| 382 | MM_OP_m (_mm_aesdec_si128, w[0]); | ||
| 383 | w -= 2; | ||
| 384 | } | ||
| 385 | while (w != p); | ||
| 386 | MM_OP_m (_mm_aesdec_si128, w[1]); | ||
| 387 | MM_OP_m (_mm_aesdeclast_si128, w[0]); | ||
| 388 | |||
| 389 | MM_XOR (m, iv); | ||
| 390 | iv = *data; | ||
| 391 | *data = m; | ||
| 392 | } | ||
| 393 | |||
| 394 | p[-2] = iv; | ||
| 395 | } | ||
| 396 | |||
| 397 | |||
| 398 | /* | ||
| 399 | SSE2: _mm_cvtsi32_si128 : movd | ||
| 400 | AVX: _mm256_setr_m128i : vinsertf128 | ||
| 401 | AVX2: _mm256_add_epi64 : vpaddq ymm, ymm, ymm | ||
| 402 | _mm256_extracti128_si256 : vextracti128 | ||
| 403 | _mm256_broadcastsi128_si256 : vbroadcasti128 | ||
| 404 | */ | ||
| 405 | |||
| 406 | #define AVX__CTR_LOOP_START \ | ||
| 407 | ctr2 = _mm256_setr_m128i(_mm_sub_epi64(ctr, one), ctr); \ | ||
| 408 | two = _mm256_setr_m128i(one, one); \ | ||
| 409 | two = _mm256_add_epi64(two, two); \ | ||
| 410 | |||
| 411 | // two = _mm256_setr_epi64x(2, 0, 2, 0); | ||
| 412 | |||
| 413 | #define AVX__CTR_LOOP_ENC \ | ||
| 414 | ctr = _mm256_extracti128_si256 (ctr2, 1); \ | ||
| 415 | |||
| 416 | VAES_FUNC_START2 (AesCtr_Code_HW_256) | ||
| 417 | { | ||
| 418 | __m128i ctr = *p; | ||
| 419 | UInt32 numRounds = *(const UInt32 *)(p + 1) * 2 + 1; | ||
| 420 | const __m128i *dataEnd; | ||
| 421 | __m128i one = _mm_cvtsi32_si128(1); | ||
| 422 | __m256i ctr2, two; | ||
| 423 | p += 2; | ||
| 424 | |||
| 425 | WIDE_LOOP_START_AVX (AVX__CTR_LOOP_START) | ||
| 426 | { | ||
| 427 | const __m256i *w = keys; | ||
| 428 | UInt32 r = numRounds - 2; | ||
| 429 | WOP (AVX__DECLARE_VAR) | ||
| 430 | AVX__WOP_KEY (AVX__CTR_START, 0); | ||
| 431 | |||
| 432 | w += 1; | ||
| 433 | do | ||
| 434 | { | ||
| 435 | AVX__WOP_KEY (AVX__AES_ENC, 0) | ||
| 436 | w += 1; | ||
| 437 | } | ||
| 438 | while (--r); | ||
| 439 | AVX__WOP_KEY (AVX__AES_ENC_LAST, 0) | ||
| 440 | |||
| 441 | WOP (AVX__CTR_END); | ||
| 442 | } | ||
| 443 | WIDE_LOOP_END_AVX (AVX__CTR_LOOP_ENC) | ||
| 444 | |||
| 445 | SINGLE_LOOP | ||
| 446 | { | ||
| 447 | UInt32 numRounds2 = *(const UInt32 *)(p - 2 + 1) - 1; | ||
| 448 | const __m128i *w = p; | ||
| 449 | __m128i m; | ||
| 450 | MM_OP (_mm_add_epi64, ctr, one); | ||
| 451 | m = _mm_xor_si128 (ctr, p[0]); | ||
| 452 | w += 1; | ||
| 453 | do | ||
| 454 | { | ||
| 455 | MM_OP_m (_mm_aesenc_si128, w[0]); | ||
| 456 | MM_OP_m (_mm_aesenc_si128, w[1]); | ||
| 457 | w += 2; | ||
| 458 | } | ||
| 459 | while (--numRounds2); | ||
| 460 | MM_OP_m (_mm_aesenc_si128, w[0]); | ||
| 461 | MM_OP_m (_mm_aesenclast_si128, w[1]); | ||
| 462 | MM_XOR (*data, m); | ||
| 463 | } | ||
| 464 | |||
| 465 | p[-2] = ctr; | ||
| 466 | } | ||
| 467 | |||
| 468 | #endif // USE_INTEL_VAES | ||
| 469 | |||
| 470 | #else // USE_INTEL_AES | ||
| 471 | |||
| 472 | /* no USE_INTEL_AES */ | ||
| 473 | |||
| 474 | #pragma message("AES HW_SW stub was used") | ||
| 475 | |||
| 476 | #define AES_TYPE_keys UInt32 | ||
| 477 | #define AES_TYPE_data Byte | ||
| 478 | |||
| 479 | #define AES_FUNC_START(name) \ | ||
| 480 | void MY_FAST_CALL name(UInt32 *p, Byte *data, size_t numBlocks) \ | ||
| 481 | |||
| 482 | #define AES_COMPAT_STUB(name) \ | ||
| 483 | AES_FUNC_START(name); \ | ||
| 484 | AES_FUNC_START(name ## _HW) \ | ||
| 485 | { name(p, data, numBlocks); } | ||
| 486 | |||
| 487 | AES_COMPAT_STUB (AesCbc_Encode) | ||
| 488 | AES_COMPAT_STUB (AesCbc_Decode) | ||
| 489 | AES_COMPAT_STUB (AesCtr_Code) | ||
| 490 | |||
| 491 | #endif // USE_INTEL_AES | ||
| 492 | |||
| 493 | |||
| 494 | #ifndef USE_INTEL_VAES | ||
| 495 | |||
| 496 | #pragma message("VAES HW_SW stub was used") | ||
| 497 | |||
| 498 | #define VAES_COMPAT_STUB(name) \ | ||
| 499 | void MY_FAST_CALL name ## _256(UInt32 *p, Byte *data, size_t numBlocks); \ | ||
| 500 | void MY_FAST_CALL name ## _256(UInt32 *p, Byte *data, size_t numBlocks) \ | ||
| 501 | { name((AES_TYPE_keys *)(void *)p, (AES_TYPE_data *)(void *)data, numBlocks); } | ||
| 502 | |||
| 503 | VAES_COMPAT_STUB (AesCbc_Decode_HW) | ||
| 504 | VAES_COMPAT_STUB (AesCtr_Code_HW) | ||
| 505 | |||
| 506 | #endif // ! USE_INTEL_VAES | ||
| 507 | |||
| 508 | |||
| 509 | #elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) | ||
| 510 | |||
| 511 | #if defined(__clang__) | ||
| 512 | #if (__clang_major__ >= 8) // fix that check | ||
| 513 | #define USE_HW_AES | ||
| 514 | #endif | ||
| 515 | #elif defined(__GNUC__) | ||
| 516 | #if (__GNUC__ >= 6) // fix that check | ||
| 517 | #define USE_HW_AES | ||
| 518 | #endif | ||
| 519 | #elif defined(_MSC_VER) | ||
| 520 | #if _MSC_VER >= 1910 | ||
| 521 | #define USE_HW_AES | ||
| 522 | #endif | ||
| 523 | #endif | ||
| 524 | |||
| 525 | #ifdef USE_HW_AES | ||
| 526 | |||
| 527 | // #pragma message("=== AES HW === ") | ||
| 528 | |||
| 529 | #if defined(__clang__) || defined(__GNUC__) | ||
| 530 | #ifdef MY_CPU_ARM64 | ||
| 531 | #define ATTRIB_AES __attribute__((__target__("+crypto"))) | ||
| 532 | #else | ||
| 533 | #define ATTRIB_AES __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) | ||
| 534 | #endif | ||
| 535 | #else | ||
| 536 | // _MSC_VER | ||
| 537 | // for arm32 | ||
| 538 | #define _ARM_USE_NEW_NEON_INTRINSICS | ||
| 539 | #endif | ||
| 540 | |||
| 541 | #ifndef ATTRIB_AES | ||
| 542 | #define ATTRIB_AES | ||
| 543 | #endif | ||
| 544 | |||
| 545 | #if defined(_MSC_VER) && defined(MY_CPU_ARM64) | ||
| 546 | #include <arm64_neon.h> | ||
| 547 | #else | ||
| 548 | #include <arm_neon.h> | ||
| 549 | #endif | ||
| 550 | |||
| 551 | typedef uint8x16_t v128; | ||
| 552 | |||
| 553 | #define AES_FUNC_START(name) \ | ||
| 554 | void MY_FAST_CALL name(v128 *p, v128 *data, size_t numBlocks) | ||
| 555 | |||
| 556 | #define AES_FUNC_START2(name) \ | ||
| 557 | AES_FUNC_START (name); \ | ||
| 558 | ATTRIB_AES \ | ||
| 559 | AES_FUNC_START (name) | ||
| 560 | |||
| 561 | #define MM_OP(op, dest, src) dest = op(dest, src); | ||
| 562 | #define MM_OP_m(op, src) MM_OP(op, m, src); | ||
| 563 | #define MM_OP1_m(op) m = op(m); | ||
| 564 | |||
| 565 | #define MM_XOR( dest, src) MM_OP(veorq_u8, dest, src); | ||
| 566 | #define MM_XOR_m( src) MM_XOR(m, src); | ||
| 567 | |||
| 568 | #define AES_E_m(k) MM_OP_m (vaeseq_u8, k); | ||
| 569 | #define AES_E_MC_m(k) AES_E_m (k); MM_OP1_m(vaesmcq_u8); | ||
| 570 | |||
| 571 | |||
| 572 | AES_FUNC_START2 (AesCbc_Encode_HW) | ||
| 573 | { | ||
| 574 | v128 m = *p; | ||
| 575 | const v128 k0 = p[2]; | ||
| 576 | const v128 k1 = p[3]; | ||
| 577 | const v128 k2 = p[4]; | ||
| 578 | const v128 k3 = p[5]; | ||
| 579 | const v128 k4 = p[6]; | ||
| 580 | const v128 k5 = p[7]; | ||
| 581 | const v128 k6 = p[8]; | ||
| 582 | const v128 k7 = p[9]; | ||
| 583 | const v128 k8 = p[10]; | ||
| 584 | const v128 k9 = p[11]; | ||
| 585 | const UInt32 numRounds2 = *(const UInt32 *)(p + 1); | ||
| 586 | const v128 *w = p + ((size_t)numRounds2 * 2); | ||
| 587 | const v128 k_z1 = w[1]; | ||
| 588 | const v128 k_z0 = w[2]; | ||
| 589 | for (; numBlocks != 0; numBlocks--, data++) | ||
| 590 | { | ||
| 591 | MM_XOR_m (*data); | ||
| 592 | AES_E_MC_m (k0) | ||
| 593 | AES_E_MC_m (k1) | ||
| 594 | AES_E_MC_m (k2) | ||
| 595 | AES_E_MC_m (k3) | ||
| 596 | AES_E_MC_m (k4) | ||
| 597 | AES_E_MC_m (k5) | ||
| 598 | AES_E_MC_m (k6) | ||
| 599 | AES_E_MC_m (k7) | ||
| 600 | AES_E_MC_m (k8) | ||
| 601 | if (numRounds2 >= 6) | ||
| 602 | { | ||
| 603 | AES_E_MC_m (k9) | ||
| 604 | AES_E_MC_m (p[12]) | ||
| 605 | if (numRounds2 != 6) | ||
| 606 | { | ||
| 607 | AES_E_MC_m (p[13]) | ||
| 608 | AES_E_MC_m (p[14]) | ||
| 609 | } | ||
| 610 | } | ||
| 611 | AES_E_m (k_z1); | ||
| 612 | MM_XOR_m (k_z0); | ||
| 613 | *data = m; | ||
| 614 | } | ||
| 615 | *p = m; | ||
| 616 | } | ||
| 617 | |||
| 618 | |||
| 619 | #define WOP_1(op) | ||
| 620 | #define WOP_2(op) WOP_1 (op) op (m1, 1); | ||
| 621 | #define WOP_3(op) WOP_2 (op) op (m2, 2); | ||
| 622 | #define WOP_4(op) WOP_3 (op) op (m3, 3); | ||
| 623 | #define WOP_5(op) WOP_4 (op) op (m4, 4); | ||
| 624 | #define WOP_6(op) WOP_5 (op) op (m5, 5); | ||
| 625 | #define WOP_7(op) WOP_6 (op) op (m6, 6); | ||
| 626 | #define WOP_8(op) WOP_7 (op) op (m7, 7); | ||
| 627 | |||
| 628 | #define NUM_WAYS 8 | ||
| 629 | #define WOP_M1 WOP_8 | ||
| 630 | |||
| 631 | #define WOP(op) op (m0, 0); WOP_M1(op) | ||
| 632 | |||
| 633 | #define DECLARE_VAR(reg, ii) v128 reg | ||
| 634 | #define LOAD_data( reg, ii) reg = data[ii]; | ||
| 635 | #define STORE_data( reg, ii) data[ii] = reg; | ||
| 636 | #if (NUM_WAYS > 1) | ||
| 637 | #define XOR_data_M1(reg, ii) MM_XOR (reg, data[ii- 1]); | ||
| 638 | #endif | ||
| 639 | |||
| 640 | #define MM_OP_key(op, reg) MM_OP (op, reg, key); | ||
| 641 | |||
| 642 | #define AES_D_m(k) MM_OP_m (vaesdq_u8, k); | ||
| 643 | #define AES_D_IMC_m(k) AES_D_m (k); MM_OP1_m (vaesimcq_u8); | ||
| 644 | |||
| 645 | #define AES_XOR( reg, ii) MM_OP_key (veorq_u8, reg) | ||
| 646 | #define AES_D( reg, ii) MM_OP_key (vaesdq_u8, reg) | ||
| 647 | #define AES_E( reg, ii) MM_OP_key (vaeseq_u8, reg) | ||
| 648 | |||
| 649 | #define AES_D_IMC( reg, ii) AES_D (reg, ii); reg = vaesimcq_u8(reg) | ||
| 650 | #define AES_E_MC( reg, ii) AES_E (reg, ii); reg = vaesmcq_u8(reg) | ||
| 651 | |||
| 652 | #define CTR_START(reg, ii) MM_OP (vaddq_u64, ctr, one); reg = vreinterpretq_u8_u64(ctr); | ||
| 653 | #define CTR_END( reg, ii) MM_XOR (data[ii], reg); | ||
| 654 | |||
| 655 | #define WOP_KEY(op, n) { \ | ||
| 656 | const v128 key = w[n]; \ | ||
| 657 | WOP(op); } | ||
| 658 | |||
| 659 | #define WIDE_LOOP_START \ | ||
| 660 | dataEnd = data + numBlocks; \ | ||
| 661 | if (numBlocks >= NUM_WAYS) \ | ||
| 662 | { dataEnd -= NUM_WAYS; do { \ | ||
| 663 | |||
| 664 | #define WIDE_LOOP_END \ | ||
| 665 | data += NUM_WAYS; \ | ||
| 666 | } while (data <= dataEnd); \ | ||
| 667 | dataEnd += NUM_WAYS; } \ | ||
| 668 | |||
| 669 | #define SINGLE_LOOP \ | ||
| 670 | for (; data < dataEnd; data++) | ||
| 671 | |||
| 672 | |||
| 673 | AES_FUNC_START2 (AesCbc_Decode_HW) | ||
| 674 | { | ||
| 675 | v128 iv = *p; | ||
| 676 | const v128 *wStart = p + ((size_t)*(const UInt32 *)(p + 1)) * 2; | ||
| 677 | const v128 *dataEnd; | ||
| 678 | p += 2; | ||
| 679 | |||
| 680 | WIDE_LOOP_START | ||
| 681 | { | ||
| 682 | const v128 *w = wStart; | ||
| 683 | WOP (DECLARE_VAR) | ||
| 684 | WOP (LOAD_data); | ||
| 685 | WOP_KEY (AES_D_IMC, 2) | ||
| 686 | do | ||
| 687 | { | ||
| 688 | WOP_KEY (AES_D_IMC, 1) | ||
| 689 | WOP_KEY (AES_D_IMC, 0) | ||
| 690 | w -= 2; | ||
| 691 | } | ||
| 692 | while (w != p); | ||
| 693 | WOP_KEY (AES_D, 1) | ||
| 694 | WOP_KEY (AES_XOR, 0) | ||
| 695 | MM_XOR (m0, iv); | ||
| 696 | WOP_M1 (XOR_data_M1) | ||
| 697 | iv = data[NUM_WAYS - 1]; | ||
| 698 | WOP (STORE_data); | ||
| 699 | } | ||
| 700 | WIDE_LOOP_END | ||
| 701 | |||
| 702 | SINGLE_LOOP | ||
| 703 | { | ||
| 704 | const v128 *w = wStart; | ||
| 705 | v128 m = *data; | ||
| 706 | AES_D_IMC_m (w[2]) | ||
| 707 | do | ||
| 708 | { | ||
| 709 | AES_D_IMC_m (w[1]); | ||
| 710 | AES_D_IMC_m (w[0]); | ||
| 711 | w -= 2; | ||
| 712 | } | ||
| 713 | while (w != p); | ||
| 714 | AES_D_m (w[1]); | ||
| 715 | MM_XOR_m (w[0]); | ||
| 716 | MM_XOR_m (iv); | ||
| 717 | iv = *data; | ||
| 718 | *data = m; | ||
| 719 | } | ||
| 720 | |||
| 721 | p[-2] = iv; | ||
| 722 | } | ||
| 723 | |||
| 724 | |||
| 725 | AES_FUNC_START2 (AesCtr_Code_HW) | ||
| 726 | { | ||
| 727 | uint64x2_t ctr = vreinterpretq_u64_u8(*p); | ||
| 728 | const v128 *wEnd = p + ((size_t)*(const UInt32 *)(p + 1)) * 2; | ||
| 729 | const v128 *dataEnd; | ||
| 730 | uint64x2_t one = vdupq_n_u64(0); | ||
| 731 | one = vsetq_lane_u64(1, one, 0); | ||
| 732 | p += 2; | ||
| 733 | |||
| 734 | WIDE_LOOP_START | ||
| 735 | { | ||
| 736 | const v128 *w = p; | ||
| 737 | WOP (DECLARE_VAR) | ||
| 738 | WOP (CTR_START); | ||
| 739 | do | ||
| 740 | { | ||
| 741 | WOP_KEY (AES_E_MC, 0) | ||
| 742 | WOP_KEY (AES_E_MC, 1) | ||
| 743 | w += 2; | ||
| 744 | } | ||
| 745 | while (w != wEnd); | ||
| 746 | WOP_KEY (AES_E_MC, 0) | ||
| 747 | WOP_KEY (AES_E, 1) | ||
| 748 | WOP_KEY (AES_XOR, 2) | ||
| 749 | WOP (CTR_END); | ||
| 750 | } | ||
| 751 | WIDE_LOOP_END | ||
| 752 | |||
| 753 | SINGLE_LOOP | ||
| 754 | { | ||
| 755 | const v128 *w = p; | ||
| 756 | v128 m; | ||
| 757 | CTR_START (m, 0); | ||
| 758 | do | ||
| 759 | { | ||
| 760 | AES_E_MC_m (w[0]); | ||
| 761 | AES_E_MC_m (w[1]); | ||
| 762 | w += 2; | ||
| 763 | } | ||
| 764 | while (w != wEnd); | ||
| 765 | AES_E_MC_m (w[0]); | ||
| 766 | AES_E_m (w[1]); | ||
| 767 | MM_XOR_m (w[2]); | ||
| 768 | CTR_END (m, 0); | ||
| 769 | } | ||
| 770 | |||
| 771 | p[-2] = vreinterpretq_u8_u64(ctr); | ||
| 772 | } | ||
| 773 | |||
| 774 | #endif // USE_HW_AES | ||
| 775 | |||
| 776 | #endif // MY_CPU_ARM_OR_ARM64 | ||
diff --git a/C/Alloc.c b/C/Alloc.c new file mode 100644 index 0000000..d1af76c --- /dev/null +++ b/C/Alloc.c | |||
| @@ -0,0 +1,463 @@ | |||
| 1 | /* Alloc.c -- Memory allocation functions | ||
| 2 | 2021-07-13 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <stdio.h> | ||
| 7 | |||
| 8 | #ifdef _WIN32 | ||
| 9 | #include <Windows.h> | ||
| 10 | #endif | ||
| 11 | #include <stdlib.h> | ||
| 12 | |||
| 13 | #include "Alloc.h" | ||
| 14 | |||
| 15 | /* #define _SZ_ALLOC_DEBUG */ | ||
| 16 | |||
| 17 | /* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ | ||
| 18 | #ifdef _SZ_ALLOC_DEBUG | ||
| 19 | |||
| 20 | #include <stdio.h> | ||
| 21 | int g_allocCount = 0; | ||
| 22 | int g_allocCountMid = 0; | ||
| 23 | int g_allocCountBig = 0; | ||
| 24 | |||
| 25 | |||
| 26 | #define CONVERT_INT_TO_STR(charType, tempSize) \ | ||
| 27 | unsigned char temp[tempSize]; unsigned i = 0; \ | ||
| 28 | while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \ | ||
| 29 | *s++ = (charType)('0' + (unsigned)val); \ | ||
| 30 | while (i != 0) { i--; *s++ = temp[i]; } \ | ||
| 31 | *s = 0; | ||
| 32 | |||
| 33 | static void ConvertUInt64ToString(UInt64 val, char *s) | ||
| 34 | { | ||
| 35 | CONVERT_INT_TO_STR(char, 24); | ||
| 36 | } | ||
| 37 | |||
| 38 | #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) | ||
| 39 | |||
| 40 | static void ConvertUInt64ToHex(UInt64 val, char *s) | ||
| 41 | { | ||
| 42 | UInt64 v = val; | ||
| 43 | unsigned i; | ||
| 44 | for (i = 1;; i++) | ||
| 45 | { | ||
| 46 | v >>= 4; | ||
| 47 | if (v == 0) | ||
| 48 | break; | ||
| 49 | } | ||
| 50 | s[i] = 0; | ||
| 51 | do | ||
| 52 | { | ||
| 53 | unsigned t = (unsigned)(val & 0xF); | ||
| 54 | val >>= 4; | ||
| 55 | s[--i] = GET_HEX_CHAR(t); | ||
| 56 | } | ||
| 57 | while (i); | ||
| 58 | } | ||
| 59 | |||
| 60 | #define DEBUG_OUT_STREAM stderr | ||
| 61 | |||
| 62 | static void Print(const char *s) | ||
| 63 | { | ||
| 64 | fputs(s, DEBUG_OUT_STREAM); | ||
| 65 | } | ||
| 66 | |||
| 67 | static void PrintAligned(const char *s, size_t align) | ||
| 68 | { | ||
| 69 | size_t len = strlen(s); | ||
| 70 | for(;;) | ||
| 71 | { | ||
| 72 | fputc(' ', DEBUG_OUT_STREAM); | ||
| 73 | if (len >= align) | ||
| 74 | break; | ||
| 75 | ++len; | ||
| 76 | } | ||
| 77 | Print(s); | ||
| 78 | } | ||
| 79 | |||
| 80 | static void PrintLn() | ||
| 81 | { | ||
| 82 | Print("\n"); | ||
| 83 | } | ||
| 84 | |||
| 85 | static void PrintHex(UInt64 v, size_t align) | ||
| 86 | { | ||
| 87 | char s[32]; | ||
| 88 | ConvertUInt64ToHex(v, s); | ||
| 89 | PrintAligned(s, align); | ||
| 90 | } | ||
| 91 | |||
| 92 | static void PrintDec(UInt64 v, size_t align) | ||
| 93 | { | ||
| 94 | char s[32]; | ||
| 95 | ConvertUInt64ToString(v, s); | ||
| 96 | PrintAligned(s, align); | ||
| 97 | } | ||
| 98 | |||
| 99 | static void PrintAddr(void *p) | ||
| 100 | { | ||
| 101 | PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12); | ||
| 102 | } | ||
| 103 | |||
| 104 | |||
| 105 | #define PRINT_ALLOC(name, cnt, size, ptr) \ | ||
| 106 | Print(name " "); \ | ||
| 107 | PrintDec(cnt++, 10); \ | ||
| 108 | PrintHex(size, 10); \ | ||
| 109 | PrintAddr(ptr); \ | ||
| 110 | PrintLn(); | ||
| 111 | |||
| 112 | #define PRINT_FREE(name, cnt, ptr) if (ptr) { \ | ||
| 113 | Print(name " "); \ | ||
| 114 | PrintDec(--cnt, 10); \ | ||
| 115 | PrintAddr(ptr); \ | ||
| 116 | PrintLn(); } | ||
| 117 | |||
| 118 | #else | ||
| 119 | |||
| 120 | #define PRINT_ALLOC(name, cnt, size, ptr) | ||
| 121 | #define PRINT_FREE(name, cnt, ptr) | ||
| 122 | #define Print(s) | ||
| 123 | #define PrintLn() | ||
| 124 | #define PrintHex(v, align) | ||
| 125 | #define PrintAddr(p) | ||
| 126 | |||
| 127 | #endif | ||
| 128 | |||
| 129 | |||
| 130 | |||
| 131 | void *MyAlloc(size_t size) | ||
| 132 | { | ||
| 133 | if (size == 0) | ||
| 134 | return NULL; | ||
| 135 | PRINT_ALLOC("Alloc ", g_allocCount, size, NULL); | ||
| 136 | #ifdef _SZ_ALLOC_DEBUG | ||
| 137 | { | ||
| 138 | void *p = malloc(size); | ||
| 139 | // PRINT_ALLOC("Alloc ", g_allocCount, size, p); | ||
| 140 | return p; | ||
| 141 | } | ||
| 142 | #else | ||
| 143 | return malloc(size); | ||
| 144 | #endif | ||
| 145 | } | ||
| 146 | |||
| 147 | void MyFree(void *address) | ||
| 148 | { | ||
| 149 | PRINT_FREE("Free ", g_allocCount, address); | ||
| 150 | |||
| 151 | free(address); | ||
| 152 | } | ||
| 153 | |||
| 154 | #ifdef _WIN32 | ||
| 155 | |||
| 156 | void *MidAlloc(size_t size) | ||
| 157 | { | ||
| 158 | if (size == 0) | ||
| 159 | return NULL; | ||
| 160 | |||
| 161 | PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, NULL); | ||
| 162 | |||
| 163 | return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); | ||
| 164 | } | ||
| 165 | |||
| 166 | void MidFree(void *address) | ||
| 167 | { | ||
| 168 | PRINT_FREE("Free-Mid", g_allocCountMid, address); | ||
| 169 | |||
| 170 | if (!address) | ||
| 171 | return; | ||
| 172 | VirtualFree(address, 0, MEM_RELEASE); | ||
| 173 | } | ||
| 174 | |||
| 175 | #ifdef _7ZIP_LARGE_PAGES | ||
| 176 | |||
| 177 | #ifdef MEM_LARGE_PAGES | ||
| 178 | #define MY__MEM_LARGE_PAGES MEM_LARGE_PAGES | ||
| 179 | #else | ||
| 180 | #define MY__MEM_LARGE_PAGES 0x20000000 | ||
| 181 | #endif | ||
| 182 | |||
| 183 | extern | ||
| 184 | SIZE_T g_LargePageSize; | ||
| 185 | SIZE_T g_LargePageSize = 0; | ||
| 186 | typedef SIZE_T (WINAPI *GetLargePageMinimumP)(VOID); | ||
| 187 | |||
| 188 | #endif // _7ZIP_LARGE_PAGES | ||
| 189 | |||
| 190 | void SetLargePageSize() | ||
| 191 | { | ||
| 192 | #ifdef _7ZIP_LARGE_PAGES | ||
| 193 | SIZE_T size; | ||
| 194 | GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP) | ||
| 195 | GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum"); | ||
| 196 | if (!largePageMinimum) | ||
| 197 | return; | ||
| 198 | size = largePageMinimum(); | ||
| 199 | if (size == 0 || (size & (size - 1)) != 0) | ||
| 200 | return; | ||
| 201 | g_LargePageSize = size; | ||
| 202 | #endif | ||
| 203 | } | ||
| 204 | |||
| 205 | |||
| 206 | void *BigAlloc(size_t size) | ||
| 207 | { | ||
| 208 | if (size == 0) | ||
| 209 | return NULL; | ||
| 210 | |||
| 211 | PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL); | ||
| 212 | |||
| 213 | #ifdef _7ZIP_LARGE_PAGES | ||
| 214 | { | ||
| 215 | SIZE_T ps = g_LargePageSize; | ||
| 216 | if (ps != 0 && ps <= (1 << 30) && size > (ps / 2)) | ||
| 217 | { | ||
| 218 | size_t size2; | ||
| 219 | ps--; | ||
| 220 | size2 = (size + ps) & ~ps; | ||
| 221 | if (size2 >= size) | ||
| 222 | { | ||
| 223 | void *res = VirtualAlloc(NULL, size2, MEM_COMMIT | MY__MEM_LARGE_PAGES, PAGE_READWRITE); | ||
| 224 | if (res) | ||
| 225 | return res; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | } | ||
| 229 | #endif | ||
| 230 | |||
| 231 | return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); | ||
| 232 | } | ||
| 233 | |||
| 234 | void BigFree(void *address) | ||
| 235 | { | ||
| 236 | PRINT_FREE("Free-Big", g_allocCountBig, address); | ||
| 237 | |||
| 238 | if (!address) | ||
| 239 | return; | ||
| 240 | VirtualFree(address, 0, MEM_RELEASE); | ||
| 241 | } | ||
| 242 | |||
| 243 | #endif | ||
| 244 | |||
| 245 | |||
| 246 | static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); } | ||
| 247 | static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MyFree(address); } | ||
| 248 | const ISzAlloc g_Alloc = { SzAlloc, SzFree }; | ||
| 249 | |||
| 250 | #ifdef _WIN32 | ||
| 251 | static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MidAlloc(size); } | ||
| 252 | static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MidFree(address); } | ||
| 253 | static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); } | ||
| 254 | static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); BigFree(address); } | ||
| 255 | const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree }; | ||
| 256 | const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; | ||
| 257 | #endif | ||
| 258 | |||
| 259 | /* | ||
| 260 | uintptr_t : <stdint.h> C99 (optional) | ||
| 261 | : unsupported in VS6 | ||
| 262 | */ | ||
| 263 | |||
| 264 | #ifdef _WIN32 | ||
| 265 | typedef UINT_PTR UIntPtr; | ||
| 266 | #else | ||
| 267 | /* | ||
| 268 | typedef uintptr_t UIntPtr; | ||
| 269 | */ | ||
| 270 | typedef ptrdiff_t UIntPtr; | ||
| 271 | #endif | ||
| 272 | |||
| 273 | |||
| 274 | #define ADJUST_ALLOC_SIZE 0 | ||
| 275 | /* | ||
| 276 | #define ADJUST_ALLOC_SIZE (sizeof(void *) - 1) | ||
| 277 | */ | ||
| 278 | /* | ||
| 279 | Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if | ||
| 280 | MyAlloc() can return address that is NOT multiple of sizeof(void *). | ||
| 281 | */ | ||
| 282 | |||
| 283 | |||
| 284 | /* | ||
| 285 | #define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1)))) | ||
| 286 | */ | ||
| 287 | #define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1)))) | ||
| 288 | |||
| 289 | |||
| 290 | #if !defined(_WIN32) && defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) | ||
| 291 | #define USE_posix_memalign | ||
| 292 | #endif | ||
| 293 | |||
| 294 | #ifndef USE_posix_memalign | ||
| 295 | #define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align) | ||
| 296 | #endif | ||
| 297 | |||
| 298 | /* | ||
| 299 | This posix_memalign() is for test purposes only. | ||
| 300 | We also need special Free() function instead of free(), | ||
| 301 | if this posix_memalign() is used. | ||
| 302 | */ | ||
| 303 | |||
| 304 | /* | ||
| 305 | static int posix_memalign(void **ptr, size_t align, size_t size) | ||
| 306 | { | ||
| 307 | size_t newSize = size + align; | ||
| 308 | void *p; | ||
| 309 | void *pAligned; | ||
| 310 | *ptr = NULL; | ||
| 311 | if (newSize < size) | ||
| 312 | return 12; // ENOMEM | ||
| 313 | p = MyAlloc(newSize); | ||
| 314 | if (!p) | ||
| 315 | return 12; // ENOMEM | ||
| 316 | pAligned = MY_ALIGN_PTR_UP_PLUS(p, align); | ||
| 317 | ((void **)pAligned)[-1] = p; | ||
| 318 | *ptr = pAligned; | ||
| 319 | return 0; | ||
| 320 | } | ||
| 321 | */ | ||
| 322 | |||
| 323 | /* | ||
| 324 | ALLOC_ALIGN_SIZE >= sizeof(void *) | ||
| 325 | ALLOC_ALIGN_SIZE >= cache_line_size | ||
| 326 | */ | ||
| 327 | |||
| 328 | #define ALLOC_ALIGN_SIZE ((size_t)1 << 7) | ||
| 329 | |||
| 330 | static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size) | ||
| 331 | { | ||
| 332 | #ifndef USE_posix_memalign | ||
| 333 | |||
| 334 | void *p; | ||
| 335 | void *pAligned; | ||
| 336 | size_t newSize; | ||
| 337 | UNUSED_VAR(pp); | ||
| 338 | |||
| 339 | /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned | ||
| 340 | block to prevent cache line sharing with another allocated blocks */ | ||
| 341 | |||
| 342 | newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE; | ||
| 343 | if (newSize < size) | ||
| 344 | return NULL; | ||
| 345 | |||
| 346 | p = MyAlloc(newSize); | ||
| 347 | |||
| 348 | if (!p) | ||
| 349 | return NULL; | ||
| 350 | pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE); | ||
| 351 | |||
| 352 | Print(" size="); PrintHex(size, 8); | ||
| 353 | Print(" a_size="); PrintHex(newSize, 8); | ||
| 354 | Print(" ptr="); PrintAddr(p); | ||
| 355 | Print(" a_ptr="); PrintAddr(pAligned); | ||
| 356 | PrintLn(); | ||
| 357 | |||
| 358 | ((void **)pAligned)[-1] = p; | ||
| 359 | |||
| 360 | return pAligned; | ||
| 361 | |||
| 362 | #else | ||
| 363 | |||
| 364 | void *p; | ||
| 365 | UNUSED_VAR(pp); | ||
| 366 | if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size)) | ||
| 367 | return NULL; | ||
| 368 | |||
| 369 | Print(" posix_memalign="); PrintAddr(p); | ||
| 370 | PrintLn(); | ||
| 371 | |||
| 372 | return p; | ||
| 373 | |||
| 374 | #endif | ||
| 375 | } | ||
| 376 | |||
| 377 | |||
| 378 | static void SzAlignedFree(ISzAllocPtr pp, void *address) | ||
| 379 | { | ||
| 380 | UNUSED_VAR(pp); | ||
| 381 | #ifndef USE_posix_memalign | ||
| 382 | if (address) | ||
| 383 | MyFree(((void **)address)[-1]); | ||
| 384 | #else | ||
| 385 | free(address); | ||
| 386 | #endif | ||
| 387 | } | ||
| 388 | |||
| 389 | |||
| 390 | const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree }; | ||
| 391 | |||
| 392 | |||
| 393 | |||
| 394 | #define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *)) | ||
| 395 | |||
| 396 | /* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */ | ||
| 397 | #define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1] | ||
| 398 | /* | ||
| 399 | #define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1] | ||
| 400 | */ | ||
| 401 | |||
| 402 | static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size) | ||
| 403 | { | ||
| 404 | CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt); | ||
| 405 | void *adr; | ||
| 406 | void *pAligned; | ||
| 407 | size_t newSize; | ||
| 408 | size_t extra; | ||
| 409 | size_t alignSize = (size_t)1 << p->numAlignBits; | ||
| 410 | |||
| 411 | if (alignSize < sizeof(void *)) | ||
| 412 | alignSize = sizeof(void *); | ||
| 413 | |||
| 414 | if (p->offset >= alignSize) | ||
| 415 | return NULL; | ||
| 416 | |||
| 417 | /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned | ||
| 418 | block to prevent cache line sharing with another allocated blocks */ | ||
| 419 | extra = p->offset & (sizeof(void *) - 1); | ||
| 420 | newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE; | ||
| 421 | if (newSize < size) | ||
| 422 | return NULL; | ||
| 423 | |||
| 424 | adr = ISzAlloc_Alloc(p->baseAlloc, newSize); | ||
| 425 | |||
| 426 | if (!adr) | ||
| 427 | return NULL; | ||
| 428 | |||
| 429 | pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr + | ||
| 430 | alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset; | ||
| 431 | |||
| 432 | PrintLn(); | ||
| 433 | Print("- Aligned: "); | ||
| 434 | Print(" size="); PrintHex(size, 8); | ||
| 435 | Print(" a_size="); PrintHex(newSize, 8); | ||
| 436 | Print(" ptr="); PrintAddr(adr); | ||
| 437 | Print(" a_ptr="); PrintAddr(pAligned); | ||
| 438 | PrintLn(); | ||
| 439 | |||
| 440 | REAL_BLOCK_PTR_VAR(pAligned) = adr; | ||
| 441 | |||
| 442 | return pAligned; | ||
| 443 | } | ||
| 444 | |||
| 445 | |||
| 446 | static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address) | ||
| 447 | { | ||
| 448 | if (address) | ||
| 449 | { | ||
| 450 | CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt); | ||
| 451 | PrintLn(); | ||
| 452 | Print("- Aligned Free: "); | ||
| 453 | PrintLn(); | ||
| 454 | ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address)); | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | |||
| 459 | void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p) | ||
| 460 | { | ||
| 461 | p->vt.Alloc = AlignOffsetAlloc_Alloc; | ||
| 462 | p->vt.Free = AlignOffsetAlloc_Free; | ||
| 463 | } | ||
diff --git a/C/Alloc.h b/C/Alloc.h new file mode 100644 index 0000000..3be2041 --- /dev/null +++ b/C/Alloc.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* Alloc.h -- Memory allocation functions | ||
| 2 | 2021-07-13 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __COMMON_ALLOC_H | ||
| 5 | #define __COMMON_ALLOC_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | void *MyAlloc(size_t size); | ||
| 12 | void MyFree(void *address); | ||
| 13 | |||
| 14 | #ifdef _WIN32 | ||
| 15 | |||
| 16 | void SetLargePageSize(void); | ||
| 17 | |||
| 18 | void *MidAlloc(size_t size); | ||
| 19 | void MidFree(void *address); | ||
| 20 | void *BigAlloc(size_t size); | ||
| 21 | void BigFree(void *address); | ||
| 22 | |||
| 23 | #else | ||
| 24 | |||
| 25 | #define MidAlloc(size) MyAlloc(size) | ||
| 26 | #define MidFree(address) MyFree(address) | ||
| 27 | #define BigAlloc(size) MyAlloc(size) | ||
| 28 | #define BigFree(address) MyFree(address) | ||
| 29 | |||
| 30 | #endif | ||
| 31 | |||
| 32 | extern const ISzAlloc g_Alloc; | ||
| 33 | |||
| 34 | #ifdef _WIN32 | ||
| 35 | extern const ISzAlloc g_BigAlloc; | ||
| 36 | extern const ISzAlloc g_MidAlloc; | ||
| 37 | #else | ||
| 38 | #define g_BigAlloc g_AlignedAlloc | ||
| 39 | #define g_MidAlloc g_AlignedAlloc | ||
| 40 | #endif | ||
| 41 | |||
| 42 | extern const ISzAlloc g_AlignedAlloc; | ||
| 43 | |||
| 44 | |||
| 45 | typedef struct | ||
| 46 | { | ||
| 47 | ISzAlloc vt; | ||
| 48 | ISzAllocPtr baseAlloc; | ||
| 49 | unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */ | ||
| 50 | size_t offset; /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */ | ||
| 51 | } CAlignOffsetAlloc; | ||
| 52 | |||
| 53 | void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p); | ||
| 54 | |||
| 55 | |||
| 56 | EXTERN_C_END | ||
| 57 | |||
| 58 | #endif | ||
diff --git a/C/Bcj2.c b/C/Bcj2.c new file mode 100644 index 0000000..c7b9567 --- /dev/null +++ b/C/Bcj2.c | |||
| @@ -0,0 +1,257 @@ | |||
| 1 | /* Bcj2.c -- BCJ2 Decoder (Converter for x86 code) | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "Bcj2.h" | ||
| 7 | #include "CpuArch.h" | ||
| 8 | |||
| 9 | #define CProb UInt16 | ||
| 10 | |||
| 11 | #define kTopValue ((UInt32)1 << 24) | ||
| 12 | #define kNumModelBits 11 | ||
| 13 | #define kBitModelTotal (1 << kNumModelBits) | ||
| 14 | #define kNumMoveBits 5 | ||
| 15 | |||
| 16 | #define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound) | ||
| 17 | #define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); | ||
| 18 | #define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); | ||
| 19 | |||
| 20 | void Bcj2Dec_Init(CBcj2Dec *p) | ||
| 21 | { | ||
| 22 | unsigned i; | ||
| 23 | |||
| 24 | p->state = BCJ2_DEC_STATE_OK; | ||
| 25 | p->ip = 0; | ||
| 26 | p->temp[3] = 0; | ||
| 27 | p->range = 0; | ||
| 28 | p->code = 0; | ||
| 29 | for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) | ||
| 30 | p->probs[i] = kBitModelTotal >> 1; | ||
| 31 | } | ||
| 32 | |||
| 33 | SRes Bcj2Dec_Decode(CBcj2Dec *p) | ||
| 34 | { | ||
| 35 | if (p->range <= 5) | ||
| 36 | { | ||
| 37 | p->state = BCJ2_DEC_STATE_OK; | ||
| 38 | for (; p->range != 5; p->range++) | ||
| 39 | { | ||
| 40 | if (p->range == 1 && p->code != 0) | ||
| 41 | return SZ_ERROR_DATA; | ||
| 42 | |||
| 43 | if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) | ||
| 44 | { | ||
| 45 | p->state = BCJ2_STREAM_RC; | ||
| 46 | return SZ_OK; | ||
| 47 | } | ||
| 48 | |||
| 49 | p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; | ||
| 50 | } | ||
| 51 | |||
| 52 | if (p->code == 0xFFFFFFFF) | ||
| 53 | return SZ_ERROR_DATA; | ||
| 54 | |||
| 55 | p->range = 0xFFFFFFFF; | ||
| 56 | } | ||
| 57 | else if (p->state >= BCJ2_DEC_STATE_ORIG_0) | ||
| 58 | { | ||
| 59 | while (p->state <= BCJ2_DEC_STATE_ORIG_3) | ||
| 60 | { | ||
| 61 | Byte *dest = p->dest; | ||
| 62 | if (dest == p->destLim) | ||
| 63 | return SZ_OK; | ||
| 64 | *dest = p->temp[(size_t)p->state - BCJ2_DEC_STATE_ORIG_0]; | ||
| 65 | p->state++; | ||
| 66 | p->dest = dest + 1; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | if (BCJ2_IS_32BIT_STREAM(p->state)) | ||
| 72 | { | ||
| 73 | const Byte *cur = p->bufs[p->state]; | ||
| 74 | if (cur == p->lims[p->state]) | ||
| 75 | return SZ_OK; | ||
| 76 | p->bufs[p->state] = cur + 4; | ||
| 77 | |||
| 78 | { | ||
| 79 | UInt32 val; | ||
| 80 | Byte *dest; | ||
| 81 | SizeT rem; | ||
| 82 | |||
| 83 | p->ip += 4; | ||
| 84 | val = GetBe32(cur) - p->ip; | ||
| 85 | dest = p->dest; | ||
| 86 | rem = p->destLim - dest; | ||
| 87 | if (rem < 4) | ||
| 88 | { | ||
| 89 | SizeT i; | ||
| 90 | SetUi32(p->temp, val); | ||
| 91 | for (i = 0; i < rem; i++) | ||
| 92 | dest[i] = p->temp[i]; | ||
| 93 | p->dest = dest + rem; | ||
| 94 | p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; | ||
| 95 | return SZ_OK; | ||
| 96 | } | ||
| 97 | SetUi32(dest, val); | ||
| 98 | p->temp[3] = (Byte)(val >> 24); | ||
| 99 | p->dest = dest + 4; | ||
| 100 | p->state = BCJ2_DEC_STATE_OK; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | */ | ||
| 104 | |||
| 105 | for (;;) | ||
| 106 | { | ||
| 107 | if (BCJ2_IS_32BIT_STREAM(p->state)) | ||
| 108 | p->state = BCJ2_DEC_STATE_OK; | ||
| 109 | else | ||
| 110 | { | ||
| 111 | if (p->range < kTopValue) | ||
| 112 | { | ||
| 113 | if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) | ||
| 114 | { | ||
| 115 | p->state = BCJ2_STREAM_RC; | ||
| 116 | return SZ_OK; | ||
| 117 | } | ||
| 118 | p->range <<= 8; | ||
| 119 | p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; | ||
| 120 | } | ||
| 121 | |||
| 122 | { | ||
| 123 | const Byte *src = p->bufs[BCJ2_STREAM_MAIN]; | ||
| 124 | const Byte *srcLim; | ||
| 125 | Byte *dest; | ||
| 126 | SizeT num = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - src); | ||
| 127 | |||
| 128 | if (num == 0) | ||
| 129 | { | ||
| 130 | p->state = BCJ2_STREAM_MAIN; | ||
| 131 | return SZ_OK; | ||
| 132 | } | ||
| 133 | |||
| 134 | dest = p->dest; | ||
| 135 | if (num > (SizeT)(p->destLim - dest)) | ||
| 136 | { | ||
| 137 | num = (SizeT)(p->destLim - dest); | ||
| 138 | if (num == 0) | ||
| 139 | { | ||
| 140 | p->state = BCJ2_DEC_STATE_ORIG; | ||
| 141 | return SZ_OK; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | srcLim = src + num; | ||
| 146 | |||
| 147 | if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80) | ||
| 148 | *dest = src[0]; | ||
| 149 | else for (;;) | ||
| 150 | { | ||
| 151 | Byte b = *src; | ||
| 152 | *dest = b; | ||
| 153 | if (b != 0x0F) | ||
| 154 | { | ||
| 155 | if ((b & 0xFE) == 0xE8) | ||
| 156 | break; | ||
| 157 | dest++; | ||
| 158 | if (++src != srcLim) | ||
| 159 | continue; | ||
| 160 | break; | ||
| 161 | } | ||
| 162 | dest++; | ||
| 163 | if (++src == srcLim) | ||
| 164 | break; | ||
| 165 | if ((*src & 0xF0) != 0x80) | ||
| 166 | continue; | ||
| 167 | *dest = *src; | ||
| 168 | break; | ||
| 169 | } | ||
| 170 | |||
| 171 | num = (SizeT)(src - p->bufs[BCJ2_STREAM_MAIN]); | ||
| 172 | |||
| 173 | if (src == srcLim) | ||
| 174 | { | ||
| 175 | p->temp[3] = src[-1]; | ||
| 176 | p->bufs[BCJ2_STREAM_MAIN] = src; | ||
| 177 | p->ip += (UInt32)num; | ||
| 178 | p->dest += num; | ||
| 179 | p->state = | ||
| 180 | p->bufs[BCJ2_STREAM_MAIN] == | ||
| 181 | p->lims[BCJ2_STREAM_MAIN] ? | ||
| 182 | (unsigned)BCJ2_STREAM_MAIN : | ||
| 183 | (unsigned)BCJ2_DEC_STATE_ORIG; | ||
| 184 | return SZ_OK; | ||
| 185 | } | ||
| 186 | |||
| 187 | { | ||
| 188 | UInt32 bound, ttt; | ||
| 189 | CProb *prob; | ||
| 190 | Byte b = src[0]; | ||
| 191 | Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]); | ||
| 192 | |||
| 193 | p->temp[3] = b; | ||
| 194 | p->bufs[BCJ2_STREAM_MAIN] = src + 1; | ||
| 195 | num++; | ||
| 196 | p->ip += (UInt32)num; | ||
| 197 | p->dest += num; | ||
| 198 | |||
| 199 | prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0)); | ||
| 200 | |||
| 201 | _IF_BIT_0 | ||
| 202 | { | ||
| 203 | _UPDATE_0 | ||
| 204 | continue; | ||
| 205 | } | ||
| 206 | _UPDATE_1 | ||
| 207 | |||
| 208 | } | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | { | ||
| 213 | UInt32 val; | ||
| 214 | unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; | ||
| 215 | const Byte *cur = p->bufs[cj]; | ||
| 216 | Byte *dest; | ||
| 217 | SizeT rem; | ||
| 218 | |||
| 219 | if (cur == p->lims[cj]) | ||
| 220 | { | ||
| 221 | p->state = cj; | ||
| 222 | break; | ||
| 223 | } | ||
| 224 | |||
| 225 | val = GetBe32(cur); | ||
| 226 | p->bufs[cj] = cur + 4; | ||
| 227 | |||
| 228 | p->ip += 4; | ||
| 229 | val -= p->ip; | ||
| 230 | dest = p->dest; | ||
| 231 | rem = (SizeT)(p->destLim - dest); | ||
| 232 | |||
| 233 | if (rem < 4) | ||
| 234 | { | ||
| 235 | p->temp[0] = (Byte)val; if (rem > 0) dest[0] = (Byte)val; val >>= 8; | ||
| 236 | p->temp[1] = (Byte)val; if (rem > 1) dest[1] = (Byte)val; val >>= 8; | ||
| 237 | p->temp[2] = (Byte)val; if (rem > 2) dest[2] = (Byte)val; val >>= 8; | ||
| 238 | p->temp[3] = (Byte)val; | ||
| 239 | p->dest = dest + rem; | ||
| 240 | p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; | ||
| 241 | break; | ||
| 242 | } | ||
| 243 | |||
| 244 | SetUi32(dest, val); | ||
| 245 | p->temp[3] = (Byte)(val >> 24); | ||
| 246 | p->dest = dest + 4; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC]) | ||
| 251 | { | ||
| 252 | p->range <<= 8; | ||
| 253 | p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; | ||
| 254 | } | ||
| 255 | |||
| 256 | return SZ_OK; | ||
| 257 | } | ||
diff --git a/C/Bcj2.h b/C/Bcj2.h new file mode 100644 index 0000000..8824080 --- /dev/null +++ b/C/Bcj2.h | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | /* Bcj2.h -- BCJ2 Converter for x86 code | ||
| 2 | 2014-11-10 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __BCJ2_H | ||
| 5 | #define __BCJ2_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define BCJ2_NUM_STREAMS 4 | ||
| 12 | |||
| 13 | enum | ||
| 14 | { | ||
| 15 | BCJ2_STREAM_MAIN, | ||
| 16 | BCJ2_STREAM_CALL, | ||
| 17 | BCJ2_STREAM_JUMP, | ||
| 18 | BCJ2_STREAM_RC | ||
| 19 | }; | ||
| 20 | |||
| 21 | enum | ||
| 22 | { | ||
| 23 | BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS, | ||
| 24 | BCJ2_DEC_STATE_ORIG_1, | ||
| 25 | BCJ2_DEC_STATE_ORIG_2, | ||
| 26 | BCJ2_DEC_STATE_ORIG_3, | ||
| 27 | |||
| 28 | BCJ2_DEC_STATE_ORIG, | ||
| 29 | BCJ2_DEC_STATE_OK | ||
| 30 | }; | ||
| 31 | |||
| 32 | enum | ||
| 33 | { | ||
| 34 | BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, | ||
| 35 | BCJ2_ENC_STATE_OK | ||
| 36 | }; | ||
| 37 | |||
| 38 | |||
| 39 | #define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) | ||
| 40 | |||
| 41 | /* | ||
| 42 | CBcj2Dec / CBcj2Enc | ||
| 43 | bufs sizes: | ||
| 44 | BUF_SIZE(n) = lims[n] - bufs[n] | ||
| 45 | bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4: | ||
| 46 | (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0 | ||
| 47 | (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0 | ||
| 48 | */ | ||
| 49 | |||
| 50 | /* | ||
| 51 | CBcj2Dec: | ||
| 52 | dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions: | ||
| 53 | bufs[BCJ2_STREAM_MAIN] >= dest && | ||
| 54 | bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv + | ||
| 55 | BUF_SIZE(BCJ2_STREAM_CALL) + | ||
| 56 | BUF_SIZE(BCJ2_STREAM_JUMP) | ||
| 57 | tempReserv = 0 : for first call of Bcj2Dec_Decode | ||
| 58 | tempReserv = 4 : for any other calls of Bcj2Dec_Decode | ||
| 59 | overlap with offset = 1 is not allowed | ||
| 60 | */ | ||
| 61 | |||
| 62 | typedef struct | ||
| 63 | { | ||
| 64 | const Byte *bufs[BCJ2_NUM_STREAMS]; | ||
| 65 | const Byte *lims[BCJ2_NUM_STREAMS]; | ||
| 66 | Byte *dest; | ||
| 67 | const Byte *destLim; | ||
| 68 | |||
| 69 | unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ | ||
| 70 | |||
| 71 | UInt32 ip; | ||
| 72 | Byte temp[4]; | ||
| 73 | UInt32 range; | ||
| 74 | UInt32 code; | ||
| 75 | UInt16 probs[2 + 256]; | ||
| 76 | } CBcj2Dec; | ||
| 77 | |||
| 78 | void Bcj2Dec_Init(CBcj2Dec *p); | ||
| 79 | |||
| 80 | /* Returns: SZ_OK or SZ_ERROR_DATA */ | ||
| 81 | SRes Bcj2Dec_Decode(CBcj2Dec *p); | ||
| 82 | |||
| 83 | #define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0) | ||
| 84 | |||
| 85 | |||
| 86 | |||
| 87 | typedef enum | ||
| 88 | { | ||
| 89 | BCJ2_ENC_FINISH_MODE_CONTINUE, | ||
| 90 | BCJ2_ENC_FINISH_MODE_END_BLOCK, | ||
| 91 | BCJ2_ENC_FINISH_MODE_END_STREAM | ||
| 92 | } EBcj2Enc_FinishMode; | ||
| 93 | |||
| 94 | typedef struct | ||
| 95 | { | ||
| 96 | Byte *bufs[BCJ2_NUM_STREAMS]; | ||
| 97 | const Byte *lims[BCJ2_NUM_STREAMS]; | ||
| 98 | const Byte *src; | ||
| 99 | const Byte *srcLim; | ||
| 100 | |||
| 101 | unsigned state; | ||
| 102 | EBcj2Enc_FinishMode finishMode; | ||
| 103 | |||
| 104 | Byte prevByte; | ||
| 105 | |||
| 106 | Byte cache; | ||
| 107 | UInt32 range; | ||
| 108 | UInt64 low; | ||
| 109 | UInt64 cacheSize; | ||
| 110 | |||
| 111 | UInt32 ip; | ||
| 112 | |||
| 113 | /* 32-bit ralative offset in JUMP/CALL commands is | ||
| 114 | - (mod 4 GB) in 32-bit mode | ||
| 115 | - signed Int32 in 64-bit mode | ||
| 116 | We use (mod 4 GB) check for fileSize. | ||
| 117 | Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */ | ||
| 118 | UInt32 fileIp; | ||
| 119 | UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */ | ||
| 120 | UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */ | ||
| 121 | |||
| 122 | UInt32 tempTarget; | ||
| 123 | unsigned tempPos; | ||
| 124 | Byte temp[4 * 2]; | ||
| 125 | |||
| 126 | unsigned flushPos; | ||
| 127 | |||
| 128 | UInt16 probs[2 + 256]; | ||
| 129 | } CBcj2Enc; | ||
| 130 | |||
| 131 | void Bcj2Enc_Init(CBcj2Enc *p); | ||
| 132 | void Bcj2Enc_Encode(CBcj2Enc *p); | ||
| 133 | |||
| 134 | #define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos) | ||
| 135 | #define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5) | ||
| 136 | |||
| 137 | |||
| 138 | #define BCJ2_RELAT_LIMIT_NUM_BITS 26 | ||
| 139 | #define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS) | ||
| 140 | |||
| 141 | /* limit for CBcj2Enc::fileSize variable */ | ||
| 142 | #define BCJ2_FileSize_MAX ((UInt32)1 << 31) | ||
| 143 | |||
| 144 | EXTERN_C_END | ||
| 145 | |||
| 146 | #endif | ||
diff --git a/C/Bcj2Enc.c b/C/Bcj2Enc.c new file mode 100644 index 0000000..682362a --- /dev/null +++ b/C/Bcj2Enc.c | |||
| @@ -0,0 +1,311 @@ | |||
| 1 | /* Bcj2Enc.c -- BCJ2 Encoder (Converter for x86 code) | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | /* #define SHOW_STAT */ | ||
| 7 | |||
| 8 | #ifdef SHOW_STAT | ||
| 9 | #include <stdio.h> | ||
| 10 | #define PRF(x) x | ||
| 11 | #else | ||
| 12 | #define PRF(x) | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #include <string.h> | ||
| 16 | |||
| 17 | #include "Bcj2.h" | ||
| 18 | #include "CpuArch.h" | ||
| 19 | |||
| 20 | #define CProb UInt16 | ||
| 21 | |||
| 22 | #define kTopValue ((UInt32)1 << 24) | ||
| 23 | #define kNumModelBits 11 | ||
| 24 | #define kBitModelTotal (1 << kNumModelBits) | ||
| 25 | #define kNumMoveBits 5 | ||
| 26 | |||
| 27 | void Bcj2Enc_Init(CBcj2Enc *p) | ||
| 28 | { | ||
| 29 | unsigned i; | ||
| 30 | |||
| 31 | p->state = BCJ2_ENC_STATE_OK; | ||
| 32 | p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; | ||
| 33 | |||
| 34 | p->prevByte = 0; | ||
| 35 | |||
| 36 | p->cache = 0; | ||
| 37 | p->range = 0xFFFFFFFF; | ||
| 38 | p->low = 0; | ||
| 39 | p->cacheSize = 1; | ||
| 40 | |||
| 41 | p->ip = 0; | ||
| 42 | |||
| 43 | p->fileIp = 0; | ||
| 44 | p->fileSize = 0; | ||
| 45 | p->relatLimit = BCJ2_RELAT_LIMIT; | ||
| 46 | |||
| 47 | p->tempPos = 0; | ||
| 48 | |||
| 49 | p->flushPos = 0; | ||
| 50 | |||
| 51 | for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) | ||
| 52 | p->probs[i] = kBitModelTotal >> 1; | ||
| 53 | } | ||
| 54 | |||
| 55 | static BoolInt MY_FAST_CALL RangeEnc_ShiftLow(CBcj2Enc *p) | ||
| 56 | { | ||
| 57 | if ((UInt32)p->low < (UInt32)0xFF000000 || (UInt32)(p->low >> 32) != 0) | ||
| 58 | { | ||
| 59 | Byte *buf = p->bufs[BCJ2_STREAM_RC]; | ||
| 60 | do | ||
| 61 | { | ||
| 62 | if (buf == p->lims[BCJ2_STREAM_RC]) | ||
| 63 | { | ||
| 64 | p->state = BCJ2_STREAM_RC; | ||
| 65 | p->bufs[BCJ2_STREAM_RC] = buf; | ||
| 66 | return True; | ||
| 67 | } | ||
| 68 | *buf++ = (Byte)(p->cache + (Byte)(p->low >> 32)); | ||
| 69 | p->cache = 0xFF; | ||
| 70 | } | ||
| 71 | while (--p->cacheSize); | ||
| 72 | p->bufs[BCJ2_STREAM_RC] = buf; | ||
| 73 | p->cache = (Byte)((UInt32)p->low >> 24); | ||
| 74 | } | ||
| 75 | p->cacheSize++; | ||
| 76 | p->low = (UInt32)p->low << 8; | ||
| 77 | return False; | ||
| 78 | } | ||
| 79 | |||
| 80 | static void Bcj2Enc_Encode_2(CBcj2Enc *p) | ||
| 81 | { | ||
| 82 | if (BCJ2_IS_32BIT_STREAM(p->state)) | ||
| 83 | { | ||
| 84 | Byte *cur = p->bufs[p->state]; | ||
| 85 | if (cur == p->lims[p->state]) | ||
| 86 | return; | ||
| 87 | SetBe32(cur, p->tempTarget); | ||
| 88 | p->bufs[p->state] = cur + 4; | ||
| 89 | } | ||
| 90 | |||
| 91 | p->state = BCJ2_ENC_STATE_ORIG; | ||
| 92 | |||
| 93 | for (;;) | ||
| 94 | { | ||
| 95 | if (p->range < kTopValue) | ||
| 96 | { | ||
| 97 | if (RangeEnc_ShiftLow(p)) | ||
| 98 | return; | ||
| 99 | p->range <<= 8; | ||
| 100 | } | ||
| 101 | |||
| 102 | { | ||
| 103 | { | ||
| 104 | const Byte *src = p->src; | ||
| 105 | const Byte *srcLim; | ||
| 106 | Byte *dest; | ||
| 107 | SizeT num = (SizeT)(p->srcLim - src); | ||
| 108 | |||
| 109 | if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE) | ||
| 110 | { | ||
| 111 | if (num <= 4) | ||
| 112 | return; | ||
| 113 | num -= 4; | ||
| 114 | } | ||
| 115 | else if (num == 0) | ||
| 116 | break; | ||
| 117 | |||
| 118 | dest = p->bufs[BCJ2_STREAM_MAIN]; | ||
| 119 | if (num > (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest)) | ||
| 120 | { | ||
| 121 | num = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest); | ||
| 122 | if (num == 0) | ||
| 123 | { | ||
| 124 | p->state = BCJ2_STREAM_MAIN; | ||
| 125 | return; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | srcLim = src + num; | ||
| 130 | |||
| 131 | if (p->prevByte == 0x0F && (src[0] & 0xF0) == 0x80) | ||
| 132 | *dest = src[0]; | ||
| 133 | else for (;;) | ||
| 134 | { | ||
| 135 | Byte b = *src; | ||
| 136 | *dest = b; | ||
| 137 | if (b != 0x0F) | ||
| 138 | { | ||
| 139 | if ((b & 0xFE) == 0xE8) | ||
| 140 | break; | ||
| 141 | dest++; | ||
| 142 | if (++src != srcLim) | ||
| 143 | continue; | ||
| 144 | break; | ||
| 145 | } | ||
| 146 | dest++; | ||
| 147 | if (++src == srcLim) | ||
| 148 | break; | ||
| 149 | if ((*src & 0xF0) != 0x80) | ||
| 150 | continue; | ||
| 151 | *dest = *src; | ||
| 152 | break; | ||
| 153 | } | ||
| 154 | |||
| 155 | num = (SizeT)(src - p->src); | ||
| 156 | |||
| 157 | if (src == srcLim) | ||
| 158 | { | ||
| 159 | p->prevByte = src[-1]; | ||
| 160 | p->bufs[BCJ2_STREAM_MAIN] = dest; | ||
| 161 | p->src = src; | ||
| 162 | p->ip += (UInt32)num; | ||
| 163 | continue; | ||
| 164 | } | ||
| 165 | |||
| 166 | { | ||
| 167 | Byte context = (Byte)(num == 0 ? p->prevByte : src[-1]); | ||
| 168 | BoolInt needConvert; | ||
| 169 | |||
| 170 | p->bufs[BCJ2_STREAM_MAIN] = dest + 1; | ||
| 171 | p->ip += (UInt32)num + 1; | ||
| 172 | src++; | ||
| 173 | |||
| 174 | needConvert = False; | ||
| 175 | |||
| 176 | if ((SizeT)(p->srcLim - src) >= 4) | ||
| 177 | { | ||
| 178 | UInt32 relatVal = GetUi32(src); | ||
| 179 | if ((p->fileSize == 0 || (UInt32)(p->ip + 4 + relatVal - p->fileIp) < p->fileSize) | ||
| 180 | && ((relatVal + p->relatLimit) >> 1) < p->relatLimit) | ||
| 181 | needConvert = True; | ||
| 182 | } | ||
| 183 | |||
| 184 | { | ||
| 185 | UInt32 bound; | ||
| 186 | unsigned ttt; | ||
| 187 | Byte b = src[-1]; | ||
| 188 | CProb *prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)context : (b == 0xE9 ? 1 : 0)); | ||
| 189 | |||
| 190 | ttt = *prob; | ||
| 191 | bound = (p->range >> kNumModelBits) * ttt; | ||
| 192 | |||
| 193 | if (!needConvert) | ||
| 194 | { | ||
| 195 | p->range = bound; | ||
| 196 | *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); | ||
| 197 | p->src = src; | ||
| 198 | p->prevByte = b; | ||
| 199 | continue; | ||
| 200 | } | ||
| 201 | |||
| 202 | p->low += bound; | ||
| 203 | p->range -= bound; | ||
| 204 | *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); | ||
| 205 | |||
| 206 | { | ||
| 207 | UInt32 relatVal = GetUi32(src); | ||
| 208 | UInt32 absVal; | ||
| 209 | p->ip += 4; | ||
| 210 | absVal = p->ip + relatVal; | ||
| 211 | p->prevByte = src[3]; | ||
| 212 | src += 4; | ||
| 213 | p->src = src; | ||
| 214 | { | ||
| 215 | unsigned cj = (b == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; | ||
| 216 | Byte *cur = p->bufs[cj]; | ||
| 217 | if (cur == p->lims[cj]) | ||
| 218 | { | ||
| 219 | p->state = cj; | ||
| 220 | p->tempTarget = absVal; | ||
| 221 | return; | ||
| 222 | } | ||
| 223 | SetBe32(cur, absVal); | ||
| 224 | p->bufs[cj] = cur + 4; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | } | ||
| 229 | } | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM) | ||
| 234 | return; | ||
| 235 | |||
| 236 | for (; p->flushPos < 5; p->flushPos++) | ||
| 237 | if (RangeEnc_ShiftLow(p)) | ||
| 238 | return; | ||
| 239 | p->state = BCJ2_ENC_STATE_OK; | ||
| 240 | } | ||
| 241 | |||
| 242 | |||
| 243 | void Bcj2Enc_Encode(CBcj2Enc *p) | ||
| 244 | { | ||
| 245 | PRF(printf("\n")); | ||
| 246 | PRF(printf("---- ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); | ||
| 247 | |||
| 248 | if (p->tempPos != 0) | ||
| 249 | { | ||
| 250 | unsigned extra = 0; | ||
| 251 | |||
| 252 | for (;;) | ||
| 253 | { | ||
| 254 | const Byte *src = p->src; | ||
| 255 | const Byte *srcLim = p->srcLim; | ||
| 256 | EBcj2Enc_FinishMode finishMode = p->finishMode; | ||
| 257 | |||
| 258 | p->src = p->temp; | ||
| 259 | p->srcLim = p->temp + p->tempPos; | ||
| 260 | if (src != srcLim) | ||
| 261 | p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; | ||
| 262 | |||
| 263 | PRF(printf(" ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); | ||
| 264 | |||
| 265 | Bcj2Enc_Encode_2(p); | ||
| 266 | |||
| 267 | { | ||
| 268 | unsigned num = (unsigned)(p->src - p->temp); | ||
| 269 | unsigned tempPos = p->tempPos - num; | ||
| 270 | unsigned i; | ||
| 271 | p->tempPos = tempPos; | ||
| 272 | for (i = 0; i < tempPos; i++) | ||
| 273 | p->temp[i] = p->temp[(size_t)i + num]; | ||
| 274 | |||
| 275 | p->src = src; | ||
| 276 | p->srcLim = srcLim; | ||
| 277 | p->finishMode = finishMode; | ||
| 278 | |||
| 279 | if (p->state != BCJ2_ENC_STATE_ORIG || src == srcLim) | ||
| 280 | return; | ||
| 281 | |||
| 282 | if (extra >= tempPos) | ||
| 283 | { | ||
| 284 | p->src = src - tempPos; | ||
| 285 | p->tempPos = 0; | ||
| 286 | break; | ||
| 287 | } | ||
| 288 | |||
| 289 | p->temp[tempPos] = src[0]; | ||
| 290 | p->tempPos = tempPos + 1; | ||
| 291 | p->src = src + 1; | ||
| 292 | extra++; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | PRF(printf("++++ ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); | ||
| 298 | |||
| 299 | Bcj2Enc_Encode_2(p); | ||
| 300 | |||
| 301 | if (p->state == BCJ2_ENC_STATE_ORIG) | ||
| 302 | { | ||
| 303 | const Byte *src = p->src; | ||
| 304 | unsigned rem = (unsigned)(p->srcLim - src); | ||
| 305 | unsigned i; | ||
| 306 | for (i = 0; i < rem; i++) | ||
| 307 | p->temp[i] = src[i]; | ||
| 308 | p->tempPos = rem; | ||
| 309 | p->src = src + rem; | ||
| 310 | } | ||
| 311 | } | ||
diff --git a/C/Blake2.h b/C/Blake2.h new file mode 100644 index 0000000..14f3cb6 --- /dev/null +++ b/C/Blake2.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | /* Blake2.h -- BLAKE2 Hash | ||
| 2 | 2015-06-30 : Igor Pavlov : Public domain | ||
| 3 | 2015 : Samuel Neves : Public domain */ | ||
| 4 | |||
| 5 | #ifndef __BLAKE2_H | ||
| 6 | #define __BLAKE2_H | ||
| 7 | |||
| 8 | #include "7zTypes.h" | ||
| 9 | |||
| 10 | EXTERN_C_BEGIN | ||
| 11 | |||
| 12 | #define BLAKE2S_BLOCK_SIZE 64 | ||
| 13 | #define BLAKE2S_DIGEST_SIZE 32 | ||
| 14 | #define BLAKE2SP_PARALLEL_DEGREE 8 | ||
| 15 | |||
| 16 | typedef struct | ||
| 17 | { | ||
| 18 | UInt32 h[8]; | ||
| 19 | UInt32 t[2]; | ||
| 20 | UInt32 f[2]; | ||
| 21 | Byte buf[BLAKE2S_BLOCK_SIZE]; | ||
| 22 | UInt32 bufPos; | ||
| 23 | UInt32 lastNode_f1; | ||
| 24 | UInt32 dummy[2]; /* for sizeof(CBlake2s) alignment */ | ||
| 25 | } CBlake2s; | ||
| 26 | |||
| 27 | /* You need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() */ | ||
| 28 | /* | ||
| 29 | void Blake2s_Init0(CBlake2s *p); | ||
| 30 | void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size); | ||
| 31 | void Blake2s_Final(CBlake2s *p, Byte *digest); | ||
| 32 | */ | ||
| 33 | |||
| 34 | |||
| 35 | typedef struct | ||
| 36 | { | ||
| 37 | CBlake2s S[BLAKE2SP_PARALLEL_DEGREE]; | ||
| 38 | unsigned bufPos; | ||
| 39 | } CBlake2sp; | ||
| 40 | |||
| 41 | |||
| 42 | void Blake2sp_Init(CBlake2sp *p); | ||
| 43 | void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size); | ||
| 44 | void Blake2sp_Final(CBlake2sp *p, Byte *digest); | ||
| 45 | |||
| 46 | EXTERN_C_END | ||
| 47 | |||
| 48 | #endif | ||
diff --git a/C/Blake2s.c b/C/Blake2s.c new file mode 100644 index 0000000..3c56a8b --- /dev/null +++ b/C/Blake2s.c | |||
| @@ -0,0 +1,244 @@ | |||
| 1 | /* Blake2s.c -- BLAKE2s and BLAKE2sp Hash | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain | ||
| 3 | 2015 : Samuel Neves : Public domain */ | ||
| 4 | |||
| 5 | #include <string.h> | ||
| 6 | |||
| 7 | #include "Blake2.h" | ||
| 8 | #include "CpuArch.h" | ||
| 9 | #include "RotateDefs.h" | ||
| 10 | |||
| 11 | #define rotr32 rotrFixed | ||
| 12 | |||
| 13 | #define BLAKE2S_NUM_ROUNDS 10 | ||
| 14 | #define BLAKE2S_FINAL_FLAG (~(UInt32)0) | ||
| 15 | |||
| 16 | static const UInt32 k_Blake2s_IV[8] = | ||
| 17 | { | ||
| 18 | 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, | ||
| 19 | 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL | ||
| 20 | }; | ||
| 21 | |||
| 22 | static const Byte k_Blake2s_Sigma[BLAKE2S_NUM_ROUNDS][16] = | ||
| 23 | { | ||
| 24 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , | ||
| 25 | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , | ||
| 26 | { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , | ||
| 27 | { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , | ||
| 28 | { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , | ||
| 29 | { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , | ||
| 30 | { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , | ||
| 31 | { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , | ||
| 32 | { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , | ||
| 33 | { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , | ||
| 34 | }; | ||
| 35 | |||
| 36 | |||
| 37 | static void Blake2s_Init0(CBlake2s *p) | ||
| 38 | { | ||
| 39 | unsigned i; | ||
| 40 | for (i = 0; i < 8; i++) | ||
| 41 | p->h[i] = k_Blake2s_IV[i]; | ||
| 42 | p->t[0] = 0; | ||
| 43 | p->t[1] = 0; | ||
| 44 | p->f[0] = 0; | ||
| 45 | p->f[1] = 0; | ||
| 46 | p->bufPos = 0; | ||
| 47 | p->lastNode_f1 = 0; | ||
| 48 | } | ||
| 49 | |||
| 50 | |||
| 51 | static void Blake2s_Compress(CBlake2s *p) | ||
| 52 | { | ||
| 53 | UInt32 m[16]; | ||
| 54 | UInt32 v[16]; | ||
| 55 | |||
| 56 | { | ||
| 57 | unsigned i; | ||
| 58 | |||
| 59 | for (i = 0; i < 16; i++) | ||
| 60 | m[i] = GetUi32(p->buf + i * sizeof(m[i])); | ||
| 61 | |||
| 62 | for (i = 0; i < 8; i++) | ||
| 63 | v[i] = p->h[i]; | ||
| 64 | } | ||
| 65 | |||
| 66 | v[ 8] = k_Blake2s_IV[0]; | ||
| 67 | v[ 9] = k_Blake2s_IV[1]; | ||
| 68 | v[10] = k_Blake2s_IV[2]; | ||
| 69 | v[11] = k_Blake2s_IV[3]; | ||
| 70 | |||
| 71 | v[12] = p->t[0] ^ k_Blake2s_IV[4]; | ||
| 72 | v[13] = p->t[1] ^ k_Blake2s_IV[5]; | ||
| 73 | v[14] = p->f[0] ^ k_Blake2s_IV[6]; | ||
| 74 | v[15] = p->f[1] ^ k_Blake2s_IV[7]; | ||
| 75 | |||
| 76 | #define G(r,i,a,b,c,d) \ | ||
| 77 | a += b + m[sigma[2*i+0]]; d ^= a; d = rotr32(d, 16); c += d; b ^= c; b = rotr32(b, 12); \ | ||
| 78 | a += b + m[sigma[2*i+1]]; d ^= a; d = rotr32(d, 8); c += d; b ^= c; b = rotr32(b, 7); \ | ||
| 79 | |||
| 80 | #define R(r) \ | ||
| 81 | G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ | ||
| 82 | G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ | ||
| 83 | G(r,2,v[ 2],v[ 6],v[10],v[14]); \ | ||
| 84 | G(r,3,v[ 3],v[ 7],v[11],v[15]); \ | ||
| 85 | G(r,4,v[ 0],v[ 5],v[10],v[15]); \ | ||
| 86 | G(r,5,v[ 1],v[ 6],v[11],v[12]); \ | ||
| 87 | G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ | ||
| 88 | G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ | ||
| 89 | |||
| 90 | { | ||
| 91 | unsigned r; | ||
| 92 | for (r = 0; r < BLAKE2S_NUM_ROUNDS; r++) | ||
| 93 | { | ||
| 94 | const Byte *sigma = k_Blake2s_Sigma[r]; | ||
| 95 | R(r); | ||
| 96 | } | ||
| 97 | /* R(0); R(1); R(2); R(3); R(4); R(5); R(6); R(7); R(8); R(9); */ | ||
| 98 | } | ||
| 99 | |||
| 100 | #undef G | ||
| 101 | #undef R | ||
| 102 | |||
| 103 | { | ||
| 104 | unsigned i; | ||
| 105 | for (i = 0; i < 8; i++) | ||
| 106 | p->h[i] ^= v[i] ^ v[i + 8]; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | |||
| 111 | #define Blake2s_Increment_Counter(S, inc) \ | ||
| 112 | { p->t[0] += (inc); p->t[1] += (p->t[0] < (inc)); } | ||
| 113 | |||
| 114 | #define Blake2s_Set_LastBlock(p) \ | ||
| 115 | { p->f[0] = BLAKE2S_FINAL_FLAG; p->f[1] = p->lastNode_f1; } | ||
| 116 | |||
| 117 | |||
| 118 | static void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size) | ||
| 119 | { | ||
| 120 | while (size != 0) | ||
| 121 | { | ||
| 122 | unsigned pos = (unsigned)p->bufPos; | ||
| 123 | unsigned rem = BLAKE2S_BLOCK_SIZE - pos; | ||
| 124 | |||
| 125 | if (size <= rem) | ||
| 126 | { | ||
| 127 | memcpy(p->buf + pos, data, size); | ||
| 128 | p->bufPos += (UInt32)size; | ||
| 129 | return; | ||
| 130 | } | ||
| 131 | |||
| 132 | memcpy(p->buf + pos, data, rem); | ||
| 133 | Blake2s_Increment_Counter(S, BLAKE2S_BLOCK_SIZE); | ||
| 134 | Blake2s_Compress(p); | ||
| 135 | p->bufPos = 0; | ||
| 136 | data += rem; | ||
| 137 | size -= rem; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | |||
| 142 | static void Blake2s_Final(CBlake2s *p, Byte *digest) | ||
| 143 | { | ||
| 144 | unsigned i; | ||
| 145 | |||
| 146 | Blake2s_Increment_Counter(S, (UInt32)p->bufPos); | ||
| 147 | Blake2s_Set_LastBlock(p); | ||
| 148 | memset(p->buf + p->bufPos, 0, BLAKE2S_BLOCK_SIZE - p->bufPos); | ||
| 149 | Blake2s_Compress(p); | ||
| 150 | |||
| 151 | for (i = 0; i < 8; i++) | ||
| 152 | SetUi32(digest + sizeof(p->h[i]) * i, p->h[i]); | ||
| 153 | } | ||
| 154 | |||
| 155 | |||
| 156 | /* ---------- BLAKE2s ---------- */ | ||
| 157 | |||
| 158 | /* we need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() */ | ||
| 159 | /* | ||
| 160 | typedef struct | ||
| 161 | { | ||
| 162 | Byte digest_length; | ||
| 163 | Byte key_length; | ||
| 164 | Byte fanout; | ||
| 165 | Byte depth; | ||
| 166 | UInt32 leaf_length; | ||
| 167 | Byte node_offset[6]; | ||
| 168 | Byte node_depth; | ||
| 169 | Byte inner_length; | ||
| 170 | Byte salt[BLAKE2S_SALTBYTES]; | ||
| 171 | Byte personal[BLAKE2S_PERSONALBYTES]; | ||
| 172 | } CBlake2sParam; | ||
| 173 | */ | ||
| 174 | |||
| 175 | |||
| 176 | static void Blake2sp_Init_Spec(CBlake2s *p, unsigned node_offset, unsigned node_depth) | ||
| 177 | { | ||
| 178 | Blake2s_Init0(p); | ||
| 179 | |||
| 180 | p->h[0] ^= (BLAKE2S_DIGEST_SIZE | ((UInt32)BLAKE2SP_PARALLEL_DEGREE << 16) | ((UInt32)2 << 24)); | ||
| 181 | p->h[2] ^= ((UInt32)node_offset); | ||
| 182 | p->h[3] ^= ((UInt32)node_depth << 16) | ((UInt32)BLAKE2S_DIGEST_SIZE << 24); | ||
| 183 | /* | ||
| 184 | P->digest_length = BLAKE2S_DIGEST_SIZE; | ||
| 185 | P->key_length = 0; | ||
| 186 | P->fanout = BLAKE2SP_PARALLEL_DEGREE; | ||
| 187 | P->depth = 2; | ||
| 188 | P->leaf_length = 0; | ||
| 189 | store48(P->node_offset, node_offset); | ||
| 190 | P->node_depth = node_depth; | ||
| 191 | P->inner_length = BLAKE2S_DIGEST_SIZE; | ||
| 192 | */ | ||
| 193 | } | ||
| 194 | |||
| 195 | |||
| 196 | void Blake2sp_Init(CBlake2sp *p) | ||
| 197 | { | ||
| 198 | unsigned i; | ||
| 199 | |||
| 200 | p->bufPos = 0; | ||
| 201 | |||
| 202 | for (i = 0; i < BLAKE2SP_PARALLEL_DEGREE; i++) | ||
| 203 | Blake2sp_Init_Spec(&p->S[i], i, 0); | ||
| 204 | |||
| 205 | p->S[BLAKE2SP_PARALLEL_DEGREE - 1].lastNode_f1 = BLAKE2S_FINAL_FLAG; | ||
| 206 | } | ||
| 207 | |||
| 208 | |||
| 209 | void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size) | ||
| 210 | { | ||
| 211 | unsigned pos = p->bufPos; | ||
| 212 | while (size != 0) | ||
| 213 | { | ||
| 214 | unsigned index = pos / BLAKE2S_BLOCK_SIZE; | ||
| 215 | unsigned rem = BLAKE2S_BLOCK_SIZE - (pos & (BLAKE2S_BLOCK_SIZE - 1)); | ||
| 216 | if (rem > size) | ||
| 217 | rem = (unsigned)size; | ||
| 218 | Blake2s_Update(&p->S[index], data, rem); | ||
| 219 | size -= rem; | ||
| 220 | data += rem; | ||
| 221 | pos += rem; | ||
| 222 | pos &= (BLAKE2S_BLOCK_SIZE * BLAKE2SP_PARALLEL_DEGREE - 1); | ||
| 223 | } | ||
| 224 | p->bufPos = pos; | ||
| 225 | } | ||
| 226 | |||
| 227 | |||
| 228 | void Blake2sp_Final(CBlake2sp *p, Byte *digest) | ||
| 229 | { | ||
| 230 | CBlake2s R; | ||
| 231 | unsigned i; | ||
| 232 | |||
| 233 | Blake2sp_Init_Spec(&R, 0, 1); | ||
| 234 | R.lastNode_f1 = BLAKE2S_FINAL_FLAG; | ||
| 235 | |||
| 236 | for (i = 0; i < BLAKE2SP_PARALLEL_DEGREE; i++) | ||
| 237 | { | ||
| 238 | Byte hash[BLAKE2S_DIGEST_SIZE]; | ||
| 239 | Blake2s_Final(&p->S[i], hash); | ||
| 240 | Blake2s_Update(&R, hash, BLAKE2S_DIGEST_SIZE); | ||
| 241 | } | ||
| 242 | |||
| 243 | Blake2s_Final(&R, digest); | ||
| 244 | } | ||
| @@ -0,0 +1,230 @@ | |||
| 1 | /* Bra.c -- Converters for RISC code | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "CpuArch.h" | ||
| 7 | #include "Bra.h" | ||
| 8 | |||
| 9 | SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) | ||
| 10 | { | ||
| 11 | Byte *p; | ||
| 12 | const Byte *lim; | ||
| 13 | size &= ~(size_t)3; | ||
| 14 | ip += 4; | ||
| 15 | p = data; | ||
| 16 | lim = data + size; | ||
| 17 | |||
| 18 | if (encoding) | ||
| 19 | |||
| 20 | for (;;) | ||
| 21 | { | ||
| 22 | for (;;) | ||
| 23 | { | ||
| 24 | if (p >= lim) | ||
| 25 | return (SizeT)(p - data); | ||
| 26 | p += 4; | ||
| 27 | if (p[-1] == 0xEB) | ||
| 28 | break; | ||
| 29 | } | ||
| 30 | { | ||
| 31 | UInt32 v = GetUi32(p - 4); | ||
| 32 | v <<= 2; | ||
| 33 | v += ip + (UInt32)(p - data); | ||
| 34 | v >>= 2; | ||
| 35 | v &= 0x00FFFFFF; | ||
| 36 | v |= 0xEB000000; | ||
| 37 | SetUi32(p - 4, v); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | for (;;) | ||
| 42 | { | ||
| 43 | for (;;) | ||
| 44 | { | ||
| 45 | if (p >= lim) | ||
| 46 | return (SizeT)(p - data); | ||
| 47 | p += 4; | ||
| 48 | if (p[-1] == 0xEB) | ||
| 49 | break; | ||
| 50 | } | ||
| 51 | { | ||
| 52 | UInt32 v = GetUi32(p - 4); | ||
| 53 | v <<= 2; | ||
| 54 | v -= ip + (UInt32)(p - data); | ||
| 55 | v >>= 2; | ||
| 56 | v &= 0x00FFFFFF; | ||
| 57 | v |= 0xEB000000; | ||
| 58 | SetUi32(p - 4, v); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | |||
| 64 | SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) | ||
| 65 | { | ||
| 66 | Byte *p; | ||
| 67 | const Byte *lim; | ||
| 68 | size &= ~(size_t)1; | ||
| 69 | p = data; | ||
| 70 | lim = data + size - 4; | ||
| 71 | |||
| 72 | if (encoding) | ||
| 73 | |||
| 74 | for (;;) | ||
| 75 | { | ||
| 76 | UInt32 b1; | ||
| 77 | for (;;) | ||
| 78 | { | ||
| 79 | UInt32 b3; | ||
| 80 | if (p > lim) | ||
| 81 | return (SizeT)(p - data); | ||
| 82 | b1 = p[1]; | ||
| 83 | b3 = p[3]; | ||
| 84 | p += 2; | ||
| 85 | b1 ^= 8; | ||
| 86 | if ((b3 & b1) >= 0xF8) | ||
| 87 | break; | ||
| 88 | } | ||
| 89 | { | ||
| 90 | UInt32 v = | ||
| 91 | ((UInt32)b1 << 19) | ||
| 92 | + (((UInt32)p[1] & 0x7) << 8) | ||
| 93 | + (((UInt32)p[-2] << 11)) | ||
| 94 | + (p[0]); | ||
| 95 | |||
| 96 | p += 2; | ||
| 97 | { | ||
| 98 | UInt32 cur = (ip + (UInt32)(p - data)) >> 1; | ||
| 99 | v += cur; | ||
| 100 | } | ||
| 101 | |||
| 102 | p[-4] = (Byte)(v >> 11); | ||
| 103 | p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7)); | ||
| 104 | p[-2] = (Byte)v; | ||
| 105 | p[-1] = (Byte)(0xF8 | (v >> 8)); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | for (;;) | ||
| 110 | { | ||
| 111 | UInt32 b1; | ||
| 112 | for (;;) | ||
| 113 | { | ||
| 114 | UInt32 b3; | ||
| 115 | if (p > lim) | ||
| 116 | return (SizeT)(p - data); | ||
| 117 | b1 = p[1]; | ||
| 118 | b3 = p[3]; | ||
| 119 | p += 2; | ||
| 120 | b1 ^= 8; | ||
| 121 | if ((b3 & b1) >= 0xF8) | ||
| 122 | break; | ||
| 123 | } | ||
| 124 | { | ||
| 125 | UInt32 v = | ||
| 126 | ((UInt32)b1 << 19) | ||
| 127 | + (((UInt32)p[1] & 0x7) << 8) | ||
| 128 | + (((UInt32)p[-2] << 11)) | ||
| 129 | + (p[0]); | ||
| 130 | |||
| 131 | p += 2; | ||
| 132 | { | ||
| 133 | UInt32 cur = (ip + (UInt32)(p - data)) >> 1; | ||
| 134 | v -= cur; | ||
| 135 | } | ||
| 136 | |||
| 137 | /* | ||
| 138 | SetUi16(p - 4, (UInt16)(((v >> 11) & 0x7FF) | 0xF000)); | ||
| 139 | SetUi16(p - 2, (UInt16)(v | 0xF800)); | ||
| 140 | */ | ||
| 141 | |||
| 142 | p[-4] = (Byte)(v >> 11); | ||
| 143 | p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7)); | ||
| 144 | p[-2] = (Byte)v; | ||
| 145 | p[-1] = (Byte)(0xF8 | (v >> 8)); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | |||
| 151 | SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) | ||
| 152 | { | ||
| 153 | Byte *p; | ||
| 154 | const Byte *lim; | ||
| 155 | size &= ~(size_t)3; | ||
| 156 | ip -= 4; | ||
| 157 | p = data; | ||
| 158 | lim = data + size; | ||
| 159 | |||
| 160 | for (;;) | ||
| 161 | { | ||
| 162 | for (;;) | ||
| 163 | { | ||
| 164 | if (p >= lim) | ||
| 165 | return (SizeT)(p - data); | ||
| 166 | p += 4; | ||
| 167 | /* if ((v & 0xFC000003) == 0x48000001) */ | ||
| 168 | if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1) | ||
| 169 | break; | ||
| 170 | } | ||
| 171 | { | ||
| 172 | UInt32 v = GetBe32(p - 4); | ||
| 173 | if (encoding) | ||
| 174 | v += ip + (UInt32)(p - data); | ||
| 175 | else | ||
| 176 | v -= ip + (UInt32)(p - data); | ||
| 177 | v &= 0x03FFFFFF; | ||
| 178 | v |= 0x48000000; | ||
| 179 | SetBe32(p - 4, v); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | |||
| 185 | SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) | ||
| 186 | { | ||
| 187 | Byte *p; | ||
| 188 | const Byte *lim; | ||
| 189 | size &= ~(size_t)3; | ||
| 190 | ip -= 4; | ||
| 191 | p = data; | ||
| 192 | lim = data + size; | ||
| 193 | |||
| 194 | for (;;) | ||
| 195 | { | ||
| 196 | for (;;) | ||
| 197 | { | ||
| 198 | if (p >= lim) | ||
| 199 | return (SizeT)(p - data); | ||
| 200 | /* | ||
| 201 | v = GetBe32(p); | ||
| 202 | p += 4; | ||
| 203 | m = v + ((UInt32)5 << 29); | ||
| 204 | m ^= (UInt32)7 << 29; | ||
| 205 | m += (UInt32)1 << 22; | ||
| 206 | if ((m & ((UInt32)0x1FF << 23)) == 0) | ||
| 207 | break; | ||
| 208 | */ | ||
| 209 | p += 4; | ||
| 210 | if ((p[-4] == 0x40 && (p[-3] & 0xC0) == 0) || | ||
| 211 | (p[-4] == 0x7F && (p[-3] >= 0xC0))) | ||
| 212 | break; | ||
| 213 | } | ||
| 214 | { | ||
| 215 | UInt32 v = GetBe32(p - 4); | ||
| 216 | v <<= 2; | ||
| 217 | if (encoding) | ||
| 218 | v += ip + (UInt32)(p - data); | ||
| 219 | else | ||
| 220 | v -= ip + (UInt32)(p - data); | ||
| 221 | |||
| 222 | v &= 0x01FFFFFF; | ||
| 223 | v -= (UInt32)1 << 24; | ||
| 224 | v ^= 0xFF000000; | ||
| 225 | v >>= 2; | ||
| 226 | v |= 0x40000000; | ||
| 227 | SetBe32(p - 4, v); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | } | ||
| @@ -0,0 +1,64 @@ | |||
| 1 | /* Bra.h -- Branch converters for executables | ||
| 2 | 2013-01-18 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __BRA_H | ||
| 5 | #define __BRA_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | /* | ||
| 12 | These functions convert relative addresses to absolute addresses | ||
| 13 | in CALL instructions to increase the compression ratio. | ||
| 14 | |||
| 15 | In: | ||
| 16 | data - data buffer | ||
| 17 | size - size of data | ||
| 18 | ip - current virtual Instruction Pinter (IP) value | ||
| 19 | state - state variable for x86 converter | ||
| 20 | encoding - 0 (for decoding), 1 (for encoding) | ||
| 21 | |||
| 22 | Out: | ||
| 23 | state - state variable for x86 converter | ||
| 24 | |||
| 25 | Returns: | ||
| 26 | The number of processed bytes. If you call these functions with multiple calls, | ||
| 27 | you must start next call with first byte after block of processed bytes. | ||
| 28 | |||
| 29 | Type Endian Alignment LookAhead | ||
| 30 | |||
| 31 | x86 little 1 4 | ||
| 32 | ARMT little 2 2 | ||
| 33 | ARM little 4 0 | ||
| 34 | PPC big 4 0 | ||
| 35 | SPARC big 4 0 | ||
| 36 | IA64 little 16 0 | ||
| 37 | |||
| 38 | size must be >= Alignment + LookAhead, if it's not last block. | ||
| 39 | If (size < Alignment + LookAhead), converter returns 0. | ||
| 40 | |||
| 41 | Example: | ||
| 42 | |||
| 43 | UInt32 ip = 0; | ||
| 44 | for () | ||
| 45 | { | ||
| 46 | ; size must be >= Alignment + LookAhead, if it's not last block | ||
| 47 | SizeT processed = Convert(data, size, ip, 1); | ||
| 48 | data += processed; | ||
| 49 | size -= processed; | ||
| 50 | ip += processed; | ||
| 51 | } | ||
| 52 | */ | ||
| 53 | |||
| 54 | #define x86_Convert_Init(state) { state = 0; } | ||
| 55 | SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); | ||
| 56 | SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); | ||
| 57 | SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); | ||
| 58 | SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); | ||
| 59 | SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); | ||
| 60 | SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); | ||
| 61 | |||
| 62 | EXTERN_C_END | ||
| 63 | |||
| 64 | #endif | ||
diff --git a/C/Bra86.c b/C/Bra86.c new file mode 100644 index 0000000..10a0fbd --- /dev/null +++ b/C/Bra86.c | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | /* Bra86.c -- Converter for x86 code (BCJ) | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "Bra.h" | ||
| 7 | |||
| 8 | #define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0) | ||
| 9 | |||
| 10 | SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) | ||
| 11 | { | ||
| 12 | SizeT pos = 0; | ||
| 13 | UInt32 mask = *state & 7; | ||
| 14 | if (size < 5) | ||
| 15 | return 0; | ||
| 16 | size -= 4; | ||
| 17 | ip += 5; | ||
| 18 | |||
| 19 | for (;;) | ||
| 20 | { | ||
| 21 | Byte *p = data + pos; | ||
| 22 | const Byte *limit = data + size; | ||
| 23 | for (; p < limit; p++) | ||
| 24 | if ((*p & 0xFE) == 0xE8) | ||
| 25 | break; | ||
| 26 | |||
| 27 | { | ||
| 28 | SizeT d = (SizeT)(p - data) - pos; | ||
| 29 | pos = (SizeT)(p - data); | ||
| 30 | if (p >= limit) | ||
| 31 | { | ||
| 32 | *state = (d > 2 ? 0 : mask >> (unsigned)d); | ||
| 33 | return pos; | ||
| 34 | } | ||
| 35 | if (d > 2) | ||
| 36 | mask = 0; | ||
| 37 | else | ||
| 38 | { | ||
| 39 | mask >>= (unsigned)d; | ||
| 40 | if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(size_t)(mask >> 1) + 1]))) | ||
| 41 | { | ||
| 42 | mask = (mask >> 1) | 4; | ||
| 43 | pos++; | ||
| 44 | continue; | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | if (Test86MSByte(p[4])) | ||
| 50 | { | ||
| 51 | UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); | ||
| 52 | UInt32 cur = ip + (UInt32)pos; | ||
| 53 | pos += 5; | ||
| 54 | if (encoding) | ||
| 55 | v += cur; | ||
| 56 | else | ||
| 57 | v -= cur; | ||
| 58 | if (mask != 0) | ||
| 59 | { | ||
| 60 | unsigned sh = (mask & 6) << 2; | ||
| 61 | if (Test86MSByte((Byte)(v >> sh))) | ||
| 62 | { | ||
| 63 | v ^= (((UInt32)0x100 << sh) - 1); | ||
| 64 | if (encoding) | ||
| 65 | v += cur; | ||
| 66 | else | ||
| 67 | v -= cur; | ||
| 68 | } | ||
| 69 | mask = 0; | ||
| 70 | } | ||
| 71 | p[1] = (Byte)v; | ||
| 72 | p[2] = (Byte)(v >> 8); | ||
| 73 | p[3] = (Byte)(v >> 16); | ||
| 74 | p[4] = (Byte)(0 - ((v >> 24) & 1)); | ||
| 75 | } | ||
| 76 | else | ||
| 77 | { | ||
| 78 | mask = (mask >> 1) | 4; | ||
| 79 | pos++; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
diff --git a/C/BraIA64.c b/C/BraIA64.c new file mode 100644 index 0000000..d1dbc62 --- /dev/null +++ b/C/BraIA64.c | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* BraIA64.c -- Converter for IA-64 code | ||
| 2 | 2017-01-26 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "CpuArch.h" | ||
| 7 | #include "Bra.h" | ||
| 8 | |||
| 9 | SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) | ||
| 10 | { | ||
| 11 | SizeT i; | ||
| 12 | if (size < 16) | ||
| 13 | return 0; | ||
| 14 | size -= 16; | ||
| 15 | i = 0; | ||
| 16 | do | ||
| 17 | { | ||
| 18 | unsigned m = ((UInt32)0x334B0000 >> (data[i] & 0x1E)) & 3; | ||
| 19 | if (m) | ||
| 20 | { | ||
| 21 | m++; | ||
| 22 | do | ||
| 23 | { | ||
| 24 | Byte *p = data + (i + (size_t)m * 5 - 8); | ||
| 25 | if (((p[3] >> m) & 15) == 5 | ||
| 26 | && (((p[-1] | ((UInt32)p[0] << 8)) >> m) & 0x70) == 0) | ||
| 27 | { | ||
| 28 | unsigned raw = GetUi32(p); | ||
| 29 | unsigned v = raw >> m; | ||
| 30 | v = (v & 0xFFFFF) | ((v & (1 << 23)) >> 3); | ||
| 31 | |||
| 32 | v <<= 4; | ||
| 33 | if (encoding) | ||
| 34 | v += ip + (UInt32)i; | ||
| 35 | else | ||
| 36 | v -= ip + (UInt32)i; | ||
| 37 | v >>= 4; | ||
| 38 | |||
| 39 | v &= 0x1FFFFF; | ||
| 40 | v += 0x700000; | ||
| 41 | v &= 0x8FFFFF; | ||
| 42 | raw &= ~((UInt32)0x8FFFFF << m); | ||
| 43 | raw |= (v << m); | ||
| 44 | SetUi32(p, raw); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | while (++m <= 4); | ||
| 48 | } | ||
| 49 | i += 16; | ||
| 50 | } | ||
| 51 | while (i <= size); | ||
| 52 | return i; | ||
| 53 | } | ||
diff --git a/C/BwtSort.c b/C/BwtSort.c new file mode 100644 index 0000000..3eb57ef --- /dev/null +++ b/C/BwtSort.c | |||
| @@ -0,0 +1,515 @@ | |||
| 1 | /* BwtSort.c -- BWT block sorting | ||
| 2 | 2021-04-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "BwtSort.h" | ||
| 7 | #include "Sort.h" | ||
| 8 | |||
| 9 | /* #define BLOCK_SORT_USE_HEAP_SORT */ | ||
| 10 | |||
| 11 | #define NO_INLINE MY_FAST_CALL | ||
| 12 | |||
| 13 | /* Don't change it !!! */ | ||
| 14 | #define kNumHashBytes 2 | ||
| 15 | #define kNumHashValues (1 << (kNumHashBytes * 8)) | ||
| 16 | |||
| 17 | /* kNumRefBitsMax must be < (kNumHashBytes * 8) = 16 */ | ||
| 18 | #define kNumRefBitsMax 12 | ||
| 19 | |||
| 20 | #define BS_TEMP_SIZE kNumHashValues | ||
| 21 | |||
| 22 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 23 | |||
| 24 | /* 32 Flags in UInt32 word */ | ||
| 25 | #define kNumFlagsBits 5 | ||
| 26 | #define kNumFlagsInWord (1 << kNumFlagsBits) | ||
| 27 | #define kFlagsMask (kNumFlagsInWord - 1) | ||
| 28 | #define kAllFlags 0xFFFFFFFF | ||
| 29 | |||
| 30 | #else | ||
| 31 | |||
| 32 | #define kNumBitsMax 20 | ||
| 33 | #define kIndexMask ((1 << kNumBitsMax) - 1) | ||
| 34 | #define kNumExtraBits (32 - kNumBitsMax) | ||
| 35 | #define kNumExtra0Bits (kNumExtraBits - 2) | ||
| 36 | #define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1) | ||
| 37 | |||
| 38 | #define SetFinishedGroupSize(p, size) \ | ||
| 39 | { *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \ | ||
| 40 | if ((size) > (1 << kNumExtra0Bits)) { \ | ||
| 41 | *(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \ | ||
| 42 | |||
| 43 | static void SetGroupSize(UInt32 *p, UInt32 size) | ||
| 44 | { | ||
| 45 | if (--size == 0) | ||
| 46 | return; | ||
| 47 | *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax); | ||
| 48 | if (size >= (1 << kNumExtra0Bits)) | ||
| 49 | { | ||
| 50 | *p |= 0x40000000; | ||
| 51 | p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | #endif | ||
| 56 | |||
| 57 | /* | ||
| 58 | SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks | ||
| 59 | "range" is not real range. It's only for optimization. | ||
| 60 | returns: 1 - if there are groups, 0 - no more groups | ||
| 61 | */ | ||
| 62 | |||
| 63 | static UInt32 NO_INLINE SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices | ||
| 64 | #ifndef BLOCK_SORT_USE_HEAP_SORT | ||
| 65 | , UInt32 left, UInt32 range | ||
| 66 | #endif | ||
| 67 | ) | ||
| 68 | { | ||
| 69 | UInt32 *ind2 = Indices + groupOffset; | ||
| 70 | UInt32 *Groups; | ||
| 71 | if (groupSize <= 1) | ||
| 72 | { | ||
| 73 | /* | ||
| 74 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 75 | SetFinishedGroupSize(ind2, 1); | ||
| 76 | #endif | ||
| 77 | */ | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | Groups = Indices + BlockSize + BS_TEMP_SIZE; | ||
| 81 | if (groupSize <= ((UInt32)1 << NumRefBits) | ||
| 82 | #ifndef BLOCK_SORT_USE_HEAP_SORT | ||
| 83 | && groupSize <= range | ||
| 84 | #endif | ||
| 85 | ) | ||
| 86 | { | ||
| 87 | UInt32 *temp = Indices + BlockSize; | ||
| 88 | UInt32 j; | ||
| 89 | UInt32 mask, thereAreGroups, group, cg; | ||
| 90 | { | ||
| 91 | UInt32 gPrev; | ||
| 92 | UInt32 gRes = 0; | ||
| 93 | { | ||
| 94 | UInt32 sp = ind2[0] + NumSortedBytes; | ||
| 95 | if (sp >= BlockSize) sp -= BlockSize; | ||
| 96 | gPrev = Groups[sp]; | ||
| 97 | temp[0] = (gPrev << NumRefBits); | ||
| 98 | } | ||
| 99 | |||
| 100 | for (j = 1; j < groupSize; j++) | ||
| 101 | { | ||
| 102 | UInt32 sp = ind2[j] + NumSortedBytes; | ||
| 103 | UInt32 g; | ||
| 104 | if (sp >= BlockSize) sp -= BlockSize; | ||
| 105 | g = Groups[sp]; | ||
| 106 | temp[j] = (g << NumRefBits) | j; | ||
| 107 | gRes |= (gPrev ^ g); | ||
| 108 | } | ||
| 109 | if (gRes == 0) | ||
| 110 | { | ||
| 111 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 112 | SetGroupSize(ind2, groupSize); | ||
| 113 | #endif | ||
| 114 | return 1; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | HeapSort(temp, groupSize); | ||
| 119 | mask = (((UInt32)1 << NumRefBits) - 1); | ||
| 120 | thereAreGroups = 0; | ||
| 121 | |||
| 122 | group = groupOffset; | ||
| 123 | cg = (temp[0] >> NumRefBits); | ||
| 124 | temp[0] = ind2[temp[0] & mask]; | ||
| 125 | |||
| 126 | { | ||
| 127 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 128 | UInt32 *Flags = Groups + BlockSize; | ||
| 129 | #else | ||
| 130 | UInt32 prevGroupStart = 0; | ||
| 131 | #endif | ||
| 132 | |||
| 133 | for (j = 1; j < groupSize; j++) | ||
| 134 | { | ||
| 135 | UInt32 val = temp[j]; | ||
| 136 | UInt32 cgCur = (val >> NumRefBits); | ||
| 137 | |||
| 138 | if (cgCur != cg) | ||
| 139 | { | ||
| 140 | cg = cgCur; | ||
| 141 | group = groupOffset + j; | ||
| 142 | |||
| 143 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 144 | { | ||
| 145 | UInt32 t = group - 1; | ||
| 146 | Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); | ||
| 147 | } | ||
| 148 | #else | ||
| 149 | SetGroupSize(temp + prevGroupStart, j - prevGroupStart); | ||
| 150 | prevGroupStart = j; | ||
| 151 | #endif | ||
| 152 | } | ||
| 153 | else | ||
| 154 | thereAreGroups = 1; | ||
| 155 | { | ||
| 156 | UInt32 ind = ind2[val & mask]; | ||
| 157 | temp[j] = ind; | ||
| 158 | Groups[ind] = group; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 163 | SetGroupSize(temp + prevGroupStart, j - prevGroupStart); | ||
| 164 | #endif | ||
| 165 | } | ||
| 166 | |||
| 167 | for (j = 0; j < groupSize; j++) | ||
| 168 | ind2[j] = temp[j]; | ||
| 169 | return thereAreGroups; | ||
| 170 | } | ||
| 171 | |||
| 172 | /* Check that all strings are in one group (cannot sort) */ | ||
| 173 | { | ||
| 174 | UInt32 group, j; | ||
| 175 | UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; | ||
| 176 | group = Groups[sp]; | ||
| 177 | for (j = 1; j < groupSize; j++) | ||
| 178 | { | ||
| 179 | sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; | ||
| 180 | if (Groups[sp] != group) | ||
| 181 | break; | ||
| 182 | } | ||
| 183 | if (j == groupSize) | ||
| 184 | { | ||
| 185 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 186 | SetGroupSize(ind2, groupSize); | ||
| 187 | #endif | ||
| 188 | return 1; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | #ifndef BLOCK_SORT_USE_HEAP_SORT | ||
| 193 | { | ||
| 194 | /* ---------- Range Sort ---------- */ | ||
| 195 | UInt32 i; | ||
| 196 | UInt32 mid; | ||
| 197 | for (;;) | ||
| 198 | { | ||
| 199 | UInt32 j; | ||
| 200 | if (range <= 1) | ||
| 201 | { | ||
| 202 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 203 | SetGroupSize(ind2, groupSize); | ||
| 204 | #endif | ||
| 205 | return 1; | ||
| 206 | } | ||
| 207 | mid = left + ((range + 1) >> 1); | ||
| 208 | j = groupSize; | ||
| 209 | i = 0; | ||
| 210 | do | ||
| 211 | { | ||
| 212 | UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; | ||
| 213 | if (Groups[sp] >= mid) | ||
| 214 | { | ||
| 215 | for (j--; j > i; j--) | ||
| 216 | { | ||
| 217 | sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; | ||
| 218 | if (Groups[sp] < mid) | ||
| 219 | { | ||
| 220 | UInt32 temp = ind2[i]; ind2[i] = ind2[j]; ind2[j] = temp; | ||
| 221 | break; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | if (i >= j) | ||
| 225 | break; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | while (++i < j); | ||
| 229 | if (i == 0) | ||
| 230 | { | ||
| 231 | range = range - (mid - left); | ||
| 232 | left = mid; | ||
| 233 | } | ||
| 234 | else if (i == groupSize) | ||
| 235 | range = (mid - left); | ||
| 236 | else | ||
| 237 | break; | ||
| 238 | } | ||
| 239 | |||
| 240 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 241 | { | ||
| 242 | UInt32 t = (groupOffset + i - 1); | ||
| 243 | UInt32 *Flags = Groups + BlockSize; | ||
| 244 | Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); | ||
| 245 | } | ||
| 246 | #endif | ||
| 247 | |||
| 248 | { | ||
| 249 | UInt32 j; | ||
| 250 | for (j = i; j < groupSize; j++) | ||
| 251 | Groups[ind2[j]] = groupOffset + i; | ||
| 252 | } | ||
| 253 | |||
| 254 | { | ||
| 255 | UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left); | ||
| 256 | return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left)); | ||
| 257 | } | ||
| 258 | |||
| 259 | } | ||
| 260 | |||
| 261 | #else | ||
| 262 | |||
| 263 | /* ---------- Heap Sort ---------- */ | ||
| 264 | |||
| 265 | { | ||
| 266 | UInt32 j; | ||
| 267 | for (j = 0; j < groupSize; j++) | ||
| 268 | { | ||
| 269 | UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; | ||
| 270 | ind2[j] = sp; | ||
| 271 | } | ||
| 272 | |||
| 273 | HeapSortRef(ind2, Groups, groupSize); | ||
| 274 | |||
| 275 | /* Write Flags */ | ||
| 276 | { | ||
| 277 | UInt32 sp = ind2[0]; | ||
| 278 | UInt32 group = Groups[sp]; | ||
| 279 | |||
| 280 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 281 | UInt32 *Flags = Groups + BlockSize; | ||
| 282 | #else | ||
| 283 | UInt32 prevGroupStart = 0; | ||
| 284 | #endif | ||
| 285 | |||
| 286 | for (j = 1; j < groupSize; j++) | ||
| 287 | { | ||
| 288 | sp = ind2[j]; | ||
| 289 | if (Groups[sp] != group) | ||
| 290 | { | ||
| 291 | group = Groups[sp]; | ||
| 292 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 293 | { | ||
| 294 | UInt32 t = groupOffset + j - 1; | ||
| 295 | Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); | ||
| 296 | } | ||
| 297 | #else | ||
| 298 | SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); | ||
| 299 | prevGroupStart = j; | ||
| 300 | #endif | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 305 | SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); | ||
| 306 | #endif | ||
| 307 | } | ||
| 308 | { | ||
| 309 | /* Write new Groups values and Check that there are groups */ | ||
| 310 | UInt32 thereAreGroups = 0; | ||
| 311 | for (j = 0; j < groupSize; j++) | ||
| 312 | { | ||
| 313 | UInt32 group = groupOffset + j; | ||
| 314 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 315 | UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax); | ||
| 316 | if ((ind2[j] & 0x40000000) != 0) | ||
| 317 | subGroupSize += ((ind2[(size_t)j + 1] >> kNumBitsMax) << kNumExtra0Bits); | ||
| 318 | subGroupSize++; | ||
| 319 | for (;;) | ||
| 320 | { | ||
| 321 | UInt32 original = ind2[j]; | ||
| 322 | UInt32 sp = original & kIndexMask; | ||
| 323 | if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes; | ||
| 324 | ind2[j] = sp | (original & ~kIndexMask); | ||
| 325 | Groups[sp] = group; | ||
| 326 | if (--subGroupSize == 0) | ||
| 327 | break; | ||
| 328 | j++; | ||
| 329 | thereAreGroups = 1; | ||
| 330 | } | ||
| 331 | #else | ||
| 332 | UInt32 *Flags = Groups + BlockSize; | ||
| 333 | for (;;) | ||
| 334 | { | ||
| 335 | UInt32 sp = ind2[j]; if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes; | ||
| 336 | ind2[j] = sp; | ||
| 337 | Groups[sp] = group; | ||
| 338 | if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0) | ||
| 339 | break; | ||
| 340 | j++; | ||
| 341 | thereAreGroups = 1; | ||
| 342 | } | ||
| 343 | #endif | ||
| 344 | } | ||
| 345 | return thereAreGroups; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | #endif | ||
| 349 | } | ||
| 350 | |||
| 351 | /* conditions: blockSize > 0 */ | ||
| 352 | UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize) | ||
| 353 | { | ||
| 354 | UInt32 *counters = Indices + blockSize; | ||
| 355 | UInt32 i; | ||
| 356 | UInt32 *Groups; | ||
| 357 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 358 | UInt32 *Flags; | ||
| 359 | #endif | ||
| 360 | |||
| 361 | /* Radix-Sort for 2 bytes */ | ||
| 362 | for (i = 0; i < kNumHashValues; i++) | ||
| 363 | counters[i] = 0; | ||
| 364 | for (i = 0; i < blockSize - 1; i++) | ||
| 365 | counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++; | ||
| 366 | counters[((UInt32)data[i] << 8) | data[0]]++; | ||
| 367 | |||
| 368 | Groups = counters + BS_TEMP_SIZE; | ||
| 369 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 370 | Flags = Groups + blockSize; | ||
| 371 | { | ||
| 372 | UInt32 numWords = (blockSize + kFlagsMask) >> kNumFlagsBits; | ||
| 373 | for (i = 0; i < numWords; i++) | ||
| 374 | Flags[i] = kAllFlags; | ||
| 375 | } | ||
| 376 | #endif | ||
| 377 | |||
| 378 | { | ||
| 379 | UInt32 sum = 0; | ||
| 380 | for (i = 0; i < kNumHashValues; i++) | ||
| 381 | { | ||
| 382 | UInt32 groupSize = counters[i]; | ||
| 383 | if (groupSize > 0) | ||
| 384 | { | ||
| 385 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 386 | UInt32 t = sum + groupSize - 1; | ||
| 387 | Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); | ||
| 388 | #endif | ||
| 389 | sum += groupSize; | ||
| 390 | } | ||
| 391 | counters[i] = sum - groupSize; | ||
| 392 | } | ||
| 393 | |||
| 394 | for (i = 0; i < blockSize - 1; i++) | ||
| 395 | Groups[i] = counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]; | ||
| 396 | Groups[i] = counters[((UInt32)data[i] << 8) | data[0]]; | ||
| 397 | |||
| 398 | for (i = 0; i < blockSize - 1; i++) | ||
| 399 | Indices[counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++] = i; | ||
| 400 | Indices[counters[((UInt32)data[i] << 8) | data[0]]++] = i; | ||
| 401 | |||
| 402 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 403 | { | ||
| 404 | UInt32 prev = 0; | ||
| 405 | for (i = 0; i < kNumHashValues; i++) | ||
| 406 | { | ||
| 407 | UInt32 prevGroupSize = counters[i] - prev; | ||
| 408 | if (prevGroupSize == 0) | ||
| 409 | continue; | ||
| 410 | SetGroupSize(Indices + prev, prevGroupSize); | ||
| 411 | prev = counters[i]; | ||
| 412 | } | ||
| 413 | } | ||
| 414 | #endif | ||
| 415 | } | ||
| 416 | |||
| 417 | { | ||
| 418 | int NumRefBits; | ||
| 419 | UInt32 NumSortedBytes; | ||
| 420 | for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++); | ||
| 421 | NumRefBits = 32 - NumRefBits; | ||
| 422 | if (NumRefBits > kNumRefBitsMax) | ||
| 423 | NumRefBits = kNumRefBitsMax; | ||
| 424 | |||
| 425 | for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1) | ||
| 426 | { | ||
| 427 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 428 | UInt32 finishedGroupSize = 0; | ||
| 429 | #endif | ||
| 430 | UInt32 newLimit = 0; | ||
| 431 | for (i = 0; i < blockSize;) | ||
| 432 | { | ||
| 433 | UInt32 groupSize; | ||
| 434 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 435 | |||
| 436 | if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0) | ||
| 437 | { | ||
| 438 | i++; | ||
| 439 | continue; | ||
| 440 | } | ||
| 441 | for (groupSize = 1; | ||
| 442 | (Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0; | ||
| 443 | groupSize++); | ||
| 444 | |||
| 445 | groupSize++; | ||
| 446 | |||
| 447 | #else | ||
| 448 | |||
| 449 | groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax); | ||
| 450 | { | ||
| 451 | BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0); | ||
| 452 | if ((Indices[i] & 0x40000000) != 0) | ||
| 453 | { | ||
| 454 | groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); | ||
| 455 | Indices[(size_t)i + 1] &= kIndexMask; | ||
| 456 | } | ||
| 457 | Indices[i] &= kIndexMask; | ||
| 458 | groupSize++; | ||
| 459 | if (finishedGroup || groupSize == 1) | ||
| 460 | { | ||
| 461 | Indices[i - finishedGroupSize] &= kIndexMask; | ||
| 462 | if (finishedGroupSize > 1) | ||
| 463 | Indices[(size_t)(i - finishedGroupSize) + 1] &= kIndexMask; | ||
| 464 | { | ||
| 465 | UInt32 newGroupSize = groupSize + finishedGroupSize; | ||
| 466 | SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize); | ||
| 467 | finishedGroupSize = newGroupSize; | ||
| 468 | } | ||
| 469 | i += groupSize; | ||
| 470 | continue; | ||
| 471 | } | ||
| 472 | finishedGroupSize = 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | #endif | ||
| 476 | |||
| 477 | if (NumSortedBytes >= blockSize) | ||
| 478 | { | ||
| 479 | UInt32 j; | ||
| 480 | for (j = 0; j < groupSize; j++) | ||
| 481 | { | ||
| 482 | UInt32 t = (i + j); | ||
| 483 | /* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */ | ||
| 484 | Groups[Indices[t]] = t; | ||
| 485 | } | ||
| 486 | } | ||
| 487 | else | ||
| 488 | if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices | ||
| 489 | #ifndef BLOCK_SORT_USE_HEAP_SORT | ||
| 490 | , 0, blockSize | ||
| 491 | #endif | ||
| 492 | ) != 0) | ||
| 493 | newLimit = i + groupSize; | ||
| 494 | i += groupSize; | ||
| 495 | } | ||
| 496 | if (newLimit == 0) | ||
| 497 | break; | ||
| 498 | } | ||
| 499 | } | ||
| 500 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 501 | for (i = 0; i < blockSize;) | ||
| 502 | { | ||
| 503 | UInt32 groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax); | ||
| 504 | if ((Indices[i] & 0x40000000) != 0) | ||
| 505 | { | ||
| 506 | groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); | ||
| 507 | Indices[(size_t)i + 1] &= kIndexMask; | ||
| 508 | } | ||
| 509 | Indices[i] &= kIndexMask; | ||
| 510 | groupSize++; | ||
| 511 | i += groupSize; | ||
| 512 | } | ||
| 513 | #endif | ||
| 514 | return Groups[0]; | ||
| 515 | } | ||
diff --git a/C/BwtSort.h b/C/BwtSort.h new file mode 100644 index 0000000..7e989a9 --- /dev/null +++ b/C/BwtSort.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* BwtSort.h -- BWT block sorting | ||
| 2 | 2013-01-18 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __BWT_SORT_H | ||
| 5 | #define __BWT_SORT_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | /* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize can be > 1M */ | ||
| 12 | /* #define BLOCK_SORT_EXTERNAL_FLAGS */ | ||
| 13 | |||
| 14 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 15 | #define BLOCK_SORT_EXTERNAL_SIZE(blockSize) ((((blockSize) + 31) >> 5)) | ||
| 16 | #else | ||
| 17 | #define BLOCK_SORT_EXTERNAL_SIZE(blockSize) 0 | ||
| 18 | #endif | ||
| 19 | |||
| 20 | #define BLOCK_SORT_BUF_SIZE(blockSize) ((blockSize) * 2 + BLOCK_SORT_EXTERNAL_SIZE(blockSize) + (1 << 16)) | ||
| 21 | |||
| 22 | UInt32 BlockSort(UInt32 *indices, const Byte *data, UInt32 blockSize); | ||
| 23 | |||
| 24 | EXTERN_C_END | ||
| 25 | |||
| 26 | #endif | ||
diff --git a/C/Compiler.h b/C/Compiler.h new file mode 100644 index 0000000..a9816fa --- /dev/null +++ b/C/Compiler.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* Compiler.h | ||
| 2 | 2021-01-05 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_COMPILER_H | ||
| 5 | #define __7Z_COMPILER_H | ||
| 6 | |||
| 7 | #ifdef __clang__ | ||
| 8 | #pragma clang diagnostic ignored "-Wunused-private-field" | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #ifdef _MSC_VER | ||
| 12 | |||
| 13 | #ifdef UNDER_CE | ||
| 14 | #define RPC_NO_WINDOWS_H | ||
| 15 | /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ | ||
| 16 | #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union | ||
| 17 | #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int | ||
| 18 | #endif | ||
| 19 | |||
| 20 | #if _MSC_VER >= 1300 | ||
| 21 | #pragma warning(disable : 4996) // This function or variable may be unsafe | ||
| 22 | #else | ||
| 23 | #pragma warning(disable : 4511) // copy constructor could not be generated | ||
| 24 | #pragma warning(disable : 4512) // assignment operator could not be generated | ||
| 25 | #pragma warning(disable : 4514) // unreferenced inline function has been removed | ||
| 26 | #pragma warning(disable : 4702) // unreachable code | ||
| 27 | #pragma warning(disable : 4710) // not inlined | ||
| 28 | #pragma warning(disable : 4714) // function marked as __forceinline not inlined | ||
| 29 | #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #ifdef __clang__ | ||
| 33 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" | ||
| 34 | #pragma clang diagnostic ignored "-Wmicrosoft-exception-spec" | ||
| 35 | // #pragma clang diagnostic ignored "-Wreserved-id-macro" | ||
| 36 | #endif | ||
| 37 | |||
| 38 | #endif | ||
| 39 | |||
| 40 | #define UNUSED_VAR(x) (void)x; | ||
| 41 | /* #define UNUSED_VAR(x) x=x; */ | ||
| 42 | |||
| 43 | #endif | ||
diff --git a/C/CpuArch.c b/C/CpuArch.c new file mode 100644 index 0000000..fa9afe3 --- /dev/null +++ b/C/CpuArch.c | |||
| @@ -0,0 +1,478 @@ | |||
| 1 | /* CpuArch.c -- CPU specific code | ||
| 2 | 2021-07-13 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "CpuArch.h" | ||
| 7 | |||
| 8 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 9 | |||
| 10 | #if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) | ||
| 11 | #define USE_ASM | ||
| 12 | #endif | ||
| 13 | |||
| 14 | #if !defined(USE_ASM) && _MSC_VER >= 1500 | ||
| 15 | #include <intrin.h> | ||
| 16 | #endif | ||
| 17 | |||
| 18 | #if defined(USE_ASM) && !defined(MY_CPU_AMD64) | ||
| 19 | static UInt32 CheckFlag(UInt32 flag) | ||
| 20 | { | ||
| 21 | #ifdef _MSC_VER | ||
| 22 | __asm pushfd; | ||
| 23 | __asm pop EAX; | ||
| 24 | __asm mov EDX, EAX; | ||
| 25 | __asm xor EAX, flag; | ||
| 26 | __asm push EAX; | ||
| 27 | __asm popfd; | ||
| 28 | __asm pushfd; | ||
| 29 | __asm pop EAX; | ||
| 30 | __asm xor EAX, EDX; | ||
| 31 | __asm push EDX; | ||
| 32 | __asm popfd; | ||
| 33 | __asm and flag, EAX; | ||
| 34 | #else | ||
| 35 | __asm__ __volatile__ ( | ||
| 36 | "pushf\n\t" | ||
| 37 | "pop %%EAX\n\t" | ||
| 38 | "movl %%EAX,%%EDX\n\t" | ||
| 39 | "xorl %0,%%EAX\n\t" | ||
| 40 | "push %%EAX\n\t" | ||
| 41 | "popf\n\t" | ||
| 42 | "pushf\n\t" | ||
| 43 | "pop %%EAX\n\t" | ||
| 44 | "xorl %%EDX,%%EAX\n\t" | ||
| 45 | "push %%EDX\n\t" | ||
| 46 | "popf\n\t" | ||
| 47 | "andl %%EAX, %0\n\t": | ||
| 48 | "=c" (flag) : "c" (flag) : | ||
| 49 | "%eax", "%edx"); | ||
| 50 | #endif | ||
| 51 | return flag; | ||
| 52 | } | ||
| 53 | #define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; | ||
| 54 | #else | ||
| 55 | #define CHECK_CPUID_IS_SUPPORTED | ||
| 56 | #endif | ||
| 57 | |||
| 58 | #ifndef USE_ASM | ||
| 59 | #ifdef _MSC_VER | ||
| 60 | #if _MSC_VER >= 1600 | ||
| 61 | #define MY__cpuidex __cpuidex | ||
| 62 | #else | ||
| 63 | |||
| 64 | /* | ||
| 65 | __cpuid (function == 4) requires subfunction number in ECX. | ||
| 66 | MSDN: The __cpuid intrinsic clears the ECX register before calling the cpuid instruction. | ||
| 67 | __cpuid() in new MSVC clears ECX. | ||
| 68 | __cpuid() in old MSVC (14.00) doesn't clear ECX | ||
| 69 | We still can use __cpuid for low (function) values that don't require ECX, | ||
| 70 | but __cpuid() in old MSVC will be incorrect for some function values: (function == 4). | ||
| 71 | So here we use the hack for old MSVC to send (subFunction) in ECX register to cpuid instruction, | ||
| 72 | where ECX value is first parameter for FAST_CALL / NO_INLINE function, | ||
| 73 | So the caller of MY__cpuidex_HACK() sets ECX as subFunction, and | ||
| 74 | old MSVC for __cpuid() doesn't change ECX and cpuid instruction gets (subFunction) value. | ||
| 75 | |||
| 76 | DON'T remove MY_NO_INLINE and MY_FAST_CALL for MY__cpuidex_HACK() !!! | ||
| 77 | */ | ||
| 78 | |||
| 79 | static | ||
| 80 | MY_NO_INLINE | ||
| 81 | void MY_FAST_CALL MY__cpuidex_HACK(UInt32 subFunction, int *CPUInfo, UInt32 function) | ||
| 82 | { | ||
| 83 | UNUSED_VAR(subFunction); | ||
| 84 | __cpuid(CPUInfo, function); | ||
| 85 | } | ||
| 86 | |||
| 87 | #define MY__cpuidex(info, func, func2) MY__cpuidex_HACK(func2, info, func) | ||
| 88 | #pragma message("======== MY__cpuidex_HACK WAS USED ========") | ||
| 89 | #endif | ||
| 90 | #else | ||
| 91 | #define MY__cpuidex(info, func, func2) __cpuid(info, func) | ||
| 92 | #pragma message("======== (INCORRECT ?) cpuid WAS USED ========") | ||
| 93 | #endif | ||
| 94 | #endif | ||
| 95 | |||
| 96 | |||
| 97 | |||
| 98 | |||
| 99 | void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) | ||
| 100 | { | ||
| 101 | #ifdef USE_ASM | ||
| 102 | |||
| 103 | #ifdef _MSC_VER | ||
| 104 | |||
| 105 | UInt32 a2, b2, c2, d2; | ||
| 106 | __asm xor EBX, EBX; | ||
| 107 | __asm xor ECX, ECX; | ||
| 108 | __asm xor EDX, EDX; | ||
| 109 | __asm mov EAX, function; | ||
| 110 | __asm cpuid; | ||
| 111 | __asm mov a2, EAX; | ||
| 112 | __asm mov b2, EBX; | ||
| 113 | __asm mov c2, ECX; | ||
| 114 | __asm mov d2, EDX; | ||
| 115 | |||
| 116 | *a = a2; | ||
| 117 | *b = b2; | ||
| 118 | *c = c2; | ||
| 119 | *d = d2; | ||
| 120 | |||
| 121 | #else | ||
| 122 | |||
| 123 | __asm__ __volatile__ ( | ||
| 124 | #if defined(MY_CPU_AMD64) && defined(__PIC__) | ||
| 125 | "mov %%rbx, %%rdi;" | ||
| 126 | "cpuid;" | ||
| 127 | "xchg %%rbx, %%rdi;" | ||
| 128 | : "=a" (*a) , | ||
| 129 | "=D" (*b) , | ||
| 130 | #elif defined(MY_CPU_X86) && defined(__PIC__) | ||
| 131 | "mov %%ebx, %%edi;" | ||
| 132 | "cpuid;" | ||
| 133 | "xchgl %%ebx, %%edi;" | ||
| 134 | : "=a" (*a) , | ||
| 135 | "=D" (*b) , | ||
| 136 | #else | ||
| 137 | "cpuid" | ||
| 138 | : "=a" (*a) , | ||
| 139 | "=b" (*b) , | ||
| 140 | #endif | ||
| 141 | "=c" (*c) , | ||
| 142 | "=d" (*d) | ||
| 143 | : "0" (function), "c"(0) ) ; | ||
| 144 | |||
| 145 | #endif | ||
| 146 | |||
| 147 | #else | ||
| 148 | |||
| 149 | int CPUInfo[4]; | ||
| 150 | |||
| 151 | MY__cpuidex(CPUInfo, (int)function, 0); | ||
| 152 | |||
| 153 | *a = (UInt32)CPUInfo[0]; | ||
| 154 | *b = (UInt32)CPUInfo[1]; | ||
| 155 | *c = (UInt32)CPUInfo[2]; | ||
| 156 | *d = (UInt32)CPUInfo[3]; | ||
| 157 | |||
| 158 | #endif | ||
| 159 | } | ||
| 160 | |||
| 161 | BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p) | ||
| 162 | { | ||
| 163 | CHECK_CPUID_IS_SUPPORTED | ||
| 164 | MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); | ||
| 165 | MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); | ||
| 166 | return True; | ||
| 167 | } | ||
| 168 | |||
| 169 | static const UInt32 kVendors[][3] = | ||
| 170 | { | ||
| 171 | { 0x756E6547, 0x49656E69, 0x6C65746E}, | ||
| 172 | { 0x68747541, 0x69746E65, 0x444D4163}, | ||
| 173 | { 0x746E6543, 0x48727561, 0x736C7561} | ||
| 174 | }; | ||
| 175 | |||
| 176 | int x86cpuid_GetFirm(const Cx86cpuid *p) | ||
| 177 | { | ||
| 178 | unsigned i; | ||
| 179 | for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) | ||
| 180 | { | ||
| 181 | const UInt32 *v = kVendors[i]; | ||
| 182 | if (v[0] == p->vendor[0] && | ||
| 183 | v[1] == p->vendor[1] && | ||
| 184 | v[2] == p->vendor[2]) | ||
| 185 | return (int)i; | ||
| 186 | } | ||
| 187 | return -1; | ||
| 188 | } | ||
| 189 | |||
| 190 | BoolInt CPU_Is_InOrder() | ||
| 191 | { | ||
| 192 | Cx86cpuid p; | ||
| 193 | int firm; | ||
| 194 | UInt32 family, model; | ||
| 195 | if (!x86cpuid_CheckAndRead(&p)) | ||
| 196 | return True; | ||
| 197 | |||
| 198 | family = x86cpuid_GetFamily(p.ver); | ||
| 199 | model = x86cpuid_GetModel(p.ver); | ||
| 200 | |||
| 201 | firm = x86cpuid_GetFirm(&p); | ||
| 202 | |||
| 203 | switch (firm) | ||
| 204 | { | ||
| 205 | case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( | ||
| 206 | /* In-Order Atom CPU */ | ||
| 207 | model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ | ||
| 208 | || model == 0x26 /* 45 nm, Z6xx */ | ||
| 209 | || model == 0x27 /* 32 nm, Z2460 */ | ||
| 210 | || model == 0x35 /* 32 nm, Z2760 */ | ||
| 211 | || model == 0x36 /* 32 nm, N2xxx, D2xxx */ | ||
| 212 | ))); | ||
| 213 | case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); | ||
| 214 | case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); | ||
| 215 | } | ||
| 216 | return True; | ||
| 217 | } | ||
| 218 | |||
| 219 | #if !defined(MY_CPU_AMD64) && defined(_WIN32) | ||
| 220 | #include <Windows.h> | ||
| 221 | static BoolInt CPU_Sys_Is_SSE_Supported() | ||
| 222 | { | ||
| 223 | OSVERSIONINFO vi; | ||
| 224 | vi.dwOSVersionInfoSize = sizeof(vi); | ||
| 225 | if (!GetVersionEx(&vi)) | ||
| 226 | return False; | ||
| 227 | return (vi.dwMajorVersion >= 5); | ||
| 228 | } | ||
| 229 | #define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; | ||
| 230 | #else | ||
| 231 | #define CHECK_SYS_SSE_SUPPORT | ||
| 232 | #endif | ||
| 233 | |||
| 234 | |||
| 235 | static UInt32 X86_CPUID_ECX_Get_Flags() | ||
| 236 | { | ||
| 237 | Cx86cpuid p; | ||
| 238 | CHECK_SYS_SSE_SUPPORT | ||
| 239 | if (!x86cpuid_CheckAndRead(&p)) | ||
| 240 | return 0; | ||
| 241 | return p.c; | ||
| 242 | } | ||
| 243 | |||
| 244 | BoolInt CPU_IsSupported_AES() | ||
| 245 | { | ||
| 246 | return (X86_CPUID_ECX_Get_Flags() >> 25) & 1; | ||
| 247 | } | ||
| 248 | |||
| 249 | BoolInt CPU_IsSupported_SSSE3() | ||
| 250 | { | ||
| 251 | return (X86_CPUID_ECX_Get_Flags() >> 9) & 1; | ||
| 252 | } | ||
| 253 | |||
| 254 | BoolInt CPU_IsSupported_SSE41() | ||
| 255 | { | ||
| 256 | return (X86_CPUID_ECX_Get_Flags() >> 19) & 1; | ||
| 257 | } | ||
| 258 | |||
| 259 | BoolInt CPU_IsSupported_SHA() | ||
| 260 | { | ||
| 261 | Cx86cpuid p; | ||
| 262 | CHECK_SYS_SSE_SUPPORT | ||
| 263 | if (!x86cpuid_CheckAndRead(&p)) | ||
| 264 | return False; | ||
| 265 | |||
| 266 | if (p.maxFunc < 7) | ||
| 267 | return False; | ||
| 268 | { | ||
| 269 | UInt32 d[4] = { 0 }; | ||
| 270 | MyCPUID(7, &d[0], &d[1], &d[2], &d[3]); | ||
| 271 | return (d[1] >> 29) & 1; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | // #include <stdio.h> | ||
| 276 | |||
| 277 | #ifdef _WIN32 | ||
| 278 | #include <Windows.h> | ||
| 279 | #endif | ||
| 280 | |||
| 281 | BoolInt CPU_IsSupported_AVX2() | ||
| 282 | { | ||
| 283 | Cx86cpuid p; | ||
| 284 | CHECK_SYS_SSE_SUPPORT | ||
| 285 | |||
| 286 | #ifdef _WIN32 | ||
| 287 | #define MY__PF_XSAVE_ENABLED 17 | ||
| 288 | if (!IsProcessorFeaturePresent(MY__PF_XSAVE_ENABLED)) | ||
| 289 | return False; | ||
| 290 | #endif | ||
| 291 | |||
| 292 | if (!x86cpuid_CheckAndRead(&p)) | ||
| 293 | return False; | ||
| 294 | if (p.maxFunc < 7) | ||
| 295 | return False; | ||
| 296 | { | ||
| 297 | UInt32 d[4] = { 0 }; | ||
| 298 | MyCPUID(7, &d[0], &d[1], &d[2], &d[3]); | ||
| 299 | // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]); | ||
| 300 | return 1 | ||
| 301 | & (d[1] >> 5); // avx2 | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | BoolInt CPU_IsSupported_VAES_AVX2() | ||
| 306 | { | ||
| 307 | Cx86cpuid p; | ||
| 308 | CHECK_SYS_SSE_SUPPORT | ||
| 309 | |||
| 310 | #ifdef _WIN32 | ||
| 311 | #define MY__PF_XSAVE_ENABLED 17 | ||
| 312 | if (!IsProcessorFeaturePresent(MY__PF_XSAVE_ENABLED)) | ||
| 313 | return False; | ||
| 314 | #endif | ||
| 315 | |||
| 316 | if (!x86cpuid_CheckAndRead(&p)) | ||
| 317 | return False; | ||
| 318 | if (p.maxFunc < 7) | ||
| 319 | return False; | ||
| 320 | { | ||
| 321 | UInt32 d[4] = { 0 }; | ||
| 322 | MyCPUID(7, &d[0], &d[1], &d[2], &d[3]); | ||
| 323 | // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]); | ||
| 324 | return 1 | ||
| 325 | & (d[1] >> 5) // avx2 | ||
| 326 | // & (d[1] >> 31) // avx512vl | ||
| 327 | & (d[2] >> 9); // vaes // VEX-256/EVEX | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | BoolInt CPU_IsSupported_PageGB() | ||
| 332 | { | ||
| 333 | Cx86cpuid cpuid; | ||
| 334 | if (!x86cpuid_CheckAndRead(&cpuid)) | ||
| 335 | return False; | ||
| 336 | { | ||
| 337 | UInt32 d[4] = { 0 }; | ||
| 338 | MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]); | ||
| 339 | if (d[0] < 0x80000001) | ||
| 340 | return False; | ||
| 341 | } | ||
| 342 | { | ||
| 343 | UInt32 d[4] = { 0 }; | ||
| 344 | MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]); | ||
| 345 | return (d[3] >> 26) & 1; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | |||
| 350 | #elif defined(MY_CPU_ARM_OR_ARM64) | ||
| 351 | |||
| 352 | #ifdef _WIN32 | ||
| 353 | |||
| 354 | #include <Windows.h> | ||
| 355 | |||
| 356 | BoolInt CPU_IsSupported_CRC32() { return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } | ||
| 357 | BoolInt CPU_IsSupported_CRYPTO() { return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } | ||
| 358 | BoolInt CPU_IsSupported_NEON() { return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } | ||
| 359 | |||
| 360 | #else | ||
| 361 | |||
| 362 | #if defined(__APPLE__) | ||
| 363 | |||
| 364 | /* | ||
| 365 | #include <stdio.h> | ||
| 366 | #include <string.h> | ||
| 367 | static void Print_sysctlbyname(const char *name) | ||
| 368 | { | ||
| 369 | size_t bufSize = 256; | ||
| 370 | char buf[256]; | ||
| 371 | int res = sysctlbyname(name, &buf, &bufSize, NULL, 0); | ||
| 372 | { | ||
| 373 | int i; | ||
| 374 | printf("\nres = %d : %s : '%s' : bufSize = %d, numeric", res, name, buf, (unsigned)bufSize); | ||
| 375 | for (i = 0; i < 20; i++) | ||
| 376 | printf(" %2x", (unsigned)(Byte)buf[i]); | ||
| 377 | |||
| 378 | } | ||
| 379 | } | ||
| 380 | */ | ||
| 381 | |||
| 382 | static BoolInt My_sysctlbyname_Get_BoolInt(const char *name) | ||
| 383 | { | ||
| 384 | UInt32 val = 0; | ||
| 385 | if (My_sysctlbyname_Get_UInt32(name, &val) == 0 && val == 1) | ||
| 386 | return 1; | ||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | /* | ||
| 391 | Print_sysctlbyname("hw.pagesize"); | ||
| 392 | Print_sysctlbyname("machdep.cpu.brand_string"); | ||
| 393 | */ | ||
| 394 | |||
| 395 | BoolInt CPU_IsSupported_CRC32(void) | ||
| 396 | { | ||
| 397 | return My_sysctlbyname_Get_BoolInt("hw.optional.armv8_crc32"); | ||
| 398 | } | ||
| 399 | |||
| 400 | BoolInt CPU_IsSupported_NEON(void) | ||
| 401 | { | ||
| 402 | return My_sysctlbyname_Get_BoolInt("hw.optional.neon"); | ||
| 403 | } | ||
| 404 | |||
| 405 | #ifdef MY_CPU_ARM64 | ||
| 406 | #define APPLE_CRYPTO_SUPPORT_VAL 1 | ||
| 407 | #else | ||
| 408 | #define APPLE_CRYPTO_SUPPORT_VAL 0 | ||
| 409 | #endif | ||
| 410 | |||
| 411 | BoolInt CPU_IsSupported_SHA1(void) { return APPLE_CRYPTO_SUPPORT_VAL; } | ||
| 412 | BoolInt CPU_IsSupported_SHA2(void) { return APPLE_CRYPTO_SUPPORT_VAL; } | ||
| 413 | BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; } | ||
| 414 | |||
| 415 | |||
| 416 | #else // __APPLE__ | ||
| 417 | |||
| 418 | #include <sys/auxv.h> | ||
| 419 | |||
| 420 | #define USE_HWCAP | ||
| 421 | |||
| 422 | #ifdef USE_HWCAP | ||
| 423 | |||
| 424 | #include <asm/hwcap.h> | ||
| 425 | |||
| 426 | #define MY_HWCAP_CHECK_FUNC_2(name1, name2) \ | ||
| 427 | BoolInt CPU_IsSupported_ ## name1() { return (getauxval(AT_HWCAP) & (HWCAP_ ## name2)) ? 1 : 0; } | ||
| 428 | |||
| 429 | #ifdef MY_CPU_ARM64 | ||
| 430 | #define MY_HWCAP_CHECK_FUNC(name) \ | ||
| 431 | MY_HWCAP_CHECK_FUNC_2(name, name) | ||
| 432 | MY_HWCAP_CHECK_FUNC_2(NEON, ASIMD) | ||
| 433 | // MY_HWCAP_CHECK_FUNC (ASIMD) | ||
| 434 | #elif defined(MY_CPU_ARM) | ||
| 435 | #define MY_HWCAP_CHECK_FUNC(name) \ | ||
| 436 | BoolInt CPU_IsSupported_ ## name() { return (getauxval(AT_HWCAP2) & (HWCAP2_ ## name)) ? 1 : 0; } | ||
| 437 | MY_HWCAP_CHECK_FUNC_2(NEON, NEON) | ||
| 438 | #endif | ||
| 439 | |||
| 440 | #else // USE_HWCAP | ||
| 441 | |||
| 442 | #define MY_HWCAP_CHECK_FUNC(name) \ | ||
| 443 | BoolInt CPU_IsSupported_ ## name() { return 0; } | ||
| 444 | MY_HWCAP_CHECK_FUNC(NEON) | ||
| 445 | |||
| 446 | #endif // USE_HWCAP | ||
| 447 | |||
| 448 | MY_HWCAP_CHECK_FUNC (CRC32) | ||
| 449 | MY_HWCAP_CHECK_FUNC (SHA1) | ||
| 450 | MY_HWCAP_CHECK_FUNC (SHA2) | ||
| 451 | MY_HWCAP_CHECK_FUNC (AES) | ||
| 452 | |||
| 453 | #endif // __APPLE__ | ||
| 454 | #endif // _WIN32 | ||
| 455 | |||
| 456 | #endif // MY_CPU_ARM_OR_ARM64 | ||
| 457 | |||
| 458 | |||
| 459 | |||
| 460 | #ifdef __APPLE__ | ||
| 461 | |||
| 462 | #include <sys/sysctl.h> | ||
| 463 | |||
| 464 | int My_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize) | ||
| 465 | { | ||
| 466 | return sysctlbyname(name, buf, bufSize, NULL, 0); | ||
| 467 | } | ||
| 468 | |||
| 469 | int My_sysctlbyname_Get_UInt32(const char *name, UInt32 *val) | ||
| 470 | { | ||
| 471 | size_t bufSize = sizeof(*val); | ||
| 472 | int res = My_sysctlbyname_Get(name, val, &bufSize); | ||
| 473 | if (res == 0 && bufSize != sizeof(*val)) | ||
| 474 | return EFAULT; | ||
| 475 | return res; | ||
| 476 | } | ||
| 477 | |||
| 478 | #endif | ||
diff --git a/C/CpuArch.h b/C/CpuArch.h new file mode 100644 index 0000000..529d3a5 --- /dev/null +++ b/C/CpuArch.h | |||
| @@ -0,0 +1,442 @@ | |||
| 1 | /* CpuArch.h -- CPU specific code | ||
| 2 | 2021-07-13 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __CPU_ARCH_H | ||
| 5 | #define __CPU_ARCH_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | /* | ||
| 12 | MY_CPU_LE means that CPU is LITTLE ENDIAN. | ||
| 13 | MY_CPU_BE means that CPU is BIG ENDIAN. | ||
| 14 | If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform. | ||
| 15 | |||
| 16 | MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. | ||
| 17 | |||
| 18 | MY_CPU_64BIT means that processor can work with 64-bit registers. | ||
| 19 | MY_CPU_64BIT can be used to select fast code branch | ||
| 20 | MY_CPU_64BIT doesn't mean that (sizeof(void *) == 8) | ||
| 21 | */ | ||
| 22 | |||
| 23 | #if defined(_M_X64) \ | ||
| 24 | || defined(_M_AMD64) \ | ||
| 25 | || defined(__x86_64__) \ | ||
| 26 | || defined(__AMD64__) \ | ||
| 27 | || defined(__amd64__) | ||
| 28 | #define MY_CPU_AMD64 | ||
| 29 | #ifdef __ILP32__ | ||
| 30 | #define MY_CPU_NAME "x32" | ||
| 31 | #define MY_CPU_SIZEOF_POINTER 4 | ||
| 32 | #else | ||
| 33 | #define MY_CPU_NAME "x64" | ||
| 34 | #define MY_CPU_SIZEOF_POINTER 8 | ||
| 35 | #endif | ||
| 36 | #define MY_CPU_64BIT | ||
| 37 | #endif | ||
| 38 | |||
| 39 | |||
| 40 | #if defined(_M_IX86) \ | ||
| 41 | || defined(__i386__) | ||
| 42 | #define MY_CPU_X86 | ||
| 43 | #define MY_CPU_NAME "x86" | ||
| 44 | /* #define MY_CPU_32BIT */ | ||
| 45 | #define MY_CPU_SIZEOF_POINTER 4 | ||
| 46 | #endif | ||
| 47 | |||
| 48 | |||
| 49 | #if defined(_M_ARM64) \ | ||
| 50 | || defined(__AARCH64EL__) \ | ||
| 51 | || defined(__AARCH64EB__) \ | ||
| 52 | || defined(__aarch64__) | ||
| 53 | #define MY_CPU_ARM64 | ||
| 54 | #define MY_CPU_NAME "arm64" | ||
| 55 | #define MY_CPU_64BIT | ||
| 56 | #endif | ||
| 57 | |||
| 58 | |||
| 59 | #if defined(_M_ARM) \ | ||
| 60 | || defined(_M_ARM_NT) \ | ||
| 61 | || defined(_M_ARMT) \ | ||
| 62 | || defined(__arm__) \ | ||
| 63 | || defined(__thumb__) \ | ||
| 64 | || defined(__ARMEL__) \ | ||
| 65 | || defined(__ARMEB__) \ | ||
| 66 | || defined(__THUMBEL__) \ | ||
| 67 | || defined(__THUMBEB__) | ||
| 68 | #define MY_CPU_ARM | ||
| 69 | |||
| 70 | #if defined(__thumb__) || defined(__THUMBEL__) || defined(_M_ARMT) | ||
| 71 | #define MY_CPU_NAME "armt" | ||
| 72 | #else | ||
| 73 | #define MY_CPU_NAME "arm" | ||
| 74 | #endif | ||
| 75 | /* #define MY_CPU_32BIT */ | ||
| 76 | #define MY_CPU_SIZEOF_POINTER 4 | ||
| 77 | #endif | ||
| 78 | |||
| 79 | |||
| 80 | #if defined(_M_IA64) \ | ||
| 81 | || defined(__ia64__) | ||
| 82 | #define MY_CPU_IA64 | ||
| 83 | #define MY_CPU_NAME "ia64" | ||
| 84 | #define MY_CPU_64BIT | ||
| 85 | #endif | ||
| 86 | |||
| 87 | |||
| 88 | #if defined(__mips64) \ | ||
| 89 | || defined(__mips64__) \ | ||
| 90 | || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3)) | ||
| 91 | #define MY_CPU_NAME "mips64" | ||
| 92 | #define MY_CPU_64BIT | ||
| 93 | #elif defined(__mips__) | ||
| 94 | #define MY_CPU_NAME "mips" | ||
| 95 | /* #define MY_CPU_32BIT */ | ||
| 96 | #endif | ||
| 97 | |||
| 98 | |||
| 99 | #if defined(__ppc64__) \ | ||
| 100 | || defined(__powerpc64__) \ | ||
| 101 | || defined(__ppc__) \ | ||
| 102 | || defined(__powerpc__) \ | ||
| 103 | || defined(__PPC__) \ | ||
| 104 | || defined(_POWER) | ||
| 105 | |||
| 106 | #if defined(__ppc64__) \ | ||
| 107 | || defined(__powerpc64__) \ | ||
| 108 | || defined(_LP64) \ | ||
| 109 | || defined(__64BIT__) | ||
| 110 | #ifdef __ILP32__ | ||
| 111 | #define MY_CPU_NAME "ppc64-32" | ||
| 112 | #define MY_CPU_SIZEOF_POINTER 4 | ||
| 113 | #else | ||
| 114 | #define MY_CPU_NAME "ppc64" | ||
| 115 | #define MY_CPU_SIZEOF_POINTER 8 | ||
| 116 | #endif | ||
| 117 | #define MY_CPU_64BIT | ||
| 118 | #else | ||
| 119 | #define MY_CPU_NAME "ppc" | ||
| 120 | #define MY_CPU_SIZEOF_POINTER 4 | ||
| 121 | /* #define MY_CPU_32BIT */ | ||
| 122 | #endif | ||
| 123 | #endif | ||
| 124 | |||
| 125 | |||
| 126 | #if defined(__sparc64__) | ||
| 127 | #define MY_CPU_NAME "sparc64" | ||
| 128 | #define MY_CPU_64BIT | ||
| 129 | #elif defined(__sparc__) | ||
| 130 | #define MY_CPU_NAME "sparc" | ||
| 131 | /* #define MY_CPU_32BIT */ | ||
| 132 | #endif | ||
| 133 | |||
| 134 | |||
| 135 | #if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) | ||
| 136 | #define MY_CPU_X86_OR_AMD64 | ||
| 137 | #endif | ||
| 138 | |||
| 139 | #if defined(MY_CPU_ARM) || defined(MY_CPU_ARM64) | ||
| 140 | #define MY_CPU_ARM_OR_ARM64 | ||
| 141 | #endif | ||
| 142 | |||
| 143 | |||
| 144 | #ifdef _WIN32 | ||
| 145 | |||
| 146 | #ifdef MY_CPU_ARM | ||
| 147 | #define MY_CPU_ARM_LE | ||
| 148 | #endif | ||
| 149 | |||
| 150 | #ifdef MY_CPU_ARM64 | ||
| 151 | #define MY_CPU_ARM64_LE | ||
| 152 | #endif | ||
| 153 | |||
| 154 | #ifdef _M_IA64 | ||
| 155 | #define MY_CPU_IA64_LE | ||
| 156 | #endif | ||
| 157 | |||
| 158 | #endif | ||
| 159 | |||
| 160 | |||
| 161 | #if defined(MY_CPU_X86_OR_AMD64) \ | ||
| 162 | || defined(MY_CPU_ARM_LE) \ | ||
| 163 | || defined(MY_CPU_ARM64_LE) \ | ||
| 164 | || defined(MY_CPU_IA64_LE) \ | ||
| 165 | || defined(__LITTLE_ENDIAN__) \ | ||
| 166 | || defined(__ARMEL__) \ | ||
| 167 | || defined(__THUMBEL__) \ | ||
| 168 | || defined(__AARCH64EL__) \ | ||
| 169 | || defined(__MIPSEL__) \ | ||
| 170 | || defined(__MIPSEL) \ | ||
| 171 | || defined(_MIPSEL) \ | ||
| 172 | || defined(__BFIN__) \ | ||
| 173 | || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) | ||
| 174 | #define MY_CPU_LE | ||
| 175 | #endif | ||
| 176 | |||
| 177 | #if defined(__BIG_ENDIAN__) \ | ||
| 178 | || defined(__ARMEB__) \ | ||
| 179 | || defined(__THUMBEB__) \ | ||
| 180 | || defined(__AARCH64EB__) \ | ||
| 181 | || defined(__MIPSEB__) \ | ||
| 182 | || defined(__MIPSEB) \ | ||
| 183 | || defined(_MIPSEB) \ | ||
| 184 | || defined(__m68k__) \ | ||
| 185 | || defined(__s390__) \ | ||
| 186 | || defined(__s390x__) \ | ||
| 187 | || defined(__zarch__) \ | ||
| 188 | || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) | ||
| 189 | #define MY_CPU_BE | ||
| 190 | #endif | ||
| 191 | |||
| 192 | |||
| 193 | #if defined(MY_CPU_LE) && defined(MY_CPU_BE) | ||
| 194 | #error Stop_Compiling_Bad_Endian | ||
| 195 | #endif | ||
| 196 | |||
| 197 | |||
| 198 | #if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT) | ||
| 199 | #error Stop_Compiling_Bad_32_64_BIT | ||
| 200 | #endif | ||
| 201 | |||
| 202 | #ifdef __SIZEOF_POINTER__ | ||
| 203 | #ifdef MY_CPU_SIZEOF_POINTER | ||
| 204 | #if MY_CPU_SIZEOF_POINTER != __SIZEOF_POINTER__ | ||
| 205 | #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE | ||
| 206 | #endif | ||
| 207 | #else | ||
| 208 | #define MY_CPU_SIZEOF_POINTER __SIZEOF_POINTER__ | ||
| 209 | #endif | ||
| 210 | #endif | ||
| 211 | |||
| 212 | #if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) | ||
| 213 | #if defined (_LP64) | ||
| 214 | #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE | ||
| 215 | #endif | ||
| 216 | #endif | ||
| 217 | |||
| 218 | #ifdef _MSC_VER | ||
| 219 | #if _MSC_VER >= 1300 | ||
| 220 | #define MY_CPU_pragma_pack_push_1 __pragma(pack(push, 1)) | ||
| 221 | #define MY_CPU_pragma_pop __pragma(pack(pop)) | ||
| 222 | #else | ||
| 223 | #define MY_CPU_pragma_pack_push_1 | ||
| 224 | #define MY_CPU_pragma_pop | ||
| 225 | #endif | ||
| 226 | #else | ||
| 227 | #ifdef __xlC__ | ||
| 228 | #define MY_CPU_pragma_pack_push_1 _Pragma("pack(1)") | ||
| 229 | #define MY_CPU_pragma_pop _Pragma("pack()") | ||
| 230 | #else | ||
| 231 | #define MY_CPU_pragma_pack_push_1 _Pragma("pack(push, 1)") | ||
| 232 | #define MY_CPU_pragma_pop _Pragma("pack(pop)") | ||
| 233 | #endif | ||
| 234 | #endif | ||
| 235 | |||
| 236 | |||
| 237 | #ifndef MY_CPU_NAME | ||
| 238 | #ifdef MY_CPU_LE | ||
| 239 | #define MY_CPU_NAME "LE" | ||
| 240 | #elif defined(MY_CPU_BE) | ||
| 241 | #define MY_CPU_NAME "BE" | ||
| 242 | #else | ||
| 243 | /* | ||
| 244 | #define MY_CPU_NAME "" | ||
| 245 | */ | ||
| 246 | #endif | ||
| 247 | #endif | ||
| 248 | |||
| 249 | |||
| 250 | |||
| 251 | |||
| 252 | |||
| 253 | #ifdef MY_CPU_LE | ||
| 254 | #if defined(MY_CPU_X86_OR_AMD64) \ | ||
| 255 | || defined(MY_CPU_ARM64) | ||
| 256 | #define MY_CPU_LE_UNALIGN | ||
| 257 | #define MY_CPU_LE_UNALIGN_64 | ||
| 258 | #elif defined(__ARM_FEATURE_UNALIGNED) | ||
| 259 | /* gcc9 for 32-bit arm can use LDRD instruction that requires 32-bit alignment. | ||
| 260 | So we can't use unaligned 64-bit operations. */ | ||
| 261 | #define MY_CPU_LE_UNALIGN | ||
| 262 | #endif | ||
| 263 | #endif | ||
| 264 | |||
| 265 | |||
| 266 | #ifdef MY_CPU_LE_UNALIGN | ||
| 267 | |||
| 268 | #define GetUi16(p) (*(const UInt16 *)(const void *)(p)) | ||
| 269 | #define GetUi32(p) (*(const UInt32 *)(const void *)(p)) | ||
| 270 | #ifdef MY_CPU_LE_UNALIGN_64 | ||
| 271 | #define GetUi64(p) (*(const UInt64 *)(const void *)(p)) | ||
| 272 | #endif | ||
| 273 | |||
| 274 | #define SetUi16(p, v) { *(UInt16 *)(void *)(p) = (v); } | ||
| 275 | #define SetUi32(p, v) { *(UInt32 *)(void *)(p) = (v); } | ||
| 276 | #ifdef MY_CPU_LE_UNALIGN_64 | ||
| 277 | #define SetUi64(p, v) { *(UInt64 *)(void *)(p) = (v); } | ||
| 278 | #endif | ||
| 279 | |||
| 280 | #else | ||
| 281 | |||
| 282 | #define GetUi16(p) ( (UInt16) ( \ | ||
| 283 | ((const Byte *)(p))[0] | \ | ||
| 284 | ((UInt16)((const Byte *)(p))[1] << 8) )) | ||
| 285 | |||
| 286 | #define GetUi32(p) ( \ | ||
| 287 | ((const Byte *)(p))[0] | \ | ||
| 288 | ((UInt32)((const Byte *)(p))[1] << 8) | \ | ||
| 289 | ((UInt32)((const Byte *)(p))[2] << 16) | \ | ||
| 290 | ((UInt32)((const Byte *)(p))[3] << 24)) | ||
| 291 | |||
| 292 | #define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ | ||
| 293 | _ppp_[0] = (Byte)_vvv_; \ | ||
| 294 | _ppp_[1] = (Byte)(_vvv_ >> 8); } | ||
| 295 | |||
| 296 | #define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ | ||
| 297 | _ppp_[0] = (Byte)_vvv_; \ | ||
| 298 | _ppp_[1] = (Byte)(_vvv_ >> 8); \ | ||
| 299 | _ppp_[2] = (Byte)(_vvv_ >> 16); \ | ||
| 300 | _ppp_[3] = (Byte)(_vvv_ >> 24); } | ||
| 301 | |||
| 302 | #endif | ||
| 303 | |||
| 304 | |||
| 305 | #ifndef MY_CPU_LE_UNALIGN_64 | ||
| 306 | |||
| 307 | #define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) | ||
| 308 | |||
| 309 | #define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \ | ||
| 310 | SetUi32(_ppp2_ , (UInt32)_vvv2_); \ | ||
| 311 | SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); } | ||
| 312 | |||
| 313 | #endif | ||
| 314 | |||
| 315 | |||
| 316 | |||
| 317 | |||
| 318 | #ifdef __has_builtin | ||
| 319 | #define MY__has_builtin(x) __has_builtin(x) | ||
| 320 | #else | ||
| 321 | #define MY__has_builtin(x) 0 | ||
| 322 | #endif | ||
| 323 | |||
| 324 | #if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ defined(_MSC_VER) && (_MSC_VER >= 1300) | ||
| 325 | |||
| 326 | /* Note: we use bswap instruction, that is unsupported in 386 cpu */ | ||
| 327 | |||
| 328 | #include <stdlib.h> | ||
| 329 | |||
| 330 | #pragma intrinsic(_byteswap_ushort) | ||
| 331 | #pragma intrinsic(_byteswap_ulong) | ||
| 332 | #pragma intrinsic(_byteswap_uint64) | ||
| 333 | |||
| 334 | /* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */ | ||
| 335 | #define GetBe32(p) _byteswap_ulong (*(const UInt32 *)(const void *)(p)) | ||
| 336 | #define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const void *)(p)) | ||
| 337 | |||
| 338 | #define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v) | ||
| 339 | |||
| 340 | #elif defined(MY_CPU_LE_UNALIGN) && ( \ | ||
| 341 | (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \ | ||
| 342 | || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) ) | ||
| 343 | |||
| 344 | /* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const void *)(p)) */ | ||
| 345 | #define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const void *)(p)) | ||
| 346 | #define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const void *)(p)) | ||
| 347 | |||
| 348 | #define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v) | ||
| 349 | |||
| 350 | #else | ||
| 351 | |||
| 352 | #define GetBe32(p) ( \ | ||
| 353 | ((UInt32)((const Byte *)(p))[0] << 24) | \ | ||
| 354 | ((UInt32)((const Byte *)(p))[1] << 16) | \ | ||
| 355 | ((UInt32)((const Byte *)(p))[2] << 8) | \ | ||
| 356 | ((const Byte *)(p))[3] ) | ||
| 357 | |||
| 358 | #define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) | ||
| 359 | |||
| 360 | #define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ | ||
| 361 | _ppp_[0] = (Byte)(_vvv_ >> 24); \ | ||
| 362 | _ppp_[1] = (Byte)(_vvv_ >> 16); \ | ||
| 363 | _ppp_[2] = (Byte)(_vvv_ >> 8); \ | ||
| 364 | _ppp_[3] = (Byte)_vvv_; } | ||
| 365 | |||
| 366 | #endif | ||
| 367 | |||
| 368 | |||
| 369 | #ifndef GetBe16 | ||
| 370 | |||
| 371 | #define GetBe16(p) ( (UInt16) ( \ | ||
| 372 | ((UInt16)((const Byte *)(p))[0] << 8) | \ | ||
| 373 | ((const Byte *)(p))[1] )) | ||
| 374 | |||
| 375 | #endif | ||
| 376 | |||
| 377 | |||
| 378 | |||
| 379 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 380 | |||
| 381 | typedef struct | ||
| 382 | { | ||
| 383 | UInt32 maxFunc; | ||
| 384 | UInt32 vendor[3]; | ||
| 385 | UInt32 ver; | ||
| 386 | UInt32 b; | ||
| 387 | UInt32 c; | ||
| 388 | UInt32 d; | ||
| 389 | } Cx86cpuid; | ||
| 390 | |||
| 391 | enum | ||
| 392 | { | ||
| 393 | CPU_FIRM_INTEL, | ||
| 394 | CPU_FIRM_AMD, | ||
| 395 | CPU_FIRM_VIA | ||
| 396 | }; | ||
| 397 | |||
| 398 | void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d); | ||
| 399 | |||
| 400 | BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p); | ||
| 401 | int x86cpuid_GetFirm(const Cx86cpuid *p); | ||
| 402 | |||
| 403 | #define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF)) | ||
| 404 | #define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF)) | ||
| 405 | #define x86cpuid_GetStepping(ver) (ver & 0xF) | ||
| 406 | |||
| 407 | BoolInt CPU_Is_InOrder(void); | ||
| 408 | |||
| 409 | BoolInt CPU_IsSupported_AES(void); | ||
| 410 | BoolInt CPU_IsSupported_AVX2(void); | ||
| 411 | BoolInt CPU_IsSupported_VAES_AVX2(void); | ||
| 412 | BoolInt CPU_IsSupported_SSSE3(void); | ||
| 413 | BoolInt CPU_IsSupported_SSE41(void); | ||
| 414 | BoolInt CPU_IsSupported_SHA(void); | ||
| 415 | BoolInt CPU_IsSupported_PageGB(void); | ||
| 416 | |||
| 417 | #elif defined(MY_CPU_ARM_OR_ARM64) | ||
| 418 | |||
| 419 | BoolInt CPU_IsSupported_CRC32(void); | ||
| 420 | BoolInt CPU_IsSupported_NEON(void); | ||
| 421 | |||
| 422 | #if defined(_WIN32) | ||
| 423 | BoolInt CPU_IsSupported_CRYPTO(void); | ||
| 424 | #define CPU_IsSupported_SHA1 CPU_IsSupported_CRYPTO | ||
| 425 | #define CPU_IsSupported_SHA2 CPU_IsSupported_CRYPTO | ||
| 426 | #define CPU_IsSupported_AES CPU_IsSupported_CRYPTO | ||
| 427 | #else | ||
| 428 | BoolInt CPU_IsSupported_SHA1(void); | ||
| 429 | BoolInt CPU_IsSupported_SHA2(void); | ||
| 430 | BoolInt CPU_IsSupported_AES(void); | ||
| 431 | #endif | ||
| 432 | |||
| 433 | #endif | ||
| 434 | |||
| 435 | #if defined(__APPLE__) | ||
| 436 | int My_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize); | ||
| 437 | int My_sysctlbyname_Get_UInt32(const char *name, UInt32 *val); | ||
| 438 | #endif | ||
| 439 | |||
| 440 | EXTERN_C_END | ||
| 441 | |||
| 442 | #endif | ||
diff --git a/C/Delta.c b/C/Delta.c new file mode 100644 index 0000000..c4a4499 --- /dev/null +++ b/C/Delta.c | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* Delta.c -- Delta converter | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "Delta.h" | ||
| 7 | |||
| 8 | void Delta_Init(Byte *state) | ||
| 9 | { | ||
| 10 | unsigned i; | ||
| 11 | for (i = 0; i < DELTA_STATE_SIZE; i++) | ||
| 12 | state[i] = 0; | ||
| 13 | } | ||
| 14 | |||
| 15 | |||
| 16 | void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) | ||
| 17 | { | ||
| 18 | Byte temp[DELTA_STATE_SIZE]; | ||
| 19 | |||
| 20 | if (size == 0) | ||
| 21 | return; | ||
| 22 | |||
| 23 | { | ||
| 24 | unsigned i = 0; | ||
| 25 | do | ||
| 26 | temp[i] = state[i]; | ||
| 27 | while (++i != delta); | ||
| 28 | } | ||
| 29 | |||
| 30 | if (size <= delta) | ||
| 31 | { | ||
| 32 | unsigned i = 0, k; | ||
| 33 | do | ||
| 34 | { | ||
| 35 | Byte b = *data; | ||
| 36 | *data++ = (Byte)(b - temp[i]); | ||
| 37 | temp[i] = b; | ||
| 38 | } | ||
| 39 | while (++i != size); | ||
| 40 | |||
| 41 | k = 0; | ||
| 42 | |||
| 43 | do | ||
| 44 | { | ||
| 45 | if (i == delta) | ||
| 46 | i = 0; | ||
| 47 | state[k] = temp[i++]; | ||
| 48 | } | ||
| 49 | while (++k != delta); | ||
| 50 | |||
| 51 | return; | ||
| 52 | } | ||
| 53 | |||
| 54 | { | ||
| 55 | Byte *p = data + size - delta; | ||
| 56 | { | ||
| 57 | unsigned i = 0; | ||
| 58 | do | ||
| 59 | state[i] = *p++; | ||
| 60 | while (++i != delta); | ||
| 61 | } | ||
| 62 | { | ||
| 63 | const Byte *lim = data + delta; | ||
| 64 | ptrdiff_t dif = -(ptrdiff_t)delta; | ||
| 65 | |||
| 66 | if (((ptrdiff_t)size + dif) & 1) | ||
| 67 | { | ||
| 68 | --p; *p = (Byte)(*p - p[dif]); | ||
| 69 | } | ||
| 70 | |||
| 71 | while (p != lim) | ||
| 72 | { | ||
| 73 | --p; *p = (Byte)(*p - p[dif]); | ||
| 74 | --p; *p = (Byte)(*p - p[dif]); | ||
| 75 | } | ||
| 76 | |||
| 77 | dif = -dif; | ||
| 78 | |||
| 79 | do | ||
| 80 | { | ||
| 81 | --p; *p = (Byte)(*p - temp[--dif]); | ||
| 82 | } | ||
| 83 | while (dif != 0); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | |||
| 89 | void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) | ||
| 90 | { | ||
| 91 | unsigned i; | ||
| 92 | const Byte *lim; | ||
| 93 | |||
| 94 | if (size == 0) | ||
| 95 | return; | ||
| 96 | |||
| 97 | i = 0; | ||
| 98 | lim = data + size; | ||
| 99 | |||
| 100 | if (size <= delta) | ||
| 101 | { | ||
| 102 | do | ||
| 103 | *data = (Byte)(*data + state[i++]); | ||
| 104 | while (++data != lim); | ||
| 105 | |||
| 106 | for (; delta != i; state++, delta--) | ||
| 107 | *state = state[i]; | ||
| 108 | data -= i; | ||
| 109 | } | ||
| 110 | else | ||
| 111 | { | ||
| 112 | /* | ||
| 113 | #define B(n) b ## n | ||
| 114 | #define I(n) Byte B(n) = state[n]; | ||
| 115 | #define U(n) { B(n) = (Byte)((B(n)) + *data++); data[-1] = (B(n)); } | ||
| 116 | #define F(n) if (data != lim) { U(n) } | ||
| 117 | |||
| 118 | if (delta == 1) | ||
| 119 | { | ||
| 120 | I(0) | ||
| 121 | if ((lim - data) & 1) { U(0) } | ||
| 122 | while (data != lim) { U(0) U(0) } | ||
| 123 | data -= 1; | ||
| 124 | } | ||
| 125 | else if (delta == 2) | ||
| 126 | { | ||
| 127 | I(0) I(1) | ||
| 128 | lim -= 1; while (data < lim) { U(0) U(1) } | ||
| 129 | lim += 1; F(0) | ||
| 130 | data -= 2; | ||
| 131 | } | ||
| 132 | else if (delta == 3) | ||
| 133 | { | ||
| 134 | I(0) I(1) I(2) | ||
| 135 | lim -= 2; while (data < lim) { U(0) U(1) U(2) } | ||
| 136 | lim += 2; F(0) F(1) | ||
| 137 | data -= 3; | ||
| 138 | } | ||
| 139 | else if (delta == 4) | ||
| 140 | { | ||
| 141 | I(0) I(1) I(2) I(3) | ||
| 142 | lim -= 3; while (data < lim) { U(0) U(1) U(2) U(3) } | ||
| 143 | lim += 3; F(0) F(1) F(2) | ||
| 144 | data -= 4; | ||
| 145 | } | ||
| 146 | else | ||
| 147 | */ | ||
| 148 | { | ||
| 149 | do | ||
| 150 | { | ||
| 151 | *data = (Byte)(*data + state[i++]); | ||
| 152 | data++; | ||
| 153 | } | ||
| 154 | while (i != delta); | ||
| 155 | |||
| 156 | { | ||
| 157 | ptrdiff_t dif = -(ptrdiff_t)delta; | ||
| 158 | do | ||
| 159 | *data = (Byte)(*data + data[dif]); | ||
| 160 | while (++data != lim); | ||
| 161 | data += dif; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | do | ||
| 167 | *state++ = *data; | ||
| 168 | while (++data != lim); | ||
| 169 | } | ||
diff --git a/C/Delta.h b/C/Delta.h new file mode 100644 index 0000000..2fa54ad --- /dev/null +++ b/C/Delta.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* Delta.h -- Delta converter | ||
| 2 | 2013-01-18 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __DELTA_H | ||
| 5 | #define __DELTA_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define DELTA_STATE_SIZE 256 | ||
| 12 | |||
| 13 | void Delta_Init(Byte *state); | ||
| 14 | void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); | ||
| 15 | void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); | ||
| 16 | |||
| 17 | EXTERN_C_END | ||
| 18 | |||
| 19 | #endif | ||
diff --git a/C/DllSecur.c b/C/DllSecur.c new file mode 100644 index 0000000..d81508c --- /dev/null +++ b/C/DllSecur.c | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | /* DllSecur.c -- DLL loading security | ||
| 2 | 2021-12-25 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #ifdef _WIN32 | ||
| 7 | |||
| 8 | #include <Windows.h> | ||
| 9 | |||
| 10 | #include "DllSecur.h" | ||
| 11 | |||
| 12 | #ifndef UNDER_CE | ||
| 13 | |||
| 14 | typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags); | ||
| 15 | |||
| 16 | #define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400 | ||
| 17 | #define MY_LOAD_LIBRARY_SEARCH_SYSTEM32 0x800 | ||
| 18 | |||
| 19 | static const char * const g_Dlls = | ||
| 20 | #ifndef _CONSOLE | ||
| 21 | "UXTHEME\0" | ||
| 22 | #endif | ||
| 23 | "USERENV\0" | ||
| 24 | "SETUPAPI\0" | ||
| 25 | "APPHELP\0" | ||
| 26 | "PROPSYS\0" | ||
| 27 | "DWMAPI\0" | ||
| 28 | "CRYPTBASE\0" | ||
| 29 | "OLEACC\0" | ||
| 30 | "CLBCATQ\0" | ||
| 31 | "VERSION\0" | ||
| 32 | ; | ||
| 33 | |||
| 34 | #endif | ||
| 35 | |||
| 36 | // #define MY_CAST_FUNC (void(*)()) | ||
| 37 | #define MY_CAST_FUNC | ||
| 38 | |||
| 39 | void My_SetDefaultDllDirectories() | ||
| 40 | { | ||
| 41 | #ifndef UNDER_CE | ||
| 42 | |||
| 43 | OSVERSIONINFO vi; | ||
| 44 | vi.dwOSVersionInfoSize = sizeof(vi); | ||
| 45 | if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0) | ||
| 46 | { | ||
| 47 | Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories) | ||
| 48 | MY_CAST_FUNC GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories"); | ||
| 49 | if (setDllDirs) | ||
| 50 | if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | |||
| 54 | #endif | ||
| 55 | } | ||
| 56 | |||
| 57 | |||
| 58 | void LoadSecurityDlls() | ||
| 59 | { | ||
| 60 | #ifndef UNDER_CE | ||
| 61 | |||
| 62 | wchar_t buf[MAX_PATH + 100]; | ||
| 63 | |||
| 64 | { | ||
| 65 | // at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ??? | ||
| 66 | OSVERSIONINFO vi; | ||
| 67 | vi.dwOSVersionInfoSize = sizeof(vi); | ||
| 68 | if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0) | ||
| 69 | { | ||
| 70 | Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories) | ||
| 71 | MY_CAST_FUNC GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories"); | ||
| 72 | if (setDllDirs) | ||
| 73 | if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) | ||
| 74 | return; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | { | ||
| 79 | unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2); | ||
| 80 | if (len == 0 || len > MAX_PATH) | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | { | ||
| 84 | const char *dll; | ||
| 85 | unsigned pos = (unsigned)lstrlenW(buf); | ||
| 86 | |||
| 87 | if (buf[pos - 1] != '\\') | ||
| 88 | buf[pos++] = '\\'; | ||
| 89 | |||
| 90 | for (dll = g_Dlls; dll[0] != 0;) | ||
| 91 | { | ||
| 92 | unsigned k = 0; | ||
| 93 | for (;;) | ||
| 94 | { | ||
| 95 | char c = *dll++; | ||
| 96 | buf[pos + k] = (Byte)c; | ||
| 97 | k++; | ||
| 98 | if (c == 0) | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | |||
| 102 | lstrcatW(buf, L".dll"); | ||
| 103 | LoadLibraryExW(buf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | #endif | ||
| 108 | } | ||
| 109 | |||
| 110 | #endif | ||
diff --git a/C/DllSecur.h b/C/DllSecur.h new file mode 100644 index 0000000..64ff26c --- /dev/null +++ b/C/DllSecur.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | /* DllSecur.h -- DLL loading for security | ||
| 2 | 2018-02-19 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __DLL_SECUR_H | ||
| 5 | #define __DLL_SECUR_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #ifdef _WIN32 | ||
| 12 | |||
| 13 | void My_SetDefaultDllDirectories(void); | ||
| 14 | void LoadSecurityDlls(void); | ||
| 15 | |||
| 16 | #endif | ||
| 17 | |||
| 18 | EXTERN_C_END | ||
| 19 | |||
| 20 | #endif | ||
diff --git a/C/HuffEnc.c b/C/HuffEnc.c new file mode 100644 index 0000000..f3c2996 --- /dev/null +++ b/C/HuffEnc.c | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | /* HuffEnc.c -- functions for Huffman encoding | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "HuffEnc.h" | ||
| 7 | #include "Sort.h" | ||
| 8 | |||
| 9 | #define kMaxLen 16 | ||
| 10 | #define NUM_BITS 10 | ||
| 11 | #define MASK (((unsigned)1 << NUM_BITS) - 1) | ||
| 12 | |||
| 13 | #define NUM_COUNTERS 64 | ||
| 14 | |||
| 15 | #define HUFFMAN_SPEED_OPT | ||
| 16 | |||
| 17 | void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen) | ||
| 18 | { | ||
| 19 | UInt32 num = 0; | ||
| 20 | /* if (maxLen > 10) maxLen = 10; */ | ||
| 21 | { | ||
| 22 | UInt32 i; | ||
| 23 | |||
| 24 | #ifdef HUFFMAN_SPEED_OPT | ||
| 25 | |||
| 26 | UInt32 counters[NUM_COUNTERS]; | ||
| 27 | for (i = 0; i < NUM_COUNTERS; i++) | ||
| 28 | counters[i] = 0; | ||
| 29 | for (i = 0; i < numSymbols; i++) | ||
| 30 | { | ||
| 31 | UInt32 freq = freqs[i]; | ||
| 32 | counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++; | ||
| 33 | } | ||
| 34 | |||
| 35 | for (i = 1; i < NUM_COUNTERS; i++) | ||
| 36 | { | ||
| 37 | UInt32 temp = counters[i]; | ||
| 38 | counters[i] = num; | ||
| 39 | num += temp; | ||
| 40 | } | ||
| 41 | |||
| 42 | for (i = 0; i < numSymbols; i++) | ||
| 43 | { | ||
| 44 | UInt32 freq = freqs[i]; | ||
| 45 | if (freq == 0) | ||
| 46 | lens[i] = 0; | ||
| 47 | else | ||
| 48 | p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS); | ||
| 49 | } | ||
| 50 | counters[0] = 0; | ||
| 51 | HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]); | ||
| 52 | |||
| 53 | #else | ||
| 54 | |||
| 55 | for (i = 0; i < numSymbols; i++) | ||
| 56 | { | ||
| 57 | UInt32 freq = freqs[i]; | ||
| 58 | if (freq == 0) | ||
| 59 | lens[i] = 0; | ||
| 60 | else | ||
| 61 | p[num++] = i | (freq << NUM_BITS); | ||
| 62 | } | ||
| 63 | HeapSort(p, num); | ||
| 64 | |||
| 65 | #endif | ||
| 66 | } | ||
| 67 | |||
| 68 | if (num < 2) | ||
| 69 | { | ||
| 70 | unsigned minCode = 0; | ||
| 71 | unsigned maxCode = 1; | ||
| 72 | if (num == 1) | ||
| 73 | { | ||
| 74 | maxCode = (unsigned)p[0] & MASK; | ||
| 75 | if (maxCode == 0) | ||
| 76 | maxCode++; | ||
| 77 | } | ||
| 78 | p[minCode] = 0; | ||
| 79 | p[maxCode] = 1; | ||
| 80 | lens[minCode] = lens[maxCode] = 1; | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | |||
| 84 | { | ||
| 85 | UInt32 b, e, i; | ||
| 86 | |||
| 87 | i = b = e = 0; | ||
| 88 | do | ||
| 89 | { | ||
| 90 | UInt32 n, m, freq; | ||
| 91 | n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; | ||
| 92 | freq = (p[n] & ~MASK); | ||
| 93 | p[n] = (p[n] & MASK) | (e << NUM_BITS); | ||
| 94 | m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; | ||
| 95 | freq += (p[m] & ~MASK); | ||
| 96 | p[m] = (p[m] & MASK) | (e << NUM_BITS); | ||
| 97 | p[e] = (p[e] & MASK) | freq; | ||
| 98 | e++; | ||
| 99 | } | ||
| 100 | while (num - e > 1); | ||
| 101 | |||
| 102 | { | ||
| 103 | UInt32 lenCounters[kMaxLen + 1]; | ||
| 104 | for (i = 0; i <= kMaxLen; i++) | ||
| 105 | lenCounters[i] = 0; | ||
| 106 | |||
| 107 | p[--e] &= MASK; | ||
| 108 | lenCounters[1] = 2; | ||
| 109 | while (e > 0) | ||
| 110 | { | ||
| 111 | UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1; | ||
| 112 | p[e] = (p[e] & MASK) | (len << NUM_BITS); | ||
| 113 | if (len >= maxLen) | ||
| 114 | for (len = maxLen - 1; lenCounters[len] == 0; len--); | ||
| 115 | lenCounters[len]--; | ||
| 116 | lenCounters[(size_t)len + 1] += 2; | ||
| 117 | } | ||
| 118 | |||
| 119 | { | ||
| 120 | UInt32 len; | ||
| 121 | i = 0; | ||
| 122 | for (len = maxLen; len != 0; len--) | ||
| 123 | { | ||
| 124 | UInt32 k; | ||
| 125 | for (k = lenCounters[len]; k != 0; k--) | ||
| 126 | lens[p[i++] & MASK] = (Byte)len; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | { | ||
| 131 | UInt32 nextCodes[kMaxLen + 1]; | ||
| 132 | { | ||
| 133 | UInt32 code = 0; | ||
| 134 | UInt32 len; | ||
| 135 | for (len = 1; len <= kMaxLen; len++) | ||
| 136 | nextCodes[len] = code = (code + lenCounters[(size_t)len - 1]) << 1; | ||
| 137 | } | ||
| 138 | /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */ | ||
| 139 | |||
| 140 | { | ||
| 141 | UInt32 k; | ||
| 142 | for (k = 0; k < numSymbols; k++) | ||
| 143 | p[k] = nextCodes[lens[k]]++; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } | ||
| 147 | } | ||
| 148 | } | ||
diff --git a/C/HuffEnc.h b/C/HuffEnc.h new file mode 100644 index 0000000..92b6878 --- /dev/null +++ b/C/HuffEnc.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* HuffEnc.h -- Huffman encoding | ||
| 2 | 2013-01-18 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __HUFF_ENC_H | ||
| 5 | #define __HUFF_ENC_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | /* | ||
| 12 | Conditions: | ||
| 13 | num <= 1024 = 2 ^ NUM_BITS | ||
| 14 | Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS) | ||
| 15 | maxLen <= 16 = kMaxLen | ||
| 16 | Num_Items(p) >= HUFFMAN_TEMP_SIZE(num) | ||
| 17 | */ | ||
| 18 | |||
| 19 | void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen); | ||
| 20 | |||
| 21 | EXTERN_C_END | ||
| 22 | |||
| 23 | #endif | ||
diff --git a/C/LzFind.c b/C/LzFind.c new file mode 100644 index 0000000..1b73c28 --- /dev/null +++ b/C/LzFind.c | |||
| @@ -0,0 +1,1628 @@ | |||
| 1 | /* LzFind.c -- Match finder for LZ algorithms | ||
| 2 | 2021-11-29 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <string.h> | ||
| 7 | // #include <stdio.h> | ||
| 8 | |||
| 9 | #include "CpuArch.h" | ||
| 10 | #include "LzFind.h" | ||
| 11 | #include "LzHash.h" | ||
| 12 | |||
| 13 | #define kBlockMoveAlign (1 << 7) // alignment for memmove() | ||
| 14 | #define kBlockSizeAlign (1 << 16) // alignment for block allocation | ||
| 15 | #define kBlockSizeReserveMin (1 << 24) // it's 1/256 from 4 GB dictinary | ||
| 16 | |||
| 17 | #define kEmptyHashValue 0 | ||
| 18 | |||
| 19 | #define kMaxValForNormalize ((UInt32)0) | ||
| 20 | // #define kMaxValForNormalize ((UInt32)(1 << 20) + 0xFFF) // for debug | ||
| 21 | |||
| 22 | // #define kNormalizeAlign (1 << 7) // alignment for speculated accesses | ||
| 23 | |||
| 24 | #define GET_AVAIL_BYTES(p) \ | ||
| 25 | Inline_MatchFinder_GetNumAvailableBytes(p) | ||
| 26 | |||
| 27 | |||
| 28 | // #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) | ||
| 29 | #define kFix5HashSize kFix4HashSize | ||
| 30 | |||
| 31 | /* | ||
| 32 | HASH2_CALC: | ||
| 33 | if (hv) match, then cur[0] and cur[1] also match | ||
| 34 | */ | ||
| 35 | #define HASH2_CALC hv = GetUi16(cur); | ||
| 36 | |||
| 37 | // (crc[0 ... 255] & 0xFF) provides one-to-one correspondence to [0 ... 255] | ||
| 38 | |||
| 39 | /* | ||
| 40 | HASH3_CALC: | ||
| 41 | if (cur[0]) and (h2) match, then cur[1] also match | ||
| 42 | if (cur[0]) and (hv) match, then cur[1] and cur[2] also match | ||
| 43 | */ | ||
| 44 | #define HASH3_CALC { \ | ||
| 45 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ | ||
| 46 | h2 = temp & (kHash2Size - 1); \ | ||
| 47 | hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } | ||
| 48 | |||
| 49 | #define HASH4_CALC { \ | ||
| 50 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ | ||
| 51 | h2 = temp & (kHash2Size - 1); \ | ||
| 52 | temp ^= ((UInt32)cur[2] << 8); \ | ||
| 53 | h3 = temp & (kHash3Size - 1); \ | ||
| 54 | hv = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hashMask; } | ||
| 55 | |||
| 56 | #define HASH5_CALC { \ | ||
| 57 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ | ||
| 58 | h2 = temp & (kHash2Size - 1); \ | ||
| 59 | temp ^= ((UInt32)cur[2] << 8); \ | ||
| 60 | h3 = temp & (kHash3Size - 1); \ | ||
| 61 | temp ^= (p->crc[cur[3]] << kLzHash_CrcShift_1); \ | ||
| 62 | /* h4 = temp & p->hash4Mask; */ /* (kHash4Size - 1); */ \ | ||
| 63 | hv = (temp ^ (p->crc[cur[4]] << kLzHash_CrcShift_2)) & p->hashMask; } | ||
| 64 | |||
| 65 | #define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; | ||
| 66 | |||
| 67 | |||
| 68 | static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc) | ||
| 69 | { | ||
| 70 | if (!p->directInput) | ||
| 71 | { | ||
| 72 | ISzAlloc_Free(alloc, p->bufferBase); | ||
| 73 | p->bufferBase = NULL; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | |||
| 78 | static int LzInWindow_Create2(CMatchFinder *p, UInt32 blockSize, ISzAllocPtr alloc) | ||
| 79 | { | ||
| 80 | if (blockSize == 0) | ||
| 81 | return 0; | ||
| 82 | if (!p->bufferBase || p->blockSize != blockSize) | ||
| 83 | { | ||
| 84 | // size_t blockSizeT; | ||
| 85 | LzInWindow_Free(p, alloc); | ||
| 86 | p->blockSize = blockSize; | ||
| 87 | // blockSizeT = blockSize; | ||
| 88 | |||
| 89 | // printf("\nblockSize = 0x%x\n", blockSize); | ||
| 90 | /* | ||
| 91 | #if defined _WIN64 | ||
| 92 | // we can allocate 4GiB, but still use UInt32 for (p->blockSize) | ||
| 93 | // we use UInt32 type for (p->blockSize), because | ||
| 94 | // we don't want to wrap over 4 GiB, | ||
| 95 | // when we use (p->streamPos - p->pos) that is UInt32. | ||
| 96 | if (blockSize >= (UInt32)0 - (UInt32)kBlockSizeAlign) | ||
| 97 | { | ||
| 98 | blockSizeT = ((size_t)1 << 32); | ||
| 99 | printf("\nchanged to blockSizeT = 4GiB\n"); | ||
| 100 | } | ||
| 101 | #endif | ||
| 102 | */ | ||
| 103 | |||
| 104 | p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, blockSize); | ||
| 105 | // printf("\nbufferBase = %p\n", p->bufferBase); | ||
| 106 | // return 0; // for debug | ||
| 107 | } | ||
| 108 | return (p->bufferBase != NULL); | ||
| 109 | } | ||
| 110 | |||
| 111 | static const Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } | ||
| 112 | |||
| 113 | static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return GET_AVAIL_BYTES(p); } | ||
| 114 | |||
| 115 | |||
| 116 | MY_NO_INLINE | ||
| 117 | static void MatchFinder_ReadBlock(CMatchFinder *p) | ||
| 118 | { | ||
| 119 | if (p->streamEndWasReached || p->result != SZ_OK) | ||
| 120 | return; | ||
| 121 | |||
| 122 | /* We use (p->streamPos - p->pos) value. | ||
| 123 | (p->streamPos < p->pos) is allowed. */ | ||
| 124 | |||
| 125 | if (p->directInput) | ||
| 126 | { | ||
| 127 | UInt32 curSize = 0xFFFFFFFF - GET_AVAIL_BYTES(p); | ||
| 128 | if (curSize > p->directInputRem) | ||
| 129 | curSize = (UInt32)p->directInputRem; | ||
| 130 | p->directInputRem -= curSize; | ||
| 131 | p->streamPos += curSize; | ||
| 132 | if (p->directInputRem == 0) | ||
| 133 | p->streamEndWasReached = 1; | ||
| 134 | return; | ||
| 135 | } | ||
| 136 | |||
| 137 | for (;;) | ||
| 138 | { | ||
| 139 | Byte *dest = p->buffer + GET_AVAIL_BYTES(p); | ||
| 140 | size_t size = (size_t)(p->bufferBase + p->blockSize - dest); | ||
| 141 | if (size == 0) | ||
| 142 | { | ||
| 143 | /* we call ReadBlock() after NeedMove() and MoveBlock(). | ||
| 144 | NeedMove() and MoveBlock() povide more than (keepSizeAfter) | ||
| 145 | to the end of (blockSize). | ||
| 146 | So we don't execute this branch in normal code flow. | ||
| 147 | We can go here, if we will call ReadBlock() before NeedMove(), MoveBlock(). | ||
| 148 | */ | ||
| 149 | // p->result = SZ_ERROR_FAIL; // we can show error here | ||
| 150 | return; | ||
| 151 | } | ||
| 152 | |||
| 153 | // #define kRead 3 | ||
| 154 | // if (size > kRead) size = kRead; // for debug | ||
| 155 | |||
| 156 | p->result = ISeqInStream_Read(p->stream, dest, &size); | ||
| 157 | if (p->result != SZ_OK) | ||
| 158 | return; | ||
| 159 | if (size == 0) | ||
| 160 | { | ||
| 161 | p->streamEndWasReached = 1; | ||
| 162 | return; | ||
| 163 | } | ||
| 164 | p->streamPos += (UInt32)size; | ||
| 165 | if (GET_AVAIL_BYTES(p) > p->keepSizeAfter) | ||
| 166 | return; | ||
| 167 | /* here and in another (p->keepSizeAfter) checks we keep on 1 byte more than was requested by Create() function | ||
| 168 | (GET_AVAIL_BYTES(p) >= p->keepSizeAfter) - minimal required size */ | ||
| 169 | } | ||
| 170 | |||
| 171 | // on exit: (p->result != SZ_OK || p->streamEndWasReached || GET_AVAIL_BYTES(p) > p->keepSizeAfter) | ||
| 172 | } | ||
| 173 | |||
| 174 | |||
| 175 | |||
| 176 | MY_NO_INLINE | ||
| 177 | void MatchFinder_MoveBlock(CMatchFinder *p) | ||
| 178 | { | ||
| 179 | const size_t offset = (size_t)(p->buffer - p->bufferBase) - p->keepSizeBefore; | ||
| 180 | const size_t keepBefore = (offset & (kBlockMoveAlign - 1)) + p->keepSizeBefore; | ||
| 181 | p->buffer = p->bufferBase + keepBefore; | ||
| 182 | memmove(p->bufferBase, | ||
| 183 | p->bufferBase + (offset & ~((size_t)kBlockMoveAlign - 1)), | ||
| 184 | keepBefore + (size_t)GET_AVAIL_BYTES(p)); | ||
| 185 | } | ||
| 186 | |||
| 187 | /* We call MoveBlock() before ReadBlock(). | ||
| 188 | So MoveBlock() can be wasteful operation, if the whole input data | ||
| 189 | can fit in current block even without calling MoveBlock(). | ||
| 190 | in important case where (dataSize <= historySize) | ||
| 191 | condition (p->blockSize > dataSize + p->keepSizeAfter) is met | ||
| 192 | So there is no MoveBlock() in that case case. | ||
| 193 | */ | ||
| 194 | |||
| 195 | int MatchFinder_NeedMove(CMatchFinder *p) | ||
| 196 | { | ||
| 197 | if (p->directInput) | ||
| 198 | return 0; | ||
| 199 | if (p->streamEndWasReached || p->result != SZ_OK) | ||
| 200 | return 0; | ||
| 201 | return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); | ||
| 202 | } | ||
| 203 | |||
| 204 | void MatchFinder_ReadIfRequired(CMatchFinder *p) | ||
| 205 | { | ||
| 206 | if (p->keepSizeAfter >= GET_AVAIL_BYTES(p)) | ||
| 207 | MatchFinder_ReadBlock(p); | ||
| 208 | } | ||
| 209 | |||
| 210 | |||
| 211 | |||
| 212 | static void MatchFinder_SetDefaultSettings(CMatchFinder *p) | ||
| 213 | { | ||
| 214 | p->cutValue = 32; | ||
| 215 | p->btMode = 1; | ||
| 216 | p->numHashBytes = 4; | ||
| 217 | p->bigHash = 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | #define kCrcPoly 0xEDB88320 | ||
| 221 | |||
| 222 | void MatchFinder_Construct(CMatchFinder *p) | ||
| 223 | { | ||
| 224 | unsigned i; | ||
| 225 | p->bufferBase = NULL; | ||
| 226 | p->directInput = 0; | ||
| 227 | p->hash = NULL; | ||
| 228 | p->expectedDataSize = (UInt64)(Int64)-1; | ||
| 229 | MatchFinder_SetDefaultSettings(p); | ||
| 230 | |||
| 231 | for (i = 0; i < 256; i++) | ||
| 232 | { | ||
| 233 | UInt32 r = (UInt32)i; | ||
| 234 | unsigned j; | ||
| 235 | for (j = 0; j < 8; j++) | ||
| 236 | r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); | ||
| 237 | p->crc[i] = r; | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc) | ||
| 242 | { | ||
| 243 | ISzAlloc_Free(alloc, p->hash); | ||
| 244 | p->hash = NULL; | ||
| 245 | } | ||
| 246 | |||
| 247 | void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc) | ||
| 248 | { | ||
| 249 | MatchFinder_FreeThisClassMemory(p, alloc); | ||
| 250 | LzInWindow_Free(p, alloc); | ||
| 251 | } | ||
| 252 | |||
| 253 | static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc) | ||
| 254 | { | ||
| 255 | size_t sizeInBytes = (size_t)num * sizeof(CLzRef); | ||
| 256 | if (sizeInBytes / sizeof(CLzRef) != num) | ||
| 257 | return NULL; | ||
| 258 | return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes); | ||
| 259 | } | ||
| 260 | |||
| 261 | #if (kBlockSizeReserveMin < kBlockSizeAlign * 2) | ||
| 262 | #error Stop_Compiling_Bad_Reserve | ||
| 263 | #endif | ||
| 264 | |||
| 265 | |||
| 266 | |||
| 267 | static UInt32 GetBlockSize(CMatchFinder *p, UInt32 historySize) | ||
| 268 | { | ||
| 269 | UInt32 blockSize = (p->keepSizeBefore + p->keepSizeAfter); | ||
| 270 | /* | ||
| 271 | if (historySize > kMaxHistorySize) | ||
| 272 | return 0; | ||
| 273 | */ | ||
| 274 | // printf("\nhistorySize == 0x%x\n", historySize); | ||
| 275 | |||
| 276 | if (p->keepSizeBefore < historySize || blockSize < p->keepSizeBefore) // if 32-bit overflow | ||
| 277 | return 0; | ||
| 278 | |||
| 279 | { | ||
| 280 | const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)kBlockSizeAlign; | ||
| 281 | const UInt32 rem = kBlockSizeMax - blockSize; | ||
| 282 | const UInt32 reserve = (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)) | ||
| 283 | + (1 << 12) + kBlockMoveAlign + kBlockSizeAlign; // do not overflow 32-bit here | ||
| 284 | if (blockSize >= kBlockSizeMax | ||
| 285 | || rem < kBlockSizeReserveMin) // we reject settings that will be slow | ||
| 286 | return 0; | ||
| 287 | if (reserve >= rem) | ||
| 288 | blockSize = kBlockSizeMax; | ||
| 289 | else | ||
| 290 | { | ||
| 291 | blockSize += reserve; | ||
| 292 | blockSize &= ~(UInt32)(kBlockSizeAlign - 1); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | // printf("\n LzFind_blockSize = %x\n", blockSize); | ||
| 296 | // printf("\n LzFind_blockSize = %d\n", blockSize >> 20); | ||
| 297 | return blockSize; | ||
| 298 | } | ||
| 299 | |||
| 300 | |||
| 301 | int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, | ||
| 302 | UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, | ||
| 303 | ISzAllocPtr alloc) | ||
| 304 | { | ||
| 305 | /* we need one additional byte in (p->keepSizeBefore), | ||
| 306 | since we use MoveBlock() after (p->pos++) and before dictionary using */ | ||
| 307 | // keepAddBufferBefore = (UInt32)0xFFFFFFFF - (1 << 22); // for debug | ||
| 308 | p->keepSizeBefore = historySize + keepAddBufferBefore + 1; | ||
| 309 | |||
| 310 | keepAddBufferAfter += matchMaxLen; | ||
| 311 | /* we need (p->keepSizeAfter >= p->numHashBytes) */ | ||
| 312 | if (keepAddBufferAfter < p->numHashBytes) | ||
| 313 | keepAddBufferAfter = p->numHashBytes; | ||
| 314 | // keepAddBufferAfter -= 2; // for debug | ||
| 315 | p->keepSizeAfter = keepAddBufferAfter; | ||
| 316 | |||
| 317 | if (p->directInput) | ||
| 318 | p->blockSize = 0; | ||
| 319 | if (p->directInput || LzInWindow_Create2(p, GetBlockSize(p, historySize), alloc)) | ||
| 320 | { | ||
| 321 | const UInt32 newCyclicBufferSize = historySize + 1; // do not change it | ||
| 322 | UInt32 hs; | ||
| 323 | p->matchMaxLen = matchMaxLen; | ||
| 324 | { | ||
| 325 | // UInt32 hs4; | ||
| 326 | p->fixedHashSize = 0; | ||
| 327 | hs = (1 << 16) - 1; | ||
| 328 | if (p->numHashBytes != 2) | ||
| 329 | { | ||
| 330 | hs = historySize; | ||
| 331 | if (hs > p->expectedDataSize) | ||
| 332 | hs = (UInt32)p->expectedDataSize; | ||
| 333 | if (hs != 0) | ||
| 334 | hs--; | ||
| 335 | hs |= (hs >> 1); | ||
| 336 | hs |= (hs >> 2); | ||
| 337 | hs |= (hs >> 4); | ||
| 338 | hs |= (hs >> 8); | ||
| 339 | // we propagated 16 bits in (hs). Low 16 bits must be set later | ||
| 340 | hs >>= 1; | ||
| 341 | if (hs >= (1 << 24)) | ||
| 342 | { | ||
| 343 | if (p->numHashBytes == 3) | ||
| 344 | hs = (1 << 24) - 1; | ||
| 345 | else | ||
| 346 | hs >>= 1; | ||
| 347 | /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ | ||
| 348 | } | ||
| 349 | |||
| 350 | // hs = ((UInt32)1 << 25) - 1; // for test | ||
| 351 | |||
| 352 | // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2) | ||
| 353 | hs |= (1 << 16) - 1; /* don't change it! */ | ||
| 354 | |||
| 355 | // bt5: we adjust the size with recommended minimum size | ||
| 356 | if (p->numHashBytes >= 5) | ||
| 357 | hs |= (256 << kLzHash_CrcShift_2) - 1; | ||
| 358 | } | ||
| 359 | p->hashMask = hs; | ||
| 360 | hs++; | ||
| 361 | |||
| 362 | /* | ||
| 363 | hs4 = (1 << 20); | ||
| 364 | if (hs4 > hs) | ||
| 365 | hs4 = hs; | ||
| 366 | // hs4 = (1 << 16); // for test | ||
| 367 | p->hash4Mask = hs4 - 1; | ||
| 368 | */ | ||
| 369 | |||
| 370 | if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; | ||
| 371 | if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; | ||
| 372 | // if (p->numHashBytes > 4) p->fixedHashSize += hs4; // kHash4Size; | ||
| 373 | hs += p->fixedHashSize; | ||
| 374 | } | ||
| 375 | |||
| 376 | { | ||
| 377 | size_t newSize; | ||
| 378 | size_t numSons; | ||
| 379 | p->historySize = historySize; | ||
| 380 | p->hashSizeSum = hs; | ||
| 381 | p->cyclicBufferSize = newCyclicBufferSize; // it must be = (historySize + 1) | ||
| 382 | |||
| 383 | numSons = newCyclicBufferSize; | ||
| 384 | if (p->btMode) | ||
| 385 | numSons <<= 1; | ||
| 386 | newSize = hs + numSons; | ||
| 387 | |||
| 388 | // aligned size is not required here, but it can be better for some loops | ||
| 389 | #define NUM_REFS_ALIGN_MASK 0xF | ||
| 390 | newSize = (newSize + NUM_REFS_ALIGN_MASK) & ~(size_t)NUM_REFS_ALIGN_MASK; | ||
| 391 | |||
| 392 | if (p->hash && p->numRefs == newSize) | ||
| 393 | return 1; | ||
| 394 | |||
| 395 | MatchFinder_FreeThisClassMemory(p, alloc); | ||
| 396 | p->numRefs = newSize; | ||
| 397 | p->hash = AllocRefs(newSize, alloc); | ||
| 398 | |||
| 399 | if (p->hash) | ||
| 400 | { | ||
| 401 | p->son = p->hash + p->hashSizeSum; | ||
| 402 | return 1; | ||
| 403 | } | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | MatchFinder_Free(p, alloc); | ||
| 408 | return 0; | ||
| 409 | } | ||
| 410 | |||
| 411 | |||
| 412 | static void MatchFinder_SetLimits(CMatchFinder *p) | ||
| 413 | { | ||
| 414 | UInt32 k; | ||
| 415 | UInt32 n = kMaxValForNormalize - p->pos; | ||
| 416 | if (n == 0) | ||
| 417 | n = (UInt32)(Int32)-1; // we allow (pos == 0) at start even with (kMaxValForNormalize == 0) | ||
| 418 | |||
| 419 | k = p->cyclicBufferSize - p->cyclicBufferPos; | ||
| 420 | if (k < n) | ||
| 421 | n = k; | ||
| 422 | |||
| 423 | k = GET_AVAIL_BYTES(p); | ||
| 424 | { | ||
| 425 | const UInt32 ksa = p->keepSizeAfter; | ||
| 426 | UInt32 mm = p->matchMaxLen; | ||
| 427 | if (k > ksa) | ||
| 428 | k -= ksa; // we must limit exactly to keepSizeAfter for ReadBlock | ||
| 429 | else if (k >= mm) | ||
| 430 | { | ||
| 431 | // the limitation for (p->lenLimit) update | ||
| 432 | k -= mm; // optimization : to reduce the number of checks | ||
| 433 | k++; | ||
| 434 | // k = 1; // non-optimized version : for debug | ||
| 435 | } | ||
| 436 | else | ||
| 437 | { | ||
| 438 | mm = k; | ||
| 439 | if (k != 0) | ||
| 440 | k = 1; | ||
| 441 | } | ||
| 442 | p->lenLimit = mm; | ||
| 443 | } | ||
| 444 | if (k < n) | ||
| 445 | n = k; | ||
| 446 | |||
| 447 | p->posLimit = p->pos + n; | ||
| 448 | } | ||
| 449 | |||
| 450 | |||
| 451 | void MatchFinder_Init_LowHash(CMatchFinder *p) | ||
| 452 | { | ||
| 453 | size_t i; | ||
| 454 | CLzRef *items = p->hash; | ||
| 455 | const size_t numItems = p->fixedHashSize; | ||
| 456 | for (i = 0; i < numItems; i++) | ||
| 457 | items[i] = kEmptyHashValue; | ||
| 458 | } | ||
| 459 | |||
| 460 | |||
| 461 | void MatchFinder_Init_HighHash(CMatchFinder *p) | ||
| 462 | { | ||
| 463 | size_t i; | ||
| 464 | CLzRef *items = p->hash + p->fixedHashSize; | ||
| 465 | const size_t numItems = (size_t)p->hashMask + 1; | ||
| 466 | for (i = 0; i < numItems; i++) | ||
| 467 | items[i] = kEmptyHashValue; | ||
| 468 | } | ||
| 469 | |||
| 470 | |||
| 471 | void MatchFinder_Init_4(CMatchFinder *p) | ||
| 472 | { | ||
| 473 | p->buffer = p->bufferBase; | ||
| 474 | { | ||
| 475 | /* kEmptyHashValue = 0 (Zero) is used in hash tables as NO-VALUE marker. | ||
| 476 | the code in CMatchFinderMt expects (pos = 1) */ | ||
| 477 | p->pos = | ||
| 478 | p->streamPos = | ||
| 479 | 1; // it's smallest optimal value. do not change it | ||
| 480 | // 0; // for debug | ||
| 481 | } | ||
| 482 | p->result = SZ_OK; | ||
| 483 | p->streamEndWasReached = 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | |||
| 487 | // (CYC_TO_POS_OFFSET == 0) is expected by some optimized code | ||
| 488 | #define CYC_TO_POS_OFFSET 0 | ||
| 489 | // #define CYC_TO_POS_OFFSET 1 // for debug | ||
| 490 | |||
| 491 | void MatchFinder_Init(CMatchFinder *p) | ||
| 492 | { | ||
| 493 | MatchFinder_Init_HighHash(p); | ||
| 494 | MatchFinder_Init_LowHash(p); | ||
| 495 | MatchFinder_Init_4(p); | ||
| 496 | // if (readData) | ||
| 497 | MatchFinder_ReadBlock(p); | ||
| 498 | |||
| 499 | /* if we init (cyclicBufferPos = pos), then we can use one variable | ||
| 500 | instead of both (cyclicBufferPos) and (pos) : only before (cyclicBufferPos) wrapping */ | ||
| 501 | p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET); // init with relation to (pos) | ||
| 502 | // p->cyclicBufferPos = 0; // smallest value | ||
| 503 | // p->son[0] = p->son[1] = 0; // unused: we can init skipped record for speculated accesses. | ||
| 504 | MatchFinder_SetLimits(p); | ||
| 505 | } | ||
| 506 | |||
| 507 | |||
| 508 | |||
| 509 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 510 | #if defined(__clang__) && (__clang_major__ >= 8) \ | ||
| 511 | || defined(__GNUC__) && (__GNUC__ >= 8) \ | ||
| 512 | || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900) | ||
| 513 | #define USE_SATUR_SUB_128 | ||
| 514 | #define USE_AVX2 | ||
| 515 | #define ATTRIB_SSE41 __attribute__((__target__("sse4.1"))) | ||
| 516 | #define ATTRIB_AVX2 __attribute__((__target__("avx2"))) | ||
| 517 | #elif defined(_MSC_VER) | ||
| 518 | #if (_MSC_VER >= 1600) | ||
| 519 | #define USE_SATUR_SUB_128 | ||
| 520 | #if (_MSC_VER >= 1900) | ||
| 521 | #define USE_AVX2 | ||
| 522 | #include <immintrin.h> // avx | ||
| 523 | #endif | ||
| 524 | #endif | ||
| 525 | #endif | ||
| 526 | |||
| 527 | // #elif defined(MY_CPU_ARM_OR_ARM64) | ||
| 528 | #elif defined(MY_CPU_ARM64) | ||
| 529 | |||
| 530 | #if defined(__clang__) && (__clang_major__ >= 8) \ | ||
| 531 | || defined(__GNUC__) && (__GNUC__ >= 8) | ||
| 532 | #define USE_SATUR_SUB_128 | ||
| 533 | #ifdef MY_CPU_ARM64 | ||
| 534 | // #define ATTRIB_SSE41 __attribute__((__target__(""))) | ||
| 535 | #else | ||
| 536 | // #define ATTRIB_SSE41 __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) | ||
| 537 | #endif | ||
| 538 | |||
| 539 | #elif defined(_MSC_VER) | ||
| 540 | #if (_MSC_VER >= 1910) | ||
| 541 | #define USE_SATUR_SUB_128 | ||
| 542 | #endif | ||
| 543 | #endif | ||
| 544 | |||
| 545 | #if defined(_MSC_VER) && defined(MY_CPU_ARM64) | ||
| 546 | #include <arm64_neon.h> | ||
| 547 | #else | ||
| 548 | #include <arm_neon.h> | ||
| 549 | #endif | ||
| 550 | |||
| 551 | #endif | ||
| 552 | |||
| 553 | /* | ||
| 554 | #ifndef ATTRIB_SSE41 | ||
| 555 | #define ATTRIB_SSE41 | ||
| 556 | #endif | ||
| 557 | #ifndef ATTRIB_AVX2 | ||
| 558 | #define ATTRIB_AVX2 | ||
| 559 | #endif | ||
| 560 | */ | ||
| 561 | |||
| 562 | #ifdef USE_SATUR_SUB_128 | ||
| 563 | |||
| 564 | // #define _SHOW_HW_STATUS | ||
| 565 | |||
| 566 | #ifdef _SHOW_HW_STATUS | ||
| 567 | #include <stdio.h> | ||
| 568 | #define _PRF(x) x | ||
| 569 | _PRF(;) | ||
| 570 | #else | ||
| 571 | #define _PRF(x) | ||
| 572 | #endif | ||
| 573 | |||
| 574 | #ifdef MY_CPU_ARM_OR_ARM64 | ||
| 575 | |||
| 576 | #ifdef MY_CPU_ARM64 | ||
| 577 | // #define FORCE_SATUR_SUB_128 | ||
| 578 | #endif | ||
| 579 | |||
| 580 | typedef uint32x4_t v128; | ||
| 581 | #define SASUB_128(i) \ | ||
| 582 | *(v128 *)(void *)(items + (i) * 4) = \ | ||
| 583 | vsubq_u32(vmaxq_u32(*(const v128 *)(const void *)(items + (i) * 4), sub2), sub2); | ||
| 584 | |||
| 585 | #else | ||
| 586 | |||
| 587 | #include <smmintrin.h> // sse4.1 | ||
| 588 | |||
| 589 | typedef __m128i v128; | ||
| 590 | #define SASUB_128(i) \ | ||
| 591 | *(v128 *)(void *)(items + (i) * 4) = \ | ||
| 592 | _mm_sub_epi32(_mm_max_epu32(*(const v128 *)(const void *)(items + (i) * 4), sub2), sub2); // SSE 4.1 | ||
| 593 | |||
| 594 | #endif | ||
| 595 | |||
| 596 | |||
| 597 | |||
| 598 | MY_NO_INLINE | ||
| 599 | static | ||
| 600 | #ifdef ATTRIB_SSE41 | ||
| 601 | ATTRIB_SSE41 | ||
| 602 | #endif | ||
| 603 | void | ||
| 604 | MY_FAST_CALL | ||
| 605 | LzFind_SaturSub_128(UInt32 subValue, CLzRef *items, const CLzRef *lim) | ||
| 606 | { | ||
| 607 | v128 sub2 = | ||
| 608 | #ifdef MY_CPU_ARM_OR_ARM64 | ||
| 609 | vdupq_n_u32(subValue); | ||
| 610 | #else | ||
| 611 | _mm_set_epi32((Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue); | ||
| 612 | #endif | ||
| 613 | do | ||
| 614 | { | ||
| 615 | SASUB_128(0) | ||
| 616 | SASUB_128(1) | ||
| 617 | SASUB_128(2) | ||
| 618 | SASUB_128(3) | ||
| 619 | items += 4 * 4; | ||
| 620 | } | ||
| 621 | while (items != lim); | ||
| 622 | } | ||
| 623 | |||
| 624 | |||
| 625 | |||
| 626 | #ifdef USE_AVX2 | ||
| 627 | |||
| 628 | #include <immintrin.h> // avx | ||
| 629 | |||
| 630 | #define SASUB_256(i) *(__m256i *)(void *)(items + (i) * 8) = _mm256_sub_epi32(_mm256_max_epu32(*(const __m256i *)(const void *)(items + (i) * 8), sub2), sub2); // AVX2 | ||
| 631 | |||
| 632 | MY_NO_INLINE | ||
| 633 | static | ||
| 634 | #ifdef ATTRIB_AVX2 | ||
| 635 | ATTRIB_AVX2 | ||
| 636 | #endif | ||
| 637 | void | ||
| 638 | MY_FAST_CALL | ||
| 639 | LzFind_SaturSub_256(UInt32 subValue, CLzRef *items, const CLzRef *lim) | ||
| 640 | { | ||
| 641 | __m256i sub2 = _mm256_set_epi32( | ||
| 642 | (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue, | ||
| 643 | (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue); | ||
| 644 | do | ||
| 645 | { | ||
| 646 | SASUB_256(0) | ||
| 647 | SASUB_256(1) | ||
| 648 | items += 2 * 8; | ||
| 649 | } | ||
| 650 | while (items != lim); | ||
| 651 | } | ||
| 652 | #endif // USE_AVX2 | ||
| 653 | |||
| 654 | #ifndef FORCE_SATUR_SUB_128 | ||
| 655 | typedef void (MY_FAST_CALL *LZFIND_SATUR_SUB_CODE_FUNC)( | ||
| 656 | UInt32 subValue, CLzRef *items, const CLzRef *lim); | ||
| 657 | static LZFIND_SATUR_SUB_CODE_FUNC g_LzFind_SaturSub; | ||
| 658 | #endif // FORCE_SATUR_SUB_128 | ||
| 659 | |||
| 660 | #endif // USE_SATUR_SUB_128 | ||
| 661 | |||
| 662 | |||
| 663 | // kEmptyHashValue must be zero | ||
| 664 | // #define SASUB_32(i) v = items[i]; m = v - subValue; if (v < subValue) m = kEmptyHashValue; items[i] = m; | ||
| 665 | #define SASUB_32(i) v = items[i]; if (v < subValue) v = subValue; items[i] = v - subValue; | ||
| 666 | |||
| 667 | #ifdef FORCE_SATUR_SUB_128 | ||
| 668 | |||
| 669 | #define DEFAULT_SaturSub LzFind_SaturSub_128 | ||
| 670 | |||
| 671 | #else | ||
| 672 | |||
| 673 | #define DEFAULT_SaturSub LzFind_SaturSub_32 | ||
| 674 | |||
| 675 | MY_NO_INLINE | ||
| 676 | static | ||
| 677 | void | ||
| 678 | MY_FAST_CALL | ||
| 679 | LzFind_SaturSub_32(UInt32 subValue, CLzRef *items, const CLzRef *lim) | ||
| 680 | { | ||
| 681 | do | ||
| 682 | { | ||
| 683 | UInt32 v; | ||
| 684 | SASUB_32(0) | ||
| 685 | SASUB_32(1) | ||
| 686 | SASUB_32(2) | ||
| 687 | SASUB_32(3) | ||
| 688 | SASUB_32(4) | ||
| 689 | SASUB_32(5) | ||
| 690 | SASUB_32(6) | ||
| 691 | SASUB_32(7) | ||
| 692 | items += 8; | ||
| 693 | } | ||
| 694 | while (items != lim); | ||
| 695 | } | ||
| 696 | |||
| 697 | #endif | ||
| 698 | |||
| 699 | |||
| 700 | MY_NO_INLINE | ||
| 701 | void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) | ||
| 702 | { | ||
| 703 | #define K_NORM_ALIGN_BLOCK_SIZE (1 << 6) | ||
| 704 | |||
| 705 | CLzRef *lim; | ||
| 706 | |||
| 707 | for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (K_NORM_ALIGN_BLOCK_SIZE - 1)) != 0; numItems--) | ||
| 708 | { | ||
| 709 | UInt32 v; | ||
| 710 | SASUB_32(0); | ||
| 711 | items++; | ||
| 712 | } | ||
| 713 | |||
| 714 | { | ||
| 715 | #define K_NORM_ALIGN_MASK (K_NORM_ALIGN_BLOCK_SIZE / 4 - 1) | ||
| 716 | lim = items + (numItems & ~(size_t)K_NORM_ALIGN_MASK); | ||
| 717 | numItems &= K_NORM_ALIGN_MASK; | ||
| 718 | if (items != lim) | ||
| 719 | { | ||
| 720 | #if defined(USE_SATUR_SUB_128) && !defined(FORCE_SATUR_SUB_128) | ||
| 721 | if (g_LzFind_SaturSub) | ||
| 722 | g_LzFind_SaturSub(subValue, items, lim); | ||
| 723 | else | ||
| 724 | #endif | ||
| 725 | DEFAULT_SaturSub(subValue, items, lim); | ||
| 726 | } | ||
| 727 | items = lim; | ||
| 728 | } | ||
| 729 | |||
| 730 | |||
| 731 | for (; numItems != 0; numItems--) | ||
| 732 | { | ||
| 733 | UInt32 v; | ||
| 734 | SASUB_32(0); | ||
| 735 | items++; | ||
| 736 | } | ||
| 737 | } | ||
| 738 | |||
| 739 | |||
| 740 | |||
| 741 | // call MatchFinder_CheckLimits() only after (p->pos++) update | ||
| 742 | |||
| 743 | MY_NO_INLINE | ||
| 744 | static void MatchFinder_CheckLimits(CMatchFinder *p) | ||
| 745 | { | ||
| 746 | if (// !p->streamEndWasReached && p->result == SZ_OK && | ||
| 747 | p->keepSizeAfter == GET_AVAIL_BYTES(p)) | ||
| 748 | { | ||
| 749 | // we try to read only in exact state (p->keepSizeAfter == GET_AVAIL_BYTES(p)) | ||
| 750 | if (MatchFinder_NeedMove(p)) | ||
| 751 | MatchFinder_MoveBlock(p); | ||
| 752 | MatchFinder_ReadBlock(p); | ||
| 753 | } | ||
| 754 | |||
| 755 | if (p->pos == kMaxValForNormalize) | ||
| 756 | if (GET_AVAIL_BYTES(p) >= p->numHashBytes) // optional optimization for last bytes of data. | ||
| 757 | /* | ||
| 758 | if we disable normalization for last bytes of data, and | ||
| 759 | if (data_size == 4 GiB), we don't call wastfull normalization, | ||
| 760 | but (pos) will be wrapped over Zero (0) in that case. | ||
| 761 | And we cannot resume later to normal operation | ||
| 762 | */ | ||
| 763 | { | ||
| 764 | // MatchFinder_Normalize(p); | ||
| 765 | /* after normalization we need (p->pos >= p->historySize + 1); */ | ||
| 766 | /* we can reduce subValue to aligned value, if want to keep alignment | ||
| 767 | of (p->pos) and (p->buffer) for speculated accesses. */ | ||
| 768 | const UInt32 subValue = (p->pos - p->historySize - 1) /* & ~(UInt32)(kNormalizeAlign - 1) */; | ||
| 769 | // const UInt32 subValue = (1 << 15); // for debug | ||
| 770 | // printf("\nMatchFinder_Normalize() subValue == 0x%x\n", subValue); | ||
| 771 | size_t numSonRefs = p->cyclicBufferSize; | ||
| 772 | if (p->btMode) | ||
| 773 | numSonRefs <<= 1; | ||
| 774 | Inline_MatchFinder_ReduceOffsets(p, subValue); | ||
| 775 | MatchFinder_Normalize3(subValue, p->hash, (size_t)p->hashSizeSum + numSonRefs); | ||
| 776 | } | ||
| 777 | |||
| 778 | if (p->cyclicBufferPos == p->cyclicBufferSize) | ||
| 779 | p->cyclicBufferPos = 0; | ||
| 780 | |||
| 781 | MatchFinder_SetLimits(p); | ||
| 782 | } | ||
| 783 | |||
| 784 | |||
| 785 | /* | ||
| 786 | (lenLimit > maxLen) | ||
| 787 | */ | ||
| 788 | MY_FORCE_INLINE | ||
| 789 | static UInt32 * Hc_GetMatchesSpec(size_t lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, | ||
| 790 | size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, | ||
| 791 | UInt32 *d, unsigned maxLen) | ||
| 792 | { | ||
| 793 | /* | ||
| 794 | son[_cyclicBufferPos] = curMatch; | ||
| 795 | for (;;) | ||
| 796 | { | ||
| 797 | UInt32 delta = pos - curMatch; | ||
| 798 | if (cutValue-- == 0 || delta >= _cyclicBufferSize) | ||
| 799 | return d; | ||
| 800 | { | ||
| 801 | const Byte *pb = cur - delta; | ||
| 802 | curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; | ||
| 803 | if (pb[maxLen] == cur[maxLen] && *pb == *cur) | ||
| 804 | { | ||
| 805 | UInt32 len = 0; | ||
| 806 | while (++len != lenLimit) | ||
| 807 | if (pb[len] != cur[len]) | ||
| 808 | break; | ||
| 809 | if (maxLen < len) | ||
| 810 | { | ||
| 811 | maxLen = len; | ||
| 812 | *d++ = len; | ||
| 813 | *d++ = delta - 1; | ||
| 814 | if (len == lenLimit) | ||
| 815 | return d; | ||
| 816 | } | ||
| 817 | } | ||
| 818 | } | ||
| 819 | } | ||
| 820 | */ | ||
| 821 | |||
| 822 | const Byte *lim = cur + lenLimit; | ||
| 823 | son[_cyclicBufferPos] = curMatch; | ||
| 824 | |||
| 825 | do | ||
| 826 | { | ||
| 827 | UInt32 delta; | ||
| 828 | |||
| 829 | if (curMatch == 0) | ||
| 830 | break; | ||
| 831 | // if (curMatch2 >= curMatch) return NULL; | ||
| 832 | delta = pos - curMatch; | ||
| 833 | if (delta >= _cyclicBufferSize) | ||
| 834 | break; | ||
| 835 | { | ||
| 836 | ptrdiff_t diff; | ||
| 837 | curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; | ||
| 838 | diff = (ptrdiff_t)0 - (ptrdiff_t)delta; | ||
| 839 | if (cur[maxLen] == cur[(ptrdiff_t)maxLen + diff]) | ||
| 840 | { | ||
| 841 | const Byte *c = cur; | ||
| 842 | while (*c == c[diff]) | ||
| 843 | { | ||
| 844 | if (++c == lim) | ||
| 845 | { | ||
| 846 | d[0] = (UInt32)(lim - cur); | ||
| 847 | d[1] = delta - 1; | ||
| 848 | return d + 2; | ||
| 849 | } | ||
| 850 | } | ||
| 851 | { | ||
| 852 | const unsigned len = (unsigned)(c - cur); | ||
| 853 | if (maxLen < len) | ||
| 854 | { | ||
| 855 | maxLen = len; | ||
| 856 | d[0] = (UInt32)len; | ||
| 857 | d[1] = delta - 1; | ||
| 858 | d += 2; | ||
| 859 | } | ||
| 860 | } | ||
| 861 | } | ||
| 862 | } | ||
| 863 | } | ||
| 864 | while (--cutValue); | ||
| 865 | |||
| 866 | return d; | ||
| 867 | } | ||
| 868 | |||
| 869 | |||
| 870 | MY_FORCE_INLINE | ||
| 871 | UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, | ||
| 872 | size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, | ||
| 873 | UInt32 *d, UInt32 maxLen) | ||
| 874 | { | ||
| 875 | CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; | ||
| 876 | CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); | ||
| 877 | unsigned len0 = 0, len1 = 0; | ||
| 878 | |||
| 879 | UInt32 cmCheck; | ||
| 880 | |||
| 881 | // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; } | ||
| 882 | |||
| 883 | cmCheck = (UInt32)(pos - _cyclicBufferSize); | ||
| 884 | if ((UInt32)pos <= _cyclicBufferSize) | ||
| 885 | cmCheck = 0; | ||
| 886 | |||
| 887 | if (cmCheck < curMatch) | ||
| 888 | do | ||
| 889 | { | ||
| 890 | const UInt32 delta = pos - curMatch; | ||
| 891 | { | ||
| 892 | CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); | ||
| 893 | const Byte *pb = cur - delta; | ||
| 894 | unsigned len = (len0 < len1 ? len0 : len1); | ||
| 895 | const UInt32 pair0 = pair[0]; | ||
| 896 | if (pb[len] == cur[len]) | ||
| 897 | { | ||
| 898 | if (++len != lenLimit && pb[len] == cur[len]) | ||
| 899 | while (++len != lenLimit) | ||
| 900 | if (pb[len] != cur[len]) | ||
| 901 | break; | ||
| 902 | if (maxLen < len) | ||
| 903 | { | ||
| 904 | maxLen = (UInt32)len; | ||
| 905 | *d++ = (UInt32)len; | ||
| 906 | *d++ = delta - 1; | ||
| 907 | if (len == lenLimit) | ||
| 908 | { | ||
| 909 | *ptr1 = pair0; | ||
| 910 | *ptr0 = pair[1]; | ||
| 911 | return d; | ||
| 912 | } | ||
| 913 | } | ||
| 914 | } | ||
| 915 | if (pb[len] < cur[len]) | ||
| 916 | { | ||
| 917 | *ptr1 = curMatch; | ||
| 918 | // const UInt32 curMatch2 = pair[1]; | ||
| 919 | // if (curMatch2 >= curMatch) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; } | ||
| 920 | // curMatch = curMatch2; | ||
| 921 | curMatch = pair[1]; | ||
| 922 | ptr1 = pair + 1; | ||
| 923 | len1 = len; | ||
| 924 | } | ||
| 925 | else | ||
| 926 | { | ||
| 927 | *ptr0 = curMatch; | ||
| 928 | curMatch = pair[0]; | ||
| 929 | ptr0 = pair; | ||
| 930 | len0 = len; | ||
| 931 | } | ||
| 932 | } | ||
| 933 | } | ||
| 934 | while(--cutValue && cmCheck < curMatch); | ||
| 935 | |||
| 936 | *ptr0 = *ptr1 = kEmptyHashValue; | ||
| 937 | return d; | ||
| 938 | } | ||
| 939 | |||
| 940 | |||
| 941 | static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, | ||
| 942 | size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) | ||
| 943 | { | ||
| 944 | CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; | ||
| 945 | CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); | ||
| 946 | unsigned len0 = 0, len1 = 0; | ||
| 947 | |||
| 948 | UInt32 cmCheck; | ||
| 949 | |||
| 950 | cmCheck = (UInt32)(pos - _cyclicBufferSize); | ||
| 951 | if ((UInt32)pos <= _cyclicBufferSize) | ||
| 952 | cmCheck = 0; | ||
| 953 | |||
| 954 | if (// curMatch >= pos || // failure | ||
| 955 | cmCheck < curMatch) | ||
| 956 | do | ||
| 957 | { | ||
| 958 | const UInt32 delta = pos - curMatch; | ||
| 959 | { | ||
| 960 | CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); | ||
| 961 | const Byte *pb = cur - delta; | ||
| 962 | unsigned len = (len0 < len1 ? len0 : len1); | ||
| 963 | if (pb[len] == cur[len]) | ||
| 964 | { | ||
| 965 | while (++len != lenLimit) | ||
| 966 | if (pb[len] != cur[len]) | ||
| 967 | break; | ||
| 968 | { | ||
| 969 | if (len == lenLimit) | ||
| 970 | { | ||
| 971 | *ptr1 = pair[0]; | ||
| 972 | *ptr0 = pair[1]; | ||
| 973 | return; | ||
| 974 | } | ||
| 975 | } | ||
| 976 | } | ||
| 977 | if (pb[len] < cur[len]) | ||
| 978 | { | ||
| 979 | *ptr1 = curMatch; | ||
| 980 | curMatch = pair[1]; | ||
| 981 | ptr1 = pair + 1; | ||
| 982 | len1 = len; | ||
| 983 | } | ||
| 984 | else | ||
| 985 | { | ||
| 986 | *ptr0 = curMatch; | ||
| 987 | curMatch = pair[0]; | ||
| 988 | ptr0 = pair; | ||
| 989 | len0 = len; | ||
| 990 | } | ||
| 991 | } | ||
| 992 | } | ||
| 993 | while(--cutValue && cmCheck < curMatch); | ||
| 994 | |||
| 995 | *ptr0 = *ptr1 = kEmptyHashValue; | ||
| 996 | return; | ||
| 997 | } | ||
| 998 | |||
| 999 | |||
| 1000 | #define MOVE_POS \ | ||
| 1001 | ++p->cyclicBufferPos; \ | ||
| 1002 | p->buffer++; \ | ||
| 1003 | { const UInt32 pos1 = p->pos + 1; p->pos = pos1; if (pos1 == p->posLimit) MatchFinder_CheckLimits(p); } | ||
| 1004 | |||
| 1005 | #define MOVE_POS_RET MOVE_POS return distances; | ||
| 1006 | |||
| 1007 | MY_NO_INLINE | ||
| 1008 | static void MatchFinder_MovePos(CMatchFinder *p) | ||
| 1009 | { | ||
| 1010 | /* we go here at the end of stream data, when (avail < num_hash_bytes) | ||
| 1011 | We don't update sons[cyclicBufferPos << btMode]. | ||
| 1012 | So (sons) record will contain junk. And we cannot resume match searching | ||
| 1013 | to normal operation, even if we will provide more input data in buffer. | ||
| 1014 | p->sons[p->cyclicBufferPos << p->btMode] = 0; // kEmptyHashValue | ||
| 1015 | if (p->btMode) | ||
| 1016 | p->sons[(p->cyclicBufferPos << p->btMode) + 1] = 0; // kEmptyHashValue | ||
| 1017 | */ | ||
| 1018 | MOVE_POS; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | #define GET_MATCHES_HEADER2(minLen, ret_op) \ | ||
| 1022 | unsigned lenLimit; UInt32 hv; Byte *cur; UInt32 curMatch; \ | ||
| 1023 | lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ | ||
| 1024 | cur = p->buffer; | ||
| 1025 | |||
| 1026 | #define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return distances) | ||
| 1027 | #define SKIP_HEADER(minLen) do { GET_MATCHES_HEADER2(minLen, continue) | ||
| 1028 | |||
| 1029 | #define MF_PARAMS(p) lenLimit, curMatch, p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue | ||
| 1030 | |||
| 1031 | #define SKIP_FOOTER SkipMatchesSpec(MF_PARAMS(p)); MOVE_POS; } while (--num); | ||
| 1032 | |||
| 1033 | #define GET_MATCHES_FOOTER_BASE(_maxLen_, func) \ | ||
| 1034 | distances = func(MF_PARAMS(p), \ | ||
| 1035 | distances, (UInt32)_maxLen_); MOVE_POS_RET; | ||
| 1036 | |||
| 1037 | #define GET_MATCHES_FOOTER_BT(_maxLen_) \ | ||
| 1038 | GET_MATCHES_FOOTER_BASE(_maxLen_, GetMatchesSpec1) | ||
| 1039 | |||
| 1040 | #define GET_MATCHES_FOOTER_HC(_maxLen_) \ | ||
| 1041 | GET_MATCHES_FOOTER_BASE(_maxLen_, Hc_GetMatchesSpec) | ||
| 1042 | |||
| 1043 | |||
| 1044 | |||
| 1045 | #define UPDATE_maxLen { \ | ||
| 1046 | const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)d2; \ | ||
| 1047 | const Byte *c = cur + maxLen; \ | ||
| 1048 | const Byte *lim = cur + lenLimit; \ | ||
| 1049 | for (; c != lim; c++) if (*(c + diff) != *c) break; \ | ||
| 1050 | maxLen = (unsigned)(c - cur); } | ||
| 1051 | |||
| 1052 | static UInt32* Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) | ||
| 1053 | { | ||
| 1054 | GET_MATCHES_HEADER(2) | ||
| 1055 | HASH2_CALC; | ||
| 1056 | curMatch = p->hash[hv]; | ||
| 1057 | p->hash[hv] = p->pos; | ||
| 1058 | GET_MATCHES_FOOTER_BT(1) | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) | ||
| 1062 | { | ||
| 1063 | GET_MATCHES_HEADER(3) | ||
| 1064 | HASH_ZIP_CALC; | ||
| 1065 | curMatch = p->hash[hv]; | ||
| 1066 | p->hash[hv] = p->pos; | ||
| 1067 | GET_MATCHES_FOOTER_BT(2) | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | |||
| 1071 | #define SET_mmm \ | ||
| 1072 | mmm = p->cyclicBufferSize; \ | ||
| 1073 | if (pos < mmm) \ | ||
| 1074 | mmm = pos; | ||
| 1075 | |||
| 1076 | |||
| 1077 | static UInt32* Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) | ||
| 1078 | { | ||
| 1079 | UInt32 mmm; | ||
| 1080 | UInt32 h2, d2, pos; | ||
| 1081 | unsigned maxLen; | ||
| 1082 | UInt32 *hash; | ||
| 1083 | GET_MATCHES_HEADER(3) | ||
| 1084 | |||
| 1085 | HASH3_CALC; | ||
| 1086 | |||
| 1087 | hash = p->hash; | ||
| 1088 | pos = p->pos; | ||
| 1089 | |||
| 1090 | d2 = pos - hash[h2]; | ||
| 1091 | |||
| 1092 | curMatch = (hash + kFix3HashSize)[hv]; | ||
| 1093 | |||
| 1094 | hash[h2] = pos; | ||
| 1095 | (hash + kFix3HashSize)[hv] = pos; | ||
| 1096 | |||
| 1097 | SET_mmm | ||
| 1098 | |||
| 1099 | maxLen = 2; | ||
| 1100 | |||
| 1101 | if (d2 < mmm && *(cur - d2) == *cur) | ||
| 1102 | { | ||
| 1103 | UPDATE_maxLen | ||
| 1104 | distances[0] = (UInt32)maxLen; | ||
| 1105 | distances[1] = d2 - 1; | ||
| 1106 | distances += 2; | ||
| 1107 | if (maxLen == lenLimit) | ||
| 1108 | { | ||
| 1109 | SkipMatchesSpec(MF_PARAMS(p)); | ||
| 1110 | MOVE_POS_RET; | ||
| 1111 | } | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | GET_MATCHES_FOOTER_BT(maxLen) | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | |||
| 1118 | static UInt32* Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) | ||
| 1119 | { | ||
| 1120 | UInt32 mmm; | ||
| 1121 | UInt32 h2, h3, d2, d3, pos; | ||
| 1122 | unsigned maxLen; | ||
| 1123 | UInt32 *hash; | ||
| 1124 | GET_MATCHES_HEADER(4) | ||
| 1125 | |||
| 1126 | HASH4_CALC; | ||
| 1127 | |||
| 1128 | hash = p->hash; | ||
| 1129 | pos = p->pos; | ||
| 1130 | |||
| 1131 | d2 = pos - hash [h2]; | ||
| 1132 | d3 = pos - (hash + kFix3HashSize)[h3]; | ||
| 1133 | curMatch = (hash + kFix4HashSize)[hv]; | ||
| 1134 | |||
| 1135 | hash [h2] = pos; | ||
| 1136 | (hash + kFix3HashSize)[h3] = pos; | ||
| 1137 | (hash + kFix4HashSize)[hv] = pos; | ||
| 1138 | |||
| 1139 | SET_mmm | ||
| 1140 | |||
| 1141 | maxLen = 3; | ||
| 1142 | |||
| 1143 | for (;;) | ||
| 1144 | { | ||
| 1145 | if (d2 < mmm && *(cur - d2) == *cur) | ||
| 1146 | { | ||
| 1147 | distances[0] = 2; | ||
| 1148 | distances[1] = d2 - 1; | ||
| 1149 | distances += 2; | ||
| 1150 | if (*(cur - d2 + 2) == cur[2]) | ||
| 1151 | { | ||
| 1152 | // distances[-2] = 3; | ||
| 1153 | } | ||
| 1154 | else if (d3 < mmm && *(cur - d3) == *cur) | ||
| 1155 | { | ||
| 1156 | d2 = d3; | ||
| 1157 | distances[1] = d3 - 1; | ||
| 1158 | distances += 2; | ||
| 1159 | } | ||
| 1160 | else | ||
| 1161 | break; | ||
| 1162 | } | ||
| 1163 | else if (d3 < mmm && *(cur - d3) == *cur) | ||
| 1164 | { | ||
| 1165 | d2 = d3; | ||
| 1166 | distances[1] = d3 - 1; | ||
| 1167 | distances += 2; | ||
| 1168 | } | ||
| 1169 | else | ||
| 1170 | break; | ||
| 1171 | |||
| 1172 | UPDATE_maxLen | ||
| 1173 | distances[-2] = (UInt32)maxLen; | ||
| 1174 | if (maxLen == lenLimit) | ||
| 1175 | { | ||
| 1176 | SkipMatchesSpec(MF_PARAMS(p)); | ||
| 1177 | MOVE_POS_RET | ||
| 1178 | } | ||
| 1179 | break; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | GET_MATCHES_FOOTER_BT(maxLen) | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | |||
| 1186 | static UInt32* Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) | ||
| 1187 | { | ||
| 1188 | UInt32 mmm; | ||
| 1189 | UInt32 h2, h3, d2, d3, maxLen, pos; | ||
| 1190 | UInt32 *hash; | ||
| 1191 | GET_MATCHES_HEADER(5) | ||
| 1192 | |||
| 1193 | HASH5_CALC; | ||
| 1194 | |||
| 1195 | hash = p->hash; | ||
| 1196 | pos = p->pos; | ||
| 1197 | |||
| 1198 | d2 = pos - hash [h2]; | ||
| 1199 | d3 = pos - (hash + kFix3HashSize)[h3]; | ||
| 1200 | // d4 = pos - (hash + kFix4HashSize)[h4]; | ||
| 1201 | |||
| 1202 | curMatch = (hash + kFix5HashSize)[hv]; | ||
| 1203 | |||
| 1204 | hash [h2] = pos; | ||
| 1205 | (hash + kFix3HashSize)[h3] = pos; | ||
| 1206 | // (hash + kFix4HashSize)[h4] = pos; | ||
| 1207 | (hash + kFix5HashSize)[hv] = pos; | ||
| 1208 | |||
| 1209 | SET_mmm | ||
| 1210 | |||
| 1211 | maxLen = 4; | ||
| 1212 | |||
| 1213 | for (;;) | ||
| 1214 | { | ||
| 1215 | if (d2 < mmm && *(cur - d2) == *cur) | ||
| 1216 | { | ||
| 1217 | distances[0] = 2; | ||
| 1218 | distances[1] = d2 - 1; | ||
| 1219 | distances += 2; | ||
| 1220 | if (*(cur - d2 + 2) == cur[2]) | ||
| 1221 | { | ||
| 1222 | } | ||
| 1223 | else if (d3 < mmm && *(cur - d3) == *cur) | ||
| 1224 | { | ||
| 1225 | distances[1] = d3 - 1; | ||
| 1226 | distances += 2; | ||
| 1227 | d2 = d3; | ||
| 1228 | } | ||
| 1229 | else | ||
| 1230 | break; | ||
| 1231 | } | ||
| 1232 | else if (d3 < mmm && *(cur - d3) == *cur) | ||
| 1233 | { | ||
| 1234 | distances[1] = d3 - 1; | ||
| 1235 | distances += 2; | ||
| 1236 | d2 = d3; | ||
| 1237 | } | ||
| 1238 | else | ||
| 1239 | break; | ||
| 1240 | |||
| 1241 | distances[-2] = 3; | ||
| 1242 | if (*(cur - d2 + 3) != cur[3]) | ||
| 1243 | break; | ||
| 1244 | UPDATE_maxLen | ||
| 1245 | distances[-2] = (UInt32)maxLen; | ||
| 1246 | if (maxLen == lenLimit) | ||
| 1247 | { | ||
| 1248 | SkipMatchesSpec(MF_PARAMS(p)); | ||
| 1249 | MOVE_POS_RET; | ||
| 1250 | } | ||
| 1251 | break; | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | GET_MATCHES_FOOTER_BT(maxLen) | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | |||
| 1258 | static UInt32* Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) | ||
| 1259 | { | ||
| 1260 | UInt32 mmm; | ||
| 1261 | UInt32 h2, h3, d2, d3, pos; | ||
| 1262 | unsigned maxLen; | ||
| 1263 | UInt32 *hash; | ||
| 1264 | GET_MATCHES_HEADER(4) | ||
| 1265 | |||
| 1266 | HASH4_CALC; | ||
| 1267 | |||
| 1268 | hash = p->hash; | ||
| 1269 | pos = p->pos; | ||
| 1270 | |||
| 1271 | d2 = pos - hash [h2]; | ||
| 1272 | d3 = pos - (hash + kFix3HashSize)[h3]; | ||
| 1273 | curMatch = (hash + kFix4HashSize)[hv]; | ||
| 1274 | |||
| 1275 | hash [h2] = pos; | ||
| 1276 | (hash + kFix3HashSize)[h3] = pos; | ||
| 1277 | (hash + kFix4HashSize)[hv] = pos; | ||
| 1278 | |||
| 1279 | SET_mmm | ||
| 1280 | |||
| 1281 | maxLen = 3; | ||
| 1282 | |||
| 1283 | for (;;) | ||
| 1284 | { | ||
| 1285 | if (d2 < mmm && *(cur - d2) == *cur) | ||
| 1286 | { | ||
| 1287 | distances[0] = 2; | ||
| 1288 | distances[1] = d2 - 1; | ||
| 1289 | distances += 2; | ||
| 1290 | if (*(cur - d2 + 2) == cur[2]) | ||
| 1291 | { | ||
| 1292 | // distances[-2] = 3; | ||
| 1293 | } | ||
| 1294 | else if (d3 < mmm && *(cur - d3) == *cur) | ||
| 1295 | { | ||
| 1296 | d2 = d3; | ||
| 1297 | distances[1] = d3 - 1; | ||
| 1298 | distances += 2; | ||
| 1299 | } | ||
| 1300 | else | ||
| 1301 | break; | ||
| 1302 | } | ||
| 1303 | else if (d3 < mmm && *(cur - d3) == *cur) | ||
| 1304 | { | ||
| 1305 | d2 = d3; | ||
| 1306 | distances[1] = d3 - 1; | ||
| 1307 | distances += 2; | ||
| 1308 | } | ||
| 1309 | else | ||
| 1310 | break; | ||
| 1311 | |||
| 1312 | UPDATE_maxLen | ||
| 1313 | distances[-2] = (UInt32)maxLen; | ||
| 1314 | if (maxLen == lenLimit) | ||
| 1315 | { | ||
| 1316 | p->son[p->cyclicBufferPos] = curMatch; | ||
| 1317 | MOVE_POS_RET; | ||
| 1318 | } | ||
| 1319 | break; | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | GET_MATCHES_FOOTER_HC(maxLen); | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | |||
| 1326 | static UInt32 * Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) | ||
| 1327 | { | ||
| 1328 | UInt32 mmm; | ||
| 1329 | UInt32 h2, h3, d2, d3, maxLen, pos; | ||
| 1330 | UInt32 *hash; | ||
| 1331 | GET_MATCHES_HEADER(5) | ||
| 1332 | |||
| 1333 | HASH5_CALC; | ||
| 1334 | |||
| 1335 | hash = p->hash; | ||
| 1336 | pos = p->pos; | ||
| 1337 | |||
| 1338 | d2 = pos - hash [h2]; | ||
| 1339 | d3 = pos - (hash + kFix3HashSize)[h3]; | ||
| 1340 | // d4 = pos - (hash + kFix4HashSize)[h4]; | ||
| 1341 | |||
| 1342 | curMatch = (hash + kFix5HashSize)[hv]; | ||
| 1343 | |||
| 1344 | hash [h2] = pos; | ||
| 1345 | (hash + kFix3HashSize)[h3] = pos; | ||
| 1346 | // (hash + kFix4HashSize)[h4] = pos; | ||
| 1347 | (hash + kFix5HashSize)[hv] = pos; | ||
| 1348 | |||
| 1349 | SET_mmm | ||
| 1350 | |||
| 1351 | maxLen = 4; | ||
| 1352 | |||
| 1353 | for (;;) | ||
| 1354 | { | ||
| 1355 | if (d2 < mmm && *(cur - d2) == *cur) | ||
| 1356 | { | ||
| 1357 | distances[0] = 2; | ||
| 1358 | distances[1] = d2 - 1; | ||
| 1359 | distances += 2; | ||
| 1360 | if (*(cur - d2 + 2) == cur[2]) | ||
| 1361 | { | ||
| 1362 | } | ||
| 1363 | else if (d3 < mmm && *(cur - d3) == *cur) | ||
| 1364 | { | ||
| 1365 | distances[1] = d3 - 1; | ||
| 1366 | distances += 2; | ||
| 1367 | d2 = d3; | ||
| 1368 | } | ||
| 1369 | else | ||
| 1370 | break; | ||
| 1371 | } | ||
| 1372 | else if (d3 < mmm && *(cur - d3) == *cur) | ||
| 1373 | { | ||
| 1374 | distances[1] = d3 - 1; | ||
| 1375 | distances += 2; | ||
| 1376 | d2 = d3; | ||
| 1377 | } | ||
| 1378 | else | ||
| 1379 | break; | ||
| 1380 | |||
| 1381 | distances[-2] = 3; | ||
| 1382 | if (*(cur - d2 + 3) != cur[3]) | ||
| 1383 | break; | ||
| 1384 | UPDATE_maxLen | ||
| 1385 | distances[-2] = maxLen; | ||
| 1386 | if (maxLen == lenLimit) | ||
| 1387 | { | ||
| 1388 | p->son[p->cyclicBufferPos] = curMatch; | ||
| 1389 | MOVE_POS_RET; | ||
| 1390 | } | ||
| 1391 | break; | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | GET_MATCHES_FOOTER_HC(maxLen); | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | |||
| 1398 | UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) | ||
| 1399 | { | ||
| 1400 | GET_MATCHES_HEADER(3) | ||
| 1401 | HASH_ZIP_CALC; | ||
| 1402 | curMatch = p->hash[hv]; | ||
| 1403 | p->hash[hv] = p->pos; | ||
| 1404 | GET_MATCHES_FOOTER_HC(2) | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | |||
| 1408 | static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) | ||
| 1409 | { | ||
| 1410 | SKIP_HEADER(2) | ||
| 1411 | { | ||
| 1412 | HASH2_CALC; | ||
| 1413 | curMatch = p->hash[hv]; | ||
| 1414 | p->hash[hv] = p->pos; | ||
| 1415 | } | ||
| 1416 | SKIP_FOOTER | ||
| 1417 | } | ||
| 1418 | |||
| 1419 | void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) | ||
| 1420 | { | ||
| 1421 | SKIP_HEADER(3) | ||
| 1422 | { | ||
| 1423 | HASH_ZIP_CALC; | ||
| 1424 | curMatch = p->hash[hv]; | ||
| 1425 | p->hash[hv] = p->pos; | ||
| 1426 | } | ||
| 1427 | SKIP_FOOTER | ||
| 1428 | } | ||
| 1429 | |||
| 1430 | static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) | ||
| 1431 | { | ||
| 1432 | SKIP_HEADER(3) | ||
| 1433 | { | ||
| 1434 | UInt32 h2; | ||
| 1435 | UInt32 *hash; | ||
| 1436 | HASH3_CALC; | ||
| 1437 | hash = p->hash; | ||
| 1438 | curMatch = (hash + kFix3HashSize)[hv]; | ||
| 1439 | hash[h2] = | ||
| 1440 | (hash + kFix3HashSize)[hv] = p->pos; | ||
| 1441 | } | ||
| 1442 | SKIP_FOOTER | ||
| 1443 | } | ||
| 1444 | |||
| 1445 | static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) | ||
| 1446 | { | ||
| 1447 | SKIP_HEADER(4) | ||
| 1448 | { | ||
| 1449 | UInt32 h2, h3; | ||
| 1450 | UInt32 *hash; | ||
| 1451 | HASH4_CALC; | ||
| 1452 | hash = p->hash; | ||
| 1453 | curMatch = (hash + kFix4HashSize)[hv]; | ||
| 1454 | hash [h2] = | ||
| 1455 | (hash + kFix3HashSize)[h3] = | ||
| 1456 | (hash + kFix4HashSize)[hv] = p->pos; | ||
| 1457 | } | ||
| 1458 | SKIP_FOOTER | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) | ||
| 1462 | { | ||
| 1463 | SKIP_HEADER(5) | ||
| 1464 | { | ||
| 1465 | UInt32 h2, h3; | ||
| 1466 | UInt32 *hash; | ||
| 1467 | HASH5_CALC; | ||
| 1468 | hash = p->hash; | ||
| 1469 | curMatch = (hash + kFix5HashSize)[hv]; | ||
| 1470 | hash [h2] = | ||
| 1471 | (hash + kFix3HashSize)[h3] = | ||
| 1472 | // (hash + kFix4HashSize)[h4] = | ||
| 1473 | (hash + kFix5HashSize)[hv] = p->pos; | ||
| 1474 | } | ||
| 1475 | SKIP_FOOTER | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | |||
| 1479 | #define HC_SKIP_HEADER(minLen) \ | ||
| 1480 | do { if (p->lenLimit < minLen) { MatchFinder_MovePos(p); num--; continue; } { \ | ||
| 1481 | Byte *cur; \ | ||
| 1482 | UInt32 *hash; \ | ||
| 1483 | UInt32 *son; \ | ||
| 1484 | UInt32 pos = p->pos; \ | ||
| 1485 | UInt32 num2 = num; \ | ||
| 1486 | /* (p->pos == p->posLimit) is not allowed here !!! */ \ | ||
| 1487 | { const UInt32 rem = p->posLimit - pos; if (num2 > rem) num2 = rem; } \ | ||
| 1488 | num -= num2; \ | ||
| 1489 | { const UInt32 cycPos = p->cyclicBufferPos; \ | ||
| 1490 | son = p->son + cycPos; \ | ||
| 1491 | p->cyclicBufferPos = cycPos + num2; } \ | ||
| 1492 | cur = p->buffer; \ | ||
| 1493 | hash = p->hash; \ | ||
| 1494 | do { \ | ||
| 1495 | UInt32 curMatch; \ | ||
| 1496 | UInt32 hv; | ||
| 1497 | |||
| 1498 | |||
| 1499 | #define HC_SKIP_FOOTER \ | ||
| 1500 | cur++; pos++; *son++ = curMatch; \ | ||
| 1501 | } while (--num2); \ | ||
| 1502 | p->buffer = cur; \ | ||
| 1503 | p->pos = pos; \ | ||
| 1504 | if (pos == p->posLimit) MatchFinder_CheckLimits(p); \ | ||
| 1505 | }} while(num); \ | ||
| 1506 | |||
| 1507 | |||
| 1508 | static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) | ||
| 1509 | { | ||
| 1510 | HC_SKIP_HEADER(4) | ||
| 1511 | |||
| 1512 | UInt32 h2, h3; | ||
| 1513 | HASH4_CALC; | ||
| 1514 | curMatch = (hash + kFix4HashSize)[hv]; | ||
| 1515 | hash [h2] = | ||
| 1516 | (hash + kFix3HashSize)[h3] = | ||
| 1517 | (hash + kFix4HashSize)[hv] = pos; | ||
| 1518 | |||
| 1519 | HC_SKIP_FOOTER | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | |||
| 1523 | static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) | ||
| 1524 | { | ||
| 1525 | HC_SKIP_HEADER(5) | ||
| 1526 | |||
| 1527 | UInt32 h2, h3; | ||
| 1528 | HASH5_CALC | ||
| 1529 | curMatch = (hash + kFix5HashSize)[hv]; | ||
| 1530 | hash [h2] = | ||
| 1531 | (hash + kFix3HashSize)[h3] = | ||
| 1532 | // (hash + kFix4HashSize)[h4] = | ||
| 1533 | (hash + kFix5HashSize)[hv] = pos; | ||
| 1534 | |||
| 1535 | HC_SKIP_FOOTER | ||
| 1536 | } | ||
| 1537 | |||
| 1538 | |||
| 1539 | void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) | ||
| 1540 | { | ||
| 1541 | HC_SKIP_HEADER(3) | ||
| 1542 | |||
| 1543 | HASH_ZIP_CALC; | ||
| 1544 | curMatch = hash[hv]; | ||
| 1545 | hash[hv] = pos; | ||
| 1546 | |||
| 1547 | HC_SKIP_FOOTER | ||
| 1548 | } | ||
| 1549 | |||
| 1550 | |||
| 1551 | void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable) | ||
| 1552 | { | ||
| 1553 | vTable->Init = (Mf_Init_Func)MatchFinder_Init; | ||
| 1554 | vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; | ||
| 1555 | vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; | ||
| 1556 | if (!p->btMode) | ||
| 1557 | { | ||
| 1558 | if (p->numHashBytes <= 4) | ||
| 1559 | { | ||
| 1560 | vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; | ||
| 1561 | vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; | ||
| 1562 | } | ||
| 1563 | else | ||
| 1564 | { | ||
| 1565 | vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches; | ||
| 1566 | vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip; | ||
| 1567 | } | ||
| 1568 | } | ||
| 1569 | else if (p->numHashBytes == 2) | ||
| 1570 | { | ||
| 1571 | vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; | ||
| 1572 | vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; | ||
| 1573 | } | ||
| 1574 | else if (p->numHashBytes == 3) | ||
| 1575 | { | ||
| 1576 | vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; | ||
| 1577 | vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; | ||
| 1578 | } | ||
| 1579 | else if (p->numHashBytes == 4) | ||
| 1580 | { | ||
| 1581 | vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; | ||
| 1582 | vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; | ||
| 1583 | } | ||
| 1584 | else | ||
| 1585 | { | ||
| 1586 | vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches; | ||
| 1587 | vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip; | ||
| 1588 | } | ||
| 1589 | } | ||
| 1590 | |||
| 1591 | |||
| 1592 | |||
| 1593 | void LzFindPrepare() | ||
| 1594 | { | ||
| 1595 | #ifndef FORCE_SATUR_SUB_128 | ||
| 1596 | #ifdef USE_SATUR_SUB_128 | ||
| 1597 | LZFIND_SATUR_SUB_CODE_FUNC f = NULL; | ||
| 1598 | #ifdef MY_CPU_ARM_OR_ARM64 | ||
| 1599 | { | ||
| 1600 | if (CPU_IsSupported_NEON()) | ||
| 1601 | { | ||
| 1602 | // #pragma message ("=== LzFind NEON") | ||
| 1603 | _PRF(printf("\n=== LzFind NEON\n")); | ||
| 1604 | f = LzFind_SaturSub_128; | ||
| 1605 | } | ||
| 1606 | // f = 0; // for debug | ||
| 1607 | } | ||
| 1608 | #else // MY_CPU_ARM_OR_ARM64 | ||
| 1609 | if (CPU_IsSupported_SSE41()) | ||
| 1610 | { | ||
| 1611 | // #pragma message ("=== LzFind SSE41") | ||
| 1612 | _PRF(printf("\n=== LzFind SSE41\n")); | ||
| 1613 | f = LzFind_SaturSub_128; | ||
| 1614 | |||
| 1615 | #ifdef USE_AVX2 | ||
| 1616 | if (CPU_IsSupported_AVX2()) | ||
| 1617 | { | ||
| 1618 | // #pragma message ("=== LzFind AVX2") | ||
| 1619 | _PRF(printf("\n=== LzFind AVX2\n")); | ||
| 1620 | f = LzFind_SaturSub_256; | ||
| 1621 | } | ||
| 1622 | #endif | ||
| 1623 | } | ||
| 1624 | #endif // MY_CPU_ARM_OR_ARM64 | ||
| 1625 | g_LzFind_SaturSub = f; | ||
| 1626 | #endif // USE_SATUR_SUB_128 | ||
| 1627 | #endif // FORCE_SATUR_SUB_128 | ||
| 1628 | } | ||
diff --git a/C/LzFind.h b/C/LzFind.h new file mode 100644 index 0000000..eea873f --- /dev/null +++ b/C/LzFind.h | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | /* LzFind.h -- Match finder for LZ algorithms | ||
| 2 | 2021-07-13 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __LZ_FIND_H | ||
| 5 | #define __LZ_FIND_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | typedef UInt32 CLzRef; | ||
| 12 | |||
| 13 | typedef struct _CMatchFinder | ||
| 14 | { | ||
| 15 | Byte *buffer; | ||
| 16 | UInt32 pos; | ||
| 17 | UInt32 posLimit; | ||
| 18 | UInt32 streamPos; /* wrap over Zero is allowed (streamPos < pos). Use (UInt32)(streamPos - pos) */ | ||
| 19 | UInt32 lenLimit; | ||
| 20 | |||
| 21 | UInt32 cyclicBufferPos; | ||
| 22 | UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ | ||
| 23 | |||
| 24 | Byte streamEndWasReached; | ||
| 25 | Byte btMode; | ||
| 26 | Byte bigHash; | ||
| 27 | Byte directInput; | ||
| 28 | |||
| 29 | UInt32 matchMaxLen; | ||
| 30 | CLzRef *hash; | ||
| 31 | CLzRef *son; | ||
| 32 | UInt32 hashMask; | ||
| 33 | UInt32 cutValue; | ||
| 34 | |||
| 35 | Byte *bufferBase; | ||
| 36 | ISeqInStream *stream; | ||
| 37 | |||
| 38 | UInt32 blockSize; | ||
| 39 | UInt32 keepSizeBefore; | ||
| 40 | UInt32 keepSizeAfter; | ||
| 41 | |||
| 42 | UInt32 numHashBytes; | ||
| 43 | size_t directInputRem; | ||
| 44 | UInt32 historySize; | ||
| 45 | UInt32 fixedHashSize; | ||
| 46 | UInt32 hashSizeSum; | ||
| 47 | SRes result; | ||
| 48 | UInt32 crc[256]; | ||
| 49 | size_t numRefs; | ||
| 50 | |||
| 51 | UInt64 expectedDataSize; | ||
| 52 | } CMatchFinder; | ||
| 53 | |||
| 54 | #define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const Byte *)(p)->buffer) | ||
| 55 | |||
| 56 | #define Inline_MatchFinder_GetNumAvailableBytes(p) ((UInt32)((p)->streamPos - (p)->pos)) | ||
| 57 | |||
| 58 | /* | ||
| 59 | #define Inline_MatchFinder_IsFinishedOK(p) \ | ||
| 60 | ((p)->streamEndWasReached \ | ||
| 61 | && (p)->streamPos == (p)->pos \ | ||
| 62 | && (!(p)->directInput || (p)->directInputRem == 0)) | ||
| 63 | */ | ||
| 64 | |||
| 65 | int MatchFinder_NeedMove(CMatchFinder *p); | ||
| 66 | /* Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */ | ||
| 67 | void MatchFinder_MoveBlock(CMatchFinder *p); | ||
| 68 | void MatchFinder_ReadIfRequired(CMatchFinder *p); | ||
| 69 | |||
| 70 | void MatchFinder_Construct(CMatchFinder *p); | ||
| 71 | |||
| 72 | /* Conditions: | ||
| 73 | historySize <= 3 GB | ||
| 74 | keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB | ||
| 75 | */ | ||
| 76 | int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, | ||
| 77 | UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, | ||
| 78 | ISzAllocPtr alloc); | ||
| 79 | void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc); | ||
| 80 | void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems); | ||
| 81 | // void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); | ||
| 82 | |||
| 83 | /* | ||
| 84 | #define Inline_MatchFinder_InitPos(p, val) \ | ||
| 85 | (p)->pos = (val); \ | ||
| 86 | (p)->streamPos = (val); | ||
| 87 | */ | ||
| 88 | |||
| 89 | #define Inline_MatchFinder_ReduceOffsets(p, subValue) \ | ||
| 90 | (p)->pos -= (subValue); \ | ||
| 91 | (p)->streamPos -= (subValue); | ||
| 92 | |||
| 93 | |||
| 94 | UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, | ||
| 95 | size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, | ||
| 96 | UInt32 *distances, UInt32 maxLen); | ||
| 97 | |||
| 98 | /* | ||
| 99 | Conditions: | ||
| 100 | Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. | ||
| 101 | Mf_GetPointerToCurrentPos_Func's result must be used only before any other function | ||
| 102 | */ | ||
| 103 | |||
| 104 | typedef void (*Mf_Init_Func)(void *object); | ||
| 105 | typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); | ||
| 106 | typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); | ||
| 107 | typedef UInt32 * (*Mf_GetMatches_Func)(void *object, UInt32 *distances); | ||
| 108 | typedef void (*Mf_Skip_Func)(void *object, UInt32); | ||
| 109 | |||
| 110 | typedef struct _IMatchFinder | ||
| 111 | { | ||
| 112 | Mf_Init_Func Init; | ||
| 113 | Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; | ||
| 114 | Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; | ||
| 115 | Mf_GetMatches_Func GetMatches; | ||
| 116 | Mf_Skip_Func Skip; | ||
| 117 | } IMatchFinder2; | ||
| 118 | |||
| 119 | void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable); | ||
| 120 | |||
| 121 | void MatchFinder_Init_LowHash(CMatchFinder *p); | ||
| 122 | void MatchFinder_Init_HighHash(CMatchFinder *p); | ||
| 123 | void MatchFinder_Init_4(CMatchFinder *p); | ||
| 124 | void MatchFinder_Init(CMatchFinder *p); | ||
| 125 | |||
| 126 | UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); | ||
| 127 | UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); | ||
| 128 | |||
| 129 | void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); | ||
| 130 | void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); | ||
| 131 | |||
| 132 | void LzFindPrepare(void); | ||
| 133 | |||
| 134 | EXTERN_C_END | ||
| 135 | |||
| 136 | #endif | ||
diff --git a/C/LzFindMt.c b/C/LzFindMt.c new file mode 100644 index 0000000..4e67fc3 --- /dev/null +++ b/C/LzFindMt.c | |||
| @@ -0,0 +1,1400 @@ | |||
| 1 | /* LzFindMt.c -- multithreaded Match finder for LZ algorithms | ||
| 2 | 2021-12-21 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | // #include <stdio.h> | ||
| 7 | |||
| 8 | #include "CpuArch.h" | ||
| 9 | |||
| 10 | #include "LzHash.h" | ||
| 11 | #include "LzFindMt.h" | ||
| 12 | |||
| 13 | // #define LOG_ITERS | ||
| 14 | |||
| 15 | // #define LOG_THREAD | ||
| 16 | |||
| 17 | #ifdef LOG_THREAD | ||
| 18 | #include <stdio.h> | ||
| 19 | #define PRF(x) x | ||
| 20 | #else | ||
| 21 | #define PRF(x) | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #ifdef LOG_ITERS | ||
| 25 | #include <stdio.h> | ||
| 26 | extern UInt64 g_NumIters_Tree; | ||
| 27 | extern UInt64 g_NumIters_Loop; | ||
| 28 | extern UInt64 g_NumIters_Bytes; | ||
| 29 | #define LOG_ITER(x) x | ||
| 30 | #else | ||
| 31 | #define LOG_ITER(x) | ||
| 32 | #endif | ||
| 33 | |||
| 34 | #define kMtHashBlockSize ((UInt32)1 << 17) | ||
| 35 | #define kMtHashNumBlocks (1 << 1) | ||
| 36 | |||
| 37 | #define GET_HASH_BLOCK_OFFSET(i) (((i) & (kMtHashNumBlocks - 1)) * kMtHashBlockSize) | ||
| 38 | |||
| 39 | #define kMtBtBlockSize ((UInt32)1 << 16) | ||
| 40 | #define kMtBtNumBlocks (1 << 4) | ||
| 41 | |||
| 42 | #define GET_BT_BLOCK_OFFSET(i) (((i) & (kMtBtNumBlocks - 1)) * (size_t)kMtBtBlockSize) | ||
| 43 | |||
| 44 | /* | ||
| 45 | HASH functions: | ||
| 46 | We use raw 8/16 bits from a[1] and a[2], | ||
| 47 | xored with crc(a[0]) and crc(a[3]). | ||
| 48 | We check a[0], a[3] only. We don't need to compare a[1] and a[2] in matches. | ||
| 49 | our crc() function provides one-to-one correspondence for low 8-bit values: | ||
| 50 | (crc[0...0xFF] & 0xFF) <-> [0...0xFF] | ||
| 51 | */ | ||
| 52 | |||
| 53 | #define MF(mt) ((mt)->MatchFinder) | ||
| 54 | #define MF_CRC (p->crc) | ||
| 55 | |||
| 56 | // #define MF(mt) (&(mt)->MatchFinder) | ||
| 57 | // #define MF_CRC (p->MatchFinder.crc) | ||
| 58 | |||
| 59 | #define MT_HASH2_CALC \ | ||
| 60 | h2 = (MF_CRC[cur[0]] ^ cur[1]) & (kHash2Size - 1); | ||
| 61 | |||
| 62 | #define MT_HASH3_CALC { \ | ||
| 63 | UInt32 temp = MF_CRC[cur[0]] ^ cur[1]; \ | ||
| 64 | h2 = temp & (kHash2Size - 1); \ | ||
| 65 | h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } | ||
| 66 | |||
| 67 | /* | ||
| 68 | #define MT_HASH3_CALC__NO_2 { \ | ||
| 69 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ | ||
| 70 | h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } | ||
| 71 | |||
| 72 | #define __MT_HASH4_CALC { \ | ||
| 73 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ | ||
| 74 | h2 = temp & (kHash2Size - 1); \ | ||
| 75 | temp ^= ((UInt32)cur[2] << 8); \ | ||
| 76 | h3 = temp & (kHash3Size - 1); \ | ||
| 77 | h4 = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hash4Mask; } | ||
| 78 | // (kHash4Size - 1); | ||
| 79 | */ | ||
| 80 | |||
| 81 | |||
| 82 | MY_NO_INLINE | ||
| 83 | static void MtSync_Construct(CMtSync *p) | ||
| 84 | { | ||
| 85 | p->affinity = 0; | ||
| 86 | p->wasCreated = False; | ||
| 87 | p->csWasInitialized = False; | ||
| 88 | p->csWasEntered = False; | ||
| 89 | Thread_Construct(&p->thread); | ||
| 90 | Event_Construct(&p->canStart); | ||
| 91 | Event_Construct(&p->wasStopped); | ||
| 92 | Semaphore_Construct(&p->freeSemaphore); | ||
| 93 | Semaphore_Construct(&p->filledSemaphore); | ||
| 94 | } | ||
| 95 | |||
| 96 | |||
| 97 | #define DEBUG_BUFFER_LOCK // define it to debug lock state | ||
| 98 | |||
| 99 | #ifdef DEBUG_BUFFER_LOCK | ||
| 100 | #include <stdlib.h> | ||
| 101 | #define BUFFER_MUST_BE_LOCKED(p) if (!(p)->csWasEntered) exit(1); | ||
| 102 | #define BUFFER_MUST_BE_UNLOCKED(p) if ( (p)->csWasEntered) exit(1); | ||
| 103 | #else | ||
| 104 | #define BUFFER_MUST_BE_LOCKED(p) | ||
| 105 | #define BUFFER_MUST_BE_UNLOCKED(p) | ||
| 106 | #endif | ||
| 107 | |||
| 108 | #define LOCK_BUFFER(p) { \ | ||
| 109 | BUFFER_MUST_BE_UNLOCKED(p); \ | ||
| 110 | CriticalSection_Enter(&(p)->cs); \ | ||
| 111 | (p)->csWasEntered = True; } | ||
| 112 | |||
| 113 | #define UNLOCK_BUFFER(p) { \ | ||
| 114 | BUFFER_MUST_BE_LOCKED(p); \ | ||
| 115 | CriticalSection_Leave(&(p)->cs); \ | ||
| 116 | (p)->csWasEntered = False; } | ||
| 117 | |||
| 118 | |||
| 119 | MY_NO_INLINE | ||
| 120 | static UInt32 MtSync_GetNextBlock(CMtSync *p) | ||
| 121 | { | ||
| 122 | UInt32 numBlocks = 0; | ||
| 123 | if (p->needStart) | ||
| 124 | { | ||
| 125 | BUFFER_MUST_BE_UNLOCKED(p) | ||
| 126 | p->numProcessedBlocks = 1; | ||
| 127 | p->needStart = False; | ||
| 128 | p->stopWriting = False; | ||
| 129 | p->exit = False; | ||
| 130 | Event_Reset(&p->wasStopped); | ||
| 131 | Event_Set(&p->canStart); | ||
| 132 | } | ||
| 133 | else | ||
| 134 | { | ||
| 135 | UNLOCK_BUFFER(p) | ||
| 136 | // we free current block | ||
| 137 | numBlocks = p->numProcessedBlocks++; | ||
| 138 | Semaphore_Release1(&p->freeSemaphore); | ||
| 139 | } | ||
| 140 | |||
| 141 | // buffer is UNLOCKED here | ||
| 142 | Semaphore_Wait(&p->filledSemaphore); | ||
| 143 | LOCK_BUFFER(p); | ||
| 144 | return numBlocks; | ||
| 145 | } | ||
| 146 | |||
| 147 | |||
| 148 | /* if Writing (Processing) thread was started, we must call MtSync_StopWriting() */ | ||
| 149 | |||
| 150 | MY_NO_INLINE | ||
| 151 | static void MtSync_StopWriting(CMtSync *p) | ||
| 152 | { | ||
| 153 | if (!Thread_WasCreated(&p->thread) || p->needStart) | ||
| 154 | return; | ||
| 155 | |||
| 156 | PRF(printf("\nMtSync_StopWriting %p\n", p)); | ||
| 157 | |||
| 158 | if (p->csWasEntered) | ||
| 159 | { | ||
| 160 | /* we don't use buffer in this thread after StopWriting(). | ||
| 161 | So we UNLOCK buffer. | ||
| 162 | And we restore default UNLOCKED state for stopped thread */ | ||
| 163 | UNLOCK_BUFFER(p) | ||
| 164 | } | ||
| 165 | |||
| 166 | /* We send (p->stopWriting) message and release freeSemaphore | ||
| 167 | to free current block. | ||
| 168 | So the thread will see (p->stopWriting) at some | ||
| 169 | iteration after Wait(freeSemaphore). | ||
| 170 | The thread doesn't need to fill all avail free blocks, | ||
| 171 | so we can get fast thread stop. | ||
| 172 | */ | ||
| 173 | |||
| 174 | p->stopWriting = True; | ||
| 175 | Semaphore_Release1(&p->freeSemaphore); // check semaphore count !!! | ||
| 176 | |||
| 177 | PRF(printf("\nMtSync_StopWriting %p : Event_Wait(&p->wasStopped)\n", p)); | ||
| 178 | Event_Wait(&p->wasStopped); | ||
| 179 | PRF(printf("\nMtSync_StopWriting %p : Event_Wait() finsihed\n", p)); | ||
| 180 | |||
| 181 | /* 21.03 : we don't restore samaphore counters here. | ||
| 182 | We will recreate and reinit samaphores in next start */ | ||
| 183 | |||
| 184 | p->needStart = True; | ||
| 185 | } | ||
| 186 | |||
| 187 | |||
| 188 | MY_NO_INLINE | ||
| 189 | static void MtSync_Destruct(CMtSync *p) | ||
| 190 | { | ||
| 191 | PRF(printf("\nMtSync_Destruct %p\n", p)); | ||
| 192 | |||
| 193 | if (Thread_WasCreated(&p->thread)) | ||
| 194 | { | ||
| 195 | /* we want thread to be in Stopped state before sending EXIT command. | ||
| 196 | note: stop(btSync) will stop (htSync) also */ | ||
| 197 | MtSync_StopWriting(p); | ||
| 198 | /* thread in Stopped state here : (p->needStart == true) */ | ||
| 199 | p->exit = True; | ||
| 200 | // if (p->needStart) // it's (true) | ||
| 201 | Event_Set(&p->canStart); // we send EXIT command to thread | ||
| 202 | Thread_Wait_Close(&p->thread); // we wait thread finishing | ||
| 203 | } | ||
| 204 | |||
| 205 | if (p->csWasInitialized) | ||
| 206 | { | ||
| 207 | CriticalSection_Delete(&p->cs); | ||
| 208 | p->csWasInitialized = False; | ||
| 209 | } | ||
| 210 | p->csWasEntered = False; | ||
| 211 | |||
| 212 | Event_Close(&p->canStart); | ||
| 213 | Event_Close(&p->wasStopped); | ||
| 214 | Semaphore_Close(&p->freeSemaphore); | ||
| 215 | Semaphore_Close(&p->filledSemaphore); | ||
| 216 | |||
| 217 | p->wasCreated = False; | ||
| 218 | } | ||
| 219 | |||
| 220 | |||
| 221 | // #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } | ||
| 222 | // we want to get real system error codes here instead of SZ_ERROR_THREAD | ||
| 223 | #define RINOK_THREAD(x) RINOK(x) | ||
| 224 | |||
| 225 | |||
| 226 | // call it before each new file (when new starting is required): | ||
| 227 | MY_NO_INLINE | ||
| 228 | static SRes MtSync_Init(CMtSync *p, UInt32 numBlocks) | ||
| 229 | { | ||
| 230 | WRes wres; | ||
| 231 | // BUFFER_MUST_BE_UNLOCKED(p) | ||
| 232 | if (!p->needStart || p->csWasEntered) | ||
| 233 | return SZ_ERROR_FAIL; | ||
| 234 | wres = Semaphore_OptCreateInit(&p->freeSemaphore, numBlocks, numBlocks); | ||
| 235 | if (wres == 0) | ||
| 236 | wres = Semaphore_OptCreateInit(&p->filledSemaphore, 0, numBlocks); | ||
| 237 | return MY_SRes_HRESULT_FROM_WRes(wres); | ||
| 238 | } | ||
| 239 | |||
| 240 | |||
| 241 | static WRes MtSync_Create_WRes(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj) | ||
| 242 | { | ||
| 243 | WRes wres; | ||
| 244 | |||
| 245 | if (p->wasCreated) | ||
| 246 | return SZ_OK; | ||
| 247 | |||
| 248 | RINOK_THREAD(CriticalSection_Init(&p->cs)); | ||
| 249 | p->csWasInitialized = True; | ||
| 250 | p->csWasEntered = False; | ||
| 251 | |||
| 252 | RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)); | ||
| 253 | RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)); | ||
| 254 | |||
| 255 | p->needStart = True; | ||
| 256 | p->exit = True; /* p->exit is unused before (canStart) Event. | ||
| 257 | But in case of some unexpected code failure we will get fast exit from thread */ | ||
| 258 | |||
| 259 | // return ERROR_TOO_MANY_POSTS; // for debug | ||
| 260 | // return EINVAL; // for debug | ||
| 261 | |||
| 262 | if (p->affinity != 0) | ||
| 263 | wres = Thread_Create_With_Affinity(&p->thread, startAddress, obj, (CAffinityMask)p->affinity); | ||
| 264 | else | ||
| 265 | wres = Thread_Create(&p->thread, startAddress, obj); | ||
| 266 | |||
| 267 | RINOK_THREAD(wres); | ||
| 268 | p->wasCreated = True; | ||
| 269 | return SZ_OK; | ||
| 270 | } | ||
| 271 | |||
| 272 | |||
| 273 | MY_NO_INLINE | ||
| 274 | static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj) | ||
| 275 | { | ||
| 276 | const WRes wres = MtSync_Create_WRes(p, startAddress, obj); | ||
| 277 | if (wres == 0) | ||
| 278 | return 0; | ||
| 279 | MtSync_Destruct(p); | ||
| 280 | return MY_SRes_HRESULT_FROM_WRes(wres); | ||
| 281 | } | ||
| 282 | |||
| 283 | |||
| 284 | // ---------- HASH THREAD ---------- | ||
| 285 | |||
| 286 | #define kMtMaxValForNormalize 0xFFFFFFFF | ||
| 287 | // #define kMtMaxValForNormalize ((1 << 21)) // for debug | ||
| 288 | // #define kNormalizeAlign (1 << 7) // alignment for speculated accesses | ||
| 289 | |||
| 290 | #ifdef MY_CPU_LE_UNALIGN | ||
| 291 | #define GetUi24hi_from32(p) ((UInt32)GetUi32(p) >> 8) | ||
| 292 | #else | ||
| 293 | #define GetUi24hi_from32(p) ((p)[1] ^ ((UInt32)(p)[2] << 8) ^ ((UInt32)(p)[3] << 16)) | ||
| 294 | #endif | ||
| 295 | |||
| 296 | #define GetHeads_DECL(name) \ | ||
| 297 | static void GetHeads ## name(const Byte *p, UInt32 pos, \ | ||
| 298 | UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) | ||
| 299 | |||
| 300 | #define GetHeads_LOOP(v) \ | ||
| 301 | for (; numHeads != 0; numHeads--) { \ | ||
| 302 | const UInt32 value = (v); \ | ||
| 303 | p++; \ | ||
| 304 | *heads++ = pos - hash[value]; \ | ||
| 305 | hash[value] = pos++; } | ||
| 306 | |||
| 307 | #define DEF_GetHeads2(name, v, action) \ | ||
| 308 | GetHeads_DECL(name) { action \ | ||
| 309 | GetHeads_LOOP(v) } | ||
| 310 | |||
| 311 | #define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) | ||
| 312 | |||
| 313 | DEF_GetHeads2(2, GetUi16(p), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) | ||
| 314 | DEF_GetHeads(3, (crc[p[0]] ^ GetUi16(p + 1)) & hashMask) | ||
| 315 | DEF_GetHeads2(3b, GetUi16(p) ^ ((UInt32)(p)[2] << 16), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) | ||
| 316 | // BT3 is not good for crc collisions for big hashMask values. | ||
| 317 | |||
| 318 | /* | ||
| 319 | GetHeads_DECL(3b) | ||
| 320 | { | ||
| 321 | UNUSED_VAR(hashMask); | ||
| 322 | UNUSED_VAR(crc); | ||
| 323 | { | ||
| 324 | const Byte *pLim = p + numHeads; | ||
| 325 | if (numHeads == 0) | ||
| 326 | return; | ||
| 327 | pLim--; | ||
| 328 | while (p < pLim) | ||
| 329 | { | ||
| 330 | UInt32 v1 = GetUi32(p); | ||
| 331 | UInt32 v0 = v1 & 0xFFFFFF; | ||
| 332 | UInt32 h0, h1; | ||
| 333 | p += 2; | ||
| 334 | v1 >>= 8; | ||
| 335 | h0 = hash[v0]; hash[v0] = pos; heads[0] = pos - h0; pos++; | ||
| 336 | h1 = hash[v1]; hash[v1] = pos; heads[1] = pos - h1; pos++; | ||
| 337 | heads += 2; | ||
| 338 | } | ||
| 339 | if (p == pLim) | ||
| 340 | { | ||
| 341 | UInt32 v0 = GetUi16(p) ^ ((UInt32)(p)[2] << 16); | ||
| 342 | *heads = pos - hash[v0]; | ||
| 343 | hash[v0] = pos; | ||
| 344 | } | ||
| 345 | } | ||
| 346 | } | ||
| 347 | */ | ||
| 348 | |||
| 349 | /* | ||
| 350 | GetHeads_DECL(4) | ||
| 351 | { | ||
| 352 | unsigned sh = 0; | ||
| 353 | UNUSED_VAR(crc) | ||
| 354 | while ((hashMask & 0x80000000) == 0) | ||
| 355 | { | ||
| 356 | hashMask <<= 1; | ||
| 357 | sh++; | ||
| 358 | } | ||
| 359 | GetHeads_LOOP((GetUi32(p) * 0xa54a1) >> sh) | ||
| 360 | } | ||
| 361 | #define GetHeads4b GetHeads4 | ||
| 362 | */ | ||
| 363 | |||
| 364 | #define USE_GetHeads_LOCAL_CRC | ||
| 365 | |||
| 366 | #ifdef USE_GetHeads_LOCAL_CRC | ||
| 367 | |||
| 368 | GetHeads_DECL(4) | ||
| 369 | { | ||
| 370 | UInt32 crc0[256]; | ||
| 371 | UInt32 crc1[256]; | ||
| 372 | { | ||
| 373 | unsigned i; | ||
| 374 | for (i = 0; i < 256; i++) | ||
| 375 | { | ||
| 376 | UInt32 v = crc[i]; | ||
| 377 | crc0[i] = v & hashMask; | ||
| 378 | crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; | ||
| 379 | // crc1[i] = rotlFixed(v, 8) & hashMask; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ (UInt32)GetUi16(p+1)) | ||
| 383 | } | ||
| 384 | |||
| 385 | GetHeads_DECL(4b) | ||
| 386 | { | ||
| 387 | UInt32 crc0[256]; | ||
| 388 | { | ||
| 389 | unsigned i; | ||
| 390 | for (i = 0; i < 256; i++) | ||
| 391 | crc0[i] = crc[i] & hashMask; | ||
| 392 | } | ||
| 393 | GetHeads_LOOP(crc0[p[0]] ^ GetUi24hi_from32(p)) | ||
| 394 | } | ||
| 395 | |||
| 396 | GetHeads_DECL(5) | ||
| 397 | { | ||
| 398 | UInt32 crc0[256]; | ||
| 399 | UInt32 crc1[256]; | ||
| 400 | UInt32 crc2[256]; | ||
| 401 | { | ||
| 402 | unsigned i; | ||
| 403 | for (i = 0; i < 256; i++) | ||
| 404 | { | ||
| 405 | UInt32 v = crc[i]; | ||
| 406 | crc0[i] = v & hashMask; | ||
| 407 | crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; | ||
| 408 | crc2[i] = (v << kLzHash_CrcShift_2) & hashMask; | ||
| 409 | } | ||
| 410 | } | ||
| 411 | GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ crc2[p[4]] ^ (UInt32)GetUi16(p+1)) | ||
| 412 | } | ||
| 413 | |||
| 414 | GetHeads_DECL(5b) | ||
| 415 | { | ||
| 416 | UInt32 crc0[256]; | ||
| 417 | UInt32 crc1[256]; | ||
| 418 | { | ||
| 419 | unsigned i; | ||
| 420 | for (i = 0; i < 256; i++) | ||
| 421 | { | ||
| 422 | UInt32 v = crc[i]; | ||
| 423 | crc0[i] = v & hashMask; | ||
| 424 | crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; | ||
| 425 | } | ||
| 426 | } | ||
| 427 | GetHeads_LOOP(crc0[p[0]] ^ crc1[p[4]] ^ GetUi24hi_from32(p)) | ||
| 428 | } | ||
| 429 | |||
| 430 | #else | ||
| 431 | |||
| 432 | DEF_GetHeads(4, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (UInt32)GetUi16(p+1)) & hashMask) | ||
| 433 | DEF_GetHeads(4b, (crc[p[0]] ^ GetUi24hi_from32(p)) & hashMask) | ||
| 434 | DEF_GetHeads(5, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (crc[p[4]] << kLzHash_CrcShift_2) ^ (UInt32)GetUi16(p + 1)) & hashMask) | ||
| 435 | DEF_GetHeads(5b, (crc[p[0]] ^ (crc[p[4]] << kLzHash_CrcShift_1) ^ GetUi24hi_from32(p)) & hashMask) | ||
| 436 | |||
| 437 | #endif | ||
| 438 | |||
| 439 | |||
| 440 | static void HashThreadFunc(CMatchFinderMt *mt) | ||
| 441 | { | ||
| 442 | CMtSync *p = &mt->hashSync; | ||
| 443 | PRF(printf("\nHashThreadFunc\n")); | ||
| 444 | |||
| 445 | for (;;) | ||
| 446 | { | ||
| 447 | UInt32 blockIndex = 0; | ||
| 448 | PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart)\n")); | ||
| 449 | Event_Wait(&p->canStart); | ||
| 450 | PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart) : after \n")); | ||
| 451 | if (p->exit) | ||
| 452 | { | ||
| 453 | PRF(printf("\nHashThreadFunc : exit \n")); | ||
| 454 | return; | ||
| 455 | } | ||
| 456 | |||
| 457 | MatchFinder_Init_HighHash(MF(mt)); | ||
| 458 | |||
| 459 | for (;;) | ||
| 460 | { | ||
| 461 | PRF(printf("Hash thread block = %d pos = %d\n", (unsigned)blockIndex, mt->MatchFinder->pos)); | ||
| 462 | |||
| 463 | { | ||
| 464 | CMatchFinder *mf = MF(mt); | ||
| 465 | if (MatchFinder_NeedMove(mf)) | ||
| 466 | { | ||
| 467 | CriticalSection_Enter(&mt->btSync.cs); | ||
| 468 | CriticalSection_Enter(&mt->hashSync.cs); | ||
| 469 | { | ||
| 470 | const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf); | ||
| 471 | ptrdiff_t offset; | ||
| 472 | MatchFinder_MoveBlock(mf); | ||
| 473 | offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf); | ||
| 474 | mt->pointerToCurPos -= offset; | ||
| 475 | mt->buffer -= offset; | ||
| 476 | } | ||
| 477 | CriticalSection_Leave(&mt->hashSync.cs); | ||
| 478 | CriticalSection_Leave(&mt->btSync.cs); | ||
| 479 | continue; | ||
| 480 | } | ||
| 481 | |||
| 482 | Semaphore_Wait(&p->freeSemaphore); | ||
| 483 | |||
| 484 | if (p->exit) // exit is unexpected here. But we check it here for some failure case | ||
| 485 | return; | ||
| 486 | |||
| 487 | // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore) | ||
| 488 | if (p->stopWriting) | ||
| 489 | break; | ||
| 490 | |||
| 491 | MatchFinder_ReadIfRequired(mf); | ||
| 492 | { | ||
| 493 | UInt32 *heads = mt->hashBuf + GET_HASH_BLOCK_OFFSET(blockIndex++); | ||
| 494 | UInt32 num = Inline_MatchFinder_GetNumAvailableBytes(mf); | ||
| 495 | heads[0] = 2; | ||
| 496 | heads[1] = num; | ||
| 497 | |||
| 498 | /* heads[1] contains the number of avail bytes: | ||
| 499 | if (avail < mf->numHashBytes) : | ||
| 500 | { | ||
| 501 | it means that stream was finished | ||
| 502 | HASH_THREAD and BT_TREAD must move position for heads[1] (avail) bytes. | ||
| 503 | HASH_THREAD doesn't stop, | ||
| 504 | HASH_THREAD fills only the header (2 numbers) for all next blocks: | ||
| 505 | {2, NumHashBytes - 1}, {2,0}, {2,0}, ... , {2,0} | ||
| 506 | } | ||
| 507 | else | ||
| 508 | { | ||
| 509 | HASH_THREAD and BT_TREAD must move position for (heads[0] - 2) bytes; | ||
| 510 | } | ||
| 511 | */ | ||
| 512 | |||
| 513 | if (num >= mf->numHashBytes) | ||
| 514 | { | ||
| 515 | num = num - mf->numHashBytes + 1; | ||
| 516 | if (num > kMtHashBlockSize - 2) | ||
| 517 | num = kMtHashBlockSize - 2; | ||
| 518 | |||
| 519 | if (mf->pos > (UInt32)kMtMaxValForNormalize - num) | ||
| 520 | { | ||
| 521 | const UInt32 subValue = (mf->pos - mf->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1); | ||
| 522 | Inline_MatchFinder_ReduceOffsets(mf, subValue); | ||
| 523 | MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1); | ||
| 524 | } | ||
| 525 | |||
| 526 | heads[0] = 2 + num; | ||
| 527 | mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); | ||
| 528 | } | ||
| 529 | |||
| 530 | mf->pos += num; // wrap over zero is allowed at the end of stream | ||
| 531 | mf->buffer += num; | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | Semaphore_Release1(&p->filledSemaphore); | ||
| 536 | } // for() processing end | ||
| 537 | |||
| 538 | // p->numBlocks_Sent = blockIndex; | ||
| 539 | Event_Set(&p->wasStopped); | ||
| 540 | } // for() thread end | ||
| 541 | } | ||
| 542 | |||
| 543 | |||
| 544 | |||
| 545 | |||
| 546 | // ---------- BT THREAD ---------- | ||
| 547 | |||
| 548 | /* we use one variable instead of two (cyclicBufferPos == pos) before CyclicBuf wrap. | ||
| 549 | here we define fixed offset of (p->pos) from (p->cyclicBufferPos) */ | ||
| 550 | #define CYC_TO_POS_OFFSET 0 | ||
| 551 | // #define CYC_TO_POS_OFFSET 1 // for debug | ||
| 552 | |||
| 553 | #define MFMT_GM_INLINE | ||
| 554 | |||
| 555 | #ifdef MFMT_GM_INLINE | ||
| 556 | |||
| 557 | /* | ||
| 558 | we use size_t for (pos) instead of UInt32 | ||
| 559 | to eliminate "movsx" BUG in old MSVC x64 compiler. | ||
| 560 | */ | ||
| 561 | |||
| 562 | |||
| 563 | UInt32 * MY_FAST_CALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, | ||
| 564 | UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, | ||
| 565 | size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, | ||
| 566 | UInt32 *posRes); | ||
| 567 | |||
| 568 | #endif | ||
| 569 | |||
| 570 | |||
| 571 | static void BtGetMatches(CMatchFinderMt *p, UInt32 *d) | ||
| 572 | { | ||
| 573 | UInt32 numProcessed = 0; | ||
| 574 | UInt32 curPos = 2; | ||
| 575 | |||
| 576 | /* GetMatchesSpec() functions don't create (len = 1) | ||
| 577 | in [len, dist] match pairs, if (p->numHashBytes >= 2) | ||
| 578 | Also we suppose here that (matchMaxLen >= 2). | ||
| 579 | So the following code for (reserve) is not required | ||
| 580 | UInt32 reserve = (p->matchMaxLen * 2); | ||
| 581 | const UInt32 kNumHashBytes_Max = 5; // BT_HASH_BYTES_MAX | ||
| 582 | if (reserve < kNumHashBytes_Max - 1) | ||
| 583 | reserve = kNumHashBytes_Max - 1; | ||
| 584 | const UInt32 limit = kMtBtBlockSize - (reserve); | ||
| 585 | */ | ||
| 586 | |||
| 587 | const UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); | ||
| 588 | |||
| 589 | d[1] = p->hashNumAvail; | ||
| 590 | |||
| 591 | if (p->failure_BT) | ||
| 592 | { | ||
| 593 | // printf("\n == 1 BtGetMatches() p->failure_BT\n"); | ||
| 594 | d[0] = 0; | ||
| 595 | // d[1] = 0; | ||
| 596 | return; | ||
| 597 | } | ||
| 598 | |||
| 599 | while (curPos < limit) | ||
| 600 | { | ||
| 601 | if (p->hashBufPos == p->hashBufPosLimit) | ||
| 602 | { | ||
| 603 | // MatchFinderMt_GetNextBlock_Hash(p); | ||
| 604 | UInt32 avail; | ||
| 605 | { | ||
| 606 | const UInt32 bi = MtSync_GetNextBlock(&p->hashSync); | ||
| 607 | const UInt32 k = GET_HASH_BLOCK_OFFSET(bi); | ||
| 608 | const UInt32 *h = p->hashBuf + k; | ||
| 609 | avail = h[1]; | ||
| 610 | p->hashBufPosLimit = k + h[0]; | ||
| 611 | p->hashNumAvail = avail; | ||
| 612 | p->hashBufPos = k + 2; | ||
| 613 | } | ||
| 614 | |||
| 615 | { | ||
| 616 | /* we must prevent UInt32 overflow for avail total value, | ||
| 617 | if avail was increased with new hash block */ | ||
| 618 | UInt32 availSum = numProcessed + avail; | ||
| 619 | if (availSum < numProcessed) | ||
| 620 | availSum = (UInt32)(Int32)-1; | ||
| 621 | d[1] = availSum; | ||
| 622 | } | ||
| 623 | |||
| 624 | if (avail >= p->numHashBytes) | ||
| 625 | continue; | ||
| 626 | |||
| 627 | // if (p->hashBufPos != p->hashBufPosLimit) exit(1); | ||
| 628 | |||
| 629 | /* (avail < p->numHashBytes) | ||
| 630 | It means that stream was finished. | ||
| 631 | And (avail) - is a number of remaining bytes, | ||
| 632 | we fill (d) for (avail) bytes for LZ_THREAD (receiver). | ||
| 633 | but we don't update (p->pos) and (p->cyclicBufferPos) here in BT_THREAD */ | ||
| 634 | |||
| 635 | /* here we suppose that we have space enough: | ||
| 636 | (kMtBtBlockSize - curPos >= p->hashNumAvail) */ | ||
| 637 | p->hashNumAvail = 0; | ||
| 638 | d[0] = curPos + avail; | ||
| 639 | d += curPos; | ||
| 640 | for (; avail != 0; avail--) | ||
| 641 | *d++ = 0; | ||
| 642 | return; | ||
| 643 | } | ||
| 644 | { | ||
| 645 | UInt32 size = p->hashBufPosLimit - p->hashBufPos; | ||
| 646 | UInt32 pos = p->pos; | ||
| 647 | UInt32 cyclicBufferPos = p->cyclicBufferPos; | ||
| 648 | UInt32 lenLimit = p->matchMaxLen; | ||
| 649 | if (lenLimit >= p->hashNumAvail) | ||
| 650 | lenLimit = p->hashNumAvail; | ||
| 651 | { | ||
| 652 | UInt32 size2 = p->hashNumAvail - lenLimit + 1; | ||
| 653 | if (size2 < size) | ||
| 654 | size = size2; | ||
| 655 | size2 = p->cyclicBufferSize - cyclicBufferPos; | ||
| 656 | if (size2 < size) | ||
| 657 | size = size2; | ||
| 658 | } | ||
| 659 | |||
| 660 | if (pos > (UInt32)kMtMaxValForNormalize - size) | ||
| 661 | { | ||
| 662 | const UInt32 subValue = (pos - p->cyclicBufferSize); // & ~(UInt32)(kNormalizeAlign - 1); | ||
| 663 | pos -= subValue; | ||
| 664 | p->pos = pos; | ||
| 665 | MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2); | ||
| 666 | } | ||
| 667 | |||
| 668 | #ifndef MFMT_GM_INLINE | ||
| 669 | while (curPos < limit && size-- != 0) | ||
| 670 | { | ||
| 671 | UInt32 *startDistances = d + curPos; | ||
| 672 | UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], | ||
| 673 | pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, | ||
| 674 | startDistances + 1, p->numHashBytes - 1) - startDistances); | ||
| 675 | *startDistances = num - 1; | ||
| 676 | curPos += num; | ||
| 677 | cyclicBufferPos++; | ||
| 678 | pos++; | ||
| 679 | p->buffer++; | ||
| 680 | } | ||
| 681 | #else | ||
| 682 | { | ||
| 683 | UInt32 posRes = pos; | ||
| 684 | const UInt32 *d_end; | ||
| 685 | { | ||
| 686 | d_end = GetMatchesSpecN_2( | ||
| 687 | p->buffer + lenLimit - 1, | ||
| 688 | pos, p->buffer, p->son, p->cutValue, d + curPos, | ||
| 689 | p->numHashBytes - 1, p->hashBuf + p->hashBufPos, | ||
| 690 | d + limit, p->hashBuf + p->hashBufPos + size, | ||
| 691 | cyclicBufferPos, p->cyclicBufferSize, | ||
| 692 | &posRes); | ||
| 693 | } | ||
| 694 | { | ||
| 695 | if (!d_end) | ||
| 696 | { | ||
| 697 | // printf("\n == 2 BtGetMatches() p->failure_BT\n"); | ||
| 698 | // internal data failure | ||
| 699 | p->failure_BT = True; | ||
| 700 | d[0] = 0; | ||
| 701 | // d[1] = 0; | ||
| 702 | return; | ||
| 703 | } | ||
| 704 | } | ||
| 705 | curPos = (UInt32)(d_end - d); | ||
| 706 | { | ||
| 707 | const UInt32 processed = posRes - pos; | ||
| 708 | pos = posRes; | ||
| 709 | p->hashBufPos += processed; | ||
| 710 | cyclicBufferPos += processed; | ||
| 711 | p->buffer += processed; | ||
| 712 | } | ||
| 713 | } | ||
| 714 | #endif | ||
| 715 | |||
| 716 | { | ||
| 717 | const UInt32 processed = pos - p->pos; | ||
| 718 | numProcessed += processed; | ||
| 719 | p->hashNumAvail -= processed; | ||
| 720 | p->pos = pos; | ||
| 721 | } | ||
| 722 | if (cyclicBufferPos == p->cyclicBufferSize) | ||
| 723 | cyclicBufferPos = 0; | ||
| 724 | p->cyclicBufferPos = cyclicBufferPos; | ||
| 725 | } | ||
| 726 | } | ||
| 727 | |||
| 728 | d[0] = curPos; | ||
| 729 | } | ||
| 730 | |||
| 731 | |||
| 732 | static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) | ||
| 733 | { | ||
| 734 | CMtSync *sync = &p->hashSync; | ||
| 735 | |||
| 736 | BUFFER_MUST_BE_UNLOCKED(sync) | ||
| 737 | |||
| 738 | if (!sync->needStart) | ||
| 739 | { | ||
| 740 | LOCK_BUFFER(sync) | ||
| 741 | } | ||
| 742 | |||
| 743 | BtGetMatches(p, p->btBuf + GET_BT_BLOCK_OFFSET(globalBlockIndex)); | ||
| 744 | |||
| 745 | /* We suppose that we have called GetNextBlock() from start. | ||
| 746 | So buffer is LOCKED */ | ||
| 747 | |||
| 748 | UNLOCK_BUFFER(sync) | ||
| 749 | } | ||
| 750 | |||
| 751 | |||
| 752 | MY_NO_INLINE | ||
| 753 | static void BtThreadFunc(CMatchFinderMt *mt) | ||
| 754 | { | ||
| 755 | CMtSync *p = &mt->btSync; | ||
| 756 | for (;;) | ||
| 757 | { | ||
| 758 | UInt32 blockIndex = 0; | ||
| 759 | Event_Wait(&p->canStart); | ||
| 760 | |||
| 761 | for (;;) | ||
| 762 | { | ||
| 763 | PRF(printf(" BT thread block = %d pos = %d\n", (unsigned)blockIndex, mt->pos)); | ||
| 764 | /* (p->exit == true) is possible after (p->canStart) at first loop iteration | ||
| 765 | and is unexpected after more Wait(freeSemaphore) iterations */ | ||
| 766 | if (p->exit) | ||
| 767 | return; | ||
| 768 | |||
| 769 | Semaphore_Wait(&p->freeSemaphore); | ||
| 770 | |||
| 771 | // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore) | ||
| 772 | if (p->stopWriting) | ||
| 773 | break; | ||
| 774 | |||
| 775 | BtFillBlock(mt, blockIndex++); | ||
| 776 | |||
| 777 | Semaphore_Release1(&p->filledSemaphore); | ||
| 778 | } | ||
| 779 | |||
| 780 | // we stop HASH_THREAD here | ||
| 781 | MtSync_StopWriting(&mt->hashSync); | ||
| 782 | |||
| 783 | // p->numBlocks_Sent = blockIndex; | ||
| 784 | Event_Set(&p->wasStopped); | ||
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | |||
| 789 | void MatchFinderMt_Construct(CMatchFinderMt *p) | ||
| 790 | { | ||
| 791 | p->hashBuf = NULL; | ||
| 792 | MtSync_Construct(&p->hashSync); | ||
| 793 | MtSync_Construct(&p->btSync); | ||
| 794 | } | ||
| 795 | |||
| 796 | static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAllocPtr alloc) | ||
| 797 | { | ||
| 798 | ISzAlloc_Free(alloc, p->hashBuf); | ||
| 799 | p->hashBuf = NULL; | ||
| 800 | } | ||
| 801 | |||
| 802 | void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc) | ||
| 803 | { | ||
| 804 | /* | ||
| 805 | HASH_THREAD can use CriticalSection(s) btSync.cs and hashSync.cs. | ||
| 806 | So we must be sure that HASH_THREAD will not use CriticalSection(s) | ||
| 807 | after deleting CriticalSection here. | ||
| 808 | |||
| 809 | we call ReleaseStream(p) | ||
| 810 | that calls StopWriting(btSync) | ||
| 811 | that calls StopWriting(hashSync), if it's required to stop HASH_THREAD. | ||
| 812 | after StopWriting() it's safe to destruct MtSync(s) in any order */ | ||
| 813 | |||
| 814 | MatchFinderMt_ReleaseStream(p); | ||
| 815 | |||
| 816 | MtSync_Destruct(&p->btSync); | ||
| 817 | MtSync_Destruct(&p->hashSync); | ||
| 818 | |||
| 819 | LOG_ITER( | ||
| 820 | printf("\nTree %9d * %7d iter = %9d = sum : bytes = %9d\n", | ||
| 821 | (UInt32)(g_NumIters_Tree / 1000), | ||
| 822 | (UInt32)(((UInt64)g_NumIters_Loop * 1000) / (g_NumIters_Tree + 1)), | ||
| 823 | (UInt32)(g_NumIters_Loop / 1000), | ||
| 824 | (UInt32)(g_NumIters_Bytes / 1000) | ||
| 825 | )); | ||
| 826 | |||
| 827 | MatchFinderMt_FreeMem(p, alloc); | ||
| 828 | } | ||
| 829 | |||
| 830 | |||
| 831 | #define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) | ||
| 832 | #define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) | ||
| 833 | |||
| 834 | |||
| 835 | static THREAD_FUNC_DECL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } | ||
| 836 | static THREAD_FUNC_DECL BtThreadFunc2(void *p) | ||
| 837 | { | ||
| 838 | Byte allocaDummy[0x180]; | ||
| 839 | unsigned i = 0; | ||
| 840 | for (i = 0; i < 16; i++) | ||
| 841 | allocaDummy[i] = (Byte)0; | ||
| 842 | if (allocaDummy[0] == 0) | ||
| 843 | BtThreadFunc((CMatchFinderMt *)p); | ||
| 844 | return 0; | ||
| 845 | } | ||
| 846 | |||
| 847 | |||
| 848 | SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, | ||
| 849 | UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc) | ||
| 850 | { | ||
| 851 | CMatchFinder *mf = MF(p); | ||
| 852 | p->historySize = historySize; | ||
| 853 | if (kMtBtBlockSize <= matchMaxLen * 4) | ||
| 854 | return SZ_ERROR_PARAM; | ||
| 855 | if (!p->hashBuf) | ||
| 856 | { | ||
| 857 | p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, ((size_t)kHashBufferSize + (size_t)kBtBufferSize) * sizeof(UInt32)); | ||
| 858 | if (!p->hashBuf) | ||
| 859 | return SZ_ERROR_MEM; | ||
| 860 | p->btBuf = p->hashBuf + kHashBufferSize; | ||
| 861 | } | ||
| 862 | keepAddBufferBefore += (kHashBufferSize + kBtBufferSize); | ||
| 863 | keepAddBufferAfter += kMtHashBlockSize; | ||
| 864 | if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc)) | ||
| 865 | return SZ_ERROR_MEM; | ||
| 866 | |||
| 867 | RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p)); | ||
| 868 | RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p)); | ||
| 869 | return SZ_OK; | ||
| 870 | } | ||
| 871 | |||
| 872 | |||
| 873 | SRes MatchFinderMt_InitMt(CMatchFinderMt *p) | ||
| 874 | { | ||
| 875 | RINOK(MtSync_Init(&p->hashSync, kMtHashNumBlocks)); | ||
| 876 | return MtSync_Init(&p->btSync, kMtBtNumBlocks); | ||
| 877 | } | ||
| 878 | |||
| 879 | |||
| 880 | static void MatchFinderMt_Init(CMatchFinderMt *p) | ||
| 881 | { | ||
| 882 | CMatchFinder *mf = MF(p); | ||
| 883 | |||
| 884 | p->btBufPos = | ||
| 885 | p->btBufPosLimit = NULL; | ||
| 886 | p->hashBufPos = | ||
| 887 | p->hashBufPosLimit = 0; | ||
| 888 | p->hashNumAvail = 0; // 21.03 | ||
| 889 | |||
| 890 | p->failure_BT = False; | ||
| 891 | |||
| 892 | /* Init without data reading. We don't want to read data in this thread */ | ||
| 893 | MatchFinder_Init_4(mf); | ||
| 894 | |||
| 895 | MatchFinder_Init_LowHash(mf); | ||
| 896 | |||
| 897 | p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf); | ||
| 898 | p->btNumAvailBytes = 0; | ||
| 899 | p->failure_LZ_BT = False; | ||
| 900 | // p->failure_LZ_LZ = False; | ||
| 901 | |||
| 902 | p->lzPos = | ||
| 903 | 1; // optimal smallest value | ||
| 904 | // 0; // for debug: ignores match to start | ||
| 905 | // kNormalizeAlign; // for debug | ||
| 906 | |||
| 907 | p->hash = mf->hash; | ||
| 908 | p->fixedHashSize = mf->fixedHashSize; | ||
| 909 | // p->hash4Mask = mf->hash4Mask; | ||
| 910 | p->crc = mf->crc; | ||
| 911 | // memcpy(p->crc, mf->crc, sizeof(mf->crc)); | ||
| 912 | |||
| 913 | p->son = mf->son; | ||
| 914 | p->matchMaxLen = mf->matchMaxLen; | ||
| 915 | p->numHashBytes = mf->numHashBytes; | ||
| 916 | |||
| 917 | /* (mf->pos) and (mf->streamPos) were already initialized to 1 in MatchFinder_Init_4() */ | ||
| 918 | // mf->streamPos = mf->pos = 1; // optimal smallest value | ||
| 919 | // 0; // for debug: ignores match to start | ||
| 920 | // kNormalizeAlign; // for debug | ||
| 921 | |||
| 922 | /* we must init (p->pos = mf->pos) for BT, because | ||
| 923 | BT code needs (p->pos == delta_value_for_empty_hash_record == mf->pos) */ | ||
| 924 | p->pos = mf->pos; // do not change it | ||
| 925 | |||
| 926 | p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET); | ||
| 927 | p->cyclicBufferSize = mf->cyclicBufferSize; | ||
| 928 | p->buffer = mf->buffer; | ||
| 929 | p->cutValue = mf->cutValue; | ||
| 930 | // p->son[0] = p->son[1] = 0; // unused: to init skipped record for speculated accesses. | ||
| 931 | } | ||
| 932 | |||
| 933 | |||
| 934 | /* ReleaseStream is required to finish multithreading */ | ||
| 935 | void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) | ||
| 936 | { | ||
| 937 | // Sleep(1); // for debug | ||
| 938 | MtSync_StopWriting(&p->btSync); | ||
| 939 | // Sleep(200); // for debug | ||
| 940 | /* p->MatchFinder->ReleaseStream(); */ | ||
| 941 | } | ||
| 942 | |||
| 943 | |||
| 944 | MY_NO_INLINE | ||
| 945 | static UInt32 MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) | ||
| 946 | { | ||
| 947 | if (p->failure_LZ_BT) | ||
| 948 | p->btBufPos = p->failureBuf; | ||
| 949 | else | ||
| 950 | { | ||
| 951 | const UInt32 bi = MtSync_GetNextBlock(&p->btSync); | ||
| 952 | const UInt32 *bt = p->btBuf + GET_BT_BLOCK_OFFSET(bi); | ||
| 953 | { | ||
| 954 | const UInt32 numItems = bt[0]; | ||
| 955 | p->btBufPosLimit = bt + numItems; | ||
| 956 | p->btNumAvailBytes = bt[1]; | ||
| 957 | p->btBufPos = bt + 2; | ||
| 958 | if (numItems < 2 || numItems > kMtBtBlockSize) | ||
| 959 | { | ||
| 960 | p->failureBuf[0] = 0; | ||
| 961 | p->btBufPos = p->failureBuf; | ||
| 962 | p->btBufPosLimit = p->failureBuf + 1; | ||
| 963 | p->failure_LZ_BT = True; | ||
| 964 | // p->btNumAvailBytes = 0; | ||
| 965 | /* we don't want to decrease AvailBytes, that was load before. | ||
| 966 | that can be unxepected for the code that have loaded anopther value before */ | ||
| 967 | } | ||
| 968 | } | ||
| 969 | |||
| 970 | if (p->lzPos >= (UInt32)kMtMaxValForNormalize - (UInt32)kMtBtBlockSize) | ||
| 971 | { | ||
| 972 | /* we don't check (lzPos) over exact avail bytes in (btBuf). | ||
| 973 | (fixedHashSize) is small, so normalization is fast */ | ||
| 974 | const UInt32 subValue = (p->lzPos - p->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1); | ||
| 975 | p->lzPos -= subValue; | ||
| 976 | MatchFinder_Normalize3(subValue, p->hash, p->fixedHashSize); | ||
| 977 | } | ||
| 978 | } | ||
| 979 | return p->btNumAvailBytes; | ||
| 980 | } | ||
| 981 | |||
| 982 | |||
| 983 | |||
| 984 | static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) | ||
| 985 | { | ||
| 986 | return p->pointerToCurPos; | ||
| 987 | } | ||
| 988 | |||
| 989 | |||
| 990 | #define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); | ||
| 991 | |||
| 992 | |||
| 993 | static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) | ||
| 994 | { | ||
| 995 | if (p->btBufPos != p->btBufPosLimit) | ||
| 996 | return p->btNumAvailBytes; | ||
| 997 | return MatchFinderMt_GetNextBlock_Bt(p); | ||
| 998 | } | ||
| 999 | |||
| 1000 | |||
| 1001 | // #define CHECK_FAILURE_LZ(_match_, _pos_) if (_match_ >= _pos_) { p->failure_LZ_LZ = True; return d; } | ||
| 1002 | #define CHECK_FAILURE_LZ(_match_, _pos_) | ||
| 1003 | |||
| 1004 | static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) | ||
| 1005 | { | ||
| 1006 | UInt32 h2, c2; | ||
| 1007 | UInt32 *hash = p->hash; | ||
| 1008 | const Byte *cur = p->pointerToCurPos; | ||
| 1009 | const UInt32 m = p->lzPos; | ||
| 1010 | MT_HASH2_CALC | ||
| 1011 | |||
| 1012 | c2 = hash[h2]; | ||
| 1013 | hash[h2] = m; | ||
| 1014 | |||
| 1015 | if (c2 >= matchMinPos) | ||
| 1016 | { | ||
| 1017 | CHECK_FAILURE_LZ(c2, m) | ||
| 1018 | if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) | ||
| 1019 | { | ||
| 1020 | *d++ = 2; | ||
| 1021 | *d++ = m - c2 - 1; | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | return d; | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) | ||
| 1029 | { | ||
| 1030 | UInt32 h2, h3, c2, c3; | ||
| 1031 | UInt32 *hash = p->hash; | ||
| 1032 | const Byte *cur = p->pointerToCurPos; | ||
| 1033 | const UInt32 m = p->lzPos; | ||
| 1034 | MT_HASH3_CALC | ||
| 1035 | |||
| 1036 | c2 = hash[h2]; | ||
| 1037 | c3 = (hash + kFix3HashSize)[h3]; | ||
| 1038 | |||
| 1039 | hash[h2] = m; | ||
| 1040 | (hash + kFix3HashSize)[h3] = m; | ||
| 1041 | |||
| 1042 | if (c2 >= matchMinPos) | ||
| 1043 | { | ||
| 1044 | CHECK_FAILURE_LZ(c2, m) | ||
| 1045 | if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) | ||
| 1046 | { | ||
| 1047 | d[1] = m - c2 - 1; | ||
| 1048 | if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) | ||
| 1049 | { | ||
| 1050 | d[0] = 3; | ||
| 1051 | return d + 2; | ||
| 1052 | } | ||
| 1053 | d[0] = 2; | ||
| 1054 | d += 2; | ||
| 1055 | } | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | if (c3 >= matchMinPos) | ||
| 1059 | { | ||
| 1060 | CHECK_FAILURE_LZ(c3, m) | ||
| 1061 | if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) | ||
| 1062 | { | ||
| 1063 | *d++ = 3; | ||
| 1064 | *d++ = m - c3 - 1; | ||
| 1065 | } | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | return d; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | |||
| 1072 | #define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; | ||
| 1073 | |||
| 1074 | /* | ||
| 1075 | static | ||
| 1076 | UInt32* MatchFinderMt_GetMatches_Bt4(CMatchFinderMt *p, UInt32 *d) | ||
| 1077 | { | ||
| 1078 | const UInt32 *bt = p->btBufPos; | ||
| 1079 | const UInt32 len = *bt++; | ||
| 1080 | const UInt32 *btLim = bt + len; | ||
| 1081 | UInt32 matchMinPos; | ||
| 1082 | UInt32 avail = p->btNumAvailBytes - 1; | ||
| 1083 | p->btBufPos = btLim; | ||
| 1084 | |||
| 1085 | { | ||
| 1086 | p->btNumAvailBytes = avail; | ||
| 1087 | |||
| 1088 | #define BT_HASH_BYTES_MAX 5 | ||
| 1089 | |||
| 1090 | matchMinPos = p->lzPos; | ||
| 1091 | |||
| 1092 | if (len != 0) | ||
| 1093 | matchMinPos -= bt[1]; | ||
| 1094 | else if (avail < (BT_HASH_BYTES_MAX - 1) - 1) | ||
| 1095 | { | ||
| 1096 | INCREASE_LZ_POS | ||
| 1097 | return d; | ||
| 1098 | } | ||
| 1099 | else | ||
| 1100 | { | ||
| 1101 | const UInt32 hs = p->historySize; | ||
| 1102 | if (matchMinPos > hs) | ||
| 1103 | matchMinPos -= hs; | ||
| 1104 | else | ||
| 1105 | matchMinPos = 1; | ||
| 1106 | } | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | for (;;) | ||
| 1110 | { | ||
| 1111 | |||
| 1112 | UInt32 h2, h3, c2, c3; | ||
| 1113 | UInt32 *hash = p->hash; | ||
| 1114 | const Byte *cur = p->pointerToCurPos; | ||
| 1115 | UInt32 m = p->lzPos; | ||
| 1116 | MT_HASH3_CALC | ||
| 1117 | |||
| 1118 | c2 = hash[h2]; | ||
| 1119 | c3 = (hash + kFix3HashSize)[h3]; | ||
| 1120 | |||
| 1121 | hash[h2] = m; | ||
| 1122 | (hash + kFix3HashSize)[h3] = m; | ||
| 1123 | |||
| 1124 | if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) | ||
| 1125 | { | ||
| 1126 | d[1] = m - c2 - 1; | ||
| 1127 | if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) | ||
| 1128 | { | ||
| 1129 | d[0] = 3; | ||
| 1130 | d += 2; | ||
| 1131 | break; | ||
| 1132 | } | ||
| 1133 | // else | ||
| 1134 | { | ||
| 1135 | d[0] = 2; | ||
| 1136 | d += 2; | ||
| 1137 | } | ||
| 1138 | } | ||
| 1139 | if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) | ||
| 1140 | { | ||
| 1141 | *d++ = 3; | ||
| 1142 | *d++ = m - c3 - 1; | ||
| 1143 | } | ||
| 1144 | break; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | if (len != 0) | ||
| 1148 | { | ||
| 1149 | do | ||
| 1150 | { | ||
| 1151 | const UInt32 v0 = bt[0]; | ||
| 1152 | const UInt32 v1 = bt[1]; | ||
| 1153 | bt += 2; | ||
| 1154 | d[0] = v0; | ||
| 1155 | d[1] = v1; | ||
| 1156 | d += 2; | ||
| 1157 | } | ||
| 1158 | while (bt != btLim); | ||
| 1159 | } | ||
| 1160 | INCREASE_LZ_POS | ||
| 1161 | return d; | ||
| 1162 | } | ||
| 1163 | */ | ||
| 1164 | |||
| 1165 | |||
| 1166 | static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) | ||
| 1167 | { | ||
| 1168 | UInt32 h2, h3, /* h4, */ c2, c3 /* , c4 */; | ||
| 1169 | UInt32 *hash = p->hash; | ||
| 1170 | const Byte *cur = p->pointerToCurPos; | ||
| 1171 | const UInt32 m = p->lzPos; | ||
| 1172 | MT_HASH3_CALC | ||
| 1173 | // MT_HASH4_CALC | ||
| 1174 | c2 = hash[h2]; | ||
| 1175 | c3 = (hash + kFix3HashSize)[h3]; | ||
| 1176 | // c4 = (hash + kFix4HashSize)[h4]; | ||
| 1177 | |||
| 1178 | hash[h2] = m; | ||
| 1179 | (hash + kFix3HashSize)[h3] = m; | ||
| 1180 | // (hash + kFix4HashSize)[h4] = m; | ||
| 1181 | |||
| 1182 | #define _USE_H2 | ||
| 1183 | |||
| 1184 | #ifdef _USE_H2 | ||
| 1185 | if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) | ||
| 1186 | { | ||
| 1187 | d[1] = m - c2 - 1; | ||
| 1188 | if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) | ||
| 1189 | { | ||
| 1190 | // d[0] = (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3]) ? 4 : 3; | ||
| 1191 | // return d + 2; | ||
| 1192 | |||
| 1193 | if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3]) | ||
| 1194 | { | ||
| 1195 | d[0] = 4; | ||
| 1196 | return d + 2; | ||
| 1197 | } | ||
| 1198 | d[0] = 3; | ||
| 1199 | d += 2; | ||
| 1200 | |||
| 1201 | #ifdef _USE_H4 | ||
| 1202 | if (c4 >= matchMinPos) | ||
| 1203 | if ( | ||
| 1204 | cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] && | ||
| 1205 | cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3] | ||
| 1206 | ) | ||
| 1207 | { | ||
| 1208 | *d++ = 4; | ||
| 1209 | *d++ = m - c4 - 1; | ||
| 1210 | } | ||
| 1211 | #endif | ||
| 1212 | return d; | ||
| 1213 | } | ||
| 1214 | d[0] = 2; | ||
| 1215 | d += 2; | ||
| 1216 | } | ||
| 1217 | #endif | ||
| 1218 | |||
| 1219 | if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) | ||
| 1220 | { | ||
| 1221 | d[1] = m - c3 - 1; | ||
| 1222 | if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m + 3] == cur[3]) | ||
| 1223 | { | ||
| 1224 | d[0] = 4; | ||
| 1225 | return d + 2; | ||
| 1226 | } | ||
| 1227 | d[0] = 3; | ||
| 1228 | d += 2; | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | #ifdef _USE_H4 | ||
| 1232 | if (c4 >= matchMinPos) | ||
| 1233 | if ( | ||
| 1234 | cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] && | ||
| 1235 | cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3] | ||
| 1236 | ) | ||
| 1237 | { | ||
| 1238 | *d++ = 4; | ||
| 1239 | *d++ = m - c4 - 1; | ||
| 1240 | } | ||
| 1241 | #endif | ||
| 1242 | |||
| 1243 | return d; | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | |||
| 1247 | static UInt32* MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *d) | ||
| 1248 | { | ||
| 1249 | const UInt32 *bt = p->btBufPos; | ||
| 1250 | const UInt32 len = *bt++; | ||
| 1251 | const UInt32 *btLim = bt + len; | ||
| 1252 | p->btBufPos = btLim; | ||
| 1253 | p->btNumAvailBytes--; | ||
| 1254 | INCREASE_LZ_POS | ||
| 1255 | { | ||
| 1256 | while (bt != btLim) | ||
| 1257 | { | ||
| 1258 | const UInt32 v0 = bt[0]; | ||
| 1259 | const UInt32 v1 = bt[1]; | ||
| 1260 | bt += 2; | ||
| 1261 | d[0] = v0; | ||
| 1262 | d[1] = v1; | ||
| 1263 | d += 2; | ||
| 1264 | } | ||
| 1265 | } | ||
| 1266 | return d; | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | |||
| 1270 | |||
| 1271 | static UInt32* MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *d) | ||
| 1272 | { | ||
| 1273 | const UInt32 *bt = p->btBufPos; | ||
| 1274 | UInt32 len = *bt++; | ||
| 1275 | const UInt32 avail = p->btNumAvailBytes - 1; | ||
| 1276 | p->btNumAvailBytes = avail; | ||
| 1277 | p->btBufPos = bt + len; | ||
| 1278 | if (len == 0) | ||
| 1279 | { | ||
| 1280 | #define BT_HASH_BYTES_MAX 5 | ||
| 1281 | if (avail >= (BT_HASH_BYTES_MAX - 1) - 1) | ||
| 1282 | { | ||
| 1283 | UInt32 m = p->lzPos; | ||
| 1284 | if (m > p->historySize) | ||
| 1285 | m -= p->historySize; | ||
| 1286 | else | ||
| 1287 | m = 1; | ||
| 1288 | d = p->MixMatchesFunc(p, m, d); | ||
| 1289 | } | ||
| 1290 | } | ||
| 1291 | else | ||
| 1292 | { | ||
| 1293 | /* | ||
| 1294 | first match pair from BinTree: (match_len, match_dist), | ||
| 1295 | (match_len >= numHashBytes). | ||
| 1296 | MixMatchesFunc() inserts only hash matches that are nearer than (match_dist) | ||
| 1297 | */ | ||
| 1298 | d = p->MixMatchesFunc(p, p->lzPos - bt[1], d); | ||
| 1299 | // if (d) // check for failure | ||
| 1300 | do | ||
| 1301 | { | ||
| 1302 | const UInt32 v0 = bt[0]; | ||
| 1303 | const UInt32 v1 = bt[1]; | ||
| 1304 | bt += 2; | ||
| 1305 | d[0] = v0; | ||
| 1306 | d[1] = v1; | ||
| 1307 | d += 2; | ||
| 1308 | } | ||
| 1309 | while (len -= 2); | ||
| 1310 | } | ||
| 1311 | INCREASE_LZ_POS | ||
| 1312 | return d; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | #define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED | ||
| 1316 | #define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; | ||
| 1317 | #define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += (size_t)*p->btBufPos + 1; } while (--num != 0); | ||
| 1318 | |||
| 1319 | static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) | ||
| 1320 | { | ||
| 1321 | SKIP_HEADER2_MT { p->btNumAvailBytes--; | ||
| 1322 | SKIP_FOOTER_MT | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) | ||
| 1326 | { | ||
| 1327 | SKIP_HEADER_MT(2) | ||
| 1328 | UInt32 h2; | ||
| 1329 | MT_HASH2_CALC | ||
| 1330 | hash[h2] = p->lzPos; | ||
| 1331 | SKIP_FOOTER_MT | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) | ||
| 1335 | { | ||
| 1336 | SKIP_HEADER_MT(3) | ||
| 1337 | UInt32 h2, h3; | ||
| 1338 | MT_HASH3_CALC | ||
| 1339 | (hash + kFix3HashSize)[h3] = | ||
| 1340 | hash[ h2] = | ||
| 1341 | p->lzPos; | ||
| 1342 | SKIP_FOOTER_MT | ||
| 1343 | } | ||
| 1344 | |||
| 1345 | /* | ||
| 1346 | // MatchFinderMt4_Skip() is similar to MatchFinderMt3_Skip(). | ||
| 1347 | // The difference is that MatchFinderMt3_Skip() updates hash for last 3 bytes of stream. | ||
| 1348 | |||
| 1349 | static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) | ||
| 1350 | { | ||
| 1351 | SKIP_HEADER_MT(4) | ||
| 1352 | UInt32 h2, h3; // h4 | ||
| 1353 | MT_HASH3_CALC | ||
| 1354 | // MT_HASH4_CALC | ||
| 1355 | // (hash + kFix4HashSize)[h4] = | ||
| 1356 | (hash + kFix3HashSize)[h3] = | ||
| 1357 | hash[ h2] = | ||
| 1358 | p->lzPos; | ||
| 1359 | SKIP_FOOTER_MT | ||
| 1360 | } | ||
| 1361 | */ | ||
| 1362 | |||
| 1363 | void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable) | ||
| 1364 | { | ||
| 1365 | vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; | ||
| 1366 | vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; | ||
| 1367 | vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; | ||
| 1368 | vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; | ||
| 1369 | |||
| 1370 | switch (MF(p)->numHashBytes) | ||
| 1371 | { | ||
| 1372 | case 2: | ||
| 1373 | p->GetHeadsFunc = GetHeads2; | ||
| 1374 | p->MixMatchesFunc = (Mf_Mix_Matches)NULL; | ||
| 1375 | vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip; | ||
| 1376 | vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches; | ||
| 1377 | break; | ||
| 1378 | case 3: | ||
| 1379 | p->GetHeadsFunc = MF(p)->bigHash ? GetHeads3b : GetHeads3; | ||
| 1380 | p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2; | ||
| 1381 | vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip; | ||
| 1382 | break; | ||
| 1383 | case 4: | ||
| 1384 | p->GetHeadsFunc = MF(p)->bigHash ? GetHeads4b : GetHeads4; | ||
| 1385 | |||
| 1386 | // it's fast inline version of GetMatches() | ||
| 1387 | // vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches_Bt4; | ||
| 1388 | |||
| 1389 | p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; | ||
| 1390 | vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; | ||
| 1391 | break; | ||
| 1392 | default: | ||
| 1393 | p->GetHeadsFunc = MF(p)->bigHash ? GetHeads5b : GetHeads5; | ||
| 1394 | p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4; | ||
| 1395 | vTable->Skip = | ||
| 1396 | (Mf_Skip_Func)MatchFinderMt3_Skip; | ||
| 1397 | // (Mf_Skip_Func)MatchFinderMt4_Skip; | ||
| 1398 | break; | ||
| 1399 | } | ||
| 1400 | } | ||
diff --git a/C/LzFindMt.h b/C/LzFindMt.h new file mode 100644 index 0000000..660b724 --- /dev/null +++ b/C/LzFindMt.h | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | /* LzFindMt.h -- multithreaded Match finder for LZ algorithms | ||
| 2 | 2021-07-12 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __LZ_FIND_MT_H | ||
| 5 | #define __LZ_FIND_MT_H | ||
| 6 | |||
| 7 | #include "LzFind.h" | ||
| 8 | #include "Threads.h" | ||
| 9 | |||
| 10 | EXTERN_C_BEGIN | ||
| 11 | |||
| 12 | typedef struct _CMtSync | ||
| 13 | { | ||
| 14 | UInt32 numProcessedBlocks; | ||
| 15 | CThread thread; | ||
| 16 | UInt64 affinity; | ||
| 17 | |||
| 18 | BoolInt wasCreated; | ||
| 19 | BoolInt needStart; | ||
| 20 | BoolInt csWasInitialized; | ||
| 21 | BoolInt csWasEntered; | ||
| 22 | |||
| 23 | BoolInt exit; | ||
| 24 | BoolInt stopWriting; | ||
| 25 | |||
| 26 | CAutoResetEvent canStart; | ||
| 27 | CAutoResetEvent wasStopped; | ||
| 28 | CSemaphore freeSemaphore; | ||
| 29 | CSemaphore filledSemaphore; | ||
| 30 | CCriticalSection cs; | ||
| 31 | // UInt32 numBlocks_Sent; | ||
| 32 | } CMtSync; | ||
| 33 | |||
| 34 | typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances); | ||
| 35 | |||
| 36 | /* kMtCacheLineDummy must be >= size_of_CPU_cache_line */ | ||
| 37 | #define kMtCacheLineDummy 128 | ||
| 38 | |||
| 39 | typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos, | ||
| 40 | UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc); | ||
| 41 | |||
| 42 | typedef struct _CMatchFinderMt | ||
| 43 | { | ||
| 44 | /* LZ */ | ||
| 45 | const Byte *pointerToCurPos; | ||
| 46 | UInt32 *btBuf; | ||
| 47 | const UInt32 *btBufPos; | ||
| 48 | const UInt32 *btBufPosLimit; | ||
| 49 | UInt32 lzPos; | ||
| 50 | UInt32 btNumAvailBytes; | ||
| 51 | |||
| 52 | UInt32 *hash; | ||
| 53 | UInt32 fixedHashSize; | ||
| 54 | // UInt32 hash4Mask; | ||
| 55 | UInt32 historySize; | ||
| 56 | const UInt32 *crc; | ||
| 57 | |||
| 58 | Mf_Mix_Matches MixMatchesFunc; | ||
| 59 | UInt32 failure_LZ_BT; // failure in BT transfered to LZ | ||
| 60 | // UInt32 failure_LZ_LZ; // failure in LZ tables | ||
| 61 | UInt32 failureBuf[1]; | ||
| 62 | // UInt32 crc[256]; | ||
| 63 | |||
| 64 | /* LZ + BT */ | ||
| 65 | CMtSync btSync; | ||
| 66 | Byte btDummy[kMtCacheLineDummy]; | ||
| 67 | |||
| 68 | /* BT */ | ||
| 69 | UInt32 *hashBuf; | ||
| 70 | UInt32 hashBufPos; | ||
| 71 | UInt32 hashBufPosLimit; | ||
| 72 | UInt32 hashNumAvail; | ||
| 73 | UInt32 failure_BT; | ||
| 74 | |||
| 75 | |||
| 76 | CLzRef *son; | ||
| 77 | UInt32 matchMaxLen; | ||
| 78 | UInt32 numHashBytes; | ||
| 79 | UInt32 pos; | ||
| 80 | const Byte *buffer; | ||
| 81 | UInt32 cyclicBufferPos; | ||
| 82 | UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ | ||
| 83 | UInt32 cutValue; | ||
| 84 | |||
| 85 | /* BT + Hash */ | ||
| 86 | CMtSync hashSync; | ||
| 87 | /* Byte hashDummy[kMtCacheLineDummy]; */ | ||
| 88 | |||
| 89 | /* Hash */ | ||
| 90 | Mf_GetHeads GetHeadsFunc; | ||
| 91 | CMatchFinder *MatchFinder; | ||
| 92 | // CMatchFinder MatchFinder; | ||
| 93 | } CMatchFinderMt; | ||
| 94 | |||
| 95 | // only for Mt part | ||
| 96 | void MatchFinderMt_Construct(CMatchFinderMt *p); | ||
| 97 | void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc); | ||
| 98 | |||
| 99 | SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, | ||
| 100 | UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc); | ||
| 101 | void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable); | ||
| 102 | |||
| 103 | /* call MatchFinderMt_InitMt() before IMatchFinder::Init() */ | ||
| 104 | SRes MatchFinderMt_InitMt(CMatchFinderMt *p); | ||
| 105 | void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); | ||
| 106 | |||
| 107 | EXTERN_C_END | ||
| 108 | |||
| 109 | #endif | ||
diff --git a/C/LzFindOpt.c b/C/LzFindOpt.c new file mode 100644 index 0000000..8ff006e --- /dev/null +++ b/C/LzFindOpt.c | |||
| @@ -0,0 +1,578 @@ | |||
| 1 | /* LzFindOpt.c -- multithreaded Match finder for LZ algorithms | ||
| 2 | 2021-07-13 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "CpuArch.h" | ||
| 7 | #include "LzFind.h" | ||
| 8 | |||
| 9 | // #include "LzFindMt.h" | ||
| 10 | |||
| 11 | // #define LOG_ITERS | ||
| 12 | |||
| 13 | // #define LOG_THREAD | ||
| 14 | |||
| 15 | #ifdef LOG_THREAD | ||
| 16 | #include <stdio.h> | ||
| 17 | #define PRF(x) x | ||
| 18 | #else | ||
| 19 | // #define PRF(x) | ||
| 20 | #endif | ||
| 21 | |||
| 22 | #ifdef LOG_ITERS | ||
| 23 | #include <stdio.h> | ||
| 24 | UInt64 g_NumIters_Tree; | ||
| 25 | UInt64 g_NumIters_Loop; | ||
| 26 | UInt64 g_NumIters_Bytes; | ||
| 27 | #define LOG_ITER(x) x | ||
| 28 | #else | ||
| 29 | #define LOG_ITER(x) | ||
| 30 | #endif | ||
| 31 | |||
| 32 | // ---------- BT THREAD ---------- | ||
| 33 | |||
| 34 | #define USE_SON_PREFETCH | ||
| 35 | #define USE_LONG_MATCH_OPT | ||
| 36 | |||
| 37 | #define kEmptyHashValue 0 | ||
| 38 | |||
| 39 | // #define CYC_TO_POS_OFFSET 0 | ||
| 40 | |||
| 41 | // #define CYC_TO_POS_OFFSET 1 // for debug | ||
| 42 | |||
| 43 | /* | ||
| 44 | MY_NO_INLINE | ||
| 45 | UInt32 * MY_FAST_CALL GetMatchesSpecN_1(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, | ||
| 46 | UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, UInt32 *posRes) | ||
| 47 | { | ||
| 48 | do | ||
| 49 | { | ||
| 50 | UInt32 delta; | ||
| 51 | if (hash == size) | ||
| 52 | break; | ||
| 53 | delta = *hash++; | ||
| 54 | |||
| 55 | if (delta == 0 || delta > (UInt32)pos) | ||
| 56 | return NULL; | ||
| 57 | |||
| 58 | lenLimit++; | ||
| 59 | |||
| 60 | if (delta == (UInt32)pos) | ||
| 61 | { | ||
| 62 | CLzRef *ptr1 = son + ((size_t)pos << 1) - CYC_TO_POS_OFFSET * 2; | ||
| 63 | *d++ = 0; | ||
| 64 | ptr1[0] = kEmptyHashValue; | ||
| 65 | ptr1[1] = kEmptyHashValue; | ||
| 66 | } | ||
| 67 | else | ||
| 68 | { | ||
| 69 | UInt32 *_distances = ++d; | ||
| 70 | |||
| 71 | CLzRef *ptr0 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2 + 1; | ||
| 72 | CLzRef *ptr1 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; | ||
| 73 | |||
| 74 | const Byte *len0 = cur, *len1 = cur; | ||
| 75 | UInt32 cutValue = _cutValue; | ||
| 76 | const Byte *maxLen = cur + _maxLen; | ||
| 77 | |||
| 78 | for (LOG_ITER(g_NumIters_Tree++);;) | ||
| 79 | { | ||
| 80 | LOG_ITER(g_NumIters_Loop++); | ||
| 81 | { | ||
| 82 | const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; | ||
| 83 | CLzRef *pair = son + ((size_t)(((ptrdiff_t)pos - CYC_TO_POS_OFFSET) + diff) << 1); | ||
| 84 | const Byte *len = (len0 < len1 ? len0 : len1); | ||
| 85 | |||
| 86 | #ifdef USE_SON_PREFETCH | ||
| 87 | const UInt32 pair0 = *pair; | ||
| 88 | #endif | ||
| 89 | |||
| 90 | if (len[diff] == len[0]) | ||
| 91 | { | ||
| 92 | if (++len != lenLimit && len[diff] == len[0]) | ||
| 93 | while (++len != lenLimit) | ||
| 94 | { | ||
| 95 | LOG_ITER(g_NumIters_Bytes++); | ||
| 96 | if (len[diff] != len[0]) | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | if (maxLen < len) | ||
| 100 | { | ||
| 101 | maxLen = len; | ||
| 102 | *d++ = (UInt32)(len - cur); | ||
| 103 | *d++ = delta - 1; | ||
| 104 | |||
| 105 | if (len == lenLimit) | ||
| 106 | { | ||
| 107 | const UInt32 pair1 = pair[1]; | ||
| 108 | *ptr1 = | ||
| 109 | #ifdef USE_SON_PREFETCH | ||
| 110 | pair0; | ||
| 111 | #else | ||
| 112 | pair[0]; | ||
| 113 | #endif | ||
| 114 | *ptr0 = pair1; | ||
| 115 | |||
| 116 | _distances[-1] = (UInt32)(d - _distances); | ||
| 117 | |||
| 118 | #ifdef USE_LONG_MATCH_OPT | ||
| 119 | |||
| 120 | if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) | ||
| 121 | break; | ||
| 122 | |||
| 123 | { | ||
| 124 | for (;;) | ||
| 125 | { | ||
| 126 | hash++; | ||
| 127 | pos++; | ||
| 128 | cur++; | ||
| 129 | lenLimit++; | ||
| 130 | { | ||
| 131 | CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; | ||
| 132 | #if 0 | ||
| 133 | *(UInt64 *)(void *)ptr = ((const UInt64 *)(const void *)ptr)[diff]; | ||
| 134 | #else | ||
| 135 | const UInt32 p0 = ptr[0 + (diff * 2)]; | ||
| 136 | const UInt32 p1 = ptr[1 + (diff * 2)]; | ||
| 137 | ptr[0] = p0; | ||
| 138 | ptr[1] = p1; | ||
| 139 | // ptr[0] = ptr[0 + (diff * 2)]; | ||
| 140 | // ptr[1] = ptr[1 + (diff * 2)]; | ||
| 141 | #endif | ||
| 142 | } | ||
| 143 | // PrintSon(son + 2, pos - 1); | ||
| 144 | // printf("\npos = %x delta = %x\n", pos, delta); | ||
| 145 | len++; | ||
| 146 | *d++ = 2; | ||
| 147 | *d++ = (UInt32)(len - cur); | ||
| 148 | *d++ = delta - 1; | ||
| 149 | if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) | ||
| 150 | break; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | #endif | ||
| 154 | |||
| 155 | break; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | { | ||
| 161 | const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff); | ||
| 162 | if (len[diff] < len[0]) | ||
| 163 | { | ||
| 164 | delta = pair[1]; | ||
| 165 | if (delta >= curMatch) | ||
| 166 | return NULL; | ||
| 167 | *ptr1 = curMatch; | ||
| 168 | ptr1 = pair + 1; | ||
| 169 | len1 = len; | ||
| 170 | } | ||
| 171 | else | ||
| 172 | { | ||
| 173 | delta = *pair; | ||
| 174 | if (delta >= curMatch) | ||
| 175 | return NULL; | ||
| 176 | *ptr0 = curMatch; | ||
| 177 | ptr0 = pair; | ||
| 178 | len0 = len; | ||
| 179 | } | ||
| 180 | |||
| 181 | delta = (UInt32)pos - delta; | ||
| 182 | |||
| 183 | if (--cutValue == 0 || delta >= pos) | ||
| 184 | { | ||
| 185 | *ptr0 = *ptr1 = kEmptyHashValue; | ||
| 186 | _distances[-1] = (UInt32)(d - _distances); | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | } // for (tree iterations) | ||
| 192 | } | ||
| 193 | pos++; | ||
| 194 | cur++; | ||
| 195 | } | ||
| 196 | while (d < limit); | ||
| 197 | *posRes = (UInt32)pos; | ||
| 198 | return d; | ||
| 199 | } | ||
| 200 | */ | ||
| 201 | |||
| 202 | /* define cbs if you use 2 functions. | ||
| 203 | GetMatchesSpecN_1() : (pos < _cyclicBufferSize) | ||
| 204 | GetMatchesSpecN_2() : (pos >= _cyclicBufferSize) | ||
| 205 | |||
| 206 | do not define cbs if you use 1 function: | ||
| 207 | GetMatchesSpecN_2() | ||
| 208 | */ | ||
| 209 | |||
| 210 | // #define cbs _cyclicBufferSize | ||
| 211 | |||
| 212 | /* | ||
| 213 | we use size_t for (pos) and (_cyclicBufferPos_ instead of UInt32 | ||
| 214 | to eliminate "movsx" BUG in old MSVC x64 compiler. | ||
| 215 | */ | ||
| 216 | |||
| 217 | UInt32 * MY_FAST_CALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, | ||
| 218 | UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, | ||
| 219 | size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, | ||
| 220 | UInt32 *posRes); | ||
| 221 | |||
| 222 | MY_NO_INLINE | ||
| 223 | UInt32 * MY_FAST_CALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, | ||
| 224 | UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, | ||
| 225 | size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, | ||
| 226 | UInt32 *posRes) | ||
| 227 | { | ||
| 228 | do // while (hash != size) | ||
| 229 | { | ||
| 230 | UInt32 delta; | ||
| 231 | |||
| 232 | #ifndef cbs | ||
| 233 | UInt32 cbs; | ||
| 234 | #endif | ||
| 235 | |||
| 236 | if (hash == size) | ||
| 237 | break; | ||
| 238 | |||
| 239 | delta = *hash++; | ||
| 240 | |||
| 241 | if (delta == 0) | ||
| 242 | return NULL; | ||
| 243 | |||
| 244 | lenLimit++; | ||
| 245 | |||
| 246 | #ifndef cbs | ||
| 247 | cbs = _cyclicBufferSize; | ||
| 248 | if ((UInt32)pos < cbs) | ||
| 249 | { | ||
| 250 | if (delta > (UInt32)pos) | ||
| 251 | return NULL; | ||
| 252 | cbs = (UInt32)pos; | ||
| 253 | } | ||
| 254 | #endif | ||
| 255 | |||
| 256 | if (delta >= cbs) | ||
| 257 | { | ||
| 258 | CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); | ||
| 259 | *d++ = 0; | ||
| 260 | ptr1[0] = kEmptyHashValue; | ||
| 261 | ptr1[1] = kEmptyHashValue; | ||
| 262 | } | ||
| 263 | else | ||
| 264 | { | ||
| 265 | UInt32 *_distances = ++d; | ||
| 266 | |||
| 267 | CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; | ||
| 268 | CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); | ||
| 269 | |||
| 270 | UInt32 cutValue = _cutValue; | ||
| 271 | const Byte *len0 = cur, *len1 = cur; | ||
| 272 | const Byte *maxLen = cur + _maxLen; | ||
| 273 | |||
| 274 | // if (cutValue == 0) { *ptr0 = *ptr1 = kEmptyHashValue; } else | ||
| 275 | for (LOG_ITER(g_NumIters_Tree++);;) | ||
| 276 | { | ||
| 277 | LOG_ITER(g_NumIters_Loop++); | ||
| 278 | { | ||
| 279 | // SPEC code | ||
| 280 | CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - (ptrdiff_t)delta | ||
| 281 | + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0) | ||
| 282 | ) << 1); | ||
| 283 | |||
| 284 | const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; | ||
| 285 | const Byte *len = (len0 < len1 ? len0 : len1); | ||
| 286 | |||
| 287 | #ifdef USE_SON_PREFETCH | ||
| 288 | const UInt32 pair0 = *pair; | ||
| 289 | #endif | ||
| 290 | |||
| 291 | if (len[diff] == len[0]) | ||
| 292 | { | ||
| 293 | if (++len != lenLimit && len[diff] == len[0]) | ||
| 294 | while (++len != lenLimit) | ||
| 295 | { | ||
| 296 | LOG_ITER(g_NumIters_Bytes++); | ||
| 297 | if (len[diff] != len[0]) | ||
| 298 | break; | ||
| 299 | } | ||
| 300 | if (maxLen < len) | ||
| 301 | { | ||
| 302 | maxLen = len; | ||
| 303 | *d++ = (UInt32)(len - cur); | ||
| 304 | *d++ = delta - 1; | ||
| 305 | |||
| 306 | if (len == lenLimit) | ||
| 307 | { | ||
| 308 | const UInt32 pair1 = pair[1]; | ||
| 309 | *ptr1 = | ||
| 310 | #ifdef USE_SON_PREFETCH | ||
| 311 | pair0; | ||
| 312 | #else | ||
| 313 | pair[0]; | ||
| 314 | #endif | ||
| 315 | *ptr0 = pair1; | ||
| 316 | |||
| 317 | _distances[-1] = (UInt32)(d - _distances); | ||
| 318 | |||
| 319 | #ifdef USE_LONG_MATCH_OPT | ||
| 320 | |||
| 321 | if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) | ||
| 322 | break; | ||
| 323 | |||
| 324 | { | ||
| 325 | for (;;) | ||
| 326 | { | ||
| 327 | *d++ = 2; | ||
| 328 | *d++ = (UInt32)(lenLimit - cur); | ||
| 329 | *d++ = delta - 1; | ||
| 330 | cur++; | ||
| 331 | lenLimit++; | ||
| 332 | // SPEC | ||
| 333 | _cyclicBufferPos++; | ||
| 334 | { | ||
| 335 | // SPEC code | ||
| 336 | CLzRef *dest = son + ((size_t)(_cyclicBufferPos) << 1); | ||
| 337 | const CLzRef *src = dest + ((diff | ||
| 338 | + (ptrdiff_t)(UInt32)((_cyclicBufferPos < delta) ? cbs : 0)) << 1); | ||
| 339 | // CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; | ||
| 340 | #if 0 | ||
| 341 | *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src); | ||
| 342 | #else | ||
| 343 | const UInt32 p0 = src[0]; | ||
| 344 | const UInt32 p1 = src[1]; | ||
| 345 | dest[0] = p0; | ||
| 346 | dest[1] = p1; | ||
| 347 | #endif | ||
| 348 | } | ||
| 349 | pos++; | ||
| 350 | hash++; | ||
| 351 | if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) | ||
| 352 | break; | ||
| 353 | } // for() end for long matches | ||
| 354 | } | ||
| 355 | #endif | ||
| 356 | |||
| 357 | break; // break from TREE iterations | ||
| 358 | } | ||
| 359 | } | ||
| 360 | } | ||
| 361 | { | ||
| 362 | const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff); | ||
| 363 | if (len[diff] < len[0]) | ||
| 364 | { | ||
| 365 | delta = pair[1]; | ||
| 366 | *ptr1 = curMatch; | ||
| 367 | ptr1 = pair + 1; | ||
| 368 | len1 = len; | ||
| 369 | if (delta >= curMatch) | ||
| 370 | return NULL; | ||
| 371 | } | ||
| 372 | else | ||
| 373 | { | ||
| 374 | delta = *pair; | ||
| 375 | *ptr0 = curMatch; | ||
| 376 | ptr0 = pair; | ||
| 377 | len0 = len; | ||
| 378 | if (delta >= curMatch) | ||
| 379 | return NULL; | ||
| 380 | } | ||
| 381 | delta = (UInt32)pos - delta; | ||
| 382 | |||
| 383 | if (--cutValue == 0 || delta >= cbs) | ||
| 384 | { | ||
| 385 | *ptr0 = *ptr1 = kEmptyHashValue; | ||
| 386 | _distances[-1] = (UInt32)(d - _distances); | ||
| 387 | break; | ||
| 388 | } | ||
| 389 | } | ||
| 390 | } | ||
| 391 | } // for (tree iterations) | ||
| 392 | } | ||
| 393 | pos++; | ||
| 394 | _cyclicBufferPos++; | ||
| 395 | cur++; | ||
| 396 | } | ||
| 397 | while (d < limit); | ||
| 398 | *posRes = (UInt32)pos; | ||
| 399 | return d; | ||
| 400 | } | ||
| 401 | |||
| 402 | |||
| 403 | |||
| 404 | /* | ||
| 405 | typedef UInt32 uint32plus; // size_t | ||
| 406 | |||
| 407 | UInt32 * MY_FAST_CALL GetMatchesSpecN_3(uint32plus lenLimit, size_t pos, const Byte *cur, CLzRef *son, | ||
| 408 | UInt32 _cutValue, UInt32 *d, uint32plus _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, | ||
| 409 | size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, | ||
| 410 | UInt32 *posRes) | ||
| 411 | { | ||
| 412 | do // while (hash != size) | ||
| 413 | { | ||
| 414 | UInt32 delta; | ||
| 415 | |||
| 416 | #ifndef cbs | ||
| 417 | UInt32 cbs; | ||
| 418 | #endif | ||
| 419 | |||
| 420 | if (hash == size) | ||
| 421 | break; | ||
| 422 | |||
| 423 | delta = *hash++; | ||
| 424 | |||
| 425 | if (delta == 0) | ||
| 426 | return NULL; | ||
| 427 | |||
| 428 | #ifndef cbs | ||
| 429 | cbs = _cyclicBufferSize; | ||
| 430 | if ((UInt32)pos < cbs) | ||
| 431 | { | ||
| 432 | if (delta > (UInt32)pos) | ||
| 433 | return NULL; | ||
| 434 | cbs = (UInt32)pos; | ||
| 435 | } | ||
| 436 | #endif | ||
| 437 | |||
| 438 | if (delta >= cbs) | ||
| 439 | { | ||
| 440 | CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); | ||
| 441 | *d++ = 0; | ||
| 442 | ptr1[0] = kEmptyHashValue; | ||
| 443 | ptr1[1] = kEmptyHashValue; | ||
| 444 | } | ||
| 445 | else | ||
| 446 | { | ||
| 447 | CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; | ||
| 448 | CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); | ||
| 449 | UInt32 *_distances = ++d; | ||
| 450 | uint32plus len0 = 0, len1 = 0; | ||
| 451 | UInt32 cutValue = _cutValue; | ||
| 452 | uint32plus maxLen = _maxLen; | ||
| 453 | // lenLimit++; // const Byte *lenLimit = cur + _lenLimit; | ||
| 454 | |||
| 455 | for (LOG_ITER(g_NumIters_Tree++);;) | ||
| 456 | { | ||
| 457 | LOG_ITER(g_NumIters_Loop++); | ||
| 458 | { | ||
| 459 | // const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; | ||
| 460 | CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - delta | ||
| 461 | + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0) | ||
| 462 | ) << 1); | ||
| 463 | const Byte *pb = cur - delta; | ||
| 464 | uint32plus len = (len0 < len1 ? len0 : len1); | ||
| 465 | |||
| 466 | #ifdef USE_SON_PREFETCH | ||
| 467 | const UInt32 pair0 = *pair; | ||
| 468 | #endif | ||
| 469 | |||
| 470 | if (pb[len] == cur[len]) | ||
| 471 | { | ||
| 472 | if (++len != lenLimit && pb[len] == cur[len]) | ||
| 473 | while (++len != lenLimit) | ||
| 474 | if (pb[len] != cur[len]) | ||
| 475 | break; | ||
| 476 | if (maxLen < len) | ||
| 477 | { | ||
| 478 | maxLen = len; | ||
| 479 | *d++ = (UInt32)len; | ||
| 480 | *d++ = delta - 1; | ||
| 481 | if (len == lenLimit) | ||
| 482 | { | ||
| 483 | { | ||
| 484 | const UInt32 pair1 = pair[1]; | ||
| 485 | *ptr0 = pair1; | ||
| 486 | *ptr1 = | ||
| 487 | #ifdef USE_SON_PREFETCH | ||
| 488 | pair0; | ||
| 489 | #else | ||
| 490 | pair[0]; | ||
| 491 | #endif | ||
| 492 | } | ||
| 493 | |||
| 494 | _distances[-1] = (UInt32)(d - _distances); | ||
| 495 | |||
| 496 | #ifdef USE_LONG_MATCH_OPT | ||
| 497 | |||
| 498 | if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit) | ||
| 499 | break; | ||
| 500 | |||
| 501 | { | ||
| 502 | const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; | ||
| 503 | for (;;) | ||
| 504 | { | ||
| 505 | *d++ = 2; | ||
| 506 | *d++ = (UInt32)lenLimit; | ||
| 507 | *d++ = delta - 1; | ||
| 508 | _cyclicBufferPos++; | ||
| 509 | { | ||
| 510 | CLzRef *dest = son + ((size_t)_cyclicBufferPos << 1); | ||
| 511 | const CLzRef *src = dest + ((diff + | ||
| 512 | (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0)) << 1); | ||
| 513 | #if 0 | ||
| 514 | *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src); | ||
| 515 | #else | ||
| 516 | const UInt32 p0 = src[0]; | ||
| 517 | const UInt32 p1 = src[1]; | ||
| 518 | dest[0] = p0; | ||
| 519 | dest[1] = p1; | ||
| 520 | #endif | ||
| 521 | } | ||
| 522 | hash++; | ||
| 523 | pos++; | ||
| 524 | cur++; | ||
| 525 | pb++; | ||
| 526 | if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit) | ||
| 527 | break; | ||
| 528 | } | ||
| 529 | } | ||
| 530 | #endif | ||
| 531 | |||
| 532 | break; | ||
| 533 | } | ||
| 534 | } | ||
| 535 | } | ||
| 536 | { | ||
| 537 | const UInt32 curMatch = (UInt32)pos - delta; | ||
| 538 | if (pb[len] < cur[len]) | ||
| 539 | { | ||
| 540 | delta = pair[1]; | ||
| 541 | *ptr1 = curMatch; | ||
| 542 | ptr1 = pair + 1; | ||
| 543 | len1 = len; | ||
| 544 | } | ||
| 545 | else | ||
| 546 | { | ||
| 547 | delta = *pair; | ||
| 548 | *ptr0 = curMatch; | ||
| 549 | ptr0 = pair; | ||
| 550 | len0 = len; | ||
| 551 | } | ||
| 552 | |||
| 553 | { | ||
| 554 | if (delta >= curMatch) | ||
| 555 | return NULL; | ||
| 556 | delta = (UInt32)pos - delta; | ||
| 557 | if (delta >= cbs | ||
| 558 | // delta >= _cyclicBufferSize || delta >= pos | ||
| 559 | || --cutValue == 0) | ||
| 560 | { | ||
| 561 | *ptr0 = *ptr1 = kEmptyHashValue; | ||
| 562 | _distances[-1] = (UInt32)(d - _distances); | ||
| 563 | break; | ||
| 564 | } | ||
| 565 | } | ||
| 566 | } | ||
| 567 | } | ||
| 568 | } // for (tree iterations) | ||
| 569 | } | ||
| 570 | pos++; | ||
| 571 | _cyclicBufferPos++; | ||
| 572 | cur++; | ||
| 573 | } | ||
| 574 | while (d < limit); | ||
| 575 | *posRes = (UInt32)pos; | ||
| 576 | return d; | ||
| 577 | } | ||
| 578 | */ | ||
diff --git a/C/LzHash.h b/C/LzHash.h new file mode 100644 index 0000000..77b898c --- /dev/null +++ b/C/LzHash.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* LzHash.h -- HASH functions for LZ algorithms | ||
| 2 | 2019-10-30 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __LZ_HASH_H | ||
| 5 | #define __LZ_HASH_H | ||
| 6 | |||
| 7 | /* | ||
| 8 | (kHash2Size >= (1 << 8)) : Required | ||
| 9 | (kHash3Size >= (1 << 16)) : Required | ||
| 10 | */ | ||
| 11 | |||
| 12 | #define kHash2Size (1 << 10) | ||
| 13 | #define kHash3Size (1 << 16) | ||
| 14 | // #define kHash4Size (1 << 20) | ||
| 15 | |||
| 16 | #define kFix3HashSize (kHash2Size) | ||
| 17 | #define kFix4HashSize (kHash2Size + kHash3Size) | ||
| 18 | // #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) | ||
| 19 | |||
| 20 | /* | ||
| 21 | We use up to 3 crc values for hash: | ||
| 22 | crc0 | ||
| 23 | crc1 << Shift_1 | ||
| 24 | crc2 << Shift_2 | ||
| 25 | (Shift_1 = 5) and (Shift_2 = 10) is good tradeoff. | ||
| 26 | Small values for Shift are not good for collision rate. | ||
| 27 | Big value for Shift_2 increases the minimum size | ||
| 28 | of hash table, that will be slow for small files. | ||
| 29 | */ | ||
| 30 | |||
| 31 | #define kLzHash_CrcShift_1 5 | ||
| 32 | #define kLzHash_CrcShift_2 10 | ||
| 33 | |||
| 34 | #endif | ||
diff --git a/C/Lzma2Dec.c b/C/Lzma2Dec.c new file mode 100644 index 0000000..ac970a8 --- /dev/null +++ b/C/Lzma2Dec.c | |||
| @@ -0,0 +1,489 @@ | |||
| 1 | /* Lzma2Dec.c -- LZMA2 Decoder | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | /* #define SHOW_DEBUG_INFO */ | ||
| 5 | |||
| 6 | #include "Precomp.h" | ||
| 7 | |||
| 8 | #ifdef SHOW_DEBUG_INFO | ||
| 9 | #include <stdio.h> | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #include <string.h> | ||
| 13 | |||
| 14 | #include "Lzma2Dec.h" | ||
| 15 | |||
| 16 | /* | ||
| 17 | 00000000 - End of data | ||
| 18 | 00000001 U U - Uncompressed, reset dic, need reset state and set new prop | ||
| 19 | 00000010 U U - Uncompressed, no reset | ||
| 20 | 100uuuuu U U P P - LZMA, no reset | ||
| 21 | 101uuuuu U U P P - LZMA, reset state | ||
| 22 | 110uuuuu U U P P S - LZMA, reset state + set new prop | ||
| 23 | 111uuuuu U U P P S - LZMA, reset state + set new prop, reset dic | ||
| 24 | |||
| 25 | u, U - Unpack Size | ||
| 26 | P - Pack Size | ||
| 27 | S - Props | ||
| 28 | */ | ||
| 29 | |||
| 30 | #define LZMA2_CONTROL_COPY_RESET_DIC 1 | ||
| 31 | |||
| 32 | #define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & (1 << 7)) == 0) | ||
| 33 | |||
| 34 | #define LZMA2_LCLP_MAX 4 | ||
| 35 | #define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) | ||
| 36 | |||
| 37 | #ifdef SHOW_DEBUG_INFO | ||
| 38 | #define PRF(x) x | ||
| 39 | #else | ||
| 40 | #define PRF(x) | ||
| 41 | #endif | ||
| 42 | |||
| 43 | typedef enum | ||
| 44 | { | ||
| 45 | LZMA2_STATE_CONTROL, | ||
| 46 | LZMA2_STATE_UNPACK0, | ||
| 47 | LZMA2_STATE_UNPACK1, | ||
| 48 | LZMA2_STATE_PACK0, | ||
| 49 | LZMA2_STATE_PACK1, | ||
| 50 | LZMA2_STATE_PROP, | ||
| 51 | LZMA2_STATE_DATA, | ||
| 52 | LZMA2_STATE_DATA_CONT, | ||
| 53 | LZMA2_STATE_FINISHED, | ||
| 54 | LZMA2_STATE_ERROR | ||
| 55 | } ELzma2State; | ||
| 56 | |||
| 57 | static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) | ||
| 58 | { | ||
| 59 | UInt32 dicSize; | ||
| 60 | if (prop > 40) | ||
| 61 | return SZ_ERROR_UNSUPPORTED; | ||
| 62 | dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); | ||
| 63 | props[0] = (Byte)LZMA2_LCLP_MAX; | ||
| 64 | props[1] = (Byte)(dicSize); | ||
| 65 | props[2] = (Byte)(dicSize >> 8); | ||
| 66 | props[3] = (Byte)(dicSize >> 16); | ||
| 67 | props[4] = (Byte)(dicSize >> 24); | ||
| 68 | return SZ_OK; | ||
| 69 | } | ||
| 70 | |||
| 71 | SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) | ||
| 72 | { | ||
| 73 | Byte props[LZMA_PROPS_SIZE]; | ||
| 74 | RINOK(Lzma2Dec_GetOldProps(prop, props)); | ||
| 75 | return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); | ||
| 76 | } | ||
| 77 | |||
| 78 | SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) | ||
| 79 | { | ||
| 80 | Byte props[LZMA_PROPS_SIZE]; | ||
| 81 | RINOK(Lzma2Dec_GetOldProps(prop, props)); | ||
| 82 | return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); | ||
| 83 | } | ||
| 84 | |||
| 85 | void Lzma2Dec_Init(CLzma2Dec *p) | ||
| 86 | { | ||
| 87 | p->state = LZMA2_STATE_CONTROL; | ||
| 88 | p->needInitLevel = 0xE0; | ||
| 89 | p->isExtraMode = False; | ||
| 90 | p->unpackSize = 0; | ||
| 91 | |||
| 92 | // p->decoder.dicPos = 0; // we can use it instead of full init | ||
| 93 | LzmaDec_Init(&p->decoder); | ||
| 94 | } | ||
| 95 | |||
| 96 | // ELzma2State | ||
| 97 | static unsigned Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) | ||
| 98 | { | ||
| 99 | switch (p->state) | ||
| 100 | { | ||
| 101 | case LZMA2_STATE_CONTROL: | ||
| 102 | p->isExtraMode = False; | ||
| 103 | p->control = b; | ||
| 104 | PRF(printf("\n %8X", (unsigned)p->decoder.dicPos)); | ||
| 105 | PRF(printf(" %02X", (unsigned)b)); | ||
| 106 | if (b == 0) | ||
| 107 | return LZMA2_STATE_FINISHED; | ||
| 108 | if (LZMA2_IS_UNCOMPRESSED_STATE(p)) | ||
| 109 | { | ||
| 110 | if (b == LZMA2_CONTROL_COPY_RESET_DIC) | ||
| 111 | p->needInitLevel = 0xC0; | ||
| 112 | else if (b > 2 || p->needInitLevel == 0xE0) | ||
| 113 | return LZMA2_STATE_ERROR; | ||
| 114 | } | ||
| 115 | else | ||
| 116 | { | ||
| 117 | if (b < p->needInitLevel) | ||
| 118 | return LZMA2_STATE_ERROR; | ||
| 119 | p->needInitLevel = 0; | ||
| 120 | p->unpackSize = (UInt32)(b & 0x1F) << 16; | ||
| 121 | } | ||
| 122 | return LZMA2_STATE_UNPACK0; | ||
| 123 | |||
| 124 | case LZMA2_STATE_UNPACK0: | ||
| 125 | p->unpackSize |= (UInt32)b << 8; | ||
| 126 | return LZMA2_STATE_UNPACK1; | ||
| 127 | |||
| 128 | case LZMA2_STATE_UNPACK1: | ||
| 129 | p->unpackSize |= (UInt32)b; | ||
| 130 | p->unpackSize++; | ||
| 131 | PRF(printf(" %7u", (unsigned)p->unpackSize)); | ||
| 132 | return LZMA2_IS_UNCOMPRESSED_STATE(p) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; | ||
| 133 | |||
| 134 | case LZMA2_STATE_PACK0: | ||
| 135 | p->packSize = (UInt32)b << 8; | ||
| 136 | return LZMA2_STATE_PACK1; | ||
| 137 | |||
| 138 | case LZMA2_STATE_PACK1: | ||
| 139 | p->packSize |= (UInt32)b; | ||
| 140 | p->packSize++; | ||
| 141 | // if (p->packSize < 5) return LZMA2_STATE_ERROR; | ||
| 142 | PRF(printf(" %5u", (unsigned)p->packSize)); | ||
| 143 | return (p->control & 0x40) ? LZMA2_STATE_PROP : LZMA2_STATE_DATA; | ||
| 144 | |||
| 145 | case LZMA2_STATE_PROP: | ||
| 146 | { | ||
| 147 | unsigned lc, lp; | ||
| 148 | if (b >= (9 * 5 * 5)) | ||
| 149 | return LZMA2_STATE_ERROR; | ||
| 150 | lc = b % 9; | ||
| 151 | b /= 9; | ||
| 152 | p->decoder.prop.pb = (Byte)(b / 5); | ||
| 153 | lp = b % 5; | ||
| 154 | if (lc + lp > LZMA2_LCLP_MAX) | ||
| 155 | return LZMA2_STATE_ERROR; | ||
| 156 | p->decoder.prop.lc = (Byte)lc; | ||
| 157 | p->decoder.prop.lp = (Byte)lp; | ||
| 158 | return LZMA2_STATE_DATA; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | return LZMA2_STATE_ERROR; | ||
| 162 | } | ||
| 163 | |||
| 164 | static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) | ||
| 165 | { | ||
| 166 | memcpy(p->dic + p->dicPos, src, size); | ||
| 167 | p->dicPos += size; | ||
| 168 | if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) | ||
| 169 | p->checkDicSize = p->prop.dicSize; | ||
| 170 | p->processedPos += (UInt32)size; | ||
| 171 | } | ||
| 172 | |||
| 173 | void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState); | ||
| 174 | |||
| 175 | |||
| 176 | SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, | ||
| 177 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) | ||
| 178 | { | ||
| 179 | SizeT inSize = *srcLen; | ||
| 180 | *srcLen = 0; | ||
| 181 | *status = LZMA_STATUS_NOT_SPECIFIED; | ||
| 182 | |||
| 183 | while (p->state != LZMA2_STATE_ERROR) | ||
| 184 | { | ||
| 185 | SizeT dicPos; | ||
| 186 | |||
| 187 | if (p->state == LZMA2_STATE_FINISHED) | ||
| 188 | { | ||
| 189 | *status = LZMA_STATUS_FINISHED_WITH_MARK; | ||
| 190 | return SZ_OK; | ||
| 191 | } | ||
| 192 | |||
| 193 | dicPos = p->decoder.dicPos; | ||
| 194 | |||
| 195 | if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) | ||
| 196 | { | ||
| 197 | *status = LZMA_STATUS_NOT_FINISHED; | ||
| 198 | return SZ_OK; | ||
| 199 | } | ||
| 200 | |||
| 201 | if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) | ||
| 202 | { | ||
| 203 | if (*srcLen == inSize) | ||
| 204 | { | ||
| 205 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; | ||
| 206 | return SZ_OK; | ||
| 207 | } | ||
| 208 | (*srcLen)++; | ||
| 209 | p->state = Lzma2Dec_UpdateState(p, *src++); | ||
| 210 | if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) | ||
| 211 | break; | ||
| 212 | continue; | ||
| 213 | } | ||
| 214 | |||
| 215 | { | ||
| 216 | SizeT inCur = inSize - *srcLen; | ||
| 217 | SizeT outCur = dicLimit - dicPos; | ||
| 218 | ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; | ||
| 219 | |||
| 220 | if (outCur >= p->unpackSize) | ||
| 221 | { | ||
| 222 | outCur = (SizeT)p->unpackSize; | ||
| 223 | curFinishMode = LZMA_FINISH_END; | ||
| 224 | } | ||
| 225 | |||
| 226 | if (LZMA2_IS_UNCOMPRESSED_STATE(p)) | ||
| 227 | { | ||
| 228 | if (inCur == 0) | ||
| 229 | { | ||
| 230 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; | ||
| 231 | return SZ_OK; | ||
| 232 | } | ||
| 233 | |||
| 234 | if (p->state == LZMA2_STATE_DATA) | ||
| 235 | { | ||
| 236 | BoolInt initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); | ||
| 237 | LzmaDec_InitDicAndState(&p->decoder, initDic, False); | ||
| 238 | } | ||
| 239 | |||
| 240 | if (inCur > outCur) | ||
| 241 | inCur = outCur; | ||
| 242 | if (inCur == 0) | ||
| 243 | break; | ||
| 244 | |||
| 245 | LzmaDec_UpdateWithUncompressed(&p->decoder, src, inCur); | ||
| 246 | |||
| 247 | src += inCur; | ||
| 248 | *srcLen += inCur; | ||
| 249 | p->unpackSize -= (UInt32)inCur; | ||
| 250 | p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; | ||
| 251 | } | ||
| 252 | else | ||
| 253 | { | ||
| 254 | SRes res; | ||
| 255 | |||
| 256 | if (p->state == LZMA2_STATE_DATA) | ||
| 257 | { | ||
| 258 | BoolInt initDic = (p->control >= 0xE0); | ||
| 259 | BoolInt initState = (p->control >= 0xA0); | ||
| 260 | LzmaDec_InitDicAndState(&p->decoder, initDic, initState); | ||
| 261 | p->state = LZMA2_STATE_DATA_CONT; | ||
| 262 | } | ||
| 263 | |||
| 264 | if (inCur > p->packSize) | ||
| 265 | inCur = (SizeT)p->packSize; | ||
| 266 | |||
| 267 | res = LzmaDec_DecodeToDic(&p->decoder, dicPos + outCur, src, &inCur, curFinishMode, status); | ||
| 268 | |||
| 269 | src += inCur; | ||
| 270 | *srcLen += inCur; | ||
| 271 | p->packSize -= (UInt32)inCur; | ||
| 272 | outCur = p->decoder.dicPos - dicPos; | ||
| 273 | p->unpackSize -= (UInt32)outCur; | ||
| 274 | |||
| 275 | if (res != 0) | ||
| 276 | break; | ||
| 277 | |||
| 278 | if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) | ||
| 279 | { | ||
| 280 | if (p->packSize == 0) | ||
| 281 | break; | ||
| 282 | return SZ_OK; | ||
| 283 | } | ||
| 284 | |||
| 285 | if (inCur == 0 && outCur == 0) | ||
| 286 | { | ||
| 287 | if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK | ||
| 288 | || p->unpackSize != 0 | ||
| 289 | || p->packSize != 0) | ||
| 290 | break; | ||
| 291 | p->state = LZMA2_STATE_CONTROL; | ||
| 292 | } | ||
| 293 | |||
| 294 | *status = LZMA_STATUS_NOT_SPECIFIED; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | *status = LZMA_STATUS_NOT_SPECIFIED; | ||
| 300 | p->state = LZMA2_STATE_ERROR; | ||
| 301 | return SZ_ERROR_DATA; | ||
| 302 | } | ||
| 303 | |||
| 304 | |||
| 305 | |||
| 306 | |||
| 307 | ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, | ||
| 308 | SizeT outSize, | ||
| 309 | const Byte *src, SizeT *srcLen, | ||
| 310 | int checkFinishBlock) | ||
| 311 | { | ||
| 312 | SizeT inSize = *srcLen; | ||
| 313 | *srcLen = 0; | ||
| 314 | |||
| 315 | while (p->state != LZMA2_STATE_ERROR) | ||
| 316 | { | ||
| 317 | if (p->state == LZMA2_STATE_FINISHED) | ||
| 318 | return (ELzma2ParseStatus)LZMA_STATUS_FINISHED_WITH_MARK; | ||
| 319 | |||
| 320 | if (outSize == 0 && !checkFinishBlock) | ||
| 321 | return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; | ||
| 322 | |||
| 323 | if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) | ||
| 324 | { | ||
| 325 | if (*srcLen == inSize) | ||
| 326 | return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; | ||
| 327 | (*srcLen)++; | ||
| 328 | |||
| 329 | p->state = Lzma2Dec_UpdateState(p, *src++); | ||
| 330 | |||
| 331 | if (p->state == LZMA2_STATE_UNPACK0) | ||
| 332 | { | ||
| 333 | // if (p->decoder.dicPos != 0) | ||
| 334 | if (p->control == LZMA2_CONTROL_COPY_RESET_DIC || p->control >= 0xE0) | ||
| 335 | return LZMA2_PARSE_STATUS_NEW_BLOCK; | ||
| 336 | // if (outSize == 0) return LZMA_STATUS_NOT_FINISHED; | ||
| 337 | } | ||
| 338 | |||
| 339 | // The following code can be commented. | ||
| 340 | // It's not big problem, if we read additional input bytes. | ||
| 341 | // It will be stopped later in LZMA2_STATE_DATA / LZMA2_STATE_DATA_CONT state. | ||
| 342 | |||
| 343 | if (outSize == 0 && p->state != LZMA2_STATE_FINISHED) | ||
| 344 | { | ||
| 345 | // checkFinishBlock is true. So we expect that block must be finished, | ||
| 346 | // We can return LZMA_STATUS_NOT_SPECIFIED or LZMA_STATUS_NOT_FINISHED here | ||
| 347 | // break; | ||
| 348 | return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; | ||
| 349 | } | ||
| 350 | |||
| 351 | if (p->state == LZMA2_STATE_DATA) | ||
| 352 | return LZMA2_PARSE_STATUS_NEW_CHUNK; | ||
| 353 | |||
| 354 | continue; | ||
| 355 | } | ||
| 356 | |||
| 357 | if (outSize == 0) | ||
| 358 | return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; | ||
| 359 | |||
| 360 | { | ||
| 361 | SizeT inCur = inSize - *srcLen; | ||
| 362 | |||
| 363 | if (LZMA2_IS_UNCOMPRESSED_STATE(p)) | ||
| 364 | { | ||
| 365 | if (inCur == 0) | ||
| 366 | return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; | ||
| 367 | if (inCur > p->unpackSize) | ||
| 368 | inCur = p->unpackSize; | ||
| 369 | if (inCur > outSize) | ||
| 370 | inCur = outSize; | ||
| 371 | p->decoder.dicPos += inCur; | ||
| 372 | src += inCur; | ||
| 373 | *srcLen += inCur; | ||
| 374 | outSize -= inCur; | ||
| 375 | p->unpackSize -= (UInt32)inCur; | ||
| 376 | p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; | ||
| 377 | } | ||
| 378 | else | ||
| 379 | { | ||
| 380 | p->isExtraMode = True; | ||
| 381 | |||
| 382 | if (inCur == 0) | ||
| 383 | { | ||
| 384 | if (p->packSize != 0) | ||
| 385 | return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; | ||
| 386 | } | ||
| 387 | else if (p->state == LZMA2_STATE_DATA) | ||
| 388 | { | ||
| 389 | p->state = LZMA2_STATE_DATA_CONT; | ||
| 390 | if (*src != 0) | ||
| 391 | { | ||
| 392 | // first byte of lzma chunk must be Zero | ||
| 393 | *srcLen += 1; | ||
| 394 | p->packSize--; | ||
| 395 | break; | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | if (inCur > p->packSize) | ||
| 400 | inCur = (SizeT)p->packSize; | ||
| 401 | |||
| 402 | src += inCur; | ||
| 403 | *srcLen += inCur; | ||
| 404 | p->packSize -= (UInt32)inCur; | ||
| 405 | |||
| 406 | if (p->packSize == 0) | ||
| 407 | { | ||
| 408 | SizeT rem = outSize; | ||
| 409 | if (rem > p->unpackSize) | ||
| 410 | rem = p->unpackSize; | ||
| 411 | p->decoder.dicPos += rem; | ||
| 412 | p->unpackSize -= (UInt32)rem; | ||
| 413 | outSize -= rem; | ||
| 414 | if (p->unpackSize == 0) | ||
| 415 | p->state = LZMA2_STATE_CONTROL; | ||
| 416 | } | ||
| 417 | } | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | p->state = LZMA2_STATE_ERROR; | ||
| 422 | return (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; | ||
| 423 | } | ||
| 424 | |||
| 425 | |||
| 426 | |||
| 427 | |||
| 428 | SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) | ||
| 429 | { | ||
| 430 | SizeT outSize = *destLen, inSize = *srcLen; | ||
| 431 | *srcLen = *destLen = 0; | ||
| 432 | |||
| 433 | for (;;) | ||
| 434 | { | ||
| 435 | SizeT inCur = inSize, outCur, dicPos; | ||
| 436 | ELzmaFinishMode curFinishMode; | ||
| 437 | SRes res; | ||
| 438 | |||
| 439 | if (p->decoder.dicPos == p->decoder.dicBufSize) | ||
| 440 | p->decoder.dicPos = 0; | ||
| 441 | dicPos = p->decoder.dicPos; | ||
| 442 | curFinishMode = LZMA_FINISH_ANY; | ||
| 443 | outCur = p->decoder.dicBufSize - dicPos; | ||
| 444 | |||
| 445 | if (outCur >= outSize) | ||
| 446 | { | ||
| 447 | outCur = outSize; | ||
| 448 | curFinishMode = finishMode; | ||
| 449 | } | ||
| 450 | |||
| 451 | res = Lzma2Dec_DecodeToDic(p, dicPos + outCur, src, &inCur, curFinishMode, status); | ||
| 452 | |||
| 453 | src += inCur; | ||
| 454 | inSize -= inCur; | ||
| 455 | *srcLen += inCur; | ||
| 456 | outCur = p->decoder.dicPos - dicPos; | ||
| 457 | memcpy(dest, p->decoder.dic + dicPos, outCur); | ||
| 458 | dest += outCur; | ||
| 459 | outSize -= outCur; | ||
| 460 | *destLen += outCur; | ||
| 461 | if (res != 0) | ||
| 462 | return res; | ||
| 463 | if (outCur == 0 || outSize == 0) | ||
| 464 | return SZ_OK; | ||
| 465 | } | ||
| 466 | } | ||
| 467 | |||
| 468 | |||
| 469 | SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, | ||
| 470 | Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc) | ||
| 471 | { | ||
| 472 | CLzma2Dec p; | ||
| 473 | SRes res; | ||
| 474 | SizeT outSize = *destLen, inSize = *srcLen; | ||
| 475 | *destLen = *srcLen = 0; | ||
| 476 | *status = LZMA_STATUS_NOT_SPECIFIED; | ||
| 477 | Lzma2Dec_Construct(&p); | ||
| 478 | RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)); | ||
| 479 | p.decoder.dic = dest; | ||
| 480 | p.decoder.dicBufSize = outSize; | ||
| 481 | Lzma2Dec_Init(&p); | ||
| 482 | *srcLen = inSize; | ||
| 483 | res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); | ||
| 484 | *destLen = p.decoder.dicPos; | ||
| 485 | if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) | ||
| 486 | res = SZ_ERROR_INPUT_EOF; | ||
| 487 | Lzma2Dec_FreeProbs(&p, alloc); | ||
| 488 | return res; | ||
| 489 | } | ||
diff --git a/C/Lzma2Dec.h b/C/Lzma2Dec.h new file mode 100644 index 0000000..b8ddeac --- /dev/null +++ b/C/Lzma2Dec.h | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | /* Lzma2Dec.h -- LZMA2 Decoder | ||
| 2 | 2018-02-19 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __LZMA2_DEC_H | ||
| 5 | #define __LZMA2_DEC_H | ||
| 6 | |||
| 7 | #include "LzmaDec.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | /* ---------- State Interface ---------- */ | ||
| 12 | |||
| 13 | typedef struct | ||
| 14 | { | ||
| 15 | unsigned state; | ||
| 16 | Byte control; | ||
| 17 | Byte needInitLevel; | ||
| 18 | Byte isExtraMode; | ||
| 19 | Byte _pad_; | ||
| 20 | UInt32 packSize; | ||
| 21 | UInt32 unpackSize; | ||
| 22 | CLzmaDec decoder; | ||
| 23 | } CLzma2Dec; | ||
| 24 | |||
| 25 | #define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) | ||
| 26 | #define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc) | ||
| 27 | #define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc) | ||
| 28 | |||
| 29 | SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); | ||
| 30 | SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); | ||
| 31 | void Lzma2Dec_Init(CLzma2Dec *p); | ||
| 32 | |||
| 33 | /* | ||
| 34 | finishMode: | ||
| 35 | It has meaning only if the decoding reaches output limit (*destLen or dicLimit). | ||
| 36 | LZMA_FINISH_ANY - use smallest number of input bytes | ||
| 37 | LZMA_FINISH_END - read EndOfStream marker after decoding | ||
| 38 | |||
| 39 | Returns: | ||
| 40 | SZ_OK | ||
| 41 | status: | ||
| 42 | LZMA_STATUS_FINISHED_WITH_MARK | ||
| 43 | LZMA_STATUS_NOT_FINISHED | ||
| 44 | LZMA_STATUS_NEEDS_MORE_INPUT | ||
| 45 | SZ_ERROR_DATA - Data error | ||
| 46 | */ | ||
| 47 | |||
| 48 | SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, | ||
| 49 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); | ||
| 50 | |||
| 51 | SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, | ||
| 52 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); | ||
| 53 | |||
| 54 | |||
| 55 | /* ---------- LZMA2 block and chunk parsing ---------- */ | ||
| 56 | |||
| 57 | /* | ||
| 58 | Lzma2Dec_Parse() parses compressed data stream up to next independent block or next chunk data. | ||
| 59 | It can return LZMA_STATUS_* code or LZMA2_PARSE_STATUS_* code: | ||
| 60 | - LZMA2_PARSE_STATUS_NEW_BLOCK - there is new block, and 1 additional byte (control byte of next block header) was read from input. | ||
| 61 | - LZMA2_PARSE_STATUS_NEW_CHUNK - there is new chunk, and only lzma2 header of new chunk was read. | ||
| 62 | CLzma2Dec::unpackSize contains unpack size of that chunk | ||
| 63 | */ | ||
| 64 | |||
| 65 | typedef enum | ||
| 66 | { | ||
| 67 | /* | ||
| 68 | LZMA_STATUS_NOT_SPECIFIED // data error | ||
| 69 | LZMA_STATUS_FINISHED_WITH_MARK | ||
| 70 | LZMA_STATUS_NOT_FINISHED // | ||
| 71 | LZMA_STATUS_NEEDS_MORE_INPUT | ||
| 72 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK // unused | ||
| 73 | */ | ||
| 74 | LZMA2_PARSE_STATUS_NEW_BLOCK = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + 1, | ||
| 75 | LZMA2_PARSE_STATUS_NEW_CHUNK | ||
| 76 | } ELzma2ParseStatus; | ||
| 77 | |||
| 78 | ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, | ||
| 79 | SizeT outSize, // output size | ||
| 80 | const Byte *src, SizeT *srcLen, | ||
| 81 | int checkFinishBlock // set (checkFinishBlock = 1), if it must read full input data, if decoder.dicPos reaches blockMax position. | ||
| 82 | ); | ||
| 83 | |||
| 84 | /* | ||
| 85 | LZMA2 parser doesn't decode LZMA chunks, so we must read | ||
| 86 | full input LZMA chunk to decode some part of LZMA chunk. | ||
| 87 | |||
| 88 | Lzma2Dec_GetUnpackExtra() returns the value that shows | ||
| 89 | max possible number of output bytes that can be output by decoder | ||
| 90 | at current input positon. | ||
| 91 | */ | ||
| 92 | |||
| 93 | #define Lzma2Dec_GetUnpackExtra(p) ((p)->isExtraMode ? (p)->unpackSize : 0); | ||
| 94 | |||
| 95 | |||
| 96 | /* ---------- One Call Interface ---------- */ | ||
| 97 | |||
| 98 | /* | ||
| 99 | finishMode: | ||
| 100 | It has meaning only if the decoding reaches output limit (*destLen). | ||
| 101 | LZMA_FINISH_ANY - use smallest number of input bytes | ||
| 102 | LZMA_FINISH_END - read EndOfStream marker after decoding | ||
| 103 | |||
| 104 | Returns: | ||
| 105 | SZ_OK | ||
| 106 | status: | ||
| 107 | LZMA_STATUS_FINISHED_WITH_MARK | ||
| 108 | LZMA_STATUS_NOT_FINISHED | ||
| 109 | SZ_ERROR_DATA - Data error | ||
| 110 | SZ_ERROR_MEM - Memory allocation error | ||
| 111 | SZ_ERROR_UNSUPPORTED - Unsupported properties | ||
| 112 | SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). | ||
| 113 | */ | ||
| 114 | |||
| 115 | SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, | ||
| 116 | Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc); | ||
| 117 | |||
| 118 | EXTERN_C_END | ||
| 119 | |||
| 120 | #endif | ||
diff --git a/C/Lzma2DecMt.c b/C/Lzma2DecMt.c new file mode 100644 index 0000000..9f1dc52 --- /dev/null +++ b/C/Lzma2DecMt.c | |||
| @@ -0,0 +1,1090 @@ | |||
| 1 | /* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread | ||
| 2 | 2021-04-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | // #define SHOW_DEBUG_INFO | ||
| 7 | |||
| 8 | // #define _7ZIP_ST | ||
| 9 | |||
| 10 | #ifdef SHOW_DEBUG_INFO | ||
| 11 | #include <stdio.h> | ||
| 12 | #endif | ||
| 13 | |||
| 14 | #ifndef _7ZIP_ST | ||
| 15 | #ifdef SHOW_DEBUG_INFO | ||
| 16 | #define PRF(x) x | ||
| 17 | #else | ||
| 18 | #define PRF(x) | ||
| 19 | #endif | ||
| 20 | #define PRF_STR(s) PRF(printf("\n" s "\n")) | ||
| 21 | #define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2)) | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #include "Alloc.h" | ||
| 25 | |||
| 26 | #include "Lzma2Dec.h" | ||
| 27 | #include "Lzma2DecMt.h" | ||
| 28 | |||
| 29 | #ifndef _7ZIP_ST | ||
| 30 | #include "MtDec.h" | ||
| 31 | |||
| 32 | #define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28) | ||
| 33 | #endif | ||
| 34 | |||
| 35 | |||
| 36 | void Lzma2DecMtProps_Init(CLzma2DecMtProps *p) | ||
| 37 | { | ||
| 38 | p->inBufSize_ST = 1 << 20; | ||
| 39 | p->outStep_ST = 1 << 20; | ||
| 40 | |||
| 41 | #ifndef _7ZIP_ST | ||
| 42 | p->numThreads = 1; | ||
| 43 | p->inBufSize_MT = 1 << 18; | ||
| 44 | p->outBlockMax = LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT; | ||
| 45 | p->inBlockMax = p->outBlockMax + p->outBlockMax / 16; | ||
| 46 | #endif | ||
| 47 | } | ||
| 48 | |||
| 49 | |||
| 50 | |||
| 51 | #ifndef _7ZIP_ST | ||
| 52 | |||
| 53 | /* ---------- CLzma2DecMtThread ---------- */ | ||
| 54 | |||
| 55 | typedef struct | ||
| 56 | { | ||
| 57 | CLzma2Dec dec; | ||
| 58 | Byte dec_created; | ||
| 59 | Byte needInit; | ||
| 60 | |||
| 61 | Byte *outBuf; | ||
| 62 | size_t outBufSize; | ||
| 63 | |||
| 64 | EMtDecParseState state; | ||
| 65 | ELzma2ParseStatus parseStatus; | ||
| 66 | |||
| 67 | size_t inPreSize; | ||
| 68 | size_t outPreSize; | ||
| 69 | |||
| 70 | size_t inCodeSize; | ||
| 71 | size_t outCodeSize; | ||
| 72 | SRes codeRes; | ||
| 73 | |||
| 74 | CAlignOffsetAlloc alloc; | ||
| 75 | |||
| 76 | Byte mtPad[1 << 7]; | ||
| 77 | } CLzma2DecMtThread; | ||
| 78 | |||
| 79 | #endif | ||
| 80 | |||
| 81 | |||
| 82 | /* ---------- CLzma2DecMt ---------- */ | ||
| 83 | |||
| 84 | typedef struct | ||
| 85 | { | ||
| 86 | // ISzAllocPtr alloc; | ||
| 87 | ISzAllocPtr allocMid; | ||
| 88 | |||
| 89 | CAlignOffsetAlloc alignOffsetAlloc; | ||
| 90 | CLzma2DecMtProps props; | ||
| 91 | Byte prop; | ||
| 92 | |||
| 93 | ISeqInStream *inStream; | ||
| 94 | ISeqOutStream *outStream; | ||
| 95 | ICompressProgress *progress; | ||
| 96 | |||
| 97 | BoolInt finishMode; | ||
| 98 | BoolInt outSize_Defined; | ||
| 99 | UInt64 outSize; | ||
| 100 | |||
| 101 | UInt64 outProcessed; | ||
| 102 | UInt64 inProcessed; | ||
| 103 | BoolInt readWasFinished; | ||
| 104 | SRes readRes; | ||
| 105 | |||
| 106 | Byte *inBuf; | ||
| 107 | size_t inBufSize; | ||
| 108 | Byte dec_created; | ||
| 109 | CLzma2Dec dec; | ||
| 110 | |||
| 111 | size_t inPos; | ||
| 112 | size_t inLim; | ||
| 113 | |||
| 114 | #ifndef _7ZIP_ST | ||
| 115 | UInt64 outProcessed_Parse; | ||
| 116 | BoolInt mtc_WasConstructed; | ||
| 117 | CMtDec mtc; | ||
| 118 | CLzma2DecMtThread coders[MTDEC__THREADS_MAX]; | ||
| 119 | #endif | ||
| 120 | |||
| 121 | } CLzma2DecMt; | ||
| 122 | |||
| 123 | |||
| 124 | |||
| 125 | CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) | ||
| 126 | { | ||
| 127 | CLzma2DecMt *p = (CLzma2DecMt *)ISzAlloc_Alloc(alloc, sizeof(CLzma2DecMt)); | ||
| 128 | if (!p) | ||
| 129 | return NULL; | ||
| 130 | |||
| 131 | // p->alloc = alloc; | ||
| 132 | p->allocMid = allocMid; | ||
| 133 | |||
| 134 | AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); | ||
| 135 | p->alignOffsetAlloc.numAlignBits = 7; | ||
| 136 | p->alignOffsetAlloc.offset = 0; | ||
| 137 | p->alignOffsetAlloc.baseAlloc = alloc; | ||
| 138 | |||
| 139 | p->inBuf = NULL; | ||
| 140 | p->inBufSize = 0; | ||
| 141 | p->dec_created = False; | ||
| 142 | |||
| 143 | // Lzma2DecMtProps_Init(&p->props); | ||
| 144 | |||
| 145 | #ifndef _7ZIP_ST | ||
| 146 | p->mtc_WasConstructed = False; | ||
| 147 | { | ||
| 148 | unsigned i; | ||
| 149 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 150 | { | ||
| 151 | CLzma2DecMtThread *t = &p->coders[i]; | ||
| 152 | t->dec_created = False; | ||
| 153 | t->outBuf = NULL; | ||
| 154 | t->outBufSize = 0; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | #endif | ||
| 158 | |||
| 159 | return p; | ||
| 160 | } | ||
| 161 | |||
| 162 | |||
| 163 | #ifndef _7ZIP_ST | ||
| 164 | |||
| 165 | static void Lzma2DecMt_FreeOutBufs(CLzma2DecMt *p) | ||
| 166 | { | ||
| 167 | unsigned i; | ||
| 168 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 169 | { | ||
| 170 | CLzma2DecMtThread *t = &p->coders[i]; | ||
| 171 | if (t->outBuf) | ||
| 172 | { | ||
| 173 | ISzAlloc_Free(p->allocMid, t->outBuf); | ||
| 174 | t->outBuf = NULL; | ||
| 175 | t->outBufSize = 0; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | #endif | ||
| 181 | |||
| 182 | |||
| 183 | static void Lzma2DecMt_FreeSt(CLzma2DecMt *p) | ||
| 184 | { | ||
| 185 | if (p->dec_created) | ||
| 186 | { | ||
| 187 | Lzma2Dec_Free(&p->dec, &p->alignOffsetAlloc.vt); | ||
| 188 | p->dec_created = False; | ||
| 189 | } | ||
| 190 | if (p->inBuf) | ||
| 191 | { | ||
| 192 | ISzAlloc_Free(p->allocMid, p->inBuf); | ||
| 193 | p->inBuf = NULL; | ||
| 194 | } | ||
| 195 | p->inBufSize = 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | |||
| 199 | void Lzma2DecMt_Destroy(CLzma2DecMtHandle pp) | ||
| 200 | { | ||
| 201 | CLzma2DecMt *p = (CLzma2DecMt *)pp; | ||
| 202 | |||
| 203 | Lzma2DecMt_FreeSt(p); | ||
| 204 | |||
| 205 | #ifndef _7ZIP_ST | ||
| 206 | |||
| 207 | if (p->mtc_WasConstructed) | ||
| 208 | { | ||
| 209 | MtDec_Destruct(&p->mtc); | ||
| 210 | p->mtc_WasConstructed = False; | ||
| 211 | } | ||
| 212 | { | ||
| 213 | unsigned i; | ||
| 214 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 215 | { | ||
| 216 | CLzma2DecMtThread *t = &p->coders[i]; | ||
| 217 | if (t->dec_created) | ||
| 218 | { | ||
| 219 | // we don't need to free dict here | ||
| 220 | Lzma2Dec_FreeProbs(&t->dec, &t->alloc.vt); // p->alloc !!! | ||
| 221 | t->dec_created = False; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | } | ||
| 225 | Lzma2DecMt_FreeOutBufs(p); | ||
| 226 | |||
| 227 | #endif | ||
| 228 | |||
| 229 | ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp); | ||
| 230 | } | ||
| 231 | |||
| 232 | |||
| 233 | |||
| 234 | #ifndef _7ZIP_ST | ||
| 235 | |||
| 236 | static void Lzma2DecMt_MtCallback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) | ||
| 237 | { | ||
| 238 | CLzma2DecMt *me = (CLzma2DecMt *)obj; | ||
| 239 | CLzma2DecMtThread *t = &me->coders[coderIndex]; | ||
| 240 | |||
| 241 | PRF_STR_INT_2("Parse", coderIndex, cc->srcSize); | ||
| 242 | |||
| 243 | cc->state = MTDEC_PARSE_CONTINUE; | ||
| 244 | |||
| 245 | if (cc->startCall) | ||
| 246 | { | ||
| 247 | if (!t->dec_created) | ||
| 248 | { | ||
| 249 | Lzma2Dec_Construct(&t->dec); | ||
| 250 | t->dec_created = True; | ||
| 251 | AlignOffsetAlloc_CreateVTable(&t->alloc); | ||
| 252 | { | ||
| 253 | /* (1 << 12) is expected size of one way in data cache. | ||
| 254 | We optimize alignment for cache line size of 128 bytes and smaller */ | ||
| 255 | const unsigned kNumAlignBits = 12; | ||
| 256 | const unsigned kNumCacheLineBits = 7; /* <= kNumAlignBits */ | ||
| 257 | t->alloc.numAlignBits = kNumAlignBits; | ||
| 258 | t->alloc.offset = ((UInt32)coderIndex * (((unsigned)1 << 11) + (1 << 8) + (1 << 6))) & (((unsigned)1 << kNumAlignBits) - ((unsigned)1 << kNumCacheLineBits)); | ||
| 259 | t->alloc.baseAlloc = me->alignOffsetAlloc.baseAlloc; | ||
| 260 | } | ||
| 261 | } | ||
| 262 | Lzma2Dec_Init(&t->dec); | ||
| 263 | |||
| 264 | t->inPreSize = 0; | ||
| 265 | t->outPreSize = 0; | ||
| 266 | // t->blockWasFinished = False; | ||
| 267 | // t->finishedWithMark = False; | ||
| 268 | t->parseStatus = (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; | ||
| 269 | t->state = MTDEC_PARSE_CONTINUE; | ||
| 270 | |||
| 271 | t->inCodeSize = 0; | ||
| 272 | t->outCodeSize = 0; | ||
| 273 | t->codeRes = SZ_OK; | ||
| 274 | |||
| 275 | // (cc->srcSize == 0) is allowed | ||
| 276 | } | ||
| 277 | |||
| 278 | { | ||
| 279 | ELzma2ParseStatus status; | ||
| 280 | BoolInt overflow; | ||
| 281 | UInt32 unpackRem = 0; | ||
| 282 | |||
| 283 | int checkFinishBlock = True; | ||
| 284 | size_t limit = me->props.outBlockMax; | ||
| 285 | if (me->outSize_Defined) | ||
| 286 | { | ||
| 287 | UInt64 rem = me->outSize - me->outProcessed_Parse; | ||
| 288 | if (limit >= rem) | ||
| 289 | { | ||
| 290 | limit = (size_t)rem; | ||
| 291 | if (!me->finishMode) | ||
| 292 | checkFinishBlock = False; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | // checkFinishBlock = False, if we want to decode partial data | ||
| 297 | // that must be finished at position <= outBlockMax. | ||
| 298 | |||
| 299 | { | ||
| 300 | const SizeT srcOrig = cc->srcSize; | ||
| 301 | SizeT srcSize_Point = 0; | ||
| 302 | SizeT dicPos_Point = 0; | ||
| 303 | |||
| 304 | cc->srcSize = 0; | ||
| 305 | overflow = False; | ||
| 306 | |||
| 307 | for (;;) | ||
| 308 | { | ||
| 309 | SizeT srcCur = srcOrig - cc->srcSize; | ||
| 310 | |||
| 311 | status = Lzma2Dec_Parse(&t->dec, | ||
| 312 | limit - t->dec.decoder.dicPos, | ||
| 313 | cc->src + cc->srcSize, &srcCur, | ||
| 314 | checkFinishBlock); | ||
| 315 | |||
| 316 | cc->srcSize += srcCur; | ||
| 317 | |||
| 318 | if (status == LZMA2_PARSE_STATUS_NEW_CHUNK) | ||
| 319 | { | ||
| 320 | if (t->dec.unpackSize > me->props.outBlockMax - t->dec.decoder.dicPos) | ||
| 321 | { | ||
| 322 | overflow = True; | ||
| 323 | break; | ||
| 324 | } | ||
| 325 | continue; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) | ||
| 329 | { | ||
| 330 | if (t->dec.decoder.dicPos == 0) | ||
| 331 | continue; | ||
| 332 | // we decode small blocks in one thread | ||
| 333 | if (t->dec.decoder.dicPos >= (1 << 14)) | ||
| 334 | break; | ||
| 335 | dicPos_Point = t->dec.decoder.dicPos; | ||
| 336 | srcSize_Point = cc->srcSize; | ||
| 337 | continue; | ||
| 338 | } | ||
| 339 | |||
| 340 | if ((int)status == LZMA_STATUS_NOT_FINISHED && checkFinishBlock | ||
| 341 | // && limit == t->dec.decoder.dicPos | ||
| 342 | // && limit == me->props.outBlockMax | ||
| 343 | ) | ||
| 344 | { | ||
| 345 | overflow = True; | ||
| 346 | break; | ||
| 347 | } | ||
| 348 | |||
| 349 | unpackRem = Lzma2Dec_GetUnpackExtra(&t->dec); | ||
| 350 | break; | ||
| 351 | } | ||
| 352 | |||
| 353 | if (dicPos_Point != 0 | ||
| 354 | && (int)status != LZMA2_PARSE_STATUS_NEW_BLOCK | ||
| 355 | && (int)status != LZMA_STATUS_FINISHED_WITH_MARK | ||
| 356 | && (int)status != LZMA_STATUS_NOT_SPECIFIED) | ||
| 357 | { | ||
| 358 | // we revert to latest newBlock state | ||
| 359 | status = LZMA2_PARSE_STATUS_NEW_BLOCK; | ||
| 360 | unpackRem = 0; | ||
| 361 | t->dec.decoder.dicPos = dicPos_Point; | ||
| 362 | cc->srcSize = srcSize_Point; | ||
| 363 | overflow = False; | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | t->inPreSize += cc->srcSize; | ||
| 368 | t->parseStatus = status; | ||
| 369 | |||
| 370 | if (overflow) | ||
| 371 | cc->state = MTDEC_PARSE_OVERFLOW; | ||
| 372 | else | ||
| 373 | { | ||
| 374 | size_t dicPos = t->dec.decoder.dicPos; | ||
| 375 | |||
| 376 | if ((int)status != LZMA_STATUS_NEEDS_MORE_INPUT) | ||
| 377 | { | ||
| 378 | if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) | ||
| 379 | { | ||
| 380 | cc->state = MTDEC_PARSE_NEW; | ||
| 381 | cc->srcSize--; // we don't need control byte of next block | ||
| 382 | t->inPreSize--; | ||
| 383 | } | ||
| 384 | else | ||
| 385 | { | ||
| 386 | cc->state = MTDEC_PARSE_END; | ||
| 387 | if ((int)status != LZMA_STATUS_FINISHED_WITH_MARK) | ||
| 388 | { | ||
| 389 | // (status == LZMA_STATUS_NOT_SPECIFIED) | ||
| 390 | // (status == LZMA_STATUS_NOT_FINISHED) | ||
| 391 | if (unpackRem != 0) | ||
| 392 | { | ||
| 393 | /* we also reserve space for max possible number of output bytes of current LZMA chunk */ | ||
| 394 | SizeT rem = limit - dicPos; | ||
| 395 | if (rem > unpackRem) | ||
| 396 | rem = unpackRem; | ||
| 397 | dicPos += rem; | ||
| 398 | } | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | me->outProcessed_Parse += dicPos; | ||
| 403 | } | ||
| 404 | |||
| 405 | cc->outPos = dicPos; | ||
| 406 | t->outPreSize = (size_t)dicPos; | ||
| 407 | } | ||
| 408 | |||
| 409 | t->state = cc->state; | ||
| 410 | return; | ||
| 411 | } | ||
| 412 | } | ||
| 413 | |||
| 414 | |||
| 415 | static SRes Lzma2DecMt_MtCallback_PreCode(void *pp, unsigned coderIndex) | ||
| 416 | { | ||
| 417 | CLzma2DecMt *me = (CLzma2DecMt *)pp; | ||
| 418 | CLzma2DecMtThread *t = &me->coders[coderIndex]; | ||
| 419 | Byte *dest = t->outBuf; | ||
| 420 | |||
| 421 | if (t->inPreSize == 0) | ||
| 422 | { | ||
| 423 | t->codeRes = SZ_ERROR_DATA; | ||
| 424 | return t->codeRes; | ||
| 425 | } | ||
| 426 | |||
| 427 | if (!dest || t->outBufSize < t->outPreSize) | ||
| 428 | { | ||
| 429 | if (dest) | ||
| 430 | { | ||
| 431 | ISzAlloc_Free(me->allocMid, dest); | ||
| 432 | t->outBuf = NULL; | ||
| 433 | t->outBufSize = 0; | ||
| 434 | } | ||
| 435 | |||
| 436 | dest = (Byte *)ISzAlloc_Alloc(me->allocMid, t->outPreSize | ||
| 437 | // + (1 << 28) | ||
| 438 | ); | ||
| 439 | // Sleep(200); | ||
| 440 | if (!dest) | ||
| 441 | return SZ_ERROR_MEM; | ||
| 442 | t->outBuf = dest; | ||
| 443 | t->outBufSize = t->outPreSize; | ||
| 444 | } | ||
| 445 | |||
| 446 | t->dec.decoder.dic = dest; | ||
| 447 | t->dec.decoder.dicBufSize = t->outPreSize; | ||
| 448 | |||
| 449 | t->needInit = True; | ||
| 450 | |||
| 451 | return Lzma2Dec_AllocateProbs(&t->dec, me->prop, &t->alloc.vt); // alloc.vt | ||
| 452 | } | ||
| 453 | |||
| 454 | |||
| 455 | static SRes Lzma2DecMt_MtCallback_Code(void *pp, unsigned coderIndex, | ||
| 456 | const Byte *src, size_t srcSize, int srcFinished, | ||
| 457 | // int finished, int blockFinished, | ||
| 458 | UInt64 *inCodePos, UInt64 *outCodePos, int *stop) | ||
| 459 | { | ||
| 460 | CLzma2DecMt *me = (CLzma2DecMt *)pp; | ||
| 461 | CLzma2DecMtThread *t = &me->coders[coderIndex]; | ||
| 462 | |||
| 463 | UNUSED_VAR(srcFinished) | ||
| 464 | |||
| 465 | PRF_STR_INT_2("Code", coderIndex, srcSize); | ||
| 466 | |||
| 467 | *inCodePos = t->inCodeSize; | ||
| 468 | *outCodePos = 0; | ||
| 469 | *stop = True; | ||
| 470 | |||
| 471 | if (t->needInit) | ||
| 472 | { | ||
| 473 | Lzma2Dec_Init(&t->dec); | ||
| 474 | t->needInit = False; | ||
| 475 | } | ||
| 476 | |||
| 477 | { | ||
| 478 | ELzmaStatus status; | ||
| 479 | size_t srcProcessed = srcSize; | ||
| 480 | BoolInt blockWasFinished = | ||
| 481 | ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK | ||
| 482 | || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK); | ||
| 483 | |||
| 484 | SRes res = Lzma2Dec_DecodeToDic(&t->dec, | ||
| 485 | t->outPreSize, | ||
| 486 | src, &srcProcessed, | ||
| 487 | blockWasFinished ? LZMA_FINISH_END : LZMA_FINISH_ANY, | ||
| 488 | &status); | ||
| 489 | |||
| 490 | t->codeRes = res; | ||
| 491 | |||
| 492 | t->inCodeSize += srcProcessed; | ||
| 493 | *inCodePos = t->inCodeSize; | ||
| 494 | t->outCodeSize = t->dec.decoder.dicPos; | ||
| 495 | *outCodePos = t->dec.decoder.dicPos; | ||
| 496 | |||
| 497 | if (res != SZ_OK) | ||
| 498 | return res; | ||
| 499 | |||
| 500 | if (srcProcessed == srcSize) | ||
| 501 | *stop = False; | ||
| 502 | |||
| 503 | if (blockWasFinished) | ||
| 504 | { | ||
| 505 | if (srcSize != srcProcessed) | ||
| 506 | return SZ_ERROR_FAIL; | ||
| 507 | |||
| 508 | if (t->inPreSize == t->inCodeSize) | ||
| 509 | { | ||
| 510 | if (t->outPreSize != t->outCodeSize) | ||
| 511 | return SZ_ERROR_FAIL; | ||
| 512 | *stop = True; | ||
| 513 | } | ||
| 514 | } | ||
| 515 | else | ||
| 516 | { | ||
| 517 | if (t->outPreSize == t->outCodeSize) | ||
| 518 | *stop = True; | ||
| 519 | } | ||
| 520 | |||
| 521 | return SZ_OK; | ||
| 522 | } | ||
| 523 | } | ||
| 524 | |||
| 525 | |||
| 526 | #define LZMA2DECMT_STREAM_WRITE_STEP (1 << 24) | ||
| 527 | |||
| 528 | static SRes Lzma2DecMt_MtCallback_Write(void *pp, unsigned coderIndex, | ||
| 529 | BoolInt needWriteToStream, | ||
| 530 | const Byte *src, size_t srcSize, BoolInt isCross, | ||
| 531 | BoolInt *needContinue, BoolInt *canRecode) | ||
| 532 | { | ||
| 533 | CLzma2DecMt *me = (CLzma2DecMt *)pp; | ||
| 534 | const CLzma2DecMtThread *t = &me->coders[coderIndex]; | ||
| 535 | size_t size = t->outCodeSize; | ||
| 536 | const Byte *data = t->outBuf; | ||
| 537 | BoolInt needContinue2 = True; | ||
| 538 | |||
| 539 | UNUSED_VAR(src) | ||
| 540 | UNUSED_VAR(srcSize) | ||
| 541 | UNUSED_VAR(isCross) | ||
| 542 | |||
| 543 | PRF_STR_INT_2("Write", coderIndex, srcSize); | ||
| 544 | |||
| 545 | *needContinue = False; | ||
| 546 | *canRecode = True; | ||
| 547 | |||
| 548 | if ( | ||
| 549 | // t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK | ||
| 550 | t->state == MTDEC_PARSE_OVERFLOW | ||
| 551 | || t->state == MTDEC_PARSE_END) | ||
| 552 | needContinue2 = False; | ||
| 553 | |||
| 554 | |||
| 555 | if (!needWriteToStream) | ||
| 556 | return SZ_OK; | ||
| 557 | |||
| 558 | me->mtc.inProcessed += t->inCodeSize; | ||
| 559 | |||
| 560 | if (t->codeRes == SZ_OK) | ||
| 561 | if ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK | ||
| 562 | || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK) | ||
| 563 | if (t->outPreSize != t->outCodeSize | ||
| 564 | || t->inPreSize != t->inCodeSize) | ||
| 565 | return SZ_ERROR_FAIL; | ||
| 566 | |||
| 567 | *canRecode = False; | ||
| 568 | |||
| 569 | if (me->outStream) | ||
| 570 | { | ||
| 571 | for (;;) | ||
| 572 | { | ||
| 573 | size_t cur = size; | ||
| 574 | size_t written; | ||
| 575 | if (cur > LZMA2DECMT_STREAM_WRITE_STEP) | ||
| 576 | cur = LZMA2DECMT_STREAM_WRITE_STEP; | ||
| 577 | |||
| 578 | written = ISeqOutStream_Write(me->outStream, data, cur); | ||
| 579 | |||
| 580 | me->outProcessed += written; | ||
| 581 | // me->mtc.writtenTotal += written; | ||
| 582 | if (written != cur) | ||
| 583 | return SZ_ERROR_WRITE; | ||
| 584 | data += cur; | ||
| 585 | size -= cur; | ||
| 586 | if (size == 0) | ||
| 587 | { | ||
| 588 | *needContinue = needContinue2; | ||
| 589 | return SZ_OK; | ||
| 590 | } | ||
| 591 | RINOK(MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0)); | ||
| 592 | } | ||
| 593 | } | ||
| 594 | |||
| 595 | return SZ_ERROR_FAIL; | ||
| 596 | /* | ||
| 597 | if (size > me->outBufSize) | ||
| 598 | return SZ_ERROR_OUTPUT_EOF; | ||
| 599 | memcpy(me->outBuf, data, size); | ||
| 600 | me->outBufSize -= size; | ||
| 601 | me->outBuf += size; | ||
| 602 | *needContinue = needContinue2; | ||
| 603 | return SZ_OK; | ||
| 604 | */ | ||
| 605 | } | ||
| 606 | |||
| 607 | #endif | ||
| 608 | |||
| 609 | |||
| 610 | static SRes Lzma2Dec_Prepare_ST(CLzma2DecMt *p) | ||
| 611 | { | ||
| 612 | if (!p->dec_created) | ||
| 613 | { | ||
| 614 | Lzma2Dec_Construct(&p->dec); | ||
| 615 | p->dec_created = True; | ||
| 616 | } | ||
| 617 | |||
| 618 | RINOK(Lzma2Dec_Allocate(&p->dec, p->prop, &p->alignOffsetAlloc.vt)); | ||
| 619 | |||
| 620 | if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) | ||
| 621 | { | ||
| 622 | ISzAlloc_Free(p->allocMid, p->inBuf); | ||
| 623 | p->inBufSize = 0; | ||
| 624 | p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); | ||
| 625 | if (!p->inBuf) | ||
| 626 | return SZ_ERROR_MEM; | ||
| 627 | p->inBufSize = p->props.inBufSize_ST; | ||
| 628 | } | ||
| 629 | |||
| 630 | Lzma2Dec_Init(&p->dec); | ||
| 631 | |||
| 632 | return SZ_OK; | ||
| 633 | } | ||
| 634 | |||
| 635 | |||
| 636 | static SRes Lzma2Dec_Decode_ST(CLzma2DecMt *p | ||
| 637 | #ifndef _7ZIP_ST | ||
| 638 | , BoolInt tMode | ||
| 639 | #endif | ||
| 640 | ) | ||
| 641 | { | ||
| 642 | SizeT wrPos; | ||
| 643 | size_t inPos, inLim; | ||
| 644 | const Byte *inData; | ||
| 645 | UInt64 inPrev, outPrev; | ||
| 646 | |||
| 647 | CLzma2Dec *dec; | ||
| 648 | |||
| 649 | #ifndef _7ZIP_ST | ||
| 650 | if (tMode) | ||
| 651 | { | ||
| 652 | Lzma2DecMt_FreeOutBufs(p); | ||
| 653 | tMode = MtDec_PrepareRead(&p->mtc); | ||
| 654 | } | ||
| 655 | #endif | ||
| 656 | |||
| 657 | RINOK(Lzma2Dec_Prepare_ST(p)); | ||
| 658 | |||
| 659 | dec = &p->dec; | ||
| 660 | |||
| 661 | inPrev = p->inProcessed; | ||
| 662 | outPrev = p->outProcessed; | ||
| 663 | |||
| 664 | inPos = 0; | ||
| 665 | inLim = 0; | ||
| 666 | inData = NULL; | ||
| 667 | wrPos = dec->decoder.dicPos; | ||
| 668 | |||
| 669 | for (;;) | ||
| 670 | { | ||
| 671 | SizeT dicPos; | ||
| 672 | SizeT size; | ||
| 673 | ELzmaFinishMode finishMode; | ||
| 674 | SizeT inProcessed; | ||
| 675 | ELzmaStatus status; | ||
| 676 | SRes res; | ||
| 677 | |||
| 678 | SizeT outProcessed; | ||
| 679 | BoolInt outFinished; | ||
| 680 | BoolInt needStop; | ||
| 681 | |||
| 682 | if (inPos == inLim) | ||
| 683 | { | ||
| 684 | #ifndef _7ZIP_ST | ||
| 685 | if (tMode) | ||
| 686 | { | ||
| 687 | inData = MtDec_Read(&p->mtc, &inLim); | ||
| 688 | inPos = 0; | ||
| 689 | if (inData) | ||
| 690 | continue; | ||
| 691 | tMode = False; | ||
| 692 | inLim = 0; | ||
| 693 | } | ||
| 694 | #endif | ||
| 695 | |||
| 696 | if (!p->readWasFinished) | ||
| 697 | { | ||
| 698 | inPos = 0; | ||
| 699 | inLim = p->inBufSize; | ||
| 700 | inData = p->inBuf; | ||
| 701 | p->readRes = ISeqInStream_Read(p->inStream, (void *)(p->inBuf), &inLim); | ||
| 702 | // p->readProcessed += inLim; | ||
| 703 | // inLim -= 5; p->readWasFinished = True; // for test | ||
| 704 | if (inLim == 0 || p->readRes != SZ_OK) | ||
| 705 | p->readWasFinished = True; | ||
| 706 | } | ||
| 707 | } | ||
| 708 | |||
| 709 | dicPos = dec->decoder.dicPos; | ||
| 710 | { | ||
| 711 | SizeT next = dec->decoder.dicBufSize; | ||
| 712 | if (next - wrPos > p->props.outStep_ST) | ||
| 713 | next = wrPos + p->props.outStep_ST; | ||
| 714 | size = next - dicPos; | ||
| 715 | } | ||
| 716 | |||
| 717 | finishMode = LZMA_FINISH_ANY; | ||
| 718 | if (p->outSize_Defined) | ||
| 719 | { | ||
| 720 | const UInt64 rem = p->outSize - p->outProcessed; | ||
| 721 | if (size >= rem) | ||
| 722 | { | ||
| 723 | size = (SizeT)rem; | ||
| 724 | if (p->finishMode) | ||
| 725 | finishMode = LZMA_FINISH_END; | ||
| 726 | } | ||
| 727 | } | ||
| 728 | |||
| 729 | inProcessed = inLim - inPos; | ||
| 730 | |||
| 731 | res = Lzma2Dec_DecodeToDic(dec, dicPos + size, inData + inPos, &inProcessed, finishMode, &status); | ||
| 732 | |||
| 733 | inPos += inProcessed; | ||
| 734 | p->inProcessed += inProcessed; | ||
| 735 | outProcessed = dec->decoder.dicPos - dicPos; | ||
| 736 | p->outProcessed += outProcessed; | ||
| 737 | |||
| 738 | outFinished = (p->outSize_Defined && p->outSize <= p->outProcessed); | ||
| 739 | |||
| 740 | needStop = (res != SZ_OK | ||
| 741 | || (inProcessed == 0 && outProcessed == 0) | ||
| 742 | || status == LZMA_STATUS_FINISHED_WITH_MARK | ||
| 743 | || (!p->finishMode && outFinished)); | ||
| 744 | |||
| 745 | if (needStop || outProcessed >= size) | ||
| 746 | { | ||
| 747 | SRes res2; | ||
| 748 | { | ||
| 749 | size_t writeSize = dec->decoder.dicPos - wrPos; | ||
| 750 | size_t written = ISeqOutStream_Write(p->outStream, dec->decoder.dic + wrPos, writeSize); | ||
| 751 | res2 = (written == writeSize) ? SZ_OK : SZ_ERROR_WRITE; | ||
| 752 | } | ||
| 753 | |||
| 754 | if (dec->decoder.dicPos == dec->decoder.dicBufSize) | ||
| 755 | dec->decoder.dicPos = 0; | ||
| 756 | wrPos = dec->decoder.dicPos; | ||
| 757 | |||
| 758 | RINOK(res2); | ||
| 759 | |||
| 760 | if (needStop) | ||
| 761 | { | ||
| 762 | if (res != SZ_OK) | ||
| 763 | return res; | ||
| 764 | |||
| 765 | if (status == LZMA_STATUS_FINISHED_WITH_MARK) | ||
| 766 | { | ||
| 767 | if (p->finishMode) | ||
| 768 | { | ||
| 769 | if (p->outSize_Defined && p->outSize != p->outProcessed) | ||
| 770 | return SZ_ERROR_DATA; | ||
| 771 | } | ||
| 772 | return SZ_OK; | ||
| 773 | } | ||
| 774 | |||
| 775 | if (!p->finishMode && outFinished) | ||
| 776 | return SZ_OK; | ||
| 777 | |||
| 778 | if (status == LZMA_STATUS_NEEDS_MORE_INPUT) | ||
| 779 | return SZ_ERROR_INPUT_EOF; | ||
| 780 | |||
| 781 | return SZ_ERROR_DATA; | ||
| 782 | } | ||
| 783 | } | ||
| 784 | |||
| 785 | if (p->progress) | ||
| 786 | { | ||
| 787 | UInt64 inDelta = p->inProcessed - inPrev; | ||
| 788 | UInt64 outDelta = p->outProcessed - outPrev; | ||
| 789 | if (inDelta >= (1 << 22) || outDelta >= (1 << 22)) | ||
| 790 | { | ||
| 791 | RINOK(ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed)); | ||
| 792 | inPrev = p->inProcessed; | ||
| 793 | outPrev = p->outProcessed; | ||
| 794 | } | ||
| 795 | } | ||
| 796 | } | ||
| 797 | } | ||
| 798 | |||
| 799 | |||
| 800 | |||
| 801 | SRes Lzma2DecMt_Decode(CLzma2DecMtHandle pp, | ||
| 802 | Byte prop, | ||
| 803 | const CLzma2DecMtProps *props, | ||
| 804 | ISeqOutStream *outStream, const UInt64 *outDataSize, int finishMode, | ||
| 805 | // Byte *outBuf, size_t *outBufSize, | ||
| 806 | ISeqInStream *inStream, | ||
| 807 | // const Byte *inData, size_t inDataSize, | ||
| 808 | UInt64 *inProcessed, | ||
| 809 | // UInt64 *outProcessed, | ||
| 810 | int *isMT, | ||
| 811 | ICompressProgress *progress) | ||
| 812 | { | ||
| 813 | CLzma2DecMt *p = (CLzma2DecMt *)pp; | ||
| 814 | #ifndef _7ZIP_ST | ||
| 815 | BoolInt tMode; | ||
| 816 | #endif | ||
| 817 | |||
| 818 | *inProcessed = 0; | ||
| 819 | |||
| 820 | if (prop > 40) | ||
| 821 | return SZ_ERROR_UNSUPPORTED; | ||
| 822 | |||
| 823 | p->prop = prop; | ||
| 824 | p->props = *props; | ||
| 825 | |||
| 826 | p->inStream = inStream; | ||
| 827 | p->outStream = outStream; | ||
| 828 | p->progress = progress; | ||
| 829 | |||
| 830 | p->outSize = 0; | ||
| 831 | p->outSize_Defined = False; | ||
| 832 | if (outDataSize) | ||
| 833 | { | ||
| 834 | p->outSize_Defined = True; | ||
| 835 | p->outSize = *outDataSize; | ||
| 836 | } | ||
| 837 | p->finishMode = finishMode; | ||
| 838 | |||
| 839 | p->outProcessed = 0; | ||
| 840 | p->inProcessed = 0; | ||
| 841 | |||
| 842 | p->readWasFinished = False; | ||
| 843 | p->readRes = SZ_OK; | ||
| 844 | |||
| 845 | *isMT = False; | ||
| 846 | |||
| 847 | |||
| 848 | #ifndef _7ZIP_ST | ||
| 849 | |||
| 850 | tMode = False; | ||
| 851 | |||
| 852 | // p->mtc.parseRes = SZ_OK; | ||
| 853 | |||
| 854 | // p->mtc.numFilledThreads = 0; | ||
| 855 | // p->mtc.crossStart = 0; | ||
| 856 | // p->mtc.crossEnd = 0; | ||
| 857 | // p->mtc.allocError_for_Read_BlockIndex = 0; | ||
| 858 | // p->mtc.isAllocError = False; | ||
| 859 | |||
| 860 | if (p->props.numThreads > 1) | ||
| 861 | { | ||
| 862 | IMtDecCallback2 vt; | ||
| 863 | |||
| 864 | Lzma2DecMt_FreeSt(p); | ||
| 865 | |||
| 866 | p->outProcessed_Parse = 0; | ||
| 867 | |||
| 868 | if (!p->mtc_WasConstructed) | ||
| 869 | { | ||
| 870 | p->mtc_WasConstructed = True; | ||
| 871 | MtDec_Construct(&p->mtc); | ||
| 872 | } | ||
| 873 | |||
| 874 | p->mtc.progress = progress; | ||
| 875 | p->mtc.inStream = inStream; | ||
| 876 | |||
| 877 | // p->outBuf = NULL; | ||
| 878 | // p->outBufSize = 0; | ||
| 879 | /* | ||
| 880 | if (!outStream) | ||
| 881 | { | ||
| 882 | // p->outBuf = outBuf; | ||
| 883 | // p->outBufSize = *outBufSize; | ||
| 884 | // *outBufSize = 0; | ||
| 885 | return SZ_ERROR_PARAM; | ||
| 886 | } | ||
| 887 | */ | ||
| 888 | |||
| 889 | // p->mtc.inBlockMax = p->props.inBlockMax; | ||
| 890 | p->mtc.alloc = &p->alignOffsetAlloc.vt; | ||
| 891 | // p->alignOffsetAlloc.baseAlloc; | ||
| 892 | // p->mtc.inData = inData; | ||
| 893 | // p->mtc.inDataSize = inDataSize; | ||
| 894 | p->mtc.mtCallback = &vt; | ||
| 895 | p->mtc.mtCallbackObject = p; | ||
| 896 | |||
| 897 | p->mtc.inBufSize = p->props.inBufSize_MT; | ||
| 898 | |||
| 899 | p->mtc.numThreadsMax = p->props.numThreads; | ||
| 900 | |||
| 901 | *isMT = True; | ||
| 902 | |||
| 903 | vt.Parse = Lzma2DecMt_MtCallback_Parse; | ||
| 904 | vt.PreCode = Lzma2DecMt_MtCallback_PreCode; | ||
| 905 | vt.Code = Lzma2DecMt_MtCallback_Code; | ||
| 906 | vt.Write = Lzma2DecMt_MtCallback_Write; | ||
| 907 | |||
| 908 | { | ||
| 909 | BoolInt needContinue = False; | ||
| 910 | |||
| 911 | SRes res = MtDec_Code(&p->mtc); | ||
| 912 | |||
| 913 | /* | ||
| 914 | if (!outStream) | ||
| 915 | *outBufSize = p->outBuf - outBuf; | ||
| 916 | */ | ||
| 917 | |||
| 918 | *inProcessed = p->mtc.inProcessed; | ||
| 919 | |||
| 920 | needContinue = False; | ||
| 921 | |||
| 922 | if (res == SZ_OK) | ||
| 923 | { | ||
| 924 | if (p->mtc.mtProgress.res != SZ_OK) | ||
| 925 | res = p->mtc.mtProgress.res; | ||
| 926 | else | ||
| 927 | needContinue = p->mtc.needContinue; | ||
| 928 | } | ||
| 929 | |||
| 930 | if (!needContinue) | ||
| 931 | { | ||
| 932 | if (res == SZ_OK) | ||
| 933 | return p->mtc.readRes; | ||
| 934 | return res; | ||
| 935 | } | ||
| 936 | |||
| 937 | tMode = True; | ||
| 938 | p->readRes = p->mtc.readRes; | ||
| 939 | p->readWasFinished = p->mtc.readWasFinished; | ||
| 940 | p->inProcessed = p->mtc.inProcessed; | ||
| 941 | |||
| 942 | PRF_STR("----- decoding ST -----"); | ||
| 943 | } | ||
| 944 | } | ||
| 945 | |||
| 946 | #endif | ||
| 947 | |||
| 948 | |||
| 949 | *isMT = False; | ||
| 950 | |||
| 951 | { | ||
| 952 | SRes res = Lzma2Dec_Decode_ST(p | ||
| 953 | #ifndef _7ZIP_ST | ||
| 954 | , tMode | ||
| 955 | #endif | ||
| 956 | ); | ||
| 957 | |||
| 958 | *inProcessed = p->inProcessed; | ||
| 959 | |||
| 960 | // res = SZ_OK; // for test | ||
| 961 | if (res == SZ_ERROR_INPUT_EOF) | ||
| 962 | { | ||
| 963 | if (p->readRes != SZ_OK) | ||
| 964 | res = p->readRes; | ||
| 965 | } | ||
| 966 | else if (res == SZ_OK && p->readRes != SZ_OK) | ||
| 967 | res = p->readRes; | ||
| 968 | |||
| 969 | /* | ||
| 970 | #ifndef _7ZIP_ST | ||
| 971 | if (res == SZ_OK && tMode && p->mtc.parseRes != SZ_OK) | ||
| 972 | res = p->mtc.parseRes; | ||
| 973 | #endif | ||
| 974 | */ | ||
| 975 | |||
| 976 | return res; | ||
| 977 | } | ||
| 978 | } | ||
| 979 | |||
| 980 | |||
| 981 | /* ---------- Read from CLzma2DecMtHandle Interface ---------- */ | ||
| 982 | |||
| 983 | SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp, | ||
| 984 | Byte prop, | ||
| 985 | const CLzma2DecMtProps *props, | ||
| 986 | const UInt64 *outDataSize, int finishMode, | ||
| 987 | ISeqInStream *inStream) | ||
| 988 | { | ||
| 989 | CLzma2DecMt *p = (CLzma2DecMt *)pp; | ||
| 990 | |||
| 991 | if (prop > 40) | ||
| 992 | return SZ_ERROR_UNSUPPORTED; | ||
| 993 | |||
| 994 | p->prop = prop; | ||
| 995 | p->props = *props; | ||
| 996 | |||
| 997 | p->inStream = inStream; | ||
| 998 | |||
| 999 | p->outSize = 0; | ||
| 1000 | p->outSize_Defined = False; | ||
| 1001 | if (outDataSize) | ||
| 1002 | { | ||
| 1003 | p->outSize_Defined = True; | ||
| 1004 | p->outSize = *outDataSize; | ||
| 1005 | } | ||
| 1006 | p->finishMode = finishMode; | ||
| 1007 | |||
| 1008 | p->outProcessed = 0; | ||
| 1009 | p->inProcessed = 0; | ||
| 1010 | |||
| 1011 | p->inPos = 0; | ||
| 1012 | p->inLim = 0; | ||
| 1013 | |||
| 1014 | return Lzma2Dec_Prepare_ST(p); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | |||
| 1018 | SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp, | ||
| 1019 | Byte *data, size_t *outSize, | ||
| 1020 | UInt64 *inStreamProcessed) | ||
| 1021 | { | ||
| 1022 | CLzma2DecMt *p = (CLzma2DecMt *)pp; | ||
| 1023 | ELzmaFinishMode finishMode; | ||
| 1024 | SRes readRes; | ||
| 1025 | size_t size = *outSize; | ||
| 1026 | |||
| 1027 | *outSize = 0; | ||
| 1028 | *inStreamProcessed = 0; | ||
| 1029 | |||
| 1030 | finishMode = LZMA_FINISH_ANY; | ||
| 1031 | if (p->outSize_Defined) | ||
| 1032 | { | ||
| 1033 | const UInt64 rem = p->outSize - p->outProcessed; | ||
| 1034 | if (size >= rem) | ||
| 1035 | { | ||
| 1036 | size = (size_t)rem; | ||
| 1037 | if (p->finishMode) | ||
| 1038 | finishMode = LZMA_FINISH_END; | ||
| 1039 | } | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | readRes = SZ_OK; | ||
| 1043 | |||
| 1044 | for (;;) | ||
| 1045 | { | ||
| 1046 | SizeT inCur; | ||
| 1047 | SizeT outCur; | ||
| 1048 | ELzmaStatus status; | ||
| 1049 | SRes res; | ||
| 1050 | |||
| 1051 | if (p->inPos == p->inLim && readRes == SZ_OK) | ||
| 1052 | { | ||
| 1053 | p->inPos = 0; | ||
| 1054 | p->inLim = p->props.inBufSize_ST; | ||
| 1055 | readRes = ISeqInStream_Read(p->inStream, p->inBuf, &p->inLim); | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | inCur = p->inLim - p->inPos; | ||
| 1059 | outCur = size; | ||
| 1060 | |||
| 1061 | res = Lzma2Dec_DecodeToBuf(&p->dec, data, &outCur, | ||
| 1062 | p->inBuf + p->inPos, &inCur, finishMode, &status); | ||
| 1063 | |||
| 1064 | p->inPos += inCur; | ||
| 1065 | p->inProcessed += inCur; | ||
| 1066 | *inStreamProcessed += inCur; | ||
| 1067 | p->outProcessed += outCur; | ||
| 1068 | *outSize += outCur; | ||
| 1069 | size -= outCur; | ||
| 1070 | data += outCur; | ||
| 1071 | |||
| 1072 | if (res != 0) | ||
| 1073 | return res; | ||
| 1074 | |||
| 1075 | /* | ||
| 1076 | if (status == LZMA_STATUS_FINISHED_WITH_MARK) | ||
| 1077 | return readRes; | ||
| 1078 | |||
| 1079 | if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT) | ||
| 1080 | { | ||
| 1081 | if (p->finishMode && p->outSize_Defined && p->outProcessed >= p->outSize) | ||
| 1082 | return SZ_ERROR_DATA; | ||
| 1083 | return readRes; | ||
| 1084 | } | ||
| 1085 | */ | ||
| 1086 | |||
| 1087 | if (inCur == 0 && outCur == 0) | ||
| 1088 | return readRes; | ||
| 1089 | } | ||
| 1090 | } | ||
diff --git a/C/Lzma2DecMt.h b/C/Lzma2DecMt.h new file mode 100644 index 0000000..7791c31 --- /dev/null +++ b/C/Lzma2DecMt.h | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | /* Lzma2DecMt.h -- LZMA2 Decoder Multi-thread | ||
| 2 | 2018-02-17 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __LZMA2_DEC_MT_H | ||
| 5 | #define __LZMA2_DEC_MT_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | typedef struct | ||
| 12 | { | ||
| 13 | size_t inBufSize_ST; | ||
| 14 | size_t outStep_ST; | ||
| 15 | |||
| 16 | #ifndef _7ZIP_ST | ||
| 17 | unsigned numThreads; | ||
| 18 | size_t inBufSize_MT; | ||
| 19 | size_t outBlockMax; | ||
| 20 | size_t inBlockMax; | ||
| 21 | #endif | ||
| 22 | } CLzma2DecMtProps; | ||
| 23 | |||
| 24 | /* init to single-thread mode */ | ||
| 25 | void Lzma2DecMtProps_Init(CLzma2DecMtProps *p); | ||
| 26 | |||
| 27 | |||
| 28 | /* ---------- CLzma2DecMtHandle Interface ---------- */ | ||
| 29 | |||
| 30 | /* Lzma2DecMt_ * functions can return the following exit codes: | ||
| 31 | SRes: | ||
| 32 | SZ_OK - OK | ||
| 33 | SZ_ERROR_MEM - Memory allocation error | ||
| 34 | SZ_ERROR_PARAM - Incorrect paramater in props | ||
| 35 | SZ_ERROR_WRITE - ISeqOutStream write callback error | ||
| 36 | // SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output | ||
| 37 | SZ_ERROR_PROGRESS - some break from progress callback | ||
| 38 | SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) | ||
| 39 | */ | ||
| 40 | |||
| 41 | typedef void * CLzma2DecMtHandle; | ||
| 42 | |||
| 43 | CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); | ||
| 44 | void Lzma2DecMt_Destroy(CLzma2DecMtHandle p); | ||
| 45 | |||
| 46 | SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p, | ||
| 47 | Byte prop, | ||
| 48 | const CLzma2DecMtProps *props, | ||
| 49 | ISeqOutStream *outStream, | ||
| 50 | const UInt64 *outDataSize, // NULL means undefined | ||
| 51 | int finishMode, // 0 - partial unpacking is allowed, 1 - if lzma2 stream must be finished | ||
| 52 | // Byte *outBuf, size_t *outBufSize, | ||
| 53 | ISeqInStream *inStream, | ||
| 54 | // const Byte *inData, size_t inDataSize, | ||
| 55 | |||
| 56 | // out variables: | ||
| 57 | UInt64 *inProcessed, | ||
| 58 | int *isMT, /* out: (*isMT == 0), if single thread decoding was used */ | ||
| 59 | |||
| 60 | // UInt64 *outProcessed, | ||
| 61 | ICompressProgress *progress); | ||
| 62 | |||
| 63 | |||
| 64 | /* ---------- Read from CLzma2DecMtHandle Interface ---------- */ | ||
| 65 | |||
| 66 | SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp, | ||
| 67 | Byte prop, | ||
| 68 | const CLzma2DecMtProps *props, | ||
| 69 | const UInt64 *outDataSize, int finishMode, | ||
| 70 | ISeqInStream *inStream); | ||
| 71 | |||
| 72 | SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp, | ||
| 73 | Byte *data, size_t *outSize, | ||
| 74 | UInt64 *inStreamProcessed); | ||
| 75 | |||
| 76 | |||
| 77 | EXTERN_C_END | ||
| 78 | |||
| 79 | #endif | ||
diff --git a/C/Lzma2Enc.c b/C/Lzma2Enc.c new file mode 100644 index 0000000..e61a5df --- /dev/null +++ b/C/Lzma2Enc.c | |||
| @@ -0,0 +1,803 @@ | |||
| 1 | /* Lzma2Enc.c -- LZMA2 Encoder | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | /* #define _7ZIP_ST */ | ||
| 9 | |||
| 10 | #include "Lzma2Enc.h" | ||
| 11 | |||
| 12 | #ifndef _7ZIP_ST | ||
| 13 | #include "MtCoder.h" | ||
| 14 | #else | ||
| 15 | #define MTCODER__THREADS_MAX 1 | ||
| 16 | #endif | ||
| 17 | |||
| 18 | #define LZMA2_CONTROL_LZMA (1 << 7) | ||
| 19 | #define LZMA2_CONTROL_COPY_NO_RESET 2 | ||
| 20 | #define LZMA2_CONTROL_COPY_RESET_DIC 1 | ||
| 21 | #define LZMA2_CONTROL_EOF 0 | ||
| 22 | |||
| 23 | #define LZMA2_LCLP_MAX 4 | ||
| 24 | |||
| 25 | #define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) | ||
| 26 | |||
| 27 | #define LZMA2_PACK_SIZE_MAX (1 << 16) | ||
| 28 | #define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX | ||
| 29 | #define LZMA2_UNPACK_SIZE_MAX (1 << 21) | ||
| 30 | #define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX | ||
| 31 | |||
| 32 | #define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) | ||
| 33 | |||
| 34 | |||
| 35 | #define PRF(x) /* x */ | ||
| 36 | |||
| 37 | |||
| 38 | /* ---------- CLimitedSeqInStream ---------- */ | ||
| 39 | |||
| 40 | typedef struct | ||
| 41 | { | ||
| 42 | ISeqInStream vt; | ||
| 43 | ISeqInStream *realStream; | ||
| 44 | UInt64 limit; | ||
| 45 | UInt64 processed; | ||
| 46 | int finished; | ||
| 47 | } CLimitedSeqInStream; | ||
| 48 | |||
| 49 | static void LimitedSeqInStream_Init(CLimitedSeqInStream *p) | ||
| 50 | { | ||
| 51 | p->limit = (UInt64)(Int64)-1; | ||
| 52 | p->processed = 0; | ||
| 53 | p->finished = 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | static SRes LimitedSeqInStream_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
| 57 | { | ||
| 58 | CLimitedSeqInStream *p = CONTAINER_FROM_VTBL(pp, CLimitedSeqInStream, vt); | ||
| 59 | size_t size2 = *size; | ||
| 60 | SRes res = SZ_OK; | ||
| 61 | |||
| 62 | if (p->limit != (UInt64)(Int64)-1) | ||
| 63 | { | ||
| 64 | UInt64 rem = p->limit - p->processed; | ||
| 65 | if (size2 > rem) | ||
| 66 | size2 = (size_t)rem; | ||
| 67 | } | ||
| 68 | if (size2 != 0) | ||
| 69 | { | ||
| 70 | res = ISeqInStream_Read(p->realStream, data, &size2); | ||
| 71 | p->finished = (size2 == 0 ? 1 : 0); | ||
| 72 | p->processed += size2; | ||
| 73 | } | ||
| 74 | *size = size2; | ||
| 75 | return res; | ||
| 76 | } | ||
| 77 | |||
| 78 | |||
| 79 | /* ---------- CLzma2EncInt ---------- */ | ||
| 80 | |||
| 81 | typedef struct | ||
| 82 | { | ||
| 83 | CLzmaEncHandle enc; | ||
| 84 | Byte propsAreSet; | ||
| 85 | Byte propsByte; | ||
| 86 | Byte needInitState; | ||
| 87 | Byte needInitProp; | ||
| 88 | UInt64 srcPos; | ||
| 89 | } CLzma2EncInt; | ||
| 90 | |||
| 91 | |||
| 92 | static SRes Lzma2EncInt_InitStream(CLzma2EncInt *p, const CLzma2EncProps *props) | ||
| 93 | { | ||
| 94 | if (!p->propsAreSet) | ||
| 95 | { | ||
| 96 | SizeT propsSize = LZMA_PROPS_SIZE; | ||
| 97 | Byte propsEncoded[LZMA_PROPS_SIZE]; | ||
| 98 | RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)); | ||
| 99 | RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)); | ||
| 100 | p->propsByte = propsEncoded[0]; | ||
| 101 | p->propsAreSet = True; | ||
| 102 | } | ||
| 103 | return SZ_OK; | ||
| 104 | } | ||
| 105 | |||
| 106 | static void Lzma2EncInt_InitBlock(CLzma2EncInt *p) | ||
| 107 | { | ||
| 108 | p->srcPos = 0; | ||
| 109 | p->needInitState = True; | ||
| 110 | p->needInitProp = True; | ||
| 111 | } | ||
| 112 | |||
| 113 | |||
| 114 | SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, | ||
| 115 | ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
| 116 | SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, | ||
| 117 | UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
| 118 | SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, | ||
| 119 | Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); | ||
| 120 | const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp); | ||
| 121 | void LzmaEnc_Finish(CLzmaEncHandle pp); | ||
| 122 | void LzmaEnc_SaveState(CLzmaEncHandle pp); | ||
| 123 | void LzmaEnc_RestoreState(CLzmaEncHandle pp); | ||
| 124 | |||
| 125 | /* | ||
| 126 | UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp); | ||
| 127 | */ | ||
| 128 | |||
| 129 | static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, | ||
| 130 | size_t *packSizeRes, ISeqOutStream *outStream) | ||
| 131 | { | ||
| 132 | size_t packSizeLimit = *packSizeRes; | ||
| 133 | size_t packSize = packSizeLimit; | ||
| 134 | UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; | ||
| 135 | unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); | ||
| 136 | BoolInt useCopyBlock; | ||
| 137 | SRes res; | ||
| 138 | |||
| 139 | *packSizeRes = 0; | ||
| 140 | if (packSize < lzHeaderSize) | ||
| 141 | return SZ_ERROR_OUTPUT_EOF; | ||
| 142 | packSize -= lzHeaderSize; | ||
| 143 | |||
| 144 | LzmaEnc_SaveState(p->enc); | ||
| 145 | res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, | ||
| 146 | outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); | ||
| 147 | |||
| 148 | PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); | ||
| 149 | |||
| 150 | if (unpackSize == 0) | ||
| 151 | return res; | ||
| 152 | |||
| 153 | if (res == SZ_OK) | ||
| 154 | useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); | ||
| 155 | else | ||
| 156 | { | ||
| 157 | if (res != SZ_ERROR_OUTPUT_EOF) | ||
| 158 | return res; | ||
| 159 | res = SZ_OK; | ||
| 160 | useCopyBlock = True; | ||
| 161 | } | ||
| 162 | |||
| 163 | if (useCopyBlock) | ||
| 164 | { | ||
| 165 | size_t destPos = 0; | ||
| 166 | PRF(printf("################# COPY ")); | ||
| 167 | |||
| 168 | while (unpackSize > 0) | ||
| 169 | { | ||
| 170 | UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; | ||
| 171 | if (packSizeLimit - destPos < u + 3) | ||
| 172 | return SZ_ERROR_OUTPUT_EOF; | ||
| 173 | outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); | ||
| 174 | outBuf[destPos++] = (Byte)((u - 1) >> 8); | ||
| 175 | outBuf[destPos++] = (Byte)(u - 1); | ||
| 176 | memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); | ||
| 177 | unpackSize -= u; | ||
| 178 | destPos += u; | ||
| 179 | p->srcPos += u; | ||
| 180 | |||
| 181 | if (outStream) | ||
| 182 | { | ||
| 183 | *packSizeRes += destPos; | ||
| 184 | if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) | ||
| 185 | return SZ_ERROR_WRITE; | ||
| 186 | destPos = 0; | ||
| 187 | } | ||
| 188 | else | ||
| 189 | *packSizeRes = destPos; | ||
| 190 | /* needInitState = True; */ | ||
| 191 | } | ||
| 192 | |||
| 193 | LzmaEnc_RestoreState(p->enc); | ||
| 194 | return SZ_OK; | ||
| 195 | } | ||
| 196 | |||
| 197 | { | ||
| 198 | size_t destPos = 0; | ||
| 199 | UInt32 u = unpackSize - 1; | ||
| 200 | UInt32 pm = (UInt32)(packSize - 1); | ||
| 201 | unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); | ||
| 202 | |||
| 203 | PRF(printf(" ")); | ||
| 204 | |||
| 205 | outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); | ||
| 206 | outBuf[destPos++] = (Byte)(u >> 8); | ||
| 207 | outBuf[destPos++] = (Byte)u; | ||
| 208 | outBuf[destPos++] = (Byte)(pm >> 8); | ||
| 209 | outBuf[destPos++] = (Byte)pm; | ||
| 210 | |||
| 211 | if (p->needInitProp) | ||
| 212 | outBuf[destPos++] = p->propsByte; | ||
| 213 | |||
| 214 | p->needInitProp = False; | ||
| 215 | p->needInitState = False; | ||
| 216 | destPos += packSize; | ||
| 217 | p->srcPos += unpackSize; | ||
| 218 | |||
| 219 | if (outStream) | ||
| 220 | if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) | ||
| 221 | return SZ_ERROR_WRITE; | ||
| 222 | |||
| 223 | *packSizeRes = destPos; | ||
| 224 | return SZ_OK; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | |||
| 229 | /* ---------- Lzma2 Props ---------- */ | ||
| 230 | |||
| 231 | void Lzma2EncProps_Init(CLzma2EncProps *p) | ||
| 232 | { | ||
| 233 | LzmaEncProps_Init(&p->lzmaProps); | ||
| 234 | p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO; | ||
| 235 | p->numBlockThreads_Reduced = -1; | ||
| 236 | p->numBlockThreads_Max = -1; | ||
| 237 | p->numTotalThreads = -1; | ||
| 238 | } | ||
| 239 | |||
| 240 | void Lzma2EncProps_Normalize(CLzma2EncProps *p) | ||
| 241 | { | ||
| 242 | UInt64 fileSize; | ||
| 243 | int t1, t1n, t2, t2r, t3; | ||
| 244 | { | ||
| 245 | CLzmaEncProps lzmaProps = p->lzmaProps; | ||
| 246 | LzmaEncProps_Normalize(&lzmaProps); | ||
| 247 | t1n = lzmaProps.numThreads; | ||
| 248 | } | ||
| 249 | |||
| 250 | t1 = p->lzmaProps.numThreads; | ||
| 251 | t2 = p->numBlockThreads_Max; | ||
| 252 | t3 = p->numTotalThreads; | ||
| 253 | |||
| 254 | if (t2 > MTCODER__THREADS_MAX) | ||
| 255 | t2 = MTCODER__THREADS_MAX; | ||
| 256 | |||
| 257 | if (t3 <= 0) | ||
| 258 | { | ||
| 259 | if (t2 <= 0) | ||
| 260 | t2 = 1; | ||
| 261 | t3 = t1n * t2; | ||
| 262 | } | ||
| 263 | else if (t2 <= 0) | ||
| 264 | { | ||
| 265 | t2 = t3 / t1n; | ||
| 266 | if (t2 == 0) | ||
| 267 | { | ||
| 268 | t1 = 1; | ||
| 269 | t2 = t3; | ||
| 270 | } | ||
| 271 | if (t2 > MTCODER__THREADS_MAX) | ||
| 272 | t2 = MTCODER__THREADS_MAX; | ||
| 273 | } | ||
| 274 | else if (t1 <= 0) | ||
| 275 | { | ||
| 276 | t1 = t3 / t2; | ||
| 277 | if (t1 == 0) | ||
| 278 | t1 = 1; | ||
| 279 | } | ||
| 280 | else | ||
| 281 | t3 = t1n * t2; | ||
| 282 | |||
| 283 | p->lzmaProps.numThreads = t1; | ||
| 284 | |||
| 285 | t2r = t2; | ||
| 286 | |||
| 287 | fileSize = p->lzmaProps.reduceSize; | ||
| 288 | |||
| 289 | if ( p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | ||
| 290 | && p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO | ||
| 291 | && (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) | ||
| 292 | p->lzmaProps.reduceSize = p->blockSize; | ||
| 293 | |||
| 294 | LzmaEncProps_Normalize(&p->lzmaProps); | ||
| 295 | |||
| 296 | p->lzmaProps.reduceSize = fileSize; | ||
| 297 | |||
| 298 | t1 = p->lzmaProps.numThreads; | ||
| 299 | |||
| 300 | if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
| 301 | { | ||
| 302 | t2r = t2 = 1; | ||
| 303 | t3 = t1; | ||
| 304 | } | ||
| 305 | else if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO && t2 <= 1) | ||
| 306 | { | ||
| 307 | /* if there is no block multi-threading, we use SOLID block */ | ||
| 308 | p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; | ||
| 309 | } | ||
| 310 | else | ||
| 311 | { | ||
| 312 | if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
| 313 | { | ||
| 314 | const UInt32 kMinSize = (UInt32)1 << 20; | ||
| 315 | const UInt32 kMaxSize = (UInt32)1 << 28; | ||
| 316 | const UInt32 dictSize = p->lzmaProps.dictSize; | ||
| 317 | UInt64 blockSize = (UInt64)dictSize << 2; | ||
| 318 | if (blockSize < kMinSize) blockSize = kMinSize; | ||
| 319 | if (blockSize > kMaxSize) blockSize = kMaxSize; | ||
| 320 | if (blockSize < dictSize) blockSize = dictSize; | ||
| 321 | blockSize += (kMinSize - 1); | ||
| 322 | blockSize &= ~(UInt64)(kMinSize - 1); | ||
| 323 | p->blockSize = blockSize; | ||
| 324 | } | ||
| 325 | |||
| 326 | if (t2 > 1 && fileSize != (UInt64)(Int64)-1) | ||
| 327 | { | ||
| 328 | UInt64 numBlocks = fileSize / p->blockSize; | ||
| 329 | if (numBlocks * p->blockSize != fileSize) | ||
| 330 | numBlocks++; | ||
| 331 | if (numBlocks < (unsigned)t2) | ||
| 332 | { | ||
| 333 | t2r = (int)numBlocks; | ||
| 334 | if (t2r == 0) | ||
| 335 | t2r = 1; | ||
| 336 | t3 = t1 * t2r; | ||
| 337 | } | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | p->numBlockThreads_Max = t2; | ||
| 342 | p->numBlockThreads_Reduced = t2r; | ||
| 343 | p->numTotalThreads = t3; | ||
| 344 | } | ||
| 345 | |||
| 346 | |||
| 347 | static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) | ||
| 348 | { | ||
| 349 | return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; | ||
| 350 | } | ||
| 351 | |||
| 352 | |||
| 353 | /* ---------- Lzma2 ---------- */ | ||
| 354 | |||
| 355 | typedef struct | ||
| 356 | { | ||
| 357 | Byte propEncoded; | ||
| 358 | CLzma2EncProps props; | ||
| 359 | UInt64 expectedDataSize; | ||
| 360 | |||
| 361 | Byte *tempBufLzma; | ||
| 362 | |||
| 363 | ISzAllocPtr alloc; | ||
| 364 | ISzAllocPtr allocBig; | ||
| 365 | |||
| 366 | CLzma2EncInt coders[MTCODER__THREADS_MAX]; | ||
| 367 | |||
| 368 | #ifndef _7ZIP_ST | ||
| 369 | |||
| 370 | ISeqOutStream *outStream; | ||
| 371 | Byte *outBuf; | ||
| 372 | size_t outBuf_Rem; /* remainder in outBuf */ | ||
| 373 | |||
| 374 | size_t outBufSize; /* size of allocated outBufs[i] */ | ||
| 375 | size_t outBufsDataSizes[MTCODER__BLOCKS_MAX]; | ||
| 376 | BoolInt mtCoder_WasConstructed; | ||
| 377 | CMtCoder mtCoder; | ||
| 378 | Byte *outBufs[MTCODER__BLOCKS_MAX]; | ||
| 379 | |||
| 380 | #endif | ||
| 381 | |||
| 382 | } CLzma2Enc; | ||
| 383 | |||
| 384 | |||
| 385 | |||
| 386 | CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 387 | { | ||
| 388 | CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc)); | ||
| 389 | if (!p) | ||
| 390 | return NULL; | ||
| 391 | Lzma2EncProps_Init(&p->props); | ||
| 392 | Lzma2EncProps_Normalize(&p->props); | ||
| 393 | p->expectedDataSize = (UInt64)(Int64)-1; | ||
| 394 | p->tempBufLzma = NULL; | ||
| 395 | p->alloc = alloc; | ||
| 396 | p->allocBig = allocBig; | ||
| 397 | { | ||
| 398 | unsigned i; | ||
| 399 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
| 400 | p->coders[i].enc = NULL; | ||
| 401 | } | ||
| 402 | |||
| 403 | #ifndef _7ZIP_ST | ||
| 404 | p->mtCoder_WasConstructed = False; | ||
| 405 | { | ||
| 406 | unsigned i; | ||
| 407 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
| 408 | p->outBufs[i] = NULL; | ||
| 409 | p->outBufSize = 0; | ||
| 410 | } | ||
| 411 | #endif | ||
| 412 | |||
| 413 | return p; | ||
| 414 | } | ||
| 415 | |||
| 416 | |||
| 417 | #ifndef _7ZIP_ST | ||
| 418 | |||
| 419 | static void Lzma2Enc_FreeOutBufs(CLzma2Enc *p) | ||
| 420 | { | ||
| 421 | unsigned i; | ||
| 422 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
| 423 | if (p->outBufs[i]) | ||
| 424 | { | ||
| 425 | ISzAlloc_Free(p->alloc, p->outBufs[i]); | ||
| 426 | p->outBufs[i] = NULL; | ||
| 427 | } | ||
| 428 | p->outBufSize = 0; | ||
| 429 | } | ||
| 430 | |||
| 431 | #endif | ||
| 432 | |||
| 433 | |||
| 434 | void Lzma2Enc_Destroy(CLzma2EncHandle pp) | ||
| 435 | { | ||
| 436 | CLzma2Enc *p = (CLzma2Enc *)pp; | ||
| 437 | unsigned i; | ||
| 438 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
| 439 | { | ||
| 440 | CLzma2EncInt *t = &p->coders[i]; | ||
| 441 | if (t->enc) | ||
| 442 | { | ||
| 443 | LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); | ||
| 444 | t->enc = NULL; | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | |||
| 449 | #ifndef _7ZIP_ST | ||
| 450 | if (p->mtCoder_WasConstructed) | ||
| 451 | { | ||
| 452 | MtCoder_Destruct(&p->mtCoder); | ||
| 453 | p->mtCoder_WasConstructed = False; | ||
| 454 | } | ||
| 455 | Lzma2Enc_FreeOutBufs(p); | ||
| 456 | #endif | ||
| 457 | |||
| 458 | ISzAlloc_Free(p->alloc, p->tempBufLzma); | ||
| 459 | p->tempBufLzma = NULL; | ||
| 460 | |||
| 461 | ISzAlloc_Free(p->alloc, pp); | ||
| 462 | } | ||
| 463 | |||
| 464 | |||
| 465 | SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) | ||
| 466 | { | ||
| 467 | CLzma2Enc *p = (CLzma2Enc *)pp; | ||
| 468 | CLzmaEncProps lzmaProps = props->lzmaProps; | ||
| 469 | LzmaEncProps_Normalize(&lzmaProps); | ||
| 470 | if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) | ||
| 471 | return SZ_ERROR_PARAM; | ||
| 472 | p->props = *props; | ||
| 473 | Lzma2EncProps_Normalize(&p->props); | ||
| 474 | return SZ_OK; | ||
| 475 | } | ||
| 476 | |||
| 477 | |||
| 478 | void Lzma2Enc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize) | ||
| 479 | { | ||
| 480 | CLzma2Enc *p = (CLzma2Enc *)pp; | ||
| 481 | p->expectedDataSize = expectedDataSiize; | ||
| 482 | } | ||
| 483 | |||
| 484 | |||
| 485 | Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp) | ||
| 486 | { | ||
| 487 | CLzma2Enc *p = (CLzma2Enc *)pp; | ||
| 488 | unsigned i; | ||
| 489 | UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); | ||
| 490 | for (i = 0; i < 40; i++) | ||
| 491 | if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) | ||
| 492 | break; | ||
| 493 | return (Byte)i; | ||
| 494 | } | ||
| 495 | |||
| 496 | |||
| 497 | static SRes Lzma2Enc_EncodeMt1( | ||
| 498 | CLzma2Enc *me, | ||
| 499 | CLzma2EncInt *p, | ||
| 500 | ISeqOutStream *outStream, | ||
| 501 | Byte *outBuf, size_t *outBufSize, | ||
| 502 | ISeqInStream *inStream, | ||
| 503 | const Byte *inData, size_t inDataSize, | ||
| 504 | int finished, | ||
| 505 | ICompressProgress *progress) | ||
| 506 | { | ||
| 507 | UInt64 unpackTotal = 0; | ||
| 508 | UInt64 packTotal = 0; | ||
| 509 | size_t outLim = 0; | ||
| 510 | CLimitedSeqInStream limitedInStream; | ||
| 511 | |||
| 512 | if (outBuf) | ||
| 513 | { | ||
| 514 | outLim = *outBufSize; | ||
| 515 | *outBufSize = 0; | ||
| 516 | } | ||
| 517 | |||
| 518 | if (!p->enc) | ||
| 519 | { | ||
| 520 | p->propsAreSet = False; | ||
| 521 | p->enc = LzmaEnc_Create(me->alloc); | ||
| 522 | if (!p->enc) | ||
| 523 | return SZ_ERROR_MEM; | ||
| 524 | } | ||
| 525 | |||
| 526 | limitedInStream.realStream = inStream; | ||
| 527 | if (inStream) | ||
| 528 | { | ||
| 529 | limitedInStream.vt.Read = LimitedSeqInStream_Read; | ||
| 530 | } | ||
| 531 | |||
| 532 | if (!outBuf) | ||
| 533 | { | ||
| 534 | // outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma | ||
| 535 | if (!me->tempBufLzma) | ||
| 536 | { | ||
| 537 | me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); | ||
| 538 | if (!me->tempBufLzma) | ||
| 539 | return SZ_ERROR_MEM; | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | RINOK(Lzma2EncInt_InitStream(p, &me->props)); | ||
| 544 | |||
| 545 | for (;;) | ||
| 546 | { | ||
| 547 | SRes res = SZ_OK; | ||
| 548 | size_t inSizeCur = 0; | ||
| 549 | |||
| 550 | Lzma2EncInt_InitBlock(p); | ||
| 551 | |||
| 552 | LimitedSeqInStream_Init(&limitedInStream); | ||
| 553 | limitedInStream.limit = me->props.blockSize; | ||
| 554 | |||
| 555 | if (inStream) | ||
| 556 | { | ||
| 557 | UInt64 expected = (UInt64)(Int64)-1; | ||
| 558 | // inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize | ||
| 559 | if (me->expectedDataSize != (UInt64)(Int64)-1 | ||
| 560 | && me->expectedDataSize >= unpackTotal) | ||
| 561 | expected = me->expectedDataSize - unpackTotal; | ||
| 562 | if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | ||
| 563 | && expected > me->props.blockSize) | ||
| 564 | expected = (size_t)me->props.blockSize; | ||
| 565 | |||
| 566 | LzmaEnc_SetDataSize(p->enc, expected); | ||
| 567 | |||
| 568 | RINOK(LzmaEnc_PrepareForLzma2(p->enc, | ||
| 569 | &limitedInStream.vt, | ||
| 570 | LZMA2_KEEP_WINDOW_SIZE, | ||
| 571 | me->alloc, | ||
| 572 | me->allocBig)); | ||
| 573 | } | ||
| 574 | else | ||
| 575 | { | ||
| 576 | inSizeCur = inDataSize - (size_t)unpackTotal; | ||
| 577 | if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | ||
| 578 | && inSizeCur > me->props.blockSize) | ||
| 579 | inSizeCur = (size_t)me->props.blockSize; | ||
| 580 | |||
| 581 | // LzmaEnc_SetDataSize(p->enc, inSizeCur); | ||
| 582 | |||
| 583 | RINOK(LzmaEnc_MemPrepare(p->enc, | ||
| 584 | inData + (size_t)unpackTotal, inSizeCur, | ||
| 585 | LZMA2_KEEP_WINDOW_SIZE, | ||
| 586 | me->alloc, | ||
| 587 | me->allocBig)); | ||
| 588 | } | ||
| 589 | |||
| 590 | for (;;) | ||
| 591 | { | ||
| 592 | size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; | ||
| 593 | if (outBuf) | ||
| 594 | packSize = outLim - (size_t)packTotal; | ||
| 595 | |||
| 596 | res = Lzma2EncInt_EncodeSubblock(p, | ||
| 597 | outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize, | ||
| 598 | outBuf ? NULL : outStream); | ||
| 599 | |||
| 600 | if (res != SZ_OK) | ||
| 601 | break; | ||
| 602 | |||
| 603 | packTotal += packSize; | ||
| 604 | if (outBuf) | ||
| 605 | *outBufSize = (size_t)packTotal; | ||
| 606 | |||
| 607 | res = Progress(progress, unpackTotal + p->srcPos, packTotal); | ||
| 608 | if (res != SZ_OK) | ||
| 609 | break; | ||
| 610 | |||
| 611 | /* | ||
| 612 | if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0) | ||
| 613 | break; | ||
| 614 | */ | ||
| 615 | |||
| 616 | if (packSize == 0) | ||
| 617 | break; | ||
| 618 | } | ||
| 619 | |||
| 620 | LzmaEnc_Finish(p->enc); | ||
| 621 | |||
| 622 | unpackTotal += p->srcPos; | ||
| 623 | |||
| 624 | RINOK(res); | ||
| 625 | |||
| 626 | if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur)) | ||
| 627 | return SZ_ERROR_FAIL; | ||
| 628 | |||
| 629 | if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize)) | ||
| 630 | { | ||
| 631 | if (finished) | ||
| 632 | { | ||
| 633 | if (outBuf) | ||
| 634 | { | ||
| 635 | const size_t destPos = *outBufSize; | ||
| 636 | if (destPos >= outLim) | ||
| 637 | return SZ_ERROR_OUTPUT_EOF; | ||
| 638 | outBuf[destPos] = LZMA2_CONTROL_EOF; // 0 | ||
| 639 | *outBufSize = destPos + 1; | ||
| 640 | } | ||
| 641 | else | ||
| 642 | { | ||
| 643 | const Byte b = LZMA2_CONTROL_EOF; // 0; | ||
| 644 | if (ISeqOutStream_Write(outStream, &b, 1) != 1) | ||
| 645 | return SZ_ERROR_WRITE; | ||
| 646 | } | ||
| 647 | } | ||
| 648 | return SZ_OK; | ||
| 649 | } | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | |||
| 654 | |||
| 655 | #ifndef _7ZIP_ST | ||
| 656 | |||
| 657 | static SRes Lzma2Enc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, | ||
| 658 | const Byte *src, size_t srcSize, int finished) | ||
| 659 | { | ||
| 660 | CLzma2Enc *me = (CLzma2Enc *)pp; | ||
| 661 | size_t destSize = me->outBufSize; | ||
| 662 | SRes res; | ||
| 663 | CMtProgressThunk progressThunk; | ||
| 664 | |||
| 665 | Byte *dest = me->outBufs[outBufIndex]; | ||
| 666 | |||
| 667 | me->outBufsDataSizes[outBufIndex] = 0; | ||
| 668 | |||
| 669 | if (!dest) | ||
| 670 | { | ||
| 671 | dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); | ||
| 672 | if (!dest) | ||
| 673 | return SZ_ERROR_MEM; | ||
| 674 | me->outBufs[outBufIndex] = dest; | ||
| 675 | } | ||
| 676 | |||
| 677 | MtProgressThunk_CreateVTable(&progressThunk); | ||
| 678 | progressThunk.mtProgress = &me->mtCoder.mtProgress; | ||
| 679 | progressThunk.inSize = 0; | ||
| 680 | progressThunk.outSize = 0; | ||
| 681 | |||
| 682 | res = Lzma2Enc_EncodeMt1(me, | ||
| 683 | &me->coders[coderIndex], | ||
| 684 | NULL, dest, &destSize, | ||
| 685 | NULL, src, srcSize, | ||
| 686 | finished, | ||
| 687 | &progressThunk.vt); | ||
| 688 | |||
| 689 | me->outBufsDataSizes[outBufIndex] = destSize; | ||
| 690 | |||
| 691 | return res; | ||
| 692 | } | ||
| 693 | |||
| 694 | |||
| 695 | static SRes Lzma2Enc_MtCallback_Write(void *pp, unsigned outBufIndex) | ||
| 696 | { | ||
| 697 | CLzma2Enc *me = (CLzma2Enc *)pp; | ||
| 698 | size_t size = me->outBufsDataSizes[outBufIndex]; | ||
| 699 | const Byte *data = me->outBufs[outBufIndex]; | ||
| 700 | |||
| 701 | if (me->outStream) | ||
| 702 | return ISeqOutStream_Write(me->outStream, data, size) == size ? SZ_OK : SZ_ERROR_WRITE; | ||
| 703 | |||
| 704 | if (size > me->outBuf_Rem) | ||
| 705 | return SZ_ERROR_OUTPUT_EOF; | ||
| 706 | memcpy(me->outBuf, data, size); | ||
| 707 | me->outBuf_Rem -= size; | ||
| 708 | me->outBuf += size; | ||
| 709 | return SZ_OK; | ||
| 710 | } | ||
| 711 | |||
| 712 | #endif | ||
| 713 | |||
| 714 | |||
| 715 | |||
| 716 | SRes Lzma2Enc_Encode2(CLzma2EncHandle pp, | ||
| 717 | ISeqOutStream *outStream, | ||
| 718 | Byte *outBuf, size_t *outBufSize, | ||
| 719 | ISeqInStream *inStream, | ||
| 720 | const Byte *inData, size_t inDataSize, | ||
| 721 | ICompressProgress *progress) | ||
| 722 | { | ||
| 723 | CLzma2Enc *p = (CLzma2Enc *)pp; | ||
| 724 | |||
| 725 | if (inStream && inData) | ||
| 726 | return SZ_ERROR_PARAM; | ||
| 727 | |||
| 728 | if (outStream && outBuf) | ||
| 729 | return SZ_ERROR_PARAM; | ||
| 730 | |||
| 731 | { | ||
| 732 | unsigned i; | ||
| 733 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
| 734 | p->coders[i].propsAreSet = False; | ||
| 735 | } | ||
| 736 | |||
| 737 | #ifndef _7ZIP_ST | ||
| 738 | |||
| 739 | if (p->props.numBlockThreads_Reduced > 1) | ||
| 740 | { | ||
| 741 | IMtCoderCallback2 vt; | ||
| 742 | |||
| 743 | if (!p->mtCoder_WasConstructed) | ||
| 744 | { | ||
| 745 | p->mtCoder_WasConstructed = True; | ||
| 746 | MtCoder_Construct(&p->mtCoder); | ||
| 747 | } | ||
| 748 | |||
| 749 | vt.Code = Lzma2Enc_MtCallback_Code; | ||
| 750 | vt.Write = Lzma2Enc_MtCallback_Write; | ||
| 751 | |||
| 752 | p->outStream = outStream; | ||
| 753 | p->outBuf = NULL; | ||
| 754 | p->outBuf_Rem = 0; | ||
| 755 | if (!outStream) | ||
| 756 | { | ||
| 757 | p->outBuf = outBuf; | ||
| 758 | p->outBuf_Rem = *outBufSize; | ||
| 759 | *outBufSize = 0; | ||
| 760 | } | ||
| 761 | |||
| 762 | p->mtCoder.allocBig = p->allocBig; | ||
| 763 | p->mtCoder.progress = progress; | ||
| 764 | p->mtCoder.inStream = inStream; | ||
| 765 | p->mtCoder.inData = inData; | ||
| 766 | p->mtCoder.inDataSize = inDataSize; | ||
| 767 | p->mtCoder.mtCallback = &vt; | ||
| 768 | p->mtCoder.mtCallbackObject = p; | ||
| 769 | |||
| 770 | p->mtCoder.blockSize = (size_t)p->props.blockSize; | ||
| 771 | if (p->mtCoder.blockSize != p->props.blockSize) | ||
| 772 | return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ | ||
| 773 | |||
| 774 | { | ||
| 775 | size_t destBlockSize = p->mtCoder.blockSize + (p->mtCoder.blockSize >> 10) + 16; | ||
| 776 | if (destBlockSize < p->mtCoder.blockSize) | ||
| 777 | return SZ_ERROR_PARAM; | ||
| 778 | if (p->outBufSize != destBlockSize) | ||
| 779 | Lzma2Enc_FreeOutBufs(p); | ||
| 780 | p->outBufSize = destBlockSize; | ||
| 781 | } | ||
| 782 | |||
| 783 | p->mtCoder.numThreadsMax = (unsigned)p->props.numBlockThreads_Max; | ||
| 784 | p->mtCoder.expectedDataSize = p->expectedDataSize; | ||
| 785 | |||
| 786 | { | ||
| 787 | SRes res = MtCoder_Code(&p->mtCoder); | ||
| 788 | if (!outStream) | ||
| 789 | *outBufSize = (size_t)(p->outBuf - outBuf); | ||
| 790 | return res; | ||
| 791 | } | ||
| 792 | } | ||
| 793 | |||
| 794 | #endif | ||
| 795 | |||
| 796 | |||
| 797 | return Lzma2Enc_EncodeMt1(p, | ||
| 798 | &p->coders[0], | ||
| 799 | outStream, outBuf, outBufSize, | ||
| 800 | inStream, inData, inDataSize, | ||
| 801 | True, /* finished */ | ||
| 802 | progress); | ||
| 803 | } | ||
diff --git a/C/Lzma2Enc.h b/C/Lzma2Enc.h new file mode 100644 index 0000000..6a6110f --- /dev/null +++ b/C/Lzma2Enc.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | /* Lzma2Enc.h -- LZMA2 Encoder | ||
| 2 | 2017-07-27 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __LZMA2_ENC_H | ||
| 5 | #define __LZMA2_ENC_H | ||
| 6 | |||
| 7 | #include "LzmaEnc.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO 0 | ||
| 12 | #define LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID ((UInt64)(Int64)-1) | ||
| 13 | |||
| 14 | typedef struct | ||
| 15 | { | ||
| 16 | CLzmaEncProps lzmaProps; | ||
| 17 | UInt64 blockSize; | ||
| 18 | int numBlockThreads_Reduced; | ||
| 19 | int numBlockThreads_Max; | ||
| 20 | int numTotalThreads; | ||
| 21 | } CLzma2EncProps; | ||
| 22 | |||
| 23 | void Lzma2EncProps_Init(CLzma2EncProps *p); | ||
| 24 | void Lzma2EncProps_Normalize(CLzma2EncProps *p); | ||
| 25 | |||
| 26 | /* ---------- CLzmaEnc2Handle Interface ---------- */ | ||
| 27 | |||
| 28 | /* Lzma2Enc_* functions can return the following exit codes: | ||
| 29 | SRes: | ||
| 30 | SZ_OK - OK | ||
| 31 | SZ_ERROR_MEM - Memory allocation error | ||
| 32 | SZ_ERROR_PARAM - Incorrect paramater in props | ||
| 33 | SZ_ERROR_WRITE - ISeqOutStream write callback error | ||
| 34 | SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output | ||
| 35 | SZ_ERROR_PROGRESS - some break from progress callback | ||
| 36 | SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) | ||
| 37 | */ | ||
| 38 | |||
| 39 | typedef void * CLzma2EncHandle; | ||
| 40 | |||
| 41 | CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
| 42 | void Lzma2Enc_Destroy(CLzma2EncHandle p); | ||
| 43 | SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props); | ||
| 44 | void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize); | ||
| 45 | Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p); | ||
| 46 | SRes Lzma2Enc_Encode2(CLzma2EncHandle p, | ||
| 47 | ISeqOutStream *outStream, | ||
| 48 | Byte *outBuf, size_t *outBufSize, | ||
| 49 | ISeqInStream *inStream, | ||
| 50 | const Byte *inData, size_t inDataSize, | ||
| 51 | ICompressProgress *progress); | ||
| 52 | |||
| 53 | EXTERN_C_END | ||
| 54 | |||
| 55 | #endif | ||
diff --git a/C/Lzma86.h b/C/Lzma86.h new file mode 100644 index 0000000..bebed5c --- /dev/null +++ b/C/Lzma86.h | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | /* Lzma86.h -- LZMA + x86 (BCJ) Filter | ||
| 2 | 2013-01-18 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __LZMA86_H | ||
| 5 | #define __LZMA86_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define LZMA86_SIZE_OFFSET (1 + 5) | ||
| 12 | #define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8) | ||
| 13 | |||
| 14 | /* | ||
| 15 | It's an example for LZMA + x86 Filter use. | ||
| 16 | You can use .lzma86 extension, if you write that stream to file. | ||
| 17 | .lzma86 header adds one additional byte to standard .lzma header. | ||
| 18 | .lzma86 header (14 bytes): | ||
| 19 | Offset Size Description | ||
| 20 | 0 1 = 0 - no filter, pure LZMA | ||
| 21 | = 1 - x86 filter + LZMA | ||
| 22 | 1 1 lc, lp and pb in encoded form | ||
| 23 | 2 4 dictSize (little endian) | ||
| 24 | 6 8 uncompressed size (little endian) | ||
| 25 | |||
| 26 | |||
| 27 | Lzma86_Encode | ||
| 28 | ------------- | ||
| 29 | level - compression level: 0 <= level <= 9, the default value for "level" is 5. | ||
| 30 | |||
| 31 | dictSize - The dictionary size in bytes. The maximum value is | ||
| 32 | 128 MB = (1 << 27) bytes for 32-bit version | ||
| 33 | 1 GB = (1 << 30) bytes for 64-bit version | ||
| 34 | The default value is 16 MB = (1 << 24) bytes, for level = 5. | ||
| 35 | It's recommended to use the dictionary that is larger than 4 KB and | ||
| 36 | that can be calculated as (1 << N) or (3 << N) sizes. | ||
| 37 | For better compression ratio dictSize must be >= inSize. | ||
| 38 | |||
| 39 | filterMode: | ||
| 40 | SZ_FILTER_NO - no Filter | ||
| 41 | SZ_FILTER_YES - x86 Filter | ||
| 42 | SZ_FILTER_AUTO - it tries both alternatives to select best. | ||
| 43 | Encoder will use 2 or 3 passes: | ||
| 44 | 2 passes when FILTER_NO provides better compression. | ||
| 45 | 3 passes when FILTER_YES provides better compression. | ||
| 46 | |||
| 47 | Lzma86Encode allocates Data with MyAlloc functions. | ||
| 48 | RAM Requirements for compressing: | ||
| 49 | RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize | ||
| 50 | filterMode FilterBlockSize | ||
| 51 | SZ_FILTER_NO 0 | ||
| 52 | SZ_FILTER_YES inSize | ||
| 53 | SZ_FILTER_AUTO inSize | ||
| 54 | |||
| 55 | |||
| 56 | Return code: | ||
| 57 | SZ_OK - OK | ||
| 58 | SZ_ERROR_MEM - Memory allocation error | ||
| 59 | SZ_ERROR_PARAM - Incorrect paramater | ||
| 60 | SZ_ERROR_OUTPUT_EOF - output buffer overflow | ||
| 61 | SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) | ||
| 62 | */ | ||
| 63 | |||
| 64 | enum ESzFilterMode | ||
| 65 | { | ||
| 66 | SZ_FILTER_NO, | ||
| 67 | SZ_FILTER_YES, | ||
| 68 | SZ_FILTER_AUTO | ||
| 69 | }; | ||
| 70 | |||
| 71 | SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, | ||
| 72 | int level, UInt32 dictSize, int filterMode); | ||
| 73 | |||
| 74 | |||
| 75 | /* | ||
| 76 | Lzma86_GetUnpackSize: | ||
| 77 | In: | ||
| 78 | src - input data | ||
| 79 | srcLen - input data size | ||
| 80 | Out: | ||
| 81 | unpackSize - size of uncompressed stream | ||
| 82 | Return code: | ||
| 83 | SZ_OK - OK | ||
| 84 | SZ_ERROR_INPUT_EOF - Error in headers | ||
| 85 | */ | ||
| 86 | |||
| 87 | SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize); | ||
| 88 | |||
| 89 | /* | ||
| 90 | Lzma86_Decode: | ||
| 91 | In: | ||
| 92 | dest - output data | ||
| 93 | destLen - output data size | ||
| 94 | src - input data | ||
| 95 | srcLen - input data size | ||
| 96 | Out: | ||
| 97 | destLen - processed output size | ||
| 98 | srcLen - processed input size | ||
| 99 | Return code: | ||
| 100 | SZ_OK - OK | ||
| 101 | SZ_ERROR_DATA - Data error | ||
| 102 | SZ_ERROR_MEM - Memory allocation error | ||
| 103 | SZ_ERROR_UNSUPPORTED - unsupported file | ||
| 104 | SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer | ||
| 105 | */ | ||
| 106 | |||
| 107 | SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen); | ||
| 108 | |||
| 109 | EXTERN_C_END | ||
| 110 | |||
| 111 | #endif | ||
diff --git a/C/Lzma86Dec.c b/C/Lzma86Dec.c new file mode 100644 index 0000000..2103174 --- /dev/null +++ b/C/Lzma86Dec.c | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder | ||
| 2 | 2016-05-16 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "Lzma86.h" | ||
| 7 | |||
| 8 | #include "Alloc.h" | ||
| 9 | #include "Bra.h" | ||
| 10 | #include "LzmaDec.h" | ||
| 11 | |||
| 12 | SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize) | ||
| 13 | { | ||
| 14 | unsigned i; | ||
| 15 | if (srcLen < LZMA86_HEADER_SIZE) | ||
| 16 | return SZ_ERROR_INPUT_EOF; | ||
| 17 | *unpackSize = 0; | ||
| 18 | for (i = 0; i < sizeof(UInt64); i++) | ||
| 19 | *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i); | ||
| 20 | return SZ_OK; | ||
| 21 | } | ||
| 22 | |||
| 23 | SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) | ||
| 24 | { | ||
| 25 | SRes res; | ||
| 26 | int useFilter; | ||
| 27 | SizeT inSizePure; | ||
| 28 | ELzmaStatus status; | ||
| 29 | |||
| 30 | if (*srcLen < LZMA86_HEADER_SIZE) | ||
| 31 | return SZ_ERROR_INPUT_EOF; | ||
| 32 | |||
| 33 | useFilter = src[0]; | ||
| 34 | |||
| 35 | if (useFilter > 1) | ||
| 36 | { | ||
| 37 | *destLen = 0; | ||
| 38 | return SZ_ERROR_UNSUPPORTED; | ||
| 39 | } | ||
| 40 | |||
| 41 | inSizePure = *srcLen - LZMA86_HEADER_SIZE; | ||
| 42 | res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure, | ||
| 43 | src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc); | ||
| 44 | *srcLen = inSizePure + LZMA86_HEADER_SIZE; | ||
| 45 | if (res != SZ_OK) | ||
| 46 | return res; | ||
| 47 | if (useFilter == 1) | ||
| 48 | { | ||
| 49 | UInt32 x86State; | ||
| 50 | x86_Convert_Init(x86State); | ||
| 51 | x86_Convert(dest, *destLen, 0, &x86State, 0); | ||
| 52 | } | ||
| 53 | return SZ_OK; | ||
| 54 | } | ||
diff --git a/C/Lzma86Enc.c b/C/Lzma86Enc.c new file mode 100644 index 0000000..14fcd65 --- /dev/null +++ b/C/Lzma86Enc.c | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | /* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder | ||
| 2 | 2018-07-04 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | #include "Lzma86.h" | ||
| 9 | |||
| 10 | #include "Alloc.h" | ||
| 11 | #include "Bra.h" | ||
| 12 | #include "LzmaEnc.h" | ||
| 13 | |||
| 14 | int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, | ||
| 15 | int level, UInt32 dictSize, int filterMode) | ||
| 16 | { | ||
| 17 | size_t outSize2 = *destLen; | ||
| 18 | Byte *filteredStream; | ||
| 19 | BoolInt useFilter; | ||
| 20 | int mainResult = SZ_ERROR_OUTPUT_EOF; | ||
| 21 | CLzmaEncProps props; | ||
| 22 | LzmaEncProps_Init(&props); | ||
| 23 | props.level = level; | ||
| 24 | props.dictSize = dictSize; | ||
| 25 | |||
| 26 | *destLen = 0; | ||
| 27 | if (outSize2 < LZMA86_HEADER_SIZE) | ||
| 28 | return SZ_ERROR_OUTPUT_EOF; | ||
| 29 | |||
| 30 | { | ||
| 31 | int i; | ||
| 32 | UInt64 t = srcLen; | ||
| 33 | for (i = 0; i < 8; i++, t >>= 8) | ||
| 34 | dest[LZMA86_SIZE_OFFSET + i] = (Byte)t; | ||
| 35 | } | ||
| 36 | |||
| 37 | filteredStream = 0; | ||
| 38 | useFilter = (filterMode != SZ_FILTER_NO); | ||
| 39 | if (useFilter) | ||
| 40 | { | ||
| 41 | if (srcLen != 0) | ||
| 42 | { | ||
| 43 | filteredStream = (Byte *)MyAlloc(srcLen); | ||
| 44 | if (filteredStream == 0) | ||
| 45 | return SZ_ERROR_MEM; | ||
| 46 | memcpy(filteredStream, src, srcLen); | ||
| 47 | } | ||
| 48 | { | ||
| 49 | UInt32 x86State; | ||
| 50 | x86_Convert_Init(x86State); | ||
| 51 | x86_Convert(filteredStream, srcLen, 0, &x86State, 1); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | { | ||
| 56 | size_t minSize = 0; | ||
| 57 | BoolInt bestIsFiltered = False; | ||
| 58 | |||
| 59 | /* passes for SZ_FILTER_AUTO: | ||
| 60 | 0 - BCJ + LZMA | ||
| 61 | 1 - LZMA | ||
| 62 | 2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better. | ||
| 63 | */ | ||
| 64 | int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1; | ||
| 65 | |||
| 66 | int i; | ||
| 67 | for (i = 0; i < numPasses; i++) | ||
| 68 | { | ||
| 69 | size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE; | ||
| 70 | size_t outPropsSize = 5; | ||
| 71 | SRes curRes; | ||
| 72 | BoolInt curModeIsFiltered = (numPasses > 1 && i == numPasses - 1); | ||
| 73 | if (curModeIsFiltered && !bestIsFiltered) | ||
| 74 | break; | ||
| 75 | if (useFilter && i == 0) | ||
| 76 | curModeIsFiltered = True; | ||
| 77 | |||
| 78 | curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed, | ||
| 79 | curModeIsFiltered ? filteredStream : src, srcLen, | ||
| 80 | &props, dest + 1, &outPropsSize, 0, | ||
| 81 | NULL, &g_Alloc, &g_Alloc); | ||
| 82 | |||
| 83 | if (curRes != SZ_ERROR_OUTPUT_EOF) | ||
| 84 | { | ||
| 85 | if (curRes != SZ_OK) | ||
| 86 | { | ||
| 87 | mainResult = curRes; | ||
| 88 | break; | ||
| 89 | } | ||
| 90 | if (outSizeProcessed <= minSize || mainResult != SZ_OK) | ||
| 91 | { | ||
| 92 | minSize = outSizeProcessed; | ||
| 93 | bestIsFiltered = curModeIsFiltered; | ||
| 94 | mainResult = SZ_OK; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | ||
| 98 | dest[0] = (Byte)(bestIsFiltered ? 1 : 0); | ||
| 99 | *destLen = LZMA86_HEADER_SIZE + minSize; | ||
| 100 | } | ||
| 101 | if (useFilter) | ||
| 102 | MyFree(filteredStream); | ||
| 103 | return mainResult; | ||
| 104 | } | ||
diff --git a/C/LzmaDec.c b/C/LzmaDec.c new file mode 100644 index 0000000..d6742e5 --- /dev/null +++ b/C/LzmaDec.c | |||
| @@ -0,0 +1,1363 @@ | |||
| 1 | /* LzmaDec.c -- LZMA Decoder | ||
| 2 | 2021-04-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | /* #include "CpuArch.h" */ | ||
| 9 | #include "LzmaDec.h" | ||
| 10 | |||
| 11 | #define kNumTopBits 24 | ||
| 12 | #define kTopValue ((UInt32)1 << kNumTopBits) | ||
| 13 | |||
| 14 | #define kNumBitModelTotalBits 11 | ||
| 15 | #define kBitModelTotal (1 << kNumBitModelTotalBits) | ||
| 16 | |||
| 17 | #define RC_INIT_SIZE 5 | ||
| 18 | |||
| 19 | #ifndef _LZMA_DEC_OPT | ||
| 20 | |||
| 21 | #define kNumMoveBits 5 | ||
| 22 | #define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } | ||
| 23 | |||
| 24 | #define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) | ||
| 25 | #define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); | ||
| 26 | #define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); | ||
| 27 | #define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ | ||
| 28 | { UPDATE_0(p); i = (i + i); A0; } else \ | ||
| 29 | { UPDATE_1(p); i = (i + i) + 1; A1; } | ||
| 30 | |||
| 31 | #define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); } | ||
| 32 | |||
| 33 | #define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \ | ||
| 34 | { UPDATE_0(p + i); A0; } else \ | ||
| 35 | { UPDATE_1(p + i); A1; } | ||
| 36 | #define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; ) | ||
| 37 | #define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; ) | ||
| 38 | #define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; ) | ||
| 39 | |||
| 40 | #define TREE_DECODE(probs, limit, i) \ | ||
| 41 | { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } | ||
| 42 | |||
| 43 | /* #define _LZMA_SIZE_OPT */ | ||
| 44 | |||
| 45 | #ifdef _LZMA_SIZE_OPT | ||
| 46 | #define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) | ||
| 47 | #else | ||
| 48 | #define TREE_6_DECODE(probs, i) \ | ||
| 49 | { i = 1; \ | ||
| 50 | TREE_GET_BIT(probs, i); \ | ||
| 51 | TREE_GET_BIT(probs, i); \ | ||
| 52 | TREE_GET_BIT(probs, i); \ | ||
| 53 | TREE_GET_BIT(probs, i); \ | ||
| 54 | TREE_GET_BIT(probs, i); \ | ||
| 55 | TREE_GET_BIT(probs, i); \ | ||
| 56 | i -= 0x40; } | ||
| 57 | #endif | ||
| 58 | |||
| 59 | #define NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol) | ||
| 60 | #define MATCHED_LITER_DEC \ | ||
| 61 | matchByte += matchByte; \ | ||
| 62 | bit = offs; \ | ||
| 63 | offs &= matchByte; \ | ||
| 64 | probLit = prob + (offs + bit + symbol); \ | ||
| 65 | GET_BIT2(probLit, symbol, offs ^= bit; , ;) | ||
| 66 | |||
| 67 | #endif // _LZMA_DEC_OPT | ||
| 68 | |||
| 69 | |||
| 70 | #define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_INPUT_EOF; range <<= 8; code = (code << 8) | (*buf++); } | ||
| 71 | |||
| 72 | #define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) | ||
| 73 | #define UPDATE_0_CHECK range = bound; | ||
| 74 | #define UPDATE_1_CHECK range -= bound; code -= bound; | ||
| 75 | #define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ | ||
| 76 | { UPDATE_0_CHECK; i = (i + i); A0; } else \ | ||
| 77 | { UPDATE_1_CHECK; i = (i + i) + 1; A1; } | ||
| 78 | #define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) | ||
| 79 | #define TREE_DECODE_CHECK(probs, limit, i) \ | ||
| 80 | { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } | ||
| 81 | |||
| 82 | |||
| 83 | #define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \ | ||
| 84 | { UPDATE_0_CHECK; i += m; m += m; } else \ | ||
| 85 | { UPDATE_1_CHECK; m += m; i += m; } | ||
| 86 | |||
| 87 | |||
| 88 | #define kNumPosBitsMax 4 | ||
| 89 | #define kNumPosStatesMax (1 << kNumPosBitsMax) | ||
| 90 | |||
| 91 | #define kLenNumLowBits 3 | ||
| 92 | #define kLenNumLowSymbols (1 << kLenNumLowBits) | ||
| 93 | #define kLenNumHighBits 8 | ||
| 94 | #define kLenNumHighSymbols (1 << kLenNumHighBits) | ||
| 95 | |||
| 96 | #define LenLow 0 | ||
| 97 | #define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits)) | ||
| 98 | #define kNumLenProbs (LenHigh + kLenNumHighSymbols) | ||
| 99 | |||
| 100 | #define LenChoice LenLow | ||
| 101 | #define LenChoice2 (LenLow + (1 << kLenNumLowBits)) | ||
| 102 | |||
| 103 | #define kNumStates 12 | ||
| 104 | #define kNumStates2 16 | ||
| 105 | #define kNumLitStates 7 | ||
| 106 | |||
| 107 | #define kStartPosModelIndex 4 | ||
| 108 | #define kEndPosModelIndex 14 | ||
| 109 | #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) | ||
| 110 | |||
| 111 | #define kNumPosSlotBits 6 | ||
| 112 | #define kNumLenToPosStates 4 | ||
| 113 | |||
| 114 | #define kNumAlignBits 4 | ||
| 115 | #define kAlignTableSize (1 << kNumAlignBits) | ||
| 116 | |||
| 117 | #define kMatchMinLen 2 | ||
| 118 | #define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols) | ||
| 119 | |||
| 120 | #define kMatchSpecLen_Error_Data (1 << 9) | ||
| 121 | #define kMatchSpecLen_Error_Fail (kMatchSpecLen_Error_Data - 1) | ||
| 122 | |||
| 123 | /* External ASM code needs same CLzmaProb array layout. So don't change it. */ | ||
| 124 | |||
| 125 | /* (probs_1664) is faster and better for code size at some platforms */ | ||
| 126 | /* | ||
| 127 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 128 | */ | ||
| 129 | #define kStartOffset 1664 | ||
| 130 | #define GET_PROBS p->probs_1664 | ||
| 131 | /* | ||
| 132 | #define GET_PROBS p->probs + kStartOffset | ||
| 133 | #else | ||
| 134 | #define kStartOffset 0 | ||
| 135 | #define GET_PROBS p->probs | ||
| 136 | #endif | ||
| 137 | */ | ||
| 138 | |||
| 139 | #define SpecPos (-kStartOffset) | ||
| 140 | #define IsRep0Long (SpecPos + kNumFullDistances) | ||
| 141 | #define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax)) | ||
| 142 | #define LenCoder (RepLenCoder + kNumLenProbs) | ||
| 143 | #define IsMatch (LenCoder + kNumLenProbs) | ||
| 144 | #define Align (IsMatch + (kNumStates2 << kNumPosBitsMax)) | ||
| 145 | #define IsRep (Align + kAlignTableSize) | ||
| 146 | #define IsRepG0 (IsRep + kNumStates) | ||
| 147 | #define IsRepG1 (IsRepG0 + kNumStates) | ||
| 148 | #define IsRepG2 (IsRepG1 + kNumStates) | ||
| 149 | #define PosSlot (IsRepG2 + kNumStates) | ||
| 150 | #define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) | ||
| 151 | #define NUM_BASE_PROBS (Literal + kStartOffset) | ||
| 152 | |||
| 153 | #if Align != 0 && kStartOffset != 0 | ||
| 154 | #error Stop_Compiling_Bad_LZMA_kAlign | ||
| 155 | #endif | ||
| 156 | |||
| 157 | #if NUM_BASE_PROBS != 1984 | ||
| 158 | #error Stop_Compiling_Bad_LZMA_PROBS | ||
| 159 | #endif | ||
| 160 | |||
| 161 | |||
| 162 | #define LZMA_LIT_SIZE 0x300 | ||
| 163 | |||
| 164 | #define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) | ||
| 165 | |||
| 166 | |||
| 167 | #define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4) | ||
| 168 | #define COMBINED_PS_STATE (posState + state) | ||
| 169 | #define GET_LEN_STATE (posState) | ||
| 170 | |||
| 171 | #define LZMA_DIC_MIN (1 << 12) | ||
| 172 | |||
| 173 | /* | ||
| 174 | p->remainLen : shows status of LZMA decoder: | ||
| 175 | < kMatchSpecLenStart : the number of bytes to be copied with (p->rep0) offset | ||
| 176 | = kMatchSpecLenStart : the LZMA stream was finished with end mark | ||
| 177 | = kMatchSpecLenStart + 1 : need init range coder | ||
| 178 | = kMatchSpecLenStart + 2 : need init range coder and state | ||
| 179 | = kMatchSpecLen_Error_Fail : Internal Code Failure | ||
| 180 | = kMatchSpecLen_Error_Data + [0 ... 273] : LZMA Data Error | ||
| 181 | */ | ||
| 182 | |||
| 183 | /* ---------- LZMA_DECODE_REAL ---------- */ | ||
| 184 | /* | ||
| 185 | LzmaDec_DecodeReal_3() can be implemented in external ASM file. | ||
| 186 | 3 - is the code compatibility version of that function for check at link time. | ||
| 187 | */ | ||
| 188 | |||
| 189 | #define LZMA_DECODE_REAL LzmaDec_DecodeReal_3 | ||
| 190 | |||
| 191 | /* | ||
| 192 | LZMA_DECODE_REAL() | ||
| 193 | In: | ||
| 194 | RangeCoder is normalized | ||
| 195 | if (p->dicPos == limit) | ||
| 196 | { | ||
| 197 | LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases. | ||
| 198 | So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol | ||
| 199 | is not END_OF_PAYALOAD_MARKER, then the function doesn't write any byte to dictionary, | ||
| 200 | the function returns SZ_OK, and the caller can use (p->remainLen) and (p->reps[0]) later. | ||
| 201 | } | ||
| 202 | |||
| 203 | Processing: | ||
| 204 | The first LZMA symbol will be decoded in any case. | ||
| 205 | All main checks for limits are at the end of main loop, | ||
| 206 | It decodes additional LZMA-symbols while (p->buf < bufLimit && dicPos < limit), | ||
| 207 | RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked. | ||
| 208 | But if (p->buf < bufLimit), the caller provided at least (LZMA_REQUIRED_INPUT_MAX + 1) bytes for | ||
| 209 | next iteration before limit (bufLimit + LZMA_REQUIRED_INPUT_MAX), | ||
| 210 | that is enough for worst case LZMA symbol with one additional RangeCoder normalization for one bit. | ||
| 211 | So that function never reads bufLimit [LZMA_REQUIRED_INPUT_MAX] byte. | ||
| 212 | |||
| 213 | Out: | ||
| 214 | RangeCoder is normalized | ||
| 215 | Result: | ||
| 216 | SZ_OK - OK | ||
| 217 | p->remainLen: | ||
| 218 | < kMatchSpecLenStart : the number of bytes to be copied with (p->reps[0]) offset | ||
| 219 | = kMatchSpecLenStart : the LZMA stream was finished with end mark | ||
| 220 | |||
| 221 | SZ_ERROR_DATA - error, when the MATCH-Symbol refers out of dictionary | ||
| 222 | p->remainLen : undefined | ||
| 223 | p->reps[*] : undefined | ||
| 224 | */ | ||
| 225 | |||
| 226 | |||
| 227 | #ifdef _LZMA_DEC_OPT | ||
| 228 | |||
| 229 | int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit); | ||
| 230 | |||
| 231 | #else | ||
| 232 | |||
| 233 | static | ||
| 234 | int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit) | ||
| 235 | { | ||
| 236 | CLzmaProb *probs = GET_PROBS; | ||
| 237 | unsigned state = (unsigned)p->state; | ||
| 238 | UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; | ||
| 239 | unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; | ||
| 240 | unsigned lc = p->prop.lc; | ||
| 241 | unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc); | ||
| 242 | |||
| 243 | Byte *dic = p->dic; | ||
| 244 | SizeT dicBufSize = p->dicBufSize; | ||
| 245 | SizeT dicPos = p->dicPos; | ||
| 246 | |||
| 247 | UInt32 processedPos = p->processedPos; | ||
| 248 | UInt32 checkDicSize = p->checkDicSize; | ||
| 249 | unsigned len = 0; | ||
| 250 | |||
| 251 | const Byte *buf = p->buf; | ||
| 252 | UInt32 range = p->range; | ||
| 253 | UInt32 code = p->code; | ||
| 254 | |||
| 255 | do | ||
| 256 | { | ||
| 257 | CLzmaProb *prob; | ||
| 258 | UInt32 bound; | ||
| 259 | unsigned ttt; | ||
| 260 | unsigned posState = CALC_POS_STATE(processedPos, pbMask); | ||
| 261 | |||
| 262 | prob = probs + IsMatch + COMBINED_PS_STATE; | ||
| 263 | IF_BIT_0(prob) | ||
| 264 | { | ||
| 265 | unsigned symbol; | ||
| 266 | UPDATE_0(prob); | ||
| 267 | prob = probs + Literal; | ||
| 268 | if (processedPos != 0 || checkDicSize != 0) | ||
| 269 | prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc); | ||
| 270 | processedPos++; | ||
| 271 | |||
| 272 | if (state < kNumLitStates) | ||
| 273 | { | ||
| 274 | state -= (state < 4) ? state : 3; | ||
| 275 | symbol = 1; | ||
| 276 | #ifdef _LZMA_SIZE_OPT | ||
| 277 | do { NORMAL_LITER_DEC } while (symbol < 0x100); | ||
| 278 | #else | ||
| 279 | NORMAL_LITER_DEC | ||
| 280 | NORMAL_LITER_DEC | ||
| 281 | NORMAL_LITER_DEC | ||
| 282 | NORMAL_LITER_DEC | ||
| 283 | NORMAL_LITER_DEC | ||
| 284 | NORMAL_LITER_DEC | ||
| 285 | NORMAL_LITER_DEC | ||
| 286 | NORMAL_LITER_DEC | ||
| 287 | #endif | ||
| 288 | } | ||
| 289 | else | ||
| 290 | { | ||
| 291 | unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; | ||
| 292 | unsigned offs = 0x100; | ||
| 293 | state -= (state < 10) ? 3 : 6; | ||
| 294 | symbol = 1; | ||
| 295 | #ifdef _LZMA_SIZE_OPT | ||
| 296 | do | ||
| 297 | { | ||
| 298 | unsigned bit; | ||
| 299 | CLzmaProb *probLit; | ||
| 300 | MATCHED_LITER_DEC | ||
| 301 | } | ||
| 302 | while (symbol < 0x100); | ||
| 303 | #else | ||
| 304 | { | ||
| 305 | unsigned bit; | ||
| 306 | CLzmaProb *probLit; | ||
| 307 | MATCHED_LITER_DEC | ||
| 308 | MATCHED_LITER_DEC | ||
| 309 | MATCHED_LITER_DEC | ||
| 310 | MATCHED_LITER_DEC | ||
| 311 | MATCHED_LITER_DEC | ||
| 312 | MATCHED_LITER_DEC | ||
| 313 | MATCHED_LITER_DEC | ||
| 314 | MATCHED_LITER_DEC | ||
| 315 | } | ||
| 316 | #endif | ||
| 317 | } | ||
| 318 | |||
| 319 | dic[dicPos++] = (Byte)symbol; | ||
| 320 | continue; | ||
| 321 | } | ||
| 322 | |||
| 323 | { | ||
| 324 | UPDATE_1(prob); | ||
| 325 | prob = probs + IsRep + state; | ||
| 326 | IF_BIT_0(prob) | ||
| 327 | { | ||
| 328 | UPDATE_0(prob); | ||
| 329 | state += kNumStates; | ||
| 330 | prob = probs + LenCoder; | ||
| 331 | } | ||
| 332 | else | ||
| 333 | { | ||
| 334 | UPDATE_1(prob); | ||
| 335 | prob = probs + IsRepG0 + state; | ||
| 336 | IF_BIT_0(prob) | ||
| 337 | { | ||
| 338 | UPDATE_0(prob); | ||
| 339 | prob = probs + IsRep0Long + COMBINED_PS_STATE; | ||
| 340 | IF_BIT_0(prob) | ||
| 341 | { | ||
| 342 | UPDATE_0(prob); | ||
| 343 | |||
| 344 | // that case was checked before with kBadRepCode | ||
| 345 | // if (checkDicSize == 0 && processedPos == 0) { len = kMatchSpecLen_Error_Data + 1; break; } | ||
| 346 | // The caller doesn't allow (dicPos == limit) case here | ||
| 347 | // so we don't need the following check: | ||
| 348 | // if (dicPos == limit) { state = state < kNumLitStates ? 9 : 11; len = 1; break; } | ||
| 349 | |||
| 350 | dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; | ||
| 351 | dicPos++; | ||
| 352 | processedPos++; | ||
| 353 | state = state < kNumLitStates ? 9 : 11; | ||
| 354 | continue; | ||
| 355 | } | ||
| 356 | UPDATE_1(prob); | ||
| 357 | } | ||
| 358 | else | ||
| 359 | { | ||
| 360 | UInt32 distance; | ||
| 361 | UPDATE_1(prob); | ||
| 362 | prob = probs + IsRepG1 + state; | ||
| 363 | IF_BIT_0(prob) | ||
| 364 | { | ||
| 365 | UPDATE_0(prob); | ||
| 366 | distance = rep1; | ||
| 367 | } | ||
| 368 | else | ||
| 369 | { | ||
| 370 | UPDATE_1(prob); | ||
| 371 | prob = probs + IsRepG2 + state; | ||
| 372 | IF_BIT_0(prob) | ||
| 373 | { | ||
| 374 | UPDATE_0(prob); | ||
| 375 | distance = rep2; | ||
| 376 | } | ||
| 377 | else | ||
| 378 | { | ||
| 379 | UPDATE_1(prob); | ||
| 380 | distance = rep3; | ||
| 381 | rep3 = rep2; | ||
| 382 | } | ||
| 383 | rep2 = rep1; | ||
| 384 | } | ||
| 385 | rep1 = rep0; | ||
| 386 | rep0 = distance; | ||
| 387 | } | ||
| 388 | state = state < kNumLitStates ? 8 : 11; | ||
| 389 | prob = probs + RepLenCoder; | ||
| 390 | } | ||
| 391 | |||
| 392 | #ifdef _LZMA_SIZE_OPT | ||
| 393 | { | ||
| 394 | unsigned lim, offset; | ||
| 395 | CLzmaProb *probLen = prob + LenChoice; | ||
| 396 | IF_BIT_0(probLen) | ||
| 397 | { | ||
| 398 | UPDATE_0(probLen); | ||
| 399 | probLen = prob + LenLow + GET_LEN_STATE; | ||
| 400 | offset = 0; | ||
| 401 | lim = (1 << kLenNumLowBits); | ||
| 402 | } | ||
| 403 | else | ||
| 404 | { | ||
| 405 | UPDATE_1(probLen); | ||
| 406 | probLen = prob + LenChoice2; | ||
| 407 | IF_BIT_0(probLen) | ||
| 408 | { | ||
| 409 | UPDATE_0(probLen); | ||
| 410 | probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); | ||
| 411 | offset = kLenNumLowSymbols; | ||
| 412 | lim = (1 << kLenNumLowBits); | ||
| 413 | } | ||
| 414 | else | ||
| 415 | { | ||
| 416 | UPDATE_1(probLen); | ||
| 417 | probLen = prob + LenHigh; | ||
| 418 | offset = kLenNumLowSymbols * 2; | ||
| 419 | lim = (1 << kLenNumHighBits); | ||
| 420 | } | ||
| 421 | } | ||
| 422 | TREE_DECODE(probLen, lim, len); | ||
| 423 | len += offset; | ||
| 424 | } | ||
| 425 | #else | ||
| 426 | { | ||
| 427 | CLzmaProb *probLen = prob + LenChoice; | ||
| 428 | IF_BIT_0(probLen) | ||
| 429 | { | ||
| 430 | UPDATE_0(probLen); | ||
| 431 | probLen = prob + LenLow + GET_LEN_STATE; | ||
| 432 | len = 1; | ||
| 433 | TREE_GET_BIT(probLen, len); | ||
| 434 | TREE_GET_BIT(probLen, len); | ||
| 435 | TREE_GET_BIT(probLen, len); | ||
| 436 | len -= 8; | ||
| 437 | } | ||
| 438 | else | ||
| 439 | { | ||
| 440 | UPDATE_1(probLen); | ||
| 441 | probLen = prob + LenChoice2; | ||
| 442 | IF_BIT_0(probLen) | ||
| 443 | { | ||
| 444 | UPDATE_0(probLen); | ||
| 445 | probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); | ||
| 446 | len = 1; | ||
| 447 | TREE_GET_BIT(probLen, len); | ||
| 448 | TREE_GET_BIT(probLen, len); | ||
| 449 | TREE_GET_BIT(probLen, len); | ||
| 450 | } | ||
| 451 | else | ||
| 452 | { | ||
| 453 | UPDATE_1(probLen); | ||
| 454 | probLen = prob + LenHigh; | ||
| 455 | TREE_DECODE(probLen, (1 << kLenNumHighBits), len); | ||
| 456 | len += kLenNumLowSymbols * 2; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | } | ||
| 460 | #endif | ||
| 461 | |||
| 462 | if (state >= kNumStates) | ||
| 463 | { | ||
| 464 | UInt32 distance; | ||
| 465 | prob = probs + PosSlot + | ||
| 466 | ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); | ||
| 467 | TREE_6_DECODE(prob, distance); | ||
| 468 | if (distance >= kStartPosModelIndex) | ||
| 469 | { | ||
| 470 | unsigned posSlot = (unsigned)distance; | ||
| 471 | unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); | ||
| 472 | distance = (2 | (distance & 1)); | ||
| 473 | if (posSlot < kEndPosModelIndex) | ||
| 474 | { | ||
| 475 | distance <<= numDirectBits; | ||
| 476 | prob = probs + SpecPos; | ||
| 477 | { | ||
| 478 | UInt32 m = 1; | ||
| 479 | distance++; | ||
| 480 | do | ||
| 481 | { | ||
| 482 | REV_BIT_VAR(prob, distance, m); | ||
| 483 | } | ||
| 484 | while (--numDirectBits); | ||
| 485 | distance -= m; | ||
| 486 | } | ||
| 487 | } | ||
| 488 | else | ||
| 489 | { | ||
| 490 | numDirectBits -= kNumAlignBits; | ||
| 491 | do | ||
| 492 | { | ||
| 493 | NORMALIZE | ||
| 494 | range >>= 1; | ||
| 495 | |||
| 496 | { | ||
| 497 | UInt32 t; | ||
| 498 | code -= range; | ||
| 499 | t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ | ||
| 500 | distance = (distance << 1) + (t + 1); | ||
| 501 | code += range & t; | ||
| 502 | } | ||
| 503 | /* | ||
| 504 | distance <<= 1; | ||
| 505 | if (code >= range) | ||
| 506 | { | ||
| 507 | code -= range; | ||
| 508 | distance |= 1; | ||
| 509 | } | ||
| 510 | */ | ||
| 511 | } | ||
| 512 | while (--numDirectBits); | ||
| 513 | prob = probs + Align; | ||
| 514 | distance <<= kNumAlignBits; | ||
| 515 | { | ||
| 516 | unsigned i = 1; | ||
| 517 | REV_BIT_CONST(prob, i, 1); | ||
| 518 | REV_BIT_CONST(prob, i, 2); | ||
| 519 | REV_BIT_CONST(prob, i, 4); | ||
| 520 | REV_BIT_LAST (prob, i, 8); | ||
| 521 | distance |= i; | ||
| 522 | } | ||
| 523 | if (distance == (UInt32)0xFFFFFFFF) | ||
| 524 | { | ||
| 525 | len = kMatchSpecLenStart; | ||
| 526 | state -= kNumStates; | ||
| 527 | break; | ||
| 528 | } | ||
| 529 | } | ||
| 530 | } | ||
| 531 | |||
| 532 | rep3 = rep2; | ||
| 533 | rep2 = rep1; | ||
| 534 | rep1 = rep0; | ||
| 535 | rep0 = distance + 1; | ||
| 536 | state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; | ||
| 537 | if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize)) | ||
| 538 | { | ||
| 539 | len += kMatchSpecLen_Error_Data + kMatchMinLen; | ||
| 540 | // len = kMatchSpecLen_Error_Data; | ||
| 541 | // len += kMatchMinLen; | ||
| 542 | break; | ||
| 543 | } | ||
| 544 | } | ||
| 545 | |||
| 546 | len += kMatchMinLen; | ||
| 547 | |||
| 548 | { | ||
| 549 | SizeT rem; | ||
| 550 | unsigned curLen; | ||
| 551 | SizeT pos; | ||
| 552 | |||
| 553 | if ((rem = limit - dicPos) == 0) | ||
| 554 | { | ||
| 555 | /* | ||
| 556 | We stop decoding and return SZ_OK, and we can resume decoding later. | ||
| 557 | Any error conditions can be tested later in caller code. | ||
| 558 | For more strict mode we can stop decoding with error | ||
| 559 | // len += kMatchSpecLen_Error_Data; | ||
| 560 | */ | ||
| 561 | break; | ||
| 562 | } | ||
| 563 | |||
| 564 | curLen = ((rem < len) ? (unsigned)rem : len); | ||
| 565 | pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); | ||
| 566 | |||
| 567 | processedPos += (UInt32)curLen; | ||
| 568 | |||
| 569 | len -= curLen; | ||
| 570 | if (curLen <= dicBufSize - pos) | ||
| 571 | { | ||
| 572 | Byte *dest = dic + dicPos; | ||
| 573 | ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; | ||
| 574 | const Byte *lim = dest + curLen; | ||
| 575 | dicPos += (SizeT)curLen; | ||
| 576 | do | ||
| 577 | *(dest) = (Byte)*(dest + src); | ||
| 578 | while (++dest != lim); | ||
| 579 | } | ||
| 580 | else | ||
| 581 | { | ||
| 582 | do | ||
| 583 | { | ||
| 584 | dic[dicPos++] = dic[pos]; | ||
| 585 | if (++pos == dicBufSize) | ||
| 586 | pos = 0; | ||
| 587 | } | ||
| 588 | while (--curLen != 0); | ||
| 589 | } | ||
| 590 | } | ||
| 591 | } | ||
| 592 | } | ||
| 593 | while (dicPos < limit && buf < bufLimit); | ||
| 594 | |||
| 595 | NORMALIZE; | ||
| 596 | |||
| 597 | p->buf = buf; | ||
| 598 | p->range = range; | ||
| 599 | p->code = code; | ||
| 600 | p->remainLen = (UInt32)len; // & (kMatchSpecLen_Error_Data - 1); // we can write real length for error matches too. | ||
| 601 | p->dicPos = dicPos; | ||
| 602 | p->processedPos = processedPos; | ||
| 603 | p->reps[0] = rep0; | ||
| 604 | p->reps[1] = rep1; | ||
| 605 | p->reps[2] = rep2; | ||
| 606 | p->reps[3] = rep3; | ||
| 607 | p->state = (UInt32)state; | ||
| 608 | if (len >= kMatchSpecLen_Error_Data) | ||
| 609 | return SZ_ERROR_DATA; | ||
| 610 | return SZ_OK; | ||
| 611 | } | ||
| 612 | #endif | ||
| 613 | |||
| 614 | |||
| 615 | |||
| 616 | static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) | ||
| 617 | { | ||
| 618 | unsigned len = (unsigned)p->remainLen; | ||
| 619 | if (len == 0 /* || len >= kMatchSpecLenStart */) | ||
| 620 | return; | ||
| 621 | { | ||
| 622 | SizeT dicPos = p->dicPos; | ||
| 623 | Byte *dic; | ||
| 624 | SizeT dicBufSize; | ||
| 625 | SizeT rep0; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ | ||
| 626 | { | ||
| 627 | SizeT rem = limit - dicPos; | ||
| 628 | if (rem < len) | ||
| 629 | { | ||
| 630 | len = (unsigned)(rem); | ||
| 631 | if (len == 0) | ||
| 632 | return; | ||
| 633 | } | ||
| 634 | } | ||
| 635 | |||
| 636 | if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) | ||
| 637 | p->checkDicSize = p->prop.dicSize; | ||
| 638 | |||
| 639 | p->processedPos += (UInt32)len; | ||
| 640 | p->remainLen -= (UInt32)len; | ||
| 641 | dic = p->dic; | ||
| 642 | rep0 = p->reps[0]; | ||
| 643 | dicBufSize = p->dicBufSize; | ||
| 644 | do | ||
| 645 | { | ||
| 646 | dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; | ||
| 647 | dicPos++; | ||
| 648 | } | ||
| 649 | while (--len); | ||
| 650 | p->dicPos = dicPos; | ||
| 651 | } | ||
| 652 | } | ||
| 653 | |||
| 654 | |||
| 655 | /* | ||
| 656 | At staring of new stream we have one of the following symbols: | ||
| 657 | - Literal - is allowed | ||
| 658 | - Non-Rep-Match - is allowed only if it's end marker symbol | ||
| 659 | - Rep-Match - is not allowed | ||
| 660 | We use early check of (RangeCoder:Code) over kBadRepCode to simplify main decoding code | ||
| 661 | */ | ||
| 662 | |||
| 663 | #define kRange0 0xFFFFFFFF | ||
| 664 | #define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)) | ||
| 665 | #define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))) | ||
| 666 | #if kBadRepCode != (0xC0000000 - 0x400) | ||
| 667 | #error Stop_Compiling_Bad_LZMA_Check | ||
| 668 | #endif | ||
| 669 | |||
| 670 | |||
| 671 | /* | ||
| 672 | LzmaDec_DecodeReal2(): | ||
| 673 | It calls LZMA_DECODE_REAL() and it adjusts limit according (p->checkDicSize). | ||
| 674 | |||
| 675 | We correct (p->checkDicSize) after LZMA_DECODE_REAL() and in LzmaDec_WriteRem(), | ||
| 676 | and we support the following state of (p->checkDicSize): | ||
| 677 | if (total_processed < p->prop.dicSize) then | ||
| 678 | { | ||
| 679 | (total_processed == p->processedPos) | ||
| 680 | (p->checkDicSize == 0) | ||
| 681 | } | ||
| 682 | else | ||
| 683 | (p->checkDicSize == p->prop.dicSize) | ||
| 684 | */ | ||
| 685 | |||
| 686 | static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) | ||
| 687 | { | ||
| 688 | if (p->checkDicSize == 0) | ||
| 689 | { | ||
| 690 | UInt32 rem = p->prop.dicSize - p->processedPos; | ||
| 691 | if (limit - p->dicPos > rem) | ||
| 692 | limit = p->dicPos + rem; | ||
| 693 | } | ||
| 694 | { | ||
| 695 | int res = LZMA_DECODE_REAL(p, limit, bufLimit); | ||
| 696 | if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) | ||
| 697 | p->checkDicSize = p->prop.dicSize; | ||
| 698 | return res; | ||
| 699 | } | ||
| 700 | } | ||
| 701 | |||
| 702 | |||
| 703 | |||
| 704 | typedef enum | ||
| 705 | { | ||
| 706 | DUMMY_INPUT_EOF, /* need more input data */ | ||
| 707 | DUMMY_LIT, | ||
| 708 | DUMMY_MATCH, | ||
| 709 | DUMMY_REP | ||
| 710 | } ELzmaDummy; | ||
| 711 | |||
| 712 | |||
| 713 | #define IS_DUMMY_END_MARKER_POSSIBLE(dummyRes) ((dummyRes) == DUMMY_MATCH) | ||
| 714 | |||
| 715 | static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, const Byte **bufOut) | ||
| 716 | { | ||
| 717 | UInt32 range = p->range; | ||
| 718 | UInt32 code = p->code; | ||
| 719 | const Byte *bufLimit = *bufOut; | ||
| 720 | const CLzmaProb *probs = GET_PROBS; | ||
| 721 | unsigned state = (unsigned)p->state; | ||
| 722 | ELzmaDummy res; | ||
| 723 | |||
| 724 | for (;;) | ||
| 725 | { | ||
| 726 | const CLzmaProb *prob; | ||
| 727 | UInt32 bound; | ||
| 728 | unsigned ttt; | ||
| 729 | unsigned posState = CALC_POS_STATE(p->processedPos, ((unsigned)1 << p->prop.pb) - 1); | ||
| 730 | |||
| 731 | prob = probs + IsMatch + COMBINED_PS_STATE; | ||
| 732 | IF_BIT_0_CHECK(prob) | ||
| 733 | { | ||
| 734 | UPDATE_0_CHECK | ||
| 735 | |||
| 736 | prob = probs + Literal; | ||
| 737 | if (p->checkDicSize != 0 || p->processedPos != 0) | ||
| 738 | prob += ((UInt32)LZMA_LIT_SIZE * | ||
| 739 | ((((p->processedPos) & (((unsigned)1 << (p->prop.lp)) - 1)) << p->prop.lc) + | ||
| 740 | ((unsigned)p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); | ||
| 741 | |||
| 742 | if (state < kNumLitStates) | ||
| 743 | { | ||
| 744 | unsigned symbol = 1; | ||
| 745 | do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); | ||
| 746 | } | ||
| 747 | else | ||
| 748 | { | ||
| 749 | unsigned matchByte = p->dic[p->dicPos - p->reps[0] + | ||
| 750 | (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; | ||
| 751 | unsigned offs = 0x100; | ||
| 752 | unsigned symbol = 1; | ||
| 753 | do | ||
| 754 | { | ||
| 755 | unsigned bit; | ||
| 756 | const CLzmaProb *probLit; | ||
| 757 | matchByte += matchByte; | ||
| 758 | bit = offs; | ||
| 759 | offs &= matchByte; | ||
| 760 | probLit = prob + (offs + bit + symbol); | ||
| 761 | GET_BIT2_CHECK(probLit, symbol, offs ^= bit; , ; ) | ||
| 762 | } | ||
| 763 | while (symbol < 0x100); | ||
| 764 | } | ||
| 765 | res = DUMMY_LIT; | ||
| 766 | } | ||
| 767 | else | ||
| 768 | { | ||
| 769 | unsigned len; | ||
| 770 | UPDATE_1_CHECK; | ||
| 771 | |||
| 772 | prob = probs + IsRep + state; | ||
| 773 | IF_BIT_0_CHECK(prob) | ||
| 774 | { | ||
| 775 | UPDATE_0_CHECK; | ||
| 776 | state = 0; | ||
| 777 | prob = probs + LenCoder; | ||
| 778 | res = DUMMY_MATCH; | ||
| 779 | } | ||
| 780 | else | ||
| 781 | { | ||
| 782 | UPDATE_1_CHECK; | ||
| 783 | res = DUMMY_REP; | ||
| 784 | prob = probs + IsRepG0 + state; | ||
| 785 | IF_BIT_0_CHECK(prob) | ||
| 786 | { | ||
| 787 | UPDATE_0_CHECK; | ||
| 788 | prob = probs + IsRep0Long + COMBINED_PS_STATE; | ||
| 789 | IF_BIT_0_CHECK(prob) | ||
| 790 | { | ||
| 791 | UPDATE_0_CHECK; | ||
| 792 | break; | ||
| 793 | } | ||
| 794 | else | ||
| 795 | { | ||
| 796 | UPDATE_1_CHECK; | ||
| 797 | } | ||
| 798 | } | ||
| 799 | else | ||
| 800 | { | ||
| 801 | UPDATE_1_CHECK; | ||
| 802 | prob = probs + IsRepG1 + state; | ||
| 803 | IF_BIT_0_CHECK(prob) | ||
| 804 | { | ||
| 805 | UPDATE_0_CHECK; | ||
| 806 | } | ||
| 807 | else | ||
| 808 | { | ||
| 809 | UPDATE_1_CHECK; | ||
| 810 | prob = probs + IsRepG2 + state; | ||
| 811 | IF_BIT_0_CHECK(prob) | ||
| 812 | { | ||
| 813 | UPDATE_0_CHECK; | ||
| 814 | } | ||
| 815 | else | ||
| 816 | { | ||
| 817 | UPDATE_1_CHECK; | ||
| 818 | } | ||
| 819 | } | ||
| 820 | } | ||
| 821 | state = kNumStates; | ||
| 822 | prob = probs + RepLenCoder; | ||
| 823 | } | ||
| 824 | { | ||
| 825 | unsigned limit, offset; | ||
| 826 | const CLzmaProb *probLen = prob + LenChoice; | ||
| 827 | IF_BIT_0_CHECK(probLen) | ||
| 828 | { | ||
| 829 | UPDATE_0_CHECK; | ||
| 830 | probLen = prob + LenLow + GET_LEN_STATE; | ||
| 831 | offset = 0; | ||
| 832 | limit = 1 << kLenNumLowBits; | ||
| 833 | } | ||
| 834 | else | ||
| 835 | { | ||
| 836 | UPDATE_1_CHECK; | ||
| 837 | probLen = prob + LenChoice2; | ||
| 838 | IF_BIT_0_CHECK(probLen) | ||
| 839 | { | ||
| 840 | UPDATE_0_CHECK; | ||
| 841 | probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); | ||
| 842 | offset = kLenNumLowSymbols; | ||
| 843 | limit = 1 << kLenNumLowBits; | ||
| 844 | } | ||
| 845 | else | ||
| 846 | { | ||
| 847 | UPDATE_1_CHECK; | ||
| 848 | probLen = prob + LenHigh; | ||
| 849 | offset = kLenNumLowSymbols * 2; | ||
| 850 | limit = 1 << kLenNumHighBits; | ||
| 851 | } | ||
| 852 | } | ||
| 853 | TREE_DECODE_CHECK(probLen, limit, len); | ||
| 854 | len += offset; | ||
| 855 | } | ||
| 856 | |||
| 857 | if (state < 4) | ||
| 858 | { | ||
| 859 | unsigned posSlot; | ||
| 860 | prob = probs + PosSlot + | ||
| 861 | ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << | ||
| 862 | kNumPosSlotBits); | ||
| 863 | TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); | ||
| 864 | if (posSlot >= kStartPosModelIndex) | ||
| 865 | { | ||
| 866 | unsigned numDirectBits = ((posSlot >> 1) - 1); | ||
| 867 | |||
| 868 | if (posSlot < kEndPosModelIndex) | ||
| 869 | { | ||
| 870 | prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits); | ||
| 871 | } | ||
| 872 | else | ||
| 873 | { | ||
| 874 | numDirectBits -= kNumAlignBits; | ||
| 875 | do | ||
| 876 | { | ||
| 877 | NORMALIZE_CHECK | ||
| 878 | range >>= 1; | ||
| 879 | code -= range & (((code - range) >> 31) - 1); | ||
| 880 | /* if (code >= range) code -= range; */ | ||
| 881 | } | ||
| 882 | while (--numDirectBits); | ||
| 883 | prob = probs + Align; | ||
| 884 | numDirectBits = kNumAlignBits; | ||
| 885 | } | ||
| 886 | { | ||
| 887 | unsigned i = 1; | ||
| 888 | unsigned m = 1; | ||
| 889 | do | ||
| 890 | { | ||
| 891 | REV_BIT_CHECK(prob, i, m); | ||
| 892 | } | ||
| 893 | while (--numDirectBits); | ||
| 894 | } | ||
| 895 | } | ||
| 896 | } | ||
| 897 | } | ||
| 898 | break; | ||
| 899 | } | ||
| 900 | NORMALIZE_CHECK; | ||
| 901 | |||
| 902 | *bufOut = buf; | ||
| 903 | return res; | ||
| 904 | } | ||
| 905 | |||
| 906 | void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState); | ||
| 907 | void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState) | ||
| 908 | { | ||
| 909 | p->remainLen = kMatchSpecLenStart + 1; | ||
| 910 | p->tempBufSize = 0; | ||
| 911 | |||
| 912 | if (initDic) | ||
| 913 | { | ||
| 914 | p->processedPos = 0; | ||
| 915 | p->checkDicSize = 0; | ||
| 916 | p->remainLen = kMatchSpecLenStart + 2; | ||
| 917 | } | ||
| 918 | if (initState) | ||
| 919 | p->remainLen = kMatchSpecLenStart + 2; | ||
| 920 | } | ||
| 921 | |||
| 922 | void LzmaDec_Init(CLzmaDec *p) | ||
| 923 | { | ||
| 924 | p->dicPos = 0; | ||
| 925 | LzmaDec_InitDicAndState(p, True, True); | ||
| 926 | } | ||
| 927 | |||
| 928 | |||
| 929 | /* | ||
| 930 | LZMA supports optional end_marker. | ||
| 931 | So the decoder can lookahead for one additional LZMA-Symbol to check end_marker. | ||
| 932 | That additional LZMA-Symbol can require up to LZMA_REQUIRED_INPUT_MAX bytes in input stream. | ||
| 933 | When the decoder reaches dicLimit, it looks (finishMode) parameter: | ||
| 934 | if (finishMode == LZMA_FINISH_ANY), the decoder doesn't lookahead | ||
| 935 | if (finishMode != LZMA_FINISH_ANY), the decoder lookahead, if end_marker is possible for current position | ||
| 936 | |||
| 937 | When the decoder lookahead, and the lookahead symbol is not end_marker, we have two ways: | ||
| 938 | 1) Strict mode (default) : the decoder returns SZ_ERROR_DATA. | ||
| 939 | 2) The relaxed mode (alternative mode) : we could return SZ_OK, and the caller | ||
| 940 | must check (status) value. The caller can show the error, | ||
| 941 | if the end of stream is expected, and the (status) is noit | ||
| 942 | LZMA_STATUS_FINISHED_WITH_MARK or LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK. | ||
| 943 | */ | ||
| 944 | |||
| 945 | |||
| 946 | #define RETURN__NOT_FINISHED__FOR_FINISH \ | ||
| 947 | *status = LZMA_STATUS_NOT_FINISHED; \ | ||
| 948 | return SZ_ERROR_DATA; // for strict mode | ||
| 949 | // return SZ_OK; // for relaxed mode | ||
| 950 | |||
| 951 | |||
| 952 | SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, | ||
| 953 | ELzmaFinishMode finishMode, ELzmaStatus *status) | ||
| 954 | { | ||
| 955 | SizeT inSize = *srcLen; | ||
| 956 | (*srcLen) = 0; | ||
| 957 | *status = LZMA_STATUS_NOT_SPECIFIED; | ||
| 958 | |||
| 959 | if (p->remainLen > kMatchSpecLenStart) | ||
| 960 | { | ||
| 961 | if (p->remainLen > kMatchSpecLenStart + 2) | ||
| 962 | return p->remainLen == kMatchSpecLen_Error_Fail ? SZ_ERROR_FAIL : SZ_ERROR_DATA; | ||
| 963 | |||
| 964 | for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) | ||
| 965 | p->tempBuf[p->tempBufSize++] = *src++; | ||
| 966 | if (p->tempBufSize != 0 && p->tempBuf[0] != 0) | ||
| 967 | return SZ_ERROR_DATA; | ||
| 968 | if (p->tempBufSize < RC_INIT_SIZE) | ||
| 969 | { | ||
| 970 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; | ||
| 971 | return SZ_OK; | ||
| 972 | } | ||
| 973 | p->code = | ||
| 974 | ((UInt32)p->tempBuf[1] << 24) | ||
| 975 | | ((UInt32)p->tempBuf[2] << 16) | ||
| 976 | | ((UInt32)p->tempBuf[3] << 8) | ||
| 977 | | ((UInt32)p->tempBuf[4]); | ||
| 978 | |||
| 979 | if (p->checkDicSize == 0 | ||
| 980 | && p->processedPos == 0 | ||
| 981 | && p->code >= kBadRepCode) | ||
| 982 | return SZ_ERROR_DATA; | ||
| 983 | |||
| 984 | p->range = 0xFFFFFFFF; | ||
| 985 | p->tempBufSize = 0; | ||
| 986 | |||
| 987 | if (p->remainLen > kMatchSpecLenStart + 1) | ||
| 988 | { | ||
| 989 | SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); | ||
| 990 | SizeT i; | ||
| 991 | CLzmaProb *probs = p->probs; | ||
| 992 | for (i = 0; i < numProbs; i++) | ||
| 993 | probs[i] = kBitModelTotal >> 1; | ||
| 994 | p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; | ||
| 995 | p->state = 0; | ||
| 996 | } | ||
| 997 | |||
| 998 | p->remainLen = 0; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | for (;;) | ||
| 1002 | { | ||
| 1003 | if (p->remainLen == kMatchSpecLenStart) | ||
| 1004 | { | ||
| 1005 | if (p->code != 0) | ||
| 1006 | return SZ_ERROR_DATA; | ||
| 1007 | *status = LZMA_STATUS_FINISHED_WITH_MARK; | ||
| 1008 | return SZ_OK; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | LzmaDec_WriteRem(p, dicLimit); | ||
| 1012 | |||
| 1013 | { | ||
| 1014 | // (p->remainLen == 0 || p->dicPos == dicLimit) | ||
| 1015 | |||
| 1016 | int checkEndMarkNow = 0; | ||
| 1017 | |||
| 1018 | if (p->dicPos >= dicLimit) | ||
| 1019 | { | ||
| 1020 | if (p->remainLen == 0 && p->code == 0) | ||
| 1021 | { | ||
| 1022 | *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; | ||
| 1023 | return SZ_OK; | ||
| 1024 | } | ||
| 1025 | if (finishMode == LZMA_FINISH_ANY) | ||
| 1026 | { | ||
| 1027 | *status = LZMA_STATUS_NOT_FINISHED; | ||
| 1028 | return SZ_OK; | ||
| 1029 | } | ||
| 1030 | if (p->remainLen != 0) | ||
| 1031 | { | ||
| 1032 | RETURN__NOT_FINISHED__FOR_FINISH; | ||
| 1033 | } | ||
| 1034 | checkEndMarkNow = 1; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | // (p->remainLen == 0) | ||
| 1038 | |||
| 1039 | if (p->tempBufSize == 0) | ||
| 1040 | { | ||
| 1041 | const Byte *bufLimit; | ||
| 1042 | int dummyProcessed = -1; | ||
| 1043 | |||
| 1044 | if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) | ||
| 1045 | { | ||
| 1046 | const Byte *bufOut = src + inSize; | ||
| 1047 | |||
| 1048 | ELzmaDummy dummyRes = LzmaDec_TryDummy(p, src, &bufOut); | ||
| 1049 | |||
| 1050 | if (dummyRes == DUMMY_INPUT_EOF) | ||
| 1051 | { | ||
| 1052 | size_t i; | ||
| 1053 | if (inSize >= LZMA_REQUIRED_INPUT_MAX) | ||
| 1054 | break; | ||
| 1055 | (*srcLen) += inSize; | ||
| 1056 | p->tempBufSize = (unsigned)inSize; | ||
| 1057 | for (i = 0; i < inSize; i++) | ||
| 1058 | p->tempBuf[i] = src[i]; | ||
| 1059 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; | ||
| 1060 | return SZ_OK; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | dummyProcessed = (int)(bufOut - src); | ||
| 1064 | if ((unsigned)dummyProcessed > LZMA_REQUIRED_INPUT_MAX) | ||
| 1065 | break; | ||
| 1066 | |||
| 1067 | if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes)) | ||
| 1068 | { | ||
| 1069 | unsigned i; | ||
| 1070 | (*srcLen) += (unsigned)dummyProcessed; | ||
| 1071 | p->tempBufSize = (unsigned)dummyProcessed; | ||
| 1072 | for (i = 0; i < (unsigned)dummyProcessed; i++) | ||
| 1073 | p->tempBuf[i] = src[i]; | ||
| 1074 | // p->remainLen = kMatchSpecLen_Error_Data; | ||
| 1075 | RETURN__NOT_FINISHED__FOR_FINISH; | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | bufLimit = src; | ||
| 1079 | // we will decode only one iteration | ||
| 1080 | } | ||
| 1081 | else | ||
| 1082 | bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; | ||
| 1083 | |||
| 1084 | p->buf = src; | ||
| 1085 | |||
| 1086 | { | ||
| 1087 | int res = LzmaDec_DecodeReal2(p, dicLimit, bufLimit); | ||
| 1088 | |||
| 1089 | SizeT processed = (SizeT)(p->buf - src); | ||
| 1090 | |||
| 1091 | if (dummyProcessed < 0) | ||
| 1092 | { | ||
| 1093 | if (processed > inSize) | ||
| 1094 | break; | ||
| 1095 | } | ||
| 1096 | else if ((unsigned)dummyProcessed != processed) | ||
| 1097 | break; | ||
| 1098 | |||
| 1099 | src += processed; | ||
| 1100 | inSize -= processed; | ||
| 1101 | (*srcLen) += processed; | ||
| 1102 | |||
| 1103 | if (res != SZ_OK) | ||
| 1104 | { | ||
| 1105 | p->remainLen = kMatchSpecLen_Error_Data; | ||
| 1106 | return SZ_ERROR_DATA; | ||
| 1107 | } | ||
| 1108 | } | ||
| 1109 | continue; | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | { | ||
| 1113 | // we have some data in (p->tempBuf) | ||
| 1114 | // in strict mode: tempBufSize is not enough for one Symbol decoding. | ||
| 1115 | // in relaxed mode: tempBufSize not larger than required for one Symbol decoding. | ||
| 1116 | |||
| 1117 | unsigned rem = p->tempBufSize; | ||
| 1118 | unsigned ahead = 0; | ||
| 1119 | int dummyProcessed = -1; | ||
| 1120 | |||
| 1121 | while (rem < LZMA_REQUIRED_INPUT_MAX && ahead < inSize) | ||
| 1122 | p->tempBuf[rem++] = src[ahead++]; | ||
| 1123 | |||
| 1124 | // ahead - the size of new data copied from (src) to (p->tempBuf) | ||
| 1125 | // rem - the size of temp buffer including new data from (src) | ||
| 1126 | |||
| 1127 | if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) | ||
| 1128 | { | ||
| 1129 | const Byte *bufOut = p->tempBuf + rem; | ||
| 1130 | |||
| 1131 | ELzmaDummy dummyRes = LzmaDec_TryDummy(p, p->tempBuf, &bufOut); | ||
| 1132 | |||
| 1133 | if (dummyRes == DUMMY_INPUT_EOF) | ||
| 1134 | { | ||
| 1135 | if (rem >= LZMA_REQUIRED_INPUT_MAX) | ||
| 1136 | break; | ||
| 1137 | p->tempBufSize = rem; | ||
| 1138 | (*srcLen) += (SizeT)ahead; | ||
| 1139 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; | ||
| 1140 | return SZ_OK; | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | dummyProcessed = (int)(bufOut - p->tempBuf); | ||
| 1144 | |||
| 1145 | if ((unsigned)dummyProcessed < p->tempBufSize) | ||
| 1146 | break; | ||
| 1147 | |||
| 1148 | if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes)) | ||
| 1149 | { | ||
| 1150 | (*srcLen) += (unsigned)dummyProcessed - p->tempBufSize; | ||
| 1151 | p->tempBufSize = (unsigned)dummyProcessed; | ||
| 1152 | // p->remainLen = kMatchSpecLen_Error_Data; | ||
| 1153 | RETURN__NOT_FINISHED__FOR_FINISH; | ||
| 1154 | } | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | p->buf = p->tempBuf; | ||
| 1158 | |||
| 1159 | { | ||
| 1160 | // we decode one symbol from (p->tempBuf) here, so the (bufLimit) is equal to (p->buf) | ||
| 1161 | int res = LzmaDec_DecodeReal2(p, dicLimit, p->buf); | ||
| 1162 | |||
| 1163 | SizeT processed = (SizeT)(p->buf - p->tempBuf); | ||
| 1164 | rem = p->tempBufSize; | ||
| 1165 | |||
| 1166 | if (dummyProcessed < 0) | ||
| 1167 | { | ||
| 1168 | if (processed > LZMA_REQUIRED_INPUT_MAX) | ||
| 1169 | break; | ||
| 1170 | if (processed < rem) | ||
| 1171 | break; | ||
| 1172 | } | ||
| 1173 | else if ((unsigned)dummyProcessed != processed) | ||
| 1174 | break; | ||
| 1175 | |||
| 1176 | processed -= rem; | ||
| 1177 | |||
| 1178 | src += processed; | ||
| 1179 | inSize -= processed; | ||
| 1180 | (*srcLen) += processed; | ||
| 1181 | p->tempBufSize = 0; | ||
| 1182 | |||
| 1183 | if (res != SZ_OK) | ||
| 1184 | { | ||
| 1185 | p->remainLen = kMatchSpecLen_Error_Data; | ||
| 1186 | return SZ_ERROR_DATA; | ||
| 1187 | } | ||
| 1188 | } | ||
| 1189 | } | ||
| 1190 | } | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | /* Some unexpected error: internal error of code, memory corruption or hardware failure */ | ||
| 1194 | p->remainLen = kMatchSpecLen_Error_Fail; | ||
| 1195 | return SZ_ERROR_FAIL; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | |||
| 1199 | |||
| 1200 | SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) | ||
| 1201 | { | ||
| 1202 | SizeT outSize = *destLen; | ||
| 1203 | SizeT inSize = *srcLen; | ||
| 1204 | *srcLen = *destLen = 0; | ||
| 1205 | for (;;) | ||
| 1206 | { | ||
| 1207 | SizeT inSizeCur = inSize, outSizeCur, dicPos; | ||
| 1208 | ELzmaFinishMode curFinishMode; | ||
| 1209 | SRes res; | ||
| 1210 | if (p->dicPos == p->dicBufSize) | ||
| 1211 | p->dicPos = 0; | ||
| 1212 | dicPos = p->dicPos; | ||
| 1213 | if (outSize > p->dicBufSize - dicPos) | ||
| 1214 | { | ||
| 1215 | outSizeCur = p->dicBufSize; | ||
| 1216 | curFinishMode = LZMA_FINISH_ANY; | ||
| 1217 | } | ||
| 1218 | else | ||
| 1219 | { | ||
| 1220 | outSizeCur = dicPos + outSize; | ||
| 1221 | curFinishMode = finishMode; | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); | ||
| 1225 | src += inSizeCur; | ||
| 1226 | inSize -= inSizeCur; | ||
| 1227 | *srcLen += inSizeCur; | ||
| 1228 | outSizeCur = p->dicPos - dicPos; | ||
| 1229 | memcpy(dest, p->dic + dicPos, outSizeCur); | ||
| 1230 | dest += outSizeCur; | ||
| 1231 | outSize -= outSizeCur; | ||
| 1232 | *destLen += outSizeCur; | ||
| 1233 | if (res != 0) | ||
| 1234 | return res; | ||
| 1235 | if (outSizeCur == 0 || outSize == 0) | ||
| 1236 | return SZ_OK; | ||
| 1237 | } | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc) | ||
| 1241 | { | ||
| 1242 | ISzAlloc_Free(alloc, p->probs); | ||
| 1243 | p->probs = NULL; | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc) | ||
| 1247 | { | ||
| 1248 | ISzAlloc_Free(alloc, p->dic); | ||
| 1249 | p->dic = NULL; | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc) | ||
| 1253 | { | ||
| 1254 | LzmaDec_FreeProbs(p, alloc); | ||
| 1255 | LzmaDec_FreeDict(p, alloc); | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) | ||
| 1259 | { | ||
| 1260 | UInt32 dicSize; | ||
| 1261 | Byte d; | ||
| 1262 | |||
| 1263 | if (size < LZMA_PROPS_SIZE) | ||
| 1264 | return SZ_ERROR_UNSUPPORTED; | ||
| 1265 | else | ||
| 1266 | dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); | ||
| 1267 | |||
| 1268 | if (dicSize < LZMA_DIC_MIN) | ||
| 1269 | dicSize = LZMA_DIC_MIN; | ||
| 1270 | p->dicSize = dicSize; | ||
| 1271 | |||
| 1272 | d = data[0]; | ||
| 1273 | if (d >= (9 * 5 * 5)) | ||
| 1274 | return SZ_ERROR_UNSUPPORTED; | ||
| 1275 | |||
| 1276 | p->lc = (Byte)(d % 9); | ||
| 1277 | d /= 9; | ||
| 1278 | p->pb = (Byte)(d / 5); | ||
| 1279 | p->lp = (Byte)(d % 5); | ||
| 1280 | |||
| 1281 | return SZ_OK; | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc) | ||
| 1285 | { | ||
| 1286 | UInt32 numProbs = LzmaProps_GetNumProbs(propNew); | ||
| 1287 | if (!p->probs || numProbs != p->numProbs) | ||
| 1288 | { | ||
| 1289 | LzmaDec_FreeProbs(p, alloc); | ||
| 1290 | p->probs = (CLzmaProb *)ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb)); | ||
| 1291 | if (!p->probs) | ||
| 1292 | return SZ_ERROR_MEM; | ||
| 1293 | p->probs_1664 = p->probs + 1664; | ||
| 1294 | p->numProbs = numProbs; | ||
| 1295 | } | ||
| 1296 | return SZ_OK; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) | ||
| 1300 | { | ||
| 1301 | CLzmaProps propNew; | ||
| 1302 | RINOK(LzmaProps_Decode(&propNew, props, propsSize)); | ||
| 1303 | RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); | ||
| 1304 | p->prop = propNew; | ||
| 1305 | return SZ_OK; | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) | ||
| 1309 | { | ||
| 1310 | CLzmaProps propNew; | ||
| 1311 | SizeT dicBufSize; | ||
| 1312 | RINOK(LzmaProps_Decode(&propNew, props, propsSize)); | ||
| 1313 | RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); | ||
| 1314 | |||
| 1315 | { | ||
| 1316 | UInt32 dictSize = propNew.dicSize; | ||
| 1317 | SizeT mask = ((UInt32)1 << 12) - 1; | ||
| 1318 | if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; | ||
| 1319 | else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;; | ||
| 1320 | dicBufSize = ((SizeT)dictSize + mask) & ~mask; | ||
| 1321 | if (dicBufSize < dictSize) | ||
| 1322 | dicBufSize = dictSize; | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | if (!p->dic || dicBufSize != p->dicBufSize) | ||
| 1326 | { | ||
| 1327 | LzmaDec_FreeDict(p, alloc); | ||
| 1328 | p->dic = (Byte *)ISzAlloc_Alloc(alloc, dicBufSize); | ||
| 1329 | if (!p->dic) | ||
| 1330 | { | ||
| 1331 | LzmaDec_FreeProbs(p, alloc); | ||
| 1332 | return SZ_ERROR_MEM; | ||
| 1333 | } | ||
| 1334 | } | ||
| 1335 | p->dicBufSize = dicBufSize; | ||
| 1336 | p->prop = propNew; | ||
| 1337 | return SZ_OK; | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, | ||
| 1341 | const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, | ||
| 1342 | ELzmaStatus *status, ISzAllocPtr alloc) | ||
| 1343 | { | ||
| 1344 | CLzmaDec p; | ||
| 1345 | SRes res; | ||
| 1346 | SizeT outSize = *destLen, inSize = *srcLen; | ||
| 1347 | *destLen = *srcLen = 0; | ||
| 1348 | *status = LZMA_STATUS_NOT_SPECIFIED; | ||
| 1349 | if (inSize < RC_INIT_SIZE) | ||
| 1350 | return SZ_ERROR_INPUT_EOF; | ||
| 1351 | LzmaDec_Construct(&p); | ||
| 1352 | RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); | ||
| 1353 | p.dic = dest; | ||
| 1354 | p.dicBufSize = outSize; | ||
| 1355 | LzmaDec_Init(&p); | ||
| 1356 | *srcLen = inSize; | ||
| 1357 | res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); | ||
| 1358 | *destLen = p.dicPos; | ||
| 1359 | if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) | ||
| 1360 | res = SZ_ERROR_INPUT_EOF; | ||
| 1361 | LzmaDec_FreeProbs(&p, alloc); | ||
| 1362 | return res; | ||
| 1363 | } | ||
diff --git a/C/LzmaDec.h b/C/LzmaDec.h new file mode 100644 index 0000000..6f12962 --- /dev/null +++ b/C/LzmaDec.h | |||
| @@ -0,0 +1,236 @@ | |||
| 1 | /* LzmaDec.h -- LZMA Decoder | ||
| 2 | 2020-03-19 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __LZMA_DEC_H | ||
| 5 | #define __LZMA_DEC_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | /* #define _LZMA_PROB32 */ | ||
| 12 | /* _LZMA_PROB32 can increase the speed on some CPUs, | ||
| 13 | but memory usage for CLzmaDec::probs will be doubled in that case */ | ||
| 14 | |||
| 15 | typedef | ||
| 16 | #ifdef _LZMA_PROB32 | ||
| 17 | UInt32 | ||
| 18 | #else | ||
| 19 | UInt16 | ||
| 20 | #endif | ||
| 21 | CLzmaProb; | ||
| 22 | |||
| 23 | |||
| 24 | /* ---------- LZMA Properties ---------- */ | ||
| 25 | |||
| 26 | #define LZMA_PROPS_SIZE 5 | ||
| 27 | |||
| 28 | typedef struct _CLzmaProps | ||
| 29 | { | ||
| 30 | Byte lc; | ||
| 31 | Byte lp; | ||
| 32 | Byte pb; | ||
| 33 | Byte _pad_; | ||
| 34 | UInt32 dicSize; | ||
| 35 | } CLzmaProps; | ||
| 36 | |||
| 37 | /* LzmaProps_Decode - decodes properties | ||
| 38 | Returns: | ||
| 39 | SZ_OK | ||
| 40 | SZ_ERROR_UNSUPPORTED - Unsupported properties | ||
| 41 | */ | ||
| 42 | |||
| 43 | SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); | ||
| 44 | |||
| 45 | |||
| 46 | /* ---------- LZMA Decoder state ---------- */ | ||
| 47 | |||
| 48 | /* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. | ||
| 49 | Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ | ||
| 50 | |||
| 51 | #define LZMA_REQUIRED_INPUT_MAX 20 | ||
| 52 | |||
| 53 | typedef struct | ||
| 54 | { | ||
| 55 | /* Don't change this structure. ASM code can use it. */ | ||
| 56 | CLzmaProps prop; | ||
| 57 | CLzmaProb *probs; | ||
| 58 | CLzmaProb *probs_1664; | ||
| 59 | Byte *dic; | ||
| 60 | SizeT dicBufSize; | ||
| 61 | SizeT dicPos; | ||
| 62 | const Byte *buf; | ||
| 63 | UInt32 range; | ||
| 64 | UInt32 code; | ||
| 65 | UInt32 processedPos; | ||
| 66 | UInt32 checkDicSize; | ||
| 67 | UInt32 reps[4]; | ||
| 68 | UInt32 state; | ||
| 69 | UInt32 remainLen; | ||
| 70 | |||
| 71 | UInt32 numProbs; | ||
| 72 | unsigned tempBufSize; | ||
| 73 | Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; | ||
| 74 | } CLzmaDec; | ||
| 75 | |||
| 76 | #define LzmaDec_Construct(p) { (p)->dic = NULL; (p)->probs = NULL; } | ||
| 77 | |||
| 78 | void LzmaDec_Init(CLzmaDec *p); | ||
| 79 | |||
| 80 | /* There are two types of LZMA streams: | ||
| 81 | - Stream with end mark. That end mark adds about 6 bytes to compressed size. | ||
| 82 | - Stream without end mark. You must know exact uncompressed size to decompress such stream. */ | ||
| 83 | |||
| 84 | typedef enum | ||
| 85 | { | ||
| 86 | LZMA_FINISH_ANY, /* finish at any point */ | ||
| 87 | LZMA_FINISH_END /* block must be finished at the end */ | ||
| 88 | } ELzmaFinishMode; | ||
| 89 | |||
| 90 | /* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! | ||
| 91 | |||
| 92 | You must use LZMA_FINISH_END, when you know that current output buffer | ||
| 93 | covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. | ||
| 94 | |||
| 95 | If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, | ||
| 96 | and output value of destLen will be less than output buffer size limit. | ||
| 97 | You can check status result also. | ||
| 98 | |||
| 99 | You can use multiple checks to test data integrity after full decompression: | ||
| 100 | 1) Check Result and "status" variable. | ||
| 101 | 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. | ||
| 102 | 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. | ||
| 103 | You must use correct finish mode in that case. */ | ||
| 104 | |||
| 105 | typedef enum | ||
| 106 | { | ||
| 107 | LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ | ||
| 108 | LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ | ||
| 109 | LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ | ||
| 110 | LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ | ||
| 111 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ | ||
| 112 | } ELzmaStatus; | ||
| 113 | |||
| 114 | /* ELzmaStatus is used only as output value for function call */ | ||
| 115 | |||
| 116 | |||
| 117 | /* ---------- Interfaces ---------- */ | ||
| 118 | |||
| 119 | /* There are 3 levels of interfaces: | ||
| 120 | 1) Dictionary Interface | ||
| 121 | 2) Buffer Interface | ||
| 122 | 3) One Call Interface | ||
| 123 | You can select any of these interfaces, but don't mix functions from different | ||
| 124 | groups for same object. */ | ||
| 125 | |||
| 126 | |||
| 127 | /* There are two variants to allocate state for Dictionary Interface: | ||
| 128 | 1) LzmaDec_Allocate / LzmaDec_Free | ||
| 129 | 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs | ||
| 130 | You can use variant 2, if you set dictionary buffer manually. | ||
| 131 | For Buffer Interface you must always use variant 1. | ||
| 132 | |||
| 133 | LzmaDec_Allocate* can return: | ||
| 134 | SZ_OK | ||
| 135 | SZ_ERROR_MEM - Memory allocation error | ||
| 136 | SZ_ERROR_UNSUPPORTED - Unsupported properties | ||
| 137 | */ | ||
| 138 | |||
| 139 | SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); | ||
| 140 | void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc); | ||
| 141 | |||
| 142 | SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); | ||
| 143 | void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc); | ||
| 144 | |||
| 145 | /* ---------- Dictionary Interface ---------- */ | ||
| 146 | |||
| 147 | /* You can use it, if you want to eliminate the overhead for data copying from | ||
| 148 | dictionary to some other external buffer. | ||
| 149 | You must work with CLzmaDec variables directly in this interface. | ||
| 150 | |||
| 151 | STEPS: | ||
| 152 | LzmaDec_Construct() | ||
| 153 | LzmaDec_Allocate() | ||
| 154 | for (each new stream) | ||
| 155 | { | ||
| 156 | LzmaDec_Init() | ||
| 157 | while (it needs more decompression) | ||
| 158 | { | ||
| 159 | LzmaDec_DecodeToDic() | ||
| 160 | use data from CLzmaDec::dic and update CLzmaDec::dicPos | ||
| 161 | } | ||
| 162 | } | ||
| 163 | LzmaDec_Free() | ||
| 164 | */ | ||
| 165 | |||
| 166 | /* LzmaDec_DecodeToDic | ||
| 167 | |||
| 168 | The decoding to internal dictionary buffer (CLzmaDec::dic). | ||
| 169 | You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! | ||
| 170 | |||
| 171 | finishMode: | ||
| 172 | It has meaning only if the decoding reaches output limit (dicLimit). | ||
| 173 | LZMA_FINISH_ANY - Decode just dicLimit bytes. | ||
| 174 | LZMA_FINISH_END - Stream must be finished after dicLimit. | ||
| 175 | |||
| 176 | Returns: | ||
| 177 | SZ_OK | ||
| 178 | status: | ||
| 179 | LZMA_STATUS_FINISHED_WITH_MARK | ||
| 180 | LZMA_STATUS_NOT_FINISHED | ||
| 181 | LZMA_STATUS_NEEDS_MORE_INPUT | ||
| 182 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK | ||
| 183 | SZ_ERROR_DATA - Data error | ||
| 184 | SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure | ||
| 185 | */ | ||
| 186 | |||
| 187 | SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, | ||
| 188 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); | ||
| 189 | |||
| 190 | |||
| 191 | /* ---------- Buffer Interface ---------- */ | ||
| 192 | |||
| 193 | /* It's zlib-like interface. | ||
| 194 | See LzmaDec_DecodeToDic description for information about STEPS and return results, | ||
| 195 | but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need | ||
| 196 | to work with CLzmaDec variables manually. | ||
| 197 | |||
| 198 | finishMode: | ||
| 199 | It has meaning only if the decoding reaches output limit (*destLen). | ||
| 200 | LZMA_FINISH_ANY - Decode just destLen bytes. | ||
| 201 | LZMA_FINISH_END - Stream must be finished after (*destLen). | ||
| 202 | */ | ||
| 203 | |||
| 204 | SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, | ||
| 205 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); | ||
| 206 | |||
| 207 | |||
| 208 | /* ---------- One Call Interface ---------- */ | ||
| 209 | |||
| 210 | /* LzmaDecode | ||
| 211 | |||
| 212 | finishMode: | ||
| 213 | It has meaning only if the decoding reaches output limit (*destLen). | ||
| 214 | LZMA_FINISH_ANY - Decode just destLen bytes. | ||
| 215 | LZMA_FINISH_END - Stream must be finished after (*destLen). | ||
| 216 | |||
| 217 | Returns: | ||
| 218 | SZ_OK | ||
| 219 | status: | ||
| 220 | LZMA_STATUS_FINISHED_WITH_MARK | ||
| 221 | LZMA_STATUS_NOT_FINISHED | ||
| 222 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK | ||
| 223 | SZ_ERROR_DATA - Data error | ||
| 224 | SZ_ERROR_MEM - Memory allocation error | ||
| 225 | SZ_ERROR_UNSUPPORTED - Unsupported properties | ||
| 226 | SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). | ||
| 227 | SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure | ||
| 228 | */ | ||
| 229 | |||
| 230 | SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, | ||
| 231 | const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, | ||
| 232 | ELzmaStatus *status, ISzAllocPtr alloc); | ||
| 233 | |||
| 234 | EXTERN_C_END | ||
| 235 | |||
| 236 | #endif | ||
diff --git a/C/LzmaEnc.c b/C/LzmaEnc.c new file mode 100644 index 0000000..b04a7b7 --- /dev/null +++ b/C/LzmaEnc.c | |||
| @@ -0,0 +1,3165 @@ | |||
| 1 | /* LzmaEnc.c -- LZMA Encoder | ||
| 2 | 2021-11-18: Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | /* #define SHOW_STAT */ | ||
| 9 | /* #define SHOW_STAT2 */ | ||
| 10 | |||
| 11 | #if defined(SHOW_STAT) || defined(SHOW_STAT2) | ||
| 12 | #include <stdio.h> | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #include "CpuArch.h" | ||
| 16 | #include "LzmaEnc.h" | ||
| 17 | |||
| 18 | #include "LzFind.h" | ||
| 19 | #ifndef _7ZIP_ST | ||
| 20 | #include "LzFindMt.h" | ||
| 21 | #endif | ||
| 22 | |||
| 23 | /* the following LzmaEnc_* declarations is internal LZMA interface for LZMA2 encoder */ | ||
| 24 | |||
| 25 | SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, | ||
| 26 | ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
| 27 | SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, | ||
| 28 | UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
| 29 | SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, | ||
| 30 | Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); | ||
| 31 | const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp); | ||
| 32 | void LzmaEnc_Finish(CLzmaEncHandle pp); | ||
| 33 | void LzmaEnc_SaveState(CLzmaEncHandle pp); | ||
| 34 | void LzmaEnc_RestoreState(CLzmaEncHandle pp); | ||
| 35 | |||
| 36 | #ifdef SHOW_STAT | ||
| 37 | static unsigned g_STAT_OFFSET = 0; | ||
| 38 | #endif | ||
| 39 | |||
| 40 | /* for good normalization speed we still reserve 256 MB before 4 GB range */ | ||
| 41 | #define kLzmaMaxHistorySize ((UInt32)15 << 28) | ||
| 42 | |||
| 43 | #define kNumTopBits 24 | ||
| 44 | #define kTopValue ((UInt32)1 << kNumTopBits) | ||
| 45 | |||
| 46 | #define kNumBitModelTotalBits 11 | ||
| 47 | #define kBitModelTotal (1 << kNumBitModelTotalBits) | ||
| 48 | #define kNumMoveBits 5 | ||
| 49 | #define kProbInitValue (kBitModelTotal >> 1) | ||
| 50 | |||
| 51 | #define kNumMoveReducingBits 4 | ||
| 52 | #define kNumBitPriceShiftBits 4 | ||
| 53 | // #define kBitPrice (1 << kNumBitPriceShiftBits) | ||
| 54 | |||
| 55 | #define REP_LEN_COUNT 64 | ||
| 56 | |||
| 57 | void LzmaEncProps_Init(CLzmaEncProps *p) | ||
| 58 | { | ||
| 59 | p->level = 5; | ||
| 60 | p->dictSize = p->mc = 0; | ||
| 61 | p->reduceSize = (UInt64)(Int64)-1; | ||
| 62 | p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; | ||
| 63 | p->writeEndMark = 0; | ||
| 64 | p->affinity = 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | void LzmaEncProps_Normalize(CLzmaEncProps *p) | ||
| 68 | { | ||
| 69 | int level = p->level; | ||
| 70 | if (level < 0) level = 5; | ||
| 71 | p->level = level; | ||
| 72 | |||
| 73 | if (p->dictSize == 0) | ||
| 74 | p->dictSize = | ||
| 75 | ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) : | ||
| 76 | ( level <= 6 ? ((UInt32)1 << (level + 19)) : | ||
| 77 | ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26) | ||
| 78 | ))); | ||
| 79 | |||
| 80 | if (p->dictSize > p->reduceSize) | ||
| 81 | { | ||
| 82 | UInt32 v = (UInt32)p->reduceSize; | ||
| 83 | const UInt32 kReduceMin = ((UInt32)1 << 12); | ||
| 84 | if (v < kReduceMin) | ||
| 85 | v = kReduceMin; | ||
| 86 | if (p->dictSize > v) | ||
| 87 | p->dictSize = v; | ||
| 88 | } | ||
| 89 | |||
| 90 | if (p->lc < 0) p->lc = 3; | ||
| 91 | if (p->lp < 0) p->lp = 0; | ||
| 92 | if (p->pb < 0) p->pb = 2; | ||
| 93 | |||
| 94 | if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); | ||
| 95 | if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); | ||
| 96 | if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); | ||
| 97 | if (p->numHashBytes < 0) p->numHashBytes = (p->btMode ? 4 : 5); | ||
| 98 | if (p->mc == 0) p->mc = (16 + ((unsigned)p->fb >> 1)) >> (p->btMode ? 0 : 1); | ||
| 99 | |||
| 100 | if (p->numThreads < 0) | ||
| 101 | p->numThreads = | ||
| 102 | #ifndef _7ZIP_ST | ||
| 103 | ((p->btMode && p->algo) ? 2 : 1); | ||
| 104 | #else | ||
| 105 | 1; | ||
| 106 | #endif | ||
| 107 | } | ||
| 108 | |||
| 109 | UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) | ||
| 110 | { | ||
| 111 | CLzmaEncProps props = *props2; | ||
| 112 | LzmaEncProps_Normalize(&props); | ||
| 113 | return props.dictSize; | ||
| 114 | } | ||
| 115 | |||
| 116 | |||
| 117 | /* | ||
| 118 | x86/x64: | ||
| 119 | |||
| 120 | BSR: | ||
| 121 | IF (SRC == 0) ZF = 1, DEST is undefined; | ||
| 122 | AMD : DEST is unchanged; | ||
| 123 | IF (SRC != 0) ZF = 0; DEST is index of top non-zero bit | ||
| 124 | BSR is slow in some processors | ||
| 125 | |||
| 126 | LZCNT: | ||
| 127 | IF (SRC == 0) CF = 1, DEST is size_in_bits_of_register(src) (32 or 64) | ||
| 128 | IF (SRC != 0) CF = 0, DEST = num_lead_zero_bits | ||
| 129 | IF (DEST == 0) ZF = 1; | ||
| 130 | |||
| 131 | LZCNT works only in new processors starting from Haswell. | ||
| 132 | if LZCNT is not supported by processor, then it's executed as BSR. | ||
| 133 | LZCNT can be faster than BSR, if supported. | ||
| 134 | */ | ||
| 135 | |||
| 136 | // #define LZMA_LOG_BSR | ||
| 137 | |||
| 138 | #if defined(MY_CPU_ARM_OR_ARM64) /* || defined(MY_CPU_X86_OR_AMD64) */ | ||
| 139 | |||
| 140 | #if (defined(__clang__) && (__clang_major__ >= 6)) \ | ||
| 141 | || (defined(__GNUC__) && (__GNUC__ >= 6)) | ||
| 142 | #define LZMA_LOG_BSR | ||
| 143 | #elif defined(_MSC_VER) && (_MSC_VER >= 1300) | ||
| 144 | // #if defined(MY_CPU_ARM_OR_ARM64) | ||
| 145 | #define LZMA_LOG_BSR | ||
| 146 | // #endif | ||
| 147 | #endif | ||
| 148 | #endif | ||
| 149 | |||
| 150 | // #include <intrin.h> | ||
| 151 | |||
| 152 | #ifdef LZMA_LOG_BSR | ||
| 153 | |||
| 154 | #if defined(__clang__) \ | ||
| 155 | || defined(__GNUC__) | ||
| 156 | |||
| 157 | /* | ||
| 158 | C code: : (30 - __builtin_clz(x)) | ||
| 159 | gcc9/gcc10 for x64 /x86 : 30 - (bsr(x) xor 31) | ||
| 160 | clang10 for x64 : 31 + (bsr(x) xor -32) | ||
| 161 | */ | ||
| 162 | |||
| 163 | #define MY_clz(x) ((unsigned)__builtin_clz(x)) | ||
| 164 | // __lzcnt32 | ||
| 165 | // __builtin_ia32_lzcnt_u32 | ||
| 166 | |||
| 167 | #else // #if defined(_MSC_VER) | ||
| 168 | |||
| 169 | #ifdef MY_CPU_ARM_OR_ARM64 | ||
| 170 | |||
| 171 | #define MY_clz _CountLeadingZeros | ||
| 172 | |||
| 173 | #else // if defined(MY_CPU_X86_OR_AMD64) | ||
| 174 | |||
| 175 | // #define MY_clz __lzcnt // we can use lzcnt (unsupported by old CPU) | ||
| 176 | // _BitScanReverse code is not optimal for some MSVC compilers | ||
| 177 | #define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); zz--; \ | ||
| 178 | res = (zz + zz) + (pos >> zz); } | ||
| 179 | |||
| 180 | #endif // MY_CPU_X86_OR_AMD64 | ||
| 181 | |||
| 182 | #endif // _MSC_VER | ||
| 183 | |||
| 184 | |||
| 185 | #ifndef BSR2_RET | ||
| 186 | |||
| 187 | #define BSR2_RET(pos, res) { unsigned zz = 30 - MY_clz(pos); \ | ||
| 188 | res = (zz + zz) + (pos >> zz); } | ||
| 189 | |||
| 190 | #endif | ||
| 191 | |||
| 192 | |||
| 193 | unsigned GetPosSlot1(UInt32 pos); | ||
| 194 | unsigned GetPosSlot1(UInt32 pos) | ||
| 195 | { | ||
| 196 | unsigned res; | ||
| 197 | BSR2_RET(pos, res); | ||
| 198 | return res; | ||
| 199 | } | ||
| 200 | #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } | ||
| 201 | #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } | ||
| 202 | |||
| 203 | |||
| 204 | #else // ! LZMA_LOG_BSR | ||
| 205 | |||
| 206 | #define kNumLogBits (11 + sizeof(size_t) / 8 * 3) | ||
| 207 | |||
| 208 | #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) | ||
| 209 | |||
| 210 | static void LzmaEnc_FastPosInit(Byte *g_FastPos) | ||
| 211 | { | ||
| 212 | unsigned slot; | ||
| 213 | g_FastPos[0] = 0; | ||
| 214 | g_FastPos[1] = 1; | ||
| 215 | g_FastPos += 2; | ||
| 216 | |||
| 217 | for (slot = 2; slot < kNumLogBits * 2; slot++) | ||
| 218 | { | ||
| 219 | size_t k = ((size_t)1 << ((slot >> 1) - 1)); | ||
| 220 | size_t j; | ||
| 221 | for (j = 0; j < k; j++) | ||
| 222 | g_FastPos[j] = (Byte)slot; | ||
| 223 | g_FastPos += k; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | /* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */ | ||
| 228 | /* | ||
| 229 | #define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \ | ||
| 230 | (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ | ||
| 231 | res = p->g_FastPos[pos >> zz] + (zz * 2); } | ||
| 232 | */ | ||
| 233 | |||
| 234 | /* | ||
| 235 | #define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \ | ||
| 236 | (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \ | ||
| 237 | res = p->g_FastPos[pos >> zz] + (zz * 2); } | ||
| 238 | */ | ||
| 239 | |||
| 240 | #define BSR2_RET(pos, res) { unsigned zz = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \ | ||
| 241 | res = p->g_FastPos[pos >> zz] + (zz * 2); } | ||
| 242 | |||
| 243 | /* | ||
| 244 | #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ | ||
| 245 | p->g_FastPos[pos >> 6] + 12 : \ | ||
| 246 | p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } | ||
| 247 | */ | ||
| 248 | |||
| 249 | #define GetPosSlot1(pos) p->g_FastPos[pos] | ||
| 250 | #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } | ||
| 251 | #define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos & (kNumFullDistances - 1)]; else BSR2_RET(pos, res); } | ||
| 252 | |||
| 253 | #endif // LZMA_LOG_BSR | ||
| 254 | |||
| 255 | |||
| 256 | #define LZMA_NUM_REPS 4 | ||
| 257 | |||
| 258 | typedef UInt16 CState; | ||
| 259 | typedef UInt16 CExtra; | ||
| 260 | |||
| 261 | typedef struct | ||
| 262 | { | ||
| 263 | UInt32 price; | ||
| 264 | CState state; | ||
| 265 | CExtra extra; | ||
| 266 | // 0 : normal | ||
| 267 | // 1 : LIT : MATCH | ||
| 268 | // > 1 : MATCH (extra-1) : LIT : REP0 (len) | ||
| 269 | UInt32 len; | ||
| 270 | UInt32 dist; | ||
| 271 | UInt32 reps[LZMA_NUM_REPS]; | ||
| 272 | } COptimal; | ||
| 273 | |||
| 274 | |||
| 275 | // 18.06 | ||
| 276 | #define kNumOpts (1 << 11) | ||
| 277 | #define kPackReserve (kNumOpts * 8) | ||
| 278 | // #define kNumOpts (1 << 12) | ||
| 279 | // #define kPackReserve (1 + kNumOpts * 2) | ||
| 280 | |||
| 281 | #define kNumLenToPosStates 4 | ||
| 282 | #define kNumPosSlotBits 6 | ||
| 283 | // #define kDicLogSizeMin 0 | ||
| 284 | #define kDicLogSizeMax 32 | ||
| 285 | #define kDistTableSizeMax (kDicLogSizeMax * 2) | ||
| 286 | |||
| 287 | #define kNumAlignBits 4 | ||
| 288 | #define kAlignTableSize (1 << kNumAlignBits) | ||
| 289 | #define kAlignMask (kAlignTableSize - 1) | ||
| 290 | |||
| 291 | #define kStartPosModelIndex 4 | ||
| 292 | #define kEndPosModelIndex 14 | ||
| 293 | #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) | ||
| 294 | |||
| 295 | typedef | ||
| 296 | #ifdef _LZMA_PROB32 | ||
| 297 | UInt32 | ||
| 298 | #else | ||
| 299 | UInt16 | ||
| 300 | #endif | ||
| 301 | CLzmaProb; | ||
| 302 | |||
| 303 | #define LZMA_PB_MAX 4 | ||
| 304 | #define LZMA_LC_MAX 8 | ||
| 305 | #define LZMA_LP_MAX 4 | ||
| 306 | |||
| 307 | #define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) | ||
| 308 | |||
| 309 | #define kLenNumLowBits 3 | ||
| 310 | #define kLenNumLowSymbols (1 << kLenNumLowBits) | ||
| 311 | #define kLenNumHighBits 8 | ||
| 312 | #define kLenNumHighSymbols (1 << kLenNumHighBits) | ||
| 313 | #define kLenNumSymbolsTotal (kLenNumLowSymbols * 2 + kLenNumHighSymbols) | ||
| 314 | |||
| 315 | #define LZMA_MATCH_LEN_MIN 2 | ||
| 316 | #define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) | ||
| 317 | |||
| 318 | #define kNumStates 12 | ||
| 319 | |||
| 320 | |||
| 321 | typedef struct | ||
| 322 | { | ||
| 323 | CLzmaProb low[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)]; | ||
| 324 | CLzmaProb high[kLenNumHighSymbols]; | ||
| 325 | } CLenEnc; | ||
| 326 | |||
| 327 | |||
| 328 | typedef struct | ||
| 329 | { | ||
| 330 | unsigned tableSize; | ||
| 331 | UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; | ||
| 332 | // UInt32 prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2]; | ||
| 333 | // UInt32 prices2[kLenNumSymbolsTotal]; | ||
| 334 | } CLenPriceEnc; | ||
| 335 | |||
| 336 | #define GET_PRICE_LEN(p, posState, len) \ | ||
| 337 | ((p)->prices[posState][(size_t)(len) - LZMA_MATCH_LEN_MIN]) | ||
| 338 | |||
| 339 | /* | ||
| 340 | #define GET_PRICE_LEN(p, posState, len) \ | ||
| 341 | ((p)->prices2[(size_t)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9))) | ||
| 342 | */ | ||
| 343 | |||
| 344 | typedef struct | ||
| 345 | { | ||
| 346 | UInt32 range; | ||
| 347 | unsigned cache; | ||
| 348 | UInt64 low; | ||
| 349 | UInt64 cacheSize; | ||
| 350 | Byte *buf; | ||
| 351 | Byte *bufLim; | ||
| 352 | Byte *bufBase; | ||
| 353 | ISeqOutStream *outStream; | ||
| 354 | UInt64 processed; | ||
| 355 | SRes res; | ||
| 356 | } CRangeEnc; | ||
| 357 | |||
| 358 | |||
| 359 | typedef struct | ||
| 360 | { | ||
| 361 | CLzmaProb *litProbs; | ||
| 362 | |||
| 363 | unsigned state; | ||
| 364 | UInt32 reps[LZMA_NUM_REPS]; | ||
| 365 | |||
| 366 | CLzmaProb posAlignEncoder[1 << kNumAlignBits]; | ||
| 367 | CLzmaProb isRep[kNumStates]; | ||
| 368 | CLzmaProb isRepG0[kNumStates]; | ||
| 369 | CLzmaProb isRepG1[kNumStates]; | ||
| 370 | CLzmaProb isRepG2[kNumStates]; | ||
| 371 | CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; | ||
| 372 | CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; | ||
| 373 | |||
| 374 | CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; | ||
| 375 | CLzmaProb posEncoders[kNumFullDistances]; | ||
| 376 | |||
| 377 | CLenEnc lenProbs; | ||
| 378 | CLenEnc repLenProbs; | ||
| 379 | |||
| 380 | } CSaveState; | ||
| 381 | |||
| 382 | |||
| 383 | typedef UInt32 CProbPrice; | ||
| 384 | |||
| 385 | |||
| 386 | typedef struct | ||
| 387 | { | ||
| 388 | void *matchFinderObj; | ||
| 389 | IMatchFinder2 matchFinder; | ||
| 390 | |||
| 391 | unsigned optCur; | ||
| 392 | unsigned optEnd; | ||
| 393 | |||
| 394 | unsigned longestMatchLen; | ||
| 395 | unsigned numPairs; | ||
| 396 | UInt32 numAvail; | ||
| 397 | |||
| 398 | unsigned state; | ||
| 399 | unsigned numFastBytes; | ||
| 400 | unsigned additionalOffset; | ||
| 401 | UInt32 reps[LZMA_NUM_REPS]; | ||
| 402 | unsigned lpMask, pbMask; | ||
| 403 | CLzmaProb *litProbs; | ||
| 404 | CRangeEnc rc; | ||
| 405 | |||
| 406 | UInt32 backRes; | ||
| 407 | |||
| 408 | unsigned lc, lp, pb; | ||
| 409 | unsigned lclp; | ||
| 410 | |||
| 411 | BoolInt fastMode; | ||
| 412 | BoolInt writeEndMark; | ||
| 413 | BoolInt finished; | ||
| 414 | BoolInt multiThread; | ||
| 415 | BoolInt needInit; | ||
| 416 | // BoolInt _maxMode; | ||
| 417 | |||
| 418 | UInt64 nowPos64; | ||
| 419 | |||
| 420 | unsigned matchPriceCount; | ||
| 421 | // unsigned alignPriceCount; | ||
| 422 | int repLenEncCounter; | ||
| 423 | |||
| 424 | unsigned distTableSize; | ||
| 425 | |||
| 426 | UInt32 dictSize; | ||
| 427 | SRes result; | ||
| 428 | |||
| 429 | #ifndef _7ZIP_ST | ||
| 430 | BoolInt mtMode; | ||
| 431 | // begin of CMatchFinderMt is used in LZ thread | ||
| 432 | CMatchFinderMt matchFinderMt; | ||
| 433 | // end of CMatchFinderMt is used in BT and HASH threads | ||
| 434 | // #else | ||
| 435 | // CMatchFinder matchFinderBase; | ||
| 436 | #endif | ||
| 437 | CMatchFinder matchFinderBase; | ||
| 438 | |||
| 439 | |||
| 440 | // we suppose that we have 8-bytes alignment after CMatchFinder | ||
| 441 | |||
| 442 | #ifndef _7ZIP_ST | ||
| 443 | Byte pad[128]; | ||
| 444 | #endif | ||
| 445 | |||
| 446 | // LZ thread | ||
| 447 | CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; | ||
| 448 | |||
| 449 | // we want {len , dist} pairs to be 8-bytes aligned in matches array | ||
| 450 | UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2]; | ||
| 451 | |||
| 452 | // we want 8-bytes alignment here | ||
| 453 | UInt32 alignPrices[kAlignTableSize]; | ||
| 454 | UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; | ||
| 455 | UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; | ||
| 456 | |||
| 457 | CLzmaProb posAlignEncoder[1 << kNumAlignBits]; | ||
| 458 | CLzmaProb isRep[kNumStates]; | ||
| 459 | CLzmaProb isRepG0[kNumStates]; | ||
| 460 | CLzmaProb isRepG1[kNumStates]; | ||
| 461 | CLzmaProb isRepG2[kNumStates]; | ||
| 462 | CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; | ||
| 463 | CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; | ||
| 464 | CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; | ||
| 465 | CLzmaProb posEncoders[kNumFullDistances]; | ||
| 466 | |||
| 467 | CLenEnc lenProbs; | ||
| 468 | CLenEnc repLenProbs; | ||
| 469 | |||
| 470 | #ifndef LZMA_LOG_BSR | ||
| 471 | Byte g_FastPos[1 << kNumLogBits]; | ||
| 472 | #endif | ||
| 473 | |||
| 474 | CLenPriceEnc lenEnc; | ||
| 475 | CLenPriceEnc repLenEnc; | ||
| 476 | |||
| 477 | COptimal opt[kNumOpts]; | ||
| 478 | |||
| 479 | CSaveState saveState; | ||
| 480 | |||
| 481 | // BoolInt mf_Failure; | ||
| 482 | #ifndef _7ZIP_ST | ||
| 483 | Byte pad2[128]; | ||
| 484 | #endif | ||
| 485 | } CLzmaEnc; | ||
| 486 | |||
| 487 | |||
| 488 | #define MFB (p->matchFinderBase) | ||
| 489 | /* | ||
| 490 | #ifndef _7ZIP_ST | ||
| 491 | #define MFB (p->matchFinderMt.MatchFinder) | ||
| 492 | #endif | ||
| 493 | */ | ||
| 494 | |||
| 495 | #define COPY_ARR(dest, src, arr) memcpy(dest->arr, src->arr, sizeof(src->arr)); | ||
| 496 | |||
| 497 | void LzmaEnc_SaveState(CLzmaEncHandle pp) | ||
| 498 | { | ||
| 499 | CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 500 | CSaveState *dest = &p->saveState; | ||
| 501 | |||
| 502 | dest->state = p->state; | ||
| 503 | |||
| 504 | dest->lenProbs = p->lenProbs; | ||
| 505 | dest->repLenProbs = p->repLenProbs; | ||
| 506 | |||
| 507 | COPY_ARR(dest, p, reps); | ||
| 508 | |||
| 509 | COPY_ARR(dest, p, posAlignEncoder); | ||
| 510 | COPY_ARR(dest, p, isRep); | ||
| 511 | COPY_ARR(dest, p, isRepG0); | ||
| 512 | COPY_ARR(dest, p, isRepG1); | ||
| 513 | COPY_ARR(dest, p, isRepG2); | ||
| 514 | COPY_ARR(dest, p, isMatch); | ||
| 515 | COPY_ARR(dest, p, isRep0Long); | ||
| 516 | COPY_ARR(dest, p, posSlotEncoder); | ||
| 517 | COPY_ARR(dest, p, posEncoders); | ||
| 518 | |||
| 519 | memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb)); | ||
| 520 | } | ||
| 521 | |||
| 522 | |||
| 523 | void LzmaEnc_RestoreState(CLzmaEncHandle pp) | ||
| 524 | { | ||
| 525 | CLzmaEnc *dest = (CLzmaEnc *)pp; | ||
| 526 | const CSaveState *p = &dest->saveState; | ||
| 527 | |||
| 528 | dest->state = p->state; | ||
| 529 | |||
| 530 | dest->lenProbs = p->lenProbs; | ||
| 531 | dest->repLenProbs = p->repLenProbs; | ||
| 532 | |||
| 533 | COPY_ARR(dest, p, reps); | ||
| 534 | |||
| 535 | COPY_ARR(dest, p, posAlignEncoder); | ||
| 536 | COPY_ARR(dest, p, isRep); | ||
| 537 | COPY_ARR(dest, p, isRepG0); | ||
| 538 | COPY_ARR(dest, p, isRepG1); | ||
| 539 | COPY_ARR(dest, p, isRepG2); | ||
| 540 | COPY_ARR(dest, p, isMatch); | ||
| 541 | COPY_ARR(dest, p, isRep0Long); | ||
| 542 | COPY_ARR(dest, p, posSlotEncoder); | ||
| 543 | COPY_ARR(dest, p, posEncoders); | ||
| 544 | |||
| 545 | memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb)); | ||
| 546 | } | ||
| 547 | |||
| 548 | |||
| 549 | |||
| 550 | SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) | ||
| 551 | { | ||
| 552 | CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 553 | CLzmaEncProps props = *props2; | ||
| 554 | LzmaEncProps_Normalize(&props); | ||
| 555 | |||
| 556 | if (props.lc > LZMA_LC_MAX | ||
| 557 | || props.lp > LZMA_LP_MAX | ||
| 558 | || props.pb > LZMA_PB_MAX) | ||
| 559 | return SZ_ERROR_PARAM; | ||
| 560 | |||
| 561 | |||
| 562 | if (props.dictSize > kLzmaMaxHistorySize) | ||
| 563 | props.dictSize = kLzmaMaxHistorySize; | ||
| 564 | |||
| 565 | #ifndef LZMA_LOG_BSR | ||
| 566 | { | ||
| 567 | const UInt64 dict64 = props.dictSize; | ||
| 568 | if (dict64 > ((UInt64)1 << kDicLogSizeMaxCompress)) | ||
| 569 | return SZ_ERROR_PARAM; | ||
| 570 | } | ||
| 571 | #endif | ||
| 572 | |||
| 573 | p->dictSize = props.dictSize; | ||
| 574 | { | ||
| 575 | unsigned fb = (unsigned)props.fb; | ||
| 576 | if (fb < 5) | ||
| 577 | fb = 5; | ||
| 578 | if (fb > LZMA_MATCH_LEN_MAX) | ||
| 579 | fb = LZMA_MATCH_LEN_MAX; | ||
| 580 | p->numFastBytes = fb; | ||
| 581 | } | ||
| 582 | p->lc = (unsigned)props.lc; | ||
| 583 | p->lp = (unsigned)props.lp; | ||
| 584 | p->pb = (unsigned)props.pb; | ||
| 585 | p->fastMode = (props.algo == 0); | ||
| 586 | // p->_maxMode = True; | ||
| 587 | MFB.btMode = (Byte)(props.btMode ? 1 : 0); | ||
| 588 | { | ||
| 589 | unsigned numHashBytes = 4; | ||
| 590 | if (props.btMode) | ||
| 591 | { | ||
| 592 | if (props.numHashBytes < 2) numHashBytes = 2; | ||
| 593 | else if (props.numHashBytes < 4) numHashBytes = (unsigned)props.numHashBytes; | ||
| 594 | } | ||
| 595 | if (props.numHashBytes >= 5) numHashBytes = 5; | ||
| 596 | |||
| 597 | MFB.numHashBytes = numHashBytes; | ||
| 598 | } | ||
| 599 | |||
| 600 | MFB.cutValue = props.mc; | ||
| 601 | |||
| 602 | p->writeEndMark = (BoolInt)props.writeEndMark; | ||
| 603 | |||
| 604 | #ifndef _7ZIP_ST | ||
| 605 | /* | ||
| 606 | if (newMultiThread != _multiThread) | ||
| 607 | { | ||
| 608 | ReleaseMatchFinder(); | ||
| 609 | _multiThread = newMultiThread; | ||
| 610 | } | ||
| 611 | */ | ||
| 612 | p->multiThread = (props.numThreads > 1); | ||
| 613 | p->matchFinderMt.btSync.affinity = | ||
| 614 | p->matchFinderMt.hashSync.affinity = props.affinity; | ||
| 615 | #endif | ||
| 616 | |||
| 617 | return SZ_OK; | ||
| 618 | } | ||
| 619 | |||
| 620 | |||
| 621 | void LzmaEnc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize) | ||
| 622 | { | ||
| 623 | CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 624 | MFB.expectedDataSize = expectedDataSiize; | ||
| 625 | } | ||
| 626 | |||
| 627 | |||
| 628 | #define kState_Start 0 | ||
| 629 | #define kState_LitAfterMatch 4 | ||
| 630 | #define kState_LitAfterRep 5 | ||
| 631 | #define kState_MatchAfterLit 7 | ||
| 632 | #define kState_RepAfterLit 8 | ||
| 633 | |||
| 634 | static const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; | ||
| 635 | static const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; | ||
| 636 | static const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; | ||
| 637 | static const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; | ||
| 638 | |||
| 639 | #define IsLitState(s) ((s) < 7) | ||
| 640 | #define GetLenToPosState2(len) (((len) < kNumLenToPosStates - 1) ? (len) : kNumLenToPosStates - 1) | ||
| 641 | #define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) | ||
| 642 | |||
| 643 | #define kInfinityPrice (1 << 30) | ||
| 644 | |||
| 645 | static void RangeEnc_Construct(CRangeEnc *p) | ||
| 646 | { | ||
| 647 | p->outStream = NULL; | ||
| 648 | p->bufBase = NULL; | ||
| 649 | } | ||
| 650 | |||
| 651 | #define RangeEnc_GetProcessed(p) ( (p)->processed + (size_t)((p)->buf - (p)->bufBase) + (p)->cacheSize) | ||
| 652 | #define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + (size_t)((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize) | ||
| 653 | |||
| 654 | #define RC_BUF_SIZE (1 << 16) | ||
| 655 | |||
| 656 | static int RangeEnc_Alloc(CRangeEnc *p, ISzAllocPtr alloc) | ||
| 657 | { | ||
| 658 | if (!p->bufBase) | ||
| 659 | { | ||
| 660 | p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE); | ||
| 661 | if (!p->bufBase) | ||
| 662 | return 0; | ||
| 663 | p->bufLim = p->bufBase + RC_BUF_SIZE; | ||
| 664 | } | ||
| 665 | return 1; | ||
| 666 | } | ||
| 667 | |||
| 668 | static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc) | ||
| 669 | { | ||
| 670 | ISzAlloc_Free(alloc, p->bufBase); | ||
| 671 | p->bufBase = NULL; | ||
| 672 | } | ||
| 673 | |||
| 674 | static void RangeEnc_Init(CRangeEnc *p) | ||
| 675 | { | ||
| 676 | p->range = 0xFFFFFFFF; | ||
| 677 | p->cache = 0; | ||
| 678 | p->low = 0; | ||
| 679 | p->cacheSize = 0; | ||
| 680 | |||
| 681 | p->buf = p->bufBase; | ||
| 682 | |||
| 683 | p->processed = 0; | ||
| 684 | p->res = SZ_OK; | ||
| 685 | } | ||
| 686 | |||
| 687 | MY_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p) | ||
| 688 | { | ||
| 689 | const size_t num = (size_t)(p->buf - p->bufBase); | ||
| 690 | if (p->res == SZ_OK) | ||
| 691 | { | ||
| 692 | if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num)) | ||
| 693 | p->res = SZ_ERROR_WRITE; | ||
| 694 | } | ||
| 695 | p->processed += num; | ||
| 696 | p->buf = p->bufBase; | ||
| 697 | } | ||
| 698 | |||
| 699 | MY_NO_INLINE static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) | ||
| 700 | { | ||
| 701 | UInt32 low = (UInt32)p->low; | ||
| 702 | unsigned high = (unsigned)(p->low >> 32); | ||
| 703 | p->low = (UInt32)(low << 8); | ||
| 704 | if (low < (UInt32)0xFF000000 || high != 0) | ||
| 705 | { | ||
| 706 | { | ||
| 707 | Byte *buf = p->buf; | ||
| 708 | *buf++ = (Byte)(p->cache + high); | ||
| 709 | p->cache = (unsigned)(low >> 24); | ||
| 710 | p->buf = buf; | ||
| 711 | if (buf == p->bufLim) | ||
| 712 | RangeEnc_FlushStream(p); | ||
| 713 | if (p->cacheSize == 0) | ||
| 714 | return; | ||
| 715 | } | ||
| 716 | high += 0xFF; | ||
| 717 | for (;;) | ||
| 718 | { | ||
| 719 | Byte *buf = p->buf; | ||
| 720 | *buf++ = (Byte)(high); | ||
| 721 | p->buf = buf; | ||
| 722 | if (buf == p->bufLim) | ||
| 723 | RangeEnc_FlushStream(p); | ||
| 724 | if (--p->cacheSize == 0) | ||
| 725 | return; | ||
| 726 | } | ||
| 727 | } | ||
| 728 | p->cacheSize++; | ||
| 729 | } | ||
| 730 | |||
| 731 | static void RangeEnc_FlushData(CRangeEnc *p) | ||
| 732 | { | ||
| 733 | int i; | ||
| 734 | for (i = 0; i < 5; i++) | ||
| 735 | RangeEnc_ShiftLow(p); | ||
| 736 | } | ||
| 737 | |||
| 738 | #define RC_NORM(p) if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(p); } | ||
| 739 | |||
| 740 | #define RC_BIT_PRE(p, prob) \ | ||
| 741 | ttt = *(prob); \ | ||
| 742 | newBound = (range >> kNumBitModelTotalBits) * ttt; | ||
| 743 | |||
| 744 | // #define _LZMA_ENC_USE_BRANCH | ||
| 745 | |||
| 746 | #ifdef _LZMA_ENC_USE_BRANCH | ||
| 747 | |||
| 748 | #define RC_BIT(p, prob, bit) { \ | ||
| 749 | RC_BIT_PRE(p, prob) \ | ||
| 750 | if (bit == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } \ | ||
| 751 | else { (p)->low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; } \ | ||
| 752 | *(prob) = (CLzmaProb)ttt; \ | ||
| 753 | RC_NORM(p) \ | ||
| 754 | } | ||
| 755 | |||
| 756 | #else | ||
| 757 | |||
| 758 | #define RC_BIT(p, prob, bit) { \ | ||
| 759 | UInt32 mask; \ | ||
| 760 | RC_BIT_PRE(p, prob) \ | ||
| 761 | mask = 0 - (UInt32)bit; \ | ||
| 762 | range &= mask; \ | ||
| 763 | mask &= newBound; \ | ||
| 764 | range -= mask; \ | ||
| 765 | (p)->low += mask; \ | ||
| 766 | mask = (UInt32)bit - 1; \ | ||
| 767 | range += newBound & mask; \ | ||
| 768 | mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1)); \ | ||
| 769 | mask += ((1 << kNumMoveBits) - 1); \ | ||
| 770 | ttt += (UInt32)((Int32)(mask - ttt) >> kNumMoveBits); \ | ||
| 771 | *(prob) = (CLzmaProb)ttt; \ | ||
| 772 | RC_NORM(p) \ | ||
| 773 | } | ||
| 774 | |||
| 775 | #endif | ||
| 776 | |||
| 777 | |||
| 778 | |||
| 779 | |||
| 780 | #define RC_BIT_0_BASE(p, prob) \ | ||
| 781 | range = newBound; *(prob) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); | ||
| 782 | |||
| 783 | #define RC_BIT_1_BASE(p, prob) \ | ||
| 784 | range -= newBound; (p)->low += newBound; *(prob) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); \ | ||
| 785 | |||
| 786 | #define RC_BIT_0(p, prob) \ | ||
| 787 | RC_BIT_0_BASE(p, prob) \ | ||
| 788 | RC_NORM(p) | ||
| 789 | |||
| 790 | #define RC_BIT_1(p, prob) \ | ||
| 791 | RC_BIT_1_BASE(p, prob) \ | ||
| 792 | RC_NORM(p) | ||
| 793 | |||
| 794 | static void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob) | ||
| 795 | { | ||
| 796 | UInt32 range, ttt, newBound; | ||
| 797 | range = p->range; | ||
| 798 | RC_BIT_PRE(p, prob) | ||
| 799 | RC_BIT_0(p, prob) | ||
| 800 | p->range = range; | ||
| 801 | } | ||
| 802 | |||
| 803 | static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 sym) | ||
| 804 | { | ||
| 805 | UInt32 range = p->range; | ||
| 806 | sym |= 0x100; | ||
| 807 | do | ||
| 808 | { | ||
| 809 | UInt32 ttt, newBound; | ||
| 810 | // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1); | ||
| 811 | CLzmaProb *prob = probs + (sym >> 8); | ||
| 812 | UInt32 bit = (sym >> 7) & 1; | ||
| 813 | sym <<= 1; | ||
| 814 | RC_BIT(p, prob, bit); | ||
| 815 | } | ||
| 816 | while (sym < 0x10000); | ||
| 817 | p->range = range; | ||
| 818 | } | ||
| 819 | |||
| 820 | static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 sym, UInt32 matchByte) | ||
| 821 | { | ||
| 822 | UInt32 range = p->range; | ||
| 823 | UInt32 offs = 0x100; | ||
| 824 | sym |= 0x100; | ||
| 825 | do | ||
| 826 | { | ||
| 827 | UInt32 ttt, newBound; | ||
| 828 | CLzmaProb *prob; | ||
| 829 | UInt32 bit; | ||
| 830 | matchByte <<= 1; | ||
| 831 | // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1); | ||
| 832 | prob = probs + (offs + (matchByte & offs) + (sym >> 8)); | ||
| 833 | bit = (sym >> 7) & 1; | ||
| 834 | sym <<= 1; | ||
| 835 | offs &= ~(matchByte ^ sym); | ||
| 836 | RC_BIT(p, prob, bit); | ||
| 837 | } | ||
| 838 | while (sym < 0x10000); | ||
| 839 | p->range = range; | ||
| 840 | } | ||
| 841 | |||
| 842 | |||
| 843 | |||
| 844 | static void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices) | ||
| 845 | { | ||
| 846 | UInt32 i; | ||
| 847 | for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++) | ||
| 848 | { | ||
| 849 | const unsigned kCyclesBits = kNumBitPriceShiftBits; | ||
| 850 | UInt32 w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1)); | ||
| 851 | unsigned bitCount = 0; | ||
| 852 | unsigned j; | ||
| 853 | for (j = 0; j < kCyclesBits; j++) | ||
| 854 | { | ||
| 855 | w = w * w; | ||
| 856 | bitCount <<= 1; | ||
| 857 | while (w >= ((UInt32)1 << 16)) | ||
| 858 | { | ||
| 859 | w >>= 1; | ||
| 860 | bitCount++; | ||
| 861 | } | ||
| 862 | } | ||
| 863 | ProbPrices[i] = (CProbPrice)(((unsigned)kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); | ||
| 864 | // printf("\n%3d: %5d", i, ProbPrices[i]); | ||
| 865 | } | ||
| 866 | } | ||
| 867 | |||
| 868 | |||
| 869 | #define GET_PRICE(prob, bit) \ | ||
| 870 | p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; | ||
| 871 | |||
| 872 | #define GET_PRICEa(prob, bit) \ | ||
| 873 | ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; | ||
| 874 | |||
| 875 | #define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] | ||
| 876 | #define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] | ||
| 877 | |||
| 878 | #define GET_PRICEa_0(prob) ProbPrices[(prob) >> kNumMoveReducingBits] | ||
| 879 | #define GET_PRICEa_1(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] | ||
| 880 | |||
| 881 | |||
| 882 | static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 sym, const CProbPrice *ProbPrices) | ||
| 883 | { | ||
| 884 | UInt32 price = 0; | ||
| 885 | sym |= 0x100; | ||
| 886 | do | ||
| 887 | { | ||
| 888 | unsigned bit = sym & 1; | ||
| 889 | sym >>= 1; | ||
| 890 | price += GET_PRICEa(probs[sym], bit); | ||
| 891 | } | ||
| 892 | while (sym >= 2); | ||
| 893 | return price; | ||
| 894 | } | ||
| 895 | |||
| 896 | |||
| 897 | static UInt32 LitEnc_Matched_GetPrice(const CLzmaProb *probs, UInt32 sym, UInt32 matchByte, const CProbPrice *ProbPrices) | ||
| 898 | { | ||
| 899 | UInt32 price = 0; | ||
| 900 | UInt32 offs = 0x100; | ||
| 901 | sym |= 0x100; | ||
| 902 | do | ||
| 903 | { | ||
| 904 | matchByte <<= 1; | ||
| 905 | price += GET_PRICEa(probs[offs + (matchByte & offs) + (sym >> 8)], (sym >> 7) & 1); | ||
| 906 | sym <<= 1; | ||
| 907 | offs &= ~(matchByte ^ sym); | ||
| 908 | } | ||
| 909 | while (sym < 0x10000); | ||
| 910 | return price; | ||
| 911 | } | ||
| 912 | |||
| 913 | |||
| 914 | static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, unsigned numBits, unsigned sym) | ||
| 915 | { | ||
| 916 | UInt32 range = rc->range; | ||
| 917 | unsigned m = 1; | ||
| 918 | do | ||
| 919 | { | ||
| 920 | UInt32 ttt, newBound; | ||
| 921 | unsigned bit = sym & 1; | ||
| 922 | // RangeEnc_EncodeBit(rc, probs + m, bit); | ||
| 923 | sym >>= 1; | ||
| 924 | RC_BIT(rc, probs + m, bit); | ||
| 925 | m = (m << 1) | bit; | ||
| 926 | } | ||
| 927 | while (--numBits); | ||
| 928 | rc->range = range; | ||
| 929 | } | ||
| 930 | |||
| 931 | |||
| 932 | |||
| 933 | static void LenEnc_Init(CLenEnc *p) | ||
| 934 | { | ||
| 935 | unsigned i; | ||
| 936 | for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++) | ||
| 937 | p->low[i] = kProbInitValue; | ||
| 938 | for (i = 0; i < kLenNumHighSymbols; i++) | ||
| 939 | p->high[i] = kProbInitValue; | ||
| 940 | } | ||
| 941 | |||
| 942 | static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posState) | ||
| 943 | { | ||
| 944 | UInt32 range, ttt, newBound; | ||
| 945 | CLzmaProb *probs = p->low; | ||
| 946 | range = rc->range; | ||
| 947 | RC_BIT_PRE(rc, probs); | ||
| 948 | if (sym >= kLenNumLowSymbols) | ||
| 949 | { | ||
| 950 | RC_BIT_1(rc, probs); | ||
| 951 | probs += kLenNumLowSymbols; | ||
| 952 | RC_BIT_PRE(rc, probs); | ||
| 953 | if (sym >= kLenNumLowSymbols * 2) | ||
| 954 | { | ||
| 955 | RC_BIT_1(rc, probs); | ||
| 956 | rc->range = range; | ||
| 957 | // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2); | ||
| 958 | LitEnc_Encode(rc, p->high, sym - kLenNumLowSymbols * 2); | ||
| 959 | return; | ||
| 960 | } | ||
| 961 | sym -= kLenNumLowSymbols; | ||
| 962 | } | ||
| 963 | |||
| 964 | // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym); | ||
| 965 | { | ||
| 966 | unsigned m; | ||
| 967 | unsigned bit; | ||
| 968 | RC_BIT_0(rc, probs); | ||
| 969 | probs += (posState << (1 + kLenNumLowBits)); | ||
| 970 | bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit); m = (1 << 1) + bit; | ||
| 971 | bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit); m = (m << 1) + bit; | ||
| 972 | bit = sym & 1; RC_BIT(rc, probs + m, bit); | ||
| 973 | rc->range = range; | ||
| 974 | } | ||
| 975 | } | ||
| 976 | |||
| 977 | static void SetPrices_3(const CLzmaProb *probs, UInt32 startPrice, UInt32 *prices, const CProbPrice *ProbPrices) | ||
| 978 | { | ||
| 979 | unsigned i; | ||
| 980 | for (i = 0; i < 8; i += 2) | ||
| 981 | { | ||
| 982 | UInt32 price = startPrice; | ||
| 983 | UInt32 prob; | ||
| 984 | price += GET_PRICEa(probs[1 ], (i >> 2)); | ||
| 985 | price += GET_PRICEa(probs[2 + (i >> 2)], (i >> 1) & 1); | ||
| 986 | prob = probs[4 + (i >> 1)]; | ||
| 987 | prices[i ] = price + GET_PRICEa_0(prob); | ||
| 988 | prices[i + 1] = price + GET_PRICEa_1(prob); | ||
| 989 | } | ||
| 990 | } | ||
| 991 | |||
| 992 | |||
| 993 | MY_NO_INLINE static void MY_FAST_CALL LenPriceEnc_UpdateTables( | ||
| 994 | CLenPriceEnc *p, | ||
| 995 | unsigned numPosStates, | ||
| 996 | const CLenEnc *enc, | ||
| 997 | const CProbPrice *ProbPrices) | ||
| 998 | { | ||
| 999 | UInt32 b; | ||
| 1000 | |||
| 1001 | { | ||
| 1002 | unsigned prob = enc->low[0]; | ||
| 1003 | UInt32 a, c; | ||
| 1004 | unsigned posState; | ||
| 1005 | b = GET_PRICEa_1(prob); | ||
| 1006 | a = GET_PRICEa_0(prob); | ||
| 1007 | c = b + GET_PRICEa_0(enc->low[kLenNumLowSymbols]); | ||
| 1008 | for (posState = 0; posState < numPosStates; posState++) | ||
| 1009 | { | ||
| 1010 | UInt32 *prices = p->prices[posState]; | ||
| 1011 | const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits)); | ||
| 1012 | SetPrices_3(probs, a, prices, ProbPrices); | ||
| 1013 | SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices); | ||
| 1014 | } | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | /* | ||
| 1018 | { | ||
| 1019 | unsigned i; | ||
| 1020 | UInt32 b; | ||
| 1021 | a = GET_PRICEa_0(enc->low[0]); | ||
| 1022 | for (i = 0; i < kLenNumLowSymbols; i++) | ||
| 1023 | p->prices2[i] = a; | ||
| 1024 | a = GET_PRICEa_1(enc->low[0]); | ||
| 1025 | b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]); | ||
| 1026 | for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++) | ||
| 1027 | p->prices2[i] = b; | ||
| 1028 | a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]); | ||
| 1029 | } | ||
| 1030 | */ | ||
| 1031 | |||
| 1032 | // p->counter = numSymbols; | ||
| 1033 | // p->counter = 64; | ||
| 1034 | |||
| 1035 | { | ||
| 1036 | unsigned i = p->tableSize; | ||
| 1037 | |||
| 1038 | if (i > kLenNumLowSymbols * 2) | ||
| 1039 | { | ||
| 1040 | const CLzmaProb *probs = enc->high; | ||
| 1041 | UInt32 *prices = p->prices[0] + kLenNumLowSymbols * 2; | ||
| 1042 | i -= kLenNumLowSymbols * 2 - 1; | ||
| 1043 | i >>= 1; | ||
| 1044 | b += GET_PRICEa_1(enc->low[kLenNumLowSymbols]); | ||
| 1045 | do | ||
| 1046 | { | ||
| 1047 | /* | ||
| 1048 | p->prices2[i] = a + | ||
| 1049 | // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices); | ||
| 1050 | LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices); | ||
| 1051 | */ | ||
| 1052 | // UInt32 price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices); | ||
| 1053 | unsigned sym = --i + (1 << (kLenNumHighBits - 1)); | ||
| 1054 | UInt32 price = b; | ||
| 1055 | do | ||
| 1056 | { | ||
| 1057 | unsigned bit = sym & 1; | ||
| 1058 | sym >>= 1; | ||
| 1059 | price += GET_PRICEa(probs[sym], bit); | ||
| 1060 | } | ||
| 1061 | while (sym >= 2); | ||
| 1062 | |||
| 1063 | { | ||
| 1064 | unsigned prob = probs[(size_t)i + (1 << (kLenNumHighBits - 1))]; | ||
| 1065 | prices[(size_t)i * 2 ] = price + GET_PRICEa_0(prob); | ||
| 1066 | prices[(size_t)i * 2 + 1] = price + GET_PRICEa_1(prob); | ||
| 1067 | } | ||
| 1068 | } | ||
| 1069 | while (i); | ||
| 1070 | |||
| 1071 | { | ||
| 1072 | unsigned posState; | ||
| 1073 | size_t num = (p->tableSize - kLenNumLowSymbols * 2) * sizeof(p->prices[0][0]); | ||
| 1074 | for (posState = 1; posState < numPosStates; posState++) | ||
| 1075 | memcpy(p->prices[posState] + kLenNumLowSymbols * 2, p->prices[0] + kLenNumLowSymbols * 2, num); | ||
| 1076 | } | ||
| 1077 | } | ||
| 1078 | } | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | /* | ||
| 1082 | #ifdef SHOW_STAT | ||
| 1083 | g_STAT_OFFSET += num; | ||
| 1084 | printf("\n MovePos %u", num); | ||
| 1085 | #endif | ||
| 1086 | */ | ||
| 1087 | |||
| 1088 | #define MOVE_POS(p, num) { \ | ||
| 1089 | p->additionalOffset += (num); \ | ||
| 1090 | p->matchFinder.Skip(p->matchFinderObj, (UInt32)(num)); } | ||
| 1091 | |||
| 1092 | |||
| 1093 | static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes) | ||
| 1094 | { | ||
| 1095 | unsigned numPairs; | ||
| 1096 | |||
| 1097 | p->additionalOffset++; | ||
| 1098 | p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); | ||
| 1099 | { | ||
| 1100 | const UInt32 *d = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); | ||
| 1101 | // if (!d) { p->mf_Failure = True; *numPairsRes = 0; return 0; } | ||
| 1102 | numPairs = (unsigned)(d - p->matches); | ||
| 1103 | } | ||
| 1104 | *numPairsRes = numPairs; | ||
| 1105 | |||
| 1106 | #ifdef SHOW_STAT | ||
| 1107 | printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2); | ||
| 1108 | g_STAT_OFFSET++; | ||
| 1109 | { | ||
| 1110 | unsigned i; | ||
| 1111 | for (i = 0; i < numPairs; i += 2) | ||
| 1112 | printf("%2u %6u | ", p->matches[i], p->matches[i + 1]); | ||
| 1113 | } | ||
| 1114 | #endif | ||
| 1115 | |||
| 1116 | if (numPairs == 0) | ||
| 1117 | return 0; | ||
| 1118 | { | ||
| 1119 | const unsigned len = p->matches[(size_t)numPairs - 2]; | ||
| 1120 | if (len != p->numFastBytes) | ||
| 1121 | return len; | ||
| 1122 | { | ||
| 1123 | UInt32 numAvail = p->numAvail; | ||
| 1124 | if (numAvail > LZMA_MATCH_LEN_MAX) | ||
| 1125 | numAvail = LZMA_MATCH_LEN_MAX; | ||
| 1126 | { | ||
| 1127 | const Byte *p1 = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; | ||
| 1128 | const Byte *p2 = p1 + len; | ||
| 1129 | const ptrdiff_t dif = (ptrdiff_t)-1 - (ptrdiff_t)p->matches[(size_t)numPairs - 1]; | ||
| 1130 | const Byte *lim = p1 + numAvail; | ||
| 1131 | for (; p2 != lim && *p2 == p2[dif]; p2++) | ||
| 1132 | {} | ||
| 1133 | return (unsigned)(p2 - p1); | ||
| 1134 | } | ||
| 1135 | } | ||
| 1136 | } | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | #define MARK_LIT ((UInt32)(Int32)-1) | ||
| 1140 | |||
| 1141 | #define MakeAs_Lit(p) { (p)->dist = MARK_LIT; (p)->extra = 0; } | ||
| 1142 | #define MakeAs_ShortRep(p) { (p)->dist = 0; (p)->extra = 0; } | ||
| 1143 | #define IsShortRep(p) ((p)->dist == 0) | ||
| 1144 | |||
| 1145 | |||
| 1146 | #define GetPrice_ShortRep(p, state, posState) \ | ||
| 1147 | ( GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState])) | ||
| 1148 | |||
| 1149 | #define GetPrice_Rep_0(p, state, posState) ( \ | ||
| 1150 | GET_PRICE_1(p->isMatch[state][posState]) \ | ||
| 1151 | + GET_PRICE_1(p->isRep0Long[state][posState])) \ | ||
| 1152 | + GET_PRICE_1(p->isRep[state]) \ | ||
| 1153 | + GET_PRICE_0(p->isRepG0[state]) | ||
| 1154 | |||
| 1155 | MY_FORCE_INLINE | ||
| 1156 | static UInt32 GetPrice_PureRep(const CLzmaEnc *p, unsigned repIndex, size_t state, size_t posState) | ||
| 1157 | { | ||
| 1158 | UInt32 price; | ||
| 1159 | UInt32 prob = p->isRepG0[state]; | ||
| 1160 | if (repIndex == 0) | ||
| 1161 | { | ||
| 1162 | price = GET_PRICE_0(prob); | ||
| 1163 | price += GET_PRICE_1(p->isRep0Long[state][posState]); | ||
| 1164 | } | ||
| 1165 | else | ||
| 1166 | { | ||
| 1167 | price = GET_PRICE_1(prob); | ||
| 1168 | prob = p->isRepG1[state]; | ||
| 1169 | if (repIndex == 1) | ||
| 1170 | price += GET_PRICE_0(prob); | ||
| 1171 | else | ||
| 1172 | { | ||
| 1173 | price += GET_PRICE_1(prob); | ||
| 1174 | price += GET_PRICE(p->isRepG2[state], repIndex - 2); | ||
| 1175 | } | ||
| 1176 | } | ||
| 1177 | return price; | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | |||
| 1181 | static unsigned Backward(CLzmaEnc *p, unsigned cur) | ||
| 1182 | { | ||
| 1183 | unsigned wr = cur + 1; | ||
| 1184 | p->optEnd = wr; | ||
| 1185 | |||
| 1186 | for (;;) | ||
| 1187 | { | ||
| 1188 | UInt32 dist = p->opt[cur].dist; | ||
| 1189 | unsigned len = (unsigned)p->opt[cur].len; | ||
| 1190 | unsigned extra = (unsigned)p->opt[cur].extra; | ||
| 1191 | cur -= len; | ||
| 1192 | |||
| 1193 | if (extra) | ||
| 1194 | { | ||
| 1195 | wr--; | ||
| 1196 | p->opt[wr].len = (UInt32)len; | ||
| 1197 | cur -= extra; | ||
| 1198 | len = extra; | ||
| 1199 | if (extra == 1) | ||
| 1200 | { | ||
| 1201 | p->opt[wr].dist = dist; | ||
| 1202 | dist = MARK_LIT; | ||
| 1203 | } | ||
| 1204 | else | ||
| 1205 | { | ||
| 1206 | p->opt[wr].dist = 0; | ||
| 1207 | len--; | ||
| 1208 | wr--; | ||
| 1209 | p->opt[wr].dist = MARK_LIT; | ||
| 1210 | p->opt[wr].len = 1; | ||
| 1211 | } | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | if (cur == 0) | ||
| 1215 | { | ||
| 1216 | p->backRes = dist; | ||
| 1217 | p->optCur = wr; | ||
| 1218 | return len; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | wr--; | ||
| 1222 | p->opt[wr].dist = dist; | ||
| 1223 | p->opt[wr].len = (UInt32)len; | ||
| 1224 | } | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | |||
| 1228 | |||
| 1229 | #define LIT_PROBS(pos, prevByte) \ | ||
| 1230 | (p->litProbs + (UInt32)3 * (((((pos) << 8) + (prevByte)) & p->lpMask) << p->lc)) | ||
| 1231 | |||
| 1232 | |||
| 1233 | static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) | ||
| 1234 | { | ||
| 1235 | unsigned last, cur; | ||
| 1236 | UInt32 reps[LZMA_NUM_REPS]; | ||
| 1237 | unsigned repLens[LZMA_NUM_REPS]; | ||
| 1238 | UInt32 *matches; | ||
| 1239 | |||
| 1240 | { | ||
| 1241 | UInt32 numAvail; | ||
| 1242 | unsigned numPairs, mainLen, repMaxIndex, i, posState; | ||
| 1243 | UInt32 matchPrice, repMatchPrice; | ||
| 1244 | const Byte *data; | ||
| 1245 | Byte curByte, matchByte; | ||
| 1246 | |||
| 1247 | p->optCur = p->optEnd = 0; | ||
| 1248 | |||
| 1249 | if (p->additionalOffset == 0) | ||
| 1250 | mainLen = ReadMatchDistances(p, &numPairs); | ||
| 1251 | else | ||
| 1252 | { | ||
| 1253 | mainLen = p->longestMatchLen; | ||
| 1254 | numPairs = p->numPairs; | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | numAvail = p->numAvail; | ||
| 1258 | if (numAvail < 2) | ||
| 1259 | { | ||
| 1260 | p->backRes = MARK_LIT; | ||
| 1261 | return 1; | ||
| 1262 | } | ||
| 1263 | if (numAvail > LZMA_MATCH_LEN_MAX) | ||
| 1264 | numAvail = LZMA_MATCH_LEN_MAX; | ||
| 1265 | |||
| 1266 | data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; | ||
| 1267 | repMaxIndex = 0; | ||
| 1268 | |||
| 1269 | for (i = 0; i < LZMA_NUM_REPS; i++) | ||
| 1270 | { | ||
| 1271 | unsigned len; | ||
| 1272 | const Byte *data2; | ||
| 1273 | reps[i] = p->reps[i]; | ||
| 1274 | data2 = data - reps[i]; | ||
| 1275 | if (data[0] != data2[0] || data[1] != data2[1]) | ||
| 1276 | { | ||
| 1277 | repLens[i] = 0; | ||
| 1278 | continue; | ||
| 1279 | } | ||
| 1280 | for (len = 2; len < numAvail && data[len] == data2[len]; len++) | ||
| 1281 | {} | ||
| 1282 | repLens[i] = len; | ||
| 1283 | if (len > repLens[repMaxIndex]) | ||
| 1284 | repMaxIndex = i; | ||
| 1285 | if (len == LZMA_MATCH_LEN_MAX) // 21.03 : optimization | ||
| 1286 | break; | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | if (repLens[repMaxIndex] >= p->numFastBytes) | ||
| 1290 | { | ||
| 1291 | unsigned len; | ||
| 1292 | p->backRes = (UInt32)repMaxIndex; | ||
| 1293 | len = repLens[repMaxIndex]; | ||
| 1294 | MOVE_POS(p, len - 1) | ||
| 1295 | return len; | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | matches = p->matches; | ||
| 1299 | #define MATCHES matches | ||
| 1300 | // #define MATCHES p->matches | ||
| 1301 | |||
| 1302 | if (mainLen >= p->numFastBytes) | ||
| 1303 | { | ||
| 1304 | p->backRes = MATCHES[(size_t)numPairs - 1] + LZMA_NUM_REPS; | ||
| 1305 | MOVE_POS(p, mainLen - 1) | ||
| 1306 | return mainLen; | ||
| 1307 | } | ||
| 1308 | |||
| 1309 | curByte = *data; | ||
| 1310 | matchByte = *(data - reps[0]); | ||
| 1311 | |||
| 1312 | last = repLens[repMaxIndex]; | ||
| 1313 | if (last <= mainLen) | ||
| 1314 | last = mainLen; | ||
| 1315 | |||
| 1316 | if (last < 2 && curByte != matchByte) | ||
| 1317 | { | ||
| 1318 | p->backRes = MARK_LIT; | ||
| 1319 | return 1; | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | p->opt[0].state = (CState)p->state; | ||
| 1323 | |||
| 1324 | posState = (position & p->pbMask); | ||
| 1325 | |||
| 1326 | { | ||
| 1327 | const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); | ||
| 1328 | p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + | ||
| 1329 | (!IsLitState(p->state) ? | ||
| 1330 | LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) : | ||
| 1331 | LitEnc_GetPrice(probs, curByte, p->ProbPrices)); | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | MakeAs_Lit(&p->opt[1]); | ||
| 1335 | |||
| 1336 | matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); | ||
| 1337 | repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); | ||
| 1338 | |||
| 1339 | // 18.06 | ||
| 1340 | if (matchByte == curByte && repLens[0] == 0) | ||
| 1341 | { | ||
| 1342 | UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, p->state, posState); | ||
| 1343 | if (shortRepPrice < p->opt[1].price) | ||
| 1344 | { | ||
| 1345 | p->opt[1].price = shortRepPrice; | ||
| 1346 | MakeAs_ShortRep(&p->opt[1]); | ||
| 1347 | } | ||
| 1348 | if (last < 2) | ||
| 1349 | { | ||
| 1350 | p->backRes = p->opt[1].dist; | ||
| 1351 | return 1; | ||
| 1352 | } | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | p->opt[1].len = 1; | ||
| 1356 | |||
| 1357 | p->opt[0].reps[0] = reps[0]; | ||
| 1358 | p->opt[0].reps[1] = reps[1]; | ||
| 1359 | p->opt[0].reps[2] = reps[2]; | ||
| 1360 | p->opt[0].reps[3] = reps[3]; | ||
| 1361 | |||
| 1362 | // ---------- REP ---------- | ||
| 1363 | |||
| 1364 | for (i = 0; i < LZMA_NUM_REPS; i++) | ||
| 1365 | { | ||
| 1366 | unsigned repLen = repLens[i]; | ||
| 1367 | UInt32 price; | ||
| 1368 | if (repLen < 2) | ||
| 1369 | continue; | ||
| 1370 | price = repMatchPrice + GetPrice_PureRep(p, i, p->state, posState); | ||
| 1371 | do | ||
| 1372 | { | ||
| 1373 | UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, repLen); | ||
| 1374 | COptimal *opt = &p->opt[repLen]; | ||
| 1375 | if (price2 < opt->price) | ||
| 1376 | { | ||
| 1377 | opt->price = price2; | ||
| 1378 | opt->len = (UInt32)repLen; | ||
| 1379 | opt->dist = (UInt32)i; | ||
| 1380 | opt->extra = 0; | ||
| 1381 | } | ||
| 1382 | } | ||
| 1383 | while (--repLen >= 2); | ||
| 1384 | } | ||
| 1385 | |||
| 1386 | |||
| 1387 | // ---------- MATCH ---------- | ||
| 1388 | { | ||
| 1389 | unsigned len = repLens[0] + 1; | ||
| 1390 | if (len <= mainLen) | ||
| 1391 | { | ||
| 1392 | unsigned offs = 0; | ||
| 1393 | UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); | ||
| 1394 | |||
| 1395 | if (len < 2) | ||
| 1396 | len = 2; | ||
| 1397 | else | ||
| 1398 | while (len > MATCHES[offs]) | ||
| 1399 | offs += 2; | ||
| 1400 | |||
| 1401 | for (; ; len++) | ||
| 1402 | { | ||
| 1403 | COptimal *opt; | ||
| 1404 | UInt32 dist = MATCHES[(size_t)offs + 1]; | ||
| 1405 | UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); | ||
| 1406 | unsigned lenToPosState = GetLenToPosState(len); | ||
| 1407 | |||
| 1408 | if (dist < kNumFullDistances) | ||
| 1409 | price += p->distancesPrices[lenToPosState][dist & (kNumFullDistances - 1)]; | ||
| 1410 | else | ||
| 1411 | { | ||
| 1412 | unsigned slot; | ||
| 1413 | GetPosSlot2(dist, slot); | ||
| 1414 | price += p->alignPrices[dist & kAlignMask]; | ||
| 1415 | price += p->posSlotPrices[lenToPosState][slot]; | ||
| 1416 | } | ||
| 1417 | |||
| 1418 | opt = &p->opt[len]; | ||
| 1419 | |||
| 1420 | if (price < opt->price) | ||
| 1421 | { | ||
| 1422 | opt->price = price; | ||
| 1423 | opt->len = (UInt32)len; | ||
| 1424 | opt->dist = dist + LZMA_NUM_REPS; | ||
| 1425 | opt->extra = 0; | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | if (len == MATCHES[offs]) | ||
| 1429 | { | ||
| 1430 | offs += 2; | ||
| 1431 | if (offs == numPairs) | ||
| 1432 | break; | ||
| 1433 | } | ||
| 1434 | } | ||
| 1435 | } | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | |||
| 1439 | cur = 0; | ||
| 1440 | |||
| 1441 | #ifdef SHOW_STAT2 | ||
| 1442 | /* if (position >= 0) */ | ||
| 1443 | { | ||
| 1444 | unsigned i; | ||
| 1445 | printf("\n pos = %4X", position); | ||
| 1446 | for (i = cur; i <= last; i++) | ||
| 1447 | printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price); | ||
| 1448 | } | ||
| 1449 | #endif | ||
| 1450 | } | ||
| 1451 | |||
| 1452 | |||
| 1453 | |||
| 1454 | // ---------- Optimal Parsing ---------- | ||
| 1455 | |||
| 1456 | for (;;) | ||
| 1457 | { | ||
| 1458 | unsigned numAvail; | ||
| 1459 | UInt32 numAvailFull; | ||
| 1460 | unsigned newLen, numPairs, prev, state, posState, startLen; | ||
| 1461 | UInt32 litPrice, matchPrice, repMatchPrice; | ||
| 1462 | BoolInt nextIsLit; | ||
| 1463 | Byte curByte, matchByte; | ||
| 1464 | const Byte *data; | ||
| 1465 | COptimal *curOpt, *nextOpt; | ||
| 1466 | |||
| 1467 | if (++cur == last) | ||
| 1468 | break; | ||
| 1469 | |||
| 1470 | // 18.06 | ||
| 1471 | if (cur >= kNumOpts - 64) | ||
| 1472 | { | ||
| 1473 | unsigned j, best; | ||
| 1474 | UInt32 price = p->opt[cur].price; | ||
| 1475 | best = cur; | ||
| 1476 | for (j = cur + 1; j <= last; j++) | ||
| 1477 | { | ||
| 1478 | UInt32 price2 = p->opt[j].price; | ||
| 1479 | if (price >= price2) | ||
| 1480 | { | ||
| 1481 | price = price2; | ||
| 1482 | best = j; | ||
| 1483 | } | ||
| 1484 | } | ||
| 1485 | { | ||
| 1486 | unsigned delta = best - cur; | ||
| 1487 | if (delta != 0) | ||
| 1488 | { | ||
| 1489 | MOVE_POS(p, delta); | ||
| 1490 | } | ||
| 1491 | } | ||
| 1492 | cur = best; | ||
| 1493 | break; | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | newLen = ReadMatchDistances(p, &numPairs); | ||
| 1497 | |||
| 1498 | if (newLen >= p->numFastBytes) | ||
| 1499 | { | ||
| 1500 | p->numPairs = numPairs; | ||
| 1501 | p->longestMatchLen = newLen; | ||
| 1502 | break; | ||
| 1503 | } | ||
| 1504 | |||
| 1505 | curOpt = &p->opt[cur]; | ||
| 1506 | |||
| 1507 | position++; | ||
| 1508 | |||
| 1509 | // we need that check here, if skip_items in p->opt are possible | ||
| 1510 | /* | ||
| 1511 | if (curOpt->price >= kInfinityPrice) | ||
| 1512 | continue; | ||
| 1513 | */ | ||
| 1514 | |||
| 1515 | prev = cur - curOpt->len; | ||
| 1516 | |||
| 1517 | if (curOpt->len == 1) | ||
| 1518 | { | ||
| 1519 | state = (unsigned)p->opt[prev].state; | ||
| 1520 | if (IsShortRep(curOpt)) | ||
| 1521 | state = kShortRepNextStates[state]; | ||
| 1522 | else | ||
| 1523 | state = kLiteralNextStates[state]; | ||
| 1524 | } | ||
| 1525 | else | ||
| 1526 | { | ||
| 1527 | const COptimal *prevOpt; | ||
| 1528 | UInt32 b0; | ||
| 1529 | UInt32 dist = curOpt->dist; | ||
| 1530 | |||
| 1531 | if (curOpt->extra) | ||
| 1532 | { | ||
| 1533 | prev -= (unsigned)curOpt->extra; | ||
| 1534 | state = kState_RepAfterLit; | ||
| 1535 | if (curOpt->extra == 1) | ||
| 1536 | state = (dist < LZMA_NUM_REPS ? kState_RepAfterLit : kState_MatchAfterLit); | ||
| 1537 | } | ||
| 1538 | else | ||
| 1539 | { | ||
| 1540 | state = (unsigned)p->opt[prev].state; | ||
| 1541 | if (dist < LZMA_NUM_REPS) | ||
| 1542 | state = kRepNextStates[state]; | ||
| 1543 | else | ||
| 1544 | state = kMatchNextStates[state]; | ||
| 1545 | } | ||
| 1546 | |||
| 1547 | prevOpt = &p->opt[prev]; | ||
| 1548 | b0 = prevOpt->reps[0]; | ||
| 1549 | |||
| 1550 | if (dist < LZMA_NUM_REPS) | ||
| 1551 | { | ||
| 1552 | if (dist == 0) | ||
| 1553 | { | ||
| 1554 | reps[0] = b0; | ||
| 1555 | reps[1] = prevOpt->reps[1]; | ||
| 1556 | reps[2] = prevOpt->reps[2]; | ||
| 1557 | reps[3] = prevOpt->reps[3]; | ||
| 1558 | } | ||
| 1559 | else | ||
| 1560 | { | ||
| 1561 | reps[1] = b0; | ||
| 1562 | b0 = prevOpt->reps[1]; | ||
| 1563 | if (dist == 1) | ||
| 1564 | { | ||
| 1565 | reps[0] = b0; | ||
| 1566 | reps[2] = prevOpt->reps[2]; | ||
| 1567 | reps[3] = prevOpt->reps[3]; | ||
| 1568 | } | ||
| 1569 | else | ||
| 1570 | { | ||
| 1571 | reps[2] = b0; | ||
| 1572 | reps[0] = prevOpt->reps[dist]; | ||
| 1573 | reps[3] = prevOpt->reps[dist ^ 1]; | ||
| 1574 | } | ||
| 1575 | } | ||
| 1576 | } | ||
| 1577 | else | ||
| 1578 | { | ||
| 1579 | reps[0] = (dist - LZMA_NUM_REPS + 1); | ||
| 1580 | reps[1] = b0; | ||
| 1581 | reps[2] = prevOpt->reps[1]; | ||
| 1582 | reps[3] = prevOpt->reps[2]; | ||
| 1583 | } | ||
| 1584 | } | ||
| 1585 | |||
| 1586 | curOpt->state = (CState)state; | ||
| 1587 | curOpt->reps[0] = reps[0]; | ||
| 1588 | curOpt->reps[1] = reps[1]; | ||
| 1589 | curOpt->reps[2] = reps[2]; | ||
| 1590 | curOpt->reps[3] = reps[3]; | ||
| 1591 | |||
| 1592 | data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; | ||
| 1593 | curByte = *data; | ||
| 1594 | matchByte = *(data - reps[0]); | ||
| 1595 | |||
| 1596 | posState = (position & p->pbMask); | ||
| 1597 | |||
| 1598 | /* | ||
| 1599 | The order of Price checks: | ||
| 1600 | < LIT | ||
| 1601 | <= SHORT_REP | ||
| 1602 | < LIT : REP_0 | ||
| 1603 | < REP [ : LIT : REP_0 ] | ||
| 1604 | < MATCH [ : LIT : REP_0 ] | ||
| 1605 | */ | ||
| 1606 | |||
| 1607 | { | ||
| 1608 | UInt32 curPrice = curOpt->price; | ||
| 1609 | unsigned prob = p->isMatch[state][posState]; | ||
| 1610 | matchPrice = curPrice + GET_PRICE_1(prob); | ||
| 1611 | litPrice = curPrice + GET_PRICE_0(prob); | ||
| 1612 | } | ||
| 1613 | |||
| 1614 | nextOpt = &p->opt[(size_t)cur + 1]; | ||
| 1615 | nextIsLit = False; | ||
| 1616 | |||
| 1617 | // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice) | ||
| 1618 | // 18.new.06 | ||
| 1619 | if ((nextOpt->price < kInfinityPrice | ||
| 1620 | // && !IsLitState(state) | ||
| 1621 | && matchByte == curByte) | ||
| 1622 | || litPrice > nextOpt->price | ||
| 1623 | ) | ||
| 1624 | litPrice = 0; | ||
| 1625 | else | ||
| 1626 | { | ||
| 1627 | const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); | ||
| 1628 | litPrice += (!IsLitState(state) ? | ||
| 1629 | LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) : | ||
| 1630 | LitEnc_GetPrice(probs, curByte, p->ProbPrices)); | ||
| 1631 | |||
| 1632 | if (litPrice < nextOpt->price) | ||
| 1633 | { | ||
| 1634 | nextOpt->price = litPrice; | ||
| 1635 | nextOpt->len = 1; | ||
| 1636 | MakeAs_Lit(nextOpt); | ||
| 1637 | nextIsLit = True; | ||
| 1638 | } | ||
| 1639 | } | ||
| 1640 | |||
| 1641 | repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); | ||
| 1642 | |||
| 1643 | numAvailFull = p->numAvail; | ||
| 1644 | { | ||
| 1645 | unsigned temp = kNumOpts - 1 - cur; | ||
| 1646 | if (numAvailFull > temp) | ||
| 1647 | numAvailFull = (UInt32)temp; | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | // 18.06 | ||
| 1651 | // ---------- SHORT_REP ---------- | ||
| 1652 | if (IsLitState(state)) // 18.new | ||
| 1653 | if (matchByte == curByte) | ||
| 1654 | if (repMatchPrice < nextOpt->price) // 18.new | ||
| 1655 | // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1)) | ||
| 1656 | if ( | ||
| 1657 | // nextOpt->price >= kInfinityPrice || | ||
| 1658 | nextOpt->len < 2 // we can check nextOpt->len, if skip items are not allowed in p->opt | ||
| 1659 | || (nextOpt->dist != 0 | ||
| 1660 | // && nextOpt->extra <= 1 // 17.old | ||
| 1661 | ) | ||
| 1662 | ) | ||
| 1663 | { | ||
| 1664 | UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, state, posState); | ||
| 1665 | // if (shortRepPrice <= nextOpt->price) // 17.old | ||
| 1666 | if (shortRepPrice < nextOpt->price) // 18.new | ||
| 1667 | { | ||
| 1668 | nextOpt->price = shortRepPrice; | ||
| 1669 | nextOpt->len = 1; | ||
| 1670 | MakeAs_ShortRep(nextOpt); | ||
| 1671 | nextIsLit = False; | ||
| 1672 | } | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | if (numAvailFull < 2) | ||
| 1676 | continue; | ||
| 1677 | numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); | ||
| 1678 | |||
| 1679 | // numAvail <= p->numFastBytes | ||
| 1680 | |||
| 1681 | // ---------- LIT : REP_0 ---------- | ||
| 1682 | |||
| 1683 | if (!nextIsLit | ||
| 1684 | && litPrice != 0 // 18.new | ||
| 1685 | && matchByte != curByte | ||
| 1686 | && numAvailFull > 2) | ||
| 1687 | { | ||
| 1688 | const Byte *data2 = data - reps[0]; | ||
| 1689 | if (data[1] == data2[1] && data[2] == data2[2]) | ||
| 1690 | { | ||
| 1691 | unsigned len; | ||
| 1692 | unsigned limit = p->numFastBytes + 1; | ||
| 1693 | if (limit > numAvailFull) | ||
| 1694 | limit = numAvailFull; | ||
| 1695 | for (len = 3; len < limit && data[len] == data2[len]; len++) | ||
| 1696 | {} | ||
| 1697 | |||
| 1698 | { | ||
| 1699 | unsigned state2 = kLiteralNextStates[state]; | ||
| 1700 | unsigned posState2 = (position + 1) & p->pbMask; | ||
| 1701 | UInt32 price = litPrice + GetPrice_Rep_0(p, state2, posState2); | ||
| 1702 | { | ||
| 1703 | unsigned offset = cur + len; | ||
| 1704 | |||
| 1705 | if (last < offset) | ||
| 1706 | last = offset; | ||
| 1707 | |||
| 1708 | // do | ||
| 1709 | { | ||
| 1710 | UInt32 price2; | ||
| 1711 | COptimal *opt; | ||
| 1712 | len--; | ||
| 1713 | // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2); | ||
| 1714 | price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len); | ||
| 1715 | |||
| 1716 | opt = &p->opt[offset]; | ||
| 1717 | // offset--; | ||
| 1718 | if (price2 < opt->price) | ||
| 1719 | { | ||
| 1720 | opt->price = price2; | ||
| 1721 | opt->len = (UInt32)len; | ||
| 1722 | opt->dist = 0; | ||
| 1723 | opt->extra = 1; | ||
| 1724 | } | ||
| 1725 | } | ||
| 1726 | // while (len >= 3); | ||
| 1727 | } | ||
| 1728 | } | ||
| 1729 | } | ||
| 1730 | } | ||
| 1731 | |||
| 1732 | startLen = 2; /* speed optimization */ | ||
| 1733 | |||
| 1734 | { | ||
| 1735 | // ---------- REP ---------- | ||
| 1736 | unsigned repIndex = 0; // 17.old | ||
| 1737 | // unsigned repIndex = IsLitState(state) ? 0 : 1; // 18.notused | ||
| 1738 | for (; repIndex < LZMA_NUM_REPS; repIndex++) | ||
| 1739 | { | ||
| 1740 | unsigned len; | ||
| 1741 | UInt32 price; | ||
| 1742 | const Byte *data2 = data - reps[repIndex]; | ||
| 1743 | if (data[0] != data2[0] || data[1] != data2[1]) | ||
| 1744 | continue; | ||
| 1745 | |||
| 1746 | for (len = 2; len < numAvail && data[len] == data2[len]; len++) | ||
| 1747 | {} | ||
| 1748 | |||
| 1749 | // if (len < startLen) continue; // 18.new: speed optimization | ||
| 1750 | |||
| 1751 | { | ||
| 1752 | unsigned offset = cur + len; | ||
| 1753 | if (last < offset) | ||
| 1754 | last = offset; | ||
| 1755 | } | ||
| 1756 | { | ||
| 1757 | unsigned len2 = len; | ||
| 1758 | price = repMatchPrice + GetPrice_PureRep(p, repIndex, state, posState); | ||
| 1759 | do | ||
| 1760 | { | ||
| 1761 | UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, len2); | ||
| 1762 | COptimal *opt = &p->opt[cur + len2]; | ||
| 1763 | if (price2 < opt->price) | ||
| 1764 | { | ||
| 1765 | opt->price = price2; | ||
| 1766 | opt->len = (UInt32)len2; | ||
| 1767 | opt->dist = (UInt32)repIndex; | ||
| 1768 | opt->extra = 0; | ||
| 1769 | } | ||
| 1770 | } | ||
| 1771 | while (--len2 >= 2); | ||
| 1772 | } | ||
| 1773 | |||
| 1774 | if (repIndex == 0) startLen = len + 1; // 17.old | ||
| 1775 | // startLen = len + 1; // 18.new | ||
| 1776 | |||
| 1777 | /* if (_maxMode) */ | ||
| 1778 | { | ||
| 1779 | // ---------- REP : LIT : REP_0 ---------- | ||
| 1780 | // numFastBytes + 1 + numFastBytes | ||
| 1781 | |||
| 1782 | unsigned len2 = len + 1; | ||
| 1783 | unsigned limit = len2 + p->numFastBytes; | ||
| 1784 | if (limit > numAvailFull) | ||
| 1785 | limit = numAvailFull; | ||
| 1786 | |||
| 1787 | len2 += 2; | ||
| 1788 | if (len2 <= limit) | ||
| 1789 | if (data[len2 - 2] == data2[len2 - 2]) | ||
| 1790 | if (data[len2 - 1] == data2[len2 - 1]) | ||
| 1791 | { | ||
| 1792 | unsigned state2 = kRepNextStates[state]; | ||
| 1793 | unsigned posState2 = (position + len) & p->pbMask; | ||
| 1794 | price += GET_PRICE_LEN(&p->repLenEnc, posState, len) | ||
| 1795 | + GET_PRICE_0(p->isMatch[state2][posState2]) | ||
| 1796 | + LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]), | ||
| 1797 | data[len], data2[len], p->ProbPrices); | ||
| 1798 | |||
| 1799 | // state2 = kLiteralNextStates[state2]; | ||
| 1800 | state2 = kState_LitAfterRep; | ||
| 1801 | posState2 = (posState2 + 1) & p->pbMask; | ||
| 1802 | |||
| 1803 | |||
| 1804 | price += GetPrice_Rep_0(p, state2, posState2); | ||
| 1805 | |||
| 1806 | for (; len2 < limit && data[len2] == data2[len2]; len2++) | ||
| 1807 | {} | ||
| 1808 | |||
| 1809 | len2 -= len; | ||
| 1810 | // if (len2 >= 3) | ||
| 1811 | { | ||
| 1812 | { | ||
| 1813 | unsigned offset = cur + len + len2; | ||
| 1814 | |||
| 1815 | if (last < offset) | ||
| 1816 | last = offset; | ||
| 1817 | // do | ||
| 1818 | { | ||
| 1819 | UInt32 price2; | ||
| 1820 | COptimal *opt; | ||
| 1821 | len2--; | ||
| 1822 | // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2); | ||
| 1823 | price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2); | ||
| 1824 | |||
| 1825 | opt = &p->opt[offset]; | ||
| 1826 | // offset--; | ||
| 1827 | if (price2 < opt->price) | ||
| 1828 | { | ||
| 1829 | opt->price = price2; | ||
| 1830 | opt->len = (UInt32)len2; | ||
| 1831 | opt->extra = (CExtra)(len + 1); | ||
| 1832 | opt->dist = (UInt32)repIndex; | ||
| 1833 | } | ||
| 1834 | } | ||
| 1835 | // while (len2 >= 3); | ||
| 1836 | } | ||
| 1837 | } | ||
| 1838 | } | ||
| 1839 | } | ||
| 1840 | } | ||
| 1841 | } | ||
| 1842 | |||
| 1843 | |||
| 1844 | // ---------- MATCH ---------- | ||
| 1845 | /* for (unsigned len = 2; len <= newLen; len++) */ | ||
| 1846 | if (newLen > numAvail) | ||
| 1847 | { | ||
| 1848 | newLen = numAvail; | ||
| 1849 | for (numPairs = 0; newLen > MATCHES[numPairs]; numPairs += 2); | ||
| 1850 | MATCHES[numPairs] = (UInt32)newLen; | ||
| 1851 | numPairs += 2; | ||
| 1852 | } | ||
| 1853 | |||
| 1854 | // startLen = 2; /* speed optimization */ | ||
| 1855 | |||
| 1856 | if (newLen >= startLen) | ||
| 1857 | { | ||
| 1858 | UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); | ||
| 1859 | UInt32 dist; | ||
| 1860 | unsigned offs, posSlot, len; | ||
| 1861 | |||
| 1862 | { | ||
| 1863 | unsigned offset = cur + newLen; | ||
| 1864 | if (last < offset) | ||
| 1865 | last = offset; | ||
| 1866 | } | ||
| 1867 | |||
| 1868 | offs = 0; | ||
| 1869 | while (startLen > MATCHES[offs]) | ||
| 1870 | offs += 2; | ||
| 1871 | dist = MATCHES[(size_t)offs + 1]; | ||
| 1872 | |||
| 1873 | // if (dist >= kNumFullDistances) | ||
| 1874 | GetPosSlot2(dist, posSlot); | ||
| 1875 | |||
| 1876 | for (len = /*2*/ startLen; ; len++) | ||
| 1877 | { | ||
| 1878 | UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); | ||
| 1879 | { | ||
| 1880 | COptimal *opt; | ||
| 1881 | unsigned lenNorm = len - 2; | ||
| 1882 | lenNorm = GetLenToPosState2(lenNorm); | ||
| 1883 | if (dist < kNumFullDistances) | ||
| 1884 | price += p->distancesPrices[lenNorm][dist & (kNumFullDistances - 1)]; | ||
| 1885 | else | ||
| 1886 | price += p->posSlotPrices[lenNorm][posSlot] + p->alignPrices[dist & kAlignMask]; | ||
| 1887 | |||
| 1888 | opt = &p->opt[cur + len]; | ||
| 1889 | if (price < opt->price) | ||
| 1890 | { | ||
| 1891 | opt->price = price; | ||
| 1892 | opt->len = (UInt32)len; | ||
| 1893 | opt->dist = dist + LZMA_NUM_REPS; | ||
| 1894 | opt->extra = 0; | ||
| 1895 | } | ||
| 1896 | } | ||
| 1897 | |||
| 1898 | if (len == MATCHES[offs]) | ||
| 1899 | { | ||
| 1900 | // if (p->_maxMode) { | ||
| 1901 | // MATCH : LIT : REP_0 | ||
| 1902 | |||
| 1903 | const Byte *data2 = data - dist - 1; | ||
| 1904 | unsigned len2 = len + 1; | ||
| 1905 | unsigned limit = len2 + p->numFastBytes; | ||
| 1906 | if (limit > numAvailFull) | ||
| 1907 | limit = numAvailFull; | ||
| 1908 | |||
| 1909 | len2 += 2; | ||
| 1910 | if (len2 <= limit) | ||
| 1911 | if (data[len2 - 2] == data2[len2 - 2]) | ||
| 1912 | if (data[len2 - 1] == data2[len2 - 1]) | ||
| 1913 | { | ||
| 1914 | for (; len2 < limit && data[len2] == data2[len2]; len2++) | ||
| 1915 | {} | ||
| 1916 | |||
| 1917 | len2 -= len; | ||
| 1918 | |||
| 1919 | // if (len2 >= 3) | ||
| 1920 | { | ||
| 1921 | unsigned state2 = kMatchNextStates[state]; | ||
| 1922 | unsigned posState2 = (position + len) & p->pbMask; | ||
| 1923 | unsigned offset; | ||
| 1924 | price += GET_PRICE_0(p->isMatch[state2][posState2]); | ||
| 1925 | price += LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]), | ||
| 1926 | data[len], data2[len], p->ProbPrices); | ||
| 1927 | |||
| 1928 | // state2 = kLiteralNextStates[state2]; | ||
| 1929 | state2 = kState_LitAfterMatch; | ||
| 1930 | |||
| 1931 | posState2 = (posState2 + 1) & p->pbMask; | ||
| 1932 | price += GetPrice_Rep_0(p, state2, posState2); | ||
| 1933 | |||
| 1934 | offset = cur + len + len2; | ||
| 1935 | |||
| 1936 | if (last < offset) | ||
| 1937 | last = offset; | ||
| 1938 | // do | ||
| 1939 | { | ||
| 1940 | UInt32 price2; | ||
| 1941 | COptimal *opt; | ||
| 1942 | len2--; | ||
| 1943 | // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2); | ||
| 1944 | price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2); | ||
| 1945 | opt = &p->opt[offset]; | ||
| 1946 | // offset--; | ||
| 1947 | if (price2 < opt->price) | ||
| 1948 | { | ||
| 1949 | opt->price = price2; | ||
| 1950 | opt->len = (UInt32)len2; | ||
| 1951 | opt->extra = (CExtra)(len + 1); | ||
| 1952 | opt->dist = dist + LZMA_NUM_REPS; | ||
| 1953 | } | ||
| 1954 | } | ||
| 1955 | // while (len2 >= 3); | ||
| 1956 | } | ||
| 1957 | |||
| 1958 | } | ||
| 1959 | |||
| 1960 | offs += 2; | ||
| 1961 | if (offs == numPairs) | ||
| 1962 | break; | ||
| 1963 | dist = MATCHES[(size_t)offs + 1]; | ||
| 1964 | // if (dist >= kNumFullDistances) | ||
| 1965 | GetPosSlot2(dist, posSlot); | ||
| 1966 | } | ||
| 1967 | } | ||
| 1968 | } | ||
| 1969 | } | ||
| 1970 | |||
| 1971 | do | ||
| 1972 | p->opt[last].price = kInfinityPrice; | ||
| 1973 | while (--last); | ||
| 1974 | |||
| 1975 | return Backward(p, cur); | ||
| 1976 | } | ||
| 1977 | |||
| 1978 | |||
| 1979 | |||
| 1980 | #define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) | ||
| 1981 | |||
| 1982 | |||
| 1983 | |||
| 1984 | static unsigned GetOptimumFast(CLzmaEnc *p) | ||
| 1985 | { | ||
| 1986 | UInt32 numAvail, mainDist; | ||
| 1987 | unsigned mainLen, numPairs, repIndex, repLen, i; | ||
| 1988 | const Byte *data; | ||
| 1989 | |||
| 1990 | if (p->additionalOffset == 0) | ||
| 1991 | mainLen = ReadMatchDistances(p, &numPairs); | ||
| 1992 | else | ||
| 1993 | { | ||
| 1994 | mainLen = p->longestMatchLen; | ||
| 1995 | numPairs = p->numPairs; | ||
| 1996 | } | ||
| 1997 | |||
| 1998 | numAvail = p->numAvail; | ||
| 1999 | p->backRes = MARK_LIT; | ||
| 2000 | if (numAvail < 2) | ||
| 2001 | return 1; | ||
| 2002 | // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused | ||
| 2003 | if (numAvail > LZMA_MATCH_LEN_MAX) | ||
| 2004 | numAvail = LZMA_MATCH_LEN_MAX; | ||
| 2005 | data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; | ||
| 2006 | repLen = repIndex = 0; | ||
| 2007 | |||
| 2008 | for (i = 0; i < LZMA_NUM_REPS; i++) | ||
| 2009 | { | ||
| 2010 | unsigned len; | ||
| 2011 | const Byte *data2 = data - p->reps[i]; | ||
| 2012 | if (data[0] != data2[0] || data[1] != data2[1]) | ||
| 2013 | continue; | ||
| 2014 | for (len = 2; len < numAvail && data[len] == data2[len]; len++) | ||
| 2015 | {} | ||
| 2016 | if (len >= p->numFastBytes) | ||
| 2017 | { | ||
| 2018 | p->backRes = (UInt32)i; | ||
| 2019 | MOVE_POS(p, len - 1) | ||
| 2020 | return len; | ||
| 2021 | } | ||
| 2022 | if (len > repLen) | ||
| 2023 | { | ||
| 2024 | repIndex = i; | ||
| 2025 | repLen = len; | ||
| 2026 | } | ||
| 2027 | } | ||
| 2028 | |||
| 2029 | if (mainLen >= p->numFastBytes) | ||
| 2030 | { | ||
| 2031 | p->backRes = p->matches[(size_t)numPairs - 1] + LZMA_NUM_REPS; | ||
| 2032 | MOVE_POS(p, mainLen - 1) | ||
| 2033 | return mainLen; | ||
| 2034 | } | ||
| 2035 | |||
| 2036 | mainDist = 0; /* for GCC */ | ||
| 2037 | |||
| 2038 | if (mainLen >= 2) | ||
| 2039 | { | ||
| 2040 | mainDist = p->matches[(size_t)numPairs - 1]; | ||
| 2041 | while (numPairs > 2) | ||
| 2042 | { | ||
| 2043 | UInt32 dist2; | ||
| 2044 | if (mainLen != p->matches[(size_t)numPairs - 4] + 1) | ||
| 2045 | break; | ||
| 2046 | dist2 = p->matches[(size_t)numPairs - 3]; | ||
| 2047 | if (!ChangePair(dist2, mainDist)) | ||
| 2048 | break; | ||
| 2049 | numPairs -= 2; | ||
| 2050 | mainLen--; | ||
| 2051 | mainDist = dist2; | ||
| 2052 | } | ||
| 2053 | if (mainLen == 2 && mainDist >= 0x80) | ||
| 2054 | mainLen = 1; | ||
| 2055 | } | ||
| 2056 | |||
| 2057 | if (repLen >= 2) | ||
| 2058 | if ( repLen + 1 >= mainLen | ||
| 2059 | || (repLen + 2 >= mainLen && mainDist >= (1 << 9)) | ||
| 2060 | || (repLen + 3 >= mainLen && mainDist >= (1 << 15))) | ||
| 2061 | { | ||
| 2062 | p->backRes = (UInt32)repIndex; | ||
| 2063 | MOVE_POS(p, repLen - 1) | ||
| 2064 | return repLen; | ||
| 2065 | } | ||
| 2066 | |||
| 2067 | if (mainLen < 2 || numAvail <= 2) | ||
| 2068 | return 1; | ||
| 2069 | |||
| 2070 | { | ||
| 2071 | unsigned len1 = ReadMatchDistances(p, &p->numPairs); | ||
| 2072 | p->longestMatchLen = len1; | ||
| 2073 | |||
| 2074 | if (len1 >= 2) | ||
| 2075 | { | ||
| 2076 | UInt32 newDist = p->matches[(size_t)p->numPairs - 1]; | ||
| 2077 | if ( (len1 >= mainLen && newDist < mainDist) | ||
| 2078 | || (len1 == mainLen + 1 && !ChangePair(mainDist, newDist)) | ||
| 2079 | || (len1 > mainLen + 1) | ||
| 2080 | || (len1 + 1 >= mainLen && mainLen >= 3 && ChangePair(newDist, mainDist))) | ||
| 2081 | return 1; | ||
| 2082 | } | ||
| 2083 | } | ||
| 2084 | |||
| 2085 | data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; | ||
| 2086 | |||
| 2087 | for (i = 0; i < LZMA_NUM_REPS; i++) | ||
| 2088 | { | ||
| 2089 | unsigned len, limit; | ||
| 2090 | const Byte *data2 = data - p->reps[i]; | ||
| 2091 | if (data[0] != data2[0] || data[1] != data2[1]) | ||
| 2092 | continue; | ||
| 2093 | limit = mainLen - 1; | ||
| 2094 | for (len = 2;; len++) | ||
| 2095 | { | ||
| 2096 | if (len >= limit) | ||
| 2097 | return 1; | ||
| 2098 | if (data[len] != data2[len]) | ||
| 2099 | break; | ||
| 2100 | } | ||
| 2101 | } | ||
| 2102 | |||
| 2103 | p->backRes = mainDist + LZMA_NUM_REPS; | ||
| 2104 | if (mainLen != 2) | ||
| 2105 | { | ||
| 2106 | MOVE_POS(p, mainLen - 2) | ||
| 2107 | } | ||
| 2108 | return mainLen; | ||
| 2109 | } | ||
| 2110 | |||
| 2111 | |||
| 2112 | |||
| 2113 | |||
| 2114 | static void WriteEndMarker(CLzmaEnc *p, unsigned posState) | ||
| 2115 | { | ||
| 2116 | UInt32 range; | ||
| 2117 | range = p->rc.range; | ||
| 2118 | { | ||
| 2119 | UInt32 ttt, newBound; | ||
| 2120 | CLzmaProb *prob = &p->isMatch[p->state][posState]; | ||
| 2121 | RC_BIT_PRE(&p->rc, prob) | ||
| 2122 | RC_BIT_1(&p->rc, prob) | ||
| 2123 | prob = &p->isRep[p->state]; | ||
| 2124 | RC_BIT_PRE(&p->rc, prob) | ||
| 2125 | RC_BIT_0(&p->rc, prob) | ||
| 2126 | } | ||
| 2127 | p->state = kMatchNextStates[p->state]; | ||
| 2128 | |||
| 2129 | p->rc.range = range; | ||
| 2130 | LenEnc_Encode(&p->lenProbs, &p->rc, 0, posState); | ||
| 2131 | range = p->rc.range; | ||
| 2132 | |||
| 2133 | { | ||
| 2134 | // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1); | ||
| 2135 | CLzmaProb *probs = p->posSlotEncoder[0]; | ||
| 2136 | unsigned m = 1; | ||
| 2137 | do | ||
| 2138 | { | ||
| 2139 | UInt32 ttt, newBound; | ||
| 2140 | RC_BIT_PRE(p, probs + m) | ||
| 2141 | RC_BIT_1(&p->rc, probs + m); | ||
| 2142 | m = (m << 1) + 1; | ||
| 2143 | } | ||
| 2144 | while (m < (1 << kNumPosSlotBits)); | ||
| 2145 | } | ||
| 2146 | { | ||
| 2147 | // RangeEnc_EncodeDirectBits(&p->rc, ((UInt32)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); UInt32 range = p->range; | ||
| 2148 | unsigned numBits = 30 - kNumAlignBits; | ||
| 2149 | do | ||
| 2150 | { | ||
| 2151 | range >>= 1; | ||
| 2152 | p->rc.low += range; | ||
| 2153 | RC_NORM(&p->rc) | ||
| 2154 | } | ||
| 2155 | while (--numBits); | ||
| 2156 | } | ||
| 2157 | |||
| 2158 | { | ||
| 2159 | // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); | ||
| 2160 | CLzmaProb *probs = p->posAlignEncoder; | ||
| 2161 | unsigned m = 1; | ||
| 2162 | do | ||
| 2163 | { | ||
| 2164 | UInt32 ttt, newBound; | ||
| 2165 | RC_BIT_PRE(p, probs + m) | ||
| 2166 | RC_BIT_1(&p->rc, probs + m); | ||
| 2167 | m = (m << 1) + 1; | ||
| 2168 | } | ||
| 2169 | while (m < kAlignTableSize); | ||
| 2170 | } | ||
| 2171 | p->rc.range = range; | ||
| 2172 | } | ||
| 2173 | |||
| 2174 | |||
| 2175 | static SRes CheckErrors(CLzmaEnc *p) | ||
| 2176 | { | ||
| 2177 | if (p->result != SZ_OK) | ||
| 2178 | return p->result; | ||
| 2179 | if (p->rc.res != SZ_OK) | ||
| 2180 | p->result = SZ_ERROR_WRITE; | ||
| 2181 | |||
| 2182 | #ifndef _7ZIP_ST | ||
| 2183 | if ( | ||
| 2184 | // p->mf_Failure || | ||
| 2185 | (p->mtMode && | ||
| 2186 | ( // p->matchFinderMt.failure_LZ_LZ || | ||
| 2187 | p->matchFinderMt.failure_LZ_BT)) | ||
| 2188 | ) | ||
| 2189 | { | ||
| 2190 | p->result = MY_HRES_ERROR__INTERNAL_ERROR; | ||
| 2191 | // printf("\nCheckErrors p->matchFinderMt.failureLZ\n"); | ||
| 2192 | } | ||
| 2193 | #endif | ||
| 2194 | |||
| 2195 | if (MFB.result != SZ_OK) | ||
| 2196 | p->result = SZ_ERROR_READ; | ||
| 2197 | |||
| 2198 | if (p->result != SZ_OK) | ||
| 2199 | p->finished = True; | ||
| 2200 | return p->result; | ||
| 2201 | } | ||
| 2202 | |||
| 2203 | |||
| 2204 | MY_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos) | ||
| 2205 | { | ||
| 2206 | /* ReleaseMFStream(); */ | ||
| 2207 | p->finished = True; | ||
| 2208 | if (p->writeEndMark) | ||
| 2209 | WriteEndMarker(p, nowPos & p->pbMask); | ||
| 2210 | RangeEnc_FlushData(&p->rc); | ||
| 2211 | RangeEnc_FlushStream(&p->rc); | ||
| 2212 | return CheckErrors(p); | ||
| 2213 | } | ||
| 2214 | |||
| 2215 | |||
| 2216 | MY_NO_INLINE static void FillAlignPrices(CLzmaEnc *p) | ||
| 2217 | { | ||
| 2218 | unsigned i; | ||
| 2219 | const CProbPrice *ProbPrices = p->ProbPrices; | ||
| 2220 | const CLzmaProb *probs = p->posAlignEncoder; | ||
| 2221 | // p->alignPriceCount = 0; | ||
| 2222 | for (i = 0; i < kAlignTableSize / 2; i++) | ||
| 2223 | { | ||
| 2224 | UInt32 price = 0; | ||
| 2225 | unsigned sym = i; | ||
| 2226 | unsigned m = 1; | ||
| 2227 | unsigned bit; | ||
| 2228 | UInt32 prob; | ||
| 2229 | bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; | ||
| 2230 | bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; | ||
| 2231 | bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; | ||
| 2232 | prob = probs[m]; | ||
| 2233 | p->alignPrices[i ] = price + GET_PRICEa_0(prob); | ||
| 2234 | p->alignPrices[i + 8] = price + GET_PRICEa_1(prob); | ||
| 2235 | // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); | ||
| 2236 | } | ||
| 2237 | } | ||
| 2238 | |||
| 2239 | |||
| 2240 | MY_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p) | ||
| 2241 | { | ||
| 2242 | // int y; for (y = 0; y < 100; y++) { | ||
| 2243 | |||
| 2244 | UInt32 tempPrices[kNumFullDistances]; | ||
| 2245 | unsigned i, lps; | ||
| 2246 | |||
| 2247 | const CProbPrice *ProbPrices = p->ProbPrices; | ||
| 2248 | p->matchPriceCount = 0; | ||
| 2249 | |||
| 2250 | for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++) | ||
| 2251 | { | ||
| 2252 | unsigned posSlot = GetPosSlot1(i); | ||
| 2253 | unsigned footerBits = (posSlot >> 1) - 1; | ||
| 2254 | unsigned base = ((2 | (posSlot & 1)) << footerBits); | ||
| 2255 | const CLzmaProb *probs = p->posEncoders + (size_t)base * 2; | ||
| 2256 | // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices); | ||
| 2257 | UInt32 price = 0; | ||
| 2258 | unsigned m = 1; | ||
| 2259 | unsigned sym = i; | ||
| 2260 | unsigned offset = (unsigned)1 << footerBits; | ||
| 2261 | base += i; | ||
| 2262 | |||
| 2263 | if (footerBits) | ||
| 2264 | do | ||
| 2265 | { | ||
| 2266 | unsigned bit = sym & 1; | ||
| 2267 | sym >>= 1; | ||
| 2268 | price += GET_PRICEa(probs[m], bit); | ||
| 2269 | m = (m << 1) + bit; | ||
| 2270 | } | ||
| 2271 | while (--footerBits); | ||
| 2272 | |||
| 2273 | { | ||
| 2274 | unsigned prob = probs[m]; | ||
| 2275 | tempPrices[base ] = price + GET_PRICEa_0(prob); | ||
| 2276 | tempPrices[base + offset] = price + GET_PRICEa_1(prob); | ||
| 2277 | } | ||
| 2278 | } | ||
| 2279 | |||
| 2280 | for (lps = 0; lps < kNumLenToPosStates; lps++) | ||
| 2281 | { | ||
| 2282 | unsigned slot; | ||
| 2283 | unsigned distTableSize2 = (p->distTableSize + 1) >> 1; | ||
| 2284 | UInt32 *posSlotPrices = p->posSlotPrices[lps]; | ||
| 2285 | const CLzmaProb *probs = p->posSlotEncoder[lps]; | ||
| 2286 | |||
| 2287 | for (slot = 0; slot < distTableSize2; slot++) | ||
| 2288 | { | ||
| 2289 | // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices); | ||
| 2290 | UInt32 price; | ||
| 2291 | unsigned bit; | ||
| 2292 | unsigned sym = slot + (1 << (kNumPosSlotBits - 1)); | ||
| 2293 | unsigned prob; | ||
| 2294 | bit = sym & 1; sym >>= 1; price = GET_PRICEa(probs[sym], bit); | ||
| 2295 | bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); | ||
| 2296 | bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); | ||
| 2297 | bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); | ||
| 2298 | bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); | ||
| 2299 | prob = probs[(size_t)slot + (1 << (kNumPosSlotBits - 1))]; | ||
| 2300 | posSlotPrices[(size_t)slot * 2 ] = price + GET_PRICEa_0(prob); | ||
| 2301 | posSlotPrices[(size_t)slot * 2 + 1] = price + GET_PRICEa_1(prob); | ||
| 2302 | } | ||
| 2303 | |||
| 2304 | { | ||
| 2305 | UInt32 delta = ((UInt32)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits); | ||
| 2306 | for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++) | ||
| 2307 | { | ||
| 2308 | posSlotPrices[(size_t)slot * 2 ] += delta; | ||
| 2309 | posSlotPrices[(size_t)slot * 2 + 1] += delta; | ||
| 2310 | delta += ((UInt32)1 << kNumBitPriceShiftBits); | ||
| 2311 | } | ||
| 2312 | } | ||
| 2313 | |||
| 2314 | { | ||
| 2315 | UInt32 *dp = p->distancesPrices[lps]; | ||
| 2316 | |||
| 2317 | dp[0] = posSlotPrices[0]; | ||
| 2318 | dp[1] = posSlotPrices[1]; | ||
| 2319 | dp[2] = posSlotPrices[2]; | ||
| 2320 | dp[3] = posSlotPrices[3]; | ||
| 2321 | |||
| 2322 | for (i = 4; i < kNumFullDistances; i += 2) | ||
| 2323 | { | ||
| 2324 | UInt32 slotPrice = posSlotPrices[GetPosSlot1(i)]; | ||
| 2325 | dp[i ] = slotPrice + tempPrices[i]; | ||
| 2326 | dp[i + 1] = slotPrice + tempPrices[i + 1]; | ||
| 2327 | } | ||
| 2328 | } | ||
| 2329 | } | ||
| 2330 | // } | ||
| 2331 | } | ||
| 2332 | |||
| 2333 | |||
| 2334 | |||
| 2335 | static void LzmaEnc_Construct(CLzmaEnc *p) | ||
| 2336 | { | ||
| 2337 | RangeEnc_Construct(&p->rc); | ||
| 2338 | MatchFinder_Construct(&MFB); | ||
| 2339 | |||
| 2340 | #ifndef _7ZIP_ST | ||
| 2341 | p->matchFinderMt.MatchFinder = &MFB; | ||
| 2342 | MatchFinderMt_Construct(&p->matchFinderMt); | ||
| 2343 | #endif | ||
| 2344 | |||
| 2345 | { | ||
| 2346 | CLzmaEncProps props; | ||
| 2347 | LzmaEncProps_Init(&props); | ||
| 2348 | LzmaEnc_SetProps(p, &props); | ||
| 2349 | } | ||
| 2350 | |||
| 2351 | #ifndef LZMA_LOG_BSR | ||
| 2352 | LzmaEnc_FastPosInit(p->g_FastPos); | ||
| 2353 | #endif | ||
| 2354 | |||
| 2355 | LzmaEnc_InitPriceTables(p->ProbPrices); | ||
| 2356 | p->litProbs = NULL; | ||
| 2357 | p->saveState.litProbs = NULL; | ||
| 2358 | } | ||
| 2359 | |||
| 2360 | CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc) | ||
| 2361 | { | ||
| 2362 | void *p; | ||
| 2363 | p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc)); | ||
| 2364 | if (p) | ||
| 2365 | LzmaEnc_Construct((CLzmaEnc *)p); | ||
| 2366 | return p; | ||
| 2367 | } | ||
| 2368 | |||
| 2369 | static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc) | ||
| 2370 | { | ||
| 2371 | ISzAlloc_Free(alloc, p->litProbs); | ||
| 2372 | ISzAlloc_Free(alloc, p->saveState.litProbs); | ||
| 2373 | p->litProbs = NULL; | ||
| 2374 | p->saveState.litProbs = NULL; | ||
| 2375 | } | ||
| 2376 | |||
| 2377 | static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 2378 | { | ||
| 2379 | #ifndef _7ZIP_ST | ||
| 2380 | MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); | ||
| 2381 | #endif | ||
| 2382 | |||
| 2383 | MatchFinder_Free(&MFB, allocBig); | ||
| 2384 | LzmaEnc_FreeLits(p, alloc); | ||
| 2385 | RangeEnc_Free(&p->rc, alloc); | ||
| 2386 | } | ||
| 2387 | |||
| 2388 | void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 2389 | { | ||
| 2390 | LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); | ||
| 2391 | ISzAlloc_Free(alloc, p); | ||
| 2392 | } | ||
| 2393 | |||
| 2394 | |||
| 2395 | MY_NO_INLINE | ||
| 2396 | static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpackSize) | ||
| 2397 | { | ||
| 2398 | UInt32 nowPos32, startPos32; | ||
| 2399 | if (p->needInit) | ||
| 2400 | { | ||
| 2401 | #ifndef _7ZIP_ST | ||
| 2402 | if (p->mtMode) | ||
| 2403 | { | ||
| 2404 | RINOK(MatchFinderMt_InitMt(&p->matchFinderMt)); | ||
| 2405 | } | ||
| 2406 | #endif | ||
| 2407 | p->matchFinder.Init(p->matchFinderObj); | ||
| 2408 | p->needInit = 0; | ||
| 2409 | } | ||
| 2410 | |||
| 2411 | if (p->finished) | ||
| 2412 | return p->result; | ||
| 2413 | RINOK(CheckErrors(p)); | ||
| 2414 | |||
| 2415 | nowPos32 = (UInt32)p->nowPos64; | ||
| 2416 | startPos32 = nowPos32; | ||
| 2417 | |||
| 2418 | if (p->nowPos64 == 0) | ||
| 2419 | { | ||
| 2420 | unsigned numPairs; | ||
| 2421 | Byte curByte; | ||
| 2422 | if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) | ||
| 2423 | return Flush(p, nowPos32); | ||
| 2424 | ReadMatchDistances(p, &numPairs); | ||
| 2425 | RangeEnc_EncodeBit_0(&p->rc, &p->isMatch[kState_Start][0]); | ||
| 2426 | // p->state = kLiteralNextStates[p->state]; | ||
| 2427 | curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset); | ||
| 2428 | LitEnc_Encode(&p->rc, p->litProbs, curByte); | ||
| 2429 | p->additionalOffset--; | ||
| 2430 | nowPos32++; | ||
| 2431 | } | ||
| 2432 | |||
| 2433 | if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) | ||
| 2434 | |||
| 2435 | for (;;) | ||
| 2436 | { | ||
| 2437 | UInt32 dist; | ||
| 2438 | unsigned len, posState; | ||
| 2439 | UInt32 range, ttt, newBound; | ||
| 2440 | CLzmaProb *probs; | ||
| 2441 | |||
| 2442 | if (p->fastMode) | ||
| 2443 | len = GetOptimumFast(p); | ||
| 2444 | else | ||
| 2445 | { | ||
| 2446 | unsigned oci = p->optCur; | ||
| 2447 | if (p->optEnd == oci) | ||
| 2448 | len = GetOptimum(p, nowPos32); | ||
| 2449 | else | ||
| 2450 | { | ||
| 2451 | const COptimal *opt = &p->opt[oci]; | ||
| 2452 | len = opt->len; | ||
| 2453 | p->backRes = opt->dist; | ||
| 2454 | p->optCur = oci + 1; | ||
| 2455 | } | ||
| 2456 | } | ||
| 2457 | |||
| 2458 | posState = (unsigned)nowPos32 & p->pbMask; | ||
| 2459 | range = p->rc.range; | ||
| 2460 | probs = &p->isMatch[p->state][posState]; | ||
| 2461 | |||
| 2462 | RC_BIT_PRE(&p->rc, probs) | ||
| 2463 | |||
| 2464 | dist = p->backRes; | ||
| 2465 | |||
| 2466 | #ifdef SHOW_STAT2 | ||
| 2467 | printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist); | ||
| 2468 | #endif | ||
| 2469 | |||
| 2470 | if (dist == MARK_LIT) | ||
| 2471 | { | ||
| 2472 | Byte curByte; | ||
| 2473 | const Byte *data; | ||
| 2474 | unsigned state; | ||
| 2475 | |||
| 2476 | RC_BIT_0(&p->rc, probs); | ||
| 2477 | p->rc.range = range; | ||
| 2478 | data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; | ||
| 2479 | probs = LIT_PROBS(nowPos32, *(data - 1)); | ||
| 2480 | curByte = *data; | ||
| 2481 | state = p->state; | ||
| 2482 | p->state = kLiteralNextStates[state]; | ||
| 2483 | if (IsLitState(state)) | ||
| 2484 | LitEnc_Encode(&p->rc, probs, curByte); | ||
| 2485 | else | ||
| 2486 | LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0])); | ||
| 2487 | } | ||
| 2488 | else | ||
| 2489 | { | ||
| 2490 | RC_BIT_1(&p->rc, probs); | ||
| 2491 | probs = &p->isRep[p->state]; | ||
| 2492 | RC_BIT_PRE(&p->rc, probs) | ||
| 2493 | |||
| 2494 | if (dist < LZMA_NUM_REPS) | ||
| 2495 | { | ||
| 2496 | RC_BIT_1(&p->rc, probs); | ||
| 2497 | probs = &p->isRepG0[p->state]; | ||
| 2498 | RC_BIT_PRE(&p->rc, probs) | ||
| 2499 | if (dist == 0) | ||
| 2500 | { | ||
| 2501 | RC_BIT_0(&p->rc, probs); | ||
| 2502 | probs = &p->isRep0Long[p->state][posState]; | ||
| 2503 | RC_BIT_PRE(&p->rc, probs) | ||
| 2504 | if (len != 1) | ||
| 2505 | { | ||
| 2506 | RC_BIT_1_BASE(&p->rc, probs); | ||
| 2507 | } | ||
| 2508 | else | ||
| 2509 | { | ||
| 2510 | RC_BIT_0_BASE(&p->rc, probs); | ||
| 2511 | p->state = kShortRepNextStates[p->state]; | ||
| 2512 | } | ||
| 2513 | } | ||
| 2514 | else | ||
| 2515 | { | ||
| 2516 | RC_BIT_1(&p->rc, probs); | ||
| 2517 | probs = &p->isRepG1[p->state]; | ||
| 2518 | RC_BIT_PRE(&p->rc, probs) | ||
| 2519 | if (dist == 1) | ||
| 2520 | { | ||
| 2521 | RC_BIT_0_BASE(&p->rc, probs); | ||
| 2522 | dist = p->reps[1]; | ||
| 2523 | } | ||
| 2524 | else | ||
| 2525 | { | ||
| 2526 | RC_BIT_1(&p->rc, probs); | ||
| 2527 | probs = &p->isRepG2[p->state]; | ||
| 2528 | RC_BIT_PRE(&p->rc, probs) | ||
| 2529 | if (dist == 2) | ||
| 2530 | { | ||
| 2531 | RC_BIT_0_BASE(&p->rc, probs); | ||
| 2532 | dist = p->reps[2]; | ||
| 2533 | } | ||
| 2534 | else | ||
| 2535 | { | ||
| 2536 | RC_BIT_1_BASE(&p->rc, probs); | ||
| 2537 | dist = p->reps[3]; | ||
| 2538 | p->reps[3] = p->reps[2]; | ||
| 2539 | } | ||
| 2540 | p->reps[2] = p->reps[1]; | ||
| 2541 | } | ||
| 2542 | p->reps[1] = p->reps[0]; | ||
| 2543 | p->reps[0] = dist; | ||
| 2544 | } | ||
| 2545 | |||
| 2546 | RC_NORM(&p->rc) | ||
| 2547 | |||
| 2548 | p->rc.range = range; | ||
| 2549 | |||
| 2550 | if (len != 1) | ||
| 2551 | { | ||
| 2552 | LenEnc_Encode(&p->repLenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState); | ||
| 2553 | --p->repLenEncCounter; | ||
| 2554 | p->state = kRepNextStates[p->state]; | ||
| 2555 | } | ||
| 2556 | } | ||
| 2557 | else | ||
| 2558 | { | ||
| 2559 | unsigned posSlot; | ||
| 2560 | RC_BIT_0(&p->rc, probs); | ||
| 2561 | p->rc.range = range; | ||
| 2562 | p->state = kMatchNextStates[p->state]; | ||
| 2563 | |||
| 2564 | LenEnc_Encode(&p->lenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState); | ||
| 2565 | // --p->lenEnc.counter; | ||
| 2566 | |||
| 2567 | dist -= LZMA_NUM_REPS; | ||
| 2568 | p->reps[3] = p->reps[2]; | ||
| 2569 | p->reps[2] = p->reps[1]; | ||
| 2570 | p->reps[1] = p->reps[0]; | ||
| 2571 | p->reps[0] = dist + 1; | ||
| 2572 | |||
| 2573 | p->matchPriceCount++; | ||
| 2574 | GetPosSlot(dist, posSlot); | ||
| 2575 | // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], posSlot); | ||
| 2576 | { | ||
| 2577 | UInt32 sym = (UInt32)posSlot + (1 << kNumPosSlotBits); | ||
| 2578 | range = p->rc.range; | ||
| 2579 | probs = p->posSlotEncoder[GetLenToPosState(len)]; | ||
| 2580 | do | ||
| 2581 | { | ||
| 2582 | CLzmaProb *prob = probs + (sym >> kNumPosSlotBits); | ||
| 2583 | UInt32 bit = (sym >> (kNumPosSlotBits - 1)) & 1; | ||
| 2584 | sym <<= 1; | ||
| 2585 | RC_BIT(&p->rc, prob, bit); | ||
| 2586 | } | ||
| 2587 | while (sym < (1 << kNumPosSlotBits * 2)); | ||
| 2588 | p->rc.range = range; | ||
| 2589 | } | ||
| 2590 | |||
| 2591 | if (dist >= kStartPosModelIndex) | ||
| 2592 | { | ||
| 2593 | unsigned footerBits = ((posSlot >> 1) - 1); | ||
| 2594 | |||
| 2595 | if (dist < kNumFullDistances) | ||
| 2596 | { | ||
| 2597 | unsigned base = ((2 | (posSlot & 1)) << footerBits); | ||
| 2598 | RcTree_ReverseEncode(&p->rc, p->posEncoders + base, footerBits, (unsigned)(dist /* - base */)); | ||
| 2599 | } | ||
| 2600 | else | ||
| 2601 | { | ||
| 2602 | UInt32 pos2 = (dist | 0xF) << (32 - footerBits); | ||
| 2603 | range = p->rc.range; | ||
| 2604 | // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); | ||
| 2605 | /* | ||
| 2606 | do | ||
| 2607 | { | ||
| 2608 | range >>= 1; | ||
| 2609 | p->rc.low += range & (0 - ((dist >> --footerBits) & 1)); | ||
| 2610 | RC_NORM(&p->rc) | ||
| 2611 | } | ||
| 2612 | while (footerBits > kNumAlignBits); | ||
| 2613 | */ | ||
| 2614 | do | ||
| 2615 | { | ||
| 2616 | range >>= 1; | ||
| 2617 | p->rc.low += range & (0 - (pos2 >> 31)); | ||
| 2618 | pos2 += pos2; | ||
| 2619 | RC_NORM(&p->rc) | ||
| 2620 | } | ||
| 2621 | while (pos2 != 0xF0000000); | ||
| 2622 | |||
| 2623 | |||
| 2624 | // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); | ||
| 2625 | |||
| 2626 | { | ||
| 2627 | unsigned m = 1; | ||
| 2628 | unsigned bit; | ||
| 2629 | bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; | ||
| 2630 | bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; | ||
| 2631 | bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; | ||
| 2632 | bit = dist & 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); | ||
| 2633 | p->rc.range = range; | ||
| 2634 | // p->alignPriceCount++; | ||
| 2635 | } | ||
| 2636 | } | ||
| 2637 | } | ||
| 2638 | } | ||
| 2639 | } | ||
| 2640 | |||
| 2641 | nowPos32 += (UInt32)len; | ||
| 2642 | p->additionalOffset -= len; | ||
| 2643 | |||
| 2644 | if (p->additionalOffset == 0) | ||
| 2645 | { | ||
| 2646 | UInt32 processed; | ||
| 2647 | |||
| 2648 | if (!p->fastMode) | ||
| 2649 | { | ||
| 2650 | /* | ||
| 2651 | if (p->alignPriceCount >= 16) // kAlignTableSize | ||
| 2652 | FillAlignPrices(p); | ||
| 2653 | if (p->matchPriceCount >= 128) | ||
| 2654 | FillDistancesPrices(p); | ||
| 2655 | if (p->lenEnc.counter <= 0) | ||
| 2656 | LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); | ||
| 2657 | */ | ||
| 2658 | if (p->matchPriceCount >= 64) | ||
| 2659 | { | ||
| 2660 | FillAlignPrices(p); | ||
| 2661 | // { int y; for (y = 0; y < 100; y++) { | ||
| 2662 | FillDistancesPrices(p); | ||
| 2663 | // }} | ||
| 2664 | LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices); | ||
| 2665 | } | ||
| 2666 | if (p->repLenEncCounter <= 0) | ||
| 2667 | { | ||
| 2668 | p->repLenEncCounter = REP_LEN_COUNT; | ||
| 2669 | LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices); | ||
| 2670 | } | ||
| 2671 | } | ||
| 2672 | |||
| 2673 | if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) | ||
| 2674 | break; | ||
| 2675 | processed = nowPos32 - startPos32; | ||
| 2676 | |||
| 2677 | if (maxPackSize) | ||
| 2678 | { | ||
| 2679 | if (processed + kNumOpts + 300 >= maxUnpackSize | ||
| 2680 | || RangeEnc_GetProcessed_sizet(&p->rc) + kPackReserve >= maxPackSize) | ||
| 2681 | break; | ||
| 2682 | } | ||
| 2683 | else if (processed >= (1 << 17)) | ||
| 2684 | { | ||
| 2685 | p->nowPos64 += nowPos32 - startPos32; | ||
| 2686 | return CheckErrors(p); | ||
| 2687 | } | ||
| 2688 | } | ||
| 2689 | } | ||
| 2690 | |||
| 2691 | p->nowPos64 += nowPos32 - startPos32; | ||
| 2692 | return Flush(p, nowPos32); | ||
| 2693 | } | ||
| 2694 | |||
| 2695 | |||
| 2696 | |||
| 2697 | #define kBigHashDicLimit ((UInt32)1 << 24) | ||
| 2698 | |||
| 2699 | static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 2700 | { | ||
| 2701 | UInt32 beforeSize = kNumOpts; | ||
| 2702 | UInt32 dictSize; | ||
| 2703 | |||
| 2704 | if (!RangeEnc_Alloc(&p->rc, alloc)) | ||
| 2705 | return SZ_ERROR_MEM; | ||
| 2706 | |||
| 2707 | #ifndef _7ZIP_ST | ||
| 2708 | p->mtMode = (p->multiThread && !p->fastMode && (MFB.btMode != 0)); | ||
| 2709 | #endif | ||
| 2710 | |||
| 2711 | { | ||
| 2712 | unsigned lclp = p->lc + p->lp; | ||
| 2713 | if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp) | ||
| 2714 | { | ||
| 2715 | LzmaEnc_FreeLits(p, alloc); | ||
| 2716 | p->litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); | ||
| 2717 | p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); | ||
| 2718 | if (!p->litProbs || !p->saveState.litProbs) | ||
| 2719 | { | ||
| 2720 | LzmaEnc_FreeLits(p, alloc); | ||
| 2721 | return SZ_ERROR_MEM; | ||
| 2722 | } | ||
| 2723 | p->lclp = lclp; | ||
| 2724 | } | ||
| 2725 | } | ||
| 2726 | |||
| 2727 | MFB.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0); | ||
| 2728 | |||
| 2729 | |||
| 2730 | dictSize = p->dictSize; | ||
| 2731 | if (dictSize == ((UInt32)2 << 30) || | ||
| 2732 | dictSize == ((UInt32)3 << 30)) | ||
| 2733 | { | ||
| 2734 | /* 21.03 : here we reduce the dictionary for 2 reasons: | ||
| 2735 | 1) we don't want 32-bit back_distance matches in decoder for 2 GB dictionary. | ||
| 2736 | 2) we want to elimate useless last MatchFinder_Normalize3() for corner cases, | ||
| 2737 | where data size is aligned for 1 GB: 5/6/8 GB. | ||
| 2738 | That reducing must be >= 1 for such corner cases. */ | ||
| 2739 | dictSize -= 1; | ||
| 2740 | } | ||
| 2741 | |||
| 2742 | if (beforeSize + dictSize < keepWindowSize) | ||
| 2743 | beforeSize = keepWindowSize - dictSize; | ||
| 2744 | |||
| 2745 | /* in worst case we can look ahead for | ||
| 2746 | max(LZMA_MATCH_LEN_MAX, numFastBytes + 1 + numFastBytes) bytes. | ||
| 2747 | we send larger value for (keepAfter) to MantchFinder_Create(): | ||
| 2748 | (numFastBytes + LZMA_MATCH_LEN_MAX + 1) | ||
| 2749 | */ | ||
| 2750 | |||
| 2751 | #ifndef _7ZIP_ST | ||
| 2752 | if (p->mtMode) | ||
| 2753 | { | ||
| 2754 | RINOK(MatchFinderMt_Create(&p->matchFinderMt, dictSize, beforeSize, | ||
| 2755 | p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 18.04 */ | ||
| 2756 | , allocBig)); | ||
| 2757 | p->matchFinderObj = &p->matchFinderMt; | ||
| 2758 | MFB.bigHash = (Byte)( | ||
| 2759 | (p->dictSize > kBigHashDicLimit && MFB.hashMask >= 0xFFFFFF) ? 1 : 0); | ||
| 2760 | MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); | ||
| 2761 | } | ||
| 2762 | else | ||
| 2763 | #endif | ||
| 2764 | { | ||
| 2765 | if (!MatchFinder_Create(&MFB, dictSize, beforeSize, | ||
| 2766 | p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 21.03 */ | ||
| 2767 | , allocBig)) | ||
| 2768 | return SZ_ERROR_MEM; | ||
| 2769 | p->matchFinderObj = &MFB; | ||
| 2770 | MatchFinder_CreateVTable(&MFB, &p->matchFinder); | ||
| 2771 | } | ||
| 2772 | |||
| 2773 | return SZ_OK; | ||
| 2774 | } | ||
| 2775 | |||
| 2776 | static void LzmaEnc_Init(CLzmaEnc *p) | ||
| 2777 | { | ||
| 2778 | unsigned i; | ||
| 2779 | p->state = 0; | ||
| 2780 | p->reps[0] = | ||
| 2781 | p->reps[1] = | ||
| 2782 | p->reps[2] = | ||
| 2783 | p->reps[3] = 1; | ||
| 2784 | |||
| 2785 | RangeEnc_Init(&p->rc); | ||
| 2786 | |||
| 2787 | for (i = 0; i < (1 << kNumAlignBits); i++) | ||
| 2788 | p->posAlignEncoder[i] = kProbInitValue; | ||
| 2789 | |||
| 2790 | for (i = 0; i < kNumStates; i++) | ||
| 2791 | { | ||
| 2792 | unsigned j; | ||
| 2793 | for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) | ||
| 2794 | { | ||
| 2795 | p->isMatch[i][j] = kProbInitValue; | ||
| 2796 | p->isRep0Long[i][j] = kProbInitValue; | ||
| 2797 | } | ||
| 2798 | p->isRep[i] = kProbInitValue; | ||
| 2799 | p->isRepG0[i] = kProbInitValue; | ||
| 2800 | p->isRepG1[i] = kProbInitValue; | ||
| 2801 | p->isRepG2[i] = kProbInitValue; | ||
| 2802 | } | ||
| 2803 | |||
| 2804 | { | ||
| 2805 | for (i = 0; i < kNumLenToPosStates; i++) | ||
| 2806 | { | ||
| 2807 | CLzmaProb *probs = p->posSlotEncoder[i]; | ||
| 2808 | unsigned j; | ||
| 2809 | for (j = 0; j < (1 << kNumPosSlotBits); j++) | ||
| 2810 | probs[j] = kProbInitValue; | ||
| 2811 | } | ||
| 2812 | } | ||
| 2813 | { | ||
| 2814 | for (i = 0; i < kNumFullDistances; i++) | ||
| 2815 | p->posEncoders[i] = kProbInitValue; | ||
| 2816 | } | ||
| 2817 | |||
| 2818 | { | ||
| 2819 | UInt32 num = (UInt32)0x300 << (p->lp + p->lc); | ||
| 2820 | UInt32 k; | ||
| 2821 | CLzmaProb *probs = p->litProbs; | ||
| 2822 | for (k = 0; k < num; k++) | ||
| 2823 | probs[k] = kProbInitValue; | ||
| 2824 | } | ||
| 2825 | |||
| 2826 | |||
| 2827 | LenEnc_Init(&p->lenProbs); | ||
| 2828 | LenEnc_Init(&p->repLenProbs); | ||
| 2829 | |||
| 2830 | p->optEnd = 0; | ||
| 2831 | p->optCur = 0; | ||
| 2832 | |||
| 2833 | { | ||
| 2834 | for (i = 0; i < kNumOpts; i++) | ||
| 2835 | p->opt[i].price = kInfinityPrice; | ||
| 2836 | } | ||
| 2837 | |||
| 2838 | p->additionalOffset = 0; | ||
| 2839 | |||
| 2840 | p->pbMask = ((unsigned)1 << p->pb) - 1; | ||
| 2841 | p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc); | ||
| 2842 | |||
| 2843 | // p->mf_Failure = False; | ||
| 2844 | } | ||
| 2845 | |||
| 2846 | |||
| 2847 | static void LzmaEnc_InitPrices(CLzmaEnc *p) | ||
| 2848 | { | ||
| 2849 | if (!p->fastMode) | ||
| 2850 | { | ||
| 2851 | FillDistancesPrices(p); | ||
| 2852 | FillAlignPrices(p); | ||
| 2853 | } | ||
| 2854 | |||
| 2855 | p->lenEnc.tableSize = | ||
| 2856 | p->repLenEnc.tableSize = | ||
| 2857 | p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; | ||
| 2858 | |||
| 2859 | p->repLenEncCounter = REP_LEN_COUNT; | ||
| 2860 | |||
| 2861 | LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices); | ||
| 2862 | LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices); | ||
| 2863 | } | ||
| 2864 | |||
| 2865 | static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 2866 | { | ||
| 2867 | unsigned i; | ||
| 2868 | for (i = kEndPosModelIndex / 2; i < kDicLogSizeMax; i++) | ||
| 2869 | if (p->dictSize <= ((UInt32)1 << i)) | ||
| 2870 | break; | ||
| 2871 | p->distTableSize = i * 2; | ||
| 2872 | |||
| 2873 | p->finished = False; | ||
| 2874 | p->result = SZ_OK; | ||
| 2875 | RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); | ||
| 2876 | LzmaEnc_Init(p); | ||
| 2877 | LzmaEnc_InitPrices(p); | ||
| 2878 | p->nowPos64 = 0; | ||
| 2879 | return SZ_OK; | ||
| 2880 | } | ||
| 2881 | |||
| 2882 | static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, | ||
| 2883 | ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 2884 | { | ||
| 2885 | CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 2886 | MFB.stream = inStream; | ||
| 2887 | p->needInit = 1; | ||
| 2888 | p->rc.outStream = outStream; | ||
| 2889 | return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); | ||
| 2890 | } | ||
| 2891 | |||
| 2892 | SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, | ||
| 2893 | ISeqInStream *inStream, UInt32 keepWindowSize, | ||
| 2894 | ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 2895 | { | ||
| 2896 | CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 2897 | MFB.stream = inStream; | ||
| 2898 | p->needInit = 1; | ||
| 2899 | return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); | ||
| 2900 | } | ||
| 2901 | |||
| 2902 | static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) | ||
| 2903 | { | ||
| 2904 | MFB.directInput = 1; | ||
| 2905 | MFB.bufferBase = (Byte *)src; | ||
| 2906 | MFB.directInputRem = srcLen; | ||
| 2907 | } | ||
| 2908 | |||
| 2909 | SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, | ||
| 2910 | UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 2911 | { | ||
| 2912 | CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 2913 | LzmaEnc_SetInputBuf(p, src, srcLen); | ||
| 2914 | p->needInit = 1; | ||
| 2915 | |||
| 2916 | LzmaEnc_SetDataSize(pp, srcLen); | ||
| 2917 | return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); | ||
| 2918 | } | ||
| 2919 | |||
| 2920 | void LzmaEnc_Finish(CLzmaEncHandle pp) | ||
| 2921 | { | ||
| 2922 | #ifndef _7ZIP_ST | ||
| 2923 | CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 2924 | if (p->mtMode) | ||
| 2925 | MatchFinderMt_ReleaseStream(&p->matchFinderMt); | ||
| 2926 | #else | ||
| 2927 | UNUSED_VAR(pp); | ||
| 2928 | #endif | ||
| 2929 | } | ||
| 2930 | |||
| 2931 | |||
| 2932 | typedef struct | ||
| 2933 | { | ||
| 2934 | ISeqOutStream vt; | ||
| 2935 | Byte *data; | ||
| 2936 | SizeT rem; | ||
| 2937 | BoolInt overflow; | ||
| 2938 | } CLzmaEnc_SeqOutStreamBuf; | ||
| 2939 | |||
| 2940 | static size_t SeqOutStreamBuf_Write(const ISeqOutStream *pp, const void *data, size_t size) | ||
| 2941 | { | ||
| 2942 | CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt); | ||
| 2943 | if (p->rem < size) | ||
| 2944 | { | ||
| 2945 | size = p->rem; | ||
| 2946 | p->overflow = True; | ||
| 2947 | } | ||
| 2948 | if (size != 0) | ||
| 2949 | { | ||
| 2950 | memcpy(p->data, data, size); | ||
| 2951 | p->rem -= size; | ||
| 2952 | p->data += size; | ||
| 2953 | } | ||
| 2954 | return size; | ||
| 2955 | } | ||
| 2956 | |||
| 2957 | |||
| 2958 | /* | ||
| 2959 | UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) | ||
| 2960 | { | ||
| 2961 | const CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 2962 | return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); | ||
| 2963 | } | ||
| 2964 | */ | ||
| 2965 | |||
| 2966 | const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) | ||
| 2967 | { | ||
| 2968 | const CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 2969 | return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; | ||
| 2970 | } | ||
| 2971 | |||
| 2972 | |||
| 2973 | SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, | ||
| 2974 | Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) | ||
| 2975 | { | ||
| 2976 | CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 2977 | UInt64 nowPos64; | ||
| 2978 | SRes res; | ||
| 2979 | CLzmaEnc_SeqOutStreamBuf outStream; | ||
| 2980 | |||
| 2981 | outStream.vt.Write = SeqOutStreamBuf_Write; | ||
| 2982 | outStream.data = dest; | ||
| 2983 | outStream.rem = *destLen; | ||
| 2984 | outStream.overflow = False; | ||
| 2985 | |||
| 2986 | p->writeEndMark = False; | ||
| 2987 | p->finished = False; | ||
| 2988 | p->result = SZ_OK; | ||
| 2989 | |||
| 2990 | if (reInit) | ||
| 2991 | LzmaEnc_Init(p); | ||
| 2992 | LzmaEnc_InitPrices(p); | ||
| 2993 | |||
| 2994 | nowPos64 = p->nowPos64; | ||
| 2995 | RangeEnc_Init(&p->rc); | ||
| 2996 | p->rc.outStream = &outStream.vt; | ||
| 2997 | |||
| 2998 | if (desiredPackSize == 0) | ||
| 2999 | return SZ_ERROR_OUTPUT_EOF; | ||
| 3000 | |||
| 3001 | res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize); | ||
| 3002 | |||
| 3003 | *unpackSize = (UInt32)(p->nowPos64 - nowPos64); | ||
| 3004 | *destLen -= outStream.rem; | ||
| 3005 | if (outStream.overflow) | ||
| 3006 | return SZ_ERROR_OUTPUT_EOF; | ||
| 3007 | |||
| 3008 | return res; | ||
| 3009 | } | ||
| 3010 | |||
| 3011 | |||
| 3012 | MY_NO_INLINE | ||
| 3013 | static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) | ||
| 3014 | { | ||
| 3015 | SRes res = SZ_OK; | ||
| 3016 | |||
| 3017 | #ifndef _7ZIP_ST | ||
| 3018 | Byte allocaDummy[0x300]; | ||
| 3019 | allocaDummy[0] = 0; | ||
| 3020 | allocaDummy[1] = allocaDummy[0]; | ||
| 3021 | #endif | ||
| 3022 | |||
| 3023 | for (;;) | ||
| 3024 | { | ||
| 3025 | res = LzmaEnc_CodeOneBlock(p, 0, 0); | ||
| 3026 | if (res != SZ_OK || p->finished) | ||
| 3027 | break; | ||
| 3028 | if (progress) | ||
| 3029 | { | ||
| 3030 | res = ICompressProgress_Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); | ||
| 3031 | if (res != SZ_OK) | ||
| 3032 | { | ||
| 3033 | res = SZ_ERROR_PROGRESS; | ||
| 3034 | break; | ||
| 3035 | } | ||
| 3036 | } | ||
| 3037 | } | ||
| 3038 | |||
| 3039 | LzmaEnc_Finish(p); | ||
| 3040 | |||
| 3041 | /* | ||
| 3042 | if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&MFB)) | ||
| 3043 | res = SZ_ERROR_FAIL; | ||
| 3044 | } | ||
| 3045 | */ | ||
| 3046 | |||
| 3047 | return res; | ||
| 3048 | } | ||
| 3049 | |||
| 3050 | |||
| 3051 | SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, | ||
| 3052 | ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 3053 | { | ||
| 3054 | RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); | ||
| 3055 | return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); | ||
| 3056 | } | ||
| 3057 | |||
| 3058 | |||
| 3059 | SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) | ||
| 3060 | { | ||
| 3061 | if (*size < LZMA_PROPS_SIZE) | ||
| 3062 | return SZ_ERROR_PARAM; | ||
| 3063 | *size = LZMA_PROPS_SIZE; | ||
| 3064 | { | ||
| 3065 | const CLzmaEnc *p = (const CLzmaEnc *)pp; | ||
| 3066 | const UInt32 dictSize = p->dictSize; | ||
| 3067 | UInt32 v; | ||
| 3068 | props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); | ||
| 3069 | |||
| 3070 | // we write aligned dictionary value to properties for lzma decoder | ||
| 3071 | if (dictSize >= ((UInt32)1 << 21)) | ||
| 3072 | { | ||
| 3073 | const UInt32 kDictMask = ((UInt32)1 << 20) - 1; | ||
| 3074 | v = (dictSize + kDictMask) & ~kDictMask; | ||
| 3075 | if (v < dictSize) | ||
| 3076 | v = dictSize; | ||
| 3077 | } | ||
| 3078 | else | ||
| 3079 | { | ||
| 3080 | unsigned i = 11 * 2; | ||
| 3081 | do | ||
| 3082 | { | ||
| 3083 | v = (UInt32)(2 + (i & 1)) << (i >> 1); | ||
| 3084 | i++; | ||
| 3085 | } | ||
| 3086 | while (v < dictSize); | ||
| 3087 | } | ||
| 3088 | |||
| 3089 | SetUi32(props + 1, v); | ||
| 3090 | return SZ_OK; | ||
| 3091 | } | ||
| 3092 | } | ||
| 3093 | |||
| 3094 | |||
| 3095 | unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle pp) | ||
| 3096 | { | ||
| 3097 | return (unsigned)((CLzmaEnc *)pp)->writeEndMark; | ||
| 3098 | } | ||
| 3099 | |||
| 3100 | |||
| 3101 | SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, | ||
| 3102 | int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 3103 | { | ||
| 3104 | SRes res; | ||
| 3105 | CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 3106 | |||
| 3107 | CLzmaEnc_SeqOutStreamBuf outStream; | ||
| 3108 | |||
| 3109 | outStream.vt.Write = SeqOutStreamBuf_Write; | ||
| 3110 | outStream.data = dest; | ||
| 3111 | outStream.rem = *destLen; | ||
| 3112 | outStream.overflow = False; | ||
| 3113 | |||
| 3114 | p->writeEndMark = writeEndMark; | ||
| 3115 | p->rc.outStream = &outStream.vt; | ||
| 3116 | |||
| 3117 | res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); | ||
| 3118 | |||
| 3119 | if (res == SZ_OK) | ||
| 3120 | { | ||
| 3121 | res = LzmaEnc_Encode2(p, progress); | ||
| 3122 | if (res == SZ_OK && p->nowPos64 != srcLen) | ||
| 3123 | res = SZ_ERROR_FAIL; | ||
| 3124 | } | ||
| 3125 | |||
| 3126 | *destLen -= outStream.rem; | ||
| 3127 | if (outStream.overflow) | ||
| 3128 | return SZ_ERROR_OUTPUT_EOF; | ||
| 3129 | return res; | ||
| 3130 | } | ||
| 3131 | |||
| 3132 | |||
| 3133 | SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, | ||
| 3134 | const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, | ||
| 3135 | ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 3136 | { | ||
| 3137 | CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); | ||
| 3138 | SRes res; | ||
| 3139 | if (!p) | ||
| 3140 | return SZ_ERROR_MEM; | ||
| 3141 | |||
| 3142 | res = LzmaEnc_SetProps(p, props); | ||
| 3143 | if (res == SZ_OK) | ||
| 3144 | { | ||
| 3145 | res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); | ||
| 3146 | if (res == SZ_OK) | ||
| 3147 | res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, | ||
| 3148 | writeEndMark, progress, alloc, allocBig); | ||
| 3149 | } | ||
| 3150 | |||
| 3151 | LzmaEnc_Destroy(p, alloc, allocBig); | ||
| 3152 | return res; | ||
| 3153 | } | ||
| 3154 | |||
| 3155 | |||
| 3156 | /* | ||
| 3157 | #ifndef _7ZIP_ST | ||
| 3158 | void LzmaEnc_GetLzThreads(CLzmaEncHandle pp, HANDLE lz_threads[2]) | ||
| 3159 | { | ||
| 3160 | const CLzmaEnc *p = (CLzmaEnc *)pp; | ||
| 3161 | lz_threads[0] = p->matchFinderMt.hashSync.thread; | ||
| 3162 | lz_threads[1] = p->matchFinderMt.btSync.thread; | ||
| 3163 | } | ||
| 3164 | #endif | ||
| 3165 | */ | ||
diff --git a/C/LzmaEnc.h b/C/LzmaEnc.h new file mode 100644 index 0000000..bc2ed50 --- /dev/null +++ b/C/LzmaEnc.h | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | /* LzmaEnc.h -- LZMA Encoder | ||
| 2 | 2019-10-30 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __LZMA_ENC_H | ||
| 5 | #define __LZMA_ENC_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define LZMA_PROPS_SIZE 5 | ||
| 12 | |||
| 13 | typedef struct _CLzmaEncProps | ||
| 14 | { | ||
| 15 | int level; /* 0 <= level <= 9 */ | ||
| 16 | UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version | ||
| 17 | (1 << 12) <= dictSize <= (3 << 29) for 64-bit version | ||
| 18 | default = (1 << 24) */ | ||
| 19 | int lc; /* 0 <= lc <= 8, default = 3 */ | ||
| 20 | int lp; /* 0 <= lp <= 4, default = 0 */ | ||
| 21 | int pb; /* 0 <= pb <= 4, default = 2 */ | ||
| 22 | int algo; /* 0 - fast, 1 - normal, default = 1 */ | ||
| 23 | int fb; /* 5 <= fb <= 273, default = 32 */ | ||
| 24 | int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ | ||
| 25 | int numHashBytes; /* 2, 3 or 4, default = 4 */ | ||
| 26 | UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ | ||
| 27 | unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ | ||
| 28 | int numThreads; /* 1 or 2, default = 2 */ | ||
| 29 | |||
| 30 | UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1. | ||
| 31 | Encoder uses this value to reduce dictionary size */ | ||
| 32 | |||
| 33 | UInt64 affinity; | ||
| 34 | } CLzmaEncProps; | ||
| 35 | |||
| 36 | void LzmaEncProps_Init(CLzmaEncProps *p); | ||
| 37 | void LzmaEncProps_Normalize(CLzmaEncProps *p); | ||
| 38 | UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); | ||
| 39 | |||
| 40 | |||
| 41 | /* ---------- CLzmaEncHandle Interface ---------- */ | ||
| 42 | |||
| 43 | /* LzmaEnc* functions can return the following exit codes: | ||
| 44 | SRes: | ||
| 45 | SZ_OK - OK | ||
| 46 | SZ_ERROR_MEM - Memory allocation error | ||
| 47 | SZ_ERROR_PARAM - Incorrect paramater in props | ||
| 48 | SZ_ERROR_WRITE - ISeqOutStream write callback error | ||
| 49 | SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output | ||
| 50 | SZ_ERROR_PROGRESS - some break from progress callback | ||
| 51 | SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) | ||
| 52 | */ | ||
| 53 | |||
| 54 | typedef void * CLzmaEncHandle; | ||
| 55 | |||
| 56 | CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc); | ||
| 57 | void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
| 58 | |||
| 59 | SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); | ||
| 60 | void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize); | ||
| 61 | SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); | ||
| 62 | unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p); | ||
| 63 | |||
| 64 | SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, | ||
| 65 | ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
| 66 | SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, | ||
| 67 | int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
| 68 | |||
| 69 | |||
| 70 | /* ---------- One Call Interface ---------- */ | ||
| 71 | |||
| 72 | SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, | ||
| 73 | const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, | ||
| 74 | ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
| 75 | |||
| 76 | EXTERN_C_END | ||
| 77 | |||
| 78 | #endif | ||
diff --git a/C/LzmaLib.c b/C/LzmaLib.c new file mode 100644 index 0000000..706e9e5 --- /dev/null +++ b/C/LzmaLib.c | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | /* LzmaLib.c -- LZMA library wrapper | ||
| 2 | 2015-06-13 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Alloc.h" | ||
| 5 | #include "LzmaDec.h" | ||
| 6 | #include "LzmaEnc.h" | ||
| 7 | #include "LzmaLib.h" | ||
| 8 | |||
| 9 | MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, | ||
| 10 | unsigned char *outProps, size_t *outPropsSize, | ||
| 11 | int level, /* 0 <= level <= 9, default = 5 */ | ||
| 12 | unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */ | ||
| 13 | int lc, /* 0 <= lc <= 8, default = 3 */ | ||
| 14 | int lp, /* 0 <= lp <= 4, default = 0 */ | ||
| 15 | int pb, /* 0 <= pb <= 4, default = 2 */ | ||
| 16 | int fb, /* 5 <= fb <= 273, default = 32 */ | ||
| 17 | int numThreads /* 1 or 2, default = 2 */ | ||
| 18 | ) | ||
| 19 | { | ||
| 20 | CLzmaEncProps props; | ||
| 21 | LzmaEncProps_Init(&props); | ||
| 22 | props.level = level; | ||
| 23 | props.dictSize = dictSize; | ||
| 24 | props.lc = lc; | ||
| 25 | props.lp = lp; | ||
| 26 | props.pb = pb; | ||
| 27 | props.fb = fb; | ||
| 28 | props.numThreads = numThreads; | ||
| 29 | |||
| 30 | return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0, | ||
| 31 | NULL, &g_Alloc, &g_Alloc); | ||
| 32 | } | ||
| 33 | |||
| 34 | |||
| 35 | MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, | ||
| 36 | const unsigned char *props, size_t propsSize) | ||
| 37 | { | ||
| 38 | ELzmaStatus status; | ||
| 39 | return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc); | ||
| 40 | } | ||
diff --git a/C/LzmaLib.h b/C/LzmaLib.h new file mode 100644 index 0000000..c343a85 --- /dev/null +++ b/C/LzmaLib.h | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | /* LzmaLib.h -- LZMA library interface | ||
| 2 | 2021-04-03 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __LZMA_LIB_H | ||
| 5 | #define __LZMA_LIB_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define MY_STDAPI int MY_STD_CALL | ||
| 12 | |||
| 13 | #define LZMA_PROPS_SIZE 5 | ||
| 14 | |||
| 15 | /* | ||
| 16 | RAM requirements for LZMA: | ||
| 17 | for compression: (dictSize * 11.5 + 6 MB) + state_size | ||
| 18 | for decompression: dictSize + state_size | ||
| 19 | state_size = (4 + (1.5 << (lc + lp))) KB | ||
| 20 | by default (lc=3, lp=0), state_size = 16 KB. | ||
| 21 | |||
| 22 | LZMA properties (5 bytes) format | ||
| 23 | Offset Size Description | ||
| 24 | 0 1 lc, lp and pb in encoded form. | ||
| 25 | 1 4 dictSize (little endian). | ||
| 26 | */ | ||
| 27 | |||
| 28 | /* | ||
| 29 | LzmaCompress | ||
| 30 | ------------ | ||
| 31 | |||
| 32 | outPropsSize - | ||
| 33 | In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. | ||
| 34 | Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. | ||
| 35 | |||
| 36 | LZMA Encoder will use defult values for any parameter, if it is | ||
| 37 | -1 for any from: level, loc, lp, pb, fb, numThreads | ||
| 38 | 0 for dictSize | ||
| 39 | |||
| 40 | level - compression level: 0 <= level <= 9; | ||
| 41 | |||
| 42 | level dictSize algo fb | ||
| 43 | 0: 64 KB 0 32 | ||
| 44 | 1: 256 KB 0 32 | ||
| 45 | 2: 1 MB 0 32 | ||
| 46 | 3: 4 MB 0 32 | ||
| 47 | 4: 16 MB 0 32 | ||
| 48 | 5: 16 MB 1 32 | ||
| 49 | 6: 32 MB 1 32 | ||
| 50 | 7: 32 MB 1 64 | ||
| 51 | 8: 64 MB 1 64 | ||
| 52 | 9: 64 MB 1 64 | ||
| 53 | |||
| 54 | The default value for "level" is 5. | ||
| 55 | |||
| 56 | algo = 0 means fast method | ||
| 57 | algo = 1 means normal method | ||
| 58 | |||
| 59 | dictSize - The dictionary size in bytes. The maximum value is | ||
| 60 | 128 MB = (1 << 27) bytes for 32-bit version | ||
| 61 | 1 GB = (1 << 30) bytes for 64-bit version | ||
| 62 | The default value is 16 MB = (1 << 24) bytes. | ||
| 63 | It's recommended to use the dictionary that is larger than 4 KB and | ||
| 64 | that can be calculated as (1 << N) or (3 << N) sizes. | ||
| 65 | |||
| 66 | lc - The number of literal context bits (high bits of previous literal). | ||
| 67 | It can be in the range from 0 to 8. The default value is 3. | ||
| 68 | Sometimes lc=4 gives the gain for big files. | ||
| 69 | |||
| 70 | lp - The number of literal pos bits (low bits of current position for literals). | ||
| 71 | It can be in the range from 0 to 4. The default value is 0. | ||
| 72 | The lp switch is intended for periodical data when the period is equal to 2^lp. | ||
| 73 | For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's | ||
| 74 | better to set lc=0, if you change lp switch. | ||
| 75 | |||
| 76 | pb - The number of pos bits (low bits of current position). | ||
| 77 | It can be in the range from 0 to 4. The default value is 2. | ||
| 78 | The pb switch is intended for periodical data when the period is equal 2^pb. | ||
| 79 | |||
| 80 | fb - Word size (the number of fast bytes). | ||
| 81 | It can be in the range from 5 to 273. The default value is 32. | ||
| 82 | Usually, a big number gives a little bit better compression ratio and | ||
| 83 | slower compression process. | ||
| 84 | |||
| 85 | numThreads - The number of thereads. 1 or 2. The default value is 2. | ||
| 86 | Fast mode (algo = 0) can use only 1 thread. | ||
| 87 | |||
| 88 | In: | ||
| 89 | dest - output data buffer | ||
| 90 | destLen - output data buffer size | ||
| 91 | src - input data | ||
| 92 | srcLen - input data size | ||
| 93 | Out: | ||
| 94 | destLen - processed output size | ||
| 95 | Returns: | ||
| 96 | SZ_OK - OK | ||
| 97 | SZ_ERROR_MEM - Memory allocation error | ||
| 98 | SZ_ERROR_PARAM - Incorrect paramater | ||
| 99 | SZ_ERROR_OUTPUT_EOF - output buffer overflow | ||
| 100 | SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) | ||
| 101 | */ | ||
| 102 | |||
| 103 | MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, | ||
| 104 | unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */ | ||
| 105 | int level, /* 0 <= level <= 9, default = 5 */ | ||
| 106 | unsigned dictSize, /* default = (1 << 24) */ | ||
| 107 | int lc, /* 0 <= lc <= 8, default = 3 */ | ||
| 108 | int lp, /* 0 <= lp <= 4, default = 0 */ | ||
| 109 | int pb, /* 0 <= pb <= 4, default = 2 */ | ||
| 110 | int fb, /* 5 <= fb <= 273, default = 32 */ | ||
| 111 | int numThreads /* 1 or 2, default = 2 */ | ||
| 112 | ); | ||
| 113 | |||
| 114 | /* | ||
| 115 | LzmaUncompress | ||
| 116 | -------------- | ||
| 117 | In: | ||
| 118 | dest - output data buffer | ||
| 119 | destLen - output data buffer size | ||
| 120 | src - input data | ||
| 121 | srcLen - input data size | ||
| 122 | Out: | ||
| 123 | destLen - processed output size | ||
| 124 | srcLen - processed input size | ||
| 125 | Returns: | ||
| 126 | SZ_OK - OK | ||
| 127 | SZ_ERROR_DATA - Data error | ||
| 128 | SZ_ERROR_MEM - Memory allocation arror | ||
| 129 | SZ_ERROR_UNSUPPORTED - Unsupported properties | ||
| 130 | SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src) | ||
| 131 | */ | ||
| 132 | |||
| 133 | MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen, | ||
| 134 | const unsigned char *props, size_t propsSize); | ||
| 135 | |||
| 136 | EXTERN_C_END | ||
| 137 | |||
| 138 | #endif | ||
diff --git a/C/MtCoder.c b/C/MtCoder.c new file mode 100644 index 0000000..99dc909 --- /dev/null +++ b/C/MtCoder.c | |||
| @@ -0,0 +1,595 @@ | |||
| 1 | /* MtCoder.c -- Multi-thread Coder | ||
| 2 | 2021-12-21 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "MtCoder.h" | ||
| 7 | |||
| 8 | #ifndef _7ZIP_ST | ||
| 9 | |||
| 10 | static SRes MtProgressThunk_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize) | ||
| 11 | { | ||
| 12 | CMtProgressThunk *thunk = CONTAINER_FROM_VTBL(pp, CMtProgressThunk, vt); | ||
| 13 | UInt64 inSize2 = 0; | ||
| 14 | UInt64 outSize2 = 0; | ||
| 15 | if (inSize != (UInt64)(Int64)-1) | ||
| 16 | { | ||
| 17 | inSize2 = inSize - thunk->inSize; | ||
| 18 | thunk->inSize = inSize; | ||
| 19 | } | ||
| 20 | if (outSize != (UInt64)(Int64)-1) | ||
| 21 | { | ||
| 22 | outSize2 = outSize - thunk->outSize; | ||
| 23 | thunk->outSize = outSize; | ||
| 24 | } | ||
| 25 | return MtProgress_ProgressAdd(thunk->mtProgress, inSize2, outSize2); | ||
| 26 | } | ||
| 27 | |||
| 28 | |||
| 29 | void MtProgressThunk_CreateVTable(CMtProgressThunk *p) | ||
| 30 | { | ||
| 31 | p->vt.Progress = MtProgressThunk_Progress; | ||
| 32 | } | ||
| 33 | |||
| 34 | |||
| 35 | |||
| 36 | #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } | ||
| 37 | |||
| 38 | |||
| 39 | static WRes ArEvent_OptCreate_And_Reset(CEvent *p) | ||
| 40 | { | ||
| 41 | if (Event_IsCreated(p)) | ||
| 42 | return Event_Reset(p); | ||
| 43 | return AutoResetEvent_CreateNotSignaled(p); | ||
| 44 | } | ||
| 45 | |||
| 46 | |||
| 47 | static THREAD_FUNC_DECL ThreadFunc(void *pp); | ||
| 48 | |||
| 49 | |||
| 50 | static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t) | ||
| 51 | { | ||
| 52 | WRes wres = ArEvent_OptCreate_And_Reset(&t->startEvent); | ||
| 53 | if (wres == 0) | ||
| 54 | { | ||
| 55 | t->stop = False; | ||
| 56 | if (!Thread_WasCreated(&t->thread)) | ||
| 57 | wres = Thread_Create(&t->thread, ThreadFunc, t); | ||
| 58 | if (wres == 0) | ||
| 59 | wres = Event_Set(&t->startEvent); | ||
| 60 | } | ||
| 61 | if (wres == 0) | ||
| 62 | return SZ_OK; | ||
| 63 | return MY_SRes_HRESULT_FROM_WRes(wres); | ||
| 64 | } | ||
| 65 | |||
| 66 | |||
| 67 | static void MtCoderThread_Destruct(CMtCoderThread *t) | ||
| 68 | { | ||
| 69 | if (Thread_WasCreated(&t->thread)) | ||
| 70 | { | ||
| 71 | t->stop = 1; | ||
| 72 | Event_Set(&t->startEvent); | ||
| 73 | Thread_Wait_Close(&t->thread); | ||
| 74 | } | ||
| 75 | |||
| 76 | Event_Close(&t->startEvent); | ||
| 77 | |||
| 78 | if (t->inBuf) | ||
| 79 | { | ||
| 80 | ISzAlloc_Free(t->mtCoder->allocBig, t->inBuf); | ||
| 81 | t->inBuf = NULL; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | |||
| 86 | |||
| 87 | static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize) | ||
| 88 | { | ||
| 89 | size_t size = *processedSize; | ||
| 90 | *processedSize = 0; | ||
| 91 | while (size != 0) | ||
| 92 | { | ||
| 93 | size_t cur = size; | ||
| 94 | SRes res = ISeqInStream_Read(stream, data, &cur); | ||
| 95 | *processedSize += cur; | ||
| 96 | data += cur; | ||
| 97 | size -= cur; | ||
| 98 | RINOK(res); | ||
| 99 | if (cur == 0) | ||
| 100 | return SZ_OK; | ||
| 101 | } | ||
| 102 | return SZ_OK; | ||
| 103 | } | ||
| 104 | |||
| 105 | |||
| 106 | /* | ||
| 107 | ThreadFunc2() returns: | ||
| 108 | SZ_OK - in all normal cases (even for stream error or memory allocation error) | ||
| 109 | SZ_ERROR_THREAD - in case of failure in system synch function | ||
| 110 | */ | ||
| 111 | |||
| 112 | static SRes ThreadFunc2(CMtCoderThread *t) | ||
| 113 | { | ||
| 114 | CMtCoder *mtc = t->mtCoder; | ||
| 115 | |||
| 116 | for (;;) | ||
| 117 | { | ||
| 118 | unsigned bi; | ||
| 119 | SRes res; | ||
| 120 | SRes res2; | ||
| 121 | BoolInt finished; | ||
| 122 | unsigned bufIndex; | ||
| 123 | size_t size; | ||
| 124 | const Byte *inData; | ||
| 125 | UInt64 readProcessed = 0; | ||
| 126 | |||
| 127 | RINOK_THREAD(Event_Wait(&mtc->readEvent)) | ||
| 128 | |||
| 129 | /* after Event_Wait(&mtc->readEvent) we must call Event_Set(&mtc->readEvent) in any case to unlock another threads */ | ||
| 130 | |||
| 131 | if (mtc->stopReading) | ||
| 132 | { | ||
| 133 | return Event_Set(&mtc->readEvent) == 0 ? SZ_OK : SZ_ERROR_THREAD; | ||
| 134 | } | ||
| 135 | |||
| 136 | res = MtProgress_GetError(&mtc->mtProgress); | ||
| 137 | |||
| 138 | size = 0; | ||
| 139 | inData = NULL; | ||
| 140 | finished = True; | ||
| 141 | |||
| 142 | if (res == SZ_OK) | ||
| 143 | { | ||
| 144 | size = mtc->blockSize; | ||
| 145 | if (mtc->inStream) | ||
| 146 | { | ||
| 147 | if (!t->inBuf) | ||
| 148 | { | ||
| 149 | t->inBuf = (Byte *)ISzAlloc_Alloc(mtc->allocBig, mtc->blockSize); | ||
| 150 | if (!t->inBuf) | ||
| 151 | res = SZ_ERROR_MEM; | ||
| 152 | } | ||
| 153 | if (res == SZ_OK) | ||
| 154 | { | ||
| 155 | res = FullRead(mtc->inStream, t->inBuf, &size); | ||
| 156 | readProcessed = mtc->readProcessed + size; | ||
| 157 | mtc->readProcessed = readProcessed; | ||
| 158 | } | ||
| 159 | if (res != SZ_OK) | ||
| 160 | { | ||
| 161 | mtc->readRes = res; | ||
| 162 | /* after reading error - we can stop encoding of previous blocks */ | ||
| 163 | MtProgress_SetError(&mtc->mtProgress, res); | ||
| 164 | } | ||
| 165 | else | ||
| 166 | finished = (size != mtc->blockSize); | ||
| 167 | } | ||
| 168 | else | ||
| 169 | { | ||
| 170 | size_t rem; | ||
| 171 | readProcessed = mtc->readProcessed; | ||
| 172 | rem = mtc->inDataSize - (size_t)readProcessed; | ||
| 173 | if (size > rem) | ||
| 174 | size = rem; | ||
| 175 | inData = mtc->inData + (size_t)readProcessed; | ||
| 176 | readProcessed += size; | ||
| 177 | mtc->readProcessed = readProcessed; | ||
| 178 | finished = (mtc->inDataSize == (size_t)readProcessed); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | /* we must get some block from blocksSemaphore before Event_Set(&mtc->readEvent) */ | ||
| 183 | |||
| 184 | res2 = SZ_OK; | ||
| 185 | |||
| 186 | if (Semaphore_Wait(&mtc->blocksSemaphore) != 0) | ||
| 187 | { | ||
| 188 | res2 = SZ_ERROR_THREAD; | ||
| 189 | if (res == SZ_OK) | ||
| 190 | { | ||
| 191 | res = res2; | ||
| 192 | // MtProgress_SetError(&mtc->mtProgress, res); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | bi = mtc->blockIndex; | ||
| 197 | |||
| 198 | if (++mtc->blockIndex >= mtc->numBlocksMax) | ||
| 199 | mtc->blockIndex = 0; | ||
| 200 | |||
| 201 | bufIndex = (unsigned)(int)-1; | ||
| 202 | |||
| 203 | if (res == SZ_OK) | ||
| 204 | res = MtProgress_GetError(&mtc->mtProgress); | ||
| 205 | |||
| 206 | if (res != SZ_OK) | ||
| 207 | finished = True; | ||
| 208 | |||
| 209 | if (!finished) | ||
| 210 | { | ||
| 211 | if (mtc->numStartedThreads < mtc->numStartedThreadsLimit | ||
| 212 | && mtc->expectedDataSize != readProcessed) | ||
| 213 | { | ||
| 214 | res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]); | ||
| 215 | if (res == SZ_OK) | ||
| 216 | mtc->numStartedThreads++; | ||
| 217 | else | ||
| 218 | { | ||
| 219 | MtProgress_SetError(&mtc->mtProgress, res); | ||
| 220 | finished = True; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | if (finished) | ||
| 226 | mtc->stopReading = True; | ||
| 227 | |||
| 228 | RINOK_THREAD(Event_Set(&mtc->readEvent)) | ||
| 229 | |||
| 230 | if (res2 != SZ_OK) | ||
| 231 | return res2; | ||
| 232 | |||
| 233 | if (res == SZ_OK) | ||
| 234 | { | ||
| 235 | CriticalSection_Enter(&mtc->cs); | ||
| 236 | bufIndex = mtc->freeBlockHead; | ||
| 237 | mtc->freeBlockHead = mtc->freeBlockList[bufIndex]; | ||
| 238 | CriticalSection_Leave(&mtc->cs); | ||
| 239 | |||
| 240 | res = mtc->mtCallback->Code(mtc->mtCallbackObject, t->index, bufIndex, | ||
| 241 | mtc->inStream ? t->inBuf : inData, size, finished); | ||
| 242 | |||
| 243 | // MtProgress_Reinit(&mtc->mtProgress, t->index); | ||
| 244 | |||
| 245 | if (res != SZ_OK) | ||
| 246 | MtProgress_SetError(&mtc->mtProgress, res); | ||
| 247 | } | ||
| 248 | |||
| 249 | { | ||
| 250 | CMtCoderBlock *block = &mtc->blocks[bi]; | ||
| 251 | block->res = res; | ||
| 252 | block->bufIndex = bufIndex; | ||
| 253 | block->finished = finished; | ||
| 254 | } | ||
| 255 | |||
| 256 | #ifdef MTCODER__USE_WRITE_THREAD | ||
| 257 | RINOK_THREAD(Event_Set(&mtc->writeEvents[bi])) | ||
| 258 | #else | ||
| 259 | { | ||
| 260 | unsigned wi; | ||
| 261 | { | ||
| 262 | CriticalSection_Enter(&mtc->cs); | ||
| 263 | wi = mtc->writeIndex; | ||
| 264 | if (wi == bi) | ||
| 265 | mtc->writeIndex = (unsigned)(int)-1; | ||
| 266 | else | ||
| 267 | mtc->ReadyBlocks[bi] = True; | ||
| 268 | CriticalSection_Leave(&mtc->cs); | ||
| 269 | } | ||
| 270 | |||
| 271 | if (wi != bi) | ||
| 272 | { | ||
| 273 | if (res != SZ_OK || finished) | ||
| 274 | return 0; | ||
| 275 | continue; | ||
| 276 | } | ||
| 277 | |||
| 278 | if (mtc->writeRes != SZ_OK) | ||
| 279 | res = mtc->writeRes; | ||
| 280 | |||
| 281 | for (;;) | ||
| 282 | { | ||
| 283 | if (res == SZ_OK && bufIndex != (unsigned)(int)-1) | ||
| 284 | { | ||
| 285 | res = mtc->mtCallback->Write(mtc->mtCallbackObject, bufIndex); | ||
| 286 | if (res != SZ_OK) | ||
| 287 | { | ||
| 288 | mtc->writeRes = res; | ||
| 289 | MtProgress_SetError(&mtc->mtProgress, res); | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | if (++wi >= mtc->numBlocksMax) | ||
| 294 | wi = 0; | ||
| 295 | { | ||
| 296 | BoolInt isReady; | ||
| 297 | |||
| 298 | CriticalSection_Enter(&mtc->cs); | ||
| 299 | |||
| 300 | if (bufIndex != (unsigned)(int)-1) | ||
| 301 | { | ||
| 302 | mtc->freeBlockList[bufIndex] = mtc->freeBlockHead; | ||
| 303 | mtc->freeBlockHead = bufIndex; | ||
| 304 | } | ||
| 305 | |||
| 306 | isReady = mtc->ReadyBlocks[wi]; | ||
| 307 | |||
| 308 | if (isReady) | ||
| 309 | mtc->ReadyBlocks[wi] = False; | ||
| 310 | else | ||
| 311 | mtc->writeIndex = wi; | ||
| 312 | |||
| 313 | CriticalSection_Leave(&mtc->cs); | ||
| 314 | |||
| 315 | RINOK_THREAD(Semaphore_Release1(&mtc->blocksSemaphore)) | ||
| 316 | |||
| 317 | if (!isReady) | ||
| 318 | break; | ||
| 319 | } | ||
| 320 | |||
| 321 | { | ||
| 322 | CMtCoderBlock *block = &mtc->blocks[wi]; | ||
| 323 | if (res == SZ_OK && block->res != SZ_OK) | ||
| 324 | res = block->res; | ||
| 325 | bufIndex = block->bufIndex; | ||
| 326 | finished = block->finished; | ||
| 327 | } | ||
| 328 | } | ||
| 329 | } | ||
| 330 | #endif | ||
| 331 | |||
| 332 | if (finished || res != SZ_OK) | ||
| 333 | return 0; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | |||
| 338 | static THREAD_FUNC_DECL ThreadFunc(void *pp) | ||
| 339 | { | ||
| 340 | CMtCoderThread *t = (CMtCoderThread *)pp; | ||
| 341 | for (;;) | ||
| 342 | { | ||
| 343 | if (Event_Wait(&t->startEvent) != 0) | ||
| 344 | return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD; | ||
| 345 | if (t->stop) | ||
| 346 | return 0; | ||
| 347 | { | ||
| 348 | SRes res = ThreadFunc2(t); | ||
| 349 | CMtCoder *mtc = t->mtCoder; | ||
| 350 | if (res != SZ_OK) | ||
| 351 | { | ||
| 352 | MtProgress_SetError(&mtc->mtProgress, res); | ||
| 353 | } | ||
| 354 | |||
| 355 | #ifndef MTCODER__USE_WRITE_THREAD | ||
| 356 | { | ||
| 357 | unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads); | ||
| 358 | if (numFinished == mtc->numStartedThreads) | ||
| 359 | if (Event_Set(&mtc->finishedEvent) != 0) | ||
| 360 | return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD; | ||
| 361 | } | ||
| 362 | #endif | ||
| 363 | } | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | |||
| 368 | |||
| 369 | void MtCoder_Construct(CMtCoder *p) | ||
| 370 | { | ||
| 371 | unsigned i; | ||
| 372 | |||
| 373 | p->blockSize = 0; | ||
| 374 | p->numThreadsMax = 0; | ||
| 375 | p->expectedDataSize = (UInt64)(Int64)-1; | ||
| 376 | |||
| 377 | p->inStream = NULL; | ||
| 378 | p->inData = NULL; | ||
| 379 | p->inDataSize = 0; | ||
| 380 | |||
| 381 | p->progress = NULL; | ||
| 382 | p->allocBig = NULL; | ||
| 383 | |||
| 384 | p->mtCallback = NULL; | ||
| 385 | p->mtCallbackObject = NULL; | ||
| 386 | |||
| 387 | p->allocatedBufsSize = 0; | ||
| 388 | |||
| 389 | Event_Construct(&p->readEvent); | ||
| 390 | Semaphore_Construct(&p->blocksSemaphore); | ||
| 391 | |||
| 392 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
| 393 | { | ||
| 394 | CMtCoderThread *t = &p->threads[i]; | ||
| 395 | t->mtCoder = p; | ||
| 396 | t->index = i; | ||
| 397 | t->inBuf = NULL; | ||
| 398 | t->stop = False; | ||
| 399 | Event_Construct(&t->startEvent); | ||
| 400 | Thread_Construct(&t->thread); | ||
| 401 | } | ||
| 402 | |||
| 403 | #ifdef MTCODER__USE_WRITE_THREAD | ||
| 404 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
| 405 | Event_Construct(&p->writeEvents[i]); | ||
| 406 | #else | ||
| 407 | Event_Construct(&p->finishedEvent); | ||
| 408 | #endif | ||
| 409 | |||
| 410 | CriticalSection_Init(&p->cs); | ||
| 411 | CriticalSection_Init(&p->mtProgress.cs); | ||
| 412 | } | ||
| 413 | |||
| 414 | |||
| 415 | |||
| 416 | |||
| 417 | static void MtCoder_Free(CMtCoder *p) | ||
| 418 | { | ||
| 419 | unsigned i; | ||
| 420 | |||
| 421 | /* | ||
| 422 | p->stopReading = True; | ||
| 423 | if (Event_IsCreated(&p->readEvent)) | ||
| 424 | Event_Set(&p->readEvent); | ||
| 425 | */ | ||
| 426 | |||
| 427 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
| 428 | MtCoderThread_Destruct(&p->threads[i]); | ||
| 429 | |||
| 430 | Event_Close(&p->readEvent); | ||
| 431 | Semaphore_Close(&p->blocksSemaphore); | ||
| 432 | |||
| 433 | #ifdef MTCODER__USE_WRITE_THREAD | ||
| 434 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
| 435 | Event_Close(&p->writeEvents[i]); | ||
| 436 | #else | ||
| 437 | Event_Close(&p->finishedEvent); | ||
| 438 | #endif | ||
| 439 | } | ||
| 440 | |||
| 441 | |||
| 442 | void MtCoder_Destruct(CMtCoder *p) | ||
| 443 | { | ||
| 444 | MtCoder_Free(p); | ||
| 445 | |||
| 446 | CriticalSection_Delete(&p->cs); | ||
| 447 | CriticalSection_Delete(&p->mtProgress.cs); | ||
| 448 | } | ||
| 449 | |||
| 450 | |||
| 451 | SRes MtCoder_Code(CMtCoder *p) | ||
| 452 | { | ||
| 453 | unsigned numThreads = p->numThreadsMax; | ||
| 454 | unsigned numBlocksMax; | ||
| 455 | unsigned i; | ||
| 456 | SRes res = SZ_OK; | ||
| 457 | |||
| 458 | if (numThreads > MTCODER__THREADS_MAX) | ||
| 459 | numThreads = MTCODER__THREADS_MAX; | ||
| 460 | numBlocksMax = MTCODER__GET_NUM_BLOCKS_FROM_THREADS(numThreads); | ||
| 461 | |||
| 462 | if (p->blockSize < ((UInt32)1 << 26)) numBlocksMax++; | ||
| 463 | if (p->blockSize < ((UInt32)1 << 24)) numBlocksMax++; | ||
| 464 | if (p->blockSize < ((UInt32)1 << 22)) numBlocksMax++; | ||
| 465 | |||
| 466 | if (numBlocksMax > MTCODER__BLOCKS_MAX) | ||
| 467 | numBlocksMax = MTCODER__BLOCKS_MAX; | ||
| 468 | |||
| 469 | if (p->blockSize != p->allocatedBufsSize) | ||
| 470 | { | ||
| 471 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
| 472 | { | ||
| 473 | CMtCoderThread *t = &p->threads[i]; | ||
| 474 | if (t->inBuf) | ||
| 475 | { | ||
| 476 | ISzAlloc_Free(p->allocBig, t->inBuf); | ||
| 477 | t->inBuf = NULL; | ||
| 478 | } | ||
| 479 | } | ||
| 480 | p->allocatedBufsSize = p->blockSize; | ||
| 481 | } | ||
| 482 | |||
| 483 | p->readRes = SZ_OK; | ||
| 484 | |||
| 485 | MtProgress_Init(&p->mtProgress, p->progress); | ||
| 486 | |||
| 487 | #ifdef MTCODER__USE_WRITE_THREAD | ||
| 488 | for (i = 0; i < numBlocksMax; i++) | ||
| 489 | { | ||
| 490 | RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->writeEvents[i])); | ||
| 491 | } | ||
| 492 | #else | ||
| 493 | RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->finishedEvent)); | ||
| 494 | #endif | ||
| 495 | |||
| 496 | { | ||
| 497 | RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->readEvent)); | ||
| 498 | RINOK_THREAD(Semaphore_OptCreateInit(&p->blocksSemaphore, numBlocksMax, numBlocksMax)); | ||
| 499 | } | ||
| 500 | |||
| 501 | for (i = 0; i < MTCODER__BLOCKS_MAX - 1; i++) | ||
| 502 | p->freeBlockList[i] = i + 1; | ||
| 503 | p->freeBlockList[MTCODER__BLOCKS_MAX - 1] = (unsigned)(int)-1; | ||
| 504 | p->freeBlockHead = 0; | ||
| 505 | |||
| 506 | p->readProcessed = 0; | ||
| 507 | p->blockIndex = 0; | ||
| 508 | p->numBlocksMax = numBlocksMax; | ||
| 509 | p->stopReading = False; | ||
| 510 | |||
| 511 | #ifndef MTCODER__USE_WRITE_THREAD | ||
| 512 | p->writeIndex = 0; | ||
| 513 | p->writeRes = SZ_OK; | ||
| 514 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
| 515 | p->ReadyBlocks[i] = False; | ||
| 516 | p->numFinishedThreads = 0; | ||
| 517 | #endif | ||
| 518 | |||
| 519 | p->numStartedThreadsLimit = numThreads; | ||
| 520 | p->numStartedThreads = 0; | ||
| 521 | |||
| 522 | // for (i = 0; i < numThreads; i++) | ||
| 523 | { | ||
| 524 | CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++]; | ||
| 525 | RINOK(MtCoderThread_CreateAndStart(nextThread)); | ||
| 526 | } | ||
| 527 | |||
| 528 | RINOK_THREAD(Event_Set(&p->readEvent)) | ||
| 529 | |||
| 530 | #ifdef MTCODER__USE_WRITE_THREAD | ||
| 531 | { | ||
| 532 | unsigned bi = 0; | ||
| 533 | |||
| 534 | for (;; bi++) | ||
| 535 | { | ||
| 536 | if (bi >= numBlocksMax) | ||
| 537 | bi = 0; | ||
| 538 | |||
| 539 | RINOK_THREAD(Event_Wait(&p->writeEvents[bi])) | ||
| 540 | |||
| 541 | { | ||
| 542 | const CMtCoderBlock *block = &p->blocks[bi]; | ||
| 543 | unsigned bufIndex = block->bufIndex; | ||
| 544 | BoolInt finished = block->finished; | ||
| 545 | if (res == SZ_OK && block->res != SZ_OK) | ||
| 546 | res = block->res; | ||
| 547 | |||
| 548 | if (bufIndex != (unsigned)(int)-1) | ||
| 549 | { | ||
| 550 | if (res == SZ_OK) | ||
| 551 | { | ||
| 552 | res = p->mtCallback->Write(p->mtCallbackObject, bufIndex); | ||
| 553 | if (res != SZ_OK) | ||
| 554 | MtProgress_SetError(&p->mtProgress, res); | ||
| 555 | } | ||
| 556 | |||
| 557 | CriticalSection_Enter(&p->cs); | ||
| 558 | { | ||
| 559 | p->freeBlockList[bufIndex] = p->freeBlockHead; | ||
| 560 | p->freeBlockHead = bufIndex; | ||
| 561 | } | ||
| 562 | CriticalSection_Leave(&p->cs); | ||
| 563 | } | ||
| 564 | |||
| 565 | RINOK_THREAD(Semaphore_Release1(&p->blocksSemaphore)) | ||
| 566 | |||
| 567 | if (finished) | ||
| 568 | break; | ||
| 569 | } | ||
| 570 | } | ||
| 571 | } | ||
| 572 | #else | ||
| 573 | { | ||
| 574 | WRes wres = Event_Wait(&p->finishedEvent); | ||
| 575 | res = MY_SRes_HRESULT_FROM_WRes(wres); | ||
| 576 | } | ||
| 577 | #endif | ||
| 578 | |||
| 579 | if (res == SZ_OK) | ||
| 580 | res = p->readRes; | ||
| 581 | |||
| 582 | if (res == SZ_OK) | ||
| 583 | res = p->mtProgress.res; | ||
| 584 | |||
| 585 | #ifndef MTCODER__USE_WRITE_THREAD | ||
| 586 | if (res == SZ_OK) | ||
| 587 | res = p->writeRes; | ||
| 588 | #endif | ||
| 589 | |||
| 590 | if (res != SZ_OK) | ||
| 591 | MtCoder_Free(p); | ||
| 592 | return res; | ||
| 593 | } | ||
| 594 | |||
| 595 | #endif | ||
diff --git a/C/MtCoder.h b/C/MtCoder.h new file mode 100644 index 0000000..5a5f4d1 --- /dev/null +++ b/C/MtCoder.h | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | /* MtCoder.h -- Multi-thread Coder | ||
| 2 | 2018-07-04 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __MT_CODER_H | ||
| 5 | #define __MT_CODER_H | ||
| 6 | |||
| 7 | #include "MtDec.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | /* | ||
| 12 | if ( defined MTCODER__USE_WRITE_THREAD) : main thread writes all data blocks to output stream | ||
| 13 | if (not defined MTCODER__USE_WRITE_THREAD) : any coder thread can write data blocks to output stream | ||
| 14 | */ | ||
| 15 | /* #define MTCODER__USE_WRITE_THREAD */ | ||
| 16 | |||
| 17 | #ifndef _7ZIP_ST | ||
| 18 | #define MTCODER__GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1) | ||
| 19 | #define MTCODER__THREADS_MAX 64 | ||
| 20 | #define MTCODER__BLOCKS_MAX (MTCODER__GET_NUM_BLOCKS_FROM_THREADS(MTCODER__THREADS_MAX) + 3) | ||
| 21 | #else | ||
| 22 | #define MTCODER__THREADS_MAX 1 | ||
| 23 | #define MTCODER__BLOCKS_MAX 1 | ||
| 24 | #endif | ||
| 25 | |||
| 26 | |||
| 27 | #ifndef _7ZIP_ST | ||
| 28 | |||
| 29 | |||
| 30 | typedef struct | ||
| 31 | { | ||
| 32 | ICompressProgress vt; | ||
| 33 | CMtProgress *mtProgress; | ||
| 34 | UInt64 inSize; | ||
| 35 | UInt64 outSize; | ||
| 36 | } CMtProgressThunk; | ||
| 37 | |||
| 38 | void MtProgressThunk_CreateVTable(CMtProgressThunk *p); | ||
| 39 | |||
| 40 | #define MtProgressThunk_Init(p) { (p)->inSize = 0; (p)->outSize = 0; } | ||
| 41 | |||
| 42 | |||
| 43 | struct _CMtCoder; | ||
| 44 | |||
| 45 | |||
| 46 | typedef struct | ||
| 47 | { | ||
| 48 | struct _CMtCoder *mtCoder; | ||
| 49 | unsigned index; | ||
| 50 | int stop; | ||
| 51 | Byte *inBuf; | ||
| 52 | |||
| 53 | CAutoResetEvent startEvent; | ||
| 54 | CThread thread; | ||
| 55 | } CMtCoderThread; | ||
| 56 | |||
| 57 | |||
| 58 | typedef struct | ||
| 59 | { | ||
| 60 | SRes (*Code)(void *p, unsigned coderIndex, unsigned outBufIndex, | ||
| 61 | const Byte *src, size_t srcSize, int finished); | ||
| 62 | SRes (*Write)(void *p, unsigned outBufIndex); | ||
| 63 | } IMtCoderCallback2; | ||
| 64 | |||
| 65 | |||
| 66 | typedef struct | ||
| 67 | { | ||
| 68 | SRes res; | ||
| 69 | unsigned bufIndex; | ||
| 70 | BoolInt finished; | ||
| 71 | } CMtCoderBlock; | ||
| 72 | |||
| 73 | |||
| 74 | typedef struct _CMtCoder | ||
| 75 | { | ||
| 76 | /* input variables */ | ||
| 77 | |||
| 78 | size_t blockSize; /* size of input block */ | ||
| 79 | unsigned numThreadsMax; | ||
| 80 | UInt64 expectedDataSize; | ||
| 81 | |||
| 82 | ISeqInStream *inStream; | ||
| 83 | const Byte *inData; | ||
| 84 | size_t inDataSize; | ||
| 85 | |||
| 86 | ICompressProgress *progress; | ||
| 87 | ISzAllocPtr allocBig; | ||
| 88 | |||
| 89 | IMtCoderCallback2 *mtCallback; | ||
| 90 | void *mtCallbackObject; | ||
| 91 | |||
| 92 | |||
| 93 | /* internal variables */ | ||
| 94 | |||
| 95 | size_t allocatedBufsSize; | ||
| 96 | |||
| 97 | CAutoResetEvent readEvent; | ||
| 98 | CSemaphore blocksSemaphore; | ||
| 99 | |||
| 100 | BoolInt stopReading; | ||
| 101 | SRes readRes; | ||
| 102 | |||
| 103 | #ifdef MTCODER__USE_WRITE_THREAD | ||
| 104 | CAutoResetEvent writeEvents[MTCODER__BLOCKS_MAX]; | ||
| 105 | #else | ||
| 106 | CAutoResetEvent finishedEvent; | ||
| 107 | SRes writeRes; | ||
| 108 | unsigned writeIndex; | ||
| 109 | Byte ReadyBlocks[MTCODER__BLOCKS_MAX]; | ||
| 110 | LONG numFinishedThreads; | ||
| 111 | #endif | ||
| 112 | |||
| 113 | unsigned numStartedThreadsLimit; | ||
| 114 | unsigned numStartedThreads; | ||
| 115 | |||
| 116 | unsigned numBlocksMax; | ||
| 117 | unsigned blockIndex; | ||
| 118 | UInt64 readProcessed; | ||
| 119 | |||
| 120 | CCriticalSection cs; | ||
| 121 | |||
| 122 | unsigned freeBlockHead; | ||
| 123 | unsigned freeBlockList[MTCODER__BLOCKS_MAX]; | ||
| 124 | |||
| 125 | CMtProgress mtProgress; | ||
| 126 | CMtCoderBlock blocks[MTCODER__BLOCKS_MAX]; | ||
| 127 | CMtCoderThread threads[MTCODER__THREADS_MAX]; | ||
| 128 | } CMtCoder; | ||
| 129 | |||
| 130 | |||
| 131 | void MtCoder_Construct(CMtCoder *p); | ||
| 132 | void MtCoder_Destruct(CMtCoder *p); | ||
| 133 | SRes MtCoder_Code(CMtCoder *p); | ||
| 134 | |||
| 135 | |||
| 136 | #endif | ||
| 137 | |||
| 138 | |||
| 139 | EXTERN_C_END | ||
| 140 | |||
| 141 | #endif | ||
diff --git a/C/MtDec.c b/C/MtDec.c new file mode 100644 index 0000000..45a6713 --- /dev/null +++ b/C/MtDec.c | |||
| @@ -0,0 +1,1139 @@ | |||
| 1 | /* MtDec.c -- Multi-thread Decoder | ||
| 2 | 2021-12-21 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | // #define SHOW_DEBUG_INFO | ||
| 7 | |||
| 8 | // #include <stdio.h> | ||
| 9 | #include <string.h> | ||
| 10 | |||
| 11 | #ifdef SHOW_DEBUG_INFO | ||
| 12 | #include <stdio.h> | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #include "MtDec.h" | ||
| 16 | |||
| 17 | #ifndef _7ZIP_ST | ||
| 18 | |||
| 19 | #ifdef SHOW_DEBUG_INFO | ||
| 20 | #define PRF(x) x | ||
| 21 | #else | ||
| 22 | #define PRF(x) | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) | ||
| 26 | |||
| 27 | void MtProgress_Init(CMtProgress *p, ICompressProgress *progress) | ||
| 28 | { | ||
| 29 | p->progress = progress; | ||
| 30 | p->res = SZ_OK; | ||
| 31 | p->totalInSize = 0; | ||
| 32 | p->totalOutSize = 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | |||
| 36 | SRes MtProgress_Progress_ST(CMtProgress *p) | ||
| 37 | { | ||
| 38 | if (p->res == SZ_OK && p->progress) | ||
| 39 | if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) | ||
| 40 | p->res = SZ_ERROR_PROGRESS; | ||
| 41 | return p->res; | ||
| 42 | } | ||
| 43 | |||
| 44 | |||
| 45 | SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize) | ||
| 46 | { | ||
| 47 | SRes res; | ||
| 48 | CriticalSection_Enter(&p->cs); | ||
| 49 | |||
| 50 | p->totalInSize += inSize; | ||
| 51 | p->totalOutSize += outSize; | ||
| 52 | if (p->res == SZ_OK && p->progress) | ||
| 53 | if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) | ||
| 54 | p->res = SZ_ERROR_PROGRESS; | ||
| 55 | res = p->res; | ||
| 56 | |||
| 57 | CriticalSection_Leave(&p->cs); | ||
| 58 | return res; | ||
| 59 | } | ||
| 60 | |||
| 61 | |||
| 62 | SRes MtProgress_GetError(CMtProgress *p) | ||
| 63 | { | ||
| 64 | SRes res; | ||
| 65 | CriticalSection_Enter(&p->cs); | ||
| 66 | res = p->res; | ||
| 67 | CriticalSection_Leave(&p->cs); | ||
| 68 | return res; | ||
| 69 | } | ||
| 70 | |||
| 71 | |||
| 72 | void MtProgress_SetError(CMtProgress *p, SRes res) | ||
| 73 | { | ||
| 74 | CriticalSection_Enter(&p->cs); | ||
| 75 | if (p->res == SZ_OK) | ||
| 76 | p->res = res; | ||
| 77 | CriticalSection_Leave(&p->cs); | ||
| 78 | } | ||
| 79 | |||
| 80 | |||
| 81 | #define RINOK_THREAD(x) RINOK_WRes(x) | ||
| 82 | |||
| 83 | |||
| 84 | static WRes ArEvent_OptCreate_And_Reset(CEvent *p) | ||
| 85 | { | ||
| 86 | if (Event_IsCreated(p)) | ||
| 87 | return Event_Reset(p); | ||
| 88 | return AutoResetEvent_CreateNotSignaled(p); | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | struct __CMtDecBufLink | ||
| 93 | { | ||
| 94 | struct __CMtDecBufLink *next; | ||
| 95 | void *pad[3]; | ||
| 96 | }; | ||
| 97 | |||
| 98 | typedef struct __CMtDecBufLink CMtDecBufLink; | ||
| 99 | |||
| 100 | #define MTDEC__LINK_DATA_OFFSET sizeof(CMtDecBufLink) | ||
| 101 | #define MTDEC__DATA_PTR_FROM_LINK(link) ((Byte *)(link) + MTDEC__LINK_DATA_OFFSET) | ||
| 102 | |||
| 103 | |||
| 104 | |||
| 105 | static THREAD_FUNC_DECL ThreadFunc(void *pp); | ||
| 106 | |||
| 107 | |||
| 108 | static WRes MtDecThread_CreateEvents(CMtDecThread *t) | ||
| 109 | { | ||
| 110 | WRes wres = ArEvent_OptCreate_And_Reset(&t->canWrite); | ||
| 111 | if (wres == 0) | ||
| 112 | { | ||
| 113 | wres = ArEvent_OptCreate_And_Reset(&t->canRead); | ||
| 114 | if (wres == 0) | ||
| 115 | return SZ_OK; | ||
| 116 | } | ||
| 117 | return wres; | ||
| 118 | } | ||
| 119 | |||
| 120 | |||
| 121 | static SRes MtDecThread_CreateAndStart(CMtDecThread *t) | ||
| 122 | { | ||
| 123 | WRes wres = MtDecThread_CreateEvents(t); | ||
| 124 | // wres = 17; // for test | ||
| 125 | if (wres == 0) | ||
| 126 | { | ||
| 127 | if (Thread_WasCreated(&t->thread)) | ||
| 128 | return SZ_OK; | ||
| 129 | wres = Thread_Create(&t->thread, ThreadFunc, t); | ||
| 130 | if (wres == 0) | ||
| 131 | return SZ_OK; | ||
| 132 | } | ||
| 133 | return MY_SRes_HRESULT_FROM_WRes(wres); | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | void MtDecThread_FreeInBufs(CMtDecThread *t) | ||
| 138 | { | ||
| 139 | if (t->inBuf) | ||
| 140 | { | ||
| 141 | void *link = t->inBuf; | ||
| 142 | t->inBuf = NULL; | ||
| 143 | do | ||
| 144 | { | ||
| 145 | void *next = ((CMtDecBufLink *)link)->next; | ||
| 146 | ISzAlloc_Free(t->mtDec->alloc, link); | ||
| 147 | link = next; | ||
| 148 | } | ||
| 149 | while (link); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | |||
| 154 | static void MtDecThread_CloseThread(CMtDecThread *t) | ||
| 155 | { | ||
| 156 | if (Thread_WasCreated(&t->thread)) | ||
| 157 | { | ||
| 158 | Event_Set(&t->canWrite); /* we can disable it. There are no threads waiting canWrite in normal cases */ | ||
| 159 | Event_Set(&t->canRead); | ||
| 160 | Thread_Wait_Close(&t->thread); | ||
| 161 | } | ||
| 162 | |||
| 163 | Event_Close(&t->canRead); | ||
| 164 | Event_Close(&t->canWrite); | ||
| 165 | } | ||
| 166 | |||
| 167 | static void MtDec_CloseThreads(CMtDec *p) | ||
| 168 | { | ||
| 169 | unsigned i; | ||
| 170 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 171 | MtDecThread_CloseThread(&p->threads[i]); | ||
| 172 | } | ||
| 173 | |||
| 174 | static void MtDecThread_Destruct(CMtDecThread *t) | ||
| 175 | { | ||
| 176 | MtDecThread_CloseThread(t); | ||
| 177 | MtDecThread_FreeInBufs(t); | ||
| 178 | } | ||
| 179 | |||
| 180 | |||
| 181 | |||
| 182 | static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize) | ||
| 183 | { | ||
| 184 | size_t size = *processedSize; | ||
| 185 | *processedSize = 0; | ||
| 186 | while (size != 0) | ||
| 187 | { | ||
| 188 | size_t cur = size; | ||
| 189 | SRes res = ISeqInStream_Read(stream, data, &cur); | ||
| 190 | *processedSize += cur; | ||
| 191 | data += cur; | ||
| 192 | size -= cur; | ||
| 193 | RINOK(res); | ||
| 194 | if (cur == 0) | ||
| 195 | return SZ_OK; | ||
| 196 | } | ||
| 197 | return SZ_OK; | ||
| 198 | } | ||
| 199 | |||
| 200 | |||
| 201 | static SRes MtDec_GetError_Spec(CMtDec *p, UInt64 interruptIndex, BoolInt *wasInterrupted) | ||
| 202 | { | ||
| 203 | SRes res; | ||
| 204 | CriticalSection_Enter(&p->mtProgress.cs); | ||
| 205 | *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); | ||
| 206 | res = p->mtProgress.res; | ||
| 207 | CriticalSection_Leave(&p->mtProgress.cs); | ||
| 208 | return res; | ||
| 209 | } | ||
| 210 | |||
| 211 | static SRes MtDec_Progress_GetError_Spec(CMtDec *p, UInt64 inSize, UInt64 outSize, UInt64 interruptIndex, BoolInt *wasInterrupted) | ||
| 212 | { | ||
| 213 | SRes res; | ||
| 214 | CriticalSection_Enter(&p->mtProgress.cs); | ||
| 215 | |||
| 216 | p->mtProgress.totalInSize += inSize; | ||
| 217 | p->mtProgress.totalOutSize += outSize; | ||
| 218 | if (p->mtProgress.res == SZ_OK && p->mtProgress.progress) | ||
| 219 | if (ICompressProgress_Progress(p->mtProgress.progress, p->mtProgress.totalInSize, p->mtProgress.totalOutSize) != SZ_OK) | ||
| 220 | p->mtProgress.res = SZ_ERROR_PROGRESS; | ||
| 221 | |||
| 222 | *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); | ||
| 223 | res = p->mtProgress.res; | ||
| 224 | |||
| 225 | CriticalSection_Leave(&p->mtProgress.cs); | ||
| 226 | |||
| 227 | return res; | ||
| 228 | } | ||
| 229 | |||
| 230 | static void MtDec_Interrupt(CMtDec *p, UInt64 interruptIndex) | ||
| 231 | { | ||
| 232 | CriticalSection_Enter(&p->mtProgress.cs); | ||
| 233 | if (!p->needInterrupt || interruptIndex < p->interruptIndex) | ||
| 234 | { | ||
| 235 | p->interruptIndex = interruptIndex; | ||
| 236 | p->needInterrupt = True; | ||
| 237 | } | ||
| 238 | CriticalSection_Leave(&p->mtProgress.cs); | ||
| 239 | } | ||
| 240 | |||
| 241 | Byte *MtDec_GetCrossBuff(CMtDec *p) | ||
| 242 | { | ||
| 243 | Byte *cr = p->crossBlock; | ||
| 244 | if (!cr) | ||
| 245 | { | ||
| 246 | cr = (Byte *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); | ||
| 247 | if (!cr) | ||
| 248 | return NULL; | ||
| 249 | p->crossBlock = cr; | ||
| 250 | } | ||
| 251 | return MTDEC__DATA_PTR_FROM_LINK(cr); | ||
| 252 | } | ||
| 253 | |||
| 254 | |||
| 255 | /* | ||
| 256 | ThreadFunc2() returns: | ||
| 257 | 0 - in all normal cases (even for stream error or memory allocation error) | ||
| 258 | (!= 0) - WRes error return by system threading function | ||
| 259 | */ | ||
| 260 | |||
| 261 | // #define MTDEC_ProgessStep (1 << 22) | ||
| 262 | #define MTDEC_ProgessStep (1 << 0) | ||
| 263 | |||
| 264 | static WRes ThreadFunc2(CMtDecThread *t) | ||
| 265 | { | ||
| 266 | CMtDec *p = t->mtDec; | ||
| 267 | |||
| 268 | PRF_STR_INT("ThreadFunc2", t->index); | ||
| 269 | |||
| 270 | // SetThreadAffinityMask(GetCurrentThread(), 1 << t->index); | ||
| 271 | |||
| 272 | for (;;) | ||
| 273 | { | ||
| 274 | SRes res, codeRes; | ||
| 275 | BoolInt wasInterrupted, isAllocError, overflow, finish; | ||
| 276 | SRes threadingErrorSRes; | ||
| 277 | BoolInt needCode, needWrite, needContinue; | ||
| 278 | |||
| 279 | size_t inDataSize_Start; | ||
| 280 | UInt64 inDataSize; | ||
| 281 | // UInt64 inDataSize_Full; | ||
| 282 | |||
| 283 | UInt64 blockIndex; | ||
| 284 | |||
| 285 | UInt64 inPrev = 0; | ||
| 286 | UInt64 outPrev = 0; | ||
| 287 | UInt64 inCodePos; | ||
| 288 | UInt64 outCodePos; | ||
| 289 | |||
| 290 | Byte *afterEndData = NULL; | ||
| 291 | size_t afterEndData_Size = 0; | ||
| 292 | BoolInt afterEndData_IsCross = False; | ||
| 293 | |||
| 294 | BoolInt canCreateNewThread = False; | ||
| 295 | // CMtDecCallbackInfo parse; | ||
| 296 | CMtDecThread *nextThread; | ||
| 297 | |||
| 298 | PRF_STR_INT("=============== Event_Wait(&t->canRead)", t->index); | ||
| 299 | |||
| 300 | RINOK_THREAD(Event_Wait(&t->canRead)); | ||
| 301 | if (p->exitThread) | ||
| 302 | return 0; | ||
| 303 | |||
| 304 | PRF_STR_INT("after Event_Wait(&t->canRead)", t->index); | ||
| 305 | |||
| 306 | // if (t->index == 3) return 19; // for test | ||
| 307 | |||
| 308 | blockIndex = p->blockIndex++; | ||
| 309 | |||
| 310 | // PRF(printf("\ncanRead\n")) | ||
| 311 | |||
| 312 | res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); | ||
| 313 | |||
| 314 | finish = p->readWasFinished; | ||
| 315 | needCode = False; | ||
| 316 | needWrite = False; | ||
| 317 | isAllocError = False; | ||
| 318 | overflow = False; | ||
| 319 | |||
| 320 | inDataSize_Start = 0; | ||
| 321 | inDataSize = 0; | ||
| 322 | // inDataSize_Full = 0; | ||
| 323 | |||
| 324 | if (res == SZ_OK && !wasInterrupted) | ||
| 325 | { | ||
| 326 | // if (p->inStream) | ||
| 327 | { | ||
| 328 | CMtDecBufLink *prev = NULL; | ||
| 329 | CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; | ||
| 330 | size_t crossSize = p->crossEnd - p->crossStart; | ||
| 331 | |||
| 332 | PRF(printf("\ncrossSize = %d\n", crossSize)); | ||
| 333 | |||
| 334 | for (;;) | ||
| 335 | { | ||
| 336 | if (!link) | ||
| 337 | { | ||
| 338 | link = (CMtDecBufLink *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); | ||
| 339 | if (!link) | ||
| 340 | { | ||
| 341 | finish = True; | ||
| 342 | // p->allocError_for_Read_BlockIndex = blockIndex; | ||
| 343 | isAllocError = True; | ||
| 344 | break; | ||
| 345 | } | ||
| 346 | link->next = NULL; | ||
| 347 | if (prev) | ||
| 348 | { | ||
| 349 | // static unsigned g_num = 0; | ||
| 350 | // printf("\n%6d : %x", ++g_num, (unsigned)(size_t)((Byte *)link - (Byte *)prev)); | ||
| 351 | prev->next = link; | ||
| 352 | } | ||
| 353 | else | ||
| 354 | t->inBuf = (void *)link; | ||
| 355 | } | ||
| 356 | |||
| 357 | { | ||
| 358 | Byte *data = MTDEC__DATA_PTR_FROM_LINK(link); | ||
| 359 | Byte *parseData = data; | ||
| 360 | size_t size; | ||
| 361 | |||
| 362 | if (crossSize != 0) | ||
| 363 | { | ||
| 364 | inDataSize = crossSize; | ||
| 365 | // inDataSize_Full = inDataSize; | ||
| 366 | inDataSize_Start = crossSize; | ||
| 367 | size = crossSize; | ||
| 368 | parseData = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; | ||
| 369 | PRF(printf("\ncross : crossStart = %7d crossEnd = %7d finish = %1d", | ||
| 370 | (int)p->crossStart, (int)p->crossEnd, (int)finish)); | ||
| 371 | } | ||
| 372 | else | ||
| 373 | { | ||
| 374 | size = p->inBufSize; | ||
| 375 | |||
| 376 | res = FullRead(p->inStream, data, &size); | ||
| 377 | |||
| 378 | // size = 10; // test | ||
| 379 | |||
| 380 | inDataSize += size; | ||
| 381 | // inDataSize_Full = inDataSize; | ||
| 382 | if (!prev) | ||
| 383 | inDataSize_Start = size; | ||
| 384 | |||
| 385 | p->readProcessed += size; | ||
| 386 | finish = (size != p->inBufSize); | ||
| 387 | if (finish) | ||
| 388 | p->readWasFinished = True; | ||
| 389 | |||
| 390 | // res = E_INVALIDARG; // test | ||
| 391 | |||
| 392 | if (res != SZ_OK) | ||
| 393 | { | ||
| 394 | // PRF(printf("\nRead error = %d\n", res)) | ||
| 395 | // we want to decode all data before error | ||
| 396 | p->readRes = res; | ||
| 397 | // p->readError_BlockIndex = blockIndex; | ||
| 398 | p->readWasFinished = True; | ||
| 399 | finish = True; | ||
| 400 | res = SZ_OK; | ||
| 401 | // break; | ||
| 402 | } | ||
| 403 | |||
| 404 | if (inDataSize - inPrev >= MTDEC_ProgessStep) | ||
| 405 | { | ||
| 406 | res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); | ||
| 407 | if (res != SZ_OK || wasInterrupted) | ||
| 408 | break; | ||
| 409 | inPrev = inDataSize; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | { | ||
| 414 | CMtDecCallbackInfo parse; | ||
| 415 | |||
| 416 | parse.startCall = (prev == NULL); | ||
| 417 | parse.src = parseData; | ||
| 418 | parse.srcSize = size; | ||
| 419 | parse.srcFinished = finish; | ||
| 420 | parse.canCreateNewThread = True; | ||
| 421 | |||
| 422 | PRF(printf("\nParse size = %d\n", (unsigned)size)); | ||
| 423 | |||
| 424 | p->mtCallback->Parse(p->mtCallbackObject, t->index, &parse); | ||
| 425 | |||
| 426 | PRF(printf(" Parse processed = %d, state = %d \n", (unsigned)parse.srcSize, (unsigned)parse.state)); | ||
| 427 | |||
| 428 | needWrite = True; | ||
| 429 | canCreateNewThread = parse.canCreateNewThread; | ||
| 430 | |||
| 431 | // printf("\n\n%12I64u %12I64u", (UInt64)p->mtProgress.totalInSize, (UInt64)p->mtProgress.totalOutSize); | ||
| 432 | |||
| 433 | if ( | ||
| 434 | // parseRes != SZ_OK || | ||
| 435 | // inDataSize - (size - parse.srcSize) > p->inBlockMax | ||
| 436 | // || | ||
| 437 | parse.state == MTDEC_PARSE_OVERFLOW | ||
| 438 | // || wasInterrupted | ||
| 439 | ) | ||
| 440 | { | ||
| 441 | // Overflow or Parse error - switch from MT decoding to ST decoding | ||
| 442 | finish = True; | ||
| 443 | overflow = True; | ||
| 444 | |||
| 445 | { | ||
| 446 | PRF(printf("\n Overflow")); | ||
| 447 | // PRF(printf("\nisBlockFinished = %d", (unsigned)parse.blockWasFinished)); | ||
| 448 | PRF(printf("\n inDataSize = %d", (unsigned)inDataSize)); | ||
| 449 | } | ||
| 450 | |||
| 451 | if (crossSize != 0) | ||
| 452 | memcpy(data, parseData, size); | ||
| 453 | p->crossStart = 0; | ||
| 454 | p->crossEnd = 0; | ||
| 455 | break; | ||
| 456 | } | ||
| 457 | |||
| 458 | if (crossSize != 0) | ||
| 459 | { | ||
| 460 | memcpy(data, parseData, parse.srcSize); | ||
| 461 | p->crossStart += parse.srcSize; | ||
| 462 | } | ||
| 463 | |||
| 464 | if (parse.state != MTDEC_PARSE_CONTINUE || finish) | ||
| 465 | { | ||
| 466 | // we don't need to parse in current thread anymore | ||
| 467 | |||
| 468 | if (parse.state == MTDEC_PARSE_END) | ||
| 469 | finish = True; | ||
| 470 | |||
| 471 | needCode = True; | ||
| 472 | // p->crossFinished = finish; | ||
| 473 | |||
| 474 | if (parse.srcSize == size) | ||
| 475 | { | ||
| 476 | // full parsed - no cross transfer | ||
| 477 | p->crossStart = 0; | ||
| 478 | p->crossEnd = 0; | ||
| 479 | break; | ||
| 480 | } | ||
| 481 | |||
| 482 | if (parse.state == MTDEC_PARSE_END) | ||
| 483 | { | ||
| 484 | afterEndData = parseData + parse.srcSize; | ||
| 485 | afterEndData_Size = size - parse.srcSize; | ||
| 486 | if (crossSize != 0) | ||
| 487 | afterEndData_IsCross = True; | ||
| 488 | // we reduce data size to required bytes (parsed only) | ||
| 489 | inDataSize -= afterEndData_Size; | ||
| 490 | if (!prev) | ||
| 491 | inDataSize_Start = parse.srcSize; | ||
| 492 | break; | ||
| 493 | } | ||
| 494 | |||
| 495 | { | ||
| 496 | // partial parsed - need cross transfer | ||
| 497 | if (crossSize != 0) | ||
| 498 | inDataSize = parse.srcSize; // it's only parsed now | ||
| 499 | else | ||
| 500 | { | ||
| 501 | // partial parsed - is not in initial cross block - we need to copy new data to cross block | ||
| 502 | Byte *cr = MtDec_GetCrossBuff(p); | ||
| 503 | if (!cr) | ||
| 504 | { | ||
| 505 | { | ||
| 506 | PRF(printf("\ncross alloc error error\n")); | ||
| 507 | // res = SZ_ERROR_MEM; | ||
| 508 | finish = True; | ||
| 509 | // p->allocError_for_Read_BlockIndex = blockIndex; | ||
| 510 | isAllocError = True; | ||
| 511 | break; | ||
| 512 | } | ||
| 513 | } | ||
| 514 | |||
| 515 | { | ||
| 516 | size_t crSize = size - parse.srcSize; | ||
| 517 | inDataSize -= crSize; | ||
| 518 | p->crossEnd = crSize; | ||
| 519 | p->crossStart = 0; | ||
| 520 | memcpy(cr, parseData + parse.srcSize, crSize); | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 524 | // inDataSize_Full = inDataSize; | ||
| 525 | if (!prev) | ||
| 526 | inDataSize_Start = parse.srcSize; // it's partial size (parsed only) | ||
| 527 | |||
| 528 | finish = False; | ||
| 529 | break; | ||
| 530 | } | ||
| 531 | } | ||
| 532 | |||
| 533 | if (parse.srcSize != size) | ||
| 534 | { | ||
| 535 | res = SZ_ERROR_FAIL; | ||
| 536 | PRF(printf("\nfinished error SZ_ERROR_FAIL = %d\n", res)); | ||
| 537 | break; | ||
| 538 | } | ||
| 539 | } | ||
| 540 | } | ||
| 541 | |||
| 542 | prev = link; | ||
| 543 | link = link->next; | ||
| 544 | |||
| 545 | if (crossSize != 0) | ||
| 546 | { | ||
| 547 | crossSize = 0; | ||
| 548 | p->crossStart = 0; | ||
| 549 | p->crossEnd = 0; | ||
| 550 | } | ||
| 551 | } | ||
| 552 | } | ||
| 553 | |||
| 554 | if (res == SZ_OK) | ||
| 555 | res = MtDec_GetError_Spec(p, blockIndex, &wasInterrupted); | ||
| 556 | } | ||
| 557 | |||
| 558 | codeRes = SZ_OK; | ||
| 559 | |||
| 560 | if (res == SZ_OK && needCode && !wasInterrupted) | ||
| 561 | { | ||
| 562 | codeRes = p->mtCallback->PreCode(p->mtCallbackObject, t->index); | ||
| 563 | if (codeRes != SZ_OK) | ||
| 564 | { | ||
| 565 | needCode = False; | ||
| 566 | finish = True; | ||
| 567 | // SZ_ERROR_MEM is expected error here. | ||
| 568 | // if (codeRes == SZ_ERROR_MEM) - we will try single-thread decoding later. | ||
| 569 | // if (codeRes != SZ_ERROR_MEM) - we can stop decoding or try single-thread decoding. | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | if (res != SZ_OK || wasInterrupted) | ||
| 574 | finish = True; | ||
| 575 | |||
| 576 | nextThread = NULL; | ||
| 577 | threadingErrorSRes = SZ_OK; | ||
| 578 | |||
| 579 | if (!finish) | ||
| 580 | { | ||
| 581 | if (p->numStartedThreads < p->numStartedThreads_Limit && canCreateNewThread) | ||
| 582 | { | ||
| 583 | SRes res2 = MtDecThread_CreateAndStart(&p->threads[p->numStartedThreads]); | ||
| 584 | if (res2 == SZ_OK) | ||
| 585 | { | ||
| 586 | // if (p->numStartedThreads % 1000 == 0) PRF(printf("\n numStartedThreads=%d\n", p->numStartedThreads)); | ||
| 587 | p->numStartedThreads++; | ||
| 588 | } | ||
| 589 | else | ||
| 590 | { | ||
| 591 | PRF(printf("\nERROR: numStartedThreads=%d\n", p->numStartedThreads)); | ||
| 592 | if (p->numStartedThreads == 1) | ||
| 593 | { | ||
| 594 | // if only one thread is possible, we leave muti-threading code | ||
| 595 | finish = True; | ||
| 596 | needCode = False; | ||
| 597 | threadingErrorSRes = res2; | ||
| 598 | } | ||
| 599 | else | ||
| 600 | p->numStartedThreads_Limit = p->numStartedThreads; | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | if (!finish) | ||
| 605 | { | ||
| 606 | unsigned nextIndex = t->index + 1; | ||
| 607 | nextThread = &p->threads[nextIndex >= p->numStartedThreads ? 0 : nextIndex]; | ||
| 608 | RINOK_THREAD(Event_Set(&nextThread->canRead)) | ||
| 609 | // We have started executing for new iteration (with next thread) | ||
| 610 | // And that next thread now is responsible for possible exit from decoding (threading_code) | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | // each call of Event_Set(&nextThread->canRead) must be followed by call of Event_Set(&nextThread->canWrite) | ||
| 615 | // if ( !finish ) we must call Event_Set(&nextThread->canWrite) in any case | ||
| 616 | // if ( finish ) we switch to single-thread mode and there are 2 ways at the end of current iteration (current block): | ||
| 617 | // - if (needContinue) after Write(&needContinue), we restore decoding with new iteration | ||
| 618 | // - otherwise we stop decoding and exit from ThreadFunc2() | ||
| 619 | |||
| 620 | // Don't change (finish) variable in the further code | ||
| 621 | |||
| 622 | |||
| 623 | // ---------- CODE ---------- | ||
| 624 | |||
| 625 | inPrev = 0; | ||
| 626 | outPrev = 0; | ||
| 627 | inCodePos = 0; | ||
| 628 | outCodePos = 0; | ||
| 629 | |||
| 630 | if (res == SZ_OK && needCode && codeRes == SZ_OK) | ||
| 631 | { | ||
| 632 | BoolInt isStartBlock = True; | ||
| 633 | CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; | ||
| 634 | |||
| 635 | for (;;) | ||
| 636 | { | ||
| 637 | size_t inSize; | ||
| 638 | int stop; | ||
| 639 | |||
| 640 | if (isStartBlock) | ||
| 641 | inSize = inDataSize_Start; | ||
| 642 | else | ||
| 643 | { | ||
| 644 | UInt64 rem = inDataSize - inCodePos; | ||
| 645 | inSize = p->inBufSize; | ||
| 646 | if (inSize > rem) | ||
| 647 | inSize = (size_t)rem; | ||
| 648 | } | ||
| 649 | |||
| 650 | inCodePos += inSize; | ||
| 651 | stop = True; | ||
| 652 | |||
| 653 | codeRes = p->mtCallback->Code(p->mtCallbackObject, t->index, | ||
| 654 | (const Byte *)MTDEC__DATA_PTR_FROM_LINK(link), inSize, | ||
| 655 | (inCodePos == inDataSize), // srcFinished | ||
| 656 | &inCodePos, &outCodePos, &stop); | ||
| 657 | |||
| 658 | if (codeRes != SZ_OK) | ||
| 659 | { | ||
| 660 | PRF(printf("\nCode Interrupt error = %x\n", codeRes)); | ||
| 661 | // we interrupt only later blocks | ||
| 662 | MtDec_Interrupt(p, blockIndex); | ||
| 663 | break; | ||
| 664 | } | ||
| 665 | |||
| 666 | if (stop || inCodePos == inDataSize) | ||
| 667 | break; | ||
| 668 | |||
| 669 | { | ||
| 670 | const UInt64 inDelta = inCodePos - inPrev; | ||
| 671 | const UInt64 outDelta = outCodePos - outPrev; | ||
| 672 | if (inDelta >= MTDEC_ProgessStep || outDelta >= MTDEC_ProgessStep) | ||
| 673 | { | ||
| 674 | // Sleep(1); | ||
| 675 | res = MtDec_Progress_GetError_Spec(p, inDelta, outDelta, blockIndex, &wasInterrupted); | ||
| 676 | if (res != SZ_OK || wasInterrupted) | ||
| 677 | break; | ||
| 678 | inPrev = inCodePos; | ||
| 679 | outPrev = outCodePos; | ||
| 680 | } | ||
| 681 | } | ||
| 682 | |||
| 683 | link = link->next; | ||
| 684 | isStartBlock = False; | ||
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | |||
| 689 | // ---------- WRITE ---------- | ||
| 690 | |||
| 691 | RINOK_THREAD(Event_Wait(&t->canWrite)); | ||
| 692 | |||
| 693 | { | ||
| 694 | BoolInt isErrorMode = False; | ||
| 695 | BoolInt canRecode = True; | ||
| 696 | BoolInt needWriteToStream = needWrite; | ||
| 697 | |||
| 698 | if (p->exitThread) return 0; // it's never executed in normal cases | ||
| 699 | |||
| 700 | if (p->wasInterrupted) | ||
| 701 | wasInterrupted = True; | ||
| 702 | else | ||
| 703 | { | ||
| 704 | if (codeRes != SZ_OK) // || !needCode // check it !!! | ||
| 705 | { | ||
| 706 | p->wasInterrupted = True; | ||
| 707 | p->codeRes = codeRes; | ||
| 708 | if (codeRes == SZ_ERROR_MEM) | ||
| 709 | isAllocError = True; | ||
| 710 | } | ||
| 711 | |||
| 712 | if (threadingErrorSRes) | ||
| 713 | { | ||
| 714 | p->wasInterrupted = True; | ||
| 715 | p->threadingErrorSRes = threadingErrorSRes; | ||
| 716 | needWriteToStream = False; | ||
| 717 | } | ||
| 718 | if (isAllocError) | ||
| 719 | { | ||
| 720 | p->wasInterrupted = True; | ||
| 721 | p->isAllocError = True; | ||
| 722 | needWriteToStream = False; | ||
| 723 | } | ||
| 724 | if (overflow) | ||
| 725 | { | ||
| 726 | p->wasInterrupted = True; | ||
| 727 | p->overflow = True; | ||
| 728 | needWriteToStream = False; | ||
| 729 | } | ||
| 730 | } | ||
| 731 | |||
| 732 | if (needCode) | ||
| 733 | { | ||
| 734 | if (wasInterrupted) | ||
| 735 | { | ||
| 736 | inCodePos = 0; | ||
| 737 | outCodePos = 0; | ||
| 738 | } | ||
| 739 | { | ||
| 740 | const UInt64 inDelta = inCodePos - inPrev; | ||
| 741 | const UInt64 outDelta = outCodePos - outPrev; | ||
| 742 | // if (inDelta != 0 || outDelta != 0) | ||
| 743 | res = MtProgress_ProgressAdd(&p->mtProgress, inDelta, outDelta); | ||
| 744 | } | ||
| 745 | } | ||
| 746 | |||
| 747 | needContinue = (!finish); | ||
| 748 | |||
| 749 | // if (res == SZ_OK && needWrite && !wasInterrupted) | ||
| 750 | if (needWrite) | ||
| 751 | { | ||
| 752 | // p->inProcessed += inCodePos; | ||
| 753 | |||
| 754 | PRF(printf("\n--Write afterSize = %d\n", (unsigned)afterEndData_Size)); | ||
| 755 | |||
| 756 | res = p->mtCallback->Write(p->mtCallbackObject, t->index, | ||
| 757 | res == SZ_OK && needWriteToStream && !wasInterrupted, // needWrite | ||
| 758 | afterEndData, afterEndData_Size, afterEndData_IsCross, | ||
| 759 | &needContinue, | ||
| 760 | &canRecode); | ||
| 761 | |||
| 762 | // res = SZ_ERROR_FAIL; // for test | ||
| 763 | |||
| 764 | PRF(printf("\nAfter Write needContinue = %d\n", (unsigned)needContinue)); | ||
| 765 | PRF(printf("\nprocessed = %d\n", (unsigned)p->inProcessed)); | ||
| 766 | |||
| 767 | if (res != SZ_OK) | ||
| 768 | { | ||
| 769 | PRF(printf("\nWrite error = %d\n", res)); | ||
| 770 | isErrorMode = True; | ||
| 771 | p->wasInterrupted = True; | ||
| 772 | } | ||
| 773 | if (res != SZ_OK | ||
| 774 | || (!needContinue && !finish)) | ||
| 775 | { | ||
| 776 | PRF(printf("\nWrite Interrupt error = %x\n", res)); | ||
| 777 | MtDec_Interrupt(p, blockIndex); | ||
| 778 | } | ||
| 779 | } | ||
| 780 | |||
| 781 | if (canRecode) | ||
| 782 | if (!needCode | ||
| 783 | || res != SZ_OK | ||
| 784 | || p->wasInterrupted | ||
| 785 | || codeRes != SZ_OK | ||
| 786 | || wasInterrupted | ||
| 787 | || p->numFilledThreads != 0 | ||
| 788 | || isErrorMode) | ||
| 789 | { | ||
| 790 | if (p->numFilledThreads == 0) | ||
| 791 | p->filledThreadStart = t->index; | ||
| 792 | if (inDataSize != 0 || !finish) | ||
| 793 | { | ||
| 794 | t->inDataSize_Start = inDataSize_Start; | ||
| 795 | t->inDataSize = inDataSize; | ||
| 796 | p->numFilledThreads++; | ||
| 797 | } | ||
| 798 | PRF(printf("\np->numFilledThreads = %d\n", p->numFilledThreads)); | ||
| 799 | PRF(printf("p->filledThreadStart = %d\n", p->filledThreadStart)); | ||
| 800 | } | ||
| 801 | |||
| 802 | if (!finish) | ||
| 803 | { | ||
| 804 | RINOK_THREAD(Event_Set(&nextThread->canWrite)); | ||
| 805 | } | ||
| 806 | else | ||
| 807 | { | ||
| 808 | if (needContinue) | ||
| 809 | { | ||
| 810 | // we restore decoding with new iteration | ||
| 811 | RINOK_THREAD(Event_Set(&p->threads[0].canWrite)); | ||
| 812 | } | ||
| 813 | else | ||
| 814 | { | ||
| 815 | // we exit from decoding | ||
| 816 | if (t->index == 0) | ||
| 817 | return SZ_OK; | ||
| 818 | p->exitThread = True; | ||
| 819 | } | ||
| 820 | RINOK_THREAD(Event_Set(&p->threads[0].canRead)); | ||
| 821 | } | ||
| 822 | } | ||
| 823 | } | ||
| 824 | } | ||
| 825 | |||
| 826 | #ifdef _WIN32 | ||
| 827 | #define USE_ALLOCA | ||
| 828 | #endif | ||
| 829 | |||
| 830 | #ifdef USE_ALLOCA | ||
| 831 | #ifdef _WIN32 | ||
| 832 | #include <malloc.h> | ||
| 833 | #else | ||
| 834 | #include <stdlib.h> | ||
| 835 | #endif | ||
| 836 | #endif | ||
| 837 | |||
| 838 | |||
| 839 | static THREAD_FUNC_DECL ThreadFunc1(void *pp) | ||
| 840 | { | ||
| 841 | WRes res; | ||
| 842 | |||
| 843 | CMtDecThread *t = (CMtDecThread *)pp; | ||
| 844 | CMtDec *p; | ||
| 845 | |||
| 846 | // fprintf(stdout, "\n%d = %p\n", t->index, &t); | ||
| 847 | |||
| 848 | res = ThreadFunc2(t); | ||
| 849 | p = t->mtDec; | ||
| 850 | if (res == 0) | ||
| 851 | return (THREAD_FUNC_RET_TYPE)(UINT_PTR)p->exitThreadWRes; | ||
| 852 | { | ||
| 853 | // it's unexpected situation for some threading function error | ||
| 854 | if (p->exitThreadWRes == 0) | ||
| 855 | p->exitThreadWRes = res; | ||
| 856 | PRF(printf("\nthread exit error = %d\n", res)); | ||
| 857 | p->exitThread = True; | ||
| 858 | Event_Set(&p->threads[0].canRead); | ||
| 859 | Event_Set(&p->threads[0].canWrite); | ||
| 860 | MtProgress_SetError(&p->mtProgress, MY_SRes_HRESULT_FROM_WRes(res)); | ||
| 861 | } | ||
| 862 | return (THREAD_FUNC_RET_TYPE)(UINT_PTR)res; | ||
| 863 | } | ||
| 864 | |||
| 865 | static MY_NO_INLINE THREAD_FUNC_DECL ThreadFunc(void *pp) | ||
| 866 | { | ||
| 867 | #ifdef USE_ALLOCA | ||
| 868 | CMtDecThread *t = (CMtDecThread *)pp; | ||
| 869 | // fprintf(stderr, "\n%d = %p - before", t->index, &t); | ||
| 870 | t->allocaPtr = alloca(t->index * 128); | ||
| 871 | #endif | ||
| 872 | return ThreadFunc1(pp); | ||
| 873 | } | ||
| 874 | |||
| 875 | |||
| 876 | int MtDec_PrepareRead(CMtDec *p) | ||
| 877 | { | ||
| 878 | if (p->crossBlock && p->crossStart == p->crossEnd) | ||
| 879 | { | ||
| 880 | ISzAlloc_Free(p->alloc, p->crossBlock); | ||
| 881 | p->crossBlock = NULL; | ||
| 882 | } | ||
| 883 | |||
| 884 | { | ||
| 885 | unsigned i; | ||
| 886 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 887 | if (i > p->numStartedThreads | ||
| 888 | || p->numFilledThreads <= | ||
| 889 | (i >= p->filledThreadStart ? | ||
| 890 | i - p->filledThreadStart : | ||
| 891 | i + p->numStartedThreads - p->filledThreadStart)) | ||
| 892 | MtDecThread_FreeInBufs(&p->threads[i]); | ||
| 893 | } | ||
| 894 | |||
| 895 | return (p->numFilledThreads != 0) || (p->crossStart != p->crossEnd); | ||
| 896 | } | ||
| 897 | |||
| 898 | |||
| 899 | const Byte *MtDec_Read(CMtDec *p, size_t *inLim) | ||
| 900 | { | ||
| 901 | while (p->numFilledThreads != 0) | ||
| 902 | { | ||
| 903 | CMtDecThread *t = &p->threads[p->filledThreadStart]; | ||
| 904 | |||
| 905 | if (*inLim != 0) | ||
| 906 | { | ||
| 907 | { | ||
| 908 | void *link = t->inBuf; | ||
| 909 | void *next = ((CMtDecBufLink *)link)->next; | ||
| 910 | ISzAlloc_Free(p->alloc, link); | ||
| 911 | t->inBuf = next; | ||
| 912 | } | ||
| 913 | |||
| 914 | if (t->inDataSize == 0) | ||
| 915 | { | ||
| 916 | MtDecThread_FreeInBufs(t); | ||
| 917 | if (--p->numFilledThreads == 0) | ||
| 918 | break; | ||
| 919 | if (++p->filledThreadStart == p->numStartedThreads) | ||
| 920 | p->filledThreadStart = 0; | ||
| 921 | t = &p->threads[p->filledThreadStart]; | ||
| 922 | } | ||
| 923 | } | ||
| 924 | |||
| 925 | { | ||
| 926 | size_t lim = t->inDataSize_Start; | ||
| 927 | if (lim != 0) | ||
| 928 | t->inDataSize_Start = 0; | ||
| 929 | else | ||
| 930 | { | ||
| 931 | UInt64 rem = t->inDataSize; | ||
| 932 | lim = p->inBufSize; | ||
| 933 | if (lim > rem) | ||
| 934 | lim = (size_t)rem; | ||
| 935 | } | ||
| 936 | t->inDataSize -= lim; | ||
| 937 | *inLim = lim; | ||
| 938 | return (const Byte *)MTDEC__DATA_PTR_FROM_LINK(t->inBuf); | ||
| 939 | } | ||
| 940 | } | ||
| 941 | |||
| 942 | { | ||
| 943 | size_t crossSize = p->crossEnd - p->crossStart; | ||
| 944 | if (crossSize != 0) | ||
| 945 | { | ||
| 946 | const Byte *data = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; | ||
| 947 | *inLim = crossSize; | ||
| 948 | p->crossStart = 0; | ||
| 949 | p->crossEnd = 0; | ||
| 950 | return data; | ||
| 951 | } | ||
| 952 | *inLim = 0; | ||
| 953 | if (p->crossBlock) | ||
| 954 | { | ||
| 955 | ISzAlloc_Free(p->alloc, p->crossBlock); | ||
| 956 | p->crossBlock = NULL; | ||
| 957 | } | ||
| 958 | return NULL; | ||
| 959 | } | ||
| 960 | } | ||
| 961 | |||
| 962 | |||
| 963 | void MtDec_Construct(CMtDec *p) | ||
| 964 | { | ||
| 965 | unsigned i; | ||
| 966 | |||
| 967 | p->inBufSize = (size_t)1 << 18; | ||
| 968 | |||
| 969 | p->numThreadsMax = 0; | ||
| 970 | |||
| 971 | p->inStream = NULL; | ||
| 972 | |||
| 973 | // p->inData = NULL; | ||
| 974 | // p->inDataSize = 0; | ||
| 975 | |||
| 976 | p->crossBlock = NULL; | ||
| 977 | p->crossStart = 0; | ||
| 978 | p->crossEnd = 0; | ||
| 979 | |||
| 980 | p->numFilledThreads = 0; | ||
| 981 | |||
| 982 | p->progress = NULL; | ||
| 983 | p->alloc = NULL; | ||
| 984 | |||
| 985 | p->mtCallback = NULL; | ||
| 986 | p->mtCallbackObject = NULL; | ||
| 987 | |||
| 988 | p->allocatedBufsSize = 0; | ||
| 989 | |||
| 990 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 991 | { | ||
| 992 | CMtDecThread *t = &p->threads[i]; | ||
| 993 | t->mtDec = p; | ||
| 994 | t->index = i; | ||
| 995 | t->inBuf = NULL; | ||
| 996 | Event_Construct(&t->canRead); | ||
| 997 | Event_Construct(&t->canWrite); | ||
| 998 | Thread_Construct(&t->thread); | ||
| 999 | } | ||
| 1000 | |||
| 1001 | // Event_Construct(&p->finishedEvent); | ||
| 1002 | |||
| 1003 | CriticalSection_Init(&p->mtProgress.cs); | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | |||
| 1007 | static void MtDec_Free(CMtDec *p) | ||
| 1008 | { | ||
| 1009 | unsigned i; | ||
| 1010 | |||
| 1011 | p->exitThread = True; | ||
| 1012 | |||
| 1013 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 1014 | MtDecThread_Destruct(&p->threads[i]); | ||
| 1015 | |||
| 1016 | // Event_Close(&p->finishedEvent); | ||
| 1017 | |||
| 1018 | if (p->crossBlock) | ||
| 1019 | { | ||
| 1020 | ISzAlloc_Free(p->alloc, p->crossBlock); | ||
| 1021 | p->crossBlock = NULL; | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | |||
| 1026 | void MtDec_Destruct(CMtDec *p) | ||
| 1027 | { | ||
| 1028 | MtDec_Free(p); | ||
| 1029 | |||
| 1030 | CriticalSection_Delete(&p->mtProgress.cs); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | |||
| 1034 | SRes MtDec_Code(CMtDec *p) | ||
| 1035 | { | ||
| 1036 | unsigned i; | ||
| 1037 | |||
| 1038 | p->inProcessed = 0; | ||
| 1039 | |||
| 1040 | p->blockIndex = 1; // it must be larger than not_defined index (0) | ||
| 1041 | p->isAllocError = False; | ||
| 1042 | p->overflow = False; | ||
| 1043 | p->threadingErrorSRes = SZ_OK; | ||
| 1044 | |||
| 1045 | p->needContinue = True; | ||
| 1046 | |||
| 1047 | p->readWasFinished = False; | ||
| 1048 | p->needInterrupt = False; | ||
| 1049 | p->interruptIndex = (UInt64)(Int64)-1; | ||
| 1050 | |||
| 1051 | p->readProcessed = 0; | ||
| 1052 | p->readRes = SZ_OK; | ||
| 1053 | p->codeRes = SZ_OK; | ||
| 1054 | p->wasInterrupted = False; | ||
| 1055 | |||
| 1056 | p->crossStart = 0; | ||
| 1057 | p->crossEnd = 0; | ||
| 1058 | |||
| 1059 | p->filledThreadStart = 0; | ||
| 1060 | p->numFilledThreads = 0; | ||
| 1061 | |||
| 1062 | { | ||
| 1063 | unsigned numThreads = p->numThreadsMax; | ||
| 1064 | if (numThreads > MTDEC__THREADS_MAX) | ||
| 1065 | numThreads = MTDEC__THREADS_MAX; | ||
| 1066 | p->numStartedThreads_Limit = numThreads; | ||
| 1067 | p->numStartedThreads = 0; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | if (p->inBufSize != p->allocatedBufsSize) | ||
| 1071 | { | ||
| 1072 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 1073 | { | ||
| 1074 | CMtDecThread *t = &p->threads[i]; | ||
| 1075 | if (t->inBuf) | ||
| 1076 | MtDecThread_FreeInBufs(t); | ||
| 1077 | } | ||
| 1078 | if (p->crossBlock) | ||
| 1079 | { | ||
| 1080 | ISzAlloc_Free(p->alloc, p->crossBlock); | ||
| 1081 | p->crossBlock = NULL; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | p->allocatedBufsSize = p->inBufSize; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | MtProgress_Init(&p->mtProgress, p->progress); | ||
| 1088 | |||
| 1089 | // RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->finishedEvent)); | ||
| 1090 | p->exitThread = False; | ||
| 1091 | p->exitThreadWRes = 0; | ||
| 1092 | |||
| 1093 | { | ||
| 1094 | WRes wres; | ||
| 1095 | SRes sres; | ||
| 1096 | CMtDecThread *nextThread = &p->threads[p->numStartedThreads++]; | ||
| 1097 | // wres = MtDecThread_CreateAndStart(nextThread); | ||
| 1098 | wres = MtDecThread_CreateEvents(nextThread); | ||
| 1099 | if (wres == 0) { wres = Event_Set(&nextThread->canWrite); | ||
| 1100 | if (wres == 0) { wres = Event_Set(&nextThread->canRead); | ||
| 1101 | if (wres == 0) { THREAD_FUNC_RET_TYPE res = ThreadFunc(nextThread); | ||
| 1102 | wres = (WRes)(UINT_PTR)res; | ||
| 1103 | if (wres != 0) | ||
| 1104 | { | ||
| 1105 | p->needContinue = False; | ||
| 1106 | MtDec_CloseThreads(p); | ||
| 1107 | }}}} | ||
| 1108 | |||
| 1109 | // wres = 17; // for test | ||
| 1110 | // wres = Event_Wait(&p->finishedEvent); | ||
| 1111 | |||
| 1112 | sres = MY_SRes_HRESULT_FROM_WRes(wres); | ||
| 1113 | |||
| 1114 | if (sres != 0) | ||
| 1115 | p->threadingErrorSRes = sres; | ||
| 1116 | |||
| 1117 | if ( | ||
| 1118 | // wres == 0 | ||
| 1119 | // wres != 0 | ||
| 1120 | // || p->mtc.codeRes == SZ_ERROR_MEM | ||
| 1121 | p->isAllocError | ||
| 1122 | || p->threadingErrorSRes != SZ_OK | ||
| 1123 | || p->overflow) | ||
| 1124 | { | ||
| 1125 | // p->needContinue = True; | ||
| 1126 | } | ||
| 1127 | else | ||
| 1128 | p->needContinue = False; | ||
| 1129 | |||
| 1130 | if (p->needContinue) | ||
| 1131 | return SZ_OK; | ||
| 1132 | |||
| 1133 | // if (sres != SZ_OK) | ||
| 1134 | return sres; | ||
| 1135 | // return SZ_ERROR_FAIL; | ||
| 1136 | } | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | #endif | ||
diff --git a/C/MtDec.h b/C/MtDec.h new file mode 100644 index 0000000..c2da46a --- /dev/null +++ b/C/MtDec.h | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | /* MtDec.h -- Multi-thread Decoder | ||
| 2 | 2020-03-05 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __MT_DEC_H | ||
| 5 | #define __MT_DEC_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | #ifndef _7ZIP_ST | ||
| 10 | #include "Threads.h" | ||
| 11 | #endif | ||
| 12 | |||
| 13 | EXTERN_C_BEGIN | ||
| 14 | |||
| 15 | #ifndef _7ZIP_ST | ||
| 16 | |||
| 17 | #ifndef _7ZIP_ST | ||
| 18 | #define MTDEC__THREADS_MAX 32 | ||
| 19 | #else | ||
| 20 | #define MTDEC__THREADS_MAX 1 | ||
| 21 | #endif | ||
| 22 | |||
| 23 | |||
| 24 | typedef struct | ||
| 25 | { | ||
| 26 | ICompressProgress *progress; | ||
| 27 | SRes res; | ||
| 28 | UInt64 totalInSize; | ||
| 29 | UInt64 totalOutSize; | ||
| 30 | CCriticalSection cs; | ||
| 31 | } CMtProgress; | ||
| 32 | |||
| 33 | void MtProgress_Init(CMtProgress *p, ICompressProgress *progress); | ||
| 34 | SRes MtProgress_Progress_ST(CMtProgress *p); | ||
| 35 | SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize); | ||
| 36 | SRes MtProgress_GetError(CMtProgress *p); | ||
| 37 | void MtProgress_SetError(CMtProgress *p, SRes res); | ||
| 38 | |||
| 39 | struct _CMtDec; | ||
| 40 | |||
| 41 | typedef struct | ||
| 42 | { | ||
| 43 | struct _CMtDec *mtDec; | ||
| 44 | unsigned index; | ||
| 45 | void *inBuf; | ||
| 46 | |||
| 47 | size_t inDataSize_Start; // size of input data in start block | ||
| 48 | UInt64 inDataSize; // total size of input data in all blocks | ||
| 49 | |||
| 50 | CThread thread; | ||
| 51 | CAutoResetEvent canRead; | ||
| 52 | CAutoResetEvent canWrite; | ||
| 53 | void *allocaPtr; | ||
| 54 | } CMtDecThread; | ||
| 55 | |||
| 56 | void MtDecThread_FreeInBufs(CMtDecThread *t); | ||
| 57 | |||
| 58 | |||
| 59 | typedef enum | ||
| 60 | { | ||
| 61 | MTDEC_PARSE_CONTINUE, // continue this block with more input data | ||
| 62 | MTDEC_PARSE_OVERFLOW, // MT buffers overflow, need switch to single-thread | ||
| 63 | MTDEC_PARSE_NEW, // new block | ||
| 64 | MTDEC_PARSE_END // end of block threading. But we still can return to threading after Write(&needContinue) | ||
| 65 | } EMtDecParseState; | ||
| 66 | |||
| 67 | typedef struct | ||
| 68 | { | ||
| 69 | // in | ||
| 70 | int startCall; | ||
| 71 | const Byte *src; | ||
| 72 | size_t srcSize; | ||
| 73 | // in : (srcSize == 0) is allowed | ||
| 74 | // out : it's allowed to return less that actually was used ? | ||
| 75 | int srcFinished; | ||
| 76 | |||
| 77 | // out | ||
| 78 | EMtDecParseState state; | ||
| 79 | BoolInt canCreateNewThread; | ||
| 80 | UInt64 outPos; // check it (size_t) | ||
| 81 | } CMtDecCallbackInfo; | ||
| 82 | |||
| 83 | |||
| 84 | typedef struct | ||
| 85 | { | ||
| 86 | void (*Parse)(void *p, unsigned coderIndex, CMtDecCallbackInfo *ci); | ||
| 87 | |||
| 88 | // PreCode() and Code(): | ||
| 89 | // (SRes_return_result != SZ_OK) means stop decoding, no need another blocks | ||
| 90 | SRes (*PreCode)(void *p, unsigned coderIndex); | ||
| 91 | SRes (*Code)(void *p, unsigned coderIndex, | ||
| 92 | const Byte *src, size_t srcSize, int srcFinished, | ||
| 93 | UInt64 *inCodePos, UInt64 *outCodePos, int *stop); | ||
| 94 | // stop - means stop another Code calls | ||
| 95 | |||
| 96 | |||
| 97 | /* Write() must be called, if Parse() was called | ||
| 98 | set (needWrite) if | ||
| 99 | { | ||
| 100 | && (was not interrupted by progress) | ||
| 101 | && (was not interrupted in previous block) | ||
| 102 | } | ||
| 103 | |||
| 104 | out: | ||
| 105 | if (*needContinue), decoder still need to continue decoding with new iteration, | ||
| 106 | even after MTDEC_PARSE_END | ||
| 107 | if (*canRecode), we didn't flush current block data, so we still can decode current block later. | ||
| 108 | */ | ||
| 109 | SRes (*Write)(void *p, unsigned coderIndex, | ||
| 110 | BoolInt needWriteToStream, | ||
| 111 | const Byte *src, size_t srcSize, BoolInt isCross, | ||
| 112 | // int srcFinished, | ||
| 113 | BoolInt *needContinue, | ||
| 114 | BoolInt *canRecode); | ||
| 115 | |||
| 116 | } IMtDecCallback2; | ||
| 117 | |||
| 118 | |||
| 119 | |||
| 120 | typedef struct _CMtDec | ||
| 121 | { | ||
| 122 | /* input variables */ | ||
| 123 | |||
| 124 | size_t inBufSize; /* size of input block */ | ||
| 125 | unsigned numThreadsMax; | ||
| 126 | // size_t inBlockMax; | ||
| 127 | unsigned numThreadsMax_2; | ||
| 128 | |||
| 129 | ISeqInStream *inStream; | ||
| 130 | // const Byte *inData; | ||
| 131 | // size_t inDataSize; | ||
| 132 | |||
| 133 | ICompressProgress *progress; | ||
| 134 | ISzAllocPtr alloc; | ||
| 135 | |||
| 136 | IMtDecCallback2 *mtCallback; | ||
| 137 | void *mtCallbackObject; | ||
| 138 | |||
| 139 | |||
| 140 | /* internal variables */ | ||
| 141 | |||
| 142 | size_t allocatedBufsSize; | ||
| 143 | |||
| 144 | BoolInt exitThread; | ||
| 145 | WRes exitThreadWRes; | ||
| 146 | |||
| 147 | UInt64 blockIndex; | ||
| 148 | BoolInt isAllocError; | ||
| 149 | BoolInt overflow; | ||
| 150 | SRes threadingErrorSRes; | ||
| 151 | |||
| 152 | BoolInt needContinue; | ||
| 153 | |||
| 154 | // CAutoResetEvent finishedEvent; | ||
| 155 | |||
| 156 | SRes readRes; | ||
| 157 | SRes codeRes; | ||
| 158 | |||
| 159 | BoolInt wasInterrupted; | ||
| 160 | |||
| 161 | unsigned numStartedThreads_Limit; | ||
| 162 | unsigned numStartedThreads; | ||
| 163 | |||
| 164 | Byte *crossBlock; | ||
| 165 | size_t crossStart; | ||
| 166 | size_t crossEnd; | ||
| 167 | UInt64 readProcessed; | ||
| 168 | BoolInt readWasFinished; | ||
| 169 | UInt64 inProcessed; | ||
| 170 | |||
| 171 | unsigned filledThreadStart; | ||
| 172 | unsigned numFilledThreads; | ||
| 173 | |||
| 174 | #ifndef _7ZIP_ST | ||
| 175 | BoolInt needInterrupt; | ||
| 176 | UInt64 interruptIndex; | ||
| 177 | CMtProgress mtProgress; | ||
| 178 | CMtDecThread threads[MTDEC__THREADS_MAX]; | ||
| 179 | #endif | ||
| 180 | } CMtDec; | ||
| 181 | |||
| 182 | |||
| 183 | void MtDec_Construct(CMtDec *p); | ||
| 184 | void MtDec_Destruct(CMtDec *p); | ||
| 185 | |||
| 186 | /* | ||
| 187 | MtDec_Code() returns: | ||
| 188 | SZ_OK - in most cases | ||
| 189 | MY_SRes_HRESULT_FROM_WRes(WRes_error) - in case of unexpected error in threading function | ||
| 190 | */ | ||
| 191 | |||
| 192 | SRes MtDec_Code(CMtDec *p); | ||
| 193 | Byte *MtDec_GetCrossBuff(CMtDec *p); | ||
| 194 | |||
| 195 | int MtDec_PrepareRead(CMtDec *p); | ||
| 196 | const Byte *MtDec_Read(CMtDec *p, size_t *inLim); | ||
| 197 | |||
| 198 | #endif | ||
| 199 | |||
| 200 | EXTERN_C_END | ||
| 201 | |||
| 202 | #endif | ||
diff --git a/C/Ppmd.h b/C/Ppmd.h new file mode 100644 index 0000000..b198792 --- /dev/null +++ b/C/Ppmd.h | |||
| @@ -0,0 +1,167 @@ | |||
| 1 | /* Ppmd.h -- PPMD codec common code | ||
| 2 | 2021-04-13 : 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 "CpuArch.h" | ||
| 9 | |||
| 10 | EXTERN_C_BEGIN | ||
| 11 | |||
| 12 | #if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) | ||
| 13 | /* | ||
| 14 | PPMD code always uses 32-bit internal fields in PPMD structures to store internal references in main block. | ||
| 15 | if (PPMD_32BIT is defined), the PPMD code stores internal pointers to 32-bit reference fields. | ||
| 16 | if (PPMD_32BIT is NOT defined), the PPMD code stores internal UInt32 offsets to reference fields. | ||
| 17 | if (pointer size is 64-bit), then (PPMD_32BIT) mode is not allowed, | ||
| 18 | if (pointer size is 32-bit), then (PPMD_32BIT) mode is optional, | ||
| 19 | and it's allowed to disable PPMD_32BIT mode even if pointer is 32-bit. | ||
| 20 | PPMD code works slightly faster in (PPMD_32BIT) mode. | ||
| 21 | */ | ||
| 22 | #define PPMD_32BIT | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #define PPMD_INT_BITS 7 | ||
| 26 | #define PPMD_PERIOD_BITS 7 | ||
| 27 | #define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) | ||
| 28 | |||
| 29 | #define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) | ||
| 30 | #define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) | ||
| 31 | #define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) | ||
| 32 | #define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) | ||
| 33 | |||
| 34 | #define PPMD_N1 4 | ||
| 35 | #define PPMD_N2 4 | ||
| 36 | #define PPMD_N3 4 | ||
| 37 | #define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) | ||
| 38 | #define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) | ||
| 39 | |||
| 40 | MY_CPU_pragma_pack_push_1 | ||
| 41 | /* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ | ||
| 42 | |||
| 43 | /* SEE-contexts for PPM-contexts with masked symbols */ | ||
| 44 | typedef struct | ||
| 45 | { | ||
| 46 | UInt16 Summ; /* Freq */ | ||
| 47 | Byte Shift; /* Speed of Freq change; low Shift is for fast change */ | ||
| 48 | Byte Count; /* Count to next change of Shift */ | ||
| 49 | } CPpmd_See; | ||
| 50 | |||
| 51 | #define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ | ||
| 52 | { (p)->Summ = (UInt16)((p)->Summ << 1); (p)->Count = (Byte)(3 << (p)->Shift++); } | ||
| 53 | |||
| 54 | |||
| 55 | typedef struct | ||
| 56 | { | ||
| 57 | Byte Symbol; | ||
| 58 | Byte Freq; | ||
| 59 | UInt16 Successor_0; | ||
| 60 | UInt16 Successor_1; | ||
| 61 | } CPpmd_State; | ||
| 62 | |||
| 63 | typedef struct CPpmd_State2_ | ||
| 64 | { | ||
| 65 | Byte Symbol; | ||
| 66 | Byte Freq; | ||
| 67 | } CPpmd_State2; | ||
| 68 | |||
| 69 | typedef struct CPpmd_State4_ | ||
| 70 | { | ||
| 71 | UInt16 Successor_0; | ||
| 72 | UInt16 Successor_1; | ||
| 73 | } CPpmd_State4; | ||
| 74 | |||
| 75 | MY_CPU_pragma_pop | ||
| 76 | |||
| 77 | /* | ||
| 78 | PPMD code can write full CPpmd_State structure data to CPpmd*_Context | ||
| 79 | at (byte offset = 2) instead of some fields of original CPpmd*_Context structure. | ||
| 80 | |||
| 81 | If we use pointers to different types, but that point to shared | ||
| 82 | memory space, we can have aliasing problem (strict aliasing). | ||
| 83 | |||
| 84 | XLC compiler in -O2 mode can change the order of memory write instructions | ||
| 85 | in relation to read instructions, if we have use pointers to different types. | ||
| 86 | |||
| 87 | To solve that aliasing problem we use combined CPpmd*_Context structure | ||
| 88 | with unions that contain the fields from both structures: | ||
| 89 | the original CPpmd*_Context and CPpmd_State. | ||
| 90 | So we can access the fields from both structures via one pointer, | ||
| 91 | and the compiler doesn't change the order of write instructions | ||
| 92 | in relation to read instructions. | ||
| 93 | |||
| 94 | If we don't use memory write instructions to shared memory in | ||
| 95 | some local code, and we use only reading instructions (read only), | ||
| 96 | then probably it's safe to use pointers to different types for reading. | ||
| 97 | */ | ||
| 98 | |||
| 99 | |||
| 100 | |||
| 101 | #ifdef PPMD_32BIT | ||
| 102 | |||
| 103 | #define Ppmd_Ref_Type(type) type * | ||
| 104 | #define Ppmd_GetRef(p, ptr) (ptr) | ||
| 105 | #define Ppmd_GetPtr(p, ptr) (ptr) | ||
| 106 | #define Ppmd_GetPtr_Type(p, ptr, note_type) (ptr) | ||
| 107 | |||
| 108 | #else | ||
| 109 | |||
| 110 | #define Ppmd_Ref_Type(type) UInt32 | ||
| 111 | #define Ppmd_GetRef(p, ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) | ||
| 112 | #define Ppmd_GetPtr(p, offs) ((void *)((p)->Base + (offs))) | ||
| 113 | #define Ppmd_GetPtr_Type(p, offs, type) ((type *)Ppmd_GetPtr(p, offs)) | ||
| 114 | |||
| 115 | #endif // PPMD_32BIT | ||
| 116 | |||
| 117 | |||
| 118 | typedef Ppmd_Ref_Type(CPpmd_State) CPpmd_State_Ref; | ||
| 119 | typedef Ppmd_Ref_Type(void) CPpmd_Void_Ref; | ||
| 120 | typedef Ppmd_Ref_Type(Byte) CPpmd_Byte_Ref; | ||
| 121 | |||
| 122 | |||
| 123 | /* | ||
| 124 | #ifdef MY_CPU_LE_UNALIGN | ||
| 125 | // the unaligned 32-bit access latency can be too large, if the data is not in L1 cache. | ||
| 126 | #define Ppmd_GET_SUCCESSOR(p) ((CPpmd_Void_Ref)*(const UInt32 *)(const void *)&(p)->Successor_0) | ||
| 127 | #define Ppmd_SET_SUCCESSOR(p, v) *(UInt32 *)(void *)(void *)&(p)->Successor_0 = (UInt32)(v) | ||
| 128 | |||
| 129 | #else | ||
| 130 | */ | ||
| 131 | |||
| 132 | /* | ||
| 133 | We can write 16-bit halves to 32-bit (Successor) field in any selected order. | ||
| 134 | But the native order is more consistent way. | ||
| 135 | So we use the native order, if LE/BE order can be detected here at compile time. | ||
| 136 | */ | ||
| 137 | |||
| 138 | #ifdef MY_CPU_BE | ||
| 139 | |||
| 140 | #define Ppmd_GET_SUCCESSOR(p) \ | ||
| 141 | ( (CPpmd_Void_Ref) (((UInt32)(p)->Successor_0 << 16) | (p)->Successor_1) ) | ||
| 142 | |||
| 143 | #define Ppmd_SET_SUCCESSOR(p, v) { \ | ||
| 144 | (p)->Successor_0 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); \ | ||
| 145 | (p)->Successor_1 = (UInt16)((UInt32)(v) /* & 0xFFFF */); } | ||
| 146 | |||
| 147 | #else | ||
| 148 | |||
| 149 | #define Ppmd_GET_SUCCESSOR(p) \ | ||
| 150 | ( (CPpmd_Void_Ref) ((p)->Successor_0 | ((UInt32)(p)->Successor_1 << 16)) ) | ||
| 151 | |||
| 152 | #define Ppmd_SET_SUCCESSOR(p, v) { \ | ||
| 153 | (p)->Successor_0 = (UInt16)((UInt32)(v) /* & 0xFFFF */); \ | ||
| 154 | (p)->Successor_1 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); } | ||
| 155 | |||
| 156 | #endif | ||
| 157 | |||
| 158 | // #endif | ||
| 159 | |||
| 160 | |||
| 161 | #define PPMD_SetAllBitsIn256Bytes(p) \ | ||
| 162 | { size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \ | ||
| 163 | p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }} | ||
| 164 | |||
| 165 | EXTERN_C_END | ||
| 166 | |||
| 167 | #endif | ||
diff --git a/C/Ppmd7.c b/C/Ppmd7.c new file mode 100644 index 0000000..cf401cb --- /dev/null +++ b/C/Ppmd7.c | |||
| @@ -0,0 +1,1104 @@ | |||
| 1 | /* Ppmd7.c -- PPMdH codec | ||
| 2 | 2021-04-13 : Igor Pavlov : Public domain | ||
| 3 | This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ | ||
| 4 | |||
| 5 | #include "Precomp.h" | ||
| 6 | |||
| 7 | #include <string.h> | ||
| 8 | |||
| 9 | #include "Ppmd7.h" | ||
| 10 | |||
| 11 | /* define PPMD7_ORDER_0_SUPPPORT to suport order-0 mode, unsupported by orignal PPMd var.H. code */ | ||
| 12 | // #define PPMD7_ORDER_0_SUPPPORT | ||
| 13 | |||
| 14 | MY_ALIGN(16) | ||
| 15 | static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; | ||
| 16 | MY_ALIGN(16) | ||
| 17 | static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; | ||
| 18 | |||
| 19 | #define MAX_FREQ 124 | ||
| 20 | #define UNIT_SIZE 12 | ||
| 21 | |||
| 22 | #define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) | ||
| 23 | #define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1]) | ||
| 24 | #define I2U(indx) ((unsigned)p->Indx2Units[indx]) | ||
| 25 | #define I2U_UInt16(indx) ((UInt16)p->Indx2Units[indx]) | ||
| 26 | |||
| 27 | #define REF(ptr) Ppmd_GetRef(p, ptr) | ||
| 28 | |||
| 29 | #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) | ||
| 30 | |||
| 31 | #define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) | ||
| 32 | #define STATS(ctx) Ppmd7_GetStats(p, ctx) | ||
| 33 | #define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) | ||
| 34 | #define SUFFIX(ctx) CTX((ctx)->Suffix) | ||
| 35 | |||
| 36 | typedef CPpmd7_Context * CTX_PTR; | ||
| 37 | |||
| 38 | struct CPpmd7_Node_; | ||
| 39 | |||
| 40 | typedef Ppmd_Ref_Type(struct CPpmd7_Node_) CPpmd7_Node_Ref; | ||
| 41 | |||
| 42 | typedef struct CPpmd7_Node_ | ||
| 43 | { | ||
| 44 | UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ | ||
| 45 | UInt16 NU; | ||
| 46 | CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ | ||
| 47 | CPpmd7_Node_Ref Prev; | ||
| 48 | } CPpmd7_Node; | ||
| 49 | |||
| 50 | #define NODE(r) Ppmd_GetPtr_Type(p, r, CPpmd7_Node) | ||
| 51 | |||
| 52 | void Ppmd7_Construct(CPpmd7 *p) | ||
| 53 | { | ||
| 54 | unsigned i, k, m; | ||
| 55 | |||
| 56 | p->Base = NULL; | ||
| 57 | |||
| 58 | for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) | ||
| 59 | { | ||
| 60 | unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); | ||
| 61 | do { p->Units2Indx[k++] = (Byte)i; } while (--step); | ||
| 62 | p->Indx2Units[i] = (Byte)k; | ||
| 63 | } | ||
| 64 | |||
| 65 | p->NS2BSIndx[0] = (0 << 1); | ||
| 66 | p->NS2BSIndx[1] = (1 << 1); | ||
| 67 | memset(p->NS2BSIndx + 2, (2 << 1), 9); | ||
| 68 | memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); | ||
| 69 | |||
| 70 | for (i = 0; i < 3; i++) | ||
| 71 | p->NS2Indx[i] = (Byte)i; | ||
| 72 | |||
| 73 | for (m = i, k = 1; i < 256; i++) | ||
| 74 | { | ||
| 75 | p->NS2Indx[i] = (Byte)m; | ||
| 76 | if (--k == 0) | ||
| 77 | k = (++m) - 2; | ||
| 78 | } | ||
| 79 | |||
| 80 | memcpy(p->ExpEscape, PPMD7_kExpEscape, 16); | ||
| 81 | } | ||
| 82 | |||
| 83 | |||
| 84 | void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc) | ||
| 85 | { | ||
| 86 | ISzAlloc_Free(alloc, p->Base); | ||
| 87 | p->Size = 0; | ||
| 88 | p->Base = NULL; | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc) | ||
| 93 | { | ||
| 94 | if (!p->Base || p->Size != size) | ||
| 95 | { | ||
| 96 | Ppmd7_Free(p, alloc); | ||
| 97 | p->AlignOffset = (4 - size) & 3; | ||
| 98 | if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == NULL) | ||
| 99 | return False; | ||
| 100 | p->Size = size; | ||
| 101 | } | ||
| 102 | return True; | ||
| 103 | } | ||
| 104 | |||
| 105 | |||
| 106 | |||
| 107 | // ---------- Internal Memory Allocator ---------- | ||
| 108 | |||
| 109 | /* We can use CPpmd7_Node in list of free units (as in Ppmd8) | ||
| 110 | But we still need one additional list walk pass in GlueFreeBlocks(). | ||
| 111 | So we use simple CPpmd_Void_Ref instead of CPpmd7_Node in InsertNode() / RemoveNode() | ||
| 112 | */ | ||
| 113 | |||
| 114 | #define EMPTY_NODE 0 | ||
| 115 | |||
| 116 | |||
| 117 | static void InsertNode(CPpmd7 *p, void *node, unsigned indx) | ||
| 118 | { | ||
| 119 | *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; | ||
| 120 | // ((CPpmd7_Node *)node)->Next = (CPpmd7_Node_Ref)p->FreeList[indx]; | ||
| 121 | |||
| 122 | p->FreeList[indx] = REF(node); | ||
| 123 | |||
| 124 | } | ||
| 125 | |||
| 126 | |||
| 127 | static void *RemoveNode(CPpmd7 *p, unsigned indx) | ||
| 128 | { | ||
| 129 | CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); | ||
| 130 | p->FreeList[indx] = *node; | ||
| 131 | // CPpmd7_Node *node = NODE((CPpmd7_Node_Ref)p->FreeList[indx]); | ||
| 132 | // p->FreeList[indx] = node->Next; | ||
| 133 | return node; | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) | ||
| 138 | { | ||
| 139 | unsigned i, nu = I2U(oldIndx) - I2U(newIndx); | ||
| 140 | ptr = (Byte *)ptr + U2B(I2U(newIndx)); | ||
| 141 | if (I2U(i = U2I(nu)) != nu) | ||
| 142 | { | ||
| 143 | unsigned k = I2U(--i); | ||
| 144 | InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); | ||
| 145 | } | ||
| 146 | InsertNode(p, ptr, i); | ||
| 147 | } | ||
| 148 | |||
| 149 | |||
| 150 | /* we use CPpmd7_Node_Union union to solve XLC -O2 strict pointer aliasing problem */ | ||
| 151 | |||
| 152 | typedef union _CPpmd7_Node_Union | ||
| 153 | { | ||
| 154 | CPpmd7_Node Node; | ||
| 155 | CPpmd7_Node_Ref NextRef; | ||
| 156 | } CPpmd7_Node_Union; | ||
| 157 | |||
| 158 | /* Original PPmdH (Ppmd7) code uses doubly linked list in GlueFreeBlocks() | ||
| 159 | we use single linked list similar to Ppmd8 code */ | ||
| 160 | |||
| 161 | |||
| 162 | static void GlueFreeBlocks(CPpmd7 *p) | ||
| 163 | { | ||
| 164 | /* | ||
| 165 | we use first UInt16 field of 12-bytes UNITs as record type stamp | ||
| 166 | CPpmd_State { Byte Symbol; Byte Freq; : Freq != 0 | ||
| 167 | CPpmd7_Context { UInt16 NumStats; : NumStats != 0 | ||
| 168 | CPpmd7_Node { UInt16 Stamp : Stamp == 0 for free record | ||
| 169 | : Stamp == 1 for head record and guard | ||
| 170 | Last 12-bytes UNIT in array is always contains 12-bytes order-0 CPpmd7_Context record. | ||
| 171 | */ | ||
| 172 | CPpmd7_Node_Ref head, n = 0; | ||
| 173 | |||
| 174 | p->GlueCount = 255; | ||
| 175 | |||
| 176 | |||
| 177 | /* we set guard NODE at LoUnit */ | ||
| 178 | if (p->LoUnit != p->HiUnit) | ||
| 179 | ((CPpmd7_Node *)(void *)p->LoUnit)->Stamp = 1; | ||
| 180 | |||
| 181 | { | ||
| 182 | /* Create list of free blocks. | ||
| 183 | We still need one additional list walk pass before Glue. */ | ||
| 184 | unsigned i; | ||
| 185 | for (i = 0; i < PPMD_NUM_INDEXES; i++) | ||
| 186 | { | ||
| 187 | const UInt16 nu = I2U_UInt16(i); | ||
| 188 | CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; | ||
| 189 | p->FreeList[i] = 0; | ||
| 190 | while (next != 0) | ||
| 191 | { | ||
| 192 | /* Don't change the order of the following commands: */ | ||
| 193 | CPpmd7_Node_Union *un = (CPpmd7_Node_Union *)NODE(next); | ||
| 194 | const CPpmd7_Node_Ref tmp = next; | ||
| 195 | next = un->NextRef; | ||
| 196 | un->Node.Stamp = EMPTY_NODE; | ||
| 197 | un->Node.NU = nu; | ||
| 198 | un->Node.Next = n; | ||
| 199 | n = tmp; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | head = n; | ||
| 205 | /* Glue and Fill must walk the list in same direction */ | ||
| 206 | { | ||
| 207 | /* Glue free blocks */ | ||
| 208 | CPpmd7_Node_Ref *prev = &head; | ||
| 209 | while (n) | ||
| 210 | { | ||
| 211 | CPpmd7_Node *node = NODE(n); | ||
| 212 | UInt32 nu = node->NU; | ||
| 213 | n = node->Next; | ||
| 214 | if (nu == 0) | ||
| 215 | { | ||
| 216 | *prev = n; | ||
| 217 | continue; | ||
| 218 | } | ||
| 219 | prev = &node->Next; | ||
| 220 | for (;;) | ||
| 221 | { | ||
| 222 | CPpmd7_Node *node2 = node + nu; | ||
| 223 | nu += node2->NU; | ||
| 224 | if (node2->Stamp != EMPTY_NODE || nu >= 0x10000) | ||
| 225 | break; | ||
| 226 | node->NU = (UInt16)nu; | ||
| 227 | node2->NU = 0; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | /* Fill lists of free blocks */ | ||
| 233 | for (n = head; n != 0;) | ||
| 234 | { | ||
| 235 | CPpmd7_Node *node = NODE(n); | ||
| 236 | UInt32 nu = node->NU; | ||
| 237 | unsigned i; | ||
| 238 | n = node->Next; | ||
| 239 | if (nu == 0) | ||
| 240 | continue; | ||
| 241 | for (; nu > 128; nu -= 128, node += 128) | ||
| 242 | InsertNode(p, node, PPMD_NUM_INDEXES - 1); | ||
| 243 | if (I2U(i = U2I(nu)) != nu) | ||
| 244 | { | ||
| 245 | unsigned k = I2U(--i); | ||
| 246 | InsertNode(p, node + k, (unsigned)nu - k - 1); | ||
| 247 | } | ||
| 248 | InsertNode(p, node, i); | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | |||
| 253 | MY_NO_INLINE | ||
| 254 | static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) | ||
| 255 | { | ||
| 256 | unsigned i; | ||
| 257 | |||
| 258 | if (p->GlueCount == 0) | ||
| 259 | { | ||
| 260 | GlueFreeBlocks(p); | ||
| 261 | if (p->FreeList[indx] != 0) | ||
| 262 | return RemoveNode(p, indx); | ||
| 263 | } | ||
| 264 | |||
| 265 | i = indx; | ||
| 266 | |||
| 267 | do | ||
| 268 | { | ||
| 269 | if (++i == PPMD_NUM_INDEXES) | ||
| 270 | { | ||
| 271 | UInt32 numBytes = U2B(I2U(indx)); | ||
| 272 | Byte *us = p->UnitsStart; | ||
| 273 | p->GlueCount--; | ||
| 274 | return ((UInt32)(us - p->Text) > numBytes) ? (p->UnitsStart = us - numBytes) : NULL; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | while (p->FreeList[i] == 0); | ||
| 278 | |||
| 279 | { | ||
| 280 | void *block = RemoveNode(p, i); | ||
| 281 | SplitBlock(p, block, i, indx); | ||
| 282 | return block; | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | |||
| 287 | static void *AllocUnits(CPpmd7 *p, unsigned indx) | ||
| 288 | { | ||
| 289 | if (p->FreeList[indx] != 0) | ||
| 290 | return RemoveNode(p, indx); | ||
| 291 | { | ||
| 292 | UInt32 numBytes = U2B(I2U(indx)); | ||
| 293 | Byte *lo = p->LoUnit; | ||
| 294 | if ((UInt32)(p->HiUnit - lo) >= numBytes) | ||
| 295 | { | ||
| 296 | p->LoUnit = lo + numBytes; | ||
| 297 | return lo; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | return AllocUnitsRare(p, indx); | ||
| 301 | } | ||
| 302 | |||
| 303 | |||
| 304 | #define MyMem12Cpy(dest, src, num) \ | ||
| 305 | { UInt32 *d = (UInt32 *)dest; const UInt32 *z = (const UInt32 *)src; UInt32 n = num; \ | ||
| 306 | do { d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; } while (--n); } | ||
| 307 | |||
| 308 | |||
| 309 | /* | ||
| 310 | static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) | ||
| 311 | { | ||
| 312 | unsigned i0 = U2I(oldNU); | ||
| 313 | unsigned i1 = U2I(newNU); | ||
| 314 | if (i0 == i1) | ||
| 315 | return oldPtr; | ||
| 316 | if (p->FreeList[i1] != 0) | ||
| 317 | { | ||
| 318 | void *ptr = RemoveNode(p, i1); | ||
| 319 | MyMem12Cpy(ptr, oldPtr, newNU); | ||
| 320 | InsertNode(p, oldPtr, i0); | ||
| 321 | return ptr; | ||
| 322 | } | ||
| 323 | SplitBlock(p, oldPtr, i0, i1); | ||
| 324 | return oldPtr; | ||
| 325 | } | ||
| 326 | */ | ||
| 327 | |||
| 328 | |||
| 329 | #define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) | ||
| 330 | static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) | ||
| 331 | { | ||
| 332 | Ppmd_SET_SUCCESSOR(p, v); | ||
| 333 | } | ||
| 334 | |||
| 335 | |||
| 336 | |||
| 337 | MY_NO_INLINE | ||
| 338 | static | ||
| 339 | void RestartModel(CPpmd7 *p) | ||
| 340 | { | ||
| 341 | unsigned i, k; | ||
| 342 | |||
| 343 | memset(p->FreeList, 0, sizeof(p->FreeList)); | ||
| 344 | |||
| 345 | p->Text = p->Base + p->AlignOffset; | ||
| 346 | p->HiUnit = p->Text + p->Size; | ||
| 347 | p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; | ||
| 348 | p->GlueCount = 0; | ||
| 349 | |||
| 350 | p->OrderFall = p->MaxOrder; | ||
| 351 | p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; | ||
| 352 | p->PrevSuccess = 0; | ||
| 353 | |||
| 354 | { | ||
| 355 | CPpmd7_Context *mc = (CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ | ||
| 356 | CPpmd_State *s = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ | ||
| 357 | |||
| 358 | p->LoUnit += U2B(256 / 2); | ||
| 359 | p->MaxContext = p->MinContext = mc; | ||
| 360 | p->FoundState = s; | ||
| 361 | |||
| 362 | mc->NumStats = 256; | ||
| 363 | mc->Union2.SummFreq = 256 + 1; | ||
| 364 | mc->Union4.Stats = REF(s); | ||
| 365 | mc->Suffix = 0; | ||
| 366 | |||
| 367 | for (i = 0; i < 256; i++, s++) | ||
| 368 | { | ||
| 369 | s->Symbol = (Byte)i; | ||
| 370 | s->Freq = 1; | ||
| 371 | SetSuccessor(s, 0); | ||
| 372 | } | ||
| 373 | |||
| 374 | #ifdef PPMD7_ORDER_0_SUPPPORT | ||
| 375 | if (p->MaxOrder == 0) | ||
| 376 | { | ||
| 377 | CPpmd_Void_Ref r = REF(mc); | ||
| 378 | s = p->FoundState; | ||
| 379 | for (i = 0; i < 256; i++, s++) | ||
| 380 | SetSuccessor(s, r); | ||
| 381 | return; | ||
| 382 | } | ||
| 383 | #endif | ||
| 384 | } | ||
| 385 | |||
| 386 | for (i = 0; i < 128; i++) | ||
| 387 | |||
| 388 | |||
| 389 | |||
| 390 | for (k = 0; k < 8; k++) | ||
| 391 | { | ||
| 392 | unsigned m; | ||
| 393 | UInt16 *dest = p->BinSumm[i] + k; | ||
| 394 | UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); | ||
| 395 | for (m = 0; m < 64; m += 8) | ||
| 396 | dest[m] = val; | ||
| 397 | } | ||
| 398 | |||
| 399 | |||
| 400 | for (i = 0; i < 25; i++) | ||
| 401 | { | ||
| 402 | |||
| 403 | CPpmd_See *s = p->See[i]; | ||
| 404 | |||
| 405 | |||
| 406 | |||
| 407 | unsigned summ = ((5 * i + 10) << (PPMD_PERIOD_BITS - 4)); | ||
| 408 | for (k = 0; k < 16; k++, s++) | ||
| 409 | { | ||
| 410 | s->Summ = (UInt16)summ; | ||
| 411 | s->Shift = (PPMD_PERIOD_BITS - 4); | ||
| 412 | s->Count = 4; | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | p->DummySee.Summ = 0; /* unused */ | ||
| 417 | p->DummySee.Shift = PPMD_PERIOD_BITS; | ||
| 418 | p->DummySee.Count = 64; /* unused */ | ||
| 419 | } | ||
| 420 | |||
| 421 | |||
| 422 | void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) | ||
| 423 | { | ||
| 424 | p->MaxOrder = maxOrder; | ||
| 425 | |||
| 426 | RestartModel(p); | ||
| 427 | } | ||
| 428 | |||
| 429 | |||
| 430 | |||
| 431 | /* | ||
| 432 | CreateSuccessors() | ||
| 433 | It's called when (FoundState->Successor) is RAW-Successor, | ||
| 434 | that is the link to position in Raw text. | ||
| 435 | So we create Context records and write the links to | ||
| 436 | FoundState->Successor and to identical RAW-Successors in suffix | ||
| 437 | contexts of MinContex. | ||
| 438 | |||
| 439 | The function returns: | ||
| 440 | if (OrderFall == 0) then MinContext is already at MAX order, | ||
| 441 | { return pointer to new or existing context of same MAX order } | ||
| 442 | else | ||
| 443 | { return pointer to new real context that will be (Order+1) in comparison with MinContext | ||
| 444 | |||
| 445 | also it can return pointer to real context of same order, | ||
| 446 | */ | ||
| 447 | |||
| 448 | MY_NO_INLINE | ||
| 449 | static CTX_PTR CreateSuccessors(CPpmd7 *p) | ||
| 450 | { | ||
| 451 | CTX_PTR c = p->MinContext; | ||
| 452 | CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); | ||
| 453 | Byte newSym, newFreq; | ||
| 454 | unsigned numPs = 0; | ||
| 455 | CPpmd_State *ps[PPMD7_MAX_ORDER]; | ||
| 456 | |||
| 457 | if (p->OrderFall != 0) | ||
| 458 | ps[numPs++] = p->FoundState; | ||
| 459 | |||
| 460 | while (c->Suffix) | ||
| 461 | { | ||
| 462 | CPpmd_Void_Ref successor; | ||
| 463 | CPpmd_State *s; | ||
| 464 | c = SUFFIX(c); | ||
| 465 | |||
| 466 | |||
| 467 | if (c->NumStats != 1) | ||
| 468 | { | ||
| 469 | Byte sym = p->FoundState->Symbol; | ||
| 470 | for (s = STATS(c); s->Symbol != sym; s++); | ||
| 471 | |||
| 472 | } | ||
| 473 | else | ||
| 474 | { | ||
| 475 | s = ONE_STATE(c); | ||
| 476 | |||
| 477 | } | ||
| 478 | successor = SUCCESSOR(s); | ||
| 479 | if (successor != upBranch) | ||
| 480 | { | ||
| 481 | // (c) is real record Context here, | ||
| 482 | c = CTX(successor); | ||
| 483 | if (numPs == 0) | ||
| 484 | { | ||
| 485 | // (c) is real record MAX Order Context here, | ||
| 486 | // So we don't need to create any new contexts. | ||
| 487 | return c; | ||
| 488 | } | ||
| 489 | break; | ||
| 490 | } | ||
| 491 | ps[numPs++] = s; | ||
| 492 | } | ||
| 493 | |||
| 494 | // All created contexts will have single-symbol with new RAW-Successor | ||
| 495 | // All new RAW-Successors will point to next position in RAW text | ||
| 496 | // after FoundState->Successor | ||
| 497 | |||
| 498 | newSym = *(const Byte *)Ppmd7_GetPtr(p, upBranch); | ||
| 499 | upBranch++; | ||
| 500 | |||
| 501 | |||
| 502 | if (c->NumStats == 1) | ||
| 503 | newFreq = ONE_STATE(c)->Freq; | ||
| 504 | else | ||
| 505 | { | ||
| 506 | UInt32 cf, s0; | ||
| 507 | CPpmd_State *s; | ||
| 508 | for (s = STATS(c); s->Symbol != newSym; s++); | ||
| 509 | cf = (UInt32)s->Freq - 1; | ||
| 510 | s0 = (UInt32)c->Union2.SummFreq - c->NumStats - cf; | ||
| 511 | /* | ||
| 512 | cf - is frequency of symbol that will be Successor in new context records. | ||
| 513 | s0 - is commulative frequency sum of another symbols from parent context. | ||
| 514 | max(newFreq)= (s->Freq + 1), when (s0 == 1) | ||
| 515 | we have requirement (Ppmd7Context_OneState()->Freq <= 128) in BinSumm[] | ||
| 516 | so (s->Freq < 128) - is requirement for multi-symbol contexts | ||
| 517 | */ | ||
| 518 | newFreq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : (2 * cf + s0 - 1) / (2 * s0) + 1)); | ||
| 519 | } | ||
| 520 | |||
| 521 | // Create new single-symbol contexts from low order to high order in loop | ||
| 522 | |||
| 523 | do | ||
| 524 | { | ||
| 525 | CTX_PTR c1; | ||
| 526 | /* = AllocContext(p); */ | ||
| 527 | if (p->HiUnit != p->LoUnit) | ||
| 528 | c1 = (CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); | ||
| 529 | else if (p->FreeList[0] != 0) | ||
| 530 | c1 = (CTX_PTR)RemoveNode(p, 0); | ||
| 531 | else | ||
| 532 | { | ||
| 533 | c1 = (CTX_PTR)AllocUnitsRare(p, 0); | ||
| 534 | if (!c1) | ||
| 535 | return NULL; | ||
| 536 | } | ||
| 537 | |||
| 538 | c1->NumStats = 1; | ||
| 539 | ONE_STATE(c1)->Symbol = newSym; | ||
| 540 | ONE_STATE(c1)->Freq = newFreq; | ||
| 541 | SetSuccessor(ONE_STATE(c1), upBranch); | ||
| 542 | c1->Suffix = REF(c); | ||
| 543 | SetSuccessor(ps[--numPs], REF(c1)); | ||
| 544 | c = c1; | ||
| 545 | } | ||
| 546 | while (numPs != 0); | ||
| 547 | |||
| 548 | return c; | ||
| 549 | } | ||
| 550 | |||
| 551 | |||
| 552 | |||
| 553 | #define SwapStates(s) \ | ||
| 554 | { CPpmd_State tmp = s[0]; s[0] = s[-1]; s[-1] = tmp; } | ||
| 555 | |||
| 556 | |||
| 557 | void Ppmd7_UpdateModel(CPpmd7 *p); | ||
| 558 | MY_NO_INLINE | ||
| 559 | void Ppmd7_UpdateModel(CPpmd7 *p) | ||
| 560 | { | ||
| 561 | CPpmd_Void_Ref maxSuccessor, minSuccessor; | ||
| 562 | CTX_PTR c, mc; | ||
| 563 | unsigned s0, ns; | ||
| 564 | |||
| 565 | |||
| 566 | |||
| 567 | if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) | ||
| 568 | { | ||
| 569 | /* Update Freqs in Suffix Context */ | ||
| 570 | |||
| 571 | c = SUFFIX(p->MinContext); | ||
| 572 | |||
| 573 | if (c->NumStats == 1) | ||
| 574 | { | ||
| 575 | CPpmd_State *s = ONE_STATE(c); | ||
| 576 | if (s->Freq < 32) | ||
| 577 | s->Freq++; | ||
| 578 | } | ||
| 579 | else | ||
| 580 | { | ||
| 581 | CPpmd_State *s = STATS(c); | ||
| 582 | Byte sym = p->FoundState->Symbol; | ||
| 583 | |||
| 584 | if (s->Symbol != sym) | ||
| 585 | { | ||
| 586 | do | ||
| 587 | { | ||
| 588 | // s++; if (s->Symbol == sym) break; | ||
| 589 | s++; | ||
| 590 | } | ||
| 591 | while (s->Symbol != sym); | ||
| 592 | |||
| 593 | if (s[0].Freq >= s[-1].Freq) | ||
| 594 | { | ||
| 595 | SwapStates(s); | ||
| 596 | s--; | ||
| 597 | } | ||
| 598 | } | ||
| 599 | |||
| 600 | if (s->Freq < MAX_FREQ - 9) | ||
| 601 | { | ||
| 602 | s->Freq = (Byte)(s->Freq + 2); | ||
| 603 | c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2); | ||
| 604 | } | ||
| 605 | } | ||
| 606 | } | ||
| 607 | |||
| 608 | |||
| 609 | if (p->OrderFall == 0) | ||
| 610 | { | ||
| 611 | /* MAX ORDER context */ | ||
| 612 | /* (FoundState->Successor) is RAW-Successor. */ | ||
| 613 | p->MaxContext = p->MinContext = CreateSuccessors(p); | ||
| 614 | if (!p->MinContext) | ||
| 615 | { | ||
| 616 | RestartModel(p); | ||
| 617 | return; | ||
| 618 | } | ||
| 619 | SetSuccessor(p->FoundState, REF(p->MinContext)); | ||
| 620 | return; | ||
| 621 | } | ||
| 622 | |||
| 623 | |||
| 624 | /* NON-MAX ORDER context */ | ||
| 625 | |||
| 626 | { | ||
| 627 | Byte *text = p->Text; | ||
| 628 | *text++ = p->FoundState->Symbol; | ||
| 629 | p->Text = text; | ||
| 630 | if (text >= p->UnitsStart) | ||
| 631 | { | ||
| 632 | RestartModel(p); | ||
| 633 | return; | ||
| 634 | } | ||
| 635 | maxSuccessor = REF(text); | ||
| 636 | } | ||
| 637 | |||
| 638 | minSuccessor = SUCCESSOR(p->FoundState); | ||
| 639 | |||
| 640 | if (minSuccessor) | ||
| 641 | { | ||
| 642 | // there is Successor for FoundState in MinContext. | ||
| 643 | // So the next context will be one order higher than MinContext. | ||
| 644 | |||
| 645 | if (minSuccessor <= maxSuccessor) | ||
| 646 | { | ||
| 647 | // minSuccessor is RAW-Successor. So we will create real contexts records: | ||
| 648 | CTX_PTR cs = CreateSuccessors(p); | ||
| 649 | if (!cs) | ||
| 650 | { | ||
| 651 | RestartModel(p); | ||
| 652 | return; | ||
| 653 | } | ||
| 654 | minSuccessor = REF(cs); | ||
| 655 | } | ||
| 656 | |||
| 657 | // minSuccessor now is real Context pointer that points to existing (Order+1) context | ||
| 658 | |||
| 659 | if (--p->OrderFall == 0) | ||
| 660 | { | ||
| 661 | /* | ||
| 662 | if we move to MaxOrder context, then minSuccessor will be common Succesor for both: | ||
| 663 | MinContext that is (MaxOrder - 1) | ||
| 664 | MaxContext that is (MaxOrder) | ||
| 665 | so we don't need new RAW-Successor, and we can use real minSuccessor | ||
| 666 | as succssors for both MinContext and MaxContext. | ||
| 667 | */ | ||
| 668 | maxSuccessor = minSuccessor; | ||
| 669 | |||
| 670 | /* | ||
| 671 | if (MaxContext != MinContext) | ||
| 672 | { | ||
| 673 | there was order fall from MaxOrder and we don't need current symbol | ||
| 674 | to transfer some RAW-Succesors to real contexts. | ||
| 675 | So we roll back pointer in raw data for one position. | ||
| 676 | } | ||
| 677 | */ | ||
| 678 | p->Text -= (p->MaxContext != p->MinContext); | ||
| 679 | } | ||
| 680 | } | ||
| 681 | else | ||
| 682 | { | ||
| 683 | /* | ||
| 684 | FoundState has NULL-Successor here. | ||
| 685 | And only root 0-order context can contain NULL-Successors. | ||
| 686 | We change Successor in FoundState to RAW-Successor, | ||
| 687 | And next context will be same 0-order root Context. | ||
| 688 | */ | ||
| 689 | SetSuccessor(p->FoundState, maxSuccessor); | ||
| 690 | minSuccessor = REF(p->MinContext); | ||
| 691 | } | ||
| 692 | |||
| 693 | mc = p->MinContext; | ||
| 694 | c = p->MaxContext; | ||
| 695 | |||
| 696 | p->MaxContext = p->MinContext = CTX(minSuccessor); | ||
| 697 | |||
| 698 | if (c == mc) | ||
| 699 | return; | ||
| 700 | |||
| 701 | // s0 : is pure Escape Freq | ||
| 702 | s0 = mc->Union2.SummFreq - (ns = mc->NumStats) - ((unsigned)p->FoundState->Freq - 1); | ||
| 703 | |||
| 704 | do | ||
| 705 | { | ||
| 706 | unsigned ns1; | ||
| 707 | UInt32 sum; | ||
| 708 | |||
| 709 | if ((ns1 = c->NumStats) != 1) | ||
| 710 | { | ||
| 711 | if ((ns1 & 1) == 0) | ||
| 712 | { | ||
| 713 | /* Expand for one UNIT */ | ||
| 714 | unsigned oldNU = ns1 >> 1; | ||
| 715 | unsigned i = U2I(oldNU); | ||
| 716 | if (i != U2I((size_t)oldNU + 1)) | ||
| 717 | { | ||
| 718 | void *ptr = AllocUnits(p, i + 1); | ||
| 719 | void *oldPtr; | ||
| 720 | if (!ptr) | ||
| 721 | { | ||
| 722 | RestartModel(p); | ||
| 723 | return; | ||
| 724 | } | ||
| 725 | oldPtr = STATS(c); | ||
| 726 | MyMem12Cpy(ptr, oldPtr, oldNU); | ||
| 727 | InsertNode(p, oldPtr, i); | ||
| 728 | c->Union4.Stats = STATS_REF(ptr); | ||
| 729 | } | ||
| 730 | } | ||
| 731 | sum = c->Union2.SummFreq; | ||
| 732 | /* max increase of Escape_Freq is 3 here. | ||
| 733 | total increase of Union2.SummFreq for all symbols is less than 256 here */ | ||
| 734 | sum += (UInt32)(2 * ns1 < ns) + 2 * ((unsigned)(4 * ns1 <= ns) & (sum <= 8 * ns1)); | ||
| 735 | /* original PPMdH uses 16-bit variable for (sum) here. | ||
| 736 | But (sum < 0x9000). So we don't truncate (sum) to 16-bit */ | ||
| 737 | // sum = (UInt16)sum; | ||
| 738 | } | ||
| 739 | else | ||
| 740 | { | ||
| 741 | // instead of One-symbol context we create 2-symbol context | ||
| 742 | CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); | ||
| 743 | if (!s) | ||
| 744 | { | ||
| 745 | RestartModel(p); | ||
| 746 | return; | ||
| 747 | } | ||
| 748 | { | ||
| 749 | unsigned freq = c->Union2.State2.Freq; | ||
| 750 | // s = *ONE_STATE(c); | ||
| 751 | s->Symbol = c->Union2.State2.Symbol; | ||
| 752 | s->Successor_0 = c->Union4.State4.Successor_0; | ||
| 753 | s->Successor_1 = c->Union4.State4.Successor_1; | ||
| 754 | // SetSuccessor(s, c->Union4.Stats); // call it only for debug purposes to check the order of | ||
| 755 | // (Successor_0 and Successor_1) in LE/BE. | ||
| 756 | c->Union4.Stats = REF(s); | ||
| 757 | if (freq < MAX_FREQ / 4 - 1) | ||
| 758 | freq <<= 1; | ||
| 759 | else | ||
| 760 | freq = MAX_FREQ - 4; | ||
| 761 | // (max(s->freq) == 120), when we convert from 1-symbol into 2-symbol context | ||
| 762 | s->Freq = (Byte)freq; | ||
| 763 | // max(InitEsc = PPMD7_kExpEscape[*]) is 25. So the max(escapeFreq) is 26 here | ||
| 764 | sum = freq + p->InitEsc + (ns > 3); | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | { | ||
| 769 | CPpmd_State *s = STATS(c) + ns1; | ||
| 770 | UInt32 cf = 2 * (sum + 6) * (UInt32)p->FoundState->Freq; | ||
| 771 | UInt32 sf = (UInt32)s0 + sum; | ||
| 772 | s->Symbol = p->FoundState->Symbol; | ||
| 773 | c->NumStats = (UInt16)(ns1 + 1); | ||
| 774 | SetSuccessor(s, maxSuccessor); | ||
| 775 | |||
| 776 | if (cf < 6 * sf) | ||
| 777 | { | ||
| 778 | cf = (UInt32)1 + (cf > sf) + (cf >= 4 * sf); | ||
| 779 | sum += 3; | ||
| 780 | /* It can add (0, 1, 2) to Escape_Freq */ | ||
| 781 | } | ||
| 782 | else | ||
| 783 | { | ||
| 784 | cf = (UInt32)4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); | ||
| 785 | sum += cf; | ||
| 786 | } | ||
| 787 | |||
| 788 | c->Union2.SummFreq = (UInt16)sum; | ||
| 789 | s->Freq = (Byte)cf; | ||
| 790 | } | ||
| 791 | c = SUFFIX(c); | ||
| 792 | } | ||
| 793 | while (c != mc); | ||
| 794 | } | ||
| 795 | |||
| 796 | |||
| 797 | |||
| 798 | MY_NO_INLINE | ||
| 799 | static void Rescale(CPpmd7 *p) | ||
| 800 | { | ||
| 801 | unsigned i, adder, sumFreq, escFreq; | ||
| 802 | CPpmd_State *stats = STATS(p->MinContext); | ||
| 803 | CPpmd_State *s = p->FoundState; | ||
| 804 | |||
| 805 | /* Sort the list by Freq */ | ||
| 806 | if (s != stats) | ||
| 807 | { | ||
| 808 | CPpmd_State tmp = *s; | ||
| 809 | do | ||
| 810 | s[0] = s[-1]; | ||
| 811 | while (--s != stats); | ||
| 812 | *s = tmp; | ||
| 813 | } | ||
| 814 | |||
| 815 | sumFreq = s->Freq; | ||
| 816 | escFreq = p->MinContext->Union2.SummFreq - sumFreq; | ||
| 817 | |||
| 818 | /* | ||
| 819 | if (p->OrderFall == 0), adder = 0 : it's allowed to remove symbol from MAX Order context | ||
| 820 | if (p->OrderFall != 0), adder = 1 : it's NOT allowed to remove symbol from NON-MAX Order context | ||
| 821 | */ | ||
| 822 | |||
| 823 | adder = (p->OrderFall != 0); | ||
| 824 | |||
| 825 | #ifdef PPMD7_ORDER_0_SUPPPORT | ||
| 826 | adder |= (p->MaxOrder == 0); // we don't remove symbols from order-0 context | ||
| 827 | #endif | ||
| 828 | |||
| 829 | sumFreq = (sumFreq + 4 + adder) >> 1; | ||
| 830 | i = (unsigned)p->MinContext->NumStats - 1; | ||
| 831 | s->Freq = (Byte)sumFreq; | ||
| 832 | |||
| 833 | do | ||
| 834 | { | ||
| 835 | unsigned freq = (++s)->Freq; | ||
| 836 | escFreq -= freq; | ||
| 837 | freq = (freq + adder) >> 1; | ||
| 838 | sumFreq += freq; | ||
| 839 | s->Freq = (Byte)freq; | ||
| 840 | if (freq > s[-1].Freq) | ||
| 841 | { | ||
| 842 | CPpmd_State tmp = *s; | ||
| 843 | CPpmd_State *s1 = s; | ||
| 844 | do | ||
| 845 | { | ||
| 846 | s1[0] = s1[-1]; | ||
| 847 | } | ||
| 848 | while (--s1 != stats && freq > s1[-1].Freq); | ||
| 849 | *s1 = tmp; | ||
| 850 | } | ||
| 851 | } | ||
| 852 | while (--i); | ||
| 853 | |||
| 854 | if (s->Freq == 0) | ||
| 855 | { | ||
| 856 | /* Remove all items with Freq == 0 */ | ||
| 857 | CPpmd7_Context *mc; | ||
| 858 | unsigned numStats, numStatsNew, n0, n1; | ||
| 859 | |||
| 860 | i = 0; do { i++; } while ((--s)->Freq == 0); | ||
| 861 | |||
| 862 | /* We increase (escFreq) for the number of removed symbols. | ||
| 863 | So we will have (0.5) increase for Escape_Freq in avarage per | ||
| 864 | removed symbol after Escape_Freq halving */ | ||
| 865 | escFreq += i; | ||
| 866 | mc = p->MinContext; | ||
| 867 | numStats = mc->NumStats; | ||
| 868 | numStatsNew = numStats - i; | ||
| 869 | mc->NumStats = (UInt16)(numStatsNew); | ||
| 870 | n0 = (numStats + 1) >> 1; | ||
| 871 | |||
| 872 | if (numStatsNew == 1) | ||
| 873 | { | ||
| 874 | /* Create Single-Symbol context */ | ||
| 875 | unsigned freq = stats->Freq; | ||
| 876 | |||
| 877 | do | ||
| 878 | { | ||
| 879 | escFreq >>= 1; | ||
| 880 | freq = (freq + 1) >> 1; | ||
| 881 | } | ||
| 882 | while (escFreq > 1); | ||
| 883 | |||
| 884 | s = ONE_STATE(mc); | ||
| 885 | *s = *stats; | ||
| 886 | s->Freq = (Byte)freq; // (freq <= 260 / 4) | ||
| 887 | p->FoundState = s; | ||
| 888 | InsertNode(p, stats, U2I(n0)); | ||
| 889 | return; | ||
| 890 | } | ||
| 891 | |||
| 892 | n1 = (numStatsNew + 1) >> 1; | ||
| 893 | if (n0 != n1) | ||
| 894 | { | ||
| 895 | // p->MinContext->Union4.Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); | ||
| 896 | unsigned i0 = U2I(n0); | ||
| 897 | unsigned i1 = U2I(n1); | ||
| 898 | if (i0 != i1) | ||
| 899 | { | ||
| 900 | if (p->FreeList[i1] != 0) | ||
| 901 | { | ||
| 902 | void *ptr = RemoveNode(p, i1); | ||
| 903 | p->MinContext->Union4.Stats = STATS_REF(ptr); | ||
| 904 | MyMem12Cpy(ptr, (const void *)stats, n1); | ||
| 905 | InsertNode(p, stats, i0); | ||
| 906 | } | ||
| 907 | else | ||
| 908 | SplitBlock(p, stats, i0, i1); | ||
| 909 | } | ||
| 910 | } | ||
| 911 | } | ||
| 912 | { | ||
| 913 | CPpmd7_Context *mc = p->MinContext; | ||
| 914 | mc->Union2.SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); | ||
| 915 | // Escape_Freq halving here | ||
| 916 | p->FoundState = STATS(mc); | ||
| 917 | } | ||
| 918 | } | ||
| 919 | |||
| 920 | |||
| 921 | CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) | ||
| 922 | { | ||
| 923 | CPpmd_See *see; | ||
| 924 | const CPpmd7_Context *mc = p->MinContext; | ||
| 925 | unsigned numStats = mc->NumStats; | ||
| 926 | if (numStats != 256) | ||
| 927 | { | ||
| 928 | unsigned nonMasked = numStats - numMasked; | ||
| 929 | see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] | ||
| 930 | + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - numStats) | ||
| 931 | + 2 * (unsigned)(mc->Union2.SummFreq < 11 * numStats) | ||
| 932 | + 4 * (unsigned)(numMasked > nonMasked) + | ||
| 933 | p->HiBitsFlag; | ||
| 934 | { | ||
| 935 | // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ | ||
| 936 | unsigned summ = (UInt16)see->Summ; // & 0xFFFF | ||
| 937 | unsigned r = (summ >> see->Shift); | ||
| 938 | see->Summ = (UInt16)(summ - r); | ||
| 939 | *escFreq = r + (r == 0); | ||
| 940 | } | ||
| 941 | } | ||
| 942 | else | ||
| 943 | { | ||
| 944 | see = &p->DummySee; | ||
| 945 | *escFreq = 1; | ||
| 946 | } | ||
| 947 | return see; | ||
| 948 | } | ||
| 949 | |||
| 950 | |||
| 951 | static void NextContext(CPpmd7 *p) | ||
| 952 | { | ||
| 953 | CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); | ||
| 954 | if (p->OrderFall == 0 && (const Byte *)c > p->Text) | ||
| 955 | p->MaxContext = p->MinContext = c; | ||
| 956 | else | ||
| 957 | Ppmd7_UpdateModel(p); | ||
| 958 | } | ||
| 959 | |||
| 960 | |||
| 961 | void Ppmd7_Update1(CPpmd7 *p) | ||
| 962 | { | ||
| 963 | CPpmd_State *s = p->FoundState; | ||
| 964 | unsigned freq = s->Freq; | ||
| 965 | freq += 4; | ||
| 966 | p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); | ||
| 967 | s->Freq = (Byte)freq; | ||
| 968 | if (freq > s[-1].Freq) | ||
| 969 | { | ||
| 970 | SwapStates(s); | ||
| 971 | p->FoundState = --s; | ||
| 972 | if (freq > MAX_FREQ) | ||
| 973 | Rescale(p); | ||
| 974 | } | ||
| 975 | NextContext(p); | ||
| 976 | } | ||
| 977 | |||
| 978 | |||
| 979 | void Ppmd7_Update1_0(CPpmd7 *p) | ||
| 980 | { | ||
| 981 | CPpmd_State *s = p->FoundState; | ||
| 982 | CPpmd7_Context *mc = p->MinContext; | ||
| 983 | unsigned freq = s->Freq; | ||
| 984 | unsigned summFreq = mc->Union2.SummFreq; | ||
| 985 | p->PrevSuccess = (2 * freq > summFreq); | ||
| 986 | p->RunLength += (int)p->PrevSuccess; | ||
| 987 | mc->Union2.SummFreq = (UInt16)(summFreq + 4); | ||
| 988 | freq += 4; | ||
| 989 | s->Freq = (Byte)freq; | ||
| 990 | if (freq > MAX_FREQ) | ||
| 991 | Rescale(p); | ||
| 992 | NextContext(p); | ||
| 993 | } | ||
| 994 | |||
| 995 | |||
| 996 | /* | ||
| 997 | void Ppmd7_UpdateBin(CPpmd7 *p) | ||
| 998 | { | ||
| 999 | unsigned freq = p->FoundState->Freq; | ||
| 1000 | p->FoundState->Freq = (Byte)(freq + (freq < 128)); | ||
| 1001 | p->PrevSuccess = 1; | ||
| 1002 | p->RunLength++; | ||
| 1003 | NextContext(p); | ||
| 1004 | } | ||
| 1005 | */ | ||
| 1006 | |||
| 1007 | void Ppmd7_Update2(CPpmd7 *p) | ||
| 1008 | { | ||
| 1009 | CPpmd_State *s = p->FoundState; | ||
| 1010 | unsigned freq = s->Freq; | ||
| 1011 | freq += 4; | ||
| 1012 | p->RunLength = p->InitRL; | ||
| 1013 | p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); | ||
| 1014 | s->Freq = (Byte)freq; | ||
| 1015 | if (freq > MAX_FREQ) | ||
| 1016 | Rescale(p); | ||
| 1017 | Ppmd7_UpdateModel(p); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | |||
| 1021 | |||
| 1022 | /* | ||
| 1023 | PPMd Memory Map: | ||
| 1024 | { | ||
| 1025 | [ 0 ] contains subset of original raw text, that is required to create context | ||
| 1026 | records, Some symbols are not written, when max order context was reached | ||
| 1027 | [ Text ] free area | ||
| 1028 | [ UnitsStart ] CPpmd_State vectors and CPpmd7_Context records | ||
| 1029 | [ LoUnit ] free area for CPpmd_State and CPpmd7_Context items | ||
| 1030 | [ HiUnit ] CPpmd7_Context records | ||
| 1031 | [ Size ] end of array | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | These addresses don't cross at any time. | ||
| 1035 | And the following condtions is true for addresses: | ||
| 1036 | (0 <= Text < UnitsStart <= LoUnit <= HiUnit <= Size) | ||
| 1037 | |||
| 1038 | Raw text is BYTE--aligned. | ||
| 1039 | the data in block [ UnitsStart ... Size ] contains 12-bytes aligned UNITs. | ||
| 1040 | |||
| 1041 | Last UNIT of array at offset (Size - 12) is root order-0 CPpmd7_Context record. | ||
| 1042 | The code can free UNITs memory blocks that were allocated to store CPpmd_State vectors. | ||
| 1043 | The code doesn't free UNITs allocated for CPpmd7_Context records. | ||
| 1044 | |||
| 1045 | The code calls RestartModel(), when there is no free memory for allocation. | ||
| 1046 | And RestartModel() changes the state to orignal start state, with full free block. | ||
| 1047 | |||
| 1048 | |||
| 1049 | The code allocates UNITs with the following order: | ||
| 1050 | |||
| 1051 | Allocation of 1 UNIT for Context record | ||
| 1052 | - from free space (HiUnit) down to (LoUnit) | ||
| 1053 | - from FreeList[0] | ||
| 1054 | - AllocUnitsRare() | ||
| 1055 | |||
| 1056 | AllocUnits() for CPpmd_State vectors: | ||
| 1057 | - from FreeList[i] | ||
| 1058 | - from free space (LoUnit) up to (HiUnit) | ||
| 1059 | - AllocUnitsRare() | ||
| 1060 | |||
| 1061 | AllocUnitsRare() | ||
| 1062 | - if (GlueCount == 0) | ||
| 1063 | { Glue lists, GlueCount = 255, allocate from FreeList[i]] } | ||
| 1064 | - loop for all higher sized FreeList[...] lists | ||
| 1065 | - from (UnitsStart - Text), GlueCount-- | ||
| 1066 | - ERROR | ||
| 1067 | |||
| 1068 | |||
| 1069 | Each Record with Context contains the CPpmd_State vector, where each | ||
| 1070 | CPpmd_State contains the link to Successor. | ||
| 1071 | There are 3 types of Successor: | ||
| 1072 | 1) NULL-Successor - NULL pointer. NULL-Successor links can be stored | ||
| 1073 | only in 0-order Root Context Record. | ||
| 1074 | We use 0 value as NULL-Successor | ||
| 1075 | 2) RAW-Successor - the link to position in raw text, | ||
| 1076 | that "RAW-Successor" is being created after first | ||
| 1077 | occurrence of new symbol for some existing context record. | ||
| 1078 | (RAW-Successor > 0). | ||
| 1079 | 3) RECORD-Successor - the link to CPpmd7_Context record of (Order+1), | ||
| 1080 | that record is being created when we go via RAW-Successor again. | ||
| 1081 | |||
| 1082 | For any successors at any time: the following condtions are true for Successor links: | ||
| 1083 | (NULL-Successor < RAW-Successor < UnitsStart <= RECORD-Successor) | ||
| 1084 | |||
| 1085 | |||
| 1086 | ---------- Symbol Frequency, SummFreq and Range in Range_Coder ---------- | ||
| 1087 | |||
| 1088 | CPpmd7_Context::SummFreq = Sum(Stats[].Freq) + Escape_Freq | ||
| 1089 | |||
| 1090 | The PPMd code tries to fulfill the condition: | ||
| 1091 | (SummFreq <= (256 * 128 = RC::kBot)) | ||
| 1092 | |||
| 1093 | We have (Sum(Stats[].Freq) <= 256 * 124), because of (MAX_FREQ = 124) | ||
| 1094 | So (4 = 128 - 124) is average reserve for Escape_Freq for each symbol. | ||
| 1095 | If (CPpmd_State::Freq) is not aligned for 4, the reserve can be 5, 6 or 7. | ||
| 1096 | SummFreq and Escape_Freq can be changed in Rescale() and *Update*() functions. | ||
| 1097 | Rescale() can remove symbols only from max-order contexts. So Escape_Freq can increase after multiple calls of Rescale() for | ||
| 1098 | max-order context. | ||
| 1099 | |||
| 1100 | When the PPMd code still break (Total <= RC::Range) condition in range coder, | ||
| 1101 | we have two ways to resolve that problem: | ||
| 1102 | 1) we can report error, if we want to keep compatibility with original PPMd code that has no fix for such cases. | ||
| 1103 | 2) we can reduce (Total) value to (RC::Range) by reducing (Escape_Freq) part of (Total) value. | ||
| 1104 | */ | ||
diff --git a/C/Ppmd7.h b/C/Ppmd7.h new file mode 100644 index 0000000..d31809a --- /dev/null +++ b/C/Ppmd7.h | |||
| @@ -0,0 +1,181 @@ | |||
| 1 | /* Ppmd7.h -- Ppmd7 (PPMdH) compression codec | ||
| 2 | 2021-04-13 : Igor Pavlov : Public domain | ||
| 3 | This code is based on: | ||
| 4 | PPMd var.H (2001): Dmitry Shkarin : Public domain */ | ||
| 5 | |||
| 6 | |||
| 7 | #ifndef __PPMD7_H | ||
| 8 | #define __PPMD7_H | ||
| 9 | |||
| 10 | #include "Ppmd.h" | ||
| 11 | |||
| 12 | EXTERN_C_BEGIN | ||
| 13 | |||
| 14 | #define PPMD7_MIN_ORDER 2 | ||
| 15 | #define PPMD7_MAX_ORDER 64 | ||
| 16 | |||
| 17 | #define PPMD7_MIN_MEM_SIZE (1 << 11) | ||
| 18 | #define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) | ||
| 19 | |||
| 20 | struct CPpmd7_Context_; | ||
| 21 | |||
| 22 | typedef Ppmd_Ref_Type(struct CPpmd7_Context_) CPpmd7_Context_Ref; | ||
| 23 | |||
| 24 | // MY_CPU_pragma_pack_push_1 | ||
| 25 | |||
| 26 | typedef struct CPpmd7_Context_ | ||
| 27 | { | ||
| 28 | UInt16 NumStats; | ||
| 29 | |||
| 30 | |||
| 31 | union | ||
| 32 | { | ||
| 33 | UInt16 SummFreq; | ||
| 34 | CPpmd_State2 State2; | ||
| 35 | } Union2; | ||
| 36 | |||
| 37 | union | ||
| 38 | { | ||
| 39 | CPpmd_State_Ref Stats; | ||
| 40 | CPpmd_State4 State4; | ||
| 41 | } Union4; | ||
| 42 | |||
| 43 | CPpmd7_Context_Ref Suffix; | ||
| 44 | } CPpmd7_Context; | ||
| 45 | |||
| 46 | // MY_CPU_pragma_pop | ||
| 47 | |||
| 48 | #define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->Union2) | ||
| 49 | |||
| 50 | |||
| 51 | |||
| 52 | |||
| 53 | typedef struct | ||
| 54 | { | ||
| 55 | UInt32 Range; | ||
| 56 | UInt32 Code; | ||
| 57 | UInt32 Low; | ||
| 58 | IByteIn *Stream; | ||
| 59 | } CPpmd7_RangeDec; | ||
| 60 | |||
| 61 | |||
| 62 | typedef struct | ||
| 63 | { | ||
| 64 | UInt32 Range; | ||
| 65 | Byte Cache; | ||
| 66 | // Byte _dummy_[3]; | ||
| 67 | UInt64 Low; | ||
| 68 | UInt64 CacheSize; | ||
| 69 | IByteOut *Stream; | ||
| 70 | } CPpmd7z_RangeEnc; | ||
| 71 | |||
| 72 | |||
| 73 | typedef struct | ||
| 74 | { | ||
| 75 | CPpmd7_Context *MinContext, *MaxContext; | ||
| 76 | CPpmd_State *FoundState; | ||
| 77 | unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; | ||
| 78 | Int32 RunLength, InitRL; /* must be 32-bit at least */ | ||
| 79 | |||
| 80 | UInt32 Size; | ||
| 81 | UInt32 GlueCount; | ||
| 82 | UInt32 AlignOffset; | ||
| 83 | Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; | ||
| 84 | |||
| 85 | |||
| 86 | |||
| 87 | |||
| 88 | union | ||
| 89 | { | ||
| 90 | CPpmd7_RangeDec dec; | ||
| 91 | CPpmd7z_RangeEnc enc; | ||
| 92 | } rc; | ||
| 93 | |||
| 94 | Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment | ||
| 95 | Byte Units2Indx[128]; | ||
| 96 | CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; | ||
| 97 | |||
| 98 | Byte NS2BSIndx[256], NS2Indx[256]; | ||
| 99 | Byte ExpEscape[16]; | ||
| 100 | CPpmd_See DummySee, See[25][16]; | ||
| 101 | UInt16 BinSumm[128][64]; | ||
| 102 | // int LastSymbol; | ||
| 103 | } CPpmd7; | ||
| 104 | |||
| 105 | |||
| 106 | void Ppmd7_Construct(CPpmd7 *p); | ||
| 107 | BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc); | ||
| 108 | void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc); | ||
| 109 | void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); | ||
| 110 | #define Ppmd7_WasAllocated(p) ((p)->Base != NULL) | ||
| 111 | |||
| 112 | |||
| 113 | /* ---------- Internal Functions ---------- */ | ||
| 114 | |||
| 115 | #define Ppmd7_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr) | ||
| 116 | #define Ppmd7_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd7_Context) | ||
| 117 | #define Ppmd7_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State) | ||
| 118 | |||
| 119 | void Ppmd7_Update1(CPpmd7 *p); | ||
| 120 | void Ppmd7_Update1_0(CPpmd7 *p); | ||
| 121 | void Ppmd7_Update2(CPpmd7 *p); | ||
| 122 | |||
| 123 | #define PPMD7_HiBitsFlag_3(sym) ((((unsigned)sym + 0xC0) >> (8 - 3)) & (1 << 3)) | ||
| 124 | #define PPMD7_HiBitsFlag_4(sym) ((((unsigned)sym + 0xC0) >> (8 - 4)) & (1 << 4)) | ||
| 125 | // #define PPMD7_HiBitsFlag_3(sym) ((sym) < 0x40 ? 0 : (1 << 3)) | ||
| 126 | // #define PPMD7_HiBitsFlag_4(sym) ((sym) < 0x40 ? 0 : (1 << 4)) | ||
| 127 | |||
| 128 | #define Ppmd7_GetBinSumm(p) \ | ||
| 129 | &p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1] \ | ||
| 130 | [ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \ | ||
| 131 | + p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] \ | ||
| 132 | + PPMD7_HiBitsFlag_4(Ppmd7Context_OneState(p->MinContext)->Symbol) \ | ||
| 133 | + (p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol)) ] | ||
| 134 | |||
| 135 | CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); | ||
| 136 | |||
| 137 | |||
| 138 | /* | ||
| 139 | We support two versions of Ppmd7 (PPMdH) methods that use same CPpmd7 structure: | ||
| 140 | 1) Ppmd7a_*: original PPMdH | ||
| 141 | 2) Ppmd7z_*: modified PPMdH with 7z Range Coder | ||
| 142 | Ppmd7_*: the structures and functions that are common for both versions of PPMd7 (PPMdH) | ||
| 143 | */ | ||
| 144 | |||
| 145 | /* ---------- Decode ---------- */ | ||
| 146 | |||
| 147 | #define PPMD7_SYM_END (-1) | ||
| 148 | #define PPMD7_SYM_ERROR (-2) | ||
| 149 | |||
| 150 | /* | ||
| 151 | You must set (CPpmd7::rc.dec.Stream) before Ppmd7*_RangeDec_Init() | ||
| 152 | |||
| 153 | Ppmd7*_DecodeSymbol() | ||
| 154 | out: | ||
| 155 | >= 0 : decoded byte | ||
| 156 | -1 : PPMD7_SYM_END : End of payload marker | ||
| 157 | -2 : PPMD7_SYM_ERROR : Data error | ||
| 158 | */ | ||
| 159 | |||
| 160 | /* Ppmd7a_* : original PPMdH */ | ||
| 161 | BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p); | ||
| 162 | #define Ppmd7a_RangeDec_IsFinishedOK(p) ((p)->Code == 0) | ||
| 163 | int Ppmd7a_DecodeSymbol(CPpmd7 *p); | ||
| 164 | |||
| 165 | /* Ppmd7z_* : modified PPMdH with 7z Range Coder */ | ||
| 166 | BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p); | ||
| 167 | #define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) | ||
| 168 | int Ppmd7z_DecodeSymbol(CPpmd7 *p); | ||
| 169 | // Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim); | ||
| 170 | |||
| 171 | |||
| 172 | /* ---------- Encode ---------- */ | ||
| 173 | |||
| 174 | void Ppmd7z_Init_RangeEnc(CPpmd7 *p); | ||
| 175 | void Ppmd7z_Flush_RangeEnc(CPpmd7 *p); | ||
| 176 | // void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol); | ||
| 177 | void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim); | ||
| 178 | |||
| 179 | EXTERN_C_END | ||
| 180 | |||
| 181 | #endif | ||
diff --git a/C/Ppmd7Dec.c b/C/Ppmd7Dec.c new file mode 100644 index 0000000..55d74ff --- /dev/null +++ b/C/Ppmd7Dec.c | |||
| @@ -0,0 +1,297 @@ | |||
| 1 | /* Ppmd7Dec.c -- Ppmd7z (PPMdH with 7z Range Coder) Decoder | ||
| 2 | 2021-04-13 : Igor Pavlov : Public domain | ||
| 3 | This code is based on: | ||
| 4 | PPMd var.H (2001): Dmitry Shkarin : Public domain */ | ||
| 5 | |||
| 6 | |||
| 7 | #include "Precomp.h" | ||
| 8 | |||
| 9 | #include "Ppmd7.h" | ||
| 10 | |||
| 11 | #define kTopValue (1 << 24) | ||
| 12 | |||
| 13 | |||
| 14 | #define READ_BYTE(p) IByteIn_Read((p)->Stream) | ||
| 15 | |||
| 16 | BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p) | ||
| 17 | { | ||
| 18 | unsigned i; | ||
| 19 | p->Code = 0; | ||
| 20 | p->Range = 0xFFFFFFFF; | ||
| 21 | if (READ_BYTE(p) != 0) | ||
| 22 | return False; | ||
| 23 | for (i = 0; i < 4; i++) | ||
| 24 | p->Code = (p->Code << 8) | READ_BYTE(p); | ||
| 25 | return (p->Code < 0xFFFFFFFF); | ||
| 26 | } | ||
| 27 | |||
| 28 | #define RC_NORM_BASE(p) if ((p)->Range < kTopValue) \ | ||
| 29 | { (p)->Code = ((p)->Code << 8) | READ_BYTE(p); (p)->Range <<= 8; | ||
| 30 | |||
| 31 | #define RC_NORM_1(p) RC_NORM_BASE(p) } | ||
| 32 | #define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }} | ||
| 33 | |||
| 34 | // we must use only one type of Normalization from two: LOCAL or REMOTE | ||
| 35 | #define RC_NORM_LOCAL(p) // RC_NORM(p) | ||
| 36 | #define RC_NORM_REMOTE(p) RC_NORM(p) | ||
| 37 | |||
| 38 | #define R (&p->rc.dec) | ||
| 39 | |||
| 40 | MY_FORCE_INLINE | ||
| 41 | // MY_NO_INLINE | ||
| 42 | static void RangeDec_Decode(CPpmd7 *p, UInt32 start, UInt32 size) | ||
| 43 | { | ||
| 44 | |||
| 45 | |||
| 46 | R->Code -= start * R->Range; | ||
| 47 | R->Range *= size; | ||
| 48 | RC_NORM_LOCAL(R) | ||
| 49 | } | ||
| 50 | |||
| 51 | #define RC_Decode(start, size) RangeDec_Decode(p, start, size); | ||
| 52 | #define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R) | ||
| 53 | #define RC_GetThreshold(total) (R->Code / (R->Range /= (total))) | ||
| 54 | |||
| 55 | |||
| 56 | #define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) | ||
| 57 | typedef CPpmd7_Context * CTX_PTR; | ||
| 58 | #define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) | ||
| 59 | void Ppmd7_UpdateModel(CPpmd7 *p); | ||
| 60 | |||
| 61 | #define MASK(sym) ((unsigned char *)charMask)[sym] | ||
| 62 | // MY_FORCE_INLINE | ||
| 63 | // static | ||
| 64 | int Ppmd7z_DecodeSymbol(CPpmd7 *p) | ||
| 65 | { | ||
| 66 | size_t charMask[256 / sizeof(size_t)]; | ||
| 67 | |||
| 68 | if (p->MinContext->NumStats != 1) | ||
| 69 | { | ||
| 70 | CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); | ||
| 71 | unsigned i; | ||
| 72 | UInt32 count, hiCnt; | ||
| 73 | UInt32 summFreq = p->MinContext->Union2.SummFreq; | ||
| 74 | |||
| 75 | |||
| 76 | |||
| 77 | |||
| 78 | count = RC_GetThreshold(summFreq); | ||
| 79 | hiCnt = count; | ||
| 80 | |||
| 81 | if ((Int32)(count -= s->Freq) < 0) | ||
| 82 | { | ||
| 83 | Byte sym; | ||
| 84 | RC_DecodeFinal(0, s->Freq); | ||
| 85 | p->FoundState = s; | ||
| 86 | sym = s->Symbol; | ||
| 87 | Ppmd7_Update1_0(p); | ||
| 88 | return sym; | ||
| 89 | } | ||
| 90 | |||
| 91 | p->PrevSuccess = 0; | ||
| 92 | i = (unsigned)p->MinContext->NumStats - 1; | ||
| 93 | |||
| 94 | do | ||
| 95 | { | ||
| 96 | if ((Int32)(count -= (++s)->Freq) < 0) | ||
| 97 | { | ||
| 98 | Byte sym; | ||
| 99 | RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq); | ||
| 100 | p->FoundState = s; | ||
| 101 | sym = s->Symbol; | ||
| 102 | Ppmd7_Update1(p); | ||
| 103 | return sym; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | while (--i); | ||
| 107 | |||
| 108 | if (hiCnt >= summFreq) | ||
| 109 | return PPMD7_SYM_ERROR; | ||
| 110 | |||
| 111 | hiCnt -= count; | ||
| 112 | RC_Decode(hiCnt, summFreq - hiCnt); | ||
| 113 | |||
| 114 | p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); | ||
| 115 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
| 116 | // i = p->MinContext->NumStats - 1; | ||
| 117 | // do { MASK((--s)->Symbol) = 0; } while (--i); | ||
| 118 | { | ||
| 119 | CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); | ||
| 120 | MASK(s->Symbol) = 0; | ||
| 121 | do | ||
| 122 | { | ||
| 123 | unsigned sym0 = s2[0].Symbol; | ||
| 124 | unsigned sym1 = s2[1].Symbol; | ||
| 125 | s2 += 2; | ||
| 126 | MASK(sym0) = 0; | ||
| 127 | MASK(sym1) = 0; | ||
| 128 | } | ||
| 129 | while (s2 < s); | ||
| 130 | } | ||
| 131 | } | ||
| 132 | else | ||
| 133 | { | ||
| 134 | CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); | ||
| 135 | UInt16 *prob = Ppmd7_GetBinSumm(p); | ||
| 136 | UInt32 pr = *prob; | ||
| 137 | UInt32 size0 = (R->Range >> 14) * pr; | ||
| 138 | pr = PPMD_UPDATE_PROB_1(pr); | ||
| 139 | |||
| 140 | if (R->Code < size0) | ||
| 141 | { | ||
| 142 | Byte sym; | ||
| 143 | *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); | ||
| 144 | |||
| 145 | // RangeDec_DecodeBit0(size0); | ||
| 146 | R->Range = size0; | ||
| 147 | RC_NORM_1(R) | ||
| 148 | /* we can use single byte normalization here because of | ||
| 149 | (min(BinSumm[][]) = 95) > (1 << (14 - 8)) */ | ||
| 150 | |||
| 151 | // sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; | ||
| 152 | // Ppmd7_UpdateBin(p); | ||
| 153 | { | ||
| 154 | unsigned freq = s->Freq; | ||
| 155 | CTX_PTR c = CTX(SUCCESSOR(s)); | ||
| 156 | sym = s->Symbol; | ||
| 157 | p->FoundState = s; | ||
| 158 | p->PrevSuccess = 1; | ||
| 159 | p->RunLength++; | ||
| 160 | s->Freq = (Byte)(freq + (freq < 128)); | ||
| 161 | // NextContext(p); | ||
| 162 | if (p->OrderFall == 0 && (const Byte *)c > p->Text) | ||
| 163 | p->MaxContext = p->MinContext = c; | ||
| 164 | else | ||
| 165 | Ppmd7_UpdateModel(p); | ||
| 166 | } | ||
| 167 | return sym; | ||
| 168 | } | ||
| 169 | |||
| 170 | *prob = (UInt16)pr; | ||
| 171 | p->InitEsc = p->ExpEscape[pr >> 10]; | ||
| 172 | |||
| 173 | // RangeDec_DecodeBit1(size0); | ||
| 174 | |||
| 175 | R->Code -= size0; | ||
| 176 | R->Range -= size0; | ||
| 177 | RC_NORM_LOCAL(R) | ||
| 178 | |||
| 179 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
| 180 | MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; | ||
| 181 | p->PrevSuccess = 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | for (;;) | ||
| 185 | { | ||
| 186 | CPpmd_State *s, *s2; | ||
| 187 | UInt32 freqSum, count, hiCnt; | ||
| 188 | |||
| 189 | CPpmd_See *see; | ||
| 190 | CPpmd7_Context *mc; | ||
| 191 | unsigned numMasked; | ||
| 192 | RC_NORM_REMOTE(R) | ||
| 193 | mc = p->MinContext; | ||
| 194 | numMasked = mc->NumStats; | ||
| 195 | |||
| 196 | do | ||
| 197 | { | ||
| 198 | p->OrderFall++; | ||
| 199 | if (!mc->Suffix) | ||
| 200 | return PPMD7_SYM_END; | ||
| 201 | mc = Ppmd7_GetContext(p, mc->Suffix); | ||
| 202 | } | ||
| 203 | while (mc->NumStats == numMasked); | ||
| 204 | |||
| 205 | s = Ppmd7_GetStats(p, mc); | ||
| 206 | |||
| 207 | { | ||
| 208 | unsigned num = mc->NumStats; | ||
| 209 | unsigned num2 = num / 2; | ||
| 210 | |||
| 211 | num &= 1; | ||
| 212 | hiCnt = (s->Freq & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num); | ||
| 213 | s += num; | ||
| 214 | p->MinContext = mc; | ||
| 215 | |||
| 216 | do | ||
| 217 | { | ||
| 218 | unsigned sym0 = s[0].Symbol; | ||
| 219 | unsigned sym1 = s[1].Symbol; | ||
| 220 | s += 2; | ||
| 221 | hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0))); | ||
| 222 | hiCnt += (s[-1].Freq & (unsigned)(MASK(sym1))); | ||
| 223 | } | ||
| 224 | while (--num2); | ||
| 225 | } | ||
| 226 | |||
| 227 | see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); | ||
| 228 | freqSum += hiCnt; | ||
| 229 | |||
| 230 | |||
| 231 | |||
| 232 | |||
| 233 | count = RC_GetThreshold(freqSum); | ||
| 234 | |||
| 235 | if (count < hiCnt) | ||
| 236 | { | ||
| 237 | Byte sym; | ||
| 238 | |||
| 239 | s = Ppmd7_GetStats(p, p->MinContext); | ||
| 240 | hiCnt = count; | ||
| 241 | // count -= s->Freq & (unsigned)(MASK(s->Symbol)); | ||
| 242 | // if ((Int32)count >= 0) | ||
| 243 | { | ||
| 244 | for (;;) | ||
| 245 | { | ||
| 246 | count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; | ||
| 247 | // count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; | ||
| 248 | }; | ||
| 249 | } | ||
| 250 | s--; | ||
| 251 | RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq); | ||
| 252 | |||
| 253 | // new (see->Summ) value can overflow over 16-bits in some rare cases | ||
| 254 | Ppmd_See_Update(see); | ||
| 255 | p->FoundState = s; | ||
| 256 | sym = s->Symbol; | ||
| 257 | Ppmd7_Update2(p); | ||
| 258 | return sym; | ||
| 259 | } | ||
| 260 | |||
| 261 | if (count >= freqSum) | ||
| 262 | return PPMD7_SYM_ERROR; | ||
| 263 | |||
| 264 | RC_Decode(hiCnt, freqSum - hiCnt); | ||
| 265 | |||
| 266 | // We increase (see->Summ) for sum of Freqs of all non_Masked symbols. | ||
| 267 | // new (see->Summ) value can overflow over 16-bits in some rare cases | ||
| 268 | see->Summ = (UInt16)(see->Summ + freqSum); | ||
| 269 | |||
| 270 | s = Ppmd7_GetStats(p, p->MinContext); | ||
| 271 | s2 = s + p->MinContext->NumStats; | ||
| 272 | do | ||
| 273 | { | ||
| 274 | MASK(s->Symbol) = 0; | ||
| 275 | s++; | ||
| 276 | } | ||
| 277 | while (s != s2); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | /* | ||
| 282 | Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim) | ||
| 283 | { | ||
| 284 | int sym = 0; | ||
| 285 | if (buf != lim) | ||
| 286 | do | ||
| 287 | { | ||
| 288 | sym = Ppmd7z_DecodeSymbol(p); | ||
| 289 | if (sym < 0) | ||
| 290 | break; | ||
| 291 | *buf = (Byte)sym; | ||
| 292 | } | ||
| 293 | while (++buf < lim); | ||
| 294 | p->LastSymbol = sym; | ||
| 295 | return buf; | ||
| 296 | } | ||
| 297 | */ | ||
diff --git a/C/Ppmd7Enc.c b/C/Ppmd7Enc.c new file mode 100644 index 0000000..62139c5 --- /dev/null +++ b/C/Ppmd7Enc.c | |||
| @@ -0,0 +1,323 @@ | |||
| 1 | /* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder | ||
| 2 | 2021-04-13 : Igor Pavlov : Public domain | ||
| 3 | This code is based on: | ||
| 4 | PPMd var.H (2001): Dmitry Shkarin : Public domain */ | ||
| 5 | |||
| 6 | |||
| 7 | #include "Precomp.h" | ||
| 8 | |||
| 9 | #include "Ppmd7.h" | ||
| 10 | |||
| 11 | #define kTopValue (1 << 24) | ||
| 12 | |||
| 13 | #define R (&p->rc.enc) | ||
| 14 | |||
| 15 | void Ppmd7z_Init_RangeEnc(CPpmd7 *p) | ||
| 16 | { | ||
| 17 | R->Low = 0; | ||
| 18 | R->Range = 0xFFFFFFFF; | ||
| 19 | R->Cache = 0; | ||
| 20 | R->CacheSize = 1; | ||
| 21 | } | ||
| 22 | |||
| 23 | MY_NO_INLINE | ||
| 24 | static void RangeEnc_ShiftLow(CPpmd7 *p) | ||
| 25 | { | ||
| 26 | if ((UInt32)R->Low < (UInt32)0xFF000000 || (unsigned)(R->Low >> 32) != 0) | ||
| 27 | { | ||
| 28 | Byte temp = R->Cache; | ||
| 29 | do | ||
| 30 | { | ||
| 31 | IByteOut_Write(R->Stream, (Byte)(temp + (Byte)(R->Low >> 32))); | ||
| 32 | temp = 0xFF; | ||
| 33 | } | ||
| 34 | while (--R->CacheSize != 0); | ||
| 35 | R->Cache = (Byte)((UInt32)R->Low >> 24); | ||
| 36 | } | ||
| 37 | R->CacheSize++; | ||
| 38 | R->Low = (UInt32)((UInt32)R->Low << 8); | ||
| 39 | } | ||
| 40 | |||
| 41 | #define RC_NORM_BASE(p) if (R->Range < kTopValue) { R->Range <<= 8; RangeEnc_ShiftLow(p); | ||
| 42 | #define RC_NORM_1(p) RC_NORM_BASE(p) } | ||
| 43 | #define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }} | ||
| 44 | |||
| 45 | // we must use only one type of Normalization from two: LOCAL or REMOTE | ||
| 46 | #define RC_NORM_LOCAL(p) // RC_NORM(p) | ||
| 47 | #define RC_NORM_REMOTE(p) RC_NORM(p) | ||
| 48 | |||
| 49 | /* | ||
| 50 | #define RangeEnc_Encode(p, start, _size_) \ | ||
| 51 | { UInt32 size = _size_; \ | ||
| 52 | R->Low += start * R->Range; \ | ||
| 53 | R->Range *= size; \ | ||
| 54 | RC_NORM_LOCAL(p); } | ||
| 55 | */ | ||
| 56 | |||
| 57 | MY_FORCE_INLINE | ||
| 58 | // MY_NO_INLINE | ||
| 59 | static void RangeEnc_Encode(CPpmd7 *p, UInt32 start, UInt32 size) | ||
| 60 | { | ||
| 61 | R->Low += start * R->Range; | ||
| 62 | R->Range *= size; | ||
| 63 | RC_NORM_LOCAL(p); | ||
| 64 | } | ||
| 65 | |||
| 66 | void Ppmd7z_Flush_RangeEnc(CPpmd7 *p) | ||
| 67 | { | ||
| 68 | unsigned i; | ||
| 69 | for (i = 0; i < 5; i++) | ||
| 70 | RangeEnc_ShiftLow(p); | ||
| 71 | } | ||
| 72 | |||
| 73 | |||
| 74 | |||
| 75 | #define RC_Encode(start, size) RangeEnc_Encode(p, start, size); | ||
| 76 | #define RC_EncodeFinal(start, size) RC_Encode(start, size); RC_NORM_REMOTE(p); | ||
| 77 | |||
| 78 | #define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) | ||
| 79 | #define SUFFIX(ctx) CTX((ctx)->Suffix) | ||
| 80 | typedef CPpmd7_Context * CTX_PTR; | ||
| 81 | #define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) | ||
| 82 | |||
| 83 | void Ppmd7_UpdateModel(CPpmd7 *p); | ||
| 84 | |||
| 85 | #define MASK(sym) ((unsigned char *)charMask)[sym] | ||
| 86 | |||
| 87 | MY_FORCE_INLINE | ||
| 88 | static | ||
| 89 | void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol) | ||
| 90 | { | ||
| 91 | size_t charMask[256 / sizeof(size_t)]; | ||
| 92 | |||
| 93 | if (p->MinContext->NumStats != 1) | ||
| 94 | { | ||
| 95 | CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); | ||
| 96 | UInt32 sum; | ||
| 97 | unsigned i; | ||
| 98 | |||
| 99 | |||
| 100 | |||
| 101 | |||
| 102 | R->Range /= p->MinContext->Union2.SummFreq; | ||
| 103 | |||
| 104 | if (s->Symbol == symbol) | ||
| 105 | { | ||
| 106 | // R->Range /= p->MinContext->Union2.SummFreq; | ||
| 107 | RC_EncodeFinal(0, s->Freq); | ||
| 108 | p->FoundState = s; | ||
| 109 | Ppmd7_Update1_0(p); | ||
| 110 | return; | ||
| 111 | } | ||
| 112 | p->PrevSuccess = 0; | ||
| 113 | sum = s->Freq; | ||
| 114 | i = (unsigned)p->MinContext->NumStats - 1; | ||
| 115 | do | ||
| 116 | { | ||
| 117 | if ((++s)->Symbol == symbol) | ||
| 118 | { | ||
| 119 | // R->Range /= p->MinContext->Union2.SummFreq; | ||
| 120 | RC_EncodeFinal(sum, s->Freq); | ||
| 121 | p->FoundState = s; | ||
| 122 | Ppmd7_Update1(p); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | sum += s->Freq; | ||
| 126 | } | ||
| 127 | while (--i); | ||
| 128 | |||
| 129 | // R->Range /= p->MinContext->Union2.SummFreq; | ||
| 130 | RC_Encode(sum, p->MinContext->Union2.SummFreq - sum); | ||
| 131 | |||
| 132 | p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); | ||
| 133 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
| 134 | // MASK(s->Symbol) = 0; | ||
| 135 | // i = p->MinContext->NumStats - 1; | ||
| 136 | // do { MASK((--s)->Symbol) = 0; } while (--i); | ||
| 137 | { | ||
| 138 | CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); | ||
| 139 | MASK(s->Symbol) = 0; | ||
| 140 | do | ||
| 141 | { | ||
| 142 | unsigned sym0 = s2[0].Symbol; | ||
| 143 | unsigned sym1 = s2[1].Symbol; | ||
| 144 | s2 += 2; | ||
| 145 | MASK(sym0) = 0; | ||
| 146 | MASK(sym1) = 0; | ||
| 147 | } | ||
| 148 | while (s2 < s); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | else | ||
| 152 | { | ||
| 153 | UInt16 *prob = Ppmd7_GetBinSumm(p); | ||
| 154 | CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); | ||
| 155 | UInt32 pr = *prob; | ||
| 156 | UInt32 bound = (R->Range >> 14) * pr; | ||
| 157 | pr = PPMD_UPDATE_PROB_1(pr); | ||
| 158 | if (s->Symbol == symbol) | ||
| 159 | { | ||
| 160 | *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); | ||
| 161 | // RangeEnc_EncodeBit_0(p, bound); | ||
| 162 | R->Range = bound; | ||
| 163 | RC_NORM_1(p); | ||
| 164 | |||
| 165 | // p->FoundState = s; | ||
| 166 | // Ppmd7_UpdateBin(p); | ||
| 167 | { | ||
| 168 | unsigned freq = s->Freq; | ||
| 169 | CTX_PTR c = CTX(SUCCESSOR(s)); | ||
| 170 | p->FoundState = s; | ||
| 171 | p->PrevSuccess = 1; | ||
| 172 | p->RunLength++; | ||
| 173 | s->Freq = (Byte)(freq + (freq < 128)); | ||
| 174 | // NextContext(p); | ||
| 175 | if (p->OrderFall == 0 && (const Byte *)c > p->Text) | ||
| 176 | p->MaxContext = p->MinContext = c; | ||
| 177 | else | ||
| 178 | Ppmd7_UpdateModel(p); | ||
| 179 | } | ||
| 180 | return; | ||
| 181 | } | ||
| 182 | |||
| 183 | *prob = (UInt16)pr; | ||
| 184 | p->InitEsc = p->ExpEscape[pr >> 10]; | ||
| 185 | // RangeEnc_EncodeBit_1(p, bound); | ||
| 186 | R->Low += bound; | ||
| 187 | R->Range -= bound; | ||
| 188 | RC_NORM_LOCAL(p) | ||
| 189 | |||
| 190 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
| 191 | MASK(s->Symbol) = 0; | ||
| 192 | p->PrevSuccess = 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | for (;;) | ||
| 196 | { | ||
| 197 | CPpmd_See *see; | ||
| 198 | CPpmd_State *s; | ||
| 199 | UInt32 sum, escFreq; | ||
| 200 | CPpmd7_Context *mc; | ||
| 201 | unsigned i, numMasked; | ||
| 202 | |||
| 203 | RC_NORM_REMOTE(p) | ||
| 204 | |||
| 205 | mc = p->MinContext; | ||
| 206 | numMasked = mc->NumStats; | ||
| 207 | |||
| 208 | do | ||
| 209 | { | ||
| 210 | p->OrderFall++; | ||
| 211 | if (!mc->Suffix) | ||
| 212 | return; /* EndMarker (symbol = -1) */ | ||
| 213 | mc = Ppmd7_GetContext(p, mc->Suffix); | ||
| 214 | i = mc->NumStats; | ||
| 215 | } | ||
| 216 | while (i == numMasked); | ||
| 217 | |||
| 218 | p->MinContext = mc; | ||
| 219 | |||
| 220 | // see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq); | ||
| 221 | { | ||
| 222 | if (i != 256) | ||
| 223 | { | ||
| 224 | unsigned nonMasked = i - numMasked; | ||
| 225 | see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] | ||
| 226 | + p->HiBitsFlag | ||
| 227 | + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - i) | ||
| 228 | + 2 * (unsigned)(mc->Union2.SummFreq < 11 * i) | ||
| 229 | + 4 * (unsigned)(numMasked > nonMasked); | ||
| 230 | { | ||
| 231 | // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ | ||
| 232 | unsigned summ = (UInt16)see->Summ; // & 0xFFFF | ||
| 233 | unsigned r = (summ >> see->Shift); | ||
| 234 | see->Summ = (UInt16)(summ - r); | ||
| 235 | escFreq = r + (r == 0); | ||
| 236 | } | ||
| 237 | } | ||
| 238 | else | ||
| 239 | { | ||
| 240 | see = &p->DummySee; | ||
| 241 | escFreq = 1; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | s = Ppmd7_GetStats(p, mc); | ||
| 246 | sum = 0; | ||
| 247 | // i = mc->NumStats; | ||
| 248 | |||
| 249 | do | ||
| 250 | { | ||
| 251 | unsigned cur = s->Symbol; | ||
| 252 | if ((int)cur == symbol) | ||
| 253 | { | ||
| 254 | UInt32 low = sum; | ||
| 255 | UInt32 freq = s->Freq; | ||
| 256 | unsigned num2; | ||
| 257 | |||
| 258 | Ppmd_See_Update(see); | ||
| 259 | p->FoundState = s; | ||
| 260 | sum += escFreq; | ||
| 261 | |||
| 262 | num2 = i / 2; | ||
| 263 | i &= 1; | ||
| 264 | sum += freq & (0 - (UInt32)i); | ||
| 265 | if (num2 != 0) | ||
| 266 | { | ||
| 267 | s += i; | ||
| 268 | for (;;) | ||
| 269 | { | ||
| 270 | unsigned sym0 = s[0].Symbol; | ||
| 271 | unsigned sym1 = s[1].Symbol; | ||
| 272 | s += 2; | ||
| 273 | sum += (s[-2].Freq & (unsigned)(MASK(sym0))); | ||
| 274 | sum += (s[-1].Freq & (unsigned)(MASK(sym1))); | ||
| 275 | if (--num2 == 0) | ||
| 276 | break; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | |||
| 281 | R->Range /= sum; | ||
| 282 | RC_EncodeFinal(low, freq); | ||
| 283 | Ppmd7_Update2(p); | ||
| 284 | return; | ||
| 285 | } | ||
| 286 | sum += (s->Freq & (unsigned)(MASK(cur))); | ||
| 287 | s++; | ||
| 288 | } | ||
| 289 | while (--i); | ||
| 290 | |||
| 291 | { | ||
| 292 | UInt32 total = sum + escFreq; | ||
| 293 | see->Summ = (UInt16)(see->Summ + total); | ||
| 294 | |||
| 295 | R->Range /= total; | ||
| 296 | RC_Encode(sum, escFreq); | ||
| 297 | } | ||
| 298 | |||
| 299 | { | ||
| 300 | CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); | ||
| 301 | s--; | ||
| 302 | MASK(s->Symbol) = 0; | ||
| 303 | do | ||
| 304 | { | ||
| 305 | unsigned sym0 = s2[0].Symbol; | ||
| 306 | unsigned sym1 = s2[1].Symbol; | ||
| 307 | s2 += 2; | ||
| 308 | MASK(sym0) = 0; | ||
| 309 | MASK(sym1) = 0; | ||
| 310 | } | ||
| 311 | while (s2 < s); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | |||
| 317 | void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim) | ||
| 318 | { | ||
| 319 | for (; buf < lim; buf++) | ||
| 320 | { | ||
| 321 | Ppmd7z_EncodeSymbol(p, *buf); | ||
| 322 | } | ||
| 323 | } | ||
diff --git a/C/Ppmd7aDec.c b/C/Ppmd7aDec.c new file mode 100644 index 0000000..c424578 --- /dev/null +++ b/C/Ppmd7aDec.c | |||
| @@ -0,0 +1,279 @@ | |||
| 1 | /* Ppmd7aDec.c -- PPMd7a (PPMdH) Decoder | ||
| 2 | 2021-04-13 : Igor Pavlov : Public domain | ||
| 3 | This code is based on: | ||
| 4 | PPMd var.H (2001): Dmitry Shkarin : Public domain | ||
| 5 | Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ | ||
| 6 | |||
| 7 | #include "Precomp.h" | ||
| 8 | |||
| 9 | #include "Ppmd7.h" | ||
| 10 | |||
| 11 | #define kTop (1 << 24) | ||
| 12 | #define kBot (1 << 15) | ||
| 13 | |||
| 14 | #define READ_BYTE(p) IByteIn_Read((p)->Stream) | ||
| 15 | |||
| 16 | BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p) | ||
| 17 | { | ||
| 18 | unsigned i; | ||
| 19 | p->Code = 0; | ||
| 20 | p->Range = 0xFFFFFFFF; | ||
| 21 | p->Low = 0; | ||
| 22 | |||
| 23 | for (i = 0; i < 4; i++) | ||
| 24 | p->Code = (p->Code << 8) | READ_BYTE(p); | ||
| 25 | return (p->Code < 0xFFFFFFFF); | ||
| 26 | } | ||
| 27 | |||
| 28 | #define RC_NORM(p) \ | ||
| 29 | while ((p->Low ^ (p->Low + p->Range)) < kTop \ | ||
| 30 | || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) { \ | ||
| 31 | p->Code = (p->Code << 8) | READ_BYTE(p); \ | ||
| 32 | p->Range <<= 8; p->Low <<= 8; } | ||
| 33 | |||
| 34 | // we must use only one type of Normalization from two: LOCAL or REMOTE | ||
| 35 | #define RC_NORM_LOCAL(p) // RC_NORM(p) | ||
| 36 | #define RC_NORM_REMOTE(p) RC_NORM(p) | ||
| 37 | |||
| 38 | #define R (&p->rc.dec) | ||
| 39 | |||
| 40 | MY_FORCE_INLINE | ||
| 41 | // MY_NO_INLINE | ||
| 42 | static void RangeDec_Decode(CPpmd7 *p, UInt32 start, UInt32 size) | ||
| 43 | { | ||
| 44 | start *= R->Range; | ||
| 45 | R->Low += start; | ||
| 46 | R->Code -= start; | ||
| 47 | R->Range *= size; | ||
| 48 | RC_NORM_LOCAL(R) | ||
| 49 | } | ||
| 50 | |||
| 51 | #define RC_Decode(start, size) RangeDec_Decode(p, start, size); | ||
| 52 | #define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R) | ||
| 53 | #define RC_GetThreshold(total) (R->Code / (R->Range /= (total))) | ||
| 54 | |||
| 55 | |||
| 56 | #define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) | ||
| 57 | typedef CPpmd7_Context * CTX_PTR; | ||
| 58 | #define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) | ||
| 59 | void Ppmd7_UpdateModel(CPpmd7 *p); | ||
| 60 | |||
| 61 | #define MASK(sym) ((unsigned char *)charMask)[sym] | ||
| 62 | |||
| 63 | |||
| 64 | int Ppmd7a_DecodeSymbol(CPpmd7 *p) | ||
| 65 | { | ||
| 66 | size_t charMask[256 / sizeof(size_t)]; | ||
| 67 | |||
| 68 | if (p->MinContext->NumStats != 1) | ||
| 69 | { | ||
| 70 | CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); | ||
| 71 | unsigned i; | ||
| 72 | UInt32 count, hiCnt; | ||
| 73 | UInt32 summFreq = p->MinContext->Union2.SummFreq; | ||
| 74 | |||
| 75 | if (summFreq > R->Range) | ||
| 76 | return PPMD7_SYM_ERROR; | ||
| 77 | |||
| 78 | count = RC_GetThreshold(summFreq); | ||
| 79 | hiCnt = count; | ||
| 80 | |||
| 81 | if ((Int32)(count -= s->Freq) < 0) | ||
| 82 | { | ||
| 83 | Byte sym; | ||
| 84 | RC_DecodeFinal(0, s->Freq); | ||
| 85 | p->FoundState = s; | ||
| 86 | sym = s->Symbol; | ||
| 87 | Ppmd7_Update1_0(p); | ||
| 88 | return sym; | ||
| 89 | } | ||
| 90 | |||
| 91 | p->PrevSuccess = 0; | ||
| 92 | i = (unsigned)p->MinContext->NumStats - 1; | ||
| 93 | |||
| 94 | do | ||
| 95 | { | ||
| 96 | if ((Int32)(count -= (++s)->Freq) < 0) | ||
| 97 | { | ||
| 98 | Byte sym; | ||
| 99 | RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq); | ||
| 100 | p->FoundState = s; | ||
| 101 | sym = s->Symbol; | ||
| 102 | Ppmd7_Update1(p); | ||
| 103 | return sym; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | while (--i); | ||
| 107 | |||
| 108 | if (hiCnt >= summFreq) | ||
| 109 | return PPMD7_SYM_ERROR; | ||
| 110 | |||
| 111 | hiCnt -= count; | ||
| 112 | RC_Decode(hiCnt, summFreq - hiCnt); | ||
| 113 | |||
| 114 | p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); | ||
| 115 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
| 116 | // i = p->MinContext->NumStats - 1; | ||
| 117 | // do { MASK((--s)->Symbol) = 0; } while (--i); | ||
| 118 | { | ||
| 119 | CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); | ||
| 120 | MASK(s->Symbol) = 0; | ||
| 121 | do | ||
| 122 | { | ||
| 123 | unsigned sym0 = s2[0].Symbol; | ||
| 124 | unsigned sym1 = s2[1].Symbol; | ||
| 125 | s2 += 2; | ||
| 126 | MASK(sym0) = 0; | ||
| 127 | MASK(sym1) = 0; | ||
| 128 | } | ||
| 129 | while (s2 < s); | ||
| 130 | } | ||
| 131 | } | ||
| 132 | else | ||
| 133 | { | ||
| 134 | CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); | ||
| 135 | UInt16 *prob = Ppmd7_GetBinSumm(p); | ||
| 136 | UInt32 pr = *prob; | ||
| 137 | UInt32 size0 = (R->Range >> 14) * pr; | ||
| 138 | pr = PPMD_UPDATE_PROB_1(pr); | ||
| 139 | |||
| 140 | if (R->Code < size0) | ||
| 141 | { | ||
| 142 | Byte sym; | ||
| 143 | *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); | ||
| 144 | |||
| 145 | // RangeDec_DecodeBit0(size0); | ||
| 146 | R->Range = size0; | ||
| 147 | RC_NORM(R) | ||
| 148 | |||
| 149 | |||
| 150 | |||
| 151 | // sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; | ||
| 152 | // Ppmd7_UpdateBin(p); | ||
| 153 | { | ||
| 154 | unsigned freq = s->Freq; | ||
| 155 | CTX_PTR c = CTX(SUCCESSOR(s)); | ||
| 156 | sym = s->Symbol; | ||
| 157 | p->FoundState = s; | ||
| 158 | p->PrevSuccess = 1; | ||
| 159 | p->RunLength++; | ||
| 160 | s->Freq = (Byte)(freq + (freq < 128)); | ||
| 161 | // NextContext(p); | ||
| 162 | if (p->OrderFall == 0 && (const Byte *)c > p->Text) | ||
| 163 | p->MaxContext = p->MinContext = c; | ||
| 164 | else | ||
| 165 | Ppmd7_UpdateModel(p); | ||
| 166 | } | ||
| 167 | return sym; | ||
| 168 | } | ||
| 169 | |||
| 170 | *prob = (UInt16)pr; | ||
| 171 | p->InitEsc = p->ExpEscape[pr >> 10]; | ||
| 172 | |||
| 173 | // RangeDec_DecodeBit1(size0); | ||
| 174 | R->Low += size0; | ||
| 175 | R->Code -= size0; | ||
| 176 | R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - size0; | ||
| 177 | RC_NORM_LOCAL(R) | ||
| 178 | |||
| 179 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
| 180 | MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; | ||
| 181 | p->PrevSuccess = 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | for (;;) | ||
| 185 | { | ||
| 186 | CPpmd_State *s, *s2; | ||
| 187 | UInt32 freqSum, count, hiCnt; | ||
| 188 | |||
| 189 | CPpmd_See *see; | ||
| 190 | CPpmd7_Context *mc; | ||
| 191 | unsigned numMasked; | ||
| 192 | RC_NORM_REMOTE(R) | ||
| 193 | mc = p->MinContext; | ||
| 194 | numMasked = mc->NumStats; | ||
| 195 | |||
| 196 | do | ||
| 197 | { | ||
| 198 | p->OrderFall++; | ||
| 199 | if (!mc->Suffix) | ||
| 200 | return PPMD7_SYM_END; | ||
| 201 | mc = Ppmd7_GetContext(p, mc->Suffix); | ||
| 202 | } | ||
| 203 | while (mc->NumStats == numMasked); | ||
| 204 | |||
| 205 | s = Ppmd7_GetStats(p, mc); | ||
| 206 | |||
| 207 | { | ||
| 208 | unsigned num = mc->NumStats; | ||
| 209 | unsigned num2 = num / 2; | ||
| 210 | |||
| 211 | num &= 1; | ||
| 212 | hiCnt = (s->Freq & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num); | ||
| 213 | s += num; | ||
| 214 | p->MinContext = mc; | ||
| 215 | |||
| 216 | do | ||
| 217 | { | ||
| 218 | unsigned sym0 = s[0].Symbol; | ||
| 219 | unsigned sym1 = s[1].Symbol; | ||
| 220 | s += 2; | ||
| 221 | hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0))); | ||
| 222 | hiCnt += (s[-1].Freq & (unsigned)(MASK(sym1))); | ||
| 223 | } | ||
| 224 | while (--num2); | ||
| 225 | } | ||
| 226 | |||
| 227 | see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); | ||
| 228 | freqSum += hiCnt; | ||
| 229 | |||
| 230 | if (freqSum > R->Range) | ||
| 231 | return PPMD7_SYM_ERROR; | ||
| 232 | |||
| 233 | count = RC_GetThreshold(freqSum); | ||
| 234 | |||
| 235 | if (count < hiCnt) | ||
| 236 | { | ||
| 237 | Byte sym; | ||
| 238 | |||
| 239 | s = Ppmd7_GetStats(p, p->MinContext); | ||
| 240 | hiCnt = count; | ||
| 241 | // count -= s->Freq & (unsigned)(MASK(s->Symbol)); | ||
| 242 | // if ((Int32)count >= 0) | ||
| 243 | { | ||
| 244 | for (;;) | ||
| 245 | { | ||
| 246 | count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; | ||
| 247 | // count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; | ||
| 248 | }; | ||
| 249 | } | ||
| 250 | s--; | ||
| 251 | RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq); | ||
| 252 | |||
| 253 | // new (see->Summ) value can overflow over 16-bits in some rare cases | ||
| 254 | Ppmd_See_Update(see); | ||
| 255 | p->FoundState = s; | ||
| 256 | sym = s->Symbol; | ||
| 257 | Ppmd7_Update2(p); | ||
| 258 | return sym; | ||
| 259 | } | ||
| 260 | |||
| 261 | if (count >= freqSum) | ||
| 262 | return PPMD7_SYM_ERROR; | ||
| 263 | |||
| 264 | RC_Decode(hiCnt, freqSum - hiCnt); | ||
| 265 | |||
| 266 | // We increase (see->Summ) for sum of Freqs of all non_Masked symbols. | ||
| 267 | // new (see->Summ) value can overflow over 16-bits in some rare cases | ||
| 268 | see->Summ = (UInt16)(see->Summ + freqSum); | ||
| 269 | |||
| 270 | s = Ppmd7_GetStats(p, p->MinContext); | ||
| 271 | s2 = s + p->MinContext->NumStats; | ||
| 272 | do | ||
| 273 | { | ||
| 274 | MASK(s->Symbol) = 0; | ||
| 275 | s++; | ||
| 276 | } | ||
| 277 | while (s != s2); | ||
| 278 | } | ||
| 279 | } | ||
diff --git a/C/Ppmd8.c b/C/Ppmd8.c new file mode 100644 index 0000000..fda8b88 --- /dev/null +++ b/C/Ppmd8.c | |||
| @@ -0,0 +1,1537 @@ | |||
| 1 | /* Ppmd8.c -- PPMdI codec | ||
| 2 | 2021-04-13 : Igor Pavlov : Public domain | ||
| 3 | This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ | ||
| 4 | |||
| 5 | #include "Precomp.h" | ||
| 6 | |||
| 7 | #include <string.h> | ||
| 8 | |||
| 9 | #include "Ppmd8.h" | ||
| 10 | |||
| 11 | |||
| 12 | |||
| 13 | |||
| 14 | MY_ALIGN(16) | ||
| 15 | static const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; | ||
| 16 | MY_ALIGN(16) | ||
| 17 | static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; | ||
| 18 | |||
| 19 | #define MAX_FREQ 124 | ||
| 20 | #define UNIT_SIZE 12 | ||
| 21 | |||
| 22 | #define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) | ||
| 23 | #define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1]) | ||
| 24 | #define I2U(indx) ((unsigned)p->Indx2Units[indx]) | ||
| 25 | |||
| 26 | |||
| 27 | #define REF(ptr) Ppmd_GetRef(p, ptr) | ||
| 28 | |||
| 29 | #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) | ||
| 30 | |||
| 31 | #define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) | ||
| 32 | #define STATS(ctx) Ppmd8_GetStats(p, ctx) | ||
| 33 | #define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) | ||
| 34 | #define SUFFIX(ctx) CTX((ctx)->Suffix) | ||
| 35 | |||
| 36 | typedef CPpmd8_Context * CTX_PTR; | ||
| 37 | |||
| 38 | struct CPpmd8_Node_; | ||
| 39 | |||
| 40 | typedef Ppmd_Ref_Type(struct CPpmd8_Node_) CPpmd8_Node_Ref; | ||
| 41 | |||
| 42 | typedef struct CPpmd8_Node_ | ||
| 43 | { | ||
| 44 | UInt32 Stamp; | ||
| 45 | |||
| 46 | CPpmd8_Node_Ref Next; | ||
| 47 | UInt32 NU; | ||
| 48 | } CPpmd8_Node; | ||
| 49 | |||
| 50 | #define NODE(r) Ppmd_GetPtr_Type(p, r, CPpmd8_Node) | ||
| 51 | |||
| 52 | void Ppmd8_Construct(CPpmd8 *p) | ||
| 53 | { | ||
| 54 | unsigned i, k, m; | ||
| 55 | |||
| 56 | p->Base = NULL; | ||
| 57 | |||
| 58 | for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) | ||
| 59 | { | ||
| 60 | unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); | ||
| 61 | do { p->Units2Indx[k++] = (Byte)i; } while (--step); | ||
| 62 | p->Indx2Units[i] = (Byte)k; | ||
| 63 | } | ||
| 64 | |||
| 65 | p->NS2BSIndx[0] = (0 << 1); | ||
| 66 | p->NS2BSIndx[1] = (1 << 1); | ||
| 67 | memset(p->NS2BSIndx + 2, (2 << 1), 9); | ||
| 68 | memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); | ||
| 69 | |||
| 70 | for (i = 0; i < 5; i++) | ||
| 71 | p->NS2Indx[i] = (Byte)i; | ||
| 72 | |||
| 73 | for (m = i, k = 1; i < 260; i++) | ||
| 74 | { | ||
| 75 | p->NS2Indx[i] = (Byte)m; | ||
| 76 | if (--k == 0) | ||
| 77 | k = (++m) - 4; | ||
| 78 | } | ||
| 79 | |||
| 80 | memcpy(p->ExpEscape, PPMD8_kExpEscape, 16); | ||
| 81 | } | ||
| 82 | |||
| 83 | |||
| 84 | void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc) | ||
| 85 | { | ||
| 86 | ISzAlloc_Free(alloc, p->Base); | ||
| 87 | p->Size = 0; | ||
| 88 | p->Base = NULL; | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc) | ||
| 93 | { | ||
| 94 | if (!p->Base || p->Size != size) | ||
| 95 | { | ||
| 96 | Ppmd8_Free(p, alloc); | ||
| 97 | p->AlignOffset = (4 - size) & 3; | ||
| 98 | if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == NULL) | ||
| 99 | return False; | ||
| 100 | p->Size = size; | ||
| 101 | } | ||
| 102 | return True; | ||
| 103 | } | ||
| 104 | |||
| 105 | |||
| 106 | |||
| 107 | // ---------- Internal Memory Allocator ---------- | ||
| 108 | |||
| 109 | |||
| 110 | |||
| 111 | |||
| 112 | |||
| 113 | |||
| 114 | #define EMPTY_NODE 0xFFFFFFFF | ||
| 115 | |||
| 116 | |||
| 117 | static void InsertNode(CPpmd8 *p, void *node, unsigned indx) | ||
| 118 | { | ||
| 119 | ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; | ||
| 120 | ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; | ||
| 121 | ((CPpmd8_Node *)node)->NU = I2U(indx); | ||
| 122 | p->FreeList[indx] = REF(node); | ||
| 123 | p->Stamps[indx]++; | ||
| 124 | } | ||
| 125 | |||
| 126 | |||
| 127 | static void *RemoveNode(CPpmd8 *p, unsigned indx) | ||
| 128 | { | ||
| 129 | CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); | ||
| 130 | p->FreeList[indx] = node->Next; | ||
| 131 | p->Stamps[indx]--; | ||
| 132 | |||
| 133 | return node; | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) | ||
| 138 | { | ||
| 139 | unsigned i, nu = I2U(oldIndx) - I2U(newIndx); | ||
| 140 | ptr = (Byte *)ptr + U2B(I2U(newIndx)); | ||
| 141 | if (I2U(i = U2I(nu)) != nu) | ||
| 142 | { | ||
| 143 | unsigned k = I2U(--i); | ||
| 144 | InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); | ||
| 145 | } | ||
| 146 | InsertNode(p, ptr, i); | ||
| 147 | } | ||
| 148 | |||
| 149 | |||
| 150 | |||
| 151 | |||
| 152 | |||
| 153 | |||
| 154 | |||
| 155 | |||
| 156 | |||
| 157 | |||
| 158 | |||
| 159 | |||
| 160 | |||
| 161 | |||
| 162 | static void GlueFreeBlocks(CPpmd8 *p) | ||
| 163 | { | ||
| 164 | /* | ||
| 165 | we use first UInt32 field of 12-bytes UNITs as record type stamp | ||
| 166 | CPpmd_State { Byte Symbol; Byte Freq; : Freq != 0xFF | ||
| 167 | CPpmd8_Context { Byte NumStats; Byte Flags; UInt16 SummFreq; : Flags != 0xFF ??? | ||
| 168 | CPpmd8_Node { UInt32 Stamp : Stamp == 0xFFFFFFFF for free record | ||
| 169 | : Stamp == 0 for guard | ||
| 170 | Last 12-bytes UNIT in array is always contains 12-bytes order-0 CPpmd8_Context record | ||
| 171 | */ | ||
| 172 | CPpmd8_Node_Ref n; | ||
| 173 | |||
| 174 | p->GlueCount = 1 << 13; | ||
| 175 | memset(p->Stamps, 0, sizeof(p->Stamps)); | ||
| 176 | |||
| 177 | /* we set guard NODE at LoUnit */ | ||
| 178 | if (p->LoUnit != p->HiUnit) | ||
| 179 | ((CPpmd8_Node *)(void *)p->LoUnit)->Stamp = 0; | ||
| 180 | |||
| 181 | { | ||
| 182 | /* Glue free blocks */ | ||
| 183 | CPpmd8_Node_Ref *prev = &n; | ||
| 184 | unsigned i; | ||
| 185 | for (i = 0; i < PPMD_NUM_INDEXES; i++) | ||
| 186 | { | ||
| 187 | |||
| 188 | CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; | ||
| 189 | p->FreeList[i] = 0; | ||
| 190 | while (next != 0) | ||
| 191 | { | ||
| 192 | CPpmd8_Node *node = NODE(next); | ||
| 193 | UInt32 nu = node->NU; | ||
| 194 | *prev = next; | ||
| 195 | next = node->Next; | ||
| 196 | if (nu != 0) | ||
| 197 | { | ||
| 198 | CPpmd8_Node *node2; | ||
| 199 | prev = &(node->Next); | ||
| 200 | while ((node2 = node + nu)->Stamp == EMPTY_NODE) | ||
| 201 | { | ||
| 202 | nu += node2->NU; | ||
| 203 | node2->NU = 0; | ||
| 204 | node->NU = nu; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | *prev = 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | |||
| 214 | |||
| 215 | |||
| 216 | |||
| 217 | |||
| 218 | |||
| 219 | |||
| 220 | |||
| 221 | |||
| 222 | |||
| 223 | |||
| 224 | |||
| 225 | |||
| 226 | |||
| 227 | |||
| 228 | |||
| 229 | |||
| 230 | |||
| 231 | |||
| 232 | /* Fill lists of free blocks */ | ||
| 233 | while (n != 0) | ||
| 234 | { | ||
| 235 | CPpmd8_Node *node = NODE(n); | ||
| 236 | UInt32 nu = node->NU; | ||
| 237 | unsigned i; | ||
| 238 | n = node->Next; | ||
| 239 | if (nu == 0) | ||
| 240 | continue; | ||
| 241 | for (; nu > 128; nu -= 128, node += 128) | ||
| 242 | InsertNode(p, node, PPMD_NUM_INDEXES - 1); | ||
| 243 | if (I2U(i = U2I(nu)) != nu) | ||
| 244 | { | ||
| 245 | unsigned k = I2U(--i); | ||
| 246 | InsertNode(p, node + k, (unsigned)nu - k - 1); | ||
| 247 | } | ||
| 248 | InsertNode(p, node, i); | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | |||
| 253 | MY_NO_INLINE | ||
| 254 | static void *AllocUnitsRare(CPpmd8 *p, unsigned indx) | ||
| 255 | { | ||
| 256 | unsigned i; | ||
| 257 | |||
| 258 | if (p->GlueCount == 0) | ||
| 259 | { | ||
| 260 | GlueFreeBlocks(p); | ||
| 261 | if (p->FreeList[indx] != 0) | ||
| 262 | return RemoveNode(p, indx); | ||
| 263 | } | ||
| 264 | |||
| 265 | i = indx; | ||
| 266 | |||
| 267 | do | ||
| 268 | { | ||
| 269 | if (++i == PPMD_NUM_INDEXES) | ||
| 270 | { | ||
| 271 | UInt32 numBytes = U2B(I2U(indx)); | ||
| 272 | Byte *us = p->UnitsStart; | ||
| 273 | p->GlueCount--; | ||
| 274 | return ((UInt32)(us - p->Text) > numBytes) ? (p->UnitsStart = us - numBytes) : (NULL); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | while (p->FreeList[i] == 0); | ||
| 278 | |||
| 279 | { | ||
| 280 | void *block = RemoveNode(p, i); | ||
| 281 | SplitBlock(p, block, i, indx); | ||
| 282 | return block; | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | |||
| 287 | static void *AllocUnits(CPpmd8 *p, unsigned indx) | ||
| 288 | { | ||
| 289 | if (p->FreeList[indx] != 0) | ||
| 290 | return RemoveNode(p, indx); | ||
| 291 | { | ||
| 292 | UInt32 numBytes = U2B(I2U(indx)); | ||
| 293 | Byte *lo = p->LoUnit; | ||
| 294 | if ((UInt32)(p->HiUnit - lo) >= numBytes) | ||
| 295 | { | ||
| 296 | p->LoUnit = lo + numBytes; | ||
| 297 | return lo; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | return AllocUnitsRare(p, indx); | ||
| 301 | } | ||
| 302 | |||
| 303 | |||
| 304 | #define MyMem12Cpy(dest, src, num) \ | ||
| 305 | { UInt32 *d = (UInt32 *)dest; const UInt32 *z = (const UInt32 *)src; UInt32 n = num; \ | ||
| 306 | do { d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; } while (--n); } | ||
| 307 | |||
| 308 | |||
| 309 | |||
| 310 | static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU) | ||
| 311 | { | ||
| 312 | unsigned i0 = U2I(oldNU); | ||
| 313 | unsigned i1 = U2I(newNU); | ||
| 314 | if (i0 == i1) | ||
| 315 | return oldPtr; | ||
| 316 | if (p->FreeList[i1] != 0) | ||
| 317 | { | ||
| 318 | void *ptr = RemoveNode(p, i1); | ||
| 319 | MyMem12Cpy(ptr, oldPtr, newNU); | ||
| 320 | InsertNode(p, oldPtr, i0); | ||
| 321 | return ptr; | ||
| 322 | } | ||
| 323 | SplitBlock(p, oldPtr, i0, i1); | ||
| 324 | return oldPtr; | ||
| 325 | } | ||
| 326 | |||
| 327 | |||
| 328 | static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) | ||
| 329 | { | ||
| 330 | InsertNode(p, ptr, U2I(nu)); | ||
| 331 | } | ||
| 332 | |||
| 333 | |||
| 334 | static void SpecialFreeUnit(CPpmd8 *p, void *ptr) | ||
| 335 | { | ||
| 336 | if ((Byte *)ptr != p->UnitsStart) | ||
| 337 | InsertNode(p, ptr, 0); | ||
| 338 | else | ||
| 339 | { | ||
| 340 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 341 | *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts() */ | ||
| 342 | #endif | ||
| 343 | p->UnitsStart += UNIT_SIZE; | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | |||
| 348 | /* | ||
| 349 | static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) | ||
| 350 | { | ||
| 351 | unsigned indx = U2I(nu); | ||
| 352 | void *ptr; | ||
| 353 | if ((Byte *)oldPtr > p->UnitsStart + (1 << 14) || REF(oldPtr) > p->FreeList[indx]) | ||
| 354 | return oldPtr; | ||
| 355 | ptr = RemoveNode(p, indx); | ||
| 356 | MyMem12Cpy(ptr, oldPtr, nu); | ||
| 357 | if ((Byte *)oldPtr != p->UnitsStart) | ||
| 358 | InsertNode(p, oldPtr, indx); | ||
| 359 | else | ||
| 360 | p->UnitsStart += U2B(I2U(indx)); | ||
| 361 | return ptr; | ||
| 362 | } | ||
| 363 | */ | ||
| 364 | |||
| 365 | static void ExpandTextArea(CPpmd8 *p) | ||
| 366 | { | ||
| 367 | UInt32 count[PPMD_NUM_INDEXES]; | ||
| 368 | unsigned i; | ||
| 369 | |||
| 370 | memset(count, 0, sizeof(count)); | ||
| 371 | if (p->LoUnit != p->HiUnit) | ||
| 372 | ((CPpmd8_Node *)(void *)p->LoUnit)->Stamp = 0; | ||
| 373 | |||
| 374 | { | ||
| 375 | CPpmd8_Node *node = (CPpmd8_Node *)(void *)p->UnitsStart; | ||
| 376 | while (node->Stamp == EMPTY_NODE) | ||
| 377 | { | ||
| 378 | UInt32 nu = node->NU; | ||
| 379 | node->Stamp = 0; | ||
| 380 | count[U2I(nu)]++; | ||
| 381 | node += nu; | ||
| 382 | } | ||
| 383 | p->UnitsStart = (Byte *)node; | ||
| 384 | } | ||
| 385 | |||
| 386 | for (i = 0; i < PPMD_NUM_INDEXES; i++) | ||
| 387 | { | ||
| 388 | UInt32 cnt = count[i]; | ||
| 389 | if (cnt == 0) | ||
| 390 | continue; | ||
| 391 | { | ||
| 392 | CPpmd8_Node_Ref *prev = (CPpmd8_Node_Ref *)&p->FreeList[i]; | ||
| 393 | CPpmd8_Node_Ref n = *prev; | ||
| 394 | p->Stamps[i] -= cnt; | ||
| 395 | for (;;) | ||
| 396 | { | ||
| 397 | CPpmd8_Node *node = NODE(n); | ||
| 398 | n = node->Next; | ||
| 399 | if (node->Stamp != 0) | ||
| 400 | { | ||
| 401 | prev = &node->Next; | ||
| 402 | continue; | ||
| 403 | } | ||
| 404 | *prev = n; | ||
| 405 | if (--cnt == 0) | ||
| 406 | break; | ||
| 407 | } | ||
| 408 | } | ||
| 409 | } | ||
| 410 | } | ||
| 411 | |||
| 412 | |||
| 413 | #define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) | ||
| 414 | static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) | ||
| 415 | { | ||
| 416 | Ppmd_SET_SUCCESSOR(p, v); | ||
| 417 | } | ||
| 418 | |||
| 419 | #define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); } | ||
| 420 | |||
| 421 | MY_NO_INLINE | ||
| 422 | static | ||
| 423 | void RestartModel(CPpmd8 *p) | ||
| 424 | { | ||
| 425 | unsigned i, k, m; | ||
| 426 | |||
| 427 | memset(p->FreeList, 0, sizeof(p->FreeList)); | ||
| 428 | memset(p->Stamps, 0, sizeof(p->Stamps)); | ||
| 429 | RESET_TEXT(0); | ||
| 430 | p->HiUnit = p->Text + p->Size; | ||
| 431 | p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; | ||
| 432 | p->GlueCount = 0; | ||
| 433 | |||
| 434 | p->OrderFall = p->MaxOrder; | ||
| 435 | p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; | ||
| 436 | p->PrevSuccess = 0; | ||
| 437 | |||
| 438 | { | ||
| 439 | CPpmd8_Context *mc = (CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ | ||
| 440 | CPpmd_State *s = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ | ||
| 441 | |||
| 442 | p->LoUnit += U2B(256 / 2); | ||
| 443 | p->MaxContext = p->MinContext = mc; | ||
| 444 | p->FoundState = s; | ||
| 445 | mc->Flags = 0; | ||
| 446 | mc->NumStats = 256 - 1; | ||
| 447 | mc->Union2.SummFreq = 256 + 1; | ||
| 448 | mc->Union4.Stats = REF(s); | ||
| 449 | mc->Suffix = 0; | ||
| 450 | |||
| 451 | for (i = 0; i < 256; i++, s++) | ||
| 452 | { | ||
| 453 | s->Symbol = (Byte)i; | ||
| 454 | s->Freq = 1; | ||
| 455 | SetSuccessor(s, 0); | ||
| 456 | } | ||
| 457 | } | ||
| 458 | |||
| 459 | |||
| 460 | |||
| 461 | |||
| 462 | |||
| 463 | |||
| 464 | |||
| 465 | |||
| 466 | |||
| 467 | |||
| 468 | |||
| 469 | |||
| 470 | for (i = m = 0; m < 25; m++) | ||
| 471 | { | ||
| 472 | while (p->NS2Indx[i] == m) | ||
| 473 | i++; | ||
| 474 | for (k = 0; k < 8; k++) | ||
| 475 | { | ||
| 476 | unsigned r; | ||
| 477 | UInt16 *dest = p->BinSumm[m] + k; | ||
| 478 | UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1)); | ||
| 479 | for (r = 0; r < 64; r += 8) | ||
| 480 | dest[r] = val; | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | for (i = m = 0; m < 24; m++) | ||
| 485 | { | ||
| 486 | unsigned summ; | ||
| 487 | CPpmd_See *s; | ||
| 488 | while (p->NS2Indx[(size_t)i + 3] == m + 3) | ||
| 489 | i++; | ||
| 490 | s = p->See[m]; | ||
| 491 | summ = ((2 * i + 5) << (PPMD_PERIOD_BITS - 4)); | ||
| 492 | for (k = 0; k < 32; k++, s++) | ||
| 493 | { | ||
| 494 | s->Summ = (UInt16)summ; | ||
| 495 | s->Shift = (PPMD_PERIOD_BITS - 4); | ||
| 496 | s->Count = 7; | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | p->DummySee.Summ = 0; /* unused */ | ||
| 501 | p->DummySee.Shift = PPMD_PERIOD_BITS; | ||
| 502 | p->DummySee.Count = 64; /* unused */ | ||
| 503 | } | ||
| 504 | |||
| 505 | |||
| 506 | void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) | ||
| 507 | { | ||
| 508 | p->MaxOrder = maxOrder; | ||
| 509 | p->RestoreMethod = restoreMethod; | ||
| 510 | RestartModel(p); | ||
| 511 | } | ||
| 512 | |||
| 513 | |||
| 514 | #define FLAG_RESCALED (1 << 2) | ||
| 515 | // #define FLAG_SYM_HIGH (1 << 3) | ||
| 516 | #define FLAG_PREV_HIGH (1 << 4) | ||
| 517 | |||
| 518 | #define HiBits_Prepare(sym) ((unsigned)(sym) + 0xC0) | ||
| 519 | |||
| 520 | #define HiBits_Convert_3(flags) (((flags) >> (8 - 3)) & (1 << 3)) | ||
| 521 | #define HiBits_Convert_4(flags) (((flags) >> (8 - 4)) & (1 << 4)) | ||
| 522 | |||
| 523 | #define PPMD8_HiBitsFlag_3(sym) HiBits_Convert_3(HiBits_Prepare(sym)) | ||
| 524 | #define PPMD8_HiBitsFlag_4(sym) HiBits_Convert_4(HiBits_Prepare(sym)) | ||
| 525 | |||
| 526 | // #define PPMD8_HiBitsFlag_3(sym) (0x08 * ((sym) >= 0x40)) | ||
| 527 | // #define PPMD8_HiBitsFlag_4(sym) (0x10 * ((sym) >= 0x40)) | ||
| 528 | |||
| 529 | /* | ||
| 530 | Refresh() is called when we remove some symbols (successors) in context. | ||
| 531 | It increases Escape_Freq for sum of all removed symbols. | ||
| 532 | */ | ||
| 533 | |||
| 534 | static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale) | ||
| 535 | { | ||
| 536 | unsigned i = ctx->NumStats, escFreq, sumFreq, flags; | ||
| 537 | CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); | ||
| 538 | ctx->Union4.Stats = REF(s); | ||
| 539 | |||
| 540 | // #ifdef PPMD8_FREEZE_SUPPORT | ||
| 541 | /* | ||
| 542 | (ctx->Union2.SummFreq >= ((UInt32)1 << 15)) can be in FREEZE mode for some files. | ||
| 543 | It's not good for range coder. So new versions of support fix: | ||
| 544 | - original PPMdI code rev.1 | ||
| 545 | + original PPMdI code rev.2 | ||
| 546 | - 7-Zip default ((PPMD8_FREEZE_SUPPORT is not defined) | ||
| 547 | + 7-Zip (p->RestoreMethod >= PPMD8_RESTORE_METHOD_FREEZE) | ||
| 548 | if we use that fixed line, we can lose compatibility with some files created before fix | ||
| 549 | if we don't use that fixed line, the program can work incorrectly in FREEZE mode in rare case. | ||
| 550 | */ | ||
| 551 | // if (p->RestoreMethod >= PPMD8_RESTORE_METHOD_FREEZE) | ||
| 552 | { | ||
| 553 | scale |= (ctx->Union2.SummFreq >= ((UInt32)1 << 15)); | ||
| 554 | } | ||
| 555 | // #endif | ||
| 556 | |||
| 557 | |||
| 558 | |||
| 559 | flags = HiBits_Prepare(s->Symbol); | ||
| 560 | { | ||
| 561 | unsigned freq = s->Freq; | ||
| 562 | escFreq = ctx->Union2.SummFreq - freq; | ||
| 563 | freq = (freq + scale) >> scale; | ||
| 564 | sumFreq = freq; | ||
| 565 | s->Freq = (Byte)freq; | ||
| 566 | } | ||
| 567 | |||
| 568 | do | ||
| 569 | { | ||
| 570 | unsigned freq = (++s)->Freq; | ||
| 571 | escFreq -= freq; | ||
| 572 | freq = (freq + scale) >> scale; | ||
| 573 | sumFreq += freq; | ||
| 574 | s->Freq = (Byte)freq; | ||
| 575 | flags |= HiBits_Prepare(s->Symbol); | ||
| 576 | } | ||
| 577 | while (--i); | ||
| 578 | |||
| 579 | ctx->Union2.SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); | ||
| 580 | ctx->Flags = (Byte)((ctx->Flags & (FLAG_PREV_HIGH + FLAG_RESCALED * scale)) + HiBits_Convert_3(flags)); | ||
| 581 | } | ||
| 582 | |||
| 583 | |||
| 584 | static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) | ||
| 585 | { | ||
| 586 | CPpmd_State tmp = *t1; | ||
| 587 | *t1 = *t2; | ||
| 588 | *t2 = tmp; | ||
| 589 | } | ||
| 590 | |||
| 591 | |||
| 592 | /* | ||
| 593 | CutOff() reduces contexts: | ||
| 594 | It conversts Successors at MaxOrder to another Contexts to NULL-Successors | ||
| 595 | It removes RAW-Successors and NULL-Successors that are not Order-0 | ||
| 596 | and it removes contexts when it has no Successors. | ||
| 597 | if the (Union4.Stats) is close to (UnitsStart), it moves it up. | ||
| 598 | */ | ||
| 599 | |||
| 600 | static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order) | ||
| 601 | { | ||
| 602 | int ns = ctx->NumStats; | ||
| 603 | unsigned nu; | ||
| 604 | CPpmd_State *stats; | ||
| 605 | |||
| 606 | if (ns == 0) | ||
| 607 | { | ||
| 608 | CPpmd_State *s = ONE_STATE(ctx); | ||
| 609 | CPpmd_Void_Ref successor = SUCCESSOR(s); | ||
| 610 | if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart) | ||
| 611 | { | ||
| 612 | if (order < p->MaxOrder) | ||
| 613 | successor = CutOff(p, CTX(successor), order + 1); | ||
| 614 | else | ||
| 615 | successor = 0; | ||
| 616 | SetSuccessor(s, successor); | ||
| 617 | if (successor || order <= 9) /* O_BOUND */ | ||
| 618 | return REF(ctx); | ||
| 619 | } | ||
| 620 | SpecialFreeUnit(p, ctx); | ||
| 621 | return 0; | ||
| 622 | } | ||
| 623 | |||
| 624 | nu = ((unsigned)ns + 2) >> 1; | ||
| 625 | // ctx->Union4.Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), nu)); | ||
| 626 | { | ||
| 627 | unsigned indx = U2I(nu); | ||
| 628 | stats = STATS(ctx); | ||
| 629 | |||
| 630 | if ((UInt32)((Byte *)stats - p->UnitsStart) <= (1 << 14) | ||
| 631 | && (CPpmd_Void_Ref)ctx->Union4.Stats <= p->FreeList[indx]) | ||
| 632 | { | ||
| 633 | void *ptr = RemoveNode(p, indx); | ||
| 634 | ctx->Union4.Stats = STATS_REF(ptr); | ||
| 635 | MyMem12Cpy(ptr, (const void *)stats, nu); | ||
| 636 | if ((Byte *)stats != p->UnitsStart) | ||
| 637 | InsertNode(p, stats, indx); | ||
| 638 | else | ||
| 639 | p->UnitsStart += U2B(I2U(indx)); | ||
| 640 | stats = ptr; | ||
| 641 | } | ||
| 642 | } | ||
| 643 | |||
| 644 | { | ||
| 645 | CPpmd_State *s = stats + (unsigned)ns; | ||
| 646 | do | ||
| 647 | { | ||
| 648 | CPpmd_Void_Ref successor = SUCCESSOR(s); | ||
| 649 | if ((Byte *)Ppmd8_GetPtr(p, successor) < p->UnitsStart) | ||
| 650 | { | ||
| 651 | CPpmd_State *s2 = stats + (unsigned)(ns--); | ||
| 652 | if (order) | ||
| 653 | { | ||
| 654 | if (s != s2) | ||
| 655 | *s = *s2; | ||
| 656 | } | ||
| 657 | else | ||
| 658 | { | ||
| 659 | SwapStates(s, s2); | ||
| 660 | SetSuccessor(s2, 0); | ||
| 661 | } | ||
| 662 | } | ||
| 663 | else | ||
| 664 | { | ||
| 665 | if (order < p->MaxOrder) | ||
| 666 | SetSuccessor(s, CutOff(p, CTX(successor), order + 1)); | ||
| 667 | else | ||
| 668 | SetSuccessor(s, 0); | ||
| 669 | } | ||
| 670 | } | ||
| 671 | while (--s >= stats); | ||
| 672 | } | ||
| 673 | |||
| 674 | if (ns != ctx->NumStats && order) | ||
| 675 | { | ||
| 676 | if (ns < 0) | ||
| 677 | { | ||
| 678 | FreeUnits(p, stats, nu); | ||
| 679 | SpecialFreeUnit(p, ctx); | ||
| 680 | return 0; | ||
| 681 | } | ||
| 682 | ctx->NumStats = (Byte)ns; | ||
| 683 | if (ns == 0) | ||
| 684 | { | ||
| 685 | const Byte sym = stats->Symbol; | ||
| 686 | ctx->Flags = (Byte)((ctx->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(sym)); | ||
| 687 | // *ONE_STATE(ctx) = *stats; | ||
| 688 | ctx->Union2.State2.Symbol = sym; | ||
| 689 | ctx->Union2.State2.Freq = (Byte)(((unsigned)stats->Freq + 11) >> 3); | ||
| 690 | ctx->Union4.State4.Successor_0 = stats->Successor_0; | ||
| 691 | ctx->Union4.State4.Successor_1 = stats->Successor_1; | ||
| 692 | FreeUnits(p, stats, nu); | ||
| 693 | } | ||
| 694 | else | ||
| 695 | { | ||
| 696 | Refresh(p, ctx, nu, ctx->Union2.SummFreq > 16 * (unsigned)ns); | ||
| 697 | } | ||
| 698 | } | ||
| 699 | |||
| 700 | return REF(ctx); | ||
| 701 | } | ||
| 702 | |||
| 703 | |||
| 704 | |||
| 705 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 706 | |||
| 707 | /* | ||
| 708 | RemoveBinContexts() | ||
| 709 | It conversts Successors at MaxOrder to another Contexts to NULL-Successors | ||
| 710 | It changes RAW-Successors to NULL-Successors | ||
| 711 | removes Bin Context without Successor, if suffix of that context is also binary. | ||
| 712 | */ | ||
| 713 | |||
| 714 | static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order) | ||
| 715 | { | ||
| 716 | if (!ctx->NumStats) | ||
| 717 | { | ||
| 718 | CPpmd_State *s = ONE_STATE(ctx); | ||
| 719 | CPpmd_Void_Ref successor = SUCCESSOR(s); | ||
| 720 | if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart && order < p->MaxOrder) | ||
| 721 | successor = RemoveBinContexts(p, CTX(successor), order + 1); | ||
| 722 | else | ||
| 723 | successor = 0; | ||
| 724 | SetSuccessor(s, successor); | ||
| 725 | /* Suffix context can be removed already, since different (high-order) | ||
| 726 | Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */ | ||
| 727 | if (!successor && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF)) | ||
| 728 | { | ||
| 729 | FreeUnits(p, ctx, 1); | ||
| 730 | return 0; | ||
| 731 | } | ||
| 732 | } | ||
| 733 | else | ||
| 734 | { | ||
| 735 | CPpmd_State *s = STATS(ctx) + ctx->NumStats; | ||
| 736 | do | ||
| 737 | { | ||
| 738 | CPpmd_Void_Ref successor = SUCCESSOR(s); | ||
| 739 | if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart && order < p->MaxOrder) | ||
| 740 | SetSuccessor(s, RemoveBinContexts(p, CTX(successor), order + 1)); | ||
| 741 | else | ||
| 742 | SetSuccessor(s, 0); | ||
| 743 | } | ||
| 744 | while (--s >= STATS(ctx)); | ||
| 745 | } | ||
| 746 | |||
| 747 | return REF(ctx); | ||
| 748 | } | ||
| 749 | |||
| 750 | #endif | ||
| 751 | |||
| 752 | |||
| 753 | |||
| 754 | static UInt32 GetUsedMemory(const CPpmd8 *p) | ||
| 755 | { | ||
| 756 | UInt32 v = 0; | ||
| 757 | unsigned i; | ||
| 758 | for (i = 0; i < PPMD_NUM_INDEXES; i++) | ||
| 759 | v += p->Stamps[i] * I2U(i); | ||
| 760 | return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); | ||
| 761 | } | ||
| 762 | |||
| 763 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 764 | #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) | ||
| 765 | #else | ||
| 766 | #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1) | ||
| 767 | #endif | ||
| 768 | |||
| 769 | |||
| 770 | static void RestoreModel(CPpmd8 *p, CTX_PTR ctxError | ||
| 771 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 772 | , CTX_PTR fSuccessor | ||
| 773 | #endif | ||
| 774 | ) | ||
| 775 | { | ||
| 776 | CTX_PTR c; | ||
| 777 | CPpmd_State *s; | ||
| 778 | RESET_TEXT(0); | ||
| 779 | |||
| 780 | // we go here in cases of error of allocation for context (c1) | ||
| 781 | // Order(MinContext) < Order(ctxError) <= Order(MaxContext) | ||
| 782 | |||
| 783 | // We remove last symbol from each of contexts [p->MaxContext ... ctxError) contexts | ||
| 784 | // So we rollback all created (symbols) before error. | ||
| 785 | for (c = p->MaxContext; c != ctxError; c = SUFFIX(c)) | ||
| 786 | if (--(c->NumStats) == 0) | ||
| 787 | { | ||
| 788 | s = STATS(c); | ||
| 789 | c->Flags = (Byte)((c->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(s->Symbol)); | ||
| 790 | // *ONE_STATE(c) = *s; | ||
| 791 | c->Union2.State2.Symbol = s->Symbol; | ||
| 792 | c->Union2.State2.Freq = (Byte)(((unsigned)s->Freq + 11) >> 3); | ||
| 793 | c->Union4.State4.Successor_0 = s->Successor_0; | ||
| 794 | c->Union4.State4.Successor_1 = s->Successor_1; | ||
| 795 | |||
| 796 | SpecialFreeUnit(p, s); | ||
| 797 | } | ||
| 798 | else | ||
| 799 | { | ||
| 800 | /* Refresh() can increase Escape_Freq on value of Freq of last symbol, that was added before error. | ||
| 801 | so the largest possible increase for Escape_Freq is (8) from value before ModelUpoadet() */ | ||
| 802 | Refresh(p, c, ((unsigned)c->NumStats + 3) >> 1, 0); | ||
| 803 | } | ||
| 804 | |||
| 805 | // increase Escape Freq for context [ctxError ... p->MinContext) | ||
| 806 | for (; c != p->MinContext; c = SUFFIX(c)) | ||
| 807 | if (c->NumStats == 0) | ||
| 808 | { | ||
| 809 | // ONE_STATE(c) | ||
| 810 | c->Union2.State2.Freq = (Byte)(((unsigned)c->Union2.State2.Freq + 1) >> 1); | ||
| 811 | } | ||
| 812 | else if ((c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 4)) > 128 + 4 * c->NumStats) | ||
| 813 | Refresh(p, c, ((unsigned)c->NumStats + 2) >> 1, 1); | ||
| 814 | |||
| 815 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 816 | if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) | ||
| 817 | { | ||
| 818 | p->MaxContext = fSuccessor; | ||
| 819 | p->GlueCount += !(p->Stamps[1] & 1); // why? | ||
| 820 | } | ||
| 821 | else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE) | ||
| 822 | { | ||
| 823 | while (p->MaxContext->Suffix) | ||
| 824 | p->MaxContext = SUFFIX(p->MaxContext); | ||
| 825 | RemoveBinContexts(p, p->MaxContext, 0); | ||
| 826 | // we change the current mode to (PPMD8_RESTORE_METHOD_FREEZE + 1) | ||
| 827 | p->RestoreMethod = PPMD8_RESTORE_METHOD_FREEZE + 1; | ||
| 828 | p->GlueCount = 0; | ||
| 829 | p->OrderFall = p->MaxOrder; | ||
| 830 | } | ||
| 831 | else | ||
| 832 | #endif | ||
| 833 | if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) | ||
| 834 | RestartModel(p); | ||
| 835 | else | ||
| 836 | { | ||
| 837 | while (p->MaxContext->Suffix) | ||
| 838 | p->MaxContext = SUFFIX(p->MaxContext); | ||
| 839 | do | ||
| 840 | { | ||
| 841 | CutOff(p, p->MaxContext, 0); | ||
| 842 | ExpandTextArea(p); | ||
| 843 | } | ||
| 844 | while (GetUsedMemory(p) > 3 * (p->Size >> 2)); | ||
| 845 | p->GlueCount = 0; | ||
| 846 | p->OrderFall = p->MaxOrder; | ||
| 847 | } | ||
| 848 | p->MinContext = p->MaxContext; | ||
| 849 | } | ||
| 850 | |||
| 851 | |||
| 852 | |||
| 853 | MY_NO_INLINE | ||
| 854 | static CTX_PTR CreateSuccessors(CPpmd8 *p, BoolInt skip, CPpmd_State *s1, CTX_PTR c) | ||
| 855 | { | ||
| 856 | |||
| 857 | CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); | ||
| 858 | Byte newSym, newFreq, flags; | ||
| 859 | unsigned numPs = 0; | ||
| 860 | CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ | ||
| 861 | |||
| 862 | if (!skip) | ||
| 863 | ps[numPs++] = p->FoundState; | ||
| 864 | |||
| 865 | while (c->Suffix) | ||
| 866 | { | ||
| 867 | CPpmd_Void_Ref successor; | ||
| 868 | CPpmd_State *s; | ||
| 869 | c = SUFFIX(c); | ||
| 870 | |||
| 871 | if (s1) { s = s1; s1 = NULL; } | ||
| 872 | else if (c->NumStats != 0) | ||
| 873 | { | ||
| 874 | Byte sym = p->FoundState->Symbol; | ||
| 875 | for (s = STATS(c); s->Symbol != sym; s++); | ||
| 876 | if (s->Freq < MAX_FREQ - 9) { s->Freq++; c->Union2.SummFreq++; } | ||
| 877 | } | ||
| 878 | else | ||
| 879 | { | ||
| 880 | s = ONE_STATE(c); | ||
| 881 | s->Freq = (Byte)(s->Freq + (!SUFFIX(c)->NumStats & (s->Freq < 24))); | ||
| 882 | } | ||
| 883 | successor = SUCCESSOR(s); | ||
| 884 | if (successor != upBranch) | ||
| 885 | { | ||
| 886 | |||
| 887 | c = CTX(successor); | ||
| 888 | if (numPs == 0) | ||
| 889 | { | ||
| 890 | |||
| 891 | |||
| 892 | return c; | ||
| 893 | } | ||
| 894 | break; | ||
| 895 | } | ||
| 896 | ps[numPs++] = s; | ||
| 897 | } | ||
| 898 | |||
| 899 | |||
| 900 | |||
| 901 | |||
| 902 | |||
| 903 | newSym = *(const Byte *)Ppmd8_GetPtr(p, upBranch); | ||
| 904 | upBranch++; | ||
| 905 | flags = (Byte)(PPMD8_HiBitsFlag_4(p->FoundState->Symbol) + PPMD8_HiBitsFlag_3(newSym)); | ||
| 906 | |||
| 907 | if (c->NumStats == 0) | ||
| 908 | newFreq = c->Union2.State2.Freq; | ||
| 909 | else | ||
| 910 | { | ||
| 911 | UInt32 cf, s0; | ||
| 912 | CPpmd_State *s; | ||
| 913 | for (s = STATS(c); s->Symbol != newSym; s++); | ||
| 914 | cf = (UInt32)s->Freq - 1; | ||
| 915 | s0 = (UInt32)c->Union2.SummFreq - c->NumStats - cf; | ||
| 916 | /* | ||
| 917 | |||
| 918 | |||
| 919 | max(newFreq)= (s->Freq - 1), when (s0 == 1) | ||
| 920 | |||
| 921 | |||
| 922 | */ | ||
| 923 | newFreq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); | ||
| 924 | } | ||
| 925 | |||
| 926 | |||
| 927 | |||
| 928 | do | ||
| 929 | { | ||
| 930 | CTX_PTR c1; | ||
| 931 | /* = AllocContext(p); */ | ||
| 932 | if (p->HiUnit != p->LoUnit) | ||
| 933 | c1 = (CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); | ||
| 934 | else if (p->FreeList[0] != 0) | ||
| 935 | c1 = (CTX_PTR)RemoveNode(p, 0); | ||
| 936 | else | ||
| 937 | { | ||
| 938 | c1 = (CTX_PTR)AllocUnitsRare(p, 0); | ||
| 939 | if (!c1) | ||
| 940 | return NULL; | ||
| 941 | } | ||
| 942 | c1->Flags = flags; | ||
| 943 | c1->NumStats = 0; | ||
| 944 | c1->Union2.State2.Symbol = newSym; | ||
| 945 | c1->Union2.State2.Freq = newFreq; | ||
| 946 | SetSuccessor(ONE_STATE(c1), upBranch); | ||
| 947 | c1->Suffix = REF(c); | ||
| 948 | SetSuccessor(ps[--numPs], REF(c1)); | ||
| 949 | c = c1; | ||
| 950 | } | ||
| 951 | while (numPs != 0); | ||
| 952 | |||
| 953 | return c; | ||
| 954 | } | ||
| 955 | |||
| 956 | |||
| 957 | static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c) | ||
| 958 | { | ||
| 959 | CPpmd_State *s = NULL; | ||
| 960 | CTX_PTR c1 = c; | ||
| 961 | CPpmd_Void_Ref upBranch = REF(p->Text); | ||
| 962 | |||
| 963 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 964 | /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */ | ||
| 965 | CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; | ||
| 966 | unsigned numPs = 0; | ||
| 967 | ps[numPs++] = p->FoundState; | ||
| 968 | #endif | ||
| 969 | |||
| 970 | SetSuccessor(p->FoundState, upBranch); | ||
| 971 | p->OrderFall++; | ||
| 972 | |||
| 973 | for (;;) | ||
| 974 | { | ||
| 975 | if (s1) | ||
| 976 | { | ||
| 977 | c = SUFFIX(c); | ||
| 978 | s = s1; | ||
| 979 | s1 = NULL; | ||
| 980 | } | ||
| 981 | else | ||
| 982 | { | ||
| 983 | if (!c->Suffix) | ||
| 984 | { | ||
| 985 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 986 | if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) | ||
| 987 | { | ||
| 988 | do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); | ||
| 989 | RESET_TEXT(1); | ||
| 990 | p->OrderFall = 1; | ||
| 991 | } | ||
| 992 | #endif | ||
| 993 | return c; | ||
| 994 | } | ||
| 995 | c = SUFFIX(c); | ||
| 996 | if (c->NumStats) | ||
| 997 | { | ||
| 998 | if ((s = STATS(c))->Symbol != p->FoundState->Symbol) | ||
| 999 | do { s++; } while (s->Symbol != p->FoundState->Symbol); | ||
| 1000 | if (s->Freq < MAX_FREQ - 9) | ||
| 1001 | { | ||
| 1002 | s->Freq = (Byte)(s->Freq + 2); | ||
| 1003 | c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2); | ||
| 1004 | } | ||
| 1005 | } | ||
| 1006 | else | ||
| 1007 | { | ||
| 1008 | s = ONE_STATE(c); | ||
| 1009 | s->Freq = (Byte)(s->Freq + (s->Freq < 32)); | ||
| 1010 | } | ||
| 1011 | } | ||
| 1012 | if (SUCCESSOR(s)) | ||
| 1013 | break; | ||
| 1014 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 1015 | ps[numPs++] = s; | ||
| 1016 | #endif | ||
| 1017 | SetSuccessor(s, upBranch); | ||
| 1018 | p->OrderFall++; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 1022 | if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) | ||
| 1023 | { | ||
| 1024 | c = CTX(SUCCESSOR(s)); | ||
| 1025 | do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); | ||
| 1026 | RESET_TEXT(1); | ||
| 1027 | p->OrderFall = 1; | ||
| 1028 | return c; | ||
| 1029 | } | ||
| 1030 | else | ||
| 1031 | #endif | ||
| 1032 | if (SUCCESSOR(s) <= upBranch) | ||
| 1033 | { | ||
| 1034 | CTX_PTR successor; | ||
| 1035 | CPpmd_State *s2 = p->FoundState; | ||
| 1036 | p->FoundState = s; | ||
| 1037 | |||
| 1038 | successor = CreateSuccessors(p, False, NULL, c); | ||
| 1039 | if (!successor) | ||
| 1040 | SetSuccessor(s, 0); | ||
| 1041 | else | ||
| 1042 | SetSuccessor(s, REF(successor)); | ||
| 1043 | p->FoundState = s2; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | { | ||
| 1047 | CPpmd_Void_Ref successor = SUCCESSOR(s); | ||
| 1048 | if (p->OrderFall == 1 && c1 == p->MaxContext) | ||
| 1049 | { | ||
| 1050 | SetSuccessor(p->FoundState, successor); | ||
| 1051 | p->Text--; | ||
| 1052 | } | ||
| 1053 | if (successor == 0) | ||
| 1054 | return NULL; | ||
| 1055 | return CTX(successor); | ||
| 1056 | } | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | |||
| 1060 | |||
| 1061 | void Ppmd8_UpdateModel(CPpmd8 *p); | ||
| 1062 | MY_NO_INLINE | ||
| 1063 | void Ppmd8_UpdateModel(CPpmd8 *p) | ||
| 1064 | { | ||
| 1065 | CPpmd_Void_Ref maxSuccessor, minSuccessor = SUCCESSOR(p->FoundState); | ||
| 1066 | CTX_PTR c; | ||
| 1067 | unsigned s0, ns, fFreq = p->FoundState->Freq; | ||
| 1068 | Byte flag, fSymbol = p->FoundState->Symbol; | ||
| 1069 | { | ||
| 1070 | CPpmd_State *s = NULL; | ||
| 1071 | if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) | ||
| 1072 | { | ||
| 1073 | /* Update Freqs in Suffix Context */ | ||
| 1074 | |||
| 1075 | c = SUFFIX(p->MinContext); | ||
| 1076 | |||
| 1077 | if (c->NumStats == 0) | ||
| 1078 | { | ||
| 1079 | s = ONE_STATE(c); | ||
| 1080 | if (s->Freq < 32) | ||
| 1081 | s->Freq++; | ||
| 1082 | } | ||
| 1083 | else | ||
| 1084 | { | ||
| 1085 | Byte sym = p->FoundState->Symbol; | ||
| 1086 | s = STATS(c); | ||
| 1087 | |||
| 1088 | if (s->Symbol != sym) | ||
| 1089 | { | ||
| 1090 | do | ||
| 1091 | { | ||
| 1092 | |||
| 1093 | s++; | ||
| 1094 | } | ||
| 1095 | while (s->Symbol != sym); | ||
| 1096 | |||
| 1097 | if (s[0].Freq >= s[-1].Freq) | ||
| 1098 | { | ||
| 1099 | SwapStates(&s[0], &s[-1]); | ||
| 1100 | s--; | ||
| 1101 | } | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | if (s->Freq < MAX_FREQ - 9) | ||
| 1105 | { | ||
| 1106 | s->Freq = (Byte)(s->Freq + 2); | ||
| 1107 | c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2); | ||
| 1108 | } | ||
| 1109 | } | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | c = p->MaxContext; | ||
| 1113 | if (p->OrderFall == 0 && minSuccessor) | ||
| 1114 | { | ||
| 1115 | CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext); | ||
| 1116 | if (!cs) | ||
| 1117 | { | ||
| 1118 | SetSuccessor(p->FoundState, 0); | ||
| 1119 | RESTORE_MODEL(c, CTX(minSuccessor)); | ||
| 1120 | return; | ||
| 1121 | } | ||
| 1122 | SetSuccessor(p->FoundState, REF(cs)); | ||
| 1123 | p->MinContext = p->MaxContext = cs; | ||
| 1124 | return; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | |||
| 1128 | |||
| 1129 | |||
| 1130 | { | ||
| 1131 | Byte *text = p->Text; | ||
| 1132 | *text++ = p->FoundState->Symbol; | ||
| 1133 | p->Text = text; | ||
| 1134 | if (text >= p->UnitsStart) | ||
| 1135 | { | ||
| 1136 | RESTORE_MODEL(c, CTX(minSuccessor)); /* check it */ | ||
| 1137 | return; | ||
| 1138 | } | ||
| 1139 | maxSuccessor = REF(text); | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | if (!minSuccessor) | ||
| 1143 | { | ||
| 1144 | CTX_PTR cs = ReduceOrder(p, s, p->MinContext); | ||
| 1145 | if (!cs) | ||
| 1146 | { | ||
| 1147 | RESTORE_MODEL(c, NULL); | ||
| 1148 | return; | ||
| 1149 | } | ||
| 1150 | minSuccessor = REF(cs); | ||
| 1151 | } | ||
| 1152 | else if ((Byte *)Ppmd8_GetPtr(p, minSuccessor) < p->UnitsStart) | ||
| 1153 | { | ||
| 1154 | CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext); | ||
| 1155 | if (!cs) | ||
| 1156 | { | ||
| 1157 | RESTORE_MODEL(c, NULL); | ||
| 1158 | return; | ||
| 1159 | } | ||
| 1160 | minSuccessor = REF(cs); | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | if (--p->OrderFall == 0) | ||
| 1164 | { | ||
| 1165 | maxSuccessor = minSuccessor; | ||
| 1166 | p->Text -= (p->MaxContext != p->MinContext); | ||
| 1167 | } | ||
| 1168 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 1169 | else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) | ||
| 1170 | { | ||
| 1171 | maxSuccessor = minSuccessor; | ||
| 1172 | RESET_TEXT(0); | ||
| 1173 | p->OrderFall = 0; | ||
| 1174 | } | ||
| 1175 | #endif | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | |||
| 1179 | |||
| 1180 | |||
| 1181 | |||
| 1182 | |||
| 1183 | |||
| 1184 | |||
| 1185 | |||
| 1186 | |||
| 1187 | |||
| 1188 | |||
| 1189 | |||
| 1190 | |||
| 1191 | |||
| 1192 | |||
| 1193 | |||
| 1194 | |||
| 1195 | |||
| 1196 | |||
| 1197 | |||
| 1198 | |||
| 1199 | |||
| 1200 | |||
| 1201 | |||
| 1202 | |||
| 1203 | |||
| 1204 | |||
| 1205 | flag = (Byte)(PPMD8_HiBitsFlag_3(fSymbol)); | ||
| 1206 | s0 = p->MinContext->Union2.SummFreq - (ns = p->MinContext->NumStats) - fFreq; | ||
| 1207 | |||
| 1208 | for (; c != p->MinContext; c = SUFFIX(c)) | ||
| 1209 | { | ||
| 1210 | unsigned ns1; | ||
| 1211 | UInt32 sum; | ||
| 1212 | |||
| 1213 | if ((ns1 = c->NumStats) != 0) | ||
| 1214 | { | ||
| 1215 | if ((ns1 & 1) != 0) | ||
| 1216 | { | ||
| 1217 | /* Expand for one UNIT */ | ||
| 1218 | unsigned oldNU = (ns1 + 1) >> 1; | ||
| 1219 | unsigned i = U2I(oldNU); | ||
| 1220 | if (i != U2I((size_t)oldNU + 1)) | ||
| 1221 | { | ||
| 1222 | void *ptr = AllocUnits(p, i + 1); | ||
| 1223 | void *oldPtr; | ||
| 1224 | if (!ptr) | ||
| 1225 | { | ||
| 1226 | RESTORE_MODEL(c, CTX(minSuccessor)); | ||
| 1227 | return; | ||
| 1228 | } | ||
| 1229 | oldPtr = STATS(c); | ||
| 1230 | MyMem12Cpy(ptr, oldPtr, oldNU); | ||
| 1231 | InsertNode(p, oldPtr, i); | ||
| 1232 | c->Union4.Stats = STATS_REF(ptr); | ||
| 1233 | } | ||
| 1234 | } | ||
| 1235 | sum = c->Union2.SummFreq; | ||
| 1236 | /* max increase of Escape_Freq is 1 here. | ||
| 1237 | an average increase is 1/3 per symbol */ | ||
| 1238 | sum += (3 * ns1 + 1 < ns); | ||
| 1239 | /* original PPMdH uses 16-bit variable for (sum) here. | ||
| 1240 | But (sum < ???). Do we need to truncate (sum) to 16-bit */ | ||
| 1241 | // sum = (UInt16)sum; | ||
| 1242 | } | ||
| 1243 | else | ||
| 1244 | { | ||
| 1245 | |||
| 1246 | CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); | ||
| 1247 | if (!s) | ||
| 1248 | { | ||
| 1249 | RESTORE_MODEL(c, CTX(minSuccessor)); | ||
| 1250 | return; | ||
| 1251 | } | ||
| 1252 | { | ||
| 1253 | unsigned freq = c->Union2.State2.Freq; | ||
| 1254 | // s = *ONE_STATE(c); | ||
| 1255 | s->Symbol = c->Union2.State2.Symbol; | ||
| 1256 | s->Successor_0 = c->Union4.State4.Successor_0; | ||
| 1257 | s->Successor_1 = c->Union4.State4.Successor_1; | ||
| 1258 | // SetSuccessor(s, c->Union4.Stats); // call it only for debug purposes to check the order of | ||
| 1259 | // (Successor_0 and Successor_1) in LE/BE. | ||
| 1260 | c->Union4.Stats = REF(s); | ||
| 1261 | if (freq < MAX_FREQ / 4 - 1) | ||
| 1262 | freq <<= 1; | ||
| 1263 | else | ||
| 1264 | freq = MAX_FREQ - 4; | ||
| 1265 | |||
| 1266 | s->Freq = (Byte)freq; | ||
| 1267 | |||
| 1268 | sum = freq + p->InitEsc + (ns > 2); // Ppmd8 (> 2) | ||
| 1269 | } | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | { | ||
| 1273 | CPpmd_State *s = STATS(c) + ns1 + 1; | ||
| 1274 | UInt32 cf = 2 * (sum + 6) * (UInt32)fFreq; | ||
| 1275 | UInt32 sf = (UInt32)s0 + sum; | ||
| 1276 | s->Symbol = fSymbol; | ||
| 1277 | c->NumStats = (Byte)(ns1 + 1); | ||
| 1278 | SetSuccessor(s, maxSuccessor); | ||
| 1279 | c->Flags |= flag; | ||
| 1280 | if (cf < 6 * sf) | ||
| 1281 | { | ||
| 1282 | cf = (unsigned)1 + (cf > sf) + (cf >= 4 * sf); | ||
| 1283 | sum += 4; | ||
| 1284 | /* It can add (1, 2, 3) to Escape_Freq */ | ||
| 1285 | } | ||
| 1286 | else | ||
| 1287 | { | ||
| 1288 | cf = (unsigned)4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); | ||
| 1289 | sum += cf; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | c->Union2.SummFreq = (UInt16)sum; | ||
| 1293 | s->Freq = (Byte)cf; | ||
| 1294 | } | ||
| 1295 | |||
| 1296 | } | ||
| 1297 | p->MaxContext = p->MinContext = CTX(minSuccessor); | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | |||
| 1301 | |||
| 1302 | MY_NO_INLINE | ||
| 1303 | static void Rescale(CPpmd8 *p) | ||
| 1304 | { | ||
| 1305 | unsigned i, adder, sumFreq, escFreq; | ||
| 1306 | CPpmd_State *stats = STATS(p->MinContext); | ||
| 1307 | CPpmd_State *s = p->FoundState; | ||
| 1308 | |||
| 1309 | /* Sort the list by Freq */ | ||
| 1310 | if (s != stats) | ||
| 1311 | { | ||
| 1312 | CPpmd_State tmp = *s; | ||
| 1313 | do | ||
| 1314 | s[0] = s[-1]; | ||
| 1315 | while (--s != stats); | ||
| 1316 | *s = tmp; | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | sumFreq = s->Freq; | ||
| 1320 | escFreq = p->MinContext->Union2.SummFreq - sumFreq; | ||
| 1321 | |||
| 1322 | |||
| 1323 | |||
| 1324 | |||
| 1325 | |||
| 1326 | |||
| 1327 | adder = (p->OrderFall != 0); | ||
| 1328 | |||
| 1329 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 1330 | adder |= (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE); | ||
| 1331 | #endif | ||
| 1332 | |||
| 1333 | sumFreq = (sumFreq + 4 + adder) >> 1; | ||
| 1334 | i = p->MinContext->NumStats; | ||
| 1335 | s->Freq = (Byte)sumFreq; | ||
| 1336 | |||
| 1337 | do | ||
| 1338 | { | ||
| 1339 | unsigned freq = (++s)->Freq; | ||
| 1340 | escFreq -= freq; | ||
| 1341 | freq = (freq + adder) >> 1; | ||
| 1342 | sumFreq += freq; | ||
| 1343 | s->Freq = (Byte)freq; | ||
| 1344 | if (freq > s[-1].Freq) | ||
| 1345 | { | ||
| 1346 | CPpmd_State tmp = *s; | ||
| 1347 | CPpmd_State *s1 = s; | ||
| 1348 | do | ||
| 1349 | { | ||
| 1350 | s1[0] = s1[-1]; | ||
| 1351 | } | ||
| 1352 | while (--s1 != stats && freq > s1[-1].Freq); | ||
| 1353 | *s1 = tmp; | ||
| 1354 | } | ||
| 1355 | } | ||
| 1356 | while (--i); | ||
| 1357 | |||
| 1358 | if (s->Freq == 0) | ||
| 1359 | { | ||
| 1360 | /* Remove all items with Freq == 0 */ | ||
| 1361 | CPpmd8_Context *mc; | ||
| 1362 | unsigned numStats, numStatsNew, n0, n1; | ||
| 1363 | |||
| 1364 | i = 0; do { i++; } while ((--s)->Freq == 0); | ||
| 1365 | |||
| 1366 | |||
| 1367 | |||
| 1368 | |||
| 1369 | escFreq += i; | ||
| 1370 | mc = p->MinContext; | ||
| 1371 | numStats = mc->NumStats; | ||
| 1372 | numStatsNew = numStats - i; | ||
| 1373 | mc->NumStats = (Byte)(numStatsNew); | ||
| 1374 | n0 = (numStats + 2) >> 1; | ||
| 1375 | |||
| 1376 | if (numStatsNew == 0) | ||
| 1377 | { | ||
| 1378 | |||
| 1379 | unsigned freq = (2 * (unsigned)stats->Freq + escFreq - 1) / escFreq; | ||
| 1380 | if (freq > MAX_FREQ / 3) | ||
| 1381 | freq = MAX_FREQ / 3; | ||
| 1382 | mc->Flags = (Byte)((mc->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(stats->Symbol)); | ||
| 1383 | |||
| 1384 | |||
| 1385 | |||
| 1386 | |||
| 1387 | |||
| 1388 | s = ONE_STATE(mc); | ||
| 1389 | *s = *stats; | ||
| 1390 | s->Freq = (Byte)freq; | ||
| 1391 | p->FoundState = s; | ||
| 1392 | InsertNode(p, stats, U2I(n0)); | ||
| 1393 | return; | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | n1 = (numStatsNew + 2) >> 1; | ||
| 1397 | if (n0 != n1) | ||
| 1398 | mc->Union4.Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); | ||
| 1399 | { | ||
| 1400 | // here we are for max order only. So Ppmd8_MakeEscFreq() doesn't use mc->Flags | ||
| 1401 | // but we still need current (Flags & FLAG_PREV_HIGH), if we will convert context to 1-symbol context later. | ||
| 1402 | /* | ||
| 1403 | unsigned flags = HiBits_Prepare((s = STATS(mc))->Symbol); | ||
| 1404 | i = mc->NumStats; | ||
| 1405 | do { flags |= HiBits_Prepare((++s)->Symbol); } while (--i); | ||
| 1406 | mc->Flags = (Byte)((mc->Flags & ~FLAG_SYM_HIGH) + HiBits_Convert_3(flags)); | ||
| 1407 | */ | ||
| 1408 | } | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | |||
| 1412 | |||
| 1413 | |||
| 1414 | |||
| 1415 | |||
| 1416 | { | ||
| 1417 | CPpmd8_Context *mc = p->MinContext; | ||
| 1418 | mc->Union2.SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); | ||
| 1419 | mc->Flags |= FLAG_RESCALED; | ||
| 1420 | p->FoundState = STATS(mc); | ||
| 1421 | } | ||
| 1422 | } | ||
| 1423 | |||
| 1424 | |||
| 1425 | CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) | ||
| 1426 | { | ||
| 1427 | CPpmd_See *see; | ||
| 1428 | const CPpmd8_Context *mc = p->MinContext; | ||
| 1429 | unsigned numStats = mc->NumStats; | ||
| 1430 | if (numStats != 0xFF) | ||
| 1431 | { | ||
| 1432 | // (3 <= numStats + 2 <= 256) (3 <= NS2Indx[3] and NS2Indx[256] === 26) | ||
| 1433 | see = p->See[(size_t)(unsigned)p->NS2Indx[(size_t)numStats + 2] - 3] | ||
| 1434 | + (mc->Union2.SummFreq > 11 * (numStats + 1)) | ||
| 1435 | + 2 * (unsigned)(2 * numStats < ((unsigned)SUFFIX(mc)->NumStats + numMasked1)) | ||
| 1436 | + mc->Flags; | ||
| 1437 | |||
| 1438 | { | ||
| 1439 | // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ | ||
| 1440 | unsigned summ = (UInt16)see->Summ; // & 0xFFFF | ||
| 1441 | unsigned r = (summ >> see->Shift); | ||
| 1442 | see->Summ = (UInt16)(summ - r); | ||
| 1443 | *escFreq = r + (r == 0); | ||
| 1444 | } | ||
| 1445 | } | ||
| 1446 | else | ||
| 1447 | { | ||
| 1448 | see = &p->DummySee; | ||
| 1449 | *escFreq = 1; | ||
| 1450 | } | ||
| 1451 | return see; | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | |||
| 1455 | static void NextContext(CPpmd8 *p) | ||
| 1456 | { | ||
| 1457 | CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); | ||
| 1458 | if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart) | ||
| 1459 | p->MaxContext = p->MinContext = c; | ||
| 1460 | else | ||
| 1461 | Ppmd8_UpdateModel(p); | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | |||
| 1465 | void Ppmd8_Update1(CPpmd8 *p) | ||
| 1466 | { | ||
| 1467 | CPpmd_State *s = p->FoundState; | ||
| 1468 | unsigned freq = s->Freq; | ||
| 1469 | freq += 4; | ||
| 1470 | p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); | ||
| 1471 | s->Freq = (Byte)freq; | ||
| 1472 | if (freq > s[-1].Freq) | ||
| 1473 | { | ||
| 1474 | SwapStates(s, &s[-1]); | ||
| 1475 | p->FoundState = --s; | ||
| 1476 | if (freq > MAX_FREQ) | ||
| 1477 | Rescale(p); | ||
| 1478 | } | ||
| 1479 | NextContext(p); | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | |||
| 1483 | void Ppmd8_Update1_0(CPpmd8 *p) | ||
| 1484 | { | ||
| 1485 | CPpmd_State *s = p->FoundState; | ||
| 1486 | CPpmd8_Context *mc = p->MinContext; | ||
| 1487 | unsigned freq = s->Freq; | ||
| 1488 | unsigned summFreq = mc->Union2.SummFreq; | ||
| 1489 | p->PrevSuccess = (2 * freq >= summFreq); // Ppmd8 (>=) | ||
| 1490 | p->RunLength += (int)p->PrevSuccess; | ||
| 1491 | mc->Union2.SummFreq = (UInt16)(summFreq + 4); | ||
| 1492 | freq += 4; | ||
| 1493 | s->Freq = (Byte)freq; | ||
| 1494 | if (freq > MAX_FREQ) | ||
| 1495 | Rescale(p); | ||
| 1496 | NextContext(p); | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | |||
| 1500 | /* | ||
| 1501 | void Ppmd8_UpdateBin(CPpmd8 *p) | ||
| 1502 | { | ||
| 1503 | unsigned freq = p->FoundState->Freq; | ||
| 1504 | p->FoundState->Freq = (Byte)(freq + (freq < 196)); // Ppmd8 (196) | ||
| 1505 | p->PrevSuccess = 1; | ||
| 1506 | p->RunLength++; | ||
| 1507 | NextContext(p); | ||
| 1508 | } | ||
| 1509 | */ | ||
| 1510 | |||
| 1511 | void Ppmd8_Update2(CPpmd8 *p) | ||
| 1512 | { | ||
| 1513 | CPpmd_State *s = p->FoundState; | ||
| 1514 | unsigned freq = s->Freq; | ||
| 1515 | freq += 4; | ||
| 1516 | p->RunLength = p->InitRL; | ||
| 1517 | p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); | ||
| 1518 | s->Freq = (Byte)freq; | ||
| 1519 | if (freq > MAX_FREQ) | ||
| 1520 | Rescale(p); | ||
| 1521 | Ppmd8_UpdateModel(p); | ||
| 1522 | } | ||
| 1523 | |||
| 1524 | /* H->I changes: | ||
| 1525 | NS2Indx | ||
| 1526 | GlueCount, and Glue method | ||
| 1527 | BinSum | ||
| 1528 | See / EscFreq | ||
| 1529 | CreateSuccessors updates more suffix contexts | ||
| 1530 | Ppmd8_UpdateModel consts. | ||
| 1531 | PrevSuccess Update | ||
| 1532 | |||
| 1533 | Flags: | ||
| 1534 | (1 << 2) - the Context was Rescaled | ||
| 1535 | (1 << 3) - there is symbol in Stats with (sym >= 0x40) in | ||
| 1536 | (1 << 4) - main symbol of context is (sym >= 0x40) | ||
| 1537 | */ | ||
diff --git a/C/Ppmd8.h b/C/Ppmd8.h new file mode 100644 index 0000000..fe93fe7 --- /dev/null +++ b/C/Ppmd8.h | |||
| @@ -0,0 +1,181 @@ | |||
| 1 | /* Ppmd8.h -- Ppmd8 (PPMdI) compression codec | ||
| 2 | 2021-04-13 : 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 | |||
| 18 | |||
| 19 | |||
| 20 | struct CPpmd8_Context_; | ||
| 21 | |||
| 22 | typedef Ppmd_Ref_Type(struct CPpmd8_Context_) CPpmd8_Context_Ref; | ||
| 23 | |||
| 24 | // MY_CPU_pragma_pack_push_1 | ||
| 25 | |||
| 26 | typedef struct CPpmd8_Context_ | ||
| 27 | { | ||
| 28 | Byte NumStats; | ||
| 29 | Byte Flags; | ||
| 30 | |||
| 31 | union | ||
| 32 | { | ||
| 33 | UInt16 SummFreq; | ||
| 34 | CPpmd_State2 State2; | ||
| 35 | } Union2; | ||
| 36 | |||
| 37 | union | ||
| 38 | { | ||
| 39 | CPpmd_State_Ref Stats; | ||
| 40 | CPpmd_State4 State4; | ||
| 41 | } Union4; | ||
| 42 | |||
| 43 | CPpmd8_Context_Ref Suffix; | ||
| 44 | } CPpmd8_Context; | ||
| 45 | |||
| 46 | // MY_CPU_pragma_pop | ||
| 47 | |||
| 48 | #define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->Union2) | ||
| 49 | |||
| 50 | /* PPMdI code rev.2 contains the fix over PPMdI code rev.1. | ||
| 51 | But the code PPMdI.2 is not compatible with PPMdI.1 for some files compressed | ||
| 52 | in FREEZE mode. So we disable FREEZE mode support. */ | ||
| 53 | |||
| 54 | // #define PPMD8_FREEZE_SUPPORT | ||
| 55 | |||
| 56 | enum | ||
| 57 | { | ||
| 58 | PPMD8_RESTORE_METHOD_RESTART, | ||
| 59 | PPMD8_RESTORE_METHOD_CUT_OFF | ||
| 60 | #ifdef PPMD8_FREEZE_SUPPORT | ||
| 61 | , PPMD8_RESTORE_METHOD_FREEZE | ||
| 62 | #endif | ||
| 63 | , PPMD8_RESTORE_METHOD_UNSUPPPORTED | ||
| 64 | }; | ||
| 65 | |||
| 66 | |||
| 67 | |||
| 68 | |||
| 69 | |||
| 70 | |||
| 71 | |||
| 72 | |||
| 73 | typedef struct | ||
| 74 | { | ||
| 75 | CPpmd8_Context *MinContext, *MaxContext; | ||
| 76 | CPpmd_State *FoundState; | ||
| 77 | unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, RestoreMethod; | ||
| 78 | Int32 RunLength, InitRL; /* must be 32-bit at least */ | ||
| 79 | |||
| 80 | UInt32 Size; | ||
| 81 | UInt32 GlueCount; | ||
| 82 | UInt32 AlignOffset; | ||
| 83 | Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; | ||
| 84 | |||
| 85 | UInt32 Range; | ||
| 86 | UInt32 Code; | ||
| 87 | UInt32 Low; | ||
| 88 | union | ||
| 89 | { | ||
| 90 | IByteIn *In; | ||
| 91 | IByteOut *Out; | ||
| 92 | } Stream; | ||
| 93 | |||
| 94 | Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment | ||
| 95 | Byte Units2Indx[128]; | ||
| 96 | CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; | ||
| 97 | UInt32 Stamps[PPMD_NUM_INDEXES]; | ||
| 98 | Byte NS2BSIndx[256], NS2Indx[260]; | ||
| 99 | Byte ExpEscape[16]; | ||
| 100 | CPpmd_See DummySee, See[24][32]; | ||
| 101 | UInt16 BinSumm[25][64]; | ||
| 102 | |||
| 103 | } CPpmd8; | ||
| 104 | |||
| 105 | |||
| 106 | void Ppmd8_Construct(CPpmd8 *p); | ||
| 107 | BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc); | ||
| 108 | void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc); | ||
| 109 | void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod); | ||
| 110 | #define Ppmd8_WasAllocated(p) ((p)->Base != NULL) | ||
| 111 | |||
| 112 | |||
| 113 | /* ---------- Internal Functions ---------- */ | ||
| 114 | |||
| 115 | #define Ppmd8_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr) | ||
| 116 | #define Ppmd8_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd8_Context) | ||
| 117 | #define Ppmd8_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State) | ||
| 118 | |||
| 119 | void Ppmd8_Update1(CPpmd8 *p); | ||
| 120 | void Ppmd8_Update1_0(CPpmd8 *p); | ||
| 121 | void Ppmd8_Update2(CPpmd8 *p); | ||
| 122 | |||
| 123 | |||
| 124 | |||
| 125 | |||
| 126 | |||
| 127 | |||
| 128 | #define Ppmd8_GetBinSumm(p) \ | ||
| 129 | &p->BinSumm[p->NS2Indx[(size_t)Ppmd8Context_OneState(p->MinContext)->Freq - 1]] \ | ||
| 130 | [ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \ | ||
| 131 | + p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \ | ||
| 132 | + p->MinContext->Flags ] | ||
| 133 | |||
| 134 | |||
| 135 | CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale); | ||
| 136 | |||
| 137 | |||
| 138 | /* 20.01: the original PPMdI encoder and decoder probably could work incorrectly in some rare cases, | ||
| 139 | where the original PPMdI code can give "Divide by Zero" operation. | ||
| 140 | We use the following fix to allow correct working of encoder and decoder in any cases. | ||
| 141 | We correct (Escape_Freq) and (_sum_), if (_sum_) is larger than p->Range) */ | ||
| 142 | #define PPMD8_CORRECT_SUM_RANGE(p, _sum_) if (_sum_ > p->Range /* /1 */) _sum_ = p->Range; | ||
| 143 | |||
| 144 | |||
| 145 | /* ---------- Decode ---------- */ | ||
| 146 | |||
| 147 | #define PPMD8_SYM_END (-1) | ||
| 148 | #define PPMD8_SYM_ERROR (-2) | ||
| 149 | |||
| 150 | /* | ||
| 151 | You must set (CPpmd8::Stream.In) before Ppmd8_RangeDec_Init() | ||
| 152 | |||
| 153 | Ppmd8_DecodeSymbol() | ||
| 154 | out: | ||
| 155 | >= 0 : decoded byte | ||
| 156 | -1 : PPMD8_SYM_END : End of payload marker | ||
| 157 | -2 : PPMD8_SYM_ERROR : Data error | ||
| 158 | */ | ||
| 159 | |||
| 160 | |||
| 161 | BoolInt Ppmd8_Init_RangeDec(CPpmd8 *p); | ||
| 162 | #define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0) | ||
| 163 | int Ppmd8_DecodeSymbol(CPpmd8 *p); | ||
| 164 | |||
| 165 | |||
| 166 | |||
| 167 | |||
| 168 | |||
| 169 | |||
| 170 | |||
| 171 | |||
| 172 | /* ---------- Encode ---------- */ | ||
| 173 | |||
| 174 | #define Ppmd8_Init_RangeEnc(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; } | ||
| 175 | void Ppmd8_Flush_RangeEnc(CPpmd8 *p); | ||
| 176 | void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); | ||
| 177 | |||
| 178 | |||
| 179 | EXTERN_C_END | ||
| 180 | |||
| 181 | #endif | ||
diff --git a/C/Ppmd8Dec.c b/C/Ppmd8Dec.c new file mode 100644 index 0000000..d205de2 --- /dev/null +++ b/C/Ppmd8Dec.c | |||
| @@ -0,0 +1,279 @@ | |||
| 1 | /* Ppmd8Dec.c -- Ppmd8 (PPMdI) Decoder | ||
| 2 | 2021-04-13 : 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 "Precomp.h" | ||
| 8 | |||
| 9 | #include "Ppmd8.h" | ||
| 10 | |||
| 11 | #define kTop (1 << 24) | ||
| 12 | #define kBot (1 << 15) | ||
| 13 | |||
| 14 | #define READ_BYTE(p) IByteIn_Read((p)->Stream.In) | ||
| 15 | |||
| 16 | BoolInt Ppmd8_Init_RangeDec(CPpmd8 *p) | ||
| 17 | { | ||
| 18 | unsigned i; | ||
| 19 | p->Code = 0; | ||
| 20 | p->Range = 0xFFFFFFFF; | ||
| 21 | p->Low = 0; | ||
| 22 | |||
| 23 | for (i = 0; i < 4; i++) | ||
| 24 | p->Code = (p->Code << 8) | READ_BYTE(p); | ||
| 25 | return (p->Code < 0xFFFFFFFF); | ||
| 26 | } | ||
| 27 | |||
| 28 | #define RC_NORM(p) \ | ||
| 29 | while ((p->Low ^ (p->Low + p->Range)) < kTop \ | ||
| 30 | || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) { \ | ||
| 31 | p->Code = (p->Code << 8) | READ_BYTE(p); \ | ||
| 32 | p->Range <<= 8; p->Low <<= 8; } | ||
| 33 | |||
| 34 | // we must use only one type of Normalization from two: LOCAL or REMOTE | ||
| 35 | #define RC_NORM_LOCAL(p) // RC_NORM(p) | ||
| 36 | #define RC_NORM_REMOTE(p) RC_NORM(p) | ||
| 37 | |||
| 38 | #define R p | ||
| 39 | |||
| 40 | MY_FORCE_INLINE | ||
| 41 | // MY_NO_INLINE | ||
| 42 | static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size) | ||
| 43 | { | ||
| 44 | start *= R->Range; | ||
| 45 | R->Low += start; | ||
| 46 | R->Code -= start; | ||
| 47 | R->Range *= size; | ||
| 48 | RC_NORM_LOCAL(R) | ||
| 49 | } | ||
| 50 | |||
| 51 | #define RC_Decode(start, size) RangeDec_Decode(p, start, size); | ||
| 52 | #define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R) | ||
| 53 | #define RC_GetThreshold(total) (R->Code / (R->Range /= (total))) | ||
| 54 | |||
| 55 | |||
| 56 | #define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) | ||
| 57 | typedef CPpmd8_Context * CTX_PTR; | ||
| 58 | #define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) | ||
| 59 | void Ppmd8_UpdateModel(CPpmd8 *p); | ||
| 60 | |||
| 61 | #define MASK(sym) ((unsigned char *)charMask)[sym] | ||
| 62 | |||
| 63 | |||
| 64 | int Ppmd8_DecodeSymbol(CPpmd8 *p) | ||
| 65 | { | ||
| 66 | size_t charMask[256 / sizeof(size_t)]; | ||
| 67 | |||
| 68 | if (p->MinContext->NumStats != 0) | ||
| 69 | { | ||
| 70 | CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); | ||
| 71 | unsigned i; | ||
| 72 | UInt32 count, hiCnt; | ||
| 73 | UInt32 summFreq = p->MinContext->Union2.SummFreq; | ||
| 74 | |||
| 75 | PPMD8_CORRECT_SUM_RANGE(p, summFreq) | ||
| 76 | |||
| 77 | |||
| 78 | count = RC_GetThreshold(summFreq); | ||
| 79 | hiCnt = count; | ||
| 80 | |||
| 81 | if ((Int32)(count -= s->Freq) < 0) | ||
| 82 | { | ||
| 83 | Byte sym; | ||
| 84 | RC_DecodeFinal(0, s->Freq); | ||
| 85 | p->FoundState = s; | ||
| 86 | sym = s->Symbol; | ||
| 87 | Ppmd8_Update1_0(p); | ||
| 88 | return sym; | ||
| 89 | } | ||
| 90 | |||
| 91 | p->PrevSuccess = 0; | ||
| 92 | i = p->MinContext->NumStats; | ||
| 93 | |||
| 94 | do | ||
| 95 | { | ||
| 96 | if ((Int32)(count -= (++s)->Freq) < 0) | ||
| 97 | { | ||
| 98 | Byte sym; | ||
| 99 | RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq); | ||
| 100 | p->FoundState = s; | ||
| 101 | sym = s->Symbol; | ||
| 102 | Ppmd8_Update1(p); | ||
| 103 | return sym; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | while (--i); | ||
| 107 | |||
| 108 | if (hiCnt >= summFreq) | ||
| 109 | return PPMD8_SYM_ERROR; | ||
| 110 | |||
| 111 | hiCnt -= count; | ||
| 112 | RC_Decode(hiCnt, summFreq - hiCnt); | ||
| 113 | |||
| 114 | |||
| 115 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
| 116 | // i = p->MinContext->NumStats - 1; | ||
| 117 | // do { MASK((--s)->Symbol) = 0; } while (--i); | ||
| 118 | { | ||
| 119 | CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); | ||
| 120 | MASK(s->Symbol) = 0; | ||
| 121 | do | ||
| 122 | { | ||
| 123 | unsigned sym0 = s2[0].Symbol; | ||
| 124 | unsigned sym1 = s2[1].Symbol; | ||
| 125 | s2 += 2; | ||
| 126 | MASK(sym0) = 0; | ||
| 127 | MASK(sym1) = 0; | ||
| 128 | } | ||
| 129 | while (s2 < s); | ||
| 130 | } | ||
| 131 | } | ||
| 132 | else | ||
| 133 | { | ||
| 134 | CPpmd_State *s = Ppmd8Context_OneState(p->MinContext); | ||
| 135 | UInt16 *prob = Ppmd8_GetBinSumm(p); | ||
| 136 | UInt32 pr = *prob; | ||
| 137 | UInt32 size0 = (R->Range >> 14) * pr; | ||
| 138 | pr = PPMD_UPDATE_PROB_1(pr); | ||
| 139 | |||
| 140 | if (R->Code < size0) | ||
| 141 | { | ||
| 142 | Byte sym; | ||
| 143 | *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); | ||
| 144 | |||
| 145 | // RangeDec_DecodeBit0(size0); | ||
| 146 | R->Range = size0; | ||
| 147 | RC_NORM(R) | ||
| 148 | |||
| 149 | |||
| 150 | |||
| 151 | // sym = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; | ||
| 152 | // Ppmd8_UpdateBin(p); | ||
| 153 | { | ||
| 154 | unsigned freq = s->Freq; | ||
| 155 | CTX_PTR c = CTX(SUCCESSOR(s)); | ||
| 156 | sym = s->Symbol; | ||
| 157 | p->FoundState = s; | ||
| 158 | p->PrevSuccess = 1; | ||
| 159 | p->RunLength++; | ||
| 160 | s->Freq = (Byte)(freq + (freq < 196)); | ||
| 161 | // NextContext(p); | ||
| 162 | if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart) | ||
| 163 | p->MaxContext = p->MinContext = c; | ||
| 164 | else | ||
| 165 | Ppmd8_UpdateModel(p); | ||
| 166 | } | ||
| 167 | return sym; | ||
| 168 | } | ||
| 169 | |||
| 170 | *prob = (UInt16)pr; | ||
| 171 | p->InitEsc = p->ExpEscape[pr >> 10]; | ||
| 172 | |||
| 173 | // RangeDec_DecodeBit1(rc2, size0); | ||
| 174 | R->Low += size0; | ||
| 175 | R->Code -= size0; | ||
| 176 | R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - size0; | ||
| 177 | RC_NORM_LOCAL(R) | ||
| 178 | |||
| 179 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
| 180 | MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; | ||
| 181 | p->PrevSuccess = 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | for (;;) | ||
| 185 | { | ||
| 186 | CPpmd_State *s, *s2; | ||
| 187 | UInt32 freqSum, count, hiCnt; | ||
| 188 | UInt32 freqSum2; | ||
| 189 | CPpmd_See *see; | ||
| 190 | CPpmd8_Context *mc; | ||
| 191 | unsigned numMasked; | ||
| 192 | RC_NORM_REMOTE(R) | ||
| 193 | mc = p->MinContext; | ||
| 194 | numMasked = mc->NumStats; | ||
| 195 | |||
| 196 | do | ||
| 197 | { | ||
| 198 | p->OrderFall++; | ||
| 199 | if (!mc->Suffix) | ||
| 200 | return PPMD8_SYM_END; | ||
| 201 | mc = Ppmd8_GetContext(p, mc->Suffix); | ||
| 202 | } | ||
| 203 | while (mc->NumStats == numMasked); | ||
| 204 | |||
| 205 | s = Ppmd8_GetStats(p, mc); | ||
| 206 | |||
| 207 | { | ||
| 208 | unsigned num = (unsigned)mc->NumStats + 1; | ||
| 209 | unsigned num2 = num / 2; | ||
| 210 | |||
| 211 | num &= 1; | ||
| 212 | hiCnt = (s->Freq & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num); | ||
| 213 | s += num; | ||
| 214 | p->MinContext = mc; | ||
| 215 | |||
| 216 | do | ||
| 217 | { | ||
| 218 | unsigned sym0 = s[0].Symbol; | ||
| 219 | unsigned sym1 = s[1].Symbol; | ||
| 220 | s += 2; | ||
| 221 | hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0))); | ||
| 222 | hiCnt += (s[-1].Freq & (unsigned)(MASK(sym1))); | ||
| 223 | } | ||
| 224 | while (--num2); | ||
| 225 | } | ||
| 226 | |||
| 227 | see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); | ||
| 228 | freqSum += hiCnt; | ||
| 229 | freqSum2 = freqSum; | ||
| 230 | PPMD8_CORRECT_SUM_RANGE(R, freqSum2); | ||
| 231 | |||
| 232 | |||
| 233 | count = RC_GetThreshold(freqSum2); | ||
| 234 | |||
| 235 | if (count < hiCnt) | ||
| 236 | { | ||
| 237 | Byte sym; | ||
| 238 | // Ppmd_See_Update(see); // new (see->Summ) value can overflow over 16-bits in some rare cases | ||
| 239 | s = Ppmd8_GetStats(p, p->MinContext); | ||
| 240 | hiCnt = count; | ||
| 241 | |||
| 242 | |||
| 243 | { | ||
| 244 | for (;;) | ||
| 245 | { | ||
| 246 | count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; | ||
| 247 | // count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; | ||
| 248 | } | ||
| 249 | } | ||
| 250 | s--; | ||
| 251 | RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq); | ||
| 252 | |||
| 253 | // new (see->Summ) value can overflow over 16-bits in some rare cases | ||
| 254 | Ppmd_See_Update(see); | ||
| 255 | p->FoundState = s; | ||
| 256 | sym = s->Symbol; | ||
| 257 | Ppmd8_Update2(p); | ||
| 258 | return sym; | ||
| 259 | } | ||
| 260 | |||
| 261 | if (count >= freqSum2) | ||
| 262 | return PPMD8_SYM_ERROR; | ||
| 263 | |||
| 264 | RC_Decode(hiCnt, freqSum2 - hiCnt); | ||
| 265 | |||
| 266 | // We increase (see->Summ) for sum of Freqs of all non_Masked symbols. | ||
| 267 | // new (see->Summ) value can overflow over 16-bits in some rare cases | ||
| 268 | see->Summ = (UInt16)(see->Summ + freqSum); | ||
| 269 | |||
| 270 | s = Ppmd8_GetStats(p, p->MinContext); | ||
| 271 | s2 = s + p->MinContext->NumStats + 1; | ||
| 272 | do | ||
| 273 | { | ||
| 274 | MASK(s->Symbol) = 0; | ||
| 275 | s++; | ||
| 276 | } | ||
| 277 | while (s != s2); | ||
| 278 | } | ||
| 279 | } | ||
diff --git a/C/Ppmd8Enc.c b/C/Ppmd8Enc.c new file mode 100644 index 0000000..32ff805 --- /dev/null +++ b/C/Ppmd8Enc.c | |||
| @@ -0,0 +1,314 @@ | |||
| 1 | /* Ppmd8Enc.c -- Ppmd8 (PPMdI) Encoder | ||
| 2 | 2021-04-13 : 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 "Precomp.h" | ||
| 8 | |||
| 9 | #include "Ppmd8.h" | ||
| 10 | |||
| 11 | #define kTop (1 << 24) | ||
| 12 | #define kBot (1 << 15) | ||
| 13 | |||
| 14 | #define WRITE_BYTE(p) IByteOut_Write(p->Stream.Out, (Byte)(p->Low >> 24)) | ||
| 15 | |||
| 16 | void Ppmd8_Flush_RangeEnc(CPpmd8 *p) | ||
| 17 | { | ||
| 18 | unsigned i; | ||
| 19 | for (i = 0; i < 4; i++, p->Low <<= 8 ) | ||
| 20 | WRITE_BYTE(p); | ||
| 21 | } | ||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | |||
| 27 | |||
| 28 | #define RC_NORM(p) \ | ||
| 29 | while ((p->Low ^ (p->Low + p->Range)) < kTop \ | ||
| 30 | || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) \ | ||
| 31 | { WRITE_BYTE(p); p->Range <<= 8; p->Low <<= 8; } | ||
| 32 | |||
| 33 | |||
| 34 | |||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | |||
| 39 | |||
| 40 | |||
| 41 | |||
| 42 | |||
| 43 | |||
| 44 | |||
| 45 | // we must use only one type of Normalization from two: LOCAL or REMOTE | ||
| 46 | #define RC_NORM_LOCAL(p) // RC_NORM(p) | ||
| 47 | #define RC_NORM_REMOTE(p) RC_NORM(p) | ||
| 48 | |||
| 49 | // #define RC_PRE(total) p->Range /= total; | ||
| 50 | // #define RC_PRE(total) | ||
| 51 | |||
| 52 | #define R p | ||
| 53 | |||
| 54 | |||
| 55 | |||
| 56 | |||
| 57 | MY_FORCE_INLINE | ||
| 58 | // MY_NO_INLINE | ||
| 59 | static void RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total) | ||
| 60 | { | ||
| 61 | R->Low += start * (R->Range /= total); | ||
| 62 | R->Range *= size; | ||
| 63 | RC_NORM_LOCAL(R); | ||
| 64 | } | ||
| 65 | |||
| 66 | |||
| 67 | |||
| 68 | |||
| 69 | |||
| 70 | |||
| 71 | |||
| 72 | |||
| 73 | |||
| 74 | |||
| 75 | #define RC_Encode(start, size, total) RangeEnc_Encode(p, start, size, total); | ||
| 76 | #define RC_EncodeFinal(start, size, total) RC_Encode(start, size, total); RC_NORM_REMOTE(p); | ||
| 77 | |||
| 78 | #define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) | ||
| 79 | |||
| 80 | typedef CPpmd8_Context * CTX_PTR; | ||
| 81 | #define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) | ||
| 82 | |||
| 83 | void Ppmd8_UpdateModel(CPpmd8 *p); | ||
| 84 | |||
| 85 | #define MASK(sym) ((unsigned char *)charMask)[sym] | ||
| 86 | |||
| 87 | // MY_FORCE_INLINE | ||
| 88 | // static | ||
| 89 | void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol) | ||
| 90 | { | ||
| 91 | size_t charMask[256 / sizeof(size_t)]; | ||
| 92 | |||
| 93 | if (p->MinContext->NumStats != 0) | ||
| 94 | { | ||
| 95 | CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); | ||
| 96 | UInt32 sum; | ||
| 97 | unsigned i; | ||
| 98 | UInt32 summFreq = p->MinContext->Union2.SummFreq; | ||
| 99 | |||
| 100 | PPMD8_CORRECT_SUM_RANGE(p, summFreq) | ||
| 101 | |||
| 102 | // RC_PRE(summFreq); | ||
| 103 | |||
| 104 | if (s->Symbol == symbol) | ||
| 105 | { | ||
| 106 | |||
| 107 | RC_EncodeFinal(0, s->Freq, summFreq); | ||
| 108 | p->FoundState = s; | ||
| 109 | Ppmd8_Update1_0(p); | ||
| 110 | return; | ||
| 111 | } | ||
| 112 | p->PrevSuccess = 0; | ||
| 113 | sum = s->Freq; | ||
| 114 | i = p->MinContext->NumStats; | ||
| 115 | do | ||
| 116 | { | ||
| 117 | if ((++s)->Symbol == symbol) | ||
| 118 | { | ||
| 119 | |||
| 120 | RC_EncodeFinal(sum, s->Freq, summFreq); | ||
| 121 | p->FoundState = s; | ||
| 122 | Ppmd8_Update1(p); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | sum += s->Freq; | ||
| 126 | } | ||
| 127 | while (--i); | ||
| 128 | |||
| 129 | |||
| 130 | RC_Encode(sum, summFreq - sum, summFreq); | ||
| 131 | |||
| 132 | |||
| 133 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
| 134 | // MASK(s->Symbol) = 0; | ||
| 135 | // i = p->MinContext->NumStats; | ||
| 136 | // do { MASK((--s)->Symbol) = 0; } while (--i); | ||
| 137 | { | ||
| 138 | CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); | ||
| 139 | MASK(s->Symbol) = 0; | ||
| 140 | do | ||
| 141 | { | ||
| 142 | unsigned sym0 = s2[0].Symbol; | ||
| 143 | unsigned sym1 = s2[1].Symbol; | ||
| 144 | s2 += 2; | ||
| 145 | MASK(sym0) = 0; | ||
| 146 | MASK(sym1) = 0; | ||
| 147 | } | ||
| 148 | while (s2 < s); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | else | ||
| 152 | { | ||
| 153 | UInt16 *prob = Ppmd8_GetBinSumm(p); | ||
| 154 | CPpmd_State *s = Ppmd8Context_OneState(p->MinContext); | ||
| 155 | UInt32 pr = *prob; | ||
| 156 | UInt32 bound = (R->Range >> 14) * pr; | ||
| 157 | pr = PPMD_UPDATE_PROB_1(pr); | ||
| 158 | if (s->Symbol == symbol) | ||
| 159 | { | ||
| 160 | *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); | ||
| 161 | // RangeEnc_EncodeBit_0(p, bound); | ||
| 162 | R->Range = bound; | ||
| 163 | RC_NORM(R); | ||
| 164 | |||
| 165 | // p->FoundState = s; | ||
| 166 | // Ppmd8_UpdateBin(p); | ||
| 167 | { | ||
| 168 | unsigned freq = s->Freq; | ||
| 169 | CTX_PTR c = CTX(SUCCESSOR(s)); | ||
| 170 | p->FoundState = s; | ||
| 171 | p->PrevSuccess = 1; | ||
| 172 | p->RunLength++; | ||
| 173 | s->Freq = (Byte)(freq + (freq < 196)); // Ppmd8 (196) | ||
| 174 | // NextContext(p); | ||
| 175 | if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart) | ||
| 176 | p->MaxContext = p->MinContext = c; | ||
| 177 | else | ||
| 178 | Ppmd8_UpdateModel(p); | ||
| 179 | } | ||
| 180 | return; | ||
| 181 | } | ||
| 182 | |||
| 183 | *prob = (UInt16)pr; | ||
| 184 | p->InitEsc = p->ExpEscape[pr >> 10]; | ||
| 185 | // RangeEnc_EncodeBit_1(p, bound); | ||
| 186 | R->Low += bound; | ||
| 187 | R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - bound; | ||
| 188 | RC_NORM_LOCAL(R) | ||
| 189 | |||
| 190 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
| 191 | MASK(s->Symbol) = 0; | ||
| 192 | p->PrevSuccess = 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | for (;;) | ||
| 196 | { | ||
| 197 | CPpmd_See *see; | ||
| 198 | CPpmd_State *s; | ||
| 199 | UInt32 sum, escFreq; | ||
| 200 | CPpmd8_Context *mc; | ||
| 201 | unsigned i, numMasked; | ||
| 202 | |||
| 203 | RC_NORM_REMOTE(p) | ||
| 204 | |||
| 205 | mc = p->MinContext; | ||
| 206 | numMasked = mc->NumStats; | ||
| 207 | |||
| 208 | do | ||
| 209 | { | ||
| 210 | p->OrderFall++; | ||
| 211 | if (!mc->Suffix) | ||
| 212 | return; /* EndMarker (symbol = -1) */ | ||
| 213 | mc = Ppmd8_GetContext(p, mc->Suffix); | ||
| 214 | |||
| 215 | } | ||
| 216 | while (mc->NumStats == numMasked); | ||
| 217 | |||
| 218 | p->MinContext = mc; | ||
| 219 | |||
| 220 | see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq); | ||
| 221 | |||
| 222 | |||
| 223 | |||
| 224 | |||
| 225 | |||
| 226 | |||
| 227 | |||
| 228 | |||
| 229 | |||
| 230 | |||
| 231 | |||
| 232 | |||
| 233 | |||
| 234 | |||
| 235 | |||
| 236 | |||
| 237 | |||
| 238 | |||
| 239 | |||
| 240 | |||
| 241 | |||
| 242 | |||
| 243 | |||
| 244 | |||
| 245 | s = Ppmd8_GetStats(p, p->MinContext); | ||
| 246 | sum = 0; | ||
| 247 | i = (unsigned)p->MinContext->NumStats + 1; | ||
| 248 | |||
| 249 | do | ||
| 250 | { | ||
| 251 | unsigned cur = s->Symbol; | ||
| 252 | if ((int)cur == symbol) | ||
| 253 | { | ||
| 254 | UInt32 low = sum; | ||
| 255 | UInt32 freq = s->Freq; | ||
| 256 | unsigned num2; | ||
| 257 | |||
| 258 | Ppmd_See_Update(see); | ||
| 259 | p->FoundState = s; | ||
| 260 | sum += escFreq; | ||
| 261 | |||
| 262 | num2 = i / 2; | ||
| 263 | i &= 1; | ||
| 264 | sum += freq & (0 - (UInt32)i); | ||
| 265 | if (num2 != 0) | ||
| 266 | { | ||
| 267 | s += i; | ||
| 268 | for (;;) | ||
| 269 | { | ||
| 270 | unsigned sym0 = s[0].Symbol; | ||
| 271 | unsigned sym1 = s[1].Symbol; | ||
| 272 | s += 2; | ||
| 273 | sum += (s[-2].Freq & (unsigned)(MASK(sym0))); | ||
| 274 | sum += (s[-1].Freq & (unsigned)(MASK(sym1))); | ||
| 275 | if (--num2 == 0) | ||
| 276 | break; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | PPMD8_CORRECT_SUM_RANGE(p, sum); | ||
| 281 | |||
| 282 | RC_EncodeFinal(low, freq, sum); | ||
| 283 | Ppmd8_Update2(p); | ||
| 284 | return; | ||
| 285 | } | ||
| 286 | sum += (s->Freq & (unsigned)(MASK(cur))); | ||
| 287 | s++; | ||
| 288 | } | ||
| 289 | while (--i); | ||
| 290 | |||
| 291 | { | ||
| 292 | UInt32 total = sum + escFreq; | ||
| 293 | see->Summ = (UInt16)(see->Summ + total); | ||
| 294 | PPMD8_CORRECT_SUM_RANGE(p, total); | ||
| 295 | |||
| 296 | RC_Encode(sum, total - sum, total); | ||
| 297 | } | ||
| 298 | |||
| 299 | { | ||
| 300 | CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); | ||
| 301 | s--; | ||
| 302 | MASK(s->Symbol) = 0; | ||
| 303 | do | ||
| 304 | { | ||
| 305 | unsigned sym0 = s2[0].Symbol; | ||
| 306 | unsigned sym1 = s2[1].Symbol; | ||
| 307 | s2 += 2; | ||
| 308 | MASK(sym0) = 0; | ||
| 309 | MASK(sym1) = 0; | ||
| 310 | } | ||
| 311 | while (s2 < s); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | } | ||
diff --git a/C/Precomp.h b/C/Precomp.h new file mode 100644 index 0000000..e8ff8b4 --- /dev/null +++ b/C/Precomp.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | /* Precomp.h -- StdAfx | ||
| 2 | 2013-11-12 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_PRECOMP_H | ||
| 5 | #define __7Z_PRECOMP_H | ||
| 6 | |||
| 7 | #include "Compiler.h" | ||
| 8 | /* #include "7zTypes.h" */ | ||
| 9 | |||
| 10 | #endif | ||
diff --git a/C/RotateDefs.h b/C/RotateDefs.h new file mode 100644 index 0000000..8f01d1a --- /dev/null +++ b/C/RotateDefs.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* RotateDefs.h -- Rotate functions | ||
| 2 | 2015-03-25 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __ROTATE_DEFS_H | ||
| 5 | #define __ROTATE_DEFS_H | ||
| 6 | |||
| 7 | #ifdef _MSC_VER | ||
| 8 | |||
| 9 | #include <stdlib.h> | ||
| 10 | |||
| 11 | /* don't use _rotl with MINGW. It can insert slow call to function. */ | ||
| 12 | |||
| 13 | /* #if (_MSC_VER >= 1200) */ | ||
| 14 | #pragma intrinsic(_rotl) | ||
| 15 | #pragma intrinsic(_rotr) | ||
| 16 | /* #endif */ | ||
| 17 | |||
| 18 | #define rotlFixed(x, n) _rotl((x), (n)) | ||
| 19 | #define rotrFixed(x, n) _rotr((x), (n)) | ||
| 20 | |||
| 21 | #else | ||
| 22 | |||
| 23 | /* new compilers can translate these macros to fast commands. */ | ||
| 24 | |||
| 25 | #define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) | ||
| 26 | #define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) | ||
| 27 | |||
| 28 | #endif | ||
| 29 | |||
| 30 | #endif | ||
diff --git a/C/Sha1.c b/C/Sha1.c new file mode 100644 index 0000000..9665b5b --- /dev/null +++ b/C/Sha1.c | |||
| @@ -0,0 +1,473 @@ | |||
| 1 | /* Sha1.c -- SHA-1 Hash | ||
| 2 | 2021-07-13 : Igor Pavlov : Public domain | ||
| 3 | This code is based on public domain code of Steve Reid from Wei Dai's Crypto++ library. */ | ||
| 4 | |||
| 5 | #include "Precomp.h" | ||
| 6 | |||
| 7 | #include <string.h> | ||
| 8 | |||
| 9 | #include "CpuArch.h" | ||
| 10 | #include "RotateDefs.h" | ||
| 11 | #include "Sha1.h" | ||
| 12 | |||
| 13 | #if defined(_MSC_VER) && (_MSC_VER < 1900) | ||
| 14 | // #define USE_MY_MM | ||
| 15 | #endif | ||
| 16 | |||
| 17 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 18 | #ifdef _MSC_VER | ||
| 19 | #if _MSC_VER >= 1200 | ||
| 20 | #define _SHA_SUPPORTED | ||
| 21 | #endif | ||
| 22 | #elif defined(__clang__) | ||
| 23 | #if (__clang_major__ >= 8) // fix that check | ||
| 24 | #define _SHA_SUPPORTED | ||
| 25 | #endif | ||
| 26 | #elif defined(__GNUC__) | ||
| 27 | #if (__GNUC__ >= 8) // fix that check | ||
| 28 | #define _SHA_SUPPORTED | ||
| 29 | #endif | ||
| 30 | #elif defined(__INTEL_COMPILER) | ||
| 31 | #if (__INTEL_COMPILER >= 1800) // fix that check | ||
| 32 | #define _SHA_SUPPORTED | ||
| 33 | #endif | ||
| 34 | #endif | ||
| 35 | #elif defined(MY_CPU_ARM_OR_ARM64) | ||
| 36 | #ifdef _MSC_VER | ||
| 37 | #if _MSC_VER >= 1910 && _MSC_VER >= 1929 && _MSC_FULL_VER >= 192930037 | ||
| 38 | #define _SHA_SUPPORTED | ||
| 39 | #endif | ||
| 40 | #elif defined(__clang__) | ||
| 41 | #if (__clang_major__ >= 8) // fix that check | ||
| 42 | #define _SHA_SUPPORTED | ||
| 43 | #endif | ||
| 44 | #elif defined(__GNUC__) | ||
| 45 | #if (__GNUC__ >= 6) // fix that check | ||
| 46 | #define _SHA_SUPPORTED | ||
| 47 | #endif | ||
| 48 | #endif | ||
| 49 | #endif | ||
| 50 | |||
| 51 | void MY_FAST_CALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks); | ||
| 52 | |||
| 53 | #ifdef _SHA_SUPPORTED | ||
| 54 | void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks); | ||
| 55 | |||
| 56 | static SHA1_FUNC_UPDATE_BLOCKS g_FUNC_UPDATE_BLOCKS = Sha1_UpdateBlocks; | ||
| 57 | static SHA1_FUNC_UPDATE_BLOCKS g_FUNC_UPDATE_BLOCKS_HW; | ||
| 58 | |||
| 59 | #define UPDATE_BLOCKS(p) p->func_UpdateBlocks | ||
| 60 | #else | ||
| 61 | #define UPDATE_BLOCKS(p) Sha1_UpdateBlocks | ||
| 62 | #endif | ||
| 63 | |||
| 64 | |||
| 65 | BoolInt Sha1_SetFunction(CSha1 *p, unsigned algo) | ||
| 66 | { | ||
| 67 | SHA1_FUNC_UPDATE_BLOCKS func = Sha1_UpdateBlocks; | ||
| 68 | |||
| 69 | #ifdef _SHA_SUPPORTED | ||
| 70 | if (algo != SHA1_ALGO_SW) | ||
| 71 | { | ||
| 72 | if (algo == SHA1_ALGO_DEFAULT) | ||
| 73 | func = g_FUNC_UPDATE_BLOCKS; | ||
| 74 | else | ||
| 75 | { | ||
| 76 | if (algo != SHA1_ALGO_HW) | ||
| 77 | return False; | ||
| 78 | func = g_FUNC_UPDATE_BLOCKS_HW; | ||
| 79 | if (!func) | ||
| 80 | return False; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | #else | ||
| 84 | if (algo > 1) | ||
| 85 | return False; | ||
| 86 | #endif | ||
| 87 | |||
| 88 | p->func_UpdateBlocks = func; | ||
| 89 | return True; | ||
| 90 | } | ||
| 91 | |||
| 92 | |||
| 93 | /* define it for speed optimization */ | ||
| 94 | // #define _SHA1_UNROLL | ||
| 95 | |||
| 96 | // allowed unroll steps: (1, 2, 4, 5, 20) | ||
| 97 | |||
| 98 | #ifdef _SHA1_UNROLL | ||
| 99 | #define STEP_PRE 20 | ||
| 100 | #define STEP_MAIN 20 | ||
| 101 | #else | ||
| 102 | #define _SHA1_BIG_W | ||
| 103 | #define STEP_PRE 5 | ||
| 104 | #define STEP_MAIN 5 | ||
| 105 | #endif | ||
| 106 | |||
| 107 | |||
| 108 | #ifdef _SHA1_BIG_W | ||
| 109 | #define kNumW 80 | ||
| 110 | #define w(i) W[i] | ||
| 111 | #else | ||
| 112 | #define kNumW 16 | ||
| 113 | #define w(i) W[(i)&15] | ||
| 114 | #endif | ||
| 115 | |||
| 116 | #define w0(i) (W[i] = GetBe32(data + (size_t)(i) * 4)) | ||
| 117 | #define w1(i) (w(i) = rotlFixed(w((size_t)(i)-3) ^ w((size_t)(i)-8) ^ w((size_t)(i)-14) ^ w((size_t)(i)-16), 1)) | ||
| 118 | |||
| 119 | #define f0(x,y,z) ( 0x5a827999 + (z^(x&(y^z))) ) | ||
| 120 | #define f1(x,y,z) ( 0x6ed9eba1 + (x^y^z) ) | ||
| 121 | #define f2(x,y,z) ( 0x8f1bbcdc + ((x&y)|(z&(x|y))) ) | ||
| 122 | #define f3(x,y,z) ( 0xca62c1d6 + (x^y^z) ) | ||
| 123 | |||
| 124 | /* | ||
| 125 | #define T1(fx, ww) \ | ||
| 126 | tmp = e + fx(b,c,d) + ww + rotlFixed(a, 5); \ | ||
| 127 | e = d; \ | ||
| 128 | d = c; \ | ||
| 129 | c = rotlFixed(b, 30); \ | ||
| 130 | b = a; \ | ||
| 131 | a = tmp; \ | ||
| 132 | */ | ||
| 133 | |||
| 134 | #define T5(a,b,c,d,e, fx, ww) \ | ||
| 135 | e += fx(b,c,d) + ww + rotlFixed(a, 5); \ | ||
| 136 | b = rotlFixed(b, 30); \ | ||
| 137 | |||
| 138 | |||
| 139 | /* | ||
| 140 | #define R1(i, fx, wx) \ | ||
| 141 | T1 ( fx, wx(i)); \ | ||
| 142 | |||
| 143 | #define R2(i, fx, wx) \ | ||
| 144 | R1 ( (i) , fx, wx); \ | ||
| 145 | R1 ( (i) + 1, fx, wx); \ | ||
| 146 | |||
| 147 | #define R4(i, fx, wx) \ | ||
| 148 | R2 ( (i) , fx, wx); \ | ||
| 149 | R2 ( (i) + 2, fx, wx); \ | ||
| 150 | */ | ||
| 151 | |||
| 152 | #define M5(i, fx, wx0, wx1) \ | ||
| 153 | T5 ( a,b,c,d,e, fx, wx0((i) ) ); \ | ||
| 154 | T5 ( e,a,b,c,d, fx, wx1((i)+1) ); \ | ||
| 155 | T5 ( d,e,a,b,c, fx, wx1((i)+2) ); \ | ||
| 156 | T5 ( c,d,e,a,b, fx, wx1((i)+3) ); \ | ||
| 157 | T5 ( b,c,d,e,a, fx, wx1((i)+4) ); \ | ||
| 158 | |||
| 159 | #define R5(i, fx, wx) \ | ||
| 160 | M5 ( i, fx, wx, wx) \ | ||
| 161 | |||
| 162 | |||
| 163 | #if STEP_PRE > 5 | ||
| 164 | |||
| 165 | #define R20_START \ | ||
| 166 | R5 ( 0, f0, w0); \ | ||
| 167 | R5 ( 5, f0, w0); \ | ||
| 168 | R5 ( 10, f0, w0); \ | ||
| 169 | M5 ( 15, f0, w0, w1); \ | ||
| 170 | |||
| 171 | #elif STEP_PRE == 5 | ||
| 172 | |||
| 173 | #define R20_START \ | ||
| 174 | { size_t i; for (i = 0; i < 15; i += STEP_PRE) \ | ||
| 175 | { R5(i, f0, w0); } } \ | ||
| 176 | M5 ( 15, f0, w0, w1); \ | ||
| 177 | |||
| 178 | #else | ||
| 179 | |||
| 180 | #if STEP_PRE == 1 | ||
| 181 | #define R_PRE R1 | ||
| 182 | #elif STEP_PRE == 2 | ||
| 183 | #define R_PRE R2 | ||
| 184 | #elif STEP_PRE == 4 | ||
| 185 | #define R_PRE R4 | ||
| 186 | #endif | ||
| 187 | |||
| 188 | #define R20_START \ | ||
| 189 | { size_t i; for (i = 0; i < 16; i += STEP_PRE) \ | ||
| 190 | { R_PRE(i, f0, w0); } } \ | ||
| 191 | R4 ( 16, f0, w1); \ | ||
| 192 | |||
| 193 | #endif | ||
| 194 | |||
| 195 | |||
| 196 | |||
| 197 | #if STEP_MAIN > 5 | ||
| 198 | |||
| 199 | #define R20(ii, fx) \ | ||
| 200 | R5 ( (ii) , fx, w1); \ | ||
| 201 | R5 ( (ii) + 5 , fx, w1); \ | ||
| 202 | R5 ( (ii) + 10, fx, w1); \ | ||
| 203 | R5 ( (ii) + 15, fx, w1); \ | ||
| 204 | |||
| 205 | #else | ||
| 206 | |||
| 207 | #if STEP_MAIN == 1 | ||
| 208 | #define R_MAIN R1 | ||
| 209 | #elif STEP_MAIN == 2 | ||
| 210 | #define R_MAIN R2 | ||
| 211 | #elif STEP_MAIN == 4 | ||
| 212 | #define R_MAIN R4 | ||
| 213 | #elif STEP_MAIN == 5 | ||
| 214 | #define R_MAIN R5 | ||
| 215 | #endif | ||
| 216 | |||
| 217 | #define R20(ii, fx) \ | ||
| 218 | { size_t i; for (i = (ii); i < (ii) + 20; i += STEP_MAIN) \ | ||
| 219 | { R_MAIN(i, fx, w1); } } \ | ||
| 220 | |||
| 221 | #endif | ||
| 222 | |||
| 223 | |||
| 224 | |||
| 225 | void Sha1_InitState(CSha1 *p) | ||
| 226 | { | ||
| 227 | p->count = 0; | ||
| 228 | p->state[0] = 0x67452301; | ||
| 229 | p->state[1] = 0xEFCDAB89; | ||
| 230 | p->state[2] = 0x98BADCFE; | ||
| 231 | p->state[3] = 0x10325476; | ||
| 232 | p->state[4] = 0xC3D2E1F0; | ||
| 233 | } | ||
| 234 | |||
| 235 | void Sha1_Init(CSha1 *p) | ||
| 236 | { | ||
| 237 | p->func_UpdateBlocks = | ||
| 238 | #ifdef _SHA_SUPPORTED | ||
| 239 | g_FUNC_UPDATE_BLOCKS; | ||
| 240 | #else | ||
| 241 | NULL; | ||
| 242 | #endif | ||
| 243 | Sha1_InitState(p); | ||
| 244 | } | ||
| 245 | |||
| 246 | |||
| 247 | MY_NO_INLINE | ||
| 248 | void MY_FAST_CALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks) | ||
| 249 | { | ||
| 250 | UInt32 a, b, c, d, e; | ||
| 251 | UInt32 W[kNumW]; | ||
| 252 | // if (numBlocks != 0x1264378347) return; | ||
| 253 | if (numBlocks == 0) | ||
| 254 | return; | ||
| 255 | |||
| 256 | a = state[0]; | ||
| 257 | b = state[1]; | ||
| 258 | c = state[2]; | ||
| 259 | d = state[3]; | ||
| 260 | e = state[4]; | ||
| 261 | |||
| 262 | do | ||
| 263 | { | ||
| 264 | #if STEP_PRE < 5 || STEP_MAIN < 5 | ||
| 265 | UInt32 tmp; | ||
| 266 | #endif | ||
| 267 | |||
| 268 | R20_START | ||
| 269 | R20(20, f1); | ||
| 270 | R20(40, f2); | ||
| 271 | R20(60, f3); | ||
| 272 | |||
| 273 | a += state[0]; | ||
| 274 | b += state[1]; | ||
| 275 | c += state[2]; | ||
| 276 | d += state[3]; | ||
| 277 | e += state[4]; | ||
| 278 | |||
| 279 | state[0] = a; | ||
| 280 | state[1] = b; | ||
| 281 | state[2] = c; | ||
| 282 | state[3] = d; | ||
| 283 | state[4] = e; | ||
| 284 | |||
| 285 | data += 64; | ||
| 286 | } | ||
| 287 | while (--numBlocks); | ||
| 288 | } | ||
| 289 | |||
| 290 | |||
| 291 | #define Sha1_UpdateBlock(p) UPDATE_BLOCKS(p)(p->state, p->buffer, 1) | ||
| 292 | |||
| 293 | void Sha1_Update(CSha1 *p, const Byte *data, size_t size) | ||
| 294 | { | ||
| 295 | if (size == 0) | ||
| 296 | return; | ||
| 297 | |||
| 298 | { | ||
| 299 | unsigned pos = (unsigned)p->count & 0x3F; | ||
| 300 | unsigned num; | ||
| 301 | |||
| 302 | p->count += size; | ||
| 303 | |||
| 304 | num = 64 - pos; | ||
| 305 | if (num > size) | ||
| 306 | { | ||
| 307 | memcpy(p->buffer + pos, data, size); | ||
| 308 | return; | ||
| 309 | } | ||
| 310 | |||
| 311 | if (pos != 0) | ||
| 312 | { | ||
| 313 | size -= num; | ||
| 314 | memcpy(p->buffer + pos, data, num); | ||
| 315 | data += num; | ||
| 316 | Sha1_UpdateBlock(p); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | { | ||
| 320 | size_t numBlocks = size >> 6; | ||
| 321 | UPDATE_BLOCKS(p)(p->state, data, numBlocks); | ||
| 322 | size &= 0x3F; | ||
| 323 | if (size == 0) | ||
| 324 | return; | ||
| 325 | data += (numBlocks << 6); | ||
| 326 | memcpy(p->buffer, data, size); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | |||
| 331 | void Sha1_Final(CSha1 *p, Byte *digest) | ||
| 332 | { | ||
| 333 | unsigned pos = (unsigned)p->count & 0x3F; | ||
| 334 | |||
| 335 | |||
| 336 | p->buffer[pos++] = 0x80; | ||
| 337 | |||
| 338 | if (pos > (64 - 8)) | ||
| 339 | { | ||
| 340 | while (pos != 64) { p->buffer[pos++] = 0; } | ||
| 341 | // memset(&p->buf.buffer[pos], 0, 64 - pos); | ||
| 342 | Sha1_UpdateBlock(p); | ||
| 343 | pos = 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | /* | ||
| 347 | if (pos & 3) | ||
| 348 | { | ||
| 349 | p->buffer[pos] = 0; | ||
| 350 | p->buffer[pos + 1] = 0; | ||
| 351 | p->buffer[pos + 2] = 0; | ||
| 352 | pos += 3; | ||
| 353 | pos &= ~3; | ||
| 354 | } | ||
| 355 | { | ||
| 356 | for (; pos < 64 - 8; pos += 4) | ||
| 357 | *(UInt32 *)(&p->buffer[pos]) = 0; | ||
| 358 | } | ||
| 359 | */ | ||
| 360 | |||
| 361 | memset(&p->buffer[pos], 0, (64 - 8) - pos); | ||
| 362 | |||
| 363 | { | ||
| 364 | UInt64 numBits = (p->count << 3); | ||
| 365 | SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32)); | ||
| 366 | SetBe32(p->buffer + 64 - 4, (UInt32)(numBits)); | ||
| 367 | } | ||
| 368 | |||
| 369 | Sha1_UpdateBlock(p); | ||
| 370 | |||
| 371 | SetBe32(digest, p->state[0]); | ||
| 372 | SetBe32(digest + 4, p->state[1]); | ||
| 373 | SetBe32(digest + 8, p->state[2]); | ||
| 374 | SetBe32(digest + 12, p->state[3]); | ||
| 375 | SetBe32(digest + 16, p->state[4]); | ||
| 376 | |||
| 377 | |||
| 378 | |||
| 379 | |||
| 380 | Sha1_InitState(p); | ||
| 381 | } | ||
| 382 | |||
| 383 | |||
| 384 | void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size) | ||
| 385 | { | ||
| 386 | const UInt64 numBits = (p->count + size) << 3; | ||
| 387 | SetBe32(&((UInt32 *)(void *)block)[SHA1_NUM_BLOCK_WORDS - 2], (UInt32)(numBits >> 32)); | ||
| 388 | SetBe32(&((UInt32 *)(void *)block)[SHA1_NUM_BLOCK_WORDS - 1], (UInt32)(numBits)); | ||
| 389 | // SetBe32((UInt32 *)(block + size), 0x80000000); | ||
| 390 | SetUi32((UInt32 *)(void *)(block + size), 0x80); | ||
| 391 | size += 4; | ||
| 392 | while (size != (SHA1_NUM_BLOCK_WORDS - 2) * 4) | ||
| 393 | { | ||
| 394 | *((UInt32 *)(void *)(block + size)) = 0; | ||
| 395 | size += 4; | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | void Sha1_GetBlockDigest(const CSha1 *p, const Byte *data, Byte *destDigest) | ||
| 400 | { | ||
| 401 | MY_ALIGN (16) | ||
| 402 | UInt32 st[SHA1_NUM_DIGEST_WORDS]; | ||
| 403 | |||
| 404 | st[0] = p->state[0]; | ||
| 405 | st[1] = p->state[1]; | ||
| 406 | st[2] = p->state[2]; | ||
| 407 | st[3] = p->state[3]; | ||
| 408 | st[4] = p->state[4]; | ||
| 409 | |||
| 410 | UPDATE_BLOCKS(p)(st, data, 1); | ||
| 411 | |||
| 412 | SetBe32(destDigest + 0 , st[0]); | ||
| 413 | SetBe32(destDigest + 1 * 4, st[1]); | ||
| 414 | SetBe32(destDigest + 2 * 4, st[2]); | ||
| 415 | SetBe32(destDigest + 3 * 4, st[3]); | ||
| 416 | SetBe32(destDigest + 4 * 4, st[4]); | ||
| 417 | } | ||
| 418 | |||
| 419 | |||
| 420 | void Sha1Prepare() | ||
| 421 | { | ||
| 422 | #ifdef _SHA_SUPPORTED | ||
| 423 | SHA1_FUNC_UPDATE_BLOCKS f, f_hw; | ||
| 424 | f = Sha1_UpdateBlocks; | ||
| 425 | f_hw = NULL; | ||
| 426 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 427 | #ifndef USE_MY_MM | ||
| 428 | if (CPU_IsSupported_SHA() | ||
| 429 | && CPU_IsSupported_SSSE3() | ||
| 430 | // && CPU_IsSupported_SSE41() | ||
| 431 | ) | ||
| 432 | #endif | ||
| 433 | #else | ||
| 434 | if (CPU_IsSupported_SHA1()) | ||
| 435 | #endif | ||
| 436 | { | ||
| 437 | // printf("\n========== HW SHA1 ======== \n"); | ||
| 438 | #if defined(MY_CPU_ARM_OR_ARM64) && defined(_MSC_VER) | ||
| 439 | /* there was bug in MSVC compiler for ARM64 -O2 before version VS2019 16.10 (19.29.30037). | ||
| 440 | It generated incorrect SHA-1 code. | ||
| 441 | 21.03 : we test sha1-hardware code at runtime initialization */ | ||
| 442 | |||
| 443 | #pragma message("== SHA1 code: MSC compiler : failure-check code was inserted") | ||
| 444 | |||
| 445 | UInt32 state[5] = { 0, 1, 2, 3, 4 } ; | ||
| 446 | Byte data[64]; | ||
| 447 | unsigned i; | ||
| 448 | for (i = 0; i < sizeof(data); i += 2) | ||
| 449 | { | ||
| 450 | data[i ] = (Byte)(i); | ||
| 451 | data[i + 1] = (Byte)(i + 1); | ||
| 452 | } | ||
| 453 | |||
| 454 | Sha1_UpdateBlocks_HW(state, data, sizeof(data) / 64); | ||
| 455 | |||
| 456 | if ( state[0] != 0x9acd7297 | ||
| 457 | || state[1] != 0x4624d898 | ||
| 458 | || state[2] != 0x0bf079f0 | ||
| 459 | || state[3] != 0x031e61b3 | ||
| 460 | || state[4] != 0x8323fe20) | ||
| 461 | { | ||
| 462 | // printf("\n========== SHA-1 hardware version failure ======== \n"); | ||
| 463 | } | ||
| 464 | else | ||
| 465 | #endif | ||
| 466 | { | ||
| 467 | f = f_hw = Sha1_UpdateBlocks_HW; | ||
| 468 | } | ||
| 469 | } | ||
| 470 | g_FUNC_UPDATE_BLOCKS = f; | ||
| 471 | g_FUNC_UPDATE_BLOCKS_HW = f_hw; | ||
| 472 | #endif | ||
| 473 | } | ||
diff --git a/C/Sha1.h b/C/Sha1.h new file mode 100644 index 0000000..345a816 --- /dev/null +++ b/C/Sha1.h | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /* Sha1.h -- SHA-1 Hash | ||
| 2 | 2021-02-08 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_SHA1_H | ||
| 5 | #define __7Z_SHA1_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define SHA1_NUM_BLOCK_WORDS 16 | ||
| 12 | #define SHA1_NUM_DIGEST_WORDS 5 | ||
| 13 | |||
| 14 | #define SHA1_BLOCK_SIZE (SHA1_NUM_BLOCK_WORDS * 4) | ||
| 15 | #define SHA1_DIGEST_SIZE (SHA1_NUM_DIGEST_WORDS * 4) | ||
| 16 | |||
| 17 | typedef void (MY_FAST_CALL *SHA1_FUNC_UPDATE_BLOCKS)(UInt32 state[5], const Byte *data, size_t numBlocks); | ||
| 18 | |||
| 19 | /* | ||
| 20 | if (the system supports different SHA1 code implementations) | ||
| 21 | { | ||
| 22 | (CSha1::func_UpdateBlocks) will be used | ||
| 23 | (CSha1::func_UpdateBlocks) can be set by | ||
| 24 | Sha1_Init() - to default (fastest) | ||
| 25 | Sha1_SetFunction() - to any algo | ||
| 26 | } | ||
| 27 | else | ||
| 28 | { | ||
| 29 | (CSha1::func_UpdateBlocks) is ignored. | ||
| 30 | } | ||
| 31 | */ | ||
| 32 | |||
| 33 | typedef struct | ||
| 34 | { | ||
| 35 | SHA1_FUNC_UPDATE_BLOCKS func_UpdateBlocks; | ||
| 36 | UInt64 count; | ||
| 37 | UInt64 __pad_2[2]; | ||
| 38 | UInt32 state[SHA1_NUM_DIGEST_WORDS]; | ||
| 39 | UInt32 __pad_3[3]; | ||
| 40 | Byte buffer[SHA1_BLOCK_SIZE]; | ||
| 41 | } CSha1; | ||
| 42 | |||
| 43 | |||
| 44 | #define SHA1_ALGO_DEFAULT 0 | ||
| 45 | #define SHA1_ALGO_SW 1 | ||
| 46 | #define SHA1_ALGO_HW 2 | ||
| 47 | |||
| 48 | /* | ||
| 49 | Sha1_SetFunction() | ||
| 50 | return: | ||
| 51 | 0 - (algo) value is not supported, and func_UpdateBlocks was not changed | ||
| 52 | 1 - func_UpdateBlocks was set according (algo) value. | ||
| 53 | */ | ||
| 54 | |||
| 55 | BoolInt Sha1_SetFunction(CSha1 *p, unsigned algo); | ||
| 56 | |||
| 57 | void Sha1_InitState(CSha1 *p); | ||
| 58 | void Sha1_Init(CSha1 *p); | ||
| 59 | void Sha1_Update(CSha1 *p, const Byte *data, size_t size); | ||
| 60 | void Sha1_Final(CSha1 *p, Byte *digest); | ||
| 61 | |||
| 62 | void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size); | ||
| 63 | void Sha1_GetBlockDigest(const CSha1 *p, const Byte *data, Byte *destDigest); | ||
| 64 | |||
| 65 | // void MY_FAST_CALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks); | ||
| 66 | |||
| 67 | /* | ||
| 68 | call Sha1Prepare() once at program start. | ||
| 69 | It prepares all supported implementations, and detects the fastest implementation. | ||
| 70 | */ | ||
| 71 | |||
| 72 | void Sha1Prepare(void); | ||
| 73 | |||
| 74 | EXTERN_C_END | ||
| 75 | |||
| 76 | #endif | ||
diff --git a/C/Sha1Opt.c b/C/Sha1Opt.c new file mode 100644 index 0000000..63132da --- /dev/null +++ b/C/Sha1Opt.c | |||
| @@ -0,0 +1,373 @@ | |||
| 1 | /* Sha1Opt.c -- SHA-1 optimized code for SHA-1 hardware instructions | ||
| 2 | 2021-04-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #if defined(_MSC_VER) | ||
| 7 | #if (_MSC_VER < 1900) && (_MSC_VER >= 1200) | ||
| 8 | // #define USE_MY_MM | ||
| 9 | #endif | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #include "CpuArch.h" | ||
| 13 | |||
| 14 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 15 | #if defined(__clang__) | ||
| 16 | #if (__clang_major__ >= 8) // fix that check | ||
| 17 | #define USE_HW_SHA | ||
| 18 | #ifndef __SHA__ | ||
| 19 | #define ATTRIB_SHA __attribute__((__target__("sha,ssse3"))) | ||
| 20 | #if defined(_MSC_VER) | ||
| 21 | // SSSE3: for clang-cl: | ||
| 22 | #include <tmmintrin.h> | ||
| 23 | #define __SHA__ | ||
| 24 | #endif | ||
| 25 | #endif | ||
| 26 | #pragma clang diagnostic ignored "-Wvector-conversion" | ||
| 27 | #endif | ||
| 28 | #elif defined(__GNUC__) | ||
| 29 | #if (__GNUC__ >= 8) // fix that check | ||
| 30 | #define USE_HW_SHA | ||
| 31 | #ifndef __SHA__ | ||
| 32 | #define ATTRIB_SHA __attribute__((__target__("sha,ssse3"))) | ||
| 33 | // #pragma GCC target("sha,ssse3") | ||
| 34 | #endif | ||
| 35 | #endif | ||
| 36 | #elif defined(__INTEL_COMPILER) | ||
| 37 | #if (__INTEL_COMPILER >= 1800) // fix that check | ||
| 38 | #define USE_HW_SHA | ||
| 39 | #endif | ||
| 40 | #elif defined(_MSC_VER) | ||
| 41 | #ifdef USE_MY_MM | ||
| 42 | #define USE_VER_MIN 1300 | ||
| 43 | #else | ||
| 44 | #define USE_VER_MIN 1910 | ||
| 45 | #endif | ||
| 46 | #if _MSC_VER >= USE_VER_MIN | ||
| 47 | #define USE_HW_SHA | ||
| 48 | #endif | ||
| 49 | #endif | ||
| 50 | // #endif // MY_CPU_X86_OR_AMD64 | ||
| 51 | |||
| 52 | #ifdef USE_HW_SHA | ||
| 53 | |||
| 54 | // #pragma message("Sha1 HW") | ||
| 55 | // #include <wmmintrin.h> | ||
| 56 | |||
| 57 | #if !defined(_MSC_VER) || (_MSC_VER >= 1900) | ||
| 58 | #include <immintrin.h> | ||
| 59 | #else | ||
| 60 | #include <emmintrin.h> | ||
| 61 | |||
| 62 | #if defined(_MSC_VER) && (_MSC_VER >= 1600) | ||
| 63 | // #include <intrin.h> | ||
| 64 | #endif | ||
| 65 | |||
| 66 | #ifdef USE_MY_MM | ||
| 67 | #include "My_mm.h" | ||
| 68 | #endif | ||
| 69 | |||
| 70 | #endif | ||
| 71 | |||
| 72 | /* | ||
| 73 | SHA1 uses: | ||
| 74 | SSE2: | ||
| 75 | _mm_loadu_si128 | ||
| 76 | _mm_storeu_si128 | ||
| 77 | _mm_set_epi32 | ||
| 78 | _mm_add_epi32 | ||
| 79 | _mm_shuffle_epi32 / pshufd | ||
| 80 | _mm_xor_si128 | ||
| 81 | _mm_cvtsi128_si32 | ||
| 82 | _mm_cvtsi32_si128 | ||
| 83 | SSSE3: | ||
| 84 | _mm_shuffle_epi8 / pshufb | ||
| 85 | |||
| 86 | SHA: | ||
| 87 | _mm_sha1* | ||
| 88 | */ | ||
| 89 | |||
| 90 | #define ADD_EPI32(dest, src) dest = _mm_add_epi32(dest, src); | ||
| 91 | #define XOR_SI128(dest, src) dest = _mm_xor_si128(dest, src); | ||
| 92 | #define SHUFFLE_EPI8(dest, mask) dest = _mm_shuffle_epi8(dest, mask); | ||
| 93 | #define SHUFFLE_EPI32(dest, mask) dest = _mm_shuffle_epi32(dest, mask); | ||
| 94 | |||
| 95 | #define SHA1_RND4(abcd, e0, f) abcd = _mm_sha1rnds4_epu32(abcd, e0, f); | ||
| 96 | #define SHA1_NEXTE(e, m) e = _mm_sha1nexte_epu32(e, m); | ||
| 97 | |||
| 98 | |||
| 99 | |||
| 100 | |||
| 101 | |||
| 102 | #define SHA1_MSG1(dest, src) dest = _mm_sha1msg1_epu32(dest, src); | ||
| 103 | #define SHA1_MSG2(dest, src) dest = _mm_sha1msg2_epu32(dest, src); | ||
| 104 | |||
| 105 | |||
| 106 | #define LOAD_SHUFFLE(m, k) \ | ||
| 107 | m = _mm_loadu_si128((const __m128i *)(const void *)(data + (k) * 16)); \ | ||
| 108 | SHUFFLE_EPI8(m, mask); \ | ||
| 109 | |||
| 110 | #define SM1(m0, m1, m2, m3) \ | ||
| 111 | SHA1_MSG1(m0, m1); \ | ||
| 112 | |||
| 113 | #define SM2(m0, m1, m2, m3) \ | ||
| 114 | XOR_SI128(m3, m1); \ | ||
| 115 | SHA1_MSG2(m3, m2); \ | ||
| 116 | |||
| 117 | #define SM3(m0, m1, m2, m3) \ | ||
| 118 | XOR_SI128(m3, m1); \ | ||
| 119 | SM1(m0, m1, m2, m3) \ | ||
| 120 | SHA1_MSG2(m3, m2); \ | ||
| 121 | |||
| 122 | #define NNN(m0, m1, m2, m3) | ||
| 123 | |||
| 124 | |||
| 125 | |||
| 126 | |||
| 127 | |||
| 128 | |||
| 129 | |||
| 130 | |||
| 131 | |||
| 132 | |||
| 133 | |||
| 134 | |||
| 135 | |||
| 136 | |||
| 137 | |||
| 138 | |||
| 139 | |||
| 140 | #define R4(k, e0, e1, m0, m1, m2, m3, OP) \ | ||
| 141 | e1 = abcd; \ | ||
| 142 | SHA1_RND4(abcd, e0, (k) / 5); \ | ||
| 143 | SHA1_NEXTE(e1, m1); \ | ||
| 144 | OP(m0, m1, m2, m3); \ | ||
| 145 | |||
| 146 | #define R16(k, mx, OP0, OP1, OP2, OP3) \ | ||
| 147 | R4 ( (k)*4+0, e0,e1, m0,m1,m2,m3, OP0 ) \ | ||
| 148 | R4 ( (k)*4+1, e1,e0, m1,m2,m3,m0, OP1 ) \ | ||
| 149 | R4 ( (k)*4+2, e0,e1, m2,m3,m0,m1, OP2 ) \ | ||
| 150 | R4 ( (k)*4+3, e1,e0, m3,mx,m1,m2, OP3 ) \ | ||
| 151 | |||
| 152 | #define PREPARE_STATE \ | ||
| 153 | SHUFFLE_EPI32 (abcd, 0x1B); \ | ||
| 154 | SHUFFLE_EPI32 (e0, 0x1B); \ | ||
| 155 | |||
| 156 | |||
| 157 | |||
| 158 | |||
| 159 | |||
| 160 | void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks); | ||
| 161 | #ifdef ATTRIB_SHA | ||
| 162 | ATTRIB_SHA | ||
| 163 | #endif | ||
| 164 | void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks) | ||
| 165 | { | ||
| 166 | const __m128i mask = _mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f); | ||
| 167 | |||
| 168 | __m128i abcd, e0; | ||
| 169 | |||
| 170 | if (numBlocks == 0) | ||
| 171 | return; | ||
| 172 | |||
| 173 | abcd = _mm_loadu_si128((const __m128i *) (const void *) &state[0]); // dbca | ||
| 174 | e0 = _mm_cvtsi32_si128((int)state[4]); // 000e | ||
| 175 | |||
| 176 | PREPARE_STATE | ||
| 177 | |||
| 178 | do | ||
| 179 | { | ||
| 180 | __m128i abcd_save, e2; | ||
| 181 | __m128i m0, m1, m2, m3; | ||
| 182 | __m128i e1; | ||
| 183 | |||
| 184 | |||
| 185 | abcd_save = abcd; | ||
| 186 | e2 = e0; | ||
| 187 | |||
| 188 | LOAD_SHUFFLE (m0, 0) | ||
| 189 | LOAD_SHUFFLE (m1, 1) | ||
| 190 | LOAD_SHUFFLE (m2, 2) | ||
| 191 | LOAD_SHUFFLE (m3, 3) | ||
| 192 | |||
| 193 | ADD_EPI32(e0, m0); | ||
| 194 | |||
| 195 | R16 ( 0, m0, SM1, SM3, SM3, SM3 ); | ||
| 196 | R16 ( 1, m0, SM3, SM3, SM3, SM3 ); | ||
| 197 | R16 ( 2, m0, SM3, SM3, SM3, SM3 ); | ||
| 198 | R16 ( 3, m0, SM3, SM3, SM3, SM3 ); | ||
| 199 | R16 ( 4, e2, SM2, NNN, NNN, NNN ); | ||
| 200 | |||
| 201 | ADD_EPI32(abcd, abcd_save); | ||
| 202 | |||
| 203 | data += 64; | ||
| 204 | } | ||
| 205 | while (--numBlocks); | ||
| 206 | |||
| 207 | PREPARE_STATE | ||
| 208 | |||
| 209 | _mm_storeu_si128((__m128i *) (void *) state, abcd); | ||
| 210 | *(state+4) = (UInt32)_mm_cvtsi128_si32(e0); | ||
| 211 | } | ||
| 212 | |||
| 213 | #endif // USE_HW_SHA | ||
| 214 | |||
| 215 | #elif defined(MY_CPU_ARM_OR_ARM64) | ||
| 216 | |||
| 217 | #if defined(__clang__) | ||
| 218 | #if (__clang_major__ >= 8) // fix that check | ||
| 219 | #define USE_HW_SHA | ||
| 220 | #endif | ||
| 221 | #elif defined(__GNUC__) | ||
| 222 | #if (__GNUC__ >= 6) // fix that check | ||
| 223 | #define USE_HW_SHA | ||
| 224 | #endif | ||
| 225 | #elif defined(_MSC_VER) | ||
| 226 | #if _MSC_VER >= 1910 | ||
| 227 | #define USE_HW_SHA | ||
| 228 | #endif | ||
| 229 | #endif | ||
| 230 | |||
| 231 | #ifdef USE_HW_SHA | ||
| 232 | |||
| 233 | // #pragma message("=== Sha1 HW === ") | ||
| 234 | |||
| 235 | #if defined(__clang__) || defined(__GNUC__) | ||
| 236 | #ifdef MY_CPU_ARM64 | ||
| 237 | #define ATTRIB_SHA __attribute__((__target__("+crypto"))) | ||
| 238 | #else | ||
| 239 | #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) | ||
| 240 | #endif | ||
| 241 | #else | ||
| 242 | // _MSC_VER | ||
| 243 | // for arm32 | ||
| 244 | #define _ARM_USE_NEW_NEON_INTRINSICS | ||
| 245 | #endif | ||
| 246 | |||
| 247 | #if defined(_MSC_VER) && defined(MY_CPU_ARM64) | ||
| 248 | #include <arm64_neon.h> | ||
| 249 | #else | ||
| 250 | #include <arm_neon.h> | ||
| 251 | #endif | ||
| 252 | |||
| 253 | typedef uint32x4_t v128; | ||
| 254 | // typedef __n128 v128; // MSVC | ||
| 255 | |||
| 256 | #ifdef MY_CPU_BE | ||
| 257 | #define MY_rev32_for_LE(x) | ||
| 258 | #else | ||
| 259 | #define MY_rev32_for_LE(x) x = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(x))) | ||
| 260 | #endif | ||
| 261 | |||
| 262 | #define LOAD_128(_p) (*(const v128 *)(const void *)(_p)) | ||
| 263 | #define STORE_128(_p, _v) *(v128 *)(void *)(_p) = (_v) | ||
| 264 | |||
| 265 | #define LOAD_SHUFFLE(m, k) \ | ||
| 266 | m = LOAD_128((data + (k) * 16)); \ | ||
| 267 | MY_rev32_for_LE(m); \ | ||
| 268 | |||
| 269 | #define SU0(dest, src2, src3) dest = vsha1su0q_u32(dest, src2, src3); | ||
| 270 | #define SU1(dest, src) dest = vsha1su1q_u32(dest, src); | ||
| 271 | #define C(e) abcd = vsha1cq_u32(abcd, e, t); | ||
| 272 | #define P(e) abcd = vsha1pq_u32(abcd, e, t); | ||
| 273 | #define M(e) abcd = vsha1mq_u32(abcd, e, t); | ||
| 274 | #define H(e) e = vsha1h_u32(vgetq_lane_u32(abcd, 0)) | ||
| 275 | #define T(m, c) t = vaddq_u32(m, c) | ||
| 276 | |||
| 277 | void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); | ||
| 278 | #ifdef ATTRIB_SHA | ||
| 279 | ATTRIB_SHA | ||
| 280 | #endif | ||
| 281 | void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) | ||
| 282 | { | ||
| 283 | v128 abcd; | ||
| 284 | v128 c0, c1, c2, c3; | ||
| 285 | uint32_t e0; | ||
| 286 | |||
| 287 | if (numBlocks == 0) | ||
| 288 | return; | ||
| 289 | |||
| 290 | c0 = vdupq_n_u32(0x5a827999); | ||
| 291 | c1 = vdupq_n_u32(0x6ed9eba1); | ||
| 292 | c2 = vdupq_n_u32(0x8f1bbcdc); | ||
| 293 | c3 = vdupq_n_u32(0xca62c1d6); | ||
| 294 | |||
| 295 | abcd = LOAD_128(&state[0]); | ||
| 296 | e0 = state[4]; | ||
| 297 | |||
| 298 | do | ||
| 299 | { | ||
| 300 | v128 abcd_save; | ||
| 301 | v128 m0, m1, m2, m3; | ||
| 302 | v128 t; | ||
| 303 | uint32_t e0_save, e1; | ||
| 304 | |||
| 305 | abcd_save = abcd; | ||
| 306 | e0_save = e0; | ||
| 307 | |||
| 308 | LOAD_SHUFFLE (m0, 0) | ||
| 309 | LOAD_SHUFFLE (m1, 1) | ||
| 310 | LOAD_SHUFFLE (m2, 2) | ||
| 311 | LOAD_SHUFFLE (m3, 3) | ||
| 312 | |||
| 313 | T(m0, c0); H(e1); C(e0); | ||
| 314 | T(m1, c0); SU0(m0, m1, m2); H(e0); C(e1); | ||
| 315 | T(m2, c0); SU0(m1, m2, m3); SU1(m0, m3); H(e1); C(e0); | ||
| 316 | T(m3, c0); SU0(m2, m3, m0); SU1(m1, m0); H(e0); C(e1); | ||
| 317 | T(m0, c0); SU0(m3, m0, m1); SU1(m2, m1); H(e1); C(e0); | ||
| 318 | T(m1, c1); SU0(m0, m1, m2); SU1(m3, m2); H(e0); P(e1); | ||
| 319 | T(m2, c1); SU0(m1, m2, m3); SU1(m0, m3); H(e1); P(e0); | ||
| 320 | T(m3, c1); SU0(m2, m3, m0); SU1(m1, m0); H(e0); P(e1); | ||
| 321 | T(m0, c1); SU0(m3, m0, m1); SU1(m2, m1); H(e1); P(e0); | ||
| 322 | T(m1, c1); SU0(m0, m1, m2); SU1(m3, m2); H(e0); P(e1); | ||
| 323 | T(m2, c2); SU0(m1, m2, m3); SU1(m0, m3); H(e1); M(e0); | ||
| 324 | T(m3, c2); SU0(m2, m3, m0); SU1(m1, m0); H(e0); M(e1); | ||
| 325 | T(m0, c2); SU0(m3, m0, m1); SU1(m2, m1); H(e1); M(e0); | ||
| 326 | T(m1, c2); SU0(m0, m1, m2); SU1(m3, m2); H(e0); M(e1); | ||
| 327 | T(m2, c2); SU0(m1, m2, m3); SU1(m0, m3); H(e1); M(e0); | ||
| 328 | T(m3, c3); SU0(m2, m3, m0); SU1(m1, m0); H(e0); P(e1); | ||
| 329 | T(m0, c3); SU0(m3, m0, m1); SU1(m2, m1); H(e1); P(e0); | ||
| 330 | T(m1, c3); SU1(m3, m2); H(e0); P(e1); | ||
| 331 | T(m2, c3); H(e1); P(e0); | ||
| 332 | T(m3, c3); H(e0); P(e1); | ||
| 333 | |||
| 334 | abcd = vaddq_u32(abcd, abcd_save); | ||
| 335 | e0 += e0_save; | ||
| 336 | |||
| 337 | data += 64; | ||
| 338 | } | ||
| 339 | while (--numBlocks); | ||
| 340 | |||
| 341 | STORE_128(&state[0], abcd); | ||
| 342 | state[4] = e0; | ||
| 343 | } | ||
| 344 | |||
| 345 | #endif // USE_HW_SHA | ||
| 346 | |||
| 347 | #endif // MY_CPU_ARM_OR_ARM64 | ||
| 348 | |||
| 349 | |||
| 350 | #ifndef USE_HW_SHA | ||
| 351 | |||
| 352 | // #error Stop_Compiling_UNSUPPORTED_SHA | ||
| 353 | // #include <stdlib.h> | ||
| 354 | |||
| 355 | // #include "Sha1.h" | ||
| 356 | void MY_FAST_CALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks); | ||
| 357 | |||
| 358 | #pragma message("Sha1 HW-SW stub was used") | ||
| 359 | |||
| 360 | void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks); | ||
| 361 | void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks) | ||
| 362 | { | ||
| 363 | Sha1_UpdateBlocks(state, data, numBlocks); | ||
| 364 | /* | ||
| 365 | UNUSED_VAR(state); | ||
| 366 | UNUSED_VAR(data); | ||
| 367 | UNUSED_VAR(numBlocks); | ||
| 368 | exit(1); | ||
| 369 | return; | ||
| 370 | */ | ||
| 371 | } | ||
| 372 | |||
| 373 | #endif | ||
diff --git a/C/Sha256.c b/C/Sha256.c new file mode 100644 index 0000000..8b3983e --- /dev/null +++ b/C/Sha256.c | |||
| @@ -0,0 +1,486 @@ | |||
| 1 | /* Sha256.c -- SHA-256 Hash | ||
| 2 | 2021-04-01 : Igor Pavlov : Public domain | ||
| 3 | This code is based on public domain code from Wei Dai's Crypto++ library. */ | ||
| 4 | |||
| 5 | #include "Precomp.h" | ||
| 6 | |||
| 7 | #include <string.h> | ||
| 8 | |||
| 9 | #include "CpuArch.h" | ||
| 10 | #include "RotateDefs.h" | ||
| 11 | #include "Sha256.h" | ||
| 12 | |||
| 13 | #if defined(_MSC_VER) && (_MSC_VER < 1900) | ||
| 14 | // #define USE_MY_MM | ||
| 15 | #endif | ||
| 16 | |||
| 17 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 18 | #ifdef _MSC_VER | ||
| 19 | #if _MSC_VER >= 1200 | ||
| 20 | #define _SHA_SUPPORTED | ||
| 21 | #endif | ||
| 22 | #elif defined(__clang__) | ||
| 23 | #if (__clang_major__ >= 8) // fix that check | ||
| 24 | #define _SHA_SUPPORTED | ||
| 25 | #endif | ||
| 26 | #elif defined(__GNUC__) | ||
| 27 | #if (__GNUC__ >= 8) // fix that check | ||
| 28 | #define _SHA_SUPPORTED | ||
| 29 | #endif | ||
| 30 | #elif defined(__INTEL_COMPILER) | ||
| 31 | #if (__INTEL_COMPILER >= 1800) // fix that check | ||
| 32 | #define _SHA_SUPPORTED | ||
| 33 | #endif | ||
| 34 | #endif | ||
| 35 | #elif defined(MY_CPU_ARM_OR_ARM64) | ||
| 36 | #ifdef _MSC_VER | ||
| 37 | #if _MSC_VER >= 1910 | ||
| 38 | #define _SHA_SUPPORTED | ||
| 39 | #endif | ||
| 40 | #elif defined(__clang__) | ||
| 41 | #if (__clang_major__ >= 8) // fix that check | ||
| 42 | #define _SHA_SUPPORTED | ||
| 43 | #endif | ||
| 44 | #elif defined(__GNUC__) | ||
| 45 | #if (__GNUC__ >= 6) // fix that check | ||
| 46 | #define _SHA_SUPPORTED | ||
| 47 | #endif | ||
| 48 | #endif | ||
| 49 | #endif | ||
| 50 | |||
| 51 | void MY_FAST_CALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); | ||
| 52 | |||
| 53 | #ifdef _SHA_SUPPORTED | ||
| 54 | void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); | ||
| 55 | |||
| 56 | static SHA256_FUNC_UPDATE_BLOCKS g_FUNC_UPDATE_BLOCKS = Sha256_UpdateBlocks; | ||
| 57 | static SHA256_FUNC_UPDATE_BLOCKS g_FUNC_UPDATE_BLOCKS_HW; | ||
| 58 | |||
| 59 | #define UPDATE_BLOCKS(p) p->func_UpdateBlocks | ||
| 60 | #else | ||
| 61 | #define UPDATE_BLOCKS(p) Sha256_UpdateBlocks | ||
| 62 | #endif | ||
| 63 | |||
| 64 | |||
| 65 | BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo) | ||
| 66 | { | ||
| 67 | SHA256_FUNC_UPDATE_BLOCKS func = Sha256_UpdateBlocks; | ||
| 68 | |||
| 69 | #ifdef _SHA_SUPPORTED | ||
| 70 | if (algo != SHA256_ALGO_SW) | ||
| 71 | { | ||
| 72 | if (algo == SHA256_ALGO_DEFAULT) | ||
| 73 | func = g_FUNC_UPDATE_BLOCKS; | ||
| 74 | else | ||
| 75 | { | ||
| 76 | if (algo != SHA256_ALGO_HW) | ||
| 77 | return False; | ||
| 78 | func = g_FUNC_UPDATE_BLOCKS_HW; | ||
| 79 | if (!func) | ||
| 80 | return False; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | #else | ||
| 84 | if (algo > 1) | ||
| 85 | return False; | ||
| 86 | #endif | ||
| 87 | |||
| 88 | p->func_UpdateBlocks = func; | ||
| 89 | return True; | ||
| 90 | } | ||
| 91 | |||
| 92 | |||
| 93 | /* define it for speed optimization */ | ||
| 94 | |||
| 95 | #ifdef _SFX | ||
| 96 | #define STEP_PRE 1 | ||
| 97 | #define STEP_MAIN 1 | ||
| 98 | #else | ||
| 99 | #define STEP_PRE 2 | ||
| 100 | #define STEP_MAIN 4 | ||
| 101 | // #define _SHA256_UNROLL | ||
| 102 | #endif | ||
| 103 | |||
| 104 | #if STEP_MAIN != 16 | ||
| 105 | #define _SHA256_BIG_W | ||
| 106 | #endif | ||
| 107 | |||
| 108 | |||
| 109 | |||
| 110 | |||
| 111 | void Sha256_InitState(CSha256 *p) | ||
| 112 | { | ||
| 113 | p->count = 0; | ||
| 114 | p->state[0] = 0x6a09e667; | ||
| 115 | p->state[1] = 0xbb67ae85; | ||
| 116 | p->state[2] = 0x3c6ef372; | ||
| 117 | p->state[3] = 0xa54ff53a; | ||
| 118 | p->state[4] = 0x510e527f; | ||
| 119 | p->state[5] = 0x9b05688c; | ||
| 120 | p->state[6] = 0x1f83d9ab; | ||
| 121 | p->state[7] = 0x5be0cd19; | ||
| 122 | } | ||
| 123 | |||
| 124 | void Sha256_Init(CSha256 *p) | ||
| 125 | { | ||
| 126 | p->func_UpdateBlocks = | ||
| 127 | #ifdef _SHA_SUPPORTED | ||
| 128 | g_FUNC_UPDATE_BLOCKS; | ||
| 129 | #else | ||
| 130 | NULL; | ||
| 131 | #endif | ||
| 132 | Sha256_InitState(p); | ||
| 133 | } | ||
| 134 | |||
| 135 | #define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22)) | ||
| 136 | #define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25)) | ||
| 137 | #define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) | ||
| 138 | #define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10)) | ||
| 139 | |||
| 140 | #define Ch(x,y,z) (z^(x&(y^z))) | ||
| 141 | #define Maj(x,y,z) ((x&y)|(z&(x|y))) | ||
| 142 | |||
| 143 | |||
| 144 | #define W_PRE(i) (W[(i) + (size_t)(j)] = GetBe32(data + ((size_t)(j) + i) * 4)) | ||
| 145 | |||
| 146 | #define blk2_main(j, i) s1(w(j, (i)-2)) + w(j, (i)-7) + s0(w(j, (i)-15)) | ||
| 147 | |||
| 148 | #ifdef _SHA256_BIG_W | ||
| 149 | // we use +i instead of +(i) to change the order to solve CLANG compiler warning for signed/unsigned. | ||
| 150 | #define w(j, i) W[(size_t)(j) + i] | ||
| 151 | #define blk2(j, i) (w(j, i) = w(j, (i)-16) + blk2_main(j, i)) | ||
| 152 | #else | ||
| 153 | #if STEP_MAIN == 16 | ||
| 154 | #define w(j, i) W[(i) & 15] | ||
| 155 | #else | ||
| 156 | #define w(j, i) W[((size_t)(j) + (i)) & 15] | ||
| 157 | #endif | ||
| 158 | #define blk2(j, i) (w(j, i) += blk2_main(j, i)) | ||
| 159 | #endif | ||
| 160 | |||
| 161 | #define W_MAIN(i) blk2(j, i) | ||
| 162 | |||
| 163 | |||
| 164 | #define T1(wx, i) \ | ||
| 165 | tmp = h + S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ | ||
| 166 | h = g; \ | ||
| 167 | g = f; \ | ||
| 168 | f = e; \ | ||
| 169 | e = d + tmp; \ | ||
| 170 | tmp += S0(a) + Maj(a, b, c); \ | ||
| 171 | d = c; \ | ||
| 172 | c = b; \ | ||
| 173 | b = a; \ | ||
| 174 | a = tmp; \ | ||
| 175 | |||
| 176 | #define R1_PRE(i) T1( W_PRE, i) | ||
| 177 | #define R1_MAIN(i) T1( W_MAIN, i) | ||
| 178 | |||
| 179 | #if (!defined(_SHA256_UNROLL) || STEP_MAIN < 8) && (STEP_MAIN >= 4) | ||
| 180 | #define R2_MAIN(i) \ | ||
| 181 | R1_MAIN(i) \ | ||
| 182 | R1_MAIN(i + 1) \ | ||
| 183 | |||
| 184 | #endif | ||
| 185 | |||
| 186 | |||
| 187 | |||
| 188 | #if defined(_SHA256_UNROLL) && STEP_MAIN >= 8 | ||
| 189 | |||
| 190 | #define T4( a,b,c,d,e,f,g,h, wx, i) \ | ||
| 191 | h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ | ||
| 192 | tmp = h; \ | ||
| 193 | h += d; \ | ||
| 194 | d = tmp + S0(a) + Maj(a, b, c); \ | ||
| 195 | |||
| 196 | #define R4( wx, i) \ | ||
| 197 | T4 ( a,b,c,d,e,f,g,h, wx, (i )); \ | ||
| 198 | T4 ( d,a,b,c,h,e,f,g, wx, (i+1)); \ | ||
| 199 | T4 ( c,d,a,b,g,h,e,f, wx, (i+2)); \ | ||
| 200 | T4 ( b,c,d,a,f,g,h,e, wx, (i+3)); \ | ||
| 201 | |||
| 202 | #define R4_PRE(i) R4( W_PRE, i) | ||
| 203 | #define R4_MAIN(i) R4( W_MAIN, i) | ||
| 204 | |||
| 205 | |||
| 206 | #define T8( a,b,c,d,e,f,g,h, wx, i) \ | ||
| 207 | h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ | ||
| 208 | d += h; \ | ||
| 209 | h += S0(a) + Maj(a, b, c); \ | ||
| 210 | |||
| 211 | #define R8( wx, i) \ | ||
| 212 | T8 ( a,b,c,d,e,f,g,h, wx, i ); \ | ||
| 213 | T8 ( h,a,b,c,d,e,f,g, wx, i+1); \ | ||
| 214 | T8 ( g,h,a,b,c,d,e,f, wx, i+2); \ | ||
| 215 | T8 ( f,g,h,a,b,c,d,e, wx, i+3); \ | ||
| 216 | T8 ( e,f,g,h,a,b,c,d, wx, i+4); \ | ||
| 217 | T8 ( d,e,f,g,h,a,b,c, wx, i+5); \ | ||
| 218 | T8 ( c,d,e,f,g,h,a,b, wx, i+6); \ | ||
| 219 | T8 ( b,c,d,e,f,g,h,a, wx, i+7); \ | ||
| 220 | |||
| 221 | #define R8_PRE(i) R8( W_PRE, i) | ||
| 222 | #define R8_MAIN(i) R8( W_MAIN, i) | ||
| 223 | |||
| 224 | #endif | ||
| 225 | |||
| 226 | void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); | ||
| 227 | |||
| 228 | // static | ||
| 229 | extern MY_ALIGN(64) | ||
| 230 | const UInt32 SHA256_K_ARRAY[64]; | ||
| 231 | |||
| 232 | MY_ALIGN(64) | ||
| 233 | const UInt32 SHA256_K_ARRAY[64] = { | ||
| 234 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, | ||
| 235 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, | ||
| 236 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, | ||
| 237 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, | ||
| 238 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, | ||
| 239 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, | ||
| 240 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, | ||
| 241 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, | ||
| 242 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, | ||
| 243 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, | ||
| 244 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, | ||
| 245 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, | ||
| 246 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, | ||
| 247 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, | ||
| 248 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, | ||
| 249 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 | ||
| 250 | }; | ||
| 251 | |||
| 252 | #define K SHA256_K_ARRAY | ||
| 253 | |||
| 254 | |||
| 255 | MY_NO_INLINE | ||
| 256 | void MY_FAST_CALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks) | ||
| 257 | { | ||
| 258 | UInt32 W | ||
| 259 | #ifdef _SHA256_BIG_W | ||
| 260 | [64]; | ||
| 261 | #else | ||
| 262 | [16]; | ||
| 263 | #endif | ||
| 264 | |||
| 265 | unsigned j; | ||
| 266 | |||
| 267 | UInt32 a,b,c,d,e,f,g,h; | ||
| 268 | |||
| 269 | #if !defined(_SHA256_UNROLL) || (STEP_MAIN <= 4) || (STEP_PRE <= 4) | ||
| 270 | UInt32 tmp; | ||
| 271 | #endif | ||
| 272 | |||
| 273 | a = state[0]; | ||
| 274 | b = state[1]; | ||
| 275 | c = state[2]; | ||
| 276 | d = state[3]; | ||
| 277 | e = state[4]; | ||
| 278 | f = state[5]; | ||
| 279 | g = state[6]; | ||
| 280 | h = state[7]; | ||
| 281 | |||
| 282 | while (numBlocks) | ||
| 283 | { | ||
| 284 | |||
| 285 | for (j = 0; j < 16; j += STEP_PRE) | ||
| 286 | { | ||
| 287 | #if STEP_PRE > 4 | ||
| 288 | |||
| 289 | #if STEP_PRE < 8 | ||
| 290 | R4_PRE(0); | ||
| 291 | #else | ||
| 292 | R8_PRE(0); | ||
| 293 | #if STEP_PRE == 16 | ||
| 294 | R8_PRE(8); | ||
| 295 | #endif | ||
| 296 | #endif | ||
| 297 | |||
| 298 | #else | ||
| 299 | |||
| 300 | R1_PRE(0); | ||
| 301 | #if STEP_PRE >= 2 | ||
| 302 | R1_PRE(1); | ||
| 303 | #if STEP_PRE >= 4 | ||
| 304 | R1_PRE(2); | ||
| 305 | R1_PRE(3); | ||
| 306 | #endif | ||
| 307 | #endif | ||
| 308 | |||
| 309 | #endif | ||
| 310 | } | ||
| 311 | |||
| 312 | for (j = 16; j < 64; j += STEP_MAIN) | ||
| 313 | { | ||
| 314 | #if defined(_SHA256_UNROLL) && STEP_MAIN >= 8 | ||
| 315 | |||
| 316 | #if STEP_MAIN < 8 | ||
| 317 | R4_MAIN(0); | ||
| 318 | #else | ||
| 319 | R8_MAIN(0); | ||
| 320 | #if STEP_MAIN == 16 | ||
| 321 | R8_MAIN(8); | ||
| 322 | #endif | ||
| 323 | #endif | ||
| 324 | |||
| 325 | #else | ||
| 326 | |||
| 327 | R1_MAIN(0); | ||
| 328 | #if STEP_MAIN >= 2 | ||
| 329 | R1_MAIN(1); | ||
| 330 | #if STEP_MAIN >= 4 | ||
| 331 | R2_MAIN(2); | ||
| 332 | #if STEP_MAIN >= 8 | ||
| 333 | R2_MAIN(4); | ||
| 334 | R2_MAIN(6); | ||
| 335 | #if STEP_MAIN >= 16 | ||
| 336 | R2_MAIN(8); | ||
| 337 | R2_MAIN(10); | ||
| 338 | R2_MAIN(12); | ||
| 339 | R2_MAIN(14); | ||
| 340 | #endif | ||
| 341 | #endif | ||
| 342 | #endif | ||
| 343 | #endif | ||
| 344 | #endif | ||
| 345 | } | ||
| 346 | |||
| 347 | a += state[0]; state[0] = a; | ||
| 348 | b += state[1]; state[1] = b; | ||
| 349 | c += state[2]; state[2] = c; | ||
| 350 | d += state[3]; state[3] = d; | ||
| 351 | e += state[4]; state[4] = e; | ||
| 352 | f += state[5]; state[5] = f; | ||
| 353 | g += state[6]; state[6] = g; | ||
| 354 | h += state[7]; state[7] = h; | ||
| 355 | |||
| 356 | data += 64; | ||
| 357 | numBlocks--; | ||
| 358 | } | ||
| 359 | |||
| 360 | /* Wipe variables */ | ||
| 361 | /* memset(W, 0, sizeof(W)); */ | ||
| 362 | } | ||
| 363 | |||
| 364 | #undef S0 | ||
| 365 | #undef S1 | ||
| 366 | #undef s0 | ||
| 367 | #undef s1 | ||
| 368 | #undef K | ||
| 369 | |||
| 370 | #define Sha256_UpdateBlock(p) UPDATE_BLOCKS(p)(p->state, p->buffer, 1) | ||
| 371 | |||
| 372 | void Sha256_Update(CSha256 *p, const Byte *data, size_t size) | ||
| 373 | { | ||
| 374 | if (size == 0) | ||
| 375 | return; | ||
| 376 | |||
| 377 | { | ||
| 378 | unsigned pos = (unsigned)p->count & 0x3F; | ||
| 379 | unsigned num; | ||
| 380 | |||
| 381 | p->count += size; | ||
| 382 | |||
| 383 | num = 64 - pos; | ||
| 384 | if (num > size) | ||
| 385 | { | ||
| 386 | memcpy(p->buffer + pos, data, size); | ||
| 387 | return; | ||
| 388 | } | ||
| 389 | |||
| 390 | if (pos != 0) | ||
| 391 | { | ||
| 392 | size -= num; | ||
| 393 | memcpy(p->buffer + pos, data, num); | ||
| 394 | data += num; | ||
| 395 | Sha256_UpdateBlock(p); | ||
| 396 | } | ||
| 397 | } | ||
| 398 | { | ||
| 399 | size_t numBlocks = size >> 6; | ||
| 400 | UPDATE_BLOCKS(p)(p->state, data, numBlocks); | ||
| 401 | size &= 0x3F; | ||
| 402 | if (size == 0) | ||
| 403 | return; | ||
| 404 | data += (numBlocks << 6); | ||
| 405 | memcpy(p->buffer, data, size); | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | |||
| 410 | void Sha256_Final(CSha256 *p, Byte *digest) | ||
| 411 | { | ||
| 412 | unsigned pos = (unsigned)p->count & 0x3F; | ||
| 413 | unsigned i; | ||
| 414 | |||
| 415 | p->buffer[pos++] = 0x80; | ||
| 416 | |||
| 417 | if (pos > (64 - 8)) | ||
| 418 | { | ||
| 419 | while (pos != 64) { p->buffer[pos++] = 0; } | ||
| 420 | // memset(&p->buf.buffer[pos], 0, 64 - pos); | ||
| 421 | Sha256_UpdateBlock(p); | ||
| 422 | pos = 0; | ||
| 423 | } | ||
| 424 | |||
| 425 | /* | ||
| 426 | if (pos & 3) | ||
| 427 | { | ||
| 428 | p->buffer[pos] = 0; | ||
| 429 | p->buffer[pos + 1] = 0; | ||
| 430 | p->buffer[pos + 2] = 0; | ||
| 431 | pos += 3; | ||
| 432 | pos &= ~3; | ||
| 433 | } | ||
| 434 | { | ||
| 435 | for (; pos < 64 - 8; pos += 4) | ||
| 436 | *(UInt32 *)(&p->buffer[pos]) = 0; | ||
| 437 | } | ||
| 438 | */ | ||
| 439 | |||
| 440 | memset(&p->buffer[pos], 0, (64 - 8) - pos); | ||
| 441 | |||
| 442 | { | ||
| 443 | UInt64 numBits = (p->count << 3); | ||
| 444 | SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32)); | ||
| 445 | SetBe32(p->buffer + 64 - 4, (UInt32)(numBits)); | ||
| 446 | } | ||
| 447 | |||
| 448 | Sha256_UpdateBlock(p); | ||
| 449 | |||
| 450 | for (i = 0; i < 8; i += 2) | ||
| 451 | { | ||
| 452 | UInt32 v0 = p->state[i]; | ||
| 453 | UInt32 v1 = p->state[(size_t)i + 1]; | ||
| 454 | SetBe32(digest , v0); | ||
| 455 | SetBe32(digest + 4, v1); | ||
| 456 | digest += 8; | ||
| 457 | } | ||
| 458 | |||
| 459 | Sha256_InitState(p); | ||
| 460 | } | ||
| 461 | |||
| 462 | |||
| 463 | void Sha256Prepare() | ||
| 464 | { | ||
| 465 | #ifdef _SHA_SUPPORTED | ||
| 466 | SHA256_FUNC_UPDATE_BLOCKS f, f_hw; | ||
| 467 | f = Sha256_UpdateBlocks; | ||
| 468 | f_hw = NULL; | ||
| 469 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 470 | #ifndef USE_MY_MM | ||
| 471 | if (CPU_IsSupported_SHA() | ||
| 472 | && CPU_IsSupported_SSSE3() | ||
| 473 | // && CPU_IsSupported_SSE41() | ||
| 474 | ) | ||
| 475 | #endif | ||
| 476 | #else | ||
| 477 | if (CPU_IsSupported_SHA2()) | ||
| 478 | #endif | ||
| 479 | { | ||
| 480 | // printf("\n========== HW SHA256 ======== \n"); | ||
| 481 | f = f_hw = Sha256_UpdateBlocks_HW; | ||
| 482 | } | ||
| 483 | g_FUNC_UPDATE_BLOCKS = f; | ||
| 484 | g_FUNC_UPDATE_BLOCKS_HW = f_hw; | ||
| 485 | #endif | ||
| 486 | } | ||
diff --git a/C/Sha256.h b/C/Sha256.h new file mode 100644 index 0000000..aa38501 --- /dev/null +++ b/C/Sha256.h | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /* Sha256.h -- SHA-256 Hash | ||
| 2 | 2021-01-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_SHA256_H | ||
| 5 | #define __7Z_SHA256_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define SHA256_NUM_BLOCK_WORDS 16 | ||
| 12 | #define SHA256_NUM_DIGEST_WORDS 8 | ||
| 13 | |||
| 14 | #define SHA256_BLOCK_SIZE (SHA256_NUM_BLOCK_WORDS * 4) | ||
| 15 | #define SHA256_DIGEST_SIZE (SHA256_NUM_DIGEST_WORDS * 4) | ||
| 16 | |||
| 17 | typedef void (MY_FAST_CALL *SHA256_FUNC_UPDATE_BLOCKS)(UInt32 state[8], const Byte *data, size_t numBlocks); | ||
| 18 | |||
| 19 | /* | ||
| 20 | if (the system supports different SHA256 code implementations) | ||
| 21 | { | ||
| 22 | (CSha256::func_UpdateBlocks) will be used | ||
| 23 | (CSha256::func_UpdateBlocks) can be set by | ||
| 24 | Sha256_Init() - to default (fastest) | ||
| 25 | Sha256_SetFunction() - to any algo | ||
| 26 | } | ||
| 27 | else | ||
| 28 | { | ||
| 29 | (CSha256::func_UpdateBlocks) is ignored. | ||
| 30 | } | ||
| 31 | */ | ||
| 32 | |||
| 33 | typedef struct | ||
| 34 | { | ||
| 35 | SHA256_FUNC_UPDATE_BLOCKS func_UpdateBlocks; | ||
| 36 | UInt64 count; | ||
| 37 | UInt64 __pad_2[2]; | ||
| 38 | UInt32 state[SHA256_NUM_DIGEST_WORDS]; | ||
| 39 | |||
| 40 | Byte buffer[SHA256_BLOCK_SIZE]; | ||
| 41 | } CSha256; | ||
| 42 | |||
| 43 | |||
| 44 | #define SHA256_ALGO_DEFAULT 0 | ||
| 45 | #define SHA256_ALGO_SW 1 | ||
| 46 | #define SHA256_ALGO_HW 2 | ||
| 47 | |||
| 48 | /* | ||
| 49 | Sha256_SetFunction() | ||
| 50 | return: | ||
| 51 | 0 - (algo) value is not supported, and func_UpdateBlocks was not changed | ||
| 52 | 1 - func_UpdateBlocks was set according (algo) value. | ||
| 53 | */ | ||
| 54 | |||
| 55 | BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo); | ||
| 56 | |||
| 57 | void Sha256_InitState(CSha256 *p); | ||
| 58 | void Sha256_Init(CSha256 *p); | ||
| 59 | void Sha256_Update(CSha256 *p, const Byte *data, size_t size); | ||
| 60 | void Sha256_Final(CSha256 *p, Byte *digest); | ||
| 61 | |||
| 62 | |||
| 63 | |||
| 64 | |||
| 65 | // void MY_FAST_CALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); | ||
| 66 | |||
| 67 | /* | ||
| 68 | call Sha256Prepare() once at program start. | ||
| 69 | It prepares all supported implementations, and detects the fastest implementation. | ||
| 70 | */ | ||
| 71 | |||
| 72 | void Sha256Prepare(void); | ||
| 73 | |||
| 74 | EXTERN_C_END | ||
| 75 | |||
| 76 | #endif | ||
diff --git a/C/Sha256Opt.c b/C/Sha256Opt.c new file mode 100644 index 0000000..decc138 --- /dev/null +++ b/C/Sha256Opt.c | |||
| @@ -0,0 +1,373 @@ | |||
| 1 | /* Sha256Opt.c -- SHA-256 optimized code for SHA-256 hardware instructions | ||
| 2 | 2021-04-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #if defined(_MSC_VER) | ||
| 7 | #if (_MSC_VER < 1900) && (_MSC_VER >= 1200) | ||
| 8 | // #define USE_MY_MM | ||
| 9 | #endif | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #include "CpuArch.h" | ||
| 13 | |||
| 14 | #ifdef MY_CPU_X86_OR_AMD64 | ||
| 15 | #if defined(__clang__) | ||
| 16 | #if (__clang_major__ >= 8) // fix that check | ||
| 17 | #define USE_HW_SHA | ||
| 18 | #ifndef __SHA__ | ||
| 19 | #define ATTRIB_SHA __attribute__((__target__("sha,ssse3"))) | ||
| 20 | #if defined(_MSC_VER) | ||
| 21 | // SSSE3: for clang-cl: | ||
| 22 | #include <tmmintrin.h> | ||
| 23 | #define __SHA__ | ||
| 24 | #endif | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #endif | ||
| 28 | #elif defined(__GNUC__) | ||
| 29 | #if (__GNUC__ >= 8) // fix that check | ||
| 30 | #define USE_HW_SHA | ||
| 31 | #ifndef __SHA__ | ||
| 32 | #define ATTRIB_SHA __attribute__((__target__("sha,ssse3"))) | ||
| 33 | // #pragma GCC target("sha,ssse3") | ||
| 34 | #endif | ||
| 35 | #endif | ||
| 36 | #elif defined(__INTEL_COMPILER) | ||
| 37 | #if (__INTEL_COMPILER >= 1800) // fix that check | ||
| 38 | #define USE_HW_SHA | ||
| 39 | #endif | ||
| 40 | #elif defined(_MSC_VER) | ||
| 41 | #ifdef USE_MY_MM | ||
| 42 | #define USE_VER_MIN 1300 | ||
| 43 | #else | ||
| 44 | #define USE_VER_MIN 1910 | ||
| 45 | #endif | ||
| 46 | #if _MSC_VER >= USE_VER_MIN | ||
| 47 | #define USE_HW_SHA | ||
| 48 | #endif | ||
| 49 | #endif | ||
| 50 | // #endif // MY_CPU_X86_OR_AMD64 | ||
| 51 | |||
| 52 | #ifdef USE_HW_SHA | ||
| 53 | |||
| 54 | // #pragma message("Sha256 HW") | ||
| 55 | // #include <wmmintrin.h> | ||
| 56 | |||
| 57 | #if !defined(_MSC_VER) || (_MSC_VER >= 1900) | ||
| 58 | #include <immintrin.h> | ||
| 59 | #else | ||
| 60 | #include <emmintrin.h> | ||
| 61 | |||
| 62 | #if defined(_MSC_VER) && (_MSC_VER >= 1600) | ||
| 63 | // #include <intrin.h> | ||
| 64 | #endif | ||
| 65 | |||
| 66 | #ifdef USE_MY_MM | ||
| 67 | #include "My_mm.h" | ||
| 68 | #endif | ||
| 69 | |||
| 70 | #endif | ||
| 71 | |||
| 72 | /* | ||
| 73 | SHA256 uses: | ||
| 74 | SSE2: | ||
| 75 | _mm_loadu_si128 | ||
| 76 | _mm_storeu_si128 | ||
| 77 | _mm_set_epi32 | ||
| 78 | _mm_add_epi32 | ||
| 79 | _mm_shuffle_epi32 / pshufd | ||
| 80 | |||
| 81 | |||
| 82 | |||
| 83 | SSSE3: | ||
| 84 | _mm_shuffle_epi8 / pshufb | ||
| 85 | _mm_alignr_epi8 | ||
| 86 | SHA: | ||
| 87 | _mm_sha256* | ||
| 88 | */ | ||
| 89 | |||
| 90 | // K array must be aligned for 16-bytes at least. | ||
| 91 | // The compiler can look align attribute and selects | ||
| 92 | // movdqu - for code without align attribute | ||
| 93 | // movdqa - for code with align attribute | ||
| 94 | extern | ||
| 95 | MY_ALIGN(64) | ||
| 96 | const UInt32 SHA256_K_ARRAY[64]; | ||
| 97 | |||
| 98 | #define K SHA256_K_ARRAY | ||
| 99 | |||
| 100 | |||
| 101 | #define ADD_EPI32(dest, src) dest = _mm_add_epi32(dest, src); | ||
| 102 | #define SHA256_MSG1(dest, src) dest = _mm_sha256msg1_epu32(dest, src); | ||
| 103 | #define SHA25G_MSG2(dest, src) dest = _mm_sha256msg2_epu32(dest, src); | ||
| 104 | |||
| 105 | |||
| 106 | #define LOAD_SHUFFLE(m, k) \ | ||
| 107 | m = _mm_loadu_si128((const __m128i *)(const void *)(data + (k) * 16)); \ | ||
| 108 | m = _mm_shuffle_epi8(m, mask); \ | ||
| 109 | |||
| 110 | #define SM1(g0, g1, g2, g3) \ | ||
| 111 | SHA256_MSG1(g3, g0); \ | ||
| 112 | |||
| 113 | #define SM2(g0, g1, g2, g3) \ | ||
| 114 | tmp = _mm_alignr_epi8(g1, g0, 4); \ | ||
| 115 | ADD_EPI32(g2, tmp); \ | ||
| 116 | SHA25G_MSG2(g2, g1); \ | ||
| 117 | |||
| 118 | // #define LS0(k, g0, g1, g2, g3) LOAD_SHUFFLE(g0, k) | ||
| 119 | // #define LS1(k, g0, g1, g2, g3) LOAD_SHUFFLE(g1, k+1) | ||
| 120 | |||
| 121 | |||
| 122 | #define NNN(g0, g1, g2, g3) | ||
| 123 | |||
| 124 | |||
| 125 | #define RND2(t0, t1) \ | ||
| 126 | t0 = _mm_sha256rnds2_epu32(t0, t1, msg); | ||
| 127 | |||
| 128 | #define RND2_0(m, k) \ | ||
| 129 | msg = _mm_add_epi32(m, *(const __m128i *) (const void *) &K[(k) * 4]); \ | ||
| 130 | RND2(state0, state1); \ | ||
| 131 | msg = _mm_shuffle_epi32(msg, 0x0E); \ | ||
| 132 | |||
| 133 | |||
| 134 | #define RND2_1 \ | ||
| 135 | RND2(state1, state0); \ | ||
| 136 | |||
| 137 | |||
| 138 | // We use scheme with 3 rounds ahead for SHA256_MSG1 / 2 rounds ahead for SHA256_MSG2 | ||
| 139 | |||
| 140 | #define R4(k, g0, g1, g2, g3, OP0, OP1) \ | ||
| 141 | RND2_0(g0, k); \ | ||
| 142 | OP0(g0, g1, g2, g3); \ | ||
| 143 | RND2_1; \ | ||
| 144 | OP1(g0, g1, g2, g3); \ | ||
| 145 | |||
| 146 | #define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \ | ||
| 147 | R4 ( (k)*4+0, m0, m1, m2, m3, OP0, OP1 ) \ | ||
| 148 | R4 ( (k)*4+1, m1, m2, m3, m0, OP2, OP3 ) \ | ||
| 149 | R4 ( (k)*4+2, m2, m3, m0, m1, OP4, OP5 ) \ | ||
| 150 | R4 ( (k)*4+3, m3, m0, m1, m2, OP6, OP7 ) \ | ||
| 151 | |||
| 152 | #define PREPARE_STATE \ | ||
| 153 | tmp = _mm_shuffle_epi32(state0, 0x1B); /* abcd */ \ | ||
| 154 | state0 = _mm_shuffle_epi32(state1, 0x1B); /* efgh */ \ | ||
| 155 | state1 = state0; \ | ||
| 156 | state0 = _mm_unpacklo_epi64(state0, tmp); /* cdgh */ \ | ||
| 157 | state1 = _mm_unpackhi_epi64(state1, tmp); /* abef */ \ | ||
| 158 | |||
| 159 | |||
| 160 | void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); | ||
| 161 | #ifdef ATTRIB_SHA | ||
| 162 | ATTRIB_SHA | ||
| 163 | #endif | ||
| 164 | void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) | ||
| 165 | { | ||
| 166 | const __m128i mask = _mm_set_epi32(0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203); | ||
| 167 | __m128i tmp; | ||
| 168 | __m128i state0, state1; | ||
| 169 | |||
| 170 | if (numBlocks == 0) | ||
| 171 | return; | ||
| 172 | |||
| 173 | state0 = _mm_loadu_si128((const __m128i *) (const void *) &state[0]); | ||
| 174 | state1 = _mm_loadu_si128((const __m128i *) (const void *) &state[4]); | ||
| 175 | |||
| 176 | PREPARE_STATE | ||
| 177 | |||
| 178 | do | ||
| 179 | { | ||
| 180 | __m128i state0_save, state1_save; | ||
| 181 | __m128i m0, m1, m2, m3; | ||
| 182 | __m128i msg; | ||
| 183 | // #define msg tmp | ||
| 184 | |||
| 185 | state0_save = state0; | ||
| 186 | state1_save = state1; | ||
| 187 | |||
| 188 | LOAD_SHUFFLE (m0, 0) | ||
| 189 | LOAD_SHUFFLE (m1, 1) | ||
| 190 | LOAD_SHUFFLE (m2, 2) | ||
| 191 | LOAD_SHUFFLE (m3, 3) | ||
| 192 | |||
| 193 | |||
| 194 | |||
| 195 | R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 ); | ||
| 196 | R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ); | ||
| 197 | R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ); | ||
| 198 | R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN ); | ||
| 199 | |||
| 200 | ADD_EPI32(state0, state0_save); | ||
| 201 | ADD_EPI32(state1, state1_save); | ||
| 202 | |||
| 203 | data += 64; | ||
| 204 | } | ||
| 205 | while (--numBlocks); | ||
| 206 | |||
| 207 | PREPARE_STATE | ||
| 208 | |||
| 209 | _mm_storeu_si128((__m128i *) (void *) &state[0], state0); | ||
| 210 | _mm_storeu_si128((__m128i *) (void *) &state[4], state1); | ||
| 211 | } | ||
| 212 | |||
| 213 | #endif // USE_HW_SHA | ||
| 214 | |||
| 215 | #elif defined(MY_CPU_ARM_OR_ARM64) | ||
| 216 | |||
| 217 | #if defined(__clang__) | ||
| 218 | #if (__clang_major__ >= 8) // fix that check | ||
| 219 | #define USE_HW_SHA | ||
| 220 | #endif | ||
| 221 | #elif defined(__GNUC__) | ||
| 222 | #if (__GNUC__ >= 6) // fix that check | ||
| 223 | #define USE_HW_SHA | ||
| 224 | #endif | ||
| 225 | #elif defined(_MSC_VER) | ||
| 226 | #if _MSC_VER >= 1910 | ||
| 227 | #define USE_HW_SHA | ||
| 228 | #endif | ||
| 229 | #endif | ||
| 230 | |||
| 231 | #ifdef USE_HW_SHA | ||
| 232 | |||
| 233 | // #pragma message("=== Sha256 HW === ") | ||
| 234 | |||
| 235 | #if defined(__clang__) || defined(__GNUC__) | ||
| 236 | #ifdef MY_CPU_ARM64 | ||
| 237 | #define ATTRIB_SHA __attribute__((__target__("+crypto"))) | ||
| 238 | #else | ||
| 239 | #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) | ||
| 240 | #endif | ||
| 241 | #else | ||
| 242 | // _MSC_VER | ||
| 243 | // for arm32 | ||
| 244 | #define _ARM_USE_NEW_NEON_INTRINSICS | ||
| 245 | #endif | ||
| 246 | |||
| 247 | #if defined(_MSC_VER) && defined(MY_CPU_ARM64) | ||
| 248 | #include <arm64_neon.h> | ||
| 249 | #else | ||
| 250 | #include <arm_neon.h> | ||
| 251 | #endif | ||
| 252 | |||
| 253 | typedef uint32x4_t v128; | ||
| 254 | // typedef __n128 v128; // MSVC | ||
| 255 | |||
| 256 | #ifdef MY_CPU_BE | ||
| 257 | #define MY_rev32_for_LE(x) | ||
| 258 | #else | ||
| 259 | #define MY_rev32_for_LE(x) x = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(x))) | ||
| 260 | #endif | ||
| 261 | |||
| 262 | #define LOAD_128(_p) (*(const v128 *)(const void *)(_p)) | ||
| 263 | #define STORE_128(_p, _v) *(v128 *)(void *)(_p) = (_v) | ||
| 264 | |||
| 265 | #define LOAD_SHUFFLE(m, k) \ | ||
| 266 | m = LOAD_128((data + (k) * 16)); \ | ||
| 267 | MY_rev32_for_LE(m); \ | ||
| 268 | |||
| 269 | // K array must be aligned for 16-bytes at least. | ||
| 270 | extern | ||
| 271 | MY_ALIGN(64) | ||
| 272 | const UInt32 SHA256_K_ARRAY[64]; | ||
| 273 | |||
| 274 | #define K SHA256_K_ARRAY | ||
| 275 | |||
| 276 | |||
| 277 | #define SHA256_SU0(dest, src) dest = vsha256su0q_u32(dest, src); | ||
| 278 | #define SHA25G_SU1(dest, src2, src3) dest = vsha256su1q_u32(dest, src2, src3); | ||
| 279 | |||
| 280 | #define SM1(g0, g1, g2, g3) SHA256_SU0(g3, g0) | ||
| 281 | #define SM2(g0, g1, g2, g3) SHA25G_SU1(g2, g0, g1) | ||
| 282 | #define NNN(g0, g1, g2, g3) | ||
| 283 | |||
| 284 | |||
| 285 | #define R4(k, g0, g1, g2, g3, OP0, OP1) \ | ||
| 286 | msg = vaddq_u32(g0, *(const v128 *) (const void *) &K[(k) * 4]); \ | ||
| 287 | tmp = state0; \ | ||
| 288 | state0 = vsha256hq_u32( state0, state1, msg ); \ | ||
| 289 | state1 = vsha256h2q_u32( state1, tmp, msg ); \ | ||
| 290 | OP0(g0, g1, g2, g3); \ | ||
| 291 | OP1(g0, g1, g2, g3); \ | ||
| 292 | |||
| 293 | |||
| 294 | #define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \ | ||
| 295 | R4 ( (k)*4+0, m0, m1, m2, m3, OP0, OP1 ) \ | ||
| 296 | R4 ( (k)*4+1, m1, m2, m3, m0, OP2, OP3 ) \ | ||
| 297 | R4 ( (k)*4+2, m2, m3, m0, m1, OP4, OP5 ) \ | ||
| 298 | R4 ( (k)*4+3, m3, m0, m1, m2, OP6, OP7 ) \ | ||
| 299 | |||
| 300 | |||
| 301 | void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); | ||
| 302 | #ifdef ATTRIB_SHA | ||
| 303 | ATTRIB_SHA | ||
| 304 | #endif | ||
| 305 | void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) | ||
| 306 | { | ||
| 307 | v128 state0, state1; | ||
| 308 | |||
| 309 | if (numBlocks == 0) | ||
| 310 | return; | ||
| 311 | |||
| 312 | state0 = LOAD_128(&state[0]); | ||
| 313 | state1 = LOAD_128(&state[4]); | ||
| 314 | |||
| 315 | do | ||
| 316 | { | ||
| 317 | v128 state0_save, state1_save; | ||
| 318 | v128 m0, m1, m2, m3; | ||
| 319 | v128 msg, tmp; | ||
| 320 | |||
| 321 | state0_save = state0; | ||
| 322 | state1_save = state1; | ||
| 323 | |||
| 324 | LOAD_SHUFFLE (m0, 0) | ||
| 325 | LOAD_SHUFFLE (m1, 1) | ||
| 326 | LOAD_SHUFFLE (m2, 2) | ||
| 327 | LOAD_SHUFFLE (m3, 3) | ||
| 328 | |||
| 329 | R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 ); | ||
| 330 | R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ); | ||
| 331 | R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ); | ||
| 332 | R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN ); | ||
| 333 | |||
| 334 | state0 = vaddq_u32(state0, state0_save); | ||
| 335 | state1 = vaddq_u32(state1, state1_save); | ||
| 336 | |||
| 337 | data += 64; | ||
| 338 | } | ||
| 339 | while (--numBlocks); | ||
| 340 | |||
| 341 | STORE_128(&state[0], state0); | ||
| 342 | STORE_128(&state[4], state1); | ||
| 343 | } | ||
| 344 | |||
| 345 | #endif // USE_HW_SHA | ||
| 346 | |||
| 347 | #endif // MY_CPU_ARM_OR_ARM64 | ||
| 348 | |||
| 349 | |||
| 350 | #ifndef USE_HW_SHA | ||
| 351 | |||
| 352 | // #error Stop_Compiling_UNSUPPORTED_SHA | ||
| 353 | // #include <stdlib.h> | ||
| 354 | |||
| 355 | // #include "Sha256.h" | ||
| 356 | void MY_FAST_CALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); | ||
| 357 | |||
| 358 | #pragma message("Sha256 HW-SW stub was used") | ||
| 359 | |||
| 360 | void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); | ||
| 361 | void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) | ||
| 362 | { | ||
| 363 | Sha256_UpdateBlocks(state, data, numBlocks); | ||
| 364 | /* | ||
| 365 | UNUSED_VAR(state); | ||
| 366 | UNUSED_VAR(data); | ||
| 367 | UNUSED_VAR(numBlocks); | ||
| 368 | exit(1); | ||
| 369 | return; | ||
| 370 | */ | ||
| 371 | } | ||
| 372 | |||
| 373 | #endif | ||
diff --git a/C/Sort.c b/C/Sort.c new file mode 100644 index 0000000..e1097e3 --- /dev/null +++ b/C/Sort.c | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | /* Sort.c -- Sort functions | ||
| 2 | 2014-04-05 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "Sort.h" | ||
| 7 | |||
| 8 | #define HeapSortDown(p, k, size, temp) \ | ||
| 9 | { for (;;) { \ | ||
| 10 | size_t s = (k << 1); \ | ||
| 11 | if (s > size) break; \ | ||
| 12 | if (s < size && p[s + 1] > p[s]) s++; \ | ||
| 13 | if (temp >= p[s]) break; \ | ||
| 14 | p[k] = p[s]; k = s; \ | ||
| 15 | } p[k] = temp; } | ||
| 16 | |||
| 17 | void HeapSort(UInt32 *p, size_t size) | ||
| 18 | { | ||
| 19 | if (size <= 1) | ||
| 20 | return; | ||
| 21 | p--; | ||
| 22 | { | ||
| 23 | size_t i = size / 2; | ||
| 24 | do | ||
| 25 | { | ||
| 26 | UInt32 temp = p[i]; | ||
| 27 | size_t k = i; | ||
| 28 | HeapSortDown(p, k, size, temp) | ||
| 29 | } | ||
| 30 | while (--i != 0); | ||
| 31 | } | ||
| 32 | /* | ||
| 33 | do | ||
| 34 | { | ||
| 35 | size_t k = 1; | ||
| 36 | UInt32 temp = p[size]; | ||
| 37 | p[size--] = p[1]; | ||
| 38 | HeapSortDown(p, k, size, temp) | ||
| 39 | } | ||
| 40 | while (size > 1); | ||
| 41 | */ | ||
| 42 | while (size > 3) | ||
| 43 | { | ||
| 44 | UInt32 temp = p[size]; | ||
| 45 | size_t k = (p[3] > p[2]) ? 3 : 2; | ||
| 46 | p[size--] = p[1]; | ||
| 47 | p[1] = p[k]; | ||
| 48 | HeapSortDown(p, k, size, temp) | ||
| 49 | } | ||
| 50 | { | ||
| 51 | UInt32 temp = p[size]; | ||
| 52 | p[size] = p[1]; | ||
| 53 | if (size > 2 && p[2] < temp) | ||
| 54 | { | ||
| 55 | p[1] = p[2]; | ||
| 56 | p[2] = temp; | ||
| 57 | } | ||
| 58 | else | ||
| 59 | p[1] = temp; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | void HeapSort64(UInt64 *p, size_t size) | ||
| 64 | { | ||
| 65 | if (size <= 1) | ||
| 66 | return; | ||
| 67 | p--; | ||
| 68 | { | ||
| 69 | size_t i = size / 2; | ||
| 70 | do | ||
| 71 | { | ||
| 72 | UInt64 temp = p[i]; | ||
| 73 | size_t k = i; | ||
| 74 | HeapSortDown(p, k, size, temp) | ||
| 75 | } | ||
| 76 | while (--i != 0); | ||
| 77 | } | ||
| 78 | /* | ||
| 79 | do | ||
| 80 | { | ||
| 81 | size_t k = 1; | ||
| 82 | UInt64 temp = p[size]; | ||
| 83 | p[size--] = p[1]; | ||
| 84 | HeapSortDown(p, k, size, temp) | ||
| 85 | } | ||
| 86 | while (size > 1); | ||
| 87 | */ | ||
| 88 | while (size > 3) | ||
| 89 | { | ||
| 90 | UInt64 temp = p[size]; | ||
| 91 | size_t k = (p[3] > p[2]) ? 3 : 2; | ||
| 92 | p[size--] = p[1]; | ||
| 93 | p[1] = p[k]; | ||
| 94 | HeapSortDown(p, k, size, temp) | ||
| 95 | } | ||
| 96 | { | ||
| 97 | UInt64 temp = p[size]; | ||
| 98 | p[size] = p[1]; | ||
| 99 | if (size > 2 && p[2] < temp) | ||
| 100 | { | ||
| 101 | p[1] = p[2]; | ||
| 102 | p[2] = temp; | ||
| 103 | } | ||
| 104 | else | ||
| 105 | p[1] = temp; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | /* | ||
| 110 | #define HeapSortRefDown(p, vals, n, size, temp) \ | ||
| 111 | { size_t k = n; UInt32 val = vals[temp]; for (;;) { \ | ||
| 112 | size_t s = (k << 1); \ | ||
| 113 | if (s > size) break; \ | ||
| 114 | if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \ | ||
| 115 | if (val >= vals[p[s]]) break; \ | ||
| 116 | p[k] = p[s]; k = s; \ | ||
| 117 | } p[k] = temp; } | ||
| 118 | |||
| 119 | void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size) | ||
| 120 | { | ||
| 121 | if (size <= 1) | ||
| 122 | return; | ||
| 123 | p--; | ||
| 124 | { | ||
| 125 | size_t i = size / 2; | ||
| 126 | do | ||
| 127 | { | ||
| 128 | UInt32 temp = p[i]; | ||
| 129 | HeapSortRefDown(p, vals, i, size, temp); | ||
| 130 | } | ||
| 131 | while (--i != 0); | ||
| 132 | } | ||
| 133 | do | ||
| 134 | { | ||
| 135 | UInt32 temp = p[size]; | ||
| 136 | p[size--] = p[1]; | ||
| 137 | HeapSortRefDown(p, vals, 1, size, temp); | ||
| 138 | } | ||
| 139 | while (size > 1); | ||
| 140 | } | ||
| 141 | */ | ||
diff --git a/C/Sort.h b/C/Sort.h new file mode 100644 index 0000000..2e2963a --- /dev/null +++ b/C/Sort.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | /* Sort.h -- Sort functions | ||
| 2 | 2014-04-05 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_SORT_H | ||
| 5 | #define __7Z_SORT_H | ||
| 6 | |||
| 7 | #include "7zTypes.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | void HeapSort(UInt32 *p, size_t size); | ||
| 12 | void HeapSort64(UInt64 *p, size_t size); | ||
| 13 | |||
| 14 | /* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */ | ||
| 15 | |||
| 16 | EXTERN_C_END | ||
| 17 | |||
| 18 | #endif | ||
diff --git a/C/Threads.c b/C/Threads.c new file mode 100644 index 0000000..58eb90f --- /dev/null +++ b/C/Threads.c | |||
| @@ -0,0 +1,540 @@ | |||
| 1 | /* Threads.c -- multithreading library | ||
| 2 | 2021-12-21 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #ifdef _WIN32 | ||
| 7 | |||
| 8 | #ifndef USE_THREADS_CreateThread | ||
| 9 | #include <process.h> | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #include "Threads.h" | ||
| 13 | |||
| 14 | static WRes GetError() | ||
| 15 | { | ||
| 16 | DWORD res = GetLastError(); | ||
| 17 | return res ? (WRes)res : 1; | ||
| 18 | } | ||
| 19 | |||
| 20 | static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); } | ||
| 21 | static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); } | ||
| 22 | |||
| 23 | WRes HandlePtr_Close(HANDLE *p) | ||
| 24 | { | ||
| 25 | if (*p != NULL) | ||
| 26 | { | ||
| 27 | if (!CloseHandle(*p)) | ||
| 28 | return GetError(); | ||
| 29 | *p = NULL; | ||
| 30 | } | ||
| 31 | return 0; | ||
| 32 | } | ||
| 33 | |||
| 34 | WRes Handle_WaitObject(HANDLE h) | ||
| 35 | { | ||
| 36 | DWORD dw = WaitForSingleObject(h, INFINITE); | ||
| 37 | /* | ||
| 38 | (dw) result: | ||
| 39 | WAIT_OBJECT_0 // 0 | ||
| 40 | WAIT_ABANDONED // 0x00000080 : is not compatible with Win32 Error space | ||
| 41 | WAIT_TIMEOUT // 0x00000102 : is compatible with Win32 Error space | ||
| 42 | WAIT_FAILED // 0xFFFFFFFF | ||
| 43 | */ | ||
| 44 | if (dw == WAIT_FAILED) | ||
| 45 | { | ||
| 46 | dw = GetLastError(); | ||
| 47 | if (dw == 0) | ||
| 48 | return WAIT_FAILED; | ||
| 49 | } | ||
| 50 | return (WRes)dw; | ||
| 51 | } | ||
| 52 | |||
| 53 | #define Thread_Wait(p) Handle_WaitObject(*(p)) | ||
| 54 | |||
| 55 | WRes Thread_Wait_Close(CThread *p) | ||
| 56 | { | ||
| 57 | WRes res = Thread_Wait(p); | ||
| 58 | WRes res2 = Thread_Close(p); | ||
| 59 | return (res != 0 ? res : res2); | ||
| 60 | } | ||
| 61 | |||
| 62 | WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) | ||
| 63 | { | ||
| 64 | /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ | ||
| 65 | |||
| 66 | #ifdef USE_THREADS_CreateThread | ||
| 67 | |||
| 68 | DWORD threadId; | ||
| 69 | *p = CreateThread(NULL, 0, func, param, 0, &threadId); | ||
| 70 | |||
| 71 | #else | ||
| 72 | |||
| 73 | unsigned threadId; | ||
| 74 | *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId)); | ||
| 75 | |||
| 76 | #endif | ||
| 77 | |||
| 78 | /* maybe we must use errno here, but probably GetLastError() is also OK. */ | ||
| 79 | return HandleToWRes(*p); | ||
| 80 | } | ||
| 81 | |||
| 82 | |||
| 83 | WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) | ||
| 84 | { | ||
| 85 | #ifdef USE_THREADS_CreateThread | ||
| 86 | |||
| 87 | UNUSED_VAR(affinity) | ||
| 88 | return Thread_Create(p, func, param); | ||
| 89 | |||
| 90 | #else | ||
| 91 | |||
| 92 | /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ | ||
| 93 | HANDLE h; | ||
| 94 | WRes wres; | ||
| 95 | unsigned threadId; | ||
| 96 | h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId)); | ||
| 97 | *p = h; | ||
| 98 | wres = HandleToWRes(h); | ||
| 99 | if (h) | ||
| 100 | { | ||
| 101 | { | ||
| 102 | // DWORD_PTR prevMask = | ||
| 103 | SetThreadAffinityMask(h, (DWORD_PTR)affinity); | ||
| 104 | /* | ||
| 105 | if (prevMask == 0) | ||
| 106 | { | ||
| 107 | // affinity change is non-critical error, so we can ignore it | ||
| 108 | // wres = GetError(); | ||
| 109 | } | ||
| 110 | */ | ||
| 111 | } | ||
| 112 | { | ||
| 113 | DWORD prevSuspendCount = ResumeThread(h); | ||
| 114 | /* ResumeThread() returns: | ||
| 115 | 0 : was_not_suspended | ||
| 116 | 1 : was_resumed | ||
| 117 | -1 : error | ||
| 118 | */ | ||
| 119 | if (prevSuspendCount == (DWORD)-1) | ||
| 120 | wres = GetError(); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | /* maybe we must use errno here, but probably GetLastError() is also OK. */ | ||
| 125 | return wres; | ||
| 126 | |||
| 127 | #endif | ||
| 128 | } | ||
| 129 | |||
| 130 | |||
| 131 | static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled) | ||
| 132 | { | ||
| 133 | *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL); | ||
| 134 | return HandleToWRes(*p); | ||
| 135 | } | ||
| 136 | |||
| 137 | WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); } | ||
| 138 | WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); } | ||
| 139 | |||
| 140 | WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); } | ||
| 141 | WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); } | ||
| 142 | WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } | ||
| 143 | WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } | ||
| 144 | |||
| 145 | |||
| 146 | WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) | ||
| 147 | { | ||
| 148 | // negative ((LONG)maxCount) is not supported in WIN32::CreateSemaphore() | ||
| 149 | *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL); | ||
| 150 | return HandleToWRes(*p); | ||
| 151 | } | ||
| 152 | |||
| 153 | WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount) | ||
| 154 | { | ||
| 155 | // if (Semaphore_IsCreated(p)) | ||
| 156 | { | ||
| 157 | WRes wres = Semaphore_Close(p); | ||
| 158 | if (wres != 0) | ||
| 159 | return wres; | ||
| 160 | } | ||
| 161 | return Semaphore_Create(p, initCount, maxCount); | ||
| 162 | } | ||
| 163 | |||
| 164 | static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) | ||
| 165 | { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); } | ||
| 166 | WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num) | ||
| 167 | { return Semaphore_Release(p, (LONG)num, NULL); } | ||
| 168 | WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); } | ||
| 169 | |||
| 170 | WRes CriticalSection_Init(CCriticalSection *p) | ||
| 171 | { | ||
| 172 | /* InitializeCriticalSection() can raise exception: | ||
| 173 | Windows XP, 2003 : can raise a STATUS_NO_MEMORY exception | ||
| 174 | Windows Vista+ : no exceptions */ | ||
| 175 | #ifdef _MSC_VER | ||
| 176 | __try | ||
| 177 | #endif | ||
| 178 | { | ||
| 179 | InitializeCriticalSection(p); | ||
| 180 | /* InitializeCriticalSectionAndSpinCount(p, 0); */ | ||
| 181 | } | ||
| 182 | #ifdef _MSC_VER | ||
| 183 | __except (EXCEPTION_EXECUTE_HANDLER) { return ERROR_NOT_ENOUGH_MEMORY; } | ||
| 184 | #endif | ||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 188 | |||
| 189 | |||
| 190 | |||
| 191 | #else // _WIN32 | ||
| 192 | |||
| 193 | // ---------- POSIX ---------- | ||
| 194 | |||
| 195 | #ifndef __APPLE__ | ||
| 196 | #ifndef _7ZIP_AFFINITY_DISABLE | ||
| 197 | // _GNU_SOURCE can be required for pthread_setaffinity_np() / CPU_ZERO / CPU_SET | ||
| 198 | #define _GNU_SOURCE | ||
| 199 | #endif | ||
| 200 | #endif | ||
| 201 | |||
| 202 | #include "Threads.h" | ||
| 203 | |||
| 204 | #include <errno.h> | ||
| 205 | #include <stdlib.h> | ||
| 206 | #include <string.h> | ||
| 207 | #ifdef _7ZIP_AFFINITY_SUPPORTED | ||
| 208 | // #include <sched.h> | ||
| 209 | #endif | ||
| 210 | |||
| 211 | |||
| 212 | // #include <stdio.h> | ||
| 213 | // #define PRF(p) p | ||
| 214 | #define PRF(p) | ||
| 215 | |||
| 216 | #define Print(s) PRF(printf("\n%s\n", s)) | ||
| 217 | |||
| 218 | // #include <stdio.h> | ||
| 219 | |||
| 220 | WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet) | ||
| 221 | { | ||
| 222 | // new thread in Posix probably inherits affinity from parrent thread | ||
| 223 | Print("Thread_Create_With_CpuSet"); | ||
| 224 | |||
| 225 | pthread_attr_t attr; | ||
| 226 | int ret; | ||
| 227 | // int ret2; | ||
| 228 | |||
| 229 | p->_created = 0; | ||
| 230 | |||
| 231 | RINOK(pthread_attr_init(&attr)); | ||
| 232 | |||
| 233 | ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); | ||
| 234 | |||
| 235 | if (!ret) | ||
| 236 | { | ||
| 237 | if (cpuSet) | ||
| 238 | { | ||
| 239 | #ifdef _7ZIP_AFFINITY_SUPPORTED | ||
| 240 | |||
| 241 | /* | ||
| 242 | printf("\n affinity :"); | ||
| 243 | unsigned i; | ||
| 244 | for (i = 0; i < sizeof(*cpuSet) && i < 8; i++) | ||
| 245 | { | ||
| 246 | Byte b = *((const Byte *)cpuSet + i); | ||
| 247 | char temp[32]; | ||
| 248 | #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) | ||
| 249 | temp[0] = GET_HEX_CHAR((b & 0xF)); | ||
| 250 | temp[1] = GET_HEX_CHAR((b >> 4)); | ||
| 251 | // temp[0] = GET_HEX_CHAR((b >> 4)); // big-endian | ||
| 252 | // temp[1] = GET_HEX_CHAR((b & 0xF)); // big-endian | ||
| 253 | temp[2] = 0; | ||
| 254 | printf("%s", temp); | ||
| 255 | } | ||
| 256 | printf("\n"); | ||
| 257 | */ | ||
| 258 | |||
| 259 | // ret2 = | ||
| 260 | pthread_attr_setaffinity_np(&attr, sizeof(*cpuSet), cpuSet); | ||
| 261 | // if (ret2) ret = ret2; | ||
| 262 | #endif | ||
| 263 | } | ||
| 264 | |||
| 265 | ret = pthread_create(&p->_tid, &attr, func, param); | ||
| 266 | |||
| 267 | if (!ret) | ||
| 268 | { | ||
| 269 | p->_created = 1; | ||
| 270 | /* | ||
| 271 | if (cpuSet) | ||
| 272 | { | ||
| 273 | // ret2 = | ||
| 274 | pthread_setaffinity_np(p->_tid, sizeof(*cpuSet), cpuSet); | ||
| 275 | // if (ret2) ret = ret2; | ||
| 276 | } | ||
| 277 | */ | ||
| 278 | } | ||
| 279 | } | ||
| 280 | // ret2 = | ||
| 281 | pthread_attr_destroy(&attr); | ||
| 282 | // if (ret2 != 0) ret = ret2; | ||
| 283 | return ret; | ||
| 284 | } | ||
| 285 | |||
| 286 | |||
| 287 | WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) | ||
| 288 | { | ||
| 289 | return Thread_Create_With_CpuSet(p, func, param, NULL); | ||
| 290 | } | ||
| 291 | |||
| 292 | |||
| 293 | WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) | ||
| 294 | { | ||
| 295 | Print("Thread_Create_WithAffinity"); | ||
| 296 | CCpuSet cs; | ||
| 297 | unsigned i; | ||
| 298 | CpuSet_Zero(&cs); | ||
| 299 | for (i = 0; i < sizeof(affinity) * 8; i++) | ||
| 300 | { | ||
| 301 | if (affinity == 0) | ||
| 302 | break; | ||
| 303 | if (affinity & 1) | ||
| 304 | { | ||
| 305 | CpuSet_Set(&cs, i); | ||
| 306 | } | ||
| 307 | affinity >>= 1; | ||
| 308 | } | ||
| 309 | return Thread_Create_With_CpuSet(p, func, param, &cs); | ||
| 310 | } | ||
| 311 | |||
| 312 | |||
| 313 | WRes Thread_Close(CThread *p) | ||
| 314 | { | ||
| 315 | // Print("Thread_Close"); | ||
| 316 | int ret; | ||
| 317 | if (!p->_created) | ||
| 318 | return 0; | ||
| 319 | |||
| 320 | ret = pthread_detach(p->_tid); | ||
| 321 | p->_tid = 0; | ||
| 322 | p->_created = 0; | ||
| 323 | return ret; | ||
| 324 | } | ||
| 325 | |||
| 326 | |||
| 327 | WRes Thread_Wait_Close(CThread *p) | ||
| 328 | { | ||
| 329 | // Print("Thread_Wait_Close"); | ||
| 330 | void *thread_return; | ||
| 331 | int ret; | ||
| 332 | if (!p->_created) | ||
| 333 | return EINVAL; | ||
| 334 | |||
| 335 | ret = pthread_join(p->_tid, &thread_return); | ||
| 336 | // probably we can't use that (_tid) after pthread_join(), so we close thread here | ||
| 337 | p->_created = 0; | ||
| 338 | p->_tid = 0; | ||
| 339 | return ret; | ||
| 340 | } | ||
| 341 | |||
| 342 | |||
| 343 | |||
| 344 | static WRes Event_Create(CEvent *p, int manualReset, int signaled) | ||
| 345 | { | ||
| 346 | RINOK(pthread_mutex_init(&p->_mutex, NULL)); | ||
| 347 | RINOK(pthread_cond_init(&p->_cond, NULL)); | ||
| 348 | p->_manual_reset = manualReset; | ||
| 349 | p->_state = (signaled ? True : False); | ||
| 350 | p->_created = 1; | ||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) | ||
| 355 | { return Event_Create(p, True, signaled); } | ||
| 356 | WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) | ||
| 357 | { return ManualResetEvent_Create(p, 0); } | ||
| 358 | WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) | ||
| 359 | { return Event_Create(p, False, signaled); } | ||
| 360 | WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) | ||
| 361 | { return AutoResetEvent_Create(p, 0); } | ||
| 362 | |||
| 363 | |||
| 364 | WRes Event_Set(CEvent *p) | ||
| 365 | { | ||
| 366 | RINOK(pthread_mutex_lock(&p->_mutex)); | ||
| 367 | p->_state = True; | ||
| 368 | int res1 = pthread_cond_broadcast(&p->_cond); | ||
| 369 | int res2 = pthread_mutex_unlock(&p->_mutex); | ||
| 370 | return (res2 ? res2 : res1); | ||
| 371 | } | ||
| 372 | |||
| 373 | WRes Event_Reset(CEvent *p) | ||
| 374 | { | ||
| 375 | RINOK(pthread_mutex_lock(&p->_mutex)); | ||
| 376 | p->_state = False; | ||
| 377 | return pthread_mutex_unlock(&p->_mutex); | ||
| 378 | } | ||
| 379 | |||
| 380 | WRes Event_Wait(CEvent *p) | ||
| 381 | { | ||
| 382 | RINOK(pthread_mutex_lock(&p->_mutex)); | ||
| 383 | while (p->_state == False) | ||
| 384 | { | ||
| 385 | // ETIMEDOUT | ||
| 386 | // ret = | ||
| 387 | pthread_cond_wait(&p->_cond, &p->_mutex); | ||
| 388 | // if (ret != 0) break; | ||
| 389 | } | ||
| 390 | if (p->_manual_reset == False) | ||
| 391 | { | ||
| 392 | p->_state = False; | ||
| 393 | } | ||
| 394 | return pthread_mutex_unlock(&p->_mutex); | ||
| 395 | } | ||
| 396 | |||
| 397 | WRes Event_Close(CEvent *p) | ||
| 398 | { | ||
| 399 | if (!p->_created) | ||
| 400 | return 0; | ||
| 401 | p->_created = 0; | ||
| 402 | { | ||
| 403 | int res1 = pthread_mutex_destroy(&p->_mutex); | ||
| 404 | int res2 = pthread_cond_destroy(&p->_cond); | ||
| 405 | return (res1 ? res1 : res2); | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | |||
| 410 | WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) | ||
| 411 | { | ||
| 412 | if (initCount > maxCount || maxCount < 1) | ||
| 413 | return EINVAL; | ||
| 414 | RINOK(pthread_mutex_init(&p->_mutex, NULL)); | ||
| 415 | RINOK(pthread_cond_init(&p->_cond, NULL)); | ||
| 416 | p->_count = initCount; | ||
| 417 | p->_maxCount = maxCount; | ||
| 418 | p->_created = 1; | ||
| 419 | return 0; | ||
| 420 | } | ||
| 421 | |||
| 422 | |||
| 423 | WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount) | ||
| 424 | { | ||
| 425 | if (Semaphore_IsCreated(p)) | ||
| 426 | { | ||
| 427 | /* | ||
| 428 | WRes wres = Semaphore_Close(p); | ||
| 429 | if (wres != 0) | ||
| 430 | return wres; | ||
| 431 | */ | ||
| 432 | if (initCount > maxCount || maxCount < 1) | ||
| 433 | return EINVAL; | ||
| 434 | // return EINVAL; // for debug | ||
| 435 | p->_count = initCount; | ||
| 436 | p->_maxCount = maxCount; | ||
| 437 | return 0; | ||
| 438 | } | ||
| 439 | return Semaphore_Create(p, initCount, maxCount); | ||
| 440 | } | ||
| 441 | |||
| 442 | |||
| 443 | WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount) | ||
| 444 | { | ||
| 445 | UInt32 newCount; | ||
| 446 | int ret; | ||
| 447 | |||
| 448 | if (releaseCount < 1) | ||
| 449 | return EINVAL; | ||
| 450 | |||
| 451 | RINOK(pthread_mutex_lock(&p->_mutex)); | ||
| 452 | |||
| 453 | newCount = p->_count + releaseCount; | ||
| 454 | if (newCount > p->_maxCount) | ||
| 455 | ret = ERROR_TOO_MANY_POSTS; // EINVAL; | ||
| 456 | else | ||
| 457 | { | ||
| 458 | p->_count = newCount; | ||
| 459 | ret = pthread_cond_broadcast(&p->_cond); | ||
| 460 | } | ||
| 461 | RINOK(pthread_mutex_unlock(&p->_mutex)); | ||
| 462 | return ret; | ||
| 463 | } | ||
| 464 | |||
| 465 | WRes Semaphore_Wait(CSemaphore *p) | ||
| 466 | { | ||
| 467 | RINOK(pthread_mutex_lock(&p->_mutex)); | ||
| 468 | while (p->_count < 1) | ||
| 469 | { | ||
| 470 | pthread_cond_wait(&p->_cond, &p->_mutex); | ||
| 471 | } | ||
| 472 | p->_count--; | ||
| 473 | return pthread_mutex_unlock(&p->_mutex); | ||
| 474 | } | ||
| 475 | |||
| 476 | WRes Semaphore_Close(CSemaphore *p) | ||
| 477 | { | ||
| 478 | if (!p->_created) | ||
| 479 | return 0; | ||
| 480 | p->_created = 0; | ||
| 481 | { | ||
| 482 | int res1 = pthread_mutex_destroy(&p->_mutex); | ||
| 483 | int res2 = pthread_cond_destroy(&p->_cond); | ||
| 484 | return (res1 ? res1 : res2); | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | |||
| 489 | |||
| 490 | WRes CriticalSection_Init(CCriticalSection *p) | ||
| 491 | { | ||
| 492 | // Print("CriticalSection_Init"); | ||
| 493 | if (!p) | ||
| 494 | return EINTR; | ||
| 495 | return pthread_mutex_init(&p->_mutex, NULL); | ||
| 496 | } | ||
| 497 | |||
| 498 | void CriticalSection_Enter(CCriticalSection *p) | ||
| 499 | { | ||
| 500 | // Print("CriticalSection_Enter"); | ||
| 501 | if (p) | ||
| 502 | { | ||
| 503 | // int ret = | ||
| 504 | pthread_mutex_lock(&p->_mutex); | ||
| 505 | } | ||
| 506 | } | ||
| 507 | |||
| 508 | void CriticalSection_Leave(CCriticalSection *p) | ||
| 509 | { | ||
| 510 | // Print("CriticalSection_Leave"); | ||
| 511 | if (p) | ||
| 512 | { | ||
| 513 | // int ret = | ||
| 514 | pthread_mutex_unlock(&p->_mutex); | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | void CriticalSection_Delete(CCriticalSection *p) | ||
| 519 | { | ||
| 520 | // Print("CriticalSection_Delete"); | ||
| 521 | if (p) | ||
| 522 | { | ||
| 523 | // int ret = | ||
| 524 | pthread_mutex_destroy(&p->_mutex); | ||
| 525 | } | ||
| 526 | } | ||
| 527 | |||
| 528 | LONG InterlockedIncrement(LONG volatile *addend) | ||
| 529 | { | ||
| 530 | // Print("InterlockedIncrement"); | ||
| 531 | #ifdef USE_HACK_UNSAFE_ATOMIC | ||
| 532 | LONG val = *addend + 1; | ||
| 533 | *addend = val; | ||
| 534 | return val; | ||
| 535 | #else | ||
| 536 | return __sync_add_and_fetch(addend, 1); | ||
| 537 | #endif | ||
| 538 | } | ||
| 539 | |||
| 540 | #endif // _WIN32 | ||
diff --git a/C/Threads.h b/C/Threads.h new file mode 100644 index 0000000..89ecb92 --- /dev/null +++ b/C/Threads.h | |||
| @@ -0,0 +1,232 @@ | |||
| 1 | /* Threads.h -- multithreading library | ||
| 2 | 2021-12-21 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_THREADS_H | ||
| 5 | #define __7Z_THREADS_H | ||
| 6 | |||
| 7 | #ifdef _WIN32 | ||
| 8 | #include <Windows.h> | ||
| 9 | #else | ||
| 10 | |||
| 11 | #if defined(__linux__) | ||
| 12 | #if !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__) | ||
| 13 | #ifndef _7ZIP_AFFINITY_DISABLE | ||
| 14 | #define _7ZIP_AFFINITY_SUPPORTED | ||
| 15 | // #pragma message(" ==== _7ZIP_AFFINITY_SUPPORTED") | ||
| 16 | // #define _GNU_SOURCE | ||
| 17 | #endif | ||
| 18 | #endif | ||
| 19 | #endif | ||
| 20 | |||
| 21 | #include <pthread.h> | ||
| 22 | |||
| 23 | #endif | ||
| 24 | |||
| 25 | #include "7zTypes.h" | ||
| 26 | |||
| 27 | EXTERN_C_BEGIN | ||
| 28 | |||
| 29 | #ifdef _WIN32 | ||
| 30 | |||
| 31 | WRes HandlePtr_Close(HANDLE *h); | ||
| 32 | WRes Handle_WaitObject(HANDLE h); | ||
| 33 | |||
| 34 | typedef HANDLE CThread; | ||
| 35 | |||
| 36 | #define Thread_Construct(p) { *(p) = NULL; } | ||
| 37 | #define Thread_WasCreated(p) (*(p) != NULL) | ||
| 38 | #define Thread_Close(p) HandlePtr_Close(p) | ||
| 39 | // #define Thread_Wait(p) Handle_WaitObject(*(p)) | ||
| 40 | |||
| 41 | #ifdef UNDER_CE | ||
| 42 | // if (USE_THREADS_CreateThread is defined), we use _beginthreadex() | ||
| 43 | // if (USE_THREADS_CreateThread is not definned), we use CreateThread() | ||
| 44 | #define USE_THREADS_CreateThread | ||
| 45 | #endif | ||
| 46 | |||
| 47 | typedef | ||
| 48 | #ifdef USE_THREADS_CreateThread | ||
| 49 | DWORD | ||
| 50 | #else | ||
| 51 | unsigned | ||
| 52 | #endif | ||
| 53 | THREAD_FUNC_RET_TYPE; | ||
| 54 | |||
| 55 | typedef DWORD_PTR CAffinityMask; | ||
| 56 | typedef DWORD_PTR CCpuSet; | ||
| 57 | |||
| 58 | #define CpuSet_Zero(p) { *(p) = 0; } | ||
| 59 | #define CpuSet_Set(p, cpu) { *(p) |= ((DWORD_PTR)1 << (cpu)); } | ||
| 60 | |||
| 61 | #else // _WIN32 | ||
| 62 | |||
| 63 | typedef struct _CThread | ||
| 64 | { | ||
| 65 | pthread_t _tid; | ||
| 66 | int _created; | ||
| 67 | } CThread; | ||
| 68 | |||
| 69 | #define Thread_Construct(p) { (p)->_tid = 0; (p)->_created = 0; } | ||
| 70 | #define Thread_WasCreated(p) ((p)->_created != 0) | ||
| 71 | WRes Thread_Close(CThread *p); | ||
| 72 | // #define Thread_Wait Thread_Wait_Close | ||
| 73 | |||
| 74 | typedef void * THREAD_FUNC_RET_TYPE; | ||
| 75 | |||
| 76 | typedef UInt64 CAffinityMask; | ||
| 77 | |||
| 78 | #ifdef _7ZIP_AFFINITY_SUPPORTED | ||
| 79 | |||
| 80 | typedef cpu_set_t CCpuSet; | ||
| 81 | #define CpuSet_Zero(p) CPU_ZERO(p) | ||
| 82 | #define CpuSet_Set(p, cpu) CPU_SET(cpu, p) | ||
| 83 | #define CpuSet_IsSet(p, cpu) CPU_ISSET(cpu, p) | ||
| 84 | |||
| 85 | #else | ||
| 86 | |||
| 87 | typedef UInt64 CCpuSet; | ||
| 88 | #define CpuSet_Zero(p) { *(p) = 0; } | ||
| 89 | #define CpuSet_Set(p, cpu) { *(p) |= ((UInt64)1 << (cpu)); } | ||
| 90 | #define CpuSet_IsSet(p, cpu) ((*(p) & ((UInt64)1 << (cpu))) != 0) | ||
| 91 | |||
| 92 | #endif | ||
| 93 | |||
| 94 | |||
| 95 | #endif // _WIN32 | ||
| 96 | |||
| 97 | |||
| 98 | #define THREAD_FUNC_CALL_TYPE MY_STD_CALL | ||
| 99 | |||
| 100 | #if defined(_WIN32) && defined(__GNUC__) | ||
| 101 | /* GCC compiler for x86 32-bit uses the rule: | ||
| 102 | the stack is 16-byte aligned before CALL instruction for function calling. | ||
| 103 | But only root function main() contains instructions that | ||
| 104 | set 16-byte alignment for stack pointer. And another functions | ||
| 105 | just keep alignment, if it was set in some parent function. | ||
| 106 | |||
| 107 | The problem: | ||
| 108 | if we create new thread in MinGW (GCC) 32-bit x86 via _beginthreadex() or CreateThread(), | ||
| 109 | the root function of thread doesn't set 16-byte alignment. | ||
| 110 | And stack frames in all child functions also will be unaligned in that case. | ||
| 111 | |||
| 112 | Here we set (force_align_arg_pointer) attribute for root function of new thread. | ||
| 113 | Do we need (force_align_arg_pointer) also for another systems? */ | ||
| 114 | |||
| 115 | #define THREAD_FUNC_ATTRIB_ALIGN_ARG __attribute__((force_align_arg_pointer)) | ||
| 116 | // #define THREAD_FUNC_ATTRIB_ALIGN_ARG // for debug : bad alignment in SSE functions | ||
| 117 | #else | ||
| 118 | #define THREAD_FUNC_ATTRIB_ALIGN_ARG | ||
| 119 | #endif | ||
| 120 | |||
| 121 | #define THREAD_FUNC_DECL THREAD_FUNC_ATTRIB_ALIGN_ARG THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE | ||
| 122 | |||
| 123 | typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); | ||
| 124 | WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); | ||
| 125 | WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity); | ||
| 126 | WRes Thread_Wait_Close(CThread *p); | ||
| 127 | |||
| 128 | #ifdef _WIN32 | ||
| 129 | #define Thread_Create_With_CpuSet(p, func, param, cs) \ | ||
| 130 | Thread_Create_With_Affinity(p, func, param, *cs) | ||
| 131 | #else | ||
| 132 | WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet); | ||
| 133 | #endif | ||
| 134 | |||
| 135 | |||
| 136 | #ifdef _WIN32 | ||
| 137 | |||
| 138 | typedef HANDLE CEvent; | ||
| 139 | typedef CEvent CAutoResetEvent; | ||
| 140 | typedef CEvent CManualResetEvent; | ||
| 141 | #define Event_Construct(p) *(p) = NULL | ||
| 142 | #define Event_IsCreated(p) (*(p) != NULL) | ||
| 143 | #define Event_Close(p) HandlePtr_Close(p) | ||
| 144 | #define Event_Wait(p) Handle_WaitObject(*(p)) | ||
| 145 | WRes Event_Set(CEvent *p); | ||
| 146 | WRes Event_Reset(CEvent *p); | ||
| 147 | WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); | ||
| 148 | WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); | ||
| 149 | WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); | ||
| 150 | WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); | ||
| 151 | |||
| 152 | typedef HANDLE CSemaphore; | ||
| 153 | #define Semaphore_Construct(p) *(p) = NULL | ||
| 154 | #define Semaphore_IsCreated(p) (*(p) != NULL) | ||
| 155 | #define Semaphore_Close(p) HandlePtr_Close(p) | ||
| 156 | #define Semaphore_Wait(p) Handle_WaitObject(*(p)) | ||
| 157 | WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); | ||
| 158 | WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); | ||
| 159 | WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); | ||
| 160 | WRes Semaphore_Release1(CSemaphore *p); | ||
| 161 | |||
| 162 | typedef CRITICAL_SECTION CCriticalSection; | ||
| 163 | WRes CriticalSection_Init(CCriticalSection *p); | ||
| 164 | #define CriticalSection_Delete(p) DeleteCriticalSection(p) | ||
| 165 | #define CriticalSection_Enter(p) EnterCriticalSection(p) | ||
| 166 | #define CriticalSection_Leave(p) LeaveCriticalSection(p) | ||
| 167 | |||
| 168 | |||
| 169 | #else // _WIN32 | ||
| 170 | |||
| 171 | typedef struct _CEvent | ||
| 172 | { | ||
| 173 | int _created; | ||
| 174 | int _manual_reset; | ||
| 175 | int _state; | ||
| 176 | pthread_mutex_t _mutex; | ||
| 177 | pthread_cond_t _cond; | ||
| 178 | } CEvent; | ||
| 179 | |||
| 180 | typedef CEvent CAutoResetEvent; | ||
| 181 | typedef CEvent CManualResetEvent; | ||
| 182 | |||
| 183 | #define Event_Construct(p) (p)->_created = 0 | ||
| 184 | #define Event_IsCreated(p) ((p)->_created) | ||
| 185 | |||
| 186 | WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); | ||
| 187 | WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); | ||
| 188 | WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); | ||
| 189 | WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); | ||
| 190 | WRes Event_Set(CEvent *p); | ||
| 191 | WRes Event_Reset(CEvent *p); | ||
| 192 | WRes Event_Wait(CEvent *p); | ||
| 193 | WRes Event_Close(CEvent *p); | ||
| 194 | |||
| 195 | |||
| 196 | typedef struct _CSemaphore | ||
| 197 | { | ||
| 198 | int _created; | ||
| 199 | UInt32 _count; | ||
| 200 | UInt32 _maxCount; | ||
| 201 | pthread_mutex_t _mutex; | ||
| 202 | pthread_cond_t _cond; | ||
| 203 | } CSemaphore; | ||
| 204 | |||
| 205 | #define Semaphore_Construct(p) (p)->_created = 0 | ||
| 206 | #define Semaphore_IsCreated(p) ((p)->_created) | ||
| 207 | |||
| 208 | WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); | ||
| 209 | WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); | ||
| 210 | WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); | ||
| 211 | #define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1) | ||
| 212 | WRes Semaphore_Wait(CSemaphore *p); | ||
| 213 | WRes Semaphore_Close(CSemaphore *p); | ||
| 214 | |||
| 215 | |||
| 216 | typedef struct _CCriticalSection | ||
| 217 | { | ||
| 218 | pthread_mutex_t _mutex; | ||
| 219 | } CCriticalSection; | ||
| 220 | |||
| 221 | WRes CriticalSection_Init(CCriticalSection *p); | ||
| 222 | void CriticalSection_Delete(CCriticalSection *cs); | ||
| 223 | void CriticalSection_Enter(CCriticalSection *cs); | ||
| 224 | void CriticalSection_Leave(CCriticalSection *cs); | ||
| 225 | |||
| 226 | LONG InterlockedIncrement(LONG volatile *addend); | ||
| 227 | |||
| 228 | #endif // _WIN32 | ||
| 229 | |||
| 230 | EXTERN_C_END | ||
| 231 | |||
| 232 | #endif | ||
diff --git a/C/Util/7z/7z.dsp b/C/Util/7z/7z.dsp new file mode 100644 index 0000000..be0f0a7 --- /dev/null +++ b/C/Util/7z/7z.dsp | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | # Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4> | ||
| 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 | ||
| 3 | # ** DO NOT EDIT ** | ||
| 4 | |||
| 5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103 | ||
| 6 | |||
| 7 | CFG=7z - Win32 Debug | ||
| 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, | ||
| 9 | !MESSAGE use the Export Makefile command and run | ||
| 10 | !MESSAGE | ||
| 11 | !MESSAGE NMAKE /f "7z.mak". | ||
| 12 | !MESSAGE | ||
| 13 | !MESSAGE You can specify a configuration when running NMAKE | ||
| 14 | !MESSAGE by defining the macro CFG on the command line. For example: | ||
| 15 | !MESSAGE | ||
| 16 | !MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug" | ||
| 17 | !MESSAGE | ||
| 18 | !MESSAGE Possible choices for configuration are: | ||
| 19 | !MESSAGE | ||
| 20 | !MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Console Application") | ||
| 21 | !MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Console Application") | ||
| 22 | !MESSAGE | ||
| 23 | |||
| 24 | # Begin Project | ||
| 25 | # PROP AllowPerConfigDependencies 0 | ||
| 26 | # PROP Scc_ProjName "" | ||
| 27 | # PROP Scc_LocalPath "" | ||
| 28 | CPP=cl.exe | ||
| 29 | RSC=rc.exe | ||
| 30 | |||
| 31 | !IF "$(CFG)" == "7z - Win32 Release" | ||
| 32 | |||
| 33 | # PROP BASE Use_MFC 0 | ||
| 34 | # PROP BASE Use_Debug_Libraries 0 | ||
| 35 | # PROP BASE Output_Dir "Release" | ||
| 36 | # PROP BASE Intermediate_Dir "Release" | ||
| 37 | # PROP BASE Target_Dir "" | ||
| 38 | # PROP Use_MFC 0 | ||
| 39 | # PROP Use_Debug_Libraries 0 | ||
| 40 | # PROP Output_Dir "Release" | ||
| 41 | # PROP Intermediate_Dir "Release" | ||
| 42 | # PROP Ignore_Export_Lib 0 | ||
| 43 | # PROP Target_Dir "" | ||
| 44 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c | ||
| 45 | # ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FAcs /Yu"Precomp.h" /FD /c | ||
| 46 | # ADD BASE RSC /l 0x419 /d "NDEBUG" | ||
| 47 | # ADD RSC /l 0x419 /d "NDEBUG" | ||
| 48 | BSC32=bscmake.exe | ||
| 49 | # ADD BASE BSC32 /nologo | ||
| 50 | # ADD BSC32 /nologo | ||
| 51 | LINK32=link.exe | ||
| 52 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 | ||
| 53 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7zDec.exe" /opt:NOWIN98 | ||
| 54 | # SUBTRACT LINK32 /pdb:none | ||
| 55 | |||
| 56 | !ELSEIF "$(CFG)" == "7z - Win32 Debug" | ||
| 57 | |||
| 58 | # PROP BASE Use_MFC 0 | ||
| 59 | # PROP BASE Use_Debug_Libraries 1 | ||
| 60 | # PROP BASE Output_Dir "Debug" | ||
| 61 | # PROP BASE Intermediate_Dir "Debug" | ||
| 62 | # PROP BASE Target_Dir "" | ||
| 63 | # PROP Use_MFC 0 | ||
| 64 | # PROP Use_Debug_Libraries 1 | ||
| 65 | # PROP Output_Dir "Debug" | ||
| 66 | # PROP Intermediate_Dir "Debug" | ||
| 67 | # PROP Ignore_Export_Lib 0 | ||
| 68 | # PROP Target_Dir "" | ||
| 69 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c | ||
| 70 | # ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_SZ_ALLOC_DEBUG2" /D "_SZ_NO_INT_64_A" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c | ||
| 71 | # ADD BASE RSC /l 0x419 /d "_DEBUG" | ||
| 72 | # ADD RSC /l 0x419 /d "_DEBUG" | ||
| 73 | BSC32=bscmake.exe | ||
| 74 | # ADD BASE BSC32 /nologo | ||
| 75 | # ADD BSC32 /nologo | ||
| 76 | LINK32=link.exe | ||
| 77 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept | ||
| 78 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7zDec.exe" /pdbtype:sept | ||
| 79 | |||
| 80 | !ENDIF | ||
| 81 | |||
| 82 | # Begin Target | ||
| 83 | |||
| 84 | # Name "7z - Win32 Release" | ||
| 85 | # Name "7z - Win32 Debug" | ||
| 86 | # Begin Group "Common" | ||
| 87 | |||
| 88 | # PROP Default_Filter "" | ||
| 89 | # Begin Source File | ||
| 90 | |||
| 91 | SOURCE=..\..\7z.h | ||
| 92 | # End Source File | ||
| 93 | # Begin Source File | ||
| 94 | |||
| 95 | SOURCE=..\..\7zAlloc.c | ||
| 96 | # End Source File | ||
| 97 | # Begin Source File | ||
| 98 | |||
| 99 | SOURCE=..\..\7zAlloc.h | ||
| 100 | # End Source File | ||
| 101 | # Begin Source File | ||
| 102 | |||
| 103 | SOURCE=..\..\7zArcIn.c | ||
| 104 | # End Source File | ||
| 105 | # Begin Source File | ||
| 106 | |||
| 107 | SOURCE=..\..\7zBuf.c | ||
| 108 | # End Source File | ||
| 109 | # Begin Source File | ||
| 110 | |||
| 111 | SOURCE=..\..\7zBuf.h | ||
| 112 | # End Source File | ||
| 113 | # Begin Source File | ||
| 114 | |||
| 115 | SOURCE=..\..\7zCrc.c | ||
| 116 | # End Source File | ||
| 117 | # Begin Source File | ||
| 118 | |||
| 119 | SOURCE=..\..\7zCrc.h | ||
| 120 | # End Source File | ||
| 121 | # Begin Source File | ||
| 122 | |||
| 123 | SOURCE=..\..\7zCrcOpt.c | ||
| 124 | # End Source File | ||
| 125 | # Begin Source File | ||
| 126 | |||
| 127 | SOURCE=..\..\7zDec.c | ||
| 128 | # ADD CPP /D "_7ZIP_PPMD_SUPPPORT" | ||
| 129 | # End Source File | ||
| 130 | # Begin Source File | ||
| 131 | |||
| 132 | SOURCE=..\..\7zFile.c | ||
| 133 | # End Source File | ||
| 134 | # Begin Source File | ||
| 135 | |||
| 136 | SOURCE=..\..\7zFile.h | ||
| 137 | # End Source File | ||
| 138 | # Begin Source File | ||
| 139 | |||
| 140 | SOURCE=..\..\7zStream.c | ||
| 141 | # End Source File | ||
| 142 | # Begin Source File | ||
| 143 | |||
| 144 | SOURCE=..\..\7zTypes.h | ||
| 145 | # End Source File | ||
| 146 | # Begin Source File | ||
| 147 | |||
| 148 | SOURCE=..\..\Bcj2.c | ||
| 149 | # End Source File | ||
| 150 | # Begin Source File | ||
| 151 | |||
| 152 | SOURCE=..\..\Bcj2.h | ||
| 153 | # End Source File | ||
| 154 | # Begin Source File | ||
| 155 | |||
| 156 | SOURCE=..\..\Bra.c | ||
| 157 | # End Source File | ||
| 158 | # Begin Source File | ||
| 159 | |||
| 160 | SOURCE=..\..\Bra.h | ||
| 161 | # End Source File | ||
| 162 | # Begin Source File | ||
| 163 | |||
| 164 | SOURCE=..\..\Bra86.c | ||
| 165 | # End Source File | ||
| 166 | # Begin Source File | ||
| 167 | |||
| 168 | SOURCE=..\..\BraIA64.c | ||
| 169 | # End Source File | ||
| 170 | # Begin Source File | ||
| 171 | |||
| 172 | SOURCE=..\..\CpuArch.c | ||
| 173 | # End Source File | ||
| 174 | # Begin Source File | ||
| 175 | |||
| 176 | SOURCE=..\..\CpuArch.h | ||
| 177 | # End Source File | ||
| 178 | # Begin Source File | ||
| 179 | |||
| 180 | SOURCE=..\..\Delta.c | ||
| 181 | # End Source File | ||
| 182 | # Begin Source File | ||
| 183 | |||
| 184 | SOURCE=..\..\Delta.h | ||
| 185 | # End Source File | ||
| 186 | # Begin Source File | ||
| 187 | |||
| 188 | SOURCE=..\..\Lzma2Dec.c | ||
| 189 | # End Source File | ||
| 190 | # Begin Source File | ||
| 191 | |||
| 192 | SOURCE=..\..\Lzma2Dec.h | ||
| 193 | # End Source File | ||
| 194 | # Begin Source File | ||
| 195 | |||
| 196 | SOURCE=..\..\LzmaDec.c | ||
| 197 | # End Source File | ||
| 198 | # Begin Source File | ||
| 199 | |||
| 200 | SOURCE=..\..\LzmaDec.h | ||
| 201 | # End Source File | ||
| 202 | # Begin Source File | ||
| 203 | |||
| 204 | SOURCE=..\..\Ppmd.h | ||
| 205 | # End Source File | ||
| 206 | # Begin Source File | ||
| 207 | |||
| 208 | SOURCE=..\..\Ppmd7.c | ||
| 209 | # End Source File | ||
| 210 | # Begin Source File | ||
| 211 | |||
| 212 | SOURCE=..\..\Ppmd7.h | ||
| 213 | # End Source File | ||
| 214 | # Begin Source File | ||
| 215 | |||
| 216 | SOURCE=..\..\Ppmd7Dec.c | ||
| 217 | # End Source File | ||
| 218 | # End Group | ||
| 219 | # Begin Group "Spec" | ||
| 220 | |||
| 221 | # PROP Default_Filter "" | ||
| 222 | # Begin Source File | ||
| 223 | |||
| 224 | SOURCE=..\..\Compiler.h | ||
| 225 | # End Source File | ||
| 226 | # Begin Source File | ||
| 227 | |||
| 228 | SOURCE=.\Precomp.c | ||
| 229 | # ADD CPP /Yc"Precomp.h" | ||
| 230 | # End Source File | ||
| 231 | # Begin Source File | ||
| 232 | |||
| 233 | SOURCE=.\Precomp.h | ||
| 234 | # End Source File | ||
| 235 | # End Group | ||
| 236 | # Begin Source File | ||
| 237 | |||
| 238 | SOURCE=.\7zMain.c | ||
| 239 | # End Source File | ||
| 240 | # End Target | ||
| 241 | # End Project | ||
diff --git a/C/Util/7z/7z.dsw b/C/Util/7z/7z.dsw new file mode 100644 index 0000000..848d13c --- /dev/null +++ b/C/Util/7z/7z.dsw | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 | ||
| 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! | ||
| 3 | |||
| 4 | ############################################################################### | ||
| 5 | |||
| 6 | Project: "7z"=.\7z.dsp - Package Owner=<4> | ||
| 7 | |||
| 8 | Package=<5> | ||
| 9 | {{{ | ||
| 10 | }}} | ||
| 11 | |||
| 12 | Package=<4> | ||
| 13 | {{{ | ||
| 14 | }}} | ||
| 15 | |||
| 16 | ############################################################################### | ||
| 17 | |||
| 18 | Global: | ||
| 19 | |||
| 20 | Package=<5> | ||
| 21 | {{{ | ||
| 22 | }}} | ||
| 23 | |||
| 24 | Package=<3> | ||
| 25 | {{{ | ||
| 26 | }}} | ||
| 27 | |||
| 28 | ############################################################################### | ||
| 29 | |||
diff --git a/C/Util/7z/7zMain.c b/C/Util/7z/7zMain.c new file mode 100644 index 0000000..9d55509 --- /dev/null +++ b/C/Util/7z/7zMain.c | |||
| @@ -0,0 +1,887 @@ | |||
| 1 | /* 7zMain.c - Test application for 7z Decoder | ||
| 2 | 2021-04-29 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <stdio.h> | ||
| 7 | #include <string.h> | ||
| 8 | |||
| 9 | #include "../../CpuArch.h" | ||
| 10 | |||
| 11 | #include "../../7z.h" | ||
| 12 | #include "../../7zAlloc.h" | ||
| 13 | #include "../../7zBuf.h" | ||
| 14 | #include "../../7zCrc.h" | ||
| 15 | #include "../../7zFile.h" | ||
| 16 | #include "../../7zVersion.h" | ||
| 17 | |||
| 18 | #ifndef USE_WINDOWS_FILE | ||
| 19 | /* for mkdir */ | ||
| 20 | #ifdef _WIN32 | ||
| 21 | #include <direct.h> | ||
| 22 | #else | ||
| 23 | #include <stdlib.h> | ||
| 24 | #include <time.h> | ||
| 25 | #ifdef __GNUC__ | ||
| 26 | #include <sys/time.h> | ||
| 27 | #endif | ||
| 28 | #include <fcntl.h> | ||
| 29 | // #include <utime.h> | ||
| 30 | #include <sys/stat.h> | ||
| 31 | #include <errno.h> | ||
| 32 | #endif | ||
| 33 | #endif | ||
| 34 | |||
| 35 | |||
| 36 | #define kInputBufSize ((size_t)1 << 18) | ||
| 37 | |||
| 38 | static const ISzAlloc g_Alloc = { SzAlloc, SzFree }; | ||
| 39 | |||
| 40 | |||
| 41 | static void Print(const char *s) | ||
| 42 | { | ||
| 43 | fputs(s, stdout); | ||
| 44 | } | ||
| 45 | |||
| 46 | |||
| 47 | static int Buf_EnsureSize(CBuf *dest, size_t size) | ||
| 48 | { | ||
| 49 | if (dest->size >= size) | ||
| 50 | return 1; | ||
| 51 | Buf_Free(dest, &g_Alloc); | ||
| 52 | return Buf_Create(dest, size, &g_Alloc); | ||
| 53 | } | ||
| 54 | |||
| 55 | #ifndef _WIN32 | ||
| 56 | #define _USE_UTF8 | ||
| 57 | #endif | ||
| 58 | |||
| 59 | /* #define _USE_UTF8 */ | ||
| 60 | |||
| 61 | #ifdef _USE_UTF8 | ||
| 62 | |||
| 63 | #define _UTF8_START(n) (0x100 - (1 << (7 - (n)))) | ||
| 64 | |||
| 65 | #define _UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6)) | ||
| 66 | |||
| 67 | #define _UTF8_HEAD(n, val) ((Byte)(_UTF8_START(n) + (val >> (6 * (n))))) | ||
| 68 | #define _UTF8_CHAR(n, val) ((Byte)(0x80 + (((val) >> (6 * (n))) & 0x3F))) | ||
| 69 | |||
| 70 | static size_t Utf16_To_Utf8_Calc(const UInt16 *src, const UInt16 *srcLim) | ||
| 71 | { | ||
| 72 | size_t size = 0; | ||
| 73 | for (;;) | ||
| 74 | { | ||
| 75 | UInt32 val; | ||
| 76 | if (src == srcLim) | ||
| 77 | return size; | ||
| 78 | |||
| 79 | size++; | ||
| 80 | val = *src++; | ||
| 81 | |||
| 82 | if (val < 0x80) | ||
| 83 | continue; | ||
| 84 | |||
| 85 | if (val < _UTF8_RANGE(1)) | ||
| 86 | { | ||
| 87 | size++; | ||
| 88 | continue; | ||
| 89 | } | ||
| 90 | |||
| 91 | if (val >= 0xD800 && val < 0xDC00 && src != srcLim) | ||
| 92 | { | ||
| 93 | UInt32 c2 = *src; | ||
| 94 | if (c2 >= 0xDC00 && c2 < 0xE000) | ||
| 95 | { | ||
| 96 | src++; | ||
| 97 | size += 3; | ||
| 98 | continue; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | size += 2; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | static Byte *Utf16_To_Utf8(Byte *dest, const UInt16 *src, const UInt16 *srcLim) | ||
| 107 | { | ||
| 108 | for (;;) | ||
| 109 | { | ||
| 110 | UInt32 val; | ||
| 111 | if (src == srcLim) | ||
| 112 | return dest; | ||
| 113 | |||
| 114 | val = *src++; | ||
| 115 | |||
| 116 | if (val < 0x80) | ||
| 117 | { | ||
| 118 | *dest++ = (Byte)val; | ||
| 119 | continue; | ||
| 120 | } | ||
| 121 | |||
| 122 | if (val < _UTF8_RANGE(1)) | ||
| 123 | { | ||
| 124 | dest[0] = _UTF8_HEAD(1, val); | ||
| 125 | dest[1] = _UTF8_CHAR(0, val); | ||
| 126 | dest += 2; | ||
| 127 | continue; | ||
| 128 | } | ||
| 129 | |||
| 130 | if (val >= 0xD800 && val < 0xDC00 && src != srcLim) | ||
| 131 | { | ||
| 132 | UInt32 c2 = *src; | ||
| 133 | if (c2 >= 0xDC00 && c2 < 0xE000) | ||
| 134 | { | ||
| 135 | src++; | ||
| 136 | val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; | ||
| 137 | dest[0] = _UTF8_HEAD(3, val); | ||
| 138 | dest[1] = _UTF8_CHAR(2, val); | ||
| 139 | dest[2] = _UTF8_CHAR(1, val); | ||
| 140 | dest[3] = _UTF8_CHAR(0, val); | ||
| 141 | dest += 4; | ||
| 142 | continue; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | dest[0] = _UTF8_HEAD(2, val); | ||
| 147 | dest[1] = _UTF8_CHAR(1, val); | ||
| 148 | dest[2] = _UTF8_CHAR(0, val); | ||
| 149 | dest += 3; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen) | ||
| 154 | { | ||
| 155 | size_t destLen = Utf16_To_Utf8_Calc(src, src + srcLen); | ||
| 156 | destLen += 1; | ||
| 157 | if (!Buf_EnsureSize(dest, destLen)) | ||
| 158 | return SZ_ERROR_MEM; | ||
| 159 | *Utf16_To_Utf8(dest->data, src, src + srcLen) = 0; | ||
| 160 | return SZ_OK; | ||
| 161 | } | ||
| 162 | |||
| 163 | #endif | ||
| 164 | |||
| 165 | static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s | ||
| 166 | #ifndef _USE_UTF8 | ||
| 167 | , UINT codePage | ||
| 168 | #endif | ||
| 169 | ) | ||
| 170 | { | ||
| 171 | unsigned len = 0; | ||
| 172 | for (len = 0; s[len] != 0; len++) {} | ||
| 173 | |||
| 174 | #ifndef _USE_UTF8 | ||
| 175 | { | ||
| 176 | const unsigned size = len * 3 + 100; | ||
| 177 | if (!Buf_EnsureSize(buf, size)) | ||
| 178 | return SZ_ERROR_MEM; | ||
| 179 | { | ||
| 180 | buf->data[0] = 0; | ||
| 181 | if (len != 0) | ||
| 182 | { | ||
| 183 | const char defaultChar = '_'; | ||
| 184 | BOOL defUsed; | ||
| 185 | const unsigned numChars = (unsigned)WideCharToMultiByte( | ||
| 186 | codePage, 0, (LPCWSTR)s, (int)len, (char *)buf->data, (int)size, &defaultChar, &defUsed); | ||
| 187 | if (numChars == 0 || numChars >= size) | ||
| 188 | return SZ_ERROR_FAIL; | ||
| 189 | buf->data[numChars] = 0; | ||
| 190 | } | ||
| 191 | return SZ_OK; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | #else | ||
| 195 | return Utf16_To_Utf8Buf(buf, s, len); | ||
| 196 | #endif | ||
| 197 | } | ||
| 198 | |||
| 199 | #ifdef _WIN32 | ||
| 200 | #ifndef USE_WINDOWS_FILE | ||
| 201 | static UINT g_FileCodePage = CP_ACP; | ||
| 202 | #define MY_FILE_CODE_PAGE_PARAM ,g_FileCodePage | ||
| 203 | #endif | ||
| 204 | #else | ||
| 205 | #define MY_FILE_CODE_PAGE_PARAM | ||
| 206 | #endif | ||
| 207 | |||
| 208 | static WRes MyCreateDir(const UInt16 *name) | ||
| 209 | { | ||
| 210 | #ifdef USE_WINDOWS_FILE | ||
| 211 | |||
| 212 | return CreateDirectoryW((LPCWSTR)name, NULL) ? 0 : GetLastError(); | ||
| 213 | |||
| 214 | #else | ||
| 215 | |||
| 216 | CBuf buf; | ||
| 217 | WRes res; | ||
| 218 | Buf_Init(&buf); | ||
| 219 | RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)); | ||
| 220 | |||
| 221 | res = | ||
| 222 | #ifdef _WIN32 | ||
| 223 | _mkdir((const char *)buf.data) | ||
| 224 | #else | ||
| 225 | mkdir((const char *)buf.data, 0777) | ||
| 226 | #endif | ||
| 227 | == 0 ? 0 : errno; | ||
| 228 | Buf_Free(&buf, &g_Alloc); | ||
| 229 | return res; | ||
| 230 | |||
| 231 | #endif | ||
| 232 | } | ||
| 233 | |||
| 234 | static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name) | ||
| 235 | { | ||
| 236 | #ifdef USE_WINDOWS_FILE | ||
| 237 | return OutFile_OpenW(p, (LPCWSTR)name); | ||
| 238 | #else | ||
| 239 | CBuf buf; | ||
| 240 | WRes res; | ||
| 241 | Buf_Init(&buf); | ||
| 242 | RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)); | ||
| 243 | res = OutFile_Open(p, (const char *)buf.data); | ||
| 244 | Buf_Free(&buf, &g_Alloc); | ||
| 245 | return res; | ||
| 246 | #endif | ||
| 247 | } | ||
| 248 | |||
| 249 | |||
| 250 | static SRes PrintString(const UInt16 *s) | ||
| 251 | { | ||
| 252 | CBuf buf; | ||
| 253 | SRes res; | ||
| 254 | Buf_Init(&buf); | ||
| 255 | res = Utf16_To_Char(&buf, s | ||
| 256 | #ifndef _USE_UTF8 | ||
| 257 | , CP_OEMCP | ||
| 258 | #endif | ||
| 259 | ); | ||
| 260 | if (res == SZ_OK) | ||
| 261 | Print((const char *)buf.data); | ||
| 262 | Buf_Free(&buf, &g_Alloc); | ||
| 263 | return res; | ||
| 264 | } | ||
| 265 | |||
| 266 | static void UInt64ToStr(UInt64 value, char *s, int numDigits) | ||
| 267 | { | ||
| 268 | char temp[32]; | ||
| 269 | int pos = 0; | ||
| 270 | do | ||
| 271 | { | ||
| 272 | temp[pos++] = (char)('0' + (unsigned)(value % 10)); | ||
| 273 | value /= 10; | ||
| 274 | } | ||
| 275 | while (value != 0); | ||
| 276 | |||
| 277 | for (numDigits -= pos; numDigits > 0; numDigits--) | ||
| 278 | *s++ = ' '; | ||
| 279 | |||
| 280 | do | ||
| 281 | *s++ = temp[--pos]; | ||
| 282 | while (pos); | ||
| 283 | *s = '\0'; | ||
| 284 | } | ||
| 285 | |||
| 286 | static char *UIntToStr(char *s, unsigned value, int numDigits) | ||
| 287 | { | ||
| 288 | char temp[16]; | ||
| 289 | int pos = 0; | ||
| 290 | do | ||
| 291 | temp[pos++] = (char)('0' + (value % 10)); | ||
| 292 | while (value /= 10); | ||
| 293 | |||
| 294 | for (numDigits -= pos; numDigits > 0; numDigits--) | ||
| 295 | *s++ = '0'; | ||
| 296 | |||
| 297 | do | ||
| 298 | *s++ = temp[--pos]; | ||
| 299 | while (pos); | ||
| 300 | *s = '\0'; | ||
| 301 | return s; | ||
| 302 | } | ||
| 303 | |||
| 304 | static void UIntToStr_2(char *s, unsigned value) | ||
| 305 | { | ||
| 306 | s[0] = (char)('0' + (value / 10)); | ||
| 307 | s[1] = (char)('0' + (value % 10)); | ||
| 308 | } | ||
| 309 | |||
| 310 | |||
| 311 | #define PERIOD_4 (4 * 365 + 1) | ||
| 312 | #define PERIOD_100 (PERIOD_4 * 25 - 1) | ||
| 313 | #define PERIOD_400 (PERIOD_100 * 4 + 1) | ||
| 314 | |||
| 315 | |||
| 316 | |||
| 317 | #ifndef _WIN32 | ||
| 318 | |||
| 319 | // MS uses long for BOOL, but long is 32-bit in MS. So we use int. | ||
| 320 | // typedef long BOOL; | ||
| 321 | typedef int BOOL; | ||
| 322 | |||
| 323 | typedef struct _FILETIME | ||
| 324 | { | ||
| 325 | DWORD dwLowDateTime; | ||
| 326 | DWORD dwHighDateTime; | ||
| 327 | } FILETIME; | ||
| 328 | |||
| 329 | static LONG TIME_GetBias() | ||
| 330 | { | ||
| 331 | time_t utc = time(NULL); | ||
| 332 | struct tm *ptm = localtime(&utc); | ||
| 333 | int localdaylight = ptm->tm_isdst; /* daylight for local timezone */ | ||
| 334 | ptm = gmtime(&utc); | ||
| 335 | ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */ | ||
| 336 | LONG bias = (int)(mktime(ptm)-utc); | ||
| 337 | return bias; | ||
| 338 | } | ||
| 339 | |||
| 340 | #define TICKS_PER_SEC 10000000 | ||
| 341 | |||
| 342 | #define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32)) | ||
| 343 | |||
| 344 | #define SET_FILETIME(ft, v64) \ | ||
| 345 | (ft)->dwLowDateTime = (DWORD)v64; \ | ||
| 346 | (ft)->dwHighDateTime = (DWORD)(v64 >> 32); | ||
| 347 | |||
| 348 | #define WINAPI | ||
| 349 | #define TRUE 1 | ||
| 350 | |||
| 351 | static BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime) | ||
| 352 | { | ||
| 353 | UInt64 v = GET_TIME_64(fileTime); | ||
| 354 | v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC); | ||
| 355 | SET_FILETIME(localFileTime, v); | ||
| 356 | return TRUE; | ||
| 357 | } | ||
| 358 | |||
| 359 | static const UInt32 kNumTimeQuantumsInSecond = 10000000; | ||
| 360 | static const UInt32 kFileTimeStartYear = 1601; | ||
| 361 | static const UInt32 kUnixTimeStartYear = 1970; | ||
| 362 | static const UInt64 kUnixTimeOffset = | ||
| 363 | (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); | ||
| 364 | |||
| 365 | static Int64 Time_FileTimeToUnixTime64(const FILETIME *ft) | ||
| 366 | { | ||
| 367 | UInt64 winTime = GET_TIME_64(ft); | ||
| 368 | return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; | ||
| 369 | } | ||
| 370 | |||
| 371 | #if defined(_AIX) | ||
| 372 | #define MY_ST_TIMESPEC st_timespec | ||
| 373 | #else | ||
| 374 | #define MY_ST_TIMESPEC timespec | ||
| 375 | #endif | ||
| 376 | |||
| 377 | static void FILETIME_To_timespec(const FILETIME *ft, struct MY_ST_TIMESPEC *ts) | ||
| 378 | { | ||
| 379 | if (ft) | ||
| 380 | { | ||
| 381 | const Int64 sec = Time_FileTimeToUnixTime64(ft); | ||
| 382 | // time_t is long | ||
| 383 | const time_t sec2 = (time_t)sec; | ||
| 384 | if (sec2 == sec) | ||
| 385 | { | ||
| 386 | ts->tv_sec = sec2; | ||
| 387 | UInt64 winTime = GET_TIME_64(ft); | ||
| 388 | ts->tv_nsec = (long)((winTime % 10000000) * 100);; | ||
| 389 | return; | ||
| 390 | } | ||
| 391 | } | ||
| 392 | // else | ||
| 393 | { | ||
| 394 | ts->tv_sec = 0; | ||
| 395 | // ts.tv_nsec = UTIME_NOW; // set to the current time | ||
| 396 | ts->tv_nsec = UTIME_OMIT; // keep old timesptamp | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | static WRes Set_File_FILETIME(const UInt16 *name, const FILETIME *mTime) | ||
| 401 | { | ||
| 402 | struct timespec times[2]; | ||
| 403 | |||
| 404 | const int flags = 0; // follow link | ||
| 405 | // = AT_SYMLINK_NOFOLLOW; // don't follow link | ||
| 406 | |||
| 407 | CBuf buf; | ||
| 408 | int res; | ||
| 409 | Buf_Init(&buf); | ||
| 410 | RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)); | ||
| 411 | FILETIME_To_timespec(NULL, ×[0]); | ||
| 412 | FILETIME_To_timespec(mTime, ×[1]); | ||
| 413 | res = utimensat(AT_FDCWD, (const char *)buf.data, times, flags); | ||
| 414 | Buf_Free(&buf, &g_Alloc); | ||
| 415 | if (res == 0) | ||
| 416 | return 0; | ||
| 417 | return errno; | ||
| 418 | } | ||
| 419 | |||
| 420 | #endif | ||
| 421 | |||
| 422 | static void NtfsFileTime_to_FILETIME(const CNtfsFileTime *t, FILETIME *ft) | ||
| 423 | { | ||
| 424 | ft->dwLowDateTime = (DWORD)(t->Low); | ||
| 425 | ft->dwHighDateTime = (DWORD)(t->High); | ||
| 426 | } | ||
| 427 | |||
| 428 | static void ConvertFileTimeToString(const CNtfsFileTime *nTime, char *s) | ||
| 429 | { | ||
| 430 | unsigned year, mon, hour, min, sec; | ||
| 431 | Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | ||
| 432 | unsigned t; | ||
| 433 | UInt32 v; | ||
| 434 | // UInt64 v64 = nt->Low | ((UInt64)nt->High << 32); | ||
| 435 | UInt64 v64; | ||
| 436 | { | ||
| 437 | FILETIME fileTime, locTime; | ||
| 438 | NtfsFileTime_to_FILETIME(nTime, &fileTime); | ||
| 439 | if (!FileTimeToLocalFileTime(&fileTime, &locTime)) | ||
| 440 | { | ||
| 441 | locTime.dwHighDateTime = | ||
| 442 | locTime.dwLowDateTime = 0; | ||
| 443 | } | ||
| 444 | v64 = locTime.dwLowDateTime | ((UInt64)locTime.dwHighDateTime << 32); | ||
| 445 | } | ||
| 446 | v64 /= 10000000; | ||
| 447 | sec = (unsigned)(v64 % 60); v64 /= 60; | ||
| 448 | min = (unsigned)(v64 % 60); v64 /= 60; | ||
| 449 | hour = (unsigned)(v64 % 24); v64 /= 24; | ||
| 450 | |||
| 451 | v = (UInt32)v64; | ||
| 452 | |||
| 453 | year = (unsigned)(1601 + v / PERIOD_400 * 400); | ||
| 454 | v %= PERIOD_400; | ||
| 455 | |||
| 456 | t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100; | ||
| 457 | t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4; | ||
| 458 | t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365; | ||
| 459 | |||
| 460 | if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) | ||
| 461 | ms[1] = 29; | ||
| 462 | for (mon = 0;; mon++) | ||
| 463 | { | ||
| 464 | unsigned d = ms[mon]; | ||
| 465 | if (v < d) | ||
| 466 | break; | ||
| 467 | v -= d; | ||
| 468 | } | ||
| 469 | s = UIntToStr(s, year, 4); *s++ = '-'; | ||
| 470 | UIntToStr_2(s, mon + 1); s[2] = '-'; s += 3; | ||
| 471 | UIntToStr_2(s, (unsigned)v + 1); s[2] = ' '; s += 3; | ||
| 472 | UIntToStr_2(s, hour); s[2] = ':'; s += 3; | ||
| 473 | UIntToStr_2(s, min); s[2] = ':'; s += 3; | ||
| 474 | UIntToStr_2(s, sec); s[2] = 0; | ||
| 475 | } | ||
| 476 | |||
| 477 | static void PrintLF() | ||
| 478 | { | ||
| 479 | Print("\n"); | ||
| 480 | } | ||
| 481 | |||
| 482 | static void PrintError(char *s) | ||
| 483 | { | ||
| 484 | Print("\nERROR: "); | ||
| 485 | Print(s); | ||
| 486 | PrintLF(); | ||
| 487 | } | ||
| 488 | |||
| 489 | static void PrintError_WRes(const char *message, WRes wres) | ||
| 490 | { | ||
| 491 | Print("\nERROR: "); | ||
| 492 | Print(message); | ||
| 493 | PrintLF(); | ||
| 494 | { | ||
| 495 | char s[32]; | ||
| 496 | UIntToStr(s, (unsigned)wres, 1); | ||
| 497 | Print("System error code: "); | ||
| 498 | Print(s); | ||
| 499 | } | ||
| 500 | // sprintf(buffer + strlen(buffer), "\nSystem error code: %d", (unsigned)wres); | ||
| 501 | #ifdef _WIN32 | ||
| 502 | { | ||
| 503 | char *s = NULL; | ||
| 504 | if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||
| 505 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | ||
| 506 | NULL, wres, 0, (LPSTR) &s, 0, NULL) != 0 && s) | ||
| 507 | { | ||
| 508 | Print(" : "); | ||
| 509 | Print(s); | ||
| 510 | LocalFree(s); | ||
| 511 | } | ||
| 512 | } | ||
| 513 | #else | ||
| 514 | { | ||
| 515 | const char *s = strerror(wres); | ||
| 516 | if (s) | ||
| 517 | { | ||
| 518 | Print(" : "); | ||
| 519 | Print(s); | ||
| 520 | } | ||
| 521 | } | ||
| 522 | #endif | ||
| 523 | PrintLF(); | ||
| 524 | } | ||
| 525 | |||
| 526 | static void GetAttribString(UInt32 wa, BoolInt isDir, char *s) | ||
| 527 | { | ||
| 528 | #ifdef USE_WINDOWS_FILE | ||
| 529 | s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : '.'); | ||
| 530 | s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY ) != 0) ? 'R': '.'); | ||
| 531 | s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN ) != 0) ? 'H': '.'); | ||
| 532 | s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM ) != 0) ? 'S': '.'); | ||
| 533 | s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE ) != 0) ? 'A': '.'); | ||
| 534 | s[5] = 0; | ||
| 535 | #else | ||
| 536 | s[0] = (char)(((wa & (1 << 4)) != 0 || isDir) ? 'D' : '.'); | ||
| 537 | s[1] = 0; | ||
| 538 | #endif | ||
| 539 | } | ||
| 540 | |||
| 541 | |||
| 542 | // #define NUM_PARENTS_MAX 128 | ||
| 543 | |||
| 544 | int MY_CDECL main(int numargs, char *args[]) | ||
| 545 | { | ||
| 546 | ISzAlloc allocImp; | ||
| 547 | ISzAlloc allocTempImp; | ||
| 548 | |||
| 549 | CFileInStream archiveStream; | ||
| 550 | CLookToRead2 lookStream; | ||
| 551 | CSzArEx db; | ||
| 552 | SRes res; | ||
| 553 | UInt16 *temp = NULL; | ||
| 554 | size_t tempSize = 0; | ||
| 555 | // UInt32 parents[NUM_PARENTS_MAX]; | ||
| 556 | |||
| 557 | Print("\n7z Decoder " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n"); | ||
| 558 | |||
| 559 | if (numargs == 1) | ||
| 560 | { | ||
| 561 | Print( | ||
| 562 | "Usage: 7zDec <command> <archive_name>\n\n" | ||
| 563 | "<Commands>\n" | ||
| 564 | " e: Extract files from archive (without using directory names)\n" | ||
| 565 | " l: List contents of archive\n" | ||
| 566 | " t: Test integrity of archive\n" | ||
| 567 | " x: eXtract files with full paths\n"); | ||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | if (numargs < 3) | ||
| 572 | { | ||
| 573 | PrintError("incorrect command"); | ||
| 574 | return 1; | ||
| 575 | } | ||
| 576 | |||
| 577 | #if defined(_WIN32) && !defined(USE_WINDOWS_FILE) && !defined(UNDER_CE) | ||
| 578 | g_FileCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; | ||
| 579 | #endif | ||
| 580 | |||
| 581 | |||
| 582 | allocImp = g_Alloc; | ||
| 583 | allocTempImp = g_Alloc; | ||
| 584 | |||
| 585 | { | ||
| 586 | WRes wres = | ||
| 587 | #ifdef UNDER_CE | ||
| 588 | InFile_OpenW(&archiveStream.file, L"\test.7z"); // change it | ||
| 589 | #else | ||
| 590 | InFile_Open(&archiveStream.file, args[2]); | ||
| 591 | #endif | ||
| 592 | if (wres != 0) | ||
| 593 | { | ||
| 594 | PrintError_WRes("cannot open input file", wres); | ||
| 595 | return 1; | ||
| 596 | } | ||
| 597 | } | ||
| 598 | |||
| 599 | FileInStream_CreateVTable(&archiveStream); | ||
| 600 | archiveStream.wres = 0; | ||
| 601 | LookToRead2_CreateVTable(&lookStream, False); | ||
| 602 | lookStream.buf = NULL; | ||
| 603 | |||
| 604 | res = SZ_OK; | ||
| 605 | |||
| 606 | { | ||
| 607 | lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize); | ||
| 608 | if (!lookStream.buf) | ||
| 609 | res = SZ_ERROR_MEM; | ||
| 610 | else | ||
| 611 | { | ||
| 612 | lookStream.bufSize = kInputBufSize; | ||
| 613 | lookStream.realStream = &archiveStream.vt; | ||
| 614 | LookToRead2_Init(&lookStream); | ||
| 615 | } | ||
| 616 | } | ||
| 617 | |||
| 618 | CrcGenerateTable(); | ||
| 619 | |||
| 620 | SzArEx_Init(&db); | ||
| 621 | |||
| 622 | if (res == SZ_OK) | ||
| 623 | { | ||
| 624 | res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp); | ||
| 625 | } | ||
| 626 | |||
| 627 | if (res == SZ_OK) | ||
| 628 | { | ||
| 629 | char *command = args[1]; | ||
| 630 | int listCommand = 0, testCommand = 0, fullPaths = 0; | ||
| 631 | |||
| 632 | if (strcmp(command, "l") == 0) listCommand = 1; | ||
| 633 | else if (strcmp(command, "t") == 0) testCommand = 1; | ||
| 634 | else if (strcmp(command, "e") == 0) { } | ||
| 635 | else if (strcmp(command, "x") == 0) { fullPaths = 1; } | ||
| 636 | else | ||
| 637 | { | ||
| 638 | PrintError("incorrect command"); | ||
| 639 | res = SZ_ERROR_FAIL; | ||
| 640 | } | ||
| 641 | |||
| 642 | if (res == SZ_OK) | ||
| 643 | { | ||
| 644 | UInt32 i; | ||
| 645 | |||
| 646 | /* | ||
| 647 | if you need cache, use these 3 variables. | ||
| 648 | if you use external function, you can make these variable as static. | ||
| 649 | */ | ||
| 650 | UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */ | ||
| 651 | Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */ | ||
| 652 | size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */ | ||
| 653 | |||
| 654 | for (i = 0; i < db.NumFiles; i++) | ||
| 655 | { | ||
| 656 | size_t offset = 0; | ||
| 657 | size_t outSizeProcessed = 0; | ||
| 658 | // const CSzFileItem *f = db.Files + i; | ||
| 659 | size_t len; | ||
| 660 | const BoolInt isDir = SzArEx_IsDir(&db, i); | ||
| 661 | if (listCommand == 0 && isDir && !fullPaths) | ||
| 662 | continue; | ||
| 663 | len = SzArEx_GetFileNameUtf16(&db, i, NULL); | ||
| 664 | // len = SzArEx_GetFullNameLen(&db, i); | ||
| 665 | |||
| 666 | if (len > tempSize) | ||
| 667 | { | ||
| 668 | SzFree(NULL, temp); | ||
| 669 | tempSize = len; | ||
| 670 | temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0])); | ||
| 671 | if (!temp) | ||
| 672 | { | ||
| 673 | res = SZ_ERROR_MEM; | ||
| 674 | break; | ||
| 675 | } | ||
| 676 | } | ||
| 677 | |||
| 678 | SzArEx_GetFileNameUtf16(&db, i, temp); | ||
| 679 | /* | ||
| 680 | if (SzArEx_GetFullNameUtf16_Back(&db, i, temp + len) != temp) | ||
| 681 | { | ||
| 682 | res = SZ_ERROR_FAIL; | ||
| 683 | break; | ||
| 684 | } | ||
| 685 | */ | ||
| 686 | |||
| 687 | if (listCommand) | ||
| 688 | { | ||
| 689 | char attr[8], s[32], t[32]; | ||
| 690 | UInt64 fileSize; | ||
| 691 | |||
| 692 | GetAttribString(SzBitWithVals_Check(&db.Attribs, i) ? db.Attribs.Vals[i] : 0, isDir, attr); | ||
| 693 | |||
| 694 | fileSize = SzArEx_GetFileSize(&db, i); | ||
| 695 | UInt64ToStr(fileSize, s, 10); | ||
| 696 | |||
| 697 | if (SzBitWithVals_Check(&db.MTime, i)) | ||
| 698 | ConvertFileTimeToString(&db.MTime.Vals[i], t); | ||
| 699 | else | ||
| 700 | { | ||
| 701 | size_t j; | ||
| 702 | for (j = 0; j < 19; j++) | ||
| 703 | t[j] = ' '; | ||
| 704 | t[j] = '\0'; | ||
| 705 | } | ||
| 706 | |||
| 707 | Print(t); | ||
| 708 | Print(" "); | ||
| 709 | Print(attr); | ||
| 710 | Print(" "); | ||
| 711 | Print(s); | ||
| 712 | Print(" "); | ||
| 713 | res = PrintString(temp); | ||
| 714 | if (res != SZ_OK) | ||
| 715 | break; | ||
| 716 | if (isDir) | ||
| 717 | Print("/"); | ||
| 718 | PrintLF(); | ||
| 719 | continue; | ||
| 720 | } | ||
| 721 | |||
| 722 | Print(testCommand ? | ||
| 723 | "T ": | ||
| 724 | "- "); | ||
| 725 | res = PrintString(temp); | ||
| 726 | if (res != SZ_OK) | ||
| 727 | break; | ||
| 728 | |||
| 729 | if (isDir) | ||
| 730 | Print("/"); | ||
| 731 | else | ||
| 732 | { | ||
| 733 | res = SzArEx_Extract(&db, &lookStream.vt, i, | ||
| 734 | &blockIndex, &outBuffer, &outBufferSize, | ||
| 735 | &offset, &outSizeProcessed, | ||
| 736 | &allocImp, &allocTempImp); | ||
| 737 | if (res != SZ_OK) | ||
| 738 | break; | ||
| 739 | } | ||
| 740 | |||
| 741 | if (!testCommand) | ||
| 742 | { | ||
| 743 | CSzFile outFile; | ||
| 744 | size_t processedSize; | ||
| 745 | size_t j; | ||
| 746 | UInt16 *name = (UInt16 *)temp; | ||
| 747 | const UInt16 *destPath = (const UInt16 *)name; | ||
| 748 | |||
| 749 | for (j = 0; name[j] != 0; j++) | ||
| 750 | if (name[j] == '/') | ||
| 751 | { | ||
| 752 | if (fullPaths) | ||
| 753 | { | ||
| 754 | name[j] = 0; | ||
| 755 | MyCreateDir(name); | ||
| 756 | name[j] = CHAR_PATH_SEPARATOR; | ||
| 757 | } | ||
| 758 | else | ||
| 759 | destPath = name + j + 1; | ||
| 760 | } | ||
| 761 | |||
| 762 | if (isDir) | ||
| 763 | { | ||
| 764 | MyCreateDir(destPath); | ||
| 765 | PrintLF(); | ||
| 766 | continue; | ||
| 767 | } | ||
| 768 | else | ||
| 769 | { | ||
| 770 | WRes wres = OutFile_OpenUtf16(&outFile, destPath); | ||
| 771 | if (wres != 0) | ||
| 772 | { | ||
| 773 | PrintError_WRes("cannot open output file", wres); | ||
| 774 | res = SZ_ERROR_FAIL; | ||
| 775 | break; | ||
| 776 | } | ||
| 777 | } | ||
| 778 | |||
| 779 | processedSize = outSizeProcessed; | ||
| 780 | |||
| 781 | { | ||
| 782 | WRes wres = File_Write(&outFile, outBuffer + offset, &processedSize); | ||
| 783 | if (wres != 0 || processedSize != outSizeProcessed) | ||
| 784 | { | ||
| 785 | PrintError_WRes("cannot write output file", wres); | ||
| 786 | res = SZ_ERROR_FAIL; | ||
| 787 | break; | ||
| 788 | } | ||
| 789 | } | ||
| 790 | |||
| 791 | { | ||
| 792 | FILETIME mtime; | ||
| 793 | FILETIME *mtimePtr = NULL; | ||
| 794 | |||
| 795 | #ifdef USE_WINDOWS_FILE | ||
| 796 | FILETIME ctime; | ||
| 797 | FILETIME *ctimePtr = NULL; | ||
| 798 | #endif | ||
| 799 | |||
| 800 | if (SzBitWithVals_Check(&db.MTime, i)) | ||
| 801 | { | ||
| 802 | const CNtfsFileTime *t = &db.MTime.Vals[i]; | ||
| 803 | mtime.dwLowDateTime = (DWORD)(t->Low); | ||
| 804 | mtime.dwHighDateTime = (DWORD)(t->High); | ||
| 805 | mtimePtr = &mtime; | ||
| 806 | } | ||
| 807 | |||
| 808 | #ifdef USE_WINDOWS_FILE | ||
| 809 | if (SzBitWithVals_Check(&db.CTime, i)) | ||
| 810 | { | ||
| 811 | const CNtfsFileTime *t = &db.CTime.Vals[i]; | ||
| 812 | ctime.dwLowDateTime = (DWORD)(t->Low); | ||
| 813 | ctime.dwHighDateTime = (DWORD)(t->High); | ||
| 814 | ctimePtr = &ctime; | ||
| 815 | } | ||
| 816 | |||
| 817 | if (mtimePtr || ctimePtr) | ||
| 818 | SetFileTime(outFile.handle, ctimePtr, NULL, mtimePtr); | ||
| 819 | #endif | ||
| 820 | |||
| 821 | { | ||
| 822 | WRes wres = File_Close(&outFile); | ||
| 823 | if (wres != 0) | ||
| 824 | { | ||
| 825 | PrintError_WRes("cannot close output file", wres); | ||
| 826 | res = SZ_ERROR_FAIL; | ||
| 827 | break; | ||
| 828 | } | ||
| 829 | } | ||
| 830 | |||
| 831 | #ifndef USE_WINDOWS_FILE | ||
| 832 | #ifdef _WIN32 | ||
| 833 | mtimePtr = mtimePtr; | ||
| 834 | #else | ||
| 835 | if (mtimePtr) | ||
| 836 | Set_File_FILETIME(destPath, mtimePtr); | ||
| 837 | #endif | ||
| 838 | #endif | ||
| 839 | } | ||
| 840 | |||
| 841 | #ifdef USE_WINDOWS_FILE | ||
| 842 | if (SzBitWithVals_Check(&db.Attribs, i)) | ||
| 843 | { | ||
| 844 | UInt32 attrib = db.Attribs.Vals[i]; | ||
| 845 | /* p7zip stores posix attributes in high 16 bits and adds 0x8000 as marker. | ||
| 846 | We remove posix bits, if we detect posix mode field */ | ||
| 847 | if ((attrib & 0xF0000000) != 0) | ||
| 848 | attrib &= 0x7FFF; | ||
| 849 | SetFileAttributesW((LPCWSTR)destPath, attrib); | ||
| 850 | } | ||
| 851 | #endif | ||
| 852 | } | ||
| 853 | PrintLF(); | ||
| 854 | } | ||
| 855 | ISzAlloc_Free(&allocImp, outBuffer); | ||
| 856 | } | ||
| 857 | } | ||
| 858 | |||
| 859 | SzFree(NULL, temp); | ||
| 860 | SzArEx_Free(&db, &allocImp); | ||
| 861 | ISzAlloc_Free(&allocImp, lookStream.buf); | ||
| 862 | |||
| 863 | File_Close(&archiveStream.file); | ||
| 864 | |||
| 865 | if (res == SZ_OK) | ||
| 866 | { | ||
| 867 | Print("\nEverything is Ok\n"); | ||
| 868 | return 0; | ||
| 869 | } | ||
| 870 | |||
| 871 | if (res == SZ_ERROR_UNSUPPORTED) | ||
| 872 | PrintError("decoder doesn't support this archive"); | ||
| 873 | else if (res == SZ_ERROR_MEM) | ||
| 874 | PrintError("cannot allocate memory"); | ||
| 875 | else if (res == SZ_ERROR_CRC) | ||
| 876 | PrintError("CRC error"); | ||
| 877 | else if (res == SZ_ERROR_READ /* || archiveStream.Res != 0 */) | ||
| 878 | PrintError_WRes("Read Error", archiveStream.wres); | ||
| 879 | else | ||
| 880 | { | ||
| 881 | char s[32]; | ||
| 882 | UInt64ToStr((unsigned)res, s, 0); | ||
| 883 | PrintError(s); | ||
| 884 | } | ||
| 885 | |||
| 886 | return 1; | ||
| 887 | } | ||
diff --git a/C/Util/7z/Precomp.c b/C/Util/7z/Precomp.c new file mode 100644 index 0000000..01605e3 --- /dev/null +++ b/C/Util/7z/Precomp.c | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | /* Precomp.c -- StdAfx | ||
| 2 | 2013-01-21 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
diff --git a/C/Util/7z/Precomp.h b/C/Util/7z/Precomp.h new file mode 100644 index 0000000..588a66f --- /dev/null +++ b/C/Util/7z/Precomp.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | /* Precomp.h -- StdAfx | ||
| 2 | 2013-06-16 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_PRECOMP_H | ||
| 5 | #define __7Z_PRECOMP_H | ||
| 6 | |||
| 7 | #include "../../Compiler.h" | ||
| 8 | #include "../../7zTypes.h" | ||
| 9 | |||
| 10 | #endif | ||
diff --git a/C/Util/7z/makefile b/C/Util/7z/makefile new file mode 100644 index 0000000..9a49fd5 --- /dev/null +++ b/C/Util/7z/makefile | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | CFLAGS = $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT | ||
| 2 | |||
| 3 | PROG = 7zDec.exe | ||
| 4 | |||
| 5 | C_OBJS = \ | ||
| 6 | $O\7zAlloc.obj \ | ||
| 7 | $O\7zBuf.obj \ | ||
| 8 | $O\7zCrc.obj \ | ||
| 9 | $O\7zCrcOpt.obj \ | ||
| 10 | $O\7zFile.obj \ | ||
| 11 | $O\7zDec.obj \ | ||
| 12 | $O\7zArcIn.obj \ | ||
| 13 | $O\7zStream.obj \ | ||
| 14 | $O\Bcj2.obj \ | ||
| 15 | $O\Bra.obj \ | ||
| 16 | $O\Bra86.obj \ | ||
| 17 | $O\BraIA64.obj \ | ||
| 18 | $O\CpuArch.obj \ | ||
| 19 | $O\Delta.obj \ | ||
| 20 | $O\Lzma2Dec.obj \ | ||
| 21 | $O\LzmaDec.obj \ | ||
| 22 | $O\Ppmd7.obj \ | ||
| 23 | $O\Ppmd7Dec.obj \ | ||
| 24 | |||
| 25 | 7Z_OBJS = \ | ||
| 26 | $O\7zMain.obj \ | ||
| 27 | |||
| 28 | OBJS = \ | ||
| 29 | $O\Precomp.obj \ | ||
| 30 | $(7Z_OBJS) \ | ||
| 31 | $(C_OBJS) \ | ||
| 32 | |||
| 33 | !include "../../../CPP/Build.mak" | ||
| 34 | |||
| 35 | $(7Z_OBJS): $(*B).c | ||
| 36 | $(CCOMPL_USE) | ||
| 37 | $(C_OBJS): ../../$(*B).c | ||
| 38 | $(CCOMPL_USE) | ||
| 39 | $O\Precomp.obj: Precomp.c | ||
| 40 | $(CCOMPL_PCH) | ||
diff --git a/C/Util/7z/makefile.gcc b/C/Util/7z/makefile.gcc new file mode 100644 index 0000000..4263d67 --- /dev/null +++ b/C/Util/7z/makefile.gcc | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | PROG = 7zdec | ||
| 2 | |||
| 3 | LOCAL_FLAGS = -D_7ZIP_PPMD_SUPPPORT | ||
| 4 | |||
| 5 | include ../../../CPP/7zip/LzmaDec_gcc.mak | ||
| 6 | |||
| 7 | |||
| 8 | OBJS = \ | ||
| 9 | $(LZMA_DEC_OPT_OBJS) \ | ||
| 10 | $O/Bcj2.o \ | ||
| 11 | $O/Bra.o \ | ||
| 12 | $O/Bra86.o \ | ||
| 13 | $O/BraIA64.o \ | ||
| 14 | $O/CpuArch.o \ | ||
| 15 | $O/Delta.o \ | ||
| 16 | $O/Lzma2Dec.o \ | ||
| 17 | $O/LzmaDec.o \ | ||
| 18 | $O/Ppmd7.o \ | ||
| 19 | $O/Ppmd7Dec.o \ | ||
| 20 | $O/7zCrc.o \ | ||
| 21 | $O/7zCrcOpt.o \ | ||
| 22 | $O/Sha256.o \ | ||
| 23 | $O/Sha256Opt.o \ | ||
| 24 | $O/7zAlloc.o \ | ||
| 25 | $O/7zArcIn.o \ | ||
| 26 | $O/7zBuf.o \ | ||
| 27 | $O/7zBuf2.o \ | ||
| 28 | $O/7zDec.o \ | ||
| 29 | $O/7zMain.o \ | ||
| 30 | $O/7zFile.o \ | ||
| 31 | $O/7zStream.o \ | ||
| 32 | |||
| 33 | |||
| 34 | include ../../7zip_gcc_c.mak | ||
diff --git a/C/Util/7zipInstall/7zip.ico b/C/Util/7zipInstall/7zip.ico new file mode 100644 index 0000000..47ffb78 --- /dev/null +++ b/C/Util/7zipInstall/7zip.ico | |||
| Binary files differ | |||
diff --git a/C/Util/7zipInstall/7zipInstall.c b/C/Util/7zipInstall/7zipInstall.c new file mode 100644 index 0000000..00d0f41 --- /dev/null +++ b/C/Util/7zipInstall/7zipInstall.c | |||
| @@ -0,0 +1,1666 @@ | |||
| 1 | /* 7zipInstall.c - 7-Zip Installer | ||
| 2 | 2021-09-02 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #define SZ_ERROR_ABORT 100 | ||
| 7 | |||
| 8 | #ifdef _MSC_VER | ||
| 9 | #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #include <windows.h> | ||
| 13 | #include <ShlObj.h> | ||
| 14 | |||
| 15 | #include "../../7z.h" | ||
| 16 | #include "../../7zAlloc.h" | ||
| 17 | #include "../../7zCrc.h" | ||
| 18 | #include "../../7zFile.h" | ||
| 19 | #include "../../7zVersion.h" | ||
| 20 | #include "../../CpuArch.h" | ||
| 21 | #include "../../DllSecur.h" | ||
| 22 | |||
| 23 | #include "resource.h" | ||
| 24 | |||
| 25 | #define LLL_(quote) L##quote | ||
| 26 | #define LLL(quote) LLL_(quote) | ||
| 27 | |||
| 28 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) | ||
| 29 | |||
| 30 | #define wcscat lstrcatW | ||
| 31 | #define wcslen lstrlenW | ||
| 32 | #define wcscpy lstrcpyW | ||
| 33 | // wcsncpy() and lstrcpynW() work differently. We don't use them. | ||
| 34 | |||
| 35 | |||
| 36 | #define kInputBufSize ((size_t)1 << 18) | ||
| 37 | |||
| 38 | |||
| 39 | #define _7ZIP_CUR_VER ((MY_VER_MAJOR << 16) | MY_VER_MINOR) | ||
| 40 | #define _7ZIP_DLL_VER_COMPAT ((16 << 16) | 3) | ||
| 41 | |||
| 42 | static LPCSTR const k_7zip = "7-Zip"; | ||
| 43 | |||
| 44 | static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip"; | ||
| 45 | |||
| 46 | // #define _64BIT_INSTALLER 1 | ||
| 47 | |||
| 48 | #ifdef _WIN64 | ||
| 49 | #define _64BIT_INSTALLER 1 | ||
| 50 | #endif | ||
| 51 | |||
| 52 | #define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION) | ||
| 53 | |||
| 54 | #ifdef _64BIT_INSTALLER | ||
| 55 | |||
| 56 | // #define USE_7ZIP_32_DLL | ||
| 57 | |||
| 58 | #if defined(_M_ARM64) || defined(_M_ARM) | ||
| 59 | #define k_Postfix L" (arm64)" | ||
| 60 | #else | ||
| 61 | #define k_Postfix L" (x64)" | ||
| 62 | #define USE_7ZIP_32_DLL | ||
| 63 | #endif | ||
| 64 | #else | ||
| 65 | #if defined(_M_ARM64) || defined(_M_ARM) | ||
| 66 | #define k_Postfix L" (arm)" | ||
| 67 | #else | ||
| 68 | // #define k_Postfix L" (x86)" | ||
| 69 | #define k_Postfix | ||
| 70 | #endif | ||
| 71 | #endif | ||
| 72 | |||
| 73 | #define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix | ||
| 74 | |||
| 75 | |||
| 76 | static LPCWSTR const k_7zip_with_Ver_str = k_7zip_with_Ver; | ||
| 77 | |||
| 78 | static LPCWSTR const k_7zip_Setup = k_7zip_with_Ver L" Setup"; | ||
| 79 | |||
| 80 | static LPCWSTR const k_Reg_Path = L"Path"; | ||
| 81 | |||
| 82 | static LPCWSTR const k_Reg_Path32 = L"Path" | ||
| 83 | #ifdef _64BIT_INSTALLER | ||
| 84 | L"64" | ||
| 85 | #else | ||
| 86 | L"32" | ||
| 87 | #endif | ||
| 88 | ; | ||
| 89 | |||
| 90 | #if defined(_64BIT_INSTALLER) && !defined(_WIN64) | ||
| 91 | #define k_Reg_WOW_Flag KEY_WOW64_64KEY | ||
| 92 | #else | ||
| 93 | #define k_Reg_WOW_Flag 0 | ||
| 94 | #endif | ||
| 95 | |||
| 96 | #ifdef _WIN64 | ||
| 97 | #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY | ||
| 98 | #else | ||
| 99 | #define k_Reg_WOW_Flag_32 0 | ||
| 100 | #endif | ||
| 101 | |||
| 102 | #define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}" | ||
| 103 | |||
| 104 | static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID; | ||
| 105 | static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32"; | ||
| 106 | |||
| 107 | #define g_AllUsers True | ||
| 108 | |||
| 109 | static BoolInt g_Install_was_Pressed; | ||
| 110 | static BoolInt g_Finished; | ||
| 111 | static BoolInt g_SilentMode; | ||
| 112 | |||
| 113 | static HWND g_HWND; | ||
| 114 | static HWND g_Path_HWND; | ||
| 115 | static HWND g_InfoLine_HWND; | ||
| 116 | static HWND g_Progress_HWND; | ||
| 117 | |||
| 118 | static DWORD g_TotalSize; | ||
| 119 | |||
| 120 | static WCHAR cmd[MAX_PATH + 4]; | ||
| 121 | static WCHAR cmdError[MAX_PATH + 4]; | ||
| 122 | static WCHAR path[MAX_PATH * 2 + 40]; | ||
| 123 | |||
| 124 | |||
| 125 | // #define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c))) | ||
| 126 | |||
| 127 | |||
| 128 | static void CpyAscii(wchar_t *dest, const char *s) | ||
| 129 | { | ||
| 130 | for (;;) | ||
| 131 | { | ||
| 132 | Byte b = (Byte)*s++; | ||
| 133 | *dest++ = b; | ||
| 134 | if (b == 0) | ||
| 135 | return; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | static void CatAscii(wchar_t *dest, const char *s) | ||
| 140 | { | ||
| 141 | dest += wcslen(dest); | ||
| 142 | CpyAscii(dest, s); | ||
| 143 | } | ||
| 144 | |||
| 145 | static void PrintErrorMessage(const char *s1, const wchar_t *s2) | ||
| 146 | { | ||
| 147 | WCHAR m[MAX_PATH + 512]; | ||
| 148 | m[0] = 0; | ||
| 149 | CatAscii(m, "ERROR:"); | ||
| 150 | if (s1) | ||
| 151 | { | ||
| 152 | CatAscii(m, "\n"); | ||
| 153 | CatAscii(m, s1); | ||
| 154 | } | ||
| 155 | if (s2) | ||
| 156 | { | ||
| 157 | CatAscii(m, "\n"); | ||
| 158 | wcscat(m, s2); | ||
| 159 | } | ||
| 160 | MessageBoxW(g_HWND, m, k_7zip_with_Ver_str, MB_ICONERROR | MB_OK); | ||
| 161 | } | ||
| 162 | |||
| 163 | |||
| 164 | typedef DWORD (WINAPI * Func_GetFileVersionInfoSizeW)(LPCWSTR lptstrFilename, LPDWORD lpdwHandle); | ||
| 165 | typedef BOOL (WINAPI * Func_GetFileVersionInfoW)(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); | ||
| 166 | typedef BOOL (WINAPI * Func_VerQueryValueW)(const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen); | ||
| 167 | |||
| 168 | static HMODULE g_version_dll_hModule; | ||
| 169 | |||
| 170 | static DWORD GetFileVersion(LPCWSTR s) | ||
| 171 | { | ||
| 172 | DWORD size = 0; | ||
| 173 | void *vi = NULL; | ||
| 174 | DWORD version = 0; | ||
| 175 | |||
| 176 | Func_GetFileVersionInfoSizeW my_GetFileVersionInfoSizeW; | ||
| 177 | Func_GetFileVersionInfoW my_GetFileVersionInfoW; | ||
| 178 | Func_VerQueryValueW my_VerQueryValueW; | ||
| 179 | |||
| 180 | if (!g_version_dll_hModule) | ||
| 181 | { | ||
| 182 | wchar_t buf[MAX_PATH + 100]; | ||
| 183 | { | ||
| 184 | unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2); | ||
| 185 | if (len == 0 || len > MAX_PATH) | ||
| 186 | return 0; | ||
| 187 | } | ||
| 188 | { | ||
| 189 | unsigned pos = (unsigned)lstrlenW(buf); | ||
| 190 | if (buf[pos - 1] != '\\') | ||
| 191 | buf[pos++] = '\\'; | ||
| 192 | lstrcpyW(buf + pos, L"version.dll"); | ||
| 193 | } | ||
| 194 | g_version_dll_hModule = LoadLibraryW(buf); | ||
| 195 | if (!g_version_dll_hModule) | ||
| 196 | return 0; | ||
| 197 | } | ||
| 198 | |||
| 199 | my_GetFileVersionInfoSizeW = (Func_GetFileVersionInfoSizeW)GetProcAddress(g_version_dll_hModule, "GetFileVersionInfoSizeW"); | ||
| 200 | my_GetFileVersionInfoW = (Func_GetFileVersionInfoW)GetProcAddress(g_version_dll_hModule, "GetFileVersionInfoW"); | ||
| 201 | my_VerQueryValueW = (Func_VerQueryValueW)GetProcAddress(g_version_dll_hModule, "VerQueryValueW"); | ||
| 202 | |||
| 203 | if (!my_GetFileVersionInfoSizeW | ||
| 204 | || !my_GetFileVersionInfoW | ||
| 205 | || !my_VerQueryValueW) | ||
| 206 | return 0; | ||
| 207 | |||
| 208 | size = my_GetFileVersionInfoSizeW(s, NULL); | ||
| 209 | if (size == 0) | ||
| 210 | return 0; | ||
| 211 | |||
| 212 | vi = malloc(size); | ||
| 213 | if (!vi) | ||
| 214 | return 0; | ||
| 215 | |||
| 216 | if (my_GetFileVersionInfoW(s, 0, size, vi)) | ||
| 217 | { | ||
| 218 | VS_FIXEDFILEINFO *fi = NULL; | ||
| 219 | UINT fiLen = 0; | ||
| 220 | if (my_VerQueryValueW(vi, L"\\", (LPVOID *)&fi, &fiLen)) | ||
| 221 | version = fi->dwFileVersionMS; | ||
| 222 | } | ||
| 223 | |||
| 224 | free(vi); | ||
| 225 | return version; | ||
| 226 | } | ||
| 227 | |||
| 228 | |||
| 229 | static WRes MyCreateDir(LPCWSTR name) | ||
| 230 | { | ||
| 231 | return CreateDirectoryW(name, NULL) ? 0 : GetLastError(); | ||
| 232 | } | ||
| 233 | |||
| 234 | #define IS_SEPAR(c) (c == WCHAR_PATH_SEPARATOR) | ||
| 235 | #define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) | ||
| 236 | #define IS_DRIVE_PATH(s) (IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2])) | ||
| 237 | |||
| 238 | static int ReverseFind_PathSepar(const wchar_t *s) | ||
| 239 | { | ||
| 240 | int separ = -1; | ||
| 241 | int i; | ||
| 242 | for (i = 0;; i++) | ||
| 243 | { | ||
| 244 | wchar_t c = s[i]; | ||
| 245 | if (c == 0) | ||
| 246 | return separ; | ||
| 247 | if (IS_SEPAR(c)) | ||
| 248 | separ = i; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | static WRes CreateComplexDir() | ||
| 253 | { | ||
| 254 | WCHAR s[MAX_PATH + 10]; | ||
| 255 | |||
| 256 | unsigned prefixSize = 0; | ||
| 257 | WRes wres; | ||
| 258 | |||
| 259 | { | ||
| 260 | size_t len = wcslen(path); | ||
| 261 | if (len > MAX_PATH) | ||
| 262 | return ERROR_INVALID_NAME; | ||
| 263 | wcscpy(s, path); | ||
| 264 | } | ||
| 265 | |||
| 266 | if (IS_DRIVE_PATH(s)) | ||
| 267 | prefixSize = 3; | ||
| 268 | else if (IS_SEPAR(s[0]) && IS_SEPAR(s[1])) | ||
| 269 | prefixSize = 2; | ||
| 270 | else | ||
| 271 | return ERROR_INVALID_NAME; | ||
| 272 | |||
| 273 | { | ||
| 274 | DWORD attrib = GetFileAttributesW(s); | ||
| 275 | if (attrib != INVALID_FILE_ATTRIBUTES) | ||
| 276 | return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ? 0 : ERROR_ALREADY_EXISTS; | ||
| 277 | } | ||
| 278 | |||
| 279 | wres = MyCreateDir(s); | ||
| 280 | if (wres == 0 || wres == ERROR_ALREADY_EXISTS) | ||
| 281 | return 0; | ||
| 282 | |||
| 283 | { | ||
| 284 | size_t len = wcslen(s); | ||
| 285 | { | ||
| 286 | int pos = ReverseFind_PathSepar(s); | ||
| 287 | if (pos < 0) | ||
| 288 | return wres; | ||
| 289 | if ((unsigned)pos < prefixSize) | ||
| 290 | return wres; | ||
| 291 | if ((unsigned)pos == len - 1) | ||
| 292 | { | ||
| 293 | if (len == 1) | ||
| 294 | return 0; | ||
| 295 | s[pos] = 0; | ||
| 296 | len = pos; | ||
| 297 | } | ||
| 298 | } | ||
| 299 | |||
| 300 | for (;;) | ||
| 301 | { | ||
| 302 | int pos; | ||
| 303 | wres = MyCreateDir(s); | ||
| 304 | if (wres == 0) | ||
| 305 | break; | ||
| 306 | if (wres == ERROR_ALREADY_EXISTS) | ||
| 307 | { | ||
| 308 | DWORD attrib = GetFileAttributesW(s); | ||
| 309 | if (attrib != INVALID_FILE_ATTRIBUTES) | ||
| 310 | if ((attrib & FILE_ATTRIBUTE_DIRECTORY) == 0) | ||
| 311 | return ERROR_ALREADY_EXISTS; | ||
| 312 | break; | ||
| 313 | } | ||
| 314 | pos = ReverseFind_PathSepar(s); | ||
| 315 | if (pos < 0 || pos == 0 || (unsigned)pos < prefixSize) | ||
| 316 | return wres; | ||
| 317 | s[pos] = 0; | ||
| 318 | } | ||
| 319 | |||
| 320 | for (;;) | ||
| 321 | { | ||
| 322 | size_t pos = wcslen(s); | ||
| 323 | if (pos >= len) | ||
| 324 | return 0; | ||
| 325 | s[pos] = CHAR_PATH_SEPARATOR; | ||
| 326 | wres = MyCreateDir(s); | ||
| 327 | if (wres != 0) | ||
| 328 | return wres; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | |||
| 334 | static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest) | ||
| 335 | { | ||
| 336 | DWORD cnt = MAX_PATH * sizeof(name[0]); | ||
| 337 | DWORD type = 0; | ||
| 338 | LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, (DWORD *)&cnt); | ||
| 339 | if (type != REG_SZ) | ||
| 340 | return False; | ||
| 341 | return res == ERROR_SUCCESS; | ||
| 342 | } | ||
| 343 | |||
| 344 | static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) | ||
| 345 | { | ||
| 346 | HKEY key = 0; | ||
| 347 | LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key); | ||
| 348 | if (res != ERROR_SUCCESS) | ||
| 349 | return False; | ||
| 350 | { | ||
| 351 | BoolInt res2 = MyRegistry_QueryString(key, valName, dest); | ||
| 352 | RegCloseKey(key); | ||
| 353 | return res2; | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | static LONG MyRegistry_SetString(HKEY hKey, LPCWSTR name, LPCWSTR val) | ||
| 358 | { | ||
| 359 | return RegSetValueExW(hKey, name, 0, REG_SZ, | ||
| 360 | (const BYTE *)val, (DWORD)(wcslen(val) + 1) * sizeof(val[0])); | ||
| 361 | } | ||
| 362 | |||
| 363 | static LONG MyRegistry_SetDWORD(HKEY hKey, LPCWSTR name, DWORD val) | ||
| 364 | { | ||
| 365 | return RegSetValueExW(hKey, name, 0, REG_DWORD, (const BYTE *)&val, sizeof(DWORD)); | ||
| 366 | } | ||
| 367 | |||
| 368 | |||
| 369 | static LONG MyRegistry_CreateKey(HKEY parentKey, LPCWSTR name, HKEY *destKey) | ||
| 370 | { | ||
| 371 | return RegCreateKeyExW(parentKey, name, 0, NULL, | ||
| 372 | REG_OPTION_NON_VOLATILE, | ||
| 373 | KEY_ALL_ACCESS | k_Reg_WOW_Flag, | ||
| 374 | NULL, destKey, NULL); | ||
| 375 | } | ||
| 376 | |||
| 377 | static LONG MyRegistry_CreateKeyAndVal(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val) | ||
| 378 | { | ||
| 379 | HKEY destKey = 0; | ||
| 380 | LONG res = MyRegistry_CreateKey(parentKey, keyName, &destKey); | ||
| 381 | if (res == ERROR_SUCCESS) | ||
| 382 | { | ||
| 383 | res = MyRegistry_SetString(destKey, valName, val); | ||
| 384 | /* res = */ RegCloseKey(destKey); | ||
| 385 | } | ||
| 386 | return res; | ||
| 387 | } | ||
| 388 | |||
| 389 | |||
| 390 | #ifdef USE_7ZIP_32_DLL | ||
| 391 | |||
| 392 | static LONG MyRegistry_CreateKey_32(HKEY parentKey, LPCWSTR name, HKEY *destKey) | ||
| 393 | { | ||
| 394 | return RegCreateKeyExW(parentKey, name, 0, NULL, | ||
| 395 | REG_OPTION_NON_VOLATILE, | ||
| 396 | KEY_ALL_ACCESS | k_Reg_WOW_Flag_32, | ||
| 397 | NULL, destKey, NULL); | ||
| 398 | } | ||
| 399 | |||
| 400 | static LONG MyRegistry_CreateKeyAndVal_32(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val) | ||
| 401 | { | ||
| 402 | HKEY destKey = 0; | ||
| 403 | LONG res = MyRegistry_CreateKey_32(parentKey, keyName, &destKey); | ||
| 404 | if (res == ERROR_SUCCESS) | ||
| 405 | { | ||
| 406 | res = MyRegistry_SetString(destKey, valName, val); | ||
| 407 | /* res = */ RegCloseKey(destKey); | ||
| 408 | } | ||
| 409 | return res; | ||
| 410 | } | ||
| 411 | |||
| 412 | #endif | ||
| 413 | |||
| 414 | |||
| 415 | |||
| 416 | #ifdef UNDER_CE | ||
| 417 | #define kBufSize (1 << 13) | ||
| 418 | #else | ||
| 419 | #define kBufSize (1 << 15) | ||
| 420 | #endif | ||
| 421 | |||
| 422 | #define kSignatureSearchLimit (1 << 22) | ||
| 423 | |||
| 424 | static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos) | ||
| 425 | { | ||
| 426 | Byte buf[kBufSize]; | ||
| 427 | size_t numPrevBytes = 0; | ||
| 428 | *resPos = 0; | ||
| 429 | |||
| 430 | for (;;) | ||
| 431 | { | ||
| 432 | size_t processed, pos; | ||
| 433 | if (*resPos > kSignatureSearchLimit) | ||
| 434 | return False; | ||
| 435 | processed = kBufSize - numPrevBytes; | ||
| 436 | if (File_Read(stream, buf + numPrevBytes, &processed) != 0) | ||
| 437 | return False; | ||
| 438 | processed += numPrevBytes; | ||
| 439 | if (processed < k7zStartHeaderSize || | ||
| 440 | (processed == k7zStartHeaderSize && numPrevBytes != 0)) | ||
| 441 | return False; | ||
| 442 | processed -= k7zStartHeaderSize; | ||
| 443 | for (pos = 0; pos <= processed; pos++) | ||
| 444 | { | ||
| 445 | for (; pos <= processed && buf[pos] != '7'; pos++); | ||
| 446 | if (pos > processed) | ||
| 447 | break; | ||
| 448 | if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0) | ||
| 449 | if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8)) | ||
| 450 | { | ||
| 451 | *resPos += pos; | ||
| 452 | return True; | ||
| 453 | } | ||
| 454 | } | ||
| 455 | *resPos += processed; | ||
| 456 | numPrevBytes = k7zStartHeaderSize; | ||
| 457 | memmove(buf, buf + processed, k7zStartHeaderSize); | ||
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 461 | static void HexToString(UInt32 val, WCHAR *s) | ||
| 462 | { | ||
| 463 | UInt64 v = val; | ||
| 464 | unsigned i; | ||
| 465 | for (i = 1;; i++) | ||
| 466 | { | ||
| 467 | v >>= 4; | ||
| 468 | if (v == 0) | ||
| 469 | break; | ||
| 470 | } | ||
| 471 | s[i] = 0; | ||
| 472 | do | ||
| 473 | { | ||
| 474 | unsigned t = (unsigned)((val & 0xF)); | ||
| 475 | val >>= 4; | ||
| 476 | s[--i] = (WCHAR)(unsigned)((t < 10) ? ('0' + t) : ('A' + (t - 10))); | ||
| 477 | } | ||
| 478 | while (i); | ||
| 479 | } | ||
| 480 | |||
| 481 | |||
| 482 | #ifndef UNDER_CE | ||
| 483 | |||
| 484 | static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM data) | ||
| 485 | { | ||
| 486 | UNUSED_VAR(lp) | ||
| 487 | UNUSED_VAR(data) | ||
| 488 | UNUSED_VAR(hwnd) | ||
| 489 | |||
| 490 | switch (uMsg) | ||
| 491 | { | ||
| 492 | case BFFM_INITIALIZED: | ||
| 493 | { | ||
| 494 | SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, data); | ||
| 495 | break; | ||
| 496 | } | ||
| 497 | case BFFM_SELCHANGED: | ||
| 498 | { | ||
| 499 | // show selected path for BIF_STATUSTEXT | ||
| 500 | WCHAR dir[MAX_PATH]; | ||
| 501 | if (!SHGetPathFromIDListW((LPITEMIDLIST)lp, dir)) | ||
| 502 | dir[0] = 0; | ||
| 503 | SendMessage(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir); | ||
| 504 | break; | ||
| 505 | } | ||
| 506 | default: | ||
| 507 | break; | ||
| 508 | } | ||
| 509 | return 0; | ||
| 510 | } | ||
| 511 | |||
| 512 | static BoolInt MyBrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags, | ||
| 513 | LPCWSTR initialFolder, LPWSTR resultPath) | ||
| 514 | { | ||
| 515 | WCHAR displayName[MAX_PATH]; | ||
| 516 | BROWSEINFOW browseInfo; | ||
| 517 | |||
| 518 | displayName[0] = 0; | ||
| 519 | browseInfo.hwndOwner = owner; | ||
| 520 | browseInfo.pidlRoot = NULL; | ||
| 521 | |||
| 522 | // there are Unicode/Astring problems in some WinCE SDK ? | ||
| 523 | browseInfo.pszDisplayName = displayName; | ||
| 524 | browseInfo.lpszTitle = title; | ||
| 525 | browseInfo.ulFlags = ulFlags; | ||
| 526 | browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc : NULL; | ||
| 527 | browseInfo.lParam = (LPARAM)initialFolder; | ||
| 528 | { | ||
| 529 | LPITEMIDLIST idlist = SHBrowseForFolderW(&browseInfo); | ||
| 530 | if (idlist) | ||
| 531 | { | ||
| 532 | SHGetPathFromIDListW(idlist, resultPath); | ||
| 533 | // free idlist | ||
| 534 | // CoTaskMemFree(idlist); | ||
| 535 | return True; | ||
| 536 | } | ||
| 537 | return False; | ||
| 538 | } | ||
| 539 | } | ||
| 540 | |||
| 541 | #endif | ||
| 542 | |||
| 543 | static void NormalizePrefix(WCHAR *s) | ||
| 544 | { | ||
| 545 | size_t i = 0; | ||
| 546 | |||
| 547 | for (;; i++) | ||
| 548 | { | ||
| 549 | wchar_t c = s[i]; | ||
| 550 | if (c == 0) | ||
| 551 | break; | ||
| 552 | if (c == '/') | ||
| 553 | s[i] = WCHAR_PATH_SEPARATOR; | ||
| 554 | } | ||
| 555 | |||
| 556 | if (i != 0 && s[i - 1] != WCHAR_PATH_SEPARATOR) | ||
| 557 | { | ||
| 558 | s[i] = WCHAR_PATH_SEPARATOR; | ||
| 559 | s[i + 1] = 0; | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | static char MyCharLower_Ascii(char c) | ||
| 564 | { | ||
| 565 | if (c >= 'A' && c <= 'Z') | ||
| 566 | return (char)((unsigned char)c + 0x20); | ||
| 567 | return c; | ||
| 568 | } | ||
| 569 | |||
| 570 | static wchar_t MyWCharLower_Ascii(wchar_t c) | ||
| 571 | { | ||
| 572 | if (c >= 'A' && c <= 'Z') | ||
| 573 | return (wchar_t)(c + 0x20); | ||
| 574 | return c; | ||
| 575 | } | ||
| 576 | |||
| 577 | static LPCWSTR FindSubString(LPCWSTR s1, const char *s2) | ||
| 578 | { | ||
| 579 | for (;;) | ||
| 580 | { | ||
| 581 | unsigned i; | ||
| 582 | if (*s1 == 0) | ||
| 583 | return NULL; | ||
| 584 | for (i = 0;; i++) | ||
| 585 | { | ||
| 586 | Byte b = s2[i]; | ||
| 587 | if (b == 0) | ||
| 588 | return s1; | ||
| 589 | if (MyWCharLower_Ascii(s1[i]) != (Byte)MyCharLower_Ascii(b)) | ||
| 590 | { | ||
| 591 | s1++; | ||
| 592 | break; | ||
| 593 | } | ||
| 594 | } | ||
| 595 | } | ||
| 596 | } | ||
| 597 | |||
| 598 | static void Set7zipPostfix(WCHAR *s) | ||
| 599 | { | ||
| 600 | NormalizePrefix(s); | ||
| 601 | if (FindSubString(s, "7-Zip")) | ||
| 602 | return; | ||
| 603 | CatAscii(s, "7-Zip\\"); | ||
| 604 | } | ||
| 605 | |||
| 606 | |||
| 607 | static int Install(void); | ||
| 608 | |||
| 609 | static void OnClose() | ||
| 610 | { | ||
| 611 | if (g_Install_was_Pressed && !g_Finished) | ||
| 612 | { | ||
| 613 | if (MessageBoxW(g_HWND, | ||
| 614 | L"Do you want to cancel " k_7zip_with_Ver L" installation?", | ||
| 615 | k_7zip_with_Ver, | ||
| 616 | MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES) | ||
| 617 | return; | ||
| 618 | } | ||
| 619 | DestroyWindow(g_HWND); | ||
| 620 | g_HWND = NULL; | ||
| 621 | } | ||
| 622 | |||
| 623 | static INT_PTR CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | ||
| 624 | { | ||
| 625 | // UNUSED_VAR(hwnd) | ||
| 626 | UNUSED_VAR(lParam) | ||
| 627 | |||
| 628 | switch (message) | ||
| 629 | { | ||
| 630 | case WM_INITDIALOG: | ||
| 631 | g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH); | ||
| 632 | g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE); | ||
| 633 | g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS); | ||
| 634 | |||
| 635 | SetWindowTextW(hwnd, k_7zip_Setup); | ||
| 636 | SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path); | ||
| 637 | |||
| 638 | ShowWindow(g_Progress_HWND, SW_HIDE); | ||
| 639 | ShowWindow(g_InfoLine_HWND, SW_HIDE); | ||
| 640 | |||
| 641 | break; | ||
| 642 | |||
| 643 | case WM_COMMAND: | ||
| 644 | switch (LOWORD(wParam)) | ||
| 645 | { | ||
| 646 | case IDOK: | ||
| 647 | { | ||
| 648 | if (g_Finished) | ||
| 649 | { | ||
| 650 | OnClose(); | ||
| 651 | break; | ||
| 652 | } | ||
| 653 | if (!g_Install_was_Pressed) | ||
| 654 | { | ||
| 655 | SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE); | ||
| 656 | |||
| 657 | EnableWindow(g_Path_HWND, FALSE); | ||
| 658 | EnableWindow(GetDlgItem(hwnd, IDB_EXTRACT_SET_PATH), FALSE); | ||
| 659 | EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); | ||
| 660 | |||
| 661 | g_Install_was_Pressed = True; | ||
| 662 | return TRUE; | ||
| 663 | } | ||
| 664 | break; | ||
| 665 | } | ||
| 666 | |||
| 667 | case IDCANCEL: | ||
| 668 | { | ||
| 669 | OnClose(); | ||
| 670 | break; | ||
| 671 | } | ||
| 672 | |||
| 673 | case IDB_EXTRACT_SET_PATH: | ||
| 674 | { | ||
| 675 | #ifndef UNDER_CE | ||
| 676 | |||
| 677 | WCHAR s[MAX_PATH]; | ||
| 678 | WCHAR s2[MAX_PATH]; | ||
| 679 | GetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s, MAX_PATH); | ||
| 680 | if (MyBrowseForFolder(hwnd, L"Select the folder for installation:" , | ||
| 681 | 0 | ||
| 682 | | BIF_NEWDIALOGSTYLE // 5.0 of ?.dll ? | ||
| 683 | | BIF_RETURNONLYFSDIRS | ||
| 684 | // | BIF_STATUSTEXT // doesn't work for BIF_NEWDIALOGSTYLE | ||
| 685 | , s, s2)) | ||
| 686 | { | ||
| 687 | Set7zipPostfix(s2); | ||
| 688 | SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s2); | ||
| 689 | } | ||
| 690 | |||
| 691 | #endif | ||
| 692 | break; | ||
| 693 | } | ||
| 694 | |||
| 695 | default: return FALSE; | ||
| 696 | } | ||
| 697 | break; | ||
| 698 | |||
| 699 | case WM_CLOSE: | ||
| 700 | OnClose(); | ||
| 701 | break; | ||
| 702 | /* | ||
| 703 | case WM_DESTROY: | ||
| 704 | PostQuitMessage(0); | ||
| 705 | return TRUE; | ||
| 706 | */ | ||
| 707 | default: | ||
| 708 | return FALSE; | ||
| 709 | } | ||
| 710 | |||
| 711 | return TRUE; | ||
| 712 | } | ||
| 713 | |||
| 714 | |||
| 715 | |||
| 716 | static LONG SetRegKey_Path2(HKEY parentKey) | ||
| 717 | { | ||
| 718 | HKEY destKey = 0; | ||
| 719 | LONG res = MyRegistry_CreateKey(parentKey, k_Reg_Software_7zip, &destKey); | ||
| 720 | if (res == ERROR_SUCCESS) | ||
| 721 | { | ||
| 722 | res = MyRegistry_SetString(destKey, k_Reg_Path32, path); | ||
| 723 | /* res = */ MyRegistry_SetString(destKey, k_Reg_Path, path); | ||
| 724 | /* res = */ RegCloseKey(destKey); | ||
| 725 | } | ||
| 726 | return res; | ||
| 727 | } | ||
| 728 | |||
| 729 | static void SetRegKey_Path() | ||
| 730 | { | ||
| 731 | SetRegKey_Path2(HKEY_CURRENT_USER); | ||
| 732 | SetRegKey_Path2(HKEY_LOCAL_MACHINE); | ||
| 733 | } | ||
| 734 | |||
| 735 | |||
| 736 | static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath) | ||
| 737 | { | ||
| 738 | IShellLinkW* sl; | ||
| 739 | |||
| 740 | // CoInitialize has already been called. | ||
| 741 | HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl); | ||
| 742 | |||
| 743 | if (SUCCEEDED(hres)) | ||
| 744 | { | ||
| 745 | IPersistFile* pf; | ||
| 746 | |||
| 747 | sl->lpVtbl->SetPath(sl, targetPath); | ||
| 748 | // sl->lpVtbl->SetDescription(sl, description); | ||
| 749 | hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf); | ||
| 750 | |||
| 751 | if (SUCCEEDED(hres)) | ||
| 752 | { | ||
| 753 | hres = pf->lpVtbl->Save(pf, srcPath, TRUE); | ||
| 754 | pf->lpVtbl->Release(pf); | ||
| 755 | } | ||
| 756 | sl->lpVtbl->Release(sl); | ||
| 757 | } | ||
| 758 | |||
| 759 | return hres; | ||
| 760 | } | ||
| 761 | |||
| 762 | static void SetShellProgramsGroup(HWND hwndOwner) | ||
| 763 | { | ||
| 764 | #ifdef UNDER_CE | ||
| 765 | |||
| 766 | // CpyAscii(link, "\\Program Files\\"); | ||
| 767 | UNUSED_VAR(hwndOwner) | ||
| 768 | |||
| 769 | #else | ||
| 770 | |||
| 771 | unsigned i = (g_AllUsers ? 0 : 2); | ||
| 772 | |||
| 773 | for (; i < 3; i++) | ||
| 774 | { | ||
| 775 | BoolInt isOK = True; | ||
| 776 | WCHAR link[MAX_PATH + 40]; | ||
| 777 | WCHAR destPath[MAX_PATH + 40]; | ||
| 778 | |||
| 779 | link[0] = 0; | ||
| 780 | |||
| 781 | if (SHGetFolderPathW(hwndOwner, | ||
| 782 | i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS, | ||
| 783 | NULL, SHGFP_TYPE_CURRENT, link) != S_OK) | ||
| 784 | continue; | ||
| 785 | |||
| 786 | NormalizePrefix(link); | ||
| 787 | CatAscii(link, k_7zip); | ||
| 788 | // CatAscii(link, "2"); | ||
| 789 | |||
| 790 | if (i != 0) | ||
| 791 | MyCreateDir(link); | ||
| 792 | |||
| 793 | NormalizePrefix(link); | ||
| 794 | |||
| 795 | { | ||
| 796 | unsigned baseLen = (unsigned)wcslen(link); | ||
| 797 | unsigned k; | ||
| 798 | |||
| 799 | for (k = 0; k < 2; k++) | ||
| 800 | { | ||
| 801 | CpyAscii(link + baseLen, k == 0 ? | ||
| 802 | "7-Zip File Manager.lnk" : | ||
| 803 | "7-Zip Help.lnk" | ||
| 804 | ); | ||
| 805 | wcscpy(destPath, path); | ||
| 806 | CatAscii(destPath, k == 0 ? | ||
| 807 | "7zFM.exe" : | ||
| 808 | "7-zip.chm"); | ||
| 809 | |||
| 810 | if (i == 0) | ||
| 811 | DeleteFileW(link); | ||
| 812 | else if (CreateShellLink(link, destPath) != S_OK) | ||
| 813 | isOK = False; | ||
| 814 | } | ||
| 815 | } | ||
| 816 | |||
| 817 | if (i != 0 && isOK) | ||
| 818 | break; | ||
| 819 | } | ||
| 820 | |||
| 821 | #endif | ||
| 822 | } | ||
| 823 | |||
| 824 | static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; | ||
| 825 | static LPCWSTR const k_7zip_ShellExtension = L"7-Zip Shell Extension"; | ||
| 826 | |||
| 827 | static void WriteCLSID() | ||
| 828 | { | ||
| 829 | HKEY destKey; | ||
| 830 | LONG res; | ||
| 831 | |||
| 832 | #ifdef USE_7ZIP_32_DLL | ||
| 833 | |||
| 834 | MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension); | ||
| 835 | |||
| 836 | res = MyRegistry_CreateKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey); | ||
| 837 | |||
| 838 | if (res == ERROR_SUCCESS) | ||
| 839 | { | ||
| 840 | WCHAR destPath[MAX_PATH + 40]; | ||
| 841 | wcscpy(destPath, path); | ||
| 842 | CatAscii(destPath, "7-zip32.dll"); | ||
| 843 | /* res = */ MyRegistry_SetString(destKey, NULL, destPath); | ||
| 844 | /* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment"); | ||
| 845 | // DeleteRegValue(destKey, L"InprocServer32"); | ||
| 846 | /* res = */ RegCloseKey(destKey); | ||
| 847 | } | ||
| 848 | |||
| 849 | #endif | ||
| 850 | |||
| 851 | |||
| 852 | MyRegistry_CreateKeyAndVal(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension); | ||
| 853 | |||
| 854 | destKey = 0; | ||
| 855 | res = MyRegistry_CreateKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey); | ||
| 856 | |||
| 857 | if (res == ERROR_SUCCESS) | ||
| 858 | { | ||
| 859 | WCHAR destPath[MAX_PATH + 40]; | ||
| 860 | wcscpy(destPath, path); | ||
| 861 | CatAscii(destPath, "7-zip.dll"); | ||
| 862 | /* res = */ MyRegistry_SetString(destKey, NULL, destPath); | ||
| 863 | /* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment"); | ||
| 864 | // DeleteRegValue(destKey, L"InprocServer32"); | ||
| 865 | /* res = */ RegCloseKey(destKey); | ||
| 866 | } | ||
| 867 | } | ||
| 868 | |||
| 869 | static LPCSTR const k_ShellEx_Items[] = | ||
| 870 | { | ||
| 871 | "*\\shellex\\ContextMenuHandlers" | ||
| 872 | , "Directory\\shellex\\ContextMenuHandlers" | ||
| 873 | , "Folder\\shellex\\ContextMenuHandlers" | ||
| 874 | , "Directory\\shellex\\DragDropHandlers" | ||
| 875 | , "Drive\\shellex\\DragDropHandlers" | ||
| 876 | }; | ||
| 877 | |||
| 878 | static void WriteShellEx() | ||
| 879 | { | ||
| 880 | unsigned i; | ||
| 881 | WCHAR destPath[MAX_PATH + 40]; | ||
| 882 | |||
| 883 | for (i = 0; i < ARRAY_SIZE(k_ShellEx_Items); i++) | ||
| 884 | { | ||
| 885 | CpyAscii(destPath, k_ShellEx_Items[i]); | ||
| 886 | CatAscii(destPath, "\\7-Zip"); | ||
| 887 | |||
| 888 | #ifdef USE_7ZIP_32_DLL | ||
| 889 | MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID); | ||
| 890 | #endif | ||
| 891 | MyRegistry_CreateKeyAndVal (HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID); | ||
| 892 | } | ||
| 893 | |||
| 894 | #ifdef USE_7ZIP_32_DLL | ||
| 895 | MyRegistry_CreateKeyAndVal_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension); | ||
| 896 | #endif | ||
| 897 | MyRegistry_CreateKeyAndVal (HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension); | ||
| 898 | |||
| 899 | |||
| 900 | wcscpy(destPath, path); | ||
| 901 | CatAscii(destPath, "7zFM.exe"); | ||
| 902 | |||
| 903 | { | ||
| 904 | HKEY destKey = 0; | ||
| 905 | LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe", &destKey); | ||
| 906 | if (res == ERROR_SUCCESS) | ||
| 907 | { | ||
| 908 | MyRegistry_SetString(destKey, NULL, destPath); | ||
| 909 | MyRegistry_SetString(destKey, L"Path", path); | ||
| 910 | RegCloseKey(destKey); | ||
| 911 | } | ||
| 912 | |||
| 913 | } | ||
| 914 | |||
| 915 | { | ||
| 916 | HKEY destKey = 0; | ||
| 917 | LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\7-Zip", &destKey); | ||
| 918 | if (res == ERROR_SUCCESS) | ||
| 919 | { | ||
| 920 | MyRegistry_SetString(destKey, L"DisplayName", k_7zip_with_Ver_str); | ||
| 921 | MyRegistry_SetString(destKey, L"DisplayVersion", LLL(MY_VERSION_NUMBERS)); | ||
| 922 | MyRegistry_SetString(destKey, L"DisplayIcon", destPath); | ||
| 923 | MyRegistry_SetString(destKey, L"InstallLocation", path); | ||
| 924 | |||
| 925 | destPath[0] = '\"'; | ||
| 926 | wcscpy(destPath + 1, path); | ||
| 927 | CatAscii(destPath, "Uninstall.exe\""); | ||
| 928 | MyRegistry_SetString(destKey, L"UninstallString", destPath); | ||
| 929 | |||
| 930 | CatAscii(destPath, " /S"); | ||
| 931 | MyRegistry_SetString(destKey, L"QuietUninstallString", destPath); | ||
| 932 | |||
| 933 | MyRegistry_SetDWORD(destKey, L"NoModify", 1); | ||
| 934 | MyRegistry_SetDWORD(destKey, L"NoRepair", 1); | ||
| 935 | |||
| 936 | MyRegistry_SetDWORD(destKey, L"EstimatedSize", g_TotalSize >> 10); | ||
| 937 | |||
| 938 | MyRegistry_SetDWORD(destKey, L"VersionMajor", MY_VER_MAJOR); | ||
| 939 | MyRegistry_SetDWORD(destKey, L"VersionMinor", MY_VER_MINOR); | ||
| 940 | |||
| 941 | MyRegistry_SetString(destKey, L"Publisher", LLL(MY_AUTHOR_NAME)); | ||
| 942 | |||
| 943 | // MyRegistry_SetString(destKey, L"HelpLink", L"http://www.7-zip.org/support.html"); | ||
| 944 | // MyRegistry_SetString(destKey, L"URLInfoAbout", L"http://www.7-zip.org/"); | ||
| 945 | // MyRegistry_SetString(destKey, L"URLUpdateInfo", L"http://www.7-zip.org/"); | ||
| 946 | |||
| 947 | RegCloseKey(destKey); | ||
| 948 | } | ||
| 949 | } | ||
| 950 | } | ||
| 951 | |||
| 952 | |||
| 953 | static const wchar_t *GetCmdParam(const wchar_t *s) | ||
| 954 | { | ||
| 955 | unsigned pos = 0; | ||
| 956 | BoolInt quoteMode = False; | ||
| 957 | for (;; s++) | ||
| 958 | { | ||
| 959 | wchar_t c = *s; | ||
| 960 | if (c == 0 || (c == L' ' && !quoteMode)) | ||
| 961 | break; | ||
| 962 | if (c == L'\"') | ||
| 963 | { | ||
| 964 | quoteMode = !quoteMode; | ||
| 965 | continue; | ||
| 966 | } | ||
| 967 | if (pos >= ARRAY_SIZE(cmd) - 1) | ||
| 968 | exit(1); | ||
| 969 | cmd[pos++] = c; | ||
| 970 | } | ||
| 971 | cmd[pos] = 0; | ||
| 972 | return s; | ||
| 973 | } | ||
| 974 | |||
| 975 | |||
| 976 | static void RemoveQuotes(wchar_t *s) | ||
| 977 | { | ||
| 978 | const wchar_t *src = s; | ||
| 979 | for (;;) | ||
| 980 | { | ||
| 981 | wchar_t c = *src++; | ||
| 982 | if (c == '\"') | ||
| 983 | continue; | ||
| 984 | *s++ = c; | ||
| 985 | if (c == 0) | ||
| 986 | return; | ||
| 987 | } | ||
| 988 | } | ||
| 989 | |||
| 990 | // #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ') | ||
| 991 | |||
| 992 | |||
| 993 | typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL); | ||
| 994 | |||
| 995 | int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, | ||
| 996 | #ifdef UNDER_CE | ||
| 997 | LPWSTR | ||
| 998 | #else | ||
| 999 | LPSTR | ||
| 1000 | #endif | ||
| 1001 | lpCmdLine, int nCmdShow) | ||
| 1002 | { | ||
| 1003 | |||
| 1004 | UNUSED_VAR(hPrevInstance) | ||
| 1005 | UNUSED_VAR(lpCmdLine) | ||
| 1006 | UNUSED_VAR(nCmdShow) | ||
| 1007 | |||
| 1008 | #ifndef UNDER_CE | ||
| 1009 | LoadSecurityDlls(); | ||
| 1010 | CoInitialize(NULL); | ||
| 1011 | #endif | ||
| 1012 | |||
| 1013 | CrcGenerateTable(); | ||
| 1014 | |||
| 1015 | { | ||
| 1016 | const wchar_t *s = GetCommandLineW(); | ||
| 1017 | |||
| 1018 | #ifndef UNDER_CE | ||
| 1019 | s = GetCmdParam(s); | ||
| 1020 | #endif | ||
| 1021 | |||
| 1022 | for (;;) | ||
| 1023 | { | ||
| 1024 | { | ||
| 1025 | wchar_t c = *s; | ||
| 1026 | if (c == 0) | ||
| 1027 | break; | ||
| 1028 | if (c == ' ') | ||
| 1029 | { | ||
| 1030 | s++; | ||
| 1031 | continue; | ||
| 1032 | } | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | { | ||
| 1036 | const wchar_t *s2 = GetCmdParam(s); | ||
| 1037 | BoolInt error = True; | ||
| 1038 | if (cmd[0] == '/') | ||
| 1039 | { | ||
| 1040 | if (cmd[1] == 'S') | ||
| 1041 | { | ||
| 1042 | if (cmd[2] == 0) | ||
| 1043 | { | ||
| 1044 | g_SilentMode = True; | ||
| 1045 | error = False; | ||
| 1046 | } | ||
| 1047 | } | ||
| 1048 | else if (cmd[1] == 'D' && cmd[2] == '=') | ||
| 1049 | { | ||
| 1050 | wcscpy(path, cmd + 3); | ||
| 1051 | // RemoveQuotes(path); | ||
| 1052 | error = False; | ||
| 1053 | } | ||
| 1054 | } | ||
| 1055 | s = s2; | ||
| 1056 | if (error && cmdError[0] == 0) | ||
| 1057 | wcscpy(cmdError, cmd); | ||
| 1058 | } | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | if (cmdError[0] != 0) | ||
| 1062 | { | ||
| 1063 | if (!g_SilentMode) | ||
| 1064 | PrintErrorMessage("Unsupported command:", cmdError); | ||
| 1065 | return 1; | ||
| 1066 | } | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | #if defined(_64BIT_INSTALLER) && !defined(_WIN64) | ||
| 1070 | { | ||
| 1071 | BOOL isWow64 = FALSE; | ||
| 1072 | Func_IsWow64Process func_IsWow64Process = (Func_IsWow64Process) | ||
| 1073 | GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "IsWow64Process"); | ||
| 1074 | |||
| 1075 | if (func_IsWow64Process) | ||
| 1076 | func_IsWow64Process(GetCurrentProcess(), &isWow64); | ||
| 1077 | |||
| 1078 | if (!isWow64) | ||
| 1079 | { | ||
| 1080 | if (!g_SilentMode) | ||
| 1081 | PrintErrorMessage("This installation requires Windows " MY_CPU_NAME, NULL); | ||
| 1082 | return 1; | ||
| 1083 | } | ||
| 1084 | } | ||
| 1085 | #endif | ||
| 1086 | |||
| 1087 | |||
| 1088 | if (path[0] == 0) | ||
| 1089 | { | ||
| 1090 | HKEY key = 0; | ||
| 1091 | BoolInt ok = False; | ||
| 1092 | LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key); | ||
| 1093 | if (res == ERROR_SUCCESS) | ||
| 1094 | { | ||
| 1095 | ok = MyRegistry_QueryString(key, k_Reg_Path32, path); | ||
| 1096 | // ok = MyRegistry_QueryString(key, k_Reg_Path, path); | ||
| 1097 | RegCloseKey(key); | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | // ok = False; | ||
| 1101 | if (!ok) | ||
| 1102 | { | ||
| 1103 | /* | ||
| 1104 | #ifdef UNDER_CE | ||
| 1105 | CpyAscii(path, "\\Program Files\\"); | ||
| 1106 | #else | ||
| 1107 | |||
| 1108 | #ifdef _64BIT_INSTALLER | ||
| 1109 | { | ||
| 1110 | DWORD ttt = GetEnvironmentVariableW(L"ProgramW6432", path, MAX_PATH); | ||
| 1111 | if (ttt == 0 || ttt > MAX_PATH) | ||
| 1112 | CpyAscii(path, "C:\\"); | ||
| 1113 | } | ||
| 1114 | #else | ||
| 1115 | if (!SHGetSpecialFolderPathW(0, path, CSIDL_PROGRAM_FILES, FALSE)) | ||
| 1116 | CpyAscii(path, "C:\\"); | ||
| 1117 | #endif | ||
| 1118 | #endif | ||
| 1119 | */ | ||
| 1120 | if (!MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", L"ProgramFilesDir", path)) | ||
| 1121 | CpyAscii(path, | ||
| 1122 | #ifdef UNDER_CE | ||
| 1123 | "\\Program Files\\" | ||
| 1124 | #else | ||
| 1125 | "C:\\" | ||
| 1126 | #endif | ||
| 1127 | ); | ||
| 1128 | |||
| 1129 | Set7zipPostfix(path); | ||
| 1130 | } | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | NormalizePrefix(path); | ||
| 1134 | |||
| 1135 | if (g_SilentMode) | ||
| 1136 | return Install(); | ||
| 1137 | |||
| 1138 | { | ||
| 1139 | int retCode = 1; | ||
| 1140 | // INT_PTR res = DialogBox( | ||
| 1141 | g_HWND = CreateDialog( | ||
| 1142 | hInstance, | ||
| 1143 | // GetModuleHandle(NULL), | ||
| 1144 | MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc); | ||
| 1145 | if (!g_HWND) | ||
| 1146 | return 1; | ||
| 1147 | |||
| 1148 | { | ||
| 1149 | HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); | ||
| 1150 | // SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon); | ||
| 1151 | SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon); | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | |||
| 1155 | { | ||
| 1156 | BOOL bRet; | ||
| 1157 | MSG msg; | ||
| 1158 | |||
| 1159 | // we need messages for all thread windows (including EDITTEXT window in dialog) | ||
| 1160 | while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) | ||
| 1161 | { | ||
| 1162 | if (bRet == -1) | ||
| 1163 | return retCode; | ||
| 1164 | if (!g_HWND) | ||
| 1165 | return retCode; | ||
| 1166 | |||
| 1167 | if (!IsDialogMessage(g_HWND, &msg)) | ||
| 1168 | { | ||
| 1169 | TranslateMessage(&msg); | ||
| 1170 | DispatchMessage(&msg); | ||
| 1171 | } | ||
| 1172 | if (!g_HWND) | ||
| 1173 | return retCode; | ||
| 1174 | |||
| 1175 | if (g_Install_was_Pressed && !g_Finished) | ||
| 1176 | { | ||
| 1177 | retCode = Install(); | ||
| 1178 | g_Finished = True; | ||
| 1179 | if (retCode != 0) | ||
| 1180 | break; | ||
| 1181 | if (!g_HWND) | ||
| 1182 | break; | ||
| 1183 | { | ||
| 1184 | SetDlgItemTextW(g_HWND, IDOK, L"Close"); | ||
| 1185 | EnableWindow(GetDlgItem(g_HWND, IDOK), TRUE); | ||
| 1186 | EnableWindow(GetDlgItem(g_HWND, IDCANCEL), FALSE); | ||
| 1187 | SendMessage(g_HWND, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(g_HWND, IDOK), TRUE); | ||
| 1188 | } | ||
| 1189 | } | ||
| 1190 | } | ||
| 1191 | |||
| 1192 | if (g_HWND) | ||
| 1193 | { | ||
| 1194 | DestroyWindow(g_HWND); | ||
| 1195 | g_HWND = NULL; | ||
| 1196 | } | ||
| 1197 | } | ||
| 1198 | |||
| 1199 | return retCode; | ||
| 1200 | } | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | |||
| 1204 | static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message) | ||
| 1205 | { | ||
| 1206 | LPWSTR msgBuf; | ||
| 1207 | if (FormatMessageW( | ||
| 1208 | FORMAT_MESSAGE_ALLOCATE_BUFFER | ||
| 1209 | | FORMAT_MESSAGE_FROM_SYSTEM | ||
| 1210 | | FORMAT_MESSAGE_IGNORE_INSERTS, | ||
| 1211 | NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0) | ||
| 1212 | return False; | ||
| 1213 | wcscpy(message, msgBuf); | ||
| 1214 | LocalFree(msgBuf); | ||
| 1215 | return True; | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | |||
| 1219 | |||
| 1220 | static int Install(void) | ||
| 1221 | { | ||
| 1222 | CFileInStream archiveStream; | ||
| 1223 | CLookToRead2 lookStream; | ||
| 1224 | CSzArEx db; | ||
| 1225 | |||
| 1226 | SRes res = SZ_OK; | ||
| 1227 | WRes winRes = 0; | ||
| 1228 | const char *errorMessage = NULL; | ||
| 1229 | |||
| 1230 | ISzAlloc allocImp; | ||
| 1231 | ISzAlloc allocTempImp; | ||
| 1232 | WCHAR sfxPath[MAX_PATH + 2]; | ||
| 1233 | |||
| 1234 | int needRebootLevel = 0; | ||
| 1235 | |||
| 1236 | allocImp.Alloc = SzAlloc; | ||
| 1237 | allocImp.Free = SzFree; | ||
| 1238 | |||
| 1239 | allocTempImp.Alloc = SzAllocTemp; | ||
| 1240 | allocTempImp.Free = SzFreeTemp; | ||
| 1241 | |||
| 1242 | { | ||
| 1243 | DWORD len = GetModuleFileNameW(NULL, sfxPath, MAX_PATH); | ||
| 1244 | if (len == 0 || len > MAX_PATH) | ||
| 1245 | return 1; | ||
| 1246 | } | ||
| 1247 | |||
| 1248 | winRes = InFile_OpenW(&archiveStream.file, sfxPath); | ||
| 1249 | |||
| 1250 | if (winRes == 0) | ||
| 1251 | { | ||
| 1252 | UInt64 pos = 0; | ||
| 1253 | if (!FindSignature(&archiveStream.file, &pos)) | ||
| 1254 | errorMessage = "Can't find 7z archive"; | ||
| 1255 | else | ||
| 1256 | winRes = File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET); | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | if (winRes != 0) | ||
| 1260 | res = SZ_ERROR_FAIL; | ||
| 1261 | |||
| 1262 | if (errorMessage) | ||
| 1263 | res = SZ_ERROR_FAIL; | ||
| 1264 | |||
| 1265 | if (res == SZ_OK) | ||
| 1266 | { | ||
| 1267 | size_t pathLen; | ||
| 1268 | if (!g_SilentMode) | ||
| 1269 | { | ||
| 1270 | GetDlgItemTextW(g_HWND, IDE_EXTRACT_PATH, path, MAX_PATH); | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | FileInStream_CreateVTable(&archiveStream); | ||
| 1274 | LookToRead2_CreateVTable(&lookStream, False); | ||
| 1275 | lookStream.buf = NULL; | ||
| 1276 | |||
| 1277 | RemoveQuotes(path); | ||
| 1278 | { | ||
| 1279 | // Remove post spaces | ||
| 1280 | unsigned endPos = 0; | ||
| 1281 | unsigned i = 0; | ||
| 1282 | |||
| 1283 | for (;;) | ||
| 1284 | { | ||
| 1285 | wchar_t c = path[i++]; | ||
| 1286 | if (c == 0) | ||
| 1287 | break; | ||
| 1288 | if (c != ' ') | ||
| 1289 | endPos = i; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | path[endPos] = 0; | ||
| 1293 | if (path[0] == 0) | ||
| 1294 | { | ||
| 1295 | PrintErrorMessage("Incorrect path", NULL); | ||
| 1296 | return 1; | ||
| 1297 | } | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | NormalizePrefix(path); | ||
| 1301 | winRes = CreateComplexDir(); | ||
| 1302 | |||
| 1303 | if (winRes != 0) | ||
| 1304 | res = SZ_ERROR_FAIL; | ||
| 1305 | |||
| 1306 | pathLen = wcslen(path); | ||
| 1307 | |||
| 1308 | if (res == SZ_OK) | ||
| 1309 | { | ||
| 1310 | lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize); | ||
| 1311 | if (!lookStream.buf) | ||
| 1312 | res = SZ_ERROR_MEM; | ||
| 1313 | else | ||
| 1314 | { | ||
| 1315 | lookStream.bufSize = kInputBufSize; | ||
| 1316 | lookStream.realStream = &archiveStream.vt; | ||
| 1317 | LookToRead2_Init(&lookStream); | ||
| 1318 | } | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | SzArEx_Init(&db); | ||
| 1322 | |||
| 1323 | if (res == SZ_OK) | ||
| 1324 | { | ||
| 1325 | res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp); | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | if (res == SZ_OK) | ||
| 1329 | { | ||
| 1330 | UInt32 i; | ||
| 1331 | UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call, if (!outBuf) */ | ||
| 1332 | Byte *outBuf = NULL; /* it must be NULL before first call for each new archive. */ | ||
| 1333 | size_t outBufSize = 0; /* it can have any value before first call, if (!outBuf) */ | ||
| 1334 | |||
| 1335 | g_TotalSize = 0; | ||
| 1336 | |||
| 1337 | if (!g_SilentMode) | ||
| 1338 | { | ||
| 1339 | ShowWindow(g_Progress_HWND, SW_SHOW); | ||
| 1340 | ShowWindow(g_InfoLine_HWND, SW_SHOW); | ||
| 1341 | SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, db.NumFiles); | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | for (i = 0; i < db.NumFiles; i++) | ||
| 1345 | { | ||
| 1346 | size_t offset = 0; | ||
| 1347 | size_t outSizeProcessed = 0; | ||
| 1348 | WCHAR *temp; | ||
| 1349 | |||
| 1350 | if (!g_SilentMode) | ||
| 1351 | { | ||
| 1352 | MSG msg; | ||
| 1353 | |||
| 1354 | // g_HWND | ||
| 1355 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) | ||
| 1356 | { | ||
| 1357 | if (!IsDialogMessage(g_HWND, &msg)) | ||
| 1358 | { | ||
| 1359 | TranslateMessage(&msg); | ||
| 1360 | DispatchMessage(&msg); | ||
| 1361 | } | ||
| 1362 | if (!g_HWND) | ||
| 1363 | return 1; | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | // Sleep(10); | ||
| 1367 | SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); | ||
| 1368 | } | ||
| 1369 | |||
| 1370 | { | ||
| 1371 | size_t len = SzArEx_GetFileNameUtf16(&db, i, NULL); | ||
| 1372 | if (len >= MAX_PATH) | ||
| 1373 | { | ||
| 1374 | res = SZ_ERROR_FAIL; | ||
| 1375 | break; | ||
| 1376 | } | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | temp = path + pathLen; | ||
| 1380 | |||
| 1381 | SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp); | ||
| 1382 | |||
| 1383 | if (!g_SilentMode) | ||
| 1384 | SetWindowTextW(g_InfoLine_HWND, temp); | ||
| 1385 | |||
| 1386 | { | ||
| 1387 | res = SzArEx_Extract(&db, &lookStream.vt, i, | ||
| 1388 | &blockIndex, &outBuf, &outBufSize, | ||
| 1389 | &offset, &outSizeProcessed, | ||
| 1390 | &allocImp, &allocTempImp); | ||
| 1391 | if (res != SZ_OK) | ||
| 1392 | break; | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | { | ||
| 1396 | CSzFile outFile; | ||
| 1397 | size_t processedSize; | ||
| 1398 | size_t j; | ||
| 1399 | // size_t nameStartPos = 0; | ||
| 1400 | UInt32 tempIndex = 0; | ||
| 1401 | int fileLevel = 1 << 2; | ||
| 1402 | WCHAR origPath[MAX_PATH * 2 + 10]; | ||
| 1403 | |||
| 1404 | for (j = 0; temp[j] != 0; j++) | ||
| 1405 | { | ||
| 1406 | if (temp[j] == '/') | ||
| 1407 | { | ||
| 1408 | temp[j] = 0; | ||
| 1409 | MyCreateDir(path); | ||
| 1410 | temp[j] = CHAR_PATH_SEPARATOR; | ||
| 1411 | // nameStartPos = j + 1; | ||
| 1412 | } | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | if (SzArEx_IsDir(&db, i)) | ||
| 1416 | { | ||
| 1417 | MyCreateDir(path); | ||
| 1418 | continue; | ||
| 1419 | } | ||
| 1420 | |||
| 1421 | { | ||
| 1422 | // BoolInt skipFile = False; | ||
| 1423 | |||
| 1424 | wcscpy(origPath, path); | ||
| 1425 | |||
| 1426 | for (;;) | ||
| 1427 | { | ||
| 1428 | WRes openRes; | ||
| 1429 | |||
| 1430 | if (tempIndex != 0) | ||
| 1431 | { | ||
| 1432 | if (tempIndex > 100) | ||
| 1433 | { | ||
| 1434 | res = SZ_ERROR_FAIL; | ||
| 1435 | break; | ||
| 1436 | } | ||
| 1437 | wcscpy(path, origPath); | ||
| 1438 | CatAscii(path, ".tmp"); | ||
| 1439 | if (tempIndex > 1) | ||
| 1440 | HexToString(tempIndex, path + wcslen(path)); | ||
| 1441 | if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES) | ||
| 1442 | { | ||
| 1443 | tempIndex++; | ||
| 1444 | continue; | ||
| 1445 | } | ||
| 1446 | } | ||
| 1447 | |||
| 1448 | { | ||
| 1449 | SetFileAttributesW(path, 0); | ||
| 1450 | openRes = OutFile_OpenW(&outFile, path); | ||
| 1451 | if (openRes == 0) | ||
| 1452 | break; | ||
| 1453 | } | ||
| 1454 | |||
| 1455 | if (tempIndex != 0) | ||
| 1456 | { | ||
| 1457 | tempIndex++; | ||
| 1458 | continue; | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | if (FindSubString(temp, "7-zip.dll") | ||
| 1462 | #ifdef USE_7ZIP_32_DLL | ||
| 1463 | || FindSubString(temp, "7-zip32.dll") | ||
| 1464 | #endif | ||
| 1465 | ) | ||
| 1466 | { | ||
| 1467 | DWORD ver = GetFileVersion(path); | ||
| 1468 | fileLevel = ((ver < _7ZIP_DLL_VER_COMPAT || ver > _7ZIP_CUR_VER) ? 2 : 1); | ||
| 1469 | tempIndex++; | ||
| 1470 | continue; | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | if (g_SilentMode) | ||
| 1474 | { | ||
| 1475 | tempIndex++; | ||
| 1476 | continue; | ||
| 1477 | } | ||
| 1478 | { | ||
| 1479 | WCHAR message[MAX_PATH * 3 + 100]; | ||
| 1480 | int mbRes; | ||
| 1481 | |||
| 1482 | CpyAscii(message, "Can't open file\n"); | ||
| 1483 | wcscat(message, path); | ||
| 1484 | CatAscii(message, "\n"); | ||
| 1485 | |||
| 1486 | GetErrorMessage(openRes, message + wcslen(message)); | ||
| 1487 | |||
| 1488 | mbRes = MessageBoxW(g_HWND, message, L"Error", MB_ICONERROR | MB_ABORTRETRYIGNORE | MB_DEFBUTTON3); | ||
| 1489 | if (mbRes == IDABORT) | ||
| 1490 | { | ||
| 1491 | res = SZ_ERROR_ABORT; | ||
| 1492 | tempIndex = 0; | ||
| 1493 | break; | ||
| 1494 | } | ||
| 1495 | if (mbRes == IDIGNORE) | ||
| 1496 | { | ||
| 1497 | // skipFile = True; | ||
| 1498 | tempIndex++; | ||
| 1499 | } | ||
| 1500 | } | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | if (res != SZ_OK) | ||
| 1504 | break; | ||
| 1505 | |||
| 1506 | /* | ||
| 1507 | if (skipFile) | ||
| 1508 | continue; | ||
| 1509 | */ | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | // if (res == SZ_OK) | ||
| 1513 | { | ||
| 1514 | processedSize = outSizeProcessed; | ||
| 1515 | winRes = File_Write(&outFile, outBuf + offset, &processedSize); | ||
| 1516 | if (winRes != 0 || processedSize != outSizeProcessed) | ||
| 1517 | { | ||
| 1518 | errorMessage = "Can't write output file"; | ||
| 1519 | res = SZ_ERROR_FAIL; | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | g_TotalSize += (DWORD)outSizeProcessed; | ||
| 1523 | |||
| 1524 | #ifdef USE_WINDOWS_FILE | ||
| 1525 | if (SzBitWithVals_Check(&db.MTime, i)) | ||
| 1526 | { | ||
| 1527 | const CNtfsFileTime *t = db.MTime.Vals + i; | ||
| 1528 | FILETIME mTime; | ||
| 1529 | mTime.dwLowDateTime = t->Low; | ||
| 1530 | mTime.dwHighDateTime = t->High; | ||
| 1531 | SetFileTime(outFile.handle, NULL, NULL, &mTime); | ||
| 1532 | } | ||
| 1533 | #endif | ||
| 1534 | |||
| 1535 | { | ||
| 1536 | SRes winRes2 = File_Close(&outFile); | ||
| 1537 | if (res != SZ_OK) | ||
| 1538 | break; | ||
| 1539 | if (winRes2 != 0) | ||
| 1540 | { | ||
| 1541 | winRes = winRes2; | ||
| 1542 | break; | ||
| 1543 | } | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | #ifdef USE_WINDOWS_FILE | ||
| 1547 | if (SzBitWithVals_Check(&db.Attribs, i)) | ||
| 1548 | SetFileAttributesW(path, db.Attribs.Vals[i]); | ||
| 1549 | #endif | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | if (tempIndex != 0) | ||
| 1553 | { | ||
| 1554 | // is it supported at win2000 ? | ||
| 1555 | #ifndef UNDER_CE | ||
| 1556 | if (!MoveFileExW(path, origPath, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING)) | ||
| 1557 | { | ||
| 1558 | winRes = GetLastError(); | ||
| 1559 | break; | ||
| 1560 | } | ||
| 1561 | needRebootLevel |= fileLevel; | ||
| 1562 | #endif | ||
| 1563 | } | ||
| 1564 | |||
| 1565 | } | ||
| 1566 | } | ||
| 1567 | |||
| 1568 | ISzAlloc_Free(&allocImp, outBuf); | ||
| 1569 | |||
| 1570 | if (!g_SilentMode) | ||
| 1571 | SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); | ||
| 1572 | |||
| 1573 | path[pathLen] = 0; | ||
| 1574 | |||
| 1575 | if (i == db.NumFiles) | ||
| 1576 | { | ||
| 1577 | SetRegKey_Path(); | ||
| 1578 | WriteCLSID(); | ||
| 1579 | WriteShellEx(); | ||
| 1580 | |||
| 1581 | SetShellProgramsGroup(g_HWND); | ||
| 1582 | if (!g_SilentMode) | ||
| 1583 | SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is installed"); | ||
| 1584 | } | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | SzArEx_Free(&db, &allocImp); | ||
| 1588 | |||
| 1589 | ISzAlloc_Free(&allocImp, lookStream.buf); | ||
| 1590 | |||
| 1591 | File_Close(&archiveStream.file); | ||
| 1592 | |||
| 1593 | } | ||
| 1594 | |||
| 1595 | if (winRes != 0) | ||
| 1596 | res = SZ_ERROR_FAIL; | ||
| 1597 | |||
| 1598 | if (res == SZ_OK) | ||
| 1599 | { | ||
| 1600 | if (!g_SilentMode && needRebootLevel > 1) | ||
| 1601 | { | ||
| 1602 | if (MessageBoxW(g_HWND, L"You must restart your system to complete the installation.\nRestart now?", | ||
| 1603 | k_7zip_Setup, MB_YESNO | MB_DEFBUTTON2) == IDYES) | ||
| 1604 | { | ||
| 1605 | #ifndef UNDER_CE | ||
| 1606 | |||
| 1607 | // Get a token for this process. | ||
| 1608 | HANDLE hToken; | ||
| 1609 | |||
| 1610 | if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) | ||
| 1611 | { | ||
| 1612 | TOKEN_PRIVILEGES tkp; | ||
| 1613 | // Get the LUID for the shutdown privilege. | ||
| 1614 | LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); | ||
| 1615 | tkp.PrivilegeCount = 1; // one privilege to set | ||
| 1616 | tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; | ||
| 1617 | // Get the shutdown privilege for this process. | ||
| 1618 | AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); | ||
| 1619 | |||
| 1620 | if (GetLastError() == ERROR_SUCCESS) | ||
| 1621 | { | ||
| 1622 | if (!ExitWindowsEx(EWX_REBOOT, 0)) | ||
| 1623 | { | ||
| 1624 | } | ||
| 1625 | } | ||
| 1626 | } | ||
| 1627 | |||
| 1628 | #endif | ||
| 1629 | } | ||
| 1630 | } | ||
| 1631 | |||
| 1632 | if (res == SZ_OK) | ||
| 1633 | return 0; | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | if (!g_SilentMode) | ||
| 1637 | { | ||
| 1638 | if (winRes != 0) | ||
| 1639 | { | ||
| 1640 | WCHAR m[MAX_PATH + 100]; | ||
| 1641 | m[0] = 0; | ||
| 1642 | GetErrorMessage(winRes, m); | ||
| 1643 | PrintErrorMessage(NULL, m); | ||
| 1644 | } | ||
| 1645 | else | ||
| 1646 | { | ||
| 1647 | if (res == SZ_ERROR_ABORT) | ||
| 1648 | return 2; | ||
| 1649 | |||
| 1650 | if (res == SZ_ERROR_UNSUPPORTED) | ||
| 1651 | errorMessage = "Decoder doesn't support this archive"; | ||
| 1652 | else if (res == SZ_ERROR_MEM) | ||
| 1653 | errorMessage = "Can't allocate required memory"; | ||
| 1654 | else if (res == SZ_ERROR_CRC) | ||
| 1655 | errorMessage = "CRC error"; | ||
| 1656 | else if (res == SZ_ERROR_DATA) | ||
| 1657 | errorMessage = "Data error"; | ||
| 1658 | |||
| 1659 | if (!errorMessage) | ||
| 1660 | errorMessage = "ERROR"; | ||
| 1661 | PrintErrorMessage(errorMessage, NULL); | ||
| 1662 | } | ||
| 1663 | } | ||
| 1664 | |||
| 1665 | return 1; | ||
| 1666 | } | ||
diff --git a/C/Util/7zipInstall/7zipInstall.dsp b/C/Util/7zipInstall/7zipInstall.dsp new file mode 100644 index 0000000..d3b5c4c --- /dev/null +++ b/C/Util/7zipInstall/7zipInstall.dsp | |||
| @@ -0,0 +1,240 @@ | |||
| 1 | # Microsoft Developer Studio Project File - Name="7zipInstall" - Package Owner=<4> | ||
| 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 | ||
| 3 | # ** DO NOT EDIT ** | ||
| 4 | |||
| 5 | # TARGTYPE "Win32 (x86) Application" 0x0101 | ||
| 6 | |||
| 7 | CFG=7zipInstall - Win32 Debug | ||
| 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, | ||
| 9 | !MESSAGE use the Export Makefile command and run | ||
| 10 | !MESSAGE | ||
| 11 | !MESSAGE NMAKE /f "7zipInstall.mak". | ||
| 12 | !MESSAGE | ||
| 13 | !MESSAGE You can specify a configuration when running NMAKE | ||
| 14 | !MESSAGE by defining the macro CFG on the command line. For example: | ||
| 15 | !MESSAGE | ||
| 16 | !MESSAGE NMAKE /f "7zipInstall.mak" CFG="7zipInstall - Win32 Debug" | ||
| 17 | !MESSAGE | ||
| 18 | !MESSAGE Possible choices for configuration are: | ||
| 19 | !MESSAGE | ||
| 20 | !MESSAGE "7zipInstall - Win32 Release" (based on "Win32 (x86) Application") | ||
| 21 | !MESSAGE "7zipInstall - Win32 Debug" (based on "Win32 (x86) Application") | ||
| 22 | !MESSAGE | ||
| 23 | |||
| 24 | # Begin Project | ||
| 25 | # PROP AllowPerConfigDependencies 0 | ||
| 26 | # PROP Scc_ProjName "" | ||
| 27 | # PROP Scc_LocalPath "" | ||
| 28 | CPP=cl.exe | ||
| 29 | MTL=midl.exe | ||
| 30 | RSC=rc.exe | ||
| 31 | |||
| 32 | !IF "$(CFG)" == "7zipInstall - Win32 Release" | ||
| 33 | |||
| 34 | # PROP BASE Use_MFC 0 | ||
| 35 | # PROP BASE Use_Debug_Libraries 0 | ||
| 36 | # PROP BASE Output_Dir "Release" | ||
| 37 | # PROP BASE Intermediate_Dir "Release" | ||
| 38 | # PROP BASE Target_Dir "" | ||
| 39 | # PROP Use_MFC 0 | ||
| 40 | # PROP Use_Debug_Libraries 0 | ||
| 41 | # PROP Output_Dir "Release" | ||
| 42 | # PROP Intermediate_Dir "Release" | ||
| 43 | # PROP Ignore_Export_Lib 0 | ||
| 44 | # PROP Target_Dir "" | ||
| 45 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c | ||
| 46 | # ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /c | ||
| 47 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | ||
| 48 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | ||
| 49 | # ADD BASE RSC /l 0x419 /d "NDEBUG" | ||
| 50 | # ADD RSC /l 0x419 /d "NDEBUG" | ||
| 51 | BSC32=bscmake.exe | ||
| 52 | # ADD BASE BSC32 /nologo | ||
| 53 | # ADD BSC32 /nologo | ||
| 54 | LINK32=link.exe | ||
| 55 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 | ||
| 56 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib version.lib /nologo /subsystem:windows /machine:I386 | ||
| 57 | |||
| 58 | !ELSEIF "$(CFG)" == "7zipInstall - Win32 Debug" | ||
| 59 | |||
| 60 | # PROP BASE Use_MFC 0 | ||
| 61 | # PROP BASE Use_Debug_Libraries 1 | ||
| 62 | # PROP BASE Output_Dir "Debug" | ||
| 63 | # PROP BASE Intermediate_Dir "Debug" | ||
| 64 | # PROP BASE Target_Dir "" | ||
| 65 | # PROP Use_MFC 0 | ||
| 66 | # PROP Use_Debug_Libraries 1 | ||
| 67 | # PROP Output_Dir "Debug" | ||
| 68 | # PROP Intermediate_Dir "Debug" | ||
| 69 | # PROP Ignore_Export_Lib 0 | ||
| 70 | # PROP Target_Dir "" | ||
| 71 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c | ||
| 72 | # ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /GZ /c | ||
| 73 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | ||
| 74 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | ||
| 75 | # ADD BASE RSC /l 0x419 /d "_DEBUG" | ||
| 76 | # ADD RSC /l 0x419 /d "_DEBUG" | ||
| 77 | BSC32=bscmake.exe | ||
| 78 | # ADD BASE BSC32 /nologo | ||
| 79 | # ADD BSC32 /nologo | ||
| 80 | LINK32=link.exe | ||
| 81 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept | ||
| 82 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib version.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept | ||
| 83 | |||
| 84 | !ENDIF | ||
| 85 | |||
| 86 | # Begin Target | ||
| 87 | |||
| 88 | # Name "7zipInstall - Win32 Release" | ||
| 89 | # Name "7zipInstall - Win32 Debug" | ||
| 90 | # Begin Group "Common" | ||
| 91 | |||
| 92 | # PROP Default_Filter "" | ||
| 93 | # Begin Source File | ||
| 94 | |||
| 95 | SOURCE=..\..\7z.h | ||
| 96 | # End Source File | ||
| 97 | # Begin Source File | ||
| 98 | |||
| 99 | SOURCE=..\..\7zAlloc.c | ||
| 100 | # End Source File | ||
| 101 | # Begin Source File | ||
| 102 | |||
| 103 | SOURCE=..\..\7zAlloc.h | ||
| 104 | # End Source File | ||
| 105 | # Begin Source File | ||
| 106 | |||
| 107 | SOURCE=..\..\7zArcIn.c | ||
| 108 | # End Source File | ||
| 109 | # Begin Source File | ||
| 110 | |||
| 111 | SOURCE=..\..\7zBuf.c | ||
| 112 | # End Source File | ||
| 113 | # Begin Source File | ||
| 114 | |||
| 115 | SOURCE=..\..\7zBuf.h | ||
| 116 | # End Source File | ||
| 117 | # Begin Source File | ||
| 118 | |||
| 119 | SOURCE=..\..\7zCrc.c | ||
| 120 | # End Source File | ||
| 121 | # Begin Source File | ||
| 122 | |||
| 123 | SOURCE=..\..\7zCrc.h | ||
| 124 | # End Source File | ||
| 125 | # Begin Source File | ||
| 126 | |||
| 127 | SOURCE=..\..\7zCrcOpt.c | ||
| 128 | # End Source File | ||
| 129 | # Begin Source File | ||
| 130 | |||
| 131 | SOURCE=..\..\7zDec.c | ||
| 132 | # End Source File | ||
| 133 | # Begin Source File | ||
| 134 | |||
| 135 | SOURCE=..\..\7zFile.c | ||
| 136 | # End Source File | ||
| 137 | # Begin Source File | ||
| 138 | |||
| 139 | SOURCE=..\..\7zFile.h | ||
| 140 | # End Source File | ||
| 141 | # Begin Source File | ||
| 142 | |||
| 143 | SOURCE=..\..\7zStream.c | ||
| 144 | # End Source File | ||
| 145 | # Begin Source File | ||
| 146 | |||
| 147 | SOURCE=..\..\7zTypes.h | ||
| 148 | # End Source File | ||
| 149 | # Begin Source File | ||
| 150 | |||
| 151 | SOURCE=..\..\7zVersion.h | ||
| 152 | # End Source File | ||
| 153 | # Begin Source File | ||
| 154 | |||
| 155 | SOURCE=..\..\Bcj2.c | ||
| 156 | # End Source File | ||
| 157 | # Begin Source File | ||
| 158 | |||
| 159 | SOURCE=..\..\Bcj2.h | ||
| 160 | # End Source File | ||
| 161 | # Begin Source File | ||
| 162 | |||
| 163 | SOURCE=..\..\Bra.c | ||
| 164 | # End Source File | ||
| 165 | # Begin Source File | ||
| 166 | |||
| 167 | SOURCE=..\..\Bra.h | ||
| 168 | # End Source File | ||
| 169 | # Begin Source File | ||
| 170 | |||
| 171 | SOURCE=..\..\Bra86.c | ||
| 172 | # End Source File | ||
| 173 | # Begin Source File | ||
| 174 | |||
| 175 | SOURCE=..\..\BraIA64.c | ||
| 176 | # End Source File | ||
| 177 | # Begin Source File | ||
| 178 | |||
| 179 | SOURCE=..\..\CpuArch.c | ||
| 180 | # End Source File | ||
| 181 | # Begin Source File | ||
| 182 | |||
| 183 | SOURCE=..\..\CpuArch.h | ||
| 184 | # End Source File | ||
| 185 | # Begin Source File | ||
| 186 | |||
| 187 | SOURCE=..\..\Delta.c | ||
| 188 | # End Source File | ||
| 189 | # Begin Source File | ||
| 190 | |||
| 191 | SOURCE=..\..\Delta.h | ||
| 192 | # End Source File | ||
| 193 | # Begin Source File | ||
| 194 | |||
| 195 | SOURCE=..\..\DllSecur.c | ||
| 196 | # End Source File | ||
| 197 | # Begin Source File | ||
| 198 | |||
| 199 | SOURCE=..\..\DllSecur.h | ||
| 200 | # End Source File | ||
| 201 | # Begin Source File | ||
| 202 | |||
| 203 | SOURCE=..\..\Lzma2Dec.c | ||
| 204 | # End Source File | ||
| 205 | # Begin Source File | ||
| 206 | |||
| 207 | SOURCE=..\..\Lzma2Dec.h | ||
| 208 | # End Source File | ||
| 209 | # Begin Source File | ||
| 210 | |||
| 211 | SOURCE=..\..\LzmaDec.c | ||
| 212 | # End Source File | ||
| 213 | # Begin Source File | ||
| 214 | |||
| 215 | SOURCE=..\..\LzmaDec.h | ||
| 216 | # End Source File | ||
| 217 | # End Group | ||
| 218 | # Begin Group "Spec" | ||
| 219 | |||
| 220 | # PROP Default_Filter "" | ||
| 221 | # Begin Source File | ||
| 222 | |||
| 223 | SOURCE=.\Precomp.c | ||
| 224 | # ADD CPP /Yc"Precomp.h" | ||
| 225 | # End Source File | ||
| 226 | # Begin Source File | ||
| 227 | |||
| 228 | SOURCE=.\Precomp.h | ||
| 229 | # End Source File | ||
| 230 | # End Group | ||
| 231 | # Begin Source File | ||
| 232 | |||
| 233 | SOURCE=.\7zipInstall.c | ||
| 234 | # End Source File | ||
| 235 | # Begin Source File | ||
| 236 | |||
| 237 | SOURCE=.\resource.rc | ||
| 238 | # End Source File | ||
| 239 | # End Target | ||
| 240 | # End Project | ||
diff --git a/C/Util/7zipInstall/7zipInstall.dsw b/C/Util/7zipInstall/7zipInstall.dsw new file mode 100644 index 0000000..b7db73f --- /dev/null +++ b/C/Util/7zipInstall/7zipInstall.dsw | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 | ||
| 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! | ||
| 3 | |||
| 4 | ############################################################################### | ||
| 5 | |||
| 6 | Project: "7zipInstall"=.\7zipInstall.dsp - Package Owner=<4> | ||
| 7 | |||
| 8 | Package=<5> | ||
| 9 | {{{ | ||
| 10 | }}} | ||
| 11 | |||
| 12 | Package=<4> | ||
| 13 | {{{ | ||
| 14 | }}} | ||
| 15 | |||
| 16 | ############################################################################### | ||
| 17 | |||
| 18 | Global: | ||
| 19 | |||
| 20 | Package=<5> | ||
| 21 | {{{ | ||
| 22 | }}} | ||
| 23 | |||
| 24 | Package=<3> | ||
| 25 | {{{ | ||
| 26 | }}} | ||
| 27 | |||
| 28 | ############################################################################### | ||
| 29 | |||
diff --git a/C/Util/7zipInstall/7zipInstall.manifest b/C/Util/7zipInstall/7zipInstall.manifest new file mode 100644 index 0000000..f5c3ae5 --- /dev/null +++ b/C/Util/7zipInstall/7zipInstall.manifest | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
| 2 | <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> | ||
| 3 | <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.7zipInstall" type="win32"/> | ||
| 4 | <description>7-Zip Installer</description> | ||
| 5 | <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges> | ||
| 6 | <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/> | ||
| 7 | </requestedPrivileges></security></trustInfo> | ||
| 8 | <dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly></dependency> | ||
| 9 | <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application> | ||
| 10 | <!-- Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> | ||
| 11 | <!-- Win 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> | ||
| 12 | <!-- Win 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> | ||
| 13 | <!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> | ||
| 14 | <!-- Win 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> | ||
| 15 | </application></compatibility> | ||
| 16 | <asmv3:application><asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> | ||
| 17 | <dpiAware>true</dpiAware></asmv3:windowsSettings></asmv3:application> | ||
| 18 | </assembly> | ||
diff --git a/C/Util/7zipInstall/Precomp.c b/C/Util/7zipInstall/Precomp.c new file mode 100644 index 0000000..01605e3 --- /dev/null +++ b/C/Util/7zipInstall/Precomp.c | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | /* Precomp.c -- StdAfx | ||
| 2 | 2013-01-21 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
diff --git a/C/Util/7zipInstall/Precomp.h b/C/Util/7zipInstall/Precomp.h new file mode 100644 index 0000000..4c90d47 --- /dev/null +++ b/C/Util/7zipInstall/Precomp.h | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | /* Precomp.h -- StdAfx | ||
| 2 | 2015-05-24 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_PRECOMP_H | ||
| 5 | #define __7Z_PRECOMP_H | ||
| 6 | |||
| 7 | #include "../../Compiler.h" | ||
| 8 | |||
| 9 | #include "../../7zTypes.h" | ||
| 10 | |||
| 11 | #endif | ||
diff --git a/C/Util/7zipInstall/makefile b/C/Util/7zipInstall/makefile new file mode 100644 index 0000000..ab8893a --- /dev/null +++ b/C/Util/7zipInstall/makefile | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | PROG = 7zipInstall.exe | ||
| 2 | MY_FIXED = 1 | ||
| 3 | |||
| 4 | !IFDEF _64BIT_INSTALLER | ||
| 5 | CFLAGS = $(CFLAGS) -D_64BIT_INSTALLER | ||
| 6 | !ENDIF | ||
| 7 | |||
| 8 | CFLAGS = $(CFLAGS) -D_LZMA_SIZE_OPT | ||
| 9 | |||
| 10 | CFLAGS = $(CFLAGS) \ | ||
| 11 | -D_7Z_NO_METHOD_LZMA2 \ | ||
| 12 | -D_7Z_NO_METHODS_FILTERS | ||
| 13 | |||
| 14 | MAIN_OBJS = \ | ||
| 15 | $O\7zipInstall.obj \ | ||
| 16 | |||
| 17 | C_OBJS = \ | ||
| 18 | $O\7zAlloc.obj \ | ||
| 19 | $O\7zArcIn.obj \ | ||
| 20 | $O\7zBuf.obj \ | ||
| 21 | $O\7zBuf2.obj \ | ||
| 22 | $O\7zCrc.obj \ | ||
| 23 | $O\7zCrcOpt.obj \ | ||
| 24 | $O\7zFile.obj \ | ||
| 25 | $O\7zDec.obj \ | ||
| 26 | $O\7zStream.obj \ | ||
| 27 | $O\Bcj2.obj \ | ||
| 28 | $O\CpuArch.obj \ | ||
| 29 | $O\DllSecur.obj \ | ||
| 30 | $O\LzmaDec.obj \ | ||
| 31 | |||
| 32 | OBJS = \ | ||
| 33 | $(MAIN_OBJS) \ | ||
| 34 | $(C_OBJS) \ | ||
| 35 | $O\resource.res | ||
| 36 | |||
| 37 | !include "../../../CPP/Build.mak" | ||
| 38 | |||
| 39 | $(MAIN_OBJS): $(*B).c | ||
| 40 | $(COMPL_O1) | ||
| 41 | $(C_OBJS): ../../$(*B).c | ||
| 42 | $(COMPL_O1) | ||
diff --git a/C/Util/7zipInstall/resource.h b/C/Util/7zipInstall/resource.h new file mode 100644 index 0000000..63c6b4c --- /dev/null +++ b/C/Util/7zipInstall/resource.h | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #define IDD_INSTALL 100 | ||
| 2 | |||
| 3 | #define IDT_EXTRACT_EXTRACT_TO 110 | ||
| 4 | #define IDE_EXTRACT_PATH 111 | ||
| 5 | #define IDB_EXTRACT_SET_PATH 112 | ||
| 6 | #define IDT_CUR_FILE 113 | ||
| 7 | #define IDC_PROGRESS 114 | ||
| 8 | |||
| 9 | #define IDI_ICON 1 | ||
diff --git a/C/Util/7zipInstall/resource.rc b/C/Util/7zipInstall/resource.rc new file mode 100644 index 0000000..df6474e --- /dev/null +++ b/C/Util/7zipInstall/resource.rc | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #include <winnt.h> | ||
| 2 | #include <WinUser.h> | ||
| 3 | #include <CommCtrl.h> | ||
| 4 | |||
| 5 | #define USE_COPYRIGHT_CR | ||
| 6 | #include "../../7zVersion.rc" | ||
| 7 | #include "resource.h" | ||
| 8 | |||
| 9 | MY_VERSION_INFO(MY_VFT_APP, "7-Zip Installer", "7zipInstall", "7zipInstall.exe") | ||
| 10 | |||
| 11 | 1 ICON "7zip.ico" | ||
| 12 | |||
| 13 | #define xc 184 | ||
| 14 | #define yc 96 | ||
| 15 | |||
| 16 | #define m 8 | ||
| 17 | #define bxs 64 | ||
| 18 | #define bys 16 | ||
| 19 | #define bxsDots 20 | ||
| 20 | |||
| 21 | #define xs (xc + m + m) | ||
| 22 | #define ys (yc + m + m) | ||
| 23 | |||
| 24 | #define bx1 (xs - m - bxs) | ||
| 25 | #define bx2 (bx1 - m - bxs) | ||
| 26 | |||
| 27 | #define by (ys - m - bys) | ||
| 28 | |||
| 29 | IDD_INSTALL DIALOG 0, 0, xs, ys | ||
| 30 | STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE | ||
| 31 | CAPTION "Install 7-Zip" | ||
| 32 | FONT 8, "MS Shell Dlg" | ||
| 33 | BEGIN | ||
| 34 | LTEXT "Destination folder:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8 | ||
| 35 | EDITTEXT IDE_EXTRACT_PATH, m, 21, xc - bxsDots - 12, 14, ES_AUTOHSCROLL | ||
| 36 | PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, 20, bxsDots, bys, WS_GROUP | ||
| 37 | |||
| 38 | LTEXT "", IDT_CUR_FILE, m, 50, xc, 8 | ||
| 39 | CONTROL "", IDC_PROGRESS, "msctls_progress32", WS_BORDER, m, 64, xc, 10 | ||
| 40 | |||
| 41 | DEFPUSHBUTTON "&Install", IDOK, bx2, by, bxs, bys, WS_GROUP | ||
| 42 | PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys | ||
| 43 | END | ||
| 44 | |||
| 45 | #ifndef UNDER_CE | ||
| 46 | 1 24 MOVEABLE PURE "7zipInstall.manifest" | ||
| 47 | #endif | ||
diff --git a/C/Util/7zipUninstall/7zipUninstall.c b/C/Util/7zipUninstall/7zipUninstall.c new file mode 100644 index 0000000..b4c6ff5 --- /dev/null +++ b/C/Util/7zipUninstall/7zipUninstall.c | |||
| @@ -0,0 +1,1183 @@ | |||
| 1 | /* 7zipUninstall.c - 7-Zip Uninstaller | ||
| 2 | 2021-11-24 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #ifdef _MSC_VER | ||
| 7 | #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union | ||
| 8 | #pragma warning(disable : 4011) // vs2010: identifier truncated to _CRT_SECURE_CPP_OVERLOAD_SECURE | ||
| 9 | #endif | ||
| 10 | |||
| 11 | // #define SZ_ERROR_ABORT 100 | ||
| 12 | |||
| 13 | #include <windows.h> | ||
| 14 | #include <ShlObj.h> | ||
| 15 | |||
| 16 | #include "../../7zVersion.h" | ||
| 17 | |||
| 18 | #include "resource.h" | ||
| 19 | |||
| 20 | #define LLL_(quote) L##quote | ||
| 21 | #define LLL(quote) LLL_(quote) | ||
| 22 | |||
| 23 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) | ||
| 24 | |||
| 25 | // static LPCWSTR const k_7zip = L"7-Zip"; | ||
| 26 | |||
| 27 | // #define _64BIT_INSTALLER 1 | ||
| 28 | |||
| 29 | #ifdef _WIN64 | ||
| 30 | #define _64BIT_INSTALLER 1 | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION) | ||
| 34 | |||
| 35 | #ifdef _64BIT_INSTALLER | ||
| 36 | |||
| 37 | // #define USE_7ZIP_32_DLL | ||
| 38 | |||
| 39 | #if defined(_M_ARM64) || defined(_M_ARM) | ||
| 40 | #define k_Postfix L" (arm64)" | ||
| 41 | #else | ||
| 42 | #define k_Postfix L" (x64)" | ||
| 43 | #define USE_7ZIP_32_DLL | ||
| 44 | #endif | ||
| 45 | #else | ||
| 46 | #if defined(_M_ARM64) || defined(_M_ARM) | ||
| 47 | #define k_Postfix L" (arm)" | ||
| 48 | #else | ||
| 49 | // #define k_Postfix L" (x86)" | ||
| 50 | #define k_Postfix | ||
| 51 | #endif | ||
| 52 | #endif | ||
| 53 | |||
| 54 | #define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix | ||
| 55 | |||
| 56 | static LPCWSTR const k_7zip_with_Ver_Uninstall = k_7zip_with_Ver L" Uninstall"; | ||
| 57 | |||
| 58 | static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip"; | ||
| 59 | |||
| 60 | static LPCWSTR const k_Reg_Path = L"Path"; | ||
| 61 | |||
| 62 | static LPCWSTR const k_Reg_Path32 = L"Path" | ||
| 63 | #ifdef _64BIT_INSTALLER | ||
| 64 | L"64" | ||
| 65 | #else | ||
| 66 | L"32" | ||
| 67 | #endif | ||
| 68 | ; | ||
| 69 | |||
| 70 | #if defined(_64BIT_INSTALLER) && !defined(_WIN64) | ||
| 71 | #define k_Reg_WOW_Flag KEY_WOW64_64KEY | ||
| 72 | #else | ||
| 73 | #define k_Reg_WOW_Flag 0 | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #ifdef _WIN64 | ||
| 77 | #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY | ||
| 78 | #else | ||
| 79 | #define k_Reg_WOW_Flag_32 0 | ||
| 80 | #endif | ||
| 81 | |||
| 82 | #define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}" | ||
| 83 | |||
| 84 | static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID; | ||
| 85 | static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32"; | ||
| 86 | |||
| 87 | |||
| 88 | #define g_AllUsers True | ||
| 89 | |||
| 90 | static BoolInt g_Install_was_Pressed; | ||
| 91 | static BoolInt g_Finished; | ||
| 92 | static BoolInt g_SilentMode; | ||
| 93 | |||
| 94 | static HWND g_HWND; | ||
| 95 | static HWND g_Path_HWND; | ||
| 96 | static HWND g_InfoLine_HWND; | ||
| 97 | static HWND g_Progress_HWND; | ||
| 98 | |||
| 99 | // WINADVAPI | ||
| 100 | typedef LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved); | ||
| 101 | static Func_RegDeleteKeyExW func_RegDeleteKeyExW; | ||
| 102 | |||
| 103 | static WCHAR cmd[MAX_PATH + 4]; | ||
| 104 | static WCHAR cmdError[MAX_PATH + 4]; | ||
| 105 | static WCHAR path[MAX_PATH * 2 + 40]; | ||
| 106 | static WCHAR workDir[MAX_PATH + 10]; | ||
| 107 | static WCHAR modulePath[MAX_PATH + 10]; | ||
| 108 | static WCHAR modulePrefix[MAX_PATH + 10]; | ||
| 109 | static WCHAR tempPath[MAX_PATH * 2 + 40]; | ||
| 110 | static WCHAR cmdLine[MAX_PATH * 3 + 40]; | ||
| 111 | static WCHAR copyPath[MAX_PATH * 2 + 40]; | ||
| 112 | |||
| 113 | static LPCWSTR const kUninstallExe = L"Uninstall.exe"; | ||
| 114 | |||
| 115 | #define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c))) | ||
| 116 | |||
| 117 | |||
| 118 | static void CpyAscii(wchar_t *dest, const char *s) | ||
| 119 | { | ||
| 120 | for (;;) | ||
| 121 | { | ||
| 122 | Byte b = (Byte)*s++; | ||
| 123 | *dest++ = b; | ||
| 124 | if (b == 0) | ||
| 125 | return; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | static void CatAscii(wchar_t *dest, const char *s) | ||
| 130 | { | ||
| 131 | dest += wcslen(dest); | ||
| 132 | CpyAscii(dest, s); | ||
| 133 | } | ||
| 134 | |||
| 135 | static void PrintErrorMessage(const char *s1, const wchar_t *s2) | ||
| 136 | { | ||
| 137 | WCHAR m[MAX_PATH + 512]; | ||
| 138 | m[0] = 0; | ||
| 139 | CatAscii(m, "ERROR:"); | ||
| 140 | if (s1) | ||
| 141 | { | ||
| 142 | CatAscii(m, "\n"); | ||
| 143 | CatAscii(m, s1); | ||
| 144 | } | ||
| 145 | if (s2) | ||
| 146 | { | ||
| 147 | CatAscii(m, "\n"); | ||
| 148 | wcscat(m, s2); | ||
| 149 | } | ||
| 150 | MessageBoxW(g_HWND, m, k_7zip_with_Ver_Uninstall, MB_ICONERROR | MB_OK); | ||
| 151 | } | ||
| 152 | |||
| 153 | |||
| 154 | static BoolInt AreStringsEqual_NoCase(const wchar_t *s1, const wchar_t *s2) | ||
| 155 | { | ||
| 156 | for (;;) | ||
| 157 | { | ||
| 158 | wchar_t c1 = *s1++; | ||
| 159 | wchar_t c2 = *s2++; | ||
| 160 | if (c1 != c2 && MAKE_CHAR_UPPER(c1) != MAKE_CHAR_UPPER(c2)) | ||
| 161 | return False; | ||
| 162 | if (c2 == 0) | ||
| 163 | return True; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | static BoolInt IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) | ||
| 168 | { | ||
| 169 | for (;;) | ||
| 170 | { | ||
| 171 | wchar_t c1; | ||
| 172 | wchar_t c2 = *s2++; | ||
| 173 | if (c2 == 0) | ||
| 174 | return True; | ||
| 175 | c1 = *s1++; | ||
| 176 | if (c1 != c2 && MAKE_CHAR_UPPER(c1) != MAKE_CHAR_UPPER(c2)) | ||
| 177 | return False; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | static void NormalizePrefix(WCHAR *s) | ||
| 182 | { | ||
| 183 | size_t len = wcslen(s); | ||
| 184 | if (len != 0) | ||
| 185 | if (s[len - 1] != WCHAR_PATH_SEPARATOR) | ||
| 186 | { | ||
| 187 | s[len] = WCHAR_PATH_SEPARATOR; | ||
| 188 | s[len + 1] = 0; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest) | ||
| 193 | { | ||
| 194 | DWORD cnt = MAX_PATH * sizeof(name[0]); | ||
| 195 | DWORD type = 0; | ||
| 196 | LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, (DWORD *)&cnt); | ||
| 197 | if (type != REG_SZ) | ||
| 198 | return False; | ||
| 199 | return res == ERROR_SUCCESS; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) | ||
| 203 | { | ||
| 204 | HKEY key = 0; | ||
| 205 | LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key); | ||
| 206 | if (res != ERROR_SUCCESS) | ||
| 207 | return False; | ||
| 208 | { | ||
| 209 | BoolInt res2 = MyRegistry_QueryString(key, valName, dest); | ||
| 210 | RegCloseKey(key); | ||
| 211 | return res2; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | static LONG MyRegistry_OpenKey_ReadWrite(HKEY parentKey, LPCWSTR name, HKEY *destKey) | ||
| 216 | { | ||
| 217 | return RegOpenKeyExW(parentKey, name, 0, KEY_READ | KEY_WRITE | k_Reg_WOW_Flag, destKey); | ||
| 218 | } | ||
| 219 | |||
| 220 | static LONG MyRegistry_DeleteKey(HKEY parentKey, LPCWSTR name) | ||
| 221 | { | ||
| 222 | #if k_Reg_WOW_Flag != 0 | ||
| 223 | if (func_RegDeleteKeyExW) | ||
| 224 | return func_RegDeleteKeyExW(parentKey, name, k_Reg_WOW_Flag, 0); | ||
| 225 | return E_FAIL; | ||
| 226 | #else | ||
| 227 | return RegDeleteKeyW(parentKey, name); | ||
| 228 | #endif | ||
| 229 | } | ||
| 230 | |||
| 231 | #ifdef USE_7ZIP_32_DLL | ||
| 232 | |||
| 233 | static int MyRegistry_QueryString2_32(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) | ||
| 234 | { | ||
| 235 | HKEY key = 0; | ||
| 236 | LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag_32, &key); | ||
| 237 | if (res != ERROR_SUCCESS) | ||
| 238 | return False; | ||
| 239 | { | ||
| 240 | BoolInt res2 = MyRegistry_QueryString(key, valName, dest); | ||
| 241 | RegCloseKey(key); | ||
| 242 | return res2; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | static LONG MyRegistry_OpenKey_ReadWrite_32(HKEY parentKey, LPCWSTR name, HKEY *destKey) | ||
| 247 | { | ||
| 248 | return RegOpenKeyExW(parentKey, name, 0, KEY_READ | KEY_WRITE | k_Reg_WOW_Flag_32, destKey); | ||
| 249 | } | ||
| 250 | |||
| 251 | static LONG MyRegistry_DeleteKey_32(HKEY parentKey, LPCWSTR name) | ||
| 252 | { | ||
| 253 | #if k_Reg_WOW_Flag_32 != 0 | ||
| 254 | if (func_RegDeleteKeyExW) | ||
| 255 | return func_RegDeleteKeyExW(parentKey, name, k_Reg_WOW_Flag_32, 0); | ||
| 256 | return E_FAIL; | ||
| 257 | #else | ||
| 258 | return RegDeleteKeyW(parentKey, name); | ||
| 259 | #endif | ||
| 260 | } | ||
| 261 | |||
| 262 | #endif | ||
| 263 | |||
| 264 | |||
| 265 | |||
| 266 | |||
| 267 | static void MyReg_DeleteVal_Path_if_Equal(HKEY hKey, LPCWSTR name) | ||
| 268 | { | ||
| 269 | WCHAR s[MAX_PATH + 10]; | ||
| 270 | if (MyRegistry_QueryString(hKey, name, s)) | ||
| 271 | { | ||
| 272 | NormalizePrefix(s); | ||
| 273 | if (AreStringsEqual_NoCase(s, path)) | ||
| 274 | RegDeleteValueW(hKey, name); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | static void SetRegKey_Path2(HKEY parentKey) | ||
| 279 | { | ||
| 280 | HKEY key = 0; | ||
| 281 | LONG res = MyRegistry_OpenKey_ReadWrite(parentKey, k_Reg_Software_7zip, &key); | ||
| 282 | if (res == ERROR_SUCCESS) | ||
| 283 | { | ||
| 284 | MyReg_DeleteVal_Path_if_Equal(key, k_Reg_Path32); | ||
| 285 | MyReg_DeleteVal_Path_if_Equal(key, k_Reg_Path); | ||
| 286 | |||
| 287 | RegCloseKey(key); | ||
| 288 | // MyRegistry_DeleteKey(parentKey, k_Reg_Software_7zip); | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | static void SetRegKey_Path() | ||
| 293 | { | ||
| 294 | SetRegKey_Path2(HKEY_CURRENT_USER); | ||
| 295 | SetRegKey_Path2(HKEY_LOCAL_MACHINE); | ||
| 296 | } | ||
| 297 | |||
| 298 | static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath) | ||
| 299 | { | ||
| 300 | IShellLinkW *sl; | ||
| 301 | |||
| 302 | // CoInitialize has already been called. | ||
| 303 | HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl); | ||
| 304 | |||
| 305 | if (SUCCEEDED(hres)) | ||
| 306 | { | ||
| 307 | IPersistFile *pf; | ||
| 308 | |||
| 309 | hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID *)&pf); | ||
| 310 | |||
| 311 | if (SUCCEEDED(hres)) | ||
| 312 | { | ||
| 313 | WCHAR s[MAX_PATH + 10]; | ||
| 314 | hres = pf->lpVtbl->Load(pf, srcPath, TRUE); | ||
| 315 | pf->lpVtbl->Release(pf); | ||
| 316 | |||
| 317 | if (SUCCEEDED(hres)) | ||
| 318 | { | ||
| 319 | hres = sl->lpVtbl->GetPath(sl, s, MAX_PATH, NULL, 0); // SLGP_RAWPATH | ||
| 320 | if (!AreStringsEqual_NoCase(s, targetPath)) | ||
| 321 | hres = S_FALSE; | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | sl->lpVtbl->Release(sl); | ||
| 326 | } | ||
| 327 | |||
| 328 | return hres; | ||
| 329 | } | ||
| 330 | |||
| 331 | static void SetShellProgramsGroup(HWND hwndOwner) | ||
| 332 | { | ||
| 333 | #ifdef UNDER_CE | ||
| 334 | |||
| 335 | UNUSED_VAR(hwndOwner) | ||
| 336 | |||
| 337 | #else | ||
| 338 | |||
| 339 | unsigned i = (g_AllUsers ? 1 : 2); | ||
| 340 | |||
| 341 | for (; i < 3; i++) | ||
| 342 | { | ||
| 343 | // BoolInt isOK = True; | ||
| 344 | WCHAR link[MAX_PATH + 40]; | ||
| 345 | WCHAR destPath[MAX_PATH + 40]; | ||
| 346 | |||
| 347 | link[0] = 0; | ||
| 348 | |||
| 349 | if (SHGetFolderPathW(hwndOwner, | ||
| 350 | i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS, | ||
| 351 | NULL, SHGFP_TYPE_CURRENT, link) != S_OK) | ||
| 352 | continue; | ||
| 353 | |||
| 354 | NormalizePrefix(link); | ||
| 355 | CatAscii(link, "7-Zip\\"); | ||
| 356 | |||
| 357 | { | ||
| 358 | const size_t baseLen = wcslen(link); | ||
| 359 | unsigned k; | ||
| 360 | BoolInt needDelete = False; | ||
| 361 | |||
| 362 | for (k = 0; k < 2; k++) | ||
| 363 | { | ||
| 364 | CpyAscii(link + baseLen, k == 0 ? | ||
| 365 | "7-Zip File Manager.lnk" : | ||
| 366 | "7-Zip Help.lnk"); | ||
| 367 | wcscpy(destPath, path); | ||
| 368 | CatAscii(destPath, k == 0 ? | ||
| 369 | "7zFM.exe" : | ||
| 370 | "7-zip.chm"); | ||
| 371 | |||
| 372 | if (CreateShellLink(link, destPath) == S_OK) | ||
| 373 | { | ||
| 374 | needDelete = True; | ||
| 375 | DeleteFileW(link); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | if (needDelete) | ||
| 380 | { | ||
| 381 | link[baseLen] = 0; | ||
| 382 | RemoveDirectoryW(link); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | #endif | ||
| 388 | } | ||
| 389 | |||
| 390 | |||
| 391 | static LPCSTR const k_ShellEx_Items[] = | ||
| 392 | { | ||
| 393 | "*\\shellex\\ContextMenuHandlers" | ||
| 394 | , "Directory\\shellex\\ContextMenuHandlers" | ||
| 395 | , "Folder\\shellex\\ContextMenuHandlers" | ||
| 396 | , "Directory\\shellex\\DragDropHandlers" | ||
| 397 | , "Drive\\shellex\\DragDropHandlers" | ||
| 398 | }; | ||
| 399 | |||
| 400 | static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; | ||
| 401 | |||
| 402 | static LPCWSTR const k_AppPaths_7zFm = L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe"; | ||
| 403 | #define k_REG_Uninstall L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" | ||
| 404 | static LPCWSTR const k_Uninstall_7zip = k_REG_Uninstall L"7-Zip"; | ||
| 405 | |||
| 406 | |||
| 407 | static void RemoveQuotes(wchar_t *s) | ||
| 408 | { | ||
| 409 | const size_t len = wcslen(s); | ||
| 410 | size_t i; | ||
| 411 | if (len == 0 || s[0] != '\"' || s[len - 1] != '\"') | ||
| 412 | return; | ||
| 413 | for (i = 0; i < len; i++) | ||
| 414 | s[i] = s[i + 1]; | ||
| 415 | s[len - 2] = 0; | ||
| 416 | } | ||
| 417 | |||
| 418 | static BoolInt AreEqual_Path_PrefixName(const wchar_t *s, const wchar_t *prefix, const wchar_t *name) | ||
| 419 | { | ||
| 420 | if (!IsString1PrefixedByString2_NoCase(s, prefix)) | ||
| 421 | return False; | ||
| 422 | return AreStringsEqual_NoCase(s + wcslen(prefix), name); | ||
| 423 | } | ||
| 424 | |||
| 425 | static void WriteCLSID() | ||
| 426 | { | ||
| 427 | WCHAR s[MAX_PATH + 30]; | ||
| 428 | |||
| 429 | if (MyRegistry_QueryString2(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s)) | ||
| 430 | { | ||
| 431 | if (AreEqual_Path_PrefixName(s, path, L"7-zip.dll")) | ||
| 432 | { | ||
| 433 | { | ||
| 434 | LONG res = MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc); | ||
| 435 | if (res == ERROR_SUCCESS) | ||
| 436 | MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip); | ||
| 437 | } | ||
| 438 | |||
| 439 | { | ||
| 440 | unsigned i; | ||
| 441 | for (i = 0; i < ARRAY_SIZE(k_ShellEx_Items); i++) | ||
| 442 | { | ||
| 443 | WCHAR destPath[MAX_PATH]; | ||
| 444 | CpyAscii(destPath, k_ShellEx_Items[i]); | ||
| 445 | CatAscii(destPath, "\\7-Zip"); | ||
| 446 | |||
| 447 | MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, destPath); | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 | { | ||
| 452 | HKEY destKey = 0; | ||
| 453 | LONG res = MyRegistry_OpenKey_ReadWrite(HKEY_LOCAL_MACHINE, k_Shell_Approved, &destKey); | ||
| 454 | if (res == ERROR_SUCCESS) | ||
| 455 | { | ||
| 456 | RegDeleteValueW(destKey, k_7zip_CLSID); | ||
| 457 | /* res = */ RegCloseKey(destKey); | ||
| 458 | } | ||
| 459 | } | ||
| 460 | } | ||
| 461 | } | ||
| 462 | |||
| 463 | |||
| 464 | #ifdef USE_7ZIP_32_DLL | ||
| 465 | |||
| 466 | if (MyRegistry_QueryString2_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s)) | ||
| 467 | { | ||
| 468 | if (AreEqual_Path_PrefixName(s, path, L"7-zip32.dll")) | ||
| 469 | { | ||
| 470 | { | ||
| 471 | LONG res = MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc); | ||
| 472 | if (res == ERROR_SUCCESS) | ||
| 473 | MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip); | ||
| 474 | } | ||
| 475 | |||
| 476 | { | ||
| 477 | unsigned i; | ||
| 478 | for (i = 0; i < ARRAY_SIZE(k_ShellEx_Items); i++) | ||
| 479 | { | ||
| 480 | WCHAR destPath[MAX_PATH]; | ||
| 481 | CpyAscii(destPath, k_ShellEx_Items[i]); | ||
| 482 | CatAscii(destPath, "\\7-Zip"); | ||
| 483 | |||
| 484 | MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, destPath); | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | { | ||
| 489 | HKEY destKey = 0; | ||
| 490 | LONG res = MyRegistry_OpenKey_ReadWrite_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, &destKey); | ||
| 491 | if (res == ERROR_SUCCESS) | ||
| 492 | { | ||
| 493 | RegDeleteValueW(destKey, k_7zip_CLSID); | ||
| 494 | /* res = */ RegCloseKey(destKey); | ||
| 495 | } | ||
| 496 | } | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | #endif | ||
| 501 | |||
| 502 | |||
| 503 | if (MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, k_AppPaths_7zFm, NULL, s)) | ||
| 504 | { | ||
| 505 | // RemoveQuotes(s); | ||
| 506 | if (AreEqual_Path_PrefixName(s, path, L"7zFM.exe")) | ||
| 507 | MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_AppPaths_7zFm); | ||
| 508 | } | ||
| 509 | |||
| 510 | if (MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, k_Uninstall_7zip, L"UninstallString", s)) | ||
| 511 | { | ||
| 512 | RemoveQuotes(s); | ||
| 513 | if (AreEqual_Path_PrefixName(s, path, kUninstallExe)) | ||
| 514 | MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_Uninstall_7zip); | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | |||
| 519 | static const wchar_t *GetCmdParam(const wchar_t *s) | ||
| 520 | { | ||
| 521 | unsigned pos = 0; | ||
| 522 | BoolInt quoteMode = False; | ||
| 523 | for (;; s++) | ||
| 524 | { | ||
| 525 | wchar_t c = *s; | ||
| 526 | if (c == 0 || (c == L' ' && !quoteMode)) | ||
| 527 | break; | ||
| 528 | if (c == L'\"') | ||
| 529 | { | ||
| 530 | quoteMode = !quoteMode; | ||
| 531 | continue; | ||
| 532 | } | ||
| 533 | if (pos >= ARRAY_SIZE(cmd) - 1) | ||
| 534 | exit(1); | ||
| 535 | cmd[pos++] = c; | ||
| 536 | } | ||
| 537 | cmd[pos] = 0; | ||
| 538 | return s; | ||
| 539 | } | ||
| 540 | |||
| 541 | /* | ||
| 542 | static void RemoveQuotes(wchar_t *s) | ||
| 543 | { | ||
| 544 | const wchar_t *src = s; | ||
| 545 | for (;;) | ||
| 546 | { | ||
| 547 | wchar_t c = *src++; | ||
| 548 | if (c == '\"') | ||
| 549 | continue; | ||
| 550 | *s++ = c; | ||
| 551 | if (c == 0) | ||
| 552 | return; | ||
| 553 | } | ||
| 554 | } | ||
| 555 | */ | ||
| 556 | |||
| 557 | static BoolInt DoesFileOrDirExist() | ||
| 558 | { | ||
| 559 | return (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES); | ||
| 560 | } | ||
| 561 | |||
| 562 | static BOOL RemoveFileAfterReboot2(const WCHAR *s) | ||
| 563 | { | ||
| 564 | #ifndef UNDER_CE | ||
| 565 | return MoveFileExW(s, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); | ||
| 566 | #else | ||
| 567 | UNUSED_VAR(s) | ||
| 568 | return TRUE; | ||
| 569 | #endif | ||
| 570 | } | ||
| 571 | |||
| 572 | static BOOL RemoveFileAfterReboot() | ||
| 573 | { | ||
| 574 | return RemoveFileAfterReboot2(path); | ||
| 575 | } | ||
| 576 | |||
| 577 | // #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ') | ||
| 578 | |||
| 579 | static BoolInt IsThereSpace(const wchar_t *s) | ||
| 580 | { | ||
| 581 | for (;;) | ||
| 582 | { | ||
| 583 | wchar_t c = *s++; | ||
| 584 | if (c == 0) | ||
| 585 | return False; | ||
| 586 | if (c == ' ') | ||
| 587 | return True; | ||
| 588 | } | ||
| 589 | } | ||
| 590 | |||
| 591 | static void AddPathParam(wchar_t *dest, const wchar_t *src) | ||
| 592 | { | ||
| 593 | BoolInt needQuote = IsThereSpace(src); | ||
| 594 | if (needQuote) | ||
| 595 | CatAscii(dest, "\""); | ||
| 596 | wcscat(dest, src); | ||
| 597 | if (needQuote) | ||
| 598 | CatAscii(dest, "\""); | ||
| 599 | } | ||
| 600 | |||
| 601 | |||
| 602 | |||
| 603 | static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message) | ||
| 604 | { | ||
| 605 | LPWSTR msgBuf; | ||
| 606 | if (FormatMessageW( | ||
| 607 | FORMAT_MESSAGE_ALLOCATE_BUFFER | ||
| 608 | | FORMAT_MESSAGE_FROM_SYSTEM | ||
| 609 | | FORMAT_MESSAGE_IGNORE_INSERTS, | ||
| 610 | NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0) | ||
| 611 | return False; | ||
| 612 | wcscpy(message, msgBuf); | ||
| 613 | LocalFree(msgBuf); | ||
| 614 | return True; | ||
| 615 | } | ||
| 616 | |||
| 617 | static BOOL RemoveDir() | ||
| 618 | { | ||
| 619 | DWORD attrib = GetFileAttributesW(path); | ||
| 620 | if (attrib == INVALID_FILE_ATTRIBUTES) | ||
| 621 | return TRUE; | ||
| 622 | if (RemoveDirectoryW(path)) | ||
| 623 | return TRUE; | ||
| 624 | return RemoveFileAfterReboot(); | ||
| 625 | } | ||
| 626 | |||
| 627 | |||
| 628 | |||
| 629 | |||
| 630 | |||
| 631 | #define k_Lang "Lang" | ||
| 632 | |||
| 633 | // NUM_LANG_TXT_FILES files are placed before en.ttt | ||
| 634 | #define NUM_LANG_TXT_FILES 92 | ||
| 635 | |||
| 636 | #ifdef USE_7ZIP_32_DLL | ||
| 637 | #define NUM_EXTRA_FILES_64BIT 1 | ||
| 638 | #else | ||
| 639 | #define NUM_EXTRA_FILES_64BIT 0 | ||
| 640 | #endif | ||
| 641 | |||
| 642 | #define NUM_FILES (NUM_LANG_TXT_FILES + 1 + 13 + NUM_EXTRA_FILES_64BIT) | ||
| 643 | |||
| 644 | static const char * const k_Names = | ||
| 645 | "af an ar ast az ba be bg bn br ca co cs cy da de el eo es et eu ext" | ||
| 646 | " fa fi fr fur fy ga gl gu he hi hr hu hy id io is it ja ka kaa kab kk ko ku ku-ckb ky" | ||
| 647 | " lij lt lv mk mn mng mng2 mr ms nb ne nl nn pa-in pl ps pt pt-br ro ru" | ||
| 648 | " sa si sk sl sq sr-spc sr-spl sv sw ta tg th tk tr tt ug uk uz uz-cyrl va vi yo zh-cn zh-tw" | ||
| 649 | " en.ttt" | ||
| 650 | " descript.ion" | ||
| 651 | " History.txt" | ||
| 652 | " License.txt" | ||
| 653 | " readme.txt" | ||
| 654 | " 7-zip.chm" | ||
| 655 | " 7z.sfx" | ||
| 656 | " 7zCon.sfx" | ||
| 657 | " 7z.exe" | ||
| 658 | " 7zG.exe" | ||
| 659 | " 7z.dll" | ||
| 660 | " 7zFM.exe" | ||
| 661 | #ifdef USE_7ZIP_32_DLL | ||
| 662 | " 7-zip32.dll" | ||
| 663 | #endif | ||
| 664 | " 7-zip.dll" | ||
| 665 | " Uninstall.exe"; | ||
| 666 | |||
| 667 | |||
| 668 | |||
| 669 | static int Install() | ||
| 670 | { | ||
| 671 | SRes res = SZ_OK; | ||
| 672 | WRes winRes = 0; | ||
| 673 | |||
| 674 | // BoolInt needReboot = False; | ||
| 675 | const size_t pathLen = wcslen(path); | ||
| 676 | |||
| 677 | if (!g_SilentMode) | ||
| 678 | { | ||
| 679 | ShowWindow(g_Progress_HWND, SW_SHOW); | ||
| 680 | ShowWindow(g_InfoLine_HWND, SW_SHOW); | ||
| 681 | SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, NUM_FILES); | ||
| 682 | } | ||
| 683 | |||
| 684 | { | ||
| 685 | unsigned i; | ||
| 686 | const char *curName = k_Names; | ||
| 687 | |||
| 688 | for (i = 0; *curName != 0; i++) | ||
| 689 | { | ||
| 690 | WCHAR *temp; | ||
| 691 | |||
| 692 | if (!g_SilentMode) | ||
| 693 | { | ||
| 694 | MSG msg; | ||
| 695 | |||
| 696 | // g_HWND | ||
| 697 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) | ||
| 698 | { | ||
| 699 | if (!IsDialogMessage(g_HWND, &msg)) | ||
| 700 | { | ||
| 701 | TranslateMessage(&msg); | ||
| 702 | DispatchMessage(&msg); | ||
| 703 | } | ||
| 704 | if (!g_HWND) | ||
| 705 | return 1; | ||
| 706 | } | ||
| 707 | |||
| 708 | // Sleep(1); | ||
| 709 | SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); | ||
| 710 | } | ||
| 711 | |||
| 712 | path[pathLen] = 0; | ||
| 713 | temp = path + pathLen; | ||
| 714 | |||
| 715 | if (i <= NUM_LANG_TXT_FILES) | ||
| 716 | CpyAscii(temp, k_Lang "\\"); | ||
| 717 | |||
| 718 | { | ||
| 719 | WCHAR *dest = temp + wcslen(temp); | ||
| 720 | |||
| 721 | for (;;) | ||
| 722 | { | ||
| 723 | char c = *curName; | ||
| 724 | if (c == 0) | ||
| 725 | break; | ||
| 726 | curName++; | ||
| 727 | if (c == ' ') | ||
| 728 | break; | ||
| 729 | *dest++ = (Byte)c; | ||
| 730 | } | ||
| 731 | |||
| 732 | *dest = 0; | ||
| 733 | } | ||
| 734 | |||
| 735 | if (i < NUM_LANG_TXT_FILES) | ||
| 736 | CatAscii(temp, ".txt"); | ||
| 737 | |||
| 738 | if (!g_SilentMode) | ||
| 739 | SetWindowTextW(g_InfoLine_HWND, temp); | ||
| 740 | |||
| 741 | { | ||
| 742 | DWORD attrib = GetFileAttributesW(path); | ||
| 743 | if (attrib == INVALID_FILE_ATTRIBUTES) | ||
| 744 | continue; | ||
| 745 | if (attrib & FILE_ATTRIBUTE_READONLY) | ||
| 746 | SetFileAttributesW(path, 0); | ||
| 747 | if (!DeleteFileW(path)) | ||
| 748 | { | ||
| 749 | if (!RemoveFileAfterReboot()) | ||
| 750 | { | ||
| 751 | winRes = GetLastError(); | ||
| 752 | } | ||
| 753 | /* | ||
| 754 | else | ||
| 755 | needReboot = True; | ||
| 756 | */ | ||
| 757 | } | ||
| 758 | } | ||
| 759 | } | ||
| 760 | |||
| 761 | CpyAscii(path + pathLen, k_Lang); | ||
| 762 | RemoveDir(); | ||
| 763 | |||
| 764 | path[pathLen] = 0; | ||
| 765 | RemoveDir(); | ||
| 766 | |||
| 767 | if (!g_SilentMode) | ||
| 768 | SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); | ||
| 769 | |||
| 770 | if (*curName == 0) | ||
| 771 | { | ||
| 772 | SetRegKey_Path(); | ||
| 773 | WriteCLSID(); | ||
| 774 | SetShellProgramsGroup(g_HWND); | ||
| 775 | if (!g_SilentMode) | ||
| 776 | SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is uninstalled"); | ||
| 777 | } | ||
| 778 | } | ||
| 779 | |||
| 780 | if (winRes != 0) | ||
| 781 | res = SZ_ERROR_FAIL; | ||
| 782 | |||
| 783 | if (res == SZ_OK) | ||
| 784 | { | ||
| 785 | // if (!g_SilentMode && needReboot); | ||
| 786 | return 0; | ||
| 787 | } | ||
| 788 | |||
| 789 | if (!g_SilentMode) | ||
| 790 | { | ||
| 791 | WCHAR m[MAX_PATH + 100]; | ||
| 792 | m[0] = 0; | ||
| 793 | if (winRes == 0 || !GetErrorMessage(winRes, m)) | ||
| 794 | CpyAscii(m, "ERROR"); | ||
| 795 | PrintErrorMessage("System ERROR:", m); | ||
| 796 | } | ||
| 797 | |||
| 798 | return 1; | ||
| 799 | } | ||
| 800 | |||
| 801 | |||
| 802 | static void OnClose() | ||
| 803 | { | ||
| 804 | if (g_Install_was_Pressed && !g_Finished) | ||
| 805 | { | ||
| 806 | if (MessageBoxW(g_HWND, | ||
| 807 | L"Do you want to cancel uninstallation?", | ||
| 808 | k_7zip_with_Ver_Uninstall, | ||
| 809 | MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES) | ||
| 810 | return; | ||
| 811 | } | ||
| 812 | DestroyWindow(g_HWND); | ||
| 813 | g_HWND = NULL; | ||
| 814 | } | ||
| 815 | |||
| 816 | static INT_PTR CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | ||
| 817 | { | ||
| 818 | UNUSED_VAR(lParam) | ||
| 819 | |||
| 820 | switch (message) | ||
| 821 | { | ||
| 822 | case WM_INITDIALOG: | ||
| 823 | g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH); | ||
| 824 | g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE); | ||
| 825 | g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS); | ||
| 826 | |||
| 827 | SetWindowTextW(hwnd, k_7zip_with_Ver_Uninstall); | ||
| 828 | SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path); | ||
| 829 | |||
| 830 | ShowWindow(g_Progress_HWND, SW_HIDE); | ||
| 831 | ShowWindow(g_InfoLine_HWND, SW_HIDE); | ||
| 832 | |||
| 833 | break; | ||
| 834 | |||
| 835 | case WM_COMMAND: | ||
| 836 | switch (LOWORD(wParam)) | ||
| 837 | { | ||
| 838 | case IDOK: | ||
| 839 | { | ||
| 840 | if (g_Finished) | ||
| 841 | { | ||
| 842 | OnClose(); | ||
| 843 | break; | ||
| 844 | } | ||
| 845 | if (!g_Install_was_Pressed) | ||
| 846 | { | ||
| 847 | SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE); | ||
| 848 | |||
| 849 | EnableWindow(g_Path_HWND, FALSE); | ||
| 850 | EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); | ||
| 851 | |||
| 852 | g_Install_was_Pressed = True; | ||
| 853 | return TRUE; | ||
| 854 | } | ||
| 855 | break; | ||
| 856 | } | ||
| 857 | |||
| 858 | case IDCANCEL: | ||
| 859 | { | ||
| 860 | OnClose(); | ||
| 861 | break; | ||
| 862 | } | ||
| 863 | |||
| 864 | default: return FALSE; | ||
| 865 | } | ||
| 866 | break; | ||
| 867 | |||
| 868 | case WM_CLOSE: | ||
| 869 | OnClose(); | ||
| 870 | break; | ||
| 871 | /* | ||
| 872 | case WM_DESTROY: | ||
| 873 | PostQuitMessage(0); | ||
| 874 | return TRUE; | ||
| 875 | */ | ||
| 876 | default: | ||
| 877 | return FALSE; | ||
| 878 | } | ||
| 879 | |||
| 880 | return TRUE; | ||
| 881 | } | ||
| 882 | |||
| 883 | |||
| 884 | int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, | ||
| 885 | #ifdef UNDER_CE | ||
| 886 | LPWSTR | ||
| 887 | #else | ||
| 888 | LPSTR | ||
| 889 | #endif | ||
| 890 | lpCmdLine, int nCmdShow) | ||
| 891 | { | ||
| 892 | const wchar_t *cmdParams; | ||
| 893 | BoolInt useTemp = True; | ||
| 894 | |||
| 895 | UNUSED_VAR(hPrevInstance) | ||
| 896 | UNUSED_VAR(lpCmdLine) | ||
| 897 | UNUSED_VAR(nCmdShow) | ||
| 898 | |||
| 899 | #ifndef UNDER_CE | ||
| 900 | CoInitialize(NULL); | ||
| 901 | #endif | ||
| 902 | |||
| 903 | #ifndef UNDER_CE | ||
| 904 | func_RegDeleteKeyExW = (Func_RegDeleteKeyExW) | ||
| 905 | GetProcAddress(GetModuleHandleW(L"advapi32.dll"), "RegDeleteKeyExW"); | ||
| 906 | #endif | ||
| 907 | |||
| 908 | { | ||
| 909 | const wchar_t *s = GetCommandLineW(); | ||
| 910 | |||
| 911 | #ifndef UNDER_CE | ||
| 912 | s = GetCmdParam(s); | ||
| 913 | #endif | ||
| 914 | |||
| 915 | cmdParams = s; | ||
| 916 | |||
| 917 | for (;;) | ||
| 918 | { | ||
| 919 | { | ||
| 920 | wchar_t c = *s; | ||
| 921 | if (c == 0) | ||
| 922 | break; | ||
| 923 | if (c == ' ') | ||
| 924 | { | ||
| 925 | s++; | ||
| 926 | continue; | ||
| 927 | } | ||
| 928 | } | ||
| 929 | |||
| 930 | { | ||
| 931 | const wchar_t *s2 = GetCmdParam(s); | ||
| 932 | BoolInt error = True; | ||
| 933 | if (cmd[0] == '/') | ||
| 934 | { | ||
| 935 | if (cmd[1] == 'S') | ||
| 936 | { | ||
| 937 | if (cmd[2] == 0) | ||
| 938 | { | ||
| 939 | g_SilentMode = True; | ||
| 940 | error = False; | ||
| 941 | } | ||
| 942 | } | ||
| 943 | else if (cmd[1] == 'N') | ||
| 944 | { | ||
| 945 | if (cmd[2] == 0) | ||
| 946 | { | ||
| 947 | useTemp = False; | ||
| 948 | error = False; | ||
| 949 | } | ||
| 950 | } | ||
| 951 | else if (cmd[1] == 'D' && cmd[2] == '=') | ||
| 952 | { | ||
| 953 | wcscpy(workDir, cmd + 3); | ||
| 954 | // RemoveQuotes(workDir); | ||
| 955 | useTemp = False; | ||
| 956 | error = False; | ||
| 957 | } | ||
| 958 | } | ||
| 959 | s = s2; | ||
| 960 | if (error && cmdError[0] == 0) | ||
| 961 | wcscpy(cmdError, cmd); | ||
| 962 | } | ||
| 963 | } | ||
| 964 | |||
| 965 | if (cmdError[0] != 0) | ||
| 966 | { | ||
| 967 | if (!g_SilentMode) | ||
| 968 | PrintErrorMessage("Unsupported command:", cmdError); | ||
| 969 | return 1; | ||
| 970 | } | ||
| 971 | } | ||
| 972 | |||
| 973 | { | ||
| 974 | wchar_t *name; | ||
| 975 | DWORD len = GetModuleFileNameW(NULL, modulePath, MAX_PATH); | ||
| 976 | if (len == 0 || len > MAX_PATH) | ||
| 977 | return 1; | ||
| 978 | |||
| 979 | name = NULL; | ||
| 980 | wcscpy(modulePrefix, modulePath); | ||
| 981 | |||
| 982 | { | ||
| 983 | wchar_t *s = modulePrefix; | ||
| 984 | for (;;) | ||
| 985 | { | ||
| 986 | wchar_t c = *s++; | ||
| 987 | if (c == 0) | ||
| 988 | break; | ||
| 989 | if (c == WCHAR_PATH_SEPARATOR) | ||
| 990 | name = s; | ||
| 991 | } | ||
| 992 | } | ||
| 993 | |||
| 994 | if (!name) | ||
| 995 | return 1; | ||
| 996 | |||
| 997 | if (!AreStringsEqual_NoCase(name, kUninstallExe)) | ||
| 998 | useTemp = False; | ||
| 999 | |||
| 1000 | *name = 0; // keep only prefix for modulePrefix | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | |||
| 1004 | if (useTemp) | ||
| 1005 | { | ||
| 1006 | DWORD winRes = GetTempPathW(MAX_PATH, path); | ||
| 1007 | |||
| 1008 | // GetTempPath: the returned string ends with a backslash | ||
| 1009 | /* | ||
| 1010 | { | ||
| 1011 | WCHAR s[MAX_PATH + 1]; | ||
| 1012 | wcscpy(s, path); | ||
| 1013 | GetLongPathNameW(s, path, MAX_PATH); | ||
| 1014 | } | ||
| 1015 | */ | ||
| 1016 | |||
| 1017 | if (winRes != 0 && winRes <= MAX_PATH + 1 | ||
| 1018 | && !IsString1PrefixedByString2_NoCase(modulePrefix, path)) | ||
| 1019 | { | ||
| 1020 | unsigned i; | ||
| 1021 | DWORD d; | ||
| 1022 | |||
| 1023 | const size_t pathLen = wcslen(path); | ||
| 1024 | d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); | ||
| 1025 | |||
| 1026 | for (i = 0; i < 100; i++, d += GetTickCount()) | ||
| 1027 | { | ||
| 1028 | CpyAscii(path + pathLen, "7z"); | ||
| 1029 | |||
| 1030 | { | ||
| 1031 | wchar_t *s = path + wcslen(path); | ||
| 1032 | UInt32 value = d; | ||
| 1033 | unsigned k; | ||
| 1034 | for (k = 0; k < 8; k++) | ||
| 1035 | { | ||
| 1036 | unsigned t = value & 0xF; | ||
| 1037 | value >>= 4; | ||
| 1038 | s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10))); | ||
| 1039 | } | ||
| 1040 | s[k] = 0; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | if (DoesFileOrDirExist()) | ||
| 1044 | continue; | ||
| 1045 | if (CreateDirectoryW(path, NULL)) | ||
| 1046 | { | ||
| 1047 | CatAscii(path, STRING_PATH_SEPARATOR); | ||
| 1048 | wcscpy(tempPath, path); | ||
| 1049 | break; | ||
| 1050 | } | ||
| 1051 | if (GetLastError() != ERROR_ALREADY_EXISTS) | ||
| 1052 | break; | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | if (tempPath[0] != 0) | ||
| 1056 | { | ||
| 1057 | wcscpy(copyPath, tempPath); | ||
| 1058 | CatAscii(copyPath, "Uninst.exe"); // we need not "Uninstall.exe" here | ||
| 1059 | |||
| 1060 | if (CopyFileW(modulePath, copyPath, TRUE)) | ||
| 1061 | { | ||
| 1062 | RemoveFileAfterReboot2(copyPath); | ||
| 1063 | RemoveFileAfterReboot2(tempPath); | ||
| 1064 | |||
| 1065 | { | ||
| 1066 | STARTUPINFOW si; | ||
| 1067 | PROCESS_INFORMATION pi; | ||
| 1068 | cmdLine[0] = 0; | ||
| 1069 | |||
| 1070 | // maybe CreateProcess supports path with spaces even without quotes. | ||
| 1071 | AddPathParam(cmdLine, copyPath); | ||
| 1072 | CatAscii(cmdLine, " /N /D="); | ||
| 1073 | AddPathParam(cmdLine, modulePrefix); | ||
| 1074 | |||
| 1075 | if (cmdParams[0] != 0 && wcslen(cmdParams) < MAX_PATH * 2 + 10) | ||
| 1076 | wcscat(cmdLine, cmdParams); | ||
| 1077 | |||
| 1078 | memset(&si, 0, sizeof(si)); | ||
| 1079 | si.cb = sizeof(si); | ||
| 1080 | |||
| 1081 | if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, tempPath, &si, &pi)) | ||
| 1082 | { | ||
| 1083 | CloseHandle(pi.hThread); | ||
| 1084 | if (pi.hProcess) | ||
| 1085 | { | ||
| 1086 | CloseHandle(pi.hProcess); | ||
| 1087 | return 0; | ||
| 1088 | } | ||
| 1089 | } | ||
| 1090 | } | ||
| 1091 | } | ||
| 1092 | } | ||
| 1093 | } | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | wcscpy(path, modulePrefix); | ||
| 1097 | |||
| 1098 | if (workDir[0] != 0) | ||
| 1099 | { | ||
| 1100 | wcscpy(path, workDir); | ||
| 1101 | NormalizePrefix(path); | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | /* | ||
| 1105 | if (path[0] == 0) | ||
| 1106 | { | ||
| 1107 | HKEY key = 0; | ||
| 1108 | BoolInt ok = False; | ||
| 1109 | LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key); | ||
| 1110 | if (res == ERROR_SUCCESS) | ||
| 1111 | { | ||
| 1112 | ok = MyRegistry_QueryString(key, k_Reg_Path32, path); | ||
| 1113 | // ok = MyRegistry_QueryString(key, k_Reg_Path, path); | ||
| 1114 | RegCloseKey(key); | ||
| 1115 | } | ||
| 1116 | } | ||
| 1117 | */ | ||
| 1118 | |||
| 1119 | |||
| 1120 | if (g_SilentMode) | ||
| 1121 | return Install(); | ||
| 1122 | |||
| 1123 | { | ||
| 1124 | int retCode = 1; | ||
| 1125 | g_HWND = CreateDialog( | ||
| 1126 | hInstance, | ||
| 1127 | // GetModuleHandle(NULL), | ||
| 1128 | MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc); | ||
| 1129 | if (!g_HWND) | ||
| 1130 | return 1; | ||
| 1131 | |||
| 1132 | { | ||
| 1133 | HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); | ||
| 1134 | // SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon); | ||
| 1135 | SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon); | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | { | ||
| 1139 | BOOL bRet; | ||
| 1140 | MSG msg; | ||
| 1141 | |||
| 1142 | while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) | ||
| 1143 | { | ||
| 1144 | if (bRet == -1) | ||
| 1145 | return retCode; | ||
| 1146 | if (!g_HWND) | ||
| 1147 | return retCode; | ||
| 1148 | |||
| 1149 | if (!IsDialogMessage(g_HWND, &msg)) | ||
| 1150 | { | ||
| 1151 | TranslateMessage(&msg); | ||
| 1152 | DispatchMessage(&msg); | ||
| 1153 | } | ||
| 1154 | if (!g_HWND) | ||
| 1155 | return retCode; | ||
| 1156 | |||
| 1157 | if (g_Install_was_Pressed && !g_Finished) | ||
| 1158 | { | ||
| 1159 | retCode = Install(); | ||
| 1160 | g_Finished = True; | ||
| 1161 | if (retCode != 0) | ||
| 1162 | break; | ||
| 1163 | if (!g_HWND) | ||
| 1164 | break; | ||
| 1165 | { | ||
| 1166 | SetDlgItemTextW(g_HWND, IDOK, L"Close"); | ||
| 1167 | EnableWindow(GetDlgItem(g_HWND, IDOK), TRUE); | ||
| 1168 | EnableWindow(GetDlgItem(g_HWND, IDCANCEL), FALSE); | ||
| 1169 | SendMessage(g_HWND, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(g_HWND, IDOK), TRUE); | ||
| 1170 | } | ||
| 1171 | } | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | if (g_HWND) | ||
| 1175 | { | ||
| 1176 | DestroyWindow(g_HWND); | ||
| 1177 | g_HWND = NULL; | ||
| 1178 | } | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | return retCode; | ||
| 1182 | } | ||
| 1183 | } | ||
diff --git a/C/Util/7zipUninstall/7zipUninstall.dsp b/C/Util/7zipUninstall/7zipUninstall.dsp new file mode 100644 index 0000000..cc7b6b6 --- /dev/null +++ b/C/Util/7zipUninstall/7zipUninstall.dsp | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | # Microsoft Developer Studio Project File - Name="7zipUninstall" - Package Owner=<4> | ||
| 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 | ||
| 3 | # ** DO NOT EDIT ** | ||
| 4 | |||
| 5 | # TARGTYPE "Win32 (x86) Application" 0x0101 | ||
| 6 | |||
| 7 | CFG=7zipUninstall - Win32 Debug | ||
| 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, | ||
| 9 | !MESSAGE use the Export Makefile command and run | ||
| 10 | !MESSAGE | ||
| 11 | !MESSAGE NMAKE /f "7zipUninstall.mak". | ||
| 12 | !MESSAGE | ||
| 13 | !MESSAGE You can specify a configuration when running NMAKE | ||
| 14 | !MESSAGE by defining the macro CFG on the command line. For example: | ||
| 15 | !MESSAGE | ||
| 16 | !MESSAGE NMAKE /f "7zipUninstall.mak" CFG="7zipUninstall - Win32 Debug" | ||
| 17 | !MESSAGE | ||
| 18 | !MESSAGE Possible choices for configuration are: | ||
| 19 | !MESSAGE | ||
| 20 | !MESSAGE "7zipUninstall - Win32 Release" (based on "Win32 (x86) Application") | ||
| 21 | !MESSAGE "7zipUninstall - Win32 Debug" (based on "Win32 (x86) Application") | ||
| 22 | !MESSAGE | ||
| 23 | |||
| 24 | # Begin Project | ||
| 25 | # PROP AllowPerConfigDependencies 0 | ||
| 26 | # PROP Scc_ProjName "" | ||
| 27 | # PROP Scc_LocalPath "" | ||
| 28 | CPP=cl.exe | ||
| 29 | MTL=midl.exe | ||
| 30 | RSC=rc.exe | ||
| 31 | |||
| 32 | !IF "$(CFG)" == "7zipUninstall - Win32 Release" | ||
| 33 | |||
| 34 | # PROP BASE Use_MFC 0 | ||
| 35 | # PROP BASE Use_Debug_Libraries 0 | ||
| 36 | # PROP BASE Output_Dir "Release" | ||
| 37 | # PROP BASE Intermediate_Dir "Release" | ||
| 38 | # PROP BASE Target_Dir "" | ||
| 39 | # PROP Use_MFC 0 | ||
| 40 | # PROP Use_Debug_Libraries 0 | ||
| 41 | # PROP Output_Dir "Release" | ||
| 42 | # PROP Intermediate_Dir "Release" | ||
| 43 | # PROP Ignore_Export_Lib 0 | ||
| 44 | # PROP Target_Dir "" | ||
| 45 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c | ||
| 46 | # ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /FAcs /Yu"Precomp.h" /FD /GF /c | ||
| 47 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | ||
| 48 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | ||
| 49 | # ADD BASE RSC /l 0x419 /d "NDEBUG" | ||
| 50 | # ADD RSC /l 0x419 /d "NDEBUG" | ||
| 51 | BSC32=bscmake.exe | ||
| 52 | # ADD BASE BSC32 /nologo | ||
| 53 | # ADD BSC32 /nologo | ||
| 54 | LINK32=link.exe | ||
| 55 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 | ||
| 56 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/Uninstall.exe" | ||
| 57 | |||
| 58 | !ELSEIF "$(CFG)" == "7zipUninstall - Win32 Debug" | ||
| 59 | |||
| 60 | # PROP BASE Use_MFC 0 | ||
| 61 | # PROP BASE Use_Debug_Libraries 1 | ||
| 62 | # PROP BASE Output_Dir "Debug" | ||
| 63 | # PROP BASE Intermediate_Dir "Debug" | ||
| 64 | # PROP BASE Target_Dir "" | ||
| 65 | # PROP Use_MFC 0 | ||
| 66 | # PROP Use_Debug_Libraries 1 | ||
| 67 | # PROP Output_Dir "Debug" | ||
| 68 | # PROP Intermediate_Dir "Debug" | ||
| 69 | # PROP Ignore_Export_Lib 0 | ||
| 70 | # PROP Target_Dir "" | ||
| 71 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c | ||
| 72 | # ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /GZ /c | ||
| 73 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | ||
| 74 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | ||
| 75 | # ADD BASE RSC /l 0x419 /d "_DEBUG" | ||
| 76 | # ADD RSC /l 0x419 /d "_DEBUG" | ||
| 77 | BSC32=bscmake.exe | ||
| 78 | # ADD BASE BSC32 /nologo | ||
| 79 | # ADD BSC32 /nologo | ||
| 80 | LINK32=link.exe | ||
| 81 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept | ||
| 82 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug/Uninstall.exe" /pdbtype:sept | ||
| 83 | |||
| 84 | !ENDIF | ||
| 85 | |||
| 86 | # Begin Target | ||
| 87 | |||
| 88 | # Name "7zipUninstall - Win32 Release" | ||
| 89 | # Name "7zipUninstall - Win32 Debug" | ||
| 90 | # Begin Group "Common" | ||
| 91 | |||
| 92 | # PROP Default_Filter "" | ||
| 93 | # Begin Source File | ||
| 94 | |||
| 95 | SOURCE=..\..\7zTypes.h | ||
| 96 | # End Source File | ||
| 97 | # Begin Source File | ||
| 98 | |||
| 99 | SOURCE=..\..\7zVersion.h | ||
| 100 | # End Source File | ||
| 101 | # End Group | ||
| 102 | # Begin Group "Spec" | ||
| 103 | |||
| 104 | # PROP Default_Filter "" | ||
| 105 | # Begin Source File | ||
| 106 | |||
| 107 | SOURCE=.\Precomp.c | ||
| 108 | # ADD CPP /Yc"Precomp.h" | ||
| 109 | # End Source File | ||
| 110 | # Begin Source File | ||
| 111 | |||
| 112 | SOURCE=.\Precomp.h | ||
| 113 | # End Source File | ||
| 114 | # End Group | ||
| 115 | # Begin Source File | ||
| 116 | |||
| 117 | SOURCE=.\7zipUninstall.c | ||
| 118 | # End Source File | ||
| 119 | # Begin Source File | ||
| 120 | |||
| 121 | SOURCE=.\resource.rc | ||
| 122 | # End Source File | ||
| 123 | # End Target | ||
| 124 | # End Project | ||
diff --git a/C/Util/7zipUninstall/7zipUninstall.dsw b/C/Util/7zipUninstall/7zipUninstall.dsw new file mode 100644 index 0000000..2873eda --- /dev/null +++ b/C/Util/7zipUninstall/7zipUninstall.dsw | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 | ||
| 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! | ||
| 3 | |||
| 4 | ############################################################################### | ||
| 5 | |||
| 6 | Project: "7zipUninstall"=.\7zipUninstall.dsp - Package Owner=<4> | ||
| 7 | |||
| 8 | Package=<5> | ||
| 9 | {{{ | ||
| 10 | }}} | ||
| 11 | |||
| 12 | Package=<4> | ||
| 13 | {{{ | ||
| 14 | }}} | ||
| 15 | |||
| 16 | ############################################################################### | ||
| 17 | |||
| 18 | Global: | ||
| 19 | |||
| 20 | Package=<5> | ||
| 21 | {{{ | ||
| 22 | }}} | ||
| 23 | |||
| 24 | Package=<3> | ||
| 25 | {{{ | ||
| 26 | }}} | ||
| 27 | |||
| 28 | ############################################################################### | ||
| 29 | |||
diff --git a/C/Util/7zipUninstall/7zipUninstall.ico b/C/Util/7zipUninstall/7zipUninstall.ico new file mode 100644 index 0000000..19eb20c --- /dev/null +++ b/C/Util/7zipUninstall/7zipUninstall.ico | |||
| Binary files differ | |||
diff --git a/C/Util/7zipUninstall/7zipUninstall.manifest b/C/Util/7zipUninstall/7zipUninstall.manifest new file mode 100644 index 0000000..a601443 --- /dev/null +++ b/C/Util/7zipUninstall/7zipUninstall.manifest | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
| 2 | <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> | ||
| 3 | <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.Uninstall" type="win32"/> | ||
| 4 | <description>7-Zip Uninstaller</description> | ||
| 5 | <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges> | ||
| 6 | <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/> | ||
| 7 | </requestedPrivileges></security></trustInfo> | ||
| 8 | <dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly></dependency> | ||
| 9 | <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application> | ||
| 10 | <!-- Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> | ||
| 11 | <!-- Win 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> | ||
| 12 | <!-- Win 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> | ||
| 13 | <!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> | ||
| 14 | <!-- Win 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> | ||
| 15 | </application></compatibility> | ||
| 16 | <asmv3:application><asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> | ||
| 17 | <dpiAware>true</dpiAware></asmv3:windowsSettings></asmv3:application> | ||
| 18 | </assembly> | ||
diff --git a/C/Util/7zipUninstall/Precomp.c b/C/Util/7zipUninstall/Precomp.c new file mode 100644 index 0000000..01605e3 --- /dev/null +++ b/C/Util/7zipUninstall/Precomp.c | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | /* Precomp.c -- StdAfx | ||
| 2 | 2013-01-21 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
diff --git a/C/Util/7zipUninstall/Precomp.h b/C/Util/7zipUninstall/Precomp.h new file mode 100644 index 0000000..4c90d47 --- /dev/null +++ b/C/Util/7zipUninstall/Precomp.h | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | /* Precomp.h -- StdAfx | ||
| 2 | 2015-05-24 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_PRECOMP_H | ||
| 5 | #define __7Z_PRECOMP_H | ||
| 6 | |||
| 7 | #include "../../Compiler.h" | ||
| 8 | |||
| 9 | #include "../../7zTypes.h" | ||
| 10 | |||
| 11 | #endif | ||
diff --git a/C/Util/7zipUninstall/makefile b/C/Util/7zipUninstall/makefile new file mode 100644 index 0000000..60c2fe2 --- /dev/null +++ b/C/Util/7zipUninstall/makefile | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | PROG = 7zipUninstall.exe | ||
| 2 | MY_FIXED = 1 | ||
| 3 | |||
| 4 | !IFDEF _64BIT_INSTALLER | ||
| 5 | CFLAGS = $(CFLAGS) -D_64BIT_INSTALLER | ||
| 6 | !ENDIF | ||
| 7 | |||
| 8 | MAIN_OBJS = \ | ||
| 9 | $O\7zipUninstall.obj \ | ||
| 10 | |||
| 11 | OBJS = \ | ||
| 12 | $(MAIN_OBJS) \ | ||
| 13 | $O\resource.res | ||
| 14 | |||
| 15 | !include "../../../CPP/Build.mak" | ||
| 16 | |||
| 17 | $(MAIN_OBJS): $(*B).c | ||
| 18 | $(COMPL_O1) | ||
diff --git a/C/Util/7zipUninstall/resource.h b/C/Util/7zipUninstall/resource.h new file mode 100644 index 0000000..b5c33ff --- /dev/null +++ b/C/Util/7zipUninstall/resource.h | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #define IDD_INSTALL 100 | ||
| 2 | |||
| 3 | #define IDT_EXTRACT_EXTRACT_TO 110 | ||
| 4 | #define IDE_EXTRACT_PATH 111 | ||
| 5 | |||
| 6 | #define IDT_CUR_FILE 113 | ||
| 7 | #define IDC_PROGRESS 114 | ||
| 8 | |||
| 9 | #define IDI_ICON 1 | ||
diff --git a/C/Util/7zipUninstall/resource.rc b/C/Util/7zipUninstall/resource.rc new file mode 100644 index 0000000..00bdcc0 --- /dev/null +++ b/C/Util/7zipUninstall/resource.rc | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #include <winnt.h> | ||
| 2 | #include <WinUser.h> | ||
| 3 | #include <CommCtrl.h> | ||
| 4 | |||
| 5 | #define USE_COPYRIGHT_CR | ||
| 6 | #include "../../7zVersion.rc" | ||
| 7 | #include "resource.h" | ||
| 8 | |||
| 9 | MY_VERSION_INFO(MY_VFT_APP, "7-Zip Uninstaller", "Uninstall", "Uninstall.exe") | ||
| 10 | |||
| 11 | 1 ICON "7zipUninstall.ico" | ||
| 12 | |||
| 13 | #define xc 184 | ||
| 14 | #define yc 96 | ||
| 15 | |||
| 16 | #define m 8 | ||
| 17 | #define bxs 64 | ||
| 18 | #define bys 16 | ||
| 19 | |||
| 20 | |||
| 21 | #define xs (xc + m + m) | ||
| 22 | #define ys (yc + m + m) | ||
| 23 | |||
| 24 | #define bx1 (xs - m - bxs) | ||
| 25 | #define bx2 (bx1 - m - bxs) | ||
| 26 | |||
| 27 | #define by (ys - m - bys) | ||
| 28 | |||
| 29 | IDD_INSTALL DIALOG 0, 0, xs, ys | ||
| 30 | STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE | ||
| 31 | CAPTION "Uninstall 7-Zip" | ||
| 32 | FONT 8, "MS Shell Dlg" | ||
| 33 | BEGIN | ||
| 34 | LTEXT "Uninstall from:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8 | ||
| 35 | EDITTEXT IDE_EXTRACT_PATH, m, 21, xc, 14, ES_AUTOHSCROLL | WS_DISABLED | ||
| 36 | |||
| 37 | |||
| 38 | LTEXT "", IDT_CUR_FILE, m, 50, xc, 8 | ||
| 39 | CONTROL "", IDC_PROGRESS, "msctls_progress32", WS_BORDER, m, 64, xc, 10 | ||
| 40 | |||
| 41 | DEFPUSHBUTTON "&Uninstall", IDOK, bx2, by, bxs, bys, WS_GROUP | ||
| 42 | PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys | ||
| 43 | END | ||
| 44 | |||
| 45 | #ifndef UNDER_CE | ||
| 46 | 1 24 MOVEABLE PURE "7zipUninstall.manifest" | ||
| 47 | #endif | ||
diff --git a/C/Util/Lzma/LzmaUtil.c b/C/Util/Lzma/LzmaUtil.c new file mode 100644 index 0000000..62a5907 --- /dev/null +++ b/C/Util/Lzma/LzmaUtil.c | |||
| @@ -0,0 +1,286 @@ | |||
| 1 | /* LzmaUtil.c -- Test application for LZMA compression | ||
| 2 | 2021-11-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "../../Precomp.h" | ||
| 5 | |||
| 6 | #include <stdio.h> | ||
| 7 | #include <stdlib.h> | ||
| 8 | #include <string.h> | ||
| 9 | |||
| 10 | #include "../../CpuArch.h" | ||
| 11 | |||
| 12 | #include "../../Alloc.h" | ||
| 13 | #include "../../7zFile.h" | ||
| 14 | #include "../../7zVersion.h" | ||
| 15 | #include "../../LzFind.h" | ||
| 16 | #include "../../LzmaDec.h" | ||
| 17 | #include "../../LzmaEnc.h" | ||
| 18 | |||
| 19 | static const char * const kCantReadMessage = "Cannot read input file"; | ||
| 20 | static const char * const kCantWriteMessage = "Cannot write output file"; | ||
| 21 | static const char * const kCantAllocateMessage = "Cannot allocate memory"; | ||
| 22 | static const char * const kDataErrorMessage = "Data error"; | ||
| 23 | |||
| 24 | static void PrintHelp(char *buffer) | ||
| 25 | { | ||
| 26 | strcat(buffer, | ||
| 27 | "\nLZMA-C " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n" | ||
| 28 | "Usage: lzma <e|d> inputFile outputFile\n" | ||
| 29 | " e: encode file\n" | ||
| 30 | " d: decode file\n"); | ||
| 31 | } | ||
| 32 | |||
| 33 | static int PrintError(char *buffer, const char *message) | ||
| 34 | { | ||
| 35 | strcat(buffer, "\nError: "); | ||
| 36 | strcat(buffer, message); | ||
| 37 | strcat(buffer, "\n"); | ||
| 38 | return 1; | ||
| 39 | } | ||
| 40 | |||
| 41 | static int PrintError_WRes(char *buffer, const char *message, WRes wres) | ||
| 42 | { | ||
| 43 | strcat(buffer, "\nError: "); | ||
| 44 | strcat(buffer, message); | ||
| 45 | sprintf(buffer + strlen(buffer), "\nSystem error code: %d", (unsigned)wres); | ||
| 46 | #ifndef _WIN32 | ||
| 47 | { | ||
| 48 | const char *s = strerror(wres); | ||
| 49 | if (s) | ||
| 50 | sprintf(buffer + strlen(buffer), " : %s", s); | ||
| 51 | } | ||
| 52 | #endif | ||
| 53 | strcat(buffer, "\n"); | ||
| 54 | return 1; | ||
| 55 | } | ||
| 56 | |||
| 57 | static int PrintErrorNumber(char *buffer, SRes val) | ||
| 58 | { | ||
| 59 | sprintf(buffer + strlen(buffer), "\n7-Zip error code: %d\n", (unsigned)val); | ||
| 60 | return 1; | ||
| 61 | } | ||
| 62 | |||
| 63 | static int PrintUserError(char *buffer) | ||
| 64 | { | ||
| 65 | return PrintError(buffer, "Incorrect command"); | ||
| 66 | } | ||
| 67 | |||
| 68 | |||
| 69 | #define IN_BUF_SIZE (1 << 16) | ||
| 70 | #define OUT_BUF_SIZE (1 << 16) | ||
| 71 | |||
| 72 | |||
| 73 | static SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream, | ||
| 74 | UInt64 unpackSize) | ||
| 75 | { | ||
| 76 | int thereIsSize = (unpackSize != (UInt64)(Int64)-1); | ||
| 77 | Byte inBuf[IN_BUF_SIZE]; | ||
| 78 | Byte outBuf[OUT_BUF_SIZE]; | ||
| 79 | size_t inPos = 0, inSize = 0, outPos = 0; | ||
| 80 | LzmaDec_Init(state); | ||
| 81 | for (;;) | ||
| 82 | { | ||
| 83 | if (inPos == inSize) | ||
| 84 | { | ||
| 85 | inSize = IN_BUF_SIZE; | ||
| 86 | RINOK(inStream->Read(inStream, inBuf, &inSize)); | ||
| 87 | inPos = 0; | ||
| 88 | } | ||
| 89 | { | ||
| 90 | SRes res; | ||
| 91 | SizeT inProcessed = inSize - inPos; | ||
| 92 | SizeT outProcessed = OUT_BUF_SIZE - outPos; | ||
| 93 | ELzmaFinishMode finishMode = LZMA_FINISH_ANY; | ||
| 94 | ELzmaStatus status; | ||
| 95 | if (thereIsSize && outProcessed > unpackSize) | ||
| 96 | { | ||
| 97 | outProcessed = (SizeT)unpackSize; | ||
| 98 | finishMode = LZMA_FINISH_END; | ||
| 99 | } | ||
| 100 | |||
| 101 | res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed, | ||
| 102 | inBuf + inPos, &inProcessed, finishMode, &status); | ||
| 103 | inPos += inProcessed; | ||
| 104 | outPos += outProcessed; | ||
| 105 | unpackSize -= outProcessed; | ||
| 106 | |||
| 107 | if (outStream) | ||
| 108 | if (outStream->Write(outStream, outBuf, outPos) != outPos) | ||
| 109 | return SZ_ERROR_WRITE; | ||
| 110 | |||
| 111 | outPos = 0; | ||
| 112 | |||
| 113 | if (res != SZ_OK || (thereIsSize && unpackSize == 0)) | ||
| 114 | return res; | ||
| 115 | |||
| 116 | if (inProcessed == 0 && outProcessed == 0) | ||
| 117 | { | ||
| 118 | if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK) | ||
| 119 | return SZ_ERROR_DATA; | ||
| 120 | return res; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | |||
| 127 | static SRes Decode(ISeqOutStream *outStream, ISeqInStream *inStream) | ||
| 128 | { | ||
| 129 | UInt64 unpackSize; | ||
| 130 | int i; | ||
| 131 | SRes res = 0; | ||
| 132 | |||
| 133 | CLzmaDec state; | ||
| 134 | |||
| 135 | /* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */ | ||
| 136 | unsigned char header[LZMA_PROPS_SIZE + 8]; | ||
| 137 | |||
| 138 | /* Read and parse header */ | ||
| 139 | |||
| 140 | RINOK(SeqInStream_Read(inStream, header, sizeof(header))); | ||
| 141 | |||
| 142 | unpackSize = 0; | ||
| 143 | for (i = 0; i < 8; i++) | ||
| 144 | unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8); | ||
| 145 | |||
| 146 | LzmaDec_Construct(&state); | ||
| 147 | RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc)); | ||
| 148 | res = Decode2(&state, outStream, inStream, unpackSize); | ||
| 149 | LzmaDec_Free(&state, &g_Alloc); | ||
| 150 | return res; | ||
| 151 | } | ||
| 152 | |||
| 153 | static SRes Encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize, char *rs) | ||
| 154 | { | ||
| 155 | CLzmaEncHandle enc; | ||
| 156 | SRes res; | ||
| 157 | CLzmaEncProps props; | ||
| 158 | |||
| 159 | UNUSED_VAR(rs); | ||
| 160 | |||
| 161 | enc = LzmaEnc_Create(&g_Alloc); | ||
| 162 | if (enc == 0) | ||
| 163 | return SZ_ERROR_MEM; | ||
| 164 | |||
| 165 | LzmaEncProps_Init(&props); | ||
| 166 | res = LzmaEnc_SetProps(enc, &props); | ||
| 167 | |||
| 168 | if (res == SZ_OK) | ||
| 169 | { | ||
| 170 | Byte header[LZMA_PROPS_SIZE + 8]; | ||
| 171 | size_t headerSize = LZMA_PROPS_SIZE; | ||
| 172 | int i; | ||
| 173 | |||
| 174 | res = LzmaEnc_WriteProperties(enc, header, &headerSize); | ||
| 175 | for (i = 0; i < 8; i++) | ||
| 176 | header[headerSize++] = (Byte)(fileSize >> (8 * i)); | ||
| 177 | if (outStream->Write(outStream, header, headerSize) != headerSize) | ||
| 178 | res = SZ_ERROR_WRITE; | ||
| 179 | else | ||
| 180 | { | ||
| 181 | if (res == SZ_OK) | ||
| 182 | res = LzmaEnc_Encode(enc, outStream, inStream, NULL, &g_Alloc, &g_Alloc); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); | ||
| 186 | return res; | ||
| 187 | } | ||
| 188 | |||
| 189 | |||
| 190 | static int main2(int numArgs, const char *args[], char *rs) | ||
| 191 | { | ||
| 192 | CFileSeqInStream inStream; | ||
| 193 | CFileOutStream outStream; | ||
| 194 | char c; | ||
| 195 | int res; | ||
| 196 | int encodeMode; | ||
| 197 | BoolInt useOutFile = False; | ||
| 198 | |||
| 199 | LzFindPrepare(); | ||
| 200 | |||
| 201 | FileSeqInStream_CreateVTable(&inStream); | ||
| 202 | File_Construct(&inStream.file); | ||
| 203 | inStream.wres = 0; | ||
| 204 | |||
| 205 | FileOutStream_CreateVTable(&outStream); | ||
| 206 | File_Construct(&outStream.file); | ||
| 207 | outStream.wres = 0; | ||
| 208 | |||
| 209 | if (numArgs == 1) | ||
| 210 | { | ||
| 211 | PrintHelp(rs); | ||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | |||
| 215 | if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1) | ||
| 216 | return PrintUserError(rs); | ||
| 217 | |||
| 218 | c = args[1][0]; | ||
| 219 | encodeMode = (c == 'e' || c == 'E'); | ||
| 220 | if (!encodeMode && c != 'd' && c != 'D') | ||
| 221 | return PrintUserError(rs); | ||
| 222 | |||
| 223 | { | ||
| 224 | size_t t4 = sizeof(UInt32); | ||
| 225 | size_t t8 = sizeof(UInt64); | ||
| 226 | if (t4 != 4 || t8 != 8) | ||
| 227 | return PrintError(rs, "Incorrect UInt32 or UInt64"); | ||
| 228 | } | ||
| 229 | |||
| 230 | { | ||
| 231 | WRes wres = InFile_Open(&inStream.file, args[2]); | ||
| 232 | if (wres != 0) | ||
| 233 | return PrintError_WRes(rs, "Cannot open input file", wres); | ||
| 234 | } | ||
| 235 | |||
| 236 | if (numArgs > 3) | ||
| 237 | { | ||
| 238 | WRes wres; | ||
| 239 | useOutFile = True; | ||
| 240 | wres = OutFile_Open(&outStream.file, args[3]); | ||
| 241 | if (wres != 0) | ||
| 242 | return PrintError_WRes(rs, "Cannot open output file", wres); | ||
| 243 | } | ||
| 244 | else if (encodeMode) | ||
| 245 | PrintUserError(rs); | ||
| 246 | |||
| 247 | if (encodeMode) | ||
| 248 | { | ||
| 249 | UInt64 fileSize; | ||
| 250 | WRes wres = File_GetLength(&inStream.file, &fileSize); | ||
| 251 | if (wres != 0) | ||
| 252 | return PrintError_WRes(rs, "Cannot get file length", wres); | ||
| 253 | res = Encode(&outStream.vt, &inStream.vt, fileSize, rs); | ||
| 254 | } | ||
| 255 | else | ||
| 256 | { | ||
| 257 | res = Decode(&outStream.vt, useOutFile ? &inStream.vt : NULL); | ||
| 258 | } | ||
| 259 | |||
| 260 | if (useOutFile) | ||
| 261 | File_Close(&outStream.file); | ||
| 262 | File_Close(&inStream.file); | ||
| 263 | |||
| 264 | if (res != SZ_OK) | ||
| 265 | { | ||
| 266 | if (res == SZ_ERROR_MEM) | ||
| 267 | return PrintError(rs, kCantAllocateMessage); | ||
| 268 | else if (res == SZ_ERROR_DATA) | ||
| 269 | return PrintError(rs, kDataErrorMessage); | ||
| 270 | else if (res == SZ_ERROR_WRITE) | ||
| 271 | return PrintError_WRes(rs, kCantWriteMessage, outStream.wres); | ||
| 272 | else if (res == SZ_ERROR_READ) | ||
| 273 | return PrintError_WRes(rs, kCantReadMessage, inStream.wres); | ||
| 274 | return PrintErrorNumber(rs, res); | ||
| 275 | } | ||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | |||
| 280 | int MY_CDECL main(int numArgs, const char *args[]) | ||
| 281 | { | ||
| 282 | char rs[1000] = { 0 }; | ||
| 283 | int res = main2(numArgs, args, rs); | ||
| 284 | fputs(rs, stdout); | ||
| 285 | return res; | ||
| 286 | } | ||
diff --git a/C/Util/Lzma/LzmaUtil.dsp b/C/Util/Lzma/LzmaUtil.dsp new file mode 100644 index 0000000..4e38e4a --- /dev/null +++ b/C/Util/Lzma/LzmaUtil.dsp | |||
| @@ -0,0 +1,172 @@ | |||
| 1 | # Microsoft Developer Studio Project File - Name="LzmaUtil" - Package Owner=<4> | ||
| 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 | ||
| 3 | # ** DO NOT EDIT ** | ||
| 4 | |||
| 5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103 | ||
| 6 | |||
| 7 | CFG=LzmaUtil - Win32 Debug | ||
| 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, | ||
| 9 | !MESSAGE use the Export Makefile command and run | ||
| 10 | !MESSAGE | ||
| 11 | !MESSAGE NMAKE /f "LzmaUtil.mak". | ||
| 12 | !MESSAGE | ||
| 13 | !MESSAGE You can specify a configuration when running NMAKE | ||
| 14 | !MESSAGE by defining the macro CFG on the command line. For example: | ||
| 15 | !MESSAGE | ||
| 16 | !MESSAGE NMAKE /f "LzmaUtil.mak" CFG="LzmaUtil - Win32 Debug" | ||
| 17 | !MESSAGE | ||
| 18 | !MESSAGE Possible choices for configuration are: | ||
| 19 | !MESSAGE | ||
| 20 | !MESSAGE "LzmaUtil - Win32 Release" (based on "Win32 (x86) Console Application") | ||
| 21 | !MESSAGE "LzmaUtil - Win32 Debug" (based on "Win32 (x86) Console Application") | ||
| 22 | !MESSAGE | ||
| 23 | |||
| 24 | # Begin Project | ||
| 25 | # PROP AllowPerConfigDependencies 0 | ||
| 26 | # PROP Scc_ProjName "" | ||
| 27 | # PROP Scc_LocalPath "" | ||
| 28 | CPP=cl.exe | ||
| 29 | RSC=rc.exe | ||
| 30 | |||
| 31 | !IF "$(CFG)" == "LzmaUtil - Win32 Release" | ||
| 32 | |||
| 33 | # PROP BASE Use_MFC 0 | ||
| 34 | # PROP BASE Use_Debug_Libraries 0 | ||
| 35 | # PROP BASE Output_Dir "Release" | ||
| 36 | # PROP BASE Intermediate_Dir "Release" | ||
| 37 | # PROP BASE Target_Dir "" | ||
| 38 | # PROP Use_MFC 0 | ||
| 39 | # PROP Use_Debug_Libraries 0 | ||
| 40 | # PROP Output_Dir "Release" | ||
| 41 | # PROP Intermediate_Dir "Release" | ||
| 42 | # PROP Ignore_Export_Lib 0 | ||
| 43 | # PROP Target_Dir "" | ||
| 44 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c | ||
| 45 | # ADD CPP /nologo /MT /W4 /WX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c | ||
| 46 | # SUBTRACT CPP /YX | ||
| 47 | # ADD BASE RSC /l 0x419 /d "NDEBUG" | ||
| 48 | # ADD RSC /l 0x419 /d "NDEBUG" | ||
| 49 | BSC32=bscmake.exe | ||
| 50 | # ADD BASE BSC32 /nologo | ||
| 51 | # ADD BSC32 /nologo | ||
| 52 | LINK32=link.exe | ||
| 53 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 | ||
| 54 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7lzma.exe" | ||
| 55 | |||
| 56 | !ELSEIF "$(CFG)" == "LzmaUtil - Win32 Debug" | ||
| 57 | |||
| 58 | # PROP BASE Use_MFC 0 | ||
| 59 | # PROP BASE Use_Debug_Libraries 1 | ||
| 60 | # PROP BASE Output_Dir "Debug" | ||
| 61 | # PROP BASE Intermediate_Dir "Debug" | ||
| 62 | # PROP BASE Target_Dir "" | ||
| 63 | # PROP Use_MFC 0 | ||
| 64 | # PROP Use_Debug_Libraries 1 | ||
| 65 | # PROP Output_Dir "Debug" | ||
| 66 | # PROP Intermediate_Dir "Debug" | ||
| 67 | # PROP Ignore_Export_Lib 0 | ||
| 68 | # PROP Target_Dir "" | ||
| 69 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c | ||
| 70 | # ADD CPP /nologo /MTd /W4 /WX /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c | ||
| 71 | # SUBTRACT CPP /YX | ||
| 72 | # ADD BASE RSC /l 0x419 /d "_DEBUG" | ||
| 73 | # ADD RSC /l 0x419 /d "_DEBUG" | ||
| 74 | BSC32=bscmake.exe | ||
| 75 | # ADD BASE BSC32 /nologo | ||
| 76 | # ADD BSC32 /nologo | ||
| 77 | LINK32=link.exe | ||
| 78 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept | ||
| 79 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7lzma.exe" /pdbtype:sept | ||
| 80 | |||
| 81 | !ENDIF | ||
| 82 | |||
| 83 | # Begin Target | ||
| 84 | |||
| 85 | # Name "LzmaUtil - Win32 Release" | ||
| 86 | # Name "LzmaUtil - Win32 Debug" | ||
| 87 | # Begin Source File | ||
| 88 | |||
| 89 | SOURCE=..\..\7zFile.c | ||
| 90 | # End Source File | ||
| 91 | # Begin Source File | ||
| 92 | |||
| 93 | SOURCE=..\..\7zFile.h | ||
| 94 | # End Source File | ||
| 95 | # Begin Source File | ||
| 96 | |||
| 97 | SOURCE=..\..\7zStream.c | ||
| 98 | # End Source File | ||
| 99 | # Begin Source File | ||
| 100 | |||
| 101 | SOURCE=..\..\7zTypes.h | ||
| 102 | # End Source File | ||
| 103 | # Begin Source File | ||
| 104 | |||
| 105 | SOURCE=..\..\7zVersion.h | ||
| 106 | # End Source File | ||
| 107 | # Begin Source File | ||
| 108 | |||
| 109 | SOURCE=..\..\Alloc.c | ||
| 110 | # End Source File | ||
| 111 | # Begin Source File | ||
| 112 | |||
| 113 | SOURCE=..\..\Alloc.h | ||
| 114 | # End Source File | ||
| 115 | # Begin Source File | ||
| 116 | |||
| 117 | SOURCE=..\..\CpuArch.h | ||
| 118 | # End Source File | ||
| 119 | # Begin Source File | ||
| 120 | |||
| 121 | SOURCE=..\..\LzFind.c | ||
| 122 | # End Source File | ||
| 123 | # Begin Source File | ||
| 124 | |||
| 125 | SOURCE=..\..\LzFind.h | ||
| 126 | # End Source File | ||
| 127 | # Begin Source File | ||
| 128 | |||
| 129 | SOURCE=..\..\LzFindMt.c | ||
| 130 | # End Source File | ||
| 131 | # Begin Source File | ||
| 132 | |||
| 133 | SOURCE=..\..\LzFindMt.h | ||
| 134 | # End Source File | ||
| 135 | # Begin Source File | ||
| 136 | |||
| 137 | SOURCE=..\..\LzFindOpt.c | ||
| 138 | # End Source File | ||
| 139 | # Begin Source File | ||
| 140 | |||
| 141 | SOURCE=..\..\LzHash.h | ||
| 142 | # End Source File | ||
| 143 | # Begin Source File | ||
| 144 | |||
| 145 | SOURCE=..\..\LzmaDec.c | ||
| 146 | # End Source File | ||
| 147 | # Begin Source File | ||
| 148 | |||
| 149 | SOURCE=..\..\LzmaDec.h | ||
| 150 | # End Source File | ||
| 151 | # Begin Source File | ||
| 152 | |||
| 153 | SOURCE=..\..\LzmaEnc.c | ||
| 154 | # End Source File | ||
| 155 | # Begin Source File | ||
| 156 | |||
| 157 | SOURCE=..\..\LzmaEnc.h | ||
| 158 | # End Source File | ||
| 159 | # Begin Source File | ||
| 160 | |||
| 161 | SOURCE=.\LzmaUtil.c | ||
| 162 | # End Source File | ||
| 163 | # Begin Source File | ||
| 164 | |||
| 165 | SOURCE=..\..\Threads.c | ||
| 166 | # End Source File | ||
| 167 | # Begin Source File | ||
| 168 | |||
| 169 | SOURCE=..\..\Threads.h | ||
| 170 | # End Source File | ||
| 171 | # End Target | ||
| 172 | # End Project | ||
diff --git a/C/Util/Lzma/LzmaUtil.dsw b/C/Util/Lzma/LzmaUtil.dsw new file mode 100644 index 0000000..c52eaf6 --- /dev/null +++ b/C/Util/Lzma/LzmaUtil.dsw | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 | ||
| 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! | ||
| 3 | |||
| 4 | ############################################################################### | ||
| 5 | |||
| 6 | Project: "LzmaUtil"=.\LzmaUtil.dsp - Package Owner=<4> | ||
| 7 | |||
| 8 | Package=<5> | ||
| 9 | {{{ | ||
| 10 | }}} | ||
| 11 | |||
| 12 | Package=<4> | ||
| 13 | {{{ | ||
| 14 | }}} | ||
| 15 | |||
| 16 | ############################################################################### | ||
| 17 | |||
| 18 | Global: | ||
| 19 | |||
| 20 | Package=<5> | ||
| 21 | {{{ | ||
| 22 | }}} | ||
| 23 | |||
| 24 | Package=<3> | ||
| 25 | {{{ | ||
| 26 | }}} | ||
| 27 | |||
| 28 | ############################################################################### | ||
| 29 | |||
diff --git a/C/Util/Lzma/makefile b/C/Util/Lzma/makefile new file mode 100644 index 0000000..7813bdb --- /dev/null +++ b/C/Util/Lzma/makefile | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | # MY_STATIC_LINK=1 | ||
| 2 | PROG = LZMAc.exe | ||
| 3 | |||
| 4 | CFLAGS = $(CFLAGS) \ | ||
| 5 | |||
| 6 | LIB_OBJS = \ | ||
| 7 | $O\LzmaUtil.obj \ | ||
| 8 | |||
| 9 | C_OBJS = \ | ||
| 10 | $O\Alloc.obj \ | ||
| 11 | $O\CpuArch.obj \ | ||
| 12 | $O\LzFind.obj \ | ||
| 13 | $O\LzFindMt.obj \ | ||
| 14 | $O\LzFindOpt.obj \ | ||
| 15 | $O\LzmaDec.obj \ | ||
| 16 | $O\LzmaEnc.obj \ | ||
| 17 | $O\7zFile.obj \ | ||
| 18 | $O\7zStream.obj \ | ||
| 19 | $O\Threads.obj \ | ||
| 20 | |||
| 21 | OBJS = \ | ||
| 22 | $(LIB_OBJS) \ | ||
| 23 | $(C_OBJS) \ | ||
| 24 | |||
| 25 | !include "../../../CPP/Build.mak" | ||
| 26 | |||
| 27 | $(LIB_OBJS): $(*B).c | ||
| 28 | $(COMPL_O2) | ||
| 29 | $(C_OBJS): ../../$(*B).c | ||
| 30 | $(COMPL_O2) | ||
diff --git a/C/Util/Lzma/makefile.gcc b/C/Util/Lzma/makefile.gcc new file mode 100644 index 0000000..2acb0b8 --- /dev/null +++ b/C/Util/Lzma/makefile.gcc | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | PROG = 7lzma | ||
| 2 | |||
| 3 | include ../../../CPP/7zip/LzmaDec_gcc.mak | ||
| 4 | |||
| 5 | |||
| 6 | OBJS = \ | ||
| 7 | $(LZMA_DEC_OPT_OBJS) \ | ||
| 8 | $O/7zFile.o \ | ||
| 9 | $O/7zStream.o \ | ||
| 10 | $O/Alloc.o \ | ||
| 11 | $O/CpuArch.o \ | ||
| 12 | $O/LzFind.o \ | ||
| 13 | $O/LzFindMt.o \ | ||
| 14 | $O/LzFindOpt.o \ | ||
| 15 | $O/LzmaDec.o \ | ||
| 16 | $O/LzmaEnc.o \ | ||
| 17 | $O/LzmaUtil.o \ | ||
| 18 | $O/Threads.o \ | ||
| 19 | |||
| 20 | |||
| 21 | include ../../7zip_gcc_c.mak | ||
diff --git a/C/Util/LzmaLib/LzmaLib.def b/C/Util/LzmaLib/LzmaLib.def new file mode 100644 index 0000000..8bc6add --- /dev/null +++ b/C/Util/LzmaLib/LzmaLib.def | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | EXPORTS | ||
| 2 | LzmaCompress | ||
| 3 | LzmaUncompress | ||
| 4 | |||
diff --git a/C/Util/LzmaLib/LzmaLib.dsp b/C/Util/LzmaLib/LzmaLib.dsp new file mode 100644 index 0000000..6ce91dc --- /dev/null +++ b/C/Util/LzmaLib/LzmaLib.dsp | |||
| @@ -0,0 +1,182 @@ | |||
| 1 | # Microsoft Developer Studio Project File - Name="LzmaLib" - Package Owner=<4> | ||
| 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 | ||
| 3 | # ** DO NOT EDIT ** | ||
| 4 | |||
| 5 | # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 | ||
| 6 | |||
| 7 | CFG=LzmaLib - Win32 Debug | ||
| 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, | ||
| 9 | !MESSAGE use the Export Makefile command and run | ||
| 10 | !MESSAGE | ||
| 11 | !MESSAGE NMAKE /f "LzmaLib.mak". | ||
| 12 | !MESSAGE | ||
| 13 | !MESSAGE You can specify a configuration when running NMAKE | ||
| 14 | !MESSAGE by defining the macro CFG on the command line. For example: | ||
| 15 | !MESSAGE | ||
| 16 | !MESSAGE NMAKE /f "LzmaLib.mak" CFG="LzmaLib - Win32 Debug" | ||
| 17 | !MESSAGE | ||
| 18 | !MESSAGE Possible choices for configuration are: | ||
| 19 | !MESSAGE | ||
| 20 | !MESSAGE "LzmaLib - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") | ||
| 21 | !MESSAGE "LzmaLib - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") | ||
| 22 | !MESSAGE | ||
| 23 | |||
| 24 | # Begin Project | ||
| 25 | # PROP AllowPerConfigDependencies 0 | ||
| 26 | # PROP Scc_ProjName "" | ||
| 27 | # PROP Scc_LocalPath "" | ||
| 28 | CPP=cl.exe | ||
| 29 | MTL=midl.exe | ||
| 30 | RSC=rc.exe | ||
| 31 | |||
| 32 | !IF "$(CFG)" == "LzmaLib - Win32 Release" | ||
| 33 | |||
| 34 | # PROP BASE Use_MFC 0 | ||
| 35 | # PROP BASE Use_Debug_Libraries 0 | ||
| 36 | # PROP BASE Output_Dir "Release" | ||
| 37 | # PROP BASE Intermediate_Dir "Release" | ||
| 38 | # PROP BASE Target_Dir "" | ||
| 39 | # PROP Use_MFC 0 | ||
| 40 | # PROP Use_Debug_Libraries 0 | ||
| 41 | # PROP Output_Dir "Release" | ||
| 42 | # PROP Intermediate_Dir "Release" | ||
| 43 | # PROP Ignore_Export_Lib 0 | ||
| 44 | # PROP Target_Dir "" | ||
| 45 | # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /c | ||
| 46 | # ADD CPP /nologo /Gr /MT /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c | ||
| 47 | # SUBTRACT CPP /YX | ||
| 48 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | ||
| 49 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | ||
| 50 | # ADD BASE RSC /l 0x419 /d "NDEBUG" | ||
| 51 | # ADD RSC /l 0x419 /d "NDEBUG" | ||
| 52 | BSC32=bscmake.exe | ||
| 53 | # ADD BASE BSC32 /nologo | ||
| 54 | # ADD BSC32 /nologo | ||
| 55 | LINK32=link.exe | ||
| 56 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 | ||
| 57 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\LZMA.dll" /opt:NOWIN98 | ||
| 58 | # SUBTRACT LINK32 /pdb:none | ||
| 59 | |||
| 60 | !ELSEIF "$(CFG)" == "LzmaLib - Win32 Debug" | ||
| 61 | |||
| 62 | # PROP BASE Use_MFC 0 | ||
| 63 | # PROP BASE Use_Debug_Libraries 1 | ||
| 64 | # PROP BASE Output_Dir "Debug" | ||
| 65 | # PROP BASE Intermediate_Dir "Debug" | ||
| 66 | # PROP BASE Target_Dir "" | ||
| 67 | # PROP Use_MFC 0 | ||
| 68 | # PROP Use_Debug_Libraries 1 | ||
| 69 | # PROP Output_Dir "Debug" | ||
| 70 | # PROP Intermediate_Dir "Debug" | ||
| 71 | # PROP Ignore_Export_Lib 0 | ||
| 72 | # PROP Target_Dir "" | ||
| 73 | # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /GZ /c | ||
| 74 | # ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /D "COMPRESS_MF_MT" /FD /GZ /c | ||
| 75 | # SUBTRACT CPP /YX | ||
| 76 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | ||
| 77 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | ||
| 78 | # ADD BASE RSC /l 0x419 /d "_DEBUG" | ||
| 79 | # ADD RSC /l 0x419 /d "_DEBUG" | ||
| 80 | BSC32=bscmake.exe | ||
| 81 | # ADD BASE BSC32 /nologo | ||
| 82 | # ADD BSC32 /nologo | ||
| 83 | LINK32=link.exe | ||
| 84 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept | ||
| 85 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\LZMA.dll" /pdbtype:sept | ||
| 86 | |||
| 87 | !ENDIF | ||
| 88 | |||
| 89 | # Begin Target | ||
| 90 | |||
| 91 | # Name "LzmaLib - Win32 Release" | ||
| 92 | # Name "LzmaLib - Win32 Debug" | ||
| 93 | # Begin Group "Spec" | ||
| 94 | |||
| 95 | # PROP Default_Filter "" | ||
| 96 | # Begin Source File | ||
| 97 | |||
| 98 | SOURCE=.\LzmaLib.def | ||
| 99 | # End Source File | ||
| 100 | # Begin Source File | ||
| 101 | |||
| 102 | SOURCE=.\LzmaLibExports.c | ||
| 103 | # End Source File | ||
| 104 | # End Group | ||
| 105 | # Begin Source File | ||
| 106 | |||
| 107 | SOURCE=..\..\7zTypes.h | ||
| 108 | # End Source File | ||
| 109 | # Begin Source File | ||
| 110 | |||
| 111 | SOURCE=..\..\Alloc.c | ||
| 112 | # End Source File | ||
| 113 | # Begin Source File | ||
| 114 | |||
| 115 | SOURCE=..\..\Alloc.h | ||
| 116 | # End Source File | ||
| 117 | # Begin Source File | ||
| 118 | |||
| 119 | SOURCE=..\..\IStream.h | ||
| 120 | # End Source File | ||
| 121 | # Begin Source File | ||
| 122 | |||
| 123 | SOURCE=..\..\LzFind.c | ||
| 124 | # End Source File | ||
| 125 | # Begin Source File | ||
| 126 | |||
| 127 | SOURCE=..\..\LzFind.h | ||
| 128 | # End Source File | ||
| 129 | # Begin Source File | ||
| 130 | |||
| 131 | SOURCE=..\..\LzFindMt.c | ||
| 132 | # End Source File | ||
| 133 | # Begin Source File | ||
| 134 | |||
| 135 | SOURCE=..\..\LzFindMt.h | ||
| 136 | # End Source File | ||
| 137 | # Begin Source File | ||
| 138 | |||
| 139 | SOURCE=..\..\LzFindOpt.c | ||
| 140 | # End Source File | ||
| 141 | # Begin Source File | ||
| 142 | |||
| 143 | SOURCE=..\..\LzHash.h | ||
| 144 | # End Source File | ||
| 145 | # Begin Source File | ||
| 146 | |||
| 147 | SOURCE=..\..\LzmaDec.c | ||
| 148 | # End Source File | ||
| 149 | # Begin Source File | ||
| 150 | |||
| 151 | SOURCE=..\..\LzmaDec.h | ||
| 152 | # End Source File | ||
| 153 | # Begin Source File | ||
| 154 | |||
| 155 | SOURCE=..\..\LzmaEnc.c | ||
| 156 | # End Source File | ||
| 157 | # Begin Source File | ||
| 158 | |||
| 159 | SOURCE=..\..\LzmaEnc.h | ||
| 160 | # End Source File | ||
| 161 | # Begin Source File | ||
| 162 | |||
| 163 | SOURCE=..\..\LzmaLib.c | ||
| 164 | # End Source File | ||
| 165 | # Begin Source File | ||
| 166 | |||
| 167 | SOURCE=..\..\LzmaLib.h | ||
| 168 | # End Source File | ||
| 169 | # Begin Source File | ||
| 170 | |||
| 171 | SOURCE=.\resource.rc | ||
| 172 | # End Source File | ||
| 173 | # Begin Source File | ||
| 174 | |||
| 175 | SOURCE=..\..\Threads.c | ||
| 176 | # End Source File | ||
| 177 | # Begin Source File | ||
| 178 | |||
| 179 | SOURCE=..\..\Threads.h | ||
| 180 | # End Source File | ||
| 181 | # End Target | ||
| 182 | # End Project | ||
diff --git a/C/Util/LzmaLib/LzmaLib.dsw b/C/Util/LzmaLib/LzmaLib.dsw new file mode 100644 index 0000000..6faf333 --- /dev/null +++ b/C/Util/LzmaLib/LzmaLib.dsw | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 | ||
| 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! | ||
| 3 | |||
| 4 | ############################################################################### | ||
| 5 | |||
| 6 | Project: "LzmaLib"=.\LzmaLib.dsp - Package Owner=<4> | ||
| 7 | |||
| 8 | Package=<5> | ||
| 9 | {{{ | ||
| 10 | }}} | ||
| 11 | |||
| 12 | Package=<4> | ||
| 13 | {{{ | ||
| 14 | }}} | ||
| 15 | |||
| 16 | ############################################################################### | ||
| 17 | |||
| 18 | Global: | ||
| 19 | |||
| 20 | Package=<5> | ||
| 21 | {{{ | ||
| 22 | }}} | ||
| 23 | |||
| 24 | Package=<3> | ||
| 25 | {{{ | ||
| 26 | }}} | ||
| 27 | |||
| 28 | ############################################################################### | ||
| 29 | |||
diff --git a/C/Util/LzmaLib/LzmaLibExports.c b/C/Util/LzmaLib/LzmaLibExports.c new file mode 100644 index 0000000..4a28a9a --- /dev/null +++ b/C/Util/LzmaLib/LzmaLibExports.c | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | /* LzmaLibExports.c -- LZMA library DLL Entry point | ||
| 2 | 2015-11-08 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "../../Precomp.h" | ||
| 5 | |||
| 6 | #include <windows.h> | ||
| 7 | |||
| 8 | BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) | ||
| 9 | { | ||
| 10 | UNUSED_VAR(hInstance); | ||
| 11 | UNUSED_VAR(dwReason); | ||
| 12 | UNUSED_VAR(lpReserved); | ||
| 13 | return TRUE; | ||
| 14 | } | ||
diff --git a/C/Util/LzmaLib/makefile b/C/Util/LzmaLib/makefile new file mode 100644 index 0000000..b36f1de --- /dev/null +++ b/C/Util/LzmaLib/makefile | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | MY_STATIC_LINK=1 | ||
| 2 | SLIB = sLZMA.lib | ||
| 3 | PROG = LZMA.dll | ||
| 4 | SLIBPATH = $O\$(SLIB) | ||
| 5 | |||
| 6 | DEF_FILE = LzmaLib.def | ||
| 7 | CFLAGS = $(CFLAGS) \ | ||
| 8 | |||
| 9 | LIB_OBJS = \ | ||
| 10 | $O\LzmaLibExports.obj \ | ||
| 11 | |||
| 12 | C_OBJS = \ | ||
| 13 | $O\Alloc.obj \ | ||
| 14 | $O\CpuArch.obj \ | ||
| 15 | $O\LzFind.obj \ | ||
| 16 | $O\LzFindMt.obj \ | ||
| 17 | $O\LzFindOpt.obj \ | ||
| 18 | $O\LzmaDec.obj \ | ||
| 19 | $O\LzmaEnc.obj \ | ||
| 20 | $O\LzmaLib.obj \ | ||
| 21 | $O\Threads.obj \ | ||
| 22 | |||
| 23 | OBJS = \ | ||
| 24 | $(LIB_OBJS) \ | ||
| 25 | $(C_OBJS) \ | ||
| 26 | $O\resource.res | ||
| 27 | |||
| 28 | !include "../../../CPP/Build.mak" | ||
| 29 | |||
| 30 | $(SLIBPATH): $O $(OBJS) | ||
| 31 | lib -out:$(SLIBPATH) $(OBJS) $(LIBS) | ||
| 32 | |||
| 33 | $(LIB_OBJS): $(*B).c | ||
| 34 | $(COMPL_O2) | ||
| 35 | $(C_OBJS): ../../$(*B).c | ||
| 36 | $(COMPL_O2) | ||
diff --git a/C/Util/LzmaLib/resource.rc b/C/Util/LzmaLib/resource.rc new file mode 100644 index 0000000..674832e --- /dev/null +++ b/C/Util/LzmaLib/resource.rc | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | #include "../../7zVersion.rc" | ||
| 2 | |||
| 3 | MY_VERSION_INFO_DLL("LZMA library", "LZMA") | ||
diff --git a/C/Util/SfxSetup/Precomp.c b/C/Util/SfxSetup/Precomp.c new file mode 100644 index 0000000..01605e3 --- /dev/null +++ b/C/Util/SfxSetup/Precomp.c | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | /* Precomp.c -- StdAfx | ||
| 2 | 2013-01-21 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
diff --git a/C/Util/SfxSetup/Precomp.h b/C/Util/SfxSetup/Precomp.h new file mode 100644 index 0000000..588a66f --- /dev/null +++ b/C/Util/SfxSetup/Precomp.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | /* Precomp.h -- StdAfx | ||
| 2 | 2013-06-16 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __7Z_PRECOMP_H | ||
| 5 | #define __7Z_PRECOMP_H | ||
| 6 | |||
| 7 | #include "../../Compiler.h" | ||
| 8 | #include "../../7zTypes.h" | ||
| 9 | |||
| 10 | #endif | ||
diff --git a/C/Util/SfxSetup/SfxSetup.c b/C/Util/SfxSetup/SfxSetup.c new file mode 100644 index 0000000..ef19aea --- /dev/null +++ b/C/Util/SfxSetup/SfxSetup.c | |||
| @@ -0,0 +1,640 @@ | |||
| 1 | /* SfxSetup.c - 7z SFX Setup | ||
| 2 | 2019-02-02 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #ifndef UNICODE | ||
| 7 | #define UNICODE | ||
| 8 | #endif | ||
| 9 | |||
| 10 | #ifndef _UNICODE | ||
| 11 | #define _UNICODE | ||
| 12 | #endif | ||
| 13 | |||
| 14 | #ifdef _CONSOLE | ||
| 15 | #include <stdio.h> | ||
| 16 | #endif | ||
| 17 | |||
| 18 | #include "../../7z.h" | ||
| 19 | #include "../../7zAlloc.h" | ||
| 20 | #include "../../7zCrc.h" | ||
| 21 | #include "../../7zFile.h" | ||
| 22 | #include "../../CpuArch.h" | ||
| 23 | #include "../../DllSecur.h" | ||
| 24 | |||
| 25 | #define k_EXE_ExtIndex 2 | ||
| 26 | |||
| 27 | #define kInputBufSize ((size_t)1 << 18) | ||
| 28 | |||
| 29 | static const char * const kExts[] = | ||
| 30 | { | ||
| 31 | "bat" | ||
| 32 | , "cmd" | ||
| 33 | , "exe" | ||
| 34 | , "inf" | ||
| 35 | , "msi" | ||
| 36 | #ifdef UNDER_CE | ||
| 37 | , "cab" | ||
| 38 | #endif | ||
| 39 | , "html" | ||
| 40 | , "htm" | ||
| 41 | }; | ||
| 42 | |||
| 43 | static const char * const kNames[] = | ||
| 44 | { | ||
| 45 | "setup" | ||
| 46 | , "install" | ||
| 47 | , "run" | ||
| 48 | , "start" | ||
| 49 | }; | ||
| 50 | |||
| 51 | static unsigned FindExt(const wchar_t *s, unsigned *extLen) | ||
| 52 | { | ||
| 53 | unsigned len = (unsigned)wcslen(s); | ||
| 54 | unsigned i; | ||
| 55 | for (i = len; i > 0; i--) | ||
| 56 | { | ||
| 57 | if (s[i - 1] == '.') | ||
| 58 | { | ||
| 59 | *extLen = len - i; | ||
| 60 | return i - 1; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | *extLen = 0; | ||
| 64 | return len; | ||
| 65 | } | ||
| 66 | |||
| 67 | #define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c))) | ||
| 68 | |||
| 69 | static unsigned FindItem(const char * const *items, unsigned num, const wchar_t *s, unsigned len) | ||
| 70 | { | ||
| 71 | unsigned i; | ||
| 72 | for (i = 0; i < num; i++) | ||
| 73 | { | ||
| 74 | const char *item = items[i]; | ||
| 75 | unsigned itemLen = (unsigned)strlen(item); | ||
| 76 | unsigned j; | ||
| 77 | if (len != itemLen) | ||
| 78 | continue; | ||
| 79 | for (j = 0; j < len; j++) | ||
| 80 | { | ||
| 81 | unsigned c = (Byte)item[j]; | ||
| 82 | if (c != s[j] && MAKE_CHAR_UPPER(c) != s[j]) | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | if (j == len) | ||
| 86 | return i; | ||
| 87 | } | ||
| 88 | return i; | ||
| 89 | } | ||
| 90 | |||
| 91 | #ifdef _CONSOLE | ||
| 92 | static BOOL WINAPI HandlerRoutine(DWORD ctrlType) | ||
| 93 | { | ||
| 94 | UNUSED_VAR(ctrlType); | ||
| 95 | return TRUE; | ||
| 96 | } | ||
| 97 | #endif | ||
| 98 | |||
| 99 | static void PrintErrorMessage(const char *message) | ||
| 100 | { | ||
| 101 | #ifdef _CONSOLE | ||
| 102 | printf("\n7-Zip Error: %s\n", message); | ||
| 103 | #else | ||
| 104 | #ifdef UNDER_CE | ||
| 105 | WCHAR messageW[256 + 4]; | ||
| 106 | unsigned i; | ||
| 107 | for (i = 0; i < 256 && message[i] != 0; i++) | ||
| 108 | messageW[i] = message[i]; | ||
| 109 | messageW[i] = 0; | ||
| 110 | MessageBoxW(0, messageW, L"7-Zip Error", MB_ICONERROR); | ||
| 111 | #else | ||
| 112 | MessageBoxA(0, message, "7-Zip Error", MB_ICONERROR); | ||
| 113 | #endif | ||
| 114 | #endif | ||
| 115 | } | ||
| 116 | |||
| 117 | static WRes MyCreateDir(const WCHAR *name) | ||
| 118 | { | ||
| 119 | return CreateDirectoryW(name, NULL) ? 0 : GetLastError(); | ||
| 120 | } | ||
| 121 | |||
| 122 | #ifdef UNDER_CE | ||
| 123 | #define kBufferSize (1 << 13) | ||
| 124 | #else | ||
| 125 | #define kBufferSize (1 << 15) | ||
| 126 | #endif | ||
| 127 | |||
| 128 | #define kSignatureSearchLimit (1 << 22) | ||
| 129 | |||
| 130 | static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos) | ||
| 131 | { | ||
| 132 | Byte buf[kBufferSize]; | ||
| 133 | size_t numPrevBytes = 0; | ||
| 134 | *resPos = 0; | ||
| 135 | for (;;) | ||
| 136 | { | ||
| 137 | size_t processed, pos; | ||
| 138 | if (*resPos > kSignatureSearchLimit) | ||
| 139 | return False; | ||
| 140 | processed = kBufferSize - numPrevBytes; | ||
| 141 | if (File_Read(stream, buf + numPrevBytes, &processed) != 0) | ||
| 142 | return False; | ||
| 143 | processed += numPrevBytes; | ||
| 144 | if (processed < k7zStartHeaderSize || | ||
| 145 | (processed == k7zStartHeaderSize && numPrevBytes != 0)) | ||
| 146 | return False; | ||
| 147 | processed -= k7zStartHeaderSize; | ||
| 148 | for (pos = 0; pos <= processed; pos++) | ||
| 149 | { | ||
| 150 | for (; pos <= processed && buf[pos] != '7'; pos++); | ||
| 151 | if (pos > processed) | ||
| 152 | break; | ||
| 153 | if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0) | ||
| 154 | if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8)) | ||
| 155 | { | ||
| 156 | *resPos += pos; | ||
| 157 | return True; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | *resPos += processed; | ||
| 161 | numPrevBytes = k7zStartHeaderSize; | ||
| 162 | memmove(buf, buf + processed, k7zStartHeaderSize); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | static BoolInt DoesFileOrDirExist(const WCHAR *path) | ||
| 167 | { | ||
| 168 | WIN32_FIND_DATAW fd; | ||
| 169 | HANDLE handle; | ||
| 170 | handle = FindFirstFileW(path, &fd); | ||
| 171 | if (handle == INVALID_HANDLE_VALUE) | ||
| 172 | return False; | ||
| 173 | FindClose(handle); | ||
| 174 | return True; | ||
| 175 | } | ||
| 176 | |||
| 177 | static WRes RemoveDirWithSubItems(WCHAR *path) | ||
| 178 | { | ||
| 179 | WIN32_FIND_DATAW fd; | ||
| 180 | HANDLE handle; | ||
| 181 | WRes res = 0; | ||
| 182 | size_t len = wcslen(path); | ||
| 183 | wcscpy(path + len, L"*"); | ||
| 184 | handle = FindFirstFileW(path, &fd); | ||
| 185 | path[len] = L'\0'; | ||
| 186 | if (handle == INVALID_HANDLE_VALUE) | ||
| 187 | return GetLastError(); | ||
| 188 | |||
| 189 | for (;;) | ||
| 190 | { | ||
| 191 | if (wcscmp(fd.cFileName, L".") != 0 && | ||
| 192 | wcscmp(fd.cFileName, L"..") != 0) | ||
| 193 | { | ||
| 194 | wcscpy(path + len, fd.cFileName); | ||
| 195 | if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) | ||
| 196 | { | ||
| 197 | wcscat(path, WSTRING_PATH_SEPARATOR); | ||
| 198 | res = RemoveDirWithSubItems(path); | ||
| 199 | } | ||
| 200 | else | ||
| 201 | { | ||
| 202 | SetFileAttributesW(path, 0); | ||
| 203 | if (DeleteFileW(path) == 0) | ||
| 204 | res = GetLastError(); | ||
| 205 | } | ||
| 206 | |||
| 207 | if (res != 0) | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | |||
| 211 | if (!FindNextFileW(handle, &fd)) | ||
| 212 | { | ||
| 213 | res = GetLastError(); | ||
| 214 | if (res == ERROR_NO_MORE_FILES) | ||
| 215 | res = 0; | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | path[len] = L'\0'; | ||
| 221 | FindClose(handle); | ||
| 222 | if (res == 0) | ||
| 223 | { | ||
| 224 | if (!RemoveDirectoryW(path)) | ||
| 225 | res = GetLastError(); | ||
| 226 | } | ||
| 227 | return res; | ||
| 228 | } | ||
| 229 | |||
| 230 | #ifdef _CONSOLE | ||
| 231 | int MY_CDECL main() | ||
| 232 | #else | ||
| 233 | int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, | ||
| 234 | #ifdef UNDER_CE | ||
| 235 | LPWSTR | ||
| 236 | #else | ||
| 237 | LPSTR | ||
| 238 | #endif | ||
| 239 | lpCmdLine, int nCmdShow) | ||
| 240 | #endif | ||
| 241 | { | ||
| 242 | CFileInStream archiveStream; | ||
| 243 | CLookToRead2 lookStream; | ||
| 244 | CSzArEx db; | ||
| 245 | SRes res = SZ_OK; | ||
| 246 | ISzAlloc allocImp; | ||
| 247 | ISzAlloc allocTempImp; | ||
| 248 | WCHAR sfxPath[MAX_PATH + 2]; | ||
| 249 | WCHAR path[MAX_PATH * 3 + 2]; | ||
| 250 | #ifndef UNDER_CE | ||
| 251 | WCHAR workCurDir[MAX_PATH + 32]; | ||
| 252 | #endif | ||
| 253 | size_t pathLen; | ||
| 254 | DWORD winRes; | ||
| 255 | const wchar_t *cmdLineParams; | ||
| 256 | const char *errorMessage = NULL; | ||
| 257 | BoolInt useShellExecute = True; | ||
| 258 | DWORD exitCode = 0; | ||
| 259 | |||
| 260 | LoadSecurityDlls(); | ||
| 261 | |||
| 262 | #ifdef _CONSOLE | ||
| 263 | SetConsoleCtrlHandler(HandlerRoutine, TRUE); | ||
| 264 | #else | ||
| 265 | UNUSED_VAR(hInstance); | ||
| 266 | UNUSED_VAR(hPrevInstance); | ||
| 267 | UNUSED_VAR(lpCmdLine); | ||
| 268 | UNUSED_VAR(nCmdShow); | ||
| 269 | #endif | ||
| 270 | |||
| 271 | CrcGenerateTable(); | ||
| 272 | |||
| 273 | allocImp.Alloc = SzAlloc; | ||
| 274 | allocImp.Free = SzFree; | ||
| 275 | |||
| 276 | allocTempImp.Alloc = SzAllocTemp; | ||
| 277 | allocTempImp.Free = SzFreeTemp; | ||
| 278 | |||
| 279 | FileInStream_CreateVTable(&archiveStream); | ||
| 280 | LookToRead2_CreateVTable(&lookStream, False); | ||
| 281 | lookStream.buf = NULL; | ||
| 282 | |||
| 283 | winRes = GetModuleFileNameW(NULL, sfxPath, MAX_PATH); | ||
| 284 | if (winRes == 0 || winRes > MAX_PATH) | ||
| 285 | return 1; | ||
| 286 | { | ||
| 287 | cmdLineParams = GetCommandLineW(); | ||
| 288 | #ifndef UNDER_CE | ||
| 289 | { | ||
| 290 | BoolInt quoteMode = False; | ||
| 291 | for (;; cmdLineParams++) | ||
| 292 | { | ||
| 293 | wchar_t c = *cmdLineParams; | ||
| 294 | if (c == L'\"') | ||
| 295 | quoteMode = !quoteMode; | ||
| 296 | else if (c == 0 || (c == L' ' && !quoteMode)) | ||
| 297 | break; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | #endif | ||
| 301 | } | ||
| 302 | |||
| 303 | { | ||
| 304 | unsigned i; | ||
| 305 | DWORD d; | ||
| 306 | winRes = GetTempPathW(MAX_PATH, path); | ||
| 307 | if (winRes == 0 || winRes > MAX_PATH) | ||
| 308 | return 1; | ||
| 309 | pathLen = wcslen(path); | ||
| 310 | d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); | ||
| 311 | |||
| 312 | for (i = 0;; i++, d += GetTickCount()) | ||
| 313 | { | ||
| 314 | if (i >= 100) | ||
| 315 | { | ||
| 316 | res = SZ_ERROR_FAIL; | ||
| 317 | break; | ||
| 318 | } | ||
| 319 | wcscpy(path + pathLen, L"7z"); | ||
| 320 | |||
| 321 | { | ||
| 322 | wchar_t *s = path + wcslen(path); | ||
| 323 | UInt32 value = d; | ||
| 324 | unsigned k; | ||
| 325 | for (k = 0; k < 8; k++) | ||
| 326 | { | ||
| 327 | unsigned t = value & 0xF; | ||
| 328 | value >>= 4; | ||
| 329 | s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10))); | ||
| 330 | } | ||
| 331 | s[k] = '\0'; | ||
| 332 | } | ||
| 333 | |||
| 334 | if (DoesFileOrDirExist(path)) | ||
| 335 | continue; | ||
| 336 | if (CreateDirectoryW(path, NULL)) | ||
| 337 | { | ||
| 338 | wcscat(path, WSTRING_PATH_SEPARATOR); | ||
| 339 | pathLen = wcslen(path); | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | if (GetLastError() != ERROR_ALREADY_EXISTS) | ||
| 343 | { | ||
| 344 | res = SZ_ERROR_FAIL; | ||
| 345 | break; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | #ifndef UNDER_CE | ||
| 350 | wcscpy(workCurDir, path); | ||
| 351 | #endif | ||
| 352 | if (res != SZ_OK) | ||
| 353 | errorMessage = "Can't create temp folder"; | ||
| 354 | } | ||
| 355 | |||
| 356 | if (res != SZ_OK) | ||
| 357 | { | ||
| 358 | if (!errorMessage) | ||
| 359 | errorMessage = "Error"; | ||
| 360 | PrintErrorMessage(errorMessage); | ||
| 361 | return 1; | ||
| 362 | } | ||
| 363 | |||
| 364 | if (InFile_OpenW(&archiveStream.file, sfxPath) != 0) | ||
| 365 | { | ||
| 366 | errorMessage = "can not open input file"; | ||
| 367 | res = SZ_ERROR_FAIL; | ||
| 368 | } | ||
| 369 | else | ||
| 370 | { | ||
| 371 | UInt64 pos = 0; | ||
| 372 | if (!FindSignature(&archiveStream.file, &pos)) | ||
| 373 | res = SZ_ERROR_FAIL; | ||
| 374 | else if (File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET) != 0) | ||
| 375 | res = SZ_ERROR_FAIL; | ||
| 376 | if (res != 0) | ||
| 377 | errorMessage = "Can't find 7z archive"; | ||
| 378 | } | ||
| 379 | |||
| 380 | if (res == SZ_OK) | ||
| 381 | { | ||
| 382 | lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize); | ||
| 383 | if (!lookStream.buf) | ||
| 384 | res = SZ_ERROR_MEM; | ||
| 385 | else | ||
| 386 | { | ||
| 387 | lookStream.bufSize = kInputBufSize; | ||
| 388 | lookStream.realStream = &archiveStream.vt; | ||
| 389 | LookToRead2_Init(&lookStream); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | SzArEx_Init(&db); | ||
| 394 | |||
| 395 | if (res == SZ_OK) | ||
| 396 | { | ||
| 397 | res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp); | ||
| 398 | } | ||
| 399 | |||
| 400 | if (res == SZ_OK) | ||
| 401 | { | ||
| 402 | UInt32 executeFileIndex = (UInt32)(Int32)-1; | ||
| 403 | UInt32 minPrice = 1 << 30; | ||
| 404 | UInt32 i; | ||
| 405 | UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */ | ||
| 406 | Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */ | ||
| 407 | size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */ | ||
| 408 | |||
| 409 | for (i = 0; i < db.NumFiles; i++) | ||
| 410 | { | ||
| 411 | size_t offset = 0; | ||
| 412 | size_t outSizeProcessed = 0; | ||
| 413 | WCHAR *temp; | ||
| 414 | |||
| 415 | if (SzArEx_GetFileNameUtf16(&db, i, NULL) >= MAX_PATH) | ||
| 416 | { | ||
| 417 | res = SZ_ERROR_FAIL; | ||
| 418 | break; | ||
| 419 | } | ||
| 420 | |||
| 421 | temp = path + pathLen; | ||
| 422 | |||
| 423 | SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp); | ||
| 424 | { | ||
| 425 | res = SzArEx_Extract(&db, &lookStream.vt, i, | ||
| 426 | &blockIndex, &outBuffer, &outBufferSize, | ||
| 427 | &offset, &outSizeProcessed, | ||
| 428 | &allocImp, &allocTempImp); | ||
| 429 | if (res != SZ_OK) | ||
| 430 | break; | ||
| 431 | } | ||
| 432 | { | ||
| 433 | CSzFile outFile; | ||
| 434 | size_t processedSize; | ||
| 435 | size_t j; | ||
| 436 | size_t nameStartPos = 0; | ||
| 437 | for (j = 0; temp[j] != 0; j++) | ||
| 438 | { | ||
| 439 | if (temp[j] == '/') | ||
| 440 | { | ||
| 441 | temp[j] = 0; | ||
| 442 | MyCreateDir(path); | ||
| 443 | temp[j] = CHAR_PATH_SEPARATOR; | ||
| 444 | nameStartPos = j + 1; | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | if (SzArEx_IsDir(&db, i)) | ||
| 449 | { | ||
| 450 | MyCreateDir(path); | ||
| 451 | continue; | ||
| 452 | } | ||
| 453 | else | ||
| 454 | { | ||
| 455 | unsigned extLen; | ||
| 456 | const WCHAR *name = temp + nameStartPos; | ||
| 457 | unsigned len = (unsigned)wcslen(name); | ||
| 458 | unsigned nameLen = FindExt(temp + nameStartPos, &extLen); | ||
| 459 | unsigned extPrice = FindItem(kExts, sizeof(kExts) / sizeof(kExts[0]), name + len - extLen, extLen); | ||
| 460 | unsigned namePrice = FindItem(kNames, sizeof(kNames) / sizeof(kNames[0]), name, nameLen); | ||
| 461 | |||
| 462 | unsigned price = namePrice + extPrice * 64 + (nameStartPos == 0 ? 0 : (1 << 12)); | ||
| 463 | if (minPrice > price) | ||
| 464 | { | ||
| 465 | minPrice = price; | ||
| 466 | executeFileIndex = i; | ||
| 467 | useShellExecute = (extPrice != k_EXE_ExtIndex); | ||
| 468 | } | ||
| 469 | |||
| 470 | if (DoesFileOrDirExist(path)) | ||
| 471 | { | ||
| 472 | errorMessage = "Duplicate file"; | ||
| 473 | res = SZ_ERROR_FAIL; | ||
| 474 | break; | ||
| 475 | } | ||
| 476 | if (OutFile_OpenW(&outFile, path)) | ||
| 477 | { | ||
| 478 | errorMessage = "Can't open output file"; | ||
| 479 | res = SZ_ERROR_FAIL; | ||
| 480 | break; | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | processedSize = outSizeProcessed; | ||
| 485 | if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed) | ||
| 486 | { | ||
| 487 | errorMessage = "Can't write output file"; | ||
| 488 | res = SZ_ERROR_FAIL; | ||
| 489 | } | ||
| 490 | |||
| 491 | #ifdef USE_WINDOWS_FILE | ||
| 492 | if (SzBitWithVals_Check(&db.MTime, i)) | ||
| 493 | { | ||
| 494 | const CNtfsFileTime *t = db.MTime.Vals + i; | ||
| 495 | FILETIME mTime; | ||
| 496 | mTime.dwLowDateTime = t->Low; | ||
| 497 | mTime.dwHighDateTime = t->High; | ||
| 498 | SetFileTime(outFile.handle, NULL, NULL, &mTime); | ||
| 499 | } | ||
| 500 | #endif | ||
| 501 | |||
| 502 | { | ||
| 503 | SRes res2 = File_Close(&outFile); | ||
| 504 | if (res != SZ_OK) | ||
| 505 | break; | ||
| 506 | if (res2 != SZ_OK) | ||
| 507 | { | ||
| 508 | res = res2; | ||
| 509 | break; | ||
| 510 | } | ||
| 511 | } | ||
| 512 | #ifdef USE_WINDOWS_FILE | ||
| 513 | if (SzBitWithVals_Check(&db.Attribs, i)) | ||
| 514 | SetFileAttributesW(path, db.Attribs.Vals[i]); | ||
| 515 | #endif | ||
| 516 | } | ||
| 517 | } | ||
| 518 | |||
| 519 | if (res == SZ_OK) | ||
| 520 | { | ||
| 521 | if (executeFileIndex == (UInt32)(Int32)-1) | ||
| 522 | { | ||
| 523 | errorMessage = "There is no file to execute"; | ||
| 524 | res = SZ_ERROR_FAIL; | ||
| 525 | } | ||
| 526 | else | ||
| 527 | { | ||
| 528 | WCHAR *temp = path + pathLen; | ||
| 529 | UInt32 j; | ||
| 530 | SzArEx_GetFileNameUtf16(&db, executeFileIndex, (UInt16 *)temp); | ||
| 531 | for (j = 0; temp[j] != 0; j++) | ||
| 532 | if (temp[j] == '/') | ||
| 533 | temp[j] = CHAR_PATH_SEPARATOR; | ||
| 534 | } | ||
| 535 | } | ||
| 536 | ISzAlloc_Free(&allocImp, outBuffer); | ||
| 537 | } | ||
| 538 | |||
| 539 | SzArEx_Free(&db, &allocImp); | ||
| 540 | |||
| 541 | ISzAlloc_Free(&allocImp, lookStream.buf); | ||
| 542 | |||
| 543 | File_Close(&archiveStream.file); | ||
| 544 | |||
| 545 | if (res == SZ_OK) | ||
| 546 | { | ||
| 547 | HANDLE hProcess = 0; | ||
| 548 | |||
| 549 | #ifndef UNDER_CE | ||
| 550 | WCHAR oldCurDir[MAX_PATH + 2]; | ||
| 551 | oldCurDir[0] = 0; | ||
| 552 | { | ||
| 553 | DWORD needLen = GetCurrentDirectory(MAX_PATH + 1, oldCurDir); | ||
| 554 | if (needLen == 0 || needLen > MAX_PATH) | ||
| 555 | oldCurDir[0] = 0; | ||
| 556 | SetCurrentDirectory(workCurDir); | ||
| 557 | } | ||
| 558 | #endif | ||
| 559 | |||
| 560 | if (useShellExecute) | ||
| 561 | { | ||
| 562 | SHELLEXECUTEINFO ei; | ||
| 563 | UINT32 executeRes; | ||
| 564 | BOOL success; | ||
| 565 | |||
| 566 | memset(&ei, 0, sizeof(ei)); | ||
| 567 | ei.cbSize = sizeof(ei); | ||
| 568 | ei.lpFile = path; | ||
| 569 | ei.fMask = SEE_MASK_NOCLOSEPROCESS | ||
| 570 | #ifndef UNDER_CE | ||
| 571 | | SEE_MASK_FLAG_DDEWAIT | ||
| 572 | #endif | ||
| 573 | /* | SEE_MASK_NO_CONSOLE */ | ||
| 574 | ; | ||
| 575 | if (wcslen(cmdLineParams) != 0) | ||
| 576 | ei.lpParameters = cmdLineParams; | ||
| 577 | ei.nShow = SW_SHOWNORMAL; /* SW_HIDE; */ | ||
| 578 | success = ShellExecuteEx(&ei); | ||
| 579 | executeRes = (UINT32)(UINT_PTR)ei.hInstApp; | ||
| 580 | if (!success || (executeRes <= 32 && executeRes != 0)) /* executeRes = 0 in Windows CE */ | ||
| 581 | res = SZ_ERROR_FAIL; | ||
| 582 | else | ||
| 583 | hProcess = ei.hProcess; | ||
| 584 | } | ||
| 585 | else | ||
| 586 | { | ||
| 587 | STARTUPINFOW si; | ||
| 588 | PROCESS_INFORMATION pi; | ||
| 589 | WCHAR cmdLine[MAX_PATH * 3]; | ||
| 590 | |||
| 591 | wcscpy(cmdLine, path); | ||
| 592 | wcscat(cmdLine, cmdLineParams); | ||
| 593 | memset(&si, 0, sizeof(si)); | ||
| 594 | si.cb = sizeof(si); | ||
| 595 | if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0) | ||
| 596 | res = SZ_ERROR_FAIL; | ||
| 597 | else | ||
| 598 | { | ||
| 599 | CloseHandle(pi.hThread); | ||
| 600 | hProcess = pi.hProcess; | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | if (hProcess != 0) | ||
| 605 | { | ||
| 606 | WaitForSingleObject(hProcess, INFINITE); | ||
| 607 | if (!GetExitCodeProcess(hProcess, &exitCode)) | ||
| 608 | exitCode = 1; | ||
| 609 | CloseHandle(hProcess); | ||
| 610 | } | ||
| 611 | |||
| 612 | #ifndef UNDER_CE | ||
| 613 | SetCurrentDirectory(oldCurDir); | ||
| 614 | #endif | ||
| 615 | } | ||
| 616 | |||
| 617 | path[pathLen] = L'\0'; | ||
| 618 | RemoveDirWithSubItems(path); | ||
| 619 | |||
| 620 | if (res == SZ_OK) | ||
| 621 | return (int)exitCode; | ||
| 622 | |||
| 623 | { | ||
| 624 | if (res == SZ_ERROR_UNSUPPORTED) | ||
| 625 | errorMessage = "Decoder doesn't support this archive"; | ||
| 626 | else if (res == SZ_ERROR_MEM) | ||
| 627 | errorMessage = "Can't allocate required memory"; | ||
| 628 | else if (res == SZ_ERROR_CRC) | ||
| 629 | errorMessage = "CRC error"; | ||
| 630 | else | ||
| 631 | { | ||
| 632 | if (!errorMessage) | ||
| 633 | errorMessage = "ERROR"; | ||
| 634 | } | ||
| 635 | |||
| 636 | if (errorMessage) | ||
| 637 | PrintErrorMessage(errorMessage); | ||
| 638 | } | ||
| 639 | return 1; | ||
| 640 | } | ||
diff --git a/C/Util/SfxSetup/SfxSetup.dsp b/C/Util/SfxSetup/SfxSetup.dsp new file mode 100644 index 0000000..60439a6 --- /dev/null +++ b/C/Util/SfxSetup/SfxSetup.dsp | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | # Microsoft Developer Studio Project File - Name="SfxSetup" - Package Owner=<4> | ||
| 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 | ||
| 3 | # ** DO NOT EDIT ** | ||
| 4 | |||
| 5 | # TARGTYPE "Win32 (x86) Application" 0x0101 | ||
| 6 | |||
| 7 | CFG=SfxSetup - Win32 Debug | ||
| 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, | ||
| 9 | !MESSAGE use the Export Makefile command and run | ||
| 10 | !MESSAGE | ||
| 11 | !MESSAGE NMAKE /f "SfxSetup.mak". | ||
| 12 | !MESSAGE | ||
| 13 | !MESSAGE You can specify a configuration when running NMAKE | ||
| 14 | !MESSAGE by defining the macro CFG on the command line. For example: | ||
| 15 | !MESSAGE | ||
| 16 | !MESSAGE NMAKE /f "SfxSetup.mak" CFG="SfxSetup - Win32 Debug" | ||
| 17 | !MESSAGE | ||
| 18 | !MESSAGE Possible choices for configuration are: | ||
| 19 | !MESSAGE | ||
| 20 | !MESSAGE "SfxSetup - Win32 Release" (based on "Win32 (x86) Application") | ||
| 21 | !MESSAGE "SfxSetup - Win32 Debug" (based on "Win32 (x86) Application") | ||
| 22 | !MESSAGE | ||
| 23 | |||
| 24 | # Begin Project | ||
| 25 | # PROP AllowPerConfigDependencies 0 | ||
| 26 | # PROP Scc_ProjName "" | ||
| 27 | # PROP Scc_LocalPath "" | ||
| 28 | CPP=cl.exe | ||
| 29 | MTL=midl.exe | ||
| 30 | RSC=rc.exe | ||
| 31 | |||
| 32 | !IF "$(CFG)" == "SfxSetup - Win32 Release" | ||
| 33 | |||
| 34 | # PROP BASE Use_MFC 0 | ||
| 35 | # PROP BASE Use_Debug_Libraries 0 | ||
| 36 | # PROP BASE Output_Dir "Release" | ||
| 37 | # PROP BASE Intermediate_Dir "Release" | ||
| 38 | # PROP BASE Target_Dir "" | ||
| 39 | # PROP Use_MFC 0 | ||
| 40 | # PROP Use_Debug_Libraries 0 | ||
| 41 | # PROP Output_Dir "Release" | ||
| 42 | # PROP Intermediate_Dir "Release" | ||
| 43 | # PROP Target_Dir "" | ||
| 44 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c | ||
| 45 | # ADD CPP /nologo /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /c | ||
| 46 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | ||
| 47 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | ||
| 48 | # ADD BASE RSC /l 0x419 /d "NDEBUG" | ||
| 49 | # ADD RSC /l 0x419 /d "NDEBUG" | ||
| 50 | BSC32=bscmake.exe | ||
| 51 | # ADD BASE BSC32 /nologo | ||
| 52 | # ADD BSC32 /nologo | ||
| 53 | LINK32=link.exe | ||
| 54 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 | ||
| 55 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 | ||
| 56 | |||
| 57 | !ELSEIF "$(CFG)" == "SfxSetup - Win32 Debug" | ||
| 58 | |||
| 59 | # PROP BASE Use_MFC 0 | ||
| 60 | # PROP BASE Use_Debug_Libraries 1 | ||
| 61 | # PROP BASE Output_Dir "Debug" | ||
| 62 | # PROP BASE Intermediate_Dir "Debug" | ||
| 63 | # PROP BASE Target_Dir "" | ||
| 64 | # PROP Use_MFC 0 | ||
| 65 | # PROP Use_Debug_Libraries 1 | ||
| 66 | # PROP Output_Dir "Debug" | ||
| 67 | # PROP Intermediate_Dir "Debug" | ||
| 68 | # PROP Ignore_Export_Lib 0 | ||
| 69 | # PROP Target_Dir "" | ||
| 70 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c | ||
| 71 | # ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c | ||
| 72 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | ||
| 73 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | ||
| 74 | # ADD BASE RSC /l 0x419 /d "_DEBUG" | ||
| 75 | # ADD RSC /l 0x419 /d "_DEBUG" | ||
| 76 | BSC32=bscmake.exe | ||
| 77 | # ADD BASE BSC32 /nologo | ||
| 78 | # ADD BSC32 /nologo | ||
| 79 | LINK32=link.exe | ||
| 80 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept | ||
| 81 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept | ||
| 82 | |||
| 83 | !ENDIF | ||
| 84 | |||
| 85 | # Begin Target | ||
| 86 | |||
| 87 | # Name "SfxSetup - Win32 Release" | ||
| 88 | # Name "SfxSetup - Win32 Debug" | ||
| 89 | # Begin Group "Common" | ||
| 90 | |||
| 91 | # PROP Default_Filter "" | ||
| 92 | # Begin Source File | ||
| 93 | |||
| 94 | SOURCE=..\..\7z.h | ||
| 95 | # End Source File | ||
| 96 | # Begin Source File | ||
| 97 | |||
| 98 | SOURCE=..\..\7zAlloc.c | ||
| 99 | # End Source File | ||
| 100 | # Begin Source File | ||
| 101 | |||
| 102 | SOURCE=..\..\7zAlloc.h | ||
| 103 | # End Source File | ||
| 104 | # Begin Source File | ||
| 105 | |||
| 106 | SOURCE=..\..\7zArcIn.c | ||
| 107 | # End Source File | ||
| 108 | # Begin Source File | ||
| 109 | |||
| 110 | SOURCE=..\..\7zBuf.c | ||
| 111 | # End Source File | ||
| 112 | # Begin Source File | ||
| 113 | |||
| 114 | SOURCE=..\..\7zBuf.h | ||
| 115 | # End Source File | ||
| 116 | # Begin Source File | ||
| 117 | |||
| 118 | SOURCE=..\..\7zCrc.c | ||
| 119 | # End Source File | ||
| 120 | # Begin Source File | ||
| 121 | |||
| 122 | SOURCE=..\..\7zCrc.h | ||
| 123 | # End Source File | ||
| 124 | # Begin Source File | ||
| 125 | |||
| 126 | SOURCE=..\..\7zCrcOpt.c | ||
| 127 | # End Source File | ||
| 128 | # Begin Source File | ||
| 129 | |||
| 130 | SOURCE=..\..\7zDec.c | ||
| 131 | # End Source File | ||
| 132 | # Begin Source File | ||
| 133 | |||
| 134 | SOURCE=..\..\7zFile.c | ||
| 135 | # End Source File | ||
| 136 | # Begin Source File | ||
| 137 | |||
| 138 | SOURCE=..\..\7zFile.h | ||
| 139 | # End Source File | ||
| 140 | # Begin Source File | ||
| 141 | |||
| 142 | SOURCE=..\..\7zStream.c | ||
| 143 | # End Source File | ||
| 144 | # Begin Source File | ||
| 145 | |||
| 146 | SOURCE=..\..\7zTypes.h | ||
| 147 | # End Source File | ||
| 148 | # Begin Source File | ||
| 149 | |||
| 150 | SOURCE=..\..\Bcj2.c | ||
| 151 | # End Source File | ||
| 152 | # Begin Source File | ||
| 153 | |||
| 154 | SOURCE=..\..\Bcj2.h | ||
| 155 | # End Source File | ||
| 156 | # Begin Source File | ||
| 157 | |||
| 158 | SOURCE=..\..\Bra.c | ||
| 159 | # End Source File | ||
| 160 | # Begin Source File | ||
| 161 | |||
| 162 | SOURCE=..\..\Bra.h | ||
| 163 | # End Source File | ||
| 164 | # Begin Source File | ||
| 165 | |||
| 166 | SOURCE=..\..\Bra86.c | ||
| 167 | # End Source File | ||
| 168 | # Begin Source File | ||
| 169 | |||
| 170 | SOURCE=..\..\BraIA64.c | ||
| 171 | # End Source File | ||
| 172 | # Begin Source File | ||
| 173 | |||
| 174 | SOURCE=..\..\CpuArch.c | ||
| 175 | # End Source File | ||
| 176 | # Begin Source File | ||
| 177 | |||
| 178 | SOURCE=..\..\CpuArch.h | ||
| 179 | # End Source File | ||
| 180 | # Begin Source File | ||
| 181 | |||
| 182 | SOURCE=..\..\Delta.c | ||
| 183 | # End Source File | ||
| 184 | # Begin Source File | ||
| 185 | |||
| 186 | SOURCE=..\..\Delta.h | ||
| 187 | # End Source File | ||
| 188 | # Begin Source File | ||
| 189 | |||
| 190 | SOURCE=..\..\DllSecur.c | ||
| 191 | # End Source File | ||
| 192 | # Begin Source File | ||
| 193 | |||
| 194 | SOURCE=..\..\DllSecur.h | ||
| 195 | # End Source File | ||
| 196 | # Begin Source File | ||
| 197 | |||
| 198 | SOURCE=..\..\Lzma2Dec.c | ||
| 199 | # End Source File | ||
| 200 | # Begin Source File | ||
| 201 | |||
| 202 | SOURCE=..\..\Lzma2Dec.h | ||
| 203 | # End Source File | ||
| 204 | # Begin Source File | ||
| 205 | |||
| 206 | SOURCE=..\..\LzmaDec.c | ||
| 207 | # End Source File | ||
| 208 | # Begin Source File | ||
| 209 | |||
| 210 | SOURCE=..\..\LzmaDec.h | ||
| 211 | # End Source File | ||
| 212 | # End Group | ||
| 213 | # Begin Group "Spec" | ||
| 214 | |||
| 215 | # PROP Default_Filter "" | ||
| 216 | # Begin Source File | ||
| 217 | |||
| 218 | SOURCE=.\Precomp.c | ||
| 219 | # ADD CPP /Yc"Precomp.h" | ||
| 220 | # End Source File | ||
| 221 | # Begin Source File | ||
| 222 | |||
| 223 | SOURCE=.\Precomp.h | ||
| 224 | # End Source File | ||
| 225 | # End Group | ||
| 226 | # Begin Source File | ||
| 227 | |||
| 228 | SOURCE=.\SfxSetup.c | ||
| 229 | # End Source File | ||
| 230 | # End Target | ||
| 231 | # End Project | ||
diff --git a/C/Util/SfxSetup/SfxSetup.dsw b/C/Util/SfxSetup/SfxSetup.dsw new file mode 100644 index 0000000..ea23111 --- /dev/null +++ b/C/Util/SfxSetup/SfxSetup.dsw | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 | ||
| 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! | ||
| 3 | |||
| 4 | ############################################################################### | ||
| 5 | |||
| 6 | Project: "SfxSetup"=.\SfxSetup.dsp - Package Owner=<4> | ||
| 7 | |||
| 8 | Package=<5> | ||
| 9 | {{{ | ||
| 10 | }}} | ||
| 11 | |||
| 12 | Package=<4> | ||
| 13 | {{{ | ||
| 14 | }}} | ||
| 15 | |||
| 16 | ############################################################################### | ||
| 17 | |||
| 18 | Global: | ||
| 19 | |||
| 20 | Package=<5> | ||
| 21 | {{{ | ||
| 22 | }}} | ||
| 23 | |||
| 24 | Package=<3> | ||
| 25 | {{{ | ||
| 26 | }}} | ||
| 27 | |||
| 28 | ############################################################################### | ||
| 29 | |||
diff --git a/C/Util/SfxSetup/makefile b/C/Util/SfxSetup/makefile new file mode 100644 index 0000000..544da67 --- /dev/null +++ b/C/Util/SfxSetup/makefile | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | PROG = 7zS2.sfx | ||
| 2 | MY_FIXED = 1 | ||
| 3 | |||
| 4 | C_OBJS = \ | ||
| 5 | $O\7zAlloc.obj \ | ||
| 6 | $O\7zArcIn.obj \ | ||
| 7 | $O\7zBuf.obj \ | ||
| 8 | $O\7zBuf2.obj \ | ||
| 9 | $O\7zCrc.obj \ | ||
| 10 | $O\7zCrcOpt.obj \ | ||
| 11 | $O\7zFile.obj \ | ||
| 12 | $O\7zDec.obj \ | ||
| 13 | $O\7zStream.obj \ | ||
| 14 | $O\Bcj2.obj \ | ||
| 15 | $O\Bra.obj \ | ||
| 16 | $O\Bra86.obj \ | ||
| 17 | $O\BraIA64.obj \ | ||
| 18 | $O\CpuArch.obj \ | ||
| 19 | $O\Delta.obj \ | ||
| 20 | $O\DllSecur.obj \ | ||
| 21 | $O\Lzma2Dec.obj \ | ||
| 22 | $O\LzmaDec.obj \ | ||
| 23 | |||
| 24 | 7Z_OBJS = \ | ||
| 25 | $O\SfxSetup.obj \ | ||
| 26 | |||
| 27 | OBJS = \ | ||
| 28 | $(7Z_OBJS) \ | ||
| 29 | $(C_OBJS) \ | ||
| 30 | $O\resource.res | ||
| 31 | |||
| 32 | !include "../../../CPP/Build.mak" | ||
| 33 | |||
| 34 | $(7Z_OBJS): $(*B).c | ||
| 35 | $(COMPL_O1) | ||
| 36 | $(C_OBJS): ../../$(*B).c | ||
| 37 | $(COMPL_O1) | ||
diff --git a/C/Util/SfxSetup/makefile_con b/C/Util/SfxSetup/makefile_con new file mode 100644 index 0000000..d0f8352 --- /dev/null +++ b/C/Util/SfxSetup/makefile_con | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | PROG = 7zS2con.sfx | ||
| 2 | MY_FIXED = 1 | ||
| 3 | CFLAGS = $(CFLAGS) -D_CONSOLE | ||
| 4 | |||
| 5 | C_OBJS = \ | ||
| 6 | $O\7zAlloc.obj \ | ||
| 7 | $O\7zArcIn.obj \ | ||
| 8 | $O\7zBuf.obj \ | ||
| 9 | $O\7zBuf2.obj \ | ||
| 10 | $O\7zCrc.obj \ | ||
| 11 | $O\7zCrcOpt.obj \ | ||
| 12 | $O\7zFile.obj \ | ||
| 13 | $O\7zDec.obj \ | ||
| 14 | $O\7zStream.obj \ | ||
| 15 | $O\Bcj2.obj \ | ||
| 16 | $O\Bra.obj \ | ||
| 17 | $O\Bra86.obj \ | ||
| 18 | $O\BraIA64.obj \ | ||
| 19 | $O\CpuArch.obj \ | ||
| 20 | $O\Delta.obj \ | ||
| 21 | $O\DllSecur.obj \ | ||
| 22 | $O\Lzma2Dec.obj \ | ||
| 23 | $O\LzmaDec.obj \ | ||
| 24 | |||
| 25 | 7Z_OBJS = \ | ||
| 26 | $O\SfxSetup.obj \ | ||
| 27 | |||
| 28 | OBJS = \ | ||
| 29 | $(7Z_OBJS) \ | ||
| 30 | $(C_OBJS) \ | ||
| 31 | $O\resource.res | ||
| 32 | |||
| 33 | !include "../../../CPP/Build.mak" | ||
| 34 | |||
| 35 | $(7Z_OBJS): $(*B).c | ||
| 36 | $(COMPL_O1) | ||
| 37 | $(C_OBJS): ../../$(*B).c | ||
| 38 | $(COMPL_O1) | ||
diff --git a/C/Util/SfxSetup/resource.rc b/C/Util/SfxSetup/resource.rc new file mode 100644 index 0000000..0c1637f --- /dev/null +++ b/C/Util/SfxSetup/resource.rc | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | #include "../../7zVersion.rc" | ||
| 2 | |||
| 3 | MY_VERSION_INFO_APP("7z Setup SFX small", "7zS2.sfx") | ||
| 4 | |||
| 5 | 1 ICON "setup.ico" | ||
diff --git a/C/Util/SfxSetup/setup.ico b/C/Util/SfxSetup/setup.ico new file mode 100644 index 0000000..dbb6ca8 --- /dev/null +++ b/C/Util/SfxSetup/setup.ico | |||
| Binary files differ | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | /* Xz.c - Xz | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "7zCrc.h" | ||
| 7 | #include "CpuArch.h" | ||
| 8 | #include "Xz.h" | ||
| 9 | #include "XzCrc64.h" | ||
| 10 | |||
| 11 | const Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; | ||
| 12 | /* const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; */ | ||
| 13 | |||
| 14 | unsigned Xz_WriteVarInt(Byte *buf, UInt64 v) | ||
| 15 | { | ||
| 16 | unsigned i = 0; | ||
| 17 | do | ||
| 18 | { | ||
| 19 | buf[i++] = (Byte)((v & 0x7F) | 0x80); | ||
| 20 | v >>= 7; | ||
| 21 | } | ||
| 22 | while (v != 0); | ||
| 23 | buf[(size_t)i - 1] &= 0x7F; | ||
| 24 | return i; | ||
| 25 | } | ||
| 26 | |||
| 27 | void Xz_Construct(CXzStream *p) | ||
| 28 | { | ||
| 29 | p->numBlocks = 0; | ||
| 30 | p->blocks = NULL; | ||
| 31 | p->flags = 0; | ||
| 32 | } | ||
| 33 | |||
| 34 | void Xz_Free(CXzStream *p, ISzAllocPtr alloc) | ||
| 35 | { | ||
| 36 | ISzAlloc_Free(alloc, p->blocks); | ||
| 37 | p->numBlocks = 0; | ||
| 38 | p->blocks = NULL; | ||
| 39 | } | ||
| 40 | |||
| 41 | unsigned XzFlags_GetCheckSize(CXzStreamFlags f) | ||
| 42 | { | ||
| 43 | unsigned t = XzFlags_GetCheckType(f); | ||
| 44 | return (t == 0) ? 0 : ((unsigned)4 << ((t - 1) / 3)); | ||
| 45 | } | ||
| 46 | |||
| 47 | void XzCheck_Init(CXzCheck *p, unsigned mode) | ||
| 48 | { | ||
| 49 | p->mode = mode; | ||
| 50 | switch (mode) | ||
| 51 | { | ||
| 52 | case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break; | ||
| 53 | case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break; | ||
| 54 | case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | void XzCheck_Update(CXzCheck *p, const void *data, size_t size) | ||
| 59 | { | ||
| 60 | switch (p->mode) | ||
| 61 | { | ||
| 62 | case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break; | ||
| 63 | case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break; | ||
| 64 | case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | int XzCheck_Final(CXzCheck *p, Byte *digest) | ||
| 69 | { | ||
| 70 | switch (p->mode) | ||
| 71 | { | ||
| 72 | case XZ_CHECK_CRC32: | ||
| 73 | SetUi32(digest, CRC_GET_DIGEST(p->crc)); | ||
| 74 | break; | ||
| 75 | case XZ_CHECK_CRC64: | ||
| 76 | { | ||
| 77 | int i; | ||
| 78 | UInt64 v = CRC64_GET_DIGEST(p->crc64); | ||
| 79 | for (i = 0; i < 8; i++, v >>= 8) | ||
| 80 | digest[i] = (Byte)(v & 0xFF); | ||
| 81 | break; | ||
| 82 | } | ||
| 83 | case XZ_CHECK_SHA256: | ||
| 84 | Sha256_Final(&p->sha, digest); | ||
| 85 | break; | ||
| 86 | default: | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | return 1; | ||
| 90 | } | ||
| @@ -0,0 +1,517 @@ | |||
| 1 | /* Xz.h - Xz interface | ||
| 2 | 2021-04-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __XZ_H | ||
| 5 | #define __XZ_H | ||
| 6 | |||
| 7 | #include "Sha256.h" | ||
| 8 | |||
| 9 | EXTERN_C_BEGIN | ||
| 10 | |||
| 11 | #define XZ_ID_Subblock 1 | ||
| 12 | #define XZ_ID_Delta 3 | ||
| 13 | #define XZ_ID_X86 4 | ||
| 14 | #define XZ_ID_PPC 5 | ||
| 15 | #define XZ_ID_IA64 6 | ||
| 16 | #define XZ_ID_ARM 7 | ||
| 17 | #define XZ_ID_ARMT 8 | ||
| 18 | #define XZ_ID_SPARC 9 | ||
| 19 | #define XZ_ID_LZMA2 0x21 | ||
| 20 | |||
| 21 | unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value); | ||
| 22 | unsigned Xz_WriteVarInt(Byte *buf, UInt64 v); | ||
| 23 | |||
| 24 | /* ---------- xz block ---------- */ | ||
| 25 | |||
| 26 | #define XZ_BLOCK_HEADER_SIZE_MAX 1024 | ||
| 27 | |||
| 28 | #define XZ_NUM_FILTERS_MAX 4 | ||
| 29 | #define XZ_BF_NUM_FILTERS_MASK 3 | ||
| 30 | #define XZ_BF_PACK_SIZE (1 << 6) | ||
| 31 | #define XZ_BF_UNPACK_SIZE (1 << 7) | ||
| 32 | |||
| 33 | #define XZ_FILTER_PROPS_SIZE_MAX 20 | ||
| 34 | |||
| 35 | typedef struct | ||
| 36 | { | ||
| 37 | UInt64 id; | ||
| 38 | UInt32 propsSize; | ||
| 39 | Byte props[XZ_FILTER_PROPS_SIZE_MAX]; | ||
| 40 | } CXzFilter; | ||
| 41 | |||
| 42 | typedef struct | ||
| 43 | { | ||
| 44 | UInt64 packSize; | ||
| 45 | UInt64 unpackSize; | ||
| 46 | Byte flags; | ||
| 47 | CXzFilter filters[XZ_NUM_FILTERS_MAX]; | ||
| 48 | } CXzBlock; | ||
| 49 | |||
| 50 | #define XzBlock_GetNumFilters(p) (((unsigned)(p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1) | ||
| 51 | #define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0) | ||
| 52 | #define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0) | ||
| 53 | #define XzBlock_HasUnsupportedFlags(p) (((p)->flags & ~(XZ_BF_NUM_FILTERS_MASK | XZ_BF_PACK_SIZE | XZ_BF_UNPACK_SIZE)) != 0) | ||
| 54 | |||
| 55 | SRes XzBlock_Parse(CXzBlock *p, const Byte *header); | ||
| 56 | SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, BoolInt *isIndex, UInt32 *headerSizeRes); | ||
| 57 | |||
| 58 | /* ---------- xz stream ---------- */ | ||
| 59 | |||
| 60 | #define XZ_SIG_SIZE 6 | ||
| 61 | #define XZ_FOOTER_SIG_SIZE 2 | ||
| 62 | |||
| 63 | extern const Byte XZ_SIG[XZ_SIG_SIZE]; | ||
| 64 | |||
| 65 | /* | ||
| 66 | extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; | ||
| 67 | */ | ||
| 68 | |||
| 69 | #define XZ_FOOTER_SIG_0 'Y' | ||
| 70 | #define XZ_FOOTER_SIG_1 'Z' | ||
| 71 | |||
| 72 | #define XZ_STREAM_FLAGS_SIZE 2 | ||
| 73 | #define XZ_STREAM_CRC_SIZE 4 | ||
| 74 | |||
| 75 | #define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE) | ||
| 76 | #define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4) | ||
| 77 | |||
| 78 | #define XZ_CHECK_MASK 0xF | ||
| 79 | #define XZ_CHECK_NO 0 | ||
| 80 | #define XZ_CHECK_CRC32 1 | ||
| 81 | #define XZ_CHECK_CRC64 4 | ||
| 82 | #define XZ_CHECK_SHA256 10 | ||
| 83 | |||
| 84 | typedef struct | ||
| 85 | { | ||
| 86 | unsigned mode; | ||
| 87 | UInt32 crc; | ||
| 88 | UInt64 crc64; | ||
| 89 | CSha256 sha; | ||
| 90 | } CXzCheck; | ||
| 91 | |||
| 92 | void XzCheck_Init(CXzCheck *p, unsigned mode); | ||
| 93 | void XzCheck_Update(CXzCheck *p, const void *data, size_t size); | ||
| 94 | int XzCheck_Final(CXzCheck *p, Byte *digest); | ||
| 95 | |||
| 96 | typedef UInt16 CXzStreamFlags; | ||
| 97 | |||
| 98 | #define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK) | ||
| 99 | #define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK) | ||
| 100 | #define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32) | ||
| 101 | unsigned XzFlags_GetCheckSize(CXzStreamFlags f); | ||
| 102 | |||
| 103 | SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf); | ||
| 104 | SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream); | ||
| 105 | |||
| 106 | typedef struct | ||
| 107 | { | ||
| 108 | UInt64 unpackSize; | ||
| 109 | UInt64 totalSize; | ||
| 110 | } CXzBlockSizes; | ||
| 111 | |||
| 112 | typedef struct | ||
| 113 | { | ||
| 114 | CXzStreamFlags flags; | ||
| 115 | size_t numBlocks; | ||
| 116 | CXzBlockSizes *blocks; | ||
| 117 | UInt64 startOffset; | ||
| 118 | } CXzStream; | ||
| 119 | |||
| 120 | void Xz_Construct(CXzStream *p); | ||
| 121 | void Xz_Free(CXzStream *p, ISzAllocPtr alloc); | ||
| 122 | |||
| 123 | #define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1) | ||
| 124 | |||
| 125 | UInt64 Xz_GetUnpackSize(const CXzStream *p); | ||
| 126 | UInt64 Xz_GetPackSize(const CXzStream *p); | ||
| 127 | |||
| 128 | typedef struct | ||
| 129 | { | ||
| 130 | size_t num; | ||
| 131 | size_t numAllocated; | ||
| 132 | CXzStream *streams; | ||
| 133 | } CXzs; | ||
| 134 | |||
| 135 | void Xzs_Construct(CXzs *p); | ||
| 136 | void Xzs_Free(CXzs *p, ISzAllocPtr alloc); | ||
| 137 | SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAllocPtr alloc); | ||
| 138 | |||
| 139 | UInt64 Xzs_GetNumBlocks(const CXzs *p); | ||
| 140 | UInt64 Xzs_GetUnpackSize(const CXzs *p); | ||
| 141 | |||
| 142 | |||
| 143 | // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder | ||
| 144 | |||
| 145 | typedef enum | ||
| 146 | { | ||
| 147 | CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ | ||
| 148 | CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ | ||
| 149 | CODER_STATUS_NOT_FINISHED, /* stream was not finished */ | ||
| 150 | CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ | ||
| 151 | } ECoderStatus; | ||
| 152 | |||
| 153 | |||
| 154 | // ECoderFinishMode values are identical to ELzmaFinishMode | ||
| 155 | |||
| 156 | typedef enum | ||
| 157 | { | ||
| 158 | CODER_FINISH_ANY, /* finish at any point */ | ||
| 159 | CODER_FINISH_END /* block must be finished at the end */ | ||
| 160 | } ECoderFinishMode; | ||
| 161 | |||
| 162 | |||
| 163 | typedef struct _IStateCoder | ||
| 164 | { | ||
| 165 | void *p; | ||
| 166 | void (*Free)(void *p, ISzAllocPtr alloc); | ||
| 167 | SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAllocPtr alloc); | ||
| 168 | void (*Init)(void *p); | ||
| 169 | SRes (*Code2)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, | ||
| 170 | int srcWasFinished, ECoderFinishMode finishMode, | ||
| 171 | // int *wasFinished, | ||
| 172 | ECoderStatus *status); | ||
| 173 | SizeT (*Filter)(void *p, Byte *data, SizeT size); | ||
| 174 | } IStateCoder; | ||
| 175 | |||
| 176 | |||
| 177 | |||
| 178 | #define MIXCODER_NUM_FILTERS_MAX 4 | ||
| 179 | |||
| 180 | typedef struct | ||
| 181 | { | ||
| 182 | ISzAllocPtr alloc; | ||
| 183 | Byte *buf; | ||
| 184 | unsigned numCoders; | ||
| 185 | |||
| 186 | Byte *outBuf; | ||
| 187 | size_t outBufSize; | ||
| 188 | size_t outWritten; // is equal to lzmaDecoder.dicPos (in outBuf mode) | ||
| 189 | BoolInt wasFinished; | ||
| 190 | SRes res; | ||
| 191 | ECoderStatus status; | ||
| 192 | // BoolInt SingleBufMode; | ||
| 193 | |||
| 194 | int finished[MIXCODER_NUM_FILTERS_MAX - 1]; | ||
| 195 | size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; | ||
| 196 | size_t size[MIXCODER_NUM_FILTERS_MAX - 1]; | ||
| 197 | UInt64 ids[MIXCODER_NUM_FILTERS_MAX]; | ||
| 198 | SRes results[MIXCODER_NUM_FILTERS_MAX]; | ||
| 199 | IStateCoder coders[MIXCODER_NUM_FILTERS_MAX]; | ||
| 200 | } CMixCoder; | ||
| 201 | |||
| 202 | |||
| 203 | typedef enum | ||
| 204 | { | ||
| 205 | XZ_STATE_STREAM_HEADER, | ||
| 206 | XZ_STATE_STREAM_INDEX, | ||
| 207 | XZ_STATE_STREAM_INDEX_CRC, | ||
| 208 | XZ_STATE_STREAM_FOOTER, | ||
| 209 | XZ_STATE_STREAM_PADDING, | ||
| 210 | XZ_STATE_BLOCK_HEADER, | ||
| 211 | XZ_STATE_BLOCK, | ||
| 212 | XZ_STATE_BLOCK_FOOTER | ||
| 213 | } EXzState; | ||
| 214 | |||
| 215 | |||
| 216 | typedef struct | ||
| 217 | { | ||
| 218 | EXzState state; | ||
| 219 | UInt32 pos; | ||
| 220 | unsigned alignPos; | ||
| 221 | unsigned indexPreSize; | ||
| 222 | |||
| 223 | CXzStreamFlags streamFlags; | ||
| 224 | |||
| 225 | UInt32 blockHeaderSize; | ||
| 226 | UInt64 packSize; | ||
| 227 | UInt64 unpackSize; | ||
| 228 | |||
| 229 | UInt64 numBlocks; // number of finished blocks in current stream | ||
| 230 | UInt64 indexSize; | ||
| 231 | UInt64 indexPos; | ||
| 232 | UInt64 padSize; | ||
| 233 | |||
| 234 | UInt64 numStartedStreams; | ||
| 235 | UInt64 numFinishedStreams; | ||
| 236 | UInt64 numTotalBlocks; | ||
| 237 | |||
| 238 | UInt32 crc; | ||
| 239 | CMixCoder decoder; | ||
| 240 | CXzBlock block; | ||
| 241 | CXzCheck check; | ||
| 242 | CSha256 sha; | ||
| 243 | |||
| 244 | BoolInt parseMode; | ||
| 245 | BoolInt headerParsedOk; | ||
| 246 | BoolInt decodeToStreamSignature; | ||
| 247 | unsigned decodeOnlyOneBlock; | ||
| 248 | |||
| 249 | Byte *outBuf; | ||
| 250 | size_t outBufSize; | ||
| 251 | size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked | ||
| 252 | |||
| 253 | Byte shaDigest[SHA256_DIGEST_SIZE]; | ||
| 254 | Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; | ||
| 255 | } CXzUnpacker; | ||
| 256 | |||
| 257 | /* alloc : aligned for cache line allocation is better */ | ||
| 258 | void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc); | ||
| 259 | void XzUnpacker_Init(CXzUnpacker *p); | ||
| 260 | void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize); | ||
| 261 | void XzUnpacker_Free(CXzUnpacker *p); | ||
| 262 | |||
| 263 | /* | ||
| 264 | XzUnpacker | ||
| 265 | The sequence for decoding functions: | ||
| 266 | { | ||
| 267 | XzUnpacker_Construct() | ||
| 268 | [Decoding_Calls] | ||
| 269 | XzUnpacker_Free() | ||
| 270 | } | ||
| 271 | |||
| 272 | [Decoding_Calls] | ||
| 273 | |||
| 274 | There are 3 types of interfaces for [Decoding_Calls] calls: | ||
| 275 | |||
| 276 | Interface-1 : Partial output buffers: | ||
| 277 | { | ||
| 278 | XzUnpacker_Init() | ||
| 279 | for() | ||
| 280 | { | ||
| 281 | XzUnpacker_Code(); | ||
| 282 | } | ||
| 283 | XzUnpacker_IsStreamWasFinished() | ||
| 284 | } | ||
| 285 | |||
| 286 | Interface-2 : Direct output buffer: | ||
| 287 | Use it, if you know exact size of decoded data, and you need | ||
| 288 | whole xz unpacked data in one output buffer. | ||
| 289 | xz unpacker doesn't allocate additional buffer for lzma2 dictionary in that mode. | ||
| 290 | { | ||
| 291 | XzUnpacker_Init() | ||
| 292 | XzUnpacker_SetOutBufMode(); // to set output buffer and size | ||
| 293 | for() | ||
| 294 | { | ||
| 295 | XzUnpacker_Code(); // (dest = NULL) in XzUnpacker_Code() | ||
| 296 | } | ||
| 297 | XzUnpacker_IsStreamWasFinished() | ||
| 298 | } | ||
| 299 | |||
| 300 | Interface-3 : Direct output buffer : One call full decoding | ||
| 301 | It unpacks whole input buffer to output buffer in one call. | ||
| 302 | It uses Interface-2 internally. | ||
| 303 | { | ||
| 304 | XzUnpacker_CodeFull() | ||
| 305 | XzUnpacker_IsStreamWasFinished() | ||
| 306 | } | ||
| 307 | */ | ||
| 308 | |||
| 309 | /* | ||
| 310 | finishMode: | ||
| 311 | It has meaning only if the decoding reaches output limit (*destLen). | ||
| 312 | CODER_FINISH_ANY - use smallest number of input bytes | ||
| 313 | CODER_FINISH_END - read EndOfStream marker after decoding | ||
| 314 | |||
| 315 | Returns: | ||
| 316 | SZ_OK | ||
| 317 | status: | ||
| 318 | CODER_STATUS_NOT_FINISHED, | ||
| 319 | CODER_STATUS_NEEDS_MORE_INPUT - the decoder can return it in two cases: | ||
| 320 | 1) it needs more input data to finish current xz stream | ||
| 321 | 2) xz stream was finished successfully. But the decoder supports multiple | ||
| 322 | concatented xz streams. So it expects more input data for new xz streams. | ||
| 323 | Call XzUnpacker_IsStreamWasFinished() to check that latest xz stream was finished successfully. | ||
| 324 | |||
| 325 | SZ_ERROR_MEM - Memory allocation error | ||
| 326 | SZ_ERROR_DATA - Data error | ||
| 327 | SZ_ERROR_UNSUPPORTED - Unsupported method or method properties | ||
| 328 | SZ_ERROR_CRC - CRC error | ||
| 329 | // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). | ||
| 330 | |||
| 331 | SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons: | ||
| 332 | - xz Stream Signature failure | ||
| 333 | - CRC32 of xz Stream Header is failed | ||
| 334 | - The size of Stream padding is not multiple of four bytes. | ||
| 335 | It's possible to get that error, if xz stream was finished and the stream | ||
| 336 | contains some another data. In that case you can call XzUnpacker_GetExtraSize() | ||
| 337 | function to get real size of xz stream. | ||
| 338 | */ | ||
| 339 | |||
| 340 | |||
| 341 | SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, | ||
| 342 | const Byte *src, SizeT *srcLen, int srcFinished, | ||
| 343 | ECoderFinishMode finishMode, ECoderStatus *status); | ||
| 344 | |||
| 345 | SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, | ||
| 346 | const Byte *src, SizeT *srcLen, | ||
| 347 | ECoderFinishMode finishMode, ECoderStatus *status); | ||
| 348 | |||
| 349 | /* | ||
| 350 | If you decode full xz stream(s), then you can call XzUnpacker_IsStreamWasFinished() | ||
| 351 | after successful XzUnpacker_CodeFull() or after last call of XzUnpacker_Code(). | ||
| 352 | */ | ||
| 353 | |||
| 354 | BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p); | ||
| 355 | |||
| 356 | /* | ||
| 357 | XzUnpacker_GetExtraSize() returns then number of unconfirmed bytes, | ||
| 358 | if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state. | ||
| 359 | These bytes can be some data after xz archive, or | ||
| 360 | it can be start of new xz stream. | ||
| 361 | |||
| 362 | Call XzUnpacker_GetExtraSize() after XzUnpacker_Code() function to detect real size of | ||
| 363 | xz stream in two cases, if XzUnpacker_Code() returns: | ||
| 364 | res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT | ||
| 365 | res == SZ_ERROR_NO_ARCHIVE | ||
| 366 | */ | ||
| 367 | |||
| 368 | UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p); | ||
| 369 | |||
| 370 | |||
| 371 | /* | ||
| 372 | for random block decoding: | ||
| 373 | XzUnpacker_Init(); | ||
| 374 | set CXzUnpacker::streamFlags | ||
| 375 | XzUnpacker_PrepareToRandomBlockDecoding() | ||
| 376 | loop | ||
| 377 | { | ||
| 378 | XzUnpacker_Code() | ||
| 379 | XzUnpacker_IsBlockFinished() | ||
| 380 | } | ||
| 381 | */ | ||
| 382 | |||
| 383 | void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p); | ||
| 384 | BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p); | ||
| 385 | |||
| 386 | #define XzUnpacker_GetPackSizeForIndex(p) ((p)->packSize + (p)->blockHeaderSize + XzFlags_GetCheckSize((p)->streamFlags)) | ||
| 387 | |||
| 388 | |||
| 389 | |||
| 390 | |||
| 391 | |||
| 392 | |||
| 393 | /* ---- Single-Thread and Multi-Thread xz Decoding with Input/Output Streams ---- */ | ||
| 394 | |||
| 395 | /* | ||
| 396 | if (CXzDecMtProps::numThreads > 1), the decoder can try to use | ||
| 397 | Multi-Threading. The decoder analyses xz block header, and if | ||
| 398 | there are pack size and unpack size values stored in xz block header, | ||
| 399 | the decoder reads compressed data of block to internal buffers, | ||
| 400 | and then it can start parallel decoding, if there are another blocks. | ||
| 401 | The decoder can switch back to Single-Thread decoding after some conditions. | ||
| 402 | |||
| 403 | The sequence of calls for xz decoding with in/out Streams: | ||
| 404 | { | ||
| 405 | XzDecMt_Create() | ||
| 406 | XzDecMtProps_Init(XzDecMtProps) to set default values of properties | ||
| 407 | // then you can change some XzDecMtProps parameters with required values | ||
| 408 | // here you can set the number of threads and (memUseMax) - the maximum | ||
| 409 | Memory usage for multithreading decoding. | ||
| 410 | for() | ||
| 411 | { | ||
| 412 | XzDecMt_Decode() // one call per one file | ||
| 413 | } | ||
| 414 | XzDecMt_Destroy() | ||
| 415 | } | ||
| 416 | */ | ||
| 417 | |||
| 418 | |||
| 419 | typedef struct | ||
| 420 | { | ||
| 421 | size_t inBufSize_ST; // size of input buffer for Single-Thread decoding | ||
| 422 | size_t outStep_ST; // size of output buffer for Single-Thread decoding | ||
| 423 | BoolInt ignoreErrors; // if set to 1, the decoder can ignore some errors and it skips broken parts of data. | ||
| 424 | |||
| 425 | #ifndef _7ZIP_ST | ||
| 426 | unsigned numThreads; // the number of threads for Multi-Thread decoding. if (umThreads == 1) it will use Single-thread decoding | ||
| 427 | size_t inBufSize_MT; // size of small input data buffers for Multi-Thread decoding. Big number of such small buffers can be created | ||
| 428 | size_t memUseMax; // the limit of total memory usage for Multi-Thread decoding. | ||
| 429 | // it's recommended to set (memUseMax) manually to value that is smaller of total size of RAM in computer. | ||
| 430 | #endif | ||
| 431 | } CXzDecMtProps; | ||
| 432 | |||
| 433 | void XzDecMtProps_Init(CXzDecMtProps *p); | ||
| 434 | |||
| 435 | |||
| 436 | typedef void * CXzDecMtHandle; | ||
| 437 | |||
| 438 | /* | ||
| 439 | alloc : XzDecMt uses CAlignOffsetAlloc internally for addresses allocated by (alloc). | ||
| 440 | allocMid : for big allocations, aligned allocation is better | ||
| 441 | */ | ||
| 442 | |||
| 443 | CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); | ||
| 444 | void XzDecMt_Destroy(CXzDecMtHandle p); | ||
| 445 | |||
| 446 | |||
| 447 | typedef struct | ||
| 448 | { | ||
| 449 | Byte UnpackSize_Defined; | ||
| 450 | Byte NumStreams_Defined; | ||
| 451 | Byte NumBlocks_Defined; | ||
| 452 | |||
| 453 | Byte DataAfterEnd; // there are some additional data after good xz streams, and that data is not new xz stream. | ||
| 454 | Byte DecodingTruncated; // Decoding was Truncated, we need only partial output data | ||
| 455 | |||
| 456 | UInt64 InSize; // pack size processed. That value doesn't include the data after | ||
| 457 | // end of xz stream, if that data was not correct | ||
| 458 | UInt64 OutSize; | ||
| 459 | |||
| 460 | UInt64 NumStreams; | ||
| 461 | UInt64 NumBlocks; | ||
| 462 | |||
| 463 | SRes DecodeRes; // the error code of xz streams data decoding | ||
| 464 | SRes ReadRes; // error code from ISeqInStream:Read() | ||
| 465 | SRes ProgressRes; // error code from ICompressProgress:Progress() | ||
| 466 | |||
| 467 | SRes CombinedRes; // Combined result error code that shows main rusult | ||
| 468 | // = S_OK, if there is no error. | ||
| 469 | // but check also (DataAfterEnd) that can show additional minor errors. | ||
| 470 | |||
| 471 | SRes CombinedRes_Type; // = SZ_ERROR_READ, if error from ISeqInStream | ||
| 472 | // = SZ_ERROR_PROGRESS, if error from ICompressProgress | ||
| 473 | // = SZ_ERROR_WRITE, if error from ISeqOutStream | ||
| 474 | // = SZ_ERROR_* codes for decoding | ||
| 475 | } CXzStatInfo; | ||
| 476 | |||
| 477 | void XzStatInfo_Clear(CXzStatInfo *p); | ||
| 478 | |||
| 479 | /* | ||
| 480 | |||
| 481 | XzDecMt_Decode() | ||
| 482 | SRes: it's combined decoding result. It also is equal to stat->CombinedRes. | ||
| 483 | |||
| 484 | SZ_OK - no error | ||
| 485 | check also output value in (stat->DataAfterEnd) | ||
| 486 | that can show additional possible error | ||
| 487 | |||
| 488 | SZ_ERROR_MEM - Memory allocation error | ||
| 489 | SZ_ERROR_NO_ARCHIVE - is not xz archive | ||
| 490 | SZ_ERROR_ARCHIVE - Headers error | ||
| 491 | SZ_ERROR_DATA - Data Error | ||
| 492 | SZ_ERROR_UNSUPPORTED - Unsupported method or method properties | ||
| 493 | SZ_ERROR_CRC - CRC Error | ||
| 494 | SZ_ERROR_INPUT_EOF - it needs more input data | ||
| 495 | SZ_ERROR_WRITE - ISeqOutStream error | ||
| 496 | (SZ_ERROR_READ) - ISeqInStream errors | ||
| 497 | (SZ_ERROR_PROGRESS) - ICompressProgress errors | ||
| 498 | // SZ_ERROR_THREAD - error in multi-threading functions | ||
| 499 | MY_SRes_HRESULT_FROM_WRes(WRes_error) - error in multi-threading function | ||
| 500 | */ | ||
| 501 | |||
| 502 | SRes XzDecMt_Decode(CXzDecMtHandle p, | ||
| 503 | const CXzDecMtProps *props, | ||
| 504 | const UInt64 *outDataSize, // NULL means undefined | ||
| 505 | int finishMode, // 0 - partial unpacking is allowed, 1 - xz stream(s) must be finished | ||
| 506 | ISeqOutStream *outStream, | ||
| 507 | // Byte *outBuf, size_t *outBufSize, | ||
| 508 | ISeqInStream *inStream, | ||
| 509 | // const Byte *inData, size_t inDataSize, | ||
| 510 | CXzStatInfo *stat, // out: decoding results and statistics | ||
| 511 | int *isMT, // out: 0 means that ST (Single-Thread) version was used | ||
| 512 | // 1 means that MT (Multi-Thread) version was used | ||
| 513 | ICompressProgress *progress); | ||
| 514 | |||
| 515 | EXTERN_C_END | ||
| 516 | |||
| 517 | #endif | ||
diff --git a/C/XzCrc64.c b/C/XzCrc64.c new file mode 100644 index 0000000..b6d02cb --- /dev/null +++ b/C/XzCrc64.c | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | /* XzCrc64.c -- CRC64 calculation | ||
| 2 | 2017-05-23 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "XzCrc64.h" | ||
| 7 | #include "CpuArch.h" | ||
| 8 | |||
| 9 | #define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42) | ||
| 10 | |||
| 11 | #ifdef MY_CPU_LE | ||
| 12 | #define CRC64_NUM_TABLES 4 | ||
| 13 | #else | ||
| 14 | #define CRC64_NUM_TABLES 5 | ||
| 15 | #define CRC_UINT64_SWAP(v) \ | ||
| 16 | ((v >> 56) \ | ||
| 17 | | ((v >> 40) & ((UInt64)0xFF << 8)) \ | ||
| 18 | | ((v >> 24) & ((UInt64)0xFF << 16)) \ | ||
| 19 | | ((v >> 8) & ((UInt64)0xFF << 24)) \ | ||
| 20 | | ((v << 8) & ((UInt64)0xFF << 32)) \ | ||
| 21 | | ((v << 24) & ((UInt64)0xFF << 40)) \ | ||
| 22 | | ((v << 40) & ((UInt64)0xFF << 48)) \ | ||
| 23 | | ((v << 56))) | ||
| 24 | |||
| 25 | UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table); | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #ifndef MY_CPU_BE | ||
| 29 | UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table); | ||
| 30 | #endif | ||
| 31 | |||
| 32 | typedef UInt64 (MY_FAST_CALL *CRC64_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table); | ||
| 33 | |||
| 34 | static CRC64_FUNC g_Crc64Update; | ||
| 35 | UInt64 g_Crc64Table[256 * CRC64_NUM_TABLES]; | ||
| 36 | |||
| 37 | UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size) | ||
| 38 | { | ||
| 39 | return g_Crc64Update(v, data, size, g_Crc64Table); | ||
| 40 | } | ||
| 41 | |||
| 42 | UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size) | ||
| 43 | { | ||
| 44 | return g_Crc64Update(CRC64_INIT_VAL, data, size, g_Crc64Table) ^ CRC64_INIT_VAL; | ||
| 45 | } | ||
| 46 | |||
| 47 | void MY_FAST_CALL Crc64GenerateTable() | ||
| 48 | { | ||
| 49 | UInt32 i; | ||
| 50 | for (i = 0; i < 256; i++) | ||
| 51 | { | ||
| 52 | UInt64 r = i; | ||
| 53 | unsigned j; | ||
| 54 | for (j = 0; j < 8; j++) | ||
| 55 | r = (r >> 1) ^ (kCrc64Poly & ((UInt64)0 - (r & 1))); | ||
| 56 | g_Crc64Table[i] = r; | ||
| 57 | } | ||
| 58 | for (i = 256; i < 256 * CRC64_NUM_TABLES; i++) | ||
| 59 | { | ||
| 60 | UInt64 r = g_Crc64Table[(size_t)i - 256]; | ||
| 61 | g_Crc64Table[i] = g_Crc64Table[r & 0xFF] ^ (r >> 8); | ||
| 62 | } | ||
| 63 | |||
| 64 | #ifdef MY_CPU_LE | ||
| 65 | |||
| 66 | g_Crc64Update = XzCrc64UpdateT4; | ||
| 67 | |||
| 68 | #else | ||
| 69 | { | ||
| 70 | #ifndef MY_CPU_BE | ||
| 71 | UInt32 k = 1; | ||
| 72 | if (*(const Byte *)&k == 1) | ||
| 73 | g_Crc64Update = XzCrc64UpdateT4; | ||
| 74 | else | ||
| 75 | #endif | ||
| 76 | { | ||
| 77 | for (i = 256 * CRC64_NUM_TABLES - 1; i >= 256; i--) | ||
| 78 | { | ||
| 79 | UInt64 x = g_Crc64Table[(size_t)i - 256]; | ||
| 80 | g_Crc64Table[i] = CRC_UINT64_SWAP(x); | ||
| 81 | } | ||
| 82 | g_Crc64Update = XzCrc64UpdateT1_BeT4; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | #endif | ||
| 86 | } | ||
diff --git a/C/XzCrc64.h b/C/XzCrc64.h new file mode 100644 index 0000000..08dbc33 --- /dev/null +++ b/C/XzCrc64.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* XzCrc64.h -- CRC64 calculation | ||
| 2 | 2013-01-18 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __XZ_CRC64_H | ||
| 5 | #define __XZ_CRC64_H | ||
| 6 | |||
| 7 | #include <stddef.h> | ||
| 8 | |||
| 9 | #include "7zTypes.h" | ||
| 10 | |||
| 11 | EXTERN_C_BEGIN | ||
| 12 | |||
| 13 | extern UInt64 g_Crc64Table[]; | ||
| 14 | |||
| 15 | void MY_FAST_CALL Crc64GenerateTable(void); | ||
| 16 | |||
| 17 | #define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF) | ||
| 18 | #define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL) | ||
| 19 | #define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) | ||
| 20 | |||
| 21 | UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size); | ||
| 22 | UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size); | ||
| 23 | |||
| 24 | EXTERN_C_END | ||
| 25 | |||
| 26 | #endif | ||
diff --git a/C/XzCrc64Opt.c b/C/XzCrc64Opt.c new file mode 100644 index 0000000..93a9fff --- /dev/null +++ b/C/XzCrc64Opt.c | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | /* XzCrc64Opt.c -- CRC64 calculation | ||
| 2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include "CpuArch.h" | ||
| 7 | |||
| 8 | #ifndef MY_CPU_BE | ||
| 9 | |||
| 10 | #define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) | ||
| 11 | |||
| 12 | UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table); | ||
| 13 | UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table) | ||
| 14 | { | ||
| 15 | const Byte *p = (const Byte *)data; | ||
| 16 | for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) | ||
| 17 | v = CRC64_UPDATE_BYTE_2(v, *p); | ||
| 18 | for (; size >= 4; size -= 4, p += 4) | ||
| 19 | { | ||
| 20 | UInt32 d = (UInt32)v ^ *(const UInt32 *)(const void *)p; | ||
| 21 | v = (v >> 32) | ||
| 22 | ^ (table + 0x300)[((d ) & 0xFF)] | ||
| 23 | ^ (table + 0x200)[((d >> 8) & 0xFF)] | ||
| 24 | ^ (table + 0x100)[((d >> 16) & 0xFF)] | ||
| 25 | ^ (table + 0x000)[((d >> 24))]; | ||
| 26 | } | ||
| 27 | for (; size > 0; size--, p++) | ||
| 28 | v = CRC64_UPDATE_BYTE_2(v, *p); | ||
| 29 | return v; | ||
| 30 | } | ||
| 31 | |||
| 32 | #endif | ||
| 33 | |||
| 34 | |||
| 35 | #ifndef MY_CPU_LE | ||
| 36 | |||
| 37 | #define CRC_UINT64_SWAP(v) \ | ||
| 38 | ((v >> 56) \ | ||
| 39 | | ((v >> 40) & ((UInt64)0xFF << 8)) \ | ||
| 40 | | ((v >> 24) & ((UInt64)0xFF << 16)) \ | ||
| 41 | | ((v >> 8) & ((UInt64)0xFF << 24)) \ | ||
| 42 | | ((v << 8) & ((UInt64)0xFF << 32)) \ | ||
| 43 | | ((v << 24) & ((UInt64)0xFF << 40)) \ | ||
| 44 | | ((v << 40) & ((UInt64)0xFF << 48)) \ | ||
| 45 | | ((v << 56))) | ||
| 46 | |||
| 47 | #define CRC64_UPDATE_BYTE_2_BE(crc, b) (table[(Byte)((crc) >> 56) ^ (b)] ^ ((crc) << 8)) | ||
| 48 | |||
| 49 | UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table); | ||
| 50 | UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table) | ||
| 51 | { | ||
| 52 | const Byte *p = (const Byte *)data; | ||
| 53 | table += 0x100; | ||
| 54 | v = CRC_UINT64_SWAP(v); | ||
| 55 | for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) | ||
| 56 | v = CRC64_UPDATE_BYTE_2_BE(v, *p); | ||
| 57 | for (; size >= 4; size -= 4, p += 4) | ||
| 58 | { | ||
| 59 | UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)(const void *)p; | ||
| 60 | v = (v << 32) | ||
| 61 | ^ (table + 0x000)[((d ) & 0xFF)] | ||
| 62 | ^ (table + 0x100)[((d >> 8) & 0xFF)] | ||
| 63 | ^ (table + 0x200)[((d >> 16) & 0xFF)] | ||
| 64 | ^ (table + 0x300)[((d >> 24))]; | ||
| 65 | } | ||
| 66 | for (; size > 0; size--, p++) | ||
| 67 | v = CRC64_UPDATE_BYTE_2_BE(v, *p); | ||
| 68 | return CRC_UINT64_SWAP(v); | ||
| 69 | } | ||
| 70 | |||
| 71 | #endif | ||
diff --git a/C/XzDec.c b/C/XzDec.c new file mode 100644 index 0000000..3f96a37 --- /dev/null +++ b/C/XzDec.c | |||
| @@ -0,0 +1,2837 @@ | |||
| 1 | /* XzDec.c -- Xz Decode | ||
| 2 | 2021-09-04 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | // #include <stdio.h> | ||
| 7 | |||
| 8 | // #define XZ_DUMP | ||
| 9 | |||
| 10 | /* #define XZ_DUMP */ | ||
| 11 | |||
| 12 | #ifdef XZ_DUMP | ||
| 13 | #include <stdio.h> | ||
| 14 | #endif | ||
| 15 | |||
| 16 | // #define SHOW_DEBUG_INFO | ||
| 17 | |||
| 18 | #ifdef SHOW_DEBUG_INFO | ||
| 19 | #include <stdio.h> | ||
| 20 | #endif | ||
| 21 | |||
| 22 | #ifdef SHOW_DEBUG_INFO | ||
| 23 | #define PRF(x) x | ||
| 24 | #else | ||
| 25 | #define PRF(x) | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #define PRF_STR(s) PRF(printf("\n" s "\n")) | ||
| 29 | #define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) | ||
| 30 | |||
| 31 | #include <stdlib.h> | ||
| 32 | #include <string.h> | ||
| 33 | |||
| 34 | #include "7zCrc.h" | ||
| 35 | #include "Alloc.h" | ||
| 36 | #include "Bra.h" | ||
| 37 | #include "CpuArch.h" | ||
| 38 | #include "Delta.h" | ||
| 39 | #include "Lzma2Dec.h" | ||
| 40 | |||
| 41 | // #define USE_SUBBLOCK | ||
| 42 | |||
| 43 | #ifdef USE_SUBBLOCK | ||
| 44 | #include "Bcj3Dec.c" | ||
| 45 | #include "SbDec.h" | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #include "Xz.h" | ||
| 49 | |||
| 50 | #define XZ_CHECK_SIZE_MAX 64 | ||
| 51 | |||
| 52 | #define CODER_BUF_SIZE ((size_t)1 << 17) | ||
| 53 | |||
| 54 | unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) | ||
| 55 | { | ||
| 56 | unsigned i, limit; | ||
| 57 | *value = 0; | ||
| 58 | limit = (maxSize > 9) ? 9 : (unsigned)maxSize; | ||
| 59 | |||
| 60 | for (i = 0; i < limit;) | ||
| 61 | { | ||
| 62 | Byte b = p[i]; | ||
| 63 | *value |= (UInt64)(b & 0x7F) << (7 * i++); | ||
| 64 | if ((b & 0x80) == 0) | ||
| 65 | return (b == 0 && i != 1) ? 0 : i; | ||
| 66 | } | ||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* ---------- BraState ---------- */ | ||
| 71 | |||
| 72 | #define BRA_BUF_SIZE (1 << 14) | ||
| 73 | |||
| 74 | typedef struct | ||
| 75 | { | ||
| 76 | size_t bufPos; | ||
| 77 | size_t bufConv; | ||
| 78 | size_t bufTotal; | ||
| 79 | |||
| 80 | int encodeMode; | ||
| 81 | |||
| 82 | UInt32 methodId; | ||
| 83 | UInt32 delta; | ||
| 84 | UInt32 ip; | ||
| 85 | UInt32 x86State; | ||
| 86 | Byte deltaState[DELTA_STATE_SIZE]; | ||
| 87 | |||
| 88 | Byte buf[BRA_BUF_SIZE]; | ||
| 89 | } CBraState; | ||
| 90 | |||
| 91 | static void BraState_Free(void *pp, ISzAllocPtr alloc) | ||
| 92 | { | ||
| 93 | ISzAlloc_Free(alloc, pp); | ||
| 94 | } | ||
| 95 | |||
| 96 | static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) | ||
| 97 | { | ||
| 98 | CBraState *p = ((CBraState *)pp); | ||
| 99 | UNUSED_VAR(alloc); | ||
| 100 | p->ip = 0; | ||
| 101 | if (p->methodId == XZ_ID_Delta) | ||
| 102 | { | ||
| 103 | if (propSize != 1) | ||
| 104 | return SZ_ERROR_UNSUPPORTED; | ||
| 105 | p->delta = (unsigned)props[0] + 1; | ||
| 106 | } | ||
| 107 | else | ||
| 108 | { | ||
| 109 | if (propSize == 4) | ||
| 110 | { | ||
| 111 | UInt32 v = GetUi32(props); | ||
| 112 | switch (p->methodId) | ||
| 113 | { | ||
| 114 | case XZ_ID_PPC: | ||
| 115 | case XZ_ID_ARM: | ||
| 116 | case XZ_ID_SPARC: | ||
| 117 | if ((v & 3) != 0) | ||
| 118 | return SZ_ERROR_UNSUPPORTED; | ||
| 119 | break; | ||
| 120 | case XZ_ID_ARMT: | ||
| 121 | if ((v & 1) != 0) | ||
| 122 | return SZ_ERROR_UNSUPPORTED; | ||
| 123 | break; | ||
| 124 | case XZ_ID_IA64: | ||
| 125 | if ((v & 0xF) != 0) | ||
| 126 | return SZ_ERROR_UNSUPPORTED; | ||
| 127 | break; | ||
| 128 | } | ||
| 129 | p->ip = v; | ||
| 130 | } | ||
| 131 | else if (propSize != 0) | ||
| 132 | return SZ_ERROR_UNSUPPORTED; | ||
| 133 | } | ||
| 134 | return SZ_OK; | ||
| 135 | } | ||
| 136 | |||
| 137 | static void BraState_Init(void *pp) | ||
| 138 | { | ||
| 139 | CBraState *p = ((CBraState *)pp); | ||
| 140 | p->bufPos = p->bufConv = p->bufTotal = 0; | ||
| 141 | x86_Convert_Init(p->x86State); | ||
| 142 | if (p->methodId == XZ_ID_Delta) | ||
| 143 | Delta_Init(p->deltaState); | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | #define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: size = isa ## _Convert(data, size, p->ip, p->encodeMode); break; | ||
| 148 | |||
| 149 | static SizeT BraState_Filter(void *pp, Byte *data, SizeT size) | ||
| 150 | { | ||
| 151 | CBraState *p = ((CBraState *)pp); | ||
| 152 | switch (p->methodId) | ||
| 153 | { | ||
| 154 | case XZ_ID_Delta: | ||
| 155 | if (p->encodeMode) | ||
| 156 | Delta_Encode(p->deltaState, p->delta, data, size); | ||
| 157 | else | ||
| 158 | Delta_Decode(p->deltaState, p->delta, data, size); | ||
| 159 | break; | ||
| 160 | case XZ_ID_X86: | ||
| 161 | size = x86_Convert(data, size, p->ip, &p->x86State, p->encodeMode); | ||
| 162 | break; | ||
| 163 | CASE_BRA_CONV(PPC) | ||
| 164 | CASE_BRA_CONV(IA64) | ||
| 165 | CASE_BRA_CONV(ARM) | ||
| 166 | CASE_BRA_CONV(ARMT) | ||
| 167 | CASE_BRA_CONV(SPARC) | ||
| 168 | } | ||
| 169 | p->ip += (UInt32)size; | ||
| 170 | return size; | ||
| 171 | } | ||
| 172 | |||
| 173 | |||
| 174 | static SRes BraState_Code2(void *pp, | ||
| 175 | Byte *dest, SizeT *destLen, | ||
| 176 | const Byte *src, SizeT *srcLen, int srcWasFinished, | ||
| 177 | ECoderFinishMode finishMode, | ||
| 178 | // int *wasFinished | ||
| 179 | ECoderStatus *status) | ||
| 180 | { | ||
| 181 | CBraState *p = ((CBraState *)pp); | ||
| 182 | SizeT destRem = *destLen; | ||
| 183 | SizeT srcRem = *srcLen; | ||
| 184 | UNUSED_VAR(finishMode); | ||
| 185 | |||
| 186 | *destLen = 0; | ||
| 187 | *srcLen = 0; | ||
| 188 | // *wasFinished = False; | ||
| 189 | *status = CODER_STATUS_NOT_FINISHED; | ||
| 190 | |||
| 191 | while (destRem > 0) | ||
| 192 | { | ||
| 193 | if (p->bufPos != p->bufConv) | ||
| 194 | { | ||
| 195 | size_t size = p->bufConv - p->bufPos; | ||
| 196 | if (size > destRem) | ||
| 197 | size = destRem; | ||
| 198 | memcpy(dest, p->buf + p->bufPos, size); | ||
| 199 | p->bufPos += size; | ||
| 200 | *destLen += size; | ||
| 201 | dest += size; | ||
| 202 | destRem -= size; | ||
| 203 | continue; | ||
| 204 | } | ||
| 205 | |||
| 206 | p->bufTotal -= p->bufPos; | ||
| 207 | memmove(p->buf, p->buf + p->bufPos, p->bufTotal); | ||
| 208 | p->bufPos = 0; | ||
| 209 | p->bufConv = 0; | ||
| 210 | { | ||
| 211 | size_t size = BRA_BUF_SIZE - p->bufTotal; | ||
| 212 | if (size > srcRem) | ||
| 213 | size = srcRem; | ||
| 214 | memcpy(p->buf + p->bufTotal, src, size); | ||
| 215 | *srcLen += size; | ||
| 216 | src += size; | ||
| 217 | srcRem -= size; | ||
| 218 | p->bufTotal += size; | ||
| 219 | } | ||
| 220 | if (p->bufTotal == 0) | ||
| 221 | break; | ||
| 222 | |||
| 223 | p->bufConv = BraState_Filter(pp, p->buf, p->bufTotal); | ||
| 224 | |||
| 225 | if (p->bufConv == 0) | ||
| 226 | { | ||
| 227 | if (!srcWasFinished) | ||
| 228 | break; | ||
| 229 | p->bufConv = p->bufTotal; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | if (p->bufTotal == p->bufPos && srcRem == 0 && srcWasFinished) | ||
| 234 | { | ||
| 235 | *status = CODER_STATUS_FINISHED_WITH_MARK; | ||
| 236 | // *wasFinished = 1; | ||
| 237 | } | ||
| 238 | |||
| 239 | return SZ_OK; | ||
| 240 | } | ||
| 241 | |||
| 242 | |||
| 243 | SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc); | ||
| 244 | SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc) | ||
| 245 | { | ||
| 246 | CBraState *decoder; | ||
| 247 | if (id < XZ_ID_Delta || id > XZ_ID_SPARC) | ||
| 248 | return SZ_ERROR_UNSUPPORTED; | ||
| 249 | decoder = (CBraState *)p->p; | ||
| 250 | if (!decoder) | ||
| 251 | { | ||
| 252 | decoder = (CBraState *)ISzAlloc_Alloc(alloc, sizeof(CBraState)); | ||
| 253 | if (!decoder) | ||
| 254 | return SZ_ERROR_MEM; | ||
| 255 | p->p = decoder; | ||
| 256 | p->Free = BraState_Free; | ||
| 257 | p->SetProps = BraState_SetProps; | ||
| 258 | p->Init = BraState_Init; | ||
| 259 | p->Code2 = BraState_Code2; | ||
| 260 | p->Filter = BraState_Filter; | ||
| 261 | } | ||
| 262 | decoder->methodId = (UInt32)id; | ||
| 263 | decoder->encodeMode = encodeMode; | ||
| 264 | return SZ_OK; | ||
| 265 | } | ||
| 266 | |||
| 267 | |||
| 268 | |||
| 269 | /* ---------- SbState ---------- */ | ||
| 270 | |||
| 271 | #ifdef USE_SUBBLOCK | ||
| 272 | |||
| 273 | static void SbState_Free(void *pp, ISzAllocPtr alloc) | ||
| 274 | { | ||
| 275 | CSbDec *p = (CSbDec *)pp; | ||
| 276 | SbDec_Free(p); | ||
| 277 | ISzAlloc_Free(alloc, pp); | ||
| 278 | } | ||
| 279 | |||
| 280 | static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) | ||
| 281 | { | ||
| 282 | UNUSED_VAR(pp); | ||
| 283 | UNUSED_VAR(props); | ||
| 284 | UNUSED_VAR(alloc); | ||
| 285 | return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED; | ||
| 286 | } | ||
| 287 | |||
| 288 | static void SbState_Init(void *pp) | ||
| 289 | { | ||
| 290 | SbDec_Init((CSbDec *)pp); | ||
| 291 | } | ||
| 292 | |||
| 293 | static SRes SbState_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, | ||
| 294 | int srcWasFinished, ECoderFinishMode finishMode, | ||
| 295 | // int *wasFinished | ||
| 296 | ECoderStatus *status) | ||
| 297 | { | ||
| 298 | CSbDec *p = (CSbDec *)pp; | ||
| 299 | SRes res; | ||
| 300 | UNUSED_VAR(srcWasFinished); | ||
| 301 | p->dest = dest; | ||
| 302 | p->destLen = *destLen; | ||
| 303 | p->src = src; | ||
| 304 | p->srcLen = *srcLen; | ||
| 305 | p->finish = finishMode; /* change it */ | ||
| 306 | res = SbDec_Decode((CSbDec *)pp); | ||
| 307 | *destLen -= p->destLen; | ||
| 308 | *srcLen -= p->srcLen; | ||
| 309 | // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */ | ||
| 310 | *status = (*destLen == 0 && *srcLen == 0) ? | ||
| 311 | CODER_STATUS_FINISHED_WITH_MARK : | ||
| 312 | CODER_STATUS_NOT_FINISHED; | ||
| 313 | return res; | ||
| 314 | } | ||
| 315 | |||
| 316 | static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc) | ||
| 317 | { | ||
| 318 | CSbDec *decoder = (CSbDec *)p->p; | ||
| 319 | if (!decoder) | ||
| 320 | { | ||
| 321 | decoder = (CSbDec *)ISzAlloc_Alloc(alloc, sizeof(CSbDec)); | ||
| 322 | if (!decoder) | ||
| 323 | return SZ_ERROR_MEM; | ||
| 324 | p->p = decoder; | ||
| 325 | p->Free = SbState_Free; | ||
| 326 | p->SetProps = SbState_SetProps; | ||
| 327 | p->Init = SbState_Init; | ||
| 328 | p->Code2 = SbState_Code2; | ||
| 329 | p->Filter = NULL; | ||
| 330 | } | ||
| 331 | SbDec_Construct(decoder); | ||
| 332 | SbDec_SetAlloc(decoder, alloc); | ||
| 333 | return SZ_OK; | ||
| 334 | } | ||
| 335 | |||
| 336 | #endif | ||
| 337 | |||
| 338 | |||
| 339 | |||
| 340 | /* ---------- Lzma2 ---------- */ | ||
| 341 | |||
| 342 | typedef struct | ||
| 343 | { | ||
| 344 | CLzma2Dec decoder; | ||
| 345 | BoolInt outBufMode; | ||
| 346 | } CLzma2Dec_Spec; | ||
| 347 | |||
| 348 | |||
| 349 | static void Lzma2State_Free(void *pp, ISzAllocPtr alloc) | ||
| 350 | { | ||
| 351 | CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; | ||
| 352 | if (p->outBufMode) | ||
| 353 | Lzma2Dec_FreeProbs(&p->decoder, alloc); | ||
| 354 | else | ||
| 355 | Lzma2Dec_Free(&p->decoder, alloc); | ||
| 356 | ISzAlloc_Free(alloc, pp); | ||
| 357 | } | ||
| 358 | |||
| 359 | static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) | ||
| 360 | { | ||
| 361 | if (propSize != 1) | ||
| 362 | return SZ_ERROR_UNSUPPORTED; | ||
| 363 | { | ||
| 364 | CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; | ||
| 365 | if (p->outBufMode) | ||
| 366 | return Lzma2Dec_AllocateProbs(&p->decoder, props[0], alloc); | ||
| 367 | else | ||
| 368 | return Lzma2Dec_Allocate(&p->decoder, props[0], alloc); | ||
| 369 | } | ||
| 370 | } | ||
| 371 | |||
| 372 | static void Lzma2State_Init(void *pp) | ||
| 373 | { | ||
| 374 | Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder); | ||
| 375 | } | ||
| 376 | |||
| 377 | |||
| 378 | /* | ||
| 379 | if (outBufMode), then (dest) is not used. Use NULL. | ||
| 380 | Data is unpacked to (spec->decoder.decoder.dic) output buffer. | ||
| 381 | */ | ||
| 382 | |||
| 383 | static SRes Lzma2State_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, | ||
| 384 | int srcWasFinished, ECoderFinishMode finishMode, | ||
| 385 | // int *wasFinished, | ||
| 386 | ECoderStatus *status) | ||
| 387 | { | ||
| 388 | CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp; | ||
| 389 | ELzmaStatus status2; | ||
| 390 | /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */ | ||
| 391 | SRes res; | ||
| 392 | UNUSED_VAR(srcWasFinished); | ||
| 393 | if (spec->outBufMode) | ||
| 394 | { | ||
| 395 | SizeT dicPos = spec->decoder.decoder.dicPos; | ||
| 396 | SizeT dicLimit = dicPos + *destLen; | ||
| 397 | res = Lzma2Dec_DecodeToDic(&spec->decoder, dicLimit, src, srcLen, (ELzmaFinishMode)finishMode, &status2); | ||
| 398 | *destLen = spec->decoder.decoder.dicPos - dicPos; | ||
| 399 | } | ||
| 400 | else | ||
| 401 | res = Lzma2Dec_DecodeToBuf(&spec->decoder, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status2); | ||
| 402 | // *wasFinished = (status2 == LZMA_STATUS_FINISHED_WITH_MARK); | ||
| 403 | // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder | ||
| 404 | *status = (ECoderStatus)status2; | ||
| 405 | return res; | ||
| 406 | } | ||
| 407 | |||
| 408 | |||
| 409 | static SRes Lzma2State_SetFromMethod(IStateCoder *p, Byte *outBuf, size_t outBufSize, ISzAllocPtr alloc) | ||
| 410 | { | ||
| 411 | CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; | ||
| 412 | if (!spec) | ||
| 413 | { | ||
| 414 | spec = (CLzma2Dec_Spec *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Dec_Spec)); | ||
| 415 | if (!spec) | ||
| 416 | return SZ_ERROR_MEM; | ||
| 417 | p->p = spec; | ||
| 418 | p->Free = Lzma2State_Free; | ||
| 419 | p->SetProps = Lzma2State_SetProps; | ||
| 420 | p->Init = Lzma2State_Init; | ||
| 421 | p->Code2 = Lzma2State_Code2; | ||
| 422 | p->Filter = NULL; | ||
| 423 | Lzma2Dec_Construct(&spec->decoder); | ||
| 424 | } | ||
| 425 | spec->outBufMode = False; | ||
| 426 | if (outBuf) | ||
| 427 | { | ||
| 428 | spec->outBufMode = True; | ||
| 429 | spec->decoder.decoder.dic = outBuf; | ||
| 430 | spec->decoder.decoder.dicBufSize = outBufSize; | ||
| 431 | } | ||
| 432 | return SZ_OK; | ||
| 433 | } | ||
| 434 | |||
| 435 | |||
| 436 | static SRes Lzma2State_ResetOutBuf(IStateCoder *p, Byte *outBuf, size_t outBufSize) | ||
| 437 | { | ||
| 438 | CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; | ||
| 439 | if ((spec->outBufMode && !outBuf) || (!spec->outBufMode && outBuf)) | ||
| 440 | return SZ_ERROR_FAIL; | ||
| 441 | if (outBuf) | ||
| 442 | { | ||
| 443 | spec->decoder.decoder.dic = outBuf; | ||
| 444 | spec->decoder.decoder.dicBufSize = outBufSize; | ||
| 445 | } | ||
| 446 | return SZ_OK; | ||
| 447 | } | ||
| 448 | |||
| 449 | |||
| 450 | |||
| 451 | static void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc) | ||
| 452 | { | ||
| 453 | unsigned i; | ||
| 454 | p->alloc = alloc; | ||
| 455 | p->buf = NULL; | ||
| 456 | p->numCoders = 0; | ||
| 457 | |||
| 458 | p->outBufSize = 0; | ||
| 459 | p->outBuf = NULL; | ||
| 460 | // p->SingleBufMode = False; | ||
| 461 | |||
| 462 | for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) | ||
| 463 | p->coders[i].p = NULL; | ||
| 464 | } | ||
| 465 | |||
| 466 | |||
| 467 | static void MixCoder_Free(CMixCoder *p) | ||
| 468 | { | ||
| 469 | unsigned i; | ||
| 470 | p->numCoders = 0; | ||
| 471 | for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) | ||
| 472 | { | ||
| 473 | IStateCoder *sc = &p->coders[i]; | ||
| 474 | if (sc->p) | ||
| 475 | { | ||
| 476 | sc->Free(sc->p, p->alloc); | ||
| 477 | sc->p = NULL; | ||
| 478 | } | ||
| 479 | } | ||
| 480 | if (p->buf) | ||
| 481 | { | ||
| 482 | ISzAlloc_Free(p->alloc, p->buf); | ||
| 483 | p->buf = NULL; /* 9.31: the BUG was fixed */ | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | static void MixCoder_Init(CMixCoder *p) | ||
| 488 | { | ||
| 489 | unsigned i; | ||
| 490 | for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++) | ||
| 491 | { | ||
| 492 | p->size[i] = 0; | ||
| 493 | p->pos[i] = 0; | ||
| 494 | p->finished[i] = 0; | ||
| 495 | } | ||
| 496 | for (i = 0; i < p->numCoders; i++) | ||
| 497 | { | ||
| 498 | IStateCoder *coder = &p->coders[i]; | ||
| 499 | coder->Init(coder->p); | ||
| 500 | p->results[i] = SZ_OK; | ||
| 501 | } | ||
| 502 | p->outWritten = 0; | ||
| 503 | p->wasFinished = False; | ||
| 504 | p->res = SZ_OK; | ||
| 505 | p->status = CODER_STATUS_NOT_SPECIFIED; | ||
| 506 | } | ||
| 507 | |||
| 508 | |||
| 509 | static SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) | ||
| 510 | { | ||
| 511 | IStateCoder *sc = &p->coders[coderIndex]; | ||
| 512 | p->ids[coderIndex] = methodId; | ||
| 513 | switch (methodId) | ||
| 514 | { | ||
| 515 | case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc); | ||
| 516 | #ifdef USE_SUBBLOCK | ||
| 517 | case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc); | ||
| 518 | #endif | ||
| 519 | } | ||
| 520 | if (coderIndex == 0) | ||
| 521 | return SZ_ERROR_UNSUPPORTED; | ||
| 522 | return BraState_SetFromMethod(sc, methodId, 0, p->alloc); | ||
| 523 | } | ||
| 524 | |||
| 525 | |||
| 526 | static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) | ||
| 527 | { | ||
| 528 | IStateCoder *sc = &p->coders[coderIndex]; | ||
| 529 | switch (methodId) | ||
| 530 | { | ||
| 531 | case XZ_ID_LZMA2: return Lzma2State_ResetOutBuf(sc, outBuf, outBufSize); | ||
| 532 | } | ||
| 533 | return SZ_ERROR_UNSUPPORTED; | ||
| 534 | } | ||
| 535 | |||
| 536 | |||
| 537 | |||
| 538 | /* | ||
| 539 | if (destFinish) - then unpack data block is finished at (*destLen) position, | ||
| 540 | and we can return data that were not processed by filter | ||
| 541 | |||
| 542 | output (status) can be : | ||
| 543 | CODER_STATUS_NOT_FINISHED | ||
| 544 | CODER_STATUS_FINISHED_WITH_MARK | ||
| 545 | CODER_STATUS_NEEDS_MORE_INPUT - not implemented still | ||
| 546 | */ | ||
| 547 | |||
| 548 | static SRes MixCoder_Code(CMixCoder *p, | ||
| 549 | Byte *dest, SizeT *destLen, int destFinish, | ||
| 550 | const Byte *src, SizeT *srcLen, int srcWasFinished, | ||
| 551 | ECoderFinishMode finishMode) | ||
| 552 | { | ||
| 553 | SizeT destLenOrig = *destLen; | ||
| 554 | SizeT srcLenOrig = *srcLen; | ||
| 555 | |||
| 556 | *destLen = 0; | ||
| 557 | *srcLen = 0; | ||
| 558 | |||
| 559 | if (p->wasFinished) | ||
| 560 | return p->res; | ||
| 561 | |||
| 562 | p->status = CODER_STATUS_NOT_FINISHED; | ||
| 563 | |||
| 564 | // if (p->SingleBufMode) | ||
| 565 | if (p->outBuf) | ||
| 566 | { | ||
| 567 | SRes res; | ||
| 568 | SizeT destLen2, srcLen2; | ||
| 569 | int wasFinished; | ||
| 570 | |||
| 571 | PRF_STR("------- MixCoder Single ----------"); | ||
| 572 | |||
| 573 | srcLen2 = srcLenOrig; | ||
| 574 | destLen2 = destLenOrig; | ||
| 575 | |||
| 576 | { | ||
| 577 | IStateCoder *coder = &p->coders[0]; | ||
| 578 | res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode, | ||
| 579 | // &wasFinished, | ||
| 580 | &p->status); | ||
| 581 | wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK); | ||
| 582 | } | ||
| 583 | |||
| 584 | p->res = res; | ||
| 585 | |||
| 586 | /* | ||
| 587 | if (wasFinished) | ||
| 588 | p->status = CODER_STATUS_FINISHED_WITH_MARK; | ||
| 589 | else | ||
| 590 | { | ||
| 591 | if (res == SZ_OK) | ||
| 592 | if (destLen2 != destLenOrig) | ||
| 593 | p->status = CODER_STATUS_NEEDS_MORE_INPUT; | ||
| 594 | } | ||
| 595 | */ | ||
| 596 | |||
| 597 | |||
| 598 | *srcLen = srcLen2; | ||
| 599 | src += srcLen2; | ||
| 600 | p->outWritten += destLen2; | ||
| 601 | |||
| 602 | if (res != SZ_OK || srcWasFinished || wasFinished) | ||
| 603 | p->wasFinished = True; | ||
| 604 | |||
| 605 | if (p->numCoders == 1) | ||
| 606 | *destLen = destLen2; | ||
| 607 | else if (p->wasFinished) | ||
| 608 | { | ||
| 609 | unsigned i; | ||
| 610 | size_t processed = p->outWritten; | ||
| 611 | |||
| 612 | for (i = 1; i < p->numCoders; i++) | ||
| 613 | { | ||
| 614 | IStateCoder *coder = &p->coders[i]; | ||
| 615 | processed = coder->Filter(coder->p, p->outBuf, processed); | ||
| 616 | if (wasFinished || (destFinish && p->outWritten == destLenOrig)) | ||
| 617 | processed = p->outWritten; | ||
| 618 | PRF_STR_INT("filter", i); | ||
| 619 | } | ||
| 620 | *destLen = processed; | ||
| 621 | } | ||
| 622 | return res; | ||
| 623 | } | ||
| 624 | |||
| 625 | PRF_STR("standard mix"); | ||
| 626 | |||
| 627 | if (p->numCoders != 1) | ||
| 628 | { | ||
| 629 | if (!p->buf) | ||
| 630 | { | ||
| 631 | p->buf = (Byte *)ISzAlloc_Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1)); | ||
| 632 | if (!p->buf) | ||
| 633 | return SZ_ERROR_MEM; | ||
| 634 | } | ||
| 635 | |||
| 636 | finishMode = CODER_FINISH_ANY; | ||
| 637 | } | ||
| 638 | |||
| 639 | for (;;) | ||
| 640 | { | ||
| 641 | BoolInt processed = False; | ||
| 642 | BoolInt allFinished = True; | ||
| 643 | SRes resMain = SZ_OK; | ||
| 644 | unsigned i; | ||
| 645 | |||
| 646 | p->status = CODER_STATUS_NOT_FINISHED; | ||
| 647 | /* | ||
| 648 | if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY) | ||
| 649 | break; | ||
| 650 | */ | ||
| 651 | |||
| 652 | for (i = 0; i < p->numCoders; i++) | ||
| 653 | { | ||
| 654 | SRes res; | ||
| 655 | IStateCoder *coder = &p->coders[i]; | ||
| 656 | Byte *dest2; | ||
| 657 | SizeT destLen2, srcLen2; // destLen2_Orig; | ||
| 658 | const Byte *src2; | ||
| 659 | int srcFinished2; | ||
| 660 | int encodingWasFinished; | ||
| 661 | ECoderStatus status2; | ||
| 662 | |||
| 663 | if (i == 0) | ||
| 664 | { | ||
| 665 | src2 = src; | ||
| 666 | srcLen2 = srcLenOrig - *srcLen; | ||
| 667 | srcFinished2 = srcWasFinished; | ||
| 668 | } | ||
| 669 | else | ||
| 670 | { | ||
| 671 | size_t k = i - 1; | ||
| 672 | src2 = p->buf + (CODER_BUF_SIZE * k) + p->pos[k]; | ||
| 673 | srcLen2 = p->size[k] - p->pos[k]; | ||
| 674 | srcFinished2 = p->finished[k]; | ||
| 675 | } | ||
| 676 | |||
| 677 | if (i == p->numCoders - 1) | ||
| 678 | { | ||
| 679 | dest2 = dest; | ||
| 680 | destLen2 = destLenOrig - *destLen; | ||
| 681 | } | ||
| 682 | else | ||
| 683 | { | ||
| 684 | if (p->pos[i] != p->size[i]) | ||
| 685 | continue; | ||
| 686 | dest2 = p->buf + (CODER_BUF_SIZE * i); | ||
| 687 | destLen2 = CODER_BUF_SIZE; | ||
| 688 | } | ||
| 689 | |||
| 690 | // destLen2_Orig = destLen2; | ||
| 691 | |||
| 692 | if (p->results[i] != SZ_OK) | ||
| 693 | { | ||
| 694 | if (resMain == SZ_OK) | ||
| 695 | resMain = p->results[i]; | ||
| 696 | continue; | ||
| 697 | } | ||
| 698 | |||
| 699 | res = coder->Code2(coder->p, | ||
| 700 | dest2, &destLen2, | ||
| 701 | src2, &srcLen2, srcFinished2, | ||
| 702 | finishMode, | ||
| 703 | // &encodingWasFinished, | ||
| 704 | &status2); | ||
| 705 | |||
| 706 | if (res != SZ_OK) | ||
| 707 | { | ||
| 708 | p->results[i] = res; | ||
| 709 | if (resMain == SZ_OK) | ||
| 710 | resMain = res; | ||
| 711 | } | ||
| 712 | |||
| 713 | encodingWasFinished = (status2 == CODER_STATUS_FINISHED_WITH_MARK); | ||
| 714 | |||
| 715 | if (!encodingWasFinished) | ||
| 716 | { | ||
| 717 | allFinished = False; | ||
| 718 | if (p->numCoders == 1 && res == SZ_OK) | ||
| 719 | p->status = status2; | ||
| 720 | } | ||
| 721 | |||
| 722 | if (i == 0) | ||
| 723 | { | ||
| 724 | *srcLen += srcLen2; | ||
| 725 | src += srcLen2; | ||
| 726 | } | ||
| 727 | else | ||
| 728 | p->pos[(size_t)i - 1] += srcLen2; | ||
| 729 | |||
| 730 | if (i == p->numCoders - 1) | ||
| 731 | { | ||
| 732 | *destLen += destLen2; | ||
| 733 | dest += destLen2; | ||
| 734 | } | ||
| 735 | else | ||
| 736 | { | ||
| 737 | p->size[i] = destLen2; | ||
| 738 | p->pos[i] = 0; | ||
| 739 | p->finished[i] = encodingWasFinished; | ||
| 740 | } | ||
| 741 | |||
| 742 | if (destLen2 != 0 || srcLen2 != 0) | ||
| 743 | processed = True; | ||
| 744 | } | ||
| 745 | |||
| 746 | if (!processed) | ||
| 747 | { | ||
| 748 | if (allFinished) | ||
| 749 | p->status = CODER_STATUS_FINISHED_WITH_MARK; | ||
| 750 | return resMain; | ||
| 751 | } | ||
| 752 | } | ||
| 753 | } | ||
| 754 | |||
| 755 | |||
| 756 | SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf) | ||
| 757 | { | ||
| 758 | *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE); | ||
| 759 | if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) != | ||
| 760 | GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE)) | ||
| 761 | return SZ_ERROR_NO_ARCHIVE; | ||
| 762 | return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED; | ||
| 763 | } | ||
| 764 | |||
| 765 | static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) | ||
| 766 | { | ||
| 767 | return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) | ||
| 768 | && GetUi32(buf) == CrcCalc(buf + 4, 6) | ||
| 769 | && flags == GetBe16(buf + 8) | ||
| 770 | && buf[10] == XZ_FOOTER_SIG_0 | ||
| 771 | && buf[11] == XZ_FOOTER_SIG_1; | ||
| 772 | } | ||
| 773 | |||
| 774 | #define READ_VARINT_AND_CHECK(buf, pos, size, res) \ | ||
| 775 | { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ | ||
| 776 | if (s == 0) return SZ_ERROR_ARCHIVE; \ | ||
| 777 | pos += s; } | ||
| 778 | |||
| 779 | |||
| 780 | static BoolInt XzBlock_AreSupportedFilters(const CXzBlock *p) | ||
| 781 | { | ||
| 782 | unsigned numFilters = XzBlock_GetNumFilters(p) - 1; | ||
| 783 | unsigned i; | ||
| 784 | { | ||
| 785 | const CXzFilter *f = &p->filters[numFilters]; | ||
| 786 | if (f->id != XZ_ID_LZMA2 || f->propsSize != 1 || f->props[0] > 40) | ||
| 787 | return False; | ||
| 788 | } | ||
| 789 | |||
| 790 | for (i = 0; i < numFilters; i++) | ||
| 791 | { | ||
| 792 | const CXzFilter *f = &p->filters[i]; | ||
| 793 | if (f->id == XZ_ID_Delta) | ||
| 794 | { | ||
| 795 | if (f->propsSize != 1) | ||
| 796 | return False; | ||
| 797 | } | ||
| 798 | else if (f->id < XZ_ID_Delta | ||
| 799 | || f->id > XZ_ID_SPARC | ||
| 800 | || (f->propsSize != 0 && f->propsSize != 4)) | ||
| 801 | return False; | ||
| 802 | } | ||
| 803 | return True; | ||
| 804 | } | ||
| 805 | |||
| 806 | |||
| 807 | SRes XzBlock_Parse(CXzBlock *p, const Byte *header) | ||
| 808 | { | ||
| 809 | unsigned pos; | ||
| 810 | unsigned numFilters, i; | ||
| 811 | unsigned headerSize = (unsigned)header[0] << 2; | ||
| 812 | |||
| 813 | /* (headerSize != 0) : another code checks */ | ||
| 814 | |||
| 815 | if (CrcCalc(header, headerSize) != GetUi32(header + headerSize)) | ||
| 816 | return SZ_ERROR_ARCHIVE; | ||
| 817 | |||
| 818 | pos = 1; | ||
| 819 | p->flags = header[pos++]; | ||
| 820 | |||
| 821 | p->packSize = (UInt64)(Int64)-1; | ||
| 822 | if (XzBlock_HasPackSize(p)) | ||
| 823 | { | ||
| 824 | READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize); | ||
| 825 | if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63) | ||
| 826 | return SZ_ERROR_ARCHIVE; | ||
| 827 | } | ||
| 828 | |||
| 829 | p->unpackSize = (UInt64)(Int64)-1; | ||
| 830 | if (XzBlock_HasUnpackSize(p)) | ||
| 831 | READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize); | ||
| 832 | |||
| 833 | numFilters = XzBlock_GetNumFilters(p); | ||
| 834 | for (i = 0; i < numFilters; i++) | ||
| 835 | { | ||
| 836 | CXzFilter *filter = p->filters + i; | ||
| 837 | UInt64 size; | ||
| 838 | READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id); | ||
| 839 | READ_VARINT_AND_CHECK(header, pos, headerSize, &size); | ||
| 840 | if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX) | ||
| 841 | return SZ_ERROR_ARCHIVE; | ||
| 842 | filter->propsSize = (UInt32)size; | ||
| 843 | memcpy(filter->props, header + pos, (size_t)size); | ||
| 844 | pos += (unsigned)size; | ||
| 845 | |||
| 846 | #ifdef XZ_DUMP | ||
| 847 | printf("\nf[%u] = %2X: ", i, (unsigned)filter->id); | ||
| 848 | { | ||
| 849 | unsigned i; | ||
| 850 | for (i = 0; i < size; i++) | ||
| 851 | printf(" %2X", filter->props[i]); | ||
| 852 | } | ||
| 853 | #endif | ||
| 854 | } | ||
| 855 | |||
| 856 | if (XzBlock_HasUnsupportedFlags(p)) | ||
| 857 | return SZ_ERROR_UNSUPPORTED; | ||
| 858 | |||
| 859 | while (pos < headerSize) | ||
| 860 | if (header[pos++] != 0) | ||
| 861 | return SZ_ERROR_ARCHIVE; | ||
| 862 | return SZ_OK; | ||
| 863 | } | ||
| 864 | |||
| 865 | |||
| 866 | |||
| 867 | |||
| 868 | static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize) | ||
| 869 | { | ||
| 870 | unsigned i; | ||
| 871 | BoolInt needReInit = True; | ||
| 872 | unsigned numFilters = XzBlock_GetNumFilters(block); | ||
| 873 | |||
| 874 | if (numFilters == p->numCoders && ((p->outBuf && outBuf) || (!p->outBuf && !outBuf))) | ||
| 875 | { | ||
| 876 | needReInit = False; | ||
| 877 | for (i = 0; i < numFilters; i++) | ||
| 878 | if (p->ids[i] != block->filters[numFilters - 1 - i].id) | ||
| 879 | { | ||
| 880 | needReInit = True; | ||
| 881 | break; | ||
| 882 | } | ||
| 883 | } | ||
| 884 | |||
| 885 | // p->SingleBufMode = (outBuf != NULL); | ||
| 886 | p->outBuf = outBuf; | ||
| 887 | p->outBufSize = outBufSize; | ||
| 888 | |||
| 889 | // p->SingleBufMode = False; | ||
| 890 | // outBuf = NULL; | ||
| 891 | |||
| 892 | if (needReInit) | ||
| 893 | { | ||
| 894 | MixCoder_Free(p); | ||
| 895 | for (i = 0; i < numFilters; i++) | ||
| 896 | { | ||
| 897 | RINOK(MixCoder_SetFromMethod(p, i, block->filters[numFilters - 1 - i].id, outBuf, outBufSize)); | ||
| 898 | } | ||
| 899 | p->numCoders = numFilters; | ||
| 900 | } | ||
| 901 | else | ||
| 902 | { | ||
| 903 | RINOK(MixCoder_ResetFromMethod(p, 0, block->filters[numFilters - 1].id, outBuf, outBufSize)); | ||
| 904 | } | ||
| 905 | |||
| 906 | for (i = 0; i < numFilters; i++) | ||
| 907 | { | ||
| 908 | const CXzFilter *f = &block->filters[numFilters - 1 - i]; | ||
| 909 | IStateCoder *sc = &p->coders[i]; | ||
| 910 | RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc)); | ||
| 911 | } | ||
| 912 | |||
| 913 | MixCoder_Init(p); | ||
| 914 | return SZ_OK; | ||
| 915 | } | ||
| 916 | |||
| 917 | |||
| 918 | |||
| 919 | void XzUnpacker_Init(CXzUnpacker *p) | ||
| 920 | { | ||
| 921 | p->state = XZ_STATE_STREAM_HEADER; | ||
| 922 | p->pos = 0; | ||
| 923 | p->numStartedStreams = 0; | ||
| 924 | p->numFinishedStreams = 0; | ||
| 925 | p->numTotalBlocks = 0; | ||
| 926 | p->padSize = 0; | ||
| 927 | p->decodeOnlyOneBlock = 0; | ||
| 928 | |||
| 929 | p->parseMode = False; | ||
| 930 | p->decodeToStreamSignature = False; | ||
| 931 | |||
| 932 | // p->outBuf = NULL; | ||
| 933 | // p->outBufSize = 0; | ||
| 934 | p->outDataWritten = 0; | ||
| 935 | } | ||
| 936 | |||
| 937 | |||
| 938 | void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize) | ||
| 939 | { | ||
| 940 | p->outBuf = outBuf; | ||
| 941 | p->outBufSize = outBufSize; | ||
| 942 | } | ||
| 943 | |||
| 944 | |||
| 945 | void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc) | ||
| 946 | { | ||
| 947 | MixCoder_Construct(&p->decoder, alloc); | ||
| 948 | p->outBuf = NULL; | ||
| 949 | p->outBufSize = 0; | ||
| 950 | XzUnpacker_Init(p); | ||
| 951 | } | ||
| 952 | |||
| 953 | |||
| 954 | void XzUnpacker_Free(CXzUnpacker *p) | ||
| 955 | { | ||
| 956 | MixCoder_Free(&p->decoder); | ||
| 957 | } | ||
| 958 | |||
| 959 | |||
| 960 | void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p) | ||
| 961 | { | ||
| 962 | p->indexSize = 0; | ||
| 963 | p->numBlocks = 0; | ||
| 964 | Sha256_Init(&p->sha); | ||
| 965 | p->state = XZ_STATE_BLOCK_HEADER; | ||
| 966 | p->pos = 0; | ||
| 967 | p->decodeOnlyOneBlock = 1; | ||
| 968 | } | ||
| 969 | |||
| 970 | |||
| 971 | static void XzUnpacker_UpdateIndex(CXzUnpacker *p, UInt64 packSize, UInt64 unpackSize) | ||
| 972 | { | ||
| 973 | Byte temp[32]; | ||
| 974 | unsigned num = Xz_WriteVarInt(temp, packSize); | ||
| 975 | num += Xz_WriteVarInt(temp + num, unpackSize); | ||
| 976 | Sha256_Update(&p->sha, temp, num); | ||
| 977 | p->indexSize += num; | ||
| 978 | p->numBlocks++; | ||
| 979 | } | ||
| 980 | |||
| 981 | |||
| 982 | |||
| 983 | SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, | ||
| 984 | const Byte *src, SizeT *srcLen, int srcFinished, | ||
| 985 | ECoderFinishMode finishMode, ECoderStatus *status) | ||
| 986 | { | ||
| 987 | SizeT destLenOrig = *destLen; | ||
| 988 | SizeT srcLenOrig = *srcLen; | ||
| 989 | *destLen = 0; | ||
| 990 | *srcLen = 0; | ||
| 991 | *status = CODER_STATUS_NOT_SPECIFIED; | ||
| 992 | |||
| 993 | for (;;) | ||
| 994 | { | ||
| 995 | SizeT srcRem; | ||
| 996 | |||
| 997 | if (p->state == XZ_STATE_BLOCK) | ||
| 998 | { | ||
| 999 | SizeT destLen2 = destLenOrig - *destLen; | ||
| 1000 | SizeT srcLen2 = srcLenOrig - *srcLen; | ||
| 1001 | SRes res; | ||
| 1002 | |||
| 1003 | ECoderFinishMode finishMode2 = finishMode; | ||
| 1004 | BoolInt srcFinished2 = srcFinished; | ||
| 1005 | BoolInt destFinish = False; | ||
| 1006 | |||
| 1007 | if (p->block.packSize != (UInt64)(Int64)-1) | ||
| 1008 | { | ||
| 1009 | UInt64 rem = p->block.packSize - p->packSize; | ||
| 1010 | if (srcLen2 >= rem) | ||
| 1011 | { | ||
| 1012 | srcFinished2 = True; | ||
| 1013 | srcLen2 = (SizeT)rem; | ||
| 1014 | } | ||
| 1015 | if (rem == 0 && p->block.unpackSize == p->unpackSize) | ||
| 1016 | return SZ_ERROR_DATA; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | if (p->block.unpackSize != (UInt64)(Int64)-1) | ||
| 1020 | { | ||
| 1021 | UInt64 rem = p->block.unpackSize - p->unpackSize; | ||
| 1022 | if (destLen2 >= rem) | ||
| 1023 | { | ||
| 1024 | destFinish = True; | ||
| 1025 | finishMode2 = CODER_FINISH_END; | ||
| 1026 | destLen2 = (SizeT)rem; | ||
| 1027 | } | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | /* | ||
| 1031 | if (srcLen2 == 0 && destLen2 == 0) | ||
| 1032 | { | ||
| 1033 | *status = CODER_STATUS_NOT_FINISHED; | ||
| 1034 | return SZ_OK; | ||
| 1035 | } | ||
| 1036 | */ | ||
| 1037 | |||
| 1038 | { | ||
| 1039 | res = MixCoder_Code(&p->decoder, | ||
| 1040 | (p->outBuf ? NULL : dest), &destLen2, destFinish, | ||
| 1041 | src, &srcLen2, srcFinished2, | ||
| 1042 | finishMode2); | ||
| 1043 | |||
| 1044 | *status = p->decoder.status; | ||
| 1045 | XzCheck_Update(&p->check, (p->outBuf ? p->outBuf + p->outDataWritten : dest), destLen2); | ||
| 1046 | if (!p->outBuf) | ||
| 1047 | dest += destLen2; | ||
| 1048 | p->outDataWritten += destLen2; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | (*srcLen) += srcLen2; | ||
| 1052 | src += srcLen2; | ||
| 1053 | p->packSize += srcLen2; | ||
| 1054 | (*destLen) += destLen2; | ||
| 1055 | p->unpackSize += destLen2; | ||
| 1056 | |||
| 1057 | RINOK(res); | ||
| 1058 | |||
| 1059 | if (*status != CODER_STATUS_FINISHED_WITH_MARK) | ||
| 1060 | { | ||
| 1061 | if (p->block.packSize == p->packSize | ||
| 1062 | && *status == CODER_STATUS_NEEDS_MORE_INPUT) | ||
| 1063 | { | ||
| 1064 | PRF_STR("CODER_STATUS_NEEDS_MORE_INPUT"); | ||
| 1065 | *status = CODER_STATUS_NOT_SPECIFIED; | ||
| 1066 | return SZ_ERROR_DATA; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | return SZ_OK; | ||
| 1070 | } | ||
| 1071 | { | ||
| 1072 | XzUnpacker_UpdateIndex(p, XzUnpacker_GetPackSizeForIndex(p), p->unpackSize); | ||
| 1073 | p->state = XZ_STATE_BLOCK_FOOTER; | ||
| 1074 | p->pos = 0; | ||
| 1075 | p->alignPos = 0; | ||
| 1076 | *status = CODER_STATUS_NOT_SPECIFIED; | ||
| 1077 | |||
| 1078 | if ((p->block.packSize != (UInt64)(Int64)-1 && p->block.packSize != p->packSize) | ||
| 1079 | || (p->block.unpackSize != (UInt64)(Int64)-1 && p->block.unpackSize != p->unpackSize)) | ||
| 1080 | { | ||
| 1081 | PRF_STR("ERROR: block.size mismatch"); | ||
| 1082 | return SZ_ERROR_DATA; | ||
| 1083 | } | ||
| 1084 | } | ||
| 1085 | // continue; | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | srcRem = srcLenOrig - *srcLen; | ||
| 1089 | |||
| 1090 | // XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes | ||
| 1091 | if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER) | ||
| 1092 | { | ||
| 1093 | *status = CODER_STATUS_NEEDS_MORE_INPUT; | ||
| 1094 | return SZ_OK; | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | switch (p->state) | ||
| 1098 | { | ||
| 1099 | case XZ_STATE_STREAM_HEADER: | ||
| 1100 | { | ||
| 1101 | if (p->pos < XZ_STREAM_HEADER_SIZE) | ||
| 1102 | { | ||
| 1103 | if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos]) | ||
| 1104 | return SZ_ERROR_NO_ARCHIVE; | ||
| 1105 | if (p->decodeToStreamSignature) | ||
| 1106 | return SZ_OK; | ||
| 1107 | p->buf[p->pos++] = *src++; | ||
| 1108 | (*srcLen)++; | ||
| 1109 | } | ||
| 1110 | else | ||
| 1111 | { | ||
| 1112 | RINOK(Xz_ParseHeader(&p->streamFlags, p->buf)); | ||
| 1113 | p->numStartedStreams++; | ||
| 1114 | p->indexSize = 0; | ||
| 1115 | p->numBlocks = 0; | ||
| 1116 | Sha256_Init(&p->sha); | ||
| 1117 | p->state = XZ_STATE_BLOCK_HEADER; | ||
| 1118 | p->pos = 0; | ||
| 1119 | } | ||
| 1120 | break; | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | case XZ_STATE_BLOCK_HEADER: | ||
| 1124 | { | ||
| 1125 | if (p->pos == 0) | ||
| 1126 | { | ||
| 1127 | p->buf[p->pos++] = *src++; | ||
| 1128 | (*srcLen)++; | ||
| 1129 | if (p->buf[0] == 0) | ||
| 1130 | { | ||
| 1131 | if (p->decodeOnlyOneBlock) | ||
| 1132 | return SZ_ERROR_DATA; | ||
| 1133 | p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); | ||
| 1134 | p->indexPos = p->indexPreSize; | ||
| 1135 | p->indexSize += p->indexPreSize; | ||
| 1136 | Sha256_Final(&p->sha, p->shaDigest); | ||
| 1137 | Sha256_Init(&p->sha); | ||
| 1138 | p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); | ||
| 1139 | p->state = XZ_STATE_STREAM_INDEX; | ||
| 1140 | break; | ||
| 1141 | } | ||
| 1142 | p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4; | ||
| 1143 | break; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | if (p->pos != p->blockHeaderSize) | ||
| 1147 | { | ||
| 1148 | UInt32 cur = p->blockHeaderSize - p->pos; | ||
| 1149 | if (cur > srcRem) | ||
| 1150 | cur = (UInt32)srcRem; | ||
| 1151 | memcpy(p->buf + p->pos, src, cur); | ||
| 1152 | p->pos += cur; | ||
| 1153 | (*srcLen) += cur; | ||
| 1154 | src += cur; | ||
| 1155 | } | ||
| 1156 | else | ||
| 1157 | { | ||
| 1158 | RINOK(XzBlock_Parse(&p->block, p->buf)); | ||
| 1159 | if (!XzBlock_AreSupportedFilters(&p->block)) | ||
| 1160 | return SZ_ERROR_UNSUPPORTED; | ||
| 1161 | p->numTotalBlocks++; | ||
| 1162 | p->state = XZ_STATE_BLOCK; | ||
| 1163 | p->packSize = 0; | ||
| 1164 | p->unpackSize = 0; | ||
| 1165 | XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags)); | ||
| 1166 | if (p->parseMode) | ||
| 1167 | { | ||
| 1168 | p->headerParsedOk = True; | ||
| 1169 | return SZ_OK; | ||
| 1170 | } | ||
| 1171 | RINOK(XzDecMix_Init(&p->decoder, &p->block, p->outBuf, p->outBufSize)); | ||
| 1172 | } | ||
| 1173 | break; | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | case XZ_STATE_BLOCK_FOOTER: | ||
| 1177 | { | ||
| 1178 | if ((((unsigned)p->packSize + p->alignPos) & 3) != 0) | ||
| 1179 | { | ||
| 1180 | if (srcRem == 0) | ||
| 1181 | { | ||
| 1182 | *status = CODER_STATUS_NEEDS_MORE_INPUT; | ||
| 1183 | return SZ_OK; | ||
| 1184 | } | ||
| 1185 | (*srcLen)++; | ||
| 1186 | p->alignPos++; | ||
| 1187 | if (*src++ != 0) | ||
| 1188 | return SZ_ERROR_CRC; | ||
| 1189 | } | ||
| 1190 | else | ||
| 1191 | { | ||
| 1192 | UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags); | ||
| 1193 | UInt32 cur = checkSize - p->pos; | ||
| 1194 | if (cur != 0) | ||
| 1195 | { | ||
| 1196 | if (srcRem == 0) | ||
| 1197 | { | ||
| 1198 | *status = CODER_STATUS_NEEDS_MORE_INPUT; | ||
| 1199 | return SZ_OK; | ||
| 1200 | } | ||
| 1201 | if (cur > srcRem) | ||
| 1202 | cur = (UInt32)srcRem; | ||
| 1203 | memcpy(p->buf + p->pos, src, cur); | ||
| 1204 | p->pos += cur; | ||
| 1205 | (*srcLen) += cur; | ||
| 1206 | src += cur; | ||
| 1207 | if (checkSize != p->pos) | ||
| 1208 | break; | ||
| 1209 | } | ||
| 1210 | { | ||
| 1211 | Byte digest[XZ_CHECK_SIZE_MAX]; | ||
| 1212 | p->state = XZ_STATE_BLOCK_HEADER; | ||
| 1213 | p->pos = 0; | ||
| 1214 | if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0) | ||
| 1215 | return SZ_ERROR_CRC; | ||
| 1216 | if (p->decodeOnlyOneBlock) | ||
| 1217 | { | ||
| 1218 | *status = CODER_STATUS_FINISHED_WITH_MARK; | ||
| 1219 | return SZ_OK; | ||
| 1220 | } | ||
| 1221 | } | ||
| 1222 | } | ||
| 1223 | break; | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | case XZ_STATE_STREAM_INDEX: | ||
| 1227 | { | ||
| 1228 | if (p->pos < p->indexPreSize) | ||
| 1229 | { | ||
| 1230 | (*srcLen)++; | ||
| 1231 | if (*src++ != p->buf[p->pos++]) | ||
| 1232 | return SZ_ERROR_CRC; | ||
| 1233 | } | ||
| 1234 | else | ||
| 1235 | { | ||
| 1236 | if (p->indexPos < p->indexSize) | ||
| 1237 | { | ||
| 1238 | UInt64 cur = p->indexSize - p->indexPos; | ||
| 1239 | if (srcRem > cur) | ||
| 1240 | srcRem = (SizeT)cur; | ||
| 1241 | p->crc = CrcUpdate(p->crc, src, srcRem); | ||
| 1242 | Sha256_Update(&p->sha, src, srcRem); | ||
| 1243 | (*srcLen) += srcRem; | ||
| 1244 | src += srcRem; | ||
| 1245 | p->indexPos += srcRem; | ||
| 1246 | } | ||
| 1247 | else if ((p->indexPos & 3) != 0) | ||
| 1248 | { | ||
| 1249 | Byte b = *src++; | ||
| 1250 | p->crc = CRC_UPDATE_BYTE(p->crc, b); | ||
| 1251 | (*srcLen)++; | ||
| 1252 | p->indexPos++; | ||
| 1253 | p->indexSize++; | ||
| 1254 | if (b != 0) | ||
| 1255 | return SZ_ERROR_CRC; | ||
| 1256 | } | ||
| 1257 | else | ||
| 1258 | { | ||
| 1259 | Byte digest[SHA256_DIGEST_SIZE]; | ||
| 1260 | p->state = XZ_STATE_STREAM_INDEX_CRC; | ||
| 1261 | p->indexSize += 4; | ||
| 1262 | p->pos = 0; | ||
| 1263 | Sha256_Final(&p->sha, digest); | ||
| 1264 | if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0) | ||
| 1265 | return SZ_ERROR_CRC; | ||
| 1266 | } | ||
| 1267 | } | ||
| 1268 | break; | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | case XZ_STATE_STREAM_INDEX_CRC: | ||
| 1272 | { | ||
| 1273 | if (p->pos < 4) | ||
| 1274 | { | ||
| 1275 | (*srcLen)++; | ||
| 1276 | p->buf[p->pos++] = *src++; | ||
| 1277 | } | ||
| 1278 | else | ||
| 1279 | { | ||
| 1280 | const Byte *ptr = p->buf; | ||
| 1281 | p->state = XZ_STATE_STREAM_FOOTER; | ||
| 1282 | p->pos = 0; | ||
| 1283 | if (CRC_GET_DIGEST(p->crc) != GetUi32(ptr)) | ||
| 1284 | return SZ_ERROR_CRC; | ||
| 1285 | } | ||
| 1286 | break; | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | case XZ_STATE_STREAM_FOOTER: | ||
| 1290 | { | ||
| 1291 | UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos; | ||
| 1292 | if (cur > srcRem) | ||
| 1293 | cur = (UInt32)srcRem; | ||
| 1294 | memcpy(p->buf + p->pos, src, cur); | ||
| 1295 | p->pos += cur; | ||
| 1296 | (*srcLen) += cur; | ||
| 1297 | src += cur; | ||
| 1298 | if (p->pos == XZ_STREAM_FOOTER_SIZE) | ||
| 1299 | { | ||
| 1300 | p->state = XZ_STATE_STREAM_PADDING; | ||
| 1301 | p->numFinishedStreams++; | ||
| 1302 | p->padSize = 0; | ||
| 1303 | if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf)) | ||
| 1304 | return SZ_ERROR_CRC; | ||
| 1305 | } | ||
| 1306 | break; | ||
| 1307 | } | ||
| 1308 | |||
| 1309 | case XZ_STATE_STREAM_PADDING: | ||
| 1310 | { | ||
| 1311 | if (*src != 0) | ||
| 1312 | { | ||
| 1313 | if (((UInt32)p->padSize & 3) != 0) | ||
| 1314 | return SZ_ERROR_NO_ARCHIVE; | ||
| 1315 | p->pos = 0; | ||
| 1316 | p->state = XZ_STATE_STREAM_HEADER; | ||
| 1317 | } | ||
| 1318 | else | ||
| 1319 | { | ||
| 1320 | (*srcLen)++; | ||
| 1321 | src++; | ||
| 1322 | p->padSize++; | ||
| 1323 | } | ||
| 1324 | break; | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | case XZ_STATE_BLOCK: break; /* to disable GCC warning */ | ||
| 1328 | } | ||
| 1329 | } | ||
| 1330 | /* | ||
| 1331 | if (p->state == XZ_STATE_FINISHED) | ||
| 1332 | *status = CODER_STATUS_FINISHED_WITH_MARK; | ||
| 1333 | return SZ_OK; | ||
| 1334 | */ | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | |||
| 1338 | SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, | ||
| 1339 | const Byte *src, SizeT *srcLen, | ||
| 1340 | ECoderFinishMode finishMode, ECoderStatus *status) | ||
| 1341 | { | ||
| 1342 | XzUnpacker_Init(p); | ||
| 1343 | XzUnpacker_SetOutBuf(p, dest, *destLen); | ||
| 1344 | |||
| 1345 | return XzUnpacker_Code(p, | ||
| 1346 | NULL, destLen, | ||
| 1347 | src, srcLen, True, | ||
| 1348 | finishMode, status); | ||
| 1349 | } | ||
| 1350 | |||
| 1351 | |||
| 1352 | BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p) | ||
| 1353 | { | ||
| 1354 | return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0); | ||
| 1355 | } | ||
| 1356 | |||
| 1357 | BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p) | ||
| 1358 | { | ||
| 1359 | return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0); | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p) | ||
| 1363 | { | ||
| 1364 | UInt64 num = 0; | ||
| 1365 | if (p->state == XZ_STATE_STREAM_PADDING) | ||
| 1366 | num = p->padSize; | ||
| 1367 | else if (p->state == XZ_STATE_STREAM_HEADER) | ||
| 1368 | num = p->padSize + p->pos; | ||
| 1369 | return num; | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | |||
| 1373 | |||
| 1374 | |||
| 1375 | |||
| 1376 | |||
| 1377 | |||
| 1378 | |||
| 1379 | |||
| 1380 | |||
| 1381 | |||
| 1382 | |||
| 1383 | |||
| 1384 | |||
| 1385 | |||
| 1386 | |||
| 1387 | |||
| 1388 | |||
| 1389 | |||
| 1390 | |||
| 1391 | |||
| 1392 | #ifndef _7ZIP_ST | ||
| 1393 | #include "MtDec.h" | ||
| 1394 | #endif | ||
| 1395 | |||
| 1396 | |||
| 1397 | void XzDecMtProps_Init(CXzDecMtProps *p) | ||
| 1398 | { | ||
| 1399 | p->inBufSize_ST = 1 << 18; | ||
| 1400 | p->outStep_ST = 1 << 20; | ||
| 1401 | p->ignoreErrors = False; | ||
| 1402 | |||
| 1403 | #ifndef _7ZIP_ST | ||
| 1404 | p->numThreads = 1; | ||
| 1405 | p->inBufSize_MT = 1 << 18; | ||
| 1406 | p->memUseMax = sizeof(size_t) << 28; | ||
| 1407 | #endif | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | |||
| 1411 | |||
| 1412 | #ifndef _7ZIP_ST | ||
| 1413 | |||
| 1414 | /* ---------- CXzDecMtThread ---------- */ | ||
| 1415 | |||
| 1416 | typedef struct | ||
| 1417 | { | ||
| 1418 | Byte *outBuf; | ||
| 1419 | size_t outBufSize; | ||
| 1420 | size_t outPreSize; | ||
| 1421 | size_t inPreSize; | ||
| 1422 | size_t inPreHeaderSize; | ||
| 1423 | size_t blockPackSize_for_Index; // including block header and checksum. | ||
| 1424 | size_t blockPackTotal; // including stream header, block header and checksum. | ||
| 1425 | size_t inCodeSize; | ||
| 1426 | size_t outCodeSize; | ||
| 1427 | ECoderStatus status; | ||
| 1428 | SRes codeRes; | ||
| 1429 | BoolInt skipMode; | ||
| 1430 | // BoolInt finishedWithMark; | ||
| 1431 | EMtDecParseState parseState; | ||
| 1432 | BoolInt parsing_Truncated; | ||
| 1433 | BoolInt atBlockHeader; | ||
| 1434 | CXzStreamFlags streamFlags; | ||
| 1435 | // UInt64 numFinishedStreams | ||
| 1436 | UInt64 numStreams; | ||
| 1437 | UInt64 numTotalBlocks; | ||
| 1438 | UInt64 numBlocks; | ||
| 1439 | |||
| 1440 | BoolInt dec_created; | ||
| 1441 | CXzUnpacker dec; | ||
| 1442 | |||
| 1443 | Byte mtPad[1 << 7]; | ||
| 1444 | } CXzDecMtThread; | ||
| 1445 | |||
| 1446 | #endif | ||
| 1447 | |||
| 1448 | |||
| 1449 | /* ---------- CXzDecMt ---------- */ | ||
| 1450 | |||
| 1451 | typedef struct | ||
| 1452 | { | ||
| 1453 | CAlignOffsetAlloc alignOffsetAlloc; | ||
| 1454 | ISzAllocPtr allocMid; | ||
| 1455 | |||
| 1456 | CXzDecMtProps props; | ||
| 1457 | size_t unpackBlockMaxSize; | ||
| 1458 | |||
| 1459 | ISeqInStream *inStream; | ||
| 1460 | ISeqOutStream *outStream; | ||
| 1461 | ICompressProgress *progress; | ||
| 1462 | |||
| 1463 | BoolInt finishMode; | ||
| 1464 | BoolInt outSize_Defined; | ||
| 1465 | UInt64 outSize; | ||
| 1466 | |||
| 1467 | UInt64 outProcessed; | ||
| 1468 | UInt64 inProcessed; | ||
| 1469 | UInt64 readProcessed; | ||
| 1470 | BoolInt readWasFinished; | ||
| 1471 | SRes readRes; | ||
| 1472 | SRes writeRes; | ||
| 1473 | |||
| 1474 | Byte *outBuf; | ||
| 1475 | size_t outBufSize; | ||
| 1476 | Byte *inBuf; | ||
| 1477 | size_t inBufSize; | ||
| 1478 | |||
| 1479 | CXzUnpacker dec; | ||
| 1480 | |||
| 1481 | ECoderStatus status; | ||
| 1482 | SRes codeRes; | ||
| 1483 | |||
| 1484 | #ifndef _7ZIP_ST | ||
| 1485 | BoolInt mainDecoderWasCalled; | ||
| 1486 | // int statErrorDefined; | ||
| 1487 | int finishedDecoderIndex; | ||
| 1488 | |||
| 1489 | // global values that are used in Parse stage | ||
| 1490 | CXzStreamFlags streamFlags; | ||
| 1491 | // UInt64 numFinishedStreams | ||
| 1492 | UInt64 numStreams; | ||
| 1493 | UInt64 numTotalBlocks; | ||
| 1494 | UInt64 numBlocks; | ||
| 1495 | |||
| 1496 | // UInt64 numBadBlocks; | ||
| 1497 | SRes mainErrorCode; // it's set to error code, if the size Code() output doesn't patch the size from Parsing stage | ||
| 1498 | // it can be = SZ_ERROR_INPUT_EOF | ||
| 1499 | // it can be = SZ_ERROR_DATA, in some another cases | ||
| 1500 | BoolInt isBlockHeaderState_Parse; | ||
| 1501 | BoolInt isBlockHeaderState_Write; | ||
| 1502 | UInt64 outProcessed_Parse; | ||
| 1503 | BoolInt parsing_Truncated; | ||
| 1504 | |||
| 1505 | BoolInt mtc_WasConstructed; | ||
| 1506 | CMtDec mtc; | ||
| 1507 | CXzDecMtThread coders[MTDEC__THREADS_MAX]; | ||
| 1508 | #endif | ||
| 1509 | |||
| 1510 | } CXzDecMt; | ||
| 1511 | |||
| 1512 | |||
| 1513 | |||
| 1514 | CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) | ||
| 1515 | { | ||
| 1516 | CXzDecMt *p = (CXzDecMt *)ISzAlloc_Alloc(alloc, sizeof(CXzDecMt)); | ||
| 1517 | if (!p) | ||
| 1518 | return NULL; | ||
| 1519 | |||
| 1520 | AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); | ||
| 1521 | p->alignOffsetAlloc.baseAlloc = alloc; | ||
| 1522 | p->alignOffsetAlloc.numAlignBits = 7; | ||
| 1523 | p->alignOffsetAlloc.offset = 0; | ||
| 1524 | |||
| 1525 | p->allocMid = allocMid; | ||
| 1526 | |||
| 1527 | p->outBuf = NULL; | ||
| 1528 | p->outBufSize = 0; | ||
| 1529 | p->inBuf = NULL; | ||
| 1530 | p->inBufSize = 0; | ||
| 1531 | |||
| 1532 | XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt); | ||
| 1533 | |||
| 1534 | p->unpackBlockMaxSize = 0; | ||
| 1535 | |||
| 1536 | XzDecMtProps_Init(&p->props); | ||
| 1537 | |||
| 1538 | #ifndef _7ZIP_ST | ||
| 1539 | p->mtc_WasConstructed = False; | ||
| 1540 | { | ||
| 1541 | unsigned i; | ||
| 1542 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 1543 | { | ||
| 1544 | CXzDecMtThread *coder = &p->coders[i]; | ||
| 1545 | coder->dec_created = False; | ||
| 1546 | coder->outBuf = NULL; | ||
| 1547 | coder->outBufSize = 0; | ||
| 1548 | } | ||
| 1549 | } | ||
| 1550 | #endif | ||
| 1551 | |||
| 1552 | return p; | ||
| 1553 | } | ||
| 1554 | |||
| 1555 | |||
| 1556 | #ifndef _7ZIP_ST | ||
| 1557 | |||
| 1558 | static void XzDecMt_FreeOutBufs(CXzDecMt *p) | ||
| 1559 | { | ||
| 1560 | unsigned i; | ||
| 1561 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 1562 | { | ||
| 1563 | CXzDecMtThread *coder = &p->coders[i]; | ||
| 1564 | if (coder->outBuf) | ||
| 1565 | { | ||
| 1566 | ISzAlloc_Free(p->allocMid, coder->outBuf); | ||
| 1567 | coder->outBuf = NULL; | ||
| 1568 | coder->outBufSize = 0; | ||
| 1569 | } | ||
| 1570 | } | ||
| 1571 | p->unpackBlockMaxSize = 0; | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | #endif | ||
| 1575 | |||
| 1576 | |||
| 1577 | |||
| 1578 | static void XzDecMt_FreeSt(CXzDecMt *p) | ||
| 1579 | { | ||
| 1580 | XzUnpacker_Free(&p->dec); | ||
| 1581 | |||
| 1582 | if (p->outBuf) | ||
| 1583 | { | ||
| 1584 | ISzAlloc_Free(p->allocMid, p->outBuf); | ||
| 1585 | p->outBuf = NULL; | ||
| 1586 | } | ||
| 1587 | p->outBufSize = 0; | ||
| 1588 | |||
| 1589 | if (p->inBuf) | ||
| 1590 | { | ||
| 1591 | ISzAlloc_Free(p->allocMid, p->inBuf); | ||
| 1592 | p->inBuf = NULL; | ||
| 1593 | } | ||
| 1594 | p->inBufSize = 0; | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | |||
| 1598 | void XzDecMt_Destroy(CXzDecMtHandle pp) | ||
| 1599 | { | ||
| 1600 | CXzDecMt *p = (CXzDecMt *)pp; | ||
| 1601 | |||
| 1602 | XzDecMt_FreeSt(p); | ||
| 1603 | |||
| 1604 | #ifndef _7ZIP_ST | ||
| 1605 | |||
| 1606 | if (p->mtc_WasConstructed) | ||
| 1607 | { | ||
| 1608 | MtDec_Destruct(&p->mtc); | ||
| 1609 | p->mtc_WasConstructed = False; | ||
| 1610 | } | ||
| 1611 | { | ||
| 1612 | unsigned i; | ||
| 1613 | for (i = 0; i < MTDEC__THREADS_MAX; i++) | ||
| 1614 | { | ||
| 1615 | CXzDecMtThread *t = &p->coders[i]; | ||
| 1616 | if (t->dec_created) | ||
| 1617 | { | ||
| 1618 | // we don't need to free dict here | ||
| 1619 | XzUnpacker_Free(&t->dec); | ||
| 1620 | t->dec_created = False; | ||
| 1621 | } | ||
| 1622 | } | ||
| 1623 | } | ||
| 1624 | XzDecMt_FreeOutBufs(p); | ||
| 1625 | |||
| 1626 | #endif | ||
| 1627 | |||
| 1628 | ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp); | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | |||
| 1632 | |||
| 1633 | #ifndef _7ZIP_ST | ||
| 1634 | |||
| 1635 | static void XzDecMt_Callback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) | ||
| 1636 | { | ||
| 1637 | CXzDecMt *me = (CXzDecMt *)obj; | ||
| 1638 | CXzDecMtThread *coder = &me->coders[coderIndex]; | ||
| 1639 | size_t srcSize = cc->srcSize; | ||
| 1640 | |||
| 1641 | cc->srcSize = 0; | ||
| 1642 | cc->outPos = 0; | ||
| 1643 | cc->state = MTDEC_PARSE_CONTINUE; | ||
| 1644 | |||
| 1645 | cc->canCreateNewThread = True; | ||
| 1646 | |||
| 1647 | if (cc->startCall) | ||
| 1648 | { | ||
| 1649 | coder->outPreSize = 0; | ||
| 1650 | coder->inPreSize = 0; | ||
| 1651 | coder->inPreHeaderSize = 0; | ||
| 1652 | coder->parseState = MTDEC_PARSE_CONTINUE; | ||
| 1653 | coder->parsing_Truncated = False; | ||
| 1654 | coder->skipMode = False; | ||
| 1655 | coder->codeRes = SZ_OK; | ||
| 1656 | coder->status = CODER_STATUS_NOT_SPECIFIED; | ||
| 1657 | coder->inCodeSize = 0; | ||
| 1658 | coder->outCodeSize = 0; | ||
| 1659 | |||
| 1660 | coder->numStreams = me->numStreams; | ||
| 1661 | coder->numTotalBlocks = me->numTotalBlocks; | ||
| 1662 | coder->numBlocks = me->numBlocks; | ||
| 1663 | |||
| 1664 | if (!coder->dec_created) | ||
| 1665 | { | ||
| 1666 | XzUnpacker_Construct(&coder->dec, &me->alignOffsetAlloc.vt); | ||
| 1667 | coder->dec_created = True; | ||
| 1668 | } | ||
| 1669 | |||
| 1670 | XzUnpacker_Init(&coder->dec); | ||
| 1671 | |||
| 1672 | if (me->isBlockHeaderState_Parse) | ||
| 1673 | { | ||
| 1674 | coder->dec.streamFlags = me->streamFlags; | ||
| 1675 | coder->atBlockHeader = True; | ||
| 1676 | XzUnpacker_PrepareToRandomBlockDecoding(&coder->dec); | ||
| 1677 | } | ||
| 1678 | else | ||
| 1679 | { | ||
| 1680 | coder->atBlockHeader = False; | ||
| 1681 | me->isBlockHeaderState_Parse = True; | ||
| 1682 | } | ||
| 1683 | |||
| 1684 | coder->dec.numStartedStreams = me->numStreams; | ||
| 1685 | coder->dec.numTotalBlocks = me->numTotalBlocks; | ||
| 1686 | coder->dec.numBlocks = me->numBlocks; | ||
| 1687 | } | ||
| 1688 | |||
| 1689 | while (!coder->skipMode) | ||
| 1690 | { | ||
| 1691 | ECoderStatus status; | ||
| 1692 | SRes res; | ||
| 1693 | size_t srcSize2 = srcSize; | ||
| 1694 | size_t destSize = (size_t)0 - 1; | ||
| 1695 | |||
| 1696 | coder->dec.parseMode = True; | ||
| 1697 | coder->dec.headerParsedOk = False; | ||
| 1698 | |||
| 1699 | PRF_STR_INT("Parse", srcSize2); | ||
| 1700 | |||
| 1701 | res = XzUnpacker_Code(&coder->dec, | ||
| 1702 | NULL, &destSize, | ||
| 1703 | cc->src, &srcSize2, cc->srcFinished, | ||
| 1704 | CODER_FINISH_END, &status); | ||
| 1705 | |||
| 1706 | // PRF(printf(" res = %d, srcSize2 = %d", res, (unsigned)srcSize2)); | ||
| 1707 | |||
| 1708 | coder->codeRes = res; | ||
| 1709 | coder->status = status; | ||
| 1710 | cc->srcSize += srcSize2; | ||
| 1711 | srcSize -= srcSize2; | ||
| 1712 | coder->inPreHeaderSize += srcSize2; | ||
| 1713 | coder->inPreSize = coder->inPreHeaderSize; | ||
| 1714 | |||
| 1715 | if (res != SZ_OK) | ||
| 1716 | { | ||
| 1717 | cc->state = | ||
| 1718 | coder->parseState = MTDEC_PARSE_END; | ||
| 1719 | /* | ||
| 1720 | if (res == SZ_ERROR_MEM) | ||
| 1721 | return res; | ||
| 1722 | return SZ_OK; | ||
| 1723 | */ | ||
| 1724 | return; // res; | ||
| 1725 | } | ||
| 1726 | |||
| 1727 | if (coder->dec.headerParsedOk) | ||
| 1728 | { | ||
| 1729 | const CXzBlock *block = &coder->dec.block; | ||
| 1730 | if (XzBlock_HasUnpackSize(block) | ||
| 1731 | // && block->unpackSize <= me->props.outBlockMax | ||
| 1732 | && XzBlock_HasPackSize(block)) | ||
| 1733 | { | ||
| 1734 | { | ||
| 1735 | if (block->unpackSize * 2 * me->mtc.numStartedThreads > me->props.memUseMax) | ||
| 1736 | { | ||
| 1737 | cc->state = MTDEC_PARSE_OVERFLOW; | ||
| 1738 | return; // SZ_OK; | ||
| 1739 | } | ||
| 1740 | } | ||
| 1741 | { | ||
| 1742 | UInt64 packSize = block->packSize; | ||
| 1743 | UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3); | ||
| 1744 | UInt32 checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags); | ||
| 1745 | UInt64 blockPackSum = coder->inPreSize + packSizeAligned + checkSize; | ||
| 1746 | // if (blockPackSum <= me->props.inBlockMax) | ||
| 1747 | // unpackBlockMaxSize | ||
| 1748 | { | ||
| 1749 | coder->blockPackSize_for_Index = (size_t)(coder->dec.blockHeaderSize + packSize + checkSize); | ||
| 1750 | coder->blockPackTotal = (size_t)blockPackSum; | ||
| 1751 | coder->outPreSize = (size_t)block->unpackSize; | ||
| 1752 | coder->streamFlags = coder->dec.streamFlags; | ||
| 1753 | me->streamFlags = coder->dec.streamFlags; | ||
| 1754 | coder->skipMode = True; | ||
| 1755 | break; | ||
| 1756 | } | ||
| 1757 | } | ||
| 1758 | } | ||
| 1759 | } | ||
| 1760 | else | ||
| 1761 | // if (coder->inPreSize <= me->props.inBlockMax) | ||
| 1762 | { | ||
| 1763 | if (!cc->srcFinished) | ||
| 1764 | return; // SZ_OK; | ||
| 1765 | cc->state = | ||
| 1766 | coder->parseState = MTDEC_PARSE_END; | ||
| 1767 | return; // SZ_OK; | ||
| 1768 | } | ||
| 1769 | cc->state = MTDEC_PARSE_OVERFLOW; | ||
| 1770 | return; // SZ_OK; | ||
| 1771 | } | ||
| 1772 | |||
| 1773 | // ---------- skipMode ---------- | ||
| 1774 | { | ||
| 1775 | UInt64 rem = coder->blockPackTotal - coder->inPreSize; | ||
| 1776 | size_t cur = srcSize; | ||
| 1777 | if (cur > rem) | ||
| 1778 | cur = (size_t)rem; | ||
| 1779 | cc->srcSize += cur; | ||
| 1780 | coder->inPreSize += cur; | ||
| 1781 | srcSize -= cur; | ||
| 1782 | |||
| 1783 | if (coder->inPreSize == coder->blockPackTotal) | ||
| 1784 | { | ||
| 1785 | if (srcSize == 0) | ||
| 1786 | { | ||
| 1787 | if (!cc->srcFinished) | ||
| 1788 | return; // SZ_OK; | ||
| 1789 | cc->state = MTDEC_PARSE_END; | ||
| 1790 | } | ||
| 1791 | else if ((cc->src)[cc->srcSize] == 0) // we check control byte of next block | ||
| 1792 | cc->state = MTDEC_PARSE_END; | ||
| 1793 | else | ||
| 1794 | { | ||
| 1795 | cc->state = MTDEC_PARSE_NEW; | ||
| 1796 | |||
| 1797 | { | ||
| 1798 | size_t blockMax = me->unpackBlockMaxSize; | ||
| 1799 | if (blockMax < coder->outPreSize) | ||
| 1800 | blockMax = coder->outPreSize; | ||
| 1801 | { | ||
| 1802 | UInt64 required = (UInt64)blockMax * (me->mtc.numStartedThreads + 1) * 2; | ||
| 1803 | if (me->props.memUseMax < required) | ||
| 1804 | cc->canCreateNewThread = False; | ||
| 1805 | } | ||
| 1806 | } | ||
| 1807 | |||
| 1808 | if (me->outSize_Defined) | ||
| 1809 | { | ||
| 1810 | // next block can be zero size | ||
| 1811 | const UInt64 rem2 = me->outSize - me->outProcessed_Parse; | ||
| 1812 | if (rem2 < coder->outPreSize) | ||
| 1813 | { | ||
| 1814 | coder->parsing_Truncated = True; | ||
| 1815 | cc->state = MTDEC_PARSE_END; | ||
| 1816 | } | ||
| 1817 | me->outProcessed_Parse += coder->outPreSize; | ||
| 1818 | } | ||
| 1819 | } | ||
| 1820 | } | ||
| 1821 | else if (cc->srcFinished) | ||
| 1822 | cc->state = MTDEC_PARSE_END; | ||
| 1823 | else | ||
| 1824 | return; // SZ_OK; | ||
| 1825 | |||
| 1826 | coder->parseState = cc->state; | ||
| 1827 | cc->outPos = coder->outPreSize; | ||
| 1828 | |||
| 1829 | me->numStreams = coder->dec.numStartedStreams; | ||
| 1830 | me->numTotalBlocks = coder->dec.numTotalBlocks; | ||
| 1831 | me->numBlocks = coder->dec.numBlocks + 1; | ||
| 1832 | return; // SZ_OK; | ||
| 1833 | } | ||
| 1834 | } | ||
| 1835 | |||
| 1836 | |||
| 1837 | static SRes XzDecMt_Callback_PreCode(void *pp, unsigned coderIndex) | ||
| 1838 | { | ||
| 1839 | CXzDecMt *me = (CXzDecMt *)pp; | ||
| 1840 | CXzDecMtThread *coder = &me->coders[coderIndex]; | ||
| 1841 | Byte *dest; | ||
| 1842 | |||
| 1843 | if (!coder->dec.headerParsedOk) | ||
| 1844 | return SZ_OK; | ||
| 1845 | |||
| 1846 | dest = coder->outBuf; | ||
| 1847 | |||
| 1848 | if (!dest || coder->outBufSize < coder->outPreSize) | ||
| 1849 | { | ||
| 1850 | if (dest) | ||
| 1851 | { | ||
| 1852 | ISzAlloc_Free(me->allocMid, dest); | ||
| 1853 | coder->outBuf = NULL; | ||
| 1854 | coder->outBufSize = 0; | ||
| 1855 | } | ||
| 1856 | { | ||
| 1857 | size_t outPreSize = coder->outPreSize; | ||
| 1858 | if (outPreSize == 0) | ||
| 1859 | outPreSize = 1; | ||
| 1860 | dest = (Byte *)ISzAlloc_Alloc(me->allocMid, outPreSize); | ||
| 1861 | } | ||
| 1862 | if (!dest) | ||
| 1863 | return SZ_ERROR_MEM; | ||
| 1864 | coder->outBuf = dest; | ||
| 1865 | coder->outBufSize = coder->outPreSize; | ||
| 1866 | |||
| 1867 | if (coder->outBufSize > me->unpackBlockMaxSize) | ||
| 1868 | me->unpackBlockMaxSize = coder->outBufSize; | ||
| 1869 | } | ||
| 1870 | |||
| 1871 | // return SZ_ERROR_MEM; | ||
| 1872 | |||
| 1873 | XzUnpacker_SetOutBuf(&coder->dec, coder->outBuf, coder->outBufSize); | ||
| 1874 | |||
| 1875 | { | ||
| 1876 | SRes res = XzDecMix_Init(&coder->dec.decoder, &coder->dec.block, coder->outBuf, coder->outBufSize); | ||
| 1877 | // res = SZ_ERROR_UNSUPPORTED; // to test | ||
| 1878 | coder->codeRes = res; | ||
| 1879 | if (res != SZ_OK) | ||
| 1880 | { | ||
| 1881 | // if (res == SZ_ERROR_MEM) return res; | ||
| 1882 | if (me->props.ignoreErrors && res != SZ_ERROR_MEM) | ||
| 1883 | return SZ_OK; | ||
| 1884 | return res; | ||
| 1885 | } | ||
| 1886 | } | ||
| 1887 | |||
| 1888 | return SZ_OK; | ||
| 1889 | } | ||
| 1890 | |||
| 1891 | |||
| 1892 | static SRes XzDecMt_Callback_Code(void *pp, unsigned coderIndex, | ||
| 1893 | const Byte *src, size_t srcSize, int srcFinished, | ||
| 1894 | // int finished, int blockFinished, | ||
| 1895 | UInt64 *inCodePos, UInt64 *outCodePos, int *stop) | ||
| 1896 | { | ||
| 1897 | CXzDecMt *me = (CXzDecMt *)pp; | ||
| 1898 | CXzDecMtThread *coder = &me->coders[coderIndex]; | ||
| 1899 | |||
| 1900 | *inCodePos = coder->inCodeSize; | ||
| 1901 | *outCodePos = coder->outCodeSize; | ||
| 1902 | *stop = True; | ||
| 1903 | |||
| 1904 | if (srcSize > coder->inPreSize - coder->inCodeSize) | ||
| 1905 | return SZ_ERROR_FAIL; | ||
| 1906 | |||
| 1907 | if (coder->inCodeSize < coder->inPreHeaderSize) | ||
| 1908 | { | ||
| 1909 | size_t step = coder->inPreHeaderSize - coder->inCodeSize; | ||
| 1910 | if (step > srcSize) | ||
| 1911 | step = srcSize; | ||
| 1912 | src += step; | ||
| 1913 | srcSize -= step; | ||
| 1914 | coder->inCodeSize += step; | ||
| 1915 | *inCodePos = coder->inCodeSize; | ||
| 1916 | if (coder->inCodeSize < coder->inPreHeaderSize) | ||
| 1917 | { | ||
| 1918 | *stop = False; | ||
| 1919 | return SZ_OK; | ||
| 1920 | } | ||
| 1921 | } | ||
| 1922 | |||
| 1923 | if (!coder->dec.headerParsedOk) | ||
| 1924 | return SZ_OK; | ||
| 1925 | if (!coder->outBuf) | ||
| 1926 | return SZ_OK; | ||
| 1927 | |||
| 1928 | if (coder->codeRes == SZ_OK) | ||
| 1929 | { | ||
| 1930 | ECoderStatus status; | ||
| 1931 | SRes res; | ||
| 1932 | size_t srcProcessed = srcSize; | ||
| 1933 | size_t outSizeCur = coder->outPreSize - coder->dec.outDataWritten; | ||
| 1934 | |||
| 1935 | // PRF(printf("\nCallback_Code: Code %d %d\n", (unsigned)srcSize, (unsigned)outSizeCur)); | ||
| 1936 | |||
| 1937 | res = XzUnpacker_Code(&coder->dec, | ||
| 1938 | NULL, &outSizeCur, | ||
| 1939 | src, &srcProcessed, srcFinished, | ||
| 1940 | // coder->finishedWithMark ? CODER_FINISH_END : CODER_FINISH_ANY, | ||
| 1941 | CODER_FINISH_END, | ||
| 1942 | &status); | ||
| 1943 | |||
| 1944 | // PRF(printf(" res = %d, srcSize2 = %d, outSizeCur = %d", res, (unsigned)srcProcessed, (unsigned)outSizeCur)); | ||
| 1945 | |||
| 1946 | coder->codeRes = res; | ||
| 1947 | coder->status = status; | ||
| 1948 | coder->inCodeSize += srcProcessed; | ||
| 1949 | coder->outCodeSize = coder->dec.outDataWritten; | ||
| 1950 | *inCodePos = coder->inCodeSize; | ||
| 1951 | *outCodePos = coder->outCodeSize; | ||
| 1952 | |||
| 1953 | if (res == SZ_OK) | ||
| 1954 | { | ||
| 1955 | if (srcProcessed == srcSize) | ||
| 1956 | *stop = False; | ||
| 1957 | return SZ_OK; | ||
| 1958 | } | ||
| 1959 | } | ||
| 1960 | |||
| 1961 | if (me->props.ignoreErrors && coder->codeRes != SZ_ERROR_MEM) | ||
| 1962 | { | ||
| 1963 | *inCodePos = coder->inPreSize; | ||
| 1964 | *outCodePos = coder->outPreSize; | ||
| 1965 | return SZ_OK; | ||
| 1966 | } | ||
| 1967 | return coder->codeRes; | ||
| 1968 | } | ||
| 1969 | |||
| 1970 | |||
| 1971 | #define XZDECMT_STREAM_WRITE_STEP (1 << 24) | ||
| 1972 | |||
| 1973 | static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex, | ||
| 1974 | BoolInt needWriteToStream, | ||
| 1975 | const Byte *src, size_t srcSize, BoolInt isCross, | ||
| 1976 | // int srcFinished, | ||
| 1977 | BoolInt *needContinue, | ||
| 1978 | BoolInt *canRecode) | ||
| 1979 | { | ||
| 1980 | CXzDecMt *me = (CXzDecMt *)pp; | ||
| 1981 | const CXzDecMtThread *coder = &me->coders[coderIndex]; | ||
| 1982 | |||
| 1983 | // PRF(printf("\nWrite processed = %d srcSize = %d\n", (unsigned)me->mtc.inProcessed, (unsigned)srcSize)); | ||
| 1984 | |||
| 1985 | *needContinue = False; | ||
| 1986 | *canRecode = True; | ||
| 1987 | |||
| 1988 | if (!needWriteToStream) | ||
| 1989 | return SZ_OK; | ||
| 1990 | |||
| 1991 | if (!coder->dec.headerParsedOk || !coder->outBuf) | ||
| 1992 | { | ||
| 1993 | if (me->finishedDecoderIndex < 0) | ||
| 1994 | me->finishedDecoderIndex = (int)coderIndex; | ||
| 1995 | return SZ_OK; | ||
| 1996 | } | ||
| 1997 | |||
| 1998 | if (me->finishedDecoderIndex >= 0) | ||
| 1999 | return SZ_OK; | ||
| 2000 | |||
| 2001 | me->mtc.inProcessed += coder->inCodeSize; | ||
| 2002 | |||
| 2003 | *canRecode = False; | ||
| 2004 | |||
| 2005 | { | ||
| 2006 | SRes res; | ||
| 2007 | size_t size = coder->outCodeSize; | ||
| 2008 | Byte *data = coder->outBuf; | ||
| 2009 | |||
| 2010 | // we use in me->dec: sha, numBlocks, indexSize | ||
| 2011 | |||
| 2012 | if (!me->isBlockHeaderState_Write) | ||
| 2013 | { | ||
| 2014 | XzUnpacker_PrepareToRandomBlockDecoding(&me->dec); | ||
| 2015 | me->dec.decodeOnlyOneBlock = False; | ||
| 2016 | me->dec.numStartedStreams = coder->dec.numStartedStreams; | ||
| 2017 | me->dec.streamFlags = coder->streamFlags; | ||
| 2018 | |||
| 2019 | me->isBlockHeaderState_Write = True; | ||
| 2020 | } | ||
| 2021 | |||
| 2022 | me->dec.numTotalBlocks = coder->dec.numTotalBlocks; | ||
| 2023 | XzUnpacker_UpdateIndex(&me->dec, coder->blockPackSize_for_Index, coder->outPreSize); | ||
| 2024 | |||
| 2025 | if (coder->outPreSize != size) | ||
| 2026 | { | ||
| 2027 | if (me->props.ignoreErrors) | ||
| 2028 | { | ||
| 2029 | memset(data + size, 0, coder->outPreSize - size); | ||
| 2030 | size = coder->outPreSize; | ||
| 2031 | } | ||
| 2032 | // me->numBadBlocks++; | ||
| 2033 | if (me->mainErrorCode == SZ_OK) | ||
| 2034 | { | ||
| 2035 | if ((int)coder->status == LZMA_STATUS_NEEDS_MORE_INPUT) | ||
| 2036 | me->mainErrorCode = SZ_ERROR_INPUT_EOF; | ||
| 2037 | else | ||
| 2038 | me->mainErrorCode = SZ_ERROR_DATA; | ||
| 2039 | } | ||
| 2040 | } | ||
| 2041 | |||
| 2042 | if (me->writeRes != SZ_OK) | ||
| 2043 | return me->writeRes; | ||
| 2044 | |||
| 2045 | res = SZ_OK; | ||
| 2046 | { | ||
| 2047 | if (me->outSize_Defined) | ||
| 2048 | { | ||
| 2049 | const UInt64 rem = me->outSize - me->outProcessed; | ||
| 2050 | if (size > rem) | ||
| 2051 | size = (SizeT)rem; | ||
| 2052 | } | ||
| 2053 | |||
| 2054 | for (;;) | ||
| 2055 | { | ||
| 2056 | size_t cur = size; | ||
| 2057 | size_t written; | ||
| 2058 | if (cur > XZDECMT_STREAM_WRITE_STEP) | ||
| 2059 | cur = XZDECMT_STREAM_WRITE_STEP; | ||
| 2060 | |||
| 2061 | written = ISeqOutStream_Write(me->outStream, data, cur); | ||
| 2062 | |||
| 2063 | // PRF(printf("\nWritten ask = %d written = %d\n", (unsigned)cur, (unsigned)written)); | ||
| 2064 | |||
| 2065 | me->outProcessed += written; | ||
| 2066 | if (written != cur) | ||
| 2067 | { | ||
| 2068 | me->writeRes = SZ_ERROR_WRITE; | ||
| 2069 | res = me->writeRes; | ||
| 2070 | break; | ||
| 2071 | } | ||
| 2072 | data += cur; | ||
| 2073 | size -= cur; | ||
| 2074 | // PRF_STR_INT("Written size =", size); | ||
| 2075 | if (size == 0) | ||
| 2076 | break; | ||
| 2077 | res = MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0); | ||
| 2078 | if (res != SZ_OK) | ||
| 2079 | break; | ||
| 2080 | } | ||
| 2081 | } | ||
| 2082 | |||
| 2083 | if (coder->codeRes != SZ_OK) | ||
| 2084 | if (!me->props.ignoreErrors) | ||
| 2085 | { | ||
| 2086 | me->finishedDecoderIndex = (int)coderIndex; | ||
| 2087 | return res; | ||
| 2088 | } | ||
| 2089 | |||
| 2090 | RINOK(res); | ||
| 2091 | |||
| 2092 | if (coder->inPreSize != coder->inCodeSize | ||
| 2093 | || coder->blockPackTotal != coder->inCodeSize) | ||
| 2094 | { | ||
| 2095 | me->finishedDecoderIndex = (int)coderIndex; | ||
| 2096 | return SZ_OK; | ||
| 2097 | } | ||
| 2098 | |||
| 2099 | if (coder->parseState != MTDEC_PARSE_END) | ||
| 2100 | { | ||
| 2101 | *needContinue = True; | ||
| 2102 | return SZ_OK; | ||
| 2103 | } | ||
| 2104 | } | ||
| 2105 | |||
| 2106 | // (coder->state == MTDEC_PARSE_END) means that there are no other working threads | ||
| 2107 | // so we can use mtc variables without lock | ||
| 2108 | |||
| 2109 | PRF_STR_INT("Write MTDEC_PARSE_END", me->mtc.inProcessed); | ||
| 2110 | |||
| 2111 | me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; | ||
| 2112 | { | ||
| 2113 | CXzUnpacker *dec = &me->dec; | ||
| 2114 | |||
| 2115 | PRF_STR_INT("PostSingle", srcSize); | ||
| 2116 | |||
| 2117 | { | ||
| 2118 | size_t srcProcessed = srcSize; | ||
| 2119 | ECoderStatus status; | ||
| 2120 | size_t outSizeCur = 0; | ||
| 2121 | SRes res; | ||
| 2122 | |||
| 2123 | // dec->decodeOnlyOneBlock = False; | ||
| 2124 | dec->decodeToStreamSignature = True; | ||
| 2125 | |||
| 2126 | me->mainDecoderWasCalled = True; | ||
| 2127 | |||
| 2128 | if (coder->parsing_Truncated) | ||
| 2129 | { | ||
| 2130 | me->parsing_Truncated = True; | ||
| 2131 | return SZ_OK; | ||
| 2132 | } | ||
| 2133 | |||
| 2134 | /* | ||
| 2135 | We have processed all xz-blocks of stream, | ||
| 2136 | And xz unpacker is at XZ_STATE_BLOCK_HEADER state, where | ||
| 2137 | (src) is a pointer to xz-Index structure. | ||
| 2138 | We finish reading of current xz-Stream, including Zero padding after xz-Stream. | ||
| 2139 | We exit, if we reach extra byte (first byte of new-Stream or another data). | ||
| 2140 | But we don't update input stream pointer for that new extra byte. | ||
| 2141 | If extra byte is not correct first byte of xz-signature, | ||
| 2142 | we have SZ_ERROR_NO_ARCHIVE error here. | ||
| 2143 | */ | ||
| 2144 | |||
| 2145 | res = XzUnpacker_Code(dec, | ||
| 2146 | NULL, &outSizeCur, | ||
| 2147 | src, &srcProcessed, | ||
| 2148 | me->mtc.readWasFinished, // srcFinished | ||
| 2149 | CODER_FINISH_END, // CODER_FINISH_ANY, | ||
| 2150 | &status); | ||
| 2151 | |||
| 2152 | // res = SZ_ERROR_ARCHIVE; // for failure test | ||
| 2153 | |||
| 2154 | me->status = status; | ||
| 2155 | me->codeRes = res; | ||
| 2156 | |||
| 2157 | if (isCross) | ||
| 2158 | me->mtc.crossStart += srcProcessed; | ||
| 2159 | |||
| 2160 | me->mtc.inProcessed += srcProcessed; | ||
| 2161 | me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; | ||
| 2162 | |||
| 2163 | srcSize -= srcProcessed; | ||
| 2164 | src += srcProcessed; | ||
| 2165 | |||
| 2166 | if (res != SZ_OK) | ||
| 2167 | { | ||
| 2168 | return SZ_OK; | ||
| 2169 | // return res; | ||
| 2170 | } | ||
| 2171 | |||
| 2172 | if (dec->state == XZ_STATE_STREAM_HEADER) | ||
| 2173 | { | ||
| 2174 | *needContinue = True; | ||
| 2175 | me->isBlockHeaderState_Parse = False; | ||
| 2176 | me->isBlockHeaderState_Write = False; | ||
| 2177 | |||
| 2178 | if (!isCross) | ||
| 2179 | { | ||
| 2180 | Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); | ||
| 2181 | if (!crossBuf) | ||
| 2182 | return SZ_ERROR_MEM; | ||
| 2183 | if (srcSize != 0) | ||
| 2184 | memcpy(crossBuf, src, srcSize); | ||
| 2185 | me->mtc.crossStart = 0; | ||
| 2186 | me->mtc.crossEnd = srcSize; | ||
| 2187 | } | ||
| 2188 | |||
| 2189 | PRF_STR_INT("XZ_STATE_STREAM_HEADER crossEnd = ", (unsigned)me->mtc.crossEnd); | ||
| 2190 | |||
| 2191 | return SZ_OK; | ||
| 2192 | } | ||
| 2193 | |||
| 2194 | if (status != CODER_STATUS_NEEDS_MORE_INPUT || srcSize != 0) | ||
| 2195 | { | ||
| 2196 | return SZ_ERROR_FAIL; | ||
| 2197 | } | ||
| 2198 | |||
| 2199 | if (me->mtc.readWasFinished) | ||
| 2200 | { | ||
| 2201 | return SZ_OK; | ||
| 2202 | } | ||
| 2203 | } | ||
| 2204 | |||
| 2205 | { | ||
| 2206 | size_t inPos; | ||
| 2207 | size_t inLim; | ||
| 2208 | // const Byte *inData; | ||
| 2209 | UInt64 inProgressPrev = me->mtc.inProcessed; | ||
| 2210 | |||
| 2211 | // XzDecMt_Prepare_InBuf_ST(p); | ||
| 2212 | Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); | ||
| 2213 | if (!crossBuf) | ||
| 2214 | return SZ_ERROR_MEM; | ||
| 2215 | |||
| 2216 | inPos = 0; | ||
| 2217 | inLim = 0; | ||
| 2218 | |||
| 2219 | // inData = crossBuf; | ||
| 2220 | |||
| 2221 | for (;;) | ||
| 2222 | { | ||
| 2223 | SizeT inProcessed; | ||
| 2224 | SizeT outProcessed; | ||
| 2225 | ECoderStatus status; | ||
| 2226 | SRes res; | ||
| 2227 | |||
| 2228 | if (inPos == inLim) | ||
| 2229 | { | ||
| 2230 | if (!me->mtc.readWasFinished) | ||
| 2231 | { | ||
| 2232 | inPos = 0; | ||
| 2233 | inLim = me->mtc.inBufSize; | ||
| 2234 | me->mtc.readRes = ISeqInStream_Read(me->inStream, (void *)crossBuf, &inLim); | ||
| 2235 | me->mtc.readProcessed += inLim; | ||
| 2236 | if (inLim == 0 || me->mtc.readRes != SZ_OK) | ||
| 2237 | me->mtc.readWasFinished = True; | ||
| 2238 | } | ||
| 2239 | } | ||
| 2240 | |||
| 2241 | inProcessed = inLim - inPos; | ||
| 2242 | outProcessed = 0; | ||
| 2243 | |||
| 2244 | res = XzUnpacker_Code(dec, | ||
| 2245 | NULL, &outProcessed, | ||
| 2246 | crossBuf + inPos, &inProcessed, | ||
| 2247 | (inProcessed == 0), // srcFinished | ||
| 2248 | CODER_FINISH_END, &status); | ||
| 2249 | |||
| 2250 | me->codeRes = res; | ||
| 2251 | me->status = status; | ||
| 2252 | inPos += inProcessed; | ||
| 2253 | me->mtc.inProcessed += inProcessed; | ||
| 2254 | me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; | ||
| 2255 | |||
| 2256 | if (res != SZ_OK) | ||
| 2257 | { | ||
| 2258 | return SZ_OK; | ||
| 2259 | // return res; | ||
| 2260 | } | ||
| 2261 | |||
| 2262 | if (dec->state == XZ_STATE_STREAM_HEADER) | ||
| 2263 | { | ||
| 2264 | *needContinue = True; | ||
| 2265 | me->mtc.crossStart = inPos; | ||
| 2266 | me->mtc.crossEnd = inLim; | ||
| 2267 | me->isBlockHeaderState_Parse = False; | ||
| 2268 | me->isBlockHeaderState_Write = False; | ||
| 2269 | return SZ_OK; | ||
| 2270 | } | ||
| 2271 | |||
| 2272 | if (status != CODER_STATUS_NEEDS_MORE_INPUT) | ||
| 2273 | return SZ_ERROR_FAIL; | ||
| 2274 | |||
| 2275 | if (me->mtc.progress) | ||
| 2276 | { | ||
| 2277 | UInt64 inDelta = me->mtc.inProcessed - inProgressPrev; | ||
| 2278 | if (inDelta >= (1 << 22)) | ||
| 2279 | { | ||
| 2280 | RINOK(MtProgress_Progress_ST(&me->mtc.mtProgress)); | ||
| 2281 | inProgressPrev = me->mtc.inProcessed; | ||
| 2282 | } | ||
| 2283 | } | ||
| 2284 | if (me->mtc.readWasFinished) | ||
| 2285 | return SZ_OK; | ||
| 2286 | } | ||
| 2287 | } | ||
| 2288 | } | ||
| 2289 | } | ||
| 2290 | |||
| 2291 | |||
| 2292 | #endif | ||
| 2293 | |||
| 2294 | |||
| 2295 | |||
| 2296 | void XzStatInfo_Clear(CXzStatInfo *p) | ||
| 2297 | { | ||
| 2298 | p->InSize = 0; | ||
| 2299 | p->OutSize = 0; | ||
| 2300 | |||
| 2301 | p->NumStreams = 0; | ||
| 2302 | p->NumBlocks = 0; | ||
| 2303 | |||
| 2304 | p->UnpackSize_Defined = False; | ||
| 2305 | |||
| 2306 | p->NumStreams_Defined = False; | ||
| 2307 | p->NumBlocks_Defined = False; | ||
| 2308 | |||
| 2309 | p->DataAfterEnd = False; | ||
| 2310 | p->DecodingTruncated = False; | ||
| 2311 | |||
| 2312 | p->DecodeRes = SZ_OK; | ||
| 2313 | p->ReadRes = SZ_OK; | ||
| 2314 | p->ProgressRes = SZ_OK; | ||
| 2315 | |||
| 2316 | p->CombinedRes = SZ_OK; | ||
| 2317 | p->CombinedRes_Type = SZ_OK; | ||
| 2318 | } | ||
| 2319 | |||
| 2320 | |||
| 2321 | |||
| 2322 | /* | ||
| 2323 | XzDecMt_Decode_ST() can return SZ_OK or the following errors | ||
| 2324 | - SZ_ERROR_MEM for memory allocation error | ||
| 2325 | - error from XzUnpacker_Code() function | ||
| 2326 | - SZ_ERROR_WRITE for ISeqOutStream::Write(). stat->CombinedRes_Type = SZ_ERROR_WRITE in that case | ||
| 2327 | - ICompressProgress::Progress() error, stat->CombinedRes_Type = SZ_ERROR_PROGRESS. | ||
| 2328 | But XzDecMt_Decode_ST() doesn't return ISeqInStream::Read() errors. | ||
| 2329 | ISeqInStream::Read() result is set to p->readRes. | ||
| 2330 | also it can set stat->CombinedRes_Type to SZ_ERROR_WRITE or SZ_ERROR_PROGRESS. | ||
| 2331 | */ | ||
| 2332 | |||
| 2333 | static SRes XzDecMt_Decode_ST(CXzDecMt *p | ||
| 2334 | #ifndef _7ZIP_ST | ||
| 2335 | , BoolInt tMode | ||
| 2336 | #endif | ||
| 2337 | , CXzStatInfo *stat) | ||
| 2338 | { | ||
| 2339 | size_t outPos; | ||
| 2340 | size_t inPos, inLim; | ||
| 2341 | const Byte *inData; | ||
| 2342 | UInt64 inPrev, outPrev; | ||
| 2343 | |||
| 2344 | CXzUnpacker *dec; | ||
| 2345 | |||
| 2346 | #ifndef _7ZIP_ST | ||
| 2347 | if (tMode) | ||
| 2348 | { | ||
| 2349 | XzDecMt_FreeOutBufs(p); | ||
| 2350 | tMode = MtDec_PrepareRead(&p->mtc); | ||
| 2351 | } | ||
| 2352 | #endif | ||
| 2353 | |||
| 2354 | if (!p->outBuf || p->outBufSize != p->props.outStep_ST) | ||
| 2355 | { | ||
| 2356 | ISzAlloc_Free(p->allocMid, p->outBuf); | ||
| 2357 | p->outBufSize = 0; | ||
| 2358 | p->outBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.outStep_ST); | ||
| 2359 | if (!p->outBuf) | ||
| 2360 | return SZ_ERROR_MEM; | ||
| 2361 | p->outBufSize = p->props.outStep_ST; | ||
| 2362 | } | ||
| 2363 | |||
| 2364 | if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) | ||
| 2365 | { | ||
| 2366 | ISzAlloc_Free(p->allocMid, p->inBuf); | ||
| 2367 | p->inBufSize = 0; | ||
| 2368 | p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); | ||
| 2369 | if (!p->inBuf) | ||
| 2370 | return SZ_ERROR_MEM; | ||
| 2371 | p->inBufSize = p->props.inBufSize_ST; | ||
| 2372 | } | ||
| 2373 | |||
| 2374 | dec = &p->dec; | ||
| 2375 | dec->decodeToStreamSignature = False; | ||
| 2376 | // dec->decodeOnlyOneBlock = False; | ||
| 2377 | |||
| 2378 | XzUnpacker_SetOutBuf(dec, NULL, 0); | ||
| 2379 | |||
| 2380 | inPrev = p->inProcessed; | ||
| 2381 | outPrev = p->outProcessed; | ||
| 2382 | |||
| 2383 | inPos = 0; | ||
| 2384 | inLim = 0; | ||
| 2385 | inData = NULL; | ||
| 2386 | outPos = 0; | ||
| 2387 | |||
| 2388 | for (;;) | ||
| 2389 | { | ||
| 2390 | SizeT outSize; | ||
| 2391 | BoolInt finished; | ||
| 2392 | ECoderFinishMode finishMode; | ||
| 2393 | SizeT inProcessed; | ||
| 2394 | ECoderStatus status; | ||
| 2395 | SRes res; | ||
| 2396 | |||
| 2397 | SizeT outProcessed; | ||
| 2398 | |||
| 2399 | |||
| 2400 | |||
| 2401 | if (inPos == inLim) | ||
| 2402 | { | ||
| 2403 | #ifndef _7ZIP_ST | ||
| 2404 | if (tMode) | ||
| 2405 | { | ||
| 2406 | inData = MtDec_Read(&p->mtc, &inLim); | ||
| 2407 | inPos = 0; | ||
| 2408 | if (inData) | ||
| 2409 | continue; | ||
| 2410 | tMode = False; | ||
| 2411 | inLim = 0; | ||
| 2412 | } | ||
| 2413 | #endif | ||
| 2414 | |||
| 2415 | if (!p->readWasFinished) | ||
| 2416 | { | ||
| 2417 | inPos = 0; | ||
| 2418 | inLim = p->inBufSize; | ||
| 2419 | inData = p->inBuf; | ||
| 2420 | p->readRes = ISeqInStream_Read(p->inStream, (void *)p->inBuf, &inLim); | ||
| 2421 | p->readProcessed += inLim; | ||
| 2422 | if (inLim == 0 || p->readRes != SZ_OK) | ||
| 2423 | p->readWasFinished = True; | ||
| 2424 | } | ||
| 2425 | } | ||
| 2426 | |||
| 2427 | outSize = p->props.outStep_ST - outPos; | ||
| 2428 | |||
| 2429 | finishMode = CODER_FINISH_ANY; | ||
| 2430 | if (p->outSize_Defined) | ||
| 2431 | { | ||
| 2432 | const UInt64 rem = p->outSize - p->outProcessed; | ||
| 2433 | if (outSize >= rem) | ||
| 2434 | { | ||
| 2435 | outSize = (SizeT)rem; | ||
| 2436 | if (p->finishMode) | ||
| 2437 | finishMode = CODER_FINISH_END; | ||
| 2438 | } | ||
| 2439 | } | ||
| 2440 | |||
| 2441 | inProcessed = inLim - inPos; | ||
| 2442 | outProcessed = outSize; | ||
| 2443 | |||
| 2444 | res = XzUnpacker_Code(dec, p->outBuf + outPos, &outProcessed, | ||
| 2445 | inData + inPos, &inProcessed, | ||
| 2446 | (inPos == inLim), // srcFinished | ||
| 2447 | finishMode, &status); | ||
| 2448 | |||
| 2449 | p->codeRes = res; | ||
| 2450 | p->status = status; | ||
| 2451 | |||
| 2452 | inPos += inProcessed; | ||
| 2453 | outPos += outProcessed; | ||
| 2454 | p->inProcessed += inProcessed; | ||
| 2455 | p->outProcessed += outProcessed; | ||
| 2456 | |||
| 2457 | finished = ((inProcessed == 0 && outProcessed == 0) || res != SZ_OK); | ||
| 2458 | |||
| 2459 | if (finished || outProcessed >= outSize) | ||
| 2460 | if (outPos != 0) | ||
| 2461 | { | ||
| 2462 | const size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos); | ||
| 2463 | // p->outProcessed += written; // 21.01: BUG fixed | ||
| 2464 | if (written != outPos) | ||
| 2465 | { | ||
| 2466 | stat->CombinedRes_Type = SZ_ERROR_WRITE; | ||
| 2467 | return SZ_ERROR_WRITE; | ||
| 2468 | } | ||
| 2469 | outPos = 0; | ||
| 2470 | } | ||
| 2471 | |||
| 2472 | if (p->progress && res == SZ_OK) | ||
| 2473 | { | ||
| 2474 | if (p->inProcessed - inPrev >= (1 << 22) || | ||
| 2475 | p->outProcessed - outPrev >= (1 << 22)) | ||
| 2476 | { | ||
| 2477 | res = ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed); | ||
| 2478 | if (res != SZ_OK) | ||
| 2479 | { | ||
| 2480 | stat->CombinedRes_Type = SZ_ERROR_PROGRESS; | ||
| 2481 | stat->ProgressRes = res; | ||
| 2482 | return res; | ||
| 2483 | } | ||
| 2484 | inPrev = p->inProcessed; | ||
| 2485 | outPrev = p->outProcessed; | ||
| 2486 | } | ||
| 2487 | } | ||
| 2488 | |||
| 2489 | if (finished) | ||
| 2490 | { | ||
| 2491 | // p->codeRes is preliminary error from XzUnpacker_Code. | ||
| 2492 | // and it can be corrected later as final result | ||
| 2493 | // so we return SZ_OK here instead of (res); | ||
| 2494 | return SZ_OK; | ||
| 2495 | // return res; | ||
| 2496 | } | ||
| 2497 | } | ||
| 2498 | } | ||
| 2499 | |||
| 2500 | |||
| 2501 | |||
| 2502 | /* | ||
| 2503 | XzStatInfo_SetStat() transforms | ||
| 2504 | CXzUnpacker return code and status to combined CXzStatInfo results. | ||
| 2505 | it can convert SZ_OK to SZ_ERROR_INPUT_EOF | ||
| 2506 | it can convert SZ_ERROR_NO_ARCHIVE to SZ_OK and (DataAfterEnd = 1) | ||
| 2507 | */ | ||
| 2508 | |||
| 2509 | static void XzStatInfo_SetStat(const CXzUnpacker *dec, | ||
| 2510 | int finishMode, | ||
| 2511 | // UInt64 readProcessed, | ||
| 2512 | UInt64 inProcessed, | ||
| 2513 | SRes res, // it's result from CXzUnpacker unpacker | ||
| 2514 | ECoderStatus status, | ||
| 2515 | BoolInt decodingTruncated, | ||
| 2516 | CXzStatInfo *stat) | ||
| 2517 | { | ||
| 2518 | UInt64 extraSize; | ||
| 2519 | |||
| 2520 | stat->DecodingTruncated = (Byte)(decodingTruncated ? 1 : 0); | ||
| 2521 | stat->InSize = inProcessed; | ||
| 2522 | stat->NumStreams = dec->numStartedStreams; | ||
| 2523 | stat->NumBlocks = dec->numTotalBlocks; | ||
| 2524 | |||
| 2525 | stat->UnpackSize_Defined = True; | ||
| 2526 | stat->NumStreams_Defined = True; | ||
| 2527 | stat->NumBlocks_Defined = True; | ||
| 2528 | |||
| 2529 | extraSize = XzUnpacker_GetExtraSize(dec); | ||
| 2530 | |||
| 2531 | if (res == SZ_OK) | ||
| 2532 | { | ||
| 2533 | if (status == CODER_STATUS_NEEDS_MORE_INPUT) | ||
| 2534 | { | ||
| 2535 | // CODER_STATUS_NEEDS_MORE_INPUT is expected status for correct xz streams | ||
| 2536 | // any extra data is part of correct data | ||
| 2537 | extraSize = 0; | ||
| 2538 | // if xz stream was not finished, then we need more data | ||
| 2539 | if (!XzUnpacker_IsStreamWasFinished(dec)) | ||
| 2540 | res = SZ_ERROR_INPUT_EOF; | ||
| 2541 | } | ||
| 2542 | else | ||
| 2543 | { | ||
| 2544 | // CODER_STATUS_FINISHED_WITH_MARK is not possible for multi stream xz decoding | ||
| 2545 | // so he we have (status == CODER_STATUS_NOT_FINISHED) | ||
| 2546 | // if (status != CODER_STATUS_FINISHED_WITH_MARK) | ||
| 2547 | if (!decodingTruncated || finishMode) | ||
| 2548 | res = SZ_ERROR_DATA; | ||
| 2549 | } | ||
| 2550 | } | ||
| 2551 | else if (res == SZ_ERROR_NO_ARCHIVE) | ||
| 2552 | { | ||
| 2553 | /* | ||
| 2554 | SZ_ERROR_NO_ARCHIVE is possible for 2 states: | ||
| 2555 | XZ_STATE_STREAM_HEADER - if bad signature or bad CRC | ||
| 2556 | XZ_STATE_STREAM_PADDING - if non-zero padding data | ||
| 2557 | extraSize and inProcessed don't include "bad" byte | ||
| 2558 | */ | ||
| 2559 | // if (inProcessed == extraSize), there was no any good xz stream header, and we keep error | ||
| 2560 | if (inProcessed != extraSize) // if there were good xz streams before error | ||
| 2561 | { | ||
| 2562 | // if (extraSize != 0 || readProcessed != inProcessed) | ||
| 2563 | { | ||
| 2564 | // he we suppose that all xz streams were finsihed OK, and we have | ||
| 2565 | // some extra data after all streams | ||
| 2566 | stat->DataAfterEnd = True; | ||
| 2567 | res = SZ_OK; | ||
| 2568 | } | ||
| 2569 | } | ||
| 2570 | } | ||
| 2571 | |||
| 2572 | if (stat->DecodeRes == SZ_OK) | ||
| 2573 | stat->DecodeRes = res; | ||
| 2574 | |||
| 2575 | stat->InSize -= extraSize; | ||
| 2576 | } | ||
| 2577 | |||
| 2578 | |||
| 2579 | |||
| 2580 | SRes XzDecMt_Decode(CXzDecMtHandle pp, | ||
| 2581 | const CXzDecMtProps *props, | ||
| 2582 | const UInt64 *outDataSize, int finishMode, | ||
| 2583 | ISeqOutStream *outStream, | ||
| 2584 | // Byte *outBuf, size_t *outBufSize, | ||
| 2585 | ISeqInStream *inStream, | ||
| 2586 | // const Byte *inData, size_t inDataSize, | ||
| 2587 | CXzStatInfo *stat, | ||
| 2588 | int *isMT, | ||
| 2589 | ICompressProgress *progress) | ||
| 2590 | { | ||
| 2591 | CXzDecMt *p = (CXzDecMt *)pp; | ||
| 2592 | #ifndef _7ZIP_ST | ||
| 2593 | BoolInt tMode; | ||
| 2594 | #endif | ||
| 2595 | |||
| 2596 | XzStatInfo_Clear(stat); | ||
| 2597 | |||
| 2598 | p->props = *props; | ||
| 2599 | |||
| 2600 | p->inStream = inStream; | ||
| 2601 | p->outStream = outStream; | ||
| 2602 | p->progress = progress; | ||
| 2603 | // p->stat = stat; | ||
| 2604 | |||
| 2605 | p->outSize = 0; | ||
| 2606 | p->outSize_Defined = False; | ||
| 2607 | if (outDataSize) | ||
| 2608 | { | ||
| 2609 | p->outSize_Defined = True; | ||
| 2610 | p->outSize = *outDataSize; | ||
| 2611 | } | ||
| 2612 | |||
| 2613 | p->finishMode = finishMode; | ||
| 2614 | |||
| 2615 | // p->outSize = 457; p->outSize_Defined = True; p->finishMode = False; // for test | ||
| 2616 | |||
| 2617 | p->writeRes = SZ_OK; | ||
| 2618 | p->outProcessed = 0; | ||
| 2619 | p->inProcessed = 0; | ||
| 2620 | p->readProcessed = 0; | ||
| 2621 | p->readWasFinished = False; | ||
| 2622 | p->readRes = SZ_OK; | ||
| 2623 | |||
| 2624 | p->codeRes = SZ_OK; | ||
| 2625 | p->status = CODER_STATUS_NOT_SPECIFIED; | ||
| 2626 | |||
| 2627 | XzUnpacker_Init(&p->dec); | ||
| 2628 | |||
| 2629 | *isMT = False; | ||
| 2630 | |||
| 2631 | /* | ||
| 2632 | p->outBuf = NULL; | ||
| 2633 | p->outBufSize = 0; | ||
| 2634 | if (!outStream) | ||
| 2635 | { | ||
| 2636 | p->outBuf = outBuf; | ||
| 2637 | p->outBufSize = *outBufSize; | ||
| 2638 | *outBufSize = 0; | ||
| 2639 | } | ||
| 2640 | */ | ||
| 2641 | |||
| 2642 | |||
| 2643 | #ifndef _7ZIP_ST | ||
| 2644 | |||
| 2645 | p->isBlockHeaderState_Parse = False; | ||
| 2646 | p->isBlockHeaderState_Write = False; | ||
| 2647 | // p->numBadBlocks = 0; | ||
| 2648 | p->mainErrorCode = SZ_OK; | ||
| 2649 | p->mainDecoderWasCalled = False; | ||
| 2650 | |||
| 2651 | tMode = False; | ||
| 2652 | |||
| 2653 | if (p->props.numThreads > 1) | ||
| 2654 | { | ||
| 2655 | IMtDecCallback2 vt; | ||
| 2656 | BoolInt needContinue; | ||
| 2657 | SRes res; | ||
| 2658 | // we just free ST buffers here | ||
| 2659 | // but we still keep state variables, that was set in XzUnpacker_Init() | ||
| 2660 | XzDecMt_FreeSt(p); | ||
| 2661 | |||
| 2662 | p->outProcessed_Parse = 0; | ||
| 2663 | p->parsing_Truncated = False; | ||
| 2664 | |||
| 2665 | p->numStreams = 0; | ||
| 2666 | p->numTotalBlocks = 0; | ||
| 2667 | p->numBlocks = 0; | ||
| 2668 | p->finishedDecoderIndex = -1; | ||
| 2669 | |||
| 2670 | if (!p->mtc_WasConstructed) | ||
| 2671 | { | ||
| 2672 | p->mtc_WasConstructed = True; | ||
| 2673 | MtDec_Construct(&p->mtc); | ||
| 2674 | } | ||
| 2675 | |||
| 2676 | p->mtc.mtCallback = &vt; | ||
| 2677 | p->mtc.mtCallbackObject = p; | ||
| 2678 | |||
| 2679 | p->mtc.progress = progress; | ||
| 2680 | p->mtc.inStream = inStream; | ||
| 2681 | p->mtc.alloc = &p->alignOffsetAlloc.vt; | ||
| 2682 | // p->mtc.inData = inData; | ||
| 2683 | // p->mtc.inDataSize = inDataSize; | ||
| 2684 | p->mtc.inBufSize = p->props.inBufSize_MT; | ||
| 2685 | // p->mtc.inBlockMax = p->props.inBlockMax; | ||
| 2686 | p->mtc.numThreadsMax = p->props.numThreads; | ||
| 2687 | |||
| 2688 | *isMT = True; | ||
| 2689 | |||
| 2690 | vt.Parse = XzDecMt_Callback_Parse; | ||
| 2691 | vt.PreCode = XzDecMt_Callback_PreCode; | ||
| 2692 | vt.Code = XzDecMt_Callback_Code; | ||
| 2693 | vt.Write = XzDecMt_Callback_Write; | ||
| 2694 | |||
| 2695 | |||
| 2696 | res = MtDec_Code(&p->mtc); | ||
| 2697 | |||
| 2698 | |||
| 2699 | stat->InSize = p->mtc.inProcessed; | ||
| 2700 | |||
| 2701 | p->inProcessed = p->mtc.inProcessed; | ||
| 2702 | p->readRes = p->mtc.readRes; | ||
| 2703 | p->readWasFinished = p->mtc.readWasFinished; | ||
| 2704 | p->readProcessed = p->mtc.readProcessed; | ||
| 2705 | |||
| 2706 | tMode = True; | ||
| 2707 | needContinue = False; | ||
| 2708 | |||
| 2709 | if (res == SZ_OK) | ||
| 2710 | { | ||
| 2711 | if (p->mtc.mtProgress.res != SZ_OK) | ||
| 2712 | { | ||
| 2713 | res = p->mtc.mtProgress.res; | ||
| 2714 | stat->ProgressRes = res; | ||
| 2715 | stat->CombinedRes_Type = SZ_ERROR_PROGRESS; | ||
| 2716 | } | ||
| 2717 | else | ||
| 2718 | needContinue = p->mtc.needContinue; | ||
| 2719 | } | ||
| 2720 | |||
| 2721 | if (!needContinue) | ||
| 2722 | { | ||
| 2723 | { | ||
| 2724 | SRes codeRes; | ||
| 2725 | BoolInt truncated = False; | ||
| 2726 | ECoderStatus status; | ||
| 2727 | const CXzUnpacker *dec; | ||
| 2728 | |||
| 2729 | stat->OutSize = p->outProcessed; | ||
| 2730 | |||
| 2731 | if (p->finishedDecoderIndex >= 0) | ||
| 2732 | { | ||
| 2733 | const CXzDecMtThread *coder = &p->coders[(unsigned)p->finishedDecoderIndex]; | ||
| 2734 | codeRes = coder->codeRes; | ||
| 2735 | dec = &coder->dec; | ||
| 2736 | status = coder->status; | ||
| 2737 | } | ||
| 2738 | else if (p->mainDecoderWasCalled) | ||
| 2739 | { | ||
| 2740 | codeRes = p->codeRes; | ||
| 2741 | dec = &p->dec; | ||
| 2742 | status = p->status; | ||
| 2743 | truncated = p->parsing_Truncated; | ||
| 2744 | } | ||
| 2745 | else | ||
| 2746 | return SZ_ERROR_FAIL; | ||
| 2747 | |||
| 2748 | if (p->mainErrorCode != SZ_OK) | ||
| 2749 | stat->DecodeRes = p->mainErrorCode; | ||
| 2750 | |||
| 2751 | XzStatInfo_SetStat(dec, p->finishMode, | ||
| 2752 | // p->mtc.readProcessed, | ||
| 2753 | p->mtc.inProcessed, | ||
| 2754 | codeRes, status, | ||
| 2755 | truncated, | ||
| 2756 | stat); | ||
| 2757 | } | ||
| 2758 | |||
| 2759 | if (res == SZ_OK) | ||
| 2760 | { | ||
| 2761 | stat->ReadRes = p->mtc.readRes; | ||
| 2762 | |||
| 2763 | if (p->writeRes != SZ_OK) | ||
| 2764 | { | ||
| 2765 | res = p->writeRes; | ||
| 2766 | stat->CombinedRes_Type = SZ_ERROR_WRITE; | ||
| 2767 | } | ||
| 2768 | else if (p->mtc.readRes != SZ_OK | ||
| 2769 | // && p->mtc.inProcessed == p->mtc.readProcessed | ||
| 2770 | && stat->DecodeRes == SZ_ERROR_INPUT_EOF) | ||
| 2771 | { | ||
| 2772 | res = p->mtc.readRes; | ||
| 2773 | stat->CombinedRes_Type = SZ_ERROR_READ; | ||
| 2774 | } | ||
| 2775 | else if (stat->DecodeRes != SZ_OK) | ||
| 2776 | res = stat->DecodeRes; | ||
| 2777 | } | ||
| 2778 | |||
| 2779 | stat->CombinedRes = res; | ||
| 2780 | if (stat->CombinedRes_Type == SZ_OK) | ||
| 2781 | stat->CombinedRes_Type = res; | ||
| 2782 | return res; | ||
| 2783 | } | ||
| 2784 | |||
| 2785 | PRF_STR("----- decoding ST -----"); | ||
| 2786 | } | ||
| 2787 | |||
| 2788 | #endif | ||
| 2789 | |||
| 2790 | |||
| 2791 | *isMT = False; | ||
| 2792 | |||
| 2793 | { | ||
| 2794 | SRes res = XzDecMt_Decode_ST(p | ||
| 2795 | #ifndef _7ZIP_ST | ||
| 2796 | , tMode | ||
| 2797 | #endif | ||
| 2798 | , stat | ||
| 2799 | ); | ||
| 2800 | |||
| 2801 | #ifndef _7ZIP_ST | ||
| 2802 | // we must set error code from MT decoding at first | ||
| 2803 | if (p->mainErrorCode != SZ_OK) | ||
| 2804 | stat->DecodeRes = p->mainErrorCode; | ||
| 2805 | #endif | ||
| 2806 | |||
| 2807 | XzStatInfo_SetStat(&p->dec, | ||
| 2808 | p->finishMode, | ||
| 2809 | // p->readProcessed, | ||
| 2810 | p->inProcessed, | ||
| 2811 | p->codeRes, p->status, | ||
| 2812 | False, // truncated | ||
| 2813 | stat); | ||
| 2814 | |||
| 2815 | stat->ReadRes = p->readRes; | ||
| 2816 | |||
| 2817 | if (res == SZ_OK) | ||
| 2818 | { | ||
| 2819 | if (p->readRes != SZ_OK | ||
| 2820 | // && p->inProcessed == p->readProcessed | ||
| 2821 | && stat->DecodeRes == SZ_ERROR_INPUT_EOF) | ||
| 2822 | { | ||
| 2823 | // we set read error as combined error, only if that error was the reason | ||
| 2824 | // of decoding problem | ||
| 2825 | res = p->readRes; | ||
| 2826 | stat->CombinedRes_Type = SZ_ERROR_READ; | ||
| 2827 | } | ||
| 2828 | else if (stat->DecodeRes != SZ_OK) | ||
| 2829 | res = stat->DecodeRes; | ||
| 2830 | } | ||
| 2831 | |||
| 2832 | stat->CombinedRes = res; | ||
| 2833 | if (stat->CombinedRes_Type == SZ_OK) | ||
| 2834 | stat->CombinedRes_Type = res; | ||
| 2835 | return res; | ||
| 2836 | } | ||
| 2837 | } | ||
diff --git a/C/XzEnc.c b/C/XzEnc.c new file mode 100644 index 0000000..be174cc --- /dev/null +++ b/C/XzEnc.c | |||
| @@ -0,0 +1,1330 @@ | |||
| 1 | /* XzEnc.c -- Xz Encode | ||
| 2 | 2021-04-01 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <stdlib.h> | ||
| 7 | #include <string.h> | ||
| 8 | |||
| 9 | #include "7zCrc.h" | ||
| 10 | #include "Bra.h" | ||
| 11 | #include "CpuArch.h" | ||
| 12 | |||
| 13 | #ifdef USE_SUBBLOCK | ||
| 14 | #include "Bcj3Enc.c" | ||
| 15 | #include "SbFind.c" | ||
| 16 | #include "SbEnc.c" | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #include "XzEnc.h" | ||
| 20 | |||
| 21 | // #define _7ZIP_ST | ||
| 22 | |||
| 23 | #ifndef _7ZIP_ST | ||
| 24 | #include "MtCoder.h" | ||
| 25 | #else | ||
| 26 | #define MTCODER__THREADS_MAX 1 | ||
| 27 | #define MTCODER__BLOCKS_MAX 1 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3) | ||
| 31 | |||
| 32 | /* max pack size for LZMA2 block + check-64bytrs: */ | ||
| 33 | #define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64) | ||
| 34 | |||
| 35 | #define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize)) | ||
| 36 | |||
| 37 | |||
| 38 | #define XzBlock_ClearFlags(p) (p)->flags = 0; | ||
| 39 | #define XzBlock_SetNumFilters(p, n) (p)->flags = (Byte)((p)->flags | ((n) - 1)); | ||
| 40 | #define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE; | ||
| 41 | #define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE; | ||
| 42 | |||
| 43 | |||
| 44 | static SRes WriteBytes(ISeqOutStream *s, const void *buf, size_t size) | ||
| 45 | { | ||
| 46 | return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; | ||
| 47 | } | ||
| 48 | |||
| 49 | static SRes WriteBytesUpdateCrc(ISeqOutStream *s, const void *buf, size_t size, UInt32 *crc) | ||
| 50 | { | ||
| 51 | *crc = CrcUpdate(*crc, buf, size); | ||
| 52 | return WriteBytes(s, buf, size); | ||
| 53 | } | ||
| 54 | |||
| 55 | |||
| 56 | static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s) | ||
| 57 | { | ||
| 58 | UInt32 crc; | ||
| 59 | Byte header[XZ_STREAM_HEADER_SIZE]; | ||
| 60 | memcpy(header, XZ_SIG, XZ_SIG_SIZE); | ||
| 61 | header[XZ_SIG_SIZE] = (Byte)(f >> 8); | ||
| 62 | header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); | ||
| 63 | crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); | ||
| 64 | SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc); | ||
| 65 | return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); | ||
| 66 | } | ||
| 67 | |||
| 68 | |||
| 69 | static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s) | ||
| 70 | { | ||
| 71 | Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; | ||
| 72 | |||
| 73 | unsigned pos = 1; | ||
| 74 | unsigned numFilters, i; | ||
| 75 | header[pos++] = p->flags; | ||
| 76 | |||
| 77 | if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); | ||
| 78 | if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); | ||
| 79 | numFilters = XzBlock_GetNumFilters(p); | ||
| 80 | |||
| 81 | for (i = 0; i < numFilters; i++) | ||
| 82 | { | ||
| 83 | const CXzFilter *f = &p->filters[i]; | ||
| 84 | pos += Xz_WriteVarInt(header + pos, f->id); | ||
| 85 | pos += Xz_WriteVarInt(header + pos, f->propsSize); | ||
| 86 | memcpy(header + pos, f->props, f->propsSize); | ||
| 87 | pos += f->propsSize; | ||
| 88 | } | ||
| 89 | |||
| 90 | while ((pos & 3) != 0) | ||
| 91 | header[pos++] = 0; | ||
| 92 | |||
| 93 | header[0] = (Byte)(pos >> 2); | ||
| 94 | SetUi32(header + pos, CrcCalc(header, pos)); | ||
| 95 | return WriteBytes(s, header, pos + 4); | ||
| 96 | } | ||
| 97 | |||
| 98 | |||
| 99 | |||
| 100 | |||
| 101 | typedef struct | ||
| 102 | { | ||
| 103 | size_t numBlocks; | ||
| 104 | size_t size; | ||
| 105 | size_t allocated; | ||
| 106 | Byte *blocks; | ||
| 107 | } CXzEncIndex; | ||
| 108 | |||
| 109 | |||
| 110 | static void XzEncIndex_Construct(CXzEncIndex *p) | ||
| 111 | { | ||
| 112 | p->numBlocks = 0; | ||
| 113 | p->size = 0; | ||
| 114 | p->allocated = 0; | ||
| 115 | p->blocks = NULL; | ||
| 116 | } | ||
| 117 | |||
| 118 | static void XzEncIndex_Init(CXzEncIndex *p) | ||
| 119 | { | ||
| 120 | p->numBlocks = 0; | ||
| 121 | p->size = 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc) | ||
| 125 | { | ||
| 126 | if (p->blocks) | ||
| 127 | { | ||
| 128 | ISzAlloc_Free(alloc, p->blocks); | ||
| 129 | p->blocks = NULL; | ||
| 130 | } | ||
| 131 | p->numBlocks = 0; | ||
| 132 | p->size = 0; | ||
| 133 | p->allocated = 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc) | ||
| 138 | { | ||
| 139 | Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize); | ||
| 140 | if (!blocks) | ||
| 141 | return SZ_ERROR_MEM; | ||
| 142 | if (p->size != 0) | ||
| 143 | memcpy(blocks, p->blocks, p->size); | ||
| 144 | if (p->blocks) | ||
| 145 | ISzAlloc_Free(alloc, p->blocks); | ||
| 146 | p->blocks = blocks; | ||
| 147 | p->allocated = newSize; | ||
| 148 | return SZ_OK; | ||
| 149 | } | ||
| 150 | |||
| 151 | |||
| 152 | static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) | ||
| 153 | { | ||
| 154 | UInt64 pos; | ||
| 155 | { | ||
| 156 | Byte buf[32]; | ||
| 157 | unsigned pos2 = Xz_WriteVarInt(buf, totalSize); | ||
| 158 | pos2 += Xz_WriteVarInt(buf + pos2, unpackSize); | ||
| 159 | pos = numBlocks * pos2; | ||
| 160 | } | ||
| 161 | |||
| 162 | if (pos <= p->allocated - p->size) | ||
| 163 | return SZ_OK; | ||
| 164 | { | ||
| 165 | UInt64 newSize64 = p->size + pos; | ||
| 166 | size_t newSize = (size_t)newSize64; | ||
| 167 | if (newSize != newSize64) | ||
| 168 | return SZ_ERROR_MEM; | ||
| 169 | return XzEncIndex_ReAlloc(p, newSize, alloc); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | |||
| 174 | static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) | ||
| 175 | { | ||
| 176 | Byte buf[32]; | ||
| 177 | unsigned pos = Xz_WriteVarInt(buf, totalSize); | ||
| 178 | pos += Xz_WriteVarInt(buf + pos, unpackSize); | ||
| 179 | |||
| 180 | if (pos > p->allocated - p->size) | ||
| 181 | { | ||
| 182 | size_t newSize = p->allocated * 2 + 16 * 2; | ||
| 183 | if (newSize < p->size + pos) | ||
| 184 | return SZ_ERROR_MEM; | ||
| 185 | RINOK(XzEncIndex_ReAlloc(p, newSize, alloc)); | ||
| 186 | } | ||
| 187 | memcpy(p->blocks + p->size, buf, pos); | ||
| 188 | p->size += pos; | ||
| 189 | p->numBlocks++; | ||
| 190 | return SZ_OK; | ||
| 191 | } | ||
| 192 | |||
| 193 | |||
| 194 | static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStream *s) | ||
| 195 | { | ||
| 196 | Byte buf[32]; | ||
| 197 | UInt64 globalPos; | ||
| 198 | UInt32 crc = CRC_INIT_VAL; | ||
| 199 | unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); | ||
| 200 | |||
| 201 | globalPos = pos; | ||
| 202 | buf[0] = 0; | ||
| 203 | RINOK(WriteBytesUpdateCrc(s, buf, pos, &crc)); | ||
| 204 | RINOK(WriteBytesUpdateCrc(s, p->blocks, p->size, &crc)); | ||
| 205 | globalPos += p->size; | ||
| 206 | |||
| 207 | pos = XZ_GET_PAD_SIZE(globalPos); | ||
| 208 | buf[1] = 0; | ||
| 209 | buf[2] = 0; | ||
| 210 | buf[3] = 0; | ||
| 211 | globalPos += pos; | ||
| 212 | |||
| 213 | crc = CrcUpdate(crc, buf + 4 - pos, pos); | ||
| 214 | SetUi32(buf + 4, CRC_GET_DIGEST(crc)); | ||
| 215 | |||
| 216 | SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2)); | ||
| 217 | buf[8 + 8] = (Byte)(flags >> 8); | ||
| 218 | buf[8 + 9] = (Byte)(flags & 0xFF); | ||
| 219 | SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6)); | ||
| 220 | buf[8 + 10] = XZ_FOOTER_SIG_0; | ||
| 221 | buf[8 + 11] = XZ_FOOTER_SIG_1; | ||
| 222 | |||
| 223 | return WriteBytes(s, buf + 4 - pos, pos + 4 + 12); | ||
| 224 | } | ||
| 225 | |||
| 226 | |||
| 227 | |||
| 228 | /* ---------- CSeqCheckInStream ---------- */ | ||
| 229 | |||
| 230 | typedef struct | ||
| 231 | { | ||
| 232 | ISeqInStream vt; | ||
| 233 | ISeqInStream *realStream; | ||
| 234 | const Byte *data; | ||
| 235 | UInt64 limit; | ||
| 236 | UInt64 processed; | ||
| 237 | int realStreamFinished; | ||
| 238 | CXzCheck check; | ||
| 239 | } CSeqCheckInStream; | ||
| 240 | |||
| 241 | static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode) | ||
| 242 | { | ||
| 243 | p->limit = (UInt64)(Int64)-1; | ||
| 244 | p->processed = 0; | ||
| 245 | p->realStreamFinished = 0; | ||
| 246 | XzCheck_Init(&p->check, checkMode); | ||
| 247 | } | ||
| 248 | |||
| 249 | static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) | ||
| 250 | { | ||
| 251 | XzCheck_Final(&p->check, digest); | ||
| 252 | } | ||
| 253 | |||
| 254 | static SRes SeqCheckInStream_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
| 255 | { | ||
| 256 | CSeqCheckInStream *p = CONTAINER_FROM_VTBL(pp, CSeqCheckInStream, vt); | ||
| 257 | size_t size2 = *size; | ||
| 258 | SRes res = SZ_OK; | ||
| 259 | |||
| 260 | if (p->limit != (UInt64)(Int64)-1) | ||
| 261 | { | ||
| 262 | UInt64 rem = p->limit - p->processed; | ||
| 263 | if (size2 > rem) | ||
| 264 | size2 = (size_t)rem; | ||
| 265 | } | ||
| 266 | if (size2 != 0) | ||
| 267 | { | ||
| 268 | if (p->realStream) | ||
| 269 | { | ||
| 270 | res = ISeqInStream_Read(p->realStream, data, &size2); | ||
| 271 | p->realStreamFinished = (size2 == 0) ? 1 : 0; | ||
| 272 | } | ||
| 273 | else | ||
| 274 | memcpy(data, p->data + (size_t)p->processed, size2); | ||
| 275 | XzCheck_Update(&p->check, data, size2); | ||
| 276 | p->processed += size2; | ||
| 277 | } | ||
| 278 | *size = size2; | ||
| 279 | return res; | ||
| 280 | } | ||
| 281 | |||
| 282 | |||
| 283 | /* ---------- CSeqSizeOutStream ---------- */ | ||
| 284 | |||
| 285 | typedef struct | ||
| 286 | { | ||
| 287 | ISeqOutStream vt; | ||
| 288 | ISeqOutStream *realStream; | ||
| 289 | Byte *outBuf; | ||
| 290 | size_t outBufLimit; | ||
| 291 | UInt64 processed; | ||
| 292 | } CSeqSizeOutStream; | ||
| 293 | |||
| 294 | static size_t SeqSizeOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) | ||
| 295 | { | ||
| 296 | CSeqSizeOutStream *p = CONTAINER_FROM_VTBL(pp, CSeqSizeOutStream, vt); | ||
| 297 | if (p->realStream) | ||
| 298 | size = ISeqOutStream_Write(p->realStream, data, size); | ||
| 299 | else | ||
| 300 | { | ||
| 301 | if (size > p->outBufLimit - (size_t)p->processed) | ||
| 302 | return 0; | ||
| 303 | memcpy(p->outBuf + (size_t)p->processed, data, size); | ||
| 304 | } | ||
| 305 | p->processed += size; | ||
| 306 | return size; | ||
| 307 | } | ||
| 308 | |||
| 309 | |||
| 310 | /* ---------- CSeqInFilter ---------- */ | ||
| 311 | |||
| 312 | #define FILTER_BUF_SIZE (1 << 20) | ||
| 313 | |||
| 314 | typedef struct | ||
| 315 | { | ||
| 316 | ISeqInStream p; | ||
| 317 | ISeqInStream *realStream; | ||
| 318 | IStateCoder StateCoder; | ||
| 319 | Byte *buf; | ||
| 320 | size_t curPos; | ||
| 321 | size_t endPos; | ||
| 322 | int srcWasFinished; | ||
| 323 | } CSeqInFilter; | ||
| 324 | |||
| 325 | |||
| 326 | SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc); | ||
| 327 | |||
| 328 | static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc) | ||
| 329 | { | ||
| 330 | if (!p->buf) | ||
| 331 | { | ||
| 332 | p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE); | ||
| 333 | if (!p->buf) | ||
| 334 | return SZ_ERROR_MEM; | ||
| 335 | } | ||
| 336 | p->curPos = p->endPos = 0; | ||
| 337 | p->srcWasFinished = 0; | ||
| 338 | RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, alloc)); | ||
| 339 | RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc)); | ||
| 340 | p->StateCoder.Init(p->StateCoder.p); | ||
| 341 | return SZ_OK; | ||
| 342 | } | ||
| 343 | |||
| 344 | |||
| 345 | static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
| 346 | { | ||
| 347 | CSeqInFilter *p = CONTAINER_FROM_VTBL(pp, CSeqInFilter, p); | ||
| 348 | size_t sizeOriginal = *size; | ||
| 349 | if (sizeOriginal == 0) | ||
| 350 | return SZ_OK; | ||
| 351 | *size = 0; | ||
| 352 | |||
| 353 | for (;;) | ||
| 354 | { | ||
| 355 | if (!p->srcWasFinished && p->curPos == p->endPos) | ||
| 356 | { | ||
| 357 | p->curPos = 0; | ||
| 358 | p->endPos = FILTER_BUF_SIZE; | ||
| 359 | RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos)); | ||
| 360 | if (p->endPos == 0) | ||
| 361 | p->srcWasFinished = 1; | ||
| 362 | } | ||
| 363 | { | ||
| 364 | SizeT srcLen = p->endPos - p->curPos; | ||
| 365 | ECoderStatus status; | ||
| 366 | SRes res; | ||
| 367 | *size = sizeOriginal; | ||
| 368 | res = p->StateCoder.Code2(p->StateCoder.p, | ||
| 369 | (Byte *)data, size, | ||
| 370 | p->buf + p->curPos, &srcLen, | ||
| 371 | p->srcWasFinished, CODER_FINISH_ANY, | ||
| 372 | &status); | ||
| 373 | p->curPos += srcLen; | ||
| 374 | if (*size != 0 || srcLen == 0 || res != SZ_OK) | ||
| 375 | return res; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | static void SeqInFilter_Construct(CSeqInFilter *p) | ||
| 381 | { | ||
| 382 | p->buf = NULL; | ||
| 383 | p->StateCoder.p = NULL; | ||
| 384 | p->p.Read = SeqInFilter_Read; | ||
| 385 | } | ||
| 386 | |||
| 387 | static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) | ||
| 388 | { | ||
| 389 | if (p->StateCoder.p) | ||
| 390 | { | ||
| 391 | p->StateCoder.Free(p->StateCoder.p, alloc); | ||
| 392 | p->StateCoder.p = NULL; | ||
| 393 | } | ||
| 394 | if (p->buf) | ||
| 395 | { | ||
| 396 | ISzAlloc_Free(alloc, p->buf); | ||
| 397 | p->buf = NULL; | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | |||
| 402 | /* ---------- CSbEncInStream ---------- */ | ||
| 403 | |||
| 404 | #ifdef USE_SUBBLOCK | ||
| 405 | |||
| 406 | typedef struct | ||
| 407 | { | ||
| 408 | ISeqInStream vt; | ||
| 409 | ISeqInStream *inStream; | ||
| 410 | CSbEnc enc; | ||
| 411 | } CSbEncInStream; | ||
| 412 | |||
| 413 | static SRes SbEncInStream_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
| 414 | { | ||
| 415 | CSbEncInStream *p = CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt); | ||
| 416 | size_t sizeOriginal = *size; | ||
| 417 | if (sizeOriginal == 0) | ||
| 418 | return SZ_OK; | ||
| 419 | |||
| 420 | for (;;) | ||
| 421 | { | ||
| 422 | if (p->enc.needRead && !p->enc.readWasFinished) | ||
| 423 | { | ||
| 424 | size_t processed = p->enc.needReadSizeMax; | ||
| 425 | RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed)); | ||
| 426 | p->enc.readPos += processed; | ||
| 427 | if (processed == 0) | ||
| 428 | { | ||
| 429 | p->enc.readWasFinished = True; | ||
| 430 | p->enc.isFinalFinished = True; | ||
| 431 | } | ||
| 432 | p->enc.needRead = False; | ||
| 433 | } | ||
| 434 | |||
| 435 | *size = sizeOriginal; | ||
| 436 | RINOK(SbEnc_Read(&p->enc, data, size)); | ||
| 437 | if (*size != 0 || !p->enc.needRead) | ||
| 438 | return SZ_OK; | ||
| 439 | } | ||
| 440 | } | ||
| 441 | |||
| 442 | void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc) | ||
| 443 | { | ||
| 444 | SbEnc_Construct(&p->enc, alloc); | ||
| 445 | p->vt.Read = SbEncInStream_Read; | ||
| 446 | } | ||
| 447 | |||
| 448 | SRes SbEncInStream_Init(CSbEncInStream *p) | ||
| 449 | { | ||
| 450 | return SbEnc_Init(&p->enc); | ||
| 451 | } | ||
| 452 | |||
| 453 | void SbEncInStream_Free(CSbEncInStream *p) | ||
| 454 | { | ||
| 455 | SbEnc_Free(&p->enc); | ||
| 456 | } | ||
| 457 | |||
| 458 | #endif | ||
| 459 | |||
| 460 | |||
| 461 | |||
| 462 | /* ---------- CXzProps ---------- */ | ||
| 463 | |||
| 464 | |||
| 465 | void XzFilterProps_Init(CXzFilterProps *p) | ||
| 466 | { | ||
| 467 | p->id = 0; | ||
| 468 | p->delta = 0; | ||
| 469 | p->ip = 0; | ||
| 470 | p->ipDefined = False; | ||
| 471 | } | ||
| 472 | |||
| 473 | void XzProps_Init(CXzProps *p) | ||
| 474 | { | ||
| 475 | p->checkId = XZ_CHECK_CRC32; | ||
| 476 | p->blockSize = XZ_PROPS__BLOCK_SIZE__AUTO; | ||
| 477 | p->numBlockThreads_Reduced = -1; | ||
| 478 | p->numBlockThreads_Max = -1; | ||
| 479 | p->numTotalThreads = -1; | ||
| 480 | p->reduceSize = (UInt64)(Int64)-1; | ||
| 481 | p->forceWriteSizesInHeader = 0; | ||
| 482 | // p->forceWriteSizesInHeader = 1; | ||
| 483 | |||
| 484 | XzFilterProps_Init(&p->filterProps); | ||
| 485 | Lzma2EncProps_Init(&p->lzma2Props); | ||
| 486 | } | ||
| 487 | |||
| 488 | |||
| 489 | static void XzEncProps_Normalize_Fixed(CXzProps *p) | ||
| 490 | { | ||
| 491 | UInt64 fileSize; | ||
| 492 | int t1, t1n, t2, t2r, t3; | ||
| 493 | { | ||
| 494 | CLzma2EncProps tp = p->lzma2Props; | ||
| 495 | if (tp.numTotalThreads <= 0) | ||
| 496 | tp.numTotalThreads = p->numTotalThreads; | ||
| 497 | Lzma2EncProps_Normalize(&tp); | ||
| 498 | t1n = tp.numTotalThreads; | ||
| 499 | } | ||
| 500 | |||
| 501 | t1 = p->lzma2Props.numTotalThreads; | ||
| 502 | t2 = p->numBlockThreads_Max; | ||
| 503 | t3 = p->numTotalThreads; | ||
| 504 | |||
| 505 | if (t2 > MTCODER__THREADS_MAX) | ||
| 506 | t2 = MTCODER__THREADS_MAX; | ||
| 507 | |||
| 508 | if (t3 <= 0) | ||
| 509 | { | ||
| 510 | if (t2 <= 0) | ||
| 511 | t2 = 1; | ||
| 512 | t3 = t1n * t2; | ||
| 513 | } | ||
| 514 | else if (t2 <= 0) | ||
| 515 | { | ||
| 516 | t2 = t3 / t1n; | ||
| 517 | if (t2 == 0) | ||
| 518 | { | ||
| 519 | t1 = 1; | ||
| 520 | t2 = t3; | ||
| 521 | } | ||
| 522 | if (t2 > MTCODER__THREADS_MAX) | ||
| 523 | t2 = MTCODER__THREADS_MAX; | ||
| 524 | } | ||
| 525 | else if (t1 <= 0) | ||
| 526 | { | ||
| 527 | t1 = t3 / t2; | ||
| 528 | if (t1 == 0) | ||
| 529 | t1 = 1; | ||
| 530 | } | ||
| 531 | else | ||
| 532 | t3 = t1n * t2; | ||
| 533 | |||
| 534 | p->lzma2Props.numTotalThreads = t1; | ||
| 535 | |||
| 536 | t2r = t2; | ||
| 537 | |||
| 538 | fileSize = p->reduceSize; | ||
| 539 | |||
| 540 | if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) | ||
| 541 | p->lzma2Props.lzmaProps.reduceSize = p->blockSize; | ||
| 542 | |||
| 543 | Lzma2EncProps_Normalize(&p->lzma2Props); | ||
| 544 | |||
| 545 | t1 = p->lzma2Props.numTotalThreads; | ||
| 546 | |||
| 547 | { | ||
| 548 | if (t2 > 1 && fileSize != (UInt64)(Int64)-1) | ||
| 549 | { | ||
| 550 | UInt64 numBlocks = fileSize / p->blockSize; | ||
| 551 | if (numBlocks * p->blockSize != fileSize) | ||
| 552 | numBlocks++; | ||
| 553 | if (numBlocks < (unsigned)t2) | ||
| 554 | { | ||
| 555 | t2r = (int)numBlocks; | ||
| 556 | if (t2r == 0) | ||
| 557 | t2r = 1; | ||
| 558 | t3 = t1 * t2r; | ||
| 559 | } | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | p->numBlockThreads_Max = t2; | ||
| 564 | p->numBlockThreads_Reduced = t2r; | ||
| 565 | p->numTotalThreads = t3; | ||
| 566 | } | ||
| 567 | |||
| 568 | |||
| 569 | static void XzProps_Normalize(CXzProps *p) | ||
| 570 | { | ||
| 571 | /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties. | ||
| 572 | Lzma2Enc_SetProps() will normalize lzma2Props later. */ | ||
| 573 | |||
| 574 | if (p->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID) | ||
| 575 | { | ||
| 576 | p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; | ||
| 577 | p->numBlockThreads_Reduced = 1; | ||
| 578 | p->numBlockThreads_Max = 1; | ||
| 579 | if (p->lzma2Props.numTotalThreads <= 0) | ||
| 580 | p->lzma2Props.numTotalThreads = p->numTotalThreads; | ||
| 581 | return; | ||
| 582 | } | ||
| 583 | else | ||
| 584 | { | ||
| 585 | CLzma2EncProps *lzma2 = &p->lzma2Props; | ||
| 586 | if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
| 587 | { | ||
| 588 | // xz-auto | ||
| 589 | p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; | ||
| 590 | |||
| 591 | if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
| 592 | { | ||
| 593 | // if (xz-auto && lzma2-solid) - we use solid for both | ||
| 594 | p->blockSize = XZ_PROPS__BLOCK_SIZE__SOLID; | ||
| 595 | p->numBlockThreads_Reduced = 1; | ||
| 596 | p->numBlockThreads_Max = 1; | ||
| 597 | if (p->lzma2Props.numTotalThreads <= 0) | ||
| 598 | p->lzma2Props.numTotalThreads = p->numTotalThreads; | ||
| 599 | } | ||
| 600 | else | ||
| 601 | { | ||
| 602 | // if (xz-auto && (lzma2-auto || lzma2-fixed_) | ||
| 603 | // we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block | ||
| 604 | CLzma2EncProps tp = p->lzma2Props; | ||
| 605 | if (tp.numTotalThreads <= 0) | ||
| 606 | tp.numTotalThreads = p->numTotalThreads; | ||
| 607 | |||
| 608 | Lzma2EncProps_Normalize(&tp); | ||
| 609 | |||
| 610 | p->blockSize = tp.blockSize; // fixed or solid | ||
| 611 | p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced; | ||
| 612 | p->numBlockThreads_Max = tp.numBlockThreads_Max; | ||
| 613 | if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
| 614 | lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | ||
| 615 | if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
| 616 | lzma2->lzmaProps.reduceSize = tp.blockSize; | ||
| 617 | lzma2->numBlockThreads_Reduced = 1; | ||
| 618 | lzma2->numBlockThreads_Max = 1; | ||
| 619 | return; | ||
| 620 | } | ||
| 621 | } | ||
| 622 | else | ||
| 623 | { | ||
| 624 | // xz-fixed | ||
| 625 | // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize | ||
| 626 | |||
| 627 | p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; | ||
| 628 | { | ||
| 629 | UInt64 r = p->reduceSize; | ||
| 630 | if (r > p->blockSize || r == (UInt64)(Int64)-1) | ||
| 631 | r = p->blockSize; | ||
| 632 | lzma2->lzmaProps.reduceSize = r; | ||
| 633 | } | ||
| 634 | if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
| 635 | lzma2->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; | ||
| 636 | else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
| 637 | lzma2->blockSize = p->blockSize; | ||
| 638 | |||
| 639 | XzEncProps_Normalize_Fixed(p); | ||
| 640 | } | ||
| 641 | } | ||
| 642 | } | ||
| 643 | |||
| 644 | |||
| 645 | /* ---------- CLzma2WithFilters ---------- */ | ||
| 646 | |||
| 647 | typedef struct | ||
| 648 | { | ||
| 649 | CLzma2EncHandle lzma2; | ||
| 650 | CSeqInFilter filter; | ||
| 651 | |||
| 652 | #ifdef USE_SUBBLOCK | ||
| 653 | CSbEncInStream sb; | ||
| 654 | #endif | ||
| 655 | } CLzma2WithFilters; | ||
| 656 | |||
| 657 | |||
| 658 | static void Lzma2WithFilters_Construct(CLzma2WithFilters *p) | ||
| 659 | { | ||
| 660 | p->lzma2 = NULL; | ||
| 661 | SeqInFilter_Construct(&p->filter); | ||
| 662 | |||
| 663 | #ifdef USE_SUBBLOCK | ||
| 664 | SbEncInStream_Construct(&p->sb, alloc); | ||
| 665 | #endif | ||
| 666 | } | ||
| 667 | |||
| 668 | |||
| 669 | static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc) | ||
| 670 | { | ||
| 671 | if (!p->lzma2) | ||
| 672 | { | ||
| 673 | p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc); | ||
| 674 | if (!p->lzma2) | ||
| 675 | return SZ_ERROR_MEM; | ||
| 676 | } | ||
| 677 | return SZ_OK; | ||
| 678 | } | ||
| 679 | |||
| 680 | |||
| 681 | static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc) | ||
| 682 | { | ||
| 683 | #ifdef USE_SUBBLOCK | ||
| 684 | SbEncInStream_Free(&p->sb); | ||
| 685 | #endif | ||
| 686 | |||
| 687 | SeqInFilter_Free(&p->filter, alloc); | ||
| 688 | if (p->lzma2) | ||
| 689 | { | ||
| 690 | Lzma2Enc_Destroy(p->lzma2); | ||
| 691 | p->lzma2 = NULL; | ||
| 692 | } | ||
| 693 | } | ||
| 694 | |||
| 695 | |||
| 696 | typedef struct | ||
| 697 | { | ||
| 698 | UInt64 unpackSize; | ||
| 699 | UInt64 totalSize; | ||
| 700 | size_t headerSize; | ||
| 701 | } CXzEncBlockInfo; | ||
| 702 | |||
| 703 | |||
| 704 | static SRes Xz_CompressBlock( | ||
| 705 | CLzma2WithFilters *lzmaf, | ||
| 706 | |||
| 707 | ISeqOutStream *outStream, | ||
| 708 | Byte *outBufHeader, | ||
| 709 | Byte *outBufData, size_t outBufDataLimit, | ||
| 710 | |||
| 711 | ISeqInStream *inStream, | ||
| 712 | // UInt64 expectedSize, | ||
| 713 | const Byte *inBuf, // used if (!inStream) | ||
| 714 | size_t inBufSize, // used if (!inStream), it's block size, props->blockSize is ignored | ||
| 715 | |||
| 716 | const CXzProps *props, | ||
| 717 | ICompressProgress *progress, | ||
| 718 | int *inStreamFinished, /* only for inStream version */ | ||
| 719 | CXzEncBlockInfo *blockSizes, | ||
| 720 | ISzAllocPtr alloc, | ||
| 721 | ISzAllocPtr allocBig) | ||
| 722 | { | ||
| 723 | CSeqCheckInStream checkInStream; | ||
| 724 | CSeqSizeOutStream seqSizeOutStream; | ||
| 725 | CXzBlock block; | ||
| 726 | unsigned filterIndex = 0; | ||
| 727 | CXzFilter *filter = NULL; | ||
| 728 | const CXzFilterProps *fp = &props->filterProps; | ||
| 729 | if (fp->id == 0) | ||
| 730 | fp = NULL; | ||
| 731 | |||
| 732 | *inStreamFinished = False; | ||
| 733 | |||
| 734 | RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig)); | ||
| 735 | |||
| 736 | RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props)); | ||
| 737 | |||
| 738 | XzBlock_ClearFlags(&block); | ||
| 739 | XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0)); | ||
| 740 | |||
| 741 | if (fp) | ||
| 742 | { | ||
| 743 | filter = &block.filters[filterIndex++]; | ||
| 744 | filter->id = fp->id; | ||
| 745 | filter->propsSize = 0; | ||
| 746 | |||
| 747 | if (fp->id == XZ_ID_Delta) | ||
| 748 | { | ||
| 749 | filter->props[0] = (Byte)(fp->delta - 1); | ||
| 750 | filter->propsSize = 1; | ||
| 751 | } | ||
| 752 | else if (fp->ipDefined) | ||
| 753 | { | ||
| 754 | Byte *ptr = filter->props; | ||
| 755 | SetUi32(ptr, fp->ip); | ||
| 756 | filter->propsSize = 4; | ||
| 757 | } | ||
| 758 | } | ||
| 759 | |||
| 760 | { | ||
| 761 | CXzFilter *f = &block.filters[filterIndex++]; | ||
| 762 | f->id = XZ_ID_LZMA2; | ||
| 763 | f->propsSize = 1; | ||
| 764 | f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); | ||
| 765 | } | ||
| 766 | |||
| 767 | seqSizeOutStream.vt.Write = SeqSizeOutStream_Write; | ||
| 768 | seqSizeOutStream.realStream = outStream; | ||
| 769 | seqSizeOutStream.outBuf = outBufData; | ||
| 770 | seqSizeOutStream.outBufLimit = outBufDataLimit; | ||
| 771 | seqSizeOutStream.processed = 0; | ||
| 772 | |||
| 773 | /* | ||
| 774 | if (expectedSize != (UInt64)(Int64)-1) | ||
| 775 | { | ||
| 776 | block.unpackSize = expectedSize; | ||
| 777 | if (props->blockSize != (UInt64)(Int64)-1) | ||
| 778 | if (expectedSize > props->blockSize) | ||
| 779 | block.unpackSize = props->blockSize; | ||
| 780 | XzBlock_SetHasUnpackSize(&block); | ||
| 781 | } | ||
| 782 | */ | ||
| 783 | |||
| 784 | if (outStream) | ||
| 785 | { | ||
| 786 | RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)); | ||
| 787 | } | ||
| 788 | |||
| 789 | checkInStream.vt.Read = SeqCheckInStream_Read; | ||
| 790 | SeqCheckInStream_Init(&checkInStream, props->checkId); | ||
| 791 | |||
| 792 | checkInStream.realStream = inStream; | ||
| 793 | checkInStream.data = inBuf; | ||
| 794 | checkInStream.limit = props->blockSize; | ||
| 795 | if (!inStream) | ||
| 796 | checkInStream.limit = inBufSize; | ||
| 797 | |||
| 798 | if (fp) | ||
| 799 | { | ||
| 800 | #ifdef USE_SUBBLOCK | ||
| 801 | if (fp->id == XZ_ID_Subblock) | ||
| 802 | { | ||
| 803 | lzmaf->sb.inStream = &checkInStream.vt; | ||
| 804 | RINOK(SbEncInStream_Init(&lzmaf->sb)); | ||
| 805 | } | ||
| 806 | else | ||
| 807 | #endif | ||
| 808 | { | ||
| 809 | lzmaf->filter.realStream = &checkInStream.vt; | ||
| 810 | RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc)); | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 | { | ||
| 815 | SRes res; | ||
| 816 | Byte *outBuf = NULL; | ||
| 817 | size_t outSize = 0; | ||
| 818 | BoolInt useStream = (fp || inStream); | ||
| 819 | // useStream = True; | ||
| 820 | |||
| 821 | if (!useStream) | ||
| 822 | { | ||
| 823 | XzCheck_Update(&checkInStream.check, inBuf, inBufSize); | ||
| 824 | checkInStream.processed = inBufSize; | ||
| 825 | } | ||
| 826 | |||
| 827 | if (!outStream) | ||
| 828 | { | ||
| 829 | outBuf = seqSizeOutStream.outBuf; // + (size_t)seqSizeOutStream.processed; | ||
| 830 | outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed; | ||
| 831 | } | ||
| 832 | |||
| 833 | res = Lzma2Enc_Encode2(lzmaf->lzma2, | ||
| 834 | outBuf ? NULL : &seqSizeOutStream.vt, | ||
| 835 | outBuf, | ||
| 836 | outBuf ? &outSize : NULL, | ||
| 837 | |||
| 838 | useStream ? | ||
| 839 | (fp ? | ||
| 840 | ( | ||
| 841 | #ifdef USE_SUBBLOCK | ||
| 842 | (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt: | ||
| 843 | #endif | ||
| 844 | &lzmaf->filter.p) : | ||
| 845 | &checkInStream.vt) : NULL, | ||
| 846 | |||
| 847 | useStream ? NULL : inBuf, | ||
| 848 | useStream ? 0 : inBufSize, | ||
| 849 | |||
| 850 | progress); | ||
| 851 | |||
| 852 | if (outBuf) | ||
| 853 | seqSizeOutStream.processed += outSize; | ||
| 854 | |||
| 855 | RINOK(res); | ||
| 856 | blockSizes->unpackSize = checkInStream.processed; | ||
| 857 | } | ||
| 858 | { | ||
| 859 | Byte buf[4 + 64]; | ||
| 860 | unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed); | ||
| 861 | UInt64 packSize = seqSizeOutStream.processed; | ||
| 862 | |||
| 863 | buf[0] = 0; | ||
| 864 | buf[1] = 0; | ||
| 865 | buf[2] = 0; | ||
| 866 | buf[3] = 0; | ||
| 867 | |||
| 868 | SeqCheckInStream_GetDigest(&checkInStream, buf + 4); | ||
| 869 | RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId))); | ||
| 870 | |||
| 871 | blockSizes->totalSize = seqSizeOutStream.processed - padSize; | ||
| 872 | |||
| 873 | if (!outStream) | ||
| 874 | { | ||
| 875 | seqSizeOutStream.outBuf = outBufHeader; | ||
| 876 | seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX; | ||
| 877 | seqSizeOutStream.processed = 0; | ||
| 878 | |||
| 879 | block.unpackSize = blockSizes->unpackSize; | ||
| 880 | XzBlock_SetHasUnpackSize(&block); | ||
| 881 | |||
| 882 | block.packSize = packSize; | ||
| 883 | XzBlock_SetHasPackSize(&block); | ||
| 884 | |||
| 885 | RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)); | ||
| 886 | |||
| 887 | blockSizes->headerSize = (size_t)seqSizeOutStream.processed; | ||
| 888 | blockSizes->totalSize += seqSizeOutStream.processed; | ||
| 889 | } | ||
| 890 | } | ||
| 891 | |||
| 892 | if (inStream) | ||
| 893 | *inStreamFinished = checkInStream.realStreamFinished; | ||
| 894 | else | ||
| 895 | { | ||
| 896 | *inStreamFinished = False; | ||
| 897 | if (checkInStream.processed != inBufSize) | ||
| 898 | return SZ_ERROR_FAIL; | ||
| 899 | } | ||
| 900 | |||
| 901 | return SZ_OK; | ||
| 902 | } | ||
| 903 | |||
| 904 | |||
| 905 | |||
| 906 | typedef struct | ||
| 907 | { | ||
| 908 | ICompressProgress vt; | ||
| 909 | ICompressProgress *progress; | ||
| 910 | UInt64 inOffset; | ||
| 911 | UInt64 outOffset; | ||
| 912 | } CCompressProgress_XzEncOffset; | ||
| 913 | |||
| 914 | |||
| 915 | static SRes CompressProgress_XzEncOffset_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize) | ||
| 916 | { | ||
| 917 | const CCompressProgress_XzEncOffset *p = CONTAINER_FROM_VTBL(pp, CCompressProgress_XzEncOffset, vt); | ||
| 918 | inSize += p->inOffset; | ||
| 919 | outSize += p->outOffset; | ||
| 920 | return ICompressProgress_Progress(p->progress, inSize, outSize); | ||
| 921 | } | ||
| 922 | |||
| 923 | |||
| 924 | |||
| 925 | |||
| 926 | typedef struct | ||
| 927 | { | ||
| 928 | ISzAllocPtr alloc; | ||
| 929 | ISzAllocPtr allocBig; | ||
| 930 | |||
| 931 | CXzProps xzProps; | ||
| 932 | UInt64 expectedDataSize; | ||
| 933 | |||
| 934 | CXzEncIndex xzIndex; | ||
| 935 | |||
| 936 | CLzma2WithFilters lzmaf_Items[MTCODER__THREADS_MAX]; | ||
| 937 | |||
| 938 | size_t outBufSize; /* size of allocated outBufs[i] */ | ||
| 939 | Byte *outBufs[MTCODER__BLOCKS_MAX]; | ||
| 940 | |||
| 941 | #ifndef _7ZIP_ST | ||
| 942 | unsigned checkType; | ||
| 943 | ISeqOutStream *outStream; | ||
| 944 | BoolInt mtCoder_WasConstructed; | ||
| 945 | CMtCoder mtCoder; | ||
| 946 | CXzEncBlockInfo EncBlocks[MTCODER__BLOCKS_MAX]; | ||
| 947 | #endif | ||
| 948 | |||
| 949 | } CXzEnc; | ||
| 950 | |||
| 951 | |||
| 952 | static void XzEnc_Construct(CXzEnc *p) | ||
| 953 | { | ||
| 954 | unsigned i; | ||
| 955 | |||
| 956 | XzEncIndex_Construct(&p->xzIndex); | ||
| 957 | |||
| 958 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
| 959 | Lzma2WithFilters_Construct(&p->lzmaf_Items[i]); | ||
| 960 | |||
| 961 | #ifndef _7ZIP_ST | ||
| 962 | p->mtCoder_WasConstructed = False; | ||
| 963 | { | ||
| 964 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
| 965 | p->outBufs[i] = NULL; | ||
| 966 | p->outBufSize = 0; | ||
| 967 | } | ||
| 968 | #endif | ||
| 969 | } | ||
| 970 | |||
| 971 | |||
| 972 | static void XzEnc_FreeOutBufs(CXzEnc *p) | ||
| 973 | { | ||
| 974 | unsigned i; | ||
| 975 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
| 976 | if (p->outBufs[i]) | ||
| 977 | { | ||
| 978 | ISzAlloc_Free(p->alloc, p->outBufs[i]); | ||
| 979 | p->outBufs[i] = NULL; | ||
| 980 | } | ||
| 981 | p->outBufSize = 0; | ||
| 982 | } | ||
| 983 | |||
| 984 | |||
| 985 | static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc) | ||
| 986 | { | ||
| 987 | unsigned i; | ||
| 988 | |||
| 989 | XzEncIndex_Free(&p->xzIndex, alloc); | ||
| 990 | |||
| 991 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
| 992 | Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc); | ||
| 993 | |||
| 994 | #ifndef _7ZIP_ST | ||
| 995 | if (p->mtCoder_WasConstructed) | ||
| 996 | { | ||
| 997 | MtCoder_Destruct(&p->mtCoder); | ||
| 998 | p->mtCoder_WasConstructed = False; | ||
| 999 | } | ||
| 1000 | XzEnc_FreeOutBufs(p); | ||
| 1001 | #endif | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | |||
| 1005 | CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
| 1006 | { | ||
| 1007 | CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc)); | ||
| 1008 | if (!p) | ||
| 1009 | return NULL; | ||
| 1010 | XzEnc_Construct(p); | ||
| 1011 | XzProps_Init(&p->xzProps); | ||
| 1012 | XzProps_Normalize(&p->xzProps); | ||
| 1013 | p->expectedDataSize = (UInt64)(Int64)-1; | ||
| 1014 | p->alloc = alloc; | ||
| 1015 | p->allocBig = allocBig; | ||
| 1016 | return p; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | |||
| 1020 | void XzEnc_Destroy(CXzEncHandle pp) | ||
| 1021 | { | ||
| 1022 | CXzEnc *p = (CXzEnc *)pp; | ||
| 1023 | XzEnc_Free(p, p->alloc); | ||
| 1024 | ISzAlloc_Free(p->alloc, p); | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | |||
| 1028 | SRes XzEnc_SetProps(CXzEncHandle pp, const CXzProps *props) | ||
| 1029 | { | ||
| 1030 | CXzEnc *p = (CXzEnc *)pp; | ||
| 1031 | p->xzProps = *props; | ||
| 1032 | XzProps_Normalize(&p->xzProps); | ||
| 1033 | return SZ_OK; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | |||
| 1037 | void XzEnc_SetDataSize(CXzEncHandle pp, UInt64 expectedDataSiize) | ||
| 1038 | { | ||
| 1039 | CXzEnc *p = (CXzEnc *)pp; | ||
| 1040 | p->expectedDataSize = expectedDataSiize; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | |||
| 1044 | |||
| 1045 | |||
| 1046 | #ifndef _7ZIP_ST | ||
| 1047 | |||
| 1048 | static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, | ||
| 1049 | const Byte *src, size_t srcSize, int finished) | ||
| 1050 | { | ||
| 1051 | CXzEnc *me = (CXzEnc *)pp; | ||
| 1052 | SRes res; | ||
| 1053 | CMtProgressThunk progressThunk; | ||
| 1054 | |||
| 1055 | Byte *dest = me->outBufs[outBufIndex]; | ||
| 1056 | |||
| 1057 | UNUSED_VAR(finished) | ||
| 1058 | |||
| 1059 | { | ||
| 1060 | CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; | ||
| 1061 | bInfo->totalSize = 0; | ||
| 1062 | bInfo->unpackSize = 0; | ||
| 1063 | bInfo->headerSize = 0; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | if (!dest) | ||
| 1067 | { | ||
| 1068 | dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); | ||
| 1069 | if (!dest) | ||
| 1070 | return SZ_ERROR_MEM; | ||
| 1071 | me->outBufs[outBufIndex] = dest; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | MtProgressThunk_CreateVTable(&progressThunk); | ||
| 1075 | progressThunk.mtProgress = &me->mtCoder.mtProgress; | ||
| 1076 | MtProgressThunk_Init(&progressThunk); | ||
| 1077 | |||
| 1078 | { | ||
| 1079 | CXzEncBlockInfo blockSizes; | ||
| 1080 | int inStreamFinished; | ||
| 1081 | |||
| 1082 | res = Xz_CompressBlock( | ||
| 1083 | &me->lzmaf_Items[coderIndex], | ||
| 1084 | |||
| 1085 | NULL, | ||
| 1086 | dest, | ||
| 1087 | dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX, | ||
| 1088 | |||
| 1089 | NULL, | ||
| 1090 | // srcSize, // expectedSize | ||
| 1091 | src, srcSize, | ||
| 1092 | |||
| 1093 | &me->xzProps, | ||
| 1094 | &progressThunk.vt, | ||
| 1095 | &inStreamFinished, | ||
| 1096 | &blockSizes, | ||
| 1097 | me->alloc, | ||
| 1098 | me->allocBig); | ||
| 1099 | |||
| 1100 | if (res == SZ_OK) | ||
| 1101 | me->EncBlocks[outBufIndex] = blockSizes; | ||
| 1102 | |||
| 1103 | return res; | ||
| 1104 | } | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | |||
| 1108 | static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex) | ||
| 1109 | { | ||
| 1110 | CXzEnc *me = (CXzEnc *)pp; | ||
| 1111 | |||
| 1112 | const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; | ||
| 1113 | const Byte *data = me->outBufs[outBufIndex]; | ||
| 1114 | |||
| 1115 | RINOK(WriteBytes(me->outStream, data, bInfo->headerSize)); | ||
| 1116 | |||
| 1117 | { | ||
| 1118 | UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize); | ||
| 1119 | RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize)); | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | #endif | ||
| 1126 | |||
| 1127 | |||
| 1128 | |||
| 1129 | SRes XzEnc_Encode(CXzEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) | ||
| 1130 | { | ||
| 1131 | CXzEnc *p = (CXzEnc *)pp; | ||
| 1132 | |||
| 1133 | const CXzProps *props = &p->xzProps; | ||
| 1134 | |||
| 1135 | XzEncIndex_Init(&p->xzIndex); | ||
| 1136 | { | ||
| 1137 | UInt64 numBlocks = 1; | ||
| 1138 | UInt64 blockSize = props->blockSize; | ||
| 1139 | |||
| 1140 | if (blockSize != XZ_PROPS__BLOCK_SIZE__SOLID | ||
| 1141 | && props->reduceSize != (UInt64)(Int64)-1) | ||
| 1142 | { | ||
| 1143 | numBlocks = props->reduceSize / blockSize; | ||
| 1144 | if (numBlocks * blockSize != props->reduceSize) | ||
| 1145 | numBlocks++; | ||
| 1146 | } | ||
| 1147 | else | ||
| 1148 | blockSize = (UInt64)1 << 62; | ||
| 1149 | |||
| 1150 | RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc)); | ||
| 1151 | } | ||
| 1152 | |||
| 1153 | RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream)); | ||
| 1154 | |||
| 1155 | |||
| 1156 | #ifndef _7ZIP_ST | ||
| 1157 | if (props->numBlockThreads_Reduced > 1) | ||
| 1158 | { | ||
| 1159 | IMtCoderCallback2 vt; | ||
| 1160 | |||
| 1161 | if (!p->mtCoder_WasConstructed) | ||
| 1162 | { | ||
| 1163 | p->mtCoder_WasConstructed = True; | ||
| 1164 | MtCoder_Construct(&p->mtCoder); | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | vt.Code = XzEnc_MtCallback_Code; | ||
| 1168 | vt.Write = XzEnc_MtCallback_Write; | ||
| 1169 | |||
| 1170 | p->checkType = props->checkId; | ||
| 1171 | p->xzProps = *props; | ||
| 1172 | |||
| 1173 | p->outStream = outStream; | ||
| 1174 | |||
| 1175 | p->mtCoder.allocBig = p->allocBig; | ||
| 1176 | p->mtCoder.progress = progress; | ||
| 1177 | p->mtCoder.inStream = inStream; | ||
| 1178 | p->mtCoder.inData = NULL; | ||
| 1179 | p->mtCoder.inDataSize = 0; | ||
| 1180 | p->mtCoder.mtCallback = &vt; | ||
| 1181 | p->mtCoder.mtCallbackObject = p; | ||
| 1182 | |||
| 1183 | if ( props->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID | ||
| 1184 | || props->blockSize == XZ_PROPS__BLOCK_SIZE__AUTO) | ||
| 1185 | return SZ_ERROR_FAIL; | ||
| 1186 | |||
| 1187 | p->mtCoder.blockSize = (size_t)props->blockSize; | ||
| 1188 | if (p->mtCoder.blockSize != props->blockSize) | ||
| 1189 | return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ | ||
| 1190 | |||
| 1191 | { | ||
| 1192 | size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize); | ||
| 1193 | if (destBlockSize < p->mtCoder.blockSize) | ||
| 1194 | return SZ_ERROR_PARAM; | ||
| 1195 | if (p->outBufSize != destBlockSize) | ||
| 1196 | XzEnc_FreeOutBufs(p); | ||
| 1197 | p->outBufSize = destBlockSize; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max; | ||
| 1201 | p->mtCoder.expectedDataSize = p->expectedDataSize; | ||
| 1202 | |||
| 1203 | RINOK(MtCoder_Code(&p->mtCoder)); | ||
| 1204 | } | ||
| 1205 | else | ||
| 1206 | #endif | ||
| 1207 | { | ||
| 1208 | int writeStartSizes; | ||
| 1209 | CCompressProgress_XzEncOffset progress2; | ||
| 1210 | Byte *bufData = NULL; | ||
| 1211 | size_t bufSize = 0; | ||
| 1212 | |||
| 1213 | progress2.vt.Progress = CompressProgress_XzEncOffset_Progress; | ||
| 1214 | progress2.inOffset = 0; | ||
| 1215 | progress2.outOffset = 0; | ||
| 1216 | progress2.progress = progress; | ||
| 1217 | |||
| 1218 | writeStartSizes = 0; | ||
| 1219 | |||
| 1220 | if (props->blockSize != XZ_PROPS__BLOCK_SIZE__SOLID) | ||
| 1221 | { | ||
| 1222 | writeStartSizes = (props->forceWriteSizesInHeader > 0); | ||
| 1223 | |||
| 1224 | if (writeStartSizes) | ||
| 1225 | { | ||
| 1226 | size_t t2; | ||
| 1227 | size_t t = (size_t)props->blockSize; | ||
| 1228 | if (t != props->blockSize) | ||
| 1229 | return SZ_ERROR_PARAM; | ||
| 1230 | t = XZ_GET_MAX_BLOCK_PACK_SIZE(t); | ||
| 1231 | if (t < props->blockSize) | ||
| 1232 | return SZ_ERROR_PARAM; | ||
| 1233 | t2 = XZ_BLOCK_HEADER_SIZE_MAX + t; | ||
| 1234 | if (!p->outBufs[0] || t2 != p->outBufSize) | ||
| 1235 | { | ||
| 1236 | XzEnc_FreeOutBufs(p); | ||
| 1237 | p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2); | ||
| 1238 | if (!p->outBufs[0]) | ||
| 1239 | return SZ_ERROR_MEM; | ||
| 1240 | p->outBufSize = t2; | ||
| 1241 | } | ||
| 1242 | bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX; | ||
| 1243 | bufSize = t; | ||
| 1244 | } | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | for (;;) | ||
| 1248 | { | ||
| 1249 | CXzEncBlockInfo blockSizes; | ||
| 1250 | int inStreamFinished; | ||
| 1251 | |||
| 1252 | /* | ||
| 1253 | UInt64 rem = (UInt64)(Int64)-1; | ||
| 1254 | if (props->reduceSize != (UInt64)(Int64)-1 | ||
| 1255 | && props->reduceSize >= progress2.inOffset) | ||
| 1256 | rem = props->reduceSize - progress2.inOffset; | ||
| 1257 | */ | ||
| 1258 | |||
| 1259 | blockSizes.headerSize = 0; // for GCC | ||
| 1260 | |||
| 1261 | RINOK(Xz_CompressBlock( | ||
| 1262 | &p->lzmaf_Items[0], | ||
| 1263 | |||
| 1264 | writeStartSizes ? NULL : outStream, | ||
| 1265 | writeStartSizes ? p->outBufs[0] : NULL, | ||
| 1266 | bufData, bufSize, | ||
| 1267 | |||
| 1268 | inStream, | ||
| 1269 | // rem, | ||
| 1270 | NULL, 0, | ||
| 1271 | |||
| 1272 | props, | ||
| 1273 | progress ? &progress2.vt : NULL, | ||
| 1274 | &inStreamFinished, | ||
| 1275 | &blockSizes, | ||
| 1276 | p->alloc, | ||
| 1277 | p->allocBig)); | ||
| 1278 | |||
| 1279 | { | ||
| 1280 | UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize); | ||
| 1281 | |||
| 1282 | if (writeStartSizes) | ||
| 1283 | { | ||
| 1284 | RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize)); | ||
| 1285 | RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize)); | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc)); | ||
| 1289 | |||
| 1290 | progress2.inOffset += blockSizes.unpackSize; | ||
| 1291 | progress2.outOffset += totalPackFull; | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | if (inStreamFinished) | ||
| 1295 | break; | ||
| 1296 | } | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream); | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | |||
| 1303 | #include "Alloc.h" | ||
| 1304 | |||
| 1305 | SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, | ||
| 1306 | const CXzProps *props, ICompressProgress *progress) | ||
| 1307 | { | ||
| 1308 | SRes res; | ||
| 1309 | CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc); | ||
| 1310 | if (!xz) | ||
| 1311 | return SZ_ERROR_MEM; | ||
| 1312 | res = XzEnc_SetProps(xz, props); | ||
| 1313 | if (res == SZ_OK) | ||
| 1314 | res = XzEnc_Encode(xz, outStream, inStream, progress); | ||
| 1315 | XzEnc_Destroy(xz); | ||
| 1316 | return res; | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | |||
| 1320 | SRes Xz_EncodeEmpty(ISeqOutStream *outStream) | ||
| 1321 | { | ||
| 1322 | SRes res; | ||
| 1323 | CXzEncIndex xzIndex; | ||
| 1324 | XzEncIndex_Construct(&xzIndex); | ||
| 1325 | res = Xz_WriteHeader((CXzStreamFlags)0, outStream); | ||
| 1326 | if (res == SZ_OK) | ||
| 1327 | res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream); | ||
| 1328 | XzEncIndex_Free(&xzIndex, NULL); // g_Alloc | ||
| 1329 | return res; | ||
| 1330 | } | ||
diff --git a/C/XzEnc.h b/C/XzEnc.h new file mode 100644 index 0000000..0c29e7e --- /dev/null +++ b/C/XzEnc.h | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | /* XzEnc.h -- Xz Encode | ||
| 2 | 2017-06-27 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #ifndef __XZ_ENC_H | ||
| 5 | #define __XZ_ENC_H | ||
| 6 | |||
| 7 | #include "Lzma2Enc.h" | ||
| 8 | |||
| 9 | #include "Xz.h" | ||
| 10 | |||
| 11 | EXTERN_C_BEGIN | ||
| 12 | |||
| 13 | |||
| 14 | #define XZ_PROPS__BLOCK_SIZE__AUTO LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO | ||
| 15 | #define XZ_PROPS__BLOCK_SIZE__SOLID LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | ||
| 16 | |||
| 17 | |||
| 18 | typedef struct | ||
| 19 | { | ||
| 20 | UInt32 id; | ||
| 21 | UInt32 delta; | ||
| 22 | UInt32 ip; | ||
| 23 | int ipDefined; | ||
| 24 | } CXzFilterProps; | ||
| 25 | |||
| 26 | void XzFilterProps_Init(CXzFilterProps *p); | ||
| 27 | |||
| 28 | |||
| 29 | typedef struct | ||
| 30 | { | ||
| 31 | CLzma2EncProps lzma2Props; | ||
| 32 | CXzFilterProps filterProps; | ||
| 33 | unsigned checkId; | ||
| 34 | UInt64 blockSize; | ||
| 35 | int numBlockThreads_Reduced; | ||
| 36 | int numBlockThreads_Max; | ||
| 37 | int numTotalThreads; | ||
| 38 | int forceWriteSizesInHeader; | ||
| 39 | UInt64 reduceSize; | ||
| 40 | } CXzProps; | ||
| 41 | |||
| 42 | void XzProps_Init(CXzProps *p); | ||
| 43 | |||
| 44 | |||
| 45 | typedef void * CXzEncHandle; | ||
| 46 | |||
| 47 | CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
| 48 | void XzEnc_Destroy(CXzEncHandle p); | ||
| 49 | SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props); | ||
| 50 | void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize); | ||
| 51 | SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress); | ||
| 52 | |||
| 53 | SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, | ||
| 54 | const CXzProps *props, ICompressProgress *progress); | ||
| 55 | |||
| 56 | SRes Xz_EncodeEmpty(ISeqOutStream *outStream); | ||
| 57 | |||
| 58 | EXTERN_C_END | ||
| 59 | |||
| 60 | #endif | ||
diff --git a/C/XzIn.c b/C/XzIn.c new file mode 100644 index 0000000..84f868e --- /dev/null +++ b/C/XzIn.c | |||
| @@ -0,0 +1,325 @@ | |||
| 1 | /* XzIn.c - Xz input | ||
| 2 | 2021-09-04 : Igor Pavlov : Public domain */ | ||
| 3 | |||
| 4 | #include "Precomp.h" | ||
| 5 | |||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | #include "7zCrc.h" | ||
| 9 | #include "CpuArch.h" | ||
| 10 | #include "Xz.h" | ||
| 11 | |||
| 12 | /* | ||
| 13 | #define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0) | ||
| 14 | */ | ||
| 15 | #define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1) | ||
| 16 | |||
| 17 | |||
| 18 | SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream) | ||
| 19 | { | ||
| 20 | Byte sig[XZ_STREAM_HEADER_SIZE]; | ||
| 21 | RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE)); | ||
| 22 | if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) | ||
| 23 | return SZ_ERROR_NO_ARCHIVE; | ||
| 24 | return Xz_ParseHeader(p, sig); | ||
| 25 | } | ||
| 26 | |||
| 27 | #define READ_VARINT_AND_CHECK(buf, pos, size, res) \ | ||
| 28 | { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ | ||
| 29 | if (s == 0) return SZ_ERROR_ARCHIVE; \ | ||
| 30 | pos += s; } | ||
| 31 | |||
| 32 | SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, BoolInt *isIndex, UInt32 *headerSizeRes) | ||
| 33 | { | ||
| 34 | Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; | ||
| 35 | unsigned headerSize; | ||
| 36 | *headerSizeRes = 0; | ||
| 37 | RINOK(SeqInStream_ReadByte(inStream, &header[0])); | ||
| 38 | headerSize = (unsigned)header[0]; | ||
| 39 | if (headerSize == 0) | ||
| 40 | { | ||
| 41 | *headerSizeRes = 1; | ||
| 42 | *isIndex = True; | ||
| 43 | return SZ_OK; | ||
| 44 | } | ||
| 45 | |||
| 46 | *isIndex = False; | ||
| 47 | headerSize = (headerSize << 2) + 4; | ||
| 48 | *headerSizeRes = headerSize; | ||
| 49 | RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1)); | ||
| 50 | return XzBlock_Parse(p, header); | ||
| 51 | } | ||
| 52 | |||
| 53 | #define ADD_SIZE_CHECK(size, val) \ | ||
| 54 | { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } | ||
| 55 | |||
| 56 | UInt64 Xz_GetUnpackSize(const CXzStream *p) | ||
| 57 | { | ||
| 58 | UInt64 size = 0; | ||
| 59 | size_t i; | ||
| 60 | for (i = 0; i < p->numBlocks; i++) | ||
| 61 | ADD_SIZE_CHECK(size, p->blocks[i].unpackSize); | ||
| 62 | return size; | ||
| 63 | } | ||
| 64 | |||
| 65 | UInt64 Xz_GetPackSize(const CXzStream *p) | ||
| 66 | { | ||
| 67 | UInt64 size = 0; | ||
| 68 | size_t i; | ||
| 69 | for (i = 0; i < p->numBlocks; i++) | ||
| 70 | ADD_SIZE_CHECK(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3); | ||
| 71 | return size; | ||
| 72 | } | ||
| 73 | |||
| 74 | /* | ||
| 75 | SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream) | ||
| 76 | { | ||
| 77 | return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f)); | ||
| 78 | } | ||
| 79 | */ | ||
| 80 | |||
| 81 | static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc) | ||
| 82 | { | ||
| 83 | size_t numBlocks, pos = 1; | ||
| 84 | UInt32 crc; | ||
| 85 | |||
| 86 | if (size < 5 || buf[0] != 0) | ||
| 87 | return SZ_ERROR_ARCHIVE; | ||
| 88 | |||
| 89 | size -= 4; | ||
| 90 | crc = CrcCalc(buf, size); | ||
| 91 | if (crc != GetUi32(buf + size)) | ||
| 92 | return SZ_ERROR_ARCHIVE; | ||
| 93 | |||
| 94 | { | ||
| 95 | UInt64 numBlocks64; | ||
| 96 | READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64); | ||
| 97 | numBlocks = (size_t)numBlocks64; | ||
| 98 | if (numBlocks != numBlocks64 || numBlocks * 2 > size) | ||
| 99 | return SZ_ERROR_ARCHIVE; | ||
| 100 | } | ||
| 101 | |||
| 102 | Xz_Free(p, alloc); | ||
| 103 | if (numBlocks != 0) | ||
| 104 | { | ||
| 105 | size_t i; | ||
| 106 | p->numBlocks = numBlocks; | ||
| 107 | p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); | ||
| 108 | if (!p->blocks) | ||
| 109 | return SZ_ERROR_MEM; | ||
| 110 | for (i = 0; i < numBlocks; i++) | ||
| 111 | { | ||
| 112 | CXzBlockSizes *block = &p->blocks[i]; | ||
| 113 | READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize); | ||
| 114 | READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize); | ||
| 115 | if (block->totalSize == 0) | ||
| 116 | return SZ_ERROR_ARCHIVE; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | while ((pos & 3) != 0) | ||
| 120 | if (buf[pos++] != 0) | ||
| 121 | return SZ_ERROR_ARCHIVE; | ||
| 122 | return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; | ||
| 123 | } | ||
| 124 | |||
| 125 | static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAllocPtr alloc) | ||
| 126 | { | ||
| 127 | SRes res; | ||
| 128 | size_t size; | ||
| 129 | Byte *buf; | ||
| 130 | if (indexSize > ((UInt32)1 << 31)) | ||
| 131 | return SZ_ERROR_UNSUPPORTED; | ||
| 132 | size = (size_t)indexSize; | ||
| 133 | if (size != indexSize) | ||
| 134 | return SZ_ERROR_UNSUPPORTED; | ||
| 135 | buf = (Byte *)ISzAlloc_Alloc(alloc, size); | ||
| 136 | if (!buf) | ||
| 137 | return SZ_ERROR_MEM; | ||
| 138 | res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); | ||
| 139 | if (res == SZ_OK) | ||
| 140 | res = Xz_ReadIndex2(p, buf, size, alloc); | ||
| 141 | ISzAlloc_Free(alloc, buf); | ||
| 142 | return res; | ||
| 143 | } | ||
| 144 | |||
| 145 | static SRes LookInStream_SeekRead_ForArc(ILookInStream *stream, UInt64 offset, void *buf, size_t size) | ||
| 146 | { | ||
| 147 | RINOK(LookInStream_SeekTo(stream, offset)); | ||
| 148 | return LookInStream_Read(stream, buf, size); | ||
| 149 | /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */ | ||
| 150 | } | ||
| 151 | |||
| 152 | static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAllocPtr alloc) | ||
| 153 | { | ||
| 154 | UInt64 indexSize; | ||
| 155 | Byte buf[XZ_STREAM_FOOTER_SIZE]; | ||
| 156 | UInt64 pos = (UInt64)*startOffset; | ||
| 157 | |||
| 158 | if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE) | ||
| 159 | return SZ_ERROR_NO_ARCHIVE; | ||
| 160 | |||
| 161 | pos -= XZ_STREAM_FOOTER_SIZE; | ||
| 162 | RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)); | ||
| 163 | |||
| 164 | if (!XZ_FOOTER_SIG_CHECK(buf + 10)) | ||
| 165 | { | ||
| 166 | UInt32 total = 0; | ||
| 167 | pos += XZ_STREAM_FOOTER_SIZE; | ||
| 168 | |||
| 169 | for (;;) | ||
| 170 | { | ||
| 171 | size_t i; | ||
| 172 | #define TEMP_BUF_SIZE (1 << 10) | ||
| 173 | Byte temp[TEMP_BUF_SIZE]; | ||
| 174 | |||
| 175 | i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos; | ||
| 176 | pos -= i; | ||
| 177 | RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i)); | ||
| 178 | total += (UInt32)i; | ||
| 179 | for (; i != 0; i--) | ||
| 180 | if (temp[i - 1] != 0) | ||
| 181 | break; | ||
| 182 | if (i != 0) | ||
| 183 | { | ||
| 184 | if ((i & 3) != 0) | ||
| 185 | return SZ_ERROR_NO_ARCHIVE; | ||
| 186 | pos += i; | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) | ||
| 190 | return SZ_ERROR_NO_ARCHIVE; | ||
| 191 | } | ||
| 192 | |||
| 193 | if (pos < XZ_STREAM_FOOTER_SIZE) | ||
| 194 | return SZ_ERROR_NO_ARCHIVE; | ||
| 195 | pos -= XZ_STREAM_FOOTER_SIZE; | ||
| 196 | RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)); | ||
| 197 | if (!XZ_FOOTER_SIG_CHECK(buf + 10)) | ||
| 198 | return SZ_ERROR_NO_ARCHIVE; | ||
| 199 | } | ||
| 200 | |||
| 201 | p->flags = (CXzStreamFlags)GetBe16(buf + 8); | ||
| 202 | |||
| 203 | if (!XzFlags_IsSupported(p->flags)) | ||
| 204 | return SZ_ERROR_UNSUPPORTED; | ||
| 205 | |||
| 206 | { | ||
| 207 | /* to eliminate GCC 6.3 warning: | ||
| 208 | dereferencing type-punned pointer will break strict-aliasing rules */ | ||
| 209 | const Byte *buf_ptr = buf; | ||
| 210 | if (GetUi32(buf_ptr) != CrcCalc(buf + 4, 6)) | ||
| 211 | return SZ_ERROR_ARCHIVE; | ||
| 212 | } | ||
| 213 | |||
| 214 | indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; | ||
| 215 | |||
| 216 | if (pos < indexSize) | ||
| 217 | return SZ_ERROR_ARCHIVE; | ||
| 218 | |||
| 219 | pos -= indexSize; | ||
| 220 | RINOK(LookInStream_SeekTo(stream, pos)); | ||
| 221 | RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)); | ||
| 222 | |||
| 223 | { | ||
| 224 | UInt64 totalSize = Xz_GetPackSize(p); | ||
| 225 | if (totalSize == XZ_SIZE_OVERFLOW | ||
| 226 | || totalSize >= ((UInt64)1 << 63) | ||
| 227 | || pos < totalSize + XZ_STREAM_HEADER_SIZE) | ||
| 228 | return SZ_ERROR_ARCHIVE; | ||
| 229 | pos -= (totalSize + XZ_STREAM_HEADER_SIZE); | ||
| 230 | RINOK(LookInStream_SeekTo(stream, pos)); | ||
| 231 | *startOffset = (Int64)pos; | ||
| 232 | } | ||
| 233 | { | ||
| 234 | CXzStreamFlags headerFlags; | ||
| 235 | CSecToRead secToRead; | ||
| 236 | SecToRead_CreateVTable(&secToRead); | ||
| 237 | secToRead.realStream = stream; | ||
| 238 | |||
| 239 | RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt)); | ||
| 240 | return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | |||
| 245 | /* ---------- Xz Streams ---------- */ | ||
| 246 | |||
| 247 | void Xzs_Construct(CXzs *p) | ||
| 248 | { | ||
| 249 | p->num = p->numAllocated = 0; | ||
| 250 | p->streams = 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | void Xzs_Free(CXzs *p, ISzAllocPtr alloc) | ||
| 254 | { | ||
| 255 | size_t i; | ||
| 256 | for (i = 0; i < p->num; i++) | ||
| 257 | Xz_Free(&p->streams[i], alloc); | ||
| 258 | ISzAlloc_Free(alloc, p->streams); | ||
| 259 | p->num = p->numAllocated = 0; | ||
| 260 | p->streams = 0; | ||
| 261 | } | ||
| 262 | |||
| 263 | UInt64 Xzs_GetNumBlocks(const CXzs *p) | ||
| 264 | { | ||
| 265 | UInt64 num = 0; | ||
| 266 | size_t i; | ||
| 267 | for (i = 0; i < p->num; i++) | ||
| 268 | num += p->streams[i].numBlocks; | ||
| 269 | return num; | ||
| 270 | } | ||
| 271 | |||
| 272 | UInt64 Xzs_GetUnpackSize(const CXzs *p) | ||
| 273 | { | ||
| 274 | UInt64 size = 0; | ||
| 275 | size_t i; | ||
| 276 | for (i = 0; i < p->num; i++) | ||
| 277 | ADD_SIZE_CHECK(size, Xz_GetUnpackSize(&p->streams[i])); | ||
| 278 | return size; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* | ||
| 282 | UInt64 Xzs_GetPackSize(const CXzs *p) | ||
| 283 | { | ||
| 284 | UInt64 size = 0; | ||
| 285 | size_t i; | ||
| 286 | for (i = 0; i < p->num; i++) | ||
| 287 | ADD_SIZE_CHECK(size, Xz_GetTotalSize(&p->streams[i])); | ||
| 288 | return size; | ||
| 289 | } | ||
| 290 | */ | ||
| 291 | |||
| 292 | SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAllocPtr alloc) | ||
| 293 | { | ||
| 294 | Int64 endOffset = 0; | ||
| 295 | RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END)); | ||
| 296 | *startOffset = endOffset; | ||
| 297 | for (;;) | ||
| 298 | { | ||
| 299 | CXzStream st; | ||
| 300 | SRes res; | ||
| 301 | Xz_Construct(&st); | ||
| 302 | res = Xz_ReadBackward(&st, stream, startOffset, alloc); | ||
| 303 | st.startOffset = (UInt64)*startOffset; | ||
| 304 | RINOK(res); | ||
| 305 | if (p->num == p->numAllocated) | ||
| 306 | { | ||
| 307 | const size_t newNum = p->num + p->num / 4 + 1; | ||
| 308 | void *data = ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream)); | ||
| 309 | if (!data) | ||
| 310 | return SZ_ERROR_MEM; | ||
| 311 | p->numAllocated = newNum; | ||
| 312 | if (p->num != 0) | ||
| 313 | memcpy(data, p->streams, p->num * sizeof(CXzStream)); | ||
| 314 | ISzAlloc_Free(alloc, p->streams); | ||
| 315 | p->streams = (CXzStream *)data; | ||
| 316 | } | ||
| 317 | p->streams[p->num++] = st; | ||
| 318 | if (*startOffset == 0) | ||
| 319 | break; | ||
| 320 | RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset)); | ||
| 321 | if (progress && ICompressProgress_Progress(progress, (UInt64)(endOffset - *startOffset), (UInt64)(Int64)-1) != SZ_OK) | ||
| 322 | return SZ_ERROR_PROGRESS; | ||
| 323 | } | ||
| 324 | return SZ_OK; | ||
| 325 | } | ||
diff --git a/C/var_clang.mak b/C/var_clang.mak new file mode 100644 index 0000000..a6df26e --- /dev/null +++ b/C/var_clang.mak | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | PLATFORM= | ||
| 2 | O=b/c | ||
| 3 | IS_X64= | ||
| 4 | IS_X86= | ||
| 5 | IS_ARM64= | ||
| 6 | CROSS_COMPILE= | ||
| 7 | MY_ARCH= | ||
| 8 | USE_ASM= | ||
| 9 | CC=$(CROSS_COMPILE)clang | ||
| 10 | CXX=$(CROSS_COMPILE)clang++ | ||
| 11 | USE_CLANG=1 | ||
diff --git a/C/var_clang_arm64.mak b/C/var_clang_arm64.mak new file mode 100644 index 0000000..4b35409 --- /dev/null +++ b/C/var_clang_arm64.mak | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | PLATFORM=arm64 | ||
| 2 | O=b/c_$(PLATFORM) | ||
| 3 | IS_X64= | ||
| 4 | IS_X86= | ||
| 5 | IS_ARM64=1 | ||
| 6 | CROSS_COMPILE= | ||
| 7 | MY_ARCH= | ||
| 8 | USE_ASM=1 | ||
| 9 | CC=$(CROSS_COMPILE)clang | ||
| 10 | CXX=$(CROSS_COMPILE)clang++ | ||
| 11 | USE_CLANG=1 | ||
diff --git a/C/var_clang_x64.mak b/C/var_clang_x64.mak new file mode 100644 index 0000000..34e1b49 --- /dev/null +++ b/C/var_clang_x64.mak | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | PLATFORM=x64 | ||
| 2 | O=b/c_$(PLATFORM) | ||
| 3 | IS_X64=1 | ||
| 4 | IS_X86= | ||
| 5 | IS_ARM64= | ||
| 6 | CROSS_COMPILE= | ||
| 7 | MY_ARCH= | ||
| 8 | USE_ASM=1 | ||
| 9 | CC=$(CROSS_COMPILE)clang | ||
| 10 | CXX=$(CROSS_COMPILE)clang++ | ||
| 11 | USE_CLANG=1 | ||
diff --git a/C/var_clang_x86.mak b/C/var_clang_x86.mak new file mode 100644 index 0000000..bd2317c --- /dev/null +++ b/C/var_clang_x86.mak | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | PLATFORM=x86 | ||
| 2 | O=b/c_$(PLATFORM) | ||
| 3 | IS_X64= | ||
| 4 | IS_X86=1 | ||
| 5 | IS_ARM64= | ||
| 6 | CROSS_COMPILE= | ||
| 7 | MY_ARCH=-m32 | ||
| 8 | USE_ASM=1 | ||
| 9 | CC=$(CROSS_COMPILE)clang | ||
| 10 | CXX=$(CROSS_COMPILE)clang++ | ||
| 11 | USE_CLANG=1 | ||
diff --git a/C/var_gcc.mak b/C/var_gcc.mak new file mode 100644 index 0000000..664491c --- /dev/null +++ b/C/var_gcc.mak | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | PLATFORM= | ||
| 2 | O=b/g | ||
| 3 | IS_X64= | ||
| 4 | IS_X86= | ||
| 5 | IS_ARM64= | ||
| 6 | CROSS_COMPILE= | ||
| 7 | MY_ARCH= | ||
| 8 | USE_ASM= | ||
| 9 | CC=$(CROSS_COMPILE)gcc | ||
| 10 | CXX=$(CROSS_COMPILE)g++ | ||
| 11 | |||
| 12 | # -march=armv8-a+crc+crypto | ||
diff --git a/C/var_gcc_arm64.mak b/C/var_gcc_arm64.mak new file mode 100644 index 0000000..4bbb687 --- /dev/null +++ b/C/var_gcc_arm64.mak | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | PLATFORM=arm64 | ||
| 2 | O=b/g_$(PLATFORM) | ||
| 3 | IS_X64= | ||
| 4 | IS_X86= | ||
| 5 | IS_ARM64=1 | ||
| 6 | CROSS_COMPILE= | ||
| 7 | MY_ARCH=-mtune=cortex-a53 | ||
| 8 | USE_ASM=1 | ||
| 9 | CC=$(CROSS_COMPILE)gcc | ||
| 10 | CXX=$(CROSS_COMPILE)g++ | ||
| 11 | |||
| 12 | # -march=armv8-a+crc+crypto | ||
diff --git a/C/var_gcc_x64.mak b/C/var_gcc_x64.mak new file mode 100644 index 0000000..1acf604 --- /dev/null +++ b/C/var_gcc_x64.mak | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | PLATFORM=x64 | ||
| 2 | O=b/g_$(PLATFORM) | ||
| 3 | IS_X64=1 | ||
| 4 | IS_X86= | ||
| 5 | IS_ARM64= | ||
| 6 | CROSS_COMPILE= | ||
| 7 | MY_ARCH= | ||
| 8 | USE_ASM=1 | ||
| 9 | CC=$(CROSS_COMPILE)gcc | ||
| 10 | CXX=$(CROSS_COMPILE)g++ | ||
diff --git a/C/var_gcc_x86.mak b/C/var_gcc_x86.mak new file mode 100644 index 0000000..f0718ec --- /dev/null +++ b/C/var_gcc_x86.mak | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | PLATFORM=x86 | ||
| 2 | O=b/g_$(PLATFORM) | ||
| 3 | IS_X64= | ||
| 4 | IS_X86=1 | ||
| 5 | IS_ARM64= | ||
| 6 | CROSS_COMPILE= | ||
| 7 | MY_ARCH=-m32 | ||
| 8 | USE_ASM=1 | ||
| 9 | CC=$(CROSS_COMPILE)gcc | ||
| 10 | CXX=$(CROSS_COMPILE)g++ | ||
diff --git a/C/var_mac_arm64.mak b/C/var_mac_arm64.mak new file mode 100644 index 0000000..adf5fa1 --- /dev/null +++ b/C/var_mac_arm64.mak | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | PLATFORM=arm64 | ||
| 2 | O=b/m_$(PLATFORM) | ||
| 3 | IS_X64= | ||
| 4 | IS_X86= | ||
| 5 | IS_ARM64=1 | ||
| 6 | CROSS_COMPILE= | ||
| 7 | MY_ARCH=-arch arm64 | ||
| 8 | USE_ASM=1 | ||
| 9 | CC=$(CROSS_COMPILE)clang | ||
| 10 | CXX=$(CROSS_COMPILE)clang++ | ||
| 11 | USE_CLANG=1 | ||
diff --git a/C/var_mac_x64.mak b/C/var_mac_x64.mak new file mode 100644 index 0000000..13d7aa7 --- /dev/null +++ b/C/var_mac_x64.mak | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | PLATFORM=x64 | ||
| 2 | O=b/m_$(PLATFORM) | ||
| 3 | IS_X64=1 | ||
| 4 | IS_X86= | ||
| 5 | IS_ARM64= | ||
| 6 | CROSS_COMPILE= | ||
| 7 | MY_ARCH=-arch x86_64 | ||
| 8 | USE_ASM= | ||
| 9 | CC=$(CROSS_COMPILE)clang | ||
| 10 | CXX=$(CROSS_COMPILE)clang++ | ||
| 11 | USE_CLANG=1 | ||
diff --git a/C/warn_clang.mak b/C/warn_clang.mak new file mode 100644 index 0000000..ed4f908 --- /dev/null +++ b/C/warn_clang.mak | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | CFLAGS_WARN_CLANG_3_8_UNIQ = \ | ||
| 2 | -Wno-reserved-id-macro \ | ||
| 3 | -Wno-old-style-cast \ | ||
| 4 | -Wno-c++11-long-long \ | ||
| 5 | -Wno-unused-macros \ | ||
| 6 | |||
| 7 | CFLAGS_WARN_CLANG_3_8 = \ | ||
| 8 | $(CFLAGS_WARN_CLANG_3_8_UNIQ) \ | ||
| 9 | -Weverything \ | ||
| 10 | -Wno-extra-semi \ | ||
| 11 | -Wno-sign-conversion \ | ||
| 12 | -Wno-language-extension-token \ | ||
| 13 | -Wno-global-constructors \ | ||
| 14 | -Wno-non-virtual-dtor \ | ||
| 15 | -Wno-switch-enum \ | ||
| 16 | -Wno-covered-switch-default \ | ||
| 17 | -Wno-cast-qual \ | ||
| 18 | -Wno-padded \ | ||
| 19 | -Wno-exit-time-destructors \ | ||
| 20 | -Wno-weak-vtables \ | ||
| 21 | |||
| 22 | CFLAGS_WARN_CLANG_12= $(CFLAGS_WARN_CLANG_3_8) \ | ||
| 23 | -Wno-extra-semi-stmt \ | ||
| 24 | -Wno-zero-as-null-pointer-constant \ | ||
| 25 | -Wno-deprecated-dynamic-exception-spec \ | ||
| 26 | -Wno-c++98-compat-pedantic \ | ||
| 27 | -Wno-atomic-implicit-seq-cst \ | ||
| 28 | -Wconversion \ | ||
| 29 | -Wno-sign-conversion \ | ||
| 30 | |||
| 31 | CFLAGS_WARN_1 = \ | ||
| 32 | -Wno-deprecated-copy-dtor \ | ||
| 33 | |||
| 34 | |||
| 35 | |||
| 36 | |||
| 37 | CFLAGS_WARN = $(CFLAGS_WARN_CLANG_12) $(CFLAGS_WARN_1) | ||
diff --git a/C/warn_clang_mac.mak b/C/warn_clang_mac.mak new file mode 100644 index 0000000..41044a2 --- /dev/null +++ b/C/warn_clang_mac.mak | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | CFLAGS_WARN_CLANG_3_8_UNIQ = \ | ||
| 2 | -Wno-reserved-id-macro \ | ||
| 3 | -Wno-old-style-cast \ | ||
| 4 | -Wno-c++11-long-long \ | ||
| 5 | -Wno-unused-macros \ | ||
| 6 | |||
| 7 | CFLAGS_WARN_CLANG_3_8 = \ | ||
| 8 | $(CFLAGS_WARN_CLANG_3_8_UNIQ) \ | ||
| 9 | -Weverything \ | ||
| 10 | -Wno-extra-semi \ | ||
| 11 | -Wno-sign-conversion \ | ||
| 12 | -Wno-language-extension-token \ | ||
| 13 | -Wno-global-constructors \ | ||
| 14 | -Wno-non-virtual-dtor \ | ||
| 15 | -Wno-switch-enum \ | ||
| 16 | -Wno-covered-switch-default \ | ||
| 17 | -Wno-cast-qual \ | ||
| 18 | -Wno-padded \ | ||
| 19 | -Wno-exit-time-destructors \ | ||
| 20 | -Wno-weak-vtables \ | ||
| 21 | |||
| 22 | CFLAGS_WARN_CLANG_12= $(CFLAGS_WARN_CLANG_3_8) \ | ||
| 23 | -Wno-extra-semi-stmt \ | ||
| 24 | -Wno-zero-as-null-pointer-constant \ | ||
| 25 | -Wno-deprecated-dynamic-exception-spec \ | ||
| 26 | -Wno-c++98-compat-pedantic \ | ||
| 27 | -Wno-atomic-implicit-seq-cst \ | ||
| 28 | -Wconversion \ | ||
| 29 | -Wno-sign-conversion \ | ||
| 30 | |||
| 31 | CFLAGS_WARN_MAC = \ | ||
| 32 | -Wno-poison-system-directories \ | ||
| 33 | -Wno-c++11-long-long \ | ||
| 34 | -Wno-atomic-implicit-seq-cst \ | ||
| 35 | |||
| 36 | |||
| 37 | CFLAGS_WARN = $(CFLAGS_WARN_CLANG_12) $(CFLAGS_WARN_MAC) | ||
diff --git a/C/warn_gcc.mak b/C/warn_gcc.mak new file mode 100644 index 0000000..7aab7a4 --- /dev/null +++ b/C/warn_gcc.mak | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | CFLAGS_WARN_GCC_4_5 = \ | ||
| 2 | |||
| 3 | CFLAGS_WARN_GCC_6 = \ | ||
| 4 | -Waddress \ | ||
| 5 | -Waggressive-loop-optimizations \ | ||
| 6 | -Wattributes \ | ||
| 7 | -Wbool-compare \ | ||
| 8 | -Wcast-align \ | ||
| 9 | -Wcomment \ | ||
| 10 | -Wdiv-by-zero \ | ||
| 11 | -Wduplicated-cond \ | ||
| 12 | -Wformat-contains-nul \ | ||
| 13 | -Winit-self \ | ||
| 14 | -Wint-to-pointer-cast \ | ||
| 15 | -Wunused \ | ||
| 16 | -Wunused-macros \ | ||
| 17 | |||
| 18 | # -Wno-strict-aliasing | ||
| 19 | |||
| 20 | CFLAGS_WARN_GCC_9 = \ | ||
| 21 | -Waddress \ | ||
| 22 | -Waddress-of-packed-member \ | ||
| 23 | -Waggressive-loop-optimizations \ | ||
| 24 | -Wattributes \ | ||
| 25 | -Wbool-compare \ | ||
| 26 | -Wbool-operation \ | ||
| 27 | -Wcast-align \ | ||
| 28 | -Wcast-align=strict \ | ||
| 29 | -Wcomment \ | ||
| 30 | -Wdangling-else \ | ||
| 31 | -Wdiv-by-zero \ | ||
| 32 | -Wduplicated-branches \ | ||
| 33 | -Wduplicated-cond \ | ||
| 34 | -Wformat-contains-nul \ | ||
| 35 | -Wimplicit-fallthrough=5 \ | ||
| 36 | -Winit-self \ | ||
| 37 | -Wint-in-bool-context \ | ||
| 38 | -Wint-to-pointer-cast \ | ||
| 39 | -Wunused \ | ||
| 40 | -Wunused-macros \ | ||
| 41 | -Wconversion \ | ||
| 42 | |||
| 43 | # -Wno-sign-conversion \ | ||
| 44 | |||
| 45 | CFLAGS_WARN_GCC_PPMD_UNALIGNED = \ | ||
| 46 | -Wno-strict-aliasing \ | ||
| 47 | |||
| 48 | |||
| 49 | CFLAGS_WARN = $(CFLAGS_WARN_GCC_9) \ | ||
| 50 | |||
| 51 | # $(CFLAGS_WARN_GCC_PPMD_UNALIGNED) | ||
