"Fossies" - the Fresh Open Source Software Archive

Member "p7zip_16.02/CPP/7zip/UI/Console/List.cpp" (20 May 2016, 31169 Bytes) of package /linux/misc/p7zip_16.02_src_all.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "List.cpp": 15.14.1_src_all_vs_16.02_src_all.

    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 *kListing = "Listing archive: ";
  132 
  133 static const char *kString_Files = "files";
  134 static const char *kString_Dirs = "folders";
  135 static const char *kString_AltStreams = "alternate streams";
  136 static const char *kString_Streams = "streams";
  137 
  138 static const char *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     char s[16];
  421     ConvertUInt32ToString(propID, s);
  422     nameA = s;
  423   }
  424 }
  425 
  426 void CFieldPrinter::AddProp(const wchar_t *name, PROPID propID, bool isRawProp)
  427 {
  428   CFieldInfo f;
  429   f.PropID = propID;
  430   f.IsRawProp = isRawProp;
  431   GetPropName(propID, name, f.NameA, f.NameU);
  432   f.NameU.AddAscii(" = ");
  433   if (!f.NameA.IsEmpty())
  434     f.NameA += " = ";
  435   else
  436   {
  437     const UString &s = f.NameU;
  438     AString sA;
  439     unsigned i;
  440     for (i = 0; i < s.Len(); i++)
  441     {
  442       wchar_t c = s[i];
  443       if (c >= 0x80)
  444         break;
  445       sA += (char)c;
  446     }
  447     if (i == s.Len())
  448       f.NameA = sA;
  449   }
  450   _fields.Add(f);
  451 }
  452 
  453 HRESULT CFieldPrinter::AddMainProps(IInArchive *archive)
  454 {
  455   UInt32 numProps;
  456   RINOK(archive->GetNumberOfProperties(&numProps));
  457   for (UInt32 i = 0; i < numProps; i++)
  458   {
  459     CMyComBSTR name;
  460     PROPID propID;
  461     VARTYPE vt;
  462     RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt));
  463     AddProp(name, propID, false);
  464   }
  465   return S_OK;
  466 }
  467 
  468 HRESULT CFieldPrinter::AddRawProps(IArchiveGetRawProps *getRawProps)
  469 {
  470   UInt32 numProps;
  471   RINOK(getRawProps->GetNumRawProps(&numProps));
  472   for (UInt32 i = 0; i < numProps; i++)
  473   {
  474     CMyComBSTR name;
  475     PROPID propID;
  476     RINOK(getRawProps->GetRawPropInfo(i, &name, &propID));
  477     AddProp(name, propID, true);
  478   }
  479   return S_OK;
  480 }
  481 
  482 void CFieldPrinter::PrintTitle()
  483 {
  484   FOR_VECTOR (i, _fields)
  485   {
  486     const CFieldInfo &f = _fields[i];
  487     PrintSpaces(f.PrefixSpacesWidth);
  488     PrintString(f.TitleAdjustment, ((f.PropID == kpidPath) ? 0: f.Width), f.NameA);
  489   }
  490 }
  491 
  492 void CFieldPrinter::PrintTitleLines()
  493 {
  494   g_StdOut << LinesString;
  495 }
  496 
  497 static void PrintTime(char *dest, const FILETIME *ft)
  498 {
  499   *dest = 0;
  500   if (ft->dwLowDateTime == 0 && ft->dwHighDateTime == 0)
  501     return;
  502   FILETIME locTime;
  503   if (!FileTimeToLocalFileTime(ft, &locTime))
  504     throw 20121211;
  505   ConvertFileTimeToString(locTime, dest, true, true);
  506 }
  507 
  508 #ifndef _SFX
  509 
  510 static inline char GetHex(Byte value)
  511 {
  512   return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
  513 }
  514 
  515 static void HexToString(char *dest, const Byte *data, UInt32 size)
  516 {
  517   for (UInt32 i = 0; i < size; i++)
  518   {
  519     Byte b = data[i];
  520     dest[0] = GetHex((Byte)((b >> 4) & 0xF));
  521     dest[1] = GetHex((Byte)(b & 0xF));
  522     dest += 2;
  523   }
  524   *dest = 0;
  525 }
  526 
  527 #endif
  528 
  529 #define MY_ENDL endl
  530 
  531 HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st)
  532 {
  533   char temp[128];
  534   size_t tempPos = 0;
  535 
  536   bool techMode = this->TechMode;
  537   /*
  538   if (techMode)
  539   {
  540     g_StdOut << "Index = ";
  541     g_StdOut << (UInt64)index;
  542     g_StdOut << endl;
  543   }
  544   */
  545   FOR_VECTOR (i, _fields)
  546   {
  547     const CFieldInfo &f = _fields[i];
  548 
  549     if (!techMode)
  550     {
  551       PrintSpacesToString(temp + tempPos, f.PrefixSpacesWidth);
  552       tempPos += f.PrefixSpacesWidth;
  553     }
  554 
  555     if (techMode)
  556     {
  557       if (!f.NameA.IsEmpty())
  558         g_StdOut << f.NameA;
  559       else
  560         g_StdOut << f.NameU;
  561     }
  562     
  563     if (f.PropID == kpidPath)
  564     {
  565       if (!techMode)
  566         g_StdOut << temp;
  567       g_StdOut.PrintUString(FilePath, TempAString);
  568       if (techMode)
  569         g_StdOut << MY_ENDL;
  570       continue;
  571     }
  572 
  573     const unsigned width = f.Width;
  574     
  575     if (f.IsRawProp)
  576     {
  577       #ifndef _SFX
  578       
  579       const void *data;
  580       UInt32 dataSize;
  581       UInt32 propType;
  582       RINOK(Arc->GetRawProps->GetRawProp(index, f.PropID, &data, &dataSize, &propType));
  583       
  584       if (dataSize != 0)
  585       {
  586         bool needPrint = true;
  587         
  588         if (f.PropID == kpidNtSecure)
  589         {
  590           if (propType != NPropDataType::kRaw)
  591             return E_FAIL;
  592           #ifndef _SFX
  593           ConvertNtSecureToString((const Byte *)data, dataSize, TempAString);
  594           g_StdOut << TempAString;
  595           needPrint = false;
  596           #endif
  597         }
  598 #ifdef _WIN32
  599         else if (f.PropID == kpidNtReparse)
  600         {
  601           UString s;
  602           if (ConvertNtReparseToString((const Byte *)data, dataSize, s))
  603           {
  604             needPrint = false;
  605             g_StdOut.PrintUString(s, TempAString);
  606           }
  607         }
  608 #endif
  609       
  610         if (needPrint)
  611         {
  612           if (propType != NPropDataType::kRaw)
  613             return E_FAIL;
  614           
  615           const UInt32 kMaxDataSize = 64;
  616           
  617           if (dataSize > kMaxDataSize)
  618           {
  619             g_StdOut << "data:";
  620             g_StdOut << dataSize;
  621           }
  622           else
  623           {
  624             char hexStr[kMaxDataSize * 2 + 4];
  625             HexToString(hexStr, (const Byte *)data, dataSize);
  626             g_StdOut << hexStr;
  627           }
  628         }
  629       }
  630       
  631       #endif
  632     }
  633     else
  634     {
  635       CPropVariant prop;
  636       switch (f.PropID)
  637       {
  638         case kpidSize: if (st.Size.Def) prop = st.Size.Val; break;
  639         case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break;
  640         case kpidMTime: if (st.MTime.Def) prop = st.MTime.Val; break;
  641         default:
  642           RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop));
  643       }
  644       if (f.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4))
  645       {
  646         GetAttribString((prop.vt == VT_EMPTY) ? 0 : prop.ulVal, IsDir, techMode, temp + tempPos);
  647         if (techMode)
  648           g_StdOut << temp + tempPos;
  649         else
  650           tempPos += strlen(temp + tempPos);
  651       }
  652       else if (prop.vt == VT_EMPTY)
  653       {
  654         if (!techMode)
  655         {
  656           PrintSpacesToString(temp + tempPos, width);
  657           tempPos += width;
  658         }
  659       }
  660       else if (prop.vt == VT_FILETIME)
  661       {
  662         PrintTime(temp + tempPos, &prop.filetime);
  663         if (techMode)
  664           g_StdOut << temp + tempPos;
  665         else
  666         {
  667           size_t len = strlen(temp + tempPos);
  668           tempPos += len;
  669           if (len < (unsigned)f.Width)
  670           {
  671             len = f.Width - len;
  672             PrintSpacesToString(temp + tempPos, (unsigned)len);
  673             tempPos += len;
  674           }
  675         }
  676       }
  677       else if (prop.vt == VT_BSTR)
  678       {
  679         TempWString.SetFromBstr(prop.bstrVal);
  680         if (techMode)
  681         {
  682           // replace CR/LF here.
  683           g_StdOut.PrintUString(TempWString, TempAString);
  684         }
  685         else
  686           PrintUString(f.TextAdjustment, width, TempWString, TempAString);
  687       }
  688       else
  689       {
  690         char s[64];
  691         ConvertPropertyToShortString(s, prop, f.PropID);
  692         if (techMode)
  693           g_StdOut << s;
  694         else
  695         {
  696           PrintStringToString(temp + tempPos, f.TextAdjustment, width, s);
  697           tempPos += strlen(temp + tempPos);
  698         }
  699       }
  700     }
  701     if (techMode)
  702       g_StdOut << MY_ENDL;
  703   }
  704   g_StdOut << MY_ENDL;
  705   return S_OK;
  706 }
  707 
  708 static void PrintNumber(EAdjustment adj, unsigned width, const CListUInt64Def &value)
  709 {
  710   char s[32];
  711   s[0] = 0;
  712   if (value.Def)
  713     ConvertUInt64ToString(value.Val, s);
  714   PrintString(adj, width, s);
  715 }
  716 
  717 void Print_UInt64_and_String(AString &s, UInt64 val, const char *name);
  718 
  719 void CFieldPrinter::PrintSum(const CListStat &st, UInt64 numDirs, const char *str)
  720 {
  721   FOR_VECTOR (i, _fields)
  722   {
  723     const CFieldInfo &f = _fields[i];
  724     PrintSpaces(f.PrefixSpacesWidth);
  725     if (f.PropID == kpidSize)
  726       PrintNumber(f.TextAdjustment, f.Width, st.Size);
  727     else if (f.PropID == kpidPackSize)
  728       PrintNumber(f.TextAdjustment, f.Width, st.PackSize);
  729     else if (f.PropID == kpidMTime)
  730     {
  731       char s[64];
  732       s[0] = 0;
  733       if (st.MTime.Def)
  734         PrintTime(s, &st.MTime.Val);
  735       PrintString(f.TextAdjustment, f.Width, s);
  736     }
  737     else if (f.PropID == kpidPath)
  738     {
  739       AString s;
  740       Print_UInt64_and_String(s, st.NumFiles, str);
  741       if (numDirs != 0)
  742       {
  743         s += ", ";
  744         Print_UInt64_and_String(s, numDirs, kString_Dirs);
  745       }
  746       PrintString(f.TextAdjustment, 0, s);
  747     }
  748     else
  749       PrintString(f.TextAdjustment, f.Width, "");
  750   }
  751   g_StdOut << endl;
  752 }
  753 
  754 void CFieldPrinter::PrintSum(const CListStat2 &stat2)
  755 {
  756   PrintSum(stat2.MainFiles, stat2.NumDirs, kString_Files);
  757   if (stat2.AltStreams.NumFiles != 0)
  758   {
  759     PrintSum(stat2.AltStreams, 0, kString_AltStreams);;
  760     CListStat st = stat2.MainFiles;
  761     st.Update(stat2.AltStreams);
  762     PrintSum(st, 0, kString_Streams);
  763   }
  764 }
  765 
  766 static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, CListUInt64Def &value)
  767 {
  768   value.Val = 0;
  769   value.Def = false;
  770   CPropVariant prop;
  771   RINOK(archive->GetProperty(index, propID, &prop));
  772   value.Def = ConvertPropVariantToUInt64(prop, value.Val);
  773   return S_OK;
  774 }
  775 
  776 static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t)
  777 {
  778   t.Val.dwLowDateTime = 0;
  779   t.Val.dwHighDateTime = 0;
  780   t.Def = false;
  781   CPropVariant prop;
  782   RINOK(archive->GetProperty(index, kpidMTime, &prop));
  783   if (prop.vt == VT_FILETIME)
  784   {
  785     t.Val = prop.filetime;
  786     t.Def = true;
  787   }
  788   else if (prop.vt != VT_EMPTY)
  789     return E_FAIL;
  790   return S_OK;
  791 }
  792 
  793 static void PrintPropNameAndNumber(CStdOutStream &so, const char *name, UInt64 val)
  794 {
  795   so << name << ": " << val << endl;
  796 }
  797 
  798 static void PrintPropName_and_Eq(CStdOutStream &so, PROPID propID)
  799 {
  800   const char *s;
  801   char temp[16];
  802   if (propID < ARRAY_SIZE(kPropIdToName))
  803     s = kPropIdToName[propID];
  804   else
  805   {
  806     ConvertUInt32ToString(propID, temp);
  807     s = temp;
  808   }
  809   so << s << " = ";
  810 }
  811 
  812 static void PrintPropNameAndNumber(CStdOutStream &so, PROPID propID, UInt64 val)
  813 {
  814   PrintPropName_and_Eq(so, propID);
  815   so << val << endl;
  816 }
  817 
  818 static void PrintPropNameAndNumber_Signed(CStdOutStream &so, PROPID propID, Int64 val)
  819 {
  820   PrintPropName_and_Eq(so, propID);
  821   so << val << endl;
  822 }
  823 
  824 static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val)
  825 {
  826   so << name << " = " << val << endl;
  827 }
  828 
  829 
  830 static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop)
  831 {
  832   UString s;
  833   ConvertPropertyToString(s, prop, propID);
  834   if (!s.IsEmpty())
  835   {
  836     AString nameA;
  837     UString nameU;
  838     GetPropName(propID, name, nameA, nameU);
  839     if (!nameA.IsEmpty())
  840       PrintPropPair(so, nameA, s);
  841     else
  842       so << nameU << " = " << s << endl;
  843   }
  844 }
  845 
  846 static HRESULT PrintArcProp(CStdOutStream &so, IInArchive *archive, PROPID propID, const wchar_t *name)
  847 {
  848   CPropVariant prop;
  849   RINOK(archive->GetArchiveProperty(propID, &prop));
  850   PrintPropertyPair2(so, propID, name, prop);
  851   return S_OK;
  852 }
  853 
  854 static void PrintArcTypeError(CStdOutStream &so, const UString &type, bool isWarning)
  855 {
  856   so << "Open " << (isWarning ? "WARNING" : "ERROR")
  857     << ": Can not open the file as ["
  858     << type
  859     << "] archive"
  860     << endl;
  861 }
  862 
  863 int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name);
  864 
  865 void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
  866 
  867 static void ErrorInfo_Print(CStdOutStream &so, const CArcErrorInfo &er)
  868 {
  869   PrintErrorFlags(so, "ERRORS:", er.GetErrorFlags());
  870   if (!er.ErrorMessage.IsEmpty())
  871     PrintPropPair(so, "ERROR", er.ErrorMessage);
  872   
  873   PrintErrorFlags(so, "WARNINGS:", er.GetWarningFlags());
  874   if (!er.WarningMessage.IsEmpty())
  875     PrintPropPair(so, "WARNING", er.WarningMessage);
  876 }
  877 
  878 HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink)
  879 {
  880   FOR_VECTOR (r, arcLink.Arcs)
  881   {
  882     const CArc &arc = arcLink.Arcs[r];
  883     const CArcErrorInfo &er = arc.ErrorInfo;
  884     
  885     so << "--\n";
  886     PrintPropPair(so, "Path", arc.Path);
  887     if (er.ErrorFormatIndex >= 0)
  888     {
  889       if (er.ErrorFormatIndex == arc.FormatIndex)
  890         so << "Warning: The archive is open with offset" << endl;
  891       else
  892         PrintArcTypeError(so, codecs->GetFormatNamePtr(er.ErrorFormatIndex), true);
  893     }
  894     PrintPropPair(so, "Type", codecs->GetFormatNamePtr(arc.FormatIndex));
  895     
  896     ErrorInfo_Print(so, er);
  897     
  898     Int64 offset = arc.GetGlobalOffset();
  899     if (offset != 0)
  900       PrintPropNameAndNumber_Signed(so, kpidOffset, offset);
  901     IInArchive *archive = arc.Archive;
  902     RINOK(PrintArcProp(so, archive, kpidPhySize, NULL));
  903     if (er.TailSize != 0)
  904       PrintPropNameAndNumber(so, kpidTailSize, er.TailSize);
  905     {
  906       UInt32 numProps;
  907       RINOK(archive->GetNumberOfArchiveProperties(&numProps));
  908       
  909       for (UInt32 j = 0; j < numProps; j++)
  910       {
  911         CMyComBSTR name;
  912         PROPID propID;
  913         VARTYPE vt;
  914         RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt));
  915         RINOK(PrintArcProp(so, archive, propID, name));
  916       }
  917     }
  918     
  919     if (r != arcLink.Arcs.Size() - 1)
  920     {
  921       UInt32 numProps;
  922       so << "----\n";
  923       if (archive->GetNumberOfProperties(&numProps) == S_OK)
  924       {
  925         UInt32 mainIndex = arcLink.Arcs[r + 1].SubfileIndex;
  926         for (UInt32 j = 0; j < numProps; j++)
  927         {
  928           CMyComBSTR name;
  929           PROPID propID;
  930           VARTYPE vt;
  931           RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt));
  932           CPropVariant prop;
  933           RINOK(archive->GetProperty(mainIndex, propID, &prop));
  934           PrintPropertyPair2(so, propID, name, prop);
  935         }
  936       }
  937     }
  938   }
  939   return S_OK;
  940 }
  941 
  942 HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink)
  943 {
  944   #ifndef _NO_CRYPTO
  945   if (arcLink.PasswordWasAsked)
  946     so << "Can not open encrypted archive. Wrong password?";
  947   else
  948   #endif
  949   {
  950     if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
  951     {
  952       so << arcLink.NonOpen_ArcPath << endl;
  953       PrintArcTypeError(so, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
  954     }
  955     else
  956       so << "Can not open the file as archive";
  957   }
  958 
  959   so << endl;
  960   so << endl;
  961   ErrorInfo_Print(so, arcLink.NonOpen_ErrorInfo);
  962 
  963   return S_OK;
  964 }
  965 
  966 bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
  967 
  968 HRESULT ListArchives(CCodecs *codecs,
  969     const CObjectVector<COpenType> &types,
  970     const CIntVector &excludedFormats,
  971     bool stdInMode,
  972     UStringVector &arcPaths, UStringVector &arcPathsFull,
  973     bool processAltStreams, bool showAltStreams,
  974     const NWildcard::CCensorNode &wildcardCensor,
  975     bool enableHeaders, bool techMode,
  976     #ifndef _NO_CRYPTO
  977     bool &passwordEnabled, UString &password,
  978     #endif
  979     #ifndef _SFX
  980     const CObjectVector<CProperty> *props,
  981     #endif
  982     UInt64 &numErrors,
  983     UInt64 &numWarnings)
  984 {
  985   bool allFilesAreAllowed = wildcardCensor.AreAllAllowed();
  986 
  987   numErrors = 0;
  988   numWarnings = 0;
  989 
  990   CFieldPrinter fp;
  991   if (!techMode)
  992     fp.Init(kStandardFieldTable, ARRAY_SIZE(kStandardFieldTable));
  993 
  994   CListStat2 stat2total;
  995   
  996   CBoolArr skipArcs(arcPaths.Size());
  997   unsigned arcIndex;
  998   for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
  999     skipArcs[arcIndex] = false;
 1000   UInt64 numVolumes = 0;
 1001   UInt64 numArcs = 0;
 1002   UInt64 totalArcSizes = 0;
 1003 
 1004   HRESULT lastError = 0;
 1005 
 1006   for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
 1007   {
 1008     if (skipArcs[arcIndex])
 1009       continue;
 1010     const UString &arcPath = arcPaths[arcIndex];
 1011     UInt64 arcPackSize = 0;
 1012     
 1013     if (!stdInMode)
 1014     {
 1015       NFile::NFind::CFileInfo fi;
 1016       if (!fi.Find(us2fs(arcPath)))
 1017       {
 1018         DWORD errorCode = GetLastError();
 1019 /* FIXME
 1020         if (errorCode == 0)
 1021           errorCode = ERROR_FILE_NOT_FOUND;
 1022 */
 1023         lastError = HRESULT_FROM_WIN32(lastError);;
 1024         g_StdOut.Flush();
 1025         *g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) <<
 1026               endl << arcPath << endl << endl;
 1027         numErrors++;
 1028         continue;
 1029       }
 1030       if (fi.IsDir())
 1031       {
 1032         g_StdOut.Flush();
 1033         *g_ErrStream << endl << kError << arcPath << " is not a file" << endl << endl;
 1034         numErrors++;
 1035         continue;
 1036       }
 1037       arcPackSize = fi.Size;
 1038       totalArcSizes += arcPackSize;
 1039     }
 1040 
 1041     CArchiveLink arcLink;
 1042 
 1043     COpenCallbackConsole openCallback;
 1044     openCallback.Init(&g_StdOut, g_ErrStream, NULL);
 1045 
 1046     #ifndef _NO_CRYPTO
 1047 
 1048     openCallback.PasswordIsDefined = passwordEnabled;
 1049     openCallback.Password = password;
 1050 
 1051     #endif
 1052 
 1053     /*
 1054     CObjectVector<COptionalOpenProperties> optPropsVector;
 1055     COptionalOpenProperties &optProps = optPropsVector.AddNew();
 1056     optProps.Props = *props;
 1057     */
 1058     
 1059     COpenOptions options;
 1060     #ifndef _SFX
 1061     options.props = props;
 1062     #endif
 1063     options.codecs = codecs;
 1064     options.types = &types;
 1065     options.excludedFormats = &excludedFormats;
 1066     options.stdInMode = stdInMode;
 1067     options.stream = NULL;
 1068     options.filePath = arcPath;
 1069 
 1070     if (enableHeaders)
 1071     {
 1072       g_StdOut << endl << kListing << arcPath << endl << endl;
 1073     }
 1074     
 1075     HRESULT result = arcLink.Open3(options, &openCallback);
 1076 
 1077     if (result != S_OK)
 1078     {
 1079       if (result == E_ABORT)
 1080         return result;
 1081       g_StdOut.Flush();
 1082       *g_ErrStream << endl << kError << arcPath << " : ";
 1083       if (result == S_FALSE)
 1084       {
 1085         Print_OpenArchive_Error(*g_ErrStream, codecs, arcLink);
 1086       }
 1087       else
 1088       {
 1089         lastError = result;
 1090         *g_ErrStream << "opening : ";
 1091         if (result == E_OUTOFMEMORY)
 1092           *g_ErrStream << "Can't allocate required memory";
 1093         else
 1094           *g_ErrStream << NError::MyFormatMessage(result);
 1095       }
 1096       *g_ErrStream << endl;
 1097       numErrors++;
 1098       continue;
 1099     }
 1100     
 1101     {
 1102       if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
 1103         numErrors++;
 1104       
 1105       FOR_VECTOR (r, arcLink.Arcs)
 1106       {
 1107         const CArcErrorInfo &arc = arcLink.Arcs[r].ErrorInfo;
 1108         if (!arc.WarningMessage.IsEmpty())
 1109           numWarnings++;
 1110         if (arc.AreThereWarnings())
 1111           numWarnings++;
 1112         if (arc.ErrorFormatIndex >= 0)
 1113           numWarnings++;
 1114         if (arc.AreThereErrors())
 1115         {
 1116           numErrors++;
 1117           // break;
 1118         }
 1119         if (!arc.ErrorMessage.IsEmpty())
 1120           numErrors++;
 1121       }
 1122     }
 1123 
 1124     numArcs++;
 1125     numVolumes++;
 1126 
 1127     if (!stdInMode)
 1128     {
 1129       numVolumes += arcLink.VolumePaths.Size();
 1130       totalArcSizes += arcLink.VolumesSize;
 1131       FOR_VECTOR (v, arcLink.VolumePaths)
 1132       {
 1133         int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]);
 1134         if (index >= 0 && (unsigned)index > arcIndex)
 1135           skipArcs[(unsigned)index] = true;
 1136       }
 1137     }
 1138 
 1139 
 1140     if (enableHeaders)
 1141     {
 1142       RINOK(Print_OpenArchive_Props(g_StdOut, codecs, arcLink));
 1143 
 1144       g_StdOut << endl;
 1145       if (techMode)
 1146         g_StdOut << "----------\n";
 1147     }
 1148 
 1149     if (enableHeaders && !techMode)
 1150     {
 1151       fp.PrintTitle();
 1152       g_StdOut << endl;
 1153       fp.PrintTitleLines();
 1154       g_StdOut << endl;
 1155     }
 1156 
 1157     const CArc &arc = arcLink.Arcs.Back();
 1158     fp.Arc = &arc;
 1159     fp.TechMode = techMode;
 1160     IInArchive *archive = arc.Archive;
 1161     if (techMode)
 1162     {
 1163       fp.Clear();
 1164       RINOK(fp.AddMainProps(archive));
 1165       if (arc.GetRawProps)
 1166       {
 1167         RINOK(fp.AddRawProps(arc.GetRawProps));
 1168       }
 1169     }
 1170     
 1171     CListStat2 stat2;
 1172     
 1173     UInt32 numItems;
 1174     RINOK(archive->GetNumberOfItems(&numItems));
 1175  
 1176     CReadArcItem item;
 1177     UStringVector pathParts;
 1178     
 1179     for (UInt32 i = 0; i < numItems; i++)
 1180     {
 1181       if (NConsoleClose::TestBreakSignal())
 1182         return E_ABORT;
 1183 
 1184       HRESULT res = arc.GetItemPath2(i, fp.FilePath);
 1185 
 1186       if (stdInMode && res == E_INVALIDARG)
 1187         break;
 1188       RINOK(res);
 1189 
 1190       if (arc.Ask_Aux)
 1191       {
 1192         bool isAux;
 1193         RINOK(Archive_IsItem_Aux(archive, i, isAux));
 1194         if (isAux)
 1195           continue;
 1196       }
 1197 
 1198       bool isAltStream = false;
 1199       if (arc.Ask_AltStream)
 1200       {
 1201         RINOK(Archive_IsItem_AltStream(archive, i, isAltStream));
 1202         if (isAltStream && !processAltStreams)
 1203           continue;
 1204       }
 1205 
 1206       RINOK(Archive_IsItem_Dir(archive, i, fp.IsDir));
 1207 
 1208       if (!allFilesAreAllowed)
 1209       {
 1210         if (isAltStream)
 1211         {
 1212           RINOK(arc.GetItem(i, item));
 1213           if (!CensorNode_CheckPath(wildcardCensor, item))
 1214             continue;
 1215         }
 1216         else
 1217         {
 1218           SplitPathToParts(fp.FilePath, pathParts);;
 1219           bool include;
 1220           if (!wildcardCensor.CheckPathVect(pathParts, !fp.IsDir, include))
 1221             continue;
 1222           if (!include)
 1223             continue;
 1224         }
 1225       }
 1226       
 1227       CListStat st;
 1228       
 1229       RINOK(GetUInt64Value(archive, i, kpidSize, st.Size));
 1230       RINOK(GetUInt64Value(archive, i, kpidPackSize, st.PackSize));
 1231       RINOK(GetItemMTime(archive, i, st.MTime));
 1232 
 1233       if (fp.IsDir)
 1234         stat2.NumDirs++;
 1235       else
 1236         st.NumFiles = 1;
 1237       stat2.GetStat(isAltStream).Update(st);
 1238 
 1239       if (isAltStream && !showAltStreams)
 1240         continue;
 1241       RINOK(fp.PrintItemInfo(i, st));
 1242     }
 1243 
 1244     UInt64 numStreams = stat2.GetNumStreams();
 1245     if (!stdInMode
 1246         && !stat2.MainFiles.PackSize.Def
 1247         && !stat2.AltStreams.PackSize.Def)
 1248     {
 1249       if (arcLink.VolumePaths.Size() != 0)
 1250         arcPackSize += arcLink.VolumesSize;
 1251       stat2.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize);
 1252     }
 1253   
 1254     stat2.MainFiles.SetSizeDefIfNoFiles();
 1255     stat2.AltStreams.SetSizeDefIfNoFiles();
 1256     
 1257     if (enableHeaders && !techMode)
 1258     {
 1259       fp.PrintTitleLines();
 1260       g_StdOut << endl;
 1261       fp.PrintSum(stat2);
 1262     }
 1263 
 1264     if (enableHeaders)
 1265     {
 1266       if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
 1267       {
 1268         g_StdOut << "----------\n";
 1269         PrintPropPair(g_StdOut, "Path", arcLink.NonOpen_ArcPath);
 1270         PrintArcTypeError(g_StdOut, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
 1271       }
 1272     }
 1273     
 1274     stat2total.Update(stat2);
 1275 
 1276     g_StdOut.Flush();
 1277   }
 1278   
 1279   if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1))
 1280   {
 1281     g_StdOut << endl;
 1282     fp.PrintTitleLines();
 1283     g_StdOut << endl;
 1284     fp.PrintSum(stat2total);
 1285     g_StdOut << endl;
 1286     PrintPropNameAndNumber(g_StdOut, "Archives", numArcs);
 1287     PrintPropNameAndNumber(g_StdOut, "Volumes", numVolumes);
 1288     PrintPropNameAndNumber(g_StdOut, "Total archives size", totalArcSizes);
 1289   }
 1290 
 1291   if (numErrors == 1 && lastError != 0)
 1292     return lastError;
 1293   
 1294   return S_OK;
 1295 }