• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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