1*f6dc9357SAndroid Build Coastguard Worker // SparseHandler.cpp 2*f6dc9357SAndroid Build Coastguard Worker 3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h" 4*f6dc9357SAndroid Build Coastguard Worker 5*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h" 6*f6dc9357SAndroid Build Coastguard Worker 7*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h" 8*f6dc9357SAndroid Build Coastguard Worker 9*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariantUtils.h" 10*f6dc9357SAndroid Build Coastguard Worker 11*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h" 12*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h" 13*f6dc9357SAndroid Build Coastguard Worker 14*f6dc9357SAndroid Build Coastguard Worker #include "HandlerCont.h" 15*f6dc9357SAndroid Build Coastguard Worker 16*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p) 17*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p) 18*f6dc9357SAndroid Build Coastguard Worker 19*f6dc9357SAndroid Build Coastguard Worker #define G16(_offs_, dest) dest = Get16(p + (_offs_)); 20*f6dc9357SAndroid Build Coastguard Worker #define G32(_offs_, dest) dest = Get32(p + (_offs_)); 21*f6dc9357SAndroid Build Coastguard Worker 22*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows; 23*f6dc9357SAndroid Build Coastguard Worker 24*f6dc9357SAndroid Build Coastguard Worker namespace NArchive { 25*f6dc9357SAndroid Build Coastguard Worker namespace NSparse { 26*f6dc9357SAndroid Build Coastguard Worker 27*f6dc9357SAndroid Build Coastguard Worker // libsparse and simg2img 28*f6dc9357SAndroid Build Coastguard Worker 29*f6dc9357SAndroid Build Coastguard Worker struct CHeader 30*f6dc9357SAndroid Build Coastguard Worker { 31*f6dc9357SAndroid Build Coastguard Worker // UInt32 magic; /* 0xed26ff3a */ 32*f6dc9357SAndroid Build Coastguard Worker // UInt16 major_version; /* (0x1) - reject images with higher major versions */ 33*f6dc9357SAndroid Build Coastguard Worker // UInt16 minor_version; /* (0x0) - allow images with higer minor versions */ 34*f6dc9357SAndroid Build Coastguard Worker UInt16 file_hdr_sz; /* 28 bytes for first revision of the file format */ 35*f6dc9357SAndroid Build Coastguard Worker UInt16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */ 36*f6dc9357SAndroid Build Coastguard Worker UInt32 BlockSize; /* block size in bytes, must be a multiple of 4 (4096) */ 37*f6dc9357SAndroid Build Coastguard Worker UInt32 NumBlocks; /* total blocks in the non-sparse output image */ 38*f6dc9357SAndroid Build Coastguard Worker UInt32 NumChunks; /* total chunks in the sparse input image */ 39*f6dc9357SAndroid Build Coastguard Worker // UInt32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" as 0. */ 40*f6dc9357SAndroid Build Coastguard Worker ParseNArchive::NSparse::CHeader41*f6dc9357SAndroid Build Coastguard Worker void Parse(const Byte *p) 42*f6dc9357SAndroid Build Coastguard Worker { 43*f6dc9357SAndroid Build Coastguard Worker // G16 (4, major_version); 44*f6dc9357SAndroid Build Coastguard Worker // G16 (6, minor_version); 45*f6dc9357SAndroid Build Coastguard Worker G16 (8, file_hdr_sz) 46*f6dc9357SAndroid Build Coastguard Worker G16 (10, chunk_hdr_sz) 47*f6dc9357SAndroid Build Coastguard Worker G32 (12, BlockSize) 48*f6dc9357SAndroid Build Coastguard Worker G32 (16, NumBlocks) 49*f6dc9357SAndroid Build Coastguard Worker G32 (20, NumChunks) 50*f6dc9357SAndroid Build Coastguard Worker // G32 (24, image_checksum); 51*f6dc9357SAndroid Build Coastguard Worker } 52*f6dc9357SAndroid Build Coastguard Worker }; 53*f6dc9357SAndroid Build Coastguard Worker 54*f6dc9357SAndroid Build Coastguard Worker // #define SPARSE_HEADER_MAGIC 0xed26ff3a 55*f6dc9357SAndroid Build Coastguard Worker 56*f6dc9357SAndroid Build Coastguard Worker #define CHUNK_TYPE_RAW 0xCAC1 57*f6dc9357SAndroid Build Coastguard Worker #define CHUNK_TYPE_FILL 0xCAC2 58*f6dc9357SAndroid Build Coastguard Worker #define CHUNK_TYPE_DONT_CARE 0xCAC3 59*f6dc9357SAndroid Build Coastguard Worker #define CHUNK_TYPE_CRC32 0xCAC4 60*f6dc9357SAndroid Build Coastguard Worker 61*f6dc9357SAndroid Build Coastguard Worker #define MY_CHUNK_TYPE_FILL 0 62*f6dc9357SAndroid Build Coastguard Worker #define MY_CHUNK_TYPE_DONT_CARE 1 63*f6dc9357SAndroid Build Coastguard Worker #define MY_CHUNK_TYPE_RAW_START 2 64*f6dc9357SAndroid Build Coastguard Worker 65*f6dc9357SAndroid Build Coastguard Worker static const char * const g_Methods[] = 66*f6dc9357SAndroid Build Coastguard Worker { 67*f6dc9357SAndroid Build Coastguard Worker "RAW" 68*f6dc9357SAndroid Build Coastguard Worker , "FILL" 69*f6dc9357SAndroid Build Coastguard Worker , "SPARSE" // "DONT_CARE" 70*f6dc9357SAndroid Build Coastguard Worker , "CRC32" 71*f6dc9357SAndroid Build Coastguard Worker }; 72*f6dc9357SAndroid Build Coastguard Worker 73*f6dc9357SAndroid Build Coastguard Worker static const unsigned kFillSize = 4; 74*f6dc9357SAndroid Build Coastguard Worker 75*f6dc9357SAndroid Build Coastguard Worker struct CChunk 76*f6dc9357SAndroid Build Coastguard Worker { 77*f6dc9357SAndroid Build Coastguard Worker UInt32 VirtBlock; 78*f6dc9357SAndroid Build Coastguard Worker Byte Fill [kFillSize]; 79*f6dc9357SAndroid Build Coastguard Worker UInt64 PhyOffset; 80*f6dc9357SAndroid Build Coastguard Worker CChunkNArchive::NSparse::CChunk81*f6dc9357SAndroid Build Coastguard Worker CChunk() 82*f6dc9357SAndroid Build Coastguard Worker { 83*f6dc9357SAndroid Build Coastguard Worker Fill[0] = 84*f6dc9357SAndroid Build Coastguard Worker Fill[1] = 85*f6dc9357SAndroid Build Coastguard Worker Fill[2] = 86*f6dc9357SAndroid Build Coastguard Worker Fill[3] = 87*f6dc9357SAndroid Build Coastguard Worker 0; 88*f6dc9357SAndroid Build Coastguard Worker } 89*f6dc9357SAndroid Build Coastguard Worker }; 90*f6dc9357SAndroid Build Coastguard Worker 91*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { 0x3a, 0xff, 0x26, 0xed, 1, 0 }; 92*f6dc9357SAndroid Build Coastguard Worker 93*f6dc9357SAndroid Build Coastguard Worker 94*f6dc9357SAndroid Build Coastguard Worker Z7_class_CHandler_final: public CHandlerImg 95*f6dc9357SAndroid Build Coastguard Worker { 96*f6dc9357SAndroid Build Coastguard Worker Z7_IFACE_COM7_IMP(IInArchive_Img) 97*f6dc9357SAndroid Build Coastguard Worker 98*f6dc9357SAndroid Build Coastguard Worker Z7_IFACE_COM7_IMP(IInArchiveGetStream) 99*f6dc9357SAndroid Build Coastguard Worker Z7_IFACE_COM7_IMP(ISequentialInStream) 100*f6dc9357SAndroid Build Coastguard Worker 101*f6dc9357SAndroid Build Coastguard Worker CRecordVector<CChunk> Chunks; 102*f6dc9357SAndroid Build Coastguard Worker UInt64 _virtSize_fromChunks; 103*f6dc9357SAndroid Build Coastguard Worker unsigned _blockSizeLog; 104*f6dc9357SAndroid Build Coastguard Worker UInt32 _chunkIndexPrev; 105*f6dc9357SAndroid Build Coastguard Worker 106*f6dc9357SAndroid Build Coastguard Worker UInt64 _packSizeProcessed; 107*f6dc9357SAndroid Build Coastguard Worker UInt64 _phySize; 108*f6dc9357SAndroid Build Coastguard Worker UInt32 _methodFlags; 109*f6dc9357SAndroid Build Coastguard Worker bool _isArc; 110*f6dc9357SAndroid Build Coastguard Worker bool _headersError; 111*f6dc9357SAndroid Build Coastguard Worker bool _unexpectedEnd; 112*f6dc9357SAndroid Build Coastguard Worker // bool _unsupported; 113*f6dc9357SAndroid Build Coastguard Worker UInt32 NumChunks; // from header 114*f6dc9357SAndroid Build Coastguard Worker 115*f6dc9357SAndroid Build Coastguard Worker HRESULT Seek2(UInt64 offset) 116*f6dc9357SAndroid Build Coastguard Worker { 117*f6dc9357SAndroid Build Coastguard Worker _posInArc = offset; 118*f6dc9357SAndroid Build Coastguard Worker return InStream_SeekSet(Stream, offset); 119*f6dc9357SAndroid Build Coastguard Worker } 120*f6dc9357SAndroid Build Coastguard Worker 121*f6dc9357SAndroid Build Coastguard Worker void InitSeekPositions() 122*f6dc9357SAndroid Build Coastguard Worker { 123*f6dc9357SAndroid Build Coastguard Worker /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()). 124*f6dc9357SAndroid Build Coastguard Worker So we must reset these variables before first call of Read() */ 125*f6dc9357SAndroid Build Coastguard Worker Reset_VirtPos(); 126*f6dc9357SAndroid Build Coastguard Worker Reset_PosInArc(); 127*f6dc9357SAndroid Build Coastguard Worker _chunkIndexPrev = 0; 128*f6dc9357SAndroid Build Coastguard Worker _packSizeProcessed = 0; 129*f6dc9357SAndroid Build Coastguard Worker } 130*f6dc9357SAndroid Build Coastguard Worker 131*f6dc9357SAndroid Build Coastguard Worker // virtual functions 132*f6dc9357SAndroid Build Coastguard Worker bool Init_PackSizeProcessed() Z7_override 133*f6dc9357SAndroid Build Coastguard Worker { 134*f6dc9357SAndroid Build Coastguard Worker _packSizeProcessed = 0; 135*f6dc9357SAndroid Build Coastguard Worker return true; 136*f6dc9357SAndroid Build Coastguard Worker } 137*f6dc9357SAndroid Build Coastguard Worker bool Get_PackSizeProcessed(UInt64 &size) Z7_override 138*f6dc9357SAndroid Build Coastguard Worker { 139*f6dc9357SAndroid Build Coastguard Worker size = _packSizeProcessed; 140*f6dc9357SAndroid Build Coastguard Worker return true; 141*f6dc9357SAndroid Build Coastguard Worker } 142*f6dc9357SAndroid Build Coastguard Worker 143*f6dc9357SAndroid Build Coastguard Worker HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override; 144*f6dc9357SAndroid Build Coastguard Worker HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed); 145*f6dc9357SAndroid Build Coastguard Worker }; 146*f6dc9357SAndroid Build Coastguard Worker 147*f6dc9357SAndroid Build Coastguard Worker 148*f6dc9357SAndroid Build Coastguard Worker 149*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] = 150*f6dc9357SAndroid Build Coastguard Worker { 151*f6dc9357SAndroid Build Coastguard Worker kpidSize, 152*f6dc9357SAndroid Build Coastguard Worker kpidPackSize 153*f6dc9357SAndroid Build Coastguard Worker }; 154*f6dc9357SAndroid Build Coastguard Worker 155*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] = 156*f6dc9357SAndroid Build Coastguard Worker { 157*f6dc9357SAndroid Build Coastguard Worker kpidClusterSize, 158*f6dc9357SAndroid Build Coastguard Worker kpidNumBlocks, 159*f6dc9357SAndroid Build Coastguard Worker kpidMethod 160*f6dc9357SAndroid Build Coastguard Worker }; 161*f6dc9357SAndroid Build Coastguard Worker 162*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props 163*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps 164*f6dc9357SAndroid Build Coastguard Worker 165*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) 166*f6dc9357SAndroid Build Coastguard Worker { 167*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN 168*f6dc9357SAndroid Build Coastguard Worker NCOM::CPropVariant prop; 169*f6dc9357SAndroid Build Coastguard Worker 170*f6dc9357SAndroid Build Coastguard Worker switch (propID) 171*f6dc9357SAndroid Build Coastguard Worker { 172*f6dc9357SAndroid Build Coastguard Worker case kpidMainSubfile: prop = (UInt32)0; break; 173*f6dc9357SAndroid Build Coastguard Worker case kpidClusterSize: prop = (UInt32)((UInt32)1 << _blockSizeLog); break; 174*f6dc9357SAndroid Build Coastguard Worker case kpidNumBlocks: prop = (UInt32)NumChunks; break; 175*f6dc9357SAndroid Build Coastguard Worker case kpidPhySize: if (_phySize != 0) prop = _phySize; break; 176*f6dc9357SAndroid Build Coastguard Worker 177*f6dc9357SAndroid Build Coastguard Worker case kpidMethod: 178*f6dc9357SAndroid Build Coastguard Worker { 179*f6dc9357SAndroid Build Coastguard Worker FLAGS_TO_PROP(g_Methods, _methodFlags, prop); 180*f6dc9357SAndroid Build Coastguard Worker break; 181*f6dc9357SAndroid Build Coastguard Worker } 182*f6dc9357SAndroid Build Coastguard Worker 183*f6dc9357SAndroid Build Coastguard Worker case kpidErrorFlags: 184*f6dc9357SAndroid Build Coastguard Worker { 185*f6dc9357SAndroid Build Coastguard Worker UInt32 v = 0; 186*f6dc9357SAndroid Build Coastguard Worker if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; 187*f6dc9357SAndroid Build Coastguard Worker if (_headersError) v |= kpv_ErrorFlags_HeadersError; 188*f6dc9357SAndroid Build Coastguard Worker if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; 189*f6dc9357SAndroid Build Coastguard Worker // if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; 190*f6dc9357SAndroid Build Coastguard Worker if (!Stream && v == 0 && _isArc) 191*f6dc9357SAndroid Build Coastguard Worker v = kpv_ErrorFlags_HeadersError; 192*f6dc9357SAndroid Build Coastguard Worker if (v != 0) 193*f6dc9357SAndroid Build Coastguard Worker prop = v; 194*f6dc9357SAndroid Build Coastguard Worker break; 195*f6dc9357SAndroid Build Coastguard Worker } 196*f6dc9357SAndroid Build Coastguard Worker } 197*f6dc9357SAndroid Build Coastguard Worker 198*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value); 199*f6dc9357SAndroid Build Coastguard Worker return S_OK; 200*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END 201*f6dc9357SAndroid Build Coastguard Worker } 202*f6dc9357SAndroid Build Coastguard Worker 203*f6dc9357SAndroid Build Coastguard Worker 204*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) 205*f6dc9357SAndroid Build Coastguard Worker { 206*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN 207*f6dc9357SAndroid Build Coastguard Worker NCOM::CPropVariant prop; 208*f6dc9357SAndroid Build Coastguard Worker 209*f6dc9357SAndroid Build Coastguard Worker switch (propID) 210*f6dc9357SAndroid Build Coastguard Worker { 211*f6dc9357SAndroid Build Coastguard Worker case kpidSize: prop = _size; break; 212*f6dc9357SAndroid Build Coastguard Worker case kpidPackSize: prop = _phySize; break; 213*f6dc9357SAndroid Build Coastguard Worker case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; 214*f6dc9357SAndroid Build Coastguard Worker } 215*f6dc9357SAndroid Build Coastguard Worker 216*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value); 217*f6dc9357SAndroid Build Coastguard Worker return S_OK; 218*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END 219*f6dc9357SAndroid Build Coastguard Worker } 220*f6dc9357SAndroid Build Coastguard Worker 221*f6dc9357SAndroid Build Coastguard Worker 222*f6dc9357SAndroid Build Coastguard Worker static unsigned GetLogSize(UInt32 size) 223*f6dc9357SAndroid Build Coastguard Worker { 224*f6dc9357SAndroid Build Coastguard Worker unsigned k; 225*f6dc9357SAndroid Build Coastguard Worker for (k = 0; k < 32; k++) 226*f6dc9357SAndroid Build Coastguard Worker if (((UInt32)1 << k) == size) 227*f6dc9357SAndroid Build Coastguard Worker return k; 228*f6dc9357SAndroid Build Coastguard Worker return k; 229*f6dc9357SAndroid Build Coastguard Worker } 230*f6dc9357SAndroid Build Coastguard Worker 231*f6dc9357SAndroid Build Coastguard Worker 232*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) 233*f6dc9357SAndroid Build Coastguard Worker { 234*f6dc9357SAndroid Build Coastguard Worker const unsigned kHeaderSize = 28; 235*f6dc9357SAndroid Build Coastguard Worker const unsigned kChunkHeaderSize = 12; 236*f6dc9357SAndroid Build Coastguard Worker CHeader h; 237*f6dc9357SAndroid Build Coastguard Worker { 238*f6dc9357SAndroid Build Coastguard Worker Byte buf[kHeaderSize]; 239*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)) 240*f6dc9357SAndroid Build Coastguard Worker if (memcmp(buf, k_Signature, 6) != 0) 241*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 242*f6dc9357SAndroid Build Coastguard Worker h.Parse(buf); 243*f6dc9357SAndroid Build Coastguard Worker } 244*f6dc9357SAndroid Build Coastguard Worker 245*f6dc9357SAndroid Build Coastguard Worker if (h.file_hdr_sz != kHeaderSize || 246*f6dc9357SAndroid Build Coastguard Worker h.chunk_hdr_sz != kChunkHeaderSize) 247*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 248*f6dc9357SAndroid Build Coastguard Worker 249*f6dc9357SAndroid Build Coastguard Worker NumChunks = h.NumChunks; 250*f6dc9357SAndroid Build Coastguard Worker 251*f6dc9357SAndroid Build Coastguard Worker const unsigned logSize = GetLogSize(h.BlockSize); 252*f6dc9357SAndroid Build Coastguard Worker if (logSize < 2 || logSize >= 32) 253*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 254*f6dc9357SAndroid Build Coastguard Worker _blockSizeLog = logSize; 255*f6dc9357SAndroid Build Coastguard Worker 256*f6dc9357SAndroid Build Coastguard Worker _size = (UInt64)h.NumBlocks << logSize; 257*f6dc9357SAndroid Build Coastguard Worker 258*f6dc9357SAndroid Build Coastguard Worker if (h.NumChunks >= (UInt32)(Int32)-2) // it's our limit 259*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 260*f6dc9357SAndroid Build Coastguard Worker 261*f6dc9357SAndroid Build Coastguard Worker _isArc = true; 262*f6dc9357SAndroid Build Coastguard Worker Chunks.Reserve(h.NumChunks + 1); 263*f6dc9357SAndroid Build Coastguard Worker UInt64 offset = kHeaderSize; 264*f6dc9357SAndroid Build Coastguard Worker UInt32 virtBlock = 0; 265*f6dc9357SAndroid Build Coastguard Worker UInt32 i; 266*f6dc9357SAndroid Build Coastguard Worker 267*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < h.NumChunks; i++) 268*f6dc9357SAndroid Build Coastguard Worker { 269*f6dc9357SAndroid Build Coastguard Worker { 270*f6dc9357SAndroid Build Coastguard Worker const UInt32 mask = ((UInt32)1 << 16) - 1; 271*f6dc9357SAndroid Build Coastguard Worker if ((i & mask) == mask && openCallback) 272*f6dc9357SAndroid Build Coastguard Worker { 273*f6dc9357SAndroid Build Coastguard Worker RINOK(openCallback->SetCompleted(NULL, &offset)) 274*f6dc9357SAndroid Build Coastguard Worker } 275*f6dc9357SAndroid Build Coastguard Worker } 276*f6dc9357SAndroid Build Coastguard Worker Byte buf[kChunkHeaderSize]; 277*f6dc9357SAndroid Build Coastguard Worker { 278*f6dc9357SAndroid Build Coastguard Worker size_t processed = kChunkHeaderSize; 279*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream(stream, buf, &processed)) 280*f6dc9357SAndroid Build Coastguard Worker if (kChunkHeaderSize != processed) 281*f6dc9357SAndroid Build Coastguard Worker { 282*f6dc9357SAndroid Build Coastguard Worker offset += kChunkHeaderSize; 283*f6dc9357SAndroid Build Coastguard Worker break; 284*f6dc9357SAndroid Build Coastguard Worker } 285*f6dc9357SAndroid Build Coastguard Worker } 286*f6dc9357SAndroid Build Coastguard Worker const UInt32 type = Get32(&buf[0]); 287*f6dc9357SAndroid Build Coastguard Worker const UInt32 numBlocks = Get32(&buf[4]); 288*f6dc9357SAndroid Build Coastguard Worker UInt32 size = Get32(&buf[8]); 289*f6dc9357SAndroid Build Coastguard Worker 290*f6dc9357SAndroid Build Coastguard Worker if (type < CHUNK_TYPE_RAW || 291*f6dc9357SAndroid Build Coastguard Worker type > CHUNK_TYPE_CRC32) 292*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 293*f6dc9357SAndroid Build Coastguard Worker if (size < kChunkHeaderSize) 294*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 295*f6dc9357SAndroid Build Coastguard Worker CChunk c; 296*f6dc9357SAndroid Build Coastguard Worker c.PhyOffset = offset + kChunkHeaderSize; 297*f6dc9357SAndroid Build Coastguard Worker c.VirtBlock = virtBlock; 298*f6dc9357SAndroid Build Coastguard Worker offset += size; 299*f6dc9357SAndroid Build Coastguard Worker size -= kChunkHeaderSize; 300*f6dc9357SAndroid Build Coastguard Worker _methodFlags |= ((UInt32)1 << (type - CHUNK_TYPE_RAW)); 301*f6dc9357SAndroid Build Coastguard Worker 302*f6dc9357SAndroid Build Coastguard Worker if (numBlocks > h.NumBlocks - virtBlock) 303*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 304*f6dc9357SAndroid Build Coastguard Worker 305*f6dc9357SAndroid Build Coastguard Worker if (type == CHUNK_TYPE_CRC32) 306*f6dc9357SAndroid Build Coastguard Worker { 307*f6dc9357SAndroid Build Coastguard Worker // crc chunk must be last chunk (i == h.NumChunks -1); 308*f6dc9357SAndroid Build Coastguard Worker if (size != kFillSize || numBlocks != 0) 309*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 310*f6dc9357SAndroid Build Coastguard Worker { 311*f6dc9357SAndroid Build Coastguard Worker size_t processed = kFillSize; 312*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream(stream, c.Fill, &processed)) 313*f6dc9357SAndroid Build Coastguard Worker if (kFillSize != processed) 314*f6dc9357SAndroid Build Coastguard Worker break; 315*f6dc9357SAndroid Build Coastguard Worker } 316*f6dc9357SAndroid Build Coastguard Worker continue; 317*f6dc9357SAndroid Build Coastguard Worker } 318*f6dc9357SAndroid Build Coastguard Worker // else 319*f6dc9357SAndroid Build Coastguard Worker { 320*f6dc9357SAndroid Build Coastguard Worker if (numBlocks == 0) 321*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 322*f6dc9357SAndroid Build Coastguard Worker 323*f6dc9357SAndroid Build Coastguard Worker if (type == CHUNK_TYPE_DONT_CARE) 324*f6dc9357SAndroid Build Coastguard Worker { 325*f6dc9357SAndroid Build Coastguard Worker if (size != 0) 326*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 327*f6dc9357SAndroid Build Coastguard Worker c.PhyOffset = MY_CHUNK_TYPE_DONT_CARE; 328*f6dc9357SAndroid Build Coastguard Worker } 329*f6dc9357SAndroid Build Coastguard Worker else if (type == CHUNK_TYPE_FILL) 330*f6dc9357SAndroid Build Coastguard Worker { 331*f6dc9357SAndroid Build Coastguard Worker if (size != kFillSize) 332*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 333*f6dc9357SAndroid Build Coastguard Worker c.PhyOffset = MY_CHUNK_TYPE_FILL; 334*f6dc9357SAndroid Build Coastguard Worker size_t processed = kFillSize; 335*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream(stream, c.Fill, &processed)) 336*f6dc9357SAndroid Build Coastguard Worker if (kFillSize != processed) 337*f6dc9357SAndroid Build Coastguard Worker break; 338*f6dc9357SAndroid Build Coastguard Worker } 339*f6dc9357SAndroid Build Coastguard Worker else if (type == CHUNK_TYPE_RAW) 340*f6dc9357SAndroid Build Coastguard Worker { 341*f6dc9357SAndroid Build Coastguard Worker /* Here we require (size == virtSize). 342*f6dc9357SAndroid Build Coastguard Worker Probably original decoder also requires it. 343*f6dc9357SAndroid Build Coastguard Worker But maybe size of last chunk can be non-aligned with blockSize ? */ 344*f6dc9357SAndroid Build Coastguard Worker const UInt32 virtSize = (numBlocks << _blockSizeLog); 345*f6dc9357SAndroid Build Coastguard Worker if (size != virtSize || numBlocks != (virtSize >> _blockSizeLog)) 346*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 347*f6dc9357SAndroid Build Coastguard Worker } 348*f6dc9357SAndroid Build Coastguard Worker else 349*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 350*f6dc9357SAndroid Build Coastguard Worker 351*f6dc9357SAndroid Build Coastguard Worker virtBlock += numBlocks; 352*f6dc9357SAndroid Build Coastguard Worker Chunks.AddInReserved(c); 353*f6dc9357SAndroid Build Coastguard Worker if (type == CHUNK_TYPE_RAW) 354*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_SeekSet(stream, offset)) 355*f6dc9357SAndroid Build Coastguard Worker } 356*f6dc9357SAndroid Build Coastguard Worker } 357*f6dc9357SAndroid Build Coastguard Worker 358*f6dc9357SAndroid Build Coastguard Worker if (i != h.NumChunks) 359*f6dc9357SAndroid Build Coastguard Worker _unexpectedEnd = true; 360*f6dc9357SAndroid Build Coastguard Worker else if (virtBlock != h.NumBlocks) 361*f6dc9357SAndroid Build Coastguard Worker _headersError = true; 362*f6dc9357SAndroid Build Coastguard Worker 363*f6dc9357SAndroid Build Coastguard Worker _phySize = offset; 364*f6dc9357SAndroid Build Coastguard Worker 365*f6dc9357SAndroid Build Coastguard Worker { 366*f6dc9357SAndroid Build Coastguard Worker CChunk c; 367*f6dc9357SAndroid Build Coastguard Worker c.VirtBlock = virtBlock; 368*f6dc9357SAndroid Build Coastguard Worker c.PhyOffset = offset; 369*f6dc9357SAndroid Build Coastguard Worker Chunks.AddInReserved(c); 370*f6dc9357SAndroid Build Coastguard Worker } 371*f6dc9357SAndroid Build Coastguard Worker _virtSize_fromChunks = (UInt64)virtBlock << _blockSizeLog; 372*f6dc9357SAndroid Build Coastguard Worker 373*f6dc9357SAndroid Build Coastguard Worker Stream = stream; 374*f6dc9357SAndroid Build Coastguard Worker return S_OK; 375*f6dc9357SAndroid Build Coastguard Worker } 376*f6dc9357SAndroid Build Coastguard Worker 377*f6dc9357SAndroid Build Coastguard Worker 378*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close()) 379*f6dc9357SAndroid Build Coastguard Worker { 380*f6dc9357SAndroid Build Coastguard Worker Chunks.Clear(); 381*f6dc9357SAndroid Build Coastguard Worker _isArc = false; 382*f6dc9357SAndroid Build Coastguard Worker _virtSize_fromChunks = 0; 383*f6dc9357SAndroid Build Coastguard Worker // _unsupported = false; 384*f6dc9357SAndroid Build Coastguard Worker _headersError = false; 385*f6dc9357SAndroid Build Coastguard Worker _unexpectedEnd = false; 386*f6dc9357SAndroid Build Coastguard Worker _phySize = 0; 387*f6dc9357SAndroid Build Coastguard Worker _methodFlags = 0; 388*f6dc9357SAndroid Build Coastguard Worker 389*f6dc9357SAndroid Build Coastguard Worker _chunkIndexPrev = 0; 390*f6dc9357SAndroid Build Coastguard Worker _packSizeProcessed = 0; 391*f6dc9357SAndroid Build Coastguard Worker 392*f6dc9357SAndroid Build Coastguard Worker // CHandlerImg: 393*f6dc9357SAndroid Build Coastguard Worker Clear_HandlerImg_Vars(); 394*f6dc9357SAndroid Build Coastguard Worker Stream.Release(); 395*f6dc9357SAndroid Build Coastguard Worker return S_OK; 396*f6dc9357SAndroid Build Coastguard Worker } 397*f6dc9357SAndroid Build Coastguard Worker 398*f6dc9357SAndroid Build Coastguard Worker 399*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) 400*f6dc9357SAndroid Build Coastguard Worker { 401*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN 402*f6dc9357SAndroid Build Coastguard Worker *stream = NULL; 403*f6dc9357SAndroid Build Coastguard Worker if (Chunks.Size() < 1) 404*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 405*f6dc9357SAndroid Build Coastguard Worker if (Chunks.Size() < 2 && _virtSize_fromChunks != 0) 406*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 407*f6dc9357SAndroid Build Coastguard Worker // if (_unsupported) return S_FALSE; 408*f6dc9357SAndroid Build Coastguard Worker InitSeekPositions(); 409*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialInStream> streamTemp = this; 410*f6dc9357SAndroid Build Coastguard Worker *stream = streamTemp.Detach(); 411*f6dc9357SAndroid Build Coastguard Worker return S_OK; 412*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END 413*f6dc9357SAndroid Build Coastguard Worker } 414*f6dc9357SAndroid Build Coastguard Worker 415*f6dc9357SAndroid Build Coastguard Worker 416*f6dc9357SAndroid Build Coastguard Worker 417*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed) 418*f6dc9357SAndroid Build Coastguard Worker { 419*f6dc9357SAndroid Build Coastguard Worker processed = 0; 420*f6dc9357SAndroid Build Coastguard Worker if (offset > _phySize || offset + size > _phySize) 421*f6dc9357SAndroid Build Coastguard Worker { 422*f6dc9357SAndroid Build Coastguard Worker // we don't expect these cases, if (_phySize) was set correctly. 423*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 424*f6dc9357SAndroid Build Coastguard Worker } 425*f6dc9357SAndroid Build Coastguard Worker if (offset != _posInArc) 426*f6dc9357SAndroid Build Coastguard Worker { 427*f6dc9357SAndroid Build Coastguard Worker const HRESULT res = Seek2(offset); 428*f6dc9357SAndroid Build Coastguard Worker if (res != S_OK) 429*f6dc9357SAndroid Build Coastguard Worker { 430*f6dc9357SAndroid Build Coastguard Worker Reset_PosInArc(); // we don't trust seek_pos in case of error 431*f6dc9357SAndroid Build Coastguard Worker return res; 432*f6dc9357SAndroid Build Coastguard Worker } 433*f6dc9357SAndroid Build Coastguard Worker } 434*f6dc9357SAndroid Build Coastguard Worker { 435*f6dc9357SAndroid Build Coastguard Worker size_t size2 = size; 436*f6dc9357SAndroid Build Coastguard Worker const HRESULT res = ReadStream(Stream, data, &size2); 437*f6dc9357SAndroid Build Coastguard Worker processed = (UInt32)size2; 438*f6dc9357SAndroid Build Coastguard Worker _packSizeProcessed += size2; 439*f6dc9357SAndroid Build Coastguard Worker _posInArc += size2; 440*f6dc9357SAndroid Build Coastguard Worker if (res != S_OK) 441*f6dc9357SAndroid Build Coastguard Worker Reset_PosInArc(); // we don't trust seek_pos in case of reading error 442*f6dc9357SAndroid Build Coastguard Worker return res; 443*f6dc9357SAndroid Build Coastguard Worker } 444*f6dc9357SAndroid Build Coastguard Worker } 445*f6dc9357SAndroid Build Coastguard Worker 446*f6dc9357SAndroid Build Coastguard Worker 447*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) 448*f6dc9357SAndroid Build Coastguard Worker { 449*f6dc9357SAndroid Build Coastguard Worker if (processedSize) 450*f6dc9357SAndroid Build Coastguard Worker *processedSize = 0; 451*f6dc9357SAndroid Build Coastguard Worker // const unsigned kLimit = (1 << 16) + 1; if (size > kLimit) size = kLimit; // for debug 452*f6dc9357SAndroid Build Coastguard Worker if (_virtPos >= _virtSize_fromChunks) 453*f6dc9357SAndroid Build Coastguard Worker return S_OK; 454*f6dc9357SAndroid Build Coastguard Worker { 455*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = _virtSize_fromChunks - _virtPos; 456*f6dc9357SAndroid Build Coastguard Worker if (size > rem) 457*f6dc9357SAndroid Build Coastguard Worker size = (UInt32)rem; 458*f6dc9357SAndroid Build Coastguard Worker if (size == 0) 459*f6dc9357SAndroid Build Coastguard Worker return S_OK; 460*f6dc9357SAndroid Build Coastguard Worker } 461*f6dc9357SAndroid Build Coastguard Worker 462*f6dc9357SAndroid Build Coastguard Worker UInt32 chunkIndex = _chunkIndexPrev; 463*f6dc9357SAndroid Build Coastguard Worker if (chunkIndex + 1 >= Chunks.Size()) 464*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 465*f6dc9357SAndroid Build Coastguard Worker { 466*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockIndex = (UInt32)(_virtPos >> _blockSizeLog); 467*f6dc9357SAndroid Build Coastguard Worker if (blockIndex < Chunks[chunkIndex ].VirtBlock || 468*f6dc9357SAndroid Build Coastguard Worker blockIndex >= Chunks[chunkIndex + 1].VirtBlock) 469*f6dc9357SAndroid Build Coastguard Worker { 470*f6dc9357SAndroid Build Coastguard Worker unsigned left = 0, right = Chunks.Size() - 1; 471*f6dc9357SAndroid Build Coastguard Worker for (;;) 472*f6dc9357SAndroid Build Coastguard Worker { 473*f6dc9357SAndroid Build Coastguard Worker const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); 474*f6dc9357SAndroid Build Coastguard Worker if (mid == left) 475*f6dc9357SAndroid Build Coastguard Worker break; 476*f6dc9357SAndroid Build Coastguard Worker if (blockIndex < Chunks[mid].VirtBlock) 477*f6dc9357SAndroid Build Coastguard Worker right = mid; 478*f6dc9357SAndroid Build Coastguard Worker else 479*f6dc9357SAndroid Build Coastguard Worker left = mid; 480*f6dc9357SAndroid Build Coastguard Worker } 481*f6dc9357SAndroid Build Coastguard Worker chunkIndex = left; 482*f6dc9357SAndroid Build Coastguard Worker _chunkIndexPrev = chunkIndex; 483*f6dc9357SAndroid Build Coastguard Worker } 484*f6dc9357SAndroid Build Coastguard Worker } 485*f6dc9357SAndroid Build Coastguard Worker 486*f6dc9357SAndroid Build Coastguard Worker const CChunk &c = Chunks[chunkIndex]; 487*f6dc9357SAndroid Build Coastguard Worker const UInt64 offset = _virtPos - ((UInt64)c.VirtBlock << _blockSizeLog); 488*f6dc9357SAndroid Build Coastguard Worker { 489*f6dc9357SAndroid Build Coastguard Worker const UInt32 numBlocks = Chunks[chunkIndex + 1].VirtBlock - c.VirtBlock; 490*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = ((UInt64)numBlocks << _blockSizeLog) - offset; 491*f6dc9357SAndroid Build Coastguard Worker if (size > rem) 492*f6dc9357SAndroid Build Coastguard Worker size = (UInt32)rem; 493*f6dc9357SAndroid Build Coastguard Worker } 494*f6dc9357SAndroid Build Coastguard Worker 495*f6dc9357SAndroid Build Coastguard Worker const UInt64 phyOffset = c.PhyOffset; 496*f6dc9357SAndroid Build Coastguard Worker 497*f6dc9357SAndroid Build Coastguard Worker if (phyOffset >= MY_CHUNK_TYPE_RAW_START) 498*f6dc9357SAndroid Build Coastguard Worker { 499*f6dc9357SAndroid Build Coastguard Worker UInt32 processed = 0; 500*f6dc9357SAndroid Build Coastguard Worker const HRESULT res = ReadPhy(phyOffset + offset, data, size, processed); 501*f6dc9357SAndroid Build Coastguard Worker if (processedSize) 502*f6dc9357SAndroid Build Coastguard Worker *processedSize = processed; 503*f6dc9357SAndroid Build Coastguard Worker _virtPos += processed; 504*f6dc9357SAndroid Build Coastguard Worker return res; 505*f6dc9357SAndroid Build Coastguard Worker } 506*f6dc9357SAndroid Build Coastguard Worker 507*f6dc9357SAndroid Build Coastguard Worker Byte b = 0; 508*f6dc9357SAndroid Build Coastguard Worker 509*f6dc9357SAndroid Build Coastguard Worker if (phyOffset == MY_CHUNK_TYPE_FILL) 510*f6dc9357SAndroid Build Coastguard Worker { 511*f6dc9357SAndroid Build Coastguard Worker const Byte b0 = c.Fill [0]; 512*f6dc9357SAndroid Build Coastguard Worker const Byte b1 = c.Fill [1]; 513*f6dc9357SAndroid Build Coastguard Worker const Byte b2 = c.Fill [2]; 514*f6dc9357SAndroid Build Coastguard Worker const Byte b3 = c.Fill [3]; 515*f6dc9357SAndroid Build Coastguard Worker if (b0 != b1 || 516*f6dc9357SAndroid Build Coastguard Worker b0 != b2 || 517*f6dc9357SAndroid Build Coastguard Worker b0 != b3) 518*f6dc9357SAndroid Build Coastguard Worker { 519*f6dc9357SAndroid Build Coastguard Worker if (processedSize) 520*f6dc9357SAndroid Build Coastguard Worker *processedSize = size; 521*f6dc9357SAndroid Build Coastguard Worker _virtPos += size; 522*f6dc9357SAndroid Build Coastguard Worker Byte *dest = (Byte *)data; 523*f6dc9357SAndroid Build Coastguard Worker while (size >= 4) 524*f6dc9357SAndroid Build Coastguard Worker { 525*f6dc9357SAndroid Build Coastguard Worker dest[0] = b0; 526*f6dc9357SAndroid Build Coastguard Worker dest[1] = b1; 527*f6dc9357SAndroid Build Coastguard Worker dest[2] = b2; 528*f6dc9357SAndroid Build Coastguard Worker dest[3] = b3; 529*f6dc9357SAndroid Build Coastguard Worker dest += 4; 530*f6dc9357SAndroid Build Coastguard Worker size -= 4; 531*f6dc9357SAndroid Build Coastguard Worker } 532*f6dc9357SAndroid Build Coastguard Worker if (size > 0) dest[0] = b0; 533*f6dc9357SAndroid Build Coastguard Worker if (size > 1) dest[1] = b1; 534*f6dc9357SAndroid Build Coastguard Worker if (size > 2) dest[2] = b2; 535*f6dc9357SAndroid Build Coastguard Worker return S_OK; 536*f6dc9357SAndroid Build Coastguard Worker } 537*f6dc9357SAndroid Build Coastguard Worker b = b0; 538*f6dc9357SAndroid Build Coastguard Worker } 539*f6dc9357SAndroid Build Coastguard Worker else if (phyOffset != MY_CHUNK_TYPE_DONT_CARE) 540*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; 541*f6dc9357SAndroid Build Coastguard Worker 542*f6dc9357SAndroid Build Coastguard Worker memset(data, b, size); 543*f6dc9357SAndroid Build Coastguard Worker _virtPos += size; 544*f6dc9357SAndroid Build Coastguard Worker if (processedSize) 545*f6dc9357SAndroid Build Coastguard Worker *processedSize = size; 546*f6dc9357SAndroid Build Coastguard Worker return S_OK; 547*f6dc9357SAndroid Build Coastguard Worker } 548*f6dc9357SAndroid Build Coastguard Worker 549*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I( 550*f6dc9357SAndroid Build Coastguard Worker "Sparse", "simg img", NULL, 0xc2, 551*f6dc9357SAndroid Build Coastguard Worker k_Signature, 552*f6dc9357SAndroid Build Coastguard Worker 0, 553*f6dc9357SAndroid Build Coastguard Worker 0, 554*f6dc9357SAndroid Build Coastguard Worker NULL) 555*f6dc9357SAndroid Build Coastguard Worker 556*f6dc9357SAndroid Build Coastguard Worker }} 557