diff options
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) | ||