xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Tar/TarHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // TarHandler.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/StringConvert.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/UTFConvert.h"
9*f6dc9357SAndroid Build Coastguard Worker 
10*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/TimeUtils.h"
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/LimitedStreams.h"
13*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MethodProps.h"
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ProgressUtils.h"
15*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StreamObjects.h"
16*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StreamUtils.h"
17*f6dc9357SAndroid Build Coastguard Worker 
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ItemNameUtils.h"
19*f6dc9357SAndroid Build Coastguard Worker 
20*f6dc9357SAndroid Build Coastguard Worker #include "TarHandler.h"
21*f6dc9357SAndroid Build Coastguard Worker 
22*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
23*f6dc9357SAndroid Build Coastguard Worker 
24*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
25*f6dc9357SAndroid Build Coastguard Worker namespace NTar {
26*f6dc9357SAndroid Build Coastguard Worker 
27*f6dc9357SAndroid Build Coastguard Worker // 21.02: we use UTF8 code page by default, even if some files show error
28*f6dc9357SAndroid Build Coastguard Worker // before 21.02 : CP_OEMCP;
29*f6dc9357SAndroid Build Coastguard Worker // static const UINT k_DefaultCodePage = CP_UTF8;
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker 
32*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
33*f6dc9357SAndroid Build Coastguard Worker {
34*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
35*f6dc9357SAndroid Build Coastguard Worker   kpidIsDir,
36*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
37*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
38*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
39*f6dc9357SAndroid Build Coastguard Worker   kpidCTime,
40*f6dc9357SAndroid Build Coastguard Worker   kpidATime,
41*f6dc9357SAndroid Build Coastguard Worker   kpidPosixAttrib,
42*f6dc9357SAndroid Build Coastguard Worker #if 0
43*f6dc9357SAndroid Build Coastguard Worker   kpidAttrib,
44*f6dc9357SAndroid Build Coastguard Worker #endif
45*f6dc9357SAndroid Build Coastguard Worker   kpidUser,
46*f6dc9357SAndroid Build Coastguard Worker   kpidGroup,
47*f6dc9357SAndroid Build Coastguard Worker   kpidUserId,
48*f6dc9357SAndroid Build Coastguard Worker   kpidGroupId,
49*f6dc9357SAndroid Build Coastguard Worker   kpidSymLink,
50*f6dc9357SAndroid Build Coastguard Worker   kpidHardLink,
51*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts,
52*f6dc9357SAndroid Build Coastguard Worker   kpidComment
53*f6dc9357SAndroid Build Coastguard Worker   , kpidDeviceMajor
54*f6dc9357SAndroid Build Coastguard Worker   , kpidDeviceMinor
55*f6dc9357SAndroid Build Coastguard Worker   // , kpidDevice
56*f6dc9357SAndroid Build Coastguard Worker   // , kpidHeadersSize // for debug
57*f6dc9357SAndroid Build Coastguard Worker   // , kpidOffset // for debug
58*f6dc9357SAndroid Build Coastguard Worker };
59*f6dc9357SAndroid Build Coastguard Worker 
60*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
61*f6dc9357SAndroid Build Coastguard Worker {
62*f6dc9357SAndroid Build Coastguard Worker   kpidHeadersSize,
63*f6dc9357SAndroid Build Coastguard Worker   kpidCodePage,
64*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts,
65*f6dc9357SAndroid Build Coastguard Worker   kpidComment
66*f6dc9357SAndroid Build Coastguard Worker };
67*f6dc9357SAndroid Build Coastguard Worker 
68*f6dc9357SAndroid Build Coastguard Worker static const char *k_Characts_Prefix = "PREFIX";
69*f6dc9357SAndroid Build Coastguard Worker 
70*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
71*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
72*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))73*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
74*f6dc9357SAndroid Build Coastguard Worker {
75*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
76*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
77*f6dc9357SAndroid Build Coastguard Worker   {
78*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize:     if (_arc._phySize_Defined) prop = _arc._phySize; break;
79*f6dc9357SAndroid Build Coastguard Worker     case kpidHeadersSize: if (_arc._phySize_Defined) prop = _arc._headersSize; break;
80*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
81*f6dc9357SAndroid Build Coastguard Worker     {
82*f6dc9357SAndroid Build Coastguard Worker       UInt32 flags = 0;
83*f6dc9357SAndroid Build Coastguard Worker       if (!_isArc)
84*f6dc9357SAndroid Build Coastguard Worker         flags |= kpv_ErrorFlags_IsNotArc;
85*f6dc9357SAndroid Build Coastguard Worker       else switch ((int)_arc._error)
86*f6dc9357SAndroid Build Coastguard Worker       {
87*f6dc9357SAndroid Build Coastguard Worker         case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break;
88*f6dc9357SAndroid Build Coastguard Worker         case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break;
89*f6dc9357SAndroid Build Coastguard Worker         // case k_ErrorType_OK: break;
90*f6dc9357SAndroid Build Coastguard Worker         // case k_ErrorType_Warning: break;
91*f6dc9357SAndroid Build Coastguard Worker         // case k_ErrorType_OK:
92*f6dc9357SAndroid Build Coastguard Worker         default: break;
93*f6dc9357SAndroid Build Coastguard Worker       }
94*f6dc9357SAndroid Build Coastguard Worker       if (flags != 0)
95*f6dc9357SAndroid Build Coastguard Worker         prop = flags;
96*f6dc9357SAndroid Build Coastguard Worker       break;
97*f6dc9357SAndroid Build Coastguard Worker     }
98*f6dc9357SAndroid Build Coastguard Worker 
99*f6dc9357SAndroid Build Coastguard Worker     case kpidWarningFlags:
100*f6dc9357SAndroid Build Coastguard Worker     {
101*f6dc9357SAndroid Build Coastguard Worker       if (_arc._is_Warning)
102*f6dc9357SAndroid Build Coastguard Worker         prop = kpv_ErrorFlags_HeadersError;
103*f6dc9357SAndroid Build Coastguard Worker       break;
104*f6dc9357SAndroid Build Coastguard Worker     }
105*f6dc9357SAndroid Build Coastguard Worker 
106*f6dc9357SAndroid Build Coastguard Worker     case kpidCodePage:
107*f6dc9357SAndroid Build Coastguard Worker     {
108*f6dc9357SAndroid Build Coastguard Worker       char sz[16];
109*f6dc9357SAndroid Build Coastguard Worker       const char *name = NULL;
110*f6dc9357SAndroid Build Coastguard Worker       switch (_openCodePage)
111*f6dc9357SAndroid Build Coastguard Worker       {
112*f6dc9357SAndroid Build Coastguard Worker         case CP_OEMCP: name = "OEM"; break;
113*f6dc9357SAndroid Build Coastguard Worker         case CP_UTF8: name = "UTF-8"; break;
114*f6dc9357SAndroid Build Coastguard Worker         default: break;
115*f6dc9357SAndroid Build Coastguard Worker       }
116*f6dc9357SAndroid Build Coastguard Worker       if (!name)
117*f6dc9357SAndroid Build Coastguard Worker       {
118*f6dc9357SAndroid Build Coastguard Worker         ConvertUInt32ToString(_openCodePage, sz);
119*f6dc9357SAndroid Build Coastguard Worker         name = sz;
120*f6dc9357SAndroid Build Coastguard Worker       }
121*f6dc9357SAndroid Build Coastguard Worker       prop = name;
122*f6dc9357SAndroid Build Coastguard Worker       break;
123*f6dc9357SAndroid Build Coastguard Worker     }
124*f6dc9357SAndroid Build Coastguard Worker 
125*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts:
126*f6dc9357SAndroid Build Coastguard Worker     {
127*f6dc9357SAndroid Build Coastguard Worker       AString s;
128*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_Gnu) s.Add_OptSpaced("GNU");
129*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_Posix) s.Add_OptSpaced("POSIX");
130*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_Pax_Items) s.Add_OptSpaced("PAX_ITEM");
131*f6dc9357SAndroid Build Coastguard Worker       if (_arc._pathPrefix_WasUsed) s.Add_OptSpaced(k_Characts_Prefix);
132*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_LongName) s.Add_OptSpaced("LongName");
133*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_LongLink) s.Add_OptSpaced("LongLink");
134*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_Pax) s.Add_OptSpaced("PAX");
135*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_pax_path) s.Add_OptSpaced("path");
136*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_pax_link) s.Add_OptSpaced("linkpath");
137*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_mtime) s.Add_OptSpaced("mtime");
138*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_atime) s.Add_OptSpaced("atime");
139*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_ctime) s.Add_OptSpaced("ctime");
140*f6dc9357SAndroid Build Coastguard Worker       if (_arc._are_SCHILY_fflags) s.Add_OptSpaced("SCHILY.fflags");
141*f6dc9357SAndroid Build Coastguard Worker       if (_arc._is_PaxGlobal_Error) s.Add_OptSpaced("PAX_GLOBAL_ERROR");
142*f6dc9357SAndroid Build Coastguard Worker       s.Add_OptSpaced(_encodingCharacts.GetCharactsString());
143*f6dc9357SAndroid Build Coastguard Worker       prop = s;
144*f6dc9357SAndroid Build Coastguard Worker       break;
145*f6dc9357SAndroid Build Coastguard Worker     }
146*f6dc9357SAndroid Build Coastguard Worker 
147*f6dc9357SAndroid Build Coastguard Worker     case kpidComment:
148*f6dc9357SAndroid Build Coastguard Worker     {
149*f6dc9357SAndroid Build Coastguard Worker       if (_arc.PaxGlobal_Defined)
150*f6dc9357SAndroid Build Coastguard Worker       {
151*f6dc9357SAndroid Build Coastguard Worker         AString s;
152*f6dc9357SAndroid Build Coastguard Worker         _arc.PaxGlobal.Print_To_String(s);
153*f6dc9357SAndroid Build Coastguard Worker         if (!s.IsEmpty())
154*f6dc9357SAndroid Build Coastguard Worker           prop = s;
155*f6dc9357SAndroid Build Coastguard Worker       }
156*f6dc9357SAndroid Build Coastguard Worker       break;
157*f6dc9357SAndroid Build Coastguard Worker     }
158*f6dc9357SAndroid Build Coastguard Worker     default: break;
159*f6dc9357SAndroid Build Coastguard Worker   }
160*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
161*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
162*f6dc9357SAndroid Build Coastguard Worker }
163*f6dc9357SAndroid Build Coastguard Worker 
164*f6dc9357SAndroid Build Coastguard Worker 
Check(const AString & s)165*f6dc9357SAndroid Build Coastguard Worker void CEncodingCharacts::Check(const AString &s)
166*f6dc9357SAndroid Build Coastguard Worker {
167*f6dc9357SAndroid Build Coastguard Worker   IsAscii = s.IsAscii();
168*f6dc9357SAndroid Build Coastguard Worker   if (!IsAscii)
169*f6dc9357SAndroid Build Coastguard Worker   {
170*f6dc9357SAndroid Build Coastguard Worker     /*
171*f6dc9357SAndroid Build Coastguard Worker     {
172*f6dc9357SAndroid Build Coastguard Worker       Oem_Checked = true;
173*f6dc9357SAndroid Build Coastguard Worker       UString u;
174*f6dc9357SAndroid Build Coastguard Worker       MultiByteToUnicodeString2(u, s, CP_OEMCP);
175*f6dc9357SAndroid Build Coastguard Worker       Oem_Ok = (u.Find((wchar_t)0xfffd) <= 0);
176*f6dc9357SAndroid Build Coastguard Worker     }
177*f6dc9357SAndroid Build Coastguard Worker     Utf_Checked = true;
178*f6dc9357SAndroid Build Coastguard Worker     */
179*f6dc9357SAndroid Build Coastguard Worker     UtfCheck.Check_AString(s);
180*f6dc9357SAndroid Build Coastguard Worker   }
181*f6dc9357SAndroid Build Coastguard Worker }
182*f6dc9357SAndroid Build Coastguard Worker 
183*f6dc9357SAndroid Build Coastguard Worker 
GetCharactsString() const184*f6dc9357SAndroid Build Coastguard Worker AString CEncodingCharacts::GetCharactsString() const
185*f6dc9357SAndroid Build Coastguard Worker {
186*f6dc9357SAndroid Build Coastguard Worker   AString s;
187*f6dc9357SAndroid Build Coastguard Worker   if (IsAscii)
188*f6dc9357SAndroid Build Coastguard Worker   {
189*f6dc9357SAndroid Build Coastguard Worker     s += "ASCII";
190*f6dc9357SAndroid Build Coastguard Worker   }
191*f6dc9357SAndroid Build Coastguard Worker   /*
192*f6dc9357SAndroid Build Coastguard Worker   if (Oem_Checked)
193*f6dc9357SAndroid Build Coastguard Worker   {
194*f6dc9357SAndroid Build Coastguard Worker     s.Add_Space_if_NotEmpty();
195*f6dc9357SAndroid Build Coastguard Worker     s += (Oem_Ok ? "oem-ok" : "oem-error");
196*f6dc9357SAndroid Build Coastguard Worker   }
197*f6dc9357SAndroid Build Coastguard Worker   if (Utf_Checked)
198*f6dc9357SAndroid Build Coastguard Worker   */
199*f6dc9357SAndroid Build Coastguard Worker   else
200*f6dc9357SAndroid Build Coastguard Worker   {
201*f6dc9357SAndroid Build Coastguard Worker     s.Add_Space_if_NotEmpty();
202*f6dc9357SAndroid Build Coastguard Worker     s += (UtfCheck.IsOK() ? "UTF8" : "UTF8-ERROR"); // "UTF8-error"
203*f6dc9357SAndroid Build Coastguard Worker     {
204*f6dc9357SAndroid Build Coastguard Worker       AString s2;
205*f6dc9357SAndroid Build Coastguard Worker       UtfCheck.PrintStatus(s2);
206*f6dc9357SAndroid Build Coastguard Worker       s.Add_Space_if_NotEmpty();
207*f6dc9357SAndroid Build Coastguard Worker       s += s2;
208*f6dc9357SAndroid Build Coastguard Worker     }
209*f6dc9357SAndroid Build Coastguard Worker   }
210*f6dc9357SAndroid Build Coastguard Worker   return s;
211*f6dc9357SAndroid Build Coastguard Worker }
212*f6dc9357SAndroid Build Coastguard Worker 
213*f6dc9357SAndroid Build Coastguard Worker 
Open2(IInStream * stream,IArchiveOpenCallback * callback)214*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
215*f6dc9357SAndroid Build Coastguard Worker {
216*f6dc9357SAndroid Build Coastguard Worker   UInt64 endPos;
217*f6dc9357SAndroid Build Coastguard Worker   {
218*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_AtBegin_GetSize(stream, endPos))
219*f6dc9357SAndroid Build Coastguard Worker   }
220*f6dc9357SAndroid Build Coastguard Worker 
221*f6dc9357SAndroid Build Coastguard Worker   _arc._phySize_Defined = true;
222*f6dc9357SAndroid Build Coastguard Worker 
223*f6dc9357SAndroid Build Coastguard Worker   // bool utf8_OK = true;
224*f6dc9357SAndroid Build Coastguard Worker 
225*f6dc9357SAndroid Build Coastguard Worker   _arc.SeqStream = stream;
226*f6dc9357SAndroid Build Coastguard Worker   _arc.InStream = stream;
227*f6dc9357SAndroid Build Coastguard Worker   _arc.OpenCallback = callback;
228*f6dc9357SAndroid Build Coastguard Worker 
229*f6dc9357SAndroid Build Coastguard Worker   CItemEx item;
230*f6dc9357SAndroid Build Coastguard Worker   for (;;)
231*f6dc9357SAndroid Build Coastguard Worker   {
232*f6dc9357SAndroid Build Coastguard Worker     _arc.NumFiles = _items.Size();
233*f6dc9357SAndroid Build Coastguard Worker     RINOK(_arc.ReadItem(item))
234*f6dc9357SAndroid Build Coastguard Worker     if (!_arc.filled)
235*f6dc9357SAndroid Build Coastguard Worker       break;
236*f6dc9357SAndroid Build Coastguard Worker 
237*f6dc9357SAndroid Build Coastguard Worker     _isArc = true;
238*f6dc9357SAndroid Build Coastguard Worker 
239*f6dc9357SAndroid Build Coastguard Worker     /*
240*f6dc9357SAndroid Build Coastguard Worker     if (!_forceCodePage)
241*f6dc9357SAndroid Build Coastguard Worker     {
242*f6dc9357SAndroid Build Coastguard Worker       if (utf8_OK) utf8_OK = CheckUTF8(item.Name, item.NameCouldBeReduced);
243*f6dc9357SAndroid Build Coastguard Worker       if (utf8_OK) utf8_OK = CheckUTF8(item.LinkName, item.LinkNameCouldBeReduced);
244*f6dc9357SAndroid Build Coastguard Worker       if (utf8_OK) utf8_OK = CheckUTF8(item.User);
245*f6dc9357SAndroid Build Coastguard Worker       if (utf8_OK) utf8_OK = CheckUTF8(item.Group);
246*f6dc9357SAndroid Build Coastguard Worker     }
247*f6dc9357SAndroid Build Coastguard Worker     */
248*f6dc9357SAndroid Build Coastguard Worker 
249*f6dc9357SAndroid Build Coastguard Worker     item.EncodingCharacts.Check(item.Name);
250*f6dc9357SAndroid Build Coastguard Worker     _encodingCharacts.Update(item.EncodingCharacts);
251*f6dc9357SAndroid Build Coastguard Worker 
252*f6dc9357SAndroid Build Coastguard Worker     _items.Add(item);
253*f6dc9357SAndroid Build Coastguard Worker 
254*f6dc9357SAndroid Build Coastguard Worker     RINOK(stream->Seek((Int64)item.Get_PackSize_Aligned(), STREAM_SEEK_CUR, &_arc._phySize))
255*f6dc9357SAndroid Build Coastguard Worker     if (_arc._phySize > endPos)
256*f6dc9357SAndroid Build Coastguard Worker     {
257*f6dc9357SAndroid Build Coastguard Worker       _arc._error = k_ErrorType_UnexpectedEnd;
258*f6dc9357SAndroid Build Coastguard Worker       break;
259*f6dc9357SAndroid Build Coastguard Worker     }
260*f6dc9357SAndroid Build Coastguard Worker     /*
261*f6dc9357SAndroid Build Coastguard Worker     if (_phySize == endPos)
262*f6dc9357SAndroid Build Coastguard Worker     {
263*f6dc9357SAndroid Build Coastguard Worker       _errorMessage = "There are no trailing zero-filled records";
264*f6dc9357SAndroid Build Coastguard Worker       break;
265*f6dc9357SAndroid Build Coastguard Worker     }
266*f6dc9357SAndroid Build Coastguard Worker     */
267*f6dc9357SAndroid Build Coastguard Worker     /*
268*f6dc9357SAndroid Build Coastguard Worker     if (callback)
269*f6dc9357SAndroid Build Coastguard Worker     {
270*f6dc9357SAndroid Build Coastguard Worker       if (_items.Size() == 1)
271*f6dc9357SAndroid Build Coastguard Worker       {
272*f6dc9357SAndroid Build Coastguard Worker         RINOK(callback->SetTotal(NULL, &endPos));
273*f6dc9357SAndroid Build Coastguard Worker       }
274*f6dc9357SAndroid Build Coastguard Worker       if ((_items.Size() & 0x3FF) == 0)
275*f6dc9357SAndroid Build Coastguard Worker       {
276*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numFiles = _items.Size();
277*f6dc9357SAndroid Build Coastguard Worker         RINOK(callback->SetCompleted(&numFiles, &_phySize));
278*f6dc9357SAndroid Build Coastguard Worker       }
279*f6dc9357SAndroid Build Coastguard Worker     }
280*f6dc9357SAndroid Build Coastguard Worker     */
281*f6dc9357SAndroid Build Coastguard Worker   }
282*f6dc9357SAndroid Build Coastguard Worker 
283*f6dc9357SAndroid Build Coastguard Worker   /*
284*f6dc9357SAndroid Build Coastguard Worker   if (!_forceCodePage)
285*f6dc9357SAndroid Build Coastguard Worker   {
286*f6dc9357SAndroid Build Coastguard Worker     if (!utf8_OK)
287*f6dc9357SAndroid Build Coastguard Worker       _curCodePage = k_DefaultCodePage;
288*f6dc9357SAndroid Build Coastguard Worker   }
289*f6dc9357SAndroid Build Coastguard Worker   */
290*f6dc9357SAndroid Build Coastguard Worker   _openCodePage = _curCodePage;
291*f6dc9357SAndroid Build Coastguard Worker 
292*f6dc9357SAndroid Build Coastguard Worker   if (_items.Size() == 0)
293*f6dc9357SAndroid Build Coastguard Worker   {
294*f6dc9357SAndroid Build Coastguard Worker     if (_arc._error != k_ErrorType_OK)
295*f6dc9357SAndroid Build Coastguard Worker     {
296*f6dc9357SAndroid Build Coastguard Worker       _isArc = false;
297*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
298*f6dc9357SAndroid Build Coastguard Worker     }
299*f6dc9357SAndroid Build Coastguard Worker     if (!callback)
300*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
301*f6dc9357SAndroid Build Coastguard Worker     Z7_DECL_CMyComPtr_QI_FROM(
302*f6dc9357SAndroid Build Coastguard Worker         IArchiveOpenVolumeCallback,
303*f6dc9357SAndroid Build Coastguard Worker         openVolumeCallback, callback)
304*f6dc9357SAndroid Build Coastguard Worker     if (!openVolumeCallback)
305*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
306*f6dc9357SAndroid Build Coastguard Worker     NCOM::CPropVariant prop;
307*f6dc9357SAndroid Build Coastguard Worker     if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK)
308*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
309*f6dc9357SAndroid Build Coastguard Worker     if (prop.vt != VT_BSTR)
310*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
311*f6dc9357SAndroid Build Coastguard Worker     unsigned len = MyStringLen(prop.bstrVal);
312*f6dc9357SAndroid Build Coastguard Worker     if (len < 4 || MyStringCompareNoCase(prop.bstrVal + len - 4, L".tar") != 0)
313*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
314*f6dc9357SAndroid Build Coastguard Worker   }
315*f6dc9357SAndroid Build Coastguard Worker 
316*f6dc9357SAndroid Build Coastguard Worker   _isArc = true;
317*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
318*f6dc9357SAndroid Build Coastguard Worker }
319*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback * openArchiveCallback))320*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback))
321*f6dc9357SAndroid Build Coastguard Worker {
322*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
323*f6dc9357SAndroid Build Coastguard Worker   // for (int i = 0; i < 10; i++) // for debug
324*f6dc9357SAndroid Build Coastguard Worker   {
325*f6dc9357SAndroid Build Coastguard Worker     Close();
326*f6dc9357SAndroid Build Coastguard Worker     RINOK(Open2(stream, openArchiveCallback))
327*f6dc9357SAndroid Build Coastguard Worker     _stream = stream;
328*f6dc9357SAndroid Build Coastguard Worker   }
329*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
330*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
331*f6dc9357SAndroid Build Coastguard Worker }
332*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::OpenSeq (ISequentialInStream * stream))333*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
334*f6dc9357SAndroid Build Coastguard Worker {
335*f6dc9357SAndroid Build Coastguard Worker   Close();
336*f6dc9357SAndroid Build Coastguard Worker   _seqStream = stream;
337*f6dc9357SAndroid Build Coastguard Worker   _isArc = true;
338*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
339*f6dc9357SAndroid Build Coastguard Worker }
340*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Close ())341*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
342*f6dc9357SAndroid Build Coastguard Worker {
343*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
344*f6dc9357SAndroid Build Coastguard Worker 
345*f6dc9357SAndroid Build Coastguard Worker   _arc.Clear();
346*f6dc9357SAndroid Build Coastguard Worker 
347*f6dc9357SAndroid Build Coastguard Worker   _curIndex = 0;
348*f6dc9357SAndroid Build Coastguard Worker   _latestIsRead = false;
349*f6dc9357SAndroid Build Coastguard Worker   _encodingCharacts.Clear();
350*f6dc9357SAndroid Build Coastguard Worker   _items.Clear();
351*f6dc9357SAndroid Build Coastguard Worker   _seqStream.Release();
352*f6dc9357SAndroid Build Coastguard Worker   _stream.Release();
353*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
354*f6dc9357SAndroid Build Coastguard Worker }
355*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))356*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
357*f6dc9357SAndroid Build Coastguard Worker {
358*f6dc9357SAndroid Build Coastguard Worker   *numItems = (_stream ? _items.Size() : (UInt32)(Int32)-1);
359*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
360*f6dc9357SAndroid Build Coastguard Worker }
361*f6dc9357SAndroid Build Coastguard Worker 
CHandler()362*f6dc9357SAndroid Build Coastguard Worker CHandler::CHandler()
363*f6dc9357SAndroid Build Coastguard Worker {
364*f6dc9357SAndroid Build Coastguard Worker   // copyCoder = new NCompress::CCopyCoder();
365*f6dc9357SAndroid Build Coastguard Worker   // copyCoder = copyCoder;
366*f6dc9357SAndroid Build Coastguard Worker   _openCodePage = CP_UTF8;
367*f6dc9357SAndroid Build Coastguard Worker   Init();
368*f6dc9357SAndroid Build Coastguard Worker }
369*f6dc9357SAndroid Build Coastguard Worker 
SkipTo(UInt32 index)370*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::SkipTo(UInt32 index)
371*f6dc9357SAndroid Build Coastguard Worker {
372*f6dc9357SAndroid Build Coastguard Worker   while (_curIndex < index || !_latestIsRead)
373*f6dc9357SAndroid Build Coastguard Worker   {
374*f6dc9357SAndroid Build Coastguard Worker     if (_latestIsRead)
375*f6dc9357SAndroid Build Coastguard Worker     {
376*f6dc9357SAndroid Build Coastguard Worker       const UInt64 packSize = _latestItem.Get_PackSize_Aligned();
377*f6dc9357SAndroid Build Coastguard Worker       RINOK(copyCoder.Interface()->Code(_seqStream, NULL, &packSize, &packSize, NULL))
378*f6dc9357SAndroid Build Coastguard Worker       _arc._phySize += copyCoder->TotalSize;
379*f6dc9357SAndroid Build Coastguard Worker       if (copyCoder->TotalSize != packSize)
380*f6dc9357SAndroid Build Coastguard Worker       {
381*f6dc9357SAndroid Build Coastguard Worker         _arc._error = k_ErrorType_UnexpectedEnd;
382*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
383*f6dc9357SAndroid Build Coastguard Worker       }
384*f6dc9357SAndroid Build Coastguard Worker       _latestIsRead = false;
385*f6dc9357SAndroid Build Coastguard Worker       _curIndex++;
386*f6dc9357SAndroid Build Coastguard Worker     }
387*f6dc9357SAndroid Build Coastguard Worker     else
388*f6dc9357SAndroid Build Coastguard Worker     {
389*f6dc9357SAndroid Build Coastguard Worker       _arc.SeqStream = _seqStream;
390*f6dc9357SAndroid Build Coastguard Worker       _arc.InStream = NULL;
391*f6dc9357SAndroid Build Coastguard Worker       RINOK(_arc.ReadItem(_latestItem))
392*f6dc9357SAndroid Build Coastguard Worker       if (!_arc.filled)
393*f6dc9357SAndroid Build Coastguard Worker       {
394*f6dc9357SAndroid Build Coastguard Worker         _arc._phySize_Defined = true;
395*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
396*f6dc9357SAndroid Build Coastguard Worker       }
397*f6dc9357SAndroid Build Coastguard Worker       _latestIsRead = true;
398*f6dc9357SAndroid Build Coastguard Worker     }
399*f6dc9357SAndroid Build Coastguard Worker   }
400*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
401*f6dc9357SAndroid Build Coastguard Worker }
402*f6dc9357SAndroid Build Coastguard Worker 
TarStringToUnicode(const AString & s,NWindows::NCOM::CPropVariant & prop,bool toOs) const403*f6dc9357SAndroid Build Coastguard Worker void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs) const
404*f6dc9357SAndroid Build Coastguard Worker {
405*f6dc9357SAndroid Build Coastguard Worker   UString dest;
406*f6dc9357SAndroid Build Coastguard Worker   if (_curCodePage == CP_UTF8)
407*f6dc9357SAndroid Build Coastguard Worker     ConvertUTF8ToUnicode(s, dest);
408*f6dc9357SAndroid Build Coastguard Worker   else
409*f6dc9357SAndroid Build Coastguard Worker     MultiByteToUnicodeString2(dest, s, _curCodePage);
410*f6dc9357SAndroid Build Coastguard Worker   if (toOs)
411*f6dc9357SAndroid Build Coastguard Worker     NItemName::ReplaceToOsSlashes_Remove_TailSlash(dest,
412*f6dc9357SAndroid Build Coastguard Worker         true); // useBackslashReplacement
413*f6dc9357SAndroid Build Coastguard Worker   prop = dest;
414*f6dc9357SAndroid Build Coastguard Worker }
415*f6dc9357SAndroid Build Coastguard Worker 
416*f6dc9357SAndroid Build Coastguard Worker 
417*f6dc9357SAndroid Build Coastguard Worker // CPaxTime is defined (NumDigits >= 0)
PaxTimeToProp(const CPaxTime & pt,NWindows::NCOM::CPropVariant & prop)418*f6dc9357SAndroid Build Coastguard Worker static void PaxTimeToProp(const CPaxTime &pt, NWindows::NCOM::CPropVariant &prop)
419*f6dc9357SAndroid Build Coastguard Worker {
420*f6dc9357SAndroid Build Coastguard Worker   UInt64 v;
421*f6dc9357SAndroid Build Coastguard Worker   if (!NTime::UnixTime64_To_FileTime64(pt.Sec, v))
422*f6dc9357SAndroid Build Coastguard Worker     return;
423*f6dc9357SAndroid Build Coastguard Worker   if (pt.Ns != 0)
424*f6dc9357SAndroid Build Coastguard Worker     v += pt.Ns / 100;
425*f6dc9357SAndroid Build Coastguard Worker   FILETIME ft;
426*f6dc9357SAndroid Build Coastguard Worker   ft.dwLowDateTime = (DWORD)v;
427*f6dc9357SAndroid Build Coastguard Worker   ft.dwHighDateTime = (DWORD)(v >> 32);
428*f6dc9357SAndroid Build Coastguard Worker   prop.SetAsTimeFrom_FT_Prec_Ns100(ft,
429*f6dc9357SAndroid Build Coastguard Worker       k_PropVar_TimePrec_Base + (unsigned)pt.NumDigits, pt.Ns % 100);
430*f6dc9357SAndroid Build Coastguard Worker }
431*f6dc9357SAndroid Build Coastguard Worker 
432*f6dc9357SAndroid Build Coastguard Worker 
AddSpecCharToString(const char c,AString & s)433*f6dc9357SAndroid Build Coastguard Worker static void AddSpecCharToString(const char c, AString &s)
434*f6dc9357SAndroid Build Coastguard Worker {
435*f6dc9357SAndroid Build Coastguard Worker   if ((Byte)c <= 0x20 || (Byte)c > 127)
436*f6dc9357SAndroid Build Coastguard Worker   {
437*f6dc9357SAndroid Build Coastguard Worker     s.Add_Char('[');
438*f6dc9357SAndroid Build Coastguard Worker     s.Add_Char(GET_HEX_CHAR_LOWER((Byte)c >> 4));
439*f6dc9357SAndroid Build Coastguard Worker     s.Add_Char(GET_HEX_CHAR_LOWER(c & 15));
440*f6dc9357SAndroid Build Coastguard Worker     s.Add_Char(']');
441*f6dc9357SAndroid Build Coastguard Worker   }
442*f6dc9357SAndroid Build Coastguard Worker   else
443*f6dc9357SAndroid Build Coastguard Worker     s.Add_Char(c);
444*f6dc9357SAndroid Build Coastguard Worker }
445*f6dc9357SAndroid Build Coastguard Worker 
AddSpecUInt64(AString & s,const char * name,UInt64 v)446*f6dc9357SAndroid Build Coastguard Worker static void AddSpecUInt64(AString &s, const char *name, UInt64 v)
447*f6dc9357SAndroid Build Coastguard Worker {
448*f6dc9357SAndroid Build Coastguard Worker   if (v != 0)
449*f6dc9357SAndroid Build Coastguard Worker   {
450*f6dc9357SAndroid Build Coastguard Worker     s.Add_OptSpaced(name);
451*f6dc9357SAndroid Build Coastguard Worker     if (v > 1)
452*f6dc9357SAndroid Build Coastguard Worker     {
453*f6dc9357SAndroid Build Coastguard Worker       s.Add_Colon();
454*f6dc9357SAndroid Build Coastguard Worker       s.Add_UInt64(v);
455*f6dc9357SAndroid Build Coastguard Worker     }
456*f6dc9357SAndroid Build Coastguard Worker   }
457*f6dc9357SAndroid Build Coastguard Worker }
458*f6dc9357SAndroid Build Coastguard Worker 
AddSpecBools(AString & s,const char * name,bool b1,bool b2)459*f6dc9357SAndroid Build Coastguard Worker static void AddSpecBools(AString &s, const char *name, bool b1, bool b2)
460*f6dc9357SAndroid Build Coastguard Worker {
461*f6dc9357SAndroid Build Coastguard Worker   if (b1)
462*f6dc9357SAndroid Build Coastguard Worker   {
463*f6dc9357SAndroid Build Coastguard Worker     s.Add_OptSpaced(name);
464*f6dc9357SAndroid Build Coastguard Worker     if (b2)
465*f6dc9357SAndroid Build Coastguard Worker       s.Add_Char('*');
466*f6dc9357SAndroid Build Coastguard Worker   }
467*f6dc9357SAndroid Build Coastguard Worker }
468*f6dc9357SAndroid Build Coastguard Worker 
469*f6dc9357SAndroid Build Coastguard Worker 
470*f6dc9357SAndroid Build Coastguard Worker #if 0
Parse_Attrib_from_SCHILY_fflags(const AString & s,UInt32 & attribRes)471*f6dc9357SAndroid Build Coastguard Worker static bool Parse_Attrib_from_SCHILY_fflags(const AString &s, UInt32 &attribRes)
472*f6dc9357SAndroid Build Coastguard Worker {
473*f6dc9357SAndroid Build Coastguard Worker   UInt32 attrib = 0;
474*f6dc9357SAndroid Build Coastguard Worker   attribRes = attrib;
475*f6dc9357SAndroid Build Coastguard Worker   unsigned pos = 0;
476*f6dc9357SAndroid Build Coastguard Worker   while (pos < s.Len())
477*f6dc9357SAndroid Build Coastguard Worker   {
478*f6dc9357SAndroid Build Coastguard Worker     int pos2 = s.Find(',', pos);
479*f6dc9357SAndroid Build Coastguard Worker     if (pos2 < 0)
480*f6dc9357SAndroid Build Coastguard Worker       pos2 = (int)s.Len();
481*f6dc9357SAndroid Build Coastguard Worker     const AString str = s.Mid(pos, (unsigned)pos2 - pos);
482*f6dc9357SAndroid Build Coastguard Worker           if (str.IsEqualTo("hidden"))  attrib |= FILE_ATTRIBUTE_HIDDEN;
483*f6dc9357SAndroid Build Coastguard Worker     else  if (str.IsEqualTo("rdonly"))  attrib |= FILE_ATTRIBUTE_READONLY;
484*f6dc9357SAndroid Build Coastguard Worker     else  if (str.IsEqualTo("system"))  attrib |= FILE_ATTRIBUTE_SYSTEM;
485*f6dc9357SAndroid Build Coastguard Worker     else
486*f6dc9357SAndroid Build Coastguard Worker       return false;
487*f6dc9357SAndroid Build Coastguard Worker     pos = (unsigned)pos2 + 1;
488*f6dc9357SAndroid Build Coastguard Worker   }
489*f6dc9357SAndroid Build Coastguard Worker   attribRes = attrib;
490*f6dc9357SAndroid Build Coastguard Worker   return true;
491*f6dc9357SAndroid Build Coastguard Worker }
492*f6dc9357SAndroid Build Coastguard Worker #endif
493*f6dc9357SAndroid Build Coastguard Worker 
494*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))495*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
496*f6dc9357SAndroid Build Coastguard Worker {
497*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
498*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
499*f6dc9357SAndroid Build Coastguard Worker 
500*f6dc9357SAndroid Build Coastguard Worker   const CItemEx *item;
501*f6dc9357SAndroid Build Coastguard Worker   if (_stream)
502*f6dc9357SAndroid Build Coastguard Worker     item = &_items[index];
503*f6dc9357SAndroid Build Coastguard Worker   else
504*f6dc9357SAndroid Build Coastguard Worker   {
505*f6dc9357SAndroid Build Coastguard Worker     if (index < _curIndex)
506*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
507*f6dc9357SAndroid Build Coastguard Worker     else
508*f6dc9357SAndroid Build Coastguard Worker     {
509*f6dc9357SAndroid Build Coastguard Worker       RINOK(SkipTo(index))
510*f6dc9357SAndroid Build Coastguard Worker       item = &_latestItem;
511*f6dc9357SAndroid Build Coastguard Worker     }
512*f6dc9357SAndroid Build Coastguard Worker   }
513*f6dc9357SAndroid Build Coastguard Worker 
514*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
515*f6dc9357SAndroid Build Coastguard Worker   {
516*f6dc9357SAndroid Build Coastguard Worker     case kpidPath: TarStringToUnicode(item->Name, prop, true); break;
517*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDir: prop = item->IsDir(); break;
518*f6dc9357SAndroid Build Coastguard Worker     case kpidSize: prop = item->Get_UnpackSize(); break;
519*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize: prop = item->Get_PackSize_Aligned(); break;
520*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime:
521*f6dc9357SAndroid Build Coastguard Worker     {
522*f6dc9357SAndroid Build Coastguard Worker       /*
523*f6dc9357SAndroid Build Coastguard Worker       // for debug:
524*f6dc9357SAndroid Build Coastguard Worker       PropVariant_SetFrom_UnixTime(prop, 1 << 30);
525*f6dc9357SAndroid Build Coastguard Worker       prop.wReserved1 = k_PropVar_TimePrec_Base + 1;
526*f6dc9357SAndroid Build Coastguard Worker       prop.wReserved2 = 12;
527*f6dc9357SAndroid Build Coastguard Worker       break;
528*f6dc9357SAndroid Build Coastguard Worker       */
529*f6dc9357SAndroid Build Coastguard Worker 
530*f6dc9357SAndroid Build Coastguard Worker       if (item->PaxTimes.MTime.IsDefined())
531*f6dc9357SAndroid Build Coastguard Worker         PaxTimeToProp(item->PaxTimes.MTime, prop);
532*f6dc9357SAndroid Build Coastguard Worker       else
533*f6dc9357SAndroid Build Coastguard Worker       // if (item->MTime != 0)
534*f6dc9357SAndroid Build Coastguard Worker       {
535*f6dc9357SAndroid Build Coastguard Worker         // we allow (item->MTime == 0)
536*f6dc9357SAndroid Build Coastguard Worker         FILETIME ft;
537*f6dc9357SAndroid Build Coastguard Worker         if (NTime::UnixTime64_To_FileTime(item->MTime, ft))
538*f6dc9357SAndroid Build Coastguard Worker         {
539*f6dc9357SAndroid Build Coastguard Worker           unsigned prec = k_PropVar_TimePrec_Unix;
540*f6dc9357SAndroid Build Coastguard Worker           if (item->MTime_IsBin)
541*f6dc9357SAndroid Build Coastguard Worker           {
542*f6dc9357SAndroid Build Coastguard Worker             /* we report here that it's Int64-UnixTime
543*f6dc9357SAndroid Build Coastguard Worker                instead of basic UInt32-UnixTime range */
544*f6dc9357SAndroid Build Coastguard Worker             prec = k_PropVar_TimePrec_Base;
545*f6dc9357SAndroid Build Coastguard Worker           }
546*f6dc9357SAndroid Build Coastguard Worker           prop.SetAsTimeFrom_FT_Prec(ft, prec);
547*f6dc9357SAndroid Build Coastguard Worker         }
548*f6dc9357SAndroid Build Coastguard Worker       }
549*f6dc9357SAndroid Build Coastguard Worker       break;
550*f6dc9357SAndroid Build Coastguard Worker     }
551*f6dc9357SAndroid Build Coastguard Worker     case kpidATime:
552*f6dc9357SAndroid Build Coastguard Worker       if (item->PaxTimes.ATime.IsDefined())
553*f6dc9357SAndroid Build Coastguard Worker         PaxTimeToProp(item->PaxTimes.ATime, prop);
554*f6dc9357SAndroid Build Coastguard Worker       break;
555*f6dc9357SAndroid Build Coastguard Worker     case kpidCTime:
556*f6dc9357SAndroid Build Coastguard Worker       if (item->PaxTimes.CTime.IsDefined())
557*f6dc9357SAndroid Build Coastguard Worker         PaxTimeToProp(item->PaxTimes.CTime, prop);
558*f6dc9357SAndroid Build Coastguard Worker       break;
559*f6dc9357SAndroid Build Coastguard Worker     case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break;
560*f6dc9357SAndroid Build Coastguard Worker 
561*f6dc9357SAndroid Build Coastguard Worker     // kpidAttrib has priority over kpidPosixAttrib in 7-Zip.
562*f6dc9357SAndroid Build Coastguard Worker     // but if we want kpidPosixAttrib priority for TAR, we disable kpidAttrib.
563*f6dc9357SAndroid Build Coastguard Worker #if 0
564*f6dc9357SAndroid Build Coastguard Worker     case kpidAttrib:
565*f6dc9357SAndroid Build Coastguard Worker     {
566*f6dc9357SAndroid Build Coastguard Worker       if (!item->SCHILY_fflags.IsEmpty())
567*f6dc9357SAndroid Build Coastguard Worker       {
568*f6dc9357SAndroid Build Coastguard Worker         UInt32 attrib = 0;
569*f6dc9357SAndroid Build Coastguard Worker         if (Parse_Attrib_from_SCHILY_fflags(item->SCHILY_fflags, attrib))
570*f6dc9357SAndroid Build Coastguard Worker         {
571*f6dc9357SAndroid Build Coastguard Worker           if (attrib != 0)
572*f6dc9357SAndroid Build Coastguard Worker           {
573*f6dc9357SAndroid Build Coastguard Worker             if (item->IsDir())
574*f6dc9357SAndroid Build Coastguard Worker               attrib |= FILE_ATTRIBUTE_DIRECTORY;
575*f6dc9357SAndroid Build Coastguard Worker             attrib |= ((UInt32)item->Get_Combined_Mode() << 16) | 0x8000; // FILE_ATTRIBUTE_UNIX_EXTENSION;
576*f6dc9357SAndroid Build Coastguard Worker             prop = attrib;
577*f6dc9357SAndroid Build Coastguard Worker           }
578*f6dc9357SAndroid Build Coastguard Worker         }
579*f6dc9357SAndroid Build Coastguard Worker       }
580*f6dc9357SAndroid Build Coastguard Worker       break;
581*f6dc9357SAndroid Build Coastguard Worker     }
582*f6dc9357SAndroid Build Coastguard Worker #endif
583*f6dc9357SAndroid Build Coastguard Worker 
584*f6dc9357SAndroid Build Coastguard Worker     case kpidUser:
585*f6dc9357SAndroid Build Coastguard Worker       if (!item->User.IsEmpty())
586*f6dc9357SAndroid Build Coastguard Worker         TarStringToUnicode(item->User, prop);
587*f6dc9357SAndroid Build Coastguard Worker       break;
588*f6dc9357SAndroid Build Coastguard Worker     case kpidGroup:
589*f6dc9357SAndroid Build Coastguard Worker       if (!item->Group.IsEmpty())
590*f6dc9357SAndroid Build Coastguard Worker         TarStringToUnicode(item->Group, prop);
591*f6dc9357SAndroid Build Coastguard Worker       break;
592*f6dc9357SAndroid Build Coastguard Worker 
593*f6dc9357SAndroid Build Coastguard Worker     case kpidUserId:
594*f6dc9357SAndroid Build Coastguard Worker       // if (item->UID != 0)
595*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)item->UID;
596*f6dc9357SAndroid Build Coastguard Worker       break;
597*f6dc9357SAndroid Build Coastguard Worker     case kpidGroupId:
598*f6dc9357SAndroid Build Coastguard Worker       // if (item->GID != 0)
599*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)item->GID;
600*f6dc9357SAndroid Build Coastguard Worker       break;
601*f6dc9357SAndroid Build Coastguard Worker 
602*f6dc9357SAndroid Build Coastguard Worker     case kpidDeviceMajor:
603*f6dc9357SAndroid Build Coastguard Worker       if (item->DeviceMajor_Defined)
604*f6dc9357SAndroid Build Coastguard Worker       // if (item->DeviceMajor != 0)
605*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)item->DeviceMajor;
606*f6dc9357SAndroid Build Coastguard Worker       break;
607*f6dc9357SAndroid Build Coastguard Worker 
608*f6dc9357SAndroid Build Coastguard Worker     case kpidDeviceMinor:
609*f6dc9357SAndroid Build Coastguard Worker       if (item->DeviceMinor_Defined)
610*f6dc9357SAndroid Build Coastguard Worker       // if (item->DeviceMinor != 0)
611*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)item->DeviceMinor;
612*f6dc9357SAndroid Build Coastguard Worker       break;
613*f6dc9357SAndroid Build Coastguard Worker     /*
614*f6dc9357SAndroid Build Coastguard Worker     case kpidDevice:
615*f6dc9357SAndroid Build Coastguard Worker       if (item->DeviceMajor_Defined)
616*f6dc9357SAndroid Build Coastguard Worker       if (item->DeviceMinor_Defined)
617*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt64)MY_dev_makedev(item->DeviceMajor, item->DeviceMinor);
618*f6dc9357SAndroid Build Coastguard Worker       break;
619*f6dc9357SAndroid Build Coastguard Worker     */
620*f6dc9357SAndroid Build Coastguard Worker 
621*f6dc9357SAndroid Build Coastguard Worker     case kpidSymLink:
622*f6dc9357SAndroid Build Coastguard Worker       if (item->Is_SymLink())
623*f6dc9357SAndroid Build Coastguard Worker         if (!item->LinkName.IsEmpty())
624*f6dc9357SAndroid Build Coastguard Worker           TarStringToUnicode(item->LinkName, prop);
625*f6dc9357SAndroid Build Coastguard Worker       break;
626*f6dc9357SAndroid Build Coastguard Worker     case kpidHardLink:
627*f6dc9357SAndroid Build Coastguard Worker       if (item->Is_HardLink())
628*f6dc9357SAndroid Build Coastguard Worker         if (!item->LinkName.IsEmpty())
629*f6dc9357SAndroid Build Coastguard Worker           TarStringToUnicode(item->LinkName, prop);
630*f6dc9357SAndroid Build Coastguard Worker       break;
631*f6dc9357SAndroid Build Coastguard Worker 
632*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts:
633*f6dc9357SAndroid Build Coastguard Worker     {
634*f6dc9357SAndroid Build Coastguard Worker       AString s;
635*f6dc9357SAndroid Build Coastguard Worker       {
636*f6dc9357SAndroid Build Coastguard Worker         s.Add_Space_if_NotEmpty();
637*f6dc9357SAndroid Build Coastguard Worker         AddSpecCharToString(item->LinkFlag, s);
638*f6dc9357SAndroid Build Coastguard Worker       }
639*f6dc9357SAndroid Build Coastguard Worker       if (item->IsMagic_GNU())
640*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("GNU");
641*f6dc9357SAndroid Build Coastguard Worker       else if (item->IsMagic_Posix_ustar_00())
642*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("POSIX");
643*f6dc9357SAndroid Build Coastguard Worker       else
644*f6dc9357SAndroid Build Coastguard Worker       {
645*f6dc9357SAndroid Build Coastguard Worker         s.Add_Space_if_NotEmpty();
646*f6dc9357SAndroid Build Coastguard Worker         for (unsigned i = 0; i < sizeof(item->Magic); i++)
647*f6dc9357SAndroid Build Coastguard Worker           AddSpecCharToString(item->Magic[i], s);
648*f6dc9357SAndroid Build Coastguard Worker       }
649*f6dc9357SAndroid Build Coastguard Worker 
650*f6dc9357SAndroid Build Coastguard Worker       if (item->IsSignedChecksum)
651*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("SignedChecksum");
652*f6dc9357SAndroid Build Coastguard Worker 
653*f6dc9357SAndroid Build Coastguard Worker       if (item->Prefix_WasUsed)
654*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced(k_Characts_Prefix);
655*f6dc9357SAndroid Build Coastguard Worker 
656*f6dc9357SAndroid Build Coastguard Worker       s.Add_OptSpaced(item->EncodingCharacts.GetCharactsString());
657*f6dc9357SAndroid Build Coastguard Worker 
658*f6dc9357SAndroid Build Coastguard Worker       // AddSpecUInt64(s, "LongName", item->Num_LongName_Records);
659*f6dc9357SAndroid Build Coastguard Worker       // AddSpecUInt64(s, "LongLink", item->Num_LongLink_Records);
660*f6dc9357SAndroid Build Coastguard Worker       AddSpecBools(s, "LongName", item->LongName_WasUsed, item->LongName_WasUsed_2);
661*f6dc9357SAndroid Build Coastguard Worker       AddSpecBools(s, "LongLink", item->LongLink_WasUsed, item->LongLink_WasUsed_2);
662*f6dc9357SAndroid Build Coastguard Worker 
663*f6dc9357SAndroid Build Coastguard Worker       if (item->MTime_IsBin)
664*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("bin_mtime");
665*f6dc9357SAndroid Build Coastguard Worker       if (item->PackSize_IsBin)
666*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("bin_psize");
667*f6dc9357SAndroid Build Coastguard Worker       if (item->Size_IsBin)
668*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("bin_size");
669*f6dc9357SAndroid Build Coastguard Worker 
670*f6dc9357SAndroid Build Coastguard Worker       AddSpecUInt64(s, "PAX", item->Num_Pax_Records);
671*f6dc9357SAndroid Build Coastguard Worker 
672*f6dc9357SAndroid Build Coastguard Worker       if (item->PaxTimes.MTime.IsDefined()) s.Add_OptSpaced("mtime");
673*f6dc9357SAndroid Build Coastguard Worker       if (item->PaxTimes.ATime.IsDefined()) s.Add_OptSpaced("atime");
674*f6dc9357SAndroid Build Coastguard Worker       if (item->PaxTimes.CTime.IsDefined()) s.Add_OptSpaced("ctime");
675*f6dc9357SAndroid Build Coastguard Worker 
676*f6dc9357SAndroid Build Coastguard Worker       if (item->pax_path_WasUsed)
677*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("pax_path");
678*f6dc9357SAndroid Build Coastguard Worker       if (item->pax_link_WasUsed)
679*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("pax_linkpath");
680*f6dc9357SAndroid Build Coastguard Worker       if (item->pax_size_WasUsed)
681*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("pax_size");
682*f6dc9357SAndroid Build Coastguard Worker       if (!item->SCHILY_fflags.IsEmpty())
683*f6dc9357SAndroid Build Coastguard Worker       {
684*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("SCHILY.fflags=");
685*f6dc9357SAndroid Build Coastguard Worker         s += item->SCHILY_fflags;
686*f6dc9357SAndroid Build Coastguard Worker       }
687*f6dc9357SAndroid Build Coastguard Worker       if (item->IsThereWarning())
688*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("WARNING");
689*f6dc9357SAndroid Build Coastguard Worker       if (item->HeaderError)
690*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("ERROR");
691*f6dc9357SAndroid Build Coastguard Worker       if (item->Pax_Error)
692*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("PAX_error");
693*f6dc9357SAndroid Build Coastguard Worker       if (!item->PaxExtra.RawLines.IsEmpty())
694*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("PAX_unsupported_line");
695*f6dc9357SAndroid Build Coastguard Worker       if (item->Pax_Overflow)
696*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("PAX_overflow");
697*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
698*f6dc9357SAndroid Build Coastguard Worker         prop = s;
699*f6dc9357SAndroid Build Coastguard Worker       break;
700*f6dc9357SAndroid Build Coastguard Worker     }
701*f6dc9357SAndroid Build Coastguard Worker     case kpidComment:
702*f6dc9357SAndroid Build Coastguard Worker     {
703*f6dc9357SAndroid Build Coastguard Worker       AString s;
704*f6dc9357SAndroid Build Coastguard Worker       item->PaxExtra.Print_To_String(s);
705*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
706*f6dc9357SAndroid Build Coastguard Worker         prop = s;
707*f6dc9357SAndroid Build Coastguard Worker       break;
708*f6dc9357SAndroid Build Coastguard Worker     }
709*f6dc9357SAndroid Build Coastguard Worker     // case kpidHeadersSize: prop = item->HeaderSize; break; // for debug
710*f6dc9357SAndroid Build Coastguard Worker     // case kpidOffset: prop = item->HeaderPos; break; // for debug
711*f6dc9357SAndroid Build Coastguard Worker     default: break;
712*f6dc9357SAndroid Build Coastguard Worker   }
713*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
714*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
715*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
716*f6dc9357SAndroid Build Coastguard Worker }
717*f6dc9357SAndroid Build Coastguard Worker 
718*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))719*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
720*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
721*f6dc9357SAndroid Build Coastguard Worker {
722*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
723*f6dc9357SAndroid Build Coastguard Worker   ISequentialInStream *stream = _seqStream;
724*f6dc9357SAndroid Build Coastguard Worker   const bool seqMode = (_stream == NULL);
725*f6dc9357SAndroid Build Coastguard Worker   if (!seqMode)
726*f6dc9357SAndroid Build Coastguard Worker     stream = _stream;
727*f6dc9357SAndroid Build Coastguard Worker 
728*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
729*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
730*f6dc9357SAndroid Build Coastguard Worker     numItems = _items.Size();
731*f6dc9357SAndroid Build Coastguard Worker   if (_stream && numItems == 0)
732*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
733*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
734*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
735*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
736*f6dc9357SAndroid Build Coastguard Worker     totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize();
737*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(totalSize))
738*f6dc9357SAndroid Build Coastguard Worker 
739*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalPackSize;
740*f6dc9357SAndroid Build Coastguard Worker   totalSize = totalPackSize = 0;
741*f6dc9357SAndroid Build Coastguard Worker 
742*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
743*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
744*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
745*f6dc9357SAndroid Build Coastguard Worker   inStream->SetStream(stream);
746*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialOutStream, CLimitedSequentialOutStream> outStreamSpec;
747*f6dc9357SAndroid Build Coastguard Worker 
748*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; ; i++)
749*f6dc9357SAndroid Build Coastguard Worker   {
750*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = totalPackSize;
751*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = totalSize;
752*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
753*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems && !seqMode)
754*f6dc9357SAndroid Build Coastguard Worker       break;
755*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
756*f6dc9357SAndroid Build Coastguard Worker     const CItemEx *item;
757*f6dc9357SAndroid Build Coastguard Worker     if (seqMode)
758*f6dc9357SAndroid Build Coastguard Worker     {
759*f6dc9357SAndroid Build Coastguard Worker       const HRESULT res = SkipTo(index);
760*f6dc9357SAndroid Build Coastguard Worker       if (res == E_INVALIDARG)
761*f6dc9357SAndroid Build Coastguard Worker         break;
762*f6dc9357SAndroid Build Coastguard Worker       RINOK(res)
763*f6dc9357SAndroid Build Coastguard Worker       item = &_latestItem;
764*f6dc9357SAndroid Build Coastguard Worker     }
765*f6dc9357SAndroid Build Coastguard Worker     else
766*f6dc9357SAndroid Build Coastguard Worker       item = &_items[index];
767*f6dc9357SAndroid Build Coastguard Worker 
768*f6dc9357SAndroid Build Coastguard Worker     Int32 askMode = testMode ?
769*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kTest :
770*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kExtract;
771*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialOutStream> realOutStream;
772*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
773*f6dc9357SAndroid Build Coastguard Worker     const UInt64 unpackSize = item->Get_UnpackSize();
774*f6dc9357SAndroid Build Coastguard Worker     totalSize += unpackSize;
775*f6dc9357SAndroid Build Coastguard Worker     totalPackSize += item->Get_PackSize_Aligned();
776*f6dc9357SAndroid Build Coastguard Worker     if (item->IsDir())
777*f6dc9357SAndroid Build Coastguard Worker     {
778*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
779*f6dc9357SAndroid Build Coastguard Worker       // realOutStream.Release();
780*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
781*f6dc9357SAndroid Build Coastguard Worker       continue;
782*f6dc9357SAndroid Build Coastguard Worker     }
783*f6dc9357SAndroid Build Coastguard Worker     bool skipMode = false;
784*f6dc9357SAndroid Build Coastguard Worker     if (!testMode && !realOutStream)
785*f6dc9357SAndroid Build Coastguard Worker     {
786*f6dc9357SAndroid Build Coastguard Worker       if (!seqMode)
787*f6dc9357SAndroid Build Coastguard Worker       {
788*f6dc9357SAndroid Build Coastguard Worker         /*
789*f6dc9357SAndroid Build Coastguard Worker         // GetStream() creates link.
790*f6dc9357SAndroid Build Coastguard Worker         // so we can show extracting info in GetStream() instead
791*f6dc9357SAndroid Build Coastguard Worker         if (item->Is_HardLink() ||
792*f6dc9357SAndroid Build Coastguard Worker             item->Is_SymLink())
793*f6dc9357SAndroid Build Coastguard Worker         {
794*f6dc9357SAndroid Build Coastguard Worker           RINOK(extractCallback->PrepareOperation(askMode))
795*f6dc9357SAndroid Build Coastguard Worker           RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
796*f6dc9357SAndroid Build Coastguard Worker         }
797*f6dc9357SAndroid Build Coastguard Worker         */
798*f6dc9357SAndroid Build Coastguard Worker         continue;
799*f6dc9357SAndroid Build Coastguard Worker       }
800*f6dc9357SAndroid Build Coastguard Worker       skipMode = true;
801*f6dc9357SAndroid Build Coastguard Worker       askMode = NExtract::NAskMode::kSkip;
802*f6dc9357SAndroid Build Coastguard Worker     }
803*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->PrepareOperation(askMode))
804*f6dc9357SAndroid Build Coastguard Worker 
805*f6dc9357SAndroid Build Coastguard Worker     outStreamSpec->SetStream(realOutStream);
806*f6dc9357SAndroid Build Coastguard Worker     realOutStream.Release();
807*f6dc9357SAndroid Build Coastguard Worker     outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
808*f6dc9357SAndroid Build Coastguard Worker 
809*f6dc9357SAndroid Build Coastguard Worker     Int32 opRes = NExtract::NOperationResult::kOK;
810*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialInStream> inStream2;
811*f6dc9357SAndroid Build Coastguard Worker     if (!item->Is_Sparse())
812*f6dc9357SAndroid Build Coastguard Worker       inStream2 = inStream;
813*f6dc9357SAndroid Build Coastguard Worker     else
814*f6dc9357SAndroid Build Coastguard Worker     {
815*f6dc9357SAndroid Build Coastguard Worker       GetStream(index, &inStream2);
816*f6dc9357SAndroid Build Coastguard Worker       if (!inStream2)
817*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
818*f6dc9357SAndroid Build Coastguard Worker     }
819*f6dc9357SAndroid Build Coastguard Worker 
820*f6dc9357SAndroid Build Coastguard Worker     {
821*f6dc9357SAndroid Build Coastguard Worker       if (item->Is_SymLink())
822*f6dc9357SAndroid Build Coastguard Worker       {
823*f6dc9357SAndroid Build Coastguard Worker         RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len()))
824*f6dc9357SAndroid Build Coastguard Worker       }
825*f6dc9357SAndroid Build Coastguard Worker       else
826*f6dc9357SAndroid Build Coastguard Worker       {
827*f6dc9357SAndroid Build Coastguard Worker         if (!seqMode)
828*f6dc9357SAndroid Build Coastguard Worker         {
829*f6dc9357SAndroid Build Coastguard Worker           RINOK(InStream_SeekSet(_stream, item->Get_DataPos()))
830*f6dc9357SAndroid Build Coastguard Worker         }
831*f6dc9357SAndroid Build Coastguard Worker         inStream->Init(item->Get_PackSize_Aligned());
832*f6dc9357SAndroid Build Coastguard Worker         RINOK(copyCoder.Interface()->Code(inStream2, outStreamSpec, NULL, NULL, lps))
833*f6dc9357SAndroid Build Coastguard Worker       }
834*f6dc9357SAndroid Build Coastguard Worker       if (outStreamSpec->GetRem() != 0)
835*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kDataError;
836*f6dc9357SAndroid Build Coastguard Worker     }
837*f6dc9357SAndroid Build Coastguard Worker     if (seqMode)
838*f6dc9357SAndroid Build Coastguard Worker     {
839*f6dc9357SAndroid Build Coastguard Worker       _latestIsRead = false;
840*f6dc9357SAndroid Build Coastguard Worker       _curIndex++;
841*f6dc9357SAndroid Build Coastguard Worker     }
842*f6dc9357SAndroid Build Coastguard Worker     outStreamSpec->ReleaseStream();
843*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(opRes))
844*f6dc9357SAndroid Build Coastguard Worker   }
845*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
846*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
847*f6dc9357SAndroid Build Coastguard Worker }
848*f6dc9357SAndroid Build Coastguard Worker 
849*f6dc9357SAndroid Build Coastguard Worker 
850*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_IInStream(
851*f6dc9357SAndroid Build Coastguard Worker   CSparseStream
852*f6dc9357SAndroid Build Coastguard Worker )
853*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phyPos;
854*f6dc9357SAndroid Build Coastguard Worker   UInt64 _virtPos;
855*f6dc9357SAndroid Build Coastguard Worker   bool _needStartSeek;
856*f6dc9357SAndroid Build Coastguard Worker 
857*f6dc9357SAndroid Build Coastguard Worker public:
858*f6dc9357SAndroid Build Coastguard Worker   CHandler *Handler;
859*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IUnknown> HandlerRef;
860*f6dc9357SAndroid Build Coastguard Worker   unsigned ItemIndex;
861*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<UInt64> PhyOffsets;
862*f6dc9357SAndroid Build Coastguard Worker 
863*f6dc9357SAndroid Build Coastguard Worker   void Init()
864*f6dc9357SAndroid Build Coastguard Worker   {
865*f6dc9357SAndroid Build Coastguard Worker     _virtPos = 0;
866*f6dc9357SAndroid Build Coastguard Worker     _phyPos = 0;
867*f6dc9357SAndroid Build Coastguard Worker     _needStartSeek = true;
868*f6dc9357SAndroid Build Coastguard Worker   }
869*f6dc9357SAndroid Build Coastguard Worker };
870*f6dc9357SAndroid Build Coastguard Worker 
871*f6dc9357SAndroid Build Coastguard Worker 
872*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize))
873*f6dc9357SAndroid Build Coastguard Worker {
874*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
875*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
876*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
877*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
878*f6dc9357SAndroid Build Coastguard Worker   const CItemEx &item = Handler->_items[ItemIndex];
879*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos >= item.Size)
880*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
881*f6dc9357SAndroid Build Coastguard Worker   {
882*f6dc9357SAndroid Build Coastguard Worker     UInt64 rem = item.Size - _virtPos;
883*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
884*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
885*f6dc9357SAndroid Build Coastguard Worker   }
886*f6dc9357SAndroid Build Coastguard Worker 
887*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = S_OK;
888*f6dc9357SAndroid Build Coastguard Worker 
889*f6dc9357SAndroid Build Coastguard Worker   if (item.SparseBlocks.IsEmpty())
890*f6dc9357SAndroid Build Coastguard Worker     memset(data, 0, size);
891*f6dc9357SAndroid Build Coastguard Worker   else
892*f6dc9357SAndroid Build Coastguard Worker   {
893*f6dc9357SAndroid Build Coastguard Worker     unsigned left = 0, right = item.SparseBlocks.Size();
894*f6dc9357SAndroid Build Coastguard Worker     for (;;)
895*f6dc9357SAndroid Build Coastguard Worker     {
896*f6dc9357SAndroid Build Coastguard Worker       const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
897*f6dc9357SAndroid Build Coastguard Worker       if (mid == left)
898*f6dc9357SAndroid Build Coastguard Worker         break;
899*f6dc9357SAndroid Build Coastguard Worker       if (_virtPos < item.SparseBlocks[mid].Offset)
900*f6dc9357SAndroid Build Coastguard Worker         right = mid;
901*f6dc9357SAndroid Build Coastguard Worker       else
902*f6dc9357SAndroid Build Coastguard Worker         left = mid;
903*f6dc9357SAndroid Build Coastguard Worker     }
904*f6dc9357SAndroid Build Coastguard Worker 
905*f6dc9357SAndroid Build Coastguard Worker     const CSparseBlock &sb = item.SparseBlocks[left];
906*f6dc9357SAndroid Build Coastguard Worker     UInt64 relat = _virtPos - sb.Offset;
907*f6dc9357SAndroid Build Coastguard Worker 
908*f6dc9357SAndroid Build Coastguard Worker     if (_virtPos >= sb.Offset && relat < sb.Size)
909*f6dc9357SAndroid Build Coastguard Worker     {
910*f6dc9357SAndroid Build Coastguard Worker       UInt64 rem = sb.Size - relat;
911*f6dc9357SAndroid Build Coastguard Worker       if (size > rem)
912*f6dc9357SAndroid Build Coastguard Worker         size = (UInt32)rem;
913*f6dc9357SAndroid Build Coastguard Worker       UInt64 phyPos = PhyOffsets[left] + relat;
914*f6dc9357SAndroid Build Coastguard Worker       if (_needStartSeek || _phyPos != phyPos)
915*f6dc9357SAndroid Build Coastguard Worker       {
916*f6dc9357SAndroid Build Coastguard Worker         RINOK(InStream_SeekSet(Handler->_stream, (item.Get_DataPos() + phyPos)))
917*f6dc9357SAndroid Build Coastguard Worker         _needStartSeek = false;
918*f6dc9357SAndroid Build Coastguard Worker         _phyPos = phyPos;
919*f6dc9357SAndroid Build Coastguard Worker       }
920*f6dc9357SAndroid Build Coastguard Worker       res = Handler->_stream->Read(data, size, &size);
921*f6dc9357SAndroid Build Coastguard Worker       _phyPos += size;
922*f6dc9357SAndroid Build Coastguard Worker     }
923*f6dc9357SAndroid Build Coastguard Worker     else
924*f6dc9357SAndroid Build Coastguard Worker     {
925*f6dc9357SAndroid Build Coastguard Worker       UInt64 next = item.Size;
926*f6dc9357SAndroid Build Coastguard Worker       if (_virtPos < sb.Offset)
927*f6dc9357SAndroid Build Coastguard Worker         next = sb.Offset;
928*f6dc9357SAndroid Build Coastguard Worker       else if (left + 1 < item.SparseBlocks.Size())
929*f6dc9357SAndroid Build Coastguard Worker         next = item.SparseBlocks[left + 1].Offset;
930*f6dc9357SAndroid Build Coastguard Worker       UInt64 rem = next - _virtPos;
931*f6dc9357SAndroid Build Coastguard Worker       if (size > rem)
932*f6dc9357SAndroid Build Coastguard Worker         size = (UInt32)rem;
933*f6dc9357SAndroid Build Coastguard Worker       memset(data, 0, size);
934*f6dc9357SAndroid Build Coastguard Worker     }
935*f6dc9357SAndroid Build Coastguard Worker   }
936*f6dc9357SAndroid Build Coastguard Worker 
937*f6dc9357SAndroid Build Coastguard Worker   _virtPos += size;
938*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
939*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
940*f6dc9357SAndroid Build Coastguard Worker   return res;
941*f6dc9357SAndroid Build Coastguard Worker }
942*f6dc9357SAndroid Build Coastguard Worker 
943*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CSparseStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
944*f6dc9357SAndroid Build Coastguard Worker {
945*f6dc9357SAndroid Build Coastguard Worker   switch (seekOrigin)
946*f6dc9357SAndroid Build Coastguard Worker   {
947*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_SET: break;
948*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_CUR: offset += _virtPos; break;
949*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_END: offset += Handler->_items[ItemIndex].Size; break;
950*f6dc9357SAndroid Build Coastguard Worker     default: return STG_E_INVALIDFUNCTION;
951*f6dc9357SAndroid Build Coastguard Worker   }
952*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
953*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
954*f6dc9357SAndroid Build Coastguard Worker   _virtPos = (UInt64)offset;
955*f6dc9357SAndroid Build Coastguard Worker   if (newPosition)
956*f6dc9357SAndroid Build Coastguard Worker     *newPosition = _virtPos;
957*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
958*f6dc9357SAndroid Build Coastguard Worker }
959*f6dc9357SAndroid Build Coastguard Worker 
960*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
961*f6dc9357SAndroid Build Coastguard Worker {
962*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
963*f6dc9357SAndroid Build Coastguard Worker 
964*f6dc9357SAndroid Build Coastguard Worker   const CItemEx &item = _items[index];
965*f6dc9357SAndroid Build Coastguard Worker 
966*f6dc9357SAndroid Build Coastguard Worker   if (item.Is_Sparse())
967*f6dc9357SAndroid Build Coastguard Worker   {
968*f6dc9357SAndroid Build Coastguard Worker     CSparseStream *streamSpec = new CSparseStream;
969*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<IInStream> streamTemp = streamSpec;
970*f6dc9357SAndroid Build Coastguard Worker     streamSpec->Init();
971*f6dc9357SAndroid Build Coastguard Worker     streamSpec->Handler = this;
972*f6dc9357SAndroid Build Coastguard Worker     streamSpec->HandlerRef = (IInArchive *)this;
973*f6dc9357SAndroid Build Coastguard Worker     streamSpec->ItemIndex = index;
974*f6dc9357SAndroid Build Coastguard Worker     streamSpec->PhyOffsets.Reserve(item.SparseBlocks.Size());
975*f6dc9357SAndroid Build Coastguard Worker     UInt64 offs = 0;
976*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR(i, item.SparseBlocks)
977*f6dc9357SAndroid Build Coastguard Worker     {
978*f6dc9357SAndroid Build Coastguard Worker       const CSparseBlock &sb = item.SparseBlocks[i];
979*f6dc9357SAndroid Build Coastguard Worker       streamSpec->PhyOffsets.AddInReserved(offs);
980*f6dc9357SAndroid Build Coastguard Worker       offs += sb.Size;
981*f6dc9357SAndroid Build Coastguard Worker     }
982*f6dc9357SAndroid Build Coastguard Worker     *stream = streamTemp.Detach();
983*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
984*f6dc9357SAndroid Build Coastguard Worker   }
985*f6dc9357SAndroid Build Coastguard Worker 
986*f6dc9357SAndroid Build Coastguard Worker   if (item.Is_SymLink())
987*f6dc9357SAndroid Build Coastguard Worker   {
988*f6dc9357SAndroid Build Coastguard Worker     Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream);
989*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
990*f6dc9357SAndroid Build Coastguard Worker   }
991*f6dc9357SAndroid Build Coastguard Worker 
992*f6dc9357SAndroid Build Coastguard Worker   return CreateLimitedInStream(_stream, item.Get_DataPos(), item.PackSize, stream);
993*f6dc9357SAndroid Build Coastguard Worker 
994*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
995*f6dc9357SAndroid Build Coastguard Worker }
996*f6dc9357SAndroid Build Coastguard Worker 
997*f6dc9357SAndroid Build Coastguard Worker 
998*f6dc9357SAndroid Build Coastguard Worker void CHandler::Init()
999*f6dc9357SAndroid Build Coastguard Worker {
1000*f6dc9357SAndroid Build Coastguard Worker   _forceCodePage = false;
1001*f6dc9357SAndroid Build Coastguard Worker   _curCodePage = _specifiedCodePage = CP_UTF8;  // CP_OEMCP;
1002*f6dc9357SAndroid Build Coastguard Worker   _posixMode = false;
1003*f6dc9357SAndroid Build Coastguard Worker   _posixMode_WasForced = false;
1004*f6dc9357SAndroid Build Coastguard Worker   // TimeOptions.Clear();
1005*f6dc9357SAndroid Build Coastguard Worker   _handlerTimeOptions.Init();
1006*f6dc9357SAndroid Build Coastguard Worker   // _handlerTimeOptions.Write_MTime.Val = true; // it's default already
1007*f6dc9357SAndroid Build Coastguard Worker }
1008*f6dc9357SAndroid Build Coastguard Worker 
1009*f6dc9357SAndroid Build Coastguard Worker 
1010*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
1011*f6dc9357SAndroid Build Coastguard Worker {
1012*f6dc9357SAndroid Build Coastguard Worker   Init();
1013*f6dc9357SAndroid Build Coastguard Worker 
1014*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0; i < numProps; i++)
1015*f6dc9357SAndroid Build Coastguard Worker   {
1016*f6dc9357SAndroid Build Coastguard Worker     UString name = names[i];
1017*f6dc9357SAndroid Build Coastguard Worker     name.MakeLower_Ascii();
1018*f6dc9357SAndroid Build Coastguard Worker     if (name.IsEmpty())
1019*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
1020*f6dc9357SAndroid Build Coastguard Worker 
1021*f6dc9357SAndroid Build Coastguard Worker     const PROPVARIANT &prop = values[i];
1022*f6dc9357SAndroid Build Coastguard Worker 
1023*f6dc9357SAndroid Build Coastguard Worker     if (name[0] == L'x')
1024*f6dc9357SAndroid Build Coastguard Worker     {
1025*f6dc9357SAndroid Build Coastguard Worker       // some clients write 'x' property. So we support it
1026*f6dc9357SAndroid Build Coastguard Worker       UInt32 level = 0;
1027*f6dc9357SAndroid Build Coastguard Worker       RINOK(ParsePropToUInt32(name.Ptr(1), prop, level))
1028*f6dc9357SAndroid Build Coastguard Worker     }
1029*f6dc9357SAndroid Build Coastguard Worker     else if (name.IsEqualTo("cp"))
1030*f6dc9357SAndroid Build Coastguard Worker     {
1031*f6dc9357SAndroid Build Coastguard Worker       UInt32 cp = CP_OEMCP;
1032*f6dc9357SAndroid Build Coastguard Worker       RINOK(ParsePropToUInt32(L"", prop, cp))
1033*f6dc9357SAndroid Build Coastguard Worker       _forceCodePage = true;
1034*f6dc9357SAndroid Build Coastguard Worker       _curCodePage = _specifiedCodePage = cp;
1035*f6dc9357SAndroid Build Coastguard Worker     }
1036*f6dc9357SAndroid Build Coastguard Worker     else if (name.IsPrefixedBy_Ascii_NoCase("mt"))
1037*f6dc9357SAndroid Build Coastguard Worker     {
1038*f6dc9357SAndroid Build Coastguard Worker     }
1039*f6dc9357SAndroid Build Coastguard Worker     else if (name.IsPrefixedBy_Ascii_NoCase("memuse"))
1040*f6dc9357SAndroid Build Coastguard Worker     {
1041*f6dc9357SAndroid Build Coastguard Worker     }
1042*f6dc9357SAndroid Build Coastguard Worker     else if (name.IsEqualTo("m"))
1043*f6dc9357SAndroid Build Coastguard Worker     {
1044*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt != VT_BSTR)
1045*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
1046*f6dc9357SAndroid Build Coastguard Worker       const UString s = prop.bstrVal;
1047*f6dc9357SAndroid Build Coastguard Worker       if (s.IsEqualTo_Ascii_NoCase("pax") ||
1048*f6dc9357SAndroid Build Coastguard Worker           s.IsEqualTo_Ascii_NoCase("posix"))
1049*f6dc9357SAndroid Build Coastguard Worker         _posixMode = true;
1050*f6dc9357SAndroid Build Coastguard Worker       else if (s.IsEqualTo_Ascii_NoCase("gnu"))
1051*f6dc9357SAndroid Build Coastguard Worker         _posixMode = false;
1052*f6dc9357SAndroid Build Coastguard Worker       else
1053*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
1054*f6dc9357SAndroid Build Coastguard Worker       _posixMode_WasForced = true;
1055*f6dc9357SAndroid Build Coastguard Worker     }
1056*f6dc9357SAndroid Build Coastguard Worker     else
1057*f6dc9357SAndroid Build Coastguard Worker     {
1058*f6dc9357SAndroid Build Coastguard Worker       /*
1059*f6dc9357SAndroid Build Coastguard Worker       if (name.IsPrefixedBy_Ascii_NoCase("td"))
1060*f6dc9357SAndroid Build Coastguard Worker       {
1061*f6dc9357SAndroid Build Coastguard Worker         name.Delete(0, 3);
1062*f6dc9357SAndroid Build Coastguard Worker         if (prop.vt == VT_EMPTY)
1063*f6dc9357SAndroid Build Coastguard Worker         {
1064*f6dc9357SAndroid Build Coastguard Worker           if (name.IsEqualTo_Ascii_NoCase("n"))
1065*f6dc9357SAndroid Build Coastguard Worker           {
1066*f6dc9357SAndroid Build Coastguard Worker             // TimeOptions.UseNativeDigits = true;
1067*f6dc9357SAndroid Build Coastguard Worker           }
1068*f6dc9357SAndroid Build Coastguard Worker           else if (name.IsEqualTo_Ascii_NoCase("r"))
1069*f6dc9357SAndroid Build Coastguard Worker           {
1070*f6dc9357SAndroid Build Coastguard Worker             // TimeOptions.RemoveZeroDigits = true;
1071*f6dc9357SAndroid Build Coastguard Worker           }
1072*f6dc9357SAndroid Build Coastguard Worker           else
1073*f6dc9357SAndroid Build Coastguard Worker             return E_INVALIDARG;
1074*f6dc9357SAndroid Build Coastguard Worker         }
1075*f6dc9357SAndroid Build Coastguard Worker         else
1076*f6dc9357SAndroid Build Coastguard Worker         {
1077*f6dc9357SAndroid Build Coastguard Worker           UInt32 numTimeDigits = 0;
1078*f6dc9357SAndroid Build Coastguard Worker           RINOK(ParsePropToUInt32(name, prop, numTimeDigits));
1079*f6dc9357SAndroid Build Coastguard Worker           TimeOptions.NumDigits_WasForced = true;
1080*f6dc9357SAndroid Build Coastguard Worker           TimeOptions.NumDigits = numTimeDigits;
1081*f6dc9357SAndroid Build Coastguard Worker         }
1082*f6dc9357SAndroid Build Coastguard Worker       }
1083*f6dc9357SAndroid Build Coastguard Worker       */
1084*f6dc9357SAndroid Build Coastguard Worker       bool processed = false;
1085*f6dc9357SAndroid Build Coastguard Worker       RINOK(_handlerTimeOptions.Parse(name, prop, processed))
1086*f6dc9357SAndroid Build Coastguard Worker       if (processed)
1087*f6dc9357SAndroid Build Coastguard Worker         continue;
1088*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
1089*f6dc9357SAndroid Build Coastguard Worker     }
1090*f6dc9357SAndroid Build Coastguard Worker   }
1091*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1092*f6dc9357SAndroid Build Coastguard Worker }
1093*f6dc9357SAndroid Build Coastguard Worker 
1094*f6dc9357SAndroid Build Coastguard Worker }}
1095