xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/CramfsHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // CramfsHandler.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/7zCrc.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Alloc.h"
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/LzmaDec.h"
9*f6dc9357SAndroid Build Coastguard Worker 
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyLinux.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringConvert.h"
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariantUtils.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "../Common/LimitedStreams.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamObjects.h"
20*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
21*f6dc9357SAndroid Build Coastguard Worker 
22*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
23*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/ZlibDecoder.h"
24*f6dc9357SAndroid Build Coastguard Worker 
25*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
26*f6dc9357SAndroid Build Coastguard Worker namespace NCramfs {
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker static const Byte kSignature[] =
29*f6dc9357SAndroid Build Coastguard Worker   { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' };
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kArcSizeMax = (256 + 16) << 20;
32*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kNumFilesMax = (1 << 19);
33*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumDirLevelsMax = (1 << 8);
34*f6dc9357SAndroid Build Coastguard Worker 
35*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kHeaderSize = 0x40;
36*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeaderNameSize = 16;
37*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kNodeSize = 12;
38*f6dc9357SAndroid Build Coastguard Worker 
39*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kFlag_FsVer2 = (1 << 0);
40*f6dc9357SAndroid Build Coastguard Worker 
41*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Flags_BlockSize_Shift = 11;
42*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Flags_BlockSize_Mask = 7;
43*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Flags_Method_Shift = 14;
44*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Flags_Method_Mask = 3;
45*f6dc9357SAndroid Build Coastguard Worker 
46*f6dc9357SAndroid Build Coastguard Worker /*
47*f6dc9357SAndroid Build Coastguard Worker   There is possible collision in flags:
48*f6dc9357SAndroid Build Coastguard Worker     - Original CramFS writes 0 in method field. But it uses ZLIB.
49*f6dc9357SAndroid Build Coastguard Worker     - Modified CramFS writes 0 in method field for "NONE" compression?
50*f6dc9357SAndroid Build Coastguard Worker   How to solve that collision?
51*f6dc9357SAndroid Build Coastguard Worker */
52*f6dc9357SAndroid Build Coastguard Worker 
53*f6dc9357SAndroid Build Coastguard Worker #define k_Flags_Method_NONE 0
54*f6dc9357SAndroid Build Coastguard Worker #define k_Flags_Method_ZLIB 1
55*f6dc9357SAndroid Build Coastguard Worker #define k_Flags_Method_LZMA 2
56*f6dc9357SAndroid Build Coastguard Worker 
57*f6dc9357SAndroid Build Coastguard Worker static const char * const k_Methods[] =
58*f6dc9357SAndroid Build Coastguard Worker {
59*f6dc9357SAndroid Build Coastguard Worker     "Copy"
60*f6dc9357SAndroid Build Coastguard Worker   , "ZLIB"
61*f6dc9357SAndroid Build Coastguard Worker   , "LZMA"
62*f6dc9357SAndroid Build Coastguard Worker   , "Unknown"
63*f6dc9357SAndroid Build Coastguard Worker };
64*f6dc9357SAndroid Build Coastguard Worker 
65*f6dc9357SAndroid Build Coastguard Worker static const CUInt32PCharPair k_Flags[] =
66*f6dc9357SAndroid Build Coastguard Worker {
67*f6dc9357SAndroid Build Coastguard Worker   { 0, "Ver2" },
68*f6dc9357SAndroid Build Coastguard Worker   { 1, "SortedDirs" },
69*f6dc9357SAndroid Build Coastguard Worker   { 8, "Holes" },
70*f6dc9357SAndroid Build Coastguard Worker   { 9, "WrongSignature" },
71*f6dc9357SAndroid Build Coastguard Worker   { 10, "ShiftedRootOffset" }
72*f6dc9357SAndroid Build Coastguard Worker };
73*f6dc9357SAndroid Build Coastguard Worker 
74*f6dc9357SAndroid Build Coastguard Worker static const unsigned kBlockSizeLog = 12;
75*f6dc9357SAndroid Build Coastguard Worker 
76*f6dc9357SAndroid Build Coastguard Worker /*
77*f6dc9357SAndroid Build Coastguard Worker struct CNode
78*f6dc9357SAndroid Build Coastguard Worker {
79*f6dc9357SAndroid Build Coastguard Worker   UInt16 Mode;
80*f6dc9357SAndroid Build Coastguard Worker   UInt16 Uid;
81*f6dc9357SAndroid Build Coastguard Worker   UInt32 Size;
82*f6dc9357SAndroid Build Coastguard Worker   Byte Gid;
83*f6dc9357SAndroid Build Coastguard Worker   UInt32 NameLen;
84*f6dc9357SAndroid Build Coastguard Worker   UInt32 Offset;
85*f6dc9357SAndroid Build Coastguard Worker 
86*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p)
87*f6dc9357SAndroid Build Coastguard Worker   {
88*f6dc9357SAndroid Build Coastguard Worker     Mode = GetUi16(p);
89*f6dc9357SAndroid Build Coastguard Worker     Uid = GetUi16(p + 2);
90*f6dc9357SAndroid Build Coastguard Worker     Size = Get32(p + 4) & 0xFFFFFF;
91*f6dc9357SAndroid Build Coastguard Worker     Gid = p[7];
92*f6dc9357SAndroid Build Coastguard Worker     NameLen = p[8] & 0x3F;
93*f6dc9357SAndroid Build Coastguard Worker     Offset = Get32(p + 8) >> 6;
94*f6dc9357SAndroid Build Coastguard Worker   }
95*f6dc9357SAndroid Build Coastguard Worker };
96*f6dc9357SAndroid Build Coastguard Worker */
97*f6dc9357SAndroid Build Coastguard Worker 
98*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) (be ? GetBe32(p) : GetUi32(p))
99*f6dc9357SAndroid Build Coastguard Worker 
GetMode(const Byte * p,bool be)100*f6dc9357SAndroid Build Coastguard Worker static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); }
IsDir(const Byte * p,bool be)101*f6dc9357SAndroid Build Coastguard Worker static bool IsDir(const Byte *p, bool be) { return MY_LIN_S_ISDIR(GetMode(p, be)); }
102*f6dc9357SAndroid Build Coastguard Worker 
GetSize(const Byte * p,bool be)103*f6dc9357SAndroid Build Coastguard Worker static UInt32 GetSize(const Byte *p, bool be)
104*f6dc9357SAndroid Build Coastguard Worker {
105*f6dc9357SAndroid Build Coastguard Worker   if (be)
106*f6dc9357SAndroid Build Coastguard Worker     return GetBe32(p + 4) >> 8;
107*f6dc9357SAndroid Build Coastguard Worker   else
108*f6dc9357SAndroid Build Coastguard Worker     return GetUi32(p + 4) & 0xFFFFFF;
109*f6dc9357SAndroid Build Coastguard Worker }
110*f6dc9357SAndroid Build Coastguard Worker 
GetNameLen(const Byte * p,bool be)111*f6dc9357SAndroid Build Coastguard Worker static UInt32 GetNameLen(const Byte *p, bool be)
112*f6dc9357SAndroid Build Coastguard Worker {
113*f6dc9357SAndroid Build Coastguard Worker   if (be)
114*f6dc9357SAndroid Build Coastguard Worker     return (p[8] & 0xFC);
115*f6dc9357SAndroid Build Coastguard Worker   else
116*f6dc9357SAndroid Build Coastguard Worker     return ((UInt32)p[8] & (UInt32)0x3F) << 2;
117*f6dc9357SAndroid Build Coastguard Worker }
118*f6dc9357SAndroid Build Coastguard Worker 
GetOffset(const Byte * p,bool be)119*f6dc9357SAndroid Build Coastguard Worker static UInt32 GetOffset(const Byte *p, bool be)
120*f6dc9357SAndroid Build Coastguard Worker {
121*f6dc9357SAndroid Build Coastguard Worker   if (be)
122*f6dc9357SAndroid Build Coastguard Worker     return (GetBe32(p + 8) & 0x03FFFFFF) << 2;
123*f6dc9357SAndroid Build Coastguard Worker   else
124*f6dc9357SAndroid Build Coastguard Worker     return GetUi32(p + 8) >> 6 << 2;
125*f6dc9357SAndroid Build Coastguard Worker }
126*f6dc9357SAndroid Build Coastguard Worker 
127*f6dc9357SAndroid Build Coastguard Worker struct CItem
128*f6dc9357SAndroid Build Coastguard Worker {
129*f6dc9357SAndroid Build Coastguard Worker   UInt32 Offset;
130*f6dc9357SAndroid Build Coastguard Worker   int Parent;
131*f6dc9357SAndroid Build Coastguard Worker };
132*f6dc9357SAndroid Build Coastguard Worker 
133*f6dc9357SAndroid Build Coastguard Worker struct CHeader
134*f6dc9357SAndroid Build Coastguard Worker {
135*f6dc9357SAndroid Build Coastguard Worker   bool be;
136*f6dc9357SAndroid Build Coastguard Worker   UInt32 Size;
137*f6dc9357SAndroid Build Coastguard Worker   UInt32 Flags;
138*f6dc9357SAndroid Build Coastguard Worker   // UInt32 Future;
139*f6dc9357SAndroid Build Coastguard Worker   UInt32 Crc;
140*f6dc9357SAndroid Build Coastguard Worker   // UInt32 Edition;
141*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumBlocks;
142*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumFiles;
143*f6dc9357SAndroid Build Coastguard Worker   char Name[kHeaderNameSize];
144*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NCramfs::CHeader145*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p)
146*f6dc9357SAndroid Build Coastguard Worker   {
147*f6dc9357SAndroid Build Coastguard Worker     if (memcmp(p + 16, kSignature, Z7_ARRAY_SIZE(kSignature)) != 0)
148*f6dc9357SAndroid Build Coastguard Worker       return false;
149*f6dc9357SAndroid Build Coastguard Worker     switch (GetUi32(p))
150*f6dc9357SAndroid Build Coastguard Worker     {
151*f6dc9357SAndroid Build Coastguard Worker       case 0x28CD3D45: be = false; break;
152*f6dc9357SAndroid Build Coastguard Worker       case 0x453DCD28: be = true; break;
153*f6dc9357SAndroid Build Coastguard Worker       default: return false;
154*f6dc9357SAndroid Build Coastguard Worker     }
155*f6dc9357SAndroid Build Coastguard Worker     Size = Get32(p + 4);
156*f6dc9357SAndroid Build Coastguard Worker     Flags = Get32(p + 8);
157*f6dc9357SAndroid Build Coastguard Worker     // Future = Get32(p + 0xC);
158*f6dc9357SAndroid Build Coastguard Worker     Crc = Get32(p + 0x20);
159*f6dc9357SAndroid Build Coastguard Worker     // Edition = Get32(p + 0x24);
160*f6dc9357SAndroid Build Coastguard Worker     NumBlocks = Get32(p + 0x28);
161*f6dc9357SAndroid Build Coastguard Worker     NumFiles = Get32(p + 0x2C);
162*f6dc9357SAndroid Build Coastguard Worker     memcpy(Name, p + 0x30, kHeaderNameSize);
163*f6dc9357SAndroid Build Coastguard Worker     return true;
164*f6dc9357SAndroid Build Coastguard Worker   }
165*f6dc9357SAndroid Build Coastguard Worker 
IsVer2NArchive::NCramfs::CHeader166*f6dc9357SAndroid Build Coastguard Worker   bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; }
GetBlockSizeShiftNArchive::NCramfs::CHeader167*f6dc9357SAndroid Build Coastguard Worker   unsigned GetBlockSizeShift() const { return (unsigned)(Flags >> k_Flags_BlockSize_Shift) & k_Flags_BlockSize_Mask; }
GetMethodNArchive::NCramfs::CHeader168*f6dc9357SAndroid Build Coastguard Worker   unsigned GetMethod() const { return (unsigned)(Flags >> k_Flags_Method_Shift) & k_Flags_Method_Mask; }
169*f6dc9357SAndroid Build Coastguard Worker };
170*f6dc9357SAndroid Build Coastguard Worker 
171*f6dc9357SAndroid Build Coastguard Worker 
172*f6dc9357SAndroid Build Coastguard Worker 
173*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_1(
174*f6dc9357SAndroid Build Coastguard Worker   IInArchiveGetStream
175*f6dc9357SAndroid Build Coastguard Worker )
176*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CItem> _items;
177*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> _stream;
178*f6dc9357SAndroid Build Coastguard Worker   Byte *_data;
179*f6dc9357SAndroid Build Coastguard Worker   UInt32 _size;
180*f6dc9357SAndroid Build Coastguard Worker   UInt32 _headersSize;
181*f6dc9357SAndroid Build Coastguard Worker 
182*f6dc9357SAndroid Build Coastguard Worker   UInt32 _errorFlags;
183*f6dc9357SAndroid Build Coastguard Worker   bool _isArc;
184*f6dc9357SAndroid Build Coastguard Worker 
185*f6dc9357SAndroid Build Coastguard Worker   CHeader _h;
186*f6dc9357SAndroid Build Coastguard Worker   UInt32 _phySize;
187*f6dc9357SAndroid Build Coastguard Worker 
188*f6dc9357SAndroid Build Coastguard Worker   unsigned _method;
189*f6dc9357SAndroid Build Coastguard Worker   unsigned _blockSizeLog;
190*f6dc9357SAndroid Build Coastguard Worker 
191*f6dc9357SAndroid Build Coastguard Worker   // Current file
192*f6dc9357SAndroid Build Coastguard Worker 
193*f6dc9357SAndroid Build Coastguard Worker   NCompress::NZlib::CDecoder *_zlibDecoderSpec;
194*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressCoder> _zlibDecoder;
195*f6dc9357SAndroid Build Coastguard Worker 
196*f6dc9357SAndroid Build Coastguard Worker   CBufInStream *_inStreamSpec;
197*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> _inStream;
198*f6dc9357SAndroid Build Coastguard Worker 
199*f6dc9357SAndroid Build Coastguard Worker   CBufPtrSeqOutStream *_outStreamSpec;
200*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> _outStream;
201*f6dc9357SAndroid Build Coastguard Worker 
202*f6dc9357SAndroid Build Coastguard Worker   UInt32 _curBlocksOffset;
203*f6dc9357SAndroid Build Coastguard Worker   UInt32 _curNumBlocks;
204*f6dc9357SAndroid Build Coastguard Worker 
205*f6dc9357SAndroid Build Coastguard Worker   HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level);
206*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open2(IInStream *inStream);
207*f6dc9357SAndroid Build Coastguard Worker   AString GetPath(unsigned index) const;
208*f6dc9357SAndroid Build Coastguard Worker   bool GetPackSize(unsigned index, UInt32 &res) const;
209*f6dc9357SAndroid Build Coastguard Worker   void Free();
210*f6dc9357SAndroid Build Coastguard Worker 
GetNumBlocks(UInt32 size) const211*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetNumBlocks(UInt32 size) const
212*f6dc9357SAndroid Build Coastguard Worker   {
213*f6dc9357SAndroid Build Coastguard Worker     return (size + ((UInt32)1 << _blockSizeLog) - 1) >> _blockSizeLog;
214*f6dc9357SAndroid Build Coastguard Worker   }
215*f6dc9357SAndroid Build Coastguard Worker 
UpdatePhySize(UInt32 s)216*f6dc9357SAndroid Build Coastguard Worker   void UpdatePhySize(UInt32 s)
217*f6dc9357SAndroid Build Coastguard Worker   {
218*f6dc9357SAndroid Build Coastguard Worker     if (_phySize < s)
219*f6dc9357SAndroid Build Coastguard Worker       _phySize = s;
220*f6dc9357SAndroid Build Coastguard Worker   }
221*f6dc9357SAndroid Build Coastguard Worker 
222*f6dc9357SAndroid Build Coastguard Worker public:
223*f6dc9357SAndroid Build Coastguard Worker   CHandler(): _data(NULL) {}
224*f6dc9357SAndroid Build Coastguard Worker   ~CHandler() { Free(); }
225*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
226*f6dc9357SAndroid Build Coastguard Worker };
227*f6dc9357SAndroid Build Coastguard Worker 
228*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
229*f6dc9357SAndroid Build Coastguard Worker {
230*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
231*f6dc9357SAndroid Build Coastguard Worker   kpidIsDir,
232*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
233*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
234*f6dc9357SAndroid Build Coastguard Worker   kpidPosixAttrib
235*f6dc9357SAndroid Build Coastguard Worker   // kpidOffset
236*f6dc9357SAndroid Build Coastguard Worker };
237*f6dc9357SAndroid Build Coastguard Worker 
238*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
239*f6dc9357SAndroid Build Coastguard Worker {
240*f6dc9357SAndroid Build Coastguard Worker   kpidVolumeName,
241*f6dc9357SAndroid Build Coastguard Worker   kpidBigEndian,
242*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts,
243*f6dc9357SAndroid Build Coastguard Worker   kpidClusterSize,
244*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
245*f6dc9357SAndroid Build Coastguard Worker   kpidHeadersSize,
246*f6dc9357SAndroid Build Coastguard Worker   kpidNumSubFiles,
247*f6dc9357SAndroid Build Coastguard Worker   kpidNumBlocks
248*f6dc9357SAndroid Build Coastguard Worker };
249*f6dc9357SAndroid Build Coastguard Worker 
250*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
251*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
252*f6dc9357SAndroid Build Coastguard Worker 
253*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level)
254*f6dc9357SAndroid Build Coastguard Worker {
255*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = _data + baseOffset;
256*f6dc9357SAndroid Build Coastguard Worker   bool be = _h.be;
257*f6dc9357SAndroid Build Coastguard Worker   if (!IsDir(p, be))
258*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
259*f6dc9357SAndroid Build Coastguard Worker   UInt32 offset = GetOffset(p, be);
260*f6dc9357SAndroid Build Coastguard Worker   UInt32 size = GetSize(p, be);
261*f6dc9357SAndroid Build Coastguard Worker   if (offset == 0 && size == 0)
262*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
263*f6dc9357SAndroid Build Coastguard Worker   UInt32 end = offset + size;
264*f6dc9357SAndroid Build Coastguard Worker   if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax)
265*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
266*f6dc9357SAndroid Build Coastguard Worker   UpdatePhySize(end);
267*f6dc9357SAndroid Build Coastguard Worker   if (end > _headersSize)
268*f6dc9357SAndroid Build Coastguard Worker     _headersSize = end;
269*f6dc9357SAndroid Build Coastguard Worker 
270*f6dc9357SAndroid Build Coastguard Worker   unsigned startIndex = _items.Size();
271*f6dc9357SAndroid Build Coastguard Worker 
272*f6dc9357SAndroid Build Coastguard Worker   while (size != 0)
273*f6dc9357SAndroid Build Coastguard Worker   {
274*f6dc9357SAndroid Build Coastguard Worker     if (size < kNodeSize || (UInt32)_items.Size() >= kNumFilesMax)
275*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
276*f6dc9357SAndroid Build Coastguard Worker     CItem item;
277*f6dc9357SAndroid Build Coastguard Worker     item.Parent = parent;
278*f6dc9357SAndroid Build Coastguard Worker     item.Offset = offset;
279*f6dc9357SAndroid Build Coastguard Worker     _items.Add(item);
280*f6dc9357SAndroid Build Coastguard Worker     UInt32 nodeLen = kNodeSize + GetNameLen(_data + offset, be);
281*f6dc9357SAndroid Build Coastguard Worker     if (size < nodeLen)
282*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
283*f6dc9357SAndroid Build Coastguard Worker     offset += nodeLen;
284*f6dc9357SAndroid Build Coastguard Worker     size -= nodeLen;
285*f6dc9357SAndroid Build Coastguard Worker   }
286*f6dc9357SAndroid Build Coastguard Worker 
287*f6dc9357SAndroid Build Coastguard Worker   unsigned endIndex = _items.Size();
288*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = startIndex; i < endIndex; i++)
289*f6dc9357SAndroid Build Coastguard Worker   {
290*f6dc9357SAndroid Build Coastguard Worker     RINOK(OpenDir((int)i, _items[i].Offset, level + 1))
291*f6dc9357SAndroid Build Coastguard Worker   }
292*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
293*f6dc9357SAndroid Build Coastguard Worker }
294*f6dc9357SAndroid Build Coastguard Worker 
295*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *inStream)
296*f6dc9357SAndroid Build Coastguard Worker {
297*f6dc9357SAndroid Build Coastguard Worker   Byte buf[kHeaderSize];
298*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize))
299*f6dc9357SAndroid Build Coastguard Worker   if (!_h.Parse(buf))
300*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
301*f6dc9357SAndroid Build Coastguard Worker   _method = k_Flags_Method_ZLIB;
302*f6dc9357SAndroid Build Coastguard Worker   _blockSizeLog = kBlockSizeLog;
303*f6dc9357SAndroid Build Coastguard Worker   _phySize = kHeaderSize;
304*f6dc9357SAndroid Build Coastguard Worker   if (_h.IsVer2())
305*f6dc9357SAndroid Build Coastguard Worker   {
306*f6dc9357SAndroid Build Coastguard Worker     _method = _h.GetMethod();
307*f6dc9357SAndroid Build Coastguard Worker     // FIT IT. Now we don't know correct way to work with collision in method field.
308*f6dc9357SAndroid Build Coastguard Worker     if (_method == k_Flags_Method_NONE)
309*f6dc9357SAndroid Build Coastguard Worker       _method = k_Flags_Method_ZLIB;
310*f6dc9357SAndroid Build Coastguard Worker     _blockSizeLog = kBlockSizeLog + _h.GetBlockSizeShift();
311*f6dc9357SAndroid Build Coastguard Worker     if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax)
312*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
313*f6dc9357SAndroid Build Coastguard Worker     _phySize = _h.Size;
314*f6dc9357SAndroid Build Coastguard Worker   }
315*f6dc9357SAndroid Build Coastguard Worker   else
316*f6dc9357SAndroid Build Coastguard Worker   {
317*f6dc9357SAndroid Build Coastguard Worker     UInt64 size;
318*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_GetSize_SeekToEnd(inStream, size))
319*f6dc9357SAndroid Build Coastguard Worker     if (size > kArcSizeMax)
320*f6dc9357SAndroid Build Coastguard Worker       size = kArcSizeMax;
321*f6dc9357SAndroid Build Coastguard Worker     _h.Size = (UInt32)size;
322*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekSet(inStream, kHeaderSize))
323*f6dc9357SAndroid Build Coastguard Worker   }
324*f6dc9357SAndroid Build Coastguard Worker   _data = (Byte *)MidAlloc(_h.Size);
325*f6dc9357SAndroid Build Coastguard Worker   if (!_data)
326*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
327*f6dc9357SAndroid Build Coastguard Worker   memcpy(_data, buf, kHeaderSize);
328*f6dc9357SAndroid Build Coastguard Worker   size_t processed = _h.Size - kHeaderSize;
329*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream(inStream, _data + kHeaderSize, &processed))
330*f6dc9357SAndroid Build Coastguard Worker   if (processed < kNodeSize)
331*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
332*f6dc9357SAndroid Build Coastguard Worker   _size = kHeaderSize + (UInt32)processed;
333*f6dc9357SAndroid Build Coastguard Worker   if (_h.IsVer2())
334*f6dc9357SAndroid Build Coastguard Worker   {
335*f6dc9357SAndroid Build Coastguard Worker     if (_size != _h.Size)
336*f6dc9357SAndroid Build Coastguard Worker       _errorFlags = kpv_ErrorFlags_UnexpectedEnd;
337*f6dc9357SAndroid Build Coastguard Worker     else
338*f6dc9357SAndroid Build Coastguard Worker     {
339*f6dc9357SAndroid Build Coastguard Worker       SetUi32(_data + 0x20, 0)
340*f6dc9357SAndroid Build Coastguard Worker       if (CrcCalc(_data, _h.Size) != _h.Crc)
341*f6dc9357SAndroid Build Coastguard Worker       {
342*f6dc9357SAndroid Build Coastguard Worker         _errorFlags = kpv_ErrorFlags_HeadersError;
343*f6dc9357SAndroid Build Coastguard Worker         // _errorMessage = "CRC error";
344*f6dc9357SAndroid Build Coastguard Worker       }
345*f6dc9357SAndroid Build Coastguard Worker     }
346*f6dc9357SAndroid Build Coastguard Worker     if (_h.NumFiles >= 1)
347*f6dc9357SAndroid Build Coastguard Worker       _items.ClearAndReserve(_h.NumFiles - 1);
348*f6dc9357SAndroid Build Coastguard Worker   }
349*f6dc9357SAndroid Build Coastguard Worker 
350*f6dc9357SAndroid Build Coastguard Worker   RINOK(OpenDir(-1, kHeaderSize, 0))
351*f6dc9357SAndroid Build Coastguard Worker 
352*f6dc9357SAndroid Build Coastguard Worker   if (!_h.IsVer2())
353*f6dc9357SAndroid Build Coastguard Worker   {
354*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, _items)
355*f6dc9357SAndroid Build Coastguard Worker     {
356*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = _items[i];
357*f6dc9357SAndroid Build Coastguard Worker       const Byte *p = _data + item.Offset;
358*f6dc9357SAndroid Build Coastguard Worker       bool be = _h.be;
359*f6dc9357SAndroid Build Coastguard Worker       if (IsDir(p, be))
360*f6dc9357SAndroid Build Coastguard Worker         continue;
361*f6dc9357SAndroid Build Coastguard Worker       UInt32 offset = GetOffset(p, be);
362*f6dc9357SAndroid Build Coastguard Worker       if (offset < kHeaderSize)
363*f6dc9357SAndroid Build Coastguard Worker         continue;
364*f6dc9357SAndroid Build Coastguard Worker       UInt32 numBlocks = GetNumBlocks(GetSize(p, be));
365*f6dc9357SAndroid Build Coastguard Worker       if (numBlocks == 0)
366*f6dc9357SAndroid Build Coastguard Worker         continue;
367*f6dc9357SAndroid Build Coastguard Worker       UInt32 start = offset + numBlocks * 4;
368*f6dc9357SAndroid Build Coastguard Worker       if (start > _size)
369*f6dc9357SAndroid Build Coastguard Worker         continue;
370*f6dc9357SAndroid Build Coastguard Worker       UInt32 end = Get32(_data + start - 4);
371*f6dc9357SAndroid Build Coastguard Worker       if (end >= start)
372*f6dc9357SAndroid Build Coastguard Worker         UpdatePhySize(end);
373*f6dc9357SAndroid Build Coastguard Worker     }
374*f6dc9357SAndroid Build Coastguard Worker 
375*f6dc9357SAndroid Build Coastguard Worker     // Read tailing zeros. Most cramfs archives use 4096-bytes aligned zeros
376*f6dc9357SAndroid Build Coastguard Worker     const UInt32 kTailSize_MAX = 1 << 12;
377*f6dc9357SAndroid Build Coastguard Worker     UInt32 endPos = (_phySize + kTailSize_MAX - 1) & ~(kTailSize_MAX - 1);
378*f6dc9357SAndroid Build Coastguard Worker     if (endPos > _size)
379*f6dc9357SAndroid Build Coastguard Worker       endPos = _size;
380*f6dc9357SAndroid Build Coastguard Worker     UInt32 pos;
381*f6dc9357SAndroid Build Coastguard Worker     for (pos = _phySize; pos < endPos && _data[pos] == 0; pos++);
382*f6dc9357SAndroid Build Coastguard Worker     if (pos == endPos)
383*f6dc9357SAndroid Build Coastguard Worker       _phySize = endPos;
384*f6dc9357SAndroid Build Coastguard Worker   }
385*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
386*f6dc9357SAndroid Build Coastguard Worker }
387*f6dc9357SAndroid Build Coastguard Worker 
388*f6dc9357SAndroid Build Coastguard Worker AString CHandler::GetPath(unsigned index) const
389*f6dc9357SAndroid Build Coastguard Worker {
390*f6dc9357SAndroid Build Coastguard Worker   unsigned len = 0;
391*f6dc9357SAndroid Build Coastguard Worker   unsigned indexMem = index;
392*f6dc9357SAndroid Build Coastguard Worker   for (;;)
393*f6dc9357SAndroid Build Coastguard Worker   {
394*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[index];
395*f6dc9357SAndroid Build Coastguard Worker     const Byte *p = _data + item.Offset;
396*f6dc9357SAndroid Build Coastguard Worker     unsigned size = GetNameLen(p, _h.be);
397*f6dc9357SAndroid Build Coastguard Worker     p += kNodeSize;
398*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
399*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < size && p[i]; i++);
400*f6dc9357SAndroid Build Coastguard Worker     len += i + 1;
401*f6dc9357SAndroid Build Coastguard Worker     index = (unsigned)item.Parent;
402*f6dc9357SAndroid Build Coastguard Worker     if (item.Parent < 0)
403*f6dc9357SAndroid Build Coastguard Worker       break;
404*f6dc9357SAndroid Build Coastguard Worker   }
405*f6dc9357SAndroid Build Coastguard Worker   len--;
406*f6dc9357SAndroid Build Coastguard Worker 
407*f6dc9357SAndroid Build Coastguard Worker   AString path;
408*f6dc9357SAndroid Build Coastguard Worker   char *dest = path.GetBuf_SetEnd(len) + len;
409*f6dc9357SAndroid Build Coastguard Worker   index = indexMem;
410*f6dc9357SAndroid Build Coastguard Worker   for (;;)
411*f6dc9357SAndroid Build Coastguard Worker   {
412*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[index];
413*f6dc9357SAndroid Build Coastguard Worker     const Byte *p = _data + item.Offset;
414*f6dc9357SAndroid Build Coastguard Worker     unsigned size = GetNameLen(p, _h.be);
415*f6dc9357SAndroid Build Coastguard Worker     p += kNodeSize;
416*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
417*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < size && p[i]; i++);
418*f6dc9357SAndroid Build Coastguard Worker     dest -= i;
419*f6dc9357SAndroid Build Coastguard Worker     memcpy(dest, p, i);
420*f6dc9357SAndroid Build Coastguard Worker     index = (unsigned)item.Parent;
421*f6dc9357SAndroid Build Coastguard Worker     if (item.Parent < 0)
422*f6dc9357SAndroid Build Coastguard Worker       break;
423*f6dc9357SAndroid Build Coastguard Worker     *(--dest) = CHAR_PATH_SEPARATOR;
424*f6dc9357SAndroid Build Coastguard Worker   }
425*f6dc9357SAndroid Build Coastguard Worker   return path;
426*f6dc9357SAndroid Build Coastguard Worker }
427*f6dc9357SAndroid Build Coastguard Worker 
428*f6dc9357SAndroid Build Coastguard Worker bool CHandler::GetPackSize(unsigned index, UInt32 &res) const
429*f6dc9357SAndroid Build Coastguard Worker {
430*f6dc9357SAndroid Build Coastguard Worker   res = 0;
431*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[index];
432*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = _data + item.Offset;
433*f6dc9357SAndroid Build Coastguard Worker   const bool be = _h.be;
434*f6dc9357SAndroid Build Coastguard Worker   const UInt32 offset = GetOffset(p, be);
435*f6dc9357SAndroid Build Coastguard Worker   if (offset < kHeaderSize)
436*f6dc9357SAndroid Build Coastguard Worker     return false;
437*f6dc9357SAndroid Build Coastguard Worker   const UInt32 numBlocks = GetNumBlocks(GetSize(p, be));
438*f6dc9357SAndroid Build Coastguard Worker   if (numBlocks == 0)
439*f6dc9357SAndroid Build Coastguard Worker     return true;
440*f6dc9357SAndroid Build Coastguard Worker   const UInt32 start = offset + numBlocks * 4;
441*f6dc9357SAndroid Build Coastguard Worker   if (start > _size)
442*f6dc9357SAndroid Build Coastguard Worker     return false;
443*f6dc9357SAndroid Build Coastguard Worker   const UInt32 end = Get32(_data + start - 4);
444*f6dc9357SAndroid Build Coastguard Worker   if (end < start)
445*f6dc9357SAndroid Build Coastguard Worker     return false;
446*f6dc9357SAndroid Build Coastguard Worker   res = end - start;
447*f6dc9357SAndroid Build Coastguard Worker   return true;
448*f6dc9357SAndroid Build Coastguard Worker }
449*f6dc9357SAndroid Build Coastguard Worker 
450*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */))
451*f6dc9357SAndroid Build Coastguard Worker {
452*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
453*f6dc9357SAndroid Build Coastguard Worker   {
454*f6dc9357SAndroid Build Coastguard Worker     Close();
455*f6dc9357SAndroid Build Coastguard Worker     RINOK(Open2(stream))
456*f6dc9357SAndroid Build Coastguard Worker     _isArc = true;
457*f6dc9357SAndroid Build Coastguard Worker     _stream = stream;
458*f6dc9357SAndroid Build Coastguard Worker   }
459*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
460*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
461*f6dc9357SAndroid Build Coastguard Worker }
462*f6dc9357SAndroid Build Coastguard Worker 
463*f6dc9357SAndroid Build Coastguard Worker void CHandler::Free()
464*f6dc9357SAndroid Build Coastguard Worker {
465*f6dc9357SAndroid Build Coastguard Worker   MidFree(_data);
466*f6dc9357SAndroid Build Coastguard Worker   _data = NULL;
467*f6dc9357SAndroid Build Coastguard Worker }
468*f6dc9357SAndroid Build Coastguard Worker 
469*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
470*f6dc9357SAndroid Build Coastguard Worker {
471*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
472*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
473*f6dc9357SAndroid Build Coastguard Worker   _errorFlags = 0;
474*f6dc9357SAndroid Build Coastguard Worker   _headersSize = 0;
475*f6dc9357SAndroid Build Coastguard Worker   _items.Clear();
476*f6dc9357SAndroid Build Coastguard Worker   _stream.Release();
477*f6dc9357SAndroid Build Coastguard Worker   Free();
478*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
479*f6dc9357SAndroid Build Coastguard Worker }
480*f6dc9357SAndroid Build Coastguard Worker 
481*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
482*f6dc9357SAndroid Build Coastguard Worker {
483*f6dc9357SAndroid Build Coastguard Worker   *numItems = _items.Size();
484*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
485*f6dc9357SAndroid Build Coastguard Worker }
486*f6dc9357SAndroid Build Coastguard Worker 
487*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
488*f6dc9357SAndroid Build Coastguard Worker {
489*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
490*f6dc9357SAndroid Build Coastguard Worker   NWindows::NCOM::CPropVariant prop;
491*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
492*f6dc9357SAndroid Build Coastguard Worker   {
493*f6dc9357SAndroid Build Coastguard Worker     case kpidVolumeName:
494*f6dc9357SAndroid Build Coastguard Worker     {
495*f6dc9357SAndroid Build Coastguard Worker       char dest[kHeaderNameSize + 4];
496*f6dc9357SAndroid Build Coastguard Worker       memcpy(dest, _h.Name, kHeaderNameSize);
497*f6dc9357SAndroid Build Coastguard Worker       dest[kHeaderNameSize] = 0;
498*f6dc9357SAndroid Build Coastguard Worker       prop = dest;
499*f6dc9357SAndroid Build Coastguard Worker       break;
500*f6dc9357SAndroid Build Coastguard Worker     }
501*f6dc9357SAndroid Build Coastguard Worker     case kpidBigEndian: prop = _h.be; break;
502*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
503*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod: prop = k_Methods[_method]; break;
504*f6dc9357SAndroid Build Coastguard Worker     case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break;
505*f6dc9357SAndroid Build Coastguard Worker     case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break;
506*f6dc9357SAndroid Build Coastguard Worker     case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break;
507*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = _phySize; break;
508*f6dc9357SAndroid Build Coastguard Worker     case kpidHeadersSize: prop = _headersSize; break;
509*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
510*f6dc9357SAndroid Build Coastguard Worker     {
511*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = _errorFlags;
512*f6dc9357SAndroid Build Coastguard Worker       if (!_isArc)
513*f6dc9357SAndroid Build Coastguard Worker         v |= kpv_ErrorFlags_IsNotArc;
514*f6dc9357SAndroid Build Coastguard Worker       prop = v;
515*f6dc9357SAndroid Build Coastguard Worker       break;
516*f6dc9357SAndroid Build Coastguard Worker     }
517*f6dc9357SAndroid Build Coastguard Worker   }
518*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
519*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
520*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
521*f6dc9357SAndroid Build Coastguard Worker }
522*f6dc9357SAndroid Build Coastguard Worker 
523*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
524*f6dc9357SAndroid Build Coastguard Worker {
525*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
526*f6dc9357SAndroid Build Coastguard Worker   NWindows::NCOM::CPropVariant prop;
527*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[index];
528*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = _data + item.Offset;
529*f6dc9357SAndroid Build Coastguard Worker   bool be = _h.be;
530*f6dc9357SAndroid Build Coastguard Worker   bool isDir = IsDir(p, be);
531*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
532*f6dc9357SAndroid Build Coastguard Worker   {
533*f6dc9357SAndroid Build Coastguard Worker     case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break;
534*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDir: prop = isDir; break;
535*f6dc9357SAndroid Build Coastguard Worker     // case kpidOffset: prop = (UInt32)GetOffset(p, be); break;
536*f6dc9357SAndroid Build Coastguard Worker     case kpidSize: if (!isDir) prop = GetSize(p, be); break;
537*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize:
538*f6dc9357SAndroid Build Coastguard Worker       if (!isDir)
539*f6dc9357SAndroid Build Coastguard Worker       {
540*f6dc9357SAndroid Build Coastguard Worker         UInt32 size;
541*f6dc9357SAndroid Build Coastguard Worker         if (GetPackSize(index, size))
542*f6dc9357SAndroid Build Coastguard Worker           prop = size;
543*f6dc9357SAndroid Build Coastguard Worker       }
544*f6dc9357SAndroid Build Coastguard Worker       break;
545*f6dc9357SAndroid Build Coastguard Worker     case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break;
546*f6dc9357SAndroid Build Coastguard Worker   }
547*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
548*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
549*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
550*f6dc9357SAndroid Build Coastguard Worker }
551*f6dc9357SAndroid Build Coastguard Worker 
552*f6dc9357SAndroid Build Coastguard Worker class CCramfsInStream: public CCachedInStream
553*f6dc9357SAndroid Build Coastguard Worker {
554*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) Z7_override;
555*f6dc9357SAndroid Build Coastguard Worker public:
556*f6dc9357SAndroid Build Coastguard Worker   CHandler *Handler;
557*f6dc9357SAndroid Build Coastguard Worker };
558*f6dc9357SAndroid Build Coastguard Worker 
559*f6dc9357SAndroid Build Coastguard Worker HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
560*f6dc9357SAndroid Build Coastguard Worker {
561*f6dc9357SAndroid Build Coastguard Worker   return Handler->ReadBlock(blockIndex, dest, blockSize);
562*f6dc9357SAndroid Build Coastguard Worker }
563*f6dc9357SAndroid Build Coastguard Worker 
564*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
565*f6dc9357SAndroid Build Coastguard Worker {
566*f6dc9357SAndroid Build Coastguard Worker   if (_method == k_Flags_Method_ZLIB)
567*f6dc9357SAndroid Build Coastguard Worker   {
568*f6dc9357SAndroid Build Coastguard Worker     if (!_zlibDecoder)
569*f6dc9357SAndroid Build Coastguard Worker     {
570*f6dc9357SAndroid Build Coastguard Worker       _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
571*f6dc9357SAndroid Build Coastguard Worker       _zlibDecoder = _zlibDecoderSpec;
572*f6dc9357SAndroid Build Coastguard Worker     }
573*f6dc9357SAndroid Build Coastguard Worker   }
574*f6dc9357SAndroid Build Coastguard Worker   else
575*f6dc9357SAndroid Build Coastguard Worker   {
576*f6dc9357SAndroid Build Coastguard Worker     if (_method != k_Flags_Method_LZMA)
577*f6dc9357SAndroid Build Coastguard Worker     {
578*f6dc9357SAndroid Build Coastguard Worker       // probably we must support no-compression archives here.
579*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
580*f6dc9357SAndroid Build Coastguard Worker     }
581*f6dc9357SAndroid Build Coastguard Worker   }
582*f6dc9357SAndroid Build Coastguard Worker 
583*f6dc9357SAndroid Build Coastguard Worker   const bool be = _h.be;
584*f6dc9357SAndroid Build Coastguard Worker   const Byte *p2 = _data + (_curBlocksOffset + (UInt32)blockIndex * 4);
585*f6dc9357SAndroid Build Coastguard Worker   const UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p2 - 4));
586*f6dc9357SAndroid Build Coastguard Worker   const UInt32 end = Get32(p2);
587*f6dc9357SAndroid Build Coastguard Worker   if (end < start || end > _size)
588*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
589*f6dc9357SAndroid Build Coastguard Worker   const UInt32 inSize = end - start;
590*f6dc9357SAndroid Build Coastguard Worker 
591*f6dc9357SAndroid Build Coastguard Worker   if (_method == k_Flags_Method_LZMA)
592*f6dc9357SAndroid Build Coastguard Worker   {
593*f6dc9357SAndroid Build Coastguard Worker     const unsigned kLzmaHeaderSize = LZMA_PROPS_SIZE + 4;
594*f6dc9357SAndroid Build Coastguard Worker     if (inSize < kLzmaHeaderSize)
595*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
596*f6dc9357SAndroid Build Coastguard Worker     const Byte *p = _data + start;
597*f6dc9357SAndroid Build Coastguard Worker     UInt32 destSize32 = GetUi32(p + LZMA_PROPS_SIZE);
598*f6dc9357SAndroid Build Coastguard Worker     if (destSize32 > blockSize)
599*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
600*f6dc9357SAndroid Build Coastguard Worker     SizeT destLen = destSize32;
601*f6dc9357SAndroid Build Coastguard Worker     SizeT srcLen = inSize - kLzmaHeaderSize;
602*f6dc9357SAndroid Build Coastguard Worker     ELzmaStatus status;
603*f6dc9357SAndroid Build Coastguard Worker     SRes res = LzmaDecode(dest, &destLen, p + kLzmaHeaderSize, &srcLen,
604*f6dc9357SAndroid Build Coastguard Worker         p, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc);
605*f6dc9357SAndroid Build Coastguard Worker     if (res != SZ_OK
606*f6dc9357SAndroid Build Coastguard Worker         || (status != LZMA_STATUS_FINISHED_WITH_MARK &&
607*f6dc9357SAndroid Build Coastguard Worker             status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
608*f6dc9357SAndroid Build Coastguard Worker         || destLen != destSize32
609*f6dc9357SAndroid Build Coastguard Worker         || srcLen != inSize - kLzmaHeaderSize)
610*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
611*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
612*f6dc9357SAndroid Build Coastguard Worker   }
613*f6dc9357SAndroid Build Coastguard Worker 
614*f6dc9357SAndroid Build Coastguard Worker   if (!_inStream)
615*f6dc9357SAndroid Build Coastguard Worker   {
616*f6dc9357SAndroid Build Coastguard Worker     _inStreamSpec = new CBufInStream();
617*f6dc9357SAndroid Build Coastguard Worker     _inStream = _inStreamSpec;
618*f6dc9357SAndroid Build Coastguard Worker   }
619*f6dc9357SAndroid Build Coastguard Worker   if (!_outStream)
620*f6dc9357SAndroid Build Coastguard Worker   {
621*f6dc9357SAndroid Build Coastguard Worker     _outStreamSpec = new CBufPtrSeqOutStream();
622*f6dc9357SAndroid Build Coastguard Worker     _outStream = _outStreamSpec;
623*f6dc9357SAndroid Build Coastguard Worker   }
624*f6dc9357SAndroid Build Coastguard Worker   _inStreamSpec->Init(_data + start, inSize);
625*f6dc9357SAndroid Build Coastguard Worker   _outStreamSpec->Init(dest, blockSize);
626*f6dc9357SAndroid Build Coastguard Worker   RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL))
627*f6dc9357SAndroid Build Coastguard Worker   return (inSize == _zlibDecoderSpec->GetInputProcessedSize() &&
628*f6dc9357SAndroid Build Coastguard Worker       _outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE;
629*f6dc9357SAndroid Build Coastguard Worker }
630*f6dc9357SAndroid Build Coastguard Worker 
631*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
632*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
633*f6dc9357SAndroid Build Coastguard Worker {
634*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
635*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
636*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
637*f6dc9357SAndroid Build Coastguard Worker     numItems = _items.Size();
638*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
639*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
640*f6dc9357SAndroid Build Coastguard Worker   bool be = _h.be;
641*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
642*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
643*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
644*f6dc9357SAndroid Build Coastguard Worker   {
645*f6dc9357SAndroid Build Coastguard Worker     const Byte *p = _data + _items[allFilesMode ? i : indices[i]].Offset;
646*f6dc9357SAndroid Build Coastguard Worker     if (!IsDir(p, be))
647*f6dc9357SAndroid Build Coastguard Worker       totalSize += GetSize(p, be);
648*f6dc9357SAndroid Build Coastguard Worker   }
649*f6dc9357SAndroid Build Coastguard Worker   extractCallback->SetTotal(totalSize);
650*f6dc9357SAndroid Build Coastguard Worker 
651*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalPackSize;
652*f6dc9357SAndroid Build Coastguard Worker   totalSize = totalPackSize = 0;
653*f6dc9357SAndroid Build Coastguard Worker 
654*f6dc9357SAndroid Build Coastguard Worker   NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
655*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
656*f6dc9357SAndroid Build Coastguard Worker 
657*f6dc9357SAndroid Build Coastguard Worker   CLocalProgress *lps = new CLocalProgress;
658*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressProgressInfo> progress = lps;
659*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
660*f6dc9357SAndroid Build Coastguard Worker 
661*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
662*f6dc9357SAndroid Build Coastguard Worker   {
663*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = totalPackSize;
664*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = totalSize;
665*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
666*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialOutStream> outStream;
667*f6dc9357SAndroid Build Coastguard Worker     const Int32 askMode = testMode ?
668*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kTest :
669*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kExtract;
670*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
671*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[index];
672*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->GetStream(index, &outStream, askMode))
673*f6dc9357SAndroid Build Coastguard Worker     const Byte *p = _data + item.Offset;
674*f6dc9357SAndroid Build Coastguard Worker 
675*f6dc9357SAndroid Build Coastguard Worker     if (IsDir(p, be))
676*f6dc9357SAndroid Build Coastguard Worker     {
677*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
678*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
679*f6dc9357SAndroid Build Coastguard Worker       continue;
680*f6dc9357SAndroid Build Coastguard Worker     }
681*f6dc9357SAndroid Build Coastguard Worker     UInt32 curSize = GetSize(p, be);
682*f6dc9357SAndroid Build Coastguard Worker     totalSize += curSize;
683*f6dc9357SAndroid Build Coastguard Worker     UInt32 packSize;
684*f6dc9357SAndroid Build Coastguard Worker     if (GetPackSize(index, packSize))
685*f6dc9357SAndroid Build Coastguard Worker       totalPackSize += packSize;
686*f6dc9357SAndroid Build Coastguard Worker 
687*f6dc9357SAndroid Build Coastguard Worker     if (!testMode && !outStream)
688*f6dc9357SAndroid Build Coastguard Worker       continue;
689*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->PrepareOperation(askMode))
690*f6dc9357SAndroid Build Coastguard Worker 
691*f6dc9357SAndroid Build Coastguard Worker     UInt32 offset = GetOffset(p, be);
692*f6dc9357SAndroid Build Coastguard Worker     if (offset < kHeaderSize)
693*f6dc9357SAndroid Build Coastguard Worker       curSize = 0;
694*f6dc9357SAndroid Build Coastguard Worker 
695*f6dc9357SAndroid Build Coastguard Worker     int res = NExtract::NOperationResult::kDataError;
696*f6dc9357SAndroid Build Coastguard Worker     {
697*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialInStream> inSeqStream;
698*f6dc9357SAndroid Build Coastguard Worker       HRESULT hres = GetStream(index, &inSeqStream);
699*f6dc9357SAndroid Build Coastguard Worker       if (hres == E_OUTOFMEMORY)
700*f6dc9357SAndroid Build Coastguard Worker         return E_OUTOFMEMORY;
701*f6dc9357SAndroid Build Coastguard Worker       if (hres == S_FALSE || !inSeqStream)
702*f6dc9357SAndroid Build Coastguard Worker         res = NExtract::NOperationResult::kUnsupportedMethod;
703*f6dc9357SAndroid Build Coastguard Worker       else
704*f6dc9357SAndroid Build Coastguard Worker       {
705*f6dc9357SAndroid Build Coastguard Worker         RINOK(hres)
706*f6dc9357SAndroid Build Coastguard Worker         {
707*f6dc9357SAndroid Build Coastguard Worker           hres = copyCoder->Code(inSeqStream, outStream, NULL, NULL, progress);
708*f6dc9357SAndroid Build Coastguard Worker           if (hres == S_OK)
709*f6dc9357SAndroid Build Coastguard Worker           {
710*f6dc9357SAndroid Build Coastguard Worker             if (copyCoderSpec->TotalSize == curSize)
711*f6dc9357SAndroid Build Coastguard Worker               res = NExtract::NOperationResult::kOK;
712*f6dc9357SAndroid Build Coastguard Worker           }
713*f6dc9357SAndroid Build Coastguard Worker           else if (hres == E_NOTIMPL)
714*f6dc9357SAndroid Build Coastguard Worker             res = NExtract::NOperationResult::kUnsupportedMethod;
715*f6dc9357SAndroid Build Coastguard Worker           else if (hres != S_FALSE)
716*f6dc9357SAndroid Build Coastguard Worker             return hres;
717*f6dc9357SAndroid Build Coastguard Worker         }
718*f6dc9357SAndroid Build Coastguard Worker       }
719*f6dc9357SAndroid Build Coastguard Worker     }
720*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(res))
721*f6dc9357SAndroid Build Coastguard Worker   }
722*f6dc9357SAndroid Build Coastguard Worker 
723*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
724*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
725*f6dc9357SAndroid Build Coastguard Worker }
726*f6dc9357SAndroid Build Coastguard Worker 
727*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
728*f6dc9357SAndroid Build Coastguard Worker {
729*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
730*f6dc9357SAndroid Build Coastguard Worker 
731*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[index];
732*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = _data + item.Offset;
733*f6dc9357SAndroid Build Coastguard Worker 
734*f6dc9357SAndroid Build Coastguard Worker   bool be = _h.be;
735*f6dc9357SAndroid Build Coastguard Worker   if (IsDir(p, be))
736*f6dc9357SAndroid Build Coastguard Worker     return E_FAIL;
737*f6dc9357SAndroid Build Coastguard Worker 
738*f6dc9357SAndroid Build Coastguard Worker   UInt32 size = GetSize(p, be);
739*f6dc9357SAndroid Build Coastguard Worker   UInt32 numBlocks = GetNumBlocks(size);
740*f6dc9357SAndroid Build Coastguard Worker   UInt32 offset = GetOffset(p, be);
741*f6dc9357SAndroid Build Coastguard Worker   if (offset < kHeaderSize)
742*f6dc9357SAndroid Build Coastguard Worker   {
743*f6dc9357SAndroid Build Coastguard Worker     if (offset != 0)
744*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
745*f6dc9357SAndroid Build Coastguard Worker     CBufInStream *streamSpec = new CBufInStream;
746*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<IInStream> streamTemp = streamSpec;
747*f6dc9357SAndroid Build Coastguard Worker     streamSpec->Init(NULL, 0);
748*f6dc9357SAndroid Build Coastguard Worker     *stream = streamTemp.Detach();
749*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
750*f6dc9357SAndroid Build Coastguard Worker   }
751*f6dc9357SAndroid Build Coastguard Worker 
752*f6dc9357SAndroid Build Coastguard Worker   if (offset + numBlocks * 4 > _size)
753*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
754*f6dc9357SAndroid Build Coastguard Worker   UInt32 prev = offset;
755*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0; i < numBlocks; i++)
756*f6dc9357SAndroid Build Coastguard Worker   {
757*f6dc9357SAndroid Build Coastguard Worker     UInt32 next = Get32(_data + offset + i * 4);
758*f6dc9357SAndroid Build Coastguard Worker     if (next < prev || next > _size)
759*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
760*f6dc9357SAndroid Build Coastguard Worker     prev = next;
761*f6dc9357SAndroid Build Coastguard Worker   }
762*f6dc9357SAndroid Build Coastguard Worker 
763*f6dc9357SAndroid Build Coastguard Worker   CCramfsInStream *streamSpec = new CCramfsInStream;
764*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> streamTemp = streamSpec;
765*f6dc9357SAndroid Build Coastguard Worker   _curNumBlocks = numBlocks;
766*f6dc9357SAndroid Build Coastguard Worker   _curBlocksOffset = offset;
767*f6dc9357SAndroid Build Coastguard Worker   streamSpec->Handler = this;
768*f6dc9357SAndroid Build Coastguard Worker   if (!streamSpec->Alloc(_blockSizeLog, 21 - _blockSizeLog))
769*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
770*f6dc9357SAndroid Build Coastguard Worker   streamSpec->Init(size);
771*f6dc9357SAndroid Build Coastguard Worker   *stream = streamTemp.Detach();
772*f6dc9357SAndroid Build Coastguard Worker 
773*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
774*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
775*f6dc9357SAndroid Build Coastguard Worker }
776*f6dc9357SAndroid Build Coastguard Worker 
777*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
778*f6dc9357SAndroid Build Coastguard Worker   "CramFS", "cramfs", NULL, 0xD3,
779*f6dc9357SAndroid Build Coastguard Worker   kSignature,
780*f6dc9357SAndroid Build Coastguard Worker   16,
781*f6dc9357SAndroid Build Coastguard Worker   0,
782*f6dc9357SAndroid Build Coastguard Worker   NULL)
783*f6dc9357SAndroid Build Coastguard Worker 
784*f6dc9357SAndroid Build Coastguard Worker }}
785