xref: /aosp_15_r20/external/lzma/C/Util/Lzma/LzmaUtil.c (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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