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