tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

7zMain.c (16494B)


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