misc/libphysfs/lzma/CPP/7zip/Archive/7z/7zHandler.cpp
branchui-scaling
changeset 15283 c4fd2813b127
parent 13390 0135e64c6c66
parent 15279 7ab5cf405686
child 15663 d92eeb468dad
equal deleted inserted replaced
13390:0135e64c6c66 15283:c4fd2813b127
     1 // 7zHandler.cpp
       
     2 
       
     3 #include "StdAfx.h"
       
     4 
       
     5 #include "7zHandler.h"
       
     6 #include "7zProperties.h"
       
     7 
       
     8 #include "../../../Common/IntToString.h"
       
     9 #include "../../../Common/ComTry.h"
       
    10 #include "../../../Windows/Defs.h"
       
    11 
       
    12 #include "../Common/ItemNameUtils.h"
       
    13 #ifdef _7Z_VOL
       
    14 #include "../Common/MultiStream.h"
       
    15 #endif
       
    16 
       
    17 #ifdef __7Z_SET_PROPERTIES
       
    18 #ifdef EXTRACT_ONLY
       
    19 #include "../Common/ParseProperties.h"
       
    20 #endif
       
    21 #endif
       
    22 
       
    23 #ifdef COMPRESS_MT
       
    24 #include "../../../Windows/System.h"
       
    25 #endif
       
    26 
       
    27 using namespace NWindows;
       
    28 
       
    29 extern UString ConvertMethodIdToString(UInt64 id);
       
    30 
       
    31 namespace NArchive {
       
    32 namespace N7z {
       
    33 
       
    34 CHandler::CHandler()
       
    35 {
       
    36   _crcSize = 4;
       
    37 
       
    38   #ifdef EXTRACT_ONLY
       
    39   #ifdef COMPRESS_MT
       
    40   _numThreads = NWindows::NSystem::GetNumberOfProcessors();
       
    41   #endif
       
    42   #else
       
    43   Init();
       
    44   #endif
       
    45 }
       
    46 
       
    47 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
       
    48 {
       
    49   *numItems = 
       
    50   #ifdef _7Z_VOL
       
    51   _refs.Size();
       
    52   #else
       
    53   *numItems = _database.Files.Size();
       
    54   #endif
       
    55   return S_OK;
       
    56 }
       
    57 
       
    58 #ifdef _SFX
       
    59 
       
    60 IMP_IInArchive_ArcProps_NO
       
    61 
       
    62 STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
       
    63 {
       
    64   return E_NOTIMPL;
       
    65 }
       
    66 
       
    67 STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,     
       
    68       BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
       
    69 {
       
    70   return E_NOTIMPL;
       
    71 }
       
    72 
       
    73 
       
    74 #else
       
    75 
       
    76 STATPROPSTG kArcProps[] = 
       
    77 {
       
    78   { NULL, kpidMethod, VT_BSTR},
       
    79   { NULL, kpidSolid, VT_BOOL},
       
    80   { NULL, kpidNumBlocks, VT_UI4}
       
    81 };
       
    82 
       
    83 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
       
    84 {
       
    85   COM_TRY_BEGIN
       
    86   NWindows::NCOM::CPropVariant prop;
       
    87   switch(propID)
       
    88   {
       
    89     case kpidMethod:
       
    90     {
       
    91       UString resString;
       
    92       CRecordVector<UInt64> ids;
       
    93       int i;
       
    94       for (i = 0; i < _database.Folders.Size(); i++)
       
    95       {
       
    96         const CFolder &f = _database.Folders[i];
       
    97         for (int j = f.Coders.Size() - 1; j >= 0; j--)
       
    98           ids.AddToUniqueSorted(f.Coders[j].MethodID);
       
    99       }
       
   100 
       
   101       for (i = 0; i < ids.Size(); i++)
       
   102       {
       
   103         UInt64 id = ids[i];
       
   104         UString methodName;
       
   105         /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
       
   106         if (methodName.IsEmpty())
       
   107           methodName = ConvertMethodIdToString(id);
       
   108         if (!resString.IsEmpty())
       
   109           resString += L' ';
       
   110         resString += methodName;
       
   111       }
       
   112       prop = resString; 
       
   113       break;
       
   114     }
       
   115     case kpidSolid: prop = _database.IsSolid(); break;
       
   116     case kpidNumBlocks: prop = (UInt32)_database.Folders.Size(); break;
       
   117   }
       
   118   prop.Detach(value);
       
   119   return S_OK;
       
   120   COM_TRY_END
       
   121 }
       
   122 
       
   123 IMP_IInArchive_ArcProps
       
   124 
       
   125 #endif
       
   126 
       
   127 static void MySetFileTime(bool timeDefined, FILETIME unixTime, NWindows::NCOM::CPropVariant &prop)
       
   128 {
       
   129   if (timeDefined)
       
   130     prop = unixTime;
       
   131 }
       
   132 
       
   133 #ifndef _SFX
       
   134 
       
   135 static UString ConvertUInt32ToString(UInt32 value)
       
   136 {
       
   137   wchar_t buffer[32];
       
   138   ConvertUInt64ToString(value, buffer);
       
   139   return buffer;
       
   140 }
       
   141 
       
   142 static UString GetStringForSizeValue(UInt32 value)
       
   143 {
       
   144   for (int i = 31; i >= 0; i--)
       
   145     if ((UInt32(1) << i) == value)
       
   146       return ConvertUInt32ToString(i);
       
   147   UString result;
       
   148   if (value % (1 << 20) == 0)
       
   149   {
       
   150     result += ConvertUInt32ToString(value >> 20);
       
   151     result += L"m";
       
   152   }
       
   153   else if (value % (1 << 10) == 0)
       
   154   {
       
   155     result += ConvertUInt32ToString(value >> 10);
       
   156     result += L"k";
       
   157   }
       
   158   else
       
   159   {
       
   160     result += ConvertUInt32ToString(value);
       
   161     result += L"b";
       
   162   }
       
   163   return result;
       
   164 }
       
   165 
       
   166 static const UInt64 k_Copy = 0x0;
       
   167 static const UInt64 k_LZMA  = 0x030101;
       
   168 static const UInt64 k_PPMD  = 0x030401;
       
   169 
       
   170 static wchar_t GetHex(Byte value)
       
   171 {
       
   172   return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
       
   173 }
       
   174 static inline UString GetHex2(Byte value)
       
   175 {
       
   176   UString result;
       
   177   result += GetHex((Byte)(value >> 4));
       
   178   result += GetHex((Byte)(value & 0xF));
       
   179   return result;
       
   180 }
       
   181 
       
   182 #endif
       
   183 
       
   184 static const UInt64 k_AES  = 0x06F10701;
       
   185 
       
   186 #ifndef _SFX
       
   187 static inline UInt32 GetUInt32FromMemLE(const Byte *p)
       
   188 {
       
   189   return p[0] | (((UInt32)p[1]) << 8) | (((UInt32)p[2]) << 16) | (((UInt32)p[3]) << 24);
       
   190 }
       
   191 #endif
       
   192 
       
   193 bool CHandler::IsEncrypted(UInt32 index2) const
       
   194 {
       
   195   CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
       
   196   if (folderIndex != kNumNoIndex)
       
   197   {
       
   198     const CFolder &folderInfo = _database.Folders[folderIndex];
       
   199     for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
       
   200       if (folderInfo.Coders[i].MethodID == k_AES)
       
   201         return true;
       
   202   }
       
   203   return false;
       
   204 }
       
   205 
       
   206 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID,  PROPVARIANT *value)
       
   207 {
       
   208   COM_TRY_BEGIN
       
   209   NWindows::NCOM::CPropVariant prop;
       
   210   
       
   211   /*
       
   212   const CRef2 &ref2 = _refs[index];
       
   213   if (ref2.Refs.IsEmpty())
       
   214     return E_FAIL;
       
   215   const CRef &ref = ref2.Refs.Front();
       
   216   */
       
   217   
       
   218   #ifdef _7Z_VOL
       
   219   const CRef &ref = _refs[index];
       
   220   const CVolume &volume = _volumes[ref.VolumeIndex];
       
   221   const CArchiveDatabaseEx &_database = volume.Database;
       
   222   UInt32 index2 = ref.ItemIndex;
       
   223   const CFileItem &item = _database.Files[index2];
       
   224   #else
       
   225   const CFileItem &item = _database.Files[index];
       
   226   UInt32 index2 = index;
       
   227   #endif
       
   228 
       
   229   switch(propID)
       
   230   {
       
   231     case kpidPath:
       
   232     {
       
   233       if (!item.Name.IsEmpty())
       
   234         prop = NItemName::GetOSName(item.Name);
       
   235       break;
       
   236     }
       
   237     case kpidIsFolder:
       
   238       prop = item.IsDirectory;
       
   239       break;
       
   240     case kpidSize:
       
   241     {
       
   242       prop = item.UnPackSize;
       
   243       // prop = ref2.UnPackSize;
       
   244       break;
       
   245     }
       
   246     case kpidPosition:
       
   247     {
       
   248       /*
       
   249       if (ref2.Refs.Size() > 1)
       
   250         prop = ref2.StartPos;
       
   251       else
       
   252       */
       
   253         if (item.IsStartPosDefined)
       
   254           prop = item.StartPos;
       
   255       break;
       
   256     }
       
   257     case kpidPackedSize:
       
   258     {
       
   259       // prop = ref2.PackSize;
       
   260       {
       
   261         CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
       
   262         if (folderIndex != kNumNoIndex)
       
   263         {
       
   264           if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2)
       
   265             prop = _database.GetFolderFullPackSize(folderIndex);
       
   266           /*
       
   267           else
       
   268             prop = (UInt64)0;
       
   269           */
       
   270         }
       
   271         else
       
   272           prop = (UInt64)0;
       
   273       }
       
   274       break;
       
   275     }
       
   276     case kpidLastAccessTime:
       
   277       MySetFileTime(item.IsLastAccessTimeDefined, item.LastAccessTime, prop);
       
   278       break;
       
   279     case kpidCreationTime:
       
   280       MySetFileTime(item.IsCreationTimeDefined, item.CreationTime, prop);
       
   281       break;
       
   282     case kpidLastWriteTime:
       
   283       MySetFileTime(item.IsLastWriteTimeDefined, item.LastWriteTime, prop);
       
   284       break;
       
   285     case kpidAttributes:
       
   286       if (item.AreAttributesDefined)
       
   287         prop = item.Attributes;
       
   288       break;
       
   289     case kpidCRC:
       
   290       if (item.IsFileCRCDefined)
       
   291         prop = item.FileCRC;
       
   292       break;
       
   293     case kpidEncrypted:
       
   294     {
       
   295       prop = IsEncrypted(index2);
       
   296       break;
       
   297     }
       
   298     #ifndef _SFX
       
   299     case kpidMethod:
       
   300       {
       
   301         CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
       
   302         if (folderIndex != kNumNoIndex)
       
   303         {
       
   304           const CFolder &folderInfo = _database.Folders[folderIndex];
       
   305           UString methodsString;
       
   306           for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
       
   307           {
       
   308             const CCoderInfo &coderInfo = folderInfo.Coders[i];
       
   309             if (!methodsString.IsEmpty())
       
   310               methodsString += L' ';
       
   311 
       
   312             {
       
   313               UString methodName;
       
   314               bool methodIsKnown = FindMethod(
       
   315                   EXTERNAL_CODECS_VARS 
       
   316                   coderInfo.MethodID, methodName);
       
   317 
       
   318               if (methodIsKnown)
       
   319               {
       
   320                 methodsString += methodName;
       
   321                 if (coderInfo.MethodID == k_LZMA)
       
   322                 {
       
   323                   if (coderInfo.Properties.GetCapacity() >= 5)
       
   324                   {
       
   325                     methodsString += L":";
       
   326                     UInt32 dicSize = GetUInt32FromMemLE(
       
   327                       ((const Byte *)coderInfo.Properties + 1));
       
   328                     methodsString += GetStringForSizeValue(dicSize);
       
   329                   }
       
   330                 }
       
   331                 else if (coderInfo.MethodID == k_PPMD)
       
   332                 {
       
   333                   if (coderInfo.Properties.GetCapacity() >= 5)
       
   334                   {
       
   335                     Byte order = *(const Byte *)coderInfo.Properties;
       
   336                     methodsString += L":o";
       
   337                     methodsString += ConvertUInt32ToString(order);
       
   338                     methodsString += L":mem";
       
   339                     UInt32 dicSize = GetUInt32FromMemLE(
       
   340                       ((const Byte *)coderInfo.Properties + 1));
       
   341                     methodsString += GetStringForSizeValue(dicSize);
       
   342                   }
       
   343                 }
       
   344                 else if (coderInfo.MethodID == k_AES)
       
   345                 {
       
   346                   if (coderInfo.Properties.GetCapacity() >= 1)
       
   347                   {
       
   348                     methodsString += L":";
       
   349                     const Byte *data = (const Byte *)coderInfo.Properties;
       
   350                     Byte firstByte = *data++;
       
   351                     UInt32 numCyclesPower = firstByte & 0x3F;
       
   352                     methodsString += ConvertUInt32ToString(numCyclesPower);
       
   353                     /*
       
   354                     if ((firstByte & 0xC0) != 0)
       
   355                     {
       
   356                       methodsString += L":";
       
   357                       return S_OK;
       
   358                       UInt32 saltSize = (firstByte >> 7) & 1;
       
   359                       UInt32 ivSize = (firstByte >> 6) & 1;
       
   360                       if (coderInfo.Properties.GetCapacity() >= 2)
       
   361                       {
       
   362                         Byte secondByte = *data++;
       
   363                         saltSize += (secondByte >> 4);
       
   364                         ivSize += (secondByte & 0x0F);
       
   365                       }
       
   366                     }
       
   367                     */
       
   368                   }
       
   369                 }
       
   370                 else
       
   371                 {
       
   372                   if (coderInfo.Properties.GetCapacity() > 0)
       
   373                   {
       
   374                     methodsString += L":[";
       
   375                     for (size_t bi = 0; bi < coderInfo.Properties.GetCapacity(); bi++)
       
   376                     {
       
   377                       if (bi > 5 && bi + 1 < coderInfo.Properties.GetCapacity())
       
   378                       {
       
   379                         methodsString += L"..";
       
   380                         break;
       
   381                       }
       
   382                       else
       
   383                         methodsString += GetHex2(coderInfo.Properties[bi]);
       
   384                     }
       
   385                     methodsString += L"]";
       
   386                   }
       
   387                 }
       
   388               }
       
   389               else
       
   390               {
       
   391                 methodsString += ConvertMethodIdToString(coderInfo.MethodID);
       
   392               }
       
   393             }
       
   394           }
       
   395           prop = methodsString;
       
   396         }
       
   397       }
       
   398       break;
       
   399     case kpidBlock:
       
   400       {
       
   401         CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
       
   402         if (folderIndex != kNumNoIndex)
       
   403           prop = (UInt32)folderIndex;
       
   404       }
       
   405       break;
       
   406     case kpidPackedSize0:
       
   407     case kpidPackedSize1:
       
   408     case kpidPackedSize2:
       
   409     case kpidPackedSize3:
       
   410     case kpidPackedSize4:
       
   411       {
       
   412         CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
       
   413         if (folderIndex != kNumNoIndex)
       
   414         {
       
   415           const CFolder &folderInfo = _database.Folders[folderIndex];
       
   416           if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
       
   417               folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
       
   418           {
       
   419             prop = _database.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
       
   420           }
       
   421           else
       
   422             prop = (UInt64)0;
       
   423         }
       
   424         else
       
   425           prop = (UInt64)0;
       
   426       }
       
   427       break;
       
   428     #endif
       
   429     case kpidIsAnti:
       
   430       prop = item.IsAnti;
       
   431       break;
       
   432   }
       
   433   prop.Detach(value);
       
   434   return S_OK;
       
   435   COM_TRY_END
       
   436 }
       
   437 
       
   438 #ifdef _7Z_VOL
       
   439 
       
   440 static const wchar_t *kExt = L"7z";
       
   441 static const wchar_t *kAfterPart = L".7z";
       
   442 
       
   443 class CVolumeName
       
   444 {
       
   445   bool _first;
       
   446   UString _unchangedPart;
       
   447   UString _changedPart;    
       
   448   UString _afterPart;    
       
   449 public:
       
   450   bool InitName(const UString &name)
       
   451   {
       
   452     _first = true;
       
   453     int dotPos = name.ReverseFind('.');
       
   454     UString basePart = name;
       
   455     if (dotPos >= 0)
       
   456     {
       
   457       UString ext = name.Mid(dotPos + 1);
       
   458       if (ext.CompareNoCase(kExt)==0 || 
       
   459         ext.CompareNoCase(L"EXE") == 0)
       
   460       {
       
   461         _afterPart = kAfterPart;
       
   462         basePart = name.Left(dotPos);
       
   463       }
       
   464     }
       
   465 
       
   466     int numLetters = 1;
       
   467     bool splitStyle = false;
       
   468     if (basePart.Right(numLetters) == L"1")
       
   469     {
       
   470       while (numLetters < basePart.Length())
       
   471       {
       
   472         if (basePart[basePart.Length() - numLetters - 1] != '0')
       
   473           break;
       
   474         numLetters++;
       
   475       }
       
   476     }
       
   477     else 
       
   478       return false;
       
   479     _unchangedPart = basePart.Left(basePart.Length() - numLetters);
       
   480     _changedPart = basePart.Right(numLetters);
       
   481     return true;
       
   482   }
       
   483 
       
   484   UString GetNextName()
       
   485   {
       
   486     UString newName; 
       
   487     // if (_newStyle || !_first)
       
   488     {
       
   489       int i;
       
   490       int numLetters = _changedPart.Length();
       
   491       for (i = numLetters - 1; i >= 0; i--)
       
   492       {
       
   493         wchar_t c = _changedPart[i];
       
   494         if (c == L'9')
       
   495         {
       
   496           c = L'0';
       
   497           newName = c + newName;
       
   498           if (i == 0)
       
   499             newName = UString(L'1') + newName;
       
   500           continue;
       
   501         }
       
   502         c++;
       
   503         newName = UString(c) + newName;
       
   504         i--;
       
   505         for (; i >= 0; i--)
       
   506           newName = _changedPart[i] + newName;
       
   507         break;
       
   508       }
       
   509       _changedPart = newName;
       
   510     }
       
   511     _first = false;
       
   512     return _unchangedPart + _changedPart + _afterPart;
       
   513   }
       
   514 };
       
   515 
       
   516 #endif
       
   517 
       
   518 STDMETHODIMP CHandler::Open(IInStream *stream,
       
   519     const UInt64 *maxCheckStartPosition, 
       
   520     IArchiveOpenCallback *openArchiveCallback)
       
   521 {
       
   522   COM_TRY_BEGIN
       
   523   Close();
       
   524   #ifndef _SFX
       
   525   _fileInfoPopIDs.Clear();
       
   526   #endif
       
   527   try
       
   528   {
       
   529     CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
       
   530     #ifdef _7Z_VOL
       
   531     CVolumeName seqName;
       
   532 
       
   533     CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
       
   534     #endif
       
   535 
       
   536     #ifndef _NO_CRYPTO
       
   537     CMyComPtr<ICryptoGetTextPassword> getTextPassword;
       
   538     if (openArchiveCallback)
       
   539     {
       
   540       openArchiveCallbackTemp.QueryInterface(
       
   541           IID_ICryptoGetTextPassword, &getTextPassword);
       
   542     }
       
   543     #endif
       
   544     #ifdef _7Z_VOL
       
   545     if (openArchiveCallback)
       
   546     {
       
   547       openArchiveCallbackTemp.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
       
   548     }
       
   549     for (;;)
       
   550     {
       
   551       CMyComPtr<IInStream> inStream;
       
   552       if (!_volumes.IsEmpty())
       
   553       {
       
   554         if (!openVolumeCallback)
       
   555           break;
       
   556         if(_volumes.Size() == 1)
       
   557         {
       
   558           UString baseName;
       
   559           {
       
   560             NCOM::CPropVariant prop;
       
   561             RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
       
   562             if (prop.vt != VT_BSTR)
       
   563               break;
       
   564             baseName = prop.bstrVal;
       
   565           }
       
   566           seqName.InitName(baseName);
       
   567         }
       
   568 
       
   569         UString fullName = seqName.GetNextName();
       
   570         HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
       
   571         if (result == S_FALSE)
       
   572           break;
       
   573         if (result != S_OK)
       
   574           return result;
       
   575         if (!stream)
       
   576           break;
       
   577       }
       
   578       else
       
   579         inStream = stream;
       
   580 
       
   581       CInArchive archive;
       
   582       RINOK(archive.Open(inStream, maxCheckStartPosition));
       
   583 
       
   584       _volumes.Add(CVolume());
       
   585       CVolume &volume = _volumes.Back();
       
   586       CArchiveDatabaseEx &database = volume.Database;
       
   587       volume.Stream = inStream;
       
   588       volume.StartRef2Index = _refs.Size();
       
   589 
       
   590       HRESULT result = archive.ReadDatabase(database
       
   591           #ifndef _NO_CRYPTO
       
   592           , getTextPassword
       
   593           #endif
       
   594           );
       
   595       if (result != S_OK)
       
   596       {
       
   597         _volumes.Clear();
       
   598         return result;
       
   599       }
       
   600       database.Fill();
       
   601       for(int i = 0; i < database.Files.Size(); i++)
       
   602       {
       
   603         CRef refNew;
       
   604         refNew.VolumeIndex = _volumes.Size() - 1;
       
   605         refNew.ItemIndex = i;
       
   606         _refs.Add(refNew);
       
   607         /*
       
   608         const CFileItem &file = database.Files[i];
       
   609         int j;
       
   610         */
       
   611         /*
       
   612         for (j = _refs.Size() - 1; j >= 0; j--)
       
   613         {
       
   614           CRef2 &ref2 = _refs[j];
       
   615           const CRef &ref = ref2.Refs.Back();
       
   616           const CVolume &volume2 = _volumes[ref.VolumeIndex];
       
   617           const CArchiveDatabaseEx &database2 = volume2.Database;
       
   618           const CFileItem &file2 = database2.Files[ref.ItemIndex];
       
   619           if (file2.Name.CompareNoCase(file.Name) == 0)
       
   620           {
       
   621             if (!file.IsStartPosDefined)
       
   622               continue;
       
   623             if (file.StartPos != ref2.StartPos + ref2.UnPackSize)
       
   624               continue;
       
   625             ref2.Refs.Add(refNew);
       
   626             break;
       
   627           }
       
   628         }
       
   629         */
       
   630         /*
       
   631         j = -1;
       
   632         if (j < 0)
       
   633         {
       
   634           CRef2 ref2New;
       
   635           ref2New.Refs.Add(refNew);
       
   636           j = _refs.Add(ref2New);
       
   637         }
       
   638         CRef2 &ref2 = _refs[j];
       
   639         ref2.UnPackSize += file.UnPackSize;
       
   640         ref2.PackSize += database.GetFilePackSize(i);
       
   641         if (ref2.Refs.Size() == 1 && file.IsStartPosDefined)
       
   642           ref2.StartPos = file.StartPos;
       
   643         */
       
   644       }
       
   645       if (database.Files.Size() != 1)
       
   646         break;
       
   647       const CFileItem &file = database.Files.Front();
       
   648       if (!file.IsStartPosDefined)
       
   649         break;
       
   650     }
       
   651     #else
       
   652     CInArchive archive;
       
   653     RINOK(archive.Open(stream, maxCheckStartPosition));
       
   654     HRESULT result = archive.ReadDatabase(
       
   655       EXTERNAL_CODECS_VARS
       
   656       _database
       
   657       #ifndef _NO_CRYPTO
       
   658       , getTextPassword
       
   659       #endif
       
   660       );
       
   661     RINOK(result);
       
   662     _database.Fill();
       
   663     _inStream = stream;
       
   664     #endif
       
   665   }
       
   666   catch(...)
       
   667   {
       
   668     Close();
       
   669     return S_FALSE;
       
   670   }
       
   671   // _inStream = stream;
       
   672   #ifndef _SFX
       
   673   FillPopIDs();
       
   674   #endif
       
   675   return S_OK;
       
   676   COM_TRY_END
       
   677 }
       
   678 
       
   679 STDMETHODIMP CHandler::Close()
       
   680 {
       
   681   COM_TRY_BEGIN
       
   682   #ifdef _7Z_VOL
       
   683   _volumes.Clear();
       
   684   _refs.Clear();
       
   685   #else
       
   686   _inStream.Release();
       
   687   _database.Clear();
       
   688   #endif
       
   689   return S_OK;
       
   690   COM_TRY_END
       
   691 }
       
   692 
       
   693 #ifdef _7Z_VOL
       
   694 STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
       
   695 {
       
   696   if (index != 0)
       
   697     return E_INVALIDARG;
       
   698   *stream = 0;
       
   699   CMultiStream *streamSpec = new CMultiStream;
       
   700   CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
       
   701   
       
   702   UInt64 pos = 0;
       
   703   const UString *fileName;
       
   704   for (int i = 0; i < _refs.Size(); i++)
       
   705   {
       
   706     const CRef &ref = _refs[i];
       
   707     const CVolume &volume = _volumes[ref.VolumeIndex];
       
   708     const CArchiveDatabaseEx &database = volume.Database;
       
   709     const CFileItem &file = database.Files[ref.ItemIndex];
       
   710     if (i == 0)
       
   711       fileName = &file.Name;
       
   712     else
       
   713       if (fileName->Compare(file.Name) != 0)
       
   714         return S_FALSE;
       
   715     if (!file.IsStartPosDefined)
       
   716       return S_FALSE;
       
   717     if (file.StartPos != pos)
       
   718       return S_FALSE;
       
   719     CNum folderIndex = database.FileIndexToFolderIndexMap[ref.ItemIndex];
       
   720     if (folderIndex == kNumNoIndex)
       
   721     {
       
   722       if (file.UnPackSize != 0)
       
   723         return E_FAIL;
       
   724       continue;
       
   725     }
       
   726     if (database.NumUnPackStreamsVector[folderIndex] != 1)
       
   727       return S_FALSE;
       
   728     const CFolder &folder = database.Folders[folderIndex];
       
   729     if (folder.Coders.Size() != 1)
       
   730       return S_FALSE;
       
   731     const CCoderInfo &coder = folder.Coders.Front();
       
   732     if (coder.NumInStreams != 1 || coder.NumOutStreams != 1)
       
   733       return S_FALSE;
       
   734     if (coder.MethodID != k_Copy)
       
   735       return S_FALSE;
       
   736 
       
   737     pos += file.UnPackSize;
       
   738     CMultiStream::CSubStreamInfo subStreamInfo;
       
   739     subStreamInfo.Stream = volume.Stream;
       
   740     subStreamInfo.Pos = database.GetFolderStreamPos(folderIndex, 0);
       
   741     subStreamInfo.Size = file.UnPackSize;
       
   742     streamSpec->Streams.Add(subStreamInfo);
       
   743   }
       
   744   streamSpec->Init();
       
   745   *stream = streamTemp.Detach();
       
   746   return S_OK;
       
   747 }
       
   748 #endif
       
   749 
       
   750 
       
   751 #ifdef __7Z_SET_PROPERTIES
       
   752 #ifdef EXTRACT_ONLY
       
   753 
       
   754 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
       
   755 {
       
   756   COM_TRY_BEGIN
       
   757   #ifdef COMPRESS_MT
       
   758   const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
       
   759   _numThreads = numProcessors;
       
   760   #endif
       
   761 
       
   762   for (int i = 0; i < numProperties; i++)
       
   763   {
       
   764     UString name = names[i];
       
   765     name.MakeUpper();
       
   766     if (name.IsEmpty())
       
   767       return E_INVALIDARG;
       
   768     const PROPVARIANT &value = values[i];
       
   769     UInt32 number;
       
   770     int index = ParseStringToUInt32(name, number);
       
   771     if (index == 0)
       
   772     {
       
   773       if(name.Left(2).CompareNoCase(L"MT") == 0)
       
   774       {
       
   775         #ifdef COMPRESS_MT
       
   776         RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
       
   777         #endif
       
   778         continue;
       
   779       }
       
   780       else
       
   781         return E_INVALIDARG;
       
   782     }
       
   783   }
       
   784   return S_OK;
       
   785   COM_TRY_END
       
   786 }  
       
   787 
       
   788 #endif
       
   789 #endif
       
   790 
       
   791 IMPL_ISetCompressCodecsInfo
       
   792 
       
   793 }}