xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/ArHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // ArHandler.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 "../../../C/CpuArch.h"
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringConvert.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringToInt.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/RegisterArc.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamObjects.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
20*f6dc9357SAndroid Build Coastguard Worker 
21*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
22*f6dc9357SAndroid Build Coastguard Worker 
23*f6dc9357SAndroid Build Coastguard Worker #include "Common/ItemNameUtils.h"
24*f6dc9357SAndroid Build Coastguard Worker 
25*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
26*f6dc9357SAndroid Build Coastguard Worker using namespace NTime;
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
29*f6dc9357SAndroid Build Coastguard Worker namespace NAr {
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker /*
32*f6dc9357SAndroid Build Coastguard Worker The end of each file member (including last file in archive) is 2-bytes aligned.
33*f6dc9357SAndroid Build Coastguard Worker It uses 0xA padding if required.
34*f6dc9357SAndroid Build Coastguard Worker 
35*f6dc9357SAndroid Build Coastguard Worker File Names:
36*f6dc9357SAndroid Build Coastguard Worker 
37*f6dc9357SAndroid Build Coastguard Worker GNU/SVR4 variant (.a static library):
38*f6dc9357SAndroid Build Coastguard Worker   /       - archive symbol table
39*f6dc9357SAndroid Build Coastguard Worker   //      - the list of the long filenames, separated by one or more LF characters.
40*f6dc9357SAndroid Build Coastguard Worker   /N      - the reference to name string in long filenames list
41*f6dc9357SAndroid Build Coastguard Worker   name/   - the name
42*f6dc9357SAndroid Build Coastguard Worker 
43*f6dc9357SAndroid Build Coastguard Worker Microsoft variant (.lib static library):
44*f6dc9357SAndroid Build Coastguard Worker   /       - First linker file (archive symbol table)
45*f6dc9357SAndroid Build Coastguard Worker   /       - Second linker file
46*f6dc9357SAndroid Build Coastguard Worker   //      - the list of the long filenames, null-terminated. Each string begins
47*f6dc9357SAndroid Build Coastguard Worker             immediately after the null byte in the previous string.
48*f6dc9357SAndroid Build Coastguard Worker   /N      - the reference to name string in long filenames list
49*f6dc9357SAndroid Build Coastguard Worker   name/   - the name
50*f6dc9357SAndroid Build Coastguard Worker 
51*f6dc9357SAndroid Build Coastguard Worker BSD (Mac OS X) variant:
52*f6dc9357SAndroid Build Coastguard Worker   "__.SYMDEF"         -  archive symbol table
53*f6dc9357SAndroid Build Coastguard Worker     or
54*f6dc9357SAndroid Build Coastguard Worker   "__.SYMDEF SORTED"  -  archive symbol table
55*f6dc9357SAndroid Build Coastguard Worker   #1/N    - the real filename of length N is appended to the file header.
56*f6dc9357SAndroid Build Coastguard Worker */
57*f6dc9357SAndroid Build Coastguard Worker 
58*f6dc9357SAndroid Build Coastguard Worker static const unsigned kSignatureLen = 8;
59*f6dc9357SAndroid Build Coastguard Worker static const Byte kSignature[kSignatureLen] =
60*f6dc9357SAndroid Build Coastguard Worker   { '!', '<', 'a', 'r', 'c', 'h', '>', 0x0A };
61*f6dc9357SAndroid Build Coastguard Worker 
62*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNameSize = 16;
63*f6dc9357SAndroid Build Coastguard Worker static const unsigned kTimeSize = 12;
64*f6dc9357SAndroid Build Coastguard Worker static const unsigned kUserSize = 6;
65*f6dc9357SAndroid Build Coastguard Worker static const unsigned kModeSize = 8;
66*f6dc9357SAndroid Build Coastguard Worker static const unsigned kSizeSize = 10;
67*f6dc9357SAndroid Build Coastguard Worker 
68*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeaderSize = kNameSize + kTimeSize + kUserSize * 2 + kModeSize + kSizeSize + 1 + 1;
69*f6dc9357SAndroid Build Coastguard Worker 
70*f6dc9357SAndroid Build Coastguard Worker enum EType
71*f6dc9357SAndroid Build Coastguard Worker {
72*f6dc9357SAndroid Build Coastguard Worker   kType_Ar,
73*f6dc9357SAndroid Build Coastguard Worker   kType_ALib,
74*f6dc9357SAndroid Build Coastguard Worker   kType_Deb,
75*f6dc9357SAndroid Build Coastguard Worker   kType_Lib
76*f6dc9357SAndroid Build Coastguard Worker };
77*f6dc9357SAndroid Build Coastguard Worker 
78*f6dc9357SAndroid Build Coastguard Worker static const char * const k_TypeExtionsions[] =
79*f6dc9357SAndroid Build Coastguard Worker {
80*f6dc9357SAndroid Build Coastguard Worker     "ar"
81*f6dc9357SAndroid Build Coastguard Worker   , "a"
82*f6dc9357SAndroid Build Coastguard Worker   , "deb"
83*f6dc9357SAndroid Build Coastguard Worker   , "lib"
84*f6dc9357SAndroid Build Coastguard Worker };
85*f6dc9357SAndroid Build Coastguard Worker 
86*f6dc9357SAndroid Build Coastguard Worker enum ESubType
87*f6dc9357SAndroid Build Coastguard Worker {
88*f6dc9357SAndroid Build Coastguard Worker   kSubType_None,
89*f6dc9357SAndroid Build Coastguard Worker   kSubType_BSD
90*f6dc9357SAndroid Build Coastguard Worker };
91*f6dc9357SAndroid Build Coastguard Worker 
92*f6dc9357SAndroid Build Coastguard Worker /*
93*f6dc9357SAndroid Build Coastguard Worker struct CHeader
94*f6dc9357SAndroid Build Coastguard Worker {
95*f6dc9357SAndroid Build Coastguard Worker   char Name[kNameSize];
96*f6dc9357SAndroid Build Coastguard Worker   char MTime[kTimeSize];
97*f6dc9357SAndroid Build Coastguard Worker   char User[kUserSize];
98*f6dc9357SAndroid Build Coastguard Worker   char Group[kUserSize];
99*f6dc9357SAndroid Build Coastguard Worker   char Mode[kModeSize];
100*f6dc9357SAndroid Build Coastguard Worker   char Size[kSizeSize];
101*f6dc9357SAndroid Build Coastguard Worker   char Quote;
102*f6dc9357SAndroid Build Coastguard Worker   char NewLine;
103*f6dc9357SAndroid Build Coastguard Worker };
104*f6dc9357SAndroid Build Coastguard Worker */
105*f6dc9357SAndroid Build Coastguard Worker 
106*f6dc9357SAndroid Build Coastguard Worker struct CItem
107*f6dc9357SAndroid Build Coastguard Worker {
108*f6dc9357SAndroid Build Coastguard Worker   AString Name;
109*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
110*f6dc9357SAndroid Build Coastguard Worker   UInt32 MTime;
111*f6dc9357SAndroid Build Coastguard Worker   UInt32 User;
112*f6dc9357SAndroid Build Coastguard Worker   UInt32 Group;
113*f6dc9357SAndroid Build Coastguard Worker   UInt32 Mode;
114*f6dc9357SAndroid Build Coastguard Worker 
115*f6dc9357SAndroid Build Coastguard Worker   UInt64 HeaderPos;
116*f6dc9357SAndroid Build Coastguard Worker   UInt64 HeaderSize;
117*f6dc9357SAndroid Build Coastguard Worker 
118*f6dc9357SAndroid Build Coastguard Worker   int TextFileIndex;
119*f6dc9357SAndroid Build Coastguard Worker   int SameNameIndex;
120*f6dc9357SAndroid Build Coastguard Worker 
CItemNArchive::NAr::CItem121*f6dc9357SAndroid Build Coastguard Worker   CItem(): TextFileIndex(-1), SameNameIndex(-1) {}
GetDataPosNArchive::NAr::CItem122*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetDataPos() const { return HeaderPos + HeaderSize; }
123*f6dc9357SAndroid Build Coastguard Worker };
124*f6dc9357SAndroid Build Coastguard Worker 
125*f6dc9357SAndroid Build Coastguard Worker class CInArchive
126*f6dc9357SAndroid Build Coastguard Worker {
127*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> m_Stream;
128*f6dc9357SAndroid Build Coastguard Worker 
129*f6dc9357SAndroid Build Coastguard Worker public:
130*f6dc9357SAndroid Build Coastguard Worker   UInt64 Position;
131*f6dc9357SAndroid Build Coastguard Worker   ESubType SubType;
132*f6dc9357SAndroid Build Coastguard Worker 
133*f6dc9357SAndroid Build Coastguard Worker   HRESULT GetNextItem(CItem &itemInfo, bool &filled);
134*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open(IInStream *inStream);
SkipData(UInt64 dataSize)135*f6dc9357SAndroid Build Coastguard Worker   HRESULT SkipData(UInt64 dataSize)
136*f6dc9357SAndroid Build Coastguard Worker   {
137*f6dc9357SAndroid Build Coastguard Worker     return m_Stream->Seek((Int64)(dataSize + (dataSize & 1)), STREAM_SEEK_CUR, &Position);
138*f6dc9357SAndroid Build Coastguard Worker   }
139*f6dc9357SAndroid Build Coastguard Worker };
140*f6dc9357SAndroid Build Coastguard Worker 
Open(IInStream * inStream)141*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Open(IInStream *inStream)
142*f6dc9357SAndroid Build Coastguard Worker {
143*f6dc9357SAndroid Build Coastguard Worker   SubType = kSubType_None;
144*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_GetPos(inStream, Position))
145*f6dc9357SAndroid Build Coastguard Worker   char signature[kSignatureLen];
146*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(inStream, signature, kSignatureLen))
147*f6dc9357SAndroid Build Coastguard Worker   Position += kSignatureLen;
148*f6dc9357SAndroid Build Coastguard Worker   if (memcmp(signature, kSignature, kSignatureLen) != 0)
149*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
150*f6dc9357SAndroid Build Coastguard Worker   m_Stream = inStream;
151*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
152*f6dc9357SAndroid Build Coastguard Worker }
153*f6dc9357SAndroid Build Coastguard Worker 
RemoveTailSpaces(char * dest,const char * s,unsigned size)154*f6dc9357SAndroid Build Coastguard Worker static unsigned RemoveTailSpaces(char *dest, const char *s, unsigned size)
155*f6dc9357SAndroid Build Coastguard Worker {
156*f6dc9357SAndroid Build Coastguard Worker   memcpy(dest, s, size);
157*f6dc9357SAndroid Build Coastguard Worker   for (; size != 0; size--)
158*f6dc9357SAndroid Build Coastguard Worker   {
159*f6dc9357SAndroid Build Coastguard Worker     if (dest[size - 1] != ' ')
160*f6dc9357SAndroid Build Coastguard Worker       break;
161*f6dc9357SAndroid Build Coastguard Worker   }
162*f6dc9357SAndroid Build Coastguard Worker   dest[size] = 0;
163*f6dc9357SAndroid Build Coastguard Worker   return size;
164*f6dc9357SAndroid Build Coastguard Worker }
165*f6dc9357SAndroid Build Coastguard Worker 
OctalToNumber32(const char * s,unsigned size,UInt32 & res)166*f6dc9357SAndroid Build Coastguard Worker static bool OctalToNumber32(const char *s, unsigned size, UInt32 &res)
167*f6dc9357SAndroid Build Coastguard Worker {
168*f6dc9357SAndroid Build Coastguard Worker   res = 0;
169*f6dc9357SAndroid Build Coastguard Worker   char sz[32];
170*f6dc9357SAndroid Build Coastguard Worker   size = RemoveTailSpaces(sz, s, size);
171*f6dc9357SAndroid Build Coastguard Worker   if (size == 0 || strcmp(sz, "-1") == 0)
172*f6dc9357SAndroid Build Coastguard Worker     return true; // some items don't contain any numbers
173*f6dc9357SAndroid Build Coastguard Worker   const char *end;
174*f6dc9357SAndroid Build Coastguard Worker   UInt64 res64 = ConvertOctStringToUInt64(sz, &end);
175*f6dc9357SAndroid Build Coastguard Worker   if ((unsigned)(end - sz) != size)
176*f6dc9357SAndroid Build Coastguard Worker     return false;
177*f6dc9357SAndroid Build Coastguard Worker   res = (UInt32)res64;
178*f6dc9357SAndroid Build Coastguard Worker   return (res64 <= 0xFFFFFFFF);
179*f6dc9357SAndroid Build Coastguard Worker }
180*f6dc9357SAndroid Build Coastguard Worker 
DecimalToNumber(const char * s,unsigned size,UInt64 & res)181*f6dc9357SAndroid Build Coastguard Worker static bool DecimalToNumber(const char *s, unsigned size, UInt64 &res)
182*f6dc9357SAndroid Build Coastguard Worker {
183*f6dc9357SAndroid Build Coastguard Worker   res = 0;
184*f6dc9357SAndroid Build Coastguard Worker   char sz[32];
185*f6dc9357SAndroid Build Coastguard Worker   size = RemoveTailSpaces(sz, s, size);
186*f6dc9357SAndroid Build Coastguard Worker   if (size == 0 || strcmp(sz, "-1") == 0)
187*f6dc9357SAndroid Build Coastguard Worker     return true; // some items don't contain any numbers
188*f6dc9357SAndroid Build Coastguard Worker   const char *end;
189*f6dc9357SAndroid Build Coastguard Worker   res = ConvertStringToUInt64(sz, &end);
190*f6dc9357SAndroid Build Coastguard Worker   return ((unsigned)(end - sz) == size);
191*f6dc9357SAndroid Build Coastguard Worker }
192*f6dc9357SAndroid Build Coastguard Worker 
DecimalToNumber32(const char * s,unsigned size,UInt32 & res)193*f6dc9357SAndroid Build Coastguard Worker static bool DecimalToNumber32(const char *s, unsigned size, UInt32 &res)
194*f6dc9357SAndroid Build Coastguard Worker {
195*f6dc9357SAndroid Build Coastguard Worker   UInt64 res64;
196*f6dc9357SAndroid Build Coastguard Worker   if (!DecimalToNumber(s, size, res64))
197*f6dc9357SAndroid Build Coastguard Worker     return false;
198*f6dc9357SAndroid Build Coastguard Worker   res = (UInt32)res64;
199*f6dc9357SAndroid Build Coastguard Worker   return (res64 <= 0xFFFFFFFF);
200*f6dc9357SAndroid Build Coastguard Worker }
201*f6dc9357SAndroid Build Coastguard Worker 
202*f6dc9357SAndroid Build Coastguard Worker #define RIF(x) { if (!(x)) return S_FALSE; }
203*f6dc9357SAndroid Build Coastguard Worker 
204*f6dc9357SAndroid Build Coastguard Worker 
GetNextItem(CItem & item,bool & filled)205*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::GetNextItem(CItem &item, bool &filled)
206*f6dc9357SAndroid Build Coastguard Worker {
207*f6dc9357SAndroid Build Coastguard Worker   filled = false;
208*f6dc9357SAndroid Build Coastguard Worker 
209*f6dc9357SAndroid Build Coastguard Worker   char header[kHeaderSize];
210*f6dc9357SAndroid Build Coastguard Worker   const char *cur = header;
211*f6dc9357SAndroid Build Coastguard Worker 
212*f6dc9357SAndroid Build Coastguard Worker   {
213*f6dc9357SAndroid Build Coastguard Worker     size_t processedSize = sizeof(header);
214*f6dc9357SAndroid Build Coastguard Worker     item.HeaderPos = Position;
215*f6dc9357SAndroid Build Coastguard Worker     item.HeaderSize = kHeaderSize;
216*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream(m_Stream, header, &processedSize))
217*f6dc9357SAndroid Build Coastguard Worker     if (processedSize != sizeof(header))
218*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
219*f6dc9357SAndroid Build Coastguard Worker     if (header[kHeaderSize - 2] != 0x60 ||
220*f6dc9357SAndroid Build Coastguard Worker       header[kHeaderSize - 1] != 0x0A)
221*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
222*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < kHeaderSize - 2; i++)
223*f6dc9357SAndroid Build Coastguard Worker       // if (header[i] < 0x20)
224*f6dc9357SAndroid Build Coastguard Worker       if (header[i] == 0)
225*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
226*f6dc9357SAndroid Build Coastguard Worker     Position += processedSize;
227*f6dc9357SAndroid Build Coastguard Worker   }
228*f6dc9357SAndroid Build Coastguard Worker 
229*f6dc9357SAndroid Build Coastguard Worker   UInt32 longNameLen = 0;
230*f6dc9357SAndroid Build Coastguard Worker   if (cur[0] == '#' &&
231*f6dc9357SAndroid Build Coastguard Worker       cur[1] == '1' &&
232*f6dc9357SAndroid Build Coastguard Worker       cur[2] == '/' &&
233*f6dc9357SAndroid Build Coastguard Worker       cur[3] != 0)
234*f6dc9357SAndroid Build Coastguard Worker   {
235*f6dc9357SAndroid Build Coastguard Worker     // BSD variant
236*f6dc9357SAndroid Build Coastguard Worker     RIF(DecimalToNumber32(cur + 3, kNameSize - 3 , longNameLen))
237*f6dc9357SAndroid Build Coastguard Worker     if (longNameLen >= (1 << 12))
238*f6dc9357SAndroid Build Coastguard Worker       longNameLen = 0;
239*f6dc9357SAndroid Build Coastguard Worker   }
240*f6dc9357SAndroid Build Coastguard Worker   else
241*f6dc9357SAndroid Build Coastguard Worker   {
242*f6dc9357SAndroid Build Coastguard Worker     char tempString[kNameSize + 1];
243*f6dc9357SAndroid Build Coastguard Worker     RemoveTailSpaces(tempString, cur, kNameSize);
244*f6dc9357SAndroid Build Coastguard Worker     item.Name = tempString;
245*f6dc9357SAndroid Build Coastguard Worker   }
246*f6dc9357SAndroid Build Coastguard Worker   cur += kNameSize;
247*f6dc9357SAndroid Build Coastguard Worker 
248*f6dc9357SAndroid Build Coastguard Worker   RIF(DecimalToNumber32(cur, kTimeSize, item.MTime)) cur += kTimeSize;
249*f6dc9357SAndroid Build Coastguard Worker   RIF(DecimalToNumber32(cur, kUserSize, item.User)) cur += kUserSize;
250*f6dc9357SAndroid Build Coastguard Worker   RIF(DecimalToNumber32(cur, kUserSize, item.Group)) cur += kUserSize;
251*f6dc9357SAndroid Build Coastguard Worker   RIF(OctalToNumber32(cur, kModeSize, item.Mode)) cur += kModeSize;
252*f6dc9357SAndroid Build Coastguard Worker   RIF(DecimalToNumber(cur, kSizeSize, item.Size)) cur += kSizeSize;
253*f6dc9357SAndroid Build Coastguard Worker 
254*f6dc9357SAndroid Build Coastguard Worker   if (longNameLen != 0 && longNameLen <= item.Size)
255*f6dc9357SAndroid Build Coastguard Worker   {
256*f6dc9357SAndroid Build Coastguard Worker     SubType = kSubType_BSD;
257*f6dc9357SAndroid Build Coastguard Worker     size_t processedSize = longNameLen;
258*f6dc9357SAndroid Build Coastguard Worker     char *s = item.Name.GetBuf(longNameLen);
259*f6dc9357SAndroid Build Coastguard Worker     HRESULT res = ReadStream(m_Stream, s, &processedSize);
260*f6dc9357SAndroid Build Coastguard Worker     item.Name.ReleaseBuf_CalcLen(longNameLen);
261*f6dc9357SAndroid Build Coastguard Worker     RINOK(res)
262*f6dc9357SAndroid Build Coastguard Worker     if (processedSize != longNameLen)
263*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
264*f6dc9357SAndroid Build Coastguard Worker     item.Size -= longNameLen;
265*f6dc9357SAndroid Build Coastguard Worker     item.HeaderSize += longNameLen;
266*f6dc9357SAndroid Build Coastguard Worker     Position += processedSize;
267*f6dc9357SAndroid Build Coastguard Worker   }
268*f6dc9357SAndroid Build Coastguard Worker 
269*f6dc9357SAndroid Build Coastguard Worker   filled = true;
270*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
271*f6dc9357SAndroid Build Coastguard Worker }
272*f6dc9357SAndroid Build Coastguard Worker 
273*f6dc9357SAndroid Build Coastguard Worker 
274*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_1(
275*f6dc9357SAndroid Build Coastguard Worker   IInArchiveGetStream
276*f6dc9357SAndroid Build Coastguard Worker )
277*f6dc9357SAndroid Build Coastguard Worker   bool _isArc;
278*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CItem> _items;
279*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> _stream;
280*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
281*f6dc9357SAndroid Build Coastguard Worker   Int32 _mainSubfile;
282*f6dc9357SAndroid Build Coastguard Worker 
283*f6dc9357SAndroid Build Coastguard Worker   EType _type;
284*f6dc9357SAndroid Build Coastguard Worker   ESubType _subType;
285*f6dc9357SAndroid Build Coastguard Worker   int _longNames_FileIndex;
286*f6dc9357SAndroid Build Coastguard Worker   unsigned _numLibFiles;
287*f6dc9357SAndroid Build Coastguard Worker   AString _errorMessage;
288*f6dc9357SAndroid Build Coastguard Worker   AString _libFiles[2];
289*f6dc9357SAndroid Build Coastguard Worker 
290*f6dc9357SAndroid Build Coastguard Worker   void UpdateErrorMessage(const char *s);
291*f6dc9357SAndroid Build Coastguard Worker 
292*f6dc9357SAndroid Build Coastguard Worker   HRESULT ParseLongNames(IInStream *stream);
293*f6dc9357SAndroid Build Coastguard Worker   void ChangeDuplicateNames();
294*f6dc9357SAndroid Build Coastguard Worker   int FindItem(UInt32 offset) const;
295*f6dc9357SAndroid Build Coastguard Worker   HRESULT AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos);
296*f6dc9357SAndroid Build Coastguard Worker   HRESULT ParseLibSymbols(IInStream *stream, unsigned fileIndex);
297*f6dc9357SAndroid Build Coastguard Worker };
298*f6dc9357SAndroid Build Coastguard Worker 
UpdateErrorMessage(const char * s)299*f6dc9357SAndroid Build Coastguard Worker void CHandler::UpdateErrorMessage(const char *s)
300*f6dc9357SAndroid Build Coastguard Worker {
301*f6dc9357SAndroid Build Coastguard Worker   if (!_errorMessage.IsEmpty())
302*f6dc9357SAndroid Build Coastguard Worker     _errorMessage.Add_LF();
303*f6dc9357SAndroid Build Coastguard Worker   _errorMessage += s;
304*f6dc9357SAndroid Build Coastguard Worker }
305*f6dc9357SAndroid Build Coastguard Worker 
306*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
307*f6dc9357SAndroid Build Coastguard Worker {
308*f6dc9357SAndroid Build Coastguard Worker   kpidSubType
309*f6dc9357SAndroid Build Coastguard Worker };
310*f6dc9357SAndroid Build Coastguard Worker 
311*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
312*f6dc9357SAndroid Build Coastguard Worker {
313*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
314*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
315*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
316*f6dc9357SAndroid Build Coastguard Worker   kpidPosixAttrib,
317*f6dc9357SAndroid Build Coastguard Worker   kpidUserId,
318*f6dc9357SAndroid Build Coastguard Worker   kpidGroupId
319*f6dc9357SAndroid Build Coastguard Worker };
320*f6dc9357SAndroid Build Coastguard Worker 
321*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
322*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
323*f6dc9357SAndroid Build Coastguard Worker 
ParseLongNames(IInStream * stream)324*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ParseLongNames(IInStream *stream)
325*f6dc9357SAndroid Build Coastguard Worker {
326*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
327*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _items.Size(); i++)
328*f6dc9357SAndroid Build Coastguard Worker     if (_items[i].Name == "//")
329*f6dc9357SAndroid Build Coastguard Worker       break;
330*f6dc9357SAndroid Build Coastguard Worker   if (i == _items.Size())
331*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
332*f6dc9357SAndroid Build Coastguard Worker 
333*f6dc9357SAndroid Build Coastguard Worker   unsigned fileIndex = i;
334*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[fileIndex];
335*f6dc9357SAndroid Build Coastguard Worker   if (item.Size > ((UInt32)1 << 30))
336*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
337*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_SeekSet(stream, item.GetDataPos()))
338*f6dc9357SAndroid Build Coastguard Worker   const size_t size = (size_t)item.Size;
339*f6dc9357SAndroid Build Coastguard Worker 
340*f6dc9357SAndroid Build Coastguard Worker   CByteArr p(size);
341*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, p, size))
342*f6dc9357SAndroid Build Coastguard Worker 
343*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _items.Size(); i++)
344*f6dc9357SAndroid Build Coastguard Worker   {
345*f6dc9357SAndroid Build Coastguard Worker     CItem &item2 = _items[i];
346*f6dc9357SAndroid Build Coastguard Worker     if (item2.Name[0] != '/')
347*f6dc9357SAndroid Build Coastguard Worker       continue;
348*f6dc9357SAndroid Build Coastguard Worker     const char *ptr = item2.Name.Ptr(1);
349*f6dc9357SAndroid Build Coastguard Worker     const char *end;
350*f6dc9357SAndroid Build Coastguard Worker     UInt32 pos = ConvertStringToUInt32(ptr, &end);
351*f6dc9357SAndroid Build Coastguard Worker     if (*end != 0 || end == ptr)
352*f6dc9357SAndroid Build Coastguard Worker       continue;
353*f6dc9357SAndroid Build Coastguard Worker     if (pos >= size)
354*f6dc9357SAndroid Build Coastguard Worker       continue;
355*f6dc9357SAndroid Build Coastguard Worker     UInt32 start = pos;
356*f6dc9357SAndroid Build Coastguard Worker     for (;;)
357*f6dc9357SAndroid Build Coastguard Worker     {
358*f6dc9357SAndroid Build Coastguard Worker       if (pos >= size)
359*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
360*f6dc9357SAndroid Build Coastguard Worker       const Byte c = p[pos];
361*f6dc9357SAndroid Build Coastguard Worker       if (c == 0 || c == 0x0A)
362*f6dc9357SAndroid Build Coastguard Worker         break;
363*f6dc9357SAndroid Build Coastguard Worker       pos++;
364*f6dc9357SAndroid Build Coastguard Worker     }
365*f6dc9357SAndroid Build Coastguard Worker     item2.Name.SetFrom((const char *)(p + start), (unsigned)(pos - start));
366*f6dc9357SAndroid Build Coastguard Worker   }
367*f6dc9357SAndroid Build Coastguard Worker 
368*f6dc9357SAndroid Build Coastguard Worker   _longNames_FileIndex = (int)fileIndex;
369*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
370*f6dc9357SAndroid Build Coastguard Worker }
371*f6dc9357SAndroid Build Coastguard Worker 
ChangeDuplicateNames()372*f6dc9357SAndroid Build Coastguard Worker void CHandler::ChangeDuplicateNames()
373*f6dc9357SAndroid Build Coastguard Worker {
374*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
375*f6dc9357SAndroid Build Coastguard Worker   for (i = 1; i < _items.Size(); i++)
376*f6dc9357SAndroid Build Coastguard Worker   {
377*f6dc9357SAndroid Build Coastguard Worker     CItem &item = _items[i];
378*f6dc9357SAndroid Build Coastguard Worker     if (item.Name[0] == '/')
379*f6dc9357SAndroid Build Coastguard Worker       continue;
380*f6dc9357SAndroid Build Coastguard Worker     CItem &prev = _items[i - 1];
381*f6dc9357SAndroid Build Coastguard Worker     if (item.Name == prev.Name)
382*f6dc9357SAndroid Build Coastguard Worker     {
383*f6dc9357SAndroid Build Coastguard Worker       if (prev.SameNameIndex < 0)
384*f6dc9357SAndroid Build Coastguard Worker         prev.SameNameIndex = 0;
385*f6dc9357SAndroid Build Coastguard Worker       item.SameNameIndex = prev.SameNameIndex + 1;
386*f6dc9357SAndroid Build Coastguard Worker     }
387*f6dc9357SAndroid Build Coastguard Worker   }
388*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _items.Size(); i++)
389*f6dc9357SAndroid Build Coastguard Worker   {
390*f6dc9357SAndroid Build Coastguard Worker     CItem &item = _items[i];
391*f6dc9357SAndroid Build Coastguard Worker     if (item.SameNameIndex < 0)
392*f6dc9357SAndroid Build Coastguard Worker       continue;
393*f6dc9357SAndroid Build Coastguard Worker     char sz[32];
394*f6dc9357SAndroid Build Coastguard Worker     ConvertUInt32ToString((unsigned)item.SameNameIndex + 1, sz);
395*f6dc9357SAndroid Build Coastguard Worker     unsigned len = MyStringLen(sz);
396*f6dc9357SAndroid Build Coastguard Worker     sz[len++] = '.';
397*f6dc9357SAndroid Build Coastguard Worker     sz[len] = 0;
398*f6dc9357SAndroid Build Coastguard Worker     item.Name.Insert(0, sz);
399*f6dc9357SAndroid Build Coastguard Worker   }
400*f6dc9357SAndroid Build Coastguard Worker }
401*f6dc9357SAndroid Build Coastguard Worker 
FindItem(UInt32 offset) const402*f6dc9357SAndroid Build Coastguard Worker int CHandler::FindItem(UInt32 offset) const
403*f6dc9357SAndroid Build Coastguard Worker {
404*f6dc9357SAndroid Build Coastguard Worker   unsigned left = 0, right = _items.Size();
405*f6dc9357SAndroid Build Coastguard Worker   while (left != right)
406*f6dc9357SAndroid Build Coastguard Worker   {
407*f6dc9357SAndroid Build Coastguard Worker     const unsigned mid = (left + right) / 2;
408*f6dc9357SAndroid Build Coastguard Worker     const UInt64 midVal = _items[mid].HeaderPos;
409*f6dc9357SAndroid Build Coastguard Worker     if (offset == midVal)
410*f6dc9357SAndroid Build Coastguard Worker       return (int)mid;
411*f6dc9357SAndroid Build Coastguard Worker     if (offset < midVal)
412*f6dc9357SAndroid Build Coastguard Worker       right = mid;
413*f6dc9357SAndroid Build Coastguard Worker     else
414*f6dc9357SAndroid Build Coastguard Worker       left = mid + 1;
415*f6dc9357SAndroid Build Coastguard Worker   }
416*f6dc9357SAndroid Build Coastguard Worker   return -1;
417*f6dc9357SAndroid Build Coastguard Worker }
418*f6dc9357SAndroid Build Coastguard Worker 
AddFunc(UInt32 offset,const Byte * data,size_t size,size_t & pos)419*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos)
420*f6dc9357SAndroid Build Coastguard Worker {
421*f6dc9357SAndroid Build Coastguard Worker   const int fileIndex = FindItem(offset);
422*f6dc9357SAndroid Build Coastguard Worker   if (fileIndex < (int)0)
423*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
424*f6dc9357SAndroid Build Coastguard Worker 
425*f6dc9357SAndroid Build Coastguard Worker   size_t i = pos;
426*f6dc9357SAndroid Build Coastguard Worker   do
427*f6dc9357SAndroid Build Coastguard Worker   {
428*f6dc9357SAndroid Build Coastguard Worker     if (i >= size)
429*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
430*f6dc9357SAndroid Build Coastguard Worker   }
431*f6dc9357SAndroid Build Coastguard Worker   while (data[i++] != 0);
432*f6dc9357SAndroid Build Coastguard Worker 
433*f6dc9357SAndroid Build Coastguard Worker   AString &s = _libFiles[_numLibFiles];
434*f6dc9357SAndroid Build Coastguard Worker   const AString &name = _items[(unsigned)fileIndex].Name;
435*f6dc9357SAndroid Build Coastguard Worker   s += name;
436*f6dc9357SAndroid Build Coastguard Worker   if (!name.IsEmpty() && name.Back() == '/')
437*f6dc9357SAndroid Build Coastguard Worker     s.DeleteBack();
438*f6dc9357SAndroid Build Coastguard Worker   s += "    ";
439*f6dc9357SAndroid Build Coastguard Worker   s += (const char *)(data + pos);
440*f6dc9357SAndroid Build Coastguard Worker   // s.Add_Char((char)0xD);
441*f6dc9357SAndroid Build Coastguard Worker   s.Add_LF();
442*f6dc9357SAndroid Build Coastguard Worker   pos = i;
443*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
444*f6dc9357SAndroid Build Coastguard Worker }
445*f6dc9357SAndroid Build Coastguard Worker 
Get32(const Byte * p,unsigned be)446*f6dc9357SAndroid Build Coastguard Worker static UInt32 Get32(const Byte *p, unsigned be) { if (be) return GetBe32(p); return GetUi32(p); }
447*f6dc9357SAndroid Build Coastguard Worker 
ParseLibSymbols(IInStream * stream,unsigned fileIndex)448*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex)
449*f6dc9357SAndroid Build Coastguard Worker {
450*f6dc9357SAndroid Build Coastguard Worker   CItem &item = _items[fileIndex];
451*f6dc9357SAndroid Build Coastguard Worker   if (item.Name != "/" &&
452*f6dc9357SAndroid Build Coastguard Worker       item.Name != "__.SYMDEF"  &&
453*f6dc9357SAndroid Build Coastguard Worker       item.Name != "__.SYMDEF SORTED")
454*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
455*f6dc9357SAndroid Build Coastguard Worker   if (item.Size > ((UInt32)1 << 30) ||
456*f6dc9357SAndroid Build Coastguard Worker       item.Size < 4)
457*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
458*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_SeekSet(stream, item.GetDataPos()))
459*f6dc9357SAndroid Build Coastguard Worker   size_t size = (size_t)item.Size;
460*f6dc9357SAndroid Build Coastguard Worker   CByteArr p(size);
461*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, p, size))
462*f6dc9357SAndroid Build Coastguard Worker 
463*f6dc9357SAndroid Build Coastguard Worker   size_t pos = 0;
464*f6dc9357SAndroid Build Coastguard Worker 
465*f6dc9357SAndroid Build Coastguard Worker   if (item.Name != "/")
466*f6dc9357SAndroid Build Coastguard Worker   {
467*f6dc9357SAndroid Build Coastguard Worker     // "__.SYMDEF" parsing (BSD)
468*f6dc9357SAndroid Build Coastguard Worker     unsigned be;
469*f6dc9357SAndroid Build Coastguard Worker     for (be = 0; be < 2; be++)
470*f6dc9357SAndroid Build Coastguard Worker     {
471*f6dc9357SAndroid Build Coastguard Worker       const UInt32 tableSize = Get32(p, be);
472*f6dc9357SAndroid Build Coastguard Worker       pos = 4;
473*f6dc9357SAndroid Build Coastguard Worker       if (size - pos < tableSize || (tableSize & 7) != 0)
474*f6dc9357SAndroid Build Coastguard Worker         continue;
475*f6dc9357SAndroid Build Coastguard Worker       size_t namesStart = pos + tableSize;
476*f6dc9357SAndroid Build Coastguard Worker       const UInt32 namesSize = Get32(p.ConstData() + namesStart, be);
477*f6dc9357SAndroid Build Coastguard Worker       namesStart += 4;
478*f6dc9357SAndroid Build Coastguard Worker       if (namesStart > size || namesStart + namesSize != size)
479*f6dc9357SAndroid Build Coastguard Worker         continue;
480*f6dc9357SAndroid Build Coastguard Worker 
481*f6dc9357SAndroid Build Coastguard Worker       const UInt32 numSymbols = tableSize >> 3;
482*f6dc9357SAndroid Build Coastguard Worker       UInt32 i;
483*f6dc9357SAndroid Build Coastguard Worker       for (i = 0; i < numSymbols; i++, pos += 8)
484*f6dc9357SAndroid Build Coastguard Worker       {
485*f6dc9357SAndroid Build Coastguard Worker         size_t namePos = Get32(p + pos, be);
486*f6dc9357SAndroid Build Coastguard Worker         const UInt32 offset = Get32(p + pos + 4, be);
487*f6dc9357SAndroid Build Coastguard Worker         if (AddFunc(offset, p + namesStart, namesSize, namePos) != S_OK)
488*f6dc9357SAndroid Build Coastguard Worker           break;
489*f6dc9357SAndroid Build Coastguard Worker       }
490*f6dc9357SAndroid Build Coastguard Worker       if (i == numSymbols)
491*f6dc9357SAndroid Build Coastguard Worker       {
492*f6dc9357SAndroid Build Coastguard Worker         pos = size;
493*f6dc9357SAndroid Build Coastguard Worker         _type = kType_ALib;
494*f6dc9357SAndroid Build Coastguard Worker         _subType = kSubType_BSD;
495*f6dc9357SAndroid Build Coastguard Worker         break;
496*f6dc9357SAndroid Build Coastguard Worker       }
497*f6dc9357SAndroid Build Coastguard Worker     }
498*f6dc9357SAndroid Build Coastguard Worker     if (be == 2)
499*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
500*f6dc9357SAndroid Build Coastguard Worker   }
501*f6dc9357SAndroid Build Coastguard Worker   else if (_numLibFiles == 0)
502*f6dc9357SAndroid Build Coastguard Worker   {
503*f6dc9357SAndroid Build Coastguard Worker     // archive symbol table (GNU)
504*f6dc9357SAndroid Build Coastguard Worker     const UInt32 numSymbols = GetBe32(p);
505*f6dc9357SAndroid Build Coastguard Worker     pos = 4;
506*f6dc9357SAndroid Build Coastguard Worker     if (numSymbols > (size - pos) / 4)
507*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
508*f6dc9357SAndroid Build Coastguard Worker     pos += 4 * numSymbols;
509*f6dc9357SAndroid Build Coastguard Worker 
510*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < numSymbols; i++)
511*f6dc9357SAndroid Build Coastguard Worker     {
512*f6dc9357SAndroid Build Coastguard Worker       const UInt32 offset = GetBe32(p + 4 + i * 4);
513*f6dc9357SAndroid Build Coastguard Worker       RINOK(AddFunc(offset, p, size, pos))
514*f6dc9357SAndroid Build Coastguard Worker     }
515*f6dc9357SAndroid Build Coastguard Worker     _type = kType_ALib;
516*f6dc9357SAndroid Build Coastguard Worker   }
517*f6dc9357SAndroid Build Coastguard Worker   else
518*f6dc9357SAndroid Build Coastguard Worker   {
519*f6dc9357SAndroid Build Coastguard Worker     // Second linker file (Microsoft .lib)
520*f6dc9357SAndroid Build Coastguard Worker     const UInt32 numMembers = GetUi32(p);
521*f6dc9357SAndroid Build Coastguard Worker     pos = 4;
522*f6dc9357SAndroid Build Coastguard Worker     if (numMembers > (size - pos) / 4)
523*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
524*f6dc9357SAndroid Build Coastguard Worker     pos += 4 * numMembers;
525*f6dc9357SAndroid Build Coastguard Worker 
526*f6dc9357SAndroid Build Coastguard Worker     if (size - pos < 4)
527*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
528*f6dc9357SAndroid Build Coastguard Worker     const UInt32 numSymbols = GetUi32(p + pos);
529*f6dc9357SAndroid Build Coastguard Worker     pos += 4;
530*f6dc9357SAndroid Build Coastguard Worker     if (numSymbols > (size - pos) / 2)
531*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
532*f6dc9357SAndroid Build Coastguard Worker     size_t indexStart = pos;
533*f6dc9357SAndroid Build Coastguard Worker     pos += 2 * numSymbols;
534*f6dc9357SAndroid Build Coastguard Worker 
535*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < numSymbols; i++)
536*f6dc9357SAndroid Build Coastguard Worker     {
537*f6dc9357SAndroid Build Coastguard Worker       // index is 1-based. So 32-bit numSymbols field works as item[0]
538*f6dc9357SAndroid Build Coastguard Worker       const UInt32 index = GetUi16(p + indexStart + i * 2);
539*f6dc9357SAndroid Build Coastguard Worker       if (index == 0 || index > numMembers)
540*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
541*f6dc9357SAndroid Build Coastguard Worker       const UInt32 offset = GetUi32(p + index * 4);
542*f6dc9357SAndroid Build Coastguard Worker       RINOK(AddFunc(offset, p, size, pos))
543*f6dc9357SAndroid Build Coastguard Worker     }
544*f6dc9357SAndroid Build Coastguard Worker     _type = kType_Lib;
545*f6dc9357SAndroid Build Coastguard Worker   }
546*f6dc9357SAndroid Build Coastguard Worker   // size can be 2-byte aligned in linux files
547*f6dc9357SAndroid Build Coastguard Worker   if (pos != size && pos + (pos & 1) != size)
548*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
549*f6dc9357SAndroid Build Coastguard Worker   item.TextFileIndex = (int)(_numLibFiles++);
550*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
551*f6dc9357SAndroid Build Coastguard Worker }
552*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback * callback))553*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
554*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * /* maxCheckStartPosition */,
555*f6dc9357SAndroid Build Coastguard Worker     IArchiveOpenCallback *callback))
556*f6dc9357SAndroid Build Coastguard Worker {
557*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
558*f6dc9357SAndroid Build Coastguard Worker   {
559*f6dc9357SAndroid Build Coastguard Worker     Close();
560*f6dc9357SAndroid Build Coastguard Worker 
561*f6dc9357SAndroid Build Coastguard Worker     UInt64 fileSize;
562*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_AtBegin_GetSize(stream, fileSize))
563*f6dc9357SAndroid Build Coastguard Worker 
564*f6dc9357SAndroid Build Coastguard Worker     CInArchive arc;
565*f6dc9357SAndroid Build Coastguard Worker     RINOK(arc.Open(stream))
566*f6dc9357SAndroid Build Coastguard Worker 
567*f6dc9357SAndroid Build Coastguard Worker     if (callback)
568*f6dc9357SAndroid Build Coastguard Worker     {
569*f6dc9357SAndroid Build Coastguard Worker       RINOK(callback->SetTotal(NULL, &fileSize))
570*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numFiles = _items.Size();
571*f6dc9357SAndroid Build Coastguard Worker       RINOK(callback->SetCompleted(&numFiles, &arc.Position))
572*f6dc9357SAndroid Build Coastguard Worker     }
573*f6dc9357SAndroid Build Coastguard Worker 
574*f6dc9357SAndroid Build Coastguard Worker     CItem item;
575*f6dc9357SAndroid Build Coastguard Worker     for (;;)
576*f6dc9357SAndroid Build Coastguard Worker     {
577*f6dc9357SAndroid Build Coastguard Worker       bool filled;
578*f6dc9357SAndroid Build Coastguard Worker       RINOK(arc.GetNextItem(item, filled))
579*f6dc9357SAndroid Build Coastguard Worker       if (!filled)
580*f6dc9357SAndroid Build Coastguard Worker         break;
581*f6dc9357SAndroid Build Coastguard Worker       _items.Add(item);
582*f6dc9357SAndroid Build Coastguard Worker       arc.SkipData(item.Size);
583*f6dc9357SAndroid Build Coastguard Worker       if (callback && (_items.Size() & 0xFF) == 0)
584*f6dc9357SAndroid Build Coastguard Worker       {
585*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numFiles = _items.Size();
586*f6dc9357SAndroid Build Coastguard Worker         RINOK(callback->SetCompleted(&numFiles, &arc.Position))
587*f6dc9357SAndroid Build Coastguard Worker       }
588*f6dc9357SAndroid Build Coastguard Worker     }
589*f6dc9357SAndroid Build Coastguard Worker 
590*f6dc9357SAndroid Build Coastguard Worker     if (_items.IsEmpty())
591*f6dc9357SAndroid Build Coastguard Worker     {
592*f6dc9357SAndroid Build Coastguard Worker       // we don't need false empty archives (8-bytes signature only)
593*f6dc9357SAndroid Build Coastguard Worker       if (arc.Position != fileSize)
594*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
595*f6dc9357SAndroid Build Coastguard Worker     }
596*f6dc9357SAndroid Build Coastguard Worker 
597*f6dc9357SAndroid Build Coastguard Worker     _isArc = true;
598*f6dc9357SAndroid Build Coastguard Worker 
599*f6dc9357SAndroid Build Coastguard Worker     _subType = arc.SubType;
600*f6dc9357SAndroid Build Coastguard Worker 
601*f6dc9357SAndroid Build Coastguard Worker     if (ParseLongNames(stream) != S_OK)
602*f6dc9357SAndroid Build Coastguard Worker       UpdateErrorMessage("Long file names parsing error");
603*f6dc9357SAndroid Build Coastguard Worker     if (_longNames_FileIndex >= 0)
604*f6dc9357SAndroid Build Coastguard Worker       _items.Delete((unsigned)_longNames_FileIndex);
605*f6dc9357SAndroid Build Coastguard Worker 
606*f6dc9357SAndroid Build Coastguard Worker     if (!_items.IsEmpty() && _items[0].Name == "debian-binary")
607*f6dc9357SAndroid Build Coastguard Worker     {
608*f6dc9357SAndroid Build Coastguard Worker       _type = kType_Deb;
609*f6dc9357SAndroid Build Coastguard Worker       _items.DeleteFrontal(1);
610*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < _items.Size(); i++)
611*f6dc9357SAndroid Build Coastguard Worker         if (_items[i].Name.IsPrefixedBy("data.tar."))
612*f6dc9357SAndroid Build Coastguard Worker         {
613*f6dc9357SAndroid Build Coastguard Worker           if (_mainSubfile < 0)
614*f6dc9357SAndroid Build Coastguard Worker             _mainSubfile = (int)i;
615*f6dc9357SAndroid Build Coastguard Worker           else
616*f6dc9357SAndroid Build Coastguard Worker           {
617*f6dc9357SAndroid Build Coastguard Worker             _mainSubfile = -1;
618*f6dc9357SAndroid Build Coastguard Worker             break;
619*f6dc9357SAndroid Build Coastguard Worker           }
620*f6dc9357SAndroid Build Coastguard Worker         }
621*f6dc9357SAndroid Build Coastguard Worker     }
622*f6dc9357SAndroid Build Coastguard Worker     else
623*f6dc9357SAndroid Build Coastguard Worker     {
624*f6dc9357SAndroid Build Coastguard Worker       ChangeDuplicateNames();
625*f6dc9357SAndroid Build Coastguard Worker       bool error = false;
626*f6dc9357SAndroid Build Coastguard Worker       for (unsigned li = 0; li < 2 && li < _items.Size(); li++)
627*f6dc9357SAndroid Build Coastguard Worker         if (ParseLibSymbols(stream, li) != S_OK)
628*f6dc9357SAndroid Build Coastguard Worker           error = true;
629*f6dc9357SAndroid Build Coastguard Worker       if (error)
630*f6dc9357SAndroid Build Coastguard Worker         UpdateErrorMessage("Library symbols information error");
631*f6dc9357SAndroid Build Coastguard Worker     }
632*f6dc9357SAndroid Build Coastguard Worker 
633*f6dc9357SAndroid Build Coastguard Worker     _stream = stream;
634*f6dc9357SAndroid Build Coastguard Worker     _phySize = arc.Position;
635*f6dc9357SAndroid Build Coastguard Worker 
636*f6dc9357SAndroid Build Coastguard Worker     /*
637*f6dc9357SAndroid Build Coastguard Worker     if (fileSize < _phySize)
638*f6dc9357SAndroid Build Coastguard Worker       UpdateErrorMessage("Unexpected end of archive");
639*f6dc9357SAndroid Build Coastguard Worker     */
640*f6dc9357SAndroid Build Coastguard Worker   }
641*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
642*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
643*f6dc9357SAndroid Build Coastguard Worker }
644*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Close ())645*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
646*f6dc9357SAndroid Build Coastguard Worker {
647*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
648*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
649*f6dc9357SAndroid Build Coastguard Worker 
650*f6dc9357SAndroid Build Coastguard Worker   _errorMessage.Empty();
651*f6dc9357SAndroid Build Coastguard Worker   _stream.Release();
652*f6dc9357SAndroid Build Coastguard Worker   _items.Clear();
653*f6dc9357SAndroid Build Coastguard Worker 
654*f6dc9357SAndroid Build Coastguard Worker   _type = kType_Ar;
655*f6dc9357SAndroid Build Coastguard Worker   _subType = kSubType_None;
656*f6dc9357SAndroid Build Coastguard Worker   _mainSubfile = -1;
657*f6dc9357SAndroid Build Coastguard Worker   _longNames_FileIndex = -1;
658*f6dc9357SAndroid Build Coastguard Worker 
659*f6dc9357SAndroid Build Coastguard Worker   _numLibFiles = 0;
660*f6dc9357SAndroid Build Coastguard Worker   _libFiles[0].Empty();
661*f6dc9357SAndroid Build Coastguard Worker   _libFiles[1].Empty();
662*f6dc9357SAndroid Build Coastguard Worker 
663*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
664*f6dc9357SAndroid Build Coastguard Worker }
665*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))666*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
667*f6dc9357SAndroid Build Coastguard Worker {
668*f6dc9357SAndroid Build Coastguard Worker   *numItems = _items.Size();
669*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
670*f6dc9357SAndroid Build Coastguard Worker }
671*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))672*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
673*f6dc9357SAndroid Build Coastguard Worker {
674*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
675*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
676*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
677*f6dc9357SAndroid Build Coastguard Worker   {
678*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = _phySize; break;
679*f6dc9357SAndroid Build Coastguard Worker     case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
680*f6dc9357SAndroid Build Coastguard Worker     case kpidExtension: prop = k_TypeExtionsions[(unsigned)_type]; break;
681*f6dc9357SAndroid Build Coastguard Worker     case kpidShortComment:
682*f6dc9357SAndroid Build Coastguard Worker     case kpidSubType:
683*f6dc9357SAndroid Build Coastguard Worker     {
684*f6dc9357SAndroid Build Coastguard Worker       AString s (k_TypeExtionsions[(unsigned)_type]);
685*f6dc9357SAndroid Build Coastguard Worker       if (_subType == kSubType_BSD)
686*f6dc9357SAndroid Build Coastguard Worker         s += ":BSD";
687*f6dc9357SAndroid Build Coastguard Worker       prop = s;
688*f6dc9357SAndroid Build Coastguard Worker       break;
689*f6dc9357SAndroid Build Coastguard Worker     }
690*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
691*f6dc9357SAndroid Build Coastguard Worker     {
692*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
693*f6dc9357SAndroid Build Coastguard Worker       if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
694*f6dc9357SAndroid Build Coastguard Worker       prop = v;
695*f6dc9357SAndroid Build Coastguard Worker       break;
696*f6dc9357SAndroid Build Coastguard Worker     }
697*f6dc9357SAndroid Build Coastguard Worker     case kpidWarning: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
698*f6dc9357SAndroid Build Coastguard Worker     case kpidIsNotArcType: if (_type != kType_Deb) prop = true; break;
699*f6dc9357SAndroid Build Coastguard Worker   }
700*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
701*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
702*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
703*f6dc9357SAndroid Build Coastguard Worker }
704*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))705*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
706*f6dc9357SAndroid Build Coastguard Worker {
707*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
708*f6dc9357SAndroid Build Coastguard Worker   NWindows::NCOM::CPropVariant prop;
709*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[index];
710*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
711*f6dc9357SAndroid Build Coastguard Worker   {
712*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
713*f6dc9357SAndroid Build Coastguard Worker       if (item.TextFileIndex >= 0)
714*f6dc9357SAndroid Build Coastguard Worker         prop = (item.TextFileIndex == 0) ? "1.txt" : "2.txt";
715*f6dc9357SAndroid Build Coastguard Worker       else
716*f6dc9357SAndroid Build Coastguard Worker         prop = (const wchar_t *)NItemName::GetOsPath_Remove_TailSlash(MultiByteToUnicodeString(item.Name, CP_OEMCP));
717*f6dc9357SAndroid Build Coastguard Worker       break;
718*f6dc9357SAndroid Build Coastguard Worker     case kpidSize:
719*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize:
720*f6dc9357SAndroid Build Coastguard Worker       if (item.TextFileIndex >= 0)
721*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len();
722*f6dc9357SAndroid Build Coastguard Worker       else
723*f6dc9357SAndroid Build Coastguard Worker         prop = item.Size;
724*f6dc9357SAndroid Build Coastguard Worker       break;
725*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime:
726*f6dc9357SAndroid Build Coastguard Worker     {
727*f6dc9357SAndroid Build Coastguard Worker       if (item.MTime != 0)
728*f6dc9357SAndroid Build Coastguard Worker         PropVariant_SetFrom_UnixTime(prop, item.MTime);
729*f6dc9357SAndroid Build Coastguard Worker       break;
730*f6dc9357SAndroid Build Coastguard Worker     }
731*f6dc9357SAndroid Build Coastguard Worker     case kpidUserId: if (item.User != 0) prop = item.User; break;
732*f6dc9357SAndroid Build Coastguard Worker     case kpidGroupId: if (item.Group != 0) prop = item.Group; break;
733*f6dc9357SAndroid Build Coastguard Worker     case kpidPosixAttrib:
734*f6dc9357SAndroid Build Coastguard Worker       if (item.TextFileIndex < 0)
735*f6dc9357SAndroid Build Coastguard Worker         prop = item.Mode;
736*f6dc9357SAndroid Build Coastguard Worker       break;
737*f6dc9357SAndroid Build Coastguard Worker   }
738*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
739*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
740*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
741*f6dc9357SAndroid Build Coastguard Worker }
742*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))743*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
744*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
745*f6dc9357SAndroid Build Coastguard Worker {
746*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
747*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
748*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
749*f6dc9357SAndroid Build Coastguard Worker     numItems = _items.Size();
750*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
751*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
752*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
753*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
754*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
755*f6dc9357SAndroid Build Coastguard Worker   {
756*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[allFilesMode ? i : indices[i]];
757*f6dc9357SAndroid Build Coastguard Worker     totalSize +=
758*f6dc9357SAndroid Build Coastguard Worker       (item.TextFileIndex >= 0) ?
759*f6dc9357SAndroid Build Coastguard Worker         (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size;
760*f6dc9357SAndroid Build Coastguard Worker   }
761*f6dc9357SAndroid Build Coastguard Worker   extractCallback->SetTotal(totalSize);
762*f6dc9357SAndroid Build Coastguard Worker 
763*f6dc9357SAndroid Build Coastguard Worker   UInt64 currentTotalSize = 0;
764*f6dc9357SAndroid Build Coastguard Worker 
765*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
766*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
767*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
768*f6dc9357SAndroid Build Coastguard Worker 
769*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
770*f6dc9357SAndroid Build Coastguard Worker   inStream->SetStream(_stream);
771*f6dc9357SAndroid Build Coastguard Worker 
772*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;; i++)
773*f6dc9357SAndroid Build Coastguard Worker   {
774*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = lps->OutSize = currentTotalSize;
775*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
776*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
777*f6dc9357SAndroid Build Coastguard Worker       break;
778*f6dc9357SAndroid Build Coastguard Worker     Int32 opRes;
779*f6dc9357SAndroid Build Coastguard Worker    {
780*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialOutStream> realOutStream;
781*f6dc9357SAndroid Build Coastguard Worker     const Int32 askMode = testMode ?
782*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kTest :
783*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kExtract;
784*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
785*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[index];
786*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
787*f6dc9357SAndroid Build Coastguard Worker     currentTotalSize += (item.TextFileIndex >= 0) ?
788*f6dc9357SAndroid Build Coastguard Worker         (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size;
789*f6dc9357SAndroid Build Coastguard Worker 
790*f6dc9357SAndroid Build Coastguard Worker     if (!testMode && !realOutStream)
791*f6dc9357SAndroid Build Coastguard Worker       continue;
792*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->PrepareOperation(askMode))
793*f6dc9357SAndroid Build Coastguard Worker     if (testMode)
794*f6dc9357SAndroid Build Coastguard Worker     {
795*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
796*f6dc9357SAndroid Build Coastguard Worker       continue;
797*f6dc9357SAndroid Build Coastguard Worker     }
798*f6dc9357SAndroid Build Coastguard Worker     opRes = NExtract::NOperationResult::kOK;
799*f6dc9357SAndroid Build Coastguard Worker     if (item.TextFileIndex >= 0)
800*f6dc9357SAndroid Build Coastguard Worker     {
801*f6dc9357SAndroid Build Coastguard Worker       const AString &f = _libFiles[(unsigned)item.TextFileIndex];
802*f6dc9357SAndroid Build Coastguard Worker       if (realOutStream)
803*f6dc9357SAndroid Build Coastguard Worker         RINOK(WriteStream(realOutStream, f, f.Len()))
804*f6dc9357SAndroid Build Coastguard Worker     }
805*f6dc9357SAndroid Build Coastguard Worker     else
806*f6dc9357SAndroid Build Coastguard Worker     {
807*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(_stream, item.GetDataPos()))
808*f6dc9357SAndroid Build Coastguard Worker       inStream->Init(item.Size);
809*f6dc9357SAndroid Build Coastguard Worker       RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
810*f6dc9357SAndroid Build Coastguard Worker       if (copyCoder->TotalSize != item.Size)
811*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kDataError;
812*f6dc9357SAndroid Build Coastguard Worker     }
813*f6dc9357SAndroid Build Coastguard Worker    }
814*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(opRes))
815*f6dc9357SAndroid Build Coastguard Worker   }
816*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
817*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
818*f6dc9357SAndroid Build Coastguard Worker }
819*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetStream (UInt32 index,ISequentialInStream ** stream))820*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
821*f6dc9357SAndroid Build Coastguard Worker {
822*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
823*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[index];
824*f6dc9357SAndroid Build Coastguard Worker   if (item.TextFileIndex >= 0)
825*f6dc9357SAndroid Build Coastguard Worker   {
826*f6dc9357SAndroid Build Coastguard Worker     const AString &f = _libFiles[(unsigned)item.TextFileIndex];
827*f6dc9357SAndroid Build Coastguard Worker     Create_BufInStream_WithNewBuffer((const void *)(const char *)f, f.Len(), stream);
828*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
829*f6dc9357SAndroid Build Coastguard Worker   }
830*f6dc9357SAndroid Build Coastguard Worker   else
831*f6dc9357SAndroid Build Coastguard Worker     return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream);
832*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
833*f6dc9357SAndroid Build Coastguard Worker }
834*f6dc9357SAndroid Build Coastguard Worker 
835*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
836*f6dc9357SAndroid Build Coastguard Worker   "Ar", "ar a deb udeb lib", NULL, 0xEC,
837*f6dc9357SAndroid Build Coastguard Worker   kSignature,
838*f6dc9357SAndroid Build Coastguard Worker   0,
839*f6dc9357SAndroid Build Coastguard Worker   0,
840*f6dc9357SAndroid Build Coastguard Worker   NULL)
841*f6dc9357SAndroid Build Coastguard Worker 
842*f6dc9357SAndroid Build Coastguard Worker }}
843