1 // 7zUpdate.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../../C/CpuArch.h"
6 
7 #include "../../../Common/Wildcard.h"
8 
9 #include "../../Common/CreateCoder.h"
10 #include "../../Common/LimitedStreams.h"
11 #include "../../Common/ProgressUtils.h"
12 
13 #include "../../Compress/CopyCoder.h"
14 
15 #include "../Common/ItemNameUtils.h"
16 #include "../Common/OutStreamWithCRC.h"
17 
18 #include "7zDecode.h"
19 #include "7zEncode.h"
20 #include "7zFolderInStream.h"
21 #include "7zHandler.h"
22 #include "7zOut.h"
23 #include "7zUpdate.h"
24 
25 namespace NArchive {
26 namespace N7z {
27 
28 #ifdef MY_CPU_X86_OR_AMD64
29 #define USE_86_FILTER
30 #endif
31 
WriteRange(IInStream * inStream,ISequentialOutStream * outStream,UInt64 position,UInt64 size,ICompressProgressInfo * progress)32 static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream,
33     UInt64 position, UInt64 size, ICompressProgressInfo *progress)
34 {
35   RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0));
36   CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
37   CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
38   streamSpec->SetStream(inStream);
39   streamSpec->Init(size);
40 
41   NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
42   CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
43   RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
44   return (copyCoderSpec->TotalSize == size ? S_OK : E_FAIL);
45 }
46 
GetReverseSlashPos(const UString & name)47 static int GetReverseSlashPos(const UString &name)
48 {
49   int slashPos = name.ReverseFind(L'/');
50   #ifdef _WIN32
51   int slash1Pos = name.ReverseFind(L'\\');
52   slashPos = MyMax(slashPos, slash1Pos);
53   #endif
54   return slashPos;
55 }
56 
GetExtensionPos() const57 int CUpdateItem::GetExtensionPos() const
58 {
59   int slashPos = GetReverseSlashPos(Name);
60   int dotPos = Name.ReverseFind(L'.');
61   if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
62     return Name.Len();
63   return dotPos + 1;
64 }
65 
GetExtension() const66 UString CUpdateItem::GetExtension() const
67 {
68   return Name.Ptr(GetExtensionPos());
69 }
70 
71 #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
72 
73 #define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b))
74 
75 /*
76 static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2)
77 {
78   size_t c1 = a1.GetCapacity();
79   size_t c2 = a2.GetCapacity();
80   RINOZ_COMP(c1, c2);
81   for (size_t i = 0; i < c1; i++)
82     RINOZ_COMP(a1[i], a2[i]);
83   return 0;
84 }
85 
86 static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2)
87 {
88   RINOZ_COMP(c1.NumInStreams, c2.NumInStreams);
89   RINOZ_COMP(c1.NumOutStreams, c2.NumOutStreams);
90   RINOZ_COMP(c1.MethodID, c2.MethodID);
91   return CompareBuffers(c1.Props, c2.Props);
92 }
93 
94 static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2)
95 {
96   RINOZ_COMP(b1.InIndex, b2.InIndex);
97   return MyCompare(b1.OutIndex, b2.OutIndex);
98 }
99 
100 static int CompareFolders(const CFolder &f1, const CFolder &f2)
101 {
102   int s1 = f1.Coders.Size();
103   int s2 = f2.Coders.Size();
104   RINOZ_COMP(s1, s2);
105   int i;
106   for (i = 0; i < s1; i++)
107     RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i]));
108   s1 = f1.BindPairs.Size();
109   s2 = f2.BindPairs.Size();
110   RINOZ_COMP(s1, s2);
111   for (i = 0; i < s1; i++)
112     RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i]));
113   return 0;
114 }
115 */
116 
117 /*
118 static int CompareFiles(const CFileItem &f1, const CFileItem &f2)
119 {
120   return CompareFileNames(f1.Name, f2.Name);
121 }
122 */
123 
124 struct CFolderRepack
125 {
126   int FolderIndex;
127   int Group;
128   CNum NumCopyFiles;
129 };
130 
CompareFolderRepacks(const CFolderRepack * p1,const CFolderRepack * p2,void *)131 static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void * /* param */)
132 {
133   RINOZ_COMP(p1->Group, p2->Group);
134   int i1 = p1->FolderIndex;
135   int i2 = p2->FolderIndex;
136   /*
137   // In that version we don't want to parse folders here, so we don't compare folders
138   // probably it must be improved in future
139   const CDbEx &db = *(const CDbEx *)param;
140   RINOZ(CompareFolders(
141       db.Folders[i1],
142       db.Folders[i2]));
143   */
144   return MyCompare(i1, i2);
145   /*
146   RINOZ_COMP(
147       db.NumUnpackStreamsVector[i1],
148       db.NumUnpackStreamsVector[i2]);
149   if (db.NumUnpackStreamsVector[i1] == 0)
150     return 0;
151   return CompareFiles(
152       db.Files[db.FolderStartFileIndex[i1]],
153       db.Files[db.FolderStartFileIndex[i2]]);
154   */
155 }
156 
157 /*
158   we sort empty files and dirs in such order:
159   - Dir.NonAnti   (name sorted)
160   - File.NonAnti  (name sorted)
161   - File.Anti     (name sorted)
162   - Dir.Anti (reverse name sorted)
163 */
164 
CompareEmptyItems(const int * p1,const int * p2,void * param)165 static int CompareEmptyItems(const int *p1, const int *p2, void *param)
166 {
167   const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;
168   const CUpdateItem &u1 = updateItems[*p1];
169   const CUpdateItem &u2 = updateItems[*p2];
170   // NonAnti < Anti
171   if (u1.IsAnti != u2.IsAnti)
172     return (u1.IsAnti ? 1 : -1);
173   if (u1.IsDir != u2.IsDir)
174   {
175     // Dir.NonAnti < File < Dir.Anti
176     if (u1.IsDir)
177       return (u1.IsAnti ? 1 : -1);
178     return (u2.IsAnti ? -1 : 1);
179   }
180   int n = CompareFileNames(u1.Name, u2.Name);
181   return (u1.IsDir && u1.IsAnti) ? -n : n;
182 }
183 
184 static const char *g_Exts =
185   " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo"
186   " zip jar ear war msi"
187   " 3gp avi mov mpeg mpg mpe wmv"
188   " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav"
189   " swf "
190   " chm hxi hxs"
191   " gif jpeg jpg jp2 png tiff  bmp ico psd psp"
192   " awg ps eps cgm dxf svg vrml wmf emf ai md"
193   " cad dwg pps key sxi"
194   " max 3ds"
195   " iso bin nrg mdf img pdi tar cpio xpi"
196   " vfd vhd vud vmc vsv"
197   " vmdk dsk nvram vmem vmsd vmsn vmss vmtm"
198   " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def"
199   " f77 f f90 f95"
200   " asm sql manifest dep "
201   " mak clw csproj vcproj sln dsp dsw "
202   " class "
203   " bat cmd"
204   " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
205   " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl vbs"
206   " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf"
207   " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf"
208   " abw afp cwk lwp wpd wps wpt wrf wri"
209   " abf afm bdf fon mgf otf pcf pfa snf ttf"
210   " dbf mdb nsf ntf wdb db fdb gdb"
211   " exe dll ocx vbx sfx sys tlb awx com obj lib out o so "
212   " pdb pch idb ncb opt";
213 
GetExtIndex(const char * ext)214 static int GetExtIndex(const char *ext)
215 {
216   int extIndex = 1;
217   const char *p = g_Exts;
218   for (;;)
219   {
220     char c = *p++;
221     if (c == 0)
222       return extIndex;
223     if (c == ' ')
224       continue;
225     int pos = 0;
226     for (;;)
227     {
228       char c2 = ext[pos++];
229       if (c2 == 0 && (c == 0 || c == ' '))
230         return extIndex;
231       if (c != c2)
232         break;
233       c = *p++;
234     }
235     extIndex++;
236     for (;;)
237     {
238       if (c == 0)
239         return extIndex;
240       if (c == ' ')
241         break;
242       c = *p++;
243     }
244   }
245 }
246 
247 struct CRefItem
248 {
249   const CUpdateItem *UpdateItem;
250   UInt32 Index;
251   UInt32 ExtensionPos;
252   UInt32 NamePos;
253   unsigned ExtensionIndex;
254 
CRefItemNArchive::N7z::CRefItem255   CRefItem() {};
CRefItemNArchive::N7z::CRefItem256   CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType):
257     UpdateItem(&ui),
258     Index(index),
259     ExtensionPos(0),
260     NamePos(0),
261     ExtensionIndex(0)
262   {
263     if (sortByType)
264     {
265       int slashPos = GetReverseSlashPos(ui.Name);
266       NamePos = slashPos + 1;
267       int dotPos = ui.Name.ReverseFind(L'.');
268       if (dotPos < 0 || dotPos < slashPos)
269         ExtensionPos = ui.Name.Len();
270       else
271       {
272         ExtensionPos = dotPos + 1;
273         if (ExtensionPos != ui.Name.Len())
274         {
275           AString s;
276           for (unsigned pos = ExtensionPos;; pos++)
277           {
278             wchar_t c = ui.Name[pos];
279             if (c >= 0x80)
280               break;
281             if (c == 0)
282             {
283               ExtensionIndex = GetExtIndex(s);
284               break;
285             }
286             s += (char)MyCharLower_Ascii((char)c);
287           }
288         }
289       }
290     }
291   }
292 };
293 
294 struct CSortParam
295 {
296   // const CObjectVector<CTreeFolder> *TreeFolders;
297   bool SortByType;
298 };
299 
300 /*
301   we sort files in such order:
302   - Dir.NonAnti   (name sorted)
303   - alt streams
304   - Dirs
305   - Dir.Anti (reverse name sorted)
306 */
307 
308 
CompareUpdateItems(const CRefItem * p1,const CRefItem * p2,void * param)309 static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param)
310 {
311   const CRefItem &a1 = *p1;
312   const CRefItem &a2 = *p2;
313   const CUpdateItem &u1 = *a1.UpdateItem;
314   const CUpdateItem &u2 = *a2.UpdateItem;
315 
316   /*
317   if (u1.IsAltStream != u2.IsAltStream)
318     return u1.IsAltStream ? 1 : -1;
319   */
320 
321   // Actually there are no dirs that time. They were stored in other steps
322   // So that code is unused?
323   if (u1.IsDir != u2.IsDir)
324     return u1.IsDir ? 1 : -1;
325   if (u1.IsDir)
326   {
327     if (u1.IsAnti != u2.IsAnti)
328       return (u1.IsAnti ? 1 : -1);
329     int n = CompareFileNames(u1.Name, u2.Name);
330     return -n;
331   }
332 
333   // bool sortByType = *(bool *)param;
334   const CSortParam *sortParam = (const CSortParam *)param;
335   bool sortByType = sortParam->SortByType;
336   if (sortByType)
337   {
338     RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex);
339     RINOZ(CompareFileNames(u1.Name.Ptr(a1.ExtensionPos), u2.Name.Ptr(a2.ExtensionPos)));
340     RINOZ(CompareFileNames(u1.Name.Ptr(a1.NamePos), u2.Name.Ptr(a2.NamePos)));
341     if (!u1.MTimeDefined && u2.MTimeDefined) return 1;
342     if (u1.MTimeDefined && !u2.MTimeDefined) return -1;
343     if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime);
344     RINOZ_COMP(u1.Size, u2.Size);
345   }
346   /*
347   int par1 = a1.UpdateItem->ParentFolderIndex;
348   int par2 = a2.UpdateItem->ParentFolderIndex;
349   const CTreeFolder &tf1 = (*sortParam->TreeFolders)[par1];
350   const CTreeFolder &tf2 = (*sortParam->TreeFolders)[par2];
351 
352   int b1 = tf1.SortIndex, e1 = tf1.SortIndexEnd;
353   int b2 = tf2.SortIndex, e2 = tf2.SortIndexEnd;
354   if (b1 < b2)
355   {
356     if (e1 <= b2)
357       return -1;
358     // p2 in p1
359     int par = par2;
360     for (;;)
361     {
362       const CTreeFolder &tf = (*sortParam->TreeFolders)[par];
363       par = tf.Parent;
364       if (par == par1)
365       {
366         RINOZ(CompareFileNames(u1.Name, tf.Name));
367         break;
368       }
369     }
370   }
371   else if (b2 < b1)
372   {
373     if (e2 <= b1)
374       return 1;
375     // p1 in p2
376     int par = par1;
377     for (;;)
378     {
379       const CTreeFolder &tf = (*sortParam->TreeFolders)[par];
380       par = tf.Parent;
381       if (par == par2)
382       {
383         RINOZ(CompareFileNames(tf.Name, u2.Name));
384         break;
385       }
386     }
387   }
388   */
389   // RINOZ_COMP(a1.UpdateItem->ParentSortIndex, a2.UpdateItem->ParentSortIndex);
390   RINOK(CompareFileNames(u1.Name, u2.Name));
391   RINOZ_COMP(a1.UpdateItem->IndexInClient, a2.UpdateItem->IndexInClient);
392   RINOZ_COMP(a1.UpdateItem->IndexInArchive, a2.UpdateItem->IndexInArchive);
393   return 0;
394 }
395 
396 struct CSolidGroup
397 {
398   CRecordVector<UInt32> Indices;
399 };
400 
401 static const wchar_t *g_ExeExts[] =
402 {
403     L"dll"
404   , L"exe"
405   , L"ocx"
406   , L"sfx"
407   , L"sys"
408 };
409 
IsExeExt(const wchar_t * ext)410 static bool IsExeExt(const wchar_t *ext)
411 {
412   for (int i = 0; i < ARRAY_SIZE(g_ExeExts); i++)
413     if (MyStringCompareNoCase(ext, g_ExeExts[i]) == 0)
414       return true;
415   return false;
416 }
417 
418 
GetMethodFull(UInt64 methodID,UInt32 numInStreams,CMethodFull & m)419 static inline void GetMethodFull(UInt64 methodID, UInt32 numInStreams, CMethodFull &m)
420 {
421   m.Id = methodID;
422   m.NumInStreams = numInStreams;
423   m.NumOutStreams = 1;
424 }
425 
AddBcj2Methods(CCompressionMethodMode & mode)426 static void AddBcj2Methods(CCompressionMethodMode &mode)
427 {
428   CMethodFull m;
429   GetMethodFull(k_LZMA, 1, m);
430 
431   m.AddProp32(NCoderPropID::kDictionarySize, 1 << 20);
432   m.AddProp32(NCoderPropID::kNumFastBytes, 128);
433   m.AddProp32(NCoderPropID::kNumThreads, 1);
434   m.AddProp32(NCoderPropID::kLitPosBits, 2);
435   m.AddProp32(NCoderPropID::kLitContextBits, 0);
436   // m.AddPropString(NCoderPropID::kMatchFinder, L"BT2");
437 
438   mode.Methods.Add(m);
439   mode.Methods.Add(m);
440 
441   CBind bind;
442   bind.OutCoder = 0;
443   bind.InStream = 0;
444   bind.InCoder = 1;  bind.OutStream = 0;  mode.Binds.Add(bind);
445   bind.InCoder = 2;  bind.OutStream = 1;  mode.Binds.Add(bind);
446   bind.InCoder = 3;  bind.OutStream = 2;  mode.Binds.Add(bind);
447 }
448 
MakeExeMethod(CCompressionMethodMode & mode,bool useFilters,bool addFilter,bool bcj2Filter)449 static void MakeExeMethod(CCompressionMethodMode &mode,
450     bool useFilters, bool addFilter, bool bcj2Filter)
451 {
452   if (!mode.Binds.IsEmpty() || !useFilters || mode.Methods.Size() > 2)
453     return;
454   if (mode.Methods.Size() == 2)
455   {
456     if (mode.Methods[0].Id == k_BCJ2)
457       AddBcj2Methods(mode);
458     return;
459   }
460   if (!addFilter)
461     return;
462   bcj2Filter = bcj2Filter;
463   #ifdef USE_86_FILTER
464   if (bcj2Filter)
465   {
466     CMethodFull m;
467     GetMethodFull(k_BCJ2, 4, m);
468     mode.Methods.Insert(0, m);
469     AddBcj2Methods(mode);
470   }
471   else
472   {
473     CMethodFull m;
474     GetMethodFull(k_BCJ, 1, m);
475     mode.Methods.Insert(0, m);
476     CBind bind;
477     bind.OutCoder = 0;
478     bind.InStream = 0;
479     bind.InCoder = 1;
480     bind.OutStream = 0;
481     mode.Binds.Add(bind);
482   }
483   #endif
484 }
485 
486 
FromUpdateItemToFileItem(const CUpdateItem & ui,CFileItem & file,CFileItem2 & file2)487 static void FromUpdateItemToFileItem(const CUpdateItem &ui,
488     CFileItem &file, CFileItem2 &file2)
489 {
490   if (ui.AttribDefined)
491     file.SetAttrib(ui.Attrib);
492 
493   file2.CTime = ui.CTime;  file2.CTimeDefined = ui.CTimeDefined;
494   file2.ATime = ui.ATime;  file2.ATimeDefined = ui.ATimeDefined;
495   file2.MTime = ui.MTime;  file2.MTimeDefined = ui.MTimeDefined;
496   file2.IsAnti = ui.IsAnti;
497   // file2.IsAux = false;
498   file2.StartPosDefined = false;
499 
500   file.Size = ui.Size;
501   file.IsDir = ui.IsDir;
502   file.HasStream = ui.HasStream();
503   // file.IsAltStream = ui.IsAltStream;
504 }
505 
506 class CFolderOutStream2:
507   public ISequentialOutStream,
508   public CMyUnknownImp
509 {
510   COutStreamWithCRC *_crcStreamSpec;
511   CMyComPtr<ISequentialOutStream> _crcStream;
512   const CDbEx *_db;
513   const CBoolVector *_extractStatuses;
514   CMyComPtr<ISequentialOutStream> _outStream;
515   UInt32 _startIndex;
516   unsigned _currentIndex;
517   bool _fileIsOpen;
518   UInt64 _rem;
519 
520   void OpenFile();
521   void CloseFile();
522   HRESULT CloseFileAndSetResult();
523   HRESULT ProcessEmptyFiles();
524 public:
525   MY_UNKNOWN_IMP
526 
CFolderOutStream2()527   CFolderOutStream2()
528   {
529     _crcStreamSpec = new COutStreamWithCRC;
530     _crcStream = _crcStreamSpec;
531   }
532 
533   HRESULT Init(const CDbEx *db, UInt32 startIndex,
534       const CBoolVector *extractStatuses, ISequentialOutStream *outStream);
535   void ReleaseOutStream();
CheckFinishedState() const536   HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
537 
538   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
539 };
540 
Init(const CDbEx * db,UInt32 startIndex,const CBoolVector * extractStatuses,ISequentialOutStream * outStream)541 HRESULT CFolderOutStream2::Init(const CDbEx *db, UInt32 startIndex,
542     const CBoolVector *extractStatuses, ISequentialOutStream *outStream)
543 {
544   _db = db;
545   _startIndex = startIndex;
546   _extractStatuses = extractStatuses;
547   _outStream = outStream;
548 
549   _currentIndex = 0;
550   _fileIsOpen = false;
551   return ProcessEmptyFiles();
552 }
553 
ReleaseOutStream()554 void CFolderOutStream2::ReleaseOutStream()
555 {
556   _outStream.Release();
557   _crcStreamSpec->ReleaseStream();
558 }
559 
OpenFile()560 void CFolderOutStream2::OpenFile()
561 {
562   _crcStreamSpec->SetStream((*_extractStatuses)[_currentIndex] ? _outStream : NULL);
563   _crcStreamSpec->Init(true);
564   _fileIsOpen = true;
565   _rem = _db->Files[_startIndex + _currentIndex].Size;
566 }
567 
CloseFile()568 void CFolderOutStream2::CloseFile()
569 {
570   _crcStreamSpec->ReleaseStream();
571   _fileIsOpen = false;
572   _currentIndex++;
573 }
574 
CloseFileAndSetResult()575 HRESULT CFolderOutStream2::CloseFileAndSetResult()
576 {
577   const CFileItem &file = _db->Files[_startIndex + _currentIndex];
578   CloseFile();
579   return (file.IsDir || !file.CrcDefined || file.Crc == _crcStreamSpec->GetCRC()) ? S_OK: S_FALSE;
580 }
581 
ProcessEmptyFiles()582 HRESULT CFolderOutStream2::ProcessEmptyFiles()
583 {
584   while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
585   {
586     OpenFile();
587     RINOK(CloseFileAndSetResult());
588   }
589   return S_OK;
590 }
591 
Write(const void * data,UInt32 size,UInt32 * processedSize)592 STDMETHODIMP CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize)
593 {
594   if (processedSize != NULL)
595     *processedSize = 0;
596   while (size != 0)
597   {
598     if (_fileIsOpen)
599     {
600       UInt32 cur = size < _rem ? size : (UInt32)_rem;
601       RINOK(_crcStream->Write(data, cur, &cur));
602       if (cur == 0)
603         break;
604       data = (const Byte *)data + cur;
605       size -= cur;
606       _rem -= cur;
607       if (processedSize != NULL)
608         *processedSize += cur;
609       if (_rem == 0)
610       {
611         RINOK(CloseFileAndSetResult());
612         RINOK(ProcessEmptyFiles());
613         continue;
614       }
615     }
616     else
617     {
618       RINOK(ProcessEmptyFiles());
619       if (_currentIndex == _extractStatuses->Size())
620       {
621         // we don't support partial extracting
622         return E_FAIL;
623       }
624       OpenFile();
625     }
626   }
627   return S_OK;
628 }
629 
630 class CThreadDecoder: public CVirtThread
631 {
632 public:
633   HRESULT Result;
634   CMyComPtr<IInStream> InStream;
635 
636   CFolderOutStream2 *FosSpec;
637   CMyComPtr<ISequentialOutStream> Fos;
638 
639   UInt64 StartPos;
640   const CFolders *Folders;
641   int FolderIndex;
642   #ifndef _NO_CRYPTO
643   CMyComPtr<ICryptoGetTextPassword> getTextPassword;
644   #endif
645 
646   DECL_EXTERNAL_CODECS_LOC_VARS2;
647   CDecoder Decoder;
648 
649   #ifndef _7ZIP_ST
650   bool MtMode;
651   UInt32 NumThreads;
652   #endif
653 
CThreadDecoder()654   CThreadDecoder():
655     Decoder(true)
656   {
657     #ifndef _7ZIP_ST
658     MtMode = false;
659     NumThreads = 1;
660     #endif
661     FosSpec = new CFolderOutStream2;
662     Fos = FosSpec;
663     Result = E_FAIL;
664   }
~CThreadDecoder()665   ~CThreadDecoder() { CVirtThread::WaitThreadFinish(); }
666   virtual void Execute();
667 };
668 
Execute()669 void CThreadDecoder::Execute()
670 {
671   try
672   {
673     #ifndef _NO_CRYPTO
674       bool isEncrypted = false;
675       bool passwordIsDefined = false;
676     #endif
677 
678     Result = Decoder.Decode(
679       EXTERNAL_CODECS_LOC_VARS
680       InStream,
681       StartPos,
682       *Folders, FolderIndex,
683       Fos,
684       NULL
685       _7Z_DECODER_CRYPRO_VARS
686       #ifndef _7ZIP_ST
687         , MtMode, NumThreads
688       #endif
689       );
690   }
691   catch(...)
692   {
693     Result = E_FAIL;
694   }
695   if (Result == S_OK)
696     Result = FosSpec->CheckFinishedState();
697   FosSpec->ReleaseOutStream();
698 }
699 
Is86FilteredFolder(const CFolder & f)700 bool static Is86FilteredFolder(const CFolder &f)
701 {
702   FOR_VECTOR(i, f.Coders)
703   {
704     CMethodId m = f.Coders[i].MethodID;
705     if (m == k_BCJ || m == k_BCJ2)
706       return true;
707   }
708   return false;
709 }
710 
711 #ifndef _NO_CRYPTO
712 
713 class CCryptoGetTextPassword:
714   public ICryptoGetTextPassword,
715   public CMyUnknownImp
716 {
717 public:
718   UString Password;
719 
720   MY_UNKNOWN_IMP
721   STDMETHOD(CryptoGetTextPassword)(BSTR *password);
722 };
723 
CryptoGetTextPassword(BSTR * password)724 STDMETHODIMP CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password)
725 {
726   return StringToBstr(Password, password);
727 }
728 
729 #endif
730 
731 static const int kNumGroupsMax = 4;
732 
Is86Group(int group)733 static bool Is86Group(int group) { return (group & 1) != 0; }
IsEncryptedGroup(int group)734 static bool IsEncryptedGroup(int group) { return (group & 2) != 0; }
GetGroupIndex(bool encrypted,int bcjFiltered)735 static int GetGroupIndex(bool encrypted, int bcjFiltered)
736   { return (encrypted ? 2 : 0) + (bcjFiltered ? 1 : 0); }
737 
GetFile(const CDatabase & inDb,int index,CFileItem & file,CFileItem2 & file2)738 static void GetFile(const CDatabase &inDb, int index, CFileItem &file, CFileItem2 &file2)
739 {
740   file = inDb.Files[index];
741   file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime);
742   file2.ATimeDefined = inDb.ATime.GetItem(index, file2.ATime);
743   file2.MTimeDefined = inDb.MTime.GetItem(index, file2.MTime);
744   file2.StartPosDefined = inDb.StartPos.GetItem(index, file2.StartPos);
745   file2.IsAnti = inDb.IsItemAnti(index);
746   // file2.IsAux = inDb.IsItemAux(index);
747 }
748 
Update(DECL_EXTERNAL_CODECS_LOC_VARS IInStream * inStream,const CDbEx * db,const CObjectVector<CUpdateItem> & updateItems,COutArchive & archive,CArchiveDatabaseOut & newDatabase,ISequentialOutStream * seqOutStream,IArchiveUpdateCallback * updateCallback,const CUpdateOptions & options,ICryptoGetTextPassword * getDecoderPassword)749 HRESULT Update(
750     DECL_EXTERNAL_CODECS_LOC_VARS
751     IInStream *inStream,
752     const CDbEx *db,
753     const CObjectVector<CUpdateItem> &updateItems,
754     // const CObjectVector<CTreeFolder> &treeFolders,
755     // const CUniqBlocks &secureBlocks,
756     COutArchive &archive,
757     CArchiveDatabaseOut &newDatabase,
758     ISequentialOutStream *seqOutStream,
759     IArchiveUpdateCallback *updateCallback,
760     const CUpdateOptions &options
761     #ifndef _NO_CRYPTO
762     , ICryptoGetTextPassword *getDecoderPassword
763     #endif
764     )
765 {
766   UInt64 numSolidFiles = options.NumSolidFiles;
767   if (numSolidFiles == 0)
768     numSolidFiles = 1;
769 
770   // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();
771 
772   /*
773   CMyComPtr<IOutStream> outStream;
774   RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
775   if (!outStream)
776     return E_NOTIMPL;
777   */
778 
779   UInt64 startBlockSize = db != 0 ? db->ArcInfo.StartPosition: 0;
780   if (startBlockSize > 0 && !options.RemoveSfxBlock)
781   {
782     RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));
783   }
784 
785   CIntArr fileIndexToUpdateIndexMap;
786   CRecordVector<CFolderRepack> folderRefs;
787   UInt64 complexity = 0;
788   UInt64 inSizeForReduce2 = 0;
789   bool needEncryptedRepack = false;
790   if (db != 0)
791   {
792     fileIndexToUpdateIndexMap.Alloc(db->Files.Size());
793     unsigned i;
794     for (i = 0; i < db->Files.Size(); i++)
795       fileIndexToUpdateIndexMap[i] = -1;
796 
797     for (i = 0; i < updateItems.Size(); i++)
798     {
799       int index = updateItems[i].IndexInArchive;
800       if (index != -1)
801         fileIndexToUpdateIndexMap[index] = i;
802     }
803 
804     for (i = 0; i < (int)db->NumFolders; i++)
805     {
806       CNum indexInFolder = 0;
807       CNum numCopyItems = 0;
808       CNum numUnpackStreams = db->NumUnpackStreamsVector[i];
809       UInt64 repackSize = 0;
810       for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++)
811       {
812         const CFileItem &file = db->Files[fi];
813         if (file.HasStream)
814         {
815           indexInFolder++;
816           int updateIndex = fileIndexToUpdateIndexMap[fi];
817           if (updateIndex >= 0 && !updateItems[updateIndex].NewData)
818           {
819             numCopyItems++;
820             repackSize += file.Size;
821           }
822         }
823       }
824 
825       if (numCopyItems == 0)
826         continue;
827 
828       CFolderRepack rep;
829       rep.FolderIndex = i;
830       rep.NumCopyFiles = numCopyItems;
831       CFolder f;
832       db->ParseFolderInfo(i, f);
833       bool isEncrypted = f.IsEncrypted();
834       rep.Group = GetGroupIndex(isEncrypted, Is86FilteredFolder(f));
835       folderRefs.Add(rep);
836       if (numCopyItems == numUnpackStreams)
837         complexity += db->GetFolderFullPackSize(i);
838       else
839       {
840         complexity += repackSize;
841         if (repackSize > inSizeForReduce2)
842           inSizeForReduce2 = repackSize;
843         if (isEncrypted)
844           needEncryptedRepack = true;
845       }
846     }
847     folderRefs.Sort(CompareFolderRepacks, (void *)db);
848   }
849 
850   UInt64 inSizeForReduce = 0;
851   unsigned i;
852   for (i = 0; i < updateItems.Size(); i++)
853   {
854     const CUpdateItem &ui = updateItems[i];
855     if (ui.NewData)
856     {
857       complexity += ui.Size;
858       if (numSolidFiles != 1)
859         inSizeForReduce += ui.Size;
860       else if (ui.Size > inSizeForReduce)
861         inSizeForReduce = ui.Size;
862     }
863   }
864 
865   if (inSizeForReduce2 > inSizeForReduce)
866     inSizeForReduce = inSizeForReduce2;
867 
868   RINOK(updateCallback->SetTotal(complexity));
869 
870   CLocalProgress *lps = new CLocalProgress;
871   CMyComPtr<ICompressProgressInfo> progress = lps;
872   lps->Init(updateCallback, true);
873 
874   CStreamBinder sb;
875   RINOK(sb.CreateEvents());
876 
877   CThreadDecoder threadDecoder;
878   if (!folderRefs.IsEmpty())
879   {
880     #ifdef EXTERNAL_CODECS
881     threadDecoder.__externalCodecs = __externalCodecs;
882     #endif
883     RINOK(threadDecoder.Create());
884   }
885 
886   CObjectVector<CSolidGroup> groups;
887   for (i = 0; i < kNumGroupsMax; i++)
888     groups.AddNew();
889 
890   {
891     // ---------- Split files to groups ----------
892 
893     bool useFilters = options.UseFilters;
894     const CCompressionMethodMode &method = *options.Method;
895     if (method.Methods.Size() != 1 || method.Binds.Size() != 0)
896       useFilters = false;
897     for (i = 0; i < updateItems.Size(); i++)
898     {
899       const CUpdateItem &ui = updateItems[i];
900       if (!ui.NewData || !ui.HasStream())
901         continue;
902       bool filteredGroup = false;
903       if (useFilters)
904       {
905         int dotPos = ui.Name.ReverseFind(L'.');
906         if (dotPos >= 0)
907           filteredGroup = IsExeExt(ui.Name.Ptr(dotPos + 1));
908       }
909       groups[GetGroupIndex(method.PasswordIsDefined, filteredGroup)].Indices.Add(i);
910     }
911   }
912 
913   #ifndef _NO_CRYPTO
914 
915   CCryptoGetTextPassword *getPasswordSpec = NULL;
916   if (needEncryptedRepack)
917   {
918     getPasswordSpec = new CCryptoGetTextPassword;
919     threadDecoder.getTextPassword = getPasswordSpec;
920 
921     if (options.Method->PasswordIsDefined)
922       getPasswordSpec->Password = options.Method->Password;
923     else
924     {
925       if (!getDecoderPassword)
926         return E_NOTIMPL;
927       CMyComBSTR password;
928       RINOK(getDecoderPassword->CryptoGetTextPassword(&password));
929       if ((BSTR)password)
930         getPasswordSpec->Password = password;
931     }
932   }
933 
934   #endif
935 
936 
937   // ---------- Compress ----------
938 
939   RINOK(archive.Create(seqOutStream, false));
940   RINOK(archive.SkipPrefixArchiveHeader());
941 
942   /*
943   CIntVector treeFolderToArcIndex;
944   treeFolderToArcIndex.Reserve(treeFolders.Size());
945   for (i = 0; i < treeFolders.Size(); i++)
946     treeFolderToArcIndex.Add(-1);
947   // ---------- Write Tree (only AUX dirs) ----------
948   for (i = 1; i < treeFolders.Size(); i++)
949   {
950     const CTreeFolder &treeFolder = treeFolders[i];
951     CFileItem file;
952     CFileItem2 file2;
953     file2.Init();
954     int secureID = 0;
955     if (treeFolder.UpdateItemIndex < 0)
956     {
957       // we can store virtual dir item wuthout attrib, but we want all items have attrib.
958       file.SetAttrib(FILE_ATTRIBUTE_DIRECTORY);
959       file2.IsAux = true;
960     }
961     else
962     {
963       const CUpdateItem &ui = updateItems[treeFolder.UpdateItemIndex];
964       // if item is not dir, then it's parent for alt streams.
965       // we will write such items later
966       if (!ui.IsDir)
967         continue;
968       secureID = ui.SecureIndex;
969       if (ui.NewProps)
970         FromUpdateItemToFileItem(ui, file, file2);
971       else
972         GetFile(*db, ui.IndexInArchive, file, file2);
973     }
974     file.Size = 0;
975     file.HasStream = false;
976     file.IsDir = true;
977     file.Parent = treeFolder.Parent;
978 
979     treeFolderToArcIndex[i] = newDatabase.Files.Size();
980     newDatabase.AddFile(file, file2, treeFolder.Name);
981 
982     if (totalSecureDataSize != 0)
983       newDatabase.SecureIDs.Add(secureID);
984   }
985   */
986 
987   {
988     /* ---------- Write non-AUX dirs and Empty files ---------- */
989     CRecordVector<int> emptyRefs;
990     for (i = 0; i < updateItems.Size(); i++)
991     {
992       const CUpdateItem &ui = updateItems[i];
993       if (ui.NewData)
994       {
995         if (ui.HasStream())
996           continue;
997       }
998       else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream)
999         continue;
1000       /*
1001       if (ui.TreeFolderIndex >= 0)
1002         continue;
1003       */
1004       emptyRefs.Add(i);
1005     }
1006     emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems);
1007     for (i = 0; i < emptyRefs.Size(); i++)
1008     {
1009       const CUpdateItem &ui = updateItems[emptyRefs[i]];
1010       CFileItem file;
1011       CFileItem2 file2;
1012       UString name;
1013       if (ui.NewProps)
1014       {
1015         FromUpdateItemToFileItem(ui, file, file2);
1016         name = ui.Name;
1017       }
1018       else
1019       {
1020         GetFile(*db, ui.IndexInArchive, file, file2);
1021         db->GetPath(ui.IndexInArchive, name);
1022       }
1023 
1024       /*
1025       if (totalSecureDataSize != 0)
1026         newDatabase.SecureIDs.Add(ui.SecureIndex);
1027       file.Parent = ui.ParentFolderIndex;
1028       */
1029       newDatabase.AddFile(file, file2, name);
1030     }
1031   }
1032 
1033   unsigned folderRefIndex = 0;
1034   lps->ProgressOffset = 0;
1035 
1036   for (int groupIndex = 0; groupIndex < kNumGroupsMax; groupIndex++)
1037   {
1038     const CSolidGroup &group = groups[groupIndex];
1039 
1040     CCompressionMethodMode method = *options.Method;
1041     MakeExeMethod(method, options.UseFilters, Is86Group(groupIndex), options.MaxFilter);
1042 
1043     if (IsEncryptedGroup(groupIndex))
1044     {
1045       if (!method.PasswordIsDefined)
1046       {
1047         #ifndef _NO_CRYPTO
1048         if (getPasswordSpec)
1049           method.Password = getPasswordSpec->Password;
1050         #endif
1051         method.PasswordIsDefined = true;
1052       }
1053     }
1054     else
1055     {
1056       method.PasswordIsDefined = false;
1057       method.Password.Empty();
1058     }
1059 
1060     CEncoder encoder(method);
1061 
1062     for (; folderRefIndex < folderRefs.Size(); folderRefIndex++)
1063     {
1064       const CFolderRepack &rep = folderRefs[folderRefIndex];
1065       if (rep.Group != groupIndex)
1066         break;
1067       int folderIndex = rep.FolderIndex;
1068 
1069       if (rep.NumCopyFiles == db->NumUnpackStreamsVector[folderIndex])
1070       {
1071         UInt64 packSize = db->GetFolderFullPackSize(folderIndex);
1072         RINOK(WriteRange(inStream, archive.SeqStream,
1073           db->GetFolderStreamPos(folderIndex, 0), packSize, progress));
1074         lps->ProgressOffset += packSize;
1075 
1076         CFolder &folder = newDatabase.Folders.AddNew();
1077         db->ParseFolderInfo(folderIndex, folder);
1078         CNum startIndex = db->FoStartPackStreamIndex[folderIndex];
1079         for (unsigned j = 0; j < folder.PackStreams.Size(); j++)
1080         {
1081           newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j));
1082           // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]);
1083           // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]);
1084         }
1085 
1086         UInt32 indexStart = db->FoToCoderUnpackSizes[folderIndex];
1087         UInt32 indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1];
1088         for (; indexStart < indexEnd; indexStart++)
1089           newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]);
1090       }
1091       else
1092       {
1093         CBoolVector extractStatuses;
1094 
1095         CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
1096         CNum indexInFolder = 0;
1097 
1098         for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
1099         {
1100           bool needExtract = false;
1101           if (db->Files[fi].HasStream)
1102           {
1103             indexInFolder++;
1104             int updateIndex = fileIndexToUpdateIndexMap[fi];
1105             if (updateIndex >= 0 && !updateItems[updateIndex].NewData)
1106               needExtract = true;
1107           }
1108           extractStatuses.Add(needExtract);
1109         }
1110 
1111         unsigned startPackIndex = newDatabase.PackSizes.Size();
1112         UInt64 curUnpackSize;
1113         {
1114           CMyComPtr<ISequentialInStream> sbInStream;
1115           {
1116             CMyComPtr<ISequentialOutStream> sbOutStream;
1117             sb.CreateStreams(&sbInStream, &sbOutStream);
1118             sb.ReInit();
1119             RINOK(threadDecoder.FosSpec->Init(db, db->FolderStartFileIndex[folderIndex], &extractStatuses, sbOutStream));
1120           }
1121 
1122           threadDecoder.InStream = inStream;
1123           threadDecoder.Folders = (const CFolders *)db;
1124           threadDecoder.FolderIndex = folderIndex;
1125           threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0);
1126 
1127           threadDecoder.Start();
1128 
1129           RINOK(encoder.Encode(
1130               EXTERNAL_CODECS_LOC_VARS
1131               sbInStream, NULL, &inSizeForReduce,
1132               newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curUnpackSize,
1133               archive.SeqStream, newDatabase.PackSizes, progress));
1134 
1135           threadDecoder.WaitExecuteFinish();
1136         }
1137 
1138         RINOK(threadDecoder.Result);
1139 
1140         for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
1141           lps->OutSize += newDatabase.PackSizes[startPackIndex];
1142         lps->InSize += curUnpackSize;
1143       }
1144 
1145       newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles);
1146 
1147       CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
1148 
1149       CNum indexInFolder = 0;
1150       for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
1151       {
1152         CFileItem file;
1153         CFileItem2 file2;
1154         GetFile(*db, fi, file, file2);
1155         UString name;
1156         db->GetPath(fi, name);
1157         if (file.HasStream)
1158         {
1159           indexInFolder++;
1160           int updateIndex = fileIndexToUpdateIndexMap[fi];
1161           if (updateIndex >= 0)
1162           {
1163             const CUpdateItem &ui = updateItems[updateIndex];
1164             if (ui.NewData)
1165               continue;
1166             if (ui.NewProps)
1167             {
1168               CFileItem uf;
1169               FromUpdateItemToFileItem(ui, uf, file2);
1170               uf.Size = file.Size;
1171               uf.Crc = file.Crc;
1172               uf.CrcDefined = file.CrcDefined;
1173               uf.HasStream = file.HasStream;
1174               file = uf;
1175               name = ui.Name;
1176             }
1177             /*
1178             file.Parent = ui.ParentFolderIndex;
1179             if (ui.TreeFolderIndex >= 0)
1180               treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size();
1181             if (totalSecureDataSize != 0)
1182               newDatabase.SecureIDs.Add(ui.SecureIndex);
1183             */
1184             newDatabase.AddFile(file, file2, name);
1185           }
1186         }
1187       }
1188     }
1189 
1190     unsigned numFiles = group.Indices.Size();
1191     if (numFiles == 0)
1192       continue;
1193     CRecordVector<CRefItem> refItems;
1194     refItems.ClearAndSetSize(numFiles);
1195     bool sortByType = (numSolidFiles > 1);
1196     for (i = 0; i < numFiles; i++)
1197       refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType);
1198     CSortParam sortParam;
1199     // sortParam.TreeFolders = &treeFolders;
1200     sortParam.SortByType = sortByType;
1201     refItems.Sort(CompareUpdateItems, (void *)&sortParam);
1202 
1203     CObjArray<UInt32> indices(numFiles);
1204 
1205     for (i = 0; i < numFiles; i++)
1206     {
1207       UInt32 index = refItems[i].Index;
1208       indices[i] = index;
1209       /*
1210       const CUpdateItem &ui = updateItems[index];
1211       CFileItem file;
1212       if (ui.NewProps)
1213         FromUpdateItemToFileItem(ui, file);
1214       else
1215         file = db.Files[ui.IndexInArchive];
1216       if (file.IsAnti || file.IsDir)
1217         return E_FAIL;
1218       newDatabase.Files.Add(file);
1219       */
1220     }
1221 
1222     for (i = 0; i < numFiles;)
1223     {
1224       UInt64 totalSize = 0;
1225       int numSubFiles;
1226       UString prevExtension;
1227       for (numSubFiles = 0; i + numSubFiles < numFiles &&
1228           numSubFiles < numSolidFiles; numSubFiles++)
1229       {
1230         const CUpdateItem &ui = updateItems[indices[i + numSubFiles]];
1231         totalSize += ui.Size;
1232         if (totalSize > options.NumSolidBytes)
1233           break;
1234         if (options.SolidExtension)
1235         {
1236           UString ext = ui.GetExtension();
1237           if (numSubFiles == 0)
1238             prevExtension = ext;
1239           else
1240             if (!ext.IsEqualToNoCase(prevExtension))
1241               break;
1242         }
1243       }
1244       if (numSubFiles < 1)
1245         numSubFiles = 1;
1246 
1247       CFolderInStream *inStreamSpec = new CFolderInStream;
1248       CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
1249       inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
1250 
1251       unsigned startPackIndex = newDatabase.PackSizes.Size();
1252       UInt64 curFolderUnpackSize;
1253       RINOK(encoder.Encode(
1254           EXTERNAL_CODECS_LOC_VARS
1255           solidInStream, NULL, &inSizeForReduce,
1256           newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curFolderUnpackSize,
1257           archive.SeqStream, newDatabase.PackSizes, progress));
1258 
1259       for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
1260         lps->OutSize += newDatabase.PackSizes[startPackIndex];
1261 
1262       lps->InSize += curFolderUnpackSize;
1263       // for ()
1264       // newDatabase.PackCRCsDefined.Add(false);
1265       // newDatabase.PackCRCs.Add(0);
1266 
1267       CNum numUnpackStreams = 0;
1268       for (int subIndex = 0; subIndex < numSubFiles; subIndex++)
1269       {
1270         const CUpdateItem &ui = updateItems[indices[i + subIndex]];
1271         CFileItem file;
1272         CFileItem2 file2;
1273         UString name;
1274         if (ui.NewProps)
1275         {
1276           FromUpdateItemToFileItem(ui, file, file2);
1277           name = ui.Name;
1278         }
1279         else
1280         {
1281           GetFile(*db, ui.IndexInArchive, file, file2);
1282           db->GetPath(ui.IndexInArchive, name);
1283         }
1284         if (file2.IsAnti || file.IsDir)
1285           return E_FAIL;
1286 
1287         /*
1288         CFileItem &file = newDatabase.Files[
1289               startFileIndexInDatabase + i + subIndex];
1290         */
1291         if (!inStreamSpec->Processed[subIndex])
1292         {
1293           continue;
1294           // file.Name += L".locked";
1295         }
1296 
1297         file.Crc = inStreamSpec->CRCs[subIndex];
1298         file.Size = inStreamSpec->Sizes[subIndex];
1299         if (file.Size != 0)
1300         {
1301           file.CrcDefined = true;
1302           file.HasStream = true;
1303           numUnpackStreams++;
1304         }
1305         else
1306         {
1307           file.CrcDefined = false;
1308           file.HasStream = false;
1309         }
1310         /*
1311         file.Parent = ui.ParentFolderIndex;
1312         if (ui.TreeFolderIndex >= 0)
1313           treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size();
1314         if (totalSecureDataSize != 0)
1315           newDatabase.SecureIDs.Add(ui.SecureIndex);
1316         */
1317         newDatabase.AddFile(file, file2, name);
1318       }
1319       // numUnpackStreams = 0 is very bad case for locked files
1320       // v3.13 doesn't understand it.
1321       newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
1322       i += numSubFiles;
1323     }
1324   }
1325 
1326   if (folderRefIndex != folderRefs.Size())
1327     return E_FAIL;
1328 
1329   RINOK(lps->SetCur());
1330 
1331   /*
1332   folderRefs.ClearAndFree();
1333   fileIndexToUpdateIndexMap.ClearAndFree();
1334   groups.ClearAndFree();
1335   */
1336 
1337   /*
1338   for (i = 0; i < newDatabase.Files.Size(); i++)
1339   {
1340     CFileItem &file = newDatabase.Files[i];
1341     file.Parent = treeFolderToArcIndex[file.Parent];
1342   }
1343 
1344   if (totalSecureDataSize != 0)
1345   {
1346     newDatabase.SecureBuf.SetCapacity(totalSecureDataSize);
1347     size_t pos = 0;
1348     newDatabase.SecureSizes.Reserve(secureBlocks.Sorted.Size());
1349     for (i = 0; i < secureBlocks.Sorted.Size(); i++)
1350     {
1351       const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]];
1352       size_t size = buf.GetCapacity();
1353       memcpy(newDatabase.SecureBuf + pos, buf, size);
1354       newDatabase.SecureSizes.Add((UInt32)size);
1355       pos += size;
1356     }
1357   }
1358   */
1359   newDatabase.ReserveDown();
1360   return S_OK;
1361 }
1362 
1363 }}
1364