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