OLD | NEW |
| (Empty) |
1 /* LzmaUtil.c -- Test application for LZMA compression | |
2 2008-11-23 : 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 | |
21 static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } | |
22 static void SzFree(void *p, void *address) { p = p; MyFree(address); } | |
23 static ISzAlloc g_Alloc = { SzAlloc, SzFree }; | |
24 | |
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 | |
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 | |
41 int PrintErrorNumber(char *buffer, SRes val) | |
42 { | |
43 sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val); | |
44 return 1; | |
45 } | |
46 | |
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 | |
55 static SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inS
tream, | |
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 | |
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 | |
134 static SRes Encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 file
Size, 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 | |
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 | |
248 int MY_CDECL main(int numArgs, const char *args[]) | |
249 { | |
250 char rs[800] = { 0 }; | |
251 int res = main2(numArgs, args, rs); | |
252 printf(rs); | |
253 return res; | |
254 } | |
OLD | NEW |