xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/QcowHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // QcowHandler.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 <stdio.h>
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
8*f6dc9357SAndroid Build Coastguard Worker 
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyBuffer2.h"
12*f6dc9357SAndroid Build Coastguard Worker 
13*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariantUtils.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamObjects.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
19*f6dc9357SAndroid Build Coastguard Worker 
20*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/DeflateDecoder.h"
21*f6dc9357SAndroid Build Coastguard Worker 
22*f6dc9357SAndroid Build Coastguard Worker #include "HandlerCont.h"
23*f6dc9357SAndroid Build Coastguard Worker 
24*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetBe32a(p)
25*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetBe64a(p)
26*f6dc9357SAndroid Build Coastguard Worker 
27*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
28*f6dc9357SAndroid Build Coastguard Worker 
29*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
30*f6dc9357SAndroid Build Coastguard Worker namespace NQcow {
31*f6dc9357SAndroid Build Coastguard Worker 
32*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] =  { 'Q', 'F', 'I', 0xFB, 0, 0, 0 };
33*f6dc9357SAndroid Build Coastguard Worker 
34*f6dc9357SAndroid Build Coastguard Worker /*
35*f6dc9357SAndroid Build Coastguard Worker VA to PA maps:
36*f6dc9357SAndroid Build Coastguard Worker   high bits (L1) :              : index in L1 (_dir) : _dir[high_index] points to Table.
37*f6dc9357SAndroid Build Coastguard Worker   mid bits  (L2) : _numMidBits  : index in Table, Table[index] points to cluster start offset in arc file.
38*f6dc9357SAndroid Build Coastguard Worker   low bits       : _clusterBits : offset inside cluster.
39*f6dc9357SAndroid Build Coastguard Worker */
40*f6dc9357SAndroid Build Coastguard Worker 
41*f6dc9357SAndroid Build Coastguard Worker Z7_class_CHandler_final: public CHandlerImg
42*f6dc9357SAndroid Build Coastguard Worker {
43*f6dc9357SAndroid Build Coastguard Worker   Z7_IFACE_COM7_IMP(IInArchive_Img)
44*f6dc9357SAndroid Build Coastguard Worker   Z7_IFACE_COM7_IMP(IInArchiveGetStream)
45*f6dc9357SAndroid Build Coastguard Worker   Z7_IFACE_COM7_IMP(ISequentialInStream)
46*f6dc9357SAndroid Build Coastguard Worker 
47*f6dc9357SAndroid Build Coastguard Worker   unsigned _clusterBits;
48*f6dc9357SAndroid Build Coastguard Worker   unsigned _numMidBits;
49*f6dc9357SAndroid Build Coastguard Worker   UInt64 _compressedFlag;
50*f6dc9357SAndroid Build Coastguard Worker 
51*f6dc9357SAndroid Build Coastguard Worker   CObjArray2<UInt32> _dir;
52*f6dc9357SAndroid Build Coastguard Worker   CAlignedBuffer _table;
53*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer _cache;
54*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer _cacheCompressed;
55*f6dc9357SAndroid Build Coastguard Worker   UInt64 _cacheCluster;
56*f6dc9357SAndroid Build Coastguard Worker 
57*f6dc9357SAndroid Build Coastguard Worker   UInt64 _comprPos;
58*f6dc9357SAndroid Build Coastguard Worker   size_t _comprSize;
59*f6dc9357SAndroid Build Coastguard Worker 
60*f6dc9357SAndroid Build Coastguard Worker   bool _needCompression;
61*f6dc9357SAndroid Build Coastguard Worker   bool _isArc;
62*f6dc9357SAndroid Build Coastguard Worker   bool _unsupported;
63*f6dc9357SAndroid Build Coastguard Worker   Byte _compressionType;
64*f6dc9357SAndroid Build Coastguard Worker 
65*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
66*f6dc9357SAndroid Build Coastguard Worker 
67*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ISequentialInStream, CBufInStream> _bufInStream;
68*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ISequentialOutStream, CBufPtrSeqOutStream> _bufOutStream;
69*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ICompressCoder, NCompress::NDeflate::NDecoder::CCOMCoder> _deflateDecoder;
70*f6dc9357SAndroid Build Coastguard Worker 
71*f6dc9357SAndroid Build Coastguard Worker   UInt32 _version;
72*f6dc9357SAndroid Build Coastguard Worker   UInt32 _cryptMethod;
73*f6dc9357SAndroid Build Coastguard Worker   UInt64 _incompatFlags;
74*f6dc9357SAndroid Build Coastguard Worker 
75*f6dc9357SAndroid Build Coastguard Worker   HRESULT Seek2(UInt64 offset)
76*f6dc9357SAndroid Build Coastguard Worker   {
77*f6dc9357SAndroid Build Coastguard Worker     _posInArc = offset;
78*f6dc9357SAndroid Build Coastguard Worker     return InStream_SeekSet(Stream, offset);
79*f6dc9357SAndroid Build Coastguard Worker   }
80*f6dc9357SAndroid Build Coastguard Worker 
81*f6dc9357SAndroid Build Coastguard Worker   HRESULT InitAndSeek()
82*f6dc9357SAndroid Build Coastguard Worker   {
83*f6dc9357SAndroid Build Coastguard Worker     _virtPos = 0;
84*f6dc9357SAndroid Build Coastguard Worker     return Seek2(0);
85*f6dc9357SAndroid Build Coastguard Worker   }
86*f6dc9357SAndroid Build Coastguard Worker 
87*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override;
88*f6dc9357SAndroid Build Coastguard Worker };
89*f6dc9357SAndroid Build Coastguard Worker 
90*f6dc9357SAndroid Build Coastguard Worker 
91*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kEmptyDirItem = (UInt32)0 - 1;
92*f6dc9357SAndroid Build Coastguard Worker 
93*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
94*f6dc9357SAndroid Build Coastguard Worker {
95*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
96*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
97*f6dc9357SAndroid Build Coastguard Worker   // printf("\nRead _virtPos = %6d  size = %6d\n", (UInt32)_virtPos, size);
98*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos >= _size)
99*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
100*f6dc9357SAndroid Build Coastguard Worker   {
101*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = _size - _virtPos;
102*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
103*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
104*f6dc9357SAndroid Build Coastguard Worker     if (size == 0)
105*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
106*f6dc9357SAndroid Build Coastguard Worker   }
107*f6dc9357SAndroid Build Coastguard Worker 
108*f6dc9357SAndroid Build Coastguard Worker   for (;;)
109*f6dc9357SAndroid Build Coastguard Worker   {
110*f6dc9357SAndroid Build Coastguard Worker     const UInt64 cluster = _virtPos >> _clusterBits;
111*f6dc9357SAndroid Build Coastguard Worker     const size_t clusterSize = (size_t)1 << _clusterBits;
112*f6dc9357SAndroid Build Coastguard Worker     const size_t lowBits = (size_t)_virtPos & (clusterSize - 1);
113*f6dc9357SAndroid Build Coastguard Worker     {
114*f6dc9357SAndroid Build Coastguard Worker       const size_t rem = clusterSize - lowBits;
115*f6dc9357SAndroid Build Coastguard Worker       if (size > rem)
116*f6dc9357SAndroid Build Coastguard Worker         size = (UInt32)rem;
117*f6dc9357SAndroid Build Coastguard Worker     }
118*f6dc9357SAndroid Build Coastguard Worker     if (cluster == _cacheCluster)
119*f6dc9357SAndroid Build Coastguard Worker     {
120*f6dc9357SAndroid Build Coastguard Worker       memcpy(data, _cache + lowBits, size);
121*f6dc9357SAndroid Build Coastguard Worker       break;
122*f6dc9357SAndroid Build Coastguard Worker     }
123*f6dc9357SAndroid Build Coastguard Worker 
124*f6dc9357SAndroid Build Coastguard Worker     const UInt64 high = cluster >> _numMidBits;
125*f6dc9357SAndroid Build Coastguard Worker 
126*f6dc9357SAndroid Build Coastguard Worker     if (high < _dir.Size())
127*f6dc9357SAndroid Build Coastguard Worker     {
128*f6dc9357SAndroid Build Coastguard Worker       const UInt32 tabl = _dir[(size_t)high];
129*f6dc9357SAndroid Build Coastguard Worker       if (tabl != kEmptyDirItem)
130*f6dc9357SAndroid Build Coastguard Worker       {
131*f6dc9357SAndroid Build Coastguard Worker         const size_t midBits = (size_t)cluster & (((size_t)1 << _numMidBits) - 1);
132*f6dc9357SAndroid Build Coastguard Worker         const Byte *p = _table + ((((size_t)tabl << _numMidBits) + midBits) << 3);
133*f6dc9357SAndroid Build Coastguard Worker         UInt64 v = Get64(p);
134*f6dc9357SAndroid Build Coastguard Worker 
135*f6dc9357SAndroid Build Coastguard Worker         if (v)
136*f6dc9357SAndroid Build Coastguard Worker         {
137*f6dc9357SAndroid Build Coastguard Worker           if (v & _compressedFlag)
138*f6dc9357SAndroid Build Coastguard Worker           {
139*f6dc9357SAndroid Build Coastguard Worker             if (_version <= 1)
140*f6dc9357SAndroid Build Coastguard Worker               return E_FAIL;
141*f6dc9357SAndroid Build Coastguard Worker             /*
142*f6dc9357SAndroid Build Coastguard Worker             the example of table record for 12-bit clusters (4KB uncompressed):
143*f6dc9357SAndroid Build Coastguard Worker               2 bits : isCompressed status
144*f6dc9357SAndroid Build Coastguard Worker               (4 == _clusterBits - 8) bits : (num_sectors - 1)
145*f6dc9357SAndroid Build Coastguard Worker                   packSize = num_sectors * 512;
146*f6dc9357SAndroid Build Coastguard Worker                   it uses one additional bit over unpacked cluster_bits.
147*f6dc9357SAndroid Build Coastguard Worker               (49 == 61 - _clusterBits) bits : offset of 512-byte sector
148*f6dc9357SAndroid Build Coastguard Worker               9 bits : offset in 512-byte sector
149*f6dc9357SAndroid Build Coastguard Worker             */
150*f6dc9357SAndroid Build Coastguard Worker             const unsigned numOffsetBits = 62 - (_clusterBits - 8);
151*f6dc9357SAndroid Build Coastguard Worker             const UInt64 offset = v & (((UInt64)1 << 62) - 1);
152*f6dc9357SAndroid Build Coastguard Worker             const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
153*f6dc9357SAndroid Build Coastguard Worker             UInt64 sectorOffset = offset & (((UInt64)1 << numOffsetBits) - (1 << 9));
154*f6dc9357SAndroid Build Coastguard Worker             const UInt64 offset2inCache = sectorOffset - _comprPos;
155*f6dc9357SAndroid Build Coastguard Worker 
156*f6dc9357SAndroid Build Coastguard Worker             // _comprPos is aligned for 512-bytes
157*f6dc9357SAndroid Build Coastguard Worker             // we try to use previous _cacheCompressed that contains compressed data
158*f6dc9357SAndroid Build Coastguard Worker             // that was read for previous unpacking
159*f6dc9357SAndroid Build Coastguard Worker 
160*f6dc9357SAndroid Build Coastguard Worker             if (sectorOffset >= _comprPos && offset2inCache < _comprSize)
161*f6dc9357SAndroid Build Coastguard Worker             {
162*f6dc9357SAndroid Build Coastguard Worker               if (offset2inCache)
163*f6dc9357SAndroid Build Coastguard Worker               {
164*f6dc9357SAndroid Build Coastguard Worker                 _comprSize -= (size_t)offset2inCache;
165*f6dc9357SAndroid Build Coastguard Worker                 memmove(_cacheCompressed, _cacheCompressed + (size_t)offset2inCache, _comprSize);
166*f6dc9357SAndroid Build Coastguard Worker                 _comprPos = sectorOffset;
167*f6dc9357SAndroid Build Coastguard Worker               }
168*f6dc9357SAndroid Build Coastguard Worker               sectorOffset += _comprSize;
169*f6dc9357SAndroid Build Coastguard Worker             }
170*f6dc9357SAndroid Build Coastguard Worker             else
171*f6dc9357SAndroid Build Coastguard Worker             {
172*f6dc9357SAndroid Build Coastguard Worker               _comprPos = sectorOffset;
173*f6dc9357SAndroid Build Coastguard Worker               _comprSize = 0;
174*f6dc9357SAndroid Build Coastguard Worker             }
175*f6dc9357SAndroid Build Coastguard Worker 
176*f6dc9357SAndroid Build Coastguard Worker             if (dataSize > _comprSize)
177*f6dc9357SAndroid Build Coastguard Worker             {
178*f6dc9357SAndroid Build Coastguard Worker               if (sectorOffset != _posInArc)
179*f6dc9357SAndroid Build Coastguard Worker               {
180*f6dc9357SAndroid Build Coastguard Worker                 // printf("\nDeflate-Seek %12I64x %12I64x\n", sectorOffset, sectorOffset - _posInArc);
181*f6dc9357SAndroid Build Coastguard Worker                 RINOK(Seek2(sectorOffset))
182*f6dc9357SAndroid Build Coastguard Worker               }
183*f6dc9357SAndroid Build Coastguard Worker               if (_cacheCompressed.Size() < dataSize)
184*f6dc9357SAndroid Build Coastguard Worker                 return E_FAIL;
185*f6dc9357SAndroid Build Coastguard Worker               const size_t dataSize3 = dataSize - _comprSize;
186*f6dc9357SAndroid Build Coastguard Worker               size_t dataSize2 = dataSize3;
187*f6dc9357SAndroid Build Coastguard Worker               // printf("\n\n=======\nReadStream = %6d _comprPos = %6d \n", (UInt32)dataSize2, (UInt32)_comprPos);
188*f6dc9357SAndroid Build Coastguard Worker               const HRESULT hres = ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2);
189*f6dc9357SAndroid Build Coastguard Worker               _posInArc += dataSize2;
190*f6dc9357SAndroid Build Coastguard Worker               RINOK(hres)
191*f6dc9357SAndroid Build Coastguard Worker               if (dataSize2 != dataSize3)
192*f6dc9357SAndroid Build Coastguard Worker                 return E_FAIL;
193*f6dc9357SAndroid Build Coastguard Worker               _comprSize += dataSize2;
194*f6dc9357SAndroid Build Coastguard Worker             }
195*f6dc9357SAndroid Build Coastguard Worker 
196*f6dc9357SAndroid Build Coastguard Worker             const size_t kSectorMask = (1 << 9) - 1;
197*f6dc9357SAndroid Build Coastguard Worker             const size_t offsetInSector = (size_t)offset & kSectorMask;
198*f6dc9357SAndroid Build Coastguard Worker             _bufInStream->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector);
199*f6dc9357SAndroid Build Coastguard Worker             _cacheCluster = (UInt64)(Int64)-1;
200*f6dc9357SAndroid Build Coastguard Worker             if (_cache.Size() < clusterSize)
201*f6dc9357SAndroid Build Coastguard Worker               return E_FAIL;
202*f6dc9357SAndroid Build Coastguard Worker             _bufOutStream->Init(_cache, clusterSize);
203*f6dc9357SAndroid Build Coastguard Worker             // Do we need to use smaller block than clusterSize for last cluster?
204*f6dc9357SAndroid Build Coastguard Worker             const UInt64 blockSize64 = clusterSize;
205*f6dc9357SAndroid Build Coastguard Worker             HRESULT res = _deflateDecoder.Interface()->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL);
206*f6dc9357SAndroid Build Coastguard Worker             /*
207*f6dc9357SAndroid Build Coastguard Worker             if (_bufOutStreamSpec->GetPos() != clusterSize)
208*f6dc9357SAndroid Build Coastguard Worker               memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos());
209*f6dc9357SAndroid Build Coastguard Worker             */
210*f6dc9357SAndroid Build Coastguard Worker             if (res == S_OK)
211*f6dc9357SAndroid Build Coastguard Worker               if (!_deflateDecoder->IsFinished()
212*f6dc9357SAndroid Build Coastguard Worker                   || _bufOutStream->GetPos() != clusterSize)
213*f6dc9357SAndroid Build Coastguard Worker                 res = S_FALSE;
214*f6dc9357SAndroid Build Coastguard Worker             RINOK(res)
215*f6dc9357SAndroid Build Coastguard Worker             _cacheCluster = cluster;
216*f6dc9357SAndroid Build Coastguard Worker             continue;
217*f6dc9357SAndroid Build Coastguard Worker             /*
218*f6dc9357SAndroid Build Coastguard Worker             memcpy(data, _cache + lowBits, size);
219*f6dc9357SAndroid Build Coastguard Worker             break;
220*f6dc9357SAndroid Build Coastguard Worker             */
221*f6dc9357SAndroid Build Coastguard Worker           }
222*f6dc9357SAndroid Build Coastguard Worker 
223*f6dc9357SAndroid Build Coastguard Worker           // version_3 supports zero clusters
224*f6dc9357SAndroid Build Coastguard Worker           if (((UInt32)v & 511) != 1)
225*f6dc9357SAndroid Build Coastguard Worker           {
226*f6dc9357SAndroid Build Coastguard Worker             v &= _compressedFlag - 1;
227*f6dc9357SAndroid Build Coastguard Worker             v += lowBits;
228*f6dc9357SAndroid Build Coastguard Worker             if (v != _posInArc)
229*f6dc9357SAndroid Build Coastguard Worker             {
230*f6dc9357SAndroid Build Coastguard Worker               // printf("\n%12I64x\n", v - _posInArc);
231*f6dc9357SAndroid Build Coastguard Worker               RINOK(Seek2(v))
232*f6dc9357SAndroid Build Coastguard Worker             }
233*f6dc9357SAndroid Build Coastguard Worker             const HRESULT res = Stream->Read(data, size, &size);
234*f6dc9357SAndroid Build Coastguard Worker             _posInArc += size;
235*f6dc9357SAndroid Build Coastguard Worker             _virtPos += size;
236*f6dc9357SAndroid Build Coastguard Worker             if (processedSize)
237*f6dc9357SAndroid Build Coastguard Worker               *processedSize = size;
238*f6dc9357SAndroid Build Coastguard Worker             return res;
239*f6dc9357SAndroid Build Coastguard Worker           }
240*f6dc9357SAndroid Build Coastguard Worker         }
241*f6dc9357SAndroid Build Coastguard Worker       }
242*f6dc9357SAndroid Build Coastguard Worker     }
243*f6dc9357SAndroid Build Coastguard Worker 
244*f6dc9357SAndroid Build Coastguard Worker     memset(data, 0, size);
245*f6dc9357SAndroid Build Coastguard Worker     break;
246*f6dc9357SAndroid Build Coastguard Worker   }
247*f6dc9357SAndroid Build Coastguard Worker 
248*f6dc9357SAndroid Build Coastguard Worker   _virtPos += size;
249*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
250*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
251*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
252*f6dc9357SAndroid Build Coastguard Worker }
253*f6dc9357SAndroid Build Coastguard Worker 
254*f6dc9357SAndroid Build Coastguard Worker 
255*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
256*f6dc9357SAndroid Build Coastguard Worker {
257*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
258*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize
259*f6dc9357SAndroid Build Coastguard Worker };
260*f6dc9357SAndroid Build Coastguard Worker 
261*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
262*f6dc9357SAndroid Build Coastguard Worker {
263*f6dc9357SAndroid Build Coastguard Worker   kpidClusterSize,
264*f6dc9357SAndroid Build Coastguard Worker   kpidSectorSize, // actually we need variable to show table size
265*f6dc9357SAndroid Build Coastguard Worker   kpidHeadersSize,
266*f6dc9357SAndroid Build Coastguard Worker   kpidUnpackVer,
267*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
268*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts
269*f6dc9357SAndroid Build Coastguard Worker };
270*f6dc9357SAndroid Build Coastguard Worker 
271*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
272*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
273*f6dc9357SAndroid Build Coastguard Worker 
274*f6dc9357SAndroid Build Coastguard Worker static const CUInt32PCharPair g_IncompatFlags_Characts[] =
275*f6dc9357SAndroid Build Coastguard Worker {
276*f6dc9357SAndroid Build Coastguard Worker   {  0, "Dirty" },
277*f6dc9357SAndroid Build Coastguard Worker   {  1, "Corrupt" },
278*f6dc9357SAndroid Build Coastguard Worker   {  2, "External_Data_File" },
279*f6dc9357SAndroid Build Coastguard Worker   {  3, "Compression" },
280*f6dc9357SAndroid Build Coastguard Worker   {  4, "Extended_L2" }
281*f6dc9357SAndroid Build Coastguard Worker };
282*f6dc9357SAndroid Build Coastguard Worker 
283*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
284*f6dc9357SAndroid Build Coastguard Worker {
285*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
286*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
287*f6dc9357SAndroid Build Coastguard Worker 
288*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
289*f6dc9357SAndroid Build Coastguard Worker   {
290*f6dc9357SAndroid Build Coastguard Worker     case kpidMainSubfile: prop = (UInt32)0; break;
291*f6dc9357SAndroid Build Coastguard Worker     case kpidClusterSize: prop = (UInt32)1 << _clusterBits; break;
292*f6dc9357SAndroid Build Coastguard Worker     case kpidSectorSize: prop = (UInt32)1 << (_numMidBits + 3); break;
293*f6dc9357SAndroid Build Coastguard Worker     case kpidHeadersSize: prop = _table.Size() + (UInt64)_dir.Size() * 8; break;
294*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: if (_phySize) prop = _phySize; break;
295*f6dc9357SAndroid Build Coastguard Worker     case kpidUnpackVer: prop = _version; break;
296*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts:
297*f6dc9357SAndroid Build Coastguard Worker     {
298*f6dc9357SAndroid Build Coastguard Worker       if (_incompatFlags)
299*f6dc9357SAndroid Build Coastguard Worker       {
300*f6dc9357SAndroid Build Coastguard Worker         AString s ("incompatible: ");
301*f6dc9357SAndroid Build Coastguard Worker         // we need to show also high 32-bits.
302*f6dc9357SAndroid Build Coastguard Worker         s += FlagsToString(g_IncompatFlags_Characts,
303*f6dc9357SAndroid Build Coastguard Worker             Z7_ARRAY_SIZE(g_IncompatFlags_Characts), (UInt32)_incompatFlags);
304*f6dc9357SAndroid Build Coastguard Worker         prop = s;
305*f6dc9357SAndroid Build Coastguard Worker       }
306*f6dc9357SAndroid Build Coastguard Worker       break;
307*f6dc9357SAndroid Build Coastguard Worker     }
308*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
309*f6dc9357SAndroid Build Coastguard Worker     {
310*f6dc9357SAndroid Build Coastguard Worker       AString s;
311*f6dc9357SAndroid Build Coastguard Worker 
312*f6dc9357SAndroid Build Coastguard Worker       if (_compressionType)
313*f6dc9357SAndroid Build Coastguard Worker       {
314*f6dc9357SAndroid Build Coastguard Worker         if (_compressionType == 1)
315*f6dc9357SAndroid Build Coastguard Worker           s += "ZSTD";
316*f6dc9357SAndroid Build Coastguard Worker         else
317*f6dc9357SAndroid Build Coastguard Worker         {
318*f6dc9357SAndroid Build Coastguard Worker           s += "Compression:";
319*f6dc9357SAndroid Build Coastguard Worker           s.Add_UInt32(_compressionType);
320*f6dc9357SAndroid Build Coastguard Worker         }
321*f6dc9357SAndroid Build Coastguard Worker       }
322*f6dc9357SAndroid Build Coastguard Worker       else if (_needCompression)
323*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("Deflate");
324*f6dc9357SAndroid Build Coastguard Worker 
325*f6dc9357SAndroid Build Coastguard Worker       if (_cryptMethod)
326*f6dc9357SAndroid Build Coastguard Worker       {
327*f6dc9357SAndroid Build Coastguard Worker         s.Add_Space_if_NotEmpty();
328*f6dc9357SAndroid Build Coastguard Worker         if (_cryptMethod == 1)
329*f6dc9357SAndroid Build Coastguard Worker           s += "AES";
330*f6dc9357SAndroid Build Coastguard Worker         if (_cryptMethod == 2)
331*f6dc9357SAndroid Build Coastguard Worker           s += "LUKS";
332*f6dc9357SAndroid Build Coastguard Worker         else
333*f6dc9357SAndroid Build Coastguard Worker         {
334*f6dc9357SAndroid Build Coastguard Worker           s += "Encryption:";
335*f6dc9357SAndroid Build Coastguard Worker           s.Add_UInt32(_cryptMethod);
336*f6dc9357SAndroid Build Coastguard Worker         }
337*f6dc9357SAndroid Build Coastguard Worker       }
338*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
339*f6dc9357SAndroid Build Coastguard Worker         prop = s;
340*f6dc9357SAndroid Build Coastguard Worker       break;
341*f6dc9357SAndroid Build Coastguard Worker     }
342*f6dc9357SAndroid Build Coastguard Worker 
343*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
344*f6dc9357SAndroid Build Coastguard Worker     {
345*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
346*f6dc9357SAndroid Build Coastguard Worker       if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
347*f6dc9357SAndroid Build Coastguard Worker       if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
348*f6dc9357SAndroid Build Coastguard Worker       // if (_headerError) v |= kpv_ErrorFlags_HeadersError;
349*f6dc9357SAndroid Build Coastguard Worker       if (!Stream && v == 0)
350*f6dc9357SAndroid Build Coastguard Worker         v = kpv_ErrorFlags_HeadersError;
351*f6dc9357SAndroid Build Coastguard Worker       if (v)
352*f6dc9357SAndroid Build Coastguard Worker         prop = v;
353*f6dc9357SAndroid Build Coastguard Worker       break;
354*f6dc9357SAndroid Build Coastguard Worker     }
355*f6dc9357SAndroid Build Coastguard Worker   }
356*f6dc9357SAndroid Build Coastguard Worker 
357*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
358*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
359*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
360*f6dc9357SAndroid Build Coastguard Worker }
361*f6dc9357SAndroid Build Coastguard Worker 
362*f6dc9357SAndroid Build Coastguard Worker 
363*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
364*f6dc9357SAndroid Build Coastguard Worker {
365*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
366*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
367*f6dc9357SAndroid Build Coastguard Worker 
368*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
369*f6dc9357SAndroid Build Coastguard Worker   {
370*f6dc9357SAndroid Build Coastguard Worker     case kpidSize: prop = _size; break;
371*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize: prop = _phySize; break;
372*f6dc9357SAndroid Build Coastguard Worker     case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
373*f6dc9357SAndroid Build Coastguard Worker   }
374*f6dc9357SAndroid Build Coastguard Worker 
375*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
376*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
377*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
378*f6dc9357SAndroid Build Coastguard Worker }
379*f6dc9357SAndroid Build Coastguard Worker 
380*f6dc9357SAndroid Build Coastguard Worker 
381*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
382*f6dc9357SAndroid Build Coastguard Worker {
383*f6dc9357SAndroid Build Coastguard Worker   UInt64 buf64[0x70 / 8];
384*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, buf64, sizeof(buf64)))
385*f6dc9357SAndroid Build Coastguard Worker   const void *buf = (const void *)buf64;
386*f6dc9357SAndroid Build Coastguard Worker   // signature: { 'Q', 'F', 'I', 0xFB }
387*f6dc9357SAndroid Build Coastguard Worker   if (*(const UInt32 *)buf != Z7_CONV_BE_TO_NATIVE_CONST32(0x514649fb))
388*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
389*f6dc9357SAndroid Build Coastguard Worker   _version = Get32((const Byte *)(const void *)buf64 + 4);
390*f6dc9357SAndroid Build Coastguard Worker   if (_version < 1 || _version > 3)
391*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
392*f6dc9357SAndroid Build Coastguard Worker 
393*f6dc9357SAndroid Build Coastguard Worker   const UInt64 k_UncompressedSize_MAX = (UInt64)1 << 60;
394*f6dc9357SAndroid Build Coastguard Worker   const UInt64 k_CompressedSize_MAX   = (UInt64)1 << 60;
395*f6dc9357SAndroid Build Coastguard Worker 
396*f6dc9357SAndroid Build Coastguard Worker   _size = Get64((const Byte *)(const void *)buf64 + 0x18);
397*f6dc9357SAndroid Build Coastguard Worker   if (_size > k_UncompressedSize_MAX)
398*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
399*f6dc9357SAndroid Build Coastguard Worker   size_t l1Size;
400*f6dc9357SAndroid Build Coastguard Worker   UInt32 headerSize;
401*f6dc9357SAndroid Build Coastguard Worker 
402*f6dc9357SAndroid Build Coastguard Worker   if (_version == 1)
403*f6dc9357SAndroid Build Coastguard Worker   {
404*f6dc9357SAndroid Build Coastguard Worker     // _mTime = Get32((const Byte *)(const void *)buf64 + 0x14); // is unused in most images
405*f6dc9357SAndroid Build Coastguard Worker     _clusterBits = ((const Byte *)(const void *)buf64)[0x20];
406*f6dc9357SAndroid Build Coastguard Worker     _numMidBits  = ((const Byte *)(const void *)buf64)[0x21];
407*f6dc9357SAndroid Build Coastguard Worker     if (_clusterBits < 9 || _clusterBits > 30)
408*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
409*f6dc9357SAndroid Build Coastguard Worker     if (_numMidBits < 1 || _numMidBits > 28)
410*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
411*f6dc9357SAndroid Build Coastguard Worker     _cryptMethod = Get32((const Byte *)(const void *)buf64 + 0x24);
412*f6dc9357SAndroid Build Coastguard Worker     const unsigned numBits2 = _clusterBits + _numMidBits;
413*f6dc9357SAndroid Build Coastguard Worker     const UInt64 l1Size64 = (_size + (((UInt64)1 << numBits2) - 1)) >> numBits2;
414*f6dc9357SAndroid Build Coastguard Worker     if (l1Size64 > ((UInt32)1 << 31))
415*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
416*f6dc9357SAndroid Build Coastguard Worker     l1Size = (size_t)l1Size64;
417*f6dc9357SAndroid Build Coastguard Worker     headerSize = 0x30;
418*f6dc9357SAndroid Build Coastguard Worker   }
419*f6dc9357SAndroid Build Coastguard Worker   else
420*f6dc9357SAndroid Build Coastguard Worker   {
421*f6dc9357SAndroid Build Coastguard Worker     _clusterBits = Get32((const Byte *)(const void *)buf64 + 0x14);
422*f6dc9357SAndroid Build Coastguard Worker     if (_clusterBits < 9 || _clusterBits > 30)
423*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
424*f6dc9357SAndroid Build Coastguard Worker     _numMidBits = _clusterBits - 3;
425*f6dc9357SAndroid Build Coastguard Worker     _cryptMethod = Get32((const Byte *)(const void *)buf64 + 0x20);
426*f6dc9357SAndroid Build Coastguard Worker     l1Size = Get32((const Byte *)(const void *)buf64 + 0x24);
427*f6dc9357SAndroid Build Coastguard Worker     headerSize = 0x48;
428*f6dc9357SAndroid Build Coastguard Worker     if (_version >= 3)
429*f6dc9357SAndroid Build Coastguard Worker     {
430*f6dc9357SAndroid Build Coastguard Worker       _incompatFlags = Get64((const Byte *)(const void *)buf64 + 0x48);
431*f6dc9357SAndroid Build Coastguard Worker       // const UInt64 CompatFlags    = Get64((const Byte *)(const void *)buf64 + 0x50);
432*f6dc9357SAndroid Build Coastguard Worker       // const UInt64 AutoClearFlags = Get64((const Byte *)(const void *)buf64 + 0x58);
433*f6dc9357SAndroid Build Coastguard Worker       // const UInt32 RefCountOrder = Get32((const Byte *)(const void *)buf64 + 0x60);
434*f6dc9357SAndroid Build Coastguard Worker       headerSize = 0x68;
435*f6dc9357SAndroid Build Coastguard Worker       const UInt32 headerSize2  = Get32((const Byte *)(const void *)buf64 + 0x64);
436*f6dc9357SAndroid Build Coastguard Worker       if (headerSize2 > (1u << 30))
437*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
438*f6dc9357SAndroid Build Coastguard Worker       if (headerSize < headerSize2)
439*f6dc9357SAndroid Build Coastguard Worker           headerSize = headerSize2;
440*f6dc9357SAndroid Build Coastguard Worker       if (headerSize2 >= 0x68 + 1)
441*f6dc9357SAndroid Build Coastguard Worker         _compressionType = ((const Byte *)(const void *)buf64)[0x68];
442*f6dc9357SAndroid Build Coastguard Worker     }
443*f6dc9357SAndroid Build Coastguard Worker 
444*f6dc9357SAndroid Build Coastguard Worker     const UInt64 refOffset = Get64((const Byte *)(const void *)buf64 + 0x30); // must be aligned for cluster
445*f6dc9357SAndroid Build Coastguard Worker     const UInt32 refClusters = Get32((const Byte *)(const void *)buf64 + 0x38);
446*f6dc9357SAndroid Build Coastguard Worker     // UInt32 numSnapshots = Get32((const Byte *)(const void *)buf64 + 0x3C);
447*f6dc9357SAndroid Build Coastguard Worker     // UInt64 snapshotsOffset = Get64((const Byte *)(const void *)buf64 + 0x40); // must be aligned for cluster
448*f6dc9357SAndroid Build Coastguard Worker     /*
449*f6dc9357SAndroid Build Coastguard Worker     if (numSnapshots)
450*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
451*f6dc9357SAndroid Build Coastguard Worker     */
452*f6dc9357SAndroid Build Coastguard Worker     if (refClusters)
453*f6dc9357SAndroid Build Coastguard Worker     {
454*f6dc9357SAndroid Build Coastguard Worker       if (refOffset > k_CompressedSize_MAX)
455*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
456*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numBytes = (UInt64)refClusters << _clusterBits;
457*f6dc9357SAndroid Build Coastguard Worker       const UInt64 end = refOffset + numBytes;
458*f6dc9357SAndroid Build Coastguard Worker       if (end > k_CompressedSize_MAX)
459*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
460*f6dc9357SAndroid Build Coastguard Worker       /*
461*f6dc9357SAndroid Build Coastguard Worker       CByteBuffer refs;
462*f6dc9357SAndroid Build Coastguard Worker       refs.Alloc(numBytes);
463*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(stream, refOffset))
464*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadStream_FALSE(stream, refs, numBytes));
465*f6dc9357SAndroid Build Coastguard Worker       */
466*f6dc9357SAndroid Build Coastguard Worker       if (_phySize < end)
467*f6dc9357SAndroid Build Coastguard Worker           _phySize = end;
468*f6dc9357SAndroid Build Coastguard Worker       /*
469*f6dc9357SAndroid Build Coastguard Worker       for (size_t i = 0; i < numBytes; i += 2)
470*f6dc9357SAndroid Build Coastguard Worker       {
471*f6dc9357SAndroid Build Coastguard Worker         UInt32 v = GetBe16((const Byte *)refs + (size_t)i);
472*f6dc9357SAndroid Build Coastguard Worker         if (v == 0)
473*f6dc9357SAndroid Build Coastguard Worker           continue;
474*f6dc9357SAndroid Build Coastguard Worker       }
475*f6dc9357SAndroid Build Coastguard Worker       */
476*f6dc9357SAndroid Build Coastguard Worker     }
477*f6dc9357SAndroid Build Coastguard Worker   }
478*f6dc9357SAndroid Build Coastguard Worker 
479*f6dc9357SAndroid Build Coastguard Worker   const UInt64 l1Offset = Get64((const Byte *)(const void *)buf64 + 0x28); // must be aligned for cluster ?
480*f6dc9357SAndroid Build Coastguard Worker   if (l1Offset < headerSize || l1Offset > k_CompressedSize_MAX)
481*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
482*f6dc9357SAndroid Build Coastguard Worker   if (_phySize < headerSize)
483*f6dc9357SAndroid Build Coastguard Worker       _phySize = headerSize;
484*f6dc9357SAndroid Build Coastguard Worker 
485*f6dc9357SAndroid Build Coastguard Worker   _isArc = true;
486*f6dc9357SAndroid Build Coastguard Worker   {
487*f6dc9357SAndroid Build Coastguard Worker     const UInt64 backOffset = Get64((const Byte *)(const void *)buf64 + 8);
488*f6dc9357SAndroid Build Coastguard Worker     // UInt32 backSize = Get32((const Byte *)(const void *)buf64 + 0x10);
489*f6dc9357SAndroid Build Coastguard Worker     if (backOffset)
490*f6dc9357SAndroid Build Coastguard Worker     {
491*f6dc9357SAndroid Build Coastguard Worker       _unsupported = true;
492*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
493*f6dc9357SAndroid Build Coastguard Worker     }
494*f6dc9357SAndroid Build Coastguard Worker   }
495*f6dc9357SAndroid Build Coastguard Worker 
496*f6dc9357SAndroid Build Coastguard Worker   UInt64 fileSize = 0;
497*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_GetSize_SeekToBegin(stream, fileSize))
498*f6dc9357SAndroid Build Coastguard Worker 
499*f6dc9357SAndroid Build Coastguard Worker   const size_t clusterSize = (size_t)1 << _clusterBits;
500*f6dc9357SAndroid Build Coastguard Worker   const size_t t1SizeBytes = (size_t)l1Size << 3;
501*f6dc9357SAndroid Build Coastguard Worker   {
502*f6dc9357SAndroid Build Coastguard Worker     const UInt64 end = l1Offset + t1SizeBytes;
503*f6dc9357SAndroid Build Coastguard Worker     if (end > k_CompressedSize_MAX)
504*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
505*f6dc9357SAndroid Build Coastguard Worker     // we need to use align end for empty qcow files
506*f6dc9357SAndroid Build Coastguard Worker     // some files has no cluster alignment padding at the end
507*f6dc9357SAndroid Build Coastguard Worker     // but has sector alignment
508*f6dc9357SAndroid Build Coastguard Worker     // end = (end + clusterSize - 1) >> _clusterBits << _clusterBits;
509*f6dc9357SAndroid Build Coastguard Worker     if (_phySize < end)
510*f6dc9357SAndroid Build Coastguard Worker         _phySize = end;
511*f6dc9357SAndroid Build Coastguard Worker     if (end > fileSize)
512*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
513*f6dc9357SAndroid Build Coastguard Worker     if (_phySize < fileSize)
514*f6dc9357SAndroid Build Coastguard Worker     {
515*f6dc9357SAndroid Build Coastguard Worker       const UInt64 end2 = (end + 511) & ~(UInt64)511;
516*f6dc9357SAndroid Build Coastguard Worker       if (end2 == fileSize)
517*f6dc9357SAndroid Build Coastguard Worker         _phySize = end2;
518*f6dc9357SAndroid Build Coastguard Worker     }
519*f6dc9357SAndroid Build Coastguard Worker   }
520*f6dc9357SAndroid Build Coastguard Worker   CObjArray<UInt64> table64(l1Size);
521*f6dc9357SAndroid Build Coastguard Worker   {
522*f6dc9357SAndroid Build Coastguard Worker     // if ((t1SizeBytes >> 3) != l1Size) return S_FALSE;
523*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekSet(stream, l1Offset))
524*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(stream, table64, t1SizeBytes))
525*f6dc9357SAndroid Build Coastguard Worker   }
526*f6dc9357SAndroid Build Coastguard Worker 
527*f6dc9357SAndroid Build Coastguard Worker   _compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62);
528*f6dc9357SAndroid Build Coastguard Worker   const UInt64 offsetMask = _compressedFlag - 1;
529*f6dc9357SAndroid Build Coastguard Worker   const size_t midSize = (size_t)1 << (_numMidBits + 3);
530*f6dc9357SAndroid Build Coastguard Worker   size_t numTables = 0;
531*f6dc9357SAndroid Build Coastguard Worker   size_t i;
532*f6dc9357SAndroid Build Coastguard Worker 
533*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < l1Size; i++)
534*f6dc9357SAndroid Build Coastguard Worker   {
535*f6dc9357SAndroid Build Coastguard Worker     const UInt64 v = Get64(table64 + (size_t)i) & offsetMask;
536*f6dc9357SAndroid Build Coastguard Worker     if (!v)
537*f6dc9357SAndroid Build Coastguard Worker       continue;
538*f6dc9357SAndroid Build Coastguard Worker     numTables++;
539*f6dc9357SAndroid Build Coastguard Worker     const UInt64 end = v + midSize;
540*f6dc9357SAndroid Build Coastguard Worker     if (end > k_CompressedSize_MAX)
541*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
542*f6dc9357SAndroid Build Coastguard Worker     if (_phySize < end)
543*f6dc9357SAndroid Build Coastguard Worker         _phySize = end;
544*f6dc9357SAndroid Build Coastguard Worker     if (end > fileSize)
545*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
546*f6dc9357SAndroid Build Coastguard Worker   }
547*f6dc9357SAndroid Build Coastguard Worker 
548*f6dc9357SAndroid Build Coastguard Worker   if (numTables)
549*f6dc9357SAndroid Build Coastguard Worker   {
550*f6dc9357SAndroid Build Coastguard Worker     const size_t size = (size_t)numTables << (_numMidBits + 3);
551*f6dc9357SAndroid Build Coastguard Worker     if (size >> (_numMidBits + 3) != numTables)
552*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
553*f6dc9357SAndroid Build Coastguard Worker     _table.Alloc(size);
554*f6dc9357SAndroid Build Coastguard Worker     if (!_table.IsAllocated())
555*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
556*f6dc9357SAndroid Build Coastguard Worker     if (openCallback)
557*f6dc9357SAndroid Build Coastguard Worker     {
558*f6dc9357SAndroid Build Coastguard Worker       const UInt64 totalBytes = size;
559*f6dc9357SAndroid Build Coastguard Worker       RINOK(openCallback->SetTotal(NULL, &totalBytes))
560*f6dc9357SAndroid Build Coastguard Worker     }
561*f6dc9357SAndroid Build Coastguard Worker   }
562*f6dc9357SAndroid Build Coastguard Worker 
563*f6dc9357SAndroid Build Coastguard Worker   _dir.SetSize((unsigned)l1Size);
564*f6dc9357SAndroid Build Coastguard Worker 
565*f6dc9357SAndroid Build Coastguard Worker   UInt32 curTable = 0;
566*f6dc9357SAndroid Build Coastguard Worker 
567*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < l1Size; i++)
568*f6dc9357SAndroid Build Coastguard Worker   {
569*f6dc9357SAndroid Build Coastguard Worker     Byte *buf2;
570*f6dc9357SAndroid Build Coastguard Worker     {
571*f6dc9357SAndroid Build Coastguard Worker       const UInt64 v = Get64(table64 + (size_t)i) & offsetMask;
572*f6dc9357SAndroid Build Coastguard Worker       if (v == 0)
573*f6dc9357SAndroid Build Coastguard Worker       {
574*f6dc9357SAndroid Build Coastguard Worker         _dir[i] = kEmptyDirItem;
575*f6dc9357SAndroid Build Coastguard Worker         continue;
576*f6dc9357SAndroid Build Coastguard Worker       }
577*f6dc9357SAndroid Build Coastguard Worker       _dir[i] = curTable;
578*f6dc9357SAndroid Build Coastguard Worker       const size_t tableOffset = (size_t)curTable << (_numMidBits + 3);
579*f6dc9357SAndroid Build Coastguard Worker       buf2 = (Byte *)_table + tableOffset;
580*f6dc9357SAndroid Build Coastguard Worker       curTable++;
581*f6dc9357SAndroid Build Coastguard Worker       if (openCallback && (tableOffset & 0xFFFFF) == 0)
582*f6dc9357SAndroid Build Coastguard Worker       {
583*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numBytes = tableOffset;
584*f6dc9357SAndroid Build Coastguard Worker         RINOK(openCallback->SetCompleted(NULL, &numBytes))
585*f6dc9357SAndroid Build Coastguard Worker       }
586*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(stream, v))
587*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadStream_FALSE(stream, buf2, midSize))
588*f6dc9357SAndroid Build Coastguard Worker     }
589*f6dc9357SAndroid Build Coastguard Worker 
590*f6dc9357SAndroid Build Coastguard Worker     for (size_t k = 0; k < midSize; k += 8)
591*f6dc9357SAndroid Build Coastguard Worker     {
592*f6dc9357SAndroid Build Coastguard Worker       const UInt64 v = Get64((const Byte *)buf2 + (size_t)k);
593*f6dc9357SAndroid Build Coastguard Worker       if (v == 0)
594*f6dc9357SAndroid Build Coastguard Worker         continue;
595*f6dc9357SAndroid Build Coastguard Worker       UInt64 offset = v & offsetMask;
596*f6dc9357SAndroid Build Coastguard Worker       size_t dataSize = clusterSize;
597*f6dc9357SAndroid Build Coastguard Worker 
598*f6dc9357SAndroid Build Coastguard Worker       if (v & _compressedFlag)
599*f6dc9357SAndroid Build Coastguard Worker       {
600*f6dc9357SAndroid Build Coastguard Worker         if (_version <= 1)
601*f6dc9357SAndroid Build Coastguard Worker         {
602*f6dc9357SAndroid Build Coastguard Worker           const unsigned numOffsetBits = 63 - _clusterBits;
603*f6dc9357SAndroid Build Coastguard Worker           dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
604*f6dc9357SAndroid Build Coastguard Worker           offset &= ((UInt64)1 << numOffsetBits) - 1;
605*f6dc9357SAndroid Build Coastguard Worker           dataSize = 0; // why ?
606*f6dc9357SAndroid Build Coastguard Worker           // offset &= ~(((UInt64)1 << 9) - 1);
607*f6dc9357SAndroid Build Coastguard Worker         }
608*f6dc9357SAndroid Build Coastguard Worker         else
609*f6dc9357SAndroid Build Coastguard Worker         {
610*f6dc9357SAndroid Build Coastguard Worker           const unsigned numOffsetBits = 62 - (_clusterBits - 8);
611*f6dc9357SAndroid Build Coastguard Worker           dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
612*f6dc9357SAndroid Build Coastguard Worker           offset &= ((UInt64)1 << numOffsetBits) - (1 << 9);
613*f6dc9357SAndroid Build Coastguard Worker         }
614*f6dc9357SAndroid Build Coastguard Worker         _needCompression = true;
615*f6dc9357SAndroid Build Coastguard Worker       }
616*f6dc9357SAndroid Build Coastguard Worker       else
617*f6dc9357SAndroid Build Coastguard Worker       {
618*f6dc9357SAndroid Build Coastguard Worker         const UInt32 low = (UInt32)v & 511;
619*f6dc9357SAndroid Build Coastguard Worker         if (low)
620*f6dc9357SAndroid Build Coastguard Worker         {
621*f6dc9357SAndroid Build Coastguard Worker           // version_3 supports zero clusters
622*f6dc9357SAndroid Build Coastguard Worker           if (_version < 3 || low != 1)
623*f6dc9357SAndroid Build Coastguard Worker           {
624*f6dc9357SAndroid Build Coastguard Worker             _unsupported = true;
625*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
626*f6dc9357SAndroid Build Coastguard Worker           }
627*f6dc9357SAndroid Build Coastguard Worker         }
628*f6dc9357SAndroid Build Coastguard Worker       }
629*f6dc9357SAndroid Build Coastguard Worker 
630*f6dc9357SAndroid Build Coastguard Worker       const UInt64 end = offset + dataSize;
631*f6dc9357SAndroid Build Coastguard Worker       if (_phySize < end)
632*f6dc9357SAndroid Build Coastguard Worker           _phySize = end;
633*f6dc9357SAndroid Build Coastguard Worker     }
634*f6dc9357SAndroid Build Coastguard Worker   }
635*f6dc9357SAndroid Build Coastguard Worker 
636*f6dc9357SAndroid Build Coastguard Worker   if (curTable != numTables)
637*f6dc9357SAndroid Build Coastguard Worker     return E_FAIL;
638*f6dc9357SAndroid Build Coastguard Worker 
639*f6dc9357SAndroid Build Coastguard Worker   if (_cryptMethod)
640*f6dc9357SAndroid Build Coastguard Worker     _unsupported = true;
641*f6dc9357SAndroid Build Coastguard Worker   if (_needCompression && _version <= 1) // that case was not implemented
642*f6dc9357SAndroid Build Coastguard Worker     _unsupported = true;
643*f6dc9357SAndroid Build Coastguard Worker   if (_compressionType)
644*f6dc9357SAndroid Build Coastguard Worker     _unsupported = true;
645*f6dc9357SAndroid Build Coastguard Worker 
646*f6dc9357SAndroid Build Coastguard Worker   Stream = stream;
647*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
648*f6dc9357SAndroid Build Coastguard Worker }
649*f6dc9357SAndroid Build Coastguard Worker 
650*f6dc9357SAndroid Build Coastguard Worker 
651*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
652*f6dc9357SAndroid Build Coastguard Worker {
653*f6dc9357SAndroid Build Coastguard Worker   _table.Free();
654*f6dc9357SAndroid Build Coastguard Worker   _dir.Free();
655*f6dc9357SAndroid Build Coastguard Worker   // _cache.Free();
656*f6dc9357SAndroid Build Coastguard Worker   // _cacheCompressed.Free();
657*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
658*f6dc9357SAndroid Build Coastguard Worker 
659*f6dc9357SAndroid Build Coastguard Worker   _cacheCluster = (UInt64)(Int64)-1;
660*f6dc9357SAndroid Build Coastguard Worker   _comprPos = 0;
661*f6dc9357SAndroid Build Coastguard Worker   _comprSize = 0;
662*f6dc9357SAndroid Build Coastguard Worker 
663*f6dc9357SAndroid Build Coastguard Worker   _needCompression = false;
664*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
665*f6dc9357SAndroid Build Coastguard Worker   _unsupported = false;
666*f6dc9357SAndroid Build Coastguard Worker 
667*f6dc9357SAndroid Build Coastguard Worker   _compressionType = 0;
668*f6dc9357SAndroid Build Coastguard Worker   _incompatFlags = 0;
669*f6dc9357SAndroid Build Coastguard Worker 
670*f6dc9357SAndroid Build Coastguard Worker   // CHandlerImg:
671*f6dc9357SAndroid Build Coastguard Worker   Clear_HandlerImg_Vars();
672*f6dc9357SAndroid Build Coastguard Worker   Stream.Release();
673*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
674*f6dc9357SAndroid Build Coastguard Worker }
675*f6dc9357SAndroid Build Coastguard Worker 
676*f6dc9357SAndroid Build Coastguard Worker 
677*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream))
678*f6dc9357SAndroid Build Coastguard Worker {
679*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
680*f6dc9357SAndroid Build Coastguard Worker   *stream = NULL;
681*f6dc9357SAndroid Build Coastguard Worker   if (_unsupported || !Stream)
682*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
683*f6dc9357SAndroid Build Coastguard Worker   if (_needCompression)
684*f6dc9357SAndroid Build Coastguard Worker   {
685*f6dc9357SAndroid Build Coastguard Worker     if (_version <= 1 || _compressionType)
686*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
687*f6dc9357SAndroid Build Coastguard Worker     _bufInStream.Create_if_Empty();
688*f6dc9357SAndroid Build Coastguard Worker     _bufOutStream.Create_if_Empty();
689*f6dc9357SAndroid Build Coastguard Worker     _deflateDecoder.Create_if_Empty();
690*f6dc9357SAndroid Build Coastguard Worker     _deflateDecoder->Set_NeedFinishInput(true);
691*f6dc9357SAndroid Build Coastguard Worker     const size_t clusterSize = (size_t)1 << _clusterBits;
692*f6dc9357SAndroid Build Coastguard Worker     _cache.AllocAtLeast(clusterSize);
693*f6dc9357SAndroid Build Coastguard Worker     _cacheCompressed.AllocAtLeast(clusterSize * 2);
694*f6dc9357SAndroid Build Coastguard Worker   }
695*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> streamTemp = this;
696*f6dc9357SAndroid Build Coastguard Worker   RINOK(InitAndSeek())
697*f6dc9357SAndroid Build Coastguard Worker   *stream = streamTemp.Detach();
698*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
699*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
700*f6dc9357SAndroid Build Coastguard Worker }
701*f6dc9357SAndroid Build Coastguard Worker 
702*f6dc9357SAndroid Build Coastguard Worker 
703*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
704*f6dc9357SAndroid Build Coastguard Worker   "QCOW", "qcow qcow2 qcow2c", NULL, 0xCA,
705*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
706*f6dc9357SAndroid Build Coastguard Worker   0,
707*f6dc9357SAndroid Build Coastguard Worker   0,
708*f6dc9357SAndroid Build Coastguard Worker   NULL)
709*f6dc9357SAndroid Build Coastguard Worker 
710*f6dc9357SAndroid Build Coastguard Worker }}
711