tor-browser

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

List.cpp (33621B)


      1 // List.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../Common/IntToString.h"
      6 #include "../../../Common/MyCom.h"
      7 #include "../../../Common/StdOutStream.h"
      8 #include "../../../Common/StringConvert.h"
      9 #include "../../../Common/UTFConvert.h"
     10 
     11 #include "../../../Windows/ErrorMsg.h"
     12 #include "../../../Windows/FileDir.h"
     13 #include "../../../Windows/PropVariant.h"
     14 #include "../../../Windows/PropVariantConv.h"
     15 
     16 #include "../Common/OpenArchive.h"
     17 #include "../Common/PropIDUtils.h"
     18 
     19 #include "ConsoleClose.h"
     20 #include "List.h"
     21 #include "OpenCallbackConsole.h"
     22 
     23 using namespace NWindows;
     24 using namespace NCOM;
     25 
     26 extern CStdOutStream *g_StdStream;
     27 extern CStdOutStream *g_ErrStream;
     28 
     29 static const char * const kPropIdToName[] =
     30 {
     31    "0"
     32  , "1"
     33  , "2"
     34  , "Path"
     35  , "Name"
     36  , "Extension"
     37  , "Folder"
     38  , "Size"
     39  , "Packed Size"
     40  , "Attributes"
     41  , "Created"
     42  , "Accessed"
     43  , "Modified"
     44  , "Solid"
     45  , "Commented"
     46  , "Encrypted"
     47  , "Split Before"
     48  , "Split After"
     49  , "Dictionary Size"
     50  , "CRC"
     51  , "Type"
     52  , "Anti"
     53  , "Method"
     54  , "Host OS"
     55  , "File System"
     56  , "User"
     57  , "Group"
     58  , "Block"
     59  , "Comment"
     60  , "Position"
     61  , "Path Prefix"
     62  , "Folders"
     63  , "Files"
     64  , "Version"
     65  , "Volume"
     66  , "Multivolume"
     67  , "Offset"
     68  , "Links"
     69  , "Blocks"
     70  , "Volumes"
     71  , "Time Type"
     72  , "64-bit"
     73  , "Big-endian"
     74  , "CPU"
     75  , "Physical Size"
     76  , "Headers Size"
     77  , "Checksum"
     78  , "Characteristics"
     79  , "Virtual Address"
     80  , "ID"
     81  , "Short Name"
     82  , "Creator Application"
     83  , "Sector Size"
     84  , "Mode"
     85  , "Symbolic Link"
     86  , "Error"
     87  , "Total Size"
     88  , "Free Space"
     89  , "Cluster Size"
     90  , "Label"
     91  , "Local Name"
     92  , "Provider"
     93  , "NT Security"
     94  , "Alternate Stream"
     95  , "Aux"
     96  , "Deleted"
     97  , "Tree"
     98  , "SHA-1"
     99  , "SHA-256"
    100  , "Error Type"
    101  , "Errors"
    102  , "Errors"
    103  , "Warnings"
    104  , "Warning"
    105  , "Streams"
    106  , "Alternate Streams"
    107  , "Alternate Streams Size"
    108  , "Virtual Size"
    109  , "Unpack Size"
    110  , "Total Physical Size"
    111  , "Volume Index"
    112  , "SubType"
    113  , "Short Comment"
    114  , "Code Page"
    115  , "Is not archive type"
    116  , "Physical Size can't be detected"
    117  , "Zeros Tail Is Allowed"
    118  , "Tail Size"
    119  , "Embedded Stub Size"
    120  , "Link"
    121  , "Hard Link"
    122  , "iNode"
    123  , "Stream ID"
    124  , "Read-only"
    125  , "Out Name"
    126  , "Copy Link"
    127 };
    128 
    129 static const char kEmptyAttribChar = '.';
    130 
    131 static const char * const kListing = "Listing archive: ";
    132 
    133 static const char * const kString_Files = "files";
    134 static const char * const kString_Dirs = "folders";
    135 static const char * const kString_AltStreams = "alternate streams";
    136 static const char * const kString_Streams = "streams";
    137 
    138 static const char * const kError = "ERROR: ";
    139 
    140 static void GetAttribString(UInt32 wa, bool isDir, bool allAttribs, char *s)
    141 {
    142  if (isDir)
    143    wa |= FILE_ATTRIBUTE_DIRECTORY;
    144  if (allAttribs)
    145  {
    146    ConvertWinAttribToString(s, wa);
    147    return;
    148  }
    149  s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0) ? 'D': kEmptyAttribChar;
    150  s[1] = ((wa & FILE_ATTRIBUTE_READONLY)  != 0) ? 'R': kEmptyAttribChar;
    151  s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN)    != 0) ? 'H': kEmptyAttribChar;
    152  s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM)    != 0) ? 'S': kEmptyAttribChar;
    153  s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE)   != 0) ? 'A': kEmptyAttribChar;
    154  s[5] = 0;
    155 }
    156 
    157 enum EAdjustment
    158 {
    159  kLeft,
    160  kCenter,
    161  kRight
    162 };
    163 
    164 struct CFieldInfo
    165 {
    166  PROPID PropID;
    167  bool IsRawProp;
    168  UString NameU;
    169  AString NameA;
    170  EAdjustment TitleAdjustment;
    171  EAdjustment TextAdjustment;
    172  unsigned PrefixSpacesWidth;
    173  unsigned Width;
    174 };
    175 
    176 struct CFieldInfoInit
    177 {
    178  PROPID PropID;
    179  const char *Name;
    180  EAdjustment TitleAdjustment;
    181  EAdjustment TextAdjustment;
    182  unsigned PrefixSpacesWidth;
    183  unsigned Width;
    184 };
    185 
    186 static const CFieldInfoInit kStandardFieldTable[] =
    187 {
    188  { kpidMTime, "   Date      Time", kLeft, kLeft, 0, 19 },
    189  { kpidAttrib, "Attr", kRight, kCenter, 1, 5 },
    190  { kpidSize, "Size", kRight, kRight, 1, 12 },
    191  { kpidPackSize, "Compressed", kRight, kRight, 1, 12 },
    192  { kpidPath, "Name", kLeft, kLeft, 2, 24 }
    193 };
    194 
    195 const unsigned kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width
    196 static const char *g_Spaces =
    197 "                                " ;
    198 
    199 static void PrintSpaces(unsigned numSpaces)
    200 {
    201  if (numSpaces > 0 && numSpaces <= kNumSpacesMax)
    202    g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces);
    203 }
    204 
    205 static void PrintSpacesToString(char *dest, unsigned numSpaces)
    206 {
    207  unsigned i;
    208  for (i = 0; i < numSpaces; i++)
    209    dest[i] = ' ';
    210  dest[i] = 0;
    211 }
    212 
    213 // extern int g_CodePage;
    214 
    215 static void PrintUString(EAdjustment adj, unsigned width, const UString &s, AString &temp)
    216 {
    217  /*
    218  // we don't need multibyte align.
    219  int codePage = g_CodePage;
    220  if (codePage == -1)
    221    codePage = CP_OEMCP;
    222  if (codePage == CP_UTF8)
    223    ConvertUnicodeToUTF8(s, temp);
    224  else
    225    UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
    226  */
    227 
    228  unsigned numSpaces = 0;
    229 
    230  if (width > s.Len())
    231  {
    232    numSpaces = width - s.Len();
    233    unsigned numLeftSpaces = 0;
    234    switch (adj)
    235    {
    236      case kLeft:   numLeftSpaces = 0; break;
    237      case kCenter: numLeftSpaces = numSpaces / 2; break;
    238      case kRight:  numLeftSpaces = numSpaces; break;
    239    }
    240    PrintSpaces(numLeftSpaces);
    241    numSpaces -= numLeftSpaces;
    242  }
    243  
    244  g_StdOut.PrintUString(s, temp);
    245  PrintSpaces(numSpaces);
    246 }
    247 
    248 static void PrintString(EAdjustment adj, unsigned width, const char *s)
    249 {
    250  unsigned numSpaces = 0;
    251  unsigned len = (unsigned)strlen(s);
    252 
    253  if (width > len)
    254  {
    255    numSpaces = width - len;
    256    unsigned numLeftSpaces = 0;
    257    switch (adj)
    258    {
    259      case kLeft:   numLeftSpaces = 0; break;
    260      case kCenter: numLeftSpaces = numSpaces / 2; break;
    261      case kRight:  numLeftSpaces = numSpaces; break;
    262    }
    263    PrintSpaces(numLeftSpaces);
    264    numSpaces -= numLeftSpaces;
    265  }
    266  
    267  g_StdOut << s;
    268  PrintSpaces(numSpaces);
    269 }
    270 
    271 static void PrintStringToString(char *dest, EAdjustment adj, unsigned width, const char *textString)
    272 {
    273  unsigned numSpaces = 0;
    274  unsigned len = (unsigned)strlen(textString);
    275  
    276  if (width > len)
    277  {
    278    numSpaces = width - len;
    279    unsigned numLeftSpaces = 0;
    280    switch (adj)
    281    {
    282      case kLeft:   numLeftSpaces = 0; break;
    283      case kCenter: numLeftSpaces = numSpaces / 2; break;
    284      case kRight:  numLeftSpaces = numSpaces; break;
    285    }
    286    PrintSpacesToString(dest, numLeftSpaces);
    287    dest += numLeftSpaces;
    288    numSpaces -= numLeftSpaces;
    289  }
    290  
    291  memcpy(dest, textString, len);
    292  dest += len;
    293  PrintSpacesToString(dest, numSpaces);
    294 }
    295 
    296 struct CListUInt64Def
    297 {
    298  UInt64 Val;
    299  bool Def;
    300 
    301  CListUInt64Def(): Val(0), Def(false) {}
    302  void Add(UInt64 v) { Val += v; Def = true; }
    303  void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); }
    304 };
    305 
    306 struct CListFileTimeDef
    307 {
    308  FILETIME Val;
    309  bool Def;
    310 
    311  CListFileTimeDef(): Def(false) { Val.dwLowDateTime = 0; Val.dwHighDateTime = 0; }
    312  void Update(const CListFileTimeDef &t)
    313  {
    314    if (t.Def && (!Def || CompareFileTime(&Val, &t.Val) < 0))
    315    {
    316      Val = t.Val;
    317      Def = true;
    318    }
    319  }
    320 };
    321 
    322 struct CListStat
    323 {
    324  CListUInt64Def Size;
    325  CListUInt64Def PackSize;
    326  CListFileTimeDef MTime;
    327  UInt64 NumFiles;
    328 
    329  CListStat(): NumFiles(0) {}
    330  void Update(const CListStat &st)
    331  {
    332    Size.Add(st.Size);
    333    PackSize.Add(st.PackSize);
    334    MTime.Update(st.MTime);
    335    NumFiles += st.NumFiles;
    336  }
    337  void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; }
    338 };
    339 
    340 struct CListStat2
    341 {
    342  CListStat MainFiles;
    343  CListStat AltStreams;
    344  UInt64 NumDirs;
    345 
    346  CListStat2(): NumDirs(0) {}
    347 
    348  void Update(const CListStat2 &st)
    349  {
    350    MainFiles.Update(st.MainFiles);
    351    AltStreams.Update(st.AltStreams);
    352    NumDirs += st.NumDirs;
    353  }
    354  const UInt64 GetNumStreams() const { return MainFiles.NumFiles + AltStreams.NumFiles; }
    355  CListStat &GetStat(bool altStreamsMode) { return altStreamsMode ? AltStreams : MainFiles; }
    356 };
    357 
    358 class CFieldPrinter
    359 {
    360  CObjectVector<CFieldInfo> _fields;
    361 
    362  void AddProp(const wchar_t *name, PROPID propID, bool isRawProp);
    363 public:
    364  const CArc *Arc;
    365  bool TechMode;
    366  UString FilePath;
    367  AString TempAString;
    368  UString TempWString;
    369  bool IsDir;
    370 
    371  AString LinesString;
    372 
    373  void Clear() { _fields.Clear(); LinesString.Empty(); }
    374  void Init(const CFieldInfoInit *standardFieldTable, unsigned numItems);
    375 
    376  HRESULT AddMainProps(IInArchive *archive);
    377  HRESULT AddRawProps(IArchiveGetRawProps *getRawProps);
    378  
    379  void PrintTitle();
    380  void PrintTitleLines();
    381  HRESULT PrintItemInfo(UInt32 index, const CListStat &st);
    382  void PrintSum(const CListStat &st, UInt64 numDirs, const char *str);
    383  void PrintSum(const CListStat2 &stat2);
    384 };
    385 
    386 void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, unsigned numItems)
    387 {
    388  Clear();
    389  for (unsigned i = 0; i < numItems; i++)
    390  {
    391    CFieldInfo &f = _fields.AddNew();
    392    const CFieldInfoInit &fii = standardFieldTable[i];
    393    f.PropID = fii.PropID;
    394    f.IsRawProp = false;
    395    f.NameA = fii.Name;
    396    f.TitleAdjustment = fii.TitleAdjustment;
    397    f.TextAdjustment = fii.TextAdjustment;
    398    f.PrefixSpacesWidth = fii.PrefixSpacesWidth;
    399    f.Width = fii.Width;
    400 
    401    unsigned k;
    402    for (k = 0; k < fii.PrefixSpacesWidth; k++)
    403      LinesString.Add_Space();
    404    for (k = 0; k < fii.Width; k++)
    405      LinesString += '-';
    406  }
    407 }
    408 
    409 static void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU)
    410 {
    411  if (propID < ARRAY_SIZE(kPropIdToName))
    412  {
    413    nameA = kPropIdToName[propID];
    414    return;
    415  }
    416  if (name)
    417    nameU = name;
    418  else
    419  {
    420    nameA.Empty();
    421    nameA.Add_UInt32(propID);
    422  }
    423 }
    424 
    425 void CFieldPrinter::AddProp(const wchar_t *name, PROPID propID, bool isRawProp)
    426 {
    427  CFieldInfo f;
    428  f.PropID = propID;
    429  f.IsRawProp = isRawProp;
    430  GetPropName(propID, name, f.NameA, f.NameU);
    431  f.NameU += " = ";
    432  if (!f.NameA.IsEmpty())
    433    f.NameA += " = ";
    434  else
    435  {
    436    const UString &s = f.NameU;
    437    AString sA;
    438    unsigned i;
    439    for (i = 0; i < s.Len(); i++)
    440    {
    441      wchar_t c = s[i];
    442      if (c >= 0x80)
    443        break;
    444      sA += (char)c;
    445    }
    446    if (i == s.Len())
    447      f.NameA = sA;
    448  }
    449  _fields.Add(f);
    450 }
    451 
    452 HRESULT CFieldPrinter::AddMainProps(IInArchive *archive)
    453 {
    454  UInt32 numProps;
    455  RINOK(archive->GetNumberOfProperties(&numProps));
    456  for (UInt32 i = 0; i < numProps; i++)
    457  {
    458    CMyComBSTR name;
    459    PROPID propID;
    460    VARTYPE vt;
    461    RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt));
    462    AddProp(name, propID, false);
    463  }
    464  return S_OK;
    465 }
    466 
    467 HRESULT CFieldPrinter::AddRawProps(IArchiveGetRawProps *getRawProps)
    468 {
    469  UInt32 numProps;
    470  RINOK(getRawProps->GetNumRawProps(&numProps));
    471  for (UInt32 i = 0; i < numProps; i++)
    472  {
    473    CMyComBSTR name;
    474    PROPID propID;
    475    RINOK(getRawProps->GetRawPropInfo(i, &name, &propID));
    476    AddProp(name, propID, true);
    477  }
    478  return S_OK;
    479 }
    480 
    481 void CFieldPrinter::PrintTitle()
    482 {
    483  FOR_VECTOR (i, _fields)
    484  {
    485    const CFieldInfo &f = _fields[i];
    486    PrintSpaces(f.PrefixSpacesWidth);
    487    PrintString(f.TitleAdjustment, ((f.PropID == kpidPath) ? 0: f.Width), f.NameA);
    488  }
    489 }
    490 
    491 void CFieldPrinter::PrintTitleLines()
    492 {
    493  g_StdOut << LinesString;
    494 }
    495 
    496 static void PrintTime(char *dest, const FILETIME *ft)
    497 {
    498  *dest = 0;
    499  if (ft->dwLowDateTime == 0 && ft->dwHighDateTime == 0)
    500    return;
    501  ConvertUtcFileTimeToString(*ft, dest, kTimestampPrintLevel_SEC);
    502 }
    503 
    504 #ifndef _SFX
    505 
    506 static inline char GetHex(Byte value)
    507 {
    508  return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
    509 }
    510 
    511 static void HexToString(char *dest, const Byte *data, UInt32 size)
    512 {
    513  for (UInt32 i = 0; i < size; i++)
    514  {
    515    Byte b = data[i];
    516    dest[0] = GetHex((Byte)((b >> 4) & 0xF));
    517    dest[1] = GetHex((Byte)(b & 0xF));
    518    dest += 2;
    519  }
    520  *dest = 0;
    521 }
    522 
    523 #endif
    524 
    525 #define MY_ENDL endl
    526 
    527 HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st)
    528 {
    529  char temp[128];
    530  size_t tempPos = 0;
    531 
    532  bool techMode = this->TechMode;
    533  /*
    534  if (techMode)
    535  {
    536    g_StdOut << "Index = ";
    537    g_StdOut << (UInt64)index;
    538    g_StdOut << endl;
    539  }
    540  */
    541  FOR_VECTOR (i, _fields)
    542  {
    543    const CFieldInfo &f = _fields[i];
    544 
    545    if (!techMode)
    546    {
    547      PrintSpacesToString(temp + tempPos, f.PrefixSpacesWidth);
    548      tempPos += f.PrefixSpacesWidth;
    549    }
    550 
    551    if (techMode)
    552    {
    553      if (!f.NameA.IsEmpty())
    554        g_StdOut << f.NameA;
    555      else
    556        g_StdOut << f.NameU;
    557    }
    558    
    559    if (f.PropID == kpidPath)
    560    {
    561      if (!techMode)
    562        g_StdOut << temp;
    563      g_StdOut.NormalizePrint_UString(FilePath, TempWString, TempAString);
    564      if (techMode)
    565        g_StdOut << MY_ENDL;
    566      continue;
    567    }
    568 
    569    const unsigned width = f.Width;
    570    
    571    if (f.IsRawProp)
    572    {
    573      #ifndef _SFX
    574      
    575      const void *data;
    576      UInt32 dataSize;
    577      UInt32 propType;
    578      RINOK(Arc->GetRawProps->GetRawProp(index, f.PropID, &data, &dataSize, &propType));
    579      
    580      if (dataSize != 0)
    581      {
    582        bool needPrint = true;
    583        
    584        if (f.PropID == kpidNtSecure)
    585        {
    586          if (propType != NPropDataType::kRaw)
    587            return E_FAIL;
    588          #ifndef _SFX
    589          ConvertNtSecureToString((const Byte *)data, dataSize, TempAString);
    590          g_StdOut << TempAString;
    591          needPrint = false;
    592          #endif
    593        }
    594        else if (f.PropID == kpidNtReparse)
    595        {
    596          UString s;
    597          if (ConvertNtReparseToString((const Byte *)data, dataSize, s))
    598          {
    599            needPrint = false;
    600            g_StdOut.PrintUString(s, TempAString);
    601          }
    602        }
    603      
    604        if (needPrint)
    605        {
    606          if (propType != NPropDataType::kRaw)
    607            return E_FAIL;
    608          
    609          const UInt32 kMaxDataSize = 64;
    610          
    611          if (dataSize > kMaxDataSize)
    612          {
    613            g_StdOut << "data:";
    614            g_StdOut << dataSize;
    615          }
    616          else
    617          {
    618            char hexStr[kMaxDataSize * 2 + 4];
    619            HexToString(hexStr, (const Byte *)data, dataSize);
    620            g_StdOut << hexStr;
    621          }
    622        }
    623      }
    624      
    625      #endif
    626    }
    627    else
    628    {
    629      CPropVariant prop;
    630      switch (f.PropID)
    631      {
    632        case kpidSize: if (st.Size.Def) prop = st.Size.Val; break;
    633        case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break;
    634        case kpidMTime: if (st.MTime.Def) prop = st.MTime.Val; break;
    635        default:
    636          RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop));
    637      }
    638      if (f.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4))
    639      {
    640        GetAttribString((prop.vt == VT_EMPTY) ? 0 : prop.ulVal, IsDir, techMode, temp + tempPos);
    641        if (techMode)
    642          g_StdOut << temp + tempPos;
    643        else
    644          tempPos += strlen(temp + tempPos);
    645      }
    646      else if (prop.vt == VT_EMPTY)
    647      {
    648        if (!techMode)
    649        {
    650          PrintSpacesToString(temp + tempPos, width);
    651          tempPos += width;
    652        }
    653      }
    654      else if (prop.vt == VT_FILETIME)
    655      {
    656        PrintTime(temp + tempPos, &prop.filetime);
    657        if (techMode)
    658          g_StdOut << temp + tempPos;
    659        else
    660        {
    661          size_t len = strlen(temp + tempPos);
    662          tempPos += len;
    663          if (len < (unsigned)f.Width)
    664          {
    665            len = f.Width - len;
    666            PrintSpacesToString(temp + tempPos, (unsigned)len);
    667            tempPos += len;
    668          }
    669        }
    670      }
    671      else if (prop.vt == VT_BSTR)
    672      {
    673        TempWString.SetFromBstr(prop.bstrVal);
    674        // do we need multi-line support here ?
    675        g_StdOut.Normalize_UString(TempWString);
    676        if (techMode)
    677        {
    678          g_StdOut.PrintUString(TempWString, TempAString);
    679        }
    680        else
    681          PrintUString(f.TextAdjustment, width, TempWString, TempAString);
    682      }
    683      else
    684      {
    685        char s[64];
    686        ConvertPropertyToShortString2(s, prop, f.PropID);
    687        if (techMode)
    688          g_StdOut << s;
    689        else
    690        {
    691          PrintStringToString(temp + tempPos, f.TextAdjustment, width, s);
    692          tempPos += strlen(temp + tempPos);
    693        }
    694      }
    695    }
    696    if (techMode)
    697      g_StdOut << MY_ENDL;
    698  }
    699  g_StdOut << MY_ENDL;
    700  return S_OK;
    701 }
    702 
    703 static void PrintNumber(EAdjustment adj, unsigned width, const CListUInt64Def &value)
    704 {
    705  char s[32];
    706  s[0] = 0;
    707  if (value.Def)
    708    ConvertUInt64ToString(value.Val, s);
    709  PrintString(adj, width, s);
    710 }
    711 
    712 void Print_UInt64_and_String(AString &s, UInt64 val, const char *name);
    713 
    714 void CFieldPrinter::PrintSum(const CListStat &st, UInt64 numDirs, const char *str)
    715 {
    716  FOR_VECTOR (i, _fields)
    717  {
    718    const CFieldInfo &f = _fields[i];
    719    PrintSpaces(f.PrefixSpacesWidth);
    720    if (f.PropID == kpidSize)
    721      PrintNumber(f.TextAdjustment, f.Width, st.Size);
    722    else if (f.PropID == kpidPackSize)
    723      PrintNumber(f.TextAdjustment, f.Width, st.PackSize);
    724    else if (f.PropID == kpidMTime)
    725    {
    726      char s[64];
    727      s[0] = 0;
    728      if (st.MTime.Def)
    729        PrintTime(s, &st.MTime.Val);
    730      PrintString(f.TextAdjustment, f.Width, s);
    731    }
    732    else if (f.PropID == kpidPath)
    733    {
    734      AString s;
    735      Print_UInt64_and_String(s, st.NumFiles, str);
    736      if (numDirs != 0)
    737      {
    738        s += ", ";
    739        Print_UInt64_and_String(s, numDirs, kString_Dirs);
    740      }
    741      PrintString(f.TextAdjustment, 0, s);
    742    }
    743    else
    744      PrintString(f.TextAdjustment, f.Width, "");
    745  }
    746  g_StdOut << endl;
    747 }
    748 
    749 void CFieldPrinter::PrintSum(const CListStat2 &stat2)
    750 {
    751  PrintSum(stat2.MainFiles, stat2.NumDirs, kString_Files);
    752  if (stat2.AltStreams.NumFiles != 0)
    753  {
    754    PrintSum(stat2.AltStreams, 0, kString_AltStreams);;
    755    CListStat st = stat2.MainFiles;
    756    st.Update(stat2.AltStreams);
    757    PrintSum(st, 0, kString_Streams);
    758  }
    759 }
    760 
    761 static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, CListUInt64Def &value)
    762 {
    763  value.Val = 0;
    764  value.Def = false;
    765  CPropVariant prop;
    766  RINOK(archive->GetProperty(index, propID, &prop));
    767  value.Def = ConvertPropVariantToUInt64(prop, value.Val);
    768  return S_OK;
    769 }
    770 
    771 static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t)
    772 {
    773  t.Val.dwLowDateTime = 0;
    774  t.Val.dwHighDateTime = 0;
    775  t.Def = false;
    776  CPropVariant prop;
    777  RINOK(archive->GetProperty(index, kpidMTime, &prop));
    778  if (prop.vt == VT_FILETIME)
    779  {
    780    t.Val = prop.filetime;
    781    t.Def = true;
    782  }
    783  else if (prop.vt != VT_EMPTY)
    784    return E_FAIL;
    785  return S_OK;
    786 }
    787 
    788 static void PrintPropNameAndNumber(CStdOutStream &so, const char *name, UInt64 val)
    789 {
    790  so << name << ": " << val << endl;
    791 }
    792 
    793 static void PrintPropName_and_Eq(CStdOutStream &so, PROPID propID)
    794 {
    795  const char *s;
    796  char temp[16];
    797  if (propID < ARRAY_SIZE(kPropIdToName))
    798    s = kPropIdToName[propID];
    799  else
    800  {
    801    ConvertUInt32ToString(propID, temp);
    802    s = temp;
    803  }
    804  so << s << " = ";
    805 }
    806 
    807 static void PrintPropNameAndNumber(CStdOutStream &so, PROPID propID, UInt64 val)
    808 {
    809  PrintPropName_and_Eq(so, propID);
    810  so << val << endl;
    811 }
    812 
    813 static void PrintPropNameAndNumber_Signed(CStdOutStream &so, PROPID propID, Int64 val)
    814 {
    815  PrintPropName_and_Eq(so, propID);
    816  so << val << endl;
    817 }
    818 
    819 
    820 static void UString_Replace_CRLF_to_LF(UString &s)
    821 {
    822  // s.Replace(L"\r\n", L"\n");
    823  wchar_t *src = s.GetBuf();
    824  wchar_t *dest = src;
    825  for (;;)
    826  {
    827    wchar_t c = *src++;
    828    if (c == 0)
    829      break;
    830    if (c == '\r' && *src == '\n')
    831    {
    832      src++;
    833      c = '\n';
    834    }
    835    *dest++ = c;
    836  }
    837  s.ReleaseBuf_SetEnd((unsigned)(dest - s.GetBuf()));
    838 }
    839 
    840 
    841 static void PrintPropVal_MultiLine(CStdOutStream &so, const wchar_t *val)
    842 {
    843  UString s = val;
    844  if (s.Find(L'\n') >= 0)
    845  {
    846    so << endl;
    847    so << "{";
    848    so << endl;
    849    UString_Replace_CRLF_to_LF(s);
    850    so.Normalize_UString__LF_Allowed(s);
    851    so << s;
    852    so << endl;
    853    so << "}";
    854  }
    855  else
    856  {
    857    so.Normalize_UString(s);
    858    so << s;
    859  }
    860  so << endl;
    861 }
    862 
    863 
    864 static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val, bool multiLine)
    865 {
    866  so << name << " = ";
    867  if (multiLine)
    868  {
    869    PrintPropVal_MultiLine(so, val);
    870    return;
    871  }
    872  UString s = val;
    873  so.Normalize_UString(s);
    874  so << s;
    875  so << endl;
    876 }
    877 
    878 
    879 static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop)
    880 {
    881  UString s;
    882  ConvertPropertyToString2(s, prop, propID);
    883  if (!s.IsEmpty())
    884  {
    885    AString nameA;
    886    UString nameU;
    887    GetPropName(propID, name, nameA, nameU);
    888    if (!nameA.IsEmpty())
    889      so << nameA;
    890    else
    891      so << nameU;
    892    so << " = ";
    893    PrintPropVal_MultiLine(so, s);
    894  }
    895 }
    896 
    897 static HRESULT PrintArcProp(CStdOutStream &so, IInArchive *archive, PROPID propID, const wchar_t *name)
    898 {
    899  CPropVariant prop;
    900  RINOK(archive->GetArchiveProperty(propID, &prop));
    901  PrintPropertyPair2(so, propID, name, prop);
    902  return S_OK;
    903 }
    904 
    905 static void PrintArcTypeError(CStdOutStream &so, const UString &type, bool isWarning)
    906 {
    907  so << "Open " << (isWarning ? "WARNING" : "ERROR")
    908    << ": Can not open the file as ["
    909    << type
    910    << "] archive"
    911    << endl;
    912 }
    913 
    914 int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name);
    915 
    916 void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
    917 
    918 static void ErrorInfo_Print(CStdOutStream &so, const CArcErrorInfo &er)
    919 {
    920  PrintErrorFlags(so, "ERRORS:", er.GetErrorFlags());
    921  if (!er.ErrorMessage.IsEmpty())
    922    PrintPropPair(so, "ERROR", er.ErrorMessage, true);
    923  
    924  PrintErrorFlags(so, "WARNINGS:", er.GetWarningFlags());
    925  if (!er.WarningMessage.IsEmpty())
    926    PrintPropPair(so, "WARNING", er.WarningMessage, true);
    927 }
    928 
    929 HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink)
    930 {
    931  FOR_VECTOR (r, arcLink.Arcs)
    932  {
    933    const CArc &arc = arcLink.Arcs[r];
    934    const CArcErrorInfo &er = arc.ErrorInfo;
    935    
    936    so << "--\n";
    937    PrintPropPair(so, "Path", arc.Path, false);
    938    if (er.ErrorFormatIndex >= 0)
    939    {
    940      if (er.ErrorFormatIndex == arc.FormatIndex)
    941        so << "Warning: The archive is open with offset" << endl;
    942      else
    943        PrintArcTypeError(so, codecs->GetFormatNamePtr(er.ErrorFormatIndex), true);
    944    }
    945    PrintPropPair(so, "Type", codecs->GetFormatNamePtr(arc.FormatIndex), false);
    946    
    947    ErrorInfo_Print(so, er);
    948    
    949    Int64 offset = arc.GetGlobalOffset();
    950    if (offset != 0)
    951      PrintPropNameAndNumber_Signed(so, kpidOffset, offset);
    952    IInArchive *archive = arc.Archive;
    953    RINOK(PrintArcProp(so, archive, kpidPhySize, NULL));
    954    if (er.TailSize != 0)
    955      PrintPropNameAndNumber(so, kpidTailSize, er.TailSize);
    956    {
    957      UInt32 numProps;
    958      RINOK(archive->GetNumberOfArchiveProperties(&numProps));
    959      
    960      for (UInt32 j = 0; j < numProps; j++)
    961      {
    962        CMyComBSTR name;
    963        PROPID propID;
    964        VARTYPE vt;
    965        RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt));
    966        RINOK(PrintArcProp(so, archive, propID, name));
    967      }
    968    }
    969    
    970    if (r != arcLink.Arcs.Size() - 1)
    971    {
    972      UInt32 numProps;
    973      so << "----\n";
    974      if (archive->GetNumberOfProperties(&numProps) == S_OK)
    975      {
    976        UInt32 mainIndex = arcLink.Arcs[r + 1].SubfileIndex;
    977        for (UInt32 j = 0; j < numProps; j++)
    978        {
    979          CMyComBSTR name;
    980          PROPID propID;
    981          VARTYPE vt;
    982          RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt));
    983          CPropVariant prop;
    984          RINOK(archive->GetProperty(mainIndex, propID, &prop));
    985          PrintPropertyPair2(so, propID, name, prop);
    986        }
    987      }
    988    }
    989  }
    990  return S_OK;
    991 }
    992 
    993 HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink)
    994 {
    995  #ifndef _NO_CRYPTO
    996  if (arcLink.PasswordWasAsked)
    997    so << "Can not open encrypted archive. Wrong password?";
    998  else
    999  #endif
   1000  {
   1001    if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
   1002    {
   1003      so.NormalizePrint_UString(arcLink.NonOpen_ArcPath);
   1004      so << endl;
   1005      PrintArcTypeError(so, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
   1006    }
   1007    else
   1008      so << "Can not open the file as archive";
   1009  }
   1010 
   1011  so << endl;
   1012  so << endl;
   1013  ErrorInfo_Print(so, arcLink.NonOpen_ErrorInfo);
   1014 
   1015  return S_OK;
   1016 }
   1017 
   1018 bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
   1019 
   1020 HRESULT ListArchives(CCodecs *codecs,
   1021    const CObjectVector<COpenType> &types,
   1022    const CIntVector &excludedFormats,
   1023    bool stdInMode,
   1024    UStringVector &arcPaths, UStringVector &arcPathsFull,
   1025    bool processAltStreams, bool showAltStreams,
   1026    const NWildcard::CCensorNode &wildcardCensor,
   1027    bool enableHeaders, bool techMode,
   1028    #ifndef _NO_CRYPTO
   1029    bool &passwordEnabled, UString &password,
   1030    #endif
   1031    #ifndef _SFX
   1032    const CObjectVector<CProperty> *props,
   1033    #endif
   1034    UInt64 &numErrors,
   1035    UInt64 &numWarnings)
   1036 {
   1037  bool allFilesAreAllowed = wildcardCensor.AreAllAllowed();
   1038 
   1039  numErrors = 0;
   1040  numWarnings = 0;
   1041 
   1042  CFieldPrinter fp;
   1043  if (!techMode)
   1044    fp.Init(kStandardFieldTable, ARRAY_SIZE(kStandardFieldTable));
   1045 
   1046  CListStat2 stat2total;
   1047  
   1048  CBoolArr skipArcs(arcPaths.Size());
   1049  unsigned arcIndex;
   1050  for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
   1051    skipArcs[arcIndex] = false;
   1052  UInt64 numVolumes = 0;
   1053  UInt64 numArcs = 0;
   1054  UInt64 totalArcSizes = 0;
   1055 
   1056  HRESULT lastError = 0;
   1057 
   1058  for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
   1059  {
   1060    if (skipArcs[arcIndex])
   1061      continue;
   1062    const UString &arcPath = arcPaths[arcIndex];
   1063    UInt64 arcPackSize = 0;
   1064    
   1065    if (!stdInMode)
   1066    {
   1067      NFile::NFind::CFileInfo fi;
   1068      if (!fi.Find(us2fs(arcPath)))
   1069      {
   1070        DWORD errorCode = GetLastError();
   1071        if (errorCode == 0)
   1072          errorCode = ERROR_FILE_NOT_FOUND;
   1073        lastError = HRESULT_FROM_WIN32(lastError);;
   1074        g_StdOut.Flush();
   1075        *g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) << endl;
   1076        g_ErrStream->NormalizePrint_UString(arcPath);
   1077        *g_ErrStream << endl << endl;
   1078        numErrors++;
   1079        continue;
   1080      }
   1081      if (fi.IsDir())
   1082      {
   1083        g_StdOut.Flush();
   1084        *g_ErrStream << endl << kError;
   1085        g_ErrStream->NormalizePrint_UString(arcPath);
   1086        *g_ErrStream << " is not a file" << endl << endl;
   1087        numErrors++;
   1088        continue;
   1089      }
   1090      arcPackSize = fi.Size;
   1091      totalArcSizes += arcPackSize;
   1092    }
   1093 
   1094    CArchiveLink arcLink;
   1095 
   1096    COpenCallbackConsole openCallback;
   1097    openCallback.Init(&g_StdOut, g_ErrStream, NULL);
   1098 
   1099    #ifndef _NO_CRYPTO
   1100 
   1101    openCallback.PasswordIsDefined = passwordEnabled;
   1102    openCallback.Password = password;
   1103 
   1104    #endif
   1105 
   1106    /*
   1107    CObjectVector<COptionalOpenProperties> optPropsVector;
   1108    COptionalOpenProperties &optProps = optPropsVector.AddNew();
   1109    optProps.Props = *props;
   1110    */
   1111    
   1112    COpenOptions options;
   1113    #ifndef _SFX
   1114    options.props = props;
   1115    #endif
   1116    options.codecs = codecs;
   1117    options.types = &types;
   1118    options.excludedFormats = &excludedFormats;
   1119    options.stdInMode = stdInMode;
   1120    options.stream = NULL;
   1121    options.filePath = arcPath;
   1122 
   1123    if (enableHeaders)
   1124    {
   1125      g_StdOut << endl << kListing;
   1126      g_StdOut.NormalizePrint_UString(arcPath);
   1127      g_StdOut << endl << endl;
   1128    }
   1129    
   1130    HRESULT result = arcLink.Open_Strict(options, &openCallback);
   1131 
   1132    if (result != S_OK)
   1133    {
   1134      if (result == E_ABORT)
   1135        return result;
   1136      g_StdOut.Flush();
   1137      *g_ErrStream << endl << kError;
   1138      g_ErrStream->NormalizePrint_UString(arcPath);
   1139      *g_ErrStream << " : ";
   1140      if (result == S_FALSE)
   1141      {
   1142        Print_OpenArchive_Error(*g_ErrStream, codecs, arcLink);
   1143      }
   1144      else
   1145      {
   1146        lastError = result;
   1147        *g_ErrStream << "opening : ";
   1148        if (result == E_OUTOFMEMORY)
   1149          *g_ErrStream << "Can't allocate required memory";
   1150        else
   1151          *g_ErrStream << NError::MyFormatMessage(result);
   1152      }
   1153      *g_ErrStream << endl;
   1154      numErrors++;
   1155      continue;
   1156    }
   1157    
   1158    {
   1159      FOR_VECTOR (r, arcLink.Arcs)
   1160      {
   1161        const CArcErrorInfo &arc = arcLink.Arcs[r].ErrorInfo;
   1162        if (!arc.WarningMessage.IsEmpty())
   1163          numWarnings++;
   1164        if (arc.AreThereWarnings())
   1165          numWarnings++;
   1166        if (arc.ErrorFormatIndex >= 0)
   1167          numWarnings++;
   1168        if (arc.AreThereErrors())
   1169        {
   1170          numErrors++;
   1171          // break;
   1172        }
   1173        if (!arc.ErrorMessage.IsEmpty())
   1174          numErrors++;
   1175      }
   1176    }
   1177 
   1178    numArcs++;
   1179    numVolumes++;
   1180 
   1181    if (!stdInMode)
   1182    {
   1183      numVolumes += arcLink.VolumePaths.Size();
   1184      totalArcSizes += arcLink.VolumesSize;
   1185      FOR_VECTOR (v, arcLink.VolumePaths)
   1186      {
   1187        int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]);
   1188        if (index >= 0 && (unsigned)index > arcIndex)
   1189          skipArcs[(unsigned)index] = true;
   1190      }
   1191    }
   1192 
   1193 
   1194    if (enableHeaders)
   1195    {
   1196      RINOK(Print_OpenArchive_Props(g_StdOut, codecs, arcLink));
   1197 
   1198      g_StdOut << endl;
   1199      if (techMode)
   1200        g_StdOut << "----------\n";
   1201    }
   1202 
   1203    if (enableHeaders && !techMode)
   1204    {
   1205      fp.PrintTitle();
   1206      g_StdOut << endl;
   1207      fp.PrintTitleLines();
   1208      g_StdOut << endl;
   1209    }
   1210 
   1211    const CArc &arc = arcLink.Arcs.Back();
   1212    fp.Arc = &arc;
   1213    fp.TechMode = techMode;
   1214    IInArchive *archive = arc.Archive;
   1215    if (techMode)
   1216    {
   1217      fp.Clear();
   1218      RINOK(fp.AddMainProps(archive));
   1219      if (arc.GetRawProps)
   1220      {
   1221        RINOK(fp.AddRawProps(arc.GetRawProps));
   1222      }
   1223    }
   1224    
   1225    CListStat2 stat2;
   1226    
   1227    UInt32 numItems;
   1228    RINOK(archive->GetNumberOfItems(&numItems));
   1229 
   1230    CReadArcItem item;
   1231    UStringVector pathParts;
   1232    
   1233    for (UInt32 i = 0; i < numItems; i++)
   1234    {
   1235      if (NConsoleClose::TestBreakSignal())
   1236        return E_ABORT;
   1237 
   1238      HRESULT res = arc.GetItemPath2(i, fp.FilePath);
   1239 
   1240      if (stdInMode && res == E_INVALIDARG)
   1241        break;
   1242      RINOK(res);
   1243 
   1244      if (arc.Ask_Aux)
   1245      {
   1246        bool isAux;
   1247        RINOK(Archive_IsItem_Aux(archive, i, isAux));
   1248        if (isAux)
   1249          continue;
   1250      }
   1251 
   1252      bool isAltStream = false;
   1253      if (arc.Ask_AltStream)
   1254      {
   1255        RINOK(Archive_IsItem_AltStream(archive, i, isAltStream));
   1256        if (isAltStream && !processAltStreams)
   1257          continue;
   1258      }
   1259 
   1260      RINOK(Archive_IsItem_Dir(archive, i, fp.IsDir));
   1261 
   1262      if (!allFilesAreAllowed)
   1263      {
   1264        if (isAltStream)
   1265        {
   1266          RINOK(arc.GetItem(i, item));
   1267          if (!CensorNode_CheckPath(wildcardCensor, item))
   1268            continue;
   1269        }
   1270        else
   1271        {
   1272          SplitPathToParts(fp.FilePath, pathParts);;
   1273          bool include;
   1274          if (!wildcardCensor.CheckPathVect(pathParts, !fp.IsDir, include))
   1275            continue;
   1276          if (!include)
   1277            continue;
   1278        }
   1279      }
   1280      
   1281      CListStat st;
   1282      
   1283      RINOK(GetUInt64Value(archive, i, kpidSize, st.Size));
   1284      RINOK(GetUInt64Value(archive, i, kpidPackSize, st.PackSize));
   1285      RINOK(GetItemMTime(archive, i, st.MTime));
   1286 
   1287      if (fp.IsDir)
   1288        stat2.NumDirs++;
   1289      else
   1290        st.NumFiles = 1;
   1291      stat2.GetStat(isAltStream).Update(st);
   1292 
   1293      if (isAltStream && !showAltStreams)
   1294        continue;
   1295      RINOK(fp.PrintItemInfo(i, st));
   1296    }
   1297 
   1298    UInt64 numStreams = stat2.GetNumStreams();
   1299    if (!stdInMode
   1300        && !stat2.MainFiles.PackSize.Def
   1301        && !stat2.AltStreams.PackSize.Def)
   1302    {
   1303      if (arcLink.VolumePaths.Size() != 0)
   1304        arcPackSize += arcLink.VolumesSize;
   1305      stat2.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize);
   1306    }
   1307  
   1308    stat2.MainFiles.SetSizeDefIfNoFiles();
   1309    stat2.AltStreams.SetSizeDefIfNoFiles();
   1310    
   1311    if (enableHeaders && !techMode)
   1312    {
   1313      fp.PrintTitleLines();
   1314      g_StdOut << endl;
   1315      fp.PrintSum(stat2);
   1316    }
   1317 
   1318    if (enableHeaders)
   1319    {
   1320      if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
   1321      {
   1322        g_StdOut << "----------\n";
   1323        PrintPropPair(g_StdOut, "Path", arcLink.NonOpen_ArcPath, false);
   1324        PrintArcTypeError(g_StdOut, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
   1325      }
   1326    }
   1327    
   1328    stat2total.Update(stat2);
   1329 
   1330    g_StdOut.Flush();
   1331  }
   1332  
   1333  if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1))
   1334  {
   1335    g_StdOut << endl;
   1336    fp.PrintTitleLines();
   1337    g_StdOut << endl;
   1338    fp.PrintSum(stat2total);
   1339    g_StdOut << endl;
   1340    PrintPropNameAndNumber(g_StdOut, "Archives", numArcs);
   1341    PrintPropNameAndNumber(g_StdOut, "Volumes", numVolumes);
   1342    PrintPropNameAndNumber(g_StdOut, "Total archives size", totalArcSizes);
   1343  }
   1344 
   1345  if (numErrors == 1 && lastError != 0)
   1346    return lastError;
   1347  
   1348  return S_OK;
   1349 }