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