diff options
Diffstat (limited to 'C/Util/7z/7zMain.c')
-rw-r--r-- | C/Util/7z/7zMain.c | 887 |
1 files changed, 887 insertions, 0 deletions
diff --git a/C/Util/7z/7zMain.c b/C/Util/7z/7zMain.c new file mode 100644 index 0000000..9d55509 --- /dev/null +++ b/C/Util/7z/7zMain.c | |||
@@ -0,0 +1,887 @@ | |||
1 | /* 7zMain.c - Test application for 7z Decoder | ||
2 | 2021-04-29 : Igor Pavlov : Public domain */ | ||
3 | |||
4 | #include "Precomp.h" | ||
5 | |||
6 | #include <stdio.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | #include "../../CpuArch.h" | ||
10 | |||
11 | #include "../../7z.h" | ||
12 | #include "../../7zAlloc.h" | ||
13 | #include "../../7zBuf.h" | ||
14 | #include "../../7zCrc.h" | ||
15 | #include "../../7zFile.h" | ||
16 | #include "../../7zVersion.h" | ||
17 | |||
18 | #ifndef USE_WINDOWS_FILE | ||
19 | /* for mkdir */ | ||
20 | #ifdef _WIN32 | ||
21 | #include <direct.h> | ||
22 | #else | ||
23 | #include <stdlib.h> | ||
24 | #include <time.h> | ||
25 | #ifdef __GNUC__ | ||
26 | #include <sys/time.h> | ||
27 | #endif | ||
28 | #include <fcntl.h> | ||
29 | // #include <utime.h> | ||
30 | #include <sys/stat.h> | ||
31 | #include <errno.h> | ||
32 | #endif | ||
33 | #endif | ||
34 | |||
35 | |||
36 | #define kInputBufSize ((size_t)1 << 18) | ||
37 | |||
38 | static const ISzAlloc g_Alloc = { SzAlloc, SzFree }; | ||
39 | |||
40 | |||
41 | static void Print(const char *s) | ||
42 | { | ||
43 | fputs(s, stdout); | ||
44 | } | ||
45 | |||
46 | |||
47 | static int Buf_EnsureSize(CBuf *dest, size_t size) | ||
48 | { | ||
49 | if (dest->size >= size) | ||
50 | return 1; | ||
51 | Buf_Free(dest, &g_Alloc); | ||
52 | return Buf_Create(dest, size, &g_Alloc); | ||
53 | } | ||
54 | |||
55 | #ifndef _WIN32 | ||
56 | #define _USE_UTF8 | ||
57 | #endif | ||
58 | |||
59 | /* #define _USE_UTF8 */ | ||
60 | |||
61 | #ifdef _USE_UTF8 | ||
62 | |||
63 | #define _UTF8_START(n) (0x100 - (1 << (7 - (n)))) | ||
64 | |||
65 | #define _UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6)) | ||
66 | |||
67 | #define _UTF8_HEAD(n, val) ((Byte)(_UTF8_START(n) + (val >> (6 * (n))))) | ||
68 | #define _UTF8_CHAR(n, val) ((Byte)(0x80 + (((val) >> (6 * (n))) & 0x3F))) | ||
69 | |||
70 | static size_t Utf16_To_Utf8_Calc(const UInt16 *src, const UInt16 *srcLim) | ||
71 | { | ||
72 | size_t size = 0; | ||
73 | for (;;) | ||
74 | { | ||
75 | UInt32 val; | ||
76 | if (src == srcLim) | ||
77 | return size; | ||
78 | |||
79 | size++; | ||
80 | val = *src++; | ||
81 | |||
82 | if (val < 0x80) | ||
83 | continue; | ||
84 | |||
85 | if (val < _UTF8_RANGE(1)) | ||
86 | { | ||
87 | size++; | ||
88 | continue; | ||
89 | } | ||
90 | |||
91 | if (val >= 0xD800 && val < 0xDC00 && src != srcLim) | ||
92 | { | ||
93 | UInt32 c2 = *src; | ||
94 | if (c2 >= 0xDC00 && c2 < 0xE000) | ||
95 | { | ||
96 | src++; | ||
97 | size += 3; | ||
98 | continue; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | size += 2; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | static Byte *Utf16_To_Utf8(Byte *dest, const UInt16 *src, const UInt16 *srcLim) | ||
107 | { | ||
108 | for (;;) | ||
109 | { | ||
110 | UInt32 val; | ||
111 | if (src == srcLim) | ||
112 | return dest; | ||
113 | |||
114 | val = *src++; | ||
115 | |||
116 | if (val < 0x80) | ||
117 | { | ||
118 | *dest++ = (Byte)val; | ||
119 | continue; | ||
120 | } | ||
121 | |||
122 | if (val < _UTF8_RANGE(1)) | ||
123 | { | ||
124 | dest[0] = _UTF8_HEAD(1, val); | ||
125 | dest[1] = _UTF8_CHAR(0, val); | ||
126 | dest += 2; | ||
127 | continue; | ||
128 | } | ||
129 | |||
130 | if (val >= 0xD800 && val < 0xDC00 && src != srcLim) | ||
131 | { | ||
132 | UInt32 c2 = *src; | ||
133 | if (c2 >= 0xDC00 && c2 < 0xE000) | ||
134 | { | ||
135 | src++; | ||
136 | val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; | ||
137 | dest[0] = _UTF8_HEAD(3, val); | ||
138 | dest[1] = _UTF8_CHAR(2, val); | ||
139 | dest[2] = _UTF8_CHAR(1, val); | ||
140 | dest[3] = _UTF8_CHAR(0, val); | ||
141 | dest += 4; | ||
142 | continue; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | dest[0] = _UTF8_HEAD(2, val); | ||
147 | dest[1] = _UTF8_CHAR(1, val); | ||
148 | dest[2] = _UTF8_CHAR(0, val); | ||
149 | dest += 3; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen) | ||
154 | { | ||
155 | size_t destLen = Utf16_To_Utf8_Calc(src, src + srcLen); | ||
156 | destLen += 1; | ||
157 | if (!Buf_EnsureSize(dest, destLen)) | ||
158 | return SZ_ERROR_MEM; | ||
159 | *Utf16_To_Utf8(dest->data, src, src + srcLen) = 0; | ||
160 | return SZ_OK; | ||
161 | } | ||
162 | |||
163 | #endif | ||
164 | |||
165 | static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s | ||
166 | #ifndef _USE_UTF8 | ||
167 | , UINT codePage | ||
168 | #endif | ||
169 | ) | ||
170 | { | ||
171 | unsigned len = 0; | ||
172 | for (len = 0; s[len] != 0; len++) {} | ||
173 | |||
174 | #ifndef _USE_UTF8 | ||
175 | { | ||
176 | const unsigned size = len * 3 + 100; | ||
177 | if (!Buf_EnsureSize(buf, size)) | ||
178 | return SZ_ERROR_MEM; | ||
179 | { | ||
180 | buf->data[0] = 0; | ||
181 | if (len != 0) | ||
182 | { | ||
183 | const char defaultChar = '_'; | ||
184 | BOOL defUsed; | ||
185 | const unsigned numChars = (unsigned)WideCharToMultiByte( | ||
186 | codePage, 0, (LPCWSTR)s, (int)len, (char *)buf->data, (int)size, &defaultChar, &defUsed); | ||
187 | if (numChars == 0 || numChars >= size) | ||
188 | return SZ_ERROR_FAIL; | ||
189 | buf->data[numChars] = 0; | ||
190 | } | ||
191 | return SZ_OK; | ||
192 | } | ||
193 | } | ||
194 | #else | ||
195 | return Utf16_To_Utf8Buf(buf, s, len); | ||
196 | #endif | ||
197 | } | ||
198 | |||
199 | #ifdef _WIN32 | ||
200 | #ifndef USE_WINDOWS_FILE | ||
201 | static UINT g_FileCodePage = CP_ACP; | ||
202 | #define MY_FILE_CODE_PAGE_PARAM ,g_FileCodePage | ||
203 | #endif | ||
204 | #else | ||
205 | #define MY_FILE_CODE_PAGE_PARAM | ||
206 | #endif | ||
207 | |||
208 | static WRes MyCreateDir(const UInt16 *name) | ||
209 | { | ||
210 | #ifdef USE_WINDOWS_FILE | ||
211 | |||
212 | return CreateDirectoryW((LPCWSTR)name, NULL) ? 0 : GetLastError(); | ||
213 | |||
214 | #else | ||
215 | |||
216 | CBuf buf; | ||
217 | WRes res; | ||
218 | Buf_Init(&buf); | ||
219 | RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)); | ||
220 | |||
221 | res = | ||
222 | #ifdef _WIN32 | ||
223 | _mkdir((const char *)buf.data) | ||
224 | #else | ||
225 | mkdir((const char *)buf.data, 0777) | ||
226 | #endif | ||
227 | == 0 ? 0 : errno; | ||
228 | Buf_Free(&buf, &g_Alloc); | ||
229 | return res; | ||
230 | |||
231 | #endif | ||
232 | } | ||
233 | |||
234 | static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name) | ||
235 | { | ||
236 | #ifdef USE_WINDOWS_FILE | ||
237 | return OutFile_OpenW(p, (LPCWSTR)name); | ||
238 | #else | ||
239 | CBuf buf; | ||
240 | WRes res; | ||
241 | Buf_Init(&buf); | ||
242 | RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)); | ||
243 | res = OutFile_Open(p, (const char *)buf.data); | ||
244 | Buf_Free(&buf, &g_Alloc); | ||
245 | return res; | ||
246 | #endif | ||
247 | } | ||
248 | |||
249 | |||
250 | static SRes PrintString(const UInt16 *s) | ||
251 | { | ||
252 | CBuf buf; | ||
253 | SRes res; | ||
254 | Buf_Init(&buf); | ||
255 | res = Utf16_To_Char(&buf, s | ||
256 | #ifndef _USE_UTF8 | ||
257 | , CP_OEMCP | ||
258 | #endif | ||
259 | ); | ||
260 | if (res == SZ_OK) | ||
261 | Print((const char *)buf.data); | ||
262 | Buf_Free(&buf, &g_Alloc); | ||
263 | return res; | ||
264 | } | ||
265 | |||
266 | static void UInt64ToStr(UInt64 value, char *s, int numDigits) | ||
267 | { | ||
268 | char temp[32]; | ||
269 | int pos = 0; | ||
270 | do | ||
271 | { | ||
272 | temp[pos++] = (char)('0' + (unsigned)(value % 10)); | ||
273 | value /= 10; | ||
274 | } | ||
275 | while (value != 0); | ||
276 | |||
277 | for (numDigits -= pos; numDigits > 0; numDigits--) | ||
278 | *s++ = ' '; | ||
279 | |||
280 | do | ||
281 | *s++ = temp[--pos]; | ||
282 | while (pos); | ||
283 | *s = '\0'; | ||
284 | } | ||
285 | |||
286 | static char *UIntToStr(char *s, unsigned value, int numDigits) | ||
287 | { | ||
288 | char temp[16]; | ||
289 | int pos = 0; | ||
290 | do | ||
291 | temp[pos++] = (char)('0' + (value % 10)); | ||
292 | while (value /= 10); | ||
293 | |||
294 | for (numDigits -= pos; numDigits > 0; numDigits--) | ||
295 | *s++ = '0'; | ||
296 | |||
297 | do | ||
298 | *s++ = temp[--pos]; | ||
299 | while (pos); | ||
300 | *s = '\0'; | ||
301 | return s; | ||
302 | } | ||
303 | |||
304 | static void UIntToStr_2(char *s, unsigned value) | ||
305 | { | ||
306 | s[0] = (char)('0' + (value / 10)); | ||
307 | s[1] = (char)('0' + (value % 10)); | ||
308 | } | ||
309 | |||
310 | |||
311 | #define PERIOD_4 (4 * 365 + 1) | ||
312 | #define PERIOD_100 (PERIOD_4 * 25 - 1) | ||
313 | #define PERIOD_400 (PERIOD_100 * 4 + 1) | ||
314 | |||
315 | |||
316 | |||
317 | #ifndef _WIN32 | ||
318 | |||
319 | // MS uses long for BOOL, but long is 32-bit in MS. So we use int. | ||
320 | // typedef long BOOL; | ||
321 | typedef int BOOL; | ||
322 | |||
323 | typedef struct _FILETIME | ||
324 | { | ||
325 | DWORD dwLowDateTime; | ||
326 | DWORD dwHighDateTime; | ||
327 | } FILETIME; | ||
328 | |||
329 | static LONG TIME_GetBias() | ||
330 | { | ||
331 | time_t utc = time(NULL); | ||
332 | struct tm *ptm = localtime(&utc); | ||
333 | int localdaylight = ptm->tm_isdst; /* daylight for local timezone */ | ||
334 | ptm = gmtime(&utc); | ||
335 | ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */ | ||
336 | LONG bias = (int)(mktime(ptm)-utc); | ||
337 | return bias; | ||
338 | } | ||
339 | |||
340 | #define TICKS_PER_SEC 10000000 | ||
341 | |||
342 | #define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32)) | ||
343 | |||
344 | #define SET_FILETIME(ft, v64) \ | ||
345 | (ft)->dwLowDateTime = (DWORD)v64; \ | ||
346 | (ft)->dwHighDateTime = (DWORD)(v64 >> 32); | ||
347 | |||
348 | #define WINAPI | ||
349 | #define TRUE 1 | ||
350 | |||
351 | static BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime) | ||
352 | { | ||
353 | UInt64 v = GET_TIME_64(fileTime); | ||
354 | v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC); | ||
355 | SET_FILETIME(localFileTime, v); | ||
356 | return TRUE; | ||
357 | } | ||
358 | |||
359 | static const UInt32 kNumTimeQuantumsInSecond = 10000000; | ||
360 | static const UInt32 kFileTimeStartYear = 1601; | ||
361 | static const UInt32 kUnixTimeStartYear = 1970; | ||
362 | static const UInt64 kUnixTimeOffset = | ||
363 | (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); | ||
364 | |||
365 | static Int64 Time_FileTimeToUnixTime64(const FILETIME *ft) | ||
366 | { | ||
367 | UInt64 winTime = GET_TIME_64(ft); | ||
368 | return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; | ||
369 | } | ||
370 | |||
371 | #if defined(_AIX) | ||
372 | #define MY_ST_TIMESPEC st_timespec | ||
373 | #else | ||
374 | #define MY_ST_TIMESPEC timespec | ||
375 | #endif | ||
376 | |||
377 | static void FILETIME_To_timespec(const FILETIME *ft, struct MY_ST_TIMESPEC *ts) | ||
378 | { | ||
379 | if (ft) | ||
380 | { | ||
381 | const Int64 sec = Time_FileTimeToUnixTime64(ft); | ||
382 | // time_t is long | ||
383 | const time_t sec2 = (time_t)sec; | ||
384 | if (sec2 == sec) | ||
385 | { | ||
386 | ts->tv_sec = sec2; | ||
387 | UInt64 winTime = GET_TIME_64(ft); | ||
388 | ts->tv_nsec = (long)((winTime % 10000000) * 100);; | ||
389 | return; | ||
390 | } | ||
391 | } | ||
392 | // else | ||
393 | { | ||
394 | ts->tv_sec = 0; | ||
395 | // ts.tv_nsec = UTIME_NOW; // set to the current time | ||
396 | ts->tv_nsec = UTIME_OMIT; // keep old timesptamp | ||
397 | } | ||
398 | } | ||
399 | |||
400 | static WRes Set_File_FILETIME(const UInt16 *name, const FILETIME *mTime) | ||
401 | { | ||
402 | struct timespec times[2]; | ||
403 | |||
404 | const int flags = 0; // follow link | ||
405 | // = AT_SYMLINK_NOFOLLOW; // don't follow link | ||
406 | |||
407 | CBuf buf; | ||
408 | int res; | ||
409 | Buf_Init(&buf); | ||
410 | RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)); | ||
411 | FILETIME_To_timespec(NULL, ×[0]); | ||
412 | FILETIME_To_timespec(mTime, ×[1]); | ||
413 | res = utimensat(AT_FDCWD, (const char *)buf.data, times, flags); | ||
414 | Buf_Free(&buf, &g_Alloc); | ||
415 | if (res == 0) | ||
416 | return 0; | ||
417 | return errno; | ||
418 | } | ||
419 | |||
420 | #endif | ||
421 | |||
422 | static void NtfsFileTime_to_FILETIME(const CNtfsFileTime *t, FILETIME *ft) | ||
423 | { | ||
424 | ft->dwLowDateTime = (DWORD)(t->Low); | ||
425 | ft->dwHighDateTime = (DWORD)(t->High); | ||
426 | } | ||
427 | |||
428 | static void ConvertFileTimeToString(const CNtfsFileTime *nTime, char *s) | ||
429 | { | ||
430 | unsigned year, mon, hour, min, sec; | ||
431 | Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | ||
432 | unsigned t; | ||
433 | UInt32 v; | ||
434 | // UInt64 v64 = nt->Low | ((UInt64)nt->High << 32); | ||
435 | UInt64 v64; | ||
436 | { | ||
437 | FILETIME fileTime, locTime; | ||
438 | NtfsFileTime_to_FILETIME(nTime, &fileTime); | ||
439 | if (!FileTimeToLocalFileTime(&fileTime, &locTime)) | ||
440 | { | ||
441 | locTime.dwHighDateTime = | ||
442 | locTime.dwLowDateTime = 0; | ||
443 | } | ||
444 | v64 = locTime.dwLowDateTime | ((UInt64)locTime.dwHighDateTime << 32); | ||
445 | } | ||
446 | v64 /= 10000000; | ||
447 | sec = (unsigned)(v64 % 60); v64 /= 60; | ||
448 | min = (unsigned)(v64 % 60); v64 /= 60; | ||
449 | hour = (unsigned)(v64 % 24); v64 /= 24; | ||
450 | |||
451 | v = (UInt32)v64; | ||
452 | |||
453 | year = (unsigned)(1601 + v / PERIOD_400 * 400); | ||
454 | v %= PERIOD_400; | ||
455 | |||
456 | t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100; | ||
457 | t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4; | ||
458 | t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365; | ||
459 | |||
460 | if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) | ||
461 | ms[1] = 29; | ||
462 | for (mon = 0;; mon++) | ||
463 | { | ||
464 | unsigned d = ms[mon]; | ||
465 | if (v < d) | ||
466 | break; | ||
467 | v -= d; | ||
468 | } | ||
469 | s = UIntToStr(s, year, 4); *s++ = '-'; | ||
470 | UIntToStr_2(s, mon + 1); s[2] = '-'; s += 3; | ||
471 | UIntToStr_2(s, (unsigned)v + 1); s[2] = ' '; s += 3; | ||
472 | UIntToStr_2(s, hour); s[2] = ':'; s += 3; | ||
473 | UIntToStr_2(s, min); s[2] = ':'; s += 3; | ||
474 | UIntToStr_2(s, sec); s[2] = 0; | ||
475 | } | ||
476 | |||
477 | static void PrintLF() | ||
478 | { | ||
479 | Print("\n"); | ||
480 | } | ||
481 | |||
482 | static void PrintError(char *s) | ||
483 | { | ||
484 | Print("\nERROR: "); | ||
485 | Print(s); | ||
486 | PrintLF(); | ||
487 | } | ||
488 | |||
489 | static void PrintError_WRes(const char *message, WRes wres) | ||
490 | { | ||
491 | Print("\nERROR: "); | ||
492 | Print(message); | ||
493 | PrintLF(); | ||
494 | { | ||
495 | char s[32]; | ||
496 | UIntToStr(s, (unsigned)wres, 1); | ||
497 | Print("System error code: "); | ||
498 | Print(s); | ||
499 | } | ||
500 | // sprintf(buffer + strlen(buffer), "\nSystem error code: %d", (unsigned)wres); | ||
501 | #ifdef _WIN32 | ||
502 | { | ||
503 | char *s = NULL; | ||
504 | if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||
505 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | ||
506 | NULL, wres, 0, (LPSTR) &s, 0, NULL) != 0 && s) | ||
507 | { | ||
508 | Print(" : "); | ||
509 | Print(s); | ||
510 | LocalFree(s); | ||
511 | } | ||
512 | } | ||
513 | #else | ||
514 | { | ||
515 | const char *s = strerror(wres); | ||
516 | if (s) | ||
517 | { | ||
518 | Print(" : "); | ||
519 | Print(s); | ||
520 | } | ||
521 | } | ||
522 | #endif | ||
523 | PrintLF(); | ||
524 | } | ||
525 | |||
526 | static void GetAttribString(UInt32 wa, BoolInt isDir, char *s) | ||
527 | { | ||
528 | #ifdef USE_WINDOWS_FILE | ||
529 | s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : '.'); | ||
530 | s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY ) != 0) ? 'R': '.'); | ||
531 | s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN ) != 0) ? 'H': '.'); | ||
532 | s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM ) != 0) ? 'S': '.'); | ||
533 | s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE ) != 0) ? 'A': '.'); | ||
534 | s[5] = 0; | ||
535 | #else | ||
536 | s[0] = (char)(((wa & (1 << 4)) != 0 || isDir) ? 'D' : '.'); | ||
537 | s[1] = 0; | ||
538 | #endif | ||
539 | } | ||
540 | |||
541 | |||
542 | // #define NUM_PARENTS_MAX 128 | ||
543 | |||
544 | int MY_CDECL main(int numargs, char *args[]) | ||
545 | { | ||
546 | ISzAlloc allocImp; | ||
547 | ISzAlloc allocTempImp; | ||
548 | |||
549 | CFileInStream archiveStream; | ||
550 | CLookToRead2 lookStream; | ||
551 | CSzArEx db; | ||
552 | SRes res; | ||
553 | UInt16 *temp = NULL; | ||
554 | size_t tempSize = 0; | ||
555 | // UInt32 parents[NUM_PARENTS_MAX]; | ||
556 | |||
557 | Print("\n7z Decoder " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n"); | ||
558 | |||
559 | if (numargs == 1) | ||
560 | { | ||
561 | Print( | ||
562 | "Usage: 7zDec <command> <archive_name>\n\n" | ||
563 | "<Commands>\n" | ||
564 | " e: Extract files from archive (without using directory names)\n" | ||
565 | " l: List contents of archive\n" | ||
566 | " t: Test integrity of archive\n" | ||
567 | " x: eXtract files with full paths\n"); | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | if (numargs < 3) | ||
572 | { | ||
573 | PrintError("incorrect command"); | ||
574 | return 1; | ||
575 | } | ||
576 | |||
577 | #if defined(_WIN32) && !defined(USE_WINDOWS_FILE) && !defined(UNDER_CE) | ||
578 | g_FileCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; | ||
579 | #endif | ||
580 | |||
581 | |||
582 | allocImp = g_Alloc; | ||
583 | allocTempImp = g_Alloc; | ||
584 | |||
585 | { | ||
586 | WRes wres = | ||
587 | #ifdef UNDER_CE | ||
588 | InFile_OpenW(&archiveStream.file, L"\test.7z"); // change it | ||
589 | #else | ||
590 | InFile_Open(&archiveStream.file, args[2]); | ||
591 | #endif | ||
592 | if (wres != 0) | ||
593 | { | ||
594 | PrintError_WRes("cannot open input file", wres); | ||
595 | return 1; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | FileInStream_CreateVTable(&archiveStream); | ||
600 | archiveStream.wres = 0; | ||
601 | LookToRead2_CreateVTable(&lookStream, False); | ||
602 | lookStream.buf = NULL; | ||
603 | |||
604 | res = SZ_OK; | ||
605 | |||
606 | { | ||
607 | lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize); | ||
608 | if (!lookStream.buf) | ||
609 | res = SZ_ERROR_MEM; | ||
610 | else | ||
611 | { | ||
612 | lookStream.bufSize = kInputBufSize; | ||
613 | lookStream.realStream = &archiveStream.vt; | ||
614 | LookToRead2_Init(&lookStream); | ||
615 | } | ||
616 | } | ||
617 | |||
618 | CrcGenerateTable(); | ||
619 | |||
620 | SzArEx_Init(&db); | ||
621 | |||
622 | if (res == SZ_OK) | ||
623 | { | ||
624 | res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp); | ||
625 | } | ||
626 | |||
627 | if (res == SZ_OK) | ||
628 | { | ||
629 | char *command = args[1]; | ||
630 | int listCommand = 0, testCommand = 0, fullPaths = 0; | ||
631 | |||
632 | if (strcmp(command, "l") == 0) listCommand = 1; | ||
633 | else if (strcmp(command, "t") == 0) testCommand = 1; | ||
634 | else if (strcmp(command, "e") == 0) { } | ||
635 | else if (strcmp(command, "x") == 0) { fullPaths = 1; } | ||
636 | else | ||
637 | { | ||
638 | PrintError("incorrect command"); | ||
639 | res = SZ_ERROR_FAIL; | ||
640 | } | ||
641 | |||
642 | if (res == SZ_OK) | ||
643 | { | ||
644 | UInt32 i; | ||
645 | |||
646 | /* | ||
647 | if you need cache, use these 3 variables. | ||
648 | if you use external function, you can make these variable as static. | ||
649 | */ | ||
650 | UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */ | ||
651 | Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */ | ||
652 | size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */ | ||
653 | |||
654 | for (i = 0; i < db.NumFiles; i++) | ||
655 | { | ||
656 | size_t offset = 0; | ||
657 | size_t outSizeProcessed = 0; | ||
658 | // const CSzFileItem *f = db.Files + i; | ||
659 | size_t len; | ||
660 | const BoolInt isDir = SzArEx_IsDir(&db, i); | ||
661 | if (listCommand == 0 && isDir && !fullPaths) | ||
662 | continue; | ||
663 | len = SzArEx_GetFileNameUtf16(&db, i, NULL); | ||
664 | // len = SzArEx_GetFullNameLen(&db, i); | ||
665 | |||
666 | if (len > tempSize) | ||
667 | { | ||
668 | SzFree(NULL, temp); | ||
669 | tempSize = len; | ||
670 | temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0])); | ||
671 | if (!temp) | ||
672 | { | ||
673 | res = SZ_ERROR_MEM; | ||
674 | break; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | SzArEx_GetFileNameUtf16(&db, i, temp); | ||
679 | /* | ||
680 | if (SzArEx_GetFullNameUtf16_Back(&db, i, temp + len) != temp) | ||
681 | { | ||
682 | res = SZ_ERROR_FAIL; | ||
683 | break; | ||
684 | } | ||
685 | */ | ||
686 | |||
687 | if (listCommand) | ||
688 | { | ||
689 | char attr[8], s[32], t[32]; | ||
690 | UInt64 fileSize; | ||
691 | |||
692 | GetAttribString(SzBitWithVals_Check(&db.Attribs, i) ? db.Attribs.Vals[i] : 0, isDir, attr); | ||
693 | |||
694 | fileSize = SzArEx_GetFileSize(&db, i); | ||
695 | UInt64ToStr(fileSize, s, 10); | ||
696 | |||
697 | if (SzBitWithVals_Check(&db.MTime, i)) | ||
698 | ConvertFileTimeToString(&db.MTime.Vals[i], t); | ||
699 | else | ||
700 | { | ||
701 | size_t j; | ||
702 | for (j = 0; j < 19; j++) | ||
703 | t[j] = ' '; | ||
704 | t[j] = '\0'; | ||
705 | } | ||
706 | |||
707 | Print(t); | ||
708 | Print(" "); | ||
709 | Print(attr); | ||
710 | Print(" "); | ||
711 | Print(s); | ||
712 | Print(" "); | ||
713 | res = PrintString(temp); | ||
714 | if (res != SZ_OK) | ||
715 | break; | ||
716 | if (isDir) | ||
717 | Print("/"); | ||
718 | PrintLF(); | ||
719 | continue; | ||
720 | } | ||
721 | |||
722 | Print(testCommand ? | ||
723 | "T ": | ||
724 | "- "); | ||
725 | res = PrintString(temp); | ||
726 | if (res != SZ_OK) | ||
727 | break; | ||
728 | |||
729 | if (isDir) | ||
730 | Print("/"); | ||
731 | else | ||
732 | { | ||
733 | res = SzArEx_Extract(&db, &lookStream.vt, i, | ||
734 | &blockIndex, &outBuffer, &outBufferSize, | ||
735 | &offset, &outSizeProcessed, | ||
736 | &allocImp, &allocTempImp); | ||
737 | if (res != SZ_OK) | ||
738 | break; | ||
739 | } | ||
740 | |||
741 | if (!testCommand) | ||
742 | { | ||
743 | CSzFile outFile; | ||
744 | size_t processedSize; | ||
745 | size_t j; | ||
746 | UInt16 *name = (UInt16 *)temp; | ||
747 | const UInt16 *destPath = (const UInt16 *)name; | ||
748 | |||
749 | for (j = 0; name[j] != 0; j++) | ||
750 | if (name[j] == '/') | ||
751 | { | ||
752 | if (fullPaths) | ||
753 | { | ||
754 | name[j] = 0; | ||
755 | MyCreateDir(name); | ||
756 | name[j] = CHAR_PATH_SEPARATOR; | ||
757 | } | ||
758 | else | ||
759 | destPath = name + j + 1; | ||
760 | } | ||
761 | |||
762 | if (isDir) | ||
763 | { | ||
764 | MyCreateDir(destPath); | ||
765 | PrintLF(); | ||
766 | continue; | ||
767 | } | ||
768 | else | ||
769 | { | ||
770 | WRes wres = OutFile_OpenUtf16(&outFile, destPath); | ||
771 | if (wres != 0) | ||
772 | { | ||
773 | PrintError_WRes("cannot open output file", wres); | ||
774 | res = SZ_ERROR_FAIL; | ||
775 | break; | ||
776 | } | ||
777 | } | ||
778 | |||
779 | processedSize = outSizeProcessed; | ||
780 | |||
781 | { | ||
782 | WRes wres = File_Write(&outFile, outBuffer + offset, &processedSize); | ||
783 | if (wres != 0 || processedSize != outSizeProcessed) | ||
784 | { | ||
785 | PrintError_WRes("cannot write output file", wres); | ||
786 | res = SZ_ERROR_FAIL; | ||
787 | break; | ||
788 | } | ||
789 | } | ||
790 | |||
791 | { | ||
792 | FILETIME mtime; | ||
793 | FILETIME *mtimePtr = NULL; | ||
794 | |||
795 | #ifdef USE_WINDOWS_FILE | ||
796 | FILETIME ctime; | ||
797 | FILETIME *ctimePtr = NULL; | ||
798 | #endif | ||
799 | |||
800 | if (SzBitWithVals_Check(&db.MTime, i)) | ||
801 | { | ||
802 | const CNtfsFileTime *t = &db.MTime.Vals[i]; | ||
803 | mtime.dwLowDateTime = (DWORD)(t->Low); | ||
804 | mtime.dwHighDateTime = (DWORD)(t->High); | ||
805 | mtimePtr = &mtime; | ||
806 | } | ||
807 | |||
808 | #ifdef USE_WINDOWS_FILE | ||
809 | if (SzBitWithVals_Check(&db.CTime, i)) | ||
810 | { | ||
811 | const CNtfsFileTime *t = &db.CTime.Vals[i]; | ||
812 | ctime.dwLowDateTime = (DWORD)(t->Low); | ||
813 | ctime.dwHighDateTime = (DWORD)(t->High); | ||
814 | ctimePtr = &ctime; | ||
815 | } | ||
816 | |||
817 | if (mtimePtr || ctimePtr) | ||
818 | SetFileTime(outFile.handle, ctimePtr, NULL, mtimePtr); | ||
819 | #endif | ||
820 | |||
821 | { | ||
822 | WRes wres = File_Close(&outFile); | ||
823 | if (wres != 0) | ||
824 | { | ||
825 | PrintError_WRes("cannot close output file", wres); | ||
826 | res = SZ_ERROR_FAIL; | ||
827 | break; | ||
828 | } | ||
829 | } | ||
830 | |||
831 | #ifndef USE_WINDOWS_FILE | ||
832 | #ifdef _WIN32 | ||
833 | mtimePtr = mtimePtr; | ||
834 | #else | ||
835 | if (mtimePtr) | ||
836 | Set_File_FILETIME(destPath, mtimePtr); | ||
837 | #endif | ||
838 | #endif | ||
839 | } | ||
840 | |||
841 | #ifdef USE_WINDOWS_FILE | ||
842 | if (SzBitWithVals_Check(&db.Attribs, i)) | ||
843 | { | ||
844 | UInt32 attrib = db.Attribs.Vals[i]; | ||
845 | /* p7zip stores posix attributes in high 16 bits and adds 0x8000 as marker. | ||
846 | We remove posix bits, if we detect posix mode field */ | ||
847 | if ((attrib & 0xF0000000) != 0) | ||
848 | attrib &= 0x7FFF; | ||
849 | SetFileAttributesW((LPCWSTR)destPath, attrib); | ||
850 | } | ||
851 | #endif | ||
852 | } | ||
853 | PrintLF(); | ||
854 | } | ||
855 | ISzAlloc_Free(&allocImp, outBuffer); | ||
856 | } | ||
857 | } | ||
858 | |||
859 | SzFree(NULL, temp); | ||
860 | SzArEx_Free(&db, &allocImp); | ||
861 | ISzAlloc_Free(&allocImp, lookStream.buf); | ||
862 | |||
863 | File_Close(&archiveStream.file); | ||
864 | |||
865 | if (res == SZ_OK) | ||
866 | { | ||
867 | Print("\nEverything is Ok\n"); | ||
868 | return 0; | ||
869 | } | ||
870 | |||
871 | if (res == SZ_ERROR_UNSUPPORTED) | ||
872 | PrintError("decoder doesn't support this archive"); | ||
873 | else if (res == SZ_ERROR_MEM) | ||
874 | PrintError("cannot allocate memory"); | ||
875 | else if (res == SZ_ERROR_CRC) | ||
876 | PrintError("CRC error"); | ||
877 | else if (res == SZ_ERROR_READ /* || archiveStream.Res != 0 */) | ||
878 | PrintError_WRes("Read Error", archiveStream.wres); | ||
879 | else | ||
880 | { | ||
881 | char s[32]; | ||
882 | UInt64ToStr((unsigned)res, s, 0); | ||
883 | PrintError(s); | ||
884 | } | ||
885 | |||
886 | return 1; | ||
887 | } | ||