1 /* LzmaUtil.c -- Test application for LZMA compression
2 2023-03-07 : Igor Pavlov : Public domain */
3
4 #include "Precomp.h"
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include "../../CpuArch.h"
11
12 #include "../../Alloc.h"
13 #include "../../7zFile.h"
14 #include "../../7zVersion.h"
15 #include "../../LzFind.h"
16 #include "../../LzmaDec.h"
17 #include "../../LzmaEnc.h"
18
19 static const char * const kCantReadMessage = "Cannot read input file";
20 static const char * const kCantWriteMessage = "Cannot write output file";
21 static const char * const kCantAllocateMessage = "Cannot allocate memory";
22 static const char * const kDataErrorMessage = "Data error";
23
Print(const char * s)24 static void Print(const char *s)
25 {
26 fputs(s, stdout);
27 }
28
PrintHelp(void)29 static void PrintHelp(void)
30 {
31 Print(
32 "\n" "LZMA-C " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE
33 "\n"
34 "\n" "Usage: lzma <e|d> inputFile outputFile"
35 "\n" " e: encode file"
36 "\n" " d: decode file"
37 "\n");
38 }
39
PrintError(const char * message)40 static int PrintError(const char *message)
41 {
42 Print("\nError: ");
43 Print(message);
44 Print("\n");
45 return 1;
46 }
47
48 #define CONVERT_INT_TO_STR(charType, tempSize) \
49 unsigned char temp[tempSize]; unsigned i = 0; \
50 while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \
51 *s++ = (charType)('0' + (unsigned)val); \
52 while (i != 0) { i--; *s++ = (charType)temp[i]; } \
53 *s = 0; \
54 return s;
55
Convert_unsigned_To_str(unsigned val,char * s)56 static char * Convert_unsigned_To_str(unsigned val, char *s)
57 {
58 CONVERT_INT_TO_STR(char, 32)
59 }
60
Print_unsigned(unsigned code)61 static void Print_unsigned(unsigned code)
62 {
63 char str[32];
64 Convert_unsigned_To_str(code, str);
65 Print(str);
66 }
67
PrintError_WRes(const char * message,WRes wres)68 static int PrintError_WRes(const char *message, WRes wres)
69 {
70 PrintError(message);
71 Print("\nSystem error code: ");
72 Print_unsigned((unsigned)wres);
73 #ifndef _WIN32
74 {
75 const char *s = strerror(wres);
76 if (s)
77 {
78 Print(" : ");
79 Print(s);
80 }
81 }
82 #endif
83 Print("\n");
84 return 1;
85 }
86
PrintErrorNumber(SRes val)87 static int PrintErrorNumber(SRes val)
88 {
89 Print("\n7-Zip error code: ");
90 Print_unsigned((unsigned)val);
91 Print("\n");
92 return 1;
93 }
94
PrintUserError(void)95 static int PrintUserError(void)
96 {
97 return PrintError("Incorrect command");
98 }
99
100
101 #define IN_BUF_SIZE (1 << 16)
102 #define OUT_BUF_SIZE (1 << 16)
103
104
Decode2(CLzmaDec * state,ISeqOutStreamPtr outStream,ISeqInStreamPtr inStream,UInt64 unpackSize)105 static SRes Decode2(CLzmaDec *state, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream,
106 UInt64 unpackSize)
107 {
108 const int thereIsSize = (unpackSize != (UInt64)(Int64)-1);
109 Byte inBuf[IN_BUF_SIZE];
110 Byte outBuf[OUT_BUF_SIZE];
111 size_t inPos = 0, inSize = 0, outPos = 0;
112 LzmaDec_Init(state);
113 for (;;)
114 {
115 if (inPos == inSize)
116 {
117 inSize = IN_BUF_SIZE;
118 RINOK(inStream->Read(inStream, inBuf, &inSize))
119 inPos = 0;
120 }
121 {
122 SRes res;
123 SizeT inProcessed = inSize - inPos;
124 SizeT outProcessed = OUT_BUF_SIZE - outPos;
125 ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
126 ELzmaStatus status;
127 if (thereIsSize && outProcessed > unpackSize)
128 {
129 outProcessed = (SizeT)unpackSize;
130 finishMode = LZMA_FINISH_END;
131 }
132
133 res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed,
134 inBuf + inPos, &inProcessed, finishMode, &status);
135 inPos += inProcessed;
136 outPos += outProcessed;
137 unpackSize -= outProcessed;
138
139 if (outStream)
140 if (outStream->Write(outStream, outBuf, outPos) != outPos)
141 return SZ_ERROR_WRITE;
142
143 outPos = 0;
144
145 if (res != SZ_OK || (thereIsSize && unpackSize == 0))
146 return res;
147
148 if (inProcessed == 0 && outProcessed == 0)
149 {
150 if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
151 return SZ_ERROR_DATA;
152 return res;
153 }
154 }
155 }
156 }
157
158
Decode(ISeqOutStreamPtr outStream,ISeqInStreamPtr inStream)159 static SRes Decode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream)
160 {
161 UInt64 unpackSize;
162 int i;
163 SRes res = 0;
164
165 CLzmaDec state;
166
167 /* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
168 unsigned char header[LZMA_PROPS_SIZE + 8];
169
170 /* Read and parse header */
171
172 {
173 size_t size = sizeof(header);
174 RINOK(SeqInStream_ReadMax(inStream, header, &size))
175 if (size != sizeof(header))
176 return SZ_ERROR_INPUT_EOF;
177 }
178 unpackSize = 0;
179 for (i = 0; i < 8; i++)
180 unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8);
181
182 LzmaDec_CONSTRUCT(&state)
183 RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc))
184 res = Decode2(&state, outStream, inStream, unpackSize);
185 LzmaDec_Free(&state, &g_Alloc);
186 return res;
187 }
188
Encode(ISeqOutStreamPtr outStream,ISeqInStreamPtr inStream,UInt64 fileSize)189 static SRes Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, UInt64 fileSize)
190 {
191 CLzmaEncHandle enc;
192 SRes res;
193 CLzmaEncProps props;
194
195 enc = LzmaEnc_Create(&g_Alloc);
196 if (enc == 0)
197 return SZ_ERROR_MEM;
198
199 LzmaEncProps_Init(&props);
200 res = LzmaEnc_SetProps(enc, &props);
201
202 if (res == SZ_OK)
203 {
204 Byte header[LZMA_PROPS_SIZE + 8];
205 size_t headerSize = LZMA_PROPS_SIZE;
206 int i;
207
208 res = LzmaEnc_WriteProperties(enc, header, &headerSize);
209 for (i = 0; i < 8; i++)
210 header[headerSize++] = (Byte)(fileSize >> (8 * i));
211 if (outStream->Write(outStream, header, headerSize) != headerSize)
212 res = SZ_ERROR_WRITE;
213 else
214 {
215 if (res == SZ_OK)
216 res = LzmaEnc_Encode(enc, outStream, inStream, NULL, &g_Alloc, &g_Alloc);
217 }
218 }
219 LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
220 return res;
221 }
222
223
main(int numArgs,const char * args[])224 int Z7_CDECL main(int numArgs, const char *args[])
225 {
226 CFileSeqInStream inStream;
227 CFileOutStream outStream;
228 char c;
229 int res;
230 int encodeMode;
231 BoolInt useOutFile = False;
232
233 LzFindPrepare();
234
235 FileSeqInStream_CreateVTable(&inStream);
236 File_Construct(&inStream.file);
237 inStream.wres = 0;
238
239 FileOutStream_CreateVTable(&outStream);
240 File_Construct(&outStream.file);
241 outStream.wres = 0;
242
243 if (numArgs == 1)
244 {
245 PrintHelp();
246 return 0;
247 }
248
249 if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1)
250 return PrintUserError();
251
252 c = args[1][0];
253 encodeMode = (c == 'e' || c == 'E');
254 if (!encodeMode && c != 'd' && c != 'D')
255 return PrintUserError();
256
257 /*
258 {
259 size_t t4 = sizeof(UInt32);
260 size_t t8 = sizeof(UInt64);
261 if (t4 != 4 || t8 != 8)
262 return PrintError("Incorrect UInt32 or UInt64");
263 }
264 */
265
266 {
267 const WRes wres = InFile_Open(&inStream.file, args[2]);
268 if (wres != 0)
269 return PrintError_WRes("Cannot open input file", wres);
270 }
271
272 if (numArgs > 3)
273 {
274 WRes wres;
275 useOutFile = True;
276 wres = OutFile_Open(&outStream.file, args[3]);
277 if (wres != 0)
278 return PrintError_WRes("Cannot open output file", wres);
279 }
280 else if (encodeMode)
281 PrintUserError();
282
283 if (encodeMode)
284 {
285 UInt64 fileSize;
286 const WRes wres = File_GetLength(&inStream.file, &fileSize);
287 if (wres != 0)
288 return PrintError_WRes("Cannot get file length", wres);
289 res = Encode(&outStream.vt, &inStream.vt, fileSize);
290 }
291 else
292 {
293 res = Decode(&outStream.vt, useOutFile ? &inStream.vt : NULL);
294 }
295
296 if (useOutFile)
297 File_Close(&outStream.file);
298 File_Close(&inStream.file);
299
300 if (res != SZ_OK)
301 {
302 if (res == SZ_ERROR_MEM)
303 return PrintError(kCantAllocateMessage);
304 else if (res == SZ_ERROR_DATA)
305 return PrintError(kDataErrorMessage);
306 else if (res == SZ_ERROR_WRITE)
307 return PrintError_WRes(kCantWriteMessage, outStream.wres);
308 else if (res == SZ_ERROR_READ)
309 return PrintError_WRes(kCantReadMessage, inStream.wres);
310 return PrintErrorNumber(res);
311 }
312 return 0;
313 }
314