other-licenses/7zstub/src/7zip/Archive/7z/7zHandler.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial