ce188d4d |
1 | /* 7zMain.c - Test application for 7z Decoder\r |
2 | 2016-05-16 : Igor Pavlov : Public domain */\r |
3 | \r |
4 | #include "Precomp.h"\r |
5 | \r |
6 | #include <stdio.h>\r |
7 | #include <string.h>\r |
8 | \r |
9 | #include "../../7z.h"\r |
10 | #include "../../7zAlloc.h"\r |
11 | #include "../../7zBuf.h"\r |
12 | #include "../../7zCrc.h"\r |
13 | #include "../../7zFile.h"\r |
14 | #include "../../7zVersion.h"\r |
15 | \r |
16 | #ifndef USE_WINDOWS_FILE\r |
17 | /* for mkdir */\r |
18 | #ifdef _WIN32\r |
19 | #include <direct.h>\r |
20 | #else\r |
21 | #include <sys/stat.h>\r |
22 | #include <errno.h>\r |
23 | #endif\r |
24 | #endif\r |
25 | \r |
26 | static ISzAlloc g_Alloc = { SzAlloc, SzFree };\r |
27 | \r |
28 | static int Buf_EnsureSize(CBuf *dest, size_t size)\r |
29 | {\r |
30 | if (dest->size >= size)\r |
31 | return 1;\r |
32 | Buf_Free(dest, &g_Alloc);\r |
33 | return Buf_Create(dest, size, &g_Alloc);\r |
34 | }\r |
35 | \r |
36 | #ifndef _WIN32\r |
37 | #define _USE_UTF8\r |
38 | #endif\r |
39 | \r |
40 | /* #define _USE_UTF8 */\r |
41 | \r |
42 | #ifdef _USE_UTF8\r |
43 | \r |
44 | #define _UTF8_START(n) (0x100 - (1 << (7 - (n))))\r |
45 | \r |
46 | #define _UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6))\r |
47 | \r |
48 | #define _UTF8_HEAD(n, val) ((Byte)(_UTF8_START(n) + (val >> (6 * (n)))))\r |
49 | #define _UTF8_CHAR(n, val) ((Byte)(0x80 + (((val) >> (6 * (n))) & 0x3F)))\r |
50 | \r |
51 | static size_t Utf16_To_Utf8_Calc(const UInt16 *src, const UInt16 *srcLim)\r |
52 | {\r |
53 | size_t size = 0;\r |
54 | for (;;)\r |
55 | {\r |
56 | UInt32 val;\r |
57 | if (src == srcLim)\r |
58 | return size;\r |
59 | \r |
60 | size++;\r |
61 | val = *src++;\r |
62 | \r |
63 | if (val < 0x80)\r |
64 | continue;\r |
65 | \r |
66 | if (val < _UTF8_RANGE(1))\r |
67 | {\r |
68 | size++;\r |
69 | continue;\r |
70 | }\r |
71 | \r |
72 | if (val >= 0xD800 && val < 0xDC00 && src != srcLim)\r |
73 | {\r |
74 | UInt32 c2 = *src;\r |
75 | if (c2 >= 0xDC00 && c2 < 0xE000)\r |
76 | {\r |
77 | src++;\r |
78 | size += 3;\r |
79 | continue;\r |
80 | }\r |
81 | }\r |
82 | \r |
83 | size += 2;\r |
84 | }\r |
85 | }\r |
86 | \r |
87 | static Byte *Utf16_To_Utf8(Byte *dest, const UInt16 *src, const UInt16 *srcLim)\r |
88 | {\r |
89 | for (;;)\r |
90 | {\r |
91 | UInt32 val;\r |
92 | if (src == srcLim)\r |
93 | return dest;\r |
94 | \r |
95 | val = *src++;\r |
96 | \r |
97 | if (val < 0x80)\r |
98 | {\r |
99 | *dest++ = (char)val;\r |
100 | continue;\r |
101 | }\r |
102 | \r |
103 | if (val < _UTF8_RANGE(1))\r |
104 | {\r |
105 | dest[0] = _UTF8_HEAD(1, val);\r |
106 | dest[1] = _UTF8_CHAR(0, val);\r |
107 | dest += 2;\r |
108 | continue;\r |
109 | }\r |
110 | \r |
111 | if (val >= 0xD800 && val < 0xDC00 && src != srcLim)\r |
112 | {\r |
113 | UInt32 c2 = *src;\r |
114 | if (c2 >= 0xDC00 && c2 < 0xE000)\r |
115 | {\r |
116 | src++;\r |
117 | val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;\r |
118 | dest[0] = _UTF8_HEAD(3, val);\r |
119 | dest[1] = _UTF8_CHAR(2, val);\r |
120 | dest[2] = _UTF8_CHAR(1, val);\r |
121 | dest[3] = _UTF8_CHAR(0, val);\r |
122 | dest += 4;\r |
123 | continue;\r |
124 | }\r |
125 | }\r |
126 | \r |
127 | dest[0] = _UTF8_HEAD(2, val);\r |
128 | dest[1] = _UTF8_CHAR(1, val);\r |
129 | dest[2] = _UTF8_CHAR(0, val);\r |
130 | dest += 3;\r |
131 | }\r |
132 | }\r |
133 | \r |
134 | static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen)\r |
135 | {\r |
136 | size_t destLen = Utf16_To_Utf8_Calc(src, src + srcLen);\r |
137 | destLen += 1;\r |
138 | if (!Buf_EnsureSize(dest, destLen))\r |
139 | return SZ_ERROR_MEM;\r |
140 | *Utf16_To_Utf8(dest->data, src, src + srcLen) = 0;\r |
141 | return SZ_OK;\r |
142 | }\r |
143 | \r |
144 | #endif\r |
145 | \r |
146 | static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s\r |
147 | #ifndef _USE_UTF8\r |
148 | , UINT codePage\r |
149 | #endif\r |
150 | )\r |
151 | {\r |
152 | unsigned len = 0;\r |
153 | for (len = 0; s[len] != 0; len++);\r |
154 | \r |
155 | #ifndef _USE_UTF8\r |
156 | {\r |
157 | unsigned size = len * 3 + 100;\r |
158 | if (!Buf_EnsureSize(buf, size))\r |
159 | return SZ_ERROR_MEM;\r |
160 | {\r |
161 | buf->data[0] = 0;\r |
162 | if (len != 0)\r |
163 | {\r |
164 | char defaultChar = '_';\r |
165 | BOOL defUsed;\r |
166 | unsigned numChars = 0;\r |
167 | numChars = WideCharToMultiByte(codePage, 0, s, len, (char *)buf->data, size, &defaultChar, &defUsed);\r |
168 | if (numChars == 0 || numChars >= size)\r |
169 | return SZ_ERROR_FAIL;\r |
170 | buf->data[numChars] = 0;\r |
171 | }\r |
172 | return SZ_OK;\r |
173 | }\r |
174 | }\r |
175 | #else\r |
176 | return Utf16_To_Utf8Buf(buf, s, len);\r |
177 | #endif\r |
178 | }\r |
179 | \r |
180 | #ifdef _WIN32\r |
181 | #ifndef USE_WINDOWS_FILE\r |
182 | static UINT g_FileCodePage = CP_ACP;\r |
183 | #endif\r |
184 | #define MY_FILE_CODE_PAGE_PARAM ,g_FileCodePage\r |
185 | #else\r |
186 | #define MY_FILE_CODE_PAGE_PARAM\r |
187 | #endif\r |
188 | \r |
189 | static WRes MyCreateDir(const UInt16 *name)\r |
190 | {\r |
191 | #ifdef USE_WINDOWS_FILE\r |
192 | \r |
193 | return CreateDirectoryW(name, NULL) ? 0 : GetLastError();\r |
194 | \r |
195 | #else\r |
196 | \r |
197 | CBuf buf;\r |
198 | WRes res;\r |
199 | Buf_Init(&buf);\r |
200 | RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM));\r |
201 | \r |
202 | res =\r |
203 | #ifdef _WIN32\r |
204 | _mkdir((const char *)buf.data)\r |
205 | #else\r |
206 | mkdir((const char *)buf.data, 0777)\r |
207 | #endif\r |
208 | == 0 ? 0 : errno;\r |
209 | Buf_Free(&buf, &g_Alloc);\r |
210 | return res;\r |
211 | \r |
212 | #endif\r |
213 | }\r |
214 | \r |
215 | static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name)\r |
216 | {\r |
217 | #ifdef USE_WINDOWS_FILE\r |
218 | return OutFile_OpenW(p, name);\r |
219 | #else\r |
220 | CBuf buf;\r |
221 | WRes res;\r |
222 | Buf_Init(&buf);\r |
223 | RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM));\r |
224 | res = OutFile_Open(p, (const char *)buf.data);\r |
225 | Buf_Free(&buf, &g_Alloc);\r |
226 | return res;\r |
227 | #endif\r |
228 | }\r |
229 | \r |
230 | static SRes PrintString(const UInt16 *s)\r |
231 | {\r |
232 | CBuf buf;\r |
233 | SRes res;\r |
234 | Buf_Init(&buf);\r |
235 | res = Utf16_To_Char(&buf, s\r |
236 | #ifndef _USE_UTF8\r |
237 | , CP_OEMCP\r |
238 | #endif\r |
239 | );\r |
240 | if (res == SZ_OK)\r |
241 | fputs((const char *)buf.data, stdout);\r |
242 | Buf_Free(&buf, &g_Alloc);\r |
243 | return res;\r |
244 | }\r |
245 | \r |
246 | static void UInt64ToStr(UInt64 value, char *s)\r |
247 | {\r |
248 | char temp[32];\r |
249 | int pos = 0;\r |
250 | do\r |
251 | {\r |
252 | temp[pos++] = (char)('0' + (unsigned)(value % 10));\r |
253 | value /= 10;\r |
254 | }\r |
255 | while (value != 0);\r |
256 | do\r |
257 | *s++ = temp[--pos];\r |
258 | while (pos);\r |
259 | *s = '\0';\r |
260 | }\r |
261 | \r |
262 | static char *UIntToStr(char *s, unsigned value, int numDigits)\r |
263 | {\r |
264 | char temp[16];\r |
265 | int pos = 0;\r |
266 | do\r |
267 | temp[pos++] = (char)('0' + (value % 10));\r |
268 | while (value /= 10);\r |
269 | for (numDigits -= pos; numDigits > 0; numDigits--)\r |
270 | *s++ = '0';\r |
271 | do\r |
272 | *s++ = temp[--pos];\r |
273 | while (pos);\r |
274 | *s = '\0';\r |
275 | return s;\r |
276 | }\r |
277 | \r |
278 | static void UIntToStr_2(char *s, unsigned value)\r |
279 | {\r |
280 | s[0] = (char)('0' + (value / 10));\r |
281 | s[1] = (char)('0' + (value % 10));\r |
282 | }\r |
283 | \r |
284 | #define PERIOD_4 (4 * 365 + 1)\r |
285 | #define PERIOD_100 (PERIOD_4 * 25 - 1)\r |
286 | #define PERIOD_400 (PERIOD_100 * 4 + 1)\r |
287 | \r |
288 | static void ConvertFileTimeToString(const CNtfsFileTime *nt, char *s)\r |
289 | {\r |
290 | unsigned year, mon, hour, min, sec;\r |
291 | Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r |
292 | unsigned t;\r |
293 | UInt32 v;\r |
294 | UInt64 v64 = nt->Low | ((UInt64)nt->High << 32);\r |
295 | v64 /= 10000000;\r |
296 | sec = (unsigned)(v64 % 60); v64 /= 60;\r |
297 | min = (unsigned)(v64 % 60); v64 /= 60;\r |
298 | hour = (unsigned)(v64 % 24); v64 /= 24;\r |
299 | \r |
300 | v = (UInt32)v64;\r |
301 | \r |
302 | year = (unsigned)(1601 + v / PERIOD_400 * 400);\r |
303 | v %= PERIOD_400;\r |
304 | \r |
305 | t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100;\r |
306 | t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4;\r |
307 | t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365;\r |
308 | \r |
309 | if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))\r |
310 | ms[1] = 29;\r |
311 | for (mon = 0;; mon++)\r |
312 | {\r |
313 | unsigned d = ms[mon];\r |
314 | if (v < d)\r |
315 | break;\r |
316 | v -= d;\r |
317 | }\r |
318 | s = UIntToStr(s, year, 4); *s++ = '-';\r |
319 | UIntToStr_2(s, mon + 1); s[2] = '-'; s += 3;\r |
320 | UIntToStr_2(s, (unsigned)v + 1); s[2] = ' '; s += 3;\r |
321 | UIntToStr_2(s, hour); s[2] = ':'; s += 3;\r |
322 | UIntToStr_2(s, min); s[2] = ':'; s += 3;\r |
323 | UIntToStr_2(s, sec); s[2] = 0;\r |
324 | }\r |
325 | \r |
326 | void PrintError(char *sz)\r |
327 | {\r |
328 | printf("\nERROR: %s\n", sz);\r |
329 | }\r |
330 | \r |
331 | static void GetAttribString(UInt32 wa, Bool isDir, char *s)\r |
332 | {\r |
333 | #ifdef USE_WINDOWS_FILE\r |
334 | s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : '.');\r |
335 | s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY ) != 0) ? 'R': '.');\r |
336 | s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN ) != 0) ? 'H': '.');\r |
337 | s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM ) != 0) ? 'S': '.');\r |
338 | s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE ) != 0) ? 'A': '.');\r |
339 | s[5] = 0;\r |
340 | #else\r |
341 | s[0] = (char)(((wa & (1 << 4)) != 0 || isDir) ? 'D' : '.');\r |
342 | s[1] = 0;\r |
343 | #endif\r |
344 | }\r |
345 | \r |
346 | // #define NUM_PARENTS_MAX 128\r |
347 | \r |
348 | int MY_CDECL main(int numargs, char *args[])\r |
349 | {\r |
350 | CFileInStream archiveStream;\r |
351 | CLookToRead lookStream;\r |
352 | CSzArEx db;\r |
353 | SRes res;\r |
354 | ISzAlloc allocImp;\r |
355 | ISzAlloc allocTempImp;\r |
356 | UInt16 *temp = NULL;\r |
357 | size_t tempSize = 0;\r |
358 | // UInt32 parents[NUM_PARENTS_MAX];\r |
359 | \r |
360 | printf("\n7z ANSI-C Decoder " MY_VERSION_COPYRIGHT_DATE "\n\n");\r |
361 | \r |
362 | if (numargs == 1)\r |
363 | {\r |
364 | printf(\r |
365 | "Usage: 7zDec <command> <archive_name>\n\n"\r |
366 | "<Commands>\n"\r |
367 | " e: Extract files from archive (without using directory names)\n"\r |
368 | " l: List contents of archive\n"\r |
369 | " t: Test integrity of archive\n"\r |
370 | " x: eXtract files with full paths\n");\r |
371 | return 0;\r |
372 | }\r |
373 | \r |
374 | if (numargs < 3)\r |
375 | {\r |
376 | PrintError("incorrect command");\r |
377 | return 1;\r |
378 | }\r |
379 | \r |
380 | #if defined(_WIN32) && !defined(USE_WINDOWS_FILE) && !defined(UNDER_CE)\r |
381 | g_FileCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;\r |
382 | #endif\r |
383 | \r |
384 | allocImp.Alloc = SzAlloc;\r |
385 | allocImp.Free = SzFree;\r |
386 | \r |
387 | allocTempImp.Alloc = SzAllocTemp;\r |
388 | allocTempImp.Free = SzFreeTemp;\r |
389 | \r |
390 | #ifdef UNDER_CE\r |
391 | if (InFile_OpenW(&archiveStream.file, L"\test.7z"))\r |
392 | #else\r |
393 | if (InFile_Open(&archiveStream.file, args[2]))\r |
394 | #endif\r |
395 | {\r |
396 | PrintError("can not open input file");\r |
397 | return 1;\r |
398 | }\r |
399 | \r |
400 | FileInStream_CreateVTable(&archiveStream);\r |
401 | LookToRead_CreateVTable(&lookStream, False);\r |
402 | \r |
403 | lookStream.realStream = &archiveStream.s;\r |
404 | LookToRead_Init(&lookStream);\r |
405 | \r |
406 | CrcGenerateTable();\r |
407 | \r |
408 | SzArEx_Init(&db);\r |
409 | \r |
410 | res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);\r |
411 | \r |
412 | if (res == SZ_OK)\r |
413 | {\r |
414 | char *command = args[1];\r |
415 | int listCommand = 0, testCommand = 0, fullPaths = 0;\r |
416 | \r |
417 | if (strcmp(command, "l") == 0) listCommand = 1;\r |
418 | else if (strcmp(command, "t") == 0) testCommand = 1;\r |
419 | else if (strcmp(command, "e") == 0) { }\r |
420 | else if (strcmp(command, "x") == 0) { fullPaths = 1; }\r |
421 | else\r |
422 | {\r |
423 | PrintError("incorrect command");\r |
424 | res = SZ_ERROR_FAIL;\r |
425 | }\r |
426 | \r |
427 | if (res == SZ_OK)\r |
428 | {\r |
429 | UInt32 i;\r |
430 | \r |
431 | /*\r |
432 | if you need cache, use these 3 variables.\r |
433 | if you use external function, you can make these variable as static.\r |
434 | */\r |
435 | UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */\r |
436 | Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */\r |
437 | size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */\r |
438 | \r |
439 | for (i = 0; i < db.NumFiles; i++)\r |
440 | {\r |
441 | size_t offset = 0;\r |
442 | size_t outSizeProcessed = 0;\r |
443 | // const CSzFileItem *f = db.Files + i;\r |
444 | size_t len;\r |
445 | unsigned isDir = SzArEx_IsDir(&db, i);\r |
446 | if (listCommand == 0 && isDir && !fullPaths)\r |
447 | continue;\r |
448 | len = SzArEx_GetFileNameUtf16(&db, i, NULL);\r |
449 | // len = SzArEx_GetFullNameLen(&db, i);\r |
450 | \r |
451 | if (len > tempSize)\r |
452 | {\r |
453 | SzFree(NULL, temp);\r |
454 | tempSize = len;\r |
455 | temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0]));\r |
456 | if (!temp)\r |
457 | {\r |
458 | res = SZ_ERROR_MEM;\r |
459 | break;\r |
460 | }\r |
461 | }\r |
462 | \r |
463 | SzArEx_GetFileNameUtf16(&db, i, temp);\r |
464 | /*\r |
465 | if (SzArEx_GetFullNameUtf16_Back(&db, i, temp + len) != temp)\r |
466 | {\r |
467 | res = SZ_ERROR_FAIL;\r |
468 | break;\r |
469 | }\r |
470 | */\r |
471 | \r |
472 | if (listCommand)\r |
473 | {\r |
474 | char attr[8], s[32], t[32];\r |
475 | UInt64 fileSize;\r |
476 | \r |
477 | GetAttribString(SzBitWithVals_Check(&db.Attribs, i) ? db.Attribs.Vals[i] : 0, isDir, attr);\r |
478 | \r |
479 | fileSize = SzArEx_GetFileSize(&db, i);\r |
480 | UInt64ToStr(fileSize, s);\r |
481 | \r |
482 | if (SzBitWithVals_Check(&db.MTime, i))\r |
483 | ConvertFileTimeToString(&db.MTime.Vals[i], t);\r |
484 | else\r |
485 | {\r |
486 | size_t j;\r |
487 | for (j = 0; j < 19; j++)\r |
488 | t[j] = ' ';\r |
489 | t[j] = '\0';\r |
490 | }\r |
491 | \r |
492 | printf("%s %s %10s ", t, attr, s);\r |
493 | res = PrintString(temp);\r |
494 | if (res != SZ_OK)\r |
495 | break;\r |
496 | if (isDir)\r |
497 | printf("/");\r |
498 | printf("\n");\r |
499 | continue;\r |
500 | }\r |
501 | \r |
502 | fputs(testCommand ?\r |
503 | "Testing ":\r |
504 | "Extracting ",\r |
505 | stdout);\r |
506 | res = PrintString(temp);\r |
507 | if (res != SZ_OK)\r |
508 | break;\r |
509 | \r |
510 | if (isDir)\r |
511 | printf("/");\r |
512 | else\r |
513 | {\r |
514 | res = SzArEx_Extract(&db, &lookStream.s, i,\r |
515 | &blockIndex, &outBuffer, &outBufferSize,\r |
516 | &offset, &outSizeProcessed,\r |
517 | &allocImp, &allocTempImp);\r |
518 | if (res != SZ_OK)\r |
519 | break;\r |
520 | }\r |
521 | \r |
522 | if (!testCommand)\r |
523 | {\r |
524 | CSzFile outFile;\r |
525 | size_t processedSize;\r |
526 | size_t j;\r |
527 | UInt16 *name = (UInt16 *)temp;\r |
528 | const UInt16 *destPath = (const UInt16 *)name;\r |
529 | \r |
530 | for (j = 0; name[j] != 0; j++)\r |
531 | if (name[j] == '/')\r |
532 | {\r |
533 | if (fullPaths)\r |
534 | {\r |
535 | name[j] = 0;\r |
536 | MyCreateDir(name);\r |
537 | name[j] = CHAR_PATH_SEPARATOR;\r |
538 | }\r |
539 | else\r |
540 | destPath = name + j + 1;\r |
541 | }\r |
542 | \r |
543 | if (isDir)\r |
544 | {\r |
545 | MyCreateDir(destPath);\r |
546 | printf("\n");\r |
547 | continue;\r |
548 | }\r |
549 | else if (OutFile_OpenUtf16(&outFile, destPath))\r |
550 | {\r |
551 | PrintError("can not open output file");\r |
552 | res = SZ_ERROR_FAIL;\r |
553 | break;\r |
554 | }\r |
555 | \r |
556 | processedSize = outSizeProcessed;\r |
557 | \r |
558 | if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed)\r |
559 | {\r |
560 | PrintError("can not write output file");\r |
561 | res = SZ_ERROR_FAIL;\r |
562 | break;\r |
563 | }\r |
564 | \r |
565 | if (File_Close(&outFile))\r |
566 | {\r |
567 | PrintError("can not close output file");\r |
568 | res = SZ_ERROR_FAIL;\r |
569 | break;\r |
570 | }\r |
571 | \r |
572 | #ifdef USE_WINDOWS_FILE\r |
573 | if (SzBitWithVals_Check(&db.Attribs, i))\r |
574 | SetFileAttributesW(destPath, db.Attribs.Vals[i]);\r |
575 | #endif\r |
576 | }\r |
577 | printf("\n");\r |
578 | }\r |
579 | IAlloc_Free(&allocImp, outBuffer);\r |
580 | }\r |
581 | }\r |
582 | \r |
583 | SzArEx_Free(&db, &allocImp);\r |
584 | SzFree(NULL, temp);\r |
585 | \r |
586 | File_Close(&archiveStream.file);\r |
587 | \r |
588 | if (res == SZ_OK)\r |
589 | {\r |
590 | printf("\nEverything is Ok\n");\r |
591 | return 0;\r |
592 | }\r |
593 | \r |
594 | if (res == SZ_ERROR_UNSUPPORTED)\r |
595 | PrintError("decoder doesn't support this archive");\r |
596 | else if (res == SZ_ERROR_MEM)\r |
597 | PrintError("can not allocate memory");\r |
598 | else if (res == SZ_ERROR_CRC)\r |
599 | PrintError("CRC error");\r |
600 | else\r |
601 | printf("\nERROR #%d\n", res);\r |
602 | \r |
603 | return 1;\r |
604 | }\r |