xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Wim/WimHandlerOut.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // WimHandlerOut.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/ComTry.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/IntToString.h"
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/MyBuffer2.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/StringToInt.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/UTFConvert.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/Wildcard.h"
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/PropVariant.h"
13*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/TimeUtils.h"
14*f6dc9357SAndroid Build Coastguard Worker 
15*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/LimitedStreams.h"
16*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ProgressUtils.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StreamUtils.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/UniqBlocks.h"
19*f6dc9357SAndroid Build Coastguard Worker 
20*f6dc9357SAndroid Build Coastguard Worker #include "../../Crypto/RandGen.h"
21*f6dc9357SAndroid Build Coastguard Worker #include "../../Crypto/Sha1Cls.h"
22*f6dc9357SAndroid Build Coastguard Worker 
23*f6dc9357SAndroid Build Coastguard Worker #include "../Common/OutStreamWithSha1.h"
24*f6dc9357SAndroid Build Coastguard Worker 
25*f6dc9357SAndroid Build Coastguard Worker #include "WimHandler.h"
26*f6dc9357SAndroid Build Coastguard Worker 
27*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
28*f6dc9357SAndroid Build Coastguard Worker 
29*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
30*f6dc9357SAndroid Build Coastguard Worker namespace NWim {
31*f6dc9357SAndroid Build Coastguard Worker 
32*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_NumSubVectors_Bits = 12; // must be <= 16
33*f6dc9357SAndroid Build Coastguard Worker 
34*f6dc9357SAndroid Build Coastguard Worker struct CSortedIndex
35*f6dc9357SAndroid Build Coastguard Worker {
36*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CUIntVector> Vectors;
37*f6dc9357SAndroid Build Coastguard Worker 
CSortedIndexNArchive::NWim::CSortedIndex38*f6dc9357SAndroid Build Coastguard Worker   CSortedIndex()
39*f6dc9357SAndroid Build Coastguard Worker   {
40*f6dc9357SAndroid Build Coastguard Worker     const unsigned k_NumSubVectors = 1 << k_NumSubVectors_Bits;
41*f6dc9357SAndroid Build Coastguard Worker     Vectors.ClearAndReserve(k_NumSubVectors);
42*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < k_NumSubVectors; i++)
43*f6dc9357SAndroid Build Coastguard Worker       Vectors.AddNew();
44*f6dc9357SAndroid Build Coastguard Worker   }
45*f6dc9357SAndroid Build Coastguard Worker };
46*f6dc9357SAndroid Build Coastguard Worker 
AddUniqHash(const CStreamInfo * streams,CSortedIndex & sorted2,const Byte * h,int streamIndexForInsert)47*f6dc9357SAndroid Build Coastguard Worker static int AddUniqHash(const CStreamInfo *streams, CSortedIndex &sorted2, const Byte *h, int streamIndexForInsert)
48*f6dc9357SAndroid Build Coastguard Worker {
49*f6dc9357SAndroid Build Coastguard Worker   const unsigned hash = (((unsigned)h[0] << 8) | (unsigned)h[1]) >> (16 - k_NumSubVectors_Bits);
50*f6dc9357SAndroid Build Coastguard Worker   CUIntVector &sorted = sorted2.Vectors[hash];
51*f6dc9357SAndroid Build Coastguard Worker   unsigned left = 0, right = sorted.Size();
52*f6dc9357SAndroid Build Coastguard Worker   while (left != right)
53*f6dc9357SAndroid Build Coastguard Worker   {
54*f6dc9357SAndroid Build Coastguard Worker     const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
55*f6dc9357SAndroid Build Coastguard Worker     const unsigned index = sorted[mid];
56*f6dc9357SAndroid Build Coastguard Worker     const Byte *hash2 = streams[index].Hash;
57*f6dc9357SAndroid Build Coastguard Worker 
58*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
59*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < kHashSize; i++)
60*f6dc9357SAndroid Build Coastguard Worker       if (h[i] != hash2[i])
61*f6dc9357SAndroid Build Coastguard Worker         break;
62*f6dc9357SAndroid Build Coastguard Worker 
63*f6dc9357SAndroid Build Coastguard Worker     if (i == kHashSize)
64*f6dc9357SAndroid Build Coastguard Worker       return (int)index;
65*f6dc9357SAndroid Build Coastguard Worker 
66*f6dc9357SAndroid Build Coastguard Worker     if (h[i] < hash2[i])
67*f6dc9357SAndroid Build Coastguard Worker       right = mid;
68*f6dc9357SAndroid Build Coastguard Worker     else
69*f6dc9357SAndroid Build Coastguard Worker       left = mid + 1;
70*f6dc9357SAndroid Build Coastguard Worker   }
71*f6dc9357SAndroid Build Coastguard Worker 
72*f6dc9357SAndroid Build Coastguard Worker   if (streamIndexForInsert != -1)
73*f6dc9357SAndroid Build Coastguard Worker     sorted.Insert(left, (unsigned)streamIndexForInsert);
74*f6dc9357SAndroid Build Coastguard Worker 
75*f6dc9357SAndroid Build Coastguard Worker   return -1;
76*f6dc9357SAndroid Build Coastguard Worker }
77*f6dc9357SAndroid Build Coastguard Worker 
78*f6dc9357SAndroid Build Coastguard Worker 
79*f6dc9357SAndroid Build Coastguard Worker struct CAltStream
80*f6dc9357SAndroid Build Coastguard Worker {
81*f6dc9357SAndroid Build Coastguard Worker   int UpdateIndex;
82*f6dc9357SAndroid Build Coastguard Worker   int HashIndex;
83*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
84*f6dc9357SAndroid Build Coastguard Worker   UString Name;
85*f6dc9357SAndroid Build Coastguard Worker   bool Skip;
86*f6dc9357SAndroid Build Coastguard Worker 
CAltStreamNArchive::NWim::CAltStream87*f6dc9357SAndroid Build Coastguard Worker   CAltStream(): UpdateIndex(-1), HashIndex(-1), Skip(false) {}
88*f6dc9357SAndroid Build Coastguard Worker };
89*f6dc9357SAndroid Build Coastguard Worker 
90*f6dc9357SAndroid Build Coastguard Worker 
91*f6dc9357SAndroid Build Coastguard Worker struct CMetaItem
92*f6dc9357SAndroid Build Coastguard Worker {
93*f6dc9357SAndroid Build Coastguard Worker   int UpdateIndex;
94*f6dc9357SAndroid Build Coastguard Worker   int HashIndex;
95*f6dc9357SAndroid Build Coastguard Worker 
96*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
97*f6dc9357SAndroid Build Coastguard Worker   FILETIME CTime;
98*f6dc9357SAndroid Build Coastguard Worker   FILETIME ATime;
99*f6dc9357SAndroid Build Coastguard Worker   FILETIME MTime;
100*f6dc9357SAndroid Build Coastguard Worker   UInt64 FileID;
101*f6dc9357SAndroid Build Coastguard Worker   UInt64 VolID;
102*f6dc9357SAndroid Build Coastguard Worker 
103*f6dc9357SAndroid Build Coastguard Worker   UString Name;
104*f6dc9357SAndroid Build Coastguard Worker   UString ShortName;
105*f6dc9357SAndroid Build Coastguard Worker 
106*f6dc9357SAndroid Build Coastguard Worker   UInt32 Attrib;
107*f6dc9357SAndroid Build Coastguard Worker   int SecurityId;       // -1: means no secutity ID
108*f6dc9357SAndroid Build Coastguard Worker   bool IsDir;
109*f6dc9357SAndroid Build Coastguard Worker   bool Skip;
110*f6dc9357SAndroid Build Coastguard Worker   unsigned NumSkipAltStreams;
111*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CAltStream> AltStreams;
112*f6dc9357SAndroid Build Coastguard Worker 
113*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer Reparse;
114*f6dc9357SAndroid Build Coastguard Worker 
GetNumAltStreamsNArchive::NWim::CMetaItem115*f6dc9357SAndroid Build Coastguard Worker   unsigned GetNumAltStreams() const { return AltStreams.Size() - NumSkipAltStreams; }
CMetaItemNArchive::NWim::CMetaItem116*f6dc9357SAndroid Build Coastguard Worker   CMetaItem():
117*f6dc9357SAndroid Build Coastguard Worker         UpdateIndex(-1)
118*f6dc9357SAndroid Build Coastguard Worker       , HashIndex(-1)
119*f6dc9357SAndroid Build Coastguard Worker       , Size(0)
120*f6dc9357SAndroid Build Coastguard Worker       , FileID(0)
121*f6dc9357SAndroid Build Coastguard Worker       , VolID(0)
122*f6dc9357SAndroid Build Coastguard Worker       , Attrib(0)
123*f6dc9357SAndroid Build Coastguard Worker       , SecurityId(-1)
124*f6dc9357SAndroid Build Coastguard Worker       , IsDir(false)
125*f6dc9357SAndroid Build Coastguard Worker       , Skip(false)
126*f6dc9357SAndroid Build Coastguard Worker       , NumSkipAltStreams(0)
127*f6dc9357SAndroid Build Coastguard Worker   {
128*f6dc9357SAndroid Build Coastguard Worker     FILETIME_Clear(CTime);
129*f6dc9357SAndroid Build Coastguard Worker     FILETIME_Clear(ATime);
130*f6dc9357SAndroid Build Coastguard Worker     FILETIME_Clear(MTime);
131*f6dc9357SAndroid Build Coastguard Worker   }
132*f6dc9357SAndroid Build Coastguard Worker };
133*f6dc9357SAndroid Build Coastguard Worker 
134*f6dc9357SAndroid Build Coastguard Worker 
Compare_HardLink_MetaItems(const CMetaItem & a1,const CMetaItem & a2)135*f6dc9357SAndroid Build Coastguard Worker static int Compare_HardLink_MetaItems(const CMetaItem &a1, const CMetaItem &a2)
136*f6dc9357SAndroid Build Coastguard Worker {
137*f6dc9357SAndroid Build Coastguard Worker   if (a1.VolID < a2.VolID) return -1;
138*f6dc9357SAndroid Build Coastguard Worker   if (a1.VolID > a2.VolID) return 1;
139*f6dc9357SAndroid Build Coastguard Worker   if (a1.FileID < a2.FileID) return -1;
140*f6dc9357SAndroid Build Coastguard Worker   if (a1.FileID > a2.FileID) return 1;
141*f6dc9357SAndroid Build Coastguard Worker   if (a1.Size < a2.Size) return -1;
142*f6dc9357SAndroid Build Coastguard Worker   if (a1.Size > a2.Size) return 1;
143*f6dc9357SAndroid Build Coastguard Worker   return ::CompareFileTime(&a1.MTime, &a2.MTime);
144*f6dc9357SAndroid Build Coastguard Worker }
145*f6dc9357SAndroid Build Coastguard Worker 
146*f6dc9357SAndroid Build Coastguard Worker 
AddToHardLinkList(const CObjectVector<CMetaItem> & metaItems,unsigned indexOfItem,CUIntVector & indexes)147*f6dc9357SAndroid Build Coastguard Worker static int AddToHardLinkList(const CObjectVector<CMetaItem> &metaItems, unsigned indexOfItem, CUIntVector &indexes)
148*f6dc9357SAndroid Build Coastguard Worker {
149*f6dc9357SAndroid Build Coastguard Worker   const CMetaItem &mi = metaItems[indexOfItem];
150*f6dc9357SAndroid Build Coastguard Worker   unsigned left = 0, right = indexes.Size();
151*f6dc9357SAndroid Build Coastguard Worker   while (left != right)
152*f6dc9357SAndroid Build Coastguard Worker   {
153*f6dc9357SAndroid Build Coastguard Worker     const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
154*f6dc9357SAndroid Build Coastguard Worker     const unsigned index = indexes[mid];
155*f6dc9357SAndroid Build Coastguard Worker     const int comp = Compare_HardLink_MetaItems(mi, metaItems[index]);
156*f6dc9357SAndroid Build Coastguard Worker     if (comp == 0)
157*f6dc9357SAndroid Build Coastguard Worker       return (int)index;
158*f6dc9357SAndroid Build Coastguard Worker     if (comp < 0)
159*f6dc9357SAndroid Build Coastguard Worker       right = mid;
160*f6dc9357SAndroid Build Coastguard Worker     else
161*f6dc9357SAndroid Build Coastguard Worker       left = mid + 1;
162*f6dc9357SAndroid Build Coastguard Worker   }
163*f6dc9357SAndroid Build Coastguard Worker   indexes.Insert(left, indexOfItem);
164*f6dc9357SAndroid Build Coastguard Worker   return -1;
165*f6dc9357SAndroid Build Coastguard Worker }
166*f6dc9357SAndroid Build Coastguard Worker 
167*f6dc9357SAndroid Build Coastguard Worker 
168*f6dc9357SAndroid Build Coastguard Worker struct CUpdateItem
169*f6dc9357SAndroid Build Coastguard Worker {
170*f6dc9357SAndroid Build Coastguard Worker   unsigned CallbackIndex; // index in callback
171*f6dc9357SAndroid Build Coastguard Worker 
172*f6dc9357SAndroid Build Coastguard Worker   int MetaIndex;          // index in in MetaItems[]
173*f6dc9357SAndroid Build Coastguard Worker 
174*f6dc9357SAndroid Build Coastguard Worker   int AltStreamIndex;     // index in CMetaItem::AltStreams vector
175*f6dc9357SAndroid Build Coastguard Worker                           // -1: if not alt stream?
176*f6dc9357SAndroid Build Coastguard Worker 
177*f6dc9357SAndroid Build Coastguard Worker   int InArcIndex;         // >= 0, if we use OLD Data
178*f6dc9357SAndroid Build Coastguard Worker                           //   -1, if we use NEW Data
179*f6dc9357SAndroid Build Coastguard Worker 
CUpdateItemNArchive::NWim::CUpdateItem180*f6dc9357SAndroid Build Coastguard Worker   CUpdateItem(): MetaIndex(-1), AltStreamIndex(-1), InArcIndex(-1) {}
181*f6dc9357SAndroid Build Coastguard Worker };
182*f6dc9357SAndroid Build Coastguard Worker 
183*f6dc9357SAndroid Build Coastguard Worker 
184*f6dc9357SAndroid Build Coastguard Worker struct CDir
185*f6dc9357SAndroid Build Coastguard Worker {
186*f6dc9357SAndroid Build Coastguard Worker   int MetaIndex;
187*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CDir> Dirs;
188*f6dc9357SAndroid Build Coastguard Worker   CUIntVector Files; // indexes in MetaItems[]
189*f6dc9357SAndroid Build Coastguard Worker 
CDirNArchive::NWim::CDir190*f6dc9357SAndroid Build Coastguard Worker   CDir(): MetaIndex(-1) {}
191*f6dc9357SAndroid Build Coastguard Worker   unsigned GetNumDirs() const;
192*f6dc9357SAndroid Build Coastguard Worker   unsigned GetNumFiles() const;
193*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetTotalSize(const CObjectVector<CMetaItem> &metaItems) const;
194*f6dc9357SAndroid Build Coastguard Worker   bool FindDir(const CObjectVector<CMetaItem> &items, const UString &name, unsigned &index);
195*f6dc9357SAndroid Build Coastguard Worker };
196*f6dc9357SAndroid Build Coastguard Worker 
197*f6dc9357SAndroid Build Coastguard Worker /* imagex counts Junctions as files (not as dirs).
198*f6dc9357SAndroid Build Coastguard Worker    We suppose that it's not correct */
199*f6dc9357SAndroid Build Coastguard Worker 
GetNumDirs() const200*f6dc9357SAndroid Build Coastguard Worker unsigned CDir::GetNumDirs() const
201*f6dc9357SAndroid Build Coastguard Worker {
202*f6dc9357SAndroid Build Coastguard Worker   unsigned num = Dirs.Size();
203*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, Dirs)
204*f6dc9357SAndroid Build Coastguard Worker     num += Dirs[i].GetNumDirs();
205*f6dc9357SAndroid Build Coastguard Worker   return num;
206*f6dc9357SAndroid Build Coastguard Worker }
207*f6dc9357SAndroid Build Coastguard Worker 
GetNumFiles() const208*f6dc9357SAndroid Build Coastguard Worker unsigned CDir::GetNumFiles() const
209*f6dc9357SAndroid Build Coastguard Worker {
210*f6dc9357SAndroid Build Coastguard Worker   unsigned num = Files.Size();
211*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, Dirs)
212*f6dc9357SAndroid Build Coastguard Worker     num += Dirs[i].GetNumFiles();
213*f6dc9357SAndroid Build Coastguard Worker   return num;
214*f6dc9357SAndroid Build Coastguard Worker }
215*f6dc9357SAndroid Build Coastguard Worker 
GetTotalSize(const CObjectVector<CMetaItem> & metaItems) const216*f6dc9357SAndroid Build Coastguard Worker UInt64 CDir::GetTotalSize(const CObjectVector<CMetaItem> &metaItems) const
217*f6dc9357SAndroid Build Coastguard Worker {
218*f6dc9357SAndroid Build Coastguard Worker   UInt64 sum = 0;
219*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
220*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < Files.Size(); i++)
221*f6dc9357SAndroid Build Coastguard Worker     sum += metaItems[Files[i]].Size;
222*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < Dirs.Size(); i++)
223*f6dc9357SAndroid Build Coastguard Worker     sum += Dirs[i].GetTotalSize(metaItems);
224*f6dc9357SAndroid Build Coastguard Worker   return sum;
225*f6dc9357SAndroid Build Coastguard Worker }
226*f6dc9357SAndroid Build Coastguard Worker 
FindDir(const CObjectVector<CMetaItem> & items,const UString & name,unsigned & index)227*f6dc9357SAndroid Build Coastguard Worker bool CDir::FindDir(const CObjectVector<CMetaItem> &items, const UString &name, unsigned &index)
228*f6dc9357SAndroid Build Coastguard Worker {
229*f6dc9357SAndroid Build Coastguard Worker   unsigned left = 0, right = Dirs.Size();
230*f6dc9357SAndroid Build Coastguard Worker   while (left != right)
231*f6dc9357SAndroid Build Coastguard Worker   {
232*f6dc9357SAndroid Build Coastguard Worker     const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
233*f6dc9357SAndroid Build Coastguard Worker     const int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name);
234*f6dc9357SAndroid Build Coastguard Worker     if (comp == 0)
235*f6dc9357SAndroid Build Coastguard Worker     {
236*f6dc9357SAndroid Build Coastguard Worker       index = mid;
237*f6dc9357SAndroid Build Coastguard Worker       return true;
238*f6dc9357SAndroid Build Coastguard Worker     }
239*f6dc9357SAndroid Build Coastguard Worker     if (comp < 0)
240*f6dc9357SAndroid Build Coastguard Worker       right = mid;
241*f6dc9357SAndroid Build Coastguard Worker     else
242*f6dc9357SAndroid Build Coastguard Worker       left = mid + 1;
243*f6dc9357SAndroid Build Coastguard Worker   }
244*f6dc9357SAndroid Build Coastguard Worker   index = left;
245*f6dc9357SAndroid Build Coastguard Worker   return false;
246*f6dc9357SAndroid Build Coastguard Worker }
247*f6dc9357SAndroid Build Coastguard Worker 
248*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetFileTimeType (UInt32 * type))249*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type))
250*f6dc9357SAndroid Build Coastguard Worker {
251*f6dc9357SAndroid Build Coastguard Worker   *type = NFileTimeType::kWindows;
252*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
253*f6dc9357SAndroid Build Coastguard Worker }
254*f6dc9357SAndroid Build Coastguard Worker 
255*f6dc9357SAndroid Build Coastguard Worker 
GetOutProperty(IArchiveUpdateCallback * callback,UInt32 callbackIndex,Int32 arcIndex,PROPID propID,PROPVARIANT * value)256*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value)
257*f6dc9357SAndroid Build Coastguard Worker {
258*f6dc9357SAndroid Build Coastguard Worker   if (arcIndex != -1)
259*f6dc9357SAndroid Build Coastguard Worker     return GetProperty((UInt32)arcIndex, propID, value);
260*f6dc9357SAndroid Build Coastguard Worker   return callback->GetProperty(callbackIndex, propID, value);
261*f6dc9357SAndroid Build Coastguard Worker }
262*f6dc9357SAndroid Build Coastguard Worker 
263*f6dc9357SAndroid Build Coastguard Worker 
GetTime(IArchiveUpdateCallback * callback,UInt32 callbackIndex,Int32 arcIndex,PROPID propID,FILETIME & ft)264*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft)
265*f6dc9357SAndroid Build Coastguard Worker {
266*f6dc9357SAndroid Build Coastguard Worker   ft.dwLowDateTime = ft.dwHighDateTime = 0;
267*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
268*f6dc9357SAndroid Build Coastguard Worker   RINOK(GetOutProperty(callback, callbackIndex, arcIndex, propID, &prop))
269*f6dc9357SAndroid Build Coastguard Worker   if (prop.vt == VT_FILETIME)
270*f6dc9357SAndroid Build Coastguard Worker     ft = prop.filetime;
271*f6dc9357SAndroid Build Coastguard Worker   else if (prop.vt != VT_EMPTY)
272*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG;
273*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
274*f6dc9357SAndroid Build Coastguard Worker }
275*f6dc9357SAndroid Build Coastguard Worker 
276*f6dc9357SAndroid Build Coastguard Worker 
GetRootTime(IArchiveGetRootProps * callback,IArchiveGetRootProps * arcRoot,PROPID propID,FILETIME & ft)277*f6dc9357SAndroid Build Coastguard Worker static HRESULT GetRootTime(
278*f6dc9357SAndroid Build Coastguard Worker     IArchiveGetRootProps *callback,
279*f6dc9357SAndroid Build Coastguard Worker     IArchiveGetRootProps *arcRoot,
280*f6dc9357SAndroid Build Coastguard Worker     PROPID propID, FILETIME &ft)
281*f6dc9357SAndroid Build Coastguard Worker {
282*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
283*f6dc9357SAndroid Build Coastguard Worker   if (callback)
284*f6dc9357SAndroid Build Coastguard Worker   {
285*f6dc9357SAndroid Build Coastguard Worker     RINOK(callback->GetRootProp(propID, &prop))
286*f6dc9357SAndroid Build Coastguard Worker     if (prop.vt == VT_FILETIME)
287*f6dc9357SAndroid Build Coastguard Worker     {
288*f6dc9357SAndroid Build Coastguard Worker       ft = prop.filetime;
289*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
290*f6dc9357SAndroid Build Coastguard Worker     }
291*f6dc9357SAndroid Build Coastguard Worker     if (prop.vt != VT_EMPTY)
292*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
293*f6dc9357SAndroid Build Coastguard Worker   }
294*f6dc9357SAndroid Build Coastguard Worker   if (arcRoot)
295*f6dc9357SAndroid Build Coastguard Worker   {
296*f6dc9357SAndroid Build Coastguard Worker     RINOK(arcRoot->GetRootProp(propID, &prop))
297*f6dc9357SAndroid Build Coastguard Worker     if (prop.vt == VT_FILETIME)
298*f6dc9357SAndroid Build Coastguard Worker     {
299*f6dc9357SAndroid Build Coastguard Worker       ft = prop.filetime;
300*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
301*f6dc9357SAndroid Build Coastguard Worker     }
302*f6dc9357SAndroid Build Coastguard Worker     if (prop.vt != VT_EMPTY)
303*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
304*f6dc9357SAndroid Build Coastguard Worker   }
305*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
306*f6dc9357SAndroid Build Coastguard Worker }
307*f6dc9357SAndroid Build Coastguard Worker 
308*f6dc9357SAndroid Build Coastguard Worker #define Set16(p, d) SetUi16(p, d)
309*f6dc9357SAndroid Build Coastguard Worker #define Set32(p, d) SetUi32(p, d)
310*f6dc9357SAndroid Build Coastguard Worker #define Set64(p, d) SetUi64(p, d)
311*f6dc9357SAndroid Build Coastguard Worker 
WriteTo(Byte * p) const312*f6dc9357SAndroid Build Coastguard Worker void CResource::WriteTo(Byte *p) const
313*f6dc9357SAndroid Build Coastguard Worker {
314*f6dc9357SAndroid Build Coastguard Worker   Set64(p, PackSize)
315*f6dc9357SAndroid Build Coastguard Worker   p[7] = Flags;
316*f6dc9357SAndroid Build Coastguard Worker   Set64(p + 8, Offset)
317*f6dc9357SAndroid Build Coastguard Worker   Set64(p + 16, UnpackSize)
318*f6dc9357SAndroid Build Coastguard Worker }
319*f6dc9357SAndroid Build Coastguard Worker 
320*f6dc9357SAndroid Build Coastguard Worker 
WriteTo(Byte * p) const321*f6dc9357SAndroid Build Coastguard Worker void CHeader::WriteTo(Byte *p) const
322*f6dc9357SAndroid Build Coastguard Worker {
323*f6dc9357SAndroid Build Coastguard Worker   memcpy(p, kSignature, kSignatureSize);
324*f6dc9357SAndroid Build Coastguard Worker   Set32(p + 8, kHeaderSizeMax)
325*f6dc9357SAndroid Build Coastguard Worker   Set32(p + 0xC, Version)
326*f6dc9357SAndroid Build Coastguard Worker   Set32(p + 0x10, Flags)
327*f6dc9357SAndroid Build Coastguard Worker   Set32(p + 0x14, ChunkSize)
328*f6dc9357SAndroid Build Coastguard Worker   memcpy(p + 0x18, Guid, 16);
329*f6dc9357SAndroid Build Coastguard Worker   Set16(p + 0x28, PartNumber)
330*f6dc9357SAndroid Build Coastguard Worker   Set16(p + 0x2A, NumParts)
331*f6dc9357SAndroid Build Coastguard Worker   Set32(p + 0x2C, NumImages)
332*f6dc9357SAndroid Build Coastguard Worker   OffsetResource.WriteTo(p + 0x30);
333*f6dc9357SAndroid Build Coastguard Worker   XmlResource.WriteTo(p + 0x48);
334*f6dc9357SAndroid Build Coastguard Worker   MetadataResource.WriteTo(p + 0x60);
335*f6dc9357SAndroid Build Coastguard Worker   IntegrityResource.WriteTo(p + 0x7C);
336*f6dc9357SAndroid Build Coastguard Worker   Set32(p + 0x78, BootIndex)
337*f6dc9357SAndroid Build Coastguard Worker   memset(p + 0x94, 0, 60);
338*f6dc9357SAndroid Build Coastguard Worker }
339*f6dc9357SAndroid Build Coastguard Worker 
340*f6dc9357SAndroid Build Coastguard Worker 
WriteTo(Byte * p) const341*f6dc9357SAndroid Build Coastguard Worker void CStreamInfo::WriteTo(Byte *p) const
342*f6dc9357SAndroid Build Coastguard Worker {
343*f6dc9357SAndroid Build Coastguard Worker   Resource.WriteTo(p);
344*f6dc9357SAndroid Build Coastguard Worker   Set16(p + 0x18, PartNumber)
345*f6dc9357SAndroid Build Coastguard Worker   Set32(p + 0x1A, RefCount)
346*f6dc9357SAndroid Build Coastguard Worker   memcpy(p + 0x1E, Hash, kHashSize);
347*f6dc9357SAndroid Build Coastguard Worker }
348*f6dc9357SAndroid Build Coastguard Worker 
349*f6dc9357SAndroid Build Coastguard Worker 
SetFileTimeToMem(Byte * p,const FILETIME & ft)350*f6dc9357SAndroid Build Coastguard Worker static void SetFileTimeToMem(Byte *p, const FILETIME &ft)
351*f6dc9357SAndroid Build Coastguard Worker {
352*f6dc9357SAndroid Build Coastguard Worker   Set32(p, ft.dwLowDateTime)
353*f6dc9357SAndroid Build Coastguard Worker   Set32(p + 4, ft.dwHighDateTime)
354*f6dc9357SAndroid Build Coastguard Worker }
355*f6dc9357SAndroid Build Coastguard Worker 
WriteItem_Dummy(const CMetaItem & item)356*f6dc9357SAndroid Build Coastguard Worker static size_t WriteItem_Dummy(const CMetaItem &item)
357*f6dc9357SAndroid Build Coastguard Worker {
358*f6dc9357SAndroid Build Coastguard Worker   if (item.Skip)
359*f6dc9357SAndroid Build Coastguard Worker     return 0;
360*f6dc9357SAndroid Build Coastguard Worker   unsigned fileNameLen = item.Name.Len() * 2;
361*f6dc9357SAndroid Build Coastguard Worker   // we write fileNameLen + 2 + 2 to be same as original WIM.
362*f6dc9357SAndroid Build Coastguard Worker   unsigned fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2);
363*f6dc9357SAndroid Build Coastguard Worker 
364*f6dc9357SAndroid Build Coastguard Worker   const unsigned shortNameLen = item.ShortName.Len() * 2;
365*f6dc9357SAndroid Build Coastguard Worker   const unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4);
366*f6dc9357SAndroid Build Coastguard Worker 
367*f6dc9357SAndroid Build Coastguard Worker   size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~(unsigned)7);
368*f6dc9357SAndroid Build Coastguard Worker   if (item.GetNumAltStreams() != 0)
369*f6dc9357SAndroid Build Coastguard Worker   {
370*f6dc9357SAndroid Build Coastguard Worker     if (!item.IsDir)
371*f6dc9357SAndroid Build Coastguard Worker     {
372*f6dc9357SAndroid Build Coastguard Worker       const UInt32 curLen = (((0x26 + 0) + 6) & ~(unsigned)7);
373*f6dc9357SAndroid Build Coastguard Worker       totalLen += curLen;
374*f6dc9357SAndroid Build Coastguard Worker     }
375*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, item.AltStreams)
376*f6dc9357SAndroid Build Coastguard Worker     {
377*f6dc9357SAndroid Build Coastguard Worker       const CAltStream &ss = item.AltStreams[i];
378*f6dc9357SAndroid Build Coastguard Worker       if (ss.Skip)
379*f6dc9357SAndroid Build Coastguard Worker         continue;
380*f6dc9357SAndroid Build Coastguard Worker       fileNameLen = ss.Name.Len() * 2;
381*f6dc9357SAndroid Build Coastguard Worker       fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2 + 2);
382*f6dc9357SAndroid Build Coastguard Worker       const UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~(unsigned)7);
383*f6dc9357SAndroid Build Coastguard Worker       totalLen += curLen;
384*f6dc9357SAndroid Build Coastguard Worker     }
385*f6dc9357SAndroid Build Coastguard Worker   }
386*f6dc9357SAndroid Build Coastguard Worker   return totalLen;
387*f6dc9357SAndroid Build Coastguard Worker }
388*f6dc9357SAndroid Build Coastguard Worker 
389*f6dc9357SAndroid Build Coastguard Worker 
WriteItem(const CStreamInfo * streams,const CMetaItem & item,Byte * p)390*f6dc9357SAndroid Build Coastguard Worker static size_t WriteItem(const CStreamInfo *streams, const CMetaItem &item, Byte *p)
391*f6dc9357SAndroid Build Coastguard Worker {
392*f6dc9357SAndroid Build Coastguard Worker   if (item.Skip)
393*f6dc9357SAndroid Build Coastguard Worker     return 0;
394*f6dc9357SAndroid Build Coastguard Worker   unsigned fileNameLen = item.Name.Len() * 2;
395*f6dc9357SAndroid Build Coastguard Worker   unsigned fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2);
396*f6dc9357SAndroid Build Coastguard Worker   unsigned shortNameLen = item.ShortName.Len() * 2;
397*f6dc9357SAndroid Build Coastguard Worker   unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4);
398*f6dc9357SAndroid Build Coastguard Worker 
399*f6dc9357SAndroid Build Coastguard Worker   size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~(unsigned)7);
400*f6dc9357SAndroid Build Coastguard Worker 
401*f6dc9357SAndroid Build Coastguard Worker   memset(p, 0, totalLen);
402*f6dc9357SAndroid Build Coastguard Worker   Set64(p, totalLen)
403*f6dc9357SAndroid Build Coastguard Worker   Set64(p + 8, item.Attrib)
404*f6dc9357SAndroid Build Coastguard Worker   Set32(p + 0xC, (UInt32)(Int32)item.SecurityId)
405*f6dc9357SAndroid Build Coastguard Worker   SetFileTimeToMem(p + 0x28, item.CTime);
406*f6dc9357SAndroid Build Coastguard Worker   SetFileTimeToMem(p + 0x30, item.ATime);
407*f6dc9357SAndroid Build Coastguard Worker   SetFileTimeToMem(p + 0x38, item.MTime);
408*f6dc9357SAndroid Build Coastguard Worker 
409*f6dc9357SAndroid Build Coastguard Worker   /* WIM format probably doesn't support hard links to symbolic links.
410*f6dc9357SAndroid Build Coastguard Worker      In these cases it just stores symbolic links (REPARSE TAGS).
411*f6dc9357SAndroid Build Coastguard Worker      Check it in new versions of WIM software form MS !!!
412*f6dc9357SAndroid Build Coastguard Worker      We also follow that scheme */
413*f6dc9357SAndroid Build Coastguard Worker 
414*f6dc9357SAndroid Build Coastguard Worker   if (item.Reparse.Size() != 0)
415*f6dc9357SAndroid Build Coastguard Worker   {
416*f6dc9357SAndroid Build Coastguard Worker     UInt32 tag = GetUi32(item.Reparse);
417*f6dc9357SAndroid Build Coastguard Worker     Set32(p + 0x58, tag)
418*f6dc9357SAndroid Build Coastguard Worker     // Set32(p + 0x5C, 0); // probably it's always ZERO
419*f6dc9357SAndroid Build Coastguard Worker   }
420*f6dc9357SAndroid Build Coastguard Worker   else if (item.FileID != 0)
421*f6dc9357SAndroid Build Coastguard Worker   {
422*f6dc9357SAndroid Build Coastguard Worker     Set64(p + 0x58, item.FileID)
423*f6dc9357SAndroid Build Coastguard Worker   }
424*f6dc9357SAndroid Build Coastguard Worker 
425*f6dc9357SAndroid Build Coastguard Worker   Set16(p + 0x62, (UInt16)shortNameLen)
426*f6dc9357SAndroid Build Coastguard Worker   Set16(p + 0x64, (UInt16)fileNameLen)
427*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
428*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i * 2 < fileNameLen; i++)
429*f6dc9357SAndroid Build Coastguard Worker     Set16(p + kDirRecordSize + i * 2, (UInt16)item.Name[i])
430*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i * 2 < shortNameLen; i++)
431*f6dc9357SAndroid Build Coastguard Worker     Set16(p + kDirRecordSize + fileNameLen2 + i * 2, (UInt16)item.ShortName[i])
432*f6dc9357SAndroid Build Coastguard Worker 
433*f6dc9357SAndroid Build Coastguard Worker   if (item.GetNumAltStreams() == 0)
434*f6dc9357SAndroid Build Coastguard Worker   {
435*f6dc9357SAndroid Build Coastguard Worker     if (item.HashIndex >= 0)
436*f6dc9357SAndroid Build Coastguard Worker       memcpy(p + 0x40, streams[item.HashIndex].Hash, kHashSize);
437*f6dc9357SAndroid Build Coastguard Worker   }
438*f6dc9357SAndroid Build Coastguard Worker   else
439*f6dc9357SAndroid Build Coastguard Worker   {
440*f6dc9357SAndroid Build Coastguard Worker     Set16(p + 0x60, (UInt16)(item.GetNumAltStreams() + (item.IsDir ? 0 : 1)))
441*f6dc9357SAndroid Build Coastguard Worker     p += totalLen;
442*f6dc9357SAndroid Build Coastguard Worker 
443*f6dc9357SAndroid Build Coastguard Worker     if (!item.IsDir)
444*f6dc9357SAndroid Build Coastguard Worker     {
445*f6dc9357SAndroid Build Coastguard Worker       const UInt32 curLen = (((0x26 + 0) + 6) & ~(unsigned)7);
446*f6dc9357SAndroid Build Coastguard Worker       memset(p, 0, curLen);
447*f6dc9357SAndroid Build Coastguard Worker       Set64(p, curLen)
448*f6dc9357SAndroid Build Coastguard Worker       if (item.HashIndex >= 0)
449*f6dc9357SAndroid Build Coastguard Worker         memcpy(p + 0x10, streams[item.HashIndex].Hash, kHashSize);
450*f6dc9357SAndroid Build Coastguard Worker       totalLen += curLen;
451*f6dc9357SAndroid Build Coastguard Worker       p += curLen;
452*f6dc9357SAndroid Build Coastguard Worker     }
453*f6dc9357SAndroid Build Coastguard Worker 
454*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (si, item.AltStreams)
455*f6dc9357SAndroid Build Coastguard Worker     {
456*f6dc9357SAndroid Build Coastguard Worker       const CAltStream &ss = item.AltStreams[si];
457*f6dc9357SAndroid Build Coastguard Worker       if (ss.Skip)
458*f6dc9357SAndroid Build Coastguard Worker         continue;
459*f6dc9357SAndroid Build Coastguard Worker 
460*f6dc9357SAndroid Build Coastguard Worker       fileNameLen = ss.Name.Len() * 2;
461*f6dc9357SAndroid Build Coastguard Worker       fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2 + 2);
462*f6dc9357SAndroid Build Coastguard Worker       UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~(unsigned)7);
463*f6dc9357SAndroid Build Coastguard Worker       memset(p, 0, curLen);
464*f6dc9357SAndroid Build Coastguard Worker 
465*f6dc9357SAndroid Build Coastguard Worker       Set64(p, curLen)
466*f6dc9357SAndroid Build Coastguard Worker       if (ss.HashIndex >= 0)
467*f6dc9357SAndroid Build Coastguard Worker         memcpy(p + 0x10, streams[ss.HashIndex].Hash, kHashSize);
468*f6dc9357SAndroid Build Coastguard Worker       Set16(p + 0x24, (UInt16)fileNameLen)
469*f6dc9357SAndroid Build Coastguard Worker       for (i = 0; i * 2 < fileNameLen; i++)
470*f6dc9357SAndroid Build Coastguard Worker         Set16(p + 0x26 + i * 2, (UInt16)ss.Name[i])
471*f6dc9357SAndroid Build Coastguard Worker       totalLen += curLen;
472*f6dc9357SAndroid Build Coastguard Worker       p += curLen;
473*f6dc9357SAndroid Build Coastguard Worker     }
474*f6dc9357SAndroid Build Coastguard Worker   }
475*f6dc9357SAndroid Build Coastguard Worker 
476*f6dc9357SAndroid Build Coastguard Worker   return totalLen;
477*f6dc9357SAndroid Build Coastguard Worker }
478*f6dc9357SAndroid Build Coastguard Worker 
479*f6dc9357SAndroid Build Coastguard Worker 
480*f6dc9357SAndroid Build Coastguard Worker struct CDb
481*f6dc9357SAndroid Build Coastguard Worker {
482*f6dc9357SAndroid Build Coastguard Worker   CMetaItem DefaultDirItem;
483*f6dc9357SAndroid Build Coastguard Worker   const CStreamInfo *Hashes;
484*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CMetaItem> MetaItems;
485*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CUpdateItem> UpdateItems;
486*f6dc9357SAndroid Build Coastguard Worker   CUIntVector UpdateIndexes; /* indexes in UpdateItems in order of writing data streams
487*f6dc9357SAndroid Build Coastguard Worker                                 to disk (the order of tree items). */
488*f6dc9357SAndroid Build Coastguard Worker 
489*f6dc9357SAndroid Build Coastguard Worker   size_t WriteTree_Dummy(const CDir &tree) const;
490*f6dc9357SAndroid Build Coastguard Worker   void WriteTree(const CDir &tree, Byte *dest, size_t &pos)  const;
491*f6dc9357SAndroid Build Coastguard Worker   void WriteOrderList(const CDir &tree);
492*f6dc9357SAndroid Build Coastguard Worker };
493*f6dc9357SAndroid Build Coastguard Worker 
494*f6dc9357SAndroid Build Coastguard Worker 
WriteTree_Dummy(const CDir & tree) const495*f6dc9357SAndroid Build Coastguard Worker size_t CDb::WriteTree_Dummy(const CDir &tree) const
496*f6dc9357SAndroid Build Coastguard Worker {
497*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
498*f6dc9357SAndroid Build Coastguard Worker   size_t pos = 0;
499*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < tree.Files.Size(); i++)
500*f6dc9357SAndroid Build Coastguard Worker     pos += WriteItem_Dummy(MetaItems[tree.Files[i]]);
501*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < tree.Dirs.Size(); i++)
502*f6dc9357SAndroid Build Coastguard Worker   {
503*f6dc9357SAndroid Build Coastguard Worker     const CDir &subDir = tree.Dirs[i];
504*f6dc9357SAndroid Build Coastguard Worker     pos += WriteItem_Dummy(MetaItems[subDir.MetaIndex]);
505*f6dc9357SAndroid Build Coastguard Worker     pos += WriteTree_Dummy(subDir);
506*f6dc9357SAndroid Build Coastguard Worker   }
507*f6dc9357SAndroid Build Coastguard Worker   return pos + 8;
508*f6dc9357SAndroid Build Coastguard Worker }
509*f6dc9357SAndroid Build Coastguard Worker 
510*f6dc9357SAndroid Build Coastguard Worker 
WriteTree(const CDir & tree,Byte * dest,size_t & pos) const511*f6dc9357SAndroid Build Coastguard Worker void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const
512*f6dc9357SAndroid Build Coastguard Worker {
513*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
514*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < tree.Files.Size(); i++)
515*f6dc9357SAndroid Build Coastguard Worker     pos += WriteItem(Hashes, MetaItems[tree.Files[i]], dest + pos);
516*f6dc9357SAndroid Build Coastguard Worker 
517*f6dc9357SAndroid Build Coastguard Worker   size_t posStart = pos;
518*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < tree.Dirs.Size(); i++)
519*f6dc9357SAndroid Build Coastguard Worker     pos += WriteItem_Dummy(MetaItems[tree.Dirs[i].MetaIndex]);
520*f6dc9357SAndroid Build Coastguard Worker 
521*f6dc9357SAndroid Build Coastguard Worker   Set64(dest + pos, 0)
522*f6dc9357SAndroid Build Coastguard Worker 
523*f6dc9357SAndroid Build Coastguard Worker   pos += 8;
524*f6dc9357SAndroid Build Coastguard Worker 
525*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < tree.Dirs.Size(); i++)
526*f6dc9357SAndroid Build Coastguard Worker   {
527*f6dc9357SAndroid Build Coastguard Worker     const CDir &subDir = tree.Dirs[i];
528*f6dc9357SAndroid Build Coastguard Worker     const CMetaItem &metaItem = MetaItems[subDir.MetaIndex];
529*f6dc9357SAndroid Build Coastguard Worker     bool needCreateTree = (metaItem.Reparse.Size() == 0)
530*f6dc9357SAndroid Build Coastguard Worker         || !subDir.Files.IsEmpty()
531*f6dc9357SAndroid Build Coastguard Worker         || !subDir.Dirs.IsEmpty();
532*f6dc9357SAndroid Build Coastguard Worker     size_t len = WriteItem(Hashes, metaItem, dest + posStart);
533*f6dc9357SAndroid Build Coastguard Worker     posStart += len;
534*f6dc9357SAndroid Build Coastguard Worker     if (needCreateTree)
535*f6dc9357SAndroid Build Coastguard Worker     {
536*f6dc9357SAndroid Build Coastguard Worker       Set64(dest + posStart - len + 0x10, pos) // subdirOffset
537*f6dc9357SAndroid Build Coastguard Worker       WriteTree(subDir, dest, pos);
538*f6dc9357SAndroid Build Coastguard Worker     }
539*f6dc9357SAndroid Build Coastguard Worker   }
540*f6dc9357SAndroid Build Coastguard Worker }
541*f6dc9357SAndroid Build Coastguard Worker 
542*f6dc9357SAndroid Build Coastguard Worker 
WriteOrderList(const CDir & tree)543*f6dc9357SAndroid Build Coastguard Worker void CDb::WriteOrderList(const CDir &tree)
544*f6dc9357SAndroid Build Coastguard Worker {
545*f6dc9357SAndroid Build Coastguard Worker   if (tree.MetaIndex >= 0)
546*f6dc9357SAndroid Build Coastguard Worker   {
547*f6dc9357SAndroid Build Coastguard Worker     const CMetaItem &mi = MetaItems[tree.MetaIndex];
548*f6dc9357SAndroid Build Coastguard Worker     if (mi.UpdateIndex >= 0)
549*f6dc9357SAndroid Build Coastguard Worker       UpdateIndexes.Add((unsigned)mi.UpdateIndex);
550*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (si, mi.AltStreams)
551*f6dc9357SAndroid Build Coastguard Worker       UpdateIndexes.Add((unsigned)mi.AltStreams[si].UpdateIndex);
552*f6dc9357SAndroid Build Coastguard Worker   }
553*f6dc9357SAndroid Build Coastguard Worker 
554*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
555*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < tree.Files.Size(); i++)
556*f6dc9357SAndroid Build Coastguard Worker   {
557*f6dc9357SAndroid Build Coastguard Worker     const CMetaItem &mi = MetaItems[tree.Files[i]];
558*f6dc9357SAndroid Build Coastguard Worker     UpdateIndexes.Add((unsigned)mi.UpdateIndex);
559*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (si, mi.AltStreams)
560*f6dc9357SAndroid Build Coastguard Worker       UpdateIndexes.Add((unsigned)mi.AltStreams[si].UpdateIndex);
561*f6dc9357SAndroid Build Coastguard Worker   }
562*f6dc9357SAndroid Build Coastguard Worker 
563*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < tree.Dirs.Size(); i++)
564*f6dc9357SAndroid Build Coastguard Worker     WriteOrderList(tree.Dirs[i]);
565*f6dc9357SAndroid Build Coastguard Worker }
566*f6dc9357SAndroid Build Coastguard Worker 
567*f6dc9357SAndroid Build Coastguard Worker 
AddTag_ToString(AString & s,const char * name,const char * value)568*f6dc9357SAndroid Build Coastguard Worker static void AddTag_ToString(AString &s, const char *name, const char *value)
569*f6dc9357SAndroid Build Coastguard Worker {
570*f6dc9357SAndroid Build Coastguard Worker   s.Add_Char('<');
571*f6dc9357SAndroid Build Coastguard Worker   s += name;
572*f6dc9357SAndroid Build Coastguard Worker   s.Add_Char('>');
573*f6dc9357SAndroid Build Coastguard Worker   s += value;
574*f6dc9357SAndroid Build Coastguard Worker   s.Add_Char('<');
575*f6dc9357SAndroid Build Coastguard Worker   s.Add_Slash();
576*f6dc9357SAndroid Build Coastguard Worker   s += name;
577*f6dc9357SAndroid Build Coastguard Worker   s.Add_Char('>');
578*f6dc9357SAndroid Build Coastguard Worker }
579*f6dc9357SAndroid Build Coastguard Worker 
580*f6dc9357SAndroid Build Coastguard Worker 
AddTagUInt64_ToString(AString & s,const char * name,UInt64 value)581*f6dc9357SAndroid Build Coastguard Worker static void AddTagUInt64_ToString(AString &s, const char *name, UInt64 value)
582*f6dc9357SAndroid Build Coastguard Worker {
583*f6dc9357SAndroid Build Coastguard Worker   char temp[32];
584*f6dc9357SAndroid Build Coastguard Worker   ConvertUInt64ToString(value, temp);
585*f6dc9357SAndroid Build Coastguard Worker   AddTag_ToString(s, name, temp);
586*f6dc9357SAndroid Build Coastguard Worker }
587*f6dc9357SAndroid Build Coastguard Worker 
588*f6dc9357SAndroid Build Coastguard Worker 
AddUniqueTag(CXmlItem & parentItem,const char * name)589*f6dc9357SAndroid Build Coastguard Worker static CXmlItem &AddUniqueTag(CXmlItem &parentItem, const char *name)
590*f6dc9357SAndroid Build Coastguard Worker {
591*f6dc9357SAndroid Build Coastguard Worker   const int index = parentItem.FindSubTag(name);
592*f6dc9357SAndroid Build Coastguard Worker   if (index < 0)
593*f6dc9357SAndroid Build Coastguard Worker   {
594*f6dc9357SAndroid Build Coastguard Worker     CXmlItem &subItem = parentItem.SubItems.AddNew();
595*f6dc9357SAndroid Build Coastguard Worker     subItem.IsTag = true;
596*f6dc9357SAndroid Build Coastguard Worker     subItem.Name = name;
597*f6dc9357SAndroid Build Coastguard Worker     return subItem;
598*f6dc9357SAndroid Build Coastguard Worker   }
599*f6dc9357SAndroid Build Coastguard Worker   CXmlItem &subItem = parentItem.SubItems[index];
600*f6dc9357SAndroid Build Coastguard Worker   subItem.SubItems.Clear();
601*f6dc9357SAndroid Build Coastguard Worker   return subItem;
602*f6dc9357SAndroid Build Coastguard Worker }
603*f6dc9357SAndroid Build Coastguard Worker 
604*f6dc9357SAndroid Build Coastguard Worker 
AddTag_UInt64_2(CXmlItem & item,UInt64 value)605*f6dc9357SAndroid Build Coastguard Worker static void AddTag_UInt64_2(CXmlItem &item, UInt64 value)
606*f6dc9357SAndroid Build Coastguard Worker {
607*f6dc9357SAndroid Build Coastguard Worker   CXmlItem &subItem = item.SubItems.AddNew();
608*f6dc9357SAndroid Build Coastguard Worker   subItem.IsTag = false;
609*f6dc9357SAndroid Build Coastguard Worker   char temp[32];
610*f6dc9357SAndroid Build Coastguard Worker   ConvertUInt64ToString(value, temp);
611*f6dc9357SAndroid Build Coastguard Worker   subItem.Name = temp;
612*f6dc9357SAndroid Build Coastguard Worker }
613*f6dc9357SAndroid Build Coastguard Worker 
614*f6dc9357SAndroid Build Coastguard Worker 
AddTag_UInt64(CXmlItem & parentItem,const char * name,UInt64 value)615*f6dc9357SAndroid Build Coastguard Worker static void AddTag_UInt64(CXmlItem &parentItem, const char *name, UInt64 value)
616*f6dc9357SAndroid Build Coastguard Worker {
617*f6dc9357SAndroid Build Coastguard Worker   AddTag_UInt64_2(AddUniqueTag(parentItem, name), value);
618*f6dc9357SAndroid Build Coastguard Worker }
619*f6dc9357SAndroid Build Coastguard Worker 
620*f6dc9357SAndroid Build Coastguard Worker 
AddTag_Hex(CXmlItem & item,const char * name,UInt32 value)621*f6dc9357SAndroid Build Coastguard Worker static void AddTag_Hex(CXmlItem &item, const char *name, UInt32 value)
622*f6dc9357SAndroid Build Coastguard Worker {
623*f6dc9357SAndroid Build Coastguard Worker   item.IsTag = true;
624*f6dc9357SAndroid Build Coastguard Worker   item.Name = name;
625*f6dc9357SAndroid Build Coastguard Worker   char temp[16];
626*f6dc9357SAndroid Build Coastguard Worker   temp[0] = '0';
627*f6dc9357SAndroid Build Coastguard Worker   temp[1] = 'x';
628*f6dc9357SAndroid Build Coastguard Worker   ConvertUInt32ToHex8Digits(value, temp + 2);
629*f6dc9357SAndroid Build Coastguard Worker   CXmlItem &subItem = item.SubItems.AddNew();
630*f6dc9357SAndroid Build Coastguard Worker   subItem.IsTag = false;
631*f6dc9357SAndroid Build Coastguard Worker   subItem.Name = temp;
632*f6dc9357SAndroid Build Coastguard Worker }
633*f6dc9357SAndroid Build Coastguard Worker 
634*f6dc9357SAndroid Build Coastguard Worker 
AddTag_Time_2(CXmlItem & item,const FILETIME & ft)635*f6dc9357SAndroid Build Coastguard Worker static void AddTag_Time_2(CXmlItem &item, const FILETIME &ft)
636*f6dc9357SAndroid Build Coastguard Worker {
637*f6dc9357SAndroid Build Coastguard Worker   AddTag_Hex(item.SubItems.AddNew(), "HIGHPART", ft.dwHighDateTime);
638*f6dc9357SAndroid Build Coastguard Worker   AddTag_Hex(item.SubItems.AddNew(), "LOWPART", ft.dwLowDateTime);
639*f6dc9357SAndroid Build Coastguard Worker }
640*f6dc9357SAndroid Build Coastguard Worker 
641*f6dc9357SAndroid Build Coastguard Worker 
AddTag_Time(CXmlItem & parentItem,const char * name,const FILETIME & ft)642*f6dc9357SAndroid Build Coastguard Worker static void AddTag_Time(CXmlItem &parentItem, const char *name, const FILETIME &ft)
643*f6dc9357SAndroid Build Coastguard Worker {
644*f6dc9357SAndroid Build Coastguard Worker   AddTag_Time_2(AddUniqueTag(parentItem, name), ft);
645*f6dc9357SAndroid Build Coastguard Worker }
646*f6dc9357SAndroid Build Coastguard Worker 
647*f6dc9357SAndroid Build Coastguard Worker 
AddTag_String_IfEmpty(CXmlItem & parentItem,const char * name,const char * value)648*f6dc9357SAndroid Build Coastguard Worker static void AddTag_String_IfEmpty(CXmlItem &parentItem, const char *name, const char *value)
649*f6dc9357SAndroid Build Coastguard Worker {
650*f6dc9357SAndroid Build Coastguard Worker   if (parentItem.FindSubTag(name) >= 0)
651*f6dc9357SAndroid Build Coastguard Worker     return;
652*f6dc9357SAndroid Build Coastguard Worker   CXmlItem &tag = parentItem.SubItems.AddNew();
653*f6dc9357SAndroid Build Coastguard Worker   tag.IsTag = true;
654*f6dc9357SAndroid Build Coastguard Worker   tag.Name = name;
655*f6dc9357SAndroid Build Coastguard Worker   CXmlItem &subItem = tag.SubItems.AddNew();
656*f6dc9357SAndroid Build Coastguard Worker   subItem.IsTag = false;
657*f6dc9357SAndroid Build Coastguard Worker   subItem.Name = value;
658*f6dc9357SAndroid Build Coastguard Worker }
659*f6dc9357SAndroid Build Coastguard Worker 
660*f6dc9357SAndroid Build Coastguard Worker 
SetDefaultFields(bool useLZX)661*f6dc9357SAndroid Build Coastguard Worker void CHeader::SetDefaultFields(bool useLZX)
662*f6dc9357SAndroid Build Coastguard Worker {
663*f6dc9357SAndroid Build Coastguard Worker   Version = k_Version_NonSolid;
664*f6dc9357SAndroid Build Coastguard Worker   Flags = NHeaderFlags::kReparsePointFixup;
665*f6dc9357SAndroid Build Coastguard Worker   ChunkSize = 0;
666*f6dc9357SAndroid Build Coastguard Worker   if (useLZX)
667*f6dc9357SAndroid Build Coastguard Worker   {
668*f6dc9357SAndroid Build Coastguard Worker     Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX;
669*f6dc9357SAndroid Build Coastguard Worker     ChunkSize = kChunkSize;
670*f6dc9357SAndroid Build Coastguard Worker     ChunkSizeBits = kChunkSizeBits;
671*f6dc9357SAndroid Build Coastguard Worker   }
672*f6dc9357SAndroid Build Coastguard Worker   MY_RAND_GEN(Guid, 16);
673*f6dc9357SAndroid Build Coastguard Worker   PartNumber = 1;
674*f6dc9357SAndroid Build Coastguard Worker   NumParts = 1;
675*f6dc9357SAndroid Build Coastguard Worker   NumImages = 1;
676*f6dc9357SAndroid Build Coastguard Worker   BootIndex = 0;
677*f6dc9357SAndroid Build Coastguard Worker   OffsetResource.Clear();
678*f6dc9357SAndroid Build Coastguard Worker   XmlResource.Clear();
679*f6dc9357SAndroid Build Coastguard Worker   MetadataResource.Clear();
680*f6dc9357SAndroid Build Coastguard Worker   IntegrityResource.Clear();
681*f6dc9357SAndroid Build Coastguard Worker }
682*f6dc9357SAndroid Build Coastguard Worker 
683*f6dc9357SAndroid Build Coastguard Worker 
AddTrees(CObjectVector<CDir> & trees,CObjectVector<CMetaItem> & metaItems,const CMetaItem & ri,int curTreeIndex)684*f6dc9357SAndroid Build Coastguard Worker static void AddTrees(CObjectVector<CDir> &trees, CObjectVector<CMetaItem> &metaItems, const CMetaItem &ri, int curTreeIndex)
685*f6dc9357SAndroid Build Coastguard Worker {
686*f6dc9357SAndroid Build Coastguard Worker   while (curTreeIndex >= (int)trees.Size())
687*f6dc9357SAndroid Build Coastguard Worker     trees.AddNew().Dirs.AddNew().MetaIndex = (int)metaItems.Add(ri);
688*f6dc9357SAndroid Build Coastguard Worker }
689*f6dc9357SAndroid Build Coastguard Worker 
690*f6dc9357SAndroid Build Coastguard Worker 
691*f6dc9357SAndroid Build Coastguard Worker #define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
692*f6dc9357SAndroid Build Coastguard Worker 
693*f6dc9357SAndroid Build Coastguard Worker 
694*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::UpdateItems (ISequentialOutStream * outSeqStream,UInt32 numItems,IArchiveUpdateCallback * callback))695*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 numItems, IArchiveUpdateCallback *callback))
696*f6dc9357SAndroid Build Coastguard Worker {
697*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
698*f6dc9357SAndroid Build Coastguard Worker 
699*f6dc9357SAndroid Build Coastguard Worker   if (!IsUpdateSupported())
700*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
701*f6dc9357SAndroid Build Coastguard Worker 
702*f6dc9357SAndroid Build Coastguard Worker   bool isUpdate = (_volumes.Size() != 0);
703*f6dc9357SAndroid Build Coastguard Worker   int defaultImageIndex = _defaultImageNumber - 1;
704*f6dc9357SAndroid Build Coastguard Worker   bool showImageNumber;
705*f6dc9357SAndroid Build Coastguard Worker 
706*f6dc9357SAndroid Build Coastguard Worker   if (isUpdate)
707*f6dc9357SAndroid Build Coastguard Worker   {
708*f6dc9357SAndroid Build Coastguard Worker     showImageNumber = _showImageNumber;
709*f6dc9357SAndroid Build Coastguard Worker     if (!showImageNumber)
710*f6dc9357SAndroid Build Coastguard Worker       defaultImageIndex = _db.IndexOfUserImage;
711*f6dc9357SAndroid Build Coastguard Worker   }
712*f6dc9357SAndroid Build Coastguard Worker   else
713*f6dc9357SAndroid Build Coastguard Worker   {
714*f6dc9357SAndroid Build Coastguard Worker     showImageNumber = (_set_use_ShowImageNumber && _set_showImageNumber);
715*f6dc9357SAndroid Build Coastguard Worker     if (!showImageNumber)
716*f6dc9357SAndroid Build Coastguard Worker       defaultImageIndex = 0;
717*f6dc9357SAndroid Build Coastguard Worker   }
718*f6dc9357SAndroid Build Coastguard Worker 
719*f6dc9357SAndroid Build Coastguard Worker   if (defaultImageIndex >= kNumImagesMaxUpdate)
720*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
721*f6dc9357SAndroid Build Coastguard Worker 
722*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IOutStream> outStream;
723*f6dc9357SAndroid Build Coastguard Worker   RINOK(outSeqStream->QueryInterface(IID_IOutStream, (void **)&outStream))
724*f6dc9357SAndroid Build Coastguard Worker   if (!outStream)
725*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
726*f6dc9357SAndroid Build Coastguard Worker   if (!callback)
727*f6dc9357SAndroid Build Coastguard Worker     return E_FAIL;
728*f6dc9357SAndroid Build Coastguard Worker 
729*f6dc9357SAndroid Build Coastguard Worker   CDb db;
730*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CDir> trees;
731*f6dc9357SAndroid Build Coastguard Worker 
732*f6dc9357SAndroid Build Coastguard Worker   CMetaItem ri; // default DIR item
733*f6dc9357SAndroid Build Coastguard Worker   FILETIME ftCur;
734*f6dc9357SAndroid Build Coastguard Worker   NTime::GetCurUtcFileTime(ftCur);
735*f6dc9357SAndroid Build Coastguard Worker   // ri.MTime = ri.ATime = ri.CTime = ftCur;
736*f6dc9357SAndroid Build Coastguard Worker   ri.Attrib = FILE_ATTRIBUTE_DIRECTORY;
737*f6dc9357SAndroid Build Coastguard Worker   ri.IsDir = true;
738*f6dc9357SAndroid Build Coastguard Worker 
739*f6dc9357SAndroid Build Coastguard Worker 
740*f6dc9357SAndroid Build Coastguard Worker   // ---------- Detect changed images ----------
741*f6dc9357SAndroid Build Coastguard Worker 
742*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
743*f6dc9357SAndroid Build Coastguard Worker   CBoolVector isChangedImage;
744*f6dc9357SAndroid Build Coastguard Worker   {
745*f6dc9357SAndroid Build Coastguard Worker     CUIntVector numUnchangedItemsInImage;
746*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < _db.Images.Size(); i++)
747*f6dc9357SAndroid Build Coastguard Worker     {
748*f6dc9357SAndroid Build Coastguard Worker       numUnchangedItemsInImage.Add(0);
749*f6dc9357SAndroid Build Coastguard Worker       isChangedImage.Add(false);
750*f6dc9357SAndroid Build Coastguard Worker     }
751*f6dc9357SAndroid Build Coastguard Worker 
752*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < numItems; i++)
753*f6dc9357SAndroid Build Coastguard Worker     {
754*f6dc9357SAndroid Build Coastguard Worker       UInt32 indexInArchive;
755*f6dc9357SAndroid Build Coastguard Worker       Int32 newData, newProps;
756*f6dc9357SAndroid Build Coastguard Worker       RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive))
757*f6dc9357SAndroid Build Coastguard Worker       if (newProps == 0)
758*f6dc9357SAndroid Build Coastguard Worker       {
759*f6dc9357SAndroid Build Coastguard Worker         if (indexInArchive >= _db.SortedItems.Size())
760*f6dc9357SAndroid Build Coastguard Worker           continue;
761*f6dc9357SAndroid Build Coastguard Worker         const CItem &item = _db.Items[_db.SortedItems[indexInArchive]];
762*f6dc9357SAndroid Build Coastguard Worker         if (newData == 0)
763*f6dc9357SAndroid Build Coastguard Worker         {
764*f6dc9357SAndroid Build Coastguard Worker           if (item.ImageIndex >= 0)
765*f6dc9357SAndroid Build Coastguard Worker             numUnchangedItemsInImage[item.ImageIndex]++;
766*f6dc9357SAndroid Build Coastguard Worker         }
767*f6dc9357SAndroid Build Coastguard Worker         else
768*f6dc9357SAndroid Build Coastguard Worker         {
769*f6dc9357SAndroid Build Coastguard Worker           // oldProps & newData. Current version of 7-Zip doesn't use it
770*f6dc9357SAndroid Build Coastguard Worker           if (item.ImageIndex >= 0)
771*f6dc9357SAndroid Build Coastguard Worker             isChangedImage[item.ImageIndex] = true;
772*f6dc9357SAndroid Build Coastguard Worker         }
773*f6dc9357SAndroid Build Coastguard Worker       }
774*f6dc9357SAndroid Build Coastguard Worker       else if (!showImageNumber)
775*f6dc9357SAndroid Build Coastguard Worker       {
776*f6dc9357SAndroid Build Coastguard Worker         if (defaultImageIndex >= 0 && defaultImageIndex < (int)isChangedImage.Size())
777*f6dc9357SAndroid Build Coastguard Worker           isChangedImage[defaultImageIndex] = true;
778*f6dc9357SAndroid Build Coastguard Worker       }
779*f6dc9357SAndroid Build Coastguard Worker       else
780*f6dc9357SAndroid Build Coastguard Worker       {
781*f6dc9357SAndroid Build Coastguard Worker         NCOM::CPropVariant prop;
782*f6dc9357SAndroid Build Coastguard Worker         RINOK(callback->GetProperty(i, kpidPath, &prop))
783*f6dc9357SAndroid Build Coastguard Worker 
784*f6dc9357SAndroid Build Coastguard Worker         if (prop.vt != VT_BSTR)
785*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
786*f6dc9357SAndroid Build Coastguard Worker         const wchar_t *path = prop.bstrVal;
787*f6dc9357SAndroid Build Coastguard Worker         if (!path)
788*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
789*f6dc9357SAndroid Build Coastguard Worker 
790*f6dc9357SAndroid Build Coastguard Worker         const wchar_t *end;
791*f6dc9357SAndroid Build Coastguard Worker         UInt64 val = ConvertStringToUInt64(path, &end);
792*f6dc9357SAndroid Build Coastguard Worker         if (end == path)
793*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
794*f6dc9357SAndroid Build Coastguard Worker         if (val == 0 || val > kNumImagesMaxUpdate)
795*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
796*f6dc9357SAndroid Build Coastguard Worker         wchar_t c = *end;
797*f6dc9357SAndroid Build Coastguard Worker         if (c != 0 && c != ':' && c != L'/' && c != WCHAR_PATH_SEPARATOR)
798*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
799*f6dc9357SAndroid Build Coastguard Worker         unsigned imageIndex = (unsigned)val - 1;
800*f6dc9357SAndroid Build Coastguard Worker         if (imageIndex < _db.Images.Size())
801*f6dc9357SAndroid Build Coastguard Worker           isChangedImage[imageIndex] = true;
802*f6dc9357SAndroid Build Coastguard Worker         if (_defaultImageNumber > 0 && val != (unsigned)_defaultImageNumber)
803*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
804*f6dc9357SAndroid Build Coastguard Worker       }
805*f6dc9357SAndroid Build Coastguard Worker     }
806*f6dc9357SAndroid Build Coastguard Worker 
807*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < _db.Images.Size(); i++)
808*f6dc9357SAndroid Build Coastguard Worker       if (!isChangedImage[i])
809*f6dc9357SAndroid Build Coastguard Worker         isChangedImage[i] = _db.GetNumUserItemsInImage(i) != numUnchangedItemsInImage[i];
810*f6dc9357SAndroid Build Coastguard Worker   }
811*f6dc9357SAndroid Build Coastguard Worker 
812*f6dc9357SAndroid Build Coastguard Worker   if (defaultImageIndex >= 0)
813*f6dc9357SAndroid Build Coastguard Worker   {
814*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < _db.Images.Size(); i++)
815*f6dc9357SAndroid Build Coastguard Worker       if ((int)i != defaultImageIndex)
816*f6dc9357SAndroid Build Coastguard Worker         isChangedImage[i] = false;
817*f6dc9357SAndroid Build Coastguard Worker   }
818*f6dc9357SAndroid Build Coastguard Worker 
819*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveGetRawProps> getRawProps;
820*f6dc9357SAndroid Build Coastguard Worker   callback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);
821*f6dc9357SAndroid Build Coastguard Worker 
822*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveGetRootProps> getRootProps;
823*f6dc9357SAndroid Build Coastguard Worker   callback->QueryInterface(IID_IArchiveGetRootProps, (void **)&getRootProps);
824*f6dc9357SAndroid Build Coastguard Worker 
825*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CUniqBlocks> secureBlocks;
826*f6dc9357SAndroid Build Coastguard Worker 
827*f6dc9357SAndroid Build Coastguard Worker   if (!showImageNumber && (getRootProps || isUpdate) &&
828*f6dc9357SAndroid Build Coastguard Worker       (
829*f6dc9357SAndroid Build Coastguard Worker         defaultImageIndex >= (int)isChangedImage.Size()
830*f6dc9357SAndroid Build Coastguard Worker         || defaultImageIndex < 0 // test it
831*f6dc9357SAndroid Build Coastguard Worker         || isChangedImage[defaultImageIndex]
832*f6dc9357SAndroid Build Coastguard Worker       ))
833*f6dc9357SAndroid Build Coastguard Worker   {
834*f6dc9357SAndroid Build Coastguard Worker     // Fill Root Item: Metadata and security
835*f6dc9357SAndroid Build Coastguard Worker     CMetaItem rootItem = ri;
836*f6dc9357SAndroid Build Coastguard Worker     {
837*f6dc9357SAndroid Build Coastguard Worker       const void *data = NULL;
838*f6dc9357SAndroid Build Coastguard Worker       UInt32 dataSize = 0;
839*f6dc9357SAndroid Build Coastguard Worker       UInt32 propType = 0;
840*f6dc9357SAndroid Build Coastguard Worker       if (getRootProps)
841*f6dc9357SAndroid Build Coastguard Worker       {
842*f6dc9357SAndroid Build Coastguard Worker         RINOK(getRootProps->GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType))
843*f6dc9357SAndroid Build Coastguard Worker       }
844*f6dc9357SAndroid Build Coastguard Worker       if (dataSize == 0 && isUpdate)
845*f6dc9357SAndroid Build Coastguard Worker       {
846*f6dc9357SAndroid Build Coastguard Worker         RINOK(GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType))
847*f6dc9357SAndroid Build Coastguard Worker       }
848*f6dc9357SAndroid Build Coastguard Worker       if (dataSize != 0)
849*f6dc9357SAndroid Build Coastguard Worker       {
850*f6dc9357SAndroid Build Coastguard Worker         if (propType != NPropDataType::kRaw)
851*f6dc9357SAndroid Build Coastguard Worker           return E_FAIL;
852*f6dc9357SAndroid Build Coastguard Worker         while (defaultImageIndex >= (int)secureBlocks.Size())
853*f6dc9357SAndroid Build Coastguard Worker           secureBlocks.AddNew();
854*f6dc9357SAndroid Build Coastguard Worker         CUniqBlocks &secUniqBlocks = secureBlocks[defaultImageIndex];
855*f6dc9357SAndroid Build Coastguard Worker         rootItem.SecurityId = (int)secUniqBlocks.AddUniq((const Byte *)data, dataSize);
856*f6dc9357SAndroid Build Coastguard Worker       }
857*f6dc9357SAndroid Build Coastguard Worker     }
858*f6dc9357SAndroid Build Coastguard Worker 
859*f6dc9357SAndroid Build Coastguard Worker     IArchiveGetRootProps *thisGetRoot = isUpdate ? this : NULL;
860*f6dc9357SAndroid Build Coastguard Worker 
861*f6dc9357SAndroid Build Coastguard Worker     if (_timeOptions.Write_CTime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidCTime, rootItem.CTime))
862*f6dc9357SAndroid Build Coastguard Worker     if (_timeOptions.Write_ATime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidATime, rootItem.ATime))
863*f6dc9357SAndroid Build Coastguard Worker     if (_timeOptions.Write_MTime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidMTime, rootItem.MTime))
864*f6dc9357SAndroid Build Coastguard Worker 
865*f6dc9357SAndroid Build Coastguard Worker     {
866*f6dc9357SAndroid Build Coastguard Worker       NCOM::CPropVariant prop;
867*f6dc9357SAndroid Build Coastguard Worker       if (getRootProps)
868*f6dc9357SAndroid Build Coastguard Worker       {
869*f6dc9357SAndroid Build Coastguard Worker         RINOK(getRootProps->GetRootProp(kpidAttrib, &prop))
870*f6dc9357SAndroid Build Coastguard Worker         if (prop.vt == VT_UI4)
871*f6dc9357SAndroid Build Coastguard Worker           rootItem.Attrib = prop.ulVal;
872*f6dc9357SAndroid Build Coastguard Worker         else if (prop.vt != VT_EMPTY)
873*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
874*f6dc9357SAndroid Build Coastguard Worker       }
875*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt == VT_EMPTY && thisGetRoot)
876*f6dc9357SAndroid Build Coastguard Worker       {
877*f6dc9357SAndroid Build Coastguard Worker         RINOK(GetRootProp(kpidAttrib, &prop))
878*f6dc9357SAndroid Build Coastguard Worker         if (prop.vt == VT_UI4)
879*f6dc9357SAndroid Build Coastguard Worker           rootItem.Attrib = prop.ulVal;
880*f6dc9357SAndroid Build Coastguard Worker         else if (prop.vt != VT_EMPTY)
881*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
882*f6dc9357SAndroid Build Coastguard Worker       }
883*f6dc9357SAndroid Build Coastguard Worker       rootItem.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
884*f6dc9357SAndroid Build Coastguard Worker     }
885*f6dc9357SAndroid Build Coastguard Worker 
886*f6dc9357SAndroid Build Coastguard Worker     AddTrees(trees, db.MetaItems, ri, defaultImageIndex);
887*f6dc9357SAndroid Build Coastguard Worker     db.MetaItems[trees[defaultImageIndex].Dirs[0].MetaIndex] = rootItem;
888*f6dc9357SAndroid Build Coastguard Worker   }
889*f6dc9357SAndroid Build Coastguard Worker 
890*f6dc9357SAndroid Build Coastguard Worker   // ---------- Request Metadata for changed items ----------
891*f6dc9357SAndroid Build Coastguard Worker 
892*f6dc9357SAndroid Build Coastguard Worker   UString fileName;
893*f6dc9357SAndroid Build Coastguard Worker 
894*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
895*f6dc9357SAndroid Build Coastguard Worker   {
896*f6dc9357SAndroid Build Coastguard Worker     CUpdateItem ui;
897*f6dc9357SAndroid Build Coastguard Worker     UInt32 indexInArchive;
898*f6dc9357SAndroid Build Coastguard Worker     Int32 newData, newProps;
899*f6dc9357SAndroid Build Coastguard Worker     RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive))
900*f6dc9357SAndroid Build Coastguard Worker 
901*f6dc9357SAndroid Build Coastguard Worker     if (newData == 0 || newProps == 0)
902*f6dc9357SAndroid Build Coastguard Worker     {
903*f6dc9357SAndroid Build Coastguard Worker       if (indexInArchive >= _db.SortedItems.Size())
904*f6dc9357SAndroid Build Coastguard Worker         continue;
905*f6dc9357SAndroid Build Coastguard Worker 
906*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = _db.Items[_db.SortedItems[indexInArchive]];
907*f6dc9357SAndroid Build Coastguard Worker 
908*f6dc9357SAndroid Build Coastguard Worker       if (item.ImageIndex >= 0)
909*f6dc9357SAndroid Build Coastguard Worker       {
910*f6dc9357SAndroid Build Coastguard Worker         if (!isChangedImage[item.ImageIndex])
911*f6dc9357SAndroid Build Coastguard Worker         {
912*f6dc9357SAndroid Build Coastguard Worker           if (newData == 0 && newProps == 0)
913*f6dc9357SAndroid Build Coastguard Worker             continue;
914*f6dc9357SAndroid Build Coastguard Worker           return E_FAIL;
915*f6dc9357SAndroid Build Coastguard Worker         }
916*f6dc9357SAndroid Build Coastguard Worker       }
917*f6dc9357SAndroid Build Coastguard Worker       else
918*f6dc9357SAndroid Build Coastguard Worker       {
919*f6dc9357SAndroid Build Coastguard Worker         // if deleted item was not renamed, we just skip it
920*f6dc9357SAndroid Build Coastguard Worker         if (newProps == 0)
921*f6dc9357SAndroid Build Coastguard Worker           continue;
922*f6dc9357SAndroid Build Coastguard Worker         if (item.StreamIndex >= 0)
923*f6dc9357SAndroid Build Coastguard Worker         {
924*f6dc9357SAndroid Build Coastguard Worker           // we don't support property change for SolidBig streams
925*f6dc9357SAndroid Build Coastguard Worker           if (_db.DataStreams[item.StreamIndex].Resource.IsSolidBig())
926*f6dc9357SAndroid Build Coastguard Worker             return E_NOTIMPL;
927*f6dc9357SAndroid Build Coastguard Worker         }
928*f6dc9357SAndroid Build Coastguard Worker       }
929*f6dc9357SAndroid Build Coastguard Worker 
930*f6dc9357SAndroid Build Coastguard Worker       if (newData == 0)
931*f6dc9357SAndroid Build Coastguard Worker         ui.InArcIndex = (Int32)indexInArchive;
932*f6dc9357SAndroid Build Coastguard Worker     }
933*f6dc9357SAndroid Build Coastguard Worker 
934*f6dc9357SAndroid Build Coastguard Worker     // we set arcIndex only if we must use old props
935*f6dc9357SAndroid Build Coastguard Worker     const Int32 arcIndex = (newProps ? -1 : (Int32)indexInArchive);
936*f6dc9357SAndroid Build Coastguard Worker 
937*f6dc9357SAndroid Build Coastguard Worker     bool isDir = false;
938*f6dc9357SAndroid Build Coastguard Worker     {
939*f6dc9357SAndroid Build Coastguard Worker       NCOM::CPropVariant prop;
940*f6dc9357SAndroid Build Coastguard Worker       RINOK(GetOutProperty(callback, i, arcIndex, kpidIsDir, &prop))
941*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt == VT_BOOL)
942*f6dc9357SAndroid Build Coastguard Worker         isDir = (prop.boolVal != VARIANT_FALSE);
943*f6dc9357SAndroid Build Coastguard Worker       else if (prop.vt != VT_EMPTY)
944*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
945*f6dc9357SAndroid Build Coastguard Worker     }
946*f6dc9357SAndroid Build Coastguard Worker 
947*f6dc9357SAndroid Build Coastguard Worker     bool isAltStream = false;
948*f6dc9357SAndroid Build Coastguard Worker     {
949*f6dc9357SAndroid Build Coastguard Worker       NCOM::CPropVariant prop;
950*f6dc9357SAndroid Build Coastguard Worker       RINOK(GetOutProperty(callback, i, arcIndex, kpidIsAltStream, &prop))
951*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt == VT_BOOL)
952*f6dc9357SAndroid Build Coastguard Worker         isAltStream = (prop.boolVal != VARIANT_FALSE);
953*f6dc9357SAndroid Build Coastguard Worker       else if (prop.vt != VT_EMPTY)
954*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
955*f6dc9357SAndroid Build Coastguard Worker     }
956*f6dc9357SAndroid Build Coastguard Worker 
957*f6dc9357SAndroid Build Coastguard Worker     if (isDir && isAltStream)
958*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
959*f6dc9357SAndroid Build Coastguard Worker 
960*f6dc9357SAndroid Build Coastguard Worker     UInt64 size = 0;
961*f6dc9357SAndroid Build Coastguard Worker     UInt64 iNode = 0;
962*f6dc9357SAndroid Build Coastguard Worker 
963*f6dc9357SAndroid Build Coastguard Worker     if (!isDir)
964*f6dc9357SAndroid Build Coastguard Worker     {
965*f6dc9357SAndroid Build Coastguard Worker       if (!newData)
966*f6dc9357SAndroid Build Coastguard Worker       {
967*f6dc9357SAndroid Build Coastguard Worker         NCOM::CPropVariant prop;
968*f6dc9357SAndroid Build Coastguard Worker         GetProperty(indexInArchive, kpidINode, &prop);
969*f6dc9357SAndroid Build Coastguard Worker         if (prop.vt == VT_UI8)
970*f6dc9357SAndroid Build Coastguard Worker           iNode = prop.uhVal.QuadPart;
971*f6dc9357SAndroid Build Coastguard Worker       }
972*f6dc9357SAndroid Build Coastguard Worker 
973*f6dc9357SAndroid Build Coastguard Worker       NCOM::CPropVariant prop;
974*f6dc9357SAndroid Build Coastguard Worker 
975*f6dc9357SAndroid Build Coastguard Worker       if (newData)
976*f6dc9357SAndroid Build Coastguard Worker       {
977*f6dc9357SAndroid Build Coastguard Worker         RINOK(callback->GetProperty(i, kpidSize, &prop))
978*f6dc9357SAndroid Build Coastguard Worker       }
979*f6dc9357SAndroid Build Coastguard Worker       else
980*f6dc9357SAndroid Build Coastguard Worker       {
981*f6dc9357SAndroid Build Coastguard Worker         RINOK(GetProperty(indexInArchive, kpidSize, &prop))
982*f6dc9357SAndroid Build Coastguard Worker       }
983*f6dc9357SAndroid Build Coastguard Worker 
984*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt == VT_UI8)
985*f6dc9357SAndroid Build Coastguard Worker         size = prop.uhVal.QuadPart;
986*f6dc9357SAndroid Build Coastguard Worker       else if (prop.vt != VT_EMPTY)
987*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
988*f6dc9357SAndroid Build Coastguard Worker     }
989*f6dc9357SAndroid Build Coastguard Worker 
990*f6dc9357SAndroid Build Coastguard Worker     {
991*f6dc9357SAndroid Build Coastguard Worker       NCOM::CPropVariant propPath;
992*f6dc9357SAndroid Build Coastguard Worker       const wchar_t *path = NULL;
993*f6dc9357SAndroid Build Coastguard Worker       RINOK(GetOutProperty(callback, i, arcIndex, kpidPath, &propPath))
994*f6dc9357SAndroid Build Coastguard Worker       if (propPath.vt == VT_BSTR)
995*f6dc9357SAndroid Build Coastguard Worker         path = propPath.bstrVal;
996*f6dc9357SAndroid Build Coastguard Worker       else if (propPath.vt != VT_EMPTY)
997*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
998*f6dc9357SAndroid Build Coastguard Worker 
999*f6dc9357SAndroid Build Coastguard Worker     if (!path)
1000*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
1001*f6dc9357SAndroid Build Coastguard Worker 
1002*f6dc9357SAndroid Build Coastguard Worker     CDir *curItem = NULL;
1003*f6dc9357SAndroid Build Coastguard Worker     bool isRootImageDir = false;
1004*f6dc9357SAndroid Build Coastguard Worker     fileName.Empty();
1005*f6dc9357SAndroid Build Coastguard Worker 
1006*f6dc9357SAndroid Build Coastguard Worker     int imageIndex;
1007*f6dc9357SAndroid Build Coastguard Worker 
1008*f6dc9357SAndroid Build Coastguard Worker     if (!showImageNumber)
1009*f6dc9357SAndroid Build Coastguard Worker     {
1010*f6dc9357SAndroid Build Coastguard Worker       imageIndex = defaultImageIndex;
1011*f6dc9357SAndroid Build Coastguard Worker       AddTrees(trees, db.MetaItems, ri, imageIndex);
1012*f6dc9357SAndroid Build Coastguard Worker       curItem = &trees[imageIndex].Dirs[0];
1013*f6dc9357SAndroid Build Coastguard Worker     }
1014*f6dc9357SAndroid Build Coastguard Worker     else
1015*f6dc9357SAndroid Build Coastguard Worker     {
1016*f6dc9357SAndroid Build Coastguard Worker       const wchar_t *end;
1017*f6dc9357SAndroid Build Coastguard Worker       UInt64 val = ConvertStringToUInt64(path, &end);
1018*f6dc9357SAndroid Build Coastguard Worker       if (end == path)
1019*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
1020*f6dc9357SAndroid Build Coastguard Worker       if (val == 0 || val > kNumImagesMaxUpdate)
1021*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
1022*f6dc9357SAndroid Build Coastguard Worker 
1023*f6dc9357SAndroid Build Coastguard Worker       imageIndex = (int)val - 1;
1024*f6dc9357SAndroid Build Coastguard Worker       if (imageIndex < (int)isChangedImage.Size())
1025*f6dc9357SAndroid Build Coastguard Worker        if (!isChangedImage[imageIndex])
1026*f6dc9357SAndroid Build Coastguard Worker           return E_FAIL;
1027*f6dc9357SAndroid Build Coastguard Worker 
1028*f6dc9357SAndroid Build Coastguard Worker       AddTrees(trees, db.MetaItems, ri, imageIndex);
1029*f6dc9357SAndroid Build Coastguard Worker       curItem = &trees[imageIndex].Dirs[0];
1030*f6dc9357SAndroid Build Coastguard Worker       wchar_t c = *end;
1031*f6dc9357SAndroid Build Coastguard Worker 
1032*f6dc9357SAndroid Build Coastguard Worker       if (c == 0)
1033*f6dc9357SAndroid Build Coastguard Worker       {
1034*f6dc9357SAndroid Build Coastguard Worker         if (!isDir || isAltStream)
1035*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1036*f6dc9357SAndroid Build Coastguard Worker         ui.MetaIndex = curItem->MetaIndex;
1037*f6dc9357SAndroid Build Coastguard Worker         isRootImageDir = true;
1038*f6dc9357SAndroid Build Coastguard Worker       }
1039*f6dc9357SAndroid Build Coastguard Worker       else if (c == ':')
1040*f6dc9357SAndroid Build Coastguard Worker       {
1041*f6dc9357SAndroid Build Coastguard Worker         if (isDir || !isAltStream)
1042*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1043*f6dc9357SAndroid Build Coastguard Worker         ui.MetaIndex = curItem->MetaIndex;
1044*f6dc9357SAndroid Build Coastguard Worker         CAltStream ss;
1045*f6dc9357SAndroid Build Coastguard Worker         ss.Size = size;
1046*f6dc9357SAndroid Build Coastguard Worker         ss.Name = end + 1;
1047*f6dc9357SAndroid Build Coastguard Worker         ss.UpdateIndex = (int)db.UpdateItems.Size();
1048*f6dc9357SAndroid Build Coastguard Worker         ui.AltStreamIndex = (int)db.MetaItems[ui.MetaIndex].AltStreams.Add(ss);
1049*f6dc9357SAndroid Build Coastguard Worker       }
1050*f6dc9357SAndroid Build Coastguard Worker       else if (c == WCHAR_PATH_SEPARATOR || c == L'/')
1051*f6dc9357SAndroid Build Coastguard Worker       {
1052*f6dc9357SAndroid Build Coastguard Worker         path = end + 1;
1053*f6dc9357SAndroid Build Coastguard Worker         if (*path == 0)
1054*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1055*f6dc9357SAndroid Build Coastguard Worker       }
1056*f6dc9357SAndroid Build Coastguard Worker       else
1057*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
1058*f6dc9357SAndroid Build Coastguard Worker     }
1059*f6dc9357SAndroid Build Coastguard Worker 
1060*f6dc9357SAndroid Build Coastguard Worker     if (ui.MetaIndex < 0)
1061*f6dc9357SAndroid Build Coastguard Worker     {
1062*f6dc9357SAndroid Build Coastguard Worker       for (;;)
1063*f6dc9357SAndroid Build Coastguard Worker       {
1064*f6dc9357SAndroid Build Coastguard Worker         const wchar_t c = *path++;
1065*f6dc9357SAndroid Build Coastguard Worker         if (c == 0)
1066*f6dc9357SAndroid Build Coastguard Worker           break;
1067*f6dc9357SAndroid Build Coastguard Worker         if (c == WCHAR_PATH_SEPARATOR || c == L'/')
1068*f6dc9357SAndroid Build Coastguard Worker         {
1069*f6dc9357SAndroid Build Coastguard Worker           unsigned indexOfDir;
1070*f6dc9357SAndroid Build Coastguard Worker           if (!curItem->FindDir(db.MetaItems, fileName, indexOfDir))
1071*f6dc9357SAndroid Build Coastguard Worker           {
1072*f6dc9357SAndroid Build Coastguard Worker             CDir &dir = curItem->Dirs.InsertNew(indexOfDir);
1073*f6dc9357SAndroid Build Coastguard Worker             dir.MetaIndex = (int)db.MetaItems.Add(ri);
1074*f6dc9357SAndroid Build Coastguard Worker             db.MetaItems.Back().Name = fileName;
1075*f6dc9357SAndroid Build Coastguard Worker           }
1076*f6dc9357SAndroid Build Coastguard Worker           curItem = &curItem->Dirs[indexOfDir];
1077*f6dc9357SAndroid Build Coastguard Worker           fileName.Empty();
1078*f6dc9357SAndroid Build Coastguard Worker         }
1079*f6dc9357SAndroid Build Coastguard Worker         else
1080*f6dc9357SAndroid Build Coastguard Worker         {
1081*f6dc9357SAndroid Build Coastguard Worker           /*
1082*f6dc9357SAndroid Build Coastguard Worker           #if WCHAR_MAX > 0xffff
1083*f6dc9357SAndroid Build Coastguard Worker           if (c >= 0x10000)
1084*f6dc9357SAndroid Build Coastguard Worker           {
1085*f6dc9357SAndroid Build Coastguard Worker             c -= 0x10000;
1086*f6dc9357SAndroid Build Coastguard Worker 
1087*f6dc9357SAndroid Build Coastguard Worker             if (c < (1 << 20))
1088*f6dc9357SAndroid Build Coastguard Worker             {
1089*f6dc9357SAndroid Build Coastguard Worker               wchar_t c0 = 0xd800 + ((c >> 10) & 0x3FF);
1090*f6dc9357SAndroid Build Coastguard Worker               fileName += c0;
1091*f6dc9357SAndroid Build Coastguard Worker               c = 0xdc00 + (c & 0x3FF);
1092*f6dc9357SAndroid Build Coastguard Worker             }
1093*f6dc9357SAndroid Build Coastguard Worker             else
1094*f6dc9357SAndroid Build Coastguard Worker               c = '_'; // we change character unsupported by UTF16
1095*f6dc9357SAndroid Build Coastguard Worker           }
1096*f6dc9357SAndroid Build Coastguard Worker           #endif
1097*f6dc9357SAndroid Build Coastguard Worker           */
1098*f6dc9357SAndroid Build Coastguard Worker 
1099*f6dc9357SAndroid Build Coastguard Worker           fileName += c;
1100*f6dc9357SAndroid Build Coastguard Worker         }
1101*f6dc9357SAndroid Build Coastguard Worker       }
1102*f6dc9357SAndroid Build Coastguard Worker 
1103*f6dc9357SAndroid Build Coastguard Worker       if (isAltStream)
1104*f6dc9357SAndroid Build Coastguard Worker       {
1105*f6dc9357SAndroid Build Coastguard Worker         int colonPos = fileName.Find(L':');
1106*f6dc9357SAndroid Build Coastguard Worker         if (colonPos < 0)
1107*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1108*f6dc9357SAndroid Build Coastguard Worker 
1109*f6dc9357SAndroid Build Coastguard Worker         // we want to support cases of c::substream, where c: is drive name
1110*f6dc9357SAndroid Build Coastguard Worker         if (colonPos == 1 && fileName[2] == L':' && IS_LETTER_CHAR(fileName[0]))
1111*f6dc9357SAndroid Build Coastguard Worker           colonPos = 2;
1112*f6dc9357SAndroid Build Coastguard Worker         const UString mainName = fileName.Left((unsigned)colonPos);
1113*f6dc9357SAndroid Build Coastguard Worker         unsigned indexOfDir;
1114*f6dc9357SAndroid Build Coastguard Worker 
1115*f6dc9357SAndroid Build Coastguard Worker         if (mainName.IsEmpty())
1116*f6dc9357SAndroid Build Coastguard Worker           ui.MetaIndex = curItem->MetaIndex;
1117*f6dc9357SAndroid Build Coastguard Worker         else if (curItem->FindDir(db.MetaItems, mainName, indexOfDir))
1118*f6dc9357SAndroid Build Coastguard Worker           ui.MetaIndex = curItem->Dirs[indexOfDir].MetaIndex;
1119*f6dc9357SAndroid Build Coastguard Worker         else
1120*f6dc9357SAndroid Build Coastguard Worker         {
1121*f6dc9357SAndroid Build Coastguard Worker           for (int j = (int)curItem->Files.Size() - 1; j >= 0; j--)
1122*f6dc9357SAndroid Build Coastguard Worker           {
1123*f6dc9357SAndroid Build Coastguard Worker             const unsigned metaIndex = curItem->Files[j];
1124*f6dc9357SAndroid Build Coastguard Worker             const CMetaItem &mi = db.MetaItems[metaIndex];
1125*f6dc9357SAndroid Build Coastguard Worker             if (CompareFileNames(mainName, mi.Name) == 0)
1126*f6dc9357SAndroid Build Coastguard Worker             {
1127*f6dc9357SAndroid Build Coastguard Worker               ui.MetaIndex = (int)metaIndex;
1128*f6dc9357SAndroid Build Coastguard Worker               break;
1129*f6dc9357SAndroid Build Coastguard Worker             }
1130*f6dc9357SAndroid Build Coastguard Worker           }
1131*f6dc9357SAndroid Build Coastguard Worker         }
1132*f6dc9357SAndroid Build Coastguard Worker 
1133*f6dc9357SAndroid Build Coastguard Worker         if (ui.MetaIndex >= 0)
1134*f6dc9357SAndroid Build Coastguard Worker         {
1135*f6dc9357SAndroid Build Coastguard Worker           CAltStream ss;
1136*f6dc9357SAndroid Build Coastguard Worker           ss.Size = size;
1137*f6dc9357SAndroid Build Coastguard Worker           ss.Name = fileName.Ptr(colonPos + 1);
1138*f6dc9357SAndroid Build Coastguard Worker           ss.UpdateIndex = (int)db.UpdateItems.Size();
1139*f6dc9357SAndroid Build Coastguard Worker           ui.AltStreamIndex = (int)db.MetaItems[ui.MetaIndex].AltStreams.Add(ss);
1140*f6dc9357SAndroid Build Coastguard Worker         }
1141*f6dc9357SAndroid Build Coastguard Worker       }
1142*f6dc9357SAndroid Build Coastguard Worker     }
1143*f6dc9357SAndroid Build Coastguard Worker 
1144*f6dc9357SAndroid Build Coastguard Worker 
1145*f6dc9357SAndroid Build Coastguard Worker     if (ui.MetaIndex < 0 || isRootImageDir)
1146*f6dc9357SAndroid Build Coastguard Worker     {
1147*f6dc9357SAndroid Build Coastguard Worker       if (!isRootImageDir)
1148*f6dc9357SAndroid Build Coastguard Worker       {
1149*f6dc9357SAndroid Build Coastguard Worker         ui.MetaIndex = (int)db.MetaItems.Size();
1150*f6dc9357SAndroid Build Coastguard Worker         db.MetaItems.AddNew();
1151*f6dc9357SAndroid Build Coastguard Worker       }
1152*f6dc9357SAndroid Build Coastguard Worker 
1153*f6dc9357SAndroid Build Coastguard Worker       CMetaItem &mi = db.MetaItems[ui.MetaIndex];
1154*f6dc9357SAndroid Build Coastguard Worker       mi.Size = size;
1155*f6dc9357SAndroid Build Coastguard Worker       mi.IsDir = isDir;
1156*f6dc9357SAndroid Build Coastguard Worker       mi.Name = fileName;
1157*f6dc9357SAndroid Build Coastguard Worker       mi.UpdateIndex = (int)db.UpdateItems.Size();
1158*f6dc9357SAndroid Build Coastguard Worker       {
1159*f6dc9357SAndroid Build Coastguard Worker         NCOM::CPropVariant prop;
1160*f6dc9357SAndroid Build Coastguard Worker         RINOK(GetOutProperty(callback, i, arcIndex, kpidAttrib, &prop))
1161*f6dc9357SAndroid Build Coastguard Worker         if (prop.vt == VT_EMPTY)
1162*f6dc9357SAndroid Build Coastguard Worker           mi.Attrib = 0;
1163*f6dc9357SAndroid Build Coastguard Worker         else if (prop.vt == VT_UI4)
1164*f6dc9357SAndroid Build Coastguard Worker           mi.Attrib = prop.ulVal;
1165*f6dc9357SAndroid Build Coastguard Worker         else
1166*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1167*f6dc9357SAndroid Build Coastguard Worker         if (isDir)
1168*f6dc9357SAndroid Build Coastguard Worker           mi.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
1169*f6dc9357SAndroid Build Coastguard Worker       }
1170*f6dc9357SAndroid Build Coastguard Worker 
1171*f6dc9357SAndroid Build Coastguard Worker       if (arcIndex != -1 || _timeOptions.Write_CTime.Val)
1172*f6dc9357SAndroid Build Coastguard Worker         RINOK(GetTime(callback, i, arcIndex, kpidCTime, mi.CTime))
1173*f6dc9357SAndroid Build Coastguard Worker       if (arcIndex != -1 || _timeOptions.Write_ATime.Val)
1174*f6dc9357SAndroid Build Coastguard Worker         RINOK(GetTime(callback, i, arcIndex, kpidATime, mi.ATime))
1175*f6dc9357SAndroid Build Coastguard Worker       if (arcIndex != -1 || _timeOptions.Write_MTime.Val)
1176*f6dc9357SAndroid Build Coastguard Worker         RINOK(GetTime(callback, i, arcIndex, kpidMTime, mi.MTime))
1177*f6dc9357SAndroid Build Coastguard Worker 
1178*f6dc9357SAndroid Build Coastguard Worker       {
1179*f6dc9357SAndroid Build Coastguard Worker         NCOM::CPropVariant prop;
1180*f6dc9357SAndroid Build Coastguard Worker         RINOK(GetOutProperty(callback, i, arcIndex, kpidShortName, &prop))
1181*f6dc9357SAndroid Build Coastguard Worker         if (prop.vt == VT_BSTR)
1182*f6dc9357SAndroid Build Coastguard Worker           mi.ShortName.SetFromBstr(prop.bstrVal);
1183*f6dc9357SAndroid Build Coastguard Worker         else if (prop.vt != VT_EMPTY)
1184*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1185*f6dc9357SAndroid Build Coastguard Worker       }
1186*f6dc9357SAndroid Build Coastguard Worker 
1187*f6dc9357SAndroid Build Coastguard Worker       while (imageIndex >= (int)secureBlocks.Size())
1188*f6dc9357SAndroid Build Coastguard Worker         secureBlocks.AddNew();
1189*f6dc9357SAndroid Build Coastguard Worker 
1190*f6dc9357SAndroid Build Coastguard Worker       if (!isAltStream && (getRawProps || arcIndex >= 0))
1191*f6dc9357SAndroid Build Coastguard Worker       {
1192*f6dc9357SAndroid Build Coastguard Worker         CUniqBlocks &secUniqBlocks = secureBlocks[imageIndex];
1193*f6dc9357SAndroid Build Coastguard Worker         const void *data;
1194*f6dc9357SAndroid Build Coastguard Worker         UInt32 dataSize;
1195*f6dc9357SAndroid Build Coastguard Worker         UInt32 propType;
1196*f6dc9357SAndroid Build Coastguard Worker 
1197*f6dc9357SAndroid Build Coastguard Worker         data = NULL;
1198*f6dc9357SAndroid Build Coastguard Worker         dataSize = 0;
1199*f6dc9357SAndroid Build Coastguard Worker         propType = 0;
1200*f6dc9357SAndroid Build Coastguard Worker 
1201*f6dc9357SAndroid Build Coastguard Worker         if (arcIndex >= 0)
1202*f6dc9357SAndroid Build Coastguard Worker         {
1203*f6dc9357SAndroid Build Coastguard Worker           GetRawProp((UInt32)arcIndex, kpidNtSecure, &data, &dataSize, &propType);
1204*f6dc9357SAndroid Build Coastguard Worker         }
1205*f6dc9357SAndroid Build Coastguard Worker         else
1206*f6dc9357SAndroid Build Coastguard Worker         {
1207*f6dc9357SAndroid Build Coastguard Worker           getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
1208*f6dc9357SAndroid Build Coastguard Worker         }
1209*f6dc9357SAndroid Build Coastguard Worker 
1210*f6dc9357SAndroid Build Coastguard Worker         if (dataSize != 0)
1211*f6dc9357SAndroid Build Coastguard Worker         {
1212*f6dc9357SAndroid Build Coastguard Worker           if (propType != NPropDataType::kRaw)
1213*f6dc9357SAndroid Build Coastguard Worker             return E_FAIL;
1214*f6dc9357SAndroid Build Coastguard Worker           mi.SecurityId = (int)secUniqBlocks.AddUniq((const Byte *)data, dataSize);
1215*f6dc9357SAndroid Build Coastguard Worker         }
1216*f6dc9357SAndroid Build Coastguard Worker 
1217*f6dc9357SAndroid Build Coastguard Worker         data = NULL;
1218*f6dc9357SAndroid Build Coastguard Worker         dataSize = 0;
1219*f6dc9357SAndroid Build Coastguard Worker         propType = 0;
1220*f6dc9357SAndroid Build Coastguard Worker 
1221*f6dc9357SAndroid Build Coastguard Worker         if (arcIndex >= 0)
1222*f6dc9357SAndroid Build Coastguard Worker         {
1223*f6dc9357SAndroid Build Coastguard Worker           GetRawProp((UInt32)arcIndex, kpidNtReparse, &data, &dataSize, &propType);
1224*f6dc9357SAndroid Build Coastguard Worker         }
1225*f6dc9357SAndroid Build Coastguard Worker         else
1226*f6dc9357SAndroid Build Coastguard Worker         {
1227*f6dc9357SAndroid Build Coastguard Worker           getRawProps->GetRawProp(i, kpidNtReparse, &data, &dataSize, &propType);
1228*f6dc9357SAndroid Build Coastguard Worker         }
1229*f6dc9357SAndroid Build Coastguard Worker 
1230*f6dc9357SAndroid Build Coastguard Worker         if (dataSize != 0)
1231*f6dc9357SAndroid Build Coastguard Worker         {
1232*f6dc9357SAndroid Build Coastguard Worker           if (propType != NPropDataType::kRaw)
1233*f6dc9357SAndroid Build Coastguard Worker             return E_FAIL;
1234*f6dc9357SAndroid Build Coastguard Worker           mi.Reparse.CopyFrom((const Byte *)data, dataSize);
1235*f6dc9357SAndroid Build Coastguard Worker         }
1236*f6dc9357SAndroid Build Coastguard Worker       }
1237*f6dc9357SAndroid Build Coastguard Worker 
1238*f6dc9357SAndroid Build Coastguard Worker       if (!isRootImageDir)
1239*f6dc9357SAndroid Build Coastguard Worker       {
1240*f6dc9357SAndroid Build Coastguard Worker         if (isDir)
1241*f6dc9357SAndroid Build Coastguard Worker         {
1242*f6dc9357SAndroid Build Coastguard Worker           unsigned indexOfDir;
1243*f6dc9357SAndroid Build Coastguard Worker           if (curItem->FindDir(db.MetaItems, fileName, indexOfDir))
1244*f6dc9357SAndroid Build Coastguard Worker             curItem->Dirs[indexOfDir].MetaIndex = ui.MetaIndex;
1245*f6dc9357SAndroid Build Coastguard Worker           else
1246*f6dc9357SAndroid Build Coastguard Worker             curItem->Dirs.InsertNew(indexOfDir).MetaIndex = ui.MetaIndex;
1247*f6dc9357SAndroid Build Coastguard Worker         }
1248*f6dc9357SAndroid Build Coastguard Worker         else
1249*f6dc9357SAndroid Build Coastguard Worker           curItem->Files.Add((unsigned)ui.MetaIndex);
1250*f6dc9357SAndroid Build Coastguard Worker       }
1251*f6dc9357SAndroid Build Coastguard Worker     }
1252*f6dc9357SAndroid Build Coastguard Worker 
1253*f6dc9357SAndroid Build Coastguard Worker     }
1254*f6dc9357SAndroid Build Coastguard Worker 
1255*f6dc9357SAndroid Build Coastguard Worker     if (iNode != 0 && ui.MetaIndex >= 0 && ui.AltStreamIndex < 0)
1256*f6dc9357SAndroid Build Coastguard Worker       db.MetaItems[ui.MetaIndex].FileID = iNode;
1257*f6dc9357SAndroid Build Coastguard Worker 
1258*f6dc9357SAndroid Build Coastguard Worker     ui.CallbackIndex = i;
1259*f6dc9357SAndroid Build Coastguard Worker     db.UpdateItems.Add(ui);
1260*f6dc9357SAndroid Build Coastguard Worker   }
1261*f6dc9357SAndroid Build Coastguard Worker 
1262*f6dc9357SAndroid Build Coastguard Worker   unsigned numNewImages = trees.Size();
1263*f6dc9357SAndroid Build Coastguard Worker   for (i = numNewImages; i < isChangedImage.Size(); i++)
1264*f6dc9357SAndroid Build Coastguard Worker     if (!isChangedImage[i])
1265*f6dc9357SAndroid Build Coastguard Worker       numNewImages = i + 1;
1266*f6dc9357SAndroid Build Coastguard Worker 
1267*f6dc9357SAndroid Build Coastguard Worker   AddTrees(trees, db.MetaItems, ri, (int)numNewImages - 1);
1268*f6dc9357SAndroid Build Coastguard Worker 
1269*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < trees.Size(); i++)
1270*f6dc9357SAndroid Build Coastguard Worker     if (i >= isChangedImage.Size() || isChangedImage[i])
1271*f6dc9357SAndroid Build Coastguard Worker       db.WriteOrderList(trees[i]);
1272*f6dc9357SAndroid Build Coastguard Worker 
1273*f6dc9357SAndroid Build Coastguard Worker 
1274*f6dc9357SAndroid Build Coastguard Worker   UInt64 complexity = 0;
1275*f6dc9357SAndroid Build Coastguard Worker 
1276*f6dc9357SAndroid Build Coastguard Worker   unsigned numDataStreams = _db.DataStreams.Size();
1277*f6dc9357SAndroid Build Coastguard Worker   CUIntArr streamsRefs(numDataStreams);
1278*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numDataStreams; i++)
1279*f6dc9357SAndroid Build Coastguard Worker     streamsRefs[i] = 0;
1280*f6dc9357SAndroid Build Coastguard Worker 
1281*f6dc9357SAndroid Build Coastguard Worker   // ---------- Calculate Streams Refs Counts in unchanged images
1282*f6dc9357SAndroid Build Coastguard Worker 
1283*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _db.Images.Size(); i++)
1284*f6dc9357SAndroid Build Coastguard Worker   {
1285*f6dc9357SAndroid Build Coastguard Worker     if (isChangedImage[i])
1286*f6dc9357SAndroid Build Coastguard Worker       continue;
1287*f6dc9357SAndroid Build Coastguard Worker     complexity += _db.MetaStreams[i].Resource.PackSize;
1288*f6dc9357SAndroid Build Coastguard Worker     const CImage &image = _db.Images[i];
1289*f6dc9357SAndroid Build Coastguard Worker     unsigned endItem = image.StartItem + image.NumItems;
1290*f6dc9357SAndroid Build Coastguard Worker     for (unsigned k = image.StartItem; k < endItem; k++)
1291*f6dc9357SAndroid Build Coastguard Worker     {
1292*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = _db.Items[k];
1293*f6dc9357SAndroid Build Coastguard Worker       if (item.StreamIndex >= 0)
1294*f6dc9357SAndroid Build Coastguard Worker         streamsRefs[(unsigned)item.StreamIndex]++;
1295*f6dc9357SAndroid Build Coastguard Worker     }
1296*f6dc9357SAndroid Build Coastguard Worker   }
1297*f6dc9357SAndroid Build Coastguard Worker 
1298*f6dc9357SAndroid Build Coastguard Worker 
1299*f6dc9357SAndroid Build Coastguard Worker   // ---------- Update Streams Refs Counts in changed images
1300*f6dc9357SAndroid Build Coastguard Worker 
1301*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < db.UpdateIndexes.Size(); i++)
1302*f6dc9357SAndroid Build Coastguard Worker   {
1303*f6dc9357SAndroid Build Coastguard Worker     const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]];
1304*f6dc9357SAndroid Build Coastguard Worker 
1305*f6dc9357SAndroid Build Coastguard Worker     if (ui.InArcIndex >= 0)
1306*f6dc9357SAndroid Build Coastguard Worker     {
1307*f6dc9357SAndroid Build Coastguard Worker       if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size())
1308*f6dc9357SAndroid Build Coastguard Worker         continue;
1309*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]];
1310*f6dc9357SAndroid Build Coastguard Worker       if (item.StreamIndex >= 0)
1311*f6dc9357SAndroid Build Coastguard Worker         streamsRefs[(unsigned)item.StreamIndex]++;
1312*f6dc9357SAndroid Build Coastguard Worker     }
1313*f6dc9357SAndroid Build Coastguard Worker     else
1314*f6dc9357SAndroid Build Coastguard Worker     {
1315*f6dc9357SAndroid Build Coastguard Worker       const CMetaItem &mi = db.MetaItems[ui.MetaIndex];
1316*f6dc9357SAndroid Build Coastguard Worker       UInt64 size;
1317*f6dc9357SAndroid Build Coastguard Worker       if (ui.AltStreamIndex < 0)
1318*f6dc9357SAndroid Build Coastguard Worker         size = mi.Size;
1319*f6dc9357SAndroid Build Coastguard Worker       else
1320*f6dc9357SAndroid Build Coastguard Worker         size = mi.AltStreams[ui.AltStreamIndex].Size;
1321*f6dc9357SAndroid Build Coastguard Worker       complexity += size;
1322*f6dc9357SAndroid Build Coastguard Worker     }
1323*f6dc9357SAndroid Build Coastguard Worker   }
1324*f6dc9357SAndroid Build Coastguard Worker 
1325*f6dc9357SAndroid Build Coastguard Worker   // Clear ref counts for SolidBig streams
1326*f6dc9357SAndroid Build Coastguard Worker 
1327*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _db.DataStreams.Size(); i++)
1328*f6dc9357SAndroid Build Coastguard Worker     if (_db.DataStreams[i].Resource.IsSolidBig())
1329*f6dc9357SAndroid Build Coastguard Worker       streamsRefs[i] = 0;
1330*f6dc9357SAndroid Build Coastguard Worker 
1331*f6dc9357SAndroid Build Coastguard Worker   // Set ref counts for SolidBig streams
1332*f6dc9357SAndroid Build Coastguard Worker 
1333*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _db.DataStreams.Size(); i++)
1334*f6dc9357SAndroid Build Coastguard Worker     if (streamsRefs[i] != 0)
1335*f6dc9357SAndroid Build Coastguard Worker     {
1336*f6dc9357SAndroid Build Coastguard Worker       const CResource &rs = _db.DataStreams[i].Resource;
1337*f6dc9357SAndroid Build Coastguard Worker       if (rs.IsSolidSmall())
1338*f6dc9357SAndroid Build Coastguard Worker         streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] = 1;
1339*f6dc9357SAndroid Build Coastguard Worker     }
1340*f6dc9357SAndroid Build Coastguard Worker 
1341*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _db.DataStreams.Size(); i++)
1342*f6dc9357SAndroid Build Coastguard Worker     if (streamsRefs[i] != 0)
1343*f6dc9357SAndroid Build Coastguard Worker     {
1344*f6dc9357SAndroid Build Coastguard Worker       const CResource &rs = _db.DataStreams[i].Resource;
1345*f6dc9357SAndroid Build Coastguard Worker       if (!rs.IsSolidSmall())
1346*f6dc9357SAndroid Build Coastguard Worker         complexity += rs.PackSize;
1347*f6dc9357SAndroid Build Coastguard Worker     }
1348*f6dc9357SAndroid Build Coastguard Worker 
1349*f6dc9357SAndroid Build Coastguard Worker   RINOK(callback->SetTotal(complexity))
1350*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalComplexity = complexity;
1351*f6dc9357SAndroid Build Coastguard Worker 
1352*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
1353*f6dc9357SAndroid Build Coastguard Worker   lps->Init(callback, true);
1354*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
1355*f6dc9357SAndroid Build Coastguard Worker 
1356*f6dc9357SAndroid Build Coastguard Worker   complexity = 0;
1357*f6dc9357SAndroid Build Coastguard Worker 
1358*f6dc9357SAndroid Build Coastguard Worker   // bool useResourceCompression = false;
1359*f6dc9357SAndroid Build Coastguard Worker   // use useResourceCompression only if CHeader::Flags compression is also set
1360*f6dc9357SAndroid Build Coastguard Worker 
1361*f6dc9357SAndroid Build Coastguard Worker   CHeader header;
1362*f6dc9357SAndroid Build Coastguard Worker   header.SetDefaultFields(false);
1363*f6dc9357SAndroid Build Coastguard Worker 
1364*f6dc9357SAndroid Build Coastguard Worker   if (isUpdate)
1365*f6dc9357SAndroid Build Coastguard Worker   {
1366*f6dc9357SAndroid Build Coastguard Worker     const CHeader &srcHeader = _volumes[1].Header;
1367*f6dc9357SAndroid Build Coastguard Worker     header.Flags = srcHeader.Flags;
1368*f6dc9357SAndroid Build Coastguard Worker     header.Version = srcHeader.Version;
1369*f6dc9357SAndroid Build Coastguard Worker     header.ChunkSize = srcHeader.ChunkSize;
1370*f6dc9357SAndroid Build Coastguard Worker     header.ChunkSizeBits = srcHeader.ChunkSizeBits;
1371*f6dc9357SAndroid Build Coastguard Worker   }
1372*f6dc9357SAndroid Build Coastguard Worker 
1373*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IStreamSetRestriction> setRestriction;
1374*f6dc9357SAndroid Build Coastguard Worker   outSeqStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction);
1375*f6dc9357SAndroid Build Coastguard Worker   if (setRestriction)
1376*f6dc9357SAndroid Build Coastguard Worker     RINOK(setRestriction->SetRestriction(0, kHeaderSizeMax))
1377*f6dc9357SAndroid Build Coastguard Worker 
1378*f6dc9357SAndroid Build Coastguard Worker   {
1379*f6dc9357SAndroid Build Coastguard Worker     Byte buf[kHeaderSizeMax];
1380*f6dc9357SAndroid Build Coastguard Worker     header.WriteTo(buf);
1381*f6dc9357SAndroid Build Coastguard Worker     RINOK(WriteStream(outStream, buf, kHeaderSizeMax))
1382*f6dc9357SAndroid Build Coastguard Worker   }
1383*f6dc9357SAndroid Build Coastguard Worker 
1384*f6dc9357SAndroid Build Coastguard Worker   UInt64 curPos = kHeaderSizeMax;
1385*f6dc9357SAndroid Build Coastguard Worker 
1386*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CInStreamWithSha1> inShaStream;
1387*f6dc9357SAndroid Build Coastguard Worker 
1388*f6dc9357SAndroid Build Coastguard Worker   CLimitedSequentialInStream *inStreamLimitedSpec = NULL;
1389*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> inStreamLimited;
1390*f6dc9357SAndroid Build Coastguard Worker   if (_volumes.Size() == 2)
1391*f6dc9357SAndroid Build Coastguard Worker   {
1392*f6dc9357SAndroid Build Coastguard Worker     inStreamLimitedSpec = new CLimitedSequentialInStream;
1393*f6dc9357SAndroid Build Coastguard Worker     inStreamLimited = inStreamLimitedSpec;
1394*f6dc9357SAndroid Build Coastguard Worker     inStreamLimitedSpec->SetStream(_volumes[1].Stream);
1395*f6dc9357SAndroid Build Coastguard Worker   }
1396*f6dc9357SAndroid Build Coastguard Worker 
1397*f6dc9357SAndroid Build Coastguard Worker 
1398*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CStreamInfo> streams;
1399*f6dc9357SAndroid Build Coastguard Worker   CSortedIndex sortedHashes; // indexes to streams, sorted by SHA1
1400*f6dc9357SAndroid Build Coastguard Worker 
1401*f6dc9357SAndroid Build Coastguard Worker   // ---------- Copy unchanged data streams ----------
1402*f6dc9357SAndroid Build Coastguard Worker 
1403*f6dc9357SAndroid Build Coastguard Worker   UInt64 solidRunOffset = 0;
1404*f6dc9357SAndroid Build Coastguard Worker   UInt64 curSolidSize = 0;
1405*f6dc9357SAndroid Build Coastguard Worker 
1406*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _db.DataStreams.Size(); i++)
1407*f6dc9357SAndroid Build Coastguard Worker   {
1408*f6dc9357SAndroid Build Coastguard Worker     const CStreamInfo &siOld = _db.DataStreams[i];
1409*f6dc9357SAndroid Build Coastguard Worker     const CResource &rs = siOld.Resource;
1410*f6dc9357SAndroid Build Coastguard Worker 
1411*f6dc9357SAndroid Build Coastguard Worker     const unsigned numRefs = streamsRefs[i];
1412*f6dc9357SAndroid Build Coastguard Worker 
1413*f6dc9357SAndroid Build Coastguard Worker     if (numRefs == 0)
1414*f6dc9357SAndroid Build Coastguard Worker     {
1415*f6dc9357SAndroid Build Coastguard Worker       if (!rs.IsSolidSmall())
1416*f6dc9357SAndroid Build Coastguard Worker         continue;
1417*f6dc9357SAndroid Build Coastguard Worker       if (streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] == 0)
1418*f6dc9357SAndroid Build Coastguard Worker         continue;
1419*f6dc9357SAndroid Build Coastguard Worker     }
1420*f6dc9357SAndroid Build Coastguard Worker 
1421*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = lps->OutSize = complexity;
1422*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
1423*f6dc9357SAndroid Build Coastguard Worker 
1424*f6dc9357SAndroid Build Coastguard Worker     const unsigned streamIndex = streams.Size();
1425*f6dc9357SAndroid Build Coastguard Worker     CStreamInfo s;
1426*f6dc9357SAndroid Build Coastguard Worker     s.Resource = rs;
1427*f6dc9357SAndroid Build Coastguard Worker     s.PartNumber = 1;
1428*f6dc9357SAndroid Build Coastguard Worker     s.RefCount = numRefs;
1429*f6dc9357SAndroid Build Coastguard Worker 
1430*f6dc9357SAndroid Build Coastguard Worker     memcpy(s.Hash, siOld.Hash, kHashSize);
1431*f6dc9357SAndroid Build Coastguard Worker 
1432*f6dc9357SAndroid Build Coastguard Worker     if (rs.IsSolid())
1433*f6dc9357SAndroid Build Coastguard Worker     {
1434*f6dc9357SAndroid Build Coastguard Worker       CSolid &ss = _db.Solids[rs.SolidIndex];
1435*f6dc9357SAndroid Build Coastguard Worker       if (rs.IsSolidSmall())
1436*f6dc9357SAndroid Build Coastguard Worker       {
1437*f6dc9357SAndroid Build Coastguard Worker         UInt64 oldOffset = ss.SolidOffset;
1438*f6dc9357SAndroid Build Coastguard Worker         if (rs.Offset < oldOffset)
1439*f6dc9357SAndroid Build Coastguard Worker           return E_FAIL;
1440*f6dc9357SAndroid Build Coastguard Worker         UInt64 relatOffset = rs.Offset - oldOffset;
1441*f6dc9357SAndroid Build Coastguard Worker         s.Resource.Offset = solidRunOffset + relatOffset;
1442*f6dc9357SAndroid Build Coastguard Worker       }
1443*f6dc9357SAndroid Build Coastguard Worker       else
1444*f6dc9357SAndroid Build Coastguard Worker       {
1445*f6dc9357SAndroid Build Coastguard Worker         // IsSolidBig
1446*f6dc9357SAndroid Build Coastguard Worker         solidRunOffset += curSolidSize;
1447*f6dc9357SAndroid Build Coastguard Worker         curSolidSize = ss.UnpackSize;
1448*f6dc9357SAndroid Build Coastguard Worker       }
1449*f6dc9357SAndroid Build Coastguard Worker     }
1450*f6dc9357SAndroid Build Coastguard Worker     else
1451*f6dc9357SAndroid Build Coastguard Worker     {
1452*f6dc9357SAndroid Build Coastguard Worker       solidRunOffset = 0;
1453*f6dc9357SAndroid Build Coastguard Worker       curSolidSize = 0;
1454*f6dc9357SAndroid Build Coastguard Worker     }
1455*f6dc9357SAndroid Build Coastguard Worker 
1456*f6dc9357SAndroid Build Coastguard Worker     if (!rs.IsSolid() || rs.IsSolidSmall())
1457*f6dc9357SAndroid Build Coastguard Worker     {
1458*f6dc9357SAndroid Build Coastguard Worker       const int find = AddUniqHash(streams.ConstData(), sortedHashes, siOld.Hash, (int)streamIndex);
1459*f6dc9357SAndroid Build Coastguard Worker       if (find != -1)
1460*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL; // two streams with same SHA-1
1461*f6dc9357SAndroid Build Coastguard Worker     }
1462*f6dc9357SAndroid Build Coastguard Worker 
1463*f6dc9357SAndroid Build Coastguard Worker     if (!rs.IsSolid() || rs.IsSolidBig())
1464*f6dc9357SAndroid Build Coastguard Worker     {
1465*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(_volumes[siOld.PartNumber].Stream, rs.Offset))
1466*f6dc9357SAndroid Build Coastguard Worker       inStreamLimitedSpec->Init(rs.PackSize);
1467*f6dc9357SAndroid Build Coastguard Worker       RINOK(copyCoder.Interface()->Code(inStreamLimited, outStream, NULL, NULL, lps))
1468*f6dc9357SAndroid Build Coastguard Worker       if (copyCoder->TotalSize != rs.PackSize)
1469*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
1470*f6dc9357SAndroid Build Coastguard Worker       s.Resource.Offset = curPos;
1471*f6dc9357SAndroid Build Coastguard Worker       curPos += rs.PackSize;
1472*f6dc9357SAndroid Build Coastguard Worker       lps->ProgressOffset += rs.PackSize;
1473*f6dc9357SAndroid Build Coastguard Worker     }
1474*f6dc9357SAndroid Build Coastguard Worker 
1475*f6dc9357SAndroid Build Coastguard Worker     streams.Add(s);
1476*f6dc9357SAndroid Build Coastguard Worker   }
1477*f6dc9357SAndroid Build Coastguard Worker 
1478*f6dc9357SAndroid Build Coastguard Worker 
1479*f6dc9357SAndroid Build Coastguard Worker   // ---------- Write new items ----------
1480*f6dc9357SAndroid Build Coastguard Worker 
1481*f6dc9357SAndroid Build Coastguard Worker   CUIntVector hlIndexes; // sorted indexes for hard link items
1482*f6dc9357SAndroid Build Coastguard Worker 
1483*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < db.UpdateIndexes.Size(); i++)
1484*f6dc9357SAndroid Build Coastguard Worker   {
1485*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = lps->OutSize = complexity;
1486*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
1487*f6dc9357SAndroid Build Coastguard Worker     const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]];
1488*f6dc9357SAndroid Build Coastguard Worker     CMetaItem &mi = db.MetaItems[ui.MetaIndex];
1489*f6dc9357SAndroid Build Coastguard Worker     UInt64 size = 0;
1490*f6dc9357SAndroid Build Coastguard Worker 
1491*f6dc9357SAndroid Build Coastguard Worker     if (ui.AltStreamIndex >= 0)
1492*f6dc9357SAndroid Build Coastguard Worker     {
1493*f6dc9357SAndroid Build Coastguard Worker       if (mi.Skip)
1494*f6dc9357SAndroid Build Coastguard Worker         continue;
1495*f6dc9357SAndroid Build Coastguard Worker       size = mi.AltStreams[ui.AltStreamIndex].Size;
1496*f6dc9357SAndroid Build Coastguard Worker     }
1497*f6dc9357SAndroid Build Coastguard Worker     else
1498*f6dc9357SAndroid Build Coastguard Worker     {
1499*f6dc9357SAndroid Build Coastguard Worker       size = mi.Size;
1500*f6dc9357SAndroid Build Coastguard Worker       if (mi.IsDir)
1501*f6dc9357SAndroid Build Coastguard Worker       {
1502*f6dc9357SAndroid Build Coastguard Worker         // we support LINK files here
1503*f6dc9357SAndroid Build Coastguard Worker         if (mi.Reparse.Size() == 0)
1504*f6dc9357SAndroid Build Coastguard Worker           continue;
1505*f6dc9357SAndroid Build Coastguard Worker       }
1506*f6dc9357SAndroid Build Coastguard Worker     }
1507*f6dc9357SAndroid Build Coastguard Worker 
1508*f6dc9357SAndroid Build Coastguard Worker     if (ui.InArcIndex >= 0)
1509*f6dc9357SAndroid Build Coastguard Worker     {
1510*f6dc9357SAndroid Build Coastguard Worker       // data streams with OLD Data were written already
1511*f6dc9357SAndroid Build Coastguard Worker       // we just need to find HashIndex in hashes.
1512*f6dc9357SAndroid Build Coastguard Worker 
1513*f6dc9357SAndroid Build Coastguard Worker       if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size())
1514*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
1515*f6dc9357SAndroid Build Coastguard Worker 
1516*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]];
1517*f6dc9357SAndroid Build Coastguard Worker 
1518*f6dc9357SAndroid Build Coastguard Worker       if (item.StreamIndex < 0)
1519*f6dc9357SAndroid Build Coastguard Worker       {
1520*f6dc9357SAndroid Build Coastguard Worker         if (size == 0)
1521*f6dc9357SAndroid Build Coastguard Worker           continue;
1522*f6dc9357SAndroid Build Coastguard Worker         // if (_db.ItemHasStream(item))
1523*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
1524*f6dc9357SAndroid Build Coastguard Worker       }
1525*f6dc9357SAndroid Build Coastguard Worker 
1526*f6dc9357SAndroid Build Coastguard Worker       // We support empty file (size = 0, but with stream and SHA-1) from old archive
1527*f6dc9357SAndroid Build Coastguard Worker 
1528*f6dc9357SAndroid Build Coastguard Worker       const CStreamInfo &siOld = _db.DataStreams[item.StreamIndex];
1529*f6dc9357SAndroid Build Coastguard Worker 
1530*f6dc9357SAndroid Build Coastguard Worker       const int index = AddUniqHash(streams.ConstData(), sortedHashes, siOld.Hash, -1);
1531*f6dc9357SAndroid Build Coastguard Worker       // we must have written that stream already
1532*f6dc9357SAndroid Build Coastguard Worker       if (index == -1)
1533*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
1534*f6dc9357SAndroid Build Coastguard Worker 
1535*f6dc9357SAndroid Build Coastguard Worker       if (ui.AltStreamIndex < 0)
1536*f6dc9357SAndroid Build Coastguard Worker         mi.HashIndex = index;
1537*f6dc9357SAndroid Build Coastguard Worker       else
1538*f6dc9357SAndroid Build Coastguard Worker         mi.AltStreams[ui.AltStreamIndex].HashIndex = index;
1539*f6dc9357SAndroid Build Coastguard Worker 
1540*f6dc9357SAndroid Build Coastguard Worker       continue;
1541*f6dc9357SAndroid Build Coastguard Worker     }
1542*f6dc9357SAndroid Build Coastguard Worker 
1543*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialInStream> fileInStream;
1544*f6dc9357SAndroid Build Coastguard Worker     HRESULT res = callback->GetStream(ui.CallbackIndex, &fileInStream);
1545*f6dc9357SAndroid Build Coastguard Worker 
1546*f6dc9357SAndroid Build Coastguard Worker     if (res == S_FALSE)
1547*f6dc9357SAndroid Build Coastguard Worker     {
1548*f6dc9357SAndroid Build Coastguard Worker       if (ui.AltStreamIndex >= 0)
1549*f6dc9357SAndroid Build Coastguard Worker       {
1550*f6dc9357SAndroid Build Coastguard Worker         mi.NumSkipAltStreams++;
1551*f6dc9357SAndroid Build Coastguard Worker         mi.AltStreams[ui.AltStreamIndex].Skip = true;
1552*f6dc9357SAndroid Build Coastguard Worker       }
1553*f6dc9357SAndroid Build Coastguard Worker       else
1554*f6dc9357SAndroid Build Coastguard Worker         mi.Skip = true;
1555*f6dc9357SAndroid Build Coastguard Worker     }
1556*f6dc9357SAndroid Build Coastguard Worker     else
1557*f6dc9357SAndroid Build Coastguard Worker     {
1558*f6dc9357SAndroid Build Coastguard Worker       RINOK(res)
1559*f6dc9357SAndroid Build Coastguard Worker 
1560*f6dc9357SAndroid Build Coastguard Worker       int miIndex = -1;
1561*f6dc9357SAndroid Build Coastguard Worker 
1562*f6dc9357SAndroid Build Coastguard Worker       if (!fileInStream)
1563*f6dc9357SAndroid Build Coastguard Worker       {
1564*f6dc9357SAndroid Build Coastguard Worker         if (!mi.IsDir)
1565*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1566*f6dc9357SAndroid Build Coastguard Worker       }
1567*f6dc9357SAndroid Build Coastguard Worker       else if (ui.AltStreamIndex < 0)
1568*f6dc9357SAndroid Build Coastguard Worker       {
1569*f6dc9357SAndroid Build Coastguard Worker         CMyComPtr<IStreamGetProps2> getProps2;
1570*f6dc9357SAndroid Build Coastguard Worker         fileInStream->QueryInterface(IID_IStreamGetProps2, (void **)&getProps2);
1571*f6dc9357SAndroid Build Coastguard Worker         if (getProps2)
1572*f6dc9357SAndroid Build Coastguard Worker         {
1573*f6dc9357SAndroid Build Coastguard Worker           CStreamFileProps props;
1574*f6dc9357SAndroid Build Coastguard Worker           if (getProps2->GetProps2(&props) == S_OK)
1575*f6dc9357SAndroid Build Coastguard Worker           {
1576*f6dc9357SAndroid Build Coastguard Worker             mi.Attrib = props.Attrib;
1577*f6dc9357SAndroid Build Coastguard Worker             if (_timeOptions.Write_CTime.Val) mi.CTime = props.CTime;
1578*f6dc9357SAndroid Build Coastguard Worker             if (_timeOptions.Write_ATime.Val) mi.ATime = props.ATime;
1579*f6dc9357SAndroid Build Coastguard Worker             if (_timeOptions.Write_MTime.Val) mi.MTime = props.MTime;
1580*f6dc9357SAndroid Build Coastguard Worker             mi.FileID = props.FileID_Low;
1581*f6dc9357SAndroid Build Coastguard Worker             if (props.NumLinks <= 1)
1582*f6dc9357SAndroid Build Coastguard Worker               mi.FileID = 0;
1583*f6dc9357SAndroid Build Coastguard Worker             mi.VolID = props.VolID;
1584*f6dc9357SAndroid Build Coastguard Worker             if (mi.FileID != 0)
1585*f6dc9357SAndroid Build Coastguard Worker               miIndex = AddToHardLinkList(db.MetaItems, (unsigned)ui.MetaIndex, hlIndexes);
1586*f6dc9357SAndroid Build Coastguard Worker 
1587*f6dc9357SAndroid Build Coastguard Worker             if (props.Size != size && props.Size != (UInt64)(Int64)-1)
1588*f6dc9357SAndroid Build Coastguard Worker             {
1589*f6dc9357SAndroid Build Coastguard Worker               const Int64 delta = (Int64)props.Size - (Int64)size;
1590*f6dc9357SAndroid Build Coastguard Worker               const Int64 newComplexity = (Int64)totalComplexity + delta;
1591*f6dc9357SAndroid Build Coastguard Worker               if (newComplexity > 0)
1592*f6dc9357SAndroid Build Coastguard Worker               {
1593*f6dc9357SAndroid Build Coastguard Worker                 totalComplexity = (UInt64)newComplexity;
1594*f6dc9357SAndroid Build Coastguard Worker                 callback->SetTotal(totalComplexity);
1595*f6dc9357SAndroid Build Coastguard Worker               }
1596*f6dc9357SAndroid Build Coastguard Worker               mi.Size = props.Size;
1597*f6dc9357SAndroid Build Coastguard Worker               size = props.Size;
1598*f6dc9357SAndroid Build Coastguard Worker             }
1599*f6dc9357SAndroid Build Coastguard Worker           }
1600*f6dc9357SAndroid Build Coastguard Worker         }
1601*f6dc9357SAndroid Build Coastguard Worker       }
1602*f6dc9357SAndroid Build Coastguard Worker 
1603*f6dc9357SAndroid Build Coastguard Worker       if (miIndex >= 0)
1604*f6dc9357SAndroid Build Coastguard Worker       {
1605*f6dc9357SAndroid Build Coastguard Worker         mi.HashIndex = db.MetaItems[miIndex].HashIndex;
1606*f6dc9357SAndroid Build Coastguard Worker         if (mi.HashIndex >= 0)
1607*f6dc9357SAndroid Build Coastguard Worker           streams[mi.HashIndex].RefCount++;
1608*f6dc9357SAndroid Build Coastguard Worker         // fix for future: maybe we need to check also that real size is equal to size from IStreamGetProps2
1609*f6dc9357SAndroid Build Coastguard Worker       }
1610*f6dc9357SAndroid Build Coastguard Worker       else if (ui.AltStreamIndex < 0 && mi.Reparse.Size() != 0)
1611*f6dc9357SAndroid Build Coastguard Worker       {
1612*f6dc9357SAndroid Build Coastguard Worker         if (mi.Reparse.Size() < 8)
1613*f6dc9357SAndroid Build Coastguard Worker           return E_FAIL;
1614*f6dc9357SAndroid Build Coastguard Worker         NCrypto::NSha1::CContext sha1;
1615*f6dc9357SAndroid Build Coastguard Worker         sha1.Init();
1616*f6dc9357SAndroid Build Coastguard Worker         const size_t packSize = mi.Reparse.Size() - 8;
1617*f6dc9357SAndroid Build Coastguard Worker         sha1.Update((const Byte *)mi.Reparse + 8, packSize);
1618*f6dc9357SAndroid Build Coastguard Worker         Byte hash[kHashSize];
1619*f6dc9357SAndroid Build Coastguard Worker         sha1.Final(hash);
1620*f6dc9357SAndroid Build Coastguard Worker 
1621*f6dc9357SAndroid Build Coastguard Worker         int index = AddUniqHash(streams.ConstData(), sortedHashes, hash, (int)streams.Size());
1622*f6dc9357SAndroid Build Coastguard Worker 
1623*f6dc9357SAndroid Build Coastguard Worker         if (index != -1)
1624*f6dc9357SAndroid Build Coastguard Worker           streams[index].RefCount++;
1625*f6dc9357SAndroid Build Coastguard Worker         else
1626*f6dc9357SAndroid Build Coastguard Worker         {
1627*f6dc9357SAndroid Build Coastguard Worker           index = (int)streams.Size();
1628*f6dc9357SAndroid Build Coastguard Worker           RINOK(WriteStream(outStream, (const Byte *)mi.Reparse + 8, packSize))
1629*f6dc9357SAndroid Build Coastguard Worker           CStreamInfo s;
1630*f6dc9357SAndroid Build Coastguard Worker           s.Resource.PackSize = packSize;
1631*f6dc9357SAndroid Build Coastguard Worker           s.Resource.Offset = curPos;
1632*f6dc9357SAndroid Build Coastguard Worker           s.Resource.UnpackSize = packSize;
1633*f6dc9357SAndroid Build Coastguard Worker           s.Resource.Flags = 0; // check it
1634*f6dc9357SAndroid Build Coastguard Worker           /*
1635*f6dc9357SAndroid Build Coastguard Worker             if (useResourceCompression)
1636*f6dc9357SAndroid Build Coastguard Worker               s.Resource.Flags = NResourceFlags::Compressed;
1637*f6dc9357SAndroid Build Coastguard Worker           */
1638*f6dc9357SAndroid Build Coastguard Worker           s.PartNumber = 1;
1639*f6dc9357SAndroid Build Coastguard Worker           s.RefCount = 1;
1640*f6dc9357SAndroid Build Coastguard Worker           memcpy(s.Hash, hash, kHashSize);
1641*f6dc9357SAndroid Build Coastguard Worker           curPos += packSize;
1642*f6dc9357SAndroid Build Coastguard Worker 
1643*f6dc9357SAndroid Build Coastguard Worker           streams.Add(s);
1644*f6dc9357SAndroid Build Coastguard Worker         }
1645*f6dc9357SAndroid Build Coastguard Worker 
1646*f6dc9357SAndroid Build Coastguard Worker         mi.HashIndex = index;
1647*f6dc9357SAndroid Build Coastguard Worker       }
1648*f6dc9357SAndroid Build Coastguard Worker       else
1649*f6dc9357SAndroid Build Coastguard Worker       {
1650*f6dc9357SAndroid Build Coastguard Worker         inShaStream->SetStream(fileInStream);
1651*f6dc9357SAndroid Build Coastguard Worker 
1652*f6dc9357SAndroid Build Coastguard Worker         CMyComPtr<IInStream> inSeekStream;
1653*f6dc9357SAndroid Build Coastguard Worker         fileInStream.QueryInterface(IID_IInStream, (void **)&inSeekStream);
1654*f6dc9357SAndroid Build Coastguard Worker 
1655*f6dc9357SAndroid Build Coastguard Worker         fileInStream.Release();
1656*f6dc9357SAndroid Build Coastguard Worker         inShaStream->Init();
1657*f6dc9357SAndroid Build Coastguard Worker         UInt64 offsetBlockSize = 0;
1658*f6dc9357SAndroid Build Coastguard Worker         /*
1659*f6dc9357SAndroid Build Coastguard Worker         if (useResourceCompression)
1660*f6dc9357SAndroid Build Coastguard Worker         {
1661*f6dc9357SAndroid Build Coastguard Worker           for (UInt64 t = kChunkSize; t < size; t += kChunkSize)
1662*f6dc9357SAndroid Build Coastguard Worker           {
1663*f6dc9357SAndroid Build Coastguard Worker             Byte buf[8];
1664*f6dc9357SAndroid Build Coastguard Worker             SetUi32(buf, (UInt32)t);
1665*f6dc9357SAndroid Build Coastguard Worker             RINOK(WriteStream(outStream, buf, 4));
1666*f6dc9357SAndroid Build Coastguard Worker             offsetBlockSize += 4;
1667*f6dc9357SAndroid Build Coastguard Worker           }
1668*f6dc9357SAndroid Build Coastguard Worker         }
1669*f6dc9357SAndroid Build Coastguard Worker         */
1670*f6dc9357SAndroid Build Coastguard Worker 
1671*f6dc9357SAndroid Build Coastguard Worker         // 22.02: we use additional read-only pass to calculate SHA-1
1672*f6dc9357SAndroid Build Coastguard Worker         bool needWritePass = true;
1673*f6dc9357SAndroid Build Coastguard Worker         int index = -1;
1674*f6dc9357SAndroid Build Coastguard Worker 
1675*f6dc9357SAndroid Build Coastguard Worker         if (inSeekStream /* && !sortedHashes.IsEmpty() */)
1676*f6dc9357SAndroid Build Coastguard Worker         {
1677*f6dc9357SAndroid Build Coastguard Worker           RINOK(copyCoder.Interface()->Code(inShaStream, NULL, NULL, NULL, lps))
1678*f6dc9357SAndroid Build Coastguard Worker           size = copyCoder->TotalSize;
1679*f6dc9357SAndroid Build Coastguard Worker           if (size == 0)
1680*f6dc9357SAndroid Build Coastguard Worker             needWritePass = false;
1681*f6dc9357SAndroid Build Coastguard Worker           else
1682*f6dc9357SAndroid Build Coastguard Worker           {
1683*f6dc9357SAndroid Build Coastguard Worker             Byte hash[kHashSize];
1684*f6dc9357SAndroid Build Coastguard Worker             inShaStream->Final(hash);
1685*f6dc9357SAndroid Build Coastguard Worker 
1686*f6dc9357SAndroid Build Coastguard Worker             index = AddUniqHash(streams.ConstData(), sortedHashes, hash, -1);
1687*f6dc9357SAndroid Build Coastguard Worker             if (index != -1)
1688*f6dc9357SAndroid Build Coastguard Worker             {
1689*f6dc9357SAndroid Build Coastguard Worker               streams[index].RefCount++;
1690*f6dc9357SAndroid Build Coastguard Worker               needWritePass = false;
1691*f6dc9357SAndroid Build Coastguard Worker             }
1692*f6dc9357SAndroid Build Coastguard Worker             else
1693*f6dc9357SAndroid Build Coastguard Worker             {
1694*f6dc9357SAndroid Build Coastguard Worker               RINOK(InStream_SeekToBegin(inSeekStream))
1695*f6dc9357SAndroid Build Coastguard Worker               inShaStream->Init();
1696*f6dc9357SAndroid Build Coastguard Worker             }
1697*f6dc9357SAndroid Build Coastguard Worker           }
1698*f6dc9357SAndroid Build Coastguard Worker         }
1699*f6dc9357SAndroid Build Coastguard Worker 
1700*f6dc9357SAndroid Build Coastguard Worker         if (needWritePass)
1701*f6dc9357SAndroid Build Coastguard Worker         {
1702*f6dc9357SAndroid Build Coastguard Worker           RINOK(copyCoder.Interface()->Code(inShaStream, outStream, NULL, NULL, lps))
1703*f6dc9357SAndroid Build Coastguard Worker           size = copyCoder->TotalSize;
1704*f6dc9357SAndroid Build Coastguard Worker         }
1705*f6dc9357SAndroid Build Coastguard Worker 
1706*f6dc9357SAndroid Build Coastguard Worker         if (size != 0)
1707*f6dc9357SAndroid Build Coastguard Worker         {
1708*f6dc9357SAndroid Build Coastguard Worker           if (needWritePass)
1709*f6dc9357SAndroid Build Coastguard Worker           {
1710*f6dc9357SAndroid Build Coastguard Worker             Byte hash[kHashSize];
1711*f6dc9357SAndroid Build Coastguard Worker             const UInt64 packSize = offsetBlockSize + size;
1712*f6dc9357SAndroid Build Coastguard Worker             inShaStream->Final(hash);
1713*f6dc9357SAndroid Build Coastguard Worker 
1714*f6dc9357SAndroid Build Coastguard Worker             index = AddUniqHash(streams.ConstData(), sortedHashes, hash, (int)streams.Size());
1715*f6dc9357SAndroid Build Coastguard Worker 
1716*f6dc9357SAndroid Build Coastguard Worker             if (index != -1)
1717*f6dc9357SAndroid Build Coastguard Worker             {
1718*f6dc9357SAndroid Build Coastguard Worker               streams[index].RefCount++;
1719*f6dc9357SAndroid Build Coastguard Worker               outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos);
1720*f6dc9357SAndroid Build Coastguard Worker               outStream->SetSize(curPos);
1721*f6dc9357SAndroid Build Coastguard Worker             }
1722*f6dc9357SAndroid Build Coastguard Worker             else
1723*f6dc9357SAndroid Build Coastguard Worker             {
1724*f6dc9357SAndroid Build Coastguard Worker               index = (int)streams.Size();
1725*f6dc9357SAndroid Build Coastguard Worker               CStreamInfo s;
1726*f6dc9357SAndroid Build Coastguard Worker               s.Resource.PackSize = packSize;
1727*f6dc9357SAndroid Build Coastguard Worker               s.Resource.Offset = curPos;
1728*f6dc9357SAndroid Build Coastguard Worker               s.Resource.UnpackSize = size;
1729*f6dc9357SAndroid Build Coastguard Worker               s.Resource.Flags = 0;
1730*f6dc9357SAndroid Build Coastguard Worker               /*
1731*f6dc9357SAndroid Build Coastguard Worker               if (useResourceCompression)
1732*f6dc9357SAndroid Build Coastguard Worker               s.Resource.Flags = NResourceFlags::Compressed;
1733*f6dc9357SAndroid Build Coastguard Worker               */
1734*f6dc9357SAndroid Build Coastguard Worker               s.PartNumber = 1;
1735*f6dc9357SAndroid Build Coastguard Worker               s.RefCount = 1;
1736*f6dc9357SAndroid Build Coastguard Worker               memcpy(s.Hash, hash, kHashSize);
1737*f6dc9357SAndroid Build Coastguard Worker               curPos += packSize;
1738*f6dc9357SAndroid Build Coastguard Worker 
1739*f6dc9357SAndroid Build Coastguard Worker               streams.Add(s);
1740*f6dc9357SAndroid Build Coastguard Worker             }
1741*f6dc9357SAndroid Build Coastguard Worker           } // needWritePass
1742*f6dc9357SAndroid Build Coastguard Worker           if (ui.AltStreamIndex < 0)
1743*f6dc9357SAndroid Build Coastguard Worker             mi.HashIndex = index;
1744*f6dc9357SAndroid Build Coastguard Worker           else
1745*f6dc9357SAndroid Build Coastguard Worker             mi.AltStreams[ui.AltStreamIndex].HashIndex = index;
1746*f6dc9357SAndroid Build Coastguard Worker         } // (size != 0)
1747*f6dc9357SAndroid Build Coastguard Worker       }
1748*f6dc9357SAndroid Build Coastguard Worker     }
1749*f6dc9357SAndroid Build Coastguard Worker     fileInStream.Release();
1750*f6dc9357SAndroid Build Coastguard Worker     complexity += size;
1751*f6dc9357SAndroid Build Coastguard Worker     RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
1752*f6dc9357SAndroid Build Coastguard Worker   }
1753*f6dc9357SAndroid Build Coastguard Worker 
1754*f6dc9357SAndroid Build Coastguard Worker   while (secureBlocks.Size() < numNewImages)
1755*f6dc9357SAndroid Build Coastguard Worker     secureBlocks.AddNew();
1756*f6dc9357SAndroid Build Coastguard Worker 
1757*f6dc9357SAndroid Build Coastguard Worker 
1758*f6dc9357SAndroid Build Coastguard Worker 
1759*f6dc9357SAndroid Build Coastguard Worker   // ---------- Write Images ----------
1760*f6dc9357SAndroid Build Coastguard Worker 
1761*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numNewImages; i++)
1762*f6dc9357SAndroid Build Coastguard Worker   {
1763*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = lps->OutSize = complexity;
1764*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
1765*f6dc9357SAndroid Build Coastguard Worker     if (i < isChangedImage.Size() && !isChangedImage[i])
1766*f6dc9357SAndroid Build Coastguard Worker     {
1767*f6dc9357SAndroid Build Coastguard Worker       CStreamInfo s = _db.MetaStreams[i];
1768*f6dc9357SAndroid Build Coastguard Worker 
1769*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(_volumes[1].Stream, s.Resource.Offset))
1770*f6dc9357SAndroid Build Coastguard Worker       inStreamLimitedSpec->Init(s.Resource.PackSize);
1771*f6dc9357SAndroid Build Coastguard Worker       RINOK(copyCoder.Interface()->Code(inStreamLimited, outStream, NULL, NULL, lps))
1772*f6dc9357SAndroid Build Coastguard Worker       if (copyCoder->TotalSize != s.Resource.PackSize)
1773*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
1774*f6dc9357SAndroid Build Coastguard Worker 
1775*f6dc9357SAndroid Build Coastguard Worker       s.Resource.Offset = curPos;
1776*f6dc9357SAndroid Build Coastguard Worker       s.PartNumber = 1;
1777*f6dc9357SAndroid Build Coastguard Worker       s.RefCount = 1;
1778*f6dc9357SAndroid Build Coastguard Worker       streams.Add(s);
1779*f6dc9357SAndroid Build Coastguard Worker 
1780*f6dc9357SAndroid Build Coastguard Worker       if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1)
1781*f6dc9357SAndroid Build Coastguard Worker       {
1782*f6dc9357SAndroid Build Coastguard Worker         header.MetadataResource = s.Resource;
1783*f6dc9357SAndroid Build Coastguard Worker         header.BootIndex = _bootIndex;
1784*f6dc9357SAndroid Build Coastguard Worker       }
1785*f6dc9357SAndroid Build Coastguard Worker 
1786*f6dc9357SAndroid Build Coastguard Worker       lps->ProgressOffset += s.Resource.PackSize;
1787*f6dc9357SAndroid Build Coastguard Worker       curPos += s.Resource.PackSize;
1788*f6dc9357SAndroid Build Coastguard Worker       // printf("\nWrite old image %x\n", i + 1);
1789*f6dc9357SAndroid Build Coastguard Worker       continue;
1790*f6dc9357SAndroid Build Coastguard Worker     }
1791*f6dc9357SAndroid Build Coastguard Worker 
1792*f6dc9357SAndroid Build Coastguard Worker     const CDir &tree = trees[i];
1793*f6dc9357SAndroid Build Coastguard Worker     const UInt32 kSecuritySize = 8;
1794*f6dc9357SAndroid Build Coastguard Worker 
1795*f6dc9357SAndroid Build Coastguard Worker     size_t pos = kSecuritySize;
1796*f6dc9357SAndroid Build Coastguard Worker 
1797*f6dc9357SAndroid Build Coastguard Worker     const CUniqBlocks &secUniqBlocks = secureBlocks[i];
1798*f6dc9357SAndroid Build Coastguard Worker     const CObjectVector<CByteBuffer> &secBufs = secUniqBlocks.Bufs;
1799*f6dc9357SAndroid Build Coastguard Worker     pos += (size_t)secUniqBlocks.GetTotalSizeInBytes();
1800*f6dc9357SAndroid Build Coastguard Worker     pos += secBufs.Size() * 8;
1801*f6dc9357SAndroid Build Coastguard Worker     pos = (pos + 7) & ~(size_t)7;
1802*f6dc9357SAndroid Build Coastguard Worker 
1803*f6dc9357SAndroid Build Coastguard Worker     db.DefaultDirItem = ri;
1804*f6dc9357SAndroid Build Coastguard Worker     pos += db.WriteTree_Dummy(tree);
1805*f6dc9357SAndroid Build Coastguard Worker 
1806*f6dc9357SAndroid Build Coastguard Worker     CByteArr meta(pos);
1807*f6dc9357SAndroid Build Coastguard Worker 
1808*f6dc9357SAndroid Build Coastguard Worker     Set32((Byte *)meta + 4, secBufs.Size()) // num security entries
1809*f6dc9357SAndroid Build Coastguard Worker     pos = kSecuritySize;
1810*f6dc9357SAndroid Build Coastguard Worker 
1811*f6dc9357SAndroid Build Coastguard Worker     if (secBufs.Size() == 0)
1812*f6dc9357SAndroid Build Coastguard Worker     {
1813*f6dc9357SAndroid Build Coastguard Worker       // we can write 0 here only if there is no security data, imageX does it,
1814*f6dc9357SAndroid Build Coastguard Worker       // but some programs expect size = 8
1815*f6dc9357SAndroid Build Coastguard Worker       Set32((Byte *)meta, 8) // size of security data
1816*f6dc9357SAndroid Build Coastguard Worker       // Set32((Byte *)meta, 0);
1817*f6dc9357SAndroid Build Coastguard Worker     }
1818*f6dc9357SAndroid Build Coastguard Worker     else
1819*f6dc9357SAndroid Build Coastguard Worker     {
1820*f6dc9357SAndroid Build Coastguard Worker       unsigned k;
1821*f6dc9357SAndroid Build Coastguard Worker       for (k = 0; k < secBufs.Size(); k++, pos += 8)
1822*f6dc9357SAndroid Build Coastguard Worker       {
1823*f6dc9357SAndroid Build Coastguard Worker         Set64(meta + pos, secBufs[k].Size())
1824*f6dc9357SAndroid Build Coastguard Worker       }
1825*f6dc9357SAndroid Build Coastguard Worker       for (k = 0; k < secBufs.Size(); k++)
1826*f6dc9357SAndroid Build Coastguard Worker       {
1827*f6dc9357SAndroid Build Coastguard Worker         const CByteBuffer &buf = secBufs[k];
1828*f6dc9357SAndroid Build Coastguard Worker         size_t size = buf.Size();
1829*f6dc9357SAndroid Build Coastguard Worker         if (size != 0)
1830*f6dc9357SAndroid Build Coastguard Worker         {
1831*f6dc9357SAndroid Build Coastguard Worker           memcpy(meta + pos, buf, size);
1832*f6dc9357SAndroid Build Coastguard Worker           pos += size;
1833*f6dc9357SAndroid Build Coastguard Worker         }
1834*f6dc9357SAndroid Build Coastguard Worker       }
1835*f6dc9357SAndroid Build Coastguard Worker       while ((pos & 7) != 0)
1836*f6dc9357SAndroid Build Coastguard Worker         meta[pos++] = 0;
1837*f6dc9357SAndroid Build Coastguard Worker       Set32((Byte *)meta, (UInt32)pos) // size of security data
1838*f6dc9357SAndroid Build Coastguard Worker     }
1839*f6dc9357SAndroid Build Coastguard Worker 
1840*f6dc9357SAndroid Build Coastguard Worker     db.Hashes = streams.ConstData();
1841*f6dc9357SAndroid Build Coastguard Worker     db.WriteTree(tree, (Byte *)meta, pos);
1842*f6dc9357SAndroid Build Coastguard Worker 
1843*f6dc9357SAndroid Build Coastguard Worker     {
1844*f6dc9357SAndroid Build Coastguard Worker       NCrypto::NSha1::CContext sha;
1845*f6dc9357SAndroid Build Coastguard Worker       sha.Init();
1846*f6dc9357SAndroid Build Coastguard Worker       sha.Update((const Byte *)meta, pos);
1847*f6dc9357SAndroid Build Coastguard Worker 
1848*f6dc9357SAndroid Build Coastguard Worker       Byte digest[kHashSize];
1849*f6dc9357SAndroid Build Coastguard Worker       sha.Final(digest);
1850*f6dc9357SAndroid Build Coastguard Worker 
1851*f6dc9357SAndroid Build Coastguard Worker       CStreamInfo s;
1852*f6dc9357SAndroid Build Coastguard Worker       s.Resource.PackSize = pos;
1853*f6dc9357SAndroid Build Coastguard Worker       s.Resource.Offset = curPos;
1854*f6dc9357SAndroid Build Coastguard Worker       s.Resource.UnpackSize = pos;
1855*f6dc9357SAndroid Build Coastguard Worker       s.Resource.Flags = NResourceFlags::kMetadata;
1856*f6dc9357SAndroid Build Coastguard Worker       s.PartNumber = 1;
1857*f6dc9357SAndroid Build Coastguard Worker       s.RefCount = 1;
1858*f6dc9357SAndroid Build Coastguard Worker       memcpy(s.Hash, digest, kHashSize);
1859*f6dc9357SAndroid Build Coastguard Worker       streams.Add(s);
1860*f6dc9357SAndroid Build Coastguard Worker 
1861*f6dc9357SAndroid Build Coastguard Worker       if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1)
1862*f6dc9357SAndroid Build Coastguard Worker       {
1863*f6dc9357SAndroid Build Coastguard Worker         header.MetadataResource = s.Resource;
1864*f6dc9357SAndroid Build Coastguard Worker         header.BootIndex = _bootIndex;
1865*f6dc9357SAndroid Build Coastguard Worker       }
1866*f6dc9357SAndroid Build Coastguard Worker 
1867*f6dc9357SAndroid Build Coastguard Worker       RINOK(WriteStream(outStream, (const Byte *)meta, pos))
1868*f6dc9357SAndroid Build Coastguard Worker       meta.Free();
1869*f6dc9357SAndroid Build Coastguard Worker       curPos += pos;
1870*f6dc9357SAndroid Build Coastguard Worker     }
1871*f6dc9357SAndroid Build Coastguard Worker   }
1872*f6dc9357SAndroid Build Coastguard Worker 
1873*f6dc9357SAndroid Build Coastguard Worker   lps->InSize = lps->OutSize = complexity;
1874*f6dc9357SAndroid Build Coastguard Worker   RINOK(lps->SetCur())
1875*f6dc9357SAndroid Build Coastguard Worker 
1876*f6dc9357SAndroid Build Coastguard Worker   header.OffsetResource.UnpackSize = header.OffsetResource.PackSize = (UInt64)streams.Size() * kStreamInfoSize;
1877*f6dc9357SAndroid Build Coastguard Worker   header.OffsetResource.Offset = curPos;
1878*f6dc9357SAndroid Build Coastguard Worker   header.OffsetResource.Flags = NResourceFlags::kMetadata;
1879*f6dc9357SAndroid Build Coastguard Worker 
1880*f6dc9357SAndroid Build Coastguard Worker 
1881*f6dc9357SAndroid Build Coastguard Worker 
1882*f6dc9357SAndroid Build Coastguard Worker   // ---------- Write Streams Info Tables ----------
1883*f6dc9357SAndroid Build Coastguard Worker 
1884*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < streams.Size(); i++)
1885*f6dc9357SAndroid Build Coastguard Worker   {
1886*f6dc9357SAndroid Build Coastguard Worker     Byte buf[kStreamInfoSize];
1887*f6dc9357SAndroid Build Coastguard Worker     streams[i].WriteTo(buf);
1888*f6dc9357SAndroid Build Coastguard Worker     RINOK(WriteStream(outStream, buf, kStreamInfoSize))
1889*f6dc9357SAndroid Build Coastguard Worker     curPos += kStreamInfoSize;
1890*f6dc9357SAndroid Build Coastguard Worker   }
1891*f6dc9357SAndroid Build Coastguard Worker 
1892*f6dc9357SAndroid Build Coastguard Worker   AString xml ("<WIM>");
1893*f6dc9357SAndroid Build Coastguard Worker   AddTagUInt64_ToString(xml, "TOTALBYTES", curPos);
1894*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < trees.Size(); i++)
1895*f6dc9357SAndroid Build Coastguard Worker   {
1896*f6dc9357SAndroid Build Coastguard Worker     const CDir &tree = trees[i];
1897*f6dc9357SAndroid Build Coastguard Worker 
1898*f6dc9357SAndroid Build Coastguard Worker     CXmlItem item;
1899*f6dc9357SAndroid Build Coastguard Worker     if (_xmls.Size() == 1)
1900*f6dc9357SAndroid Build Coastguard Worker     {
1901*f6dc9357SAndroid Build Coastguard Worker       const CWimXml &_oldXml = _xmls[0];
1902*f6dc9357SAndroid Build Coastguard Worker       if (i < _oldXml.Images.Size())
1903*f6dc9357SAndroid Build Coastguard Worker       {
1904*f6dc9357SAndroid Build Coastguard Worker         // int ttt = _oldXml.Images[i].ItemIndexInXml;
1905*f6dc9357SAndroid Build Coastguard Worker         item = _oldXml.Xml.Root.SubItems[_oldXml.Images[i].ItemIndexInXml];
1906*f6dc9357SAndroid Build Coastguard Worker       }
1907*f6dc9357SAndroid Build Coastguard Worker     }
1908*f6dc9357SAndroid Build Coastguard Worker     if (i >= isChangedImage.Size() || isChangedImage[i])
1909*f6dc9357SAndroid Build Coastguard Worker     {
1910*f6dc9357SAndroid Build Coastguard Worker       char temp[16];
1911*f6dc9357SAndroid Build Coastguard Worker       if (item.Name.IsEmpty())
1912*f6dc9357SAndroid Build Coastguard Worker       {
1913*f6dc9357SAndroid Build Coastguard Worker         ConvertUInt32ToString(i + 1, temp);
1914*f6dc9357SAndroid Build Coastguard Worker         item.Name = "IMAGE";
1915*f6dc9357SAndroid Build Coastguard Worker         item.IsTag = true;
1916*f6dc9357SAndroid Build Coastguard Worker         CXmlProp &prop = item.Props.AddNew();
1917*f6dc9357SAndroid Build Coastguard Worker         prop.Name = "INDEX";
1918*f6dc9357SAndroid Build Coastguard Worker         prop.Value = temp;
1919*f6dc9357SAndroid Build Coastguard Worker       }
1920*f6dc9357SAndroid Build Coastguard Worker 
1921*f6dc9357SAndroid Build Coastguard Worker       AddTag_String_IfEmpty(item, "NAME", temp);
1922*f6dc9357SAndroid Build Coastguard Worker       AddTag_UInt64(item, "DIRCOUNT", tree.GetNumDirs() - 1);
1923*f6dc9357SAndroid Build Coastguard Worker       AddTag_UInt64(item, "FILECOUNT", tree.GetNumFiles());
1924*f6dc9357SAndroid Build Coastguard Worker       AddTag_UInt64(item, "TOTALBYTES", tree.GetTotalSize(db.MetaItems));
1925*f6dc9357SAndroid Build Coastguard Worker 
1926*f6dc9357SAndroid Build Coastguard Worker       AddTag_Time(item, "CREATIONTIME", ftCur);
1927*f6dc9357SAndroid Build Coastguard Worker       AddTag_Time(item, "LASTMODIFICATIONTIME", ftCur);
1928*f6dc9357SAndroid Build Coastguard Worker     }
1929*f6dc9357SAndroid Build Coastguard Worker 
1930*f6dc9357SAndroid Build Coastguard Worker     item.AppendTo(xml);
1931*f6dc9357SAndroid Build Coastguard Worker   }
1932*f6dc9357SAndroid Build Coastguard Worker   xml += "</WIM>";
1933*f6dc9357SAndroid Build Coastguard Worker 
1934*f6dc9357SAndroid Build Coastguard Worker   size_t xmlSize;
1935*f6dc9357SAndroid Build Coastguard Worker   {
1936*f6dc9357SAndroid Build Coastguard Worker     UString utf16;
1937*f6dc9357SAndroid Build Coastguard Worker     if (!ConvertUTF8ToUnicode(xml, utf16))
1938*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1939*f6dc9357SAndroid Build Coastguard Worker     xmlSize = ((size_t)utf16.Len() + 1) * 2;
1940*f6dc9357SAndroid Build Coastguard Worker 
1941*f6dc9357SAndroid Build Coastguard Worker     CByteArr xmlBuf(xmlSize);
1942*f6dc9357SAndroid Build Coastguard Worker     Set16((Byte *)xmlBuf, 0xFEFF)
1943*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < (unsigned)utf16.Len(); i++)
1944*f6dc9357SAndroid Build Coastguard Worker     {
1945*f6dc9357SAndroid Build Coastguard Worker       Set16((Byte *)xmlBuf + 2 + (size_t)i * 2, (UInt16)utf16[i])
1946*f6dc9357SAndroid Build Coastguard Worker     }
1947*f6dc9357SAndroid Build Coastguard Worker     RINOK(WriteStream(outStream, (const Byte *)xmlBuf, xmlSize))
1948*f6dc9357SAndroid Build Coastguard Worker   }
1949*f6dc9357SAndroid Build Coastguard Worker 
1950*f6dc9357SAndroid Build Coastguard Worker   header.XmlResource.UnpackSize =
1951*f6dc9357SAndroid Build Coastguard Worker   header.XmlResource.PackSize = xmlSize;
1952*f6dc9357SAndroid Build Coastguard Worker   header.XmlResource.Offset = curPos;
1953*f6dc9357SAndroid Build Coastguard Worker   header.XmlResource.Flags = NResourceFlags::kMetadata;
1954*f6dc9357SAndroid Build Coastguard Worker 
1955*f6dc9357SAndroid Build Coastguard Worker   outStream->Seek(0, STREAM_SEEK_SET, NULL);
1956*f6dc9357SAndroid Build Coastguard Worker   header.NumImages = trees.Size();
1957*f6dc9357SAndroid Build Coastguard Worker   {
1958*f6dc9357SAndroid Build Coastguard Worker     Byte buf[kHeaderSizeMax];
1959*f6dc9357SAndroid Build Coastguard Worker     header.WriteTo(buf);
1960*f6dc9357SAndroid Build Coastguard Worker     RINOK(WriteStream(outStream, buf, kHeaderSizeMax))
1961*f6dc9357SAndroid Build Coastguard Worker   }
1962*f6dc9357SAndroid Build Coastguard Worker 
1963*f6dc9357SAndroid Build Coastguard Worker   if (setRestriction)
1964*f6dc9357SAndroid Build Coastguard Worker     RINOK(setRestriction->SetRestriction(0, 0))
1965*f6dc9357SAndroid Build Coastguard Worker 
1966*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1967*f6dc9357SAndroid Build Coastguard Worker 
1968*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1969*f6dc9357SAndroid Build Coastguard Worker }
1970*f6dc9357SAndroid Build Coastguard Worker 
1971*f6dc9357SAndroid Build Coastguard Worker }}
1972