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