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