diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/VhdHandler.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/VhdHandler.cpp | 734 |
1 files changed, 0 insertions, 734 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/VhdHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/VhdHandler.cpp deleted file mode 100644 index 9d1c928e6..000000000 --- a/src/libs/7zip/win/CPP/7zip/Archive/VhdHandler.cpp +++ /dev/null @@ -1,734 +0,0 @@ -// VhdHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/MyString.h" - -#include "Windows/PropVariant.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#define Get16(p) GetBe16(p) -#define Get32(p) GetBe32(p) -#define Get64(p) GetBe64(p) - -#define G32(p, dest) dest = Get32(p); -#define G64(p, dest) dest = Get64(p); - -using namespace NWindows; - -namespace NArchive { -namespace NVhd { - -static const UInt32 kUnusedBlock = 0xFFFFFFFF; - -static const UInt32 kDiskType_Fixed = 2; -static const UInt32 kDiskType_Dynamic = 3; -static const UInt32 kDiskType_Diff = 4; - -static const char *kDiskTypes[] = -{ - "0", - "1", - "Fixed", - "Dynamic", - "Differencing" -}; - -struct CFooter -{ - // UInt32 Features; - // UInt32 FormatVersion; - UInt64 DataOffset; - UInt32 CTime; - UInt32 CreatorApp; - UInt32 CreatorVersion; - UInt32 CreatorHostOS; - // UInt64 OriginalSize; - UInt64 CurrentSize; - UInt32 DiskGeometry; - UInt32 Type; - Byte Id[16]; - Byte SavedState; - - bool IsFixed() const { return Type == kDiskType_Fixed; } - bool ThereIsDynamic() const { return Type == kDiskType_Dynamic || Type == kDiskType_Diff; } - // bool IsSupported() const { return Type == kDiskType_Fixed || Type == kDiskType_Dynamic || Type == kDiskType_Diff; } - UInt32 NumCyls() const { return DiskGeometry >> 16; } - UInt32 NumHeads() const { return (DiskGeometry >> 8) & 0xFF; } - UInt32 NumSectorsPerTrack() const { return DiskGeometry & 0xFF; } - AString GetTypeString() const; - bool Parse(const Byte *p); -}; - -AString CFooter::GetTypeString() const -{ - if (Type < sizeof(kDiskTypes) / sizeof(kDiskTypes[0])) - return kDiskTypes[Type]; - char s[16]; - ConvertUInt32ToString(Type, s); - return s; -} - -static bool CheckBlock(const Byte *p, unsigned size, unsigned checkSumOffset, unsigned zeroOffset) -{ - UInt32 sum = 0; - unsigned i; - for (i = 0; i < checkSumOffset; i++) - sum += p[i]; - for (i = checkSumOffset + 4; i < size; i++) - sum += p[i]; - if (~sum != Get32(p + checkSumOffset)) - return false; - for (i = zeroOffset; i < size; i++) - if (p[i] != 0) - return false; - return true; -} - -bool CFooter::Parse(const Byte *p) -{ - if (memcmp(p, "conectix", 8) != 0) - return false; - // G32(p + 0x08, Features); - // G32(p + 0x0C, FormatVersion); - G64(p + 0x10, DataOffset); - G32(p + 0x18, CTime); - G32(p + 0x1C, CreatorApp); - G32(p + 0x20, CreatorVersion); - G32(p + 0x24, CreatorHostOS); - // G64(p + 0x28, OriginalSize); - G64(p + 0x30, CurrentSize); - G32(p + 0x38, DiskGeometry); - G32(p + 0x3C, Type); - memcpy(Id, p + 0x44, 16); - SavedState = p[0x54]; - return CheckBlock(p, 512, 0x40, 0x55); -} - -/* -struct CParentLocatorEntry -{ - UInt32 Code; - UInt32 DataSpace; - UInt32 DataLen; - UInt64 DataOffset; - - bool Parse(const Byte *p); -}; -bool CParentLocatorEntry::Parse(const Byte *p) -{ - G32(p + 0x00, Code); - G32(p + 0x04, DataSpace); - G32(p + 0x08, DataLen); - G32(p + 0x10, DataOffset); - return (Get32(p + 0x0C) == 0); // Resrved -} -*/ - -struct CDynHeader -{ - // UInt64 DataOffset; - UInt64 TableOffset; - // UInt32 HeaderVersion; - UInt32 NumBlocks; - int BlockSizeLog; - UInt32 ParentTime; - Byte ParentId[16]; - UString ParentName; - // CParentLocatorEntry ParentLocators[8]; - - bool Parse(const Byte *p); - UInt32 NumBitMapSectors() const - { - UInt32 numSectorsInBlock = (1 << (BlockSizeLog - 9)); - return (numSectorsInBlock + 512 * 8 - 1) / (512 * 8); - } -}; - -static int GetLog(UInt32 num) -{ - for (int i = 0; i < 31; i++) - if (((UInt32)1 << i) == num) - return i; - return -1; -} - -bool CDynHeader::Parse(const Byte *p) -{ - if (memcmp(p, "cxsparse", 8) != 0) - return false; - // G64(p + 0x08, DataOffset); - G64(p + 0x10, TableOffset); - // G32(p + 0x18, HeaderVersion); - G32(p + 0x1C, NumBlocks); - BlockSizeLog = GetLog(Get32(p + 0x20)); - if (BlockSizeLog < 9 || BlockSizeLog > 30) - return false; - G32(p + 0x38, ParentTime); - if (Get32(p + 0x3C) != 0) // reserved - return false; - memcpy(ParentId, p + 0x28, 16); - { - const int kNameLength = 256; - wchar_t *s = ParentName.GetBuffer(kNameLength); - for (unsigned i = 0; i < kNameLength; i++) - s[i] = Get16(p + 0x40 + i * 2); - s[kNameLength] = 0; - ParentName.ReleaseBuffer(); - } - /* - for (int i = 0; i < 8; i++) - if (!ParentLocators[i].Parse(p + 0x240 + i * 24)) - return false; - */ - return CheckBlock(p, 1024, 0x24, 0x240 + 8 * 24); -} - -class CHandler: - public IInStream, - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - UInt64 _virtPos; - UInt64 _phyPos; - UInt64 _phyLimit; - - CFooter Footer; - CDynHeader Dyn; - CRecordVector<UInt32> Bat; - CByteBuffer BitMap; - UInt32 BitMapTag; - UInt32 NumUsedBlocks; - CMyComPtr<IInStream> Stream; - CMyComPtr<IInStream> ParentStream; - CHandler *Parent; - - HRESULT Seek(UInt64 offset); - HRESULT InitAndSeek(); - HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size); - - bool NeedParent() const { return Footer.Type == kDiskType_Diff; } - UInt64 GetPackSize() const - { return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; } - - UString GetParentName() const - { - const CHandler *p = this; - UString res; - while (p && p->NeedParent()) - { - if (!res.IsEmpty()) - res += L" -> "; - res += p->Dyn.ParentName; - p = p->Parent; - } - return res; - } - - bool IsOK() const - { - const CHandler *p = this; - while (p->NeedParent()) - { - p = p->Parent; - if (p == 0) - return false; - } - return true; - } - - HRESULT Open3(); - HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level); - -public: - MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream) - - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); -}; - -HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(offset, STREAM_SEEK_SET, NULL); } - -HRESULT CHandler::InitAndSeek() -{ - if (ParentStream) - { - RINOK(Parent->InitAndSeek()); - } - _virtPos = _phyPos = 0; - BitMapTag = kUnusedBlock; - BitMap.SetCapacity(Dyn.NumBitMapSectors() << 9); - return Seek(0); -} - -HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size) -{ - if (offset + size > _phyLimit) - return S_FALSE; - if (offset != _phyPos) - { - _phyPos = offset; - RINOK(Seek(offset)); - } - HRESULT res = ReadStream_FALSE(Stream, data, size); - _phyPos += size; - return res; -} - -HRESULT CHandler::Open3() -{ - RINOK(Stream->Seek(0, STREAM_SEEK_END, &_phyPos)); - if (_phyPos < 512) - return S_FALSE; - const UInt32 kDynSize = 1024; - Byte buf[kDynSize]; - - _phyLimit = _phyPos; - RINOK(ReadPhy(_phyLimit - 512, buf, 512)); - if (!Footer.Parse(buf)) - return S_FALSE; - _phyLimit -= 512; - - if (!Footer.ThereIsDynamic()) - return S_OK; - - RINOK(ReadPhy(0, buf + 512, 512)); - if (memcmp(buf, buf + 512, 512) != 0) - return S_FALSE; - - RINOK(ReadPhy(Footer.DataOffset, buf, kDynSize)); - if (!Dyn.Parse(buf)) - return S_FALSE; - - if (Dyn.NumBlocks >= (UInt32)1 << 31) - return S_FALSE; - if (Footer.CurrentSize == 0) - { - if (Dyn.NumBlocks != 0) - return S_FALSE; - } - else if (((Footer.CurrentSize - 1) >> Dyn.BlockSizeLog) + 1 != Dyn.NumBlocks) - return S_FALSE; - - Bat.Reserve(Dyn.NumBlocks); - while ((UInt32)Bat.Size() < Dyn.NumBlocks) - { - RINOK(ReadPhy(Dyn.TableOffset + (UInt64)Bat.Size() * 4, buf, 512)); - for (UInt32 j = 0; j < 512; j += 4) - { - UInt32 v = Get32(buf + j); - if (v != kUnusedBlock) - NumUsedBlocks++; - Bat.Add(v); - if ((UInt32)Bat.Size() >= Dyn.NumBlocks) - break; - } - } - return S_OK; -} - -STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize != NULL) - *processedSize = 0; - if (_virtPos >= Footer.CurrentSize) - return (Footer.CurrentSize == _virtPos) ? S_OK: E_FAIL; - UInt64 rem = Footer.CurrentSize - _virtPos; - if (size > rem) - size = (UInt32)rem; - if (size == 0) - return S_OK; - UInt32 blockIndex = (UInt32)(_virtPos >> Dyn.BlockSizeLog); - UInt32 blockSectIndex = Bat[blockIndex]; - UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog; - UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); - size = MyMin(blockSize - offsetInBlock, size); - - HRESULT res = S_OK; - if (blockSectIndex == kUnusedBlock) - { - if (ParentStream) - { - RINOK(ParentStream->Seek(_virtPos, STREAM_SEEK_SET, NULL)); - res = ParentStream->Read(data, size, &size); - } - else - memset(data, 0, size); - } - else - { - UInt64 newPos = (UInt64)blockSectIndex << 9; - if (BitMapTag != blockIndex) - { - RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.GetCapacity())); - BitMapTag = blockIndex; - } - RINOK(ReadPhy(newPos + BitMap.GetCapacity() + offsetInBlock, data, size)); - for (UInt32 cur = 0; cur < size;) - { - UInt32 rem = MyMin(0x200 - (offsetInBlock & 0x1FF), size - cur); - UInt32 bmi = offsetInBlock >> 9; - if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0) - { - if (ParentStream) - { - RINOK(ParentStream->Seek(_virtPos + cur, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(ParentStream, (Byte *)data + cur, rem)); - } - else - { - const Byte *p = (const Byte *)data + cur; - for (UInt32 i = 0; i < rem; i++) - if (p[i] != 0) - return S_FALSE; - } - } - offsetInBlock += rem; - cur += rem; - } - } - if (processedSize != NULL) - *processedSize = size; - _virtPos += size; - return res; -} - -STDMETHODIMP CHandler::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) -{ - switch(seekOrigin) - { - case STREAM_SEEK_SET: _virtPos = offset; break; - case STREAM_SEEK_CUR: _virtPos += offset; break; - case STREAM_SEEK_END: _virtPos = Footer.CurrentSize + offset; break; - default: return STG_E_INVALIDFUNCTION; - } - if (newPosition) - *newPosition = _virtPos; - return S_OK; -} - -enum -{ - kpidParent = kpidUserDefined, - kpidSavedState -}; - -STATPROPSTG kArcProps[] = -{ - { NULL, kpidSize, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidClusterSize, VT_UI8}, - { NULL, kpidMethod, VT_BSTR}, - { L"Parent", kpidParent, VT_BSTR}, - { NULL, kpidCreatorApp, VT_BSTR}, - { NULL, kpidHostOS, VT_BSTR}, - { L"Saved State", kpidSavedState, VT_BOOL}, - { NULL, kpidId, VT_BSTR} - }; - -STATPROPSTG kProps[] = -{ - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME} - - /* - { NULL, kpidNumCyls, VT_UI4}, - { NULL, kpidNumHeads, VT_UI4}, - { NULL, kpidSectorsPerTrack, VT_UI4} - */ -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_WITH_NAME - -// VHD start time: 2000-01-01 -static const UInt64 kVhdTimeStartValue = (UInt64)3600 * 24 * (399 * 365 + 24 * 4); - -static void VhdTimeToFileTime(UInt32 vhdTime, NCOM::CPropVariant &prop) -{ - FILETIME ft, utc; - UInt64 v = (kVhdTimeStartValue + vhdTime) * 10000000; - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); - // specification says that it's UTC time, but Virtual PC 6 writes local time. Why? - LocalFileTimeToFileTime(&ft, &utc); - prop = utc; -} - -static void StringToAString(char *dest, UInt32 s) -{ - for (int i = 24; i >= 0; i -= 8) - { - Byte b = (Byte)((s >> i) & 0xFF); - if (b < 0x20 || b > 0x7F) - break; - *dest++ = b; - } - *dest = 0; -} - -static void ConvertByteToHex(unsigned value, char *s) -{ - for (int i = 0; i < 2; i++) - { - unsigned t = value & 0xF; - value >>= 4; - s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); - } -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch(propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break; - case kpidClusterSize: if (Footer.ThereIsDynamic()) prop = (UInt32)1 << Dyn.BlockSizeLog; break; - case kpidMethod: - { - AString s = Footer.GetTypeString(); - if (NeedParent()) - { - s += " -> "; - const CHandler *p = this; - while (p != 0 && p->NeedParent()) - p = p->Parent; - if (p == 0) - s += '?'; - else - s += p->Footer.GetTypeString(); - } - prop = s; - break; - } - case kpidCreatorApp: - { - char s[16]; - StringToAString(s, Footer.CreatorApp); - AString res = s; - res.Trim(); - ConvertUInt32ToString(Footer.CreatorVersion >> 16, s); - res += ' '; - res += s; - res += '.'; - ConvertUInt32ToString(Footer.CreatorVersion & 0xFFFF, s); - res += s; - prop = res; - break; - } - case kpidHostOS: - { - if (Footer.CreatorHostOS == 0x5769326b) - prop = "Windows"; - else - { - char s[16]; - StringToAString(s, Footer.CreatorHostOS); - prop = s; - } - break; - } - case kpidId: - { - char s[32 + 4]; - for (int i = 0; i < 16; i++) - ConvertByteToHex(Footer.Id[i], s + i * 2); - s[32] = 0; - prop = s; - break; - } - case kpidSavedState: prop = Footer.SavedState ? true : false; break; - case kpidParent: if (NeedParent()) prop = GetParentName(); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level) -{ - Close(); - Stream = stream; - if (level > 32) - return S_FALSE; - RINOK(Open3()); - if (child && memcmp(child->Dyn.ParentId, Footer.Id, 16) != 0) - return S_FALSE; - if (Footer.Type != kDiskType_Diff) - return S_OK; - CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; - if (openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback) != S_OK) - return S_FALSE; - CMyComPtr<IInStream> nextStream; - HRESULT res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream); - if (res == S_FALSE) - return S_OK; - RINOK(res); - - Parent = new CHandler; - ParentStream = Parent; - return Parent->Open2(nextStream, this, openArchiveCallback, level + 1); -} - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * openArchiveCallback) -{ - COM_TRY_BEGIN - { - HRESULT res; - try - { - res = Open2(stream, NULL, openArchiveCallback, 0); - if (res == S_OK) - return S_OK; - } - catch(...) - { - Close(); - throw; - } - Close(); - return res; - } - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - Bat.Clear(); - NumUsedBlocks = 0; - Parent = 0; - Stream.Release(); - ParentStream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = 1; - return S_OK; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - - switch(propID) - { - case kpidSize: prop = Footer.CurrentSize; break; - case kpidPackSize: prop = GetPackSize(); break; - case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break; - /* - case kpidNumCyls: prop = Footer.NumCyls(); break; - case kpidNumHeads: prop = Footer.NumHeads(); break; - case kpidSectorsPerTrack: prop = Footer.NumSectorsPerTrack(); break; - */ - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - RINOK(extractCallback->SetTotal(Footer.CurrentSize)); - CMyComPtr<ISequentialOutStream> outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &outStream, askMode)); - if (!testMode && !outStream) - return S_OK; - RINOK(extractCallback->PrepareOperation(askMode)); - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr<ICompressProgressInfo> progress = lps; - lps->Init(extractCallback, false); - - int res = NExtract::NOperationResult::kDataError; - CMyComPtr<ISequentialInStream> inStream; - HRESULT hres = GetStream(0, &inStream); - if (hres == S_FALSE) - res = NExtract::NOperationResult::kUnSupportedMethod; - else - { - RINOK(hres); - HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress); - if (hres == S_OK) - { - if (copyCoderSpec->TotalSize == Footer.CurrentSize) - res = NExtract::NOperationResult::kOK; - } - else - { - if (hres != S_FALSE) - { - RINOK(hres); - } - } - } - outStream.Release(); - return extractCallback->SetOperationResult(res); - COM_TRY_END -} - -STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - if (Footer.IsFixed()) - { - CLimitedInStream *streamSpec = new CLimitedInStream; - CMyComPtr<ISequentialInStream> streamTemp = streamSpec; - streamSpec->SetStream(Stream); - streamSpec->InitAndSeek(0, Footer.CurrentSize); - RINOK(streamSpec->SeekToStart()); - *stream = streamTemp.Detach(); - return S_OK; - } - if (!Footer.ThereIsDynamic() || !IsOK()) - return S_FALSE; - CMyComPtr<ISequentialInStream> streamTemp = this; - RINOK(InitAndSeek()); - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -static IInArchive *CreateArc() { return new CHandler; } - -static CArcInfo g_ArcInfo = - { L"VHD", L"vhd", L".mbr", 0xDC, { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 }, 10, false, CreateArc, 0 }; - -REGISTER_ARC(Vhd) - -}} |