Upload 2.0.2
[physicsfs] / lzma / C / Archive / 7z / 7zMain.c
1 /* 
2 7zMain.c
3 Test application for 7z Decoder
4 LZMA SDK 4.43 Copyright (c) 1999-2006 Igor Pavlov (2006-06-04)
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #ifdef _WIN32
12 #define USE_WINDOWS_FUNCTIONS
13 #endif
14
15 #ifdef USE_WINDOWS_FUNCTIONS
16 #include <windows.h>
17 #endif
18
19 #include "7zIn.h"
20 #include "7zExtract.h"
21
22 #include "../../7zCrc.h"
23
24
25 #ifdef USE_WINDOWS_FUNCTIONS
26 typedef HANDLE MY_FILE_HANDLE;
27 #else
28 typedef FILE *MY_FILE_HANDLE;
29 #endif
30
31 void ConvertNumberToString(CFileSize value, char *s)
32 {
33   char temp[32];
34   int pos = 0;
35   do 
36   {
37     temp[pos++] = (char)('0' + (int)(value % 10));
38     value /= 10;
39   }
40   while (value != 0);
41   do
42     *s++ = temp[--pos];
43   while(pos > 0);
44   *s = '\0';
45 }
46
47 #define PERIOD_4 (4 * 365 + 1)
48 #define PERIOD_100 (PERIOD_4 * 25 - 1)
49 #define PERIOD_400 (PERIOD_100 * 4 + 1)
50
51 void ConvertFileTimeToString(CArchiveFileTime *ft, char *s)
52 {
53   unsigned year, mon, day, hour, min, sec;
54   UInt64 v64 = ft->Low | ((UInt64)ft->High << 32);
55   Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
56   unsigned temp;
57   UInt32 v; 
58   v64 /= 10000000;
59   sec = (unsigned)(v64 % 60);
60   v64 /= 60;
61   min = (unsigned)(v64 % 60);
62   v64 /= 60;
63   hour = (unsigned)(v64 % 24);
64   v64 /= 24;
65
66   v = (UInt32)v64;
67
68   year = (unsigned)(1601 + v / PERIOD_400 * 400);
69   v %= PERIOD_400;
70
71   temp = (unsigned)(v / PERIOD_100);
72   if (temp == 4)
73     temp = 3;
74   year += temp * 100;
75   v -= temp * PERIOD_100;
76
77   temp = v / PERIOD_4;
78   if (temp == 25)
79     temp = 24;
80   year += temp * 4;
81   v -= temp * PERIOD_4;
82
83   temp = v / 365;
84   if (temp == 4)
85     temp = 3;
86   year += temp;
87   v -= temp * 365;
88
89   if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
90     ms[1] = 29;
91   for (mon = 1; mon <= 12; mon++)
92   {
93     unsigned s = ms[mon - 1];
94     if (v < s)
95       break;
96     v -= s;
97   }
98   day = (unsigned)v + 1;
99   sprintf(s, "%04d-%02d-%02d %02d:%02d:%02d", year, mon, day, hour, min, sec);
100 }
101
102
103 #ifdef USE_WINDOWS_FUNCTIONS
104 /*
105    ReadFile and WriteFile functions in Windows have BUG:
106    If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) 
107    from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES 
108    (Insufficient system resources exist to complete the requested service).
109 */
110 #define kChunkSizeMax (1 << 24)
111 #endif
112
113 size_t MyReadFile(MY_FILE_HANDLE file, void *data, size_t size)
114
115   if (size == 0)
116     return 0;
117   #ifdef USE_WINDOWS_FUNCTIONS
118   {
119     size_t processedSize = 0;
120     do
121     {
122       DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
123       DWORD processedLoc = 0;
124       BOOL res = ReadFile(file, data, curSize, &processedLoc, NULL);
125       data = (void *)((unsigned char *)data + processedLoc);
126       size -= processedLoc;
127       processedSize += processedLoc;
128       if (!res || processedLoc == 0)
129         break;
130     }
131     while (size > 0);
132     return processedSize;
133   }
134   #else
135   return fread(data, 1, size, file); 
136   #endif
137 }
138
139 size_t MyWriteFile(MY_FILE_HANDLE file, void *data, size_t size)
140
141   if (size == 0)
142     return 0;
143   #ifdef USE_WINDOWS_FUNCTIONS
144   {
145     size_t processedSize = 0;
146     do
147     {
148       DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
149       DWORD processedLoc = 0;
150       BOOL res = WriteFile(file, data, curSize, &processedLoc, NULL);
151       data = (void *)((unsigned char *)data + processedLoc);
152       size -= processedLoc;
153       processedSize += processedLoc;
154       if (!res)
155         break;
156     }
157     while (size > 0);
158     return processedSize;
159   }
160   #else
161   return fwrite(data, 1, size, file); 
162   #endif
163 }
164
165 int MyCloseFile(MY_FILE_HANDLE file)
166
167   #ifdef USE_WINDOWS_FUNCTIONS
168   return (CloseHandle(file) != FALSE) ? 0 : 1;
169   #else
170   return fclose(file); 
171   #endif
172 }
173
174 typedef struct _CFileInStream
175 {
176   ISzInStream InStream;
177   MY_FILE_HANDLE File;
178 } CFileInStream;
179
180 #ifdef _LZMA_IN_CB
181
182 #define kBufferSize (1 << 12)
183 Byte g_Buffer[kBufferSize];
184
185 SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize)
186 {
187   CFileInStream *s = (CFileInStream *)object;
188   size_t processedSizeLoc;
189   if (maxRequiredSize > kBufferSize)
190     maxRequiredSize = kBufferSize;
191   processedSizeLoc = MyReadFile(s->File, g_Buffer, maxRequiredSize);
192   *buffer = g_Buffer;
193   if (processedSize != 0)
194     *processedSize = processedSizeLoc;
195   return SZ_OK;
196 }
197
198 #else
199
200 SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size, size_t *processedSize)
201 {
202   CFileInStream *s = (CFileInStream *)object;
203   size_t processedSizeLoc = MyReadFile(s->File, buffer, size);
204   if (processedSize != 0)
205     *processedSize = processedSizeLoc;
206   return SZ_OK;
207 }
208
209 #endif
210
211 SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
212 {
213   CFileInStream *s = (CFileInStream *)object;
214
215   #ifdef USE_WINDOWS_FUNCTIONS
216   {
217     LARGE_INTEGER value;
218     value.LowPart = (DWORD)pos;
219     value.HighPart = (LONG)((UInt64)pos >> 32);
220     #ifdef _SZ_FILE_SIZE_32
221     /* VC 6.0 has bug with >> 32 shifts. */
222     value.HighPart = 0;
223     #endif
224     value.LowPart = SetFilePointer(s->File, value.LowPart, &value.HighPart, FILE_BEGIN);
225     if (value.LowPart == 0xFFFFFFFF)
226       if(GetLastError() != NO_ERROR) 
227         return SZE_FAIL;
228     return SZ_OK;
229   }
230   #else
231   int res = fseek(s->File, (long)pos, SEEK_SET);
232   if (res == 0)
233     return SZ_OK;
234   return SZE_FAIL;
235   #endif
236 }
237
238 void PrintError(char *sz)
239 {
240   printf("\nERROR: %s\n", sz);
241 }
242
243 int main(int numargs, char *args[])
244 {
245   CFileInStream archiveStream;
246   CArchiveDatabaseEx db;
247   SZ_RESULT res;
248   ISzAlloc allocImp;
249   ISzAlloc allocTempImp;
250
251   printf("\n7z ANSI-C Decoder 4.48  Copyright (c) 1999-2007 Igor Pavlov  2007-06-21\n");
252   if (numargs == 1)
253   {
254     printf(
255       "\nUsage: 7zDec <command> <archive_name>\n\n"
256       "<Commands>\n"
257       "  e: Extract files from archive\n"
258       "  l: List contents of archive\n"
259       "  t: Test integrity of archive\n");
260     return 0;
261   }
262   if (numargs < 3)
263   {
264     PrintError("incorrect command");
265     return 1;
266   }
267
268   archiveStream.File = 
269   #ifdef USE_WINDOWS_FUNCTIONS
270   CreateFile(args[2], GENERIC_READ, FILE_SHARE_READ, 
271       NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
272   if (archiveStream.File == INVALID_HANDLE_VALUE)
273   #else
274   archiveStream.File = fopen(args[2], "rb");
275   if (archiveStream.File == 0)
276   #endif
277   {
278     PrintError("can not open input file");
279     return 1;
280   }
281
282   archiveStream.InStream.Read = SzFileReadImp;
283   archiveStream.InStream.Seek = SzFileSeekImp;
284
285   allocImp.Alloc = SzAlloc;
286   allocImp.Free = SzFree;
287
288   allocTempImp.Alloc = SzAllocTemp;
289   allocTempImp.Free = SzFreeTemp;
290
291   CrcGenerateTable();
292
293   SzArDbExInit(&db);
294   res = SzArchiveOpen(&archiveStream.InStream, &db, &allocImp, &allocTempImp);
295   if (res == SZ_OK)
296   {
297     char *command = args[1];
298     int listCommand = 0;
299     int testCommand = 0;
300     int extractCommand = 0;
301     if (strcmp(command, "l") == 0)
302       listCommand = 1;
303     if (strcmp(command, "t") == 0)
304       testCommand = 1;
305     else if (strcmp(command, "e") == 0)
306       extractCommand = 1;
307
308     if (listCommand)
309     {
310       UInt32 i;
311       for (i = 0; i < db.Database.NumFiles; i++)
312       {
313         CFileItem *f = db.Database.Files + i;
314         char s[32], t[32];
315         ConvertNumberToString(f->Size, s);
316         if (f->IsLastWriteTimeDefined)
317           ConvertFileTimeToString(&f->LastWriteTime, t);
318         else
319           strcpy(t, "                   ");
320
321         printf("%10s %s  %s\n", s, t, f->Name);
322       }
323     }
324     else if (testCommand || extractCommand)
325     {
326       UInt32 i;
327
328       /*
329       if you need cache, use these 3 variables.
330       if you use external function, you can make these variable as static.
331       */
332       UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
333       Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
334       size_t outBufferSize = 0;  /* it can have any value before first call (if outBuffer = 0) */
335
336       printf("\n");
337       for (i = 0; i < db.Database.NumFiles; i++)
338       {
339         size_t offset;
340         size_t outSizeProcessed;
341         CFileItem *f = db.Database.Files + i;
342         if (f->IsDirectory)
343           printf("Directory ");
344         else
345           printf(testCommand ? 
346             "Testing   ":
347             "Extracting");
348         printf(" %s", f->Name);
349         if (f->IsDirectory)
350         {
351           printf("\n");
352           continue;
353         }
354         res = SzExtract(&archiveStream.InStream, &db, i, 
355             &blockIndex, &outBuffer, &outBufferSize, 
356             &offset, &outSizeProcessed, 
357             &allocImp, &allocTempImp);
358         if (res != SZ_OK)
359           break;
360         if (!testCommand)
361         {
362           MY_FILE_HANDLE outputHandle;
363           size_t processedSize;
364           char *fileName = f->Name;
365           size_t nameLen = strlen(f->Name);
366           for (; nameLen > 0; nameLen--)
367             if (f->Name[nameLen - 1] == '/')
368             {
369               fileName = f->Name + nameLen;
370               break;
371             }
372             
373           outputHandle = 
374           #ifdef USE_WINDOWS_FUNCTIONS
375             CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_READ, 
376                 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
377           if (outputHandle == INVALID_HANDLE_VALUE)
378           #else
379           fopen(fileName, "wb+");
380           if (outputHandle == 0)
381           #endif
382           {
383             PrintError("can not open output file");
384             res = SZE_FAIL;
385             break;
386           }
387           processedSize = MyWriteFile(outputHandle, outBuffer + offset, outSizeProcessed);
388           if (processedSize != outSizeProcessed)
389           {
390             PrintError("can not write output file");
391             res = SZE_FAIL;
392             break;
393           }
394           if (MyCloseFile(outputHandle))
395           {
396             PrintError("can not close output file");
397             res = SZE_FAIL;
398             break;
399           }
400         }
401         printf("\n");
402       }
403       allocImp.Free(outBuffer);
404     }
405     else
406     {
407       PrintError("incorrect command");
408       res = SZE_FAIL;
409     }
410   }
411   SzArDbExFree(&db, allocImp.Free);
412
413   MyCloseFile(archiveStream.File);
414   if (res == SZ_OK)
415   {
416     printf("\nEverything is Ok\n");
417     return 0;
418   }
419   if (res == (SZ_RESULT)SZE_NOTIMPL)
420     PrintError("decoder doesn't support this archive");
421   else if (res == (SZ_RESULT)SZE_OUTOFMEMORY)
422     PrintError("can not allocate memory");
423   else if (res == (SZ_RESULT)SZE_CRC_ERROR)
424     PrintError("CRC error");
425   else     
426     printf("\nERROR #%d\n", res);
427   return 1;
428 }