aboutsummaryrefslogtreecommitdiff
path: root/C
diff options
context:
space:
mode:
Diffstat (limited to 'C')
-rw-r--r--C/7z.h204
-rw-r--r--C/7zAlloc.c80
-rw-r--r--C/7zAlloc.h19
-rw-r--r--C/7zArcIn.c1783
-rw-r--r--C/7zBuf.c36
-rw-r--r--C/7zBuf.h35
-rw-r--r--C/7zBuf2.c52
-rw-r--r--C/7zCrc.c322
-rw-r--r--C/7zCrc.h25
-rw-r--r--C/7zCrcOpt.c117
-rw-r--r--C/7zDec.c600
-rw-r--r--C/7zFile.c442
-rw-r--r--C/7zFile.h91
-rw-r--r--C/7zStream.c176
-rw-r--r--C/7zTypes.h525
-rw-r--r--C/7zVersion.h27
-rw-r--r--C/7zVersion.rc55
-rw-r--r--C/7zip_gcc_c.mak313
-rw-r--r--C/Aes.c375
-rw-r--r--C/Aes.h60
-rw-r--r--C/AesOpt.c776
-rw-r--r--C/Alloc.c463
-rw-r--r--C/Alloc.h58
-rw-r--r--C/Bcj2.c257
-rw-r--r--C/Bcj2.h146
-rw-r--r--C/Bcj2Enc.c311
-rw-r--r--C/Blake2.h48
-rw-r--r--C/Blake2s.c244
-rw-r--r--C/Bra.c230
-rw-r--r--C/Bra.h64
-rw-r--r--C/Bra86.c82
-rw-r--r--C/BraIA64.c53
-rw-r--r--C/BwtSort.c515
-rw-r--r--C/BwtSort.h26
-rw-r--r--C/Compiler.h43
-rw-r--r--C/CpuArch.c478
-rw-r--r--C/CpuArch.h442
-rw-r--r--C/Delta.c169
-rw-r--r--C/Delta.h19
-rw-r--r--C/DllSecur.c110
-rw-r--r--C/DllSecur.h20
-rw-r--r--C/HuffEnc.c148
-rw-r--r--C/HuffEnc.h23
-rw-r--r--C/LzFind.c1628
-rw-r--r--C/LzFind.h136
-rw-r--r--C/LzFindMt.c1400
-rw-r--r--C/LzFindMt.h109
-rw-r--r--C/LzFindOpt.c578
-rw-r--r--C/LzHash.h34
-rw-r--r--C/Lzma2Dec.c489
-rw-r--r--C/Lzma2Dec.h120
-rw-r--r--C/Lzma2DecMt.c1090
-rw-r--r--C/Lzma2DecMt.h79
-rw-r--r--C/Lzma2Enc.c803
-rw-r--r--C/Lzma2Enc.h55
-rw-r--r--C/Lzma86.h111
-rw-r--r--C/Lzma86Dec.c54
-rw-r--r--C/Lzma86Enc.c104
-rw-r--r--C/LzmaDec.c1363
-rw-r--r--C/LzmaDec.h236
-rw-r--r--C/LzmaEnc.c3165
-rw-r--r--C/LzmaEnc.h78
-rw-r--r--C/LzmaLib.c40
-rw-r--r--C/LzmaLib.h138
-rw-r--r--C/MtCoder.c595
-rw-r--r--C/MtCoder.h141
-rw-r--r--C/MtDec.c1139
-rw-r--r--C/MtDec.h202
-rw-r--r--C/Ppmd.h167
-rw-r--r--C/Ppmd7.c1104
-rw-r--r--C/Ppmd7.h181
-rw-r--r--C/Ppmd7Dec.c297
-rw-r--r--C/Ppmd7Enc.c323
-rw-r--r--C/Ppmd7aDec.c279
-rw-r--r--C/Ppmd8.c1537
-rw-r--r--C/Ppmd8.h181
-rw-r--r--C/Ppmd8Dec.c279
-rw-r--r--C/Ppmd8Enc.c314
-rw-r--r--C/Precomp.h10
-rw-r--r--C/RotateDefs.h30
-rw-r--r--C/Sha1.c473
-rw-r--r--C/Sha1.h76
-rw-r--r--C/Sha1Opt.c373
-rw-r--r--C/Sha256.c486
-rw-r--r--C/Sha256.h76
-rw-r--r--C/Sha256Opt.c373
-rw-r--r--C/Sort.c141
-rw-r--r--C/Sort.h18
-rw-r--r--C/Threads.c540
-rw-r--r--C/Threads.h232
-rw-r--r--C/Util/7z/7z.dsp241
-rw-r--r--C/Util/7z/7z.dsw29
-rw-r--r--C/Util/7z/7zMain.c887
-rw-r--r--C/Util/7z/Precomp.c4
-rw-r--r--C/Util/7z/Precomp.h10
-rw-r--r--C/Util/7z/makefile40
-rw-r--r--C/Util/7z/makefile.gcc34
-rw-r--r--C/Util/7zipInstall/7zip.icobin0 -> 1078 bytes
-rw-r--r--C/Util/7zipInstall/7zipInstall.c1666
-rw-r--r--C/Util/7zipInstall/7zipInstall.dsp240
-rw-r--r--C/Util/7zipInstall/7zipInstall.dsw29
-rw-r--r--C/Util/7zipInstall/7zipInstall.manifest18
-rw-r--r--C/Util/7zipInstall/Precomp.c4
-rw-r--r--C/Util/7zipInstall/Precomp.h11
-rw-r--r--C/Util/7zipInstall/makefile42
-rw-r--r--C/Util/7zipInstall/resource.h9
-rw-r--r--C/Util/7zipInstall/resource.rc47
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.c1183
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.dsp124
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.dsw29
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.icobin0 -> 1078 bytes
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.manifest18
-rw-r--r--C/Util/7zipUninstall/Precomp.c4
-rw-r--r--C/Util/7zipUninstall/Precomp.h11
-rw-r--r--C/Util/7zipUninstall/makefile18
-rw-r--r--C/Util/7zipUninstall/resource.h9
-rw-r--r--C/Util/7zipUninstall/resource.rc47
-rw-r--r--C/Util/Lzma/LzmaUtil.c286
-rw-r--r--C/Util/Lzma/LzmaUtil.dsp172
-rw-r--r--C/Util/Lzma/LzmaUtil.dsw29
-rw-r--r--C/Util/Lzma/makefile30
-rw-r--r--C/Util/Lzma/makefile.gcc21
-rw-r--r--C/Util/LzmaLib/LzmaLib.def4
-rw-r--r--C/Util/LzmaLib/LzmaLib.dsp182
-rw-r--r--C/Util/LzmaLib/LzmaLib.dsw29
-rw-r--r--C/Util/LzmaLib/LzmaLibExports.c14
-rw-r--r--C/Util/LzmaLib/makefile36
-rw-r--r--C/Util/LzmaLib/resource.rc3
-rw-r--r--C/Util/SfxSetup/Precomp.c4
-rw-r--r--C/Util/SfxSetup/Precomp.h10
-rw-r--r--C/Util/SfxSetup/SfxSetup.c640
-rw-r--r--C/Util/SfxSetup/SfxSetup.dsp231
-rw-r--r--C/Util/SfxSetup/SfxSetup.dsw29
-rw-r--r--C/Util/SfxSetup/makefile37
-rw-r--r--C/Util/SfxSetup/makefile_con38
-rw-r--r--C/Util/SfxSetup/resource.rc5
-rw-r--r--C/Util/SfxSetup/setup.icobin0 -> 1078 bytes
-rw-r--r--C/Xz.c90
-rw-r--r--C/Xz.h517
-rw-r--r--C/XzCrc64.c86
-rw-r--r--C/XzCrc64.h26
-rw-r--r--C/XzCrc64Opt.c71
-rw-r--r--C/XzDec.c2837
-rw-r--r--C/XzEnc.c1330
-rw-r--r--C/XzEnc.h60
-rw-r--r--C/XzIn.c325
-rw-r--r--C/var_clang.mak11
-rw-r--r--C/var_clang_arm64.mak11
-rw-r--r--C/var_clang_x64.mak11
-rw-r--r--C/var_clang_x86.mak11
-rw-r--r--C/var_gcc.mak12
-rw-r--r--C/var_gcc_arm64.mak12
-rw-r--r--C/var_gcc_x64.mak10
-rw-r--r--C/var_gcc_x86.mak10
-rw-r--r--C/var_mac_arm64.mak11
-rw-r--r--C/var_mac_x64.mak11
-rw-r--r--C/warn_clang.mak37
-rw-r--r--C/warn_clang_mac.mak37
-rw-r--r--C/warn_gcc.mak51
159 files changed, 43570 insertions, 0 deletions
diff --git a/C/7z.h b/C/7z.h
new file mode 100644
index 0000000..304f75f
--- /dev/null
+++ b/C/7z.h
@@ -0,0 +1,204 @@
1/* 7z.h -- 7z interface
22018-07-02 : Igor Pavlov : Public domain */
3
4#ifndef __7Z_H
5#define __7Z_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11#define k7zStartHeaderSize 0x20
12#define k7zSignatureSize 6
13
14extern const Byte k7zSignature[k7zSignatureSize];
15
16typedef struct
17{
18 const Byte *Data;
19 size_t Size;
20} CSzData;
21
22/* CSzCoderInfo & CSzFolder support only default methods */
23
24typedef struct
25{
26 size_t PropsOffset;
27 UInt32 MethodID;
28 Byte NumStreams;
29 Byte PropsSize;
30} CSzCoderInfo;
31
32typedef 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
42typedef 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
54SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd);
55
56typedef struct
57{
58 UInt32 Low;
59 UInt32 High;
60} CNtfsFileTime;
61
62typedef struct
63{
64 Byte *Defs; /* MSB 0 bit numbering */
65 UInt32 *Vals;
66} CSzBitUi32s;
67
68typedef 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
79typedef 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
98UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex);
99
100SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
101 ILookInStream *stream, UInt64 startPos,
102 Byte *outBuffer, size_t outSize,
103 ISzAllocPtr allocMain);
104
105typedef 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
135void SzArEx_Init(CSzArEx *p);
136void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc);
137UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
138int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
139
140/*
141if dest == NULL, the return value specifies the required size of the buffer,
142 in 16-bit characters, including the null-terminating character.
143if 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
146size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
147
148/*
149size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex);
150UInt16 *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
175SRes 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/*
189SzArEx_Open Errors:
190SZ_ERROR_NO_ARCHIVE
191SZ_ERROR_ARCHIVE
192SZ_ERROR_UNSUPPORTED
193SZ_ERROR_MEM
194SZ_ERROR_CRC
195SZ_ERROR_INPUT_EOF
196SZ_ERROR_FAIL
197*/
198
199SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream,
200 ISzAllocPtr allocMain, ISzAllocPtr allocTemp);
201
202EXTERN_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
22017-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>
20int g_allocCount = 0;
21int g_allocCountTemp = 0;
22
23#endif
24
25void *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
37void 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
50void *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
65void 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
22017-04-03 : Igor Pavlov : Public domain */
3
4#ifndef __7Z_ALLOC_H
5#define __7Z_ALLOC_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11void *SzAlloc(ISzAllocPtr p, size_t size);
12void SzFree(ISzAllocPtr p, void *address);
13
14void *SzAllocTemp(ISzAllocPtr p, size_t size);
15void SzFreeTemp(ISzAllocPtr p, void *address);
16
17EXTERN_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
22021-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
26enum 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
59const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
60
61#define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
62
63static 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
78static 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
86static 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
93static 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
112static 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
129void 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
152void 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
174static 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
195static 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
233static 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
258static 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
268static 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
282static 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
292static 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
310static 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
338static 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
359static 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
366static 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
385static 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/*
424static 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
434SRes 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
601static 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
636static 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
845UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex)
846{
847 return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]];
848}
849
850
851typedef struct
852{
853 UInt32 NumTotalSubStreams;
854 UInt32 NumSubDigests;
855 CSzData sdNumSubStreams;
856 CSzData sdSizes;
857 CSzData sdCRCs;
858} CSubStreamInfo;
859
860
861static 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
934static 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
978static 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
1020static 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
1049static 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
1100static 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
1479static 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
1509static 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
1637SRes 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
1647SRes 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
1724size_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/*
1739size_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
1757UInt16 *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
22017-04-03 : Igor Pavlov : Public domain */
3
4#include "Precomp.h"
5
6#include "7zBuf.h"
7
8void Buf_Init(CBuf *p)
9{
10 p->data = 0;
11 p->size = 0;
12}
13
14int 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
31void 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
22017-04-03 : Igor Pavlov : Public domain */
3
4#ifndef __7Z_BUF_H
5#define __7Z_BUF_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11typedef struct
12{
13 Byte *data;
14 size_t size;
15} CBuf;
16
17void Buf_Init(CBuf *p);
18int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc);
19void Buf_Free(CBuf *p, ISzAllocPtr alloc);
20
21typedef struct
22{
23 Byte *data;
24 size_t size;
25 size_t pos;
26} CDynBuf;
27
28void DynBuf_Construct(CDynBuf *p);
29void DynBuf_SeekToBeg(CDynBuf *p);
30int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc);
31void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc);
32
33EXTERN_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
22017-04-03 : Igor Pavlov : Public domain */
3
4#include "Precomp.h"
5
6#include <string.h>
7
8#include "7zBuf.h"
9
10void DynBuf_Construct(CDynBuf *p)
11{
12 p->data = 0;
13 p->size = 0;
14 p->pos = 0;
15}
16
17void DynBuf_SeekToBeg(CDynBuf *p)
18{
19 p->pos = 0;
20}
21
22int 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
46void 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
22021-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
27typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
28
29extern
30CRC_FUNC g_CrcUpdateT4;
31CRC_FUNC g_CrcUpdateT4;
32extern
33CRC_FUNC g_CrcUpdateT8;
34CRC_FUNC g_CrcUpdateT8;
35extern
36CRC_FUNC g_CrcUpdateT0_32;
37CRC_FUNC g_CrcUpdateT0_32;
38extern
39CRC_FUNC g_CrcUpdateT0_64;
40CRC_FUNC g_CrcUpdateT0_64;
41extern
42CRC_FUNC g_CrcUpdate;
43CRC_FUNC g_CrcUpdate;
44
45UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
46
47UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
48{
49 return g_CrcUpdate(v, data, size, g_CrcTable);
50}
51
52UInt32 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
59UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);
60UInt32 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
108MY_FORCE_INLINE
109UInt32 __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
116MY_FORCE_INLINE
117UInt32 __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
127MY_FORCE_INLINE
128UInt32 __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
158ATTRIB_CRC
159UInt32 MY_FAST_CALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table);
160ATTRIB_CRC
161UInt32 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
190ATTRIB_CRC
191UInt32 MY_FAST_CALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table);
192ATTRIB_CRC
193UInt32 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
229void 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
22013-01-18 : Igor Pavlov : Public domain */
3
4#ifndef __7Z_CRC_H
5#define __7Z_CRC_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11extern UInt32 g_CrcTable[];
12
13/* Call CrcGenerateTable one time before other CRC functions */
14void 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
20UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
21UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
22
23EXTERN_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
22021-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
12UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
13UInt32 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
32UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
33UInt32 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
68UInt32 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
89UInt32 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
22021-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
43typedef 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
55static 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
76static 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
141static 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
201static 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
260static 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
279static 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
296static 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
306static 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
379static 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
558SRes 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
22021-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
40void 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
53static 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
86WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
87
88WRes 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
102static 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}
111WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
112WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
113#endif
114
115WRes 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
155WRes 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
221WRes 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
283WRes 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
343WRes 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
390static 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
398void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
399{
400 p->vt.Read = FileSeqInStream_Read;
401}
402
403
404/* ---------- FileInStream ---------- */
405
406static 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
414static 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
422void FileInStream_CreateVTable(CFileInStream *p)
423{
424 p->vt.Read = FileInStream_Read;
425 p->vt.Seek = FileInStream_Seek;
426}
427
428
429/* ---------- FileOutStream ---------- */
430
431static 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
439void 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
22021-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
22EXTERN_C_BEGIN
23
24/* ---------- File ---------- */
25
26typedef 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
37void File_Construct(CSzFile *p);
38#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
39WRes InFile_Open(CSzFile *p, const char *name);
40WRes OutFile_Open(CSzFile *p, const char *name);
41#endif
42#ifdef USE_WINDOWS_FILE
43WRes InFile_OpenW(CSzFile *p, const WCHAR *name);
44WRes OutFile_OpenW(CSzFile *p, const WCHAR *name);
45#endif
46WRes File_Close(CSzFile *p);
47
48/* reads max(*size, remain file's size) bytes */
49WRes File_Read(CSzFile *p, void *data, size_t *size);
50
51/* writes *size bytes */
52WRes File_Write(CSzFile *p, const void *data, size_t *size);
53
54WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);
55WRes File_GetLength(CSzFile *p, UInt64 *length);
56
57
58/* ---------- FileInStream ---------- */
59
60typedef struct
61{
62 ISeqInStream vt;
63 CSzFile file;
64 WRes wres;
65} CFileSeqInStream;
66
67void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
68
69
70typedef struct
71{
72 ISeekInStream vt;
73 CSzFile file;
74 WRes wres;
75} CFileInStream;
76
77void FileInStream_CreateVTable(CFileInStream *p);
78
79
80typedef struct
81{
82 ISeqOutStream vt;
83 CSzFile file;
84 WRes wres;
85} CFileOutStream;
86
87void FileOutStream_CreateVTable(CFileOutStream *p);
88
89EXTERN_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
22021-02-09 : Igor Pavlov : Public domain */
3
4#include "Precomp.h"
5
6#include <string.h>
7
8#include "7zTypes.h"
9
10SRes 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
24SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size)
25{
26 return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
27}
28
29SRes 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
38SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset)
39{
40 Int64 t = (Int64)offset;
41 return ILookInStream_Seek(stream, &t, SZ_SEEK_SET);
42}
43
44SRes 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
54SRes 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
68SRes 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
77static 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
96static 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
116static SRes LookToRead2_Skip(const ILookInStream *pp, size_t offset)
117{
118 GET_LookToRead2
119 p->pos += offset;
120 return SZ_OK;
121}
122
123static 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
137static 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
144void 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
156static 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
162void SecToLook_CreateVTable(CSecToLook *p)
163{
164 p->vt.Read = SecToLook_Read;
165}
166
167static 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
173void 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
22021-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
25EXTERN_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
45typedef 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; */
62typedef 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
70typedef 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
137typedef long INT_PTR;
138typedef 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
170typedef unsigned char Byte;
171typedef short Int16;
172typedef unsigned short UInt16;
173
174#ifdef _LZMA_UINT32_IS_ULONG
175typedef long Int32;
176typedef unsigned long UInt32;
177#else
178typedef int Int32;
179typedef unsigned int UInt32;
180#endif
181
182
183#ifndef _WIN32
184
185typedef int INT;
186typedef Int32 INT32;
187typedef unsigned int UINT;
188typedef UInt32 UINT32;
189typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit for _WIN32 compatibility
190typedef UINT32 ULONG;
191
192#undef DWORD
193typedef UINT32 DWORD;
194
195#define VOID void
196
197#define HRESULT LONG
198
199typedef 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)
203typedef long INT_PTR;
204typedef unsigned long UINT_PTR;
205typedef long LONG_PTR;
206typedef unsigned long DWORD_PTR;
207
208typedef 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
221typedef long Int64;
222typedef unsigned long UInt64;
223
224#else
225
226#if defined(_MSC_VER) || defined(__BORLANDC__)
227typedef __int64 Int64;
228typedef unsigned __int64 UInt64;
229#define UINT64_CONST(n) n
230#else
231typedef long long int Int64;
232typedef 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
239typedef UInt32 SizeT;
240#else
241typedef size_t SizeT;
242#endif
243
244typedef 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
303typedef struct IByteIn IByteIn;
304struct 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
311typedef struct IByteOut IByteOut;
312struct IByteOut
313{
314 void (*Write)(const IByteOut *p, Byte b);
315};
316#define IByteOut_Write(p, b) (p)->Write(p, b)
317
318
319typedef struct ISeqInStream ISeqInStream;
320struct 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 */
329SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size);
330SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType);
331SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf);
332
333
334typedef struct ISeqOutStream ISeqOutStream;
335struct 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
343typedef enum
344{
345 SZ_SEEK_SET = 0,
346 SZ_SEEK_CUR = 1,
347 SZ_SEEK_END = 2
348} ESzSeek;
349
350
351typedef struct ISeekInStream ISeekInStream;
352struct 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
361typedef struct ILookInStream ILookInStream;
362struct 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
382SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size);
383SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset);
384
385/* reads via ILookInStream::Read */
386SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType);
387SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size);
388
389
390
391typedef 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
404void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead);
405
406#define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; }
407
408
409typedef struct
410{
411 ISeqInStream vt;
412 const ILookInStream *realStream;
413} CSecToLook;
414
415void SecToLook_CreateVTable(CSecToLook *p);
416
417
418
419typedef struct
420{
421 ISeqInStream vt;
422 const ILookInStream *realStream;
423} CSecToRead;
424
425void SecToRead_CreateVTable(CSecToRead *p);
426
427
428typedef struct ICompressProgress ICompressProgress;
429
430struct 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
440typedef struct ISzAlloc ISzAlloc;
441typedef const ISzAlloc * ISzAllocPtr;
442
443struct 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
523EXTERN_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) \
23LANGUAGE 9, 1 \
241 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 \
32BEGIN \
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 \
51END
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
2MY_ARCH_2 = $(MY_ARCH)
3
4MY_ASM = jwasm
5MY_ASM = asmc
6
7PROGPATH = $(O)/$(PROG)
8PROGPATH_STATIC = $(O)/$(PROG)s
9
10
11# for object file
12CFLAGS_BASE_LIST = -c
13# for ASM file
14# CFLAGS_BASE_LIST = -S
15CFLAGS_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
19LDFLAGS_STATIC = -DNDEBUG
20# -static
21
22ifdef SystemDrive
23IS_MINGW = 1
24endif
25
26ifdef DEF_FILE
27
28
29ifdef IS_MINGW
30SHARED_EXT=.dll
31LDFLAGS = -shared -DEF $(DEF_FILE) $(LDFLAGS_STATIC)
32else
33SHARED_EXT=.so
34LDFLAGS = -shared -fPIC $(LDFLAGS_STATIC)
35CC_SHARED=-fPIC
36endif
37
38
39else
40
41LDFLAGS = $(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
47ifdef IS_MINGW
48SHARED_EXT=.exe
49else
50SHARED_EXT=
51endif
52
53endif
54
55
56PROGPATH = $(O)/$(PROG)$(SHARED_EXT)
57PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT)
58
59ifndef O
60O=_o
61endif
62
63ifdef IS_MINGW
64
65RM = del
66MY_MKDIR=mkdir
67LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32
68
69
70CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE
71# -Wno-delete-non-virtual-dtor
72
73DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
74
75else
76
77RM = rm -f
78MY_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
84LIB2 = -lpthread -ldl
85
86DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
87
88endif
89
90
91
92CFLAGS = $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(CC_SHARED) -o $@
93
94
95ifdef IS_X64
96AFLAGS_ABI = -elf64 -DABI_LINUX
97else
98AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL
99# -DABI_CDECL
100# -DABI_LINUX
101# -DABI_CDECL
102endif
103AFLAGS = $(AFLAGS_ABI) -Fo$(O)/
104
105
106CXX_WARN_FLAGS =
107#-Wno-invalid-offsetof
108#-Wno-reorder
109
110CXXFLAGS = $(LOCAL_FLAGS) $(CXXFLAGS_BASE2) $(CFLAGS_BASE) $(CXXFLAGS_EXTRA) $(CC_SHARED) -o $@ $(CXX_WARN_FLAGS)
111
112STATIC_TARGET=
113ifdef COMPL_STATIC
114STATIC_TARGET=$(PROGPATH_STATIC)
115endif
116
117
118all: $(O) $(PROGPATH) $(STATIC_TARGET)
119
120$(O):
121 $(MY_MKDIR) $(O)
122
123LFLAGS_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
131ifndef NO_DEFAULT_RES
132$O/resource.o: resource.rc
133 windres.exe $(RFLAGS) resource.rc $O/resource.o
134endif
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
238ifdef USE_ASM
239ifdef IS_X64
240USE_X86_ASM=1
241else
242ifdef IS_X86
243USE_X86_ASM=1
244endif
245endif
246endif
247
248ifdef 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) $<
259else
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) $<
270endif
271
272
273ifdef USE_LZMA_DEC_ASM
274
275ifdef IS_X64
276$O/LzmaDecOpt.o: ../../../Asm/x86/LzmaDecOpt.asm
277 $(MY_ASM) $(AFLAGS) $<
278endif
279
280ifdef IS_ARM64
281$O/LzmaDecOpt.o: ../../../Asm/arm64/LzmaDecOpt.S ../../../Asm/arm64/7zAsm.S
282 $(CC) $(CFLAGS) $<
283endif
284
285$O/LzmaDec.o: ../../LzmaDec.c
286 $(CC) $(CFLAGS) -D_LZMA_DEC_OPT $<
287
288else
289
290$O/LzmaDec.o: ../../LzmaDec.c
291 $(CC) $(CFLAGS) $<
292
293endif
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
312clean:
313 -$(DEL_OBJ_EXE)
diff --git a/C/Aes.c b/C/Aes.c
new file mode 100644
index 0000000..27e32e6
--- /dev/null
+++ b/C/Aes.c
@@ -0,0 +1,375 @@
1/* Aes.c -- AES encryption / decryption
22021-05-13 : Igor Pavlov : Public domain */
3
4#include "Precomp.h"
5
6#include "CpuArch.h"
7#include "Aes.h"
8
9AES_CODE_FUNC g_AesCbc_Decode;
10#ifndef _SFX
11AES_CODE_FUNC g_AesCbc_Encode;
12AES_CODE_FUNC g_AesCtr_Code;
13UInt32 g_Aes_SupportedFunctions_Flags;
14#endif
15
16static UInt32 T[256 * 4];
17static 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
36static UInt32 D[256 * 4];
37static 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
84void 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
197void 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
233void 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
255static 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
278MY_FORCE_INLINE
279static 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
300void 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
307void 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
325void 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
349void 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}
diff --git a/C/Aes.h b/C/Aes.h
new file mode 100644
index 0000000..2aa2256
--- /dev/null
+++ b/C/Aes.h
@@ -0,0 +1,60 @@
1/* Aes.h -- AES encryption / decryption
22018-04-28 : Igor Pavlov : Public domain */
3
4#ifndef __AES_H
5#define __AES_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11#define AES_BLOCK_SIZE 16
12
13/* Call AesGenTables one time before other AES functions */
14void 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) */
23typedef void (MY_FAST_CALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize);
24void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize);
25void 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] */
28void 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 */
32typedef void (MY_FAST_CALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks);
33
34extern AES_CODE_FUNC g_AesCbc_Decode;
35#ifndef _SFX
36extern AES_CODE_FUNC g_AesCbc_Encode;
37extern AES_CODE_FUNC g_AesCtr_Code;
38#define k_Aes_SupportedFunctions_HW (1 << 2)
39#define k_Aes_SupportedFunctions_HW_256 (1 << 3)
40extern 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
47DECLARE__AES_CODE_FUNC (AesCbc_Encode)
48DECLARE__AES_CODE_FUNC (AesCbc_Decode)
49DECLARE__AES_CODE_FUNC (AesCtr_Code)
50
51DECLARE__AES_CODE_FUNC (AesCbc_Encode_HW)
52DECLARE__AES_CODE_FUNC (AesCbc_Decode_HW)
53DECLARE__AES_CODE_FUNC (AesCtr_Code_HW)
54
55DECLARE__AES_CODE_FUNC (AesCbc_Decode_HW_256)
56DECLARE__AES_CODE_FUNC (AesCtr_Code_HW_256)
57
58EXTERN_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
22021-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) \
67AES_FUNC_START (name); \
68ATTRIB_AES \
69AES_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
78AES_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
219AES_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
272AES_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) \
341AES_FUNC_START (name); \
342ATTRIB_VAES \
343AES_FUNC_START (name)
344
345VAES_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/*
399SSE2: _mm_cvtsi32_si128 : movd
400AVX: _mm256_setr_m128i : vinsertf128
401AVX2: _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
416VAES_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
487AES_COMPAT_STUB (AesCbc_Encode)
488AES_COMPAT_STUB (AesCbc_Decode)
489AES_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
503VAES_COMPAT_STUB (AesCbc_Decode_HW)
504VAES_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
551typedef 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) \
557AES_FUNC_START (name); \
558ATTRIB_AES \
559AES_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
572AES_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
673AES_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
725AES_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
22021-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>
21int g_allocCount = 0;
22int g_allocCountMid = 0;
23int 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
33static 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
40static 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
62static void Print(const char *s)
63{
64 fputs(s, DEBUG_OUT_STREAM);
65}
66
67static 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
80static void PrintLn()
81{
82 Print("\n");
83}
84
85static void PrintHex(UInt64 v, size_t align)
86{
87 char s[32];
88 ConvertUInt64ToHex(v, s);
89 PrintAligned(s, align);
90}
91
92static void PrintDec(UInt64 v, size_t align)
93{
94 char s[32];
95 ConvertUInt64ToString(v, s);
96 PrintAligned(s, align);
97}
98
99static 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
131void *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
147void MyFree(void *address)
148{
149 PRINT_FREE("Free ", g_allocCount, address);
150
151 free(address);
152}
153
154#ifdef _WIN32
155
156void *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
166void 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
183extern
184SIZE_T g_LargePageSize;
185SIZE_T g_LargePageSize = 0;
186typedef SIZE_T (WINAPI *GetLargePageMinimumP)(VOID);
187
188#endif // _7ZIP_LARGE_PAGES
189
190void 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
206void *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
234void 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
246static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); }
247static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MyFree(address); }
248const ISzAlloc g_Alloc = { SzAlloc, SzFree };
249
250#ifdef _WIN32
251static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MidAlloc(size); }
252static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MidFree(address); }
253static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); }
254static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); BigFree(address); }
255const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
256const 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/*
305static 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
330static 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
378static 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
390const 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
402static 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
446static 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
459void 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
22021-07-13 : Igor Pavlov : Public domain */
3
4#ifndef __COMMON_ALLOC_H
5#define __COMMON_ALLOC_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11void *MyAlloc(size_t size);
12void MyFree(void *address);
13
14#ifdef _WIN32
15
16void SetLargePageSize(void);
17
18void *MidAlloc(size_t size);
19void MidFree(void *address);
20void *BigAlloc(size_t size);
21void 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
32extern const ISzAlloc g_Alloc;
33
34#ifdef _WIN32
35extern const ISzAlloc g_BigAlloc;
36extern const ISzAlloc g_MidAlloc;
37#else
38#define g_BigAlloc g_AlignedAlloc
39#define g_MidAlloc g_AlignedAlloc
40#endif
41
42extern const ISzAlloc g_AlignedAlloc;
43
44
45typedef 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
53void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p);
54
55
56EXTERN_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)
22021-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
20void 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
33SRes 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
22014-11-10 : Igor Pavlov : Public domain */
3
4#ifndef __BCJ2_H
5#define __BCJ2_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11#define BCJ2_NUM_STREAMS 4
12
13enum
14{
15 BCJ2_STREAM_MAIN,
16 BCJ2_STREAM_CALL,
17 BCJ2_STREAM_JUMP,
18 BCJ2_STREAM_RC
19};
20
21enum
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
32enum
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/*
42CBcj2Dec / CBcj2Enc
43bufs sizes:
44 BUF_SIZE(n) = lims[n] - bufs[n]
45bufs 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/*
51CBcj2Dec:
52dest 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
62typedef 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
78void Bcj2Dec_Init(CBcj2Dec *p);
79
80/* Returns: SZ_OK or SZ_ERROR_DATA */
81SRes Bcj2Dec_Decode(CBcj2Dec *p);
82
83#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0)
84
85
86
87typedef 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
94typedef 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
131void Bcj2Enc_Init(CBcj2Enc *p);
132void 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
144EXTERN_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)
22021-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
27void 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
55static 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
80static 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
243void 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
22015-06-30 : Igor Pavlov : Public domain
32015 : Samuel Neves : Public domain */
4
5#ifndef __BLAKE2_H
6#define __BLAKE2_H
7
8#include "7zTypes.h"
9
10EXTERN_C_BEGIN
11
12#define BLAKE2S_BLOCK_SIZE 64
13#define BLAKE2S_DIGEST_SIZE 32
14#define BLAKE2SP_PARALLEL_DEGREE 8
15
16typedef 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/*
29void Blake2s_Init0(CBlake2s *p);
30void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size);
31void Blake2s_Final(CBlake2s *p, Byte *digest);
32*/
33
34
35typedef struct
36{
37 CBlake2s S[BLAKE2SP_PARALLEL_DEGREE];
38 unsigned bufPos;
39} CBlake2sp;
40
41
42void Blake2sp_Init(CBlake2sp *p);
43void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size);
44void Blake2sp_Final(CBlake2sp *p, Byte *digest);
45
46EXTERN_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
22021-02-09 : Igor Pavlov : Public domain
32015 : 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
16static const UInt32 k_Blake2s_IV[8] =
17{
18 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
19 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
20};
21
22static 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
37static 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
51static 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
118static 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
142static 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/*
160typedef 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
176static 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
196void 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
209void 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
228void 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}
diff --git a/C/Bra.c b/C/Bra.c
new file mode 100644
index 0000000..3b854d9
--- /dev/null
+++ b/C/Bra.c
@@ -0,0 +1,230 @@
1/* Bra.c -- Converters for RISC code
22021-02-09 : Igor Pavlov : Public domain */
3
4#include "Precomp.h"
5
6#include "CpuArch.h"
7#include "Bra.h"
8
9SizeT 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
64SizeT 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
151SizeT 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
185SizeT 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}
diff --git a/C/Bra.h b/C/Bra.h
new file mode 100644
index 0000000..855e37a
--- /dev/null
+++ b/C/Bra.h
@@ -0,0 +1,64 @@
1/* Bra.h -- Branch converters for executables
22013-01-18 : Igor Pavlov : Public domain */
3
4#ifndef __BRA_H
5#define __BRA_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11/*
12These functions convert relative addresses to absolute addresses
13in 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; }
55SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
56SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
57SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
58SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
59SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
60SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
61
62EXTERN_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)
22021-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
10SizeT 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
22017-01-26 : Igor Pavlov : Public domain */
3
4#include "Precomp.h"
5
6#include "CpuArch.h"
7#include "Bra.h"
8
9SizeT 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
22021-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
43static 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/*
58SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks
59 "range" is not real range. It's only for optimization.
60returns: 1 - if there are groups, 0 - no more groups
61*/
62
63static 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 */
352UInt32 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
22013-01-18 : Igor Pavlov : Public domain */
3
4#ifndef __BWT_SORT_H
5#define __BWT_SORT_H
6
7#include "7zTypes.h"
8
9EXTERN_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
22UInt32 BlockSort(UInt32 *indices, const Byte *data, UInt32 blockSize);
23
24EXTERN_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
22021-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
22021-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)
19static 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
79static
80MY_NO_INLINE
81void 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
99void 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
161BoolInt 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
169static const UInt32 kVendors[][3] =
170{
171 { 0x756E6547, 0x49656E69, 0x6C65746E},
172 { 0x68747541, 0x69746E65, 0x444D4163},
173 { 0x746E6543, 0x48727561, 0x736C7561}
174};
175
176int 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
190BoolInt 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>
221static 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
235static 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
244BoolInt CPU_IsSupported_AES()
245{
246 return (X86_CPUID_ECX_Get_Flags() >> 25) & 1;
247}
248
249BoolInt CPU_IsSupported_SSSE3()
250{
251 return (X86_CPUID_ECX_Get_Flags() >> 9) & 1;
252}
253
254BoolInt CPU_IsSupported_SSE41()
255{
256 return (X86_CPUID_ECX_Get_Flags() >> 19) & 1;
257}
258
259BoolInt 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
281BoolInt 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
305BoolInt 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
331BoolInt 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
356BoolInt CPU_IsSupported_CRC32() { return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
357BoolInt CPU_IsSupported_CRYPTO() { return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
358BoolInt 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>
367static 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
382static 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
395BoolInt CPU_IsSupported_CRC32(void)
396{
397 return My_sysctlbyname_Get_BoolInt("hw.optional.armv8_crc32");
398}
399
400BoolInt 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
411BoolInt CPU_IsSupported_SHA1(void) { return APPLE_CRYPTO_SUPPORT_VAL; }
412BoolInt CPU_IsSupported_SHA2(void) { return APPLE_CRYPTO_SUPPORT_VAL; }
413BoolInt 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
448MY_HWCAP_CHECK_FUNC (CRC32)
449MY_HWCAP_CHECK_FUNC (SHA1)
450MY_HWCAP_CHECK_FUNC (SHA2)
451MY_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
464int My_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize)
465{
466 return sysctlbyname(name, buf, bufSize, NULL, 0);
467}
468
469int 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
22021-07-13 : Igor Pavlov : Public domain */
3
4#ifndef __CPU_ARCH_H
5#define __CPU_ARCH_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11/*
12MY_CPU_LE means that CPU is LITTLE ENDIAN.
13MY_CPU_BE means that CPU is BIG ENDIAN.
14If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
15
16MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
17
18MY_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
381typedef struct
382{
383 UInt32 maxFunc;
384 UInt32 vendor[3];
385 UInt32 ver;
386 UInt32 b;
387 UInt32 c;
388 UInt32 d;
389} Cx86cpuid;
390
391enum
392{
393 CPU_FIRM_INTEL,
394 CPU_FIRM_AMD,
395 CPU_FIRM_VIA
396};
397
398void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
399
400BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p);
401int 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
407BoolInt CPU_Is_InOrder(void);
408
409BoolInt CPU_IsSupported_AES(void);
410BoolInt CPU_IsSupported_AVX2(void);
411BoolInt CPU_IsSupported_VAES_AVX2(void);
412BoolInt CPU_IsSupported_SSSE3(void);
413BoolInt CPU_IsSupported_SSE41(void);
414BoolInt CPU_IsSupported_SHA(void);
415BoolInt CPU_IsSupported_PageGB(void);
416
417#elif defined(MY_CPU_ARM_OR_ARM64)
418
419BoolInt CPU_IsSupported_CRC32(void);
420BoolInt CPU_IsSupported_NEON(void);
421
422#if defined(_WIN32)
423BoolInt 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
428BoolInt CPU_IsSupported_SHA1(void);
429BoolInt CPU_IsSupported_SHA2(void);
430BoolInt CPU_IsSupported_AES(void);
431#endif
432
433#endif
434
435#if defined(__APPLE__)
436int My_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize);
437int My_sysctlbyname_Get_UInt32(const char *name, UInt32 *val);
438#endif
439
440EXTERN_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
22021-02-09 : Igor Pavlov : Public domain */
3
4#include "Precomp.h"
5
6#include "Delta.h"
7
8void Delta_Init(Byte *state)
9{
10 unsigned i;
11 for (i = 0; i < DELTA_STATE_SIZE; i++)
12 state[i] = 0;
13}
14
15
16void 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
89void 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
22013-01-18 : Igor Pavlov : Public domain */
3
4#ifndef __DELTA_H
5#define __DELTA_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11#define DELTA_STATE_SIZE 256
12
13void Delta_Init(Byte *state);
14void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
15void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
16
17EXTERN_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
22021-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
14typedef 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
19static 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
39void 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
58void 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
22018-02-19 : Igor Pavlov : Public domain */
3
4#ifndef __DLL_SECUR_H
5#define __DLL_SECUR_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11#ifdef _WIN32
12
13void My_SetDefaultDllDirectories(void);
14void LoadSecurityDlls(void);
15
16#endif
17
18EXTERN_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
22021-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
17void 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
22013-01-18 : Igor Pavlov : Public domain */
3
4#ifndef __HUFF_ENC_H
5#define __HUFF_ENC_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11/*
12Conditions:
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
19void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen);
20
21EXTERN_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
22021-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
68static 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
78static 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
111static const Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
112
113static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return GET_AVAIL_BYTES(p); }
114
115
116MY_NO_INLINE
117static 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
176MY_NO_INLINE
177void 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
195int 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
204void MatchFinder_ReadIfRequired(CMatchFinder *p)
205{
206 if (p->keepSizeAfter >= GET_AVAIL_BYTES(p))
207 MatchFinder_ReadBlock(p);
208}
209
210
211
212static 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
222void 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
241static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc)
242{
243 ISzAlloc_Free(alloc, p->hash);
244 p->hash = NULL;
245}
246
247void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc)
248{
249 MatchFinder_FreeThisClassMemory(p, alloc);
250 LzInWindow_Free(p, alloc);
251}
252
253static 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
267static 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
301int 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
412static 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
451void 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
461void 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
471void 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
491void 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
580typedef 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
589typedef __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
598MY_NO_INLINE
599static
600#ifdef ATTRIB_SSE41
601ATTRIB_SSE41
602#endif
603void
604MY_FAST_CALL
605LzFind_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
632MY_NO_INLINE
633static
634#ifdef ATTRIB_AVX2
635ATTRIB_AVX2
636#endif
637void
638MY_FAST_CALL
639LzFind_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
655typedef void (MY_FAST_CALL *LZFIND_SATUR_SUB_CODE_FUNC)(
656 UInt32 subValue, CLzRef *items, const CLzRef *lim);
657static 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
675MY_NO_INLINE
676static
677void
678MY_FAST_CALL
679LzFind_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
700MY_NO_INLINE
701void 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
743MY_NO_INLINE
744static 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*/
788MY_FORCE_INLINE
789static 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
870MY_FORCE_INLINE
871UInt32 * 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
941static 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
1007MY_NO_INLINE
1008static 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
1052static 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
1061UInt32* 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
1077static 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
1118static 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
1186static 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
1258static 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
1326static 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
1398UInt32* 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
1408static 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
1419void 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
1430static 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
1445static 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
1461static 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
1508static 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
1523static 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
1539void 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
1551void 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
1593void 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
22021-07-13 : Igor Pavlov : Public domain */
3
4#ifndef __LZ_FIND_H
5#define __LZ_FIND_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11typedef UInt32 CLzRef;
12
13typedef 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
65int MatchFinder_NeedMove(CMatchFinder *p);
66/* Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */
67void MatchFinder_MoveBlock(CMatchFinder *p);
68void MatchFinder_ReadIfRequired(CMatchFinder *p);
69
70void MatchFinder_Construct(CMatchFinder *p);
71
72/* Conditions:
73 historySize <= 3 GB
74 keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
75*/
76int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
77 UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
78 ISzAllocPtr alloc);
79void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
80void 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
94UInt32 * 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/*
99Conditions:
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
104typedef void (*Mf_Init_Func)(void *object);
105typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
106typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
107typedef UInt32 * (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
108typedef void (*Mf_Skip_Func)(void *object, UInt32);
109
110typedef 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
119void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable);
120
121void MatchFinder_Init_LowHash(CMatchFinder *p);
122void MatchFinder_Init_HighHash(CMatchFinder *p);
123void MatchFinder_Init_4(CMatchFinder *p);
124void MatchFinder_Init(CMatchFinder *p);
125
126UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
127UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
128
129void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
130void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
131
132void LzFindPrepare(void);
133
134EXTERN_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
22021-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>
26extern UInt64 g_NumIters_Tree;
27extern UInt64 g_NumIters_Loop;
28extern 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
82MY_NO_INLINE
83static 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
119MY_NO_INLINE
120static 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
150MY_NO_INLINE
151static 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
188MY_NO_INLINE
189static 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):
227MY_NO_INLINE
228static 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
241static 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
273MY_NO_INLINE
274static 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
313DEF_GetHeads2(2, GetUi16(p), UNUSED_VAR(hashMask); UNUSED_VAR(crc); )
314DEF_GetHeads(3, (crc[p[0]] ^ GetUi16(p + 1)) & hashMask)
315DEF_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/*
319GetHeads_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/*
350GetHeads_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
368GetHeads_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
385GetHeads_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
396GetHeads_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
414GetHeads_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
432DEF_GetHeads(4, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (UInt32)GetUi16(p+1)) & hashMask)
433DEF_GetHeads(4b, (crc[p[0]] ^ GetUi24hi_from32(p)) & hashMask)
434DEF_GetHeads(5, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (crc[p[4]] << kLzHash_CrcShift_2) ^ (UInt32)GetUi16(p + 1)) & hashMask)
435DEF_GetHeads(5b, (crc[p[0]] ^ (crc[p[4]] << kLzHash_CrcShift_1) ^ GetUi24hi_from32(p)) & hashMask)
436
437#endif
438
439
440static 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
563UInt32 * 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
571static 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
732static 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
752MY_NO_INLINE
753static 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
789void MatchFinderMt_Construct(CMatchFinderMt *p)
790{
791 p->hashBuf = NULL;
792 MtSync_Construct(&p->hashSync);
793 MtSync_Construct(&p->btSync);
794}
795
796static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAllocPtr alloc)
797{
798 ISzAlloc_Free(alloc, p->hashBuf);
799 p->hashBuf = NULL;
800}
801
802void 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
835static THREAD_FUNC_DECL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
836static 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
848SRes 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
873SRes MatchFinderMt_InitMt(CMatchFinderMt *p)
874{
875 RINOK(MtSync_Init(&p->hashSync, kMtHashNumBlocks));
876 return MtSync_Init(&p->btSync, kMtBtNumBlocks);
877}
878
879
880static 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 */
935void 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
944MY_NO_INLINE
945static 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
984static 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
993static 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
1004static 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
1028static 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/*
1075static
1076UInt32* 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
1166static 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
1247static 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
1271static 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
1319static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
1320{
1321 SKIP_HEADER2_MT { p->btNumAvailBytes--;
1322 SKIP_FOOTER_MT
1323}
1324
1325static 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
1334static 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
1349static 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
1363void 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
22021-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
10EXTERN_C_BEGIN
11
12typedef 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
34typedef 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
39typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos,
40 UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc);
41
42typedef 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
96void MatchFinderMt_Construct(CMatchFinderMt *p);
97void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc);
98
99SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
100 UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc);
101void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable);
102
103/* call MatchFinderMt_InitMt() before IMatchFinder::Init() */
104SRes MatchFinderMt_InitMt(CMatchFinderMt *p);
105void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
106
107EXTERN_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
22021-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>
24UInt64 g_NumIters_Tree;
25UInt64 g_NumIters_Loop;
26UInt64 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/*
44MY_NO_INLINE
45UInt32 * 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 }
67else
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
217UInt32 * 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
222MY_NO_INLINE
223UInt32 * 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 }
263else
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/*
405typedef UInt32 uint32plus; // size_t
406
407UInt32 * 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 }
445else
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
22019-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
22021-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/*
1700000000 - End of data
1800000001 U U - Uncompressed, reset dic, need reset state and set new prop
1900000010 U U - Uncompressed, no reset
20100uuuuu U U P P - LZMA, no reset
21101uuuuu U U P P - LZMA, reset state
22110uuuuu U U P P S - LZMA, reset state + set new prop
23111uuuuu 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
43typedef 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
57static 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
71SRes 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
78SRes 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
85void 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
97static 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
164static 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
173void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState);
174
175
176SRes 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
307ELzma2ParseStatus 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
428SRes 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
469SRes 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
22018-02-19 : Igor Pavlov : Public domain */
3
4#ifndef __LZMA2_DEC_H
5#define __LZMA2_DEC_H
6
7#include "LzmaDec.h"
8
9EXTERN_C_BEGIN
10
11/* ---------- State Interface ---------- */
12
13typedef 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
29SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc);
30SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc);
31void Lzma2Dec_Init(CLzma2Dec *p);
32
33/*
34finishMode:
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
39Returns:
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
48SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
49 const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
50
51SRes 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/*
58Lzma2Dec_Parse() parses compressed data stream up to next independent block or next chunk data.
59It 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
65typedef 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
78ELzma2ParseStatus 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/*
85LZMA2 parser doesn't decode LZMA chunks, so we must read
86 full input LZMA chunk to decode some part of LZMA chunk.
87
88Lzma2Dec_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/*
99finishMode:
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
104Returns:
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
115SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
116 Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc);
117
118EXTERN_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
22021-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
36void 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
55typedef 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
84typedef 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
125CLzma2DecMtHandle 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
165static 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
183static 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
199void 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
236static 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
415static 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
455static 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
528static 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
610static 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
636static 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
801SRes 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
983SRes 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
1018SRes 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
22018-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
9EXTERN_C_BEGIN
10
11typedef 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 */
25void Lzma2DecMtProps_Init(CLzma2DecMtProps *p);
26
27
28/* ---------- CLzma2DecMtHandle Interface ---------- */
29
30/* Lzma2DecMt_ * functions can return the following exit codes:
31SRes:
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
41typedef void * CLzma2DecMtHandle;
42
43CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid);
44void Lzma2DecMt_Destroy(CLzma2DecMtHandle p);
45
46SRes 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
66SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp,
67 Byte prop,
68 const CLzma2DecMtProps *props,
69 const UInt64 *outDataSize, int finishMode,
70 ISeqInStream *inStream);
71
72SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp,
73 Byte *data, size_t *outSize,
74 UInt64 *inStreamProcessed);
75
76
77EXTERN_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
22021-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
40typedef struct
41{
42 ISeqInStream vt;
43 ISeqInStream *realStream;
44 UInt64 limit;
45 UInt64 processed;
46 int finished;
47} CLimitedSeqInStream;
48
49static void LimitedSeqInStream_Init(CLimitedSeqInStream *p)
50{
51 p->limit = (UInt64)(Int64)-1;
52 p->processed = 0;
53 p->finished = 0;
54}
55
56static 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
81typedef struct
82{
83 CLzmaEncHandle enc;
84 Byte propsAreSet;
85 Byte propsByte;
86 Byte needInitState;
87 Byte needInitProp;
88 UInt64 srcPos;
89} CLzma2EncInt;
90
91
92static 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
106static void Lzma2EncInt_InitBlock(CLzma2EncInt *p)
107{
108 p->srcPos = 0;
109 p->needInitState = True;
110 p->needInitProp = True;
111}
112
113
114SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize,
115 ISzAllocPtr alloc, ISzAllocPtr allocBig);
116SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
117 UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig);
118SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,
119 Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize);
120const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp);
121void LzmaEnc_Finish(CLzmaEncHandle pp);
122void LzmaEnc_SaveState(CLzmaEncHandle pp);
123void LzmaEnc_RestoreState(CLzmaEncHandle pp);
124
125/*
126UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp);
127*/
128
129static 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
231void 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
240void 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
347static 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
355typedef 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
386CLzma2EncHandle 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
419static 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
434void 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
465SRes 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
478void Lzma2Enc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize)
479{
480 CLzma2Enc *p = (CLzma2Enc *)pp;
481 p->expectedDataSize = expectedDataSiize;
482}
483
484
485Byte 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
497static 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
657static 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
695static 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
716SRes 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
22017-07-27 : Igor Pavlov : Public domain */
3
4#ifndef __LZMA2_ENC_H
5#define __LZMA2_ENC_H
6
7#include "LzmaEnc.h"
8
9EXTERN_C_BEGIN
10
11#define LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO 0
12#define LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID ((UInt64)(Int64)-1)
13
14typedef struct
15{
16 CLzmaEncProps lzmaProps;
17 UInt64 blockSize;
18 int numBlockThreads_Reduced;
19 int numBlockThreads_Max;
20 int numTotalThreads;
21} CLzma2EncProps;
22
23void Lzma2EncProps_Init(CLzma2EncProps *p);
24void Lzma2EncProps_Normalize(CLzma2EncProps *p);
25
26/* ---------- CLzmaEnc2Handle Interface ---------- */
27
28/* Lzma2Enc_* functions can return the following exit codes:
29SRes:
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
39typedef void * CLzma2EncHandle;
40
41CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig);
42void Lzma2Enc_Destroy(CLzma2EncHandle p);
43SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props);
44void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize);
45Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p);
46SRes 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
53EXTERN_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
22013-01-18 : Igor Pavlov : Public domain */
3
4#ifndef __LZMA86_H
5#define __LZMA86_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11#define LZMA86_SIZE_OFFSET (1 + 5)
12#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8)
13
14/*
15It's an example for LZMA + x86 Filter use.
16You 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
27Lzma86_Encode
28-------------
29level - compression level: 0 <= level <= 9, the default value for "level" is 5.
30
31dictSize - 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
39filterMode:
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
47Lzma86Encode allocates Data with MyAlloc functions.
48RAM 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
56Return 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
64enum ESzFilterMode
65{
66 SZ_FILTER_NO,
67 SZ_FILTER_YES,
68 SZ_FILTER_AUTO
69};
70
71SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
72 int level, UInt32 dictSize, int filterMode);
73
74
75/*
76Lzma86_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
87SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize);
88
89/*
90Lzma86_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
107SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen);
108
109EXTERN_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
22016-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
12SRes 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
23SRes 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
22018-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
14int 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
22021-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/*
174p->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/*
185LzmaDec_DecodeReal_3() can be implemented in external ASM file.
1863 - 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/*
192LZMA_DECODE_REAL()
193In:
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
203Processing:
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
213Out:
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
229int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit);
230
231#else
232
233static
234int 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
616static 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/*
656At 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
660We 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/*
672LzmaDec_DecodeReal2():
673 It calls LZMA_DECODE_REAL() and it adjusts limit according (p->checkDicSize).
674
675We correct (p->checkDicSize) after LZMA_DECODE_REAL() and in LzmaDec_WriteRem(),
676and 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
686static 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
704typedef 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
715static 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
906void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState);
907void 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
922void LzmaDec_Init(CLzmaDec *p)
923{
924 p->dicPos = 0;
925 LzmaDec_InitDicAndState(p, True, True);
926}
927
928
929/*
930LZMA supports optional end_marker.
931So the decoder can lookahead for one additional LZMA-Symbol to check end_marker.
932That additional LZMA-Symbol can require up to LZMA_REQUIRED_INPUT_MAX bytes in input stream.
933When 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
937When 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
952SRes 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
1200SRes 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
1240void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc)
1241{
1242 ISzAlloc_Free(alloc, p->probs);
1243 p->probs = NULL;
1244}
1245
1246static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc)
1247{
1248 ISzAlloc_Free(alloc, p->dic);
1249 p->dic = NULL;
1250}
1251
1252void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc)
1253{
1254 LzmaDec_FreeProbs(p, alloc);
1255 LzmaDec_FreeDict(p, alloc);
1256}
1257
1258SRes 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
1284static 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
1299SRes 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
1308SRes 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
1340SRes 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
22020-03-19 : Igor Pavlov : Public domain */
3
4#ifndef __LZMA_DEC_H
5#define __LZMA_DEC_H
6
7#include "7zTypes.h"
8
9EXTERN_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
15typedef
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
28typedef 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
38Returns:
39 SZ_OK
40 SZ_ERROR_UNSUPPORTED - Unsupported properties
41*/
42
43SRes 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
53typedef 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
78void 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
84typedef 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
105typedef 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
133LzmaDec_Allocate* can return:
134 SZ_OK
135 SZ_ERROR_MEM - Memory allocation error
136 SZ_ERROR_UNSUPPORTED - Unsupported properties
137*/
138
139SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
140void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc);
141
142SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
143void 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
171finishMode:
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
176Returns:
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
187SRes 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
198finishMode:
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
204SRes 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
212finishMode:
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
217Returns:
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
230SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
231 const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
232 ELzmaStatus *status, ISzAllocPtr alloc);
233
234EXTERN_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
22021-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
25SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize,
26 ISzAllocPtr alloc, ISzAllocPtr allocBig);
27SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
28 UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig);
29SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,
30 Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize);
31const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp);
32void LzmaEnc_Finish(CLzmaEncHandle pp);
33void LzmaEnc_SaveState(CLzmaEncHandle pp);
34void LzmaEnc_RestoreState(CLzmaEncHandle pp);
35
36#ifdef SHOW_STAT
37static 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
57void 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
67void 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
109UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
110{
111 CLzmaEncProps props = *props2;
112 LzmaEncProps_Normalize(&props);
113 return props.dictSize;
114}
115
116
117/*
118x86/x64:
119
120BSR:
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
126LZCNT:
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
131LZCNT works only in new processors starting from Haswell.
132if LZCNT is not supported by processor, then it's executed as BSR.
133LZCNT 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
193unsigned GetPosSlot1(UInt32 pos);
194unsigned 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
210static 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
258typedef UInt16 CState;
259typedef UInt16 CExtra;
260
261typedef 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
295typedef
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
321typedef struct
322{
323 CLzmaProb low[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)];
324 CLzmaProb high[kLenNumHighSymbols];
325} CLenEnc;
326
327
328typedef 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
344typedef 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
359typedef 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
383typedef UInt32 CProbPrice;
384
385
386typedef 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
497void 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
523void 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
550SRes 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
621void 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
634static const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
635static const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
636static const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
637static 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
645static 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
656static 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
668static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc)
669{
670 ISzAlloc_Free(alloc, p->bufBase);
671 p->bufBase = NULL;
672}
673
674static 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
687MY_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
699MY_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
731static 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
794static 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
803static 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
820static 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
844static 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
882static 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
897static 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
914static 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
933static 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
942static 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
977static 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
993MY_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
1093static 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
1155MY_FORCE_INLINE
1156static 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
1181static 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
1233static 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
1984static 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
2114static 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
2175static 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
2204MY_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
2216MY_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
2240MY_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
2335static 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
2360CLzmaEncHandle 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
2369static 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
2377static 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
2388void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
2389{
2390 LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
2391 ISzAlloc_Free(alloc, p);
2392}
2393
2394
2395MY_NO_INLINE
2396static 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
2699static 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
2776static 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
2847static 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
2865static 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
2882static 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
2892SRes 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
2902static 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
2909SRes 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
2920void 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
2932typedef struct
2933{
2934 ISeqOutStream vt;
2935 Byte *data;
2936 SizeT rem;
2937 BoolInt overflow;
2938} CLzmaEnc_SeqOutStreamBuf;
2939
2940static 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/*
2959UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
2960{
2961 const CLzmaEnc *p = (CLzmaEnc *)pp;
2962 return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
2963}
2964*/
2965
2966const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
2967{
2968 const CLzmaEnc *p = (CLzmaEnc *)pp;
2969 return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
2970}
2971
2972
2973SRes 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
3012MY_NO_INLINE
3013static 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
3051SRes 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
3059SRes 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
3095unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle pp)
3096{
3097 return (unsigned)((CLzmaEnc *)pp)->writeEndMark;
3098}
3099
3100
3101SRes 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
3133SRes 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
3158void 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
22019-10-30 : Igor Pavlov : Public domain */
3
4#ifndef __LZMA_ENC_H
5#define __LZMA_ENC_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11#define LZMA_PROPS_SIZE 5
12
13typedef 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
36void LzmaEncProps_Init(CLzmaEncProps *p);
37void LzmaEncProps_Normalize(CLzmaEncProps *p);
38UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
39
40
41/* ---------- CLzmaEncHandle Interface ---------- */
42
43/* LzmaEnc* functions can return the following exit codes:
44SRes:
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
54typedef void * CLzmaEncHandle;
55
56CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc);
57void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig);
58
59SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
60void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize);
61SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
62unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p);
63
64SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
65 ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
66SRes 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
72SRes 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
76EXTERN_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
22015-06-13 : Igor Pavlov : Public domain */
3
4#include "Alloc.h"
5#include "LzmaDec.h"
6#include "LzmaEnc.h"
7#include "LzmaLib.h"
8
9MY_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
35MY_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
22021-04-03 : Igor Pavlov : Public domain */
3
4#ifndef __LZMA_LIB_H
5#define __LZMA_LIB_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11#define MY_STDAPI int MY_STD_CALL
12
13#define LZMA_PROPS_SIZE 5
14
15/*
16RAM 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
22LZMA 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/*
29LzmaCompress
30------------
31
32outPropsSize -
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
40level - 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
59dictSize - 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
66lc - 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
70lp - 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
76pb - 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
80fb - 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
85numThreads - The number of thereads. 1 or 2. The default value is 2.
86 Fast mode (algo = 0) can use only 1 thread.
87
88In:
89 dest - output data buffer
90 destLen - output data buffer size
91 src - input data
92 srcLen - input data size
93Out:
94 destLen - processed output size
95Returns:
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
103MY_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/*
115LzmaUncompress
116--------------
117In:
118 dest - output data buffer
119 destLen - output data buffer size
120 src - input data
121 srcLen - input data size
122Out:
123 destLen - processed output size
124 srcLen - processed input size
125Returns:
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
133MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen,
134 const unsigned char *props, size_t propsSize);
135
136EXTERN_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
22021-12-21 : Igor Pavlov : Public domain */
3
4#include "Precomp.h"
5
6#include "MtCoder.h"
7
8#ifndef _7ZIP_ST
9
10static 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
29void 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
39static 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
47static THREAD_FUNC_DECL ThreadFunc(void *pp);
48
49
50static 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
67static 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
87static 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
112static 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
338static 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
369void 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
417static 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
442void MtCoder_Destruct(CMtCoder *p)
443{
444 MtCoder_Free(p);
445
446 CriticalSection_Delete(&p->cs);
447 CriticalSection_Delete(&p->mtProgress.cs);
448}
449
450
451SRes 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
22018-07-04 : Igor Pavlov : Public domain */
3
4#ifndef __MT_CODER_H
5#define __MT_CODER_H
6
7#include "MtDec.h"
8
9EXTERN_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
30typedef struct
31{
32 ICompressProgress vt;
33 CMtProgress *mtProgress;
34 UInt64 inSize;
35 UInt64 outSize;
36} CMtProgressThunk;
37
38void MtProgressThunk_CreateVTable(CMtProgressThunk *p);
39
40#define MtProgressThunk_Init(p) { (p)->inSize = 0; (p)->outSize = 0; }
41
42
43struct _CMtCoder;
44
45
46typedef 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
58typedef 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
66typedef struct
67{
68 SRes res;
69 unsigned bufIndex;
70 BoolInt finished;
71} CMtCoderBlock;
72
73
74typedef 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
131void MtCoder_Construct(CMtCoder *p);
132void MtCoder_Destruct(CMtCoder *p);
133SRes MtCoder_Code(CMtCoder *p);
134
135
136#endif
137
138
139EXTERN_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
22021-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
27void 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
36SRes 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
45SRes 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
62SRes 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
72void 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
84static 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
92struct __CMtDecBufLink
93{
94 struct __CMtDecBufLink *next;
95 void *pad[3];
96};
97
98typedef 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
105static THREAD_FUNC_DECL ThreadFunc(void *pp);
106
107
108static 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
121static 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
137void 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
154static 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
167static 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
174static void MtDecThread_Destruct(CMtDecThread *t)
175{
176 MtDecThread_CloseThread(t);
177 MtDecThread_FreeInBufs(t);
178}
179
180
181
182static 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
201static 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
211static 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
230static 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
241Byte *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
264static 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
839static 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
865static 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
876int 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
899const 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
963void 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
1007static 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
1026void MtDec_Destruct(CMtDec *p)
1027{
1028 MtDec_Free(p);
1029
1030 CriticalSection_Delete(&p->mtProgress.cs);
1031}
1032
1033
1034SRes 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
22020-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
13EXTERN_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
24typedef struct
25{
26 ICompressProgress *progress;
27 SRes res;
28 UInt64 totalInSize;
29 UInt64 totalOutSize;
30 CCriticalSection cs;
31} CMtProgress;
32
33void MtProgress_Init(CMtProgress *p, ICompressProgress *progress);
34SRes MtProgress_Progress_ST(CMtProgress *p);
35SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize);
36SRes MtProgress_GetError(CMtProgress *p);
37void MtProgress_SetError(CMtProgress *p, SRes res);
38
39struct _CMtDec;
40
41typedef 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
56void MtDecThread_FreeInBufs(CMtDecThread *t);
57
58
59typedef 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
67typedef 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
84typedef 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
120typedef 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
183void MtDec_Construct(CMtDec *p);
184void MtDec_Destruct(CMtDec *p);
185
186/*
187MtDec_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
192SRes MtDec_Code(CMtDec *p);
193Byte *MtDec_GetCrossBuff(CMtDec *p);
194
195int MtDec_PrepareRead(CMtDec *p);
196const Byte *MtDec_Read(CMtDec *p, size_t *inLim);
197
198#endif
199
200EXTERN_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
22021-04-13 : Igor Pavlov : Public domain
3This 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
10EXTERN_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
40MY_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 */
44typedef 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
55typedef struct
56{
57 Byte Symbol;
58 Byte Freq;
59 UInt16 Successor_0;
60 UInt16 Successor_1;
61} CPpmd_State;
62
63typedef struct CPpmd_State2_
64{
65 Byte Symbol;
66 Byte Freq;
67} CPpmd_State2;
68
69typedef struct CPpmd_State4_
70{
71 UInt16 Successor_0;
72 UInt16 Successor_1;
73} CPpmd_State4;
74
75MY_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
118typedef Ppmd_Ref_Type(CPpmd_State) CPpmd_State_Ref;
119typedef Ppmd_Ref_Type(void) CPpmd_Void_Ref;
120typedef 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
165EXTERN_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
22021-04-13 : Igor Pavlov : Public domain
3This 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
14MY_ALIGN(16)
15static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
16MY_ALIGN(16)
17static 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
36typedef CPpmd7_Context * CTX_PTR;
37
38struct CPpmd7_Node_;
39
40typedef Ppmd_Ref_Type(struct CPpmd7_Node_) CPpmd7_Node_Ref;
41
42typedef 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
52void 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
84void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc)
85{
86 ISzAlloc_Free(alloc, p->Base);
87 p->Size = 0;
88 p->Base = NULL;
89}
90
91
92BoolInt 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
117static 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
127static 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
137static 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
152typedef 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
162static 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
253MY_NO_INLINE
254static 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
287static 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/*
310static 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)
330static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
331{
332 Ppmd_SET_SUCCESSOR(p, v);
333}
334
335
336
337MY_NO_INLINE
338static
339void 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
422void 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
448MY_NO_INLINE
449static 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
557void Ppmd7_UpdateModel(CPpmd7 *p);
558MY_NO_INLINE
559void 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
798MY_NO_INLINE
799static 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
921CPpmd_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
951static 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
961void 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
979void 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/*
997void 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
1007void 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/*
1023PPMd 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
1034These addresses don't cross at any time.
1035And the following condtions is true for addresses:
1036 (0 <= Text < UnitsStart <= LoUnit <= HiUnit <= Size)
1037
1038Raw text is BYTE--aligned.
1039the data in block [ UnitsStart ... Size ] contains 12-bytes aligned UNITs.
1040
1041Last UNIT of array at offset (Size - 12) is root order-0 CPpmd7_Context record.
1042The code can free UNITs memory blocks that were allocated to store CPpmd_State vectors.
1043The code doesn't free UNITs allocated for CPpmd7_Context records.
1044
1045The code calls RestartModel(), when there is no free memory for allocation.
1046And RestartModel() changes the state to orignal start state, with full free block.
1047
1048
1049The code allocates UNITs with the following order:
1050
1051Allocation of 1 UNIT for Context record
1052 - from free space (HiUnit) down to (LoUnit)
1053 - from FreeList[0]
1054 - AllocUnitsRare()
1055
1056AllocUnits() for CPpmd_State vectors:
1057 - from FreeList[i]
1058 - from free space (LoUnit) up to (HiUnit)
1059 - AllocUnitsRare()
1060
1061AllocUnitsRare()
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
1069Each Record with Context contains the CPpmd_State vector, where each
1070CPpmd_State contains the link to Successor.
1071There 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
1082For 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
1088CPpmd7_Context::SummFreq = Sum(Stats[].Freq) + Escape_Freq
1089
1090The PPMd code tries to fulfill the condition:
1091 (SummFreq <= (256 * 128 = RC::kBot))
1092
1093We have (Sum(Stats[].Freq) <= 256 * 124), because of (MAX_FREQ = 124)
1094So (4 = 128 - 124) is average reserve for Escape_Freq for each symbol.
1095If (CPpmd_State::Freq) is not aligned for 4, the reserve can be 5, 6 or 7.
1096SummFreq and Escape_Freq can be changed in Rescale() and *Update*() functions.
1097Rescale() can remove symbols only from max-order contexts. So Escape_Freq can increase after multiple calls of Rescale() for
1098max-order context.
1099
1100When the PPMd code still break (Total <= RC::Range) condition in range coder,
1101we 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
22021-04-13 : Igor Pavlov : Public domain
3This 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
12EXTERN_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
20struct CPpmd7_Context_;
21
22typedef Ppmd_Ref_Type(struct CPpmd7_Context_) CPpmd7_Context_Ref;
23
24// MY_CPU_pragma_pack_push_1
25
26typedef 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
53typedef struct
54{
55 UInt32 Range;
56 UInt32 Code;
57 UInt32 Low;
58 IByteIn *Stream;
59} CPpmd7_RangeDec;
60
61
62typedef 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
73typedef 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
106void Ppmd7_Construct(CPpmd7 *p);
107BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc);
108void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc);
109void 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
119void Ppmd7_Update1(CPpmd7 *p);
120void Ppmd7_Update1_0(CPpmd7 *p);
121void 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
135CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
136
137
138/*
139We 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
142Ppmd7_*: 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/*
151You must set (CPpmd7::rc.dec.Stream) before Ppmd7*_RangeDec_Init()
152
153Ppmd7*_DecodeSymbol()
154out:
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 */
161BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p);
162#define Ppmd7a_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
163int Ppmd7a_DecodeSymbol(CPpmd7 *p);
164
165/* Ppmd7z_* : modified PPMdH with 7z Range Coder */
166BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p);
167#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
168int Ppmd7z_DecodeSymbol(CPpmd7 *p);
169// Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim);
170
171
172/* ---------- Encode ---------- */
173
174void Ppmd7z_Init_RangeEnc(CPpmd7 *p);
175void Ppmd7z_Flush_RangeEnc(CPpmd7 *p);
176// void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol);
177void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim);
178
179EXTERN_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
22021-04-13 : Igor Pavlov : Public domain
3This 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
16BoolInt 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
40MY_FORCE_INLINE
41// MY_NO_INLINE
42static 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))
57typedef CPpmd7_Context * CTX_PTR;
58#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
59void Ppmd7_UpdateModel(CPpmd7 *p);
60
61#define MASK(sym) ((unsigned char *)charMask)[sym]
62// MY_FORCE_INLINE
63// static
64int 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/*
282Byte *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
22021-04-13 : Igor Pavlov : Public domain
3This 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
15void Ppmd7z_Init_RangeEnc(CPpmd7 *p)
16{
17 R->Low = 0;
18 R->Range = 0xFFFFFFFF;
19 R->Cache = 0;
20 R->CacheSize = 1;
21}
22
23MY_NO_INLINE
24static 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
57MY_FORCE_INLINE
58// MY_NO_INLINE
59static 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
66void 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)
80typedef CPpmd7_Context * CTX_PTR;
81#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
82
83void Ppmd7_UpdateModel(CPpmd7 *p);
84
85#define MASK(sym) ((unsigned char *)charMask)[sym]
86
87MY_FORCE_INLINE
88static
89void 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
317void 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
22021-04-13 : Igor Pavlov : Public domain
3This 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
16BoolInt 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
40MY_FORCE_INLINE
41// MY_NO_INLINE
42static 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))
57typedef CPpmd7_Context * CTX_PTR;
58#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
59void Ppmd7_UpdateModel(CPpmd7 *p);
60
61#define MASK(sym) ((unsigned char *)charMask)[sym]
62
63
64int 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
22021-04-13 : Igor Pavlov : Public domain
3This 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
14MY_ALIGN(16)
15static const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
16MY_ALIGN(16)
17static 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
36typedef CPpmd8_Context * CTX_PTR;
37
38struct CPpmd8_Node_;
39
40typedef Ppmd_Ref_Type(struct CPpmd8_Node_) CPpmd8_Node_Ref;
41
42typedef 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
52void 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
84void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc)
85{
86 ISzAlloc_Free(alloc, p->Base);
87 p->Size = 0;
88 p->Base = NULL;
89}
90
91
92BoolInt 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
117static 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
127static 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
137static 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
162static 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
253MY_NO_INLINE
254static 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
287static 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
310static 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
328static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu)
329{
330 InsertNode(p, ptr, U2I(nu));
331}
332
333
334static 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/*
349static 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
365static 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)
414static 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
421MY_NO_INLINE
422static
423void 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
506void 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/*
530Refresh() is called when we remove some symbols (successors) in context.
531It increases Escape_Freq for sum of all removed symbols.
532*/
533
534static 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
584static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
585{
586 CPpmd_State tmp = *t1;
587 *t1 = *t2;
588 *t2 = tmp;
589}
590
591
592/*
593CutOff() 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
600static 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/*
708RemoveBinContexts()
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
714static 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
754static 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
770static 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
853MY_NO_INLINE
854static 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
957static 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
1061void Ppmd8_UpdateModel(CPpmd8 *p);
1062MY_NO_INLINE
1063void 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
1302MY_NO_INLINE
1303static 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
1425CPpmd_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
1455static 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
1465void 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
1483void 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/*
1501void 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
1511void 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
1533Flags:
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
22021-04-13 : Igor Pavlov : Public domain
3This 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
12EXTERN_C_BEGIN
13
14#define PPMD8_MIN_ORDER 2
15#define PPMD8_MAX_ORDER 16
16
17
18
19
20struct CPpmd8_Context_;
21
22typedef Ppmd_Ref_Type(struct CPpmd8_Context_) CPpmd8_Context_Ref;
23
24// MY_CPU_pragma_pack_push_1
25
26typedef 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
56enum
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
73typedef 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
106void Ppmd8_Construct(CPpmd8 *p);
107BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc);
108void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc);
109void 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
119void Ppmd8_Update1(CPpmd8 *p);
120void Ppmd8_Update1_0(CPpmd8 *p);
121void 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
135CPpmd_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/*
151You must set (CPpmd8::Stream.In) before Ppmd8_RangeDec_Init()
152
153Ppmd8_DecodeSymbol()
154out:
155 >= 0 : decoded byte
156 -1 : PPMD8_SYM_END : End of payload marker
157 -2 : PPMD8_SYM_ERROR : Data error
158*/
159
160
161BoolInt Ppmd8_Init_RangeDec(CPpmd8 *p);
162#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
163int 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; }
175void Ppmd8_Flush_RangeEnc(CPpmd8 *p);
176void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol);
177
178
179EXTERN_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
22021-04-13 : Igor Pavlov : Public domain
3This 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
16BoolInt 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
40MY_FORCE_INLINE
41// MY_NO_INLINE
42static 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))
57typedef CPpmd8_Context * CTX_PTR;
58#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
59void Ppmd8_UpdateModel(CPpmd8 *p);
60
61#define MASK(sym) ((unsigned char *)charMask)[sym]
62
63
64int 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
22021-04-13 : Igor Pavlov : Public domain
3This 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
16void 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
57MY_FORCE_INLINE
58// MY_NO_INLINE
59static 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
80typedef CPpmd8_Context * CTX_PTR;
81#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
82
83void Ppmd8_UpdateModel(CPpmd8 *p);
84
85#define MASK(sym) ((unsigned char *)charMask)[sym]
86
87// MY_FORCE_INLINE
88// static
89void 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
22013-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
22015-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
22021-07-13 : Igor Pavlov : Public domain
3This 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
51void 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
65BoolInt 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
225void 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
235void 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
247MY_NO_INLINE
248void 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
293void 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
331void 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
384void 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
399void 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
420void 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
22021-02-08 : Igor Pavlov : Public domain */
3
4#ifndef __7Z_SHA1_H
5#define __7Z_SHA1_H
6
7#include "7zTypes.h"
8
9EXTERN_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
17typedef 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
33typedef 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/*
49Sha1_SetFunction()
50return:
51 0 - (algo) value is not supported, and func_UpdateBlocks was not changed
52 1 - func_UpdateBlocks was set according (algo) value.
53*/
54
55BoolInt Sha1_SetFunction(CSha1 *p, unsigned algo);
56
57void Sha1_InitState(CSha1 *p);
58void Sha1_Init(CSha1 *p);
59void Sha1_Update(CSha1 *p, const Byte *data, size_t size);
60void Sha1_Final(CSha1 *p, Byte *digest);
61
62void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size);
63void 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/*
68call Sha1Prepare() once at program start.
69It prepares all supported implementations, and detects the fastest implementation.
70*/
71
72void Sha1Prepare(void);
73
74EXTERN_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
22021-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/*
73SHA1 uses:
74SSE2:
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
83SSSE3:
84 _mm_shuffle_epi8 / pshufb
85
86SHA:
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
160void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks);
161#ifdef ATTRIB_SHA
162ATTRIB_SHA
163#endif
164void 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
253typedef 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
277void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
278#ifdef ATTRIB_SHA
279ATTRIB_SHA
280#endif
281void 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"
356void 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
360void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks);
361void 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
22021-04-01 : Igor Pavlov : Public domain
3This 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
51void 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
65BoolInt 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
111void 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
124void 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
226void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
227
228// static
229extern MY_ALIGN(64)
230const UInt32 SHA256_K_ARRAY[64];
231
232MY_ALIGN(64)
233const 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
255MY_NO_INLINE
256void 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
372void 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
410void 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
463void 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
22021-01-01 : Igor Pavlov : Public domain */
3
4#ifndef __7Z_SHA256_H
5#define __7Z_SHA256_H
6
7#include "7zTypes.h"
8
9EXTERN_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
17typedef 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
33typedef 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/*
49Sha256_SetFunction()
50return:
51 0 - (algo) value is not supported, and func_UpdateBlocks was not changed
52 1 - func_UpdateBlocks was set according (algo) value.
53*/
54
55BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo);
56
57void Sha256_InitState(CSha256 *p);
58void Sha256_Init(CSha256 *p);
59void Sha256_Update(CSha256 *p, const Byte *data, size_t size);
60void 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/*
68call Sha256Prepare() once at program start.
69It prepares all supported implementations, and detects the fastest implementation.
70*/
71
72void Sha256Prepare(void);
73
74EXTERN_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
22021-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/*
73SHA256 uses:
74SSE2:
75 _mm_loadu_si128
76 _mm_storeu_si128
77 _mm_set_epi32
78 _mm_add_epi32
79 _mm_shuffle_epi32 / pshufd
80
81
82
83SSSE3:
84 _mm_shuffle_epi8 / pshufb
85 _mm_alignr_epi8
86SHA:
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
94extern
95MY_ALIGN(64)
96const 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
160void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
161#ifdef ATTRIB_SHA
162ATTRIB_SHA
163#endif
164void 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
253typedef 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.
270extern
271MY_ALIGN(64)
272const 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
301void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
302#ifdef ATTRIB_SHA
303ATTRIB_SHA
304#endif
305void 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"
356void 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
360void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
361void 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
22014-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
17void 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
63void 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
119void 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
22014-04-05 : Igor Pavlov : Public domain */
3
4#ifndef __7Z_SORT_H
5#define __7Z_SORT_H
6
7#include "7zTypes.h"
8
9EXTERN_C_BEGIN
10
11void HeapSort(UInt32 *p, size_t size);
12void HeapSort64(UInt64 *p, size_t size);
13
14/* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */
15
16EXTERN_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
22021-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
14static WRes GetError()
15{
16 DWORD res = GetLastError();
17 return res ? (WRes)res : 1;
18}
19
20static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); }
21static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }
22
23WRes 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
34WRes 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
55WRes 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
62WRes 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
83WRes 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
131static 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
137WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
138WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }
139
140WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
141WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
142WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
143WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }
144
145
146WRes 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
153WRes 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
164static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
165 { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
166WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
167 { return Semaphore_Release(p, (LONG)num, NULL); }
168WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }
169
170WRes 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
220WRes 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
287WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
288{
289 return Thread_Create_With_CpuSet(p, func, param, NULL);
290}
291
292
293WRes 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
313WRes 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
327WRes 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
344static 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
354WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled)
355 { return Event_Create(p, True, signaled); }
356WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p)
357 { return ManualResetEvent_Create(p, 0); }
358WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled)
359 { return Event_Create(p, False, signaled); }
360WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p)
361 { return AutoResetEvent_Create(p, 0); }
362
363
364WRes 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
373WRes 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
380WRes 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
397WRes 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
410WRes 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
423WRes 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
443WRes 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
465WRes 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
476WRes 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
490WRes 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
498void 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
508void 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
518void 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
528LONG 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
22021-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
27EXTERN_C_BEGIN
28
29#ifdef _WIN32
30
31WRes HandlePtr_Close(HANDLE *h);
32WRes Handle_WaitObject(HANDLE h);
33
34typedef 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
47typedef
48 #ifdef USE_THREADS_CreateThread
49 DWORD
50 #else
51 unsigned
52 #endif
53 THREAD_FUNC_RET_TYPE;
54
55typedef DWORD_PTR CAffinityMask;
56typedef 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
63typedef 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)
71WRes Thread_Close(CThread *p);
72// #define Thread_Wait Thread_Wait_Close
73
74typedef void * THREAD_FUNC_RET_TYPE;
75
76typedef UInt64 CAffinityMask;
77
78#ifdef _7ZIP_AFFINITY_SUPPORTED
79
80typedef 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
87typedef 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
123typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *);
124WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param);
125WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity);
126WRes 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
132WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet);
133#endif
134
135
136#ifdef _WIN32
137
138typedef HANDLE CEvent;
139typedef CEvent CAutoResetEvent;
140typedef 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))
145WRes Event_Set(CEvent *p);
146WRes Event_Reset(CEvent *p);
147WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
148WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
149WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
150WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
151
152typedef 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))
157WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
158WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
159WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
160WRes Semaphore_Release1(CSemaphore *p);
161
162typedef CRITICAL_SECTION CCriticalSection;
163WRes 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
171typedef 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
180typedef CEvent CAutoResetEvent;
181typedef CEvent CManualResetEvent;
182
183#define Event_Construct(p) (p)->_created = 0
184#define Event_IsCreated(p) ((p)->_created)
185
186WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
187WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
188WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
189WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
190WRes Event_Set(CEvent *p);
191WRes Event_Reset(CEvent *p);
192WRes Event_Wait(CEvent *p);
193WRes Event_Close(CEvent *p);
194
195
196typedef 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
208WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
209WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
210WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
211#define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1)
212WRes Semaphore_Wait(CSemaphore *p);
213WRes Semaphore_Close(CSemaphore *p);
214
215
216typedef struct _CCriticalSection
217{
218 pthread_mutex_t _mutex;
219} CCriticalSection;
220
221WRes CriticalSection_Init(CCriticalSection *p);
222void CriticalSection_Delete(CCriticalSection *cs);
223void CriticalSection_Enter(CCriticalSection *cs);
224void CriticalSection_Leave(CCriticalSection *cs);
225
226LONG InterlockedIncrement(LONG volatile *addend);
227
228#endif // _WIN32
229
230EXTERN_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
7CFG=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 ""
28CPP=cl.exe
29RSC=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"
48BSC32=bscmake.exe
49# ADD BASE BSC32 /nologo
50# ADD BSC32 /nologo
51LINK32=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"
73BSC32=bscmake.exe
74# ADD BASE BSC32 /nologo
75# ADD BSC32 /nologo
76LINK32=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
91SOURCE=..\..\7z.h
92# End Source File
93# Begin Source File
94
95SOURCE=..\..\7zAlloc.c
96# End Source File
97# Begin Source File
98
99SOURCE=..\..\7zAlloc.h
100# End Source File
101# Begin Source File
102
103SOURCE=..\..\7zArcIn.c
104# End Source File
105# Begin Source File
106
107SOURCE=..\..\7zBuf.c
108# End Source File
109# Begin Source File
110
111SOURCE=..\..\7zBuf.h
112# End Source File
113# Begin Source File
114
115SOURCE=..\..\7zCrc.c
116# End Source File
117# Begin Source File
118
119SOURCE=..\..\7zCrc.h
120# End Source File
121# Begin Source File
122
123SOURCE=..\..\7zCrcOpt.c
124# End Source File
125# Begin Source File
126
127SOURCE=..\..\7zDec.c
128# ADD CPP /D "_7ZIP_PPMD_SUPPPORT"
129# End Source File
130# Begin Source File
131
132SOURCE=..\..\7zFile.c
133# End Source File
134# Begin Source File
135
136SOURCE=..\..\7zFile.h
137# End Source File
138# Begin Source File
139
140SOURCE=..\..\7zStream.c
141# End Source File
142# Begin Source File
143
144SOURCE=..\..\7zTypes.h
145# End Source File
146# Begin Source File
147
148SOURCE=..\..\Bcj2.c
149# End Source File
150# Begin Source File
151
152SOURCE=..\..\Bcj2.h
153# End Source File
154# Begin Source File
155
156SOURCE=..\..\Bra.c
157# End Source File
158# Begin Source File
159
160SOURCE=..\..\Bra.h
161# End Source File
162# Begin Source File
163
164SOURCE=..\..\Bra86.c
165# End Source File
166# Begin Source File
167
168SOURCE=..\..\BraIA64.c
169# End Source File
170# Begin Source File
171
172SOURCE=..\..\CpuArch.c
173# End Source File
174# Begin Source File
175
176SOURCE=..\..\CpuArch.h
177# End Source File
178# Begin Source File
179
180SOURCE=..\..\Delta.c
181# End Source File
182# Begin Source File
183
184SOURCE=..\..\Delta.h
185# End Source File
186# Begin Source File
187
188SOURCE=..\..\Lzma2Dec.c
189# End Source File
190# Begin Source File
191
192SOURCE=..\..\Lzma2Dec.h
193# End Source File
194# Begin Source File
195
196SOURCE=..\..\LzmaDec.c
197# End Source File
198# Begin Source File
199
200SOURCE=..\..\LzmaDec.h
201# End Source File
202# Begin Source File
203
204SOURCE=..\..\Ppmd.h
205# End Source File
206# Begin Source File
207
208SOURCE=..\..\Ppmd7.c
209# End Source File
210# Begin Source File
211
212SOURCE=..\..\Ppmd7.h
213# End Source File
214# Begin Source File
215
216SOURCE=..\..\Ppmd7Dec.c
217# End Source File
218# End Group
219# Begin Group "Spec"
220
221# PROP Default_Filter ""
222# Begin Source File
223
224SOURCE=..\..\Compiler.h
225# End Source File
226# Begin Source File
227
228SOURCE=.\Precomp.c
229# ADD CPP /Yc"Precomp.h"
230# End Source File
231# Begin Source File
232
233SOURCE=.\Precomp.h
234# End Source File
235# End Group
236# Begin Source File
237
238SOURCE=.\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 @@
1Microsoft Developer Studio Workspace File, Format Version 6.00
2# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
3
4###############################################################################
5
6Project: "7z"=.\7z.dsp - Package Owner=<4>
7
8Package=<5>
9{{{
10}}}
11
12Package=<4>
13{{{
14}}}
15
16###############################################################################
17
18Global:
19
20Package=<5>
21{{{
22}}}
23
24Package=<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
22021-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
38static const ISzAlloc g_Alloc = { SzAlloc, SzFree };
39
40
41static void Print(const char *s)
42{
43 fputs(s, stdout);
44}
45
46
47static 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
70static 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
106static 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
153static 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
165static 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
208static 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
234static 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
250static 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
266static 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
286static 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
304static 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;
321typedef int BOOL;
322
323typedef struct _FILETIME
324{
325 DWORD dwLowDateTime;
326 DWORD dwHighDateTime;
327} FILETIME;
328
329static 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
351static 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
359static const UInt32 kNumTimeQuantumsInSecond = 10000000;
360static const UInt32 kFileTimeStartYear = 1601;
361static const UInt32 kUnixTimeStartYear = 1970;
362static const UInt64 kUnixTimeOffset =
363 (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear));
364
365static 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
377static 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
400static 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, &times[0]);
412 FILETIME_To_timespec(mTime, &times[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
422static void NtfsFileTime_to_FILETIME(const CNtfsFileTime *t, FILETIME *ft)
423{
424 ft->dwLowDateTime = (DWORD)(t->Low);
425 ft->dwHighDateTime = (DWORD)(t->High);
426}
427
428static 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
477static void PrintLF()
478{
479 Print("\n");
480}
481
482static void PrintError(char *s)
483{
484 Print("\nERROR: ");
485 Print(s);
486 PrintLF();
487}
488
489static 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
526static 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
544int 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
22013-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
22013-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 @@
1CFLAGS = $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT
2
3PROG = 7zDec.exe
4
5C_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
257Z_OBJS = \
26 $O\7zMain.obj \
27
28OBJS = \
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 @@
1PROG = 7zdec
2
3LOCAL_FLAGS = -D_7ZIP_PPMD_SUPPPORT
4
5include ../../../CPP/7zip/LzmaDec_gcc.mak
6
7
8OBJS = \
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
34include ../../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
22021-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
42static LPCSTR const k_7zip = "7-Zip";
43
44static 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
76static LPCWSTR const k_7zip_with_Ver_str = k_7zip_with_Ver;
77
78static LPCWSTR const k_7zip_Setup = k_7zip_with_Ver L" Setup";
79
80static LPCWSTR const k_Reg_Path = L"Path";
81
82static 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
104static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID;
105static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32";
106
107#define g_AllUsers True
108
109static BoolInt g_Install_was_Pressed;
110static BoolInt g_Finished;
111static BoolInt g_SilentMode;
112
113static HWND g_HWND;
114static HWND g_Path_HWND;
115static HWND g_InfoLine_HWND;
116static HWND g_Progress_HWND;
117
118static DWORD g_TotalSize;
119
120static WCHAR cmd[MAX_PATH + 4];
121static WCHAR cmdError[MAX_PATH + 4];
122static WCHAR path[MAX_PATH * 2 + 40];
123
124
125// #define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c)))
126
127
128static 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
139static void CatAscii(wchar_t *dest, const char *s)
140{
141 dest += wcslen(dest);
142 CpyAscii(dest, s);
143}
144
145static 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
164typedef DWORD (WINAPI * Func_GetFileVersionInfoSizeW)(LPCWSTR lptstrFilename, LPDWORD lpdwHandle);
165typedef BOOL (WINAPI * Func_GetFileVersionInfoW)(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
166typedef BOOL (WINAPI * Func_VerQueryValueW)(const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen);
167
168static HMODULE g_version_dll_hModule;
169
170static 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
229static 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
238static 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
252static 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
334static 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
344static 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
357static 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
363static 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
369static 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
377static 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
392static 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
400static 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
424static 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
461static 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
484static 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
512static 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
543static 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
563static char MyCharLower_Ascii(char c)
564{
565 if (c >= 'A' && c <= 'Z')
566 return (char)((unsigned char)c + 0x20);
567 return c;
568}
569
570static 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
577static 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
598static void Set7zipPostfix(WCHAR *s)
599{
600 NormalizePrefix(s);
601 if (FindSubString(s, "7-Zip"))
602 return;
603 CatAscii(s, "7-Zip\\");
604}
605
606
607static int Install(void);
608
609static 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
623static 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
716static 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
729static void SetRegKey_Path()
730{
731 SetRegKey_Path2(HKEY_CURRENT_USER);
732 SetRegKey_Path2(HKEY_LOCAL_MACHINE);
733}
734
735
736static 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
762static 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
824static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
825static LPCWSTR const k_7zip_ShellExtension = L"7-Zip Shell Extension";
826
827static 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
869static 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
878static 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
953static 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
976static 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
993typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL);
994
995int 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
1204static 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
1220static 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
1265if (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
7CFG=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 ""
28CPP=cl.exe
29MTL=midl.exe
30RSC=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"
51BSC32=bscmake.exe
52# ADD BASE BSC32 /nologo
53# ADD BSC32 /nologo
54LINK32=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"
77BSC32=bscmake.exe
78# ADD BASE BSC32 /nologo
79# ADD BSC32 /nologo
80LINK32=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
95SOURCE=..\..\7z.h
96# End Source File
97# Begin Source File
98
99SOURCE=..\..\7zAlloc.c
100# End Source File
101# Begin Source File
102
103SOURCE=..\..\7zAlloc.h
104# End Source File
105# Begin Source File
106
107SOURCE=..\..\7zArcIn.c
108# End Source File
109# Begin Source File
110
111SOURCE=..\..\7zBuf.c
112# End Source File
113# Begin Source File
114
115SOURCE=..\..\7zBuf.h
116# End Source File
117# Begin Source File
118
119SOURCE=..\..\7zCrc.c
120# End Source File
121# Begin Source File
122
123SOURCE=..\..\7zCrc.h
124# End Source File
125# Begin Source File
126
127SOURCE=..\..\7zCrcOpt.c
128# End Source File
129# Begin Source File
130
131SOURCE=..\..\7zDec.c
132# End Source File
133# Begin Source File
134
135SOURCE=..\..\7zFile.c
136# End Source File
137# Begin Source File
138
139SOURCE=..\..\7zFile.h
140# End Source File
141# Begin Source File
142
143SOURCE=..\..\7zStream.c
144# End Source File
145# Begin Source File
146
147SOURCE=..\..\7zTypes.h
148# End Source File
149# Begin Source File
150
151SOURCE=..\..\7zVersion.h
152# End Source File
153# Begin Source File
154
155SOURCE=..\..\Bcj2.c
156# End Source File
157# Begin Source File
158
159SOURCE=..\..\Bcj2.h
160# End Source File
161# Begin Source File
162
163SOURCE=..\..\Bra.c
164# End Source File
165# Begin Source File
166
167SOURCE=..\..\Bra.h
168# End Source File
169# Begin Source File
170
171SOURCE=..\..\Bra86.c
172# End Source File
173# Begin Source File
174
175SOURCE=..\..\BraIA64.c
176# End Source File
177# Begin Source File
178
179SOURCE=..\..\CpuArch.c
180# End Source File
181# Begin Source File
182
183SOURCE=..\..\CpuArch.h
184# End Source File
185# Begin Source File
186
187SOURCE=..\..\Delta.c
188# End Source File
189# Begin Source File
190
191SOURCE=..\..\Delta.h
192# End Source File
193# Begin Source File
194
195SOURCE=..\..\DllSecur.c
196# End Source File
197# Begin Source File
198
199SOURCE=..\..\DllSecur.h
200# End Source File
201# Begin Source File
202
203SOURCE=..\..\Lzma2Dec.c
204# End Source File
205# Begin Source File
206
207SOURCE=..\..\Lzma2Dec.h
208# End Source File
209# Begin Source File
210
211SOURCE=..\..\LzmaDec.c
212# End Source File
213# Begin Source File
214
215SOURCE=..\..\LzmaDec.h
216# End Source File
217# End Group
218# Begin Group "Spec"
219
220# PROP Default_Filter ""
221# Begin Source File
222
223SOURCE=.\Precomp.c
224# ADD CPP /Yc"Precomp.h"
225# End Source File
226# Begin Source File
227
228SOURCE=.\Precomp.h
229# End Source File
230# End Group
231# Begin Source File
232
233SOURCE=.\7zipInstall.c
234# End Source File
235# Begin Source File
236
237SOURCE=.\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 @@
1Microsoft Developer Studio Workspace File, Format Version 6.00
2# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
3
4###############################################################################
5
6Project: "7zipInstall"=.\7zipInstall.dsp - Package Owner=<4>
7
8Package=<5>
9{{{
10}}}
11
12Package=<4>
13{{{
14}}}
15
16###############################################################################
17
18Global:
19
20Package=<5>
21{{{
22}}}
23
24Package=<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
22013-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
22015-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 @@
1PROG = 7zipInstall.exe
2MY_FIXED = 1
3
4!IFDEF _64BIT_INSTALLER
5CFLAGS = $(CFLAGS) -D_64BIT_INSTALLER
6!ENDIF
7
8CFLAGS = $(CFLAGS) -D_LZMA_SIZE_OPT
9
10CFLAGS = $(CFLAGS) \
11 -D_7Z_NO_METHOD_LZMA2 \
12 -D_7Z_NO_METHODS_FILTERS
13
14MAIN_OBJS = \
15 $O\7zipInstall.obj \
16
17C_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
32OBJS = \
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
9MY_VERSION_INFO(MY_VFT_APP, "7-Zip Installer", "7zipInstall", "7zipInstall.exe")
10
111 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
29IDD_INSTALL DIALOG 0, 0, xs, ys
30STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
31CAPTION "Install 7-Zip"
32FONT 8, "MS Shell Dlg"
33BEGIN
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
43END
44
45#ifndef UNDER_CE
461 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
22021-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
56static LPCWSTR const k_7zip_with_Ver_Uninstall = k_7zip_with_Ver L" Uninstall";
57
58static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip";
59
60static LPCWSTR const k_Reg_Path = L"Path";
61
62static 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
84static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID;
85static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32";
86
87
88#define g_AllUsers True
89
90static BoolInt g_Install_was_Pressed;
91static BoolInt g_Finished;
92static BoolInt g_SilentMode;
93
94static HWND g_HWND;
95static HWND g_Path_HWND;
96static HWND g_InfoLine_HWND;
97static HWND g_Progress_HWND;
98
99// WINADVAPI
100typedef LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved);
101static Func_RegDeleteKeyExW func_RegDeleteKeyExW;
102
103static WCHAR cmd[MAX_PATH + 4];
104static WCHAR cmdError[MAX_PATH + 4];
105static WCHAR path[MAX_PATH * 2 + 40];
106static WCHAR workDir[MAX_PATH + 10];
107static WCHAR modulePath[MAX_PATH + 10];
108static WCHAR modulePrefix[MAX_PATH + 10];
109static WCHAR tempPath[MAX_PATH * 2 + 40];
110static WCHAR cmdLine[MAX_PATH * 3 + 40];
111static WCHAR copyPath[MAX_PATH * 2 + 40];
112
113static LPCWSTR const kUninstallExe = L"Uninstall.exe";
114
115#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c)))
116
117
118static 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
129static void CatAscii(wchar_t *dest, const char *s)
130{
131 dest += wcslen(dest);
132 CpyAscii(dest, s);
133}
134
135static 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
154static 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
167static 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
181static 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
192static 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
202static 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
215static 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
220static 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
233static 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
246static 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
251static 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
267static 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
278static 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
292static void SetRegKey_Path()
293{
294 SetRegKey_Path2(HKEY_CURRENT_USER);
295 SetRegKey_Path2(HKEY_LOCAL_MACHINE);
296}
297
298static 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
331static 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
391static 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
400static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
401
402static 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\\"
404static LPCWSTR const k_Uninstall_7zip = k_REG_Uninstall L"7-Zip";
405
406
407static 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
418static 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
425static 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
519static 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/*
542static 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
557static BoolInt DoesFileOrDirExist()
558{
559 return (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES);
560}
561
562static 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
572static BOOL RemoveFileAfterReboot()
573{
574 return RemoveFileAfterReboot2(path);
575}
576
577// #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ')
578
579static 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
591static 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
603static 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
617static 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
644static 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
669static 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
802static 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
816static 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
884int 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
7CFG=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 ""
28CPP=cl.exe
29MTL=midl.exe
30RSC=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"
51BSC32=bscmake.exe
52# ADD BASE BSC32 /nologo
53# ADD BSC32 /nologo
54LINK32=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"
77BSC32=bscmake.exe
78# ADD BASE BSC32 /nologo
79# ADD BSC32 /nologo
80LINK32=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
95SOURCE=..\..\7zTypes.h
96# End Source File
97# Begin Source File
98
99SOURCE=..\..\7zVersion.h
100# End Source File
101# End Group
102# Begin Group "Spec"
103
104# PROP Default_Filter ""
105# Begin Source File
106
107SOURCE=.\Precomp.c
108# ADD CPP /Yc"Precomp.h"
109# End Source File
110# Begin Source File
111
112SOURCE=.\Precomp.h
113# End Source File
114# End Group
115# Begin Source File
116
117SOURCE=.\7zipUninstall.c
118# End Source File
119# Begin Source File
120
121SOURCE=.\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 @@
1Microsoft Developer Studio Workspace File, Format Version 6.00
2# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
3
4###############################################################################
5
6Project: "7zipUninstall"=.\7zipUninstall.dsp - Package Owner=<4>
7
8Package=<5>
9{{{
10}}}
11
12Package=<4>
13{{{
14}}}
15
16###############################################################################
17
18Global:
19
20Package=<5>
21{{{
22}}}
23
24Package=<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
22013-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
22015-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 @@
1PROG = 7zipUninstall.exe
2MY_FIXED = 1
3
4!IFDEF _64BIT_INSTALLER
5CFLAGS = $(CFLAGS) -D_64BIT_INSTALLER
6!ENDIF
7
8MAIN_OBJS = \
9 $O\7zipUninstall.obj \
10
11OBJS = \
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
9MY_VERSION_INFO(MY_VFT_APP, "7-Zip Uninstaller", "Uninstall", "Uninstall.exe")
10
111 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
29IDD_INSTALL DIALOG 0, 0, xs, ys
30STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
31CAPTION "Uninstall 7-Zip"
32FONT 8, "MS Shell Dlg"
33BEGIN
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
43END
44
45#ifndef UNDER_CE
461 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
22021-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
19static const char * const kCantReadMessage = "Cannot read input file";
20static const char * const kCantWriteMessage = "Cannot write output file";
21static const char * const kCantAllocateMessage = "Cannot allocate memory";
22static const char * const kDataErrorMessage = "Data error";
23
24static 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
33static 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
41static 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
57static 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
63static 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
73static 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
127static 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
153static 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
190static 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
280int 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
7CFG=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 ""
28CPP=cl.exe
29RSC=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"
49BSC32=bscmake.exe
50# ADD BASE BSC32 /nologo
51# ADD BSC32 /nologo
52LINK32=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"
74BSC32=bscmake.exe
75# ADD BASE BSC32 /nologo
76# ADD BSC32 /nologo
77LINK32=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
89SOURCE=..\..\7zFile.c
90# End Source File
91# Begin Source File
92
93SOURCE=..\..\7zFile.h
94# End Source File
95# Begin Source File
96
97SOURCE=..\..\7zStream.c
98# End Source File
99# Begin Source File
100
101SOURCE=..\..\7zTypes.h
102# End Source File
103# Begin Source File
104
105SOURCE=..\..\7zVersion.h
106# End Source File
107# Begin Source File
108
109SOURCE=..\..\Alloc.c
110# End Source File
111# Begin Source File
112
113SOURCE=..\..\Alloc.h
114# End Source File
115# Begin Source File
116
117SOURCE=..\..\CpuArch.h
118# End Source File
119# Begin Source File
120
121SOURCE=..\..\LzFind.c
122# End Source File
123# Begin Source File
124
125SOURCE=..\..\LzFind.h
126# End Source File
127# Begin Source File
128
129SOURCE=..\..\LzFindMt.c
130# End Source File
131# Begin Source File
132
133SOURCE=..\..\LzFindMt.h
134# End Source File
135# Begin Source File
136
137SOURCE=..\..\LzFindOpt.c
138# End Source File
139# Begin Source File
140
141SOURCE=..\..\LzHash.h
142# End Source File
143# Begin Source File
144
145SOURCE=..\..\LzmaDec.c
146# End Source File
147# Begin Source File
148
149SOURCE=..\..\LzmaDec.h
150# End Source File
151# Begin Source File
152
153SOURCE=..\..\LzmaEnc.c
154# End Source File
155# Begin Source File
156
157SOURCE=..\..\LzmaEnc.h
158# End Source File
159# Begin Source File
160
161SOURCE=.\LzmaUtil.c
162# End Source File
163# Begin Source File
164
165SOURCE=..\..\Threads.c
166# End Source File
167# Begin Source File
168
169SOURCE=..\..\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 @@
1Microsoft Developer Studio Workspace File, Format Version 6.00
2# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
3
4###############################################################################
5
6Project: "LzmaUtil"=.\LzmaUtil.dsp - Package Owner=<4>
7
8Package=<5>
9{{{
10}}}
11
12Package=<4>
13{{{
14}}}
15
16###############################################################################
17
18Global:
19
20Package=<5>
21{{{
22}}}
23
24Package=<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
2PROG = LZMAc.exe
3
4CFLAGS = $(CFLAGS) \
5
6LIB_OBJS = \
7 $O\LzmaUtil.obj \
8
9C_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
21OBJS = \
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 @@
1PROG = 7lzma
2
3include ../../../CPP/7zip/LzmaDec_gcc.mak
4
5
6OBJS = \
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
21include ../../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 @@
1EXPORTS
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
7CFG=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 ""
28CPP=cl.exe
29MTL=midl.exe
30RSC=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"
52BSC32=bscmake.exe
53# ADD BASE BSC32 /nologo
54# ADD BSC32 /nologo
55LINK32=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"
80BSC32=bscmake.exe
81# ADD BASE BSC32 /nologo
82# ADD BSC32 /nologo
83LINK32=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
98SOURCE=.\LzmaLib.def
99# End Source File
100# Begin Source File
101
102SOURCE=.\LzmaLibExports.c
103# End Source File
104# End Group
105# Begin Source File
106
107SOURCE=..\..\7zTypes.h
108# End Source File
109# Begin Source File
110
111SOURCE=..\..\Alloc.c
112# End Source File
113# Begin Source File
114
115SOURCE=..\..\Alloc.h
116# End Source File
117# Begin Source File
118
119SOURCE=..\..\IStream.h
120# End Source File
121# Begin Source File
122
123SOURCE=..\..\LzFind.c
124# End Source File
125# Begin Source File
126
127SOURCE=..\..\LzFind.h
128# End Source File
129# Begin Source File
130
131SOURCE=..\..\LzFindMt.c
132# End Source File
133# Begin Source File
134
135SOURCE=..\..\LzFindMt.h
136# End Source File
137# Begin Source File
138
139SOURCE=..\..\LzFindOpt.c
140# End Source File
141# Begin Source File
142
143SOURCE=..\..\LzHash.h
144# End Source File
145# Begin Source File
146
147SOURCE=..\..\LzmaDec.c
148# End Source File
149# Begin Source File
150
151SOURCE=..\..\LzmaDec.h
152# End Source File
153# Begin Source File
154
155SOURCE=..\..\LzmaEnc.c
156# End Source File
157# Begin Source File
158
159SOURCE=..\..\LzmaEnc.h
160# End Source File
161# Begin Source File
162
163SOURCE=..\..\LzmaLib.c
164# End Source File
165# Begin Source File
166
167SOURCE=..\..\LzmaLib.h
168# End Source File
169# Begin Source File
170
171SOURCE=.\resource.rc
172# End Source File
173# Begin Source File
174
175SOURCE=..\..\Threads.c
176# End Source File
177# Begin Source File
178
179SOURCE=..\..\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 @@
1Microsoft Developer Studio Workspace File, Format Version 6.00
2# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
3
4###############################################################################
5
6Project: "LzmaLib"=.\LzmaLib.dsp - Package Owner=<4>
7
8Package=<5>
9{{{
10}}}
11
12Package=<4>
13{{{
14}}}
15
16###############################################################################
17
18Global:
19
20Package=<5>
21{{{
22}}}
23
24Package=<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
22015-11-08 : Igor Pavlov : Public domain */
3
4#include "../../Precomp.h"
5
6#include <windows.h>
7
8BOOL 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 @@
1MY_STATIC_LINK=1
2SLIB = sLZMA.lib
3PROG = LZMA.dll
4SLIBPATH = $O\$(SLIB)
5
6DEF_FILE = LzmaLib.def
7CFLAGS = $(CFLAGS) \
8
9LIB_OBJS = \
10 $O\LzmaLibExports.obj \
11
12C_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
23OBJS = \
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
3MY_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
22013-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
22013-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
22019-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
29static 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
43static const char * const kNames[] =
44{
45 "setup"
46 , "install"
47 , "run"
48 , "start"
49};
50
51static 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
69static 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
92static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
93{
94 UNUSED_VAR(ctrlType);
95 return TRUE;
96}
97#endif
98
99static 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
117static 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
130static 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
166static 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
177static 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
231int MY_CDECL main()
232#else
233int 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
7CFG=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 ""
28CPP=cl.exe
29MTL=midl.exe
30RSC=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"
50BSC32=bscmake.exe
51# ADD BASE BSC32 /nologo
52# ADD BSC32 /nologo
53LINK32=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"
76BSC32=bscmake.exe
77# ADD BASE BSC32 /nologo
78# ADD BSC32 /nologo
79LINK32=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
94SOURCE=..\..\7z.h
95# End Source File
96# Begin Source File
97
98SOURCE=..\..\7zAlloc.c
99# End Source File
100# Begin Source File
101
102SOURCE=..\..\7zAlloc.h
103# End Source File
104# Begin Source File
105
106SOURCE=..\..\7zArcIn.c
107# End Source File
108# Begin Source File
109
110SOURCE=..\..\7zBuf.c
111# End Source File
112# Begin Source File
113
114SOURCE=..\..\7zBuf.h
115# End Source File
116# Begin Source File
117
118SOURCE=..\..\7zCrc.c
119# End Source File
120# Begin Source File
121
122SOURCE=..\..\7zCrc.h
123# End Source File
124# Begin Source File
125
126SOURCE=..\..\7zCrcOpt.c
127# End Source File
128# Begin Source File
129
130SOURCE=..\..\7zDec.c
131# End Source File
132# Begin Source File
133
134SOURCE=..\..\7zFile.c
135# End Source File
136# Begin Source File
137
138SOURCE=..\..\7zFile.h
139# End Source File
140# Begin Source File
141
142SOURCE=..\..\7zStream.c
143# End Source File
144# Begin Source File
145
146SOURCE=..\..\7zTypes.h
147# End Source File
148# Begin Source File
149
150SOURCE=..\..\Bcj2.c
151# End Source File
152# Begin Source File
153
154SOURCE=..\..\Bcj2.h
155# End Source File
156# Begin Source File
157
158SOURCE=..\..\Bra.c
159# End Source File
160# Begin Source File
161
162SOURCE=..\..\Bra.h
163# End Source File
164# Begin Source File
165
166SOURCE=..\..\Bra86.c
167# End Source File
168# Begin Source File
169
170SOURCE=..\..\BraIA64.c
171# End Source File
172# Begin Source File
173
174SOURCE=..\..\CpuArch.c
175# End Source File
176# Begin Source File
177
178SOURCE=..\..\CpuArch.h
179# End Source File
180# Begin Source File
181
182SOURCE=..\..\Delta.c
183# End Source File
184# Begin Source File
185
186SOURCE=..\..\Delta.h
187# End Source File
188# Begin Source File
189
190SOURCE=..\..\DllSecur.c
191# End Source File
192# Begin Source File
193
194SOURCE=..\..\DllSecur.h
195# End Source File
196# Begin Source File
197
198SOURCE=..\..\Lzma2Dec.c
199# End Source File
200# Begin Source File
201
202SOURCE=..\..\Lzma2Dec.h
203# End Source File
204# Begin Source File
205
206SOURCE=..\..\LzmaDec.c
207# End Source File
208# Begin Source File
209
210SOURCE=..\..\LzmaDec.h
211# End Source File
212# End Group
213# Begin Group "Spec"
214
215# PROP Default_Filter ""
216# Begin Source File
217
218SOURCE=.\Precomp.c
219# ADD CPP /Yc"Precomp.h"
220# End Source File
221# Begin Source File
222
223SOURCE=.\Precomp.h
224# End Source File
225# End Group
226# Begin Source File
227
228SOURCE=.\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 @@
1Microsoft Developer Studio Workspace File, Format Version 6.00
2# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
3
4###############################################################################
5
6Project: "SfxSetup"=.\SfxSetup.dsp - Package Owner=<4>
7
8Package=<5>
9{{{
10}}}
11
12Package=<4>
13{{{
14}}}
15
16###############################################################################
17
18Global:
19
20Package=<5>
21{{{
22}}}
23
24Package=<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 @@
1PROG = 7zS2.sfx
2MY_FIXED = 1
3
4C_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
247Z_OBJS = \
25 $O\SfxSetup.obj \
26
27OBJS = \
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 @@
1PROG = 7zS2con.sfx
2MY_FIXED = 1
3CFLAGS = $(CFLAGS) -D_CONSOLE
4
5C_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
257Z_OBJS = \
26 $O\SfxSetup.obj \
27
28OBJS = \
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
3MY_VERSION_INFO_APP("7z Setup SFX small", "7zS2.sfx")
4
51 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
diff --git a/C/Xz.c b/C/Xz.c
new file mode 100644
index 0000000..7c53b60
--- /dev/null
+++ b/C/Xz.c
@@ -0,0 +1,90 @@
1/* Xz.c - Xz
22021-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
11const 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
14unsigned 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
27void Xz_Construct(CXzStream *p)
28{
29 p->numBlocks = 0;
30 p->blocks = NULL;
31 p->flags = 0;
32}
33
34void Xz_Free(CXzStream *p, ISzAllocPtr alloc)
35{
36 ISzAlloc_Free(alloc, p->blocks);
37 p->numBlocks = 0;
38 p->blocks = NULL;
39}
40
41unsigned XzFlags_GetCheckSize(CXzStreamFlags f)
42{
43 unsigned t = XzFlags_GetCheckType(f);
44 return (t == 0) ? 0 : ((unsigned)4 << ((t - 1) / 3));
45}
46
47void 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
58void 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
68int 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}
diff --git a/C/Xz.h b/C/Xz.h
new file mode 100644
index 0000000..849b944
--- /dev/null
+++ b/C/Xz.h
@@ -0,0 +1,517 @@
1/* Xz.h - Xz interface
22021-04-01 : Igor Pavlov : Public domain */
3
4#ifndef __XZ_H
5#define __XZ_H
6
7#include "Sha256.h"
8
9EXTERN_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
21unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value);
22unsigned 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
35typedef struct
36{
37 UInt64 id;
38 UInt32 propsSize;
39 Byte props[XZ_FILTER_PROPS_SIZE_MAX];
40} CXzFilter;
41
42typedef 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
55SRes XzBlock_Parse(CXzBlock *p, const Byte *header);
56SRes 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
63extern const Byte XZ_SIG[XZ_SIG_SIZE];
64
65/*
66extern 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
84typedef struct
85{
86 unsigned mode;
87 UInt32 crc;
88 UInt64 crc64;
89 CSha256 sha;
90} CXzCheck;
91
92void XzCheck_Init(CXzCheck *p, unsigned mode);
93void XzCheck_Update(CXzCheck *p, const void *data, size_t size);
94int XzCheck_Final(CXzCheck *p, Byte *digest);
95
96typedef 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)
101unsigned XzFlags_GetCheckSize(CXzStreamFlags f);
102
103SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf);
104SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream);
105
106typedef struct
107{
108 UInt64 unpackSize;
109 UInt64 totalSize;
110} CXzBlockSizes;
111
112typedef struct
113{
114 CXzStreamFlags flags;
115 size_t numBlocks;
116 CXzBlockSizes *blocks;
117 UInt64 startOffset;
118} CXzStream;
119
120void Xz_Construct(CXzStream *p);
121void Xz_Free(CXzStream *p, ISzAllocPtr alloc);
122
123#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1)
124
125UInt64 Xz_GetUnpackSize(const CXzStream *p);
126UInt64 Xz_GetPackSize(const CXzStream *p);
127
128typedef struct
129{
130 size_t num;
131 size_t numAllocated;
132 CXzStream *streams;
133} CXzs;
134
135void Xzs_Construct(CXzs *p);
136void Xzs_Free(CXzs *p, ISzAllocPtr alloc);
137SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAllocPtr alloc);
138
139UInt64 Xzs_GetNumBlocks(const CXzs *p);
140UInt64 Xzs_GetUnpackSize(const CXzs *p);
141
142
143// ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder
144
145typedef 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
156typedef 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
163typedef 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
180typedef 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
203typedef 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
216typedef 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 */
258void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc);
259void XzUnpacker_Init(CXzUnpacker *p);
260void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize);
261void 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/*
310finishMode:
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
315Returns:
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
341SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
342 const Byte *src, SizeT *srcLen, int srcFinished,
343 ECoderFinishMode finishMode, ECoderStatus *status);
344
345SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen,
346 const Byte *src, SizeT *srcLen,
347 ECoderFinishMode finishMode, ECoderStatus *status);
348
349/*
350If you decode full xz stream(s), then you can call XzUnpacker_IsStreamWasFinished()
351after successful XzUnpacker_CodeFull() or after last call of XzUnpacker_Code().
352*/
353
354BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p);
355
356/*
357XzUnpacker_GetExtraSize() returns then number of unconfirmed bytes,
358 if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state.
359These bytes can be some data after xz archive, or
360it can be start of new xz stream.
361
362Call XzUnpacker_GetExtraSize() after XzUnpacker_Code() function to detect real size of
363xz 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
368UInt64 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
383void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p);
384BoolInt 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
419typedef 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
433void XzDecMtProps_Init(CXzDecMtProps *p);
434
435
436typedef 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
443CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid);
444void XzDecMt_Destroy(CXzDecMtHandle p);
445
446
447typedef 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
477void XzStatInfo_Clear(CXzStatInfo *p);
478
479/*
480
481XzDecMt_Decode()
482SRes: 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
502SRes 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
515EXTERN_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
22017-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
32typedef UInt64 (MY_FAST_CALL *CRC64_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table);
33
34static CRC64_FUNC g_Crc64Update;
35UInt64 g_Crc64Table[256 * CRC64_NUM_TABLES];
36
37UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size)
38{
39 return g_Crc64Update(v, data, size, g_Crc64Table);
40}
41
42UInt64 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
47void 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
22013-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
11EXTERN_C_BEGIN
12
13extern UInt64 g_Crc64Table[];
14
15void 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
21UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size);
22UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size);
23
24EXTERN_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
22021-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
12UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
13UInt64 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
49UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
50UInt64 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
22021-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
54unsigned 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
74typedef 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
91static void BraState_Free(void *pp, ISzAllocPtr alloc)
92{
93 ISzAlloc_Free(alloc, pp);
94}
95
96static 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
137static 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
149static 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
174static 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
243SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc);
244SRes 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
273static void SbState_Free(void *pp, ISzAllocPtr alloc)
274{
275 CSbDec *p = (CSbDec *)pp;
276 SbDec_Free(p);
277 ISzAlloc_Free(alloc, pp);
278}
279
280static 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
288static void SbState_Init(void *pp)
289{
290 SbDec_Init((CSbDec *)pp);
291}
292
293static 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
316static 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
342typedef struct
343{
344 CLzma2Dec decoder;
345 BoolInt outBufMode;
346} CLzma2Dec_Spec;
347
348
349static 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
359static 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
372static 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
383static 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
409static 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
436static 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
451static 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
467static 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
487static 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
509static 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
526static 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
542output (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
548static 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
756SRes 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
765static 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
780static 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
807SRes 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
868static 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
919void 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
938void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize)
939{
940 p->outBuf = outBuf;
941 p->outBufSize = outBufSize;
942}
943
944
945void 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
954void XzUnpacker_Free(CXzUnpacker *p)
955{
956 MixCoder_Free(&p->decoder);
957}
958
959
960void 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
971static 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
983SRes 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
1338SRes 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
1352BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p)
1353{
1354 return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0);
1355}
1356
1357BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p)
1358{
1359 return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
1360}
1361
1362UInt64 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
1397void 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
1416typedef 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
1451typedef 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
1514CXzDecMtHandle 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
1558static 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
1578static 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
1598void 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
1635static 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
1837static 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
1892static 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
1973static 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
2296void 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
2333static 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/*
2503XzStatInfo_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
2509static 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
2580SRes 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
22021-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
44static 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
49static 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
56static 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
69static 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
101typedef struct
102{
103 size_t numBlocks;
104 size_t size;
105 size_t allocated;
106 Byte *blocks;
107} CXzEncIndex;
108
109
110static void XzEncIndex_Construct(CXzEncIndex *p)
111{
112 p->numBlocks = 0;
113 p->size = 0;
114 p->allocated = 0;
115 p->blocks = NULL;
116}
117
118static void XzEncIndex_Init(CXzEncIndex *p)
119{
120 p->numBlocks = 0;
121 p->size = 0;
122}
123
124static 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
137static 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
152static 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
174static 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
194static 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
230typedef 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
241static 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
249static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
250{
251 XzCheck_Final(&p->check, digest);
252}
253
254static 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
285typedef struct
286{
287 ISeqOutStream vt;
288 ISeqOutStream *realStream;
289 Byte *outBuf;
290 size_t outBufLimit;
291 UInt64 processed;
292} CSeqSizeOutStream;
293
294static 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
314typedef 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
326SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc);
327
328static 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
345static 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
380static void SeqInFilter_Construct(CSeqInFilter *p)
381{
382 p->buf = NULL;
383 p->StateCoder.p = NULL;
384 p->p.Read = SeqInFilter_Read;
385}
386
387static 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
406typedef struct
407{
408 ISeqInStream vt;
409 ISeqInStream *inStream;
410 CSbEnc enc;
411} CSbEncInStream;
412
413static 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
442void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc)
443{
444 SbEnc_Construct(&p->enc, alloc);
445 p->vt.Read = SbEncInStream_Read;
446}
447
448SRes SbEncInStream_Init(CSbEncInStream *p)
449{
450 return SbEnc_Init(&p->enc);
451}
452
453void SbEncInStream_Free(CSbEncInStream *p)
454{
455 SbEnc_Free(&p->enc);
456}
457
458#endif
459
460
461
462/* ---------- CXzProps ---------- */
463
464
465void XzFilterProps_Init(CXzFilterProps *p)
466{
467 p->id = 0;
468 p->delta = 0;
469 p->ip = 0;
470 p->ipDefined = False;
471}
472
473void 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
489static 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
569static 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
647typedef struct
648{
649 CLzma2EncHandle lzma2;
650 CSeqInFilter filter;
651
652 #ifdef USE_SUBBLOCK
653 CSbEncInStream sb;
654 #endif
655} CLzma2WithFilters;
656
657
658static 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
669static 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
681static 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
696typedef struct
697{
698 UInt64 unpackSize;
699 UInt64 totalSize;
700 size_t headerSize;
701} CXzEncBlockInfo;
702
703
704static 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
906typedef struct
907{
908 ICompressProgress vt;
909 ICompressProgress *progress;
910 UInt64 inOffset;
911 UInt64 outOffset;
912} CCompressProgress_XzEncOffset;
913
914
915static 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
926typedef 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
952static 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
972static 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
985static 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
1005CXzEncHandle 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
1020void 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
1028SRes 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
1037void 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
1048static 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
1108static 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
1129SRes 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
1305SRes 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
1320SRes 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
22017-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
11EXTERN_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
18typedef struct
19{
20 UInt32 id;
21 UInt32 delta;
22 UInt32 ip;
23 int ipDefined;
24} CXzFilterProps;
25
26void XzFilterProps_Init(CXzFilterProps *p);
27
28
29typedef 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
42void XzProps_Init(CXzProps *p);
43
44
45typedef void * CXzEncHandle;
46
47CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig);
48void XzEnc_Destroy(CXzEncHandle p);
49SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props);
50void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize);
51SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress);
52
53SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
54 const CXzProps *props, ICompressProgress *progress);
55
56SRes Xz_EncodeEmpty(ISeqOutStream *outStream);
57
58EXTERN_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
22021-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
18SRes 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
32SRes 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
56UInt64 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
65UInt64 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/*
75SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream)
76{
77 return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
78}
79*/
80
81static 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
125static 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
145static 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
152static 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
247void Xzs_Construct(CXzs *p)
248{
249 p->num = p->numAllocated = 0;
250 p->streams = 0;
251}
252
253void 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
263UInt64 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
272UInt64 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/*
282UInt64 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
292SRes 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 @@
1PLATFORM=
2O=b/c
3IS_X64=
4IS_X86=
5IS_ARM64=
6CROSS_COMPILE=
7MY_ARCH=
8USE_ASM=
9CC=$(CROSS_COMPILE)clang
10CXX=$(CROSS_COMPILE)clang++
11USE_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 @@
1PLATFORM=arm64
2O=b/c_$(PLATFORM)
3IS_X64=
4IS_X86=
5IS_ARM64=1
6CROSS_COMPILE=
7MY_ARCH=
8USE_ASM=1
9CC=$(CROSS_COMPILE)clang
10CXX=$(CROSS_COMPILE)clang++
11USE_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 @@
1PLATFORM=x64
2O=b/c_$(PLATFORM)
3IS_X64=1
4IS_X86=
5IS_ARM64=
6CROSS_COMPILE=
7MY_ARCH=
8USE_ASM=1
9CC=$(CROSS_COMPILE)clang
10CXX=$(CROSS_COMPILE)clang++
11USE_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 @@
1PLATFORM=x86
2O=b/c_$(PLATFORM)
3IS_X64=
4IS_X86=1
5IS_ARM64=
6CROSS_COMPILE=
7MY_ARCH=-m32
8USE_ASM=1
9CC=$(CROSS_COMPILE)clang
10CXX=$(CROSS_COMPILE)clang++
11USE_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 @@
1PLATFORM=
2O=b/g
3IS_X64=
4IS_X86=
5IS_ARM64=
6CROSS_COMPILE=
7MY_ARCH=
8USE_ASM=
9CC=$(CROSS_COMPILE)gcc
10CXX=$(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 @@
1PLATFORM=arm64
2O=b/g_$(PLATFORM)
3IS_X64=
4IS_X86=
5IS_ARM64=1
6CROSS_COMPILE=
7MY_ARCH=-mtune=cortex-a53
8USE_ASM=1
9CC=$(CROSS_COMPILE)gcc
10CXX=$(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 @@
1PLATFORM=x64
2O=b/g_$(PLATFORM)
3IS_X64=1
4IS_X86=
5IS_ARM64=
6CROSS_COMPILE=
7MY_ARCH=
8USE_ASM=1
9CC=$(CROSS_COMPILE)gcc
10CXX=$(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 @@
1PLATFORM=x86
2O=b/g_$(PLATFORM)
3IS_X64=
4IS_X86=1
5IS_ARM64=
6CROSS_COMPILE=
7MY_ARCH=-m32
8USE_ASM=1
9CC=$(CROSS_COMPILE)gcc
10CXX=$(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 @@
1PLATFORM=arm64
2O=b/m_$(PLATFORM)
3IS_X64=
4IS_X86=
5IS_ARM64=1
6CROSS_COMPILE=
7MY_ARCH=-arch arm64
8USE_ASM=1
9CC=$(CROSS_COMPILE)clang
10CXX=$(CROSS_COMPILE)clang++
11USE_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 @@
1PLATFORM=x64
2O=b/m_$(PLATFORM)
3IS_X64=1
4IS_X86=
5IS_ARM64=
6CROSS_COMPILE=
7MY_ARCH=-arch x86_64
8USE_ASM=
9CC=$(CROSS_COMPILE)clang
10CXX=$(CROSS_COMPILE)clang++
11USE_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 @@
1CFLAGS_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
7CFLAGS_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
22CFLAGS_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
31CFLAGS_WARN_1 = \
32 -Wno-deprecated-copy-dtor \
33
34
35
36
37CFLAGS_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 @@
1CFLAGS_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
7CFLAGS_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
22CFLAGS_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
31CFLAGS_WARN_MAC = \
32 -Wno-poison-system-directories \
33 -Wno-c++11-long-long \
34 -Wno-atomic-implicit-seq-cst \
35
36
37CFLAGS_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 @@
1CFLAGS_WARN_GCC_4_5 = \
2
3CFLAGS_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
20CFLAGS_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
45CFLAGS_WARN_GCC_PPMD_UNALIGNED = \
46 -Wno-strict-aliasing \
47
48
49CFLAGS_WARN = $(CFLAGS_WARN_GCC_9) \
50
51# $(CFLAGS_WARN_GCC_PPMD_UNALIGNED)