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