misc/libphysfs/lzma/C/Archive/7z/7zMain.c
changeset 13881 99b265e0d1d0
parent 13880 5f819b90d479
child 13882 b172a5d40eee
equal deleted inserted replaced
13880:5f819b90d479 13881:99b265e0d1d0
     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 }