tor-browser

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

7zHandlerOut.cpp (25241B)


      1 // 7zHandlerOut.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../Common/ComTry.h"
      6 #include "../../../Common/StringToInt.h"
      7 #include "../../../Common/Wildcard.h"
      8 
      9 #include "../Common/ItemNameUtils.h"
     10 #include "../Common/ParseProperties.h"
     11 
     12 #include "7zHandler.h"
     13 #include "7zOut.h"
     14 #include "7zUpdate.h"
     15 
     16 #ifndef EXTRACT_ONLY
     17 
     18 using namespace NWindows;
     19 
     20 namespace NArchive {
     21 namespace N7z {
     22 
     23 #define k_LZMA_Name "LZMA"
     24 #define kDefaultMethodName "LZMA2"
     25 #define k_Copy_Name "Copy"
     26 
     27 #define k_MatchFinder_ForHeaders "BT2"
     28 
     29 static const UInt32 k_NumFastBytes_ForHeaders = 273;
     30 static const UInt32 k_Level_ForHeaders = 5;
     31 static const UInt32 k_Dictionary_ForHeaders =
     32  #ifdef UNDER_CE
     33  1 << 18;
     34  #else
     35  1 << 20;
     36  #endif
     37 
     38 STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
     39 {
     40  *type = NFileTimeType::kWindows;
     41  return S_OK;
     42 }
     43 
     44 HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)
     45 {
     46  dest.CodecIndex = FindMethod_Index(
     47      EXTERNAL_CODECS_VARS
     48      m.MethodName, true,
     49      dest.Id, dest.NumStreams);
     50  if (dest.CodecIndex < 0)
     51    return E_INVALIDARG;
     52  (CProps &)dest = (CProps &)m;
     53  return S_OK;
     54 }
     55 
     56 HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
     57 {
     58  if (!_compressHeaders)
     59    return S_OK;
     60  COneMethodInfo m;
     61  m.MethodName = k_LZMA_Name;
     62  m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
     63  m.AddProp_Level(k_Level_ForHeaders);
     64  m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
     65  m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
     66  m.AddProp_NumThreads(1);
     67 
     68  CMethodFull &methodFull = headerMethod.Methods.AddNew();
     69  return PropsMethod_To_FullMethod(methodFull, m);
     70 }
     71 
     72 HRESULT CHandler::SetMainMethod(
     73    CCompressionMethodMode &methodMode
     74    #ifndef _7ZIP_ST
     75    , UInt32 numThreads
     76    #endif
     77    )
     78 {
     79  methodMode.Bonds = _bonds;
     80 
     81  CObjectVector<COneMethodInfo> methods = _methods;
     82 
     83  {
     84    FOR_VECTOR (i, methods)
     85    {
     86      AString &methodName = methods[i].MethodName;
     87      if (methodName.IsEmpty())
     88        methodName = kDefaultMethodName;
     89    }
     90    if (methods.IsEmpty())
     91    {
     92      COneMethodInfo &m = methods.AddNew();
     93      m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
     94      methodMode.DefaultMethod_was_Inserted = true;
     95    }
     96  }
     97 
     98  if (!_filterMethod.MethodName.IsEmpty())
     99  {
    100    // if (methodMode.Bonds.IsEmpty())
    101    {
    102      FOR_VECTOR (k, methodMode.Bonds)
    103      {
    104        CBond2 &bond = methodMode.Bonds[k];
    105        bond.InCoder++;
    106        bond.OutCoder++;
    107      }
    108      methods.Insert(0, _filterMethod);
    109      methodMode.Filter_was_Inserted = true;
    110    }
    111  }
    112 
    113  const UInt64 kSolidBytes_Min = (1 << 24);
    114  const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1;
    115 
    116  bool needSolid = false;
    117  
    118  FOR_VECTOR (i, methods)
    119  {
    120    COneMethodInfo &oneMethodInfo = methods[i];
    121 
    122    SetGlobalLevelTo(oneMethodInfo);
    123    #ifndef _7ZIP_ST
    124    CMultiMethodProps::SetMethodThreadsTo(oneMethodInfo, numThreads);
    125    #endif
    126 
    127    CMethodFull &methodFull = methodMode.Methods.AddNew();
    128    RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo));
    129 
    130    if (methodFull.Id != k_Copy)
    131      needSolid = true;
    132 
    133    if (_numSolidBytesDefined)
    134      continue;
    135 
    136    UInt32 dicSize;
    137    switch (methodFull.Id)
    138    {
    139      case k_LZMA:
    140      case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break;
    141      case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break;
    142      case k_Deflate: dicSize = (UInt32)1 << 15; break;
    143      case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;
    144      default: continue;
    145    }
    146    
    147    _numSolidBytes = (UInt64)dicSize << 7;
    148    if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min;
    149    if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max;
    150    _numSolidBytesDefined = true;
    151  }
    152 
    153  if (!_numSolidBytesDefined)
    154    if (needSolid)
    155      _numSolidBytes = kSolidBytes_Max;
    156    else
    157      _numSolidBytes = 0;
    158  _numSolidBytesDefined = true;
    159  return S_OK;
    160 }
    161 
    162 static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined)
    163 {
    164  // ft = 0;
    165  // ftDefined = false;
    166  NCOM::CPropVariant prop;
    167  RINOK(updateCallback->GetProperty(index, propID, &prop));
    168  if (prop.vt == VT_FILETIME)
    169  {
    170    ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32);
    171    ftDefined = true;
    172  }
    173  else if (prop.vt != VT_EMPTY)
    174    return E_INVALIDARG;
    175  else
    176  {
    177    ft = 0;
    178    ftDefined = false;
    179  }
    180  return S_OK;
    181 }
    182 
    183 /*
    184 
    185 #ifdef _WIN32
    186 static const wchar_t kDirDelimiter1 = L'\\';
    187 #endif
    188 static const wchar_t kDirDelimiter2 = L'/';
    189 
    190 static inline bool IsCharDirLimiter(wchar_t c)
    191 {
    192  return (
    193    #ifdef _WIN32
    194    c == kDirDelimiter1 ||
    195    #endif
    196    c == kDirDelimiter2);
    197 }
    198 
    199 static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
    200 {
    201  CTreeFolder &tf = treeFolders[cur];
    202  tf.SortIndex = curSortIndex++;
    203  for (int i = 0; i < tf.SubFolders.Size(); i++)
    204    curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
    205  tf.SortIndexEnd = curSortIndex;
    206  return curSortIndex;
    207 }
    208 
    209 static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
    210 {
    211  const CIntVector &subFolders = treeFolders[cur].SubFolders;
    212  int left = 0, right = subFolders.Size();
    213  insertPos = -1;
    214  for (;;)
    215  {
    216    if (left == right)
    217    {
    218      insertPos = left;
    219      return -1;
    220    }
    221    int mid = (left + right) / 2;
    222    int midFolder = subFolders[mid];
    223    int compare = CompareFileNames(name, treeFolders[midFolder].Name);
    224    if (compare == 0)
    225      return midFolder;
    226    if (compare < 0)
    227      right = mid;
    228    else
    229      left = mid + 1;
    230  }
    231 }
    232 
    233 static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
    234 {
    235  int insertPos;
    236  int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
    237  if (folderIndex < 0)
    238  {
    239    folderIndex = treeFolders.Size();
    240    CTreeFolder &newFolder = treeFolders.AddNew();
    241    newFolder.Parent = cur;
    242    newFolder.Name = name;
    243    treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
    244  }
    245  // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
    246  return folderIndex;
    247 }
    248 */
    249 
    250 STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
    251    IArchiveUpdateCallback *updateCallback)
    252 {
    253  COM_TRY_BEGIN
    254 
    255  const CDbEx *db = 0;
    256  #ifdef _7Z_VOL
    257  if (_volumes.Size() > 1)
    258    return E_FAIL;
    259  const CVolume *volume = 0;
    260  if (_volumes.Size() == 1)
    261  {
    262    volume = &_volumes.Front();
    263    db = &volume->Database;
    264  }
    265  #else
    266  if (_inStream != 0)
    267    db = &_db;
    268  #endif
    269 
    270  /*
    271  CMyComPtr<IArchiveGetRawProps> getRawProps;
    272  updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);
    273 
    274  CUniqBlocks secureBlocks;
    275  secureBlocks.AddUniq(NULL, 0);
    276 
    277  CObjectVector<CTreeFolder> treeFolders;
    278  {
    279    CTreeFolder folder;
    280    folder.Parent = -1;
    281    treeFolders.Add(folder);
    282  }
    283  */
    284 
    285  CObjectVector<CUpdateItem> updateItems;
    286 
    287  bool need_CTime = (Write_CTime.Def && Write_CTime.Val);
    288  bool need_ATime = (Write_ATime.Def && Write_ATime.Val);
    289  bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def);
    290  bool need_Attrib = (Write_Attrib.Def && Write_Attrib.Val || !Write_Attrib.Def);
    291  
    292  if (db && !db->Files.IsEmpty())
    293  {
    294    if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
    295    if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
    296    if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
    297    if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty();
    298  }
    299 
    300  // UString s;
    301  UString name;
    302 
    303  for (UInt32 i = 0; i < numItems; i++)
    304  {
    305    Int32 newData, newProps;
    306    UInt32 indexInArchive;
    307    if (!updateCallback)
    308      return E_FAIL;
    309    RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
    310    CUpdateItem ui;
    311    ui.NewProps = IntToBool(newProps);
    312    ui.NewData = IntToBool(newData);
    313    ui.IndexInArchive = indexInArchive;
    314    ui.IndexInClient = i;
    315    ui.IsAnti = false;
    316    ui.Size = 0;
    317 
    318    name.Empty();
    319    // bool isAltStream = false;
    320    if (ui.IndexInArchive != -1)
    321    {
    322      if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size())
    323        return E_INVALIDARG;
    324      const CFileItem &fi = db->Files[ui.IndexInArchive];
    325      if (!ui.NewProps)
    326      {
    327        _db.GetPath(ui.IndexInArchive, name);
    328      }
    329      ui.IsDir = fi.IsDir;
    330      ui.Size = fi.Size;
    331      // isAltStream = fi.IsAltStream;
    332      ui.IsAnti = db->IsItemAnti(ui.IndexInArchive);
    333      
    334      if (!ui.NewProps)
    335      {
    336        ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime);
    337        ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime);
    338        ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime);
    339      }
    340    }
    341 
    342    if (ui.NewProps)
    343    {
    344      bool folderStatusIsDefined;
    345      if (need_Attrib)
    346      {
    347        NCOM::CPropVariant prop;
    348        RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop));
    349        if (prop.vt == VT_EMPTY)
    350          ui.AttribDefined = false;
    351        else if (prop.vt != VT_UI4)
    352          return E_INVALIDARG;
    353        else
    354        {
    355          ui.Attrib = prop.ulVal;
    356          ui.AttribDefined = true;
    357        }
    358      }
    359      
    360      // we need MTime to sort files.
    361      if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined));
    362      if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined));
    363      if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined));
    364 
    365      /*
    366      if (getRawProps)
    367      {
    368        const void *data;
    369        UInt32 dataSize;
    370        UInt32 propType;
    371 
    372        getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
    373        if (dataSize != 0 && propType != NPropDataType::kRaw)
    374          return E_FAIL;
    375        ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize);
    376      }
    377      */
    378 
    379      {
    380        NCOM::CPropVariant prop;
    381        RINOK(updateCallback->GetProperty(i, kpidPath, &prop));
    382        if (prop.vt == VT_EMPTY)
    383        {
    384        }
    385        else if (prop.vt != VT_BSTR)
    386          return E_INVALIDARG;
    387        else
    388        {
    389          name = prop.bstrVal;
    390          NItemName::ReplaceSlashes_OsToUnix(name);
    391        }
    392      }
    393      {
    394        NCOM::CPropVariant prop;
    395        RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop));
    396        if (prop.vt == VT_EMPTY)
    397          folderStatusIsDefined = false;
    398        else if (prop.vt != VT_BOOL)
    399          return E_INVALIDARG;
    400        else
    401        {
    402          ui.IsDir = (prop.boolVal != VARIANT_FALSE);
    403          folderStatusIsDefined = true;
    404        }
    405      }
    406 
    407      {
    408        NCOM::CPropVariant prop;
    409        RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop));
    410        if (prop.vt == VT_EMPTY)
    411          ui.IsAnti = false;
    412        else if (prop.vt != VT_BOOL)
    413          return E_INVALIDARG;
    414        else
    415          ui.IsAnti = (prop.boolVal != VARIANT_FALSE);
    416      }
    417 
    418      /*
    419      {
    420        NCOM::CPropVariant prop;
    421        RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop));
    422        if (prop.vt == VT_EMPTY)
    423          isAltStream = false;
    424        else if (prop.vt != VT_BOOL)
    425          return E_INVALIDARG;
    426        else
    427          isAltStream = (prop.boolVal != VARIANT_FALSE);
    428      }
    429      */
    430 
    431      if (ui.IsAnti)
    432      {
    433        ui.AttribDefined = false;
    434 
    435        ui.CTimeDefined = false;
    436        ui.ATimeDefined = false;
    437        ui.MTimeDefined = false;
    438        
    439        ui.Size = 0;
    440      }
    441 
    442      if (!folderStatusIsDefined && ui.AttribDefined)
    443        ui.SetDirStatusFromAttrib();
    444    }
    445    else
    446    {
    447      /*
    448      if (_db.SecureIDs.IsEmpty())
    449        ui.SecureIndex = secureBlocks.AddUniq(NULL, 0);
    450      else
    451      {
    452        int id = _db.SecureIDs[ui.IndexInArchive];
    453        size_t offs = _db.SecureOffsets[id];
    454        size_t size = _db.SecureOffsets[id + 1] - offs;
    455        ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size);
    456      }
    457      */
    458    }
    459 
    460    /*
    461    {
    462      int folderIndex = 0;
    463      if (_useParents)
    464      {
    465        int j;
    466        s.Empty();
    467        for (j = 0; j < name.Len(); j++)
    468        {
    469          wchar_t c = name[j];
    470          if (IsCharDirLimiter(c))
    471          {
    472            folderIndex = AddFolder(treeFolders, folderIndex, s);
    473            s.Empty();
    474            continue;
    475          }
    476          s += c;
    477        }
    478        if (isAltStream)
    479        {
    480          int colonPos = s.Find(':');
    481          if (colonPos < 0)
    482          {
    483            // isAltStream = false;
    484            return E_INVALIDARG;
    485          }
    486          UString mainName = s.Left(colonPos);
    487          int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName);
    488          if (treeFolders[newFolderIndex].UpdateItemIndex < 0)
    489          {
    490            for (int j = updateItems.Size() - 1; j >= 0; j--)
    491            {
    492              CUpdateItem &ui2 = updateItems[j];
    493              if (ui2.ParentFolderIndex == folderIndex
    494                  && ui2.Name == mainName)
    495              {
    496                ui2.TreeFolderIndex = newFolderIndex;
    497                treeFolders[newFolderIndex].UpdateItemIndex = j;
    498              }
    499            }
    500          }
    501          folderIndex = newFolderIndex;
    502          s.Delete(0, colonPos + 1);
    503        }
    504        ui.Name = s;
    505      }
    506      else
    507        ui.Name = name;
    508      ui.IsAltStream = isAltStream;
    509      ui.ParentFolderIndex = folderIndex;
    510      ui.TreeFolderIndex = -1;
    511      if (ui.IsDir && !s.IsEmpty())
    512      {
    513        ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s);
    514        treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size();
    515      }
    516    }
    517    */
    518    ui.Name = name;
    519 
    520    if (ui.NewData)
    521    {
    522      ui.Size = 0;
    523      if (!ui.IsDir)
    524      {
    525        NCOM::CPropVariant prop;
    526        RINOK(updateCallback->GetProperty(i, kpidSize, &prop));
    527        if (prop.vt != VT_UI8)
    528          return E_INVALIDARG;
    529        ui.Size = (UInt64)prop.uhVal.QuadPart;
    530        if (ui.Size != 0 && ui.IsAnti)
    531          return E_INVALIDARG;
    532      }
    533    }
    534    
    535    updateItems.Add(ui);
    536  }
    537 
    538  /*
    539  FillSortIndex(treeFolders, 0, 0);
    540  for (i = 0; i < (UInt32)updateItems.Size(); i++)
    541  {
    542    CUpdateItem &ui = updateItems[i];
    543    ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex;
    544    ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd;
    545  }
    546  */
    547 
    548  CCompressionMethodMode methodMode, headerMethod;
    549 
    550  HRESULT res = SetMainMethod(methodMode
    551    #ifndef _7ZIP_ST
    552    , _numThreads
    553    #endif
    554    );
    555  RINOK(res);
    556 
    557  RINOK(SetHeaderMethod(headerMethod));
    558  
    559  #ifndef _7ZIP_ST
    560  methodMode.NumThreads = _numThreads;
    561  methodMode.MultiThreadMixer = _useMultiThreadMixer;
    562  headerMethod.NumThreads = 1;
    563  headerMethod.MultiThreadMixer = _useMultiThreadMixer;
    564  #endif
    565 
    566  CMyComPtr<ICryptoGetTextPassword2> getPassword2;
    567  updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);
    568 
    569  methodMode.PasswordIsDefined = false;
    570  methodMode.Password.Empty();
    571  if (getPassword2)
    572  {
    573    CMyComBSTR password;
    574    Int32 passwordIsDefined;
    575    RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password));
    576    methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
    577    if (methodMode.PasswordIsDefined && password)
    578      methodMode.Password = password;
    579  }
    580 
    581  bool compressMainHeader = _compressHeaders;  // check it
    582 
    583  bool encryptHeaders = false;
    584 
    585  #ifndef _NO_CRYPTO
    586  if (!methodMode.PasswordIsDefined && _passwordIsDefined)
    587  {
    588    // if header is compressed, we use that password for updated archive
    589    methodMode.PasswordIsDefined = true;
    590    methodMode.Password = _password;
    591  }
    592  #endif
    593 
    594  if (methodMode.PasswordIsDefined)
    595  {
    596    if (_encryptHeadersSpecified)
    597      encryptHeaders = _encryptHeaders;
    598    #ifndef _NO_CRYPTO
    599    else
    600      encryptHeaders = _passwordIsDefined;
    601    #endif
    602    compressMainHeader = true;
    603    if (encryptHeaders)
    604    {
    605      headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
    606      headerMethod.Password = methodMode.Password;
    607    }
    608  }
    609 
    610  if (numItems < 2)
    611    compressMainHeader = false;
    612 
    613  int level = GetLevel();
    614 
    615  CUpdateOptions options;
    616  options.Method = &methodMode;
    617  options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
    618  options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
    619  options.MaxFilter = (level >= 8);
    620  options.AnalysisLevel = GetAnalysisLevel();
    621 
    622  options.HeaderOptions.CompressMainHeader = compressMainHeader;
    623  /*
    624  options.HeaderOptions.WriteCTime = Write_CTime;
    625  options.HeaderOptions.WriteATime = Write_ATime;
    626  options.HeaderOptions.WriteMTime = Write_MTime;
    627  options.HeaderOptions.WriteAttrib = Write_Attrib;
    628  */
    629  
    630  options.NumSolidFiles = _numSolidFiles;
    631  options.NumSolidBytes = _numSolidBytes;
    632  options.SolidExtension = _solidExtension;
    633  options.UseTypeSorting = _useTypeSorting;
    634 
    635  options.RemoveSfxBlock = _removeSfxBlock;
    636  // options.VolumeMode = _volumeMode;
    637 
    638  options.MultiThreadMixer = _useMultiThreadMixer;
    639 
    640  COutArchive archive;
    641  CArchiveDatabaseOut newDatabase;
    642 
    643  CMyComPtr<ICryptoGetTextPassword> getPassword;
    644  updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);
    645  
    646  /*
    647  if (secureBlocks.Sorted.Size() > 1)
    648  {
    649    secureBlocks.GetReverseMap();
    650    for (int i = 0; i < updateItems.Size(); i++)
    651    {
    652      int &secureIndex = updateItems[i].SecureIndex;
    653      secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
    654    }
    655  }
    656  */
    657 
    658  res = Update(
    659      EXTERNAL_CODECS_VARS
    660      #ifdef _7Z_VOL
    661      volume ? volume->Stream: 0,
    662      volume ? db : 0,
    663      #else
    664      _inStream,
    665      db,
    666      #endif
    667      updateItems,
    668      // treeFolders,
    669      // secureBlocks,
    670      archive, newDatabase, outStream, updateCallback, options
    671      #ifndef _NO_CRYPTO
    672      , getPassword
    673      #endif
    674      );
    675 
    676  RINOK(res);
    677 
    678  updateItems.ClearAndFree();
    679 
    680  return archive.WriteDatabase(EXTERNAL_CODECS_VARS
    681      newDatabase, options.HeaderMethod, options.HeaderOptions);
    682 
    683  COM_TRY_END
    684 }
    685 
    686 static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream)
    687 {
    688  stream = 0;
    689  {
    690    unsigned index = ParseStringToUInt32(srcString, coder);
    691    if (index == 0)
    692      return E_INVALIDARG;
    693    srcString.DeleteFrontal(index);
    694  }
    695  if (srcString[0] == 's')
    696  {
    697    srcString.Delete(0);
    698    unsigned index = ParseStringToUInt32(srcString, stream);
    699    if (index == 0)
    700      return E_INVALIDARG;
    701    srcString.DeleteFrontal(index);
    702  }
    703  return S_OK;
    704 }
    705 
    706 void COutHandler::InitProps7z()
    707 {
    708  _removeSfxBlock = false;
    709  _compressHeaders = true;
    710  _encryptHeadersSpecified = false;
    711  _encryptHeaders = false;
    712  // _useParents = false;
    713  
    714  Write_CTime.Init();
    715  Write_ATime.Init();
    716  Write_MTime.Init();
    717  Write_Attrib.Init();
    718 
    719  _useMultiThreadMixer = true;
    720 
    721  // _volumeMode = false;
    722 
    723  InitSolid();
    724  _useTypeSorting = false;
    725 }
    726 
    727 void COutHandler::InitProps()
    728 {
    729  CMultiMethodProps::Init();
    730  InitProps7z();
    731 }
    732 
    733 
    734 
    735 HRESULT COutHandler::SetSolidFromString(const UString &s)
    736 {
    737  UString s2 = s;
    738  s2.MakeLower_Ascii();
    739  for (unsigned i = 0; i < s2.Len();)
    740  {
    741    const wchar_t *start = ((const wchar_t *)s2) + i;
    742    const wchar_t *end;
    743    UInt64 v = ConvertStringToUInt64(start, &end);
    744    if (start == end)
    745    {
    746      if (s2[i++] != 'e')
    747        return E_INVALIDARG;
    748      _solidExtension = true;
    749      continue;
    750    }
    751    i += (int)(end - start);
    752    if (i == s2.Len())
    753      return E_INVALIDARG;
    754    wchar_t c = s2[i++];
    755    if (c == 'f')
    756    {
    757      if (v < 1)
    758        v = 1;
    759      _numSolidFiles = v;
    760    }
    761    else
    762    {
    763      unsigned numBits;
    764      switch (c)
    765      {
    766        case 'b': numBits =  0; break;
    767        case 'k': numBits = 10; break;
    768        case 'm': numBits = 20; break;
    769        case 'g': numBits = 30; break;
    770        case 't': numBits = 40; break;
    771        default: return E_INVALIDARG;
    772      }
    773      _numSolidBytes = (v << numBits);
    774      _numSolidBytesDefined = true;
    775      /*
    776      if (_numSolidBytes == 0)
    777        _numSolidFiles = 1;
    778      */
    779    }
    780  }
    781  return S_OK;
    782 }
    783 
    784 HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
    785 {
    786  bool isSolid;
    787  switch (value.vt)
    788  {
    789    case VT_EMPTY: isSolid = true; break;
    790    case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
    791    case VT_BSTR:
    792      if (StringToBool(value.bstrVal, isSolid))
    793        break;
    794      return SetSolidFromString(value.bstrVal);
    795    default: return E_INVALIDARG;
    796  }
    797  if (isSolid)
    798    InitSolid();
    799  else
    800    _numSolidFiles = 1;
    801  return S_OK;
    802 }
    803 
    804 static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
    805 {
    806  RINOK(PROPVARIANT_to_bool(prop, dest.Val));
    807  dest.Def = true;
    808  return S_OK;
    809 }
    810 
    811 HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
    812 {
    813  UString name = nameSpec;
    814  name.MakeLower_Ascii();
    815  if (name.IsEmpty())
    816    return E_INVALIDARG;
    817  
    818  if (name[0] == L's')
    819  {
    820    name.Delete(0);
    821    if (name.IsEmpty())
    822      return SetSolidFromPROPVARIANT(value);
    823    if (value.vt != VT_EMPTY)
    824      return E_INVALIDARG;
    825    return SetSolidFromString(name);
    826  }
    827 
    828  UInt32 number;
    829  int index = ParseStringToUInt32(name, number);
    830  // UString realName = name.Ptr(index);
    831  if (index == 0)
    832  {
    833    if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock);
    834    if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders);
    835    // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents);
    836    
    837    if (name.IsEqualTo("hcf"))
    838    {
    839      bool compressHeadersFull = true;
    840      RINOK(PROPVARIANT_to_bool(value, compressHeadersFull));
    841      return compressHeadersFull ? S_OK: E_INVALIDARG;
    842    }
    843    
    844    if (name.IsEqualTo("he"))
    845    {
    846      RINOK(PROPVARIANT_to_bool(value, _encryptHeaders));
    847      _encryptHeadersSpecified = true;
    848      return S_OK;
    849    }
    850    
    851    if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime);
    852    if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime);
    853    if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime);
    854    
    855    if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib);
    856    
    857    if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);
    858 
    859    if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting);
    860 
    861    // if (name.IsEqualTo("v"))  return PROPVARIANT_to_bool(value, _volumeMode);
    862  }
    863  return CMultiMethodProps::SetProperty(name, value);
    864 }
    865 
    866 STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
    867 {
    868  COM_TRY_BEGIN
    869  _bonds.Clear();
    870  InitProps();
    871 
    872  for (UInt32 i = 0; i < numProps; i++)
    873  {
    874    UString name = names[i];
    875    name.MakeLower_Ascii();
    876    if (name.IsEmpty())
    877      return E_INVALIDARG;
    878 
    879    const PROPVARIANT &value = values[i];
    880 
    881    if (name[0] == 'b')
    882    {
    883      if (value.vt != VT_EMPTY)
    884        return E_INVALIDARG;
    885      name.Delete(0);
    886      
    887      CBond2 bond;
    888      RINOK(ParseBond(name, bond.OutCoder, bond.OutStream));
    889      if (name[0] != ':')
    890        return E_INVALIDARG;
    891      name.Delete(0);
    892      UInt32 inStream = 0;
    893      RINOK(ParseBond(name, bond.InCoder, inStream));
    894      if (inStream != 0)
    895        return E_INVALIDARG;
    896      if (!name.IsEmpty())
    897        return E_INVALIDARG;
    898      _bonds.Add(bond);
    899      continue;
    900    }
    901 
    902    RINOK(SetProperty(name, value));
    903  }
    904 
    905  unsigned numEmptyMethods = GetNumEmptyMethods();
    906  if (numEmptyMethods > 0)
    907  {
    908    unsigned k;
    909    for (k = 0; k < _bonds.Size(); k++)
    910    {
    911      const CBond2 &bond = _bonds[k];
    912      if (bond.InCoder < (UInt32)numEmptyMethods ||
    913          bond.OutCoder < (UInt32)numEmptyMethods)
    914        return E_INVALIDARG;
    915    }
    916    for (k = 0; k < _bonds.Size(); k++)
    917    {
    918      CBond2 &bond = _bonds[k];
    919      bond.InCoder -= (UInt32)numEmptyMethods;
    920      bond.OutCoder -= (UInt32)numEmptyMethods;
    921    }
    922    _methods.DeleteFrontal(numEmptyMethods);
    923  }
    924  
    925  FOR_VECTOR (k, _bonds)
    926  {
    927    const CBond2 &bond = _bonds[k];
    928    if (bond.InCoder >= (UInt32)_methods.Size() ||
    929        bond.OutCoder >= (UInt32)_methods.Size())
    930      return E_INVALIDARG;
    931  }
    932 
    933  return S_OK;
    934  COM_TRY_END
    935 }
    936 
    937 }}
    938 
    939 #endif