"Fossies" - the Fresh Open Source Software Archive

Member "p7zip_16.02/CPP/7zip/Archive/7z/7zHandlerOut.cpp" (20 May 2016, 23724 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 "7zHandlerOut.cpp": 15.14.1_src_all_vs_16.02_src_all.

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