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