diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp | 996 |
1 files changed, 0 insertions, 996 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp deleted file mode 100644 index 1c374a444..000000000 --- a/src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp +++ /dev/null @@ -1,996 +0,0 @@ -// FatHandler.cpp - -#include "StdAfx.h" - -// #include <stdio.h> - -#include "../../../C/CpuArch.h" - -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/MyCom.h" -#include "Common/StringConvert.h" - -#include "Windows/PropVariant.h" -#include "Windows/Time.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#include "Common/DummyOutStream.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) - -#define PRF(x) /* x */ - -namespace NArchive { -namespace NFat { - -static const UInt32 kFatItemUsedByDirMask = (UInt32)1 << 31; - -struct CHeader -{ - UInt32 NumSectors; - UInt16 NumReservedSectors; - Byte NumFats; - UInt32 NumFatSectors; - UInt32 RootDirSector; - UInt32 NumRootDirSectors; - UInt32 DataSector; - - UInt32 FatSize; - UInt32 BadCluster; - - Byte NumFatBits; - Byte SectorSizeLog; - Byte SectorsPerClusterLog; - Byte ClusterSizeLog; - - UInt16 SectorsPerTrack; - UInt16 NumHeads; - UInt32 NumHiddenSectors; - - bool VolFieldsDefined; - - UInt32 VolId; - // Byte VolName[11]; - // Byte FileSys[8]; - - // Byte OemName[5]; - Byte MediaType; - - // 32-bit FAT - UInt16 Flags; - UInt16 FsInfoSector; - UInt32 RootCluster; - - bool IsFat32() const { return NumFatBits == 32; } - UInt64 GetPhySize() const { return (UInt64)NumSectors << SectorSizeLog; } - UInt32 SectorSize() const { return (UInt32)1 << SectorSizeLog; } - UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; } - UInt32 ClusterToSector(UInt32 c) const { return DataSector + ((c - 2) << SectorsPerClusterLog); } - UInt32 IsEoc(UInt32 c) const { return c > BadCluster; } - UInt32 IsEocAndUnused(UInt32 c) const { return c > BadCluster && (c & kFatItemUsedByDirMask) == 0; } - UInt32 IsValidCluster(UInt32 c) const { return c >= 2 && c < FatSize; } - UInt32 SizeToSectors(UInt32 size) const { return (size + SectorSize() - 1) >> SectorSizeLog; } - UInt32 CalcFatSizeInSectors() const { return SizeToSectors((FatSize * (NumFatBits / 4) + 1) / 2); } - - UInt32 GetFatSector() const - { - UInt32 index = (IsFat32() && (Flags & 0x80) != 0) ? (Flags & 0xF) : 0; - if (index > NumFats) - index = 0; - return NumReservedSectors + index * NumFatSectors; - } - - UInt64 GetFilePackSize(UInt32 unpackSize) const - { - UInt64 mask = ClusterSize() - 1; - return (unpackSize + mask) & ~mask; - } - - UInt32 GetNumClusters(UInt32 size) const - { return (UInt32)(((UInt64)size + ClusterSize() - 1) >> ClusterSizeLog); } - - bool Parse(const Byte *p); -}; - -static int GetLog(UInt32 num) -{ - for (int i = 0; i < 31; i++) - if (((UInt32)1 << i) == num) - return i; - return -1; -} - -bool CHeader::Parse(const Byte *p) -{ - if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) - return false; - - int codeOffset = 0; - switch (p[0]) - { - case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break; - case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break; - default: return false; - } - { - int s = GetLog(Get16(p + 11)); - if (s < 9 || s > 12) - return false; - SectorSizeLog = (Byte)s; - s = GetLog(p[13]); - if (s < 0) - return false; - SectorsPerClusterLog = (Byte)s; - ClusterSizeLog = SectorSizeLog + SectorsPerClusterLog; - } - - NumReservedSectors = Get16(p + 14); - if (NumReservedSectors == 0) - return false; - - NumFats = p[16]; - if (NumFats < 1 || NumFats > 4) - return false; - - UInt16 numRootDirEntries = Get16(p + 17); - if (numRootDirEntries == 0) - { - if (codeOffset < 90) - return false; - NumFatBits = 32; - NumRootDirSectors = 0; - } - else - { - if (codeOffset < 62) - return false; - NumFatBits = 0; - UInt32 mask = (1 << (SectorSizeLog - 5)) - 1; - if ((numRootDirEntries & mask) != 0) - return false; - NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5); - } - - NumSectors = Get16(p + 19); - if (NumSectors == 0) - NumSectors = Get32(p + 32); - else if (IsFat32()) - return false; - - MediaType = p[21]; - NumFatSectors = Get16(p + 22); - SectorsPerTrack = Get16(p + 24); - NumHeads = Get16(p + 26); - NumHiddenSectors = Get32(p + 28); - - // memcpy(OemName, p + 3, 5); - - p += 36; - if (IsFat32()) - { - if (NumFatSectors != 0) - return false; - NumFatSectors = Get32(p); - if (NumFatSectors >= (1 << 24)) - return false; - - Flags = Get16(p + 4); - if (Get16(p + 6) != 0) - return false; - RootCluster = Get32(p + 8); - FsInfoSector = Get16(p + 12); - for (int i = 16; i < 28; i++) - if (p[i] != 0) - return false; - p += 28; - } - - // DriveNumber = p[0]; - VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig - VolId = Get32(p + 3); - // memcpy(VolName, p + 7, 11); - // memcpy(FileSys, p + 18, 8); - - if (NumFatSectors == 0) - return false; - RootDirSector = NumReservedSectors + NumFatSectors * NumFats; - DataSector = RootDirSector + NumRootDirSectors; - if (NumSectors < DataSector) - return false; - UInt32 numDataSectors = NumSectors - DataSector; - UInt32 numClusters = numDataSectors >> SectorsPerClusterLog; - - BadCluster = 0x0FFFFFF7; - if (numClusters < 0xFFF5) - { - if (NumFatBits == 32) - return false; - NumFatBits = (numClusters < 0xFF5) ? 12: 16; - BadCluster &= ((1 << NumFatBits) - 1); - } - else if (NumFatBits != 32) - return false; - - FatSize = numClusters + 2; - if (FatSize > BadCluster || CalcFatSizeInSectors() > NumFatSectors) - return false; - return true; -} - -struct CItem -{ - UString UName; - char DosName[11]; - Byte CTime2; - UInt32 CTime; - UInt32 MTime; - UInt16 ADate; - Byte Attrib; - Byte Flags; - UInt32 Size; - UInt32 Cluster; - Int32 Parent; - - // NT uses Flags to store Low Case status - bool NameIsLow() const { return (Flags & 0x8) != 0; } - bool ExtIsLow() const { return (Flags & 0x10) != 0; } - bool IsDir() const { return (Attrib & 0x10) != 0; } - UString GetShortName() const; - UString GetName() const; - UString GetVolName() const; -}; - -static int CopyAndTrim(char *dest, const char *src, int size, bool toLower) -{ - int i; - memcpy(dest, src, size); - if (toLower) - for (i = 0; i < size; i++) - { - char c = dest[i]; - if (c >= 'A' && c <= 'Z') - dest[i] = c + 0x20; - } - for (i = size - 1; i >= 0 && dest[i] == ' '; i--); - return i + 1; -} - -static UString FatStringToUnicode(const char *s) -{ - return MultiByteToUnicodeString(s, CP_OEMCP); -} - -UString CItem::GetShortName() const -{ - char s[16]; - int i = CopyAndTrim(s, DosName, 8, NameIsLow()); - s[i++] = '.'; - int j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow()); - if (j == 0) - j--; - s[i + j] = 0; - return FatStringToUnicode(s); -} - -UString CItem::GetName() const -{ - if (!UName.IsEmpty()) - return UName; - return GetShortName(); -} - -UString CItem::GetVolName() const -{ - if (!UName.IsEmpty()) - return UName; - char s[12]; - int i = CopyAndTrim(s, DosName, 11, false); - s[i] = 0; - return FatStringToUnicode(s); -} - -struct CDatabase -{ - CHeader Header; - CObjectVector<CItem> Items; - UInt32 *Fat; - CMyComPtr<IInStream> InStream; - IArchiveOpenCallback *OpenCallback; - - UInt32 NumFreeClusters; - bool VolItemDefined; - CItem VolItem; - UInt32 NumDirClusters; - CByteBuffer ByteBuf; - UInt64 NumCurUsedBytes; - - CDatabase(): Fat(0) {} - ~CDatabase() { ClearAndClose(); } - - void Clear(); - void ClearAndClose(); - HRESULT OpenProgressFat(bool changeTotal = true); - HRESULT OpenProgress(); - - UString GetItemPath(Int32 index) const; - HRESULT Open(); - HRESULT ReadDir(Int32 parent, UInt32 cluster, int level); - - UInt64 GetHeadersSize() const - { - return (UInt64)(Header.DataSector + (NumDirClusters << Header.SectorsPerClusterLog)) << Header.SectorSizeLog; - } - HRESULT SeekToSector(UInt32 sector); - HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); } -}; - -HRESULT CDatabase::SeekToSector(UInt32 sector) -{ - return InStream->Seek((UInt64)sector << Header.SectorSizeLog, STREAM_SEEK_SET, NULL); -} - -void CDatabase::Clear() -{ - VolItemDefined = false; - NumDirClusters = 0; - NumCurUsedBytes = 0; - - Items.Clear(); - delete []Fat; - Fat = 0; -} - -void CDatabase::ClearAndClose() -{ - Clear(); - InStream.Release(); -} - -HRESULT CDatabase::OpenProgressFat(bool changeTotal) -{ - if (!OpenCallback) - return S_OK; - if (changeTotal) - { - UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) + - ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog); - RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes)); - } - return OpenCallback->SetCompleted(NULL, &NumCurUsedBytes); -} - -HRESULT CDatabase::OpenProgress() -{ - if (!OpenCallback) - return S_OK; - UInt64 numItems = Items.Size(); - return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes); -} - -UString CDatabase::GetItemPath(Int32 index) const -{ - const CItem *item = &Items[index]; - UString name = item->GetName(); - for (;;) - { - index = item->Parent; - if (index < 0) - return name; - item = &Items[index]; - name = item->GetName() + WCHAR_PATH_SEPARATOR + name; - } -} - -static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, int numChars) -{ - for (int i = 0; i < numChars; i++) - { - wchar_t c = Get16(p + i * 2); - if (c != 0 && c != 0xFFFF) - *dest++ = c; - } - *dest = 0; - return dest; -} - -HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level) -{ - int startIndex = Items.Size(); - if (startIndex >= (1 << 30) || level > 256) - return S_FALSE; - - UInt32 sectorIndex = 0; - UInt32 blockSize = Header.ClusterSize(); - bool clusterMode = (Header.IsFat32() || parent >= 0); - if (!clusterMode) - { - blockSize = Header.SectorSize(); - RINOK(SeekToSector(Header.RootDirSector)); - } - - ByteBuf.SetCapacity(blockSize); - UString curName; - int checkSum = -1; - int numLongRecords = -1; - for (UInt32 pos = blockSize;; pos += 32) - { - if (pos == blockSize) - { - pos = 0; - - if ((NumDirClusters & 0xFF) == 0) - { - RINOK(OpenProgress()); - } - - if (clusterMode) - { - if (Header.IsEoc(cluster)) - break; - if (!Header.IsValidCluster(cluster)) - return S_FALSE; - PRF(printf("\nCluster = %4X", cluster)); - RINOK(SeekToCluster(cluster)); - UInt32 newCluster = Fat[cluster]; - if ((newCluster & kFatItemUsedByDirMask) != 0) - return S_FALSE; - Fat[cluster] |= kFatItemUsedByDirMask; - cluster = newCluster; - NumDirClusters++; - NumCurUsedBytes += Header.ClusterSize(); - } - else if (sectorIndex++ >= Header.NumRootDirSectors) - break; - - RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)); - } - const Byte *p = ByteBuf + pos; - if (p[0] == 0) - { - /* - // FreeDOS formats FAT partition with cluster chain longer than required. - if (clusterMode && !Header.IsEoc(cluster)) - return S_FALSE; - */ - break; - } - if (p[0] == 0xE5) - { - if (numLongRecords > 0) - return S_FALSE; - continue; - } - - Byte attrib = p[11]; - if ((attrib & 0x3F) == 0xF) - { - if (p[0] > 0x7F || Get16(p + 26) != 0) - return S_FALSE; - int longIndex = p[0] & 0x3F; - if (longIndex == 0) - return S_FALSE; - bool isLast = (p[0] & 0x40) != 0; - if (numLongRecords < 0) - { - if (!isLast) - return S_FALSE; - numLongRecords = longIndex; - } - else if (isLast || numLongRecords != longIndex) - return S_FALSE; - - numLongRecords--; - - if (p[12] == 0) - { - wchar_t nameBuf[14]; - wchar_t *dest; - - dest = AddSubStringToName(nameBuf, p + 1, 5); - dest = AddSubStringToName(dest, p + 14, 6); - AddSubStringToName(dest, p + 28, 2); - curName = nameBuf + curName; - if (isLast) - checkSum = p[13]; - if (checkSum != p[13]) - return S_FALSE; - } - } - else - { - if (numLongRecords > 0) - return S_FALSE; - CItem item; - memcpy(item.DosName, p, 11); - - if (checkSum >= 0) - { - Byte sum = 0; - for (int i = 0; i < 11; i++) - sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]; - if (sum == checkSum) - item.UName = curName; - } - - if (item.DosName[0] == 5) - item.DosName[0] = (char)(Byte)0xE5; - item.Attrib = attrib; - item.Flags = p[12]; - item.Size = Get32(p + 28); - item.Cluster = Get16(p + 26); - if (Header.NumFatBits > 16) - item.Cluster |= ((UInt32)Get16(p + 20) << 16); - else - { - // OS/2 and WinNT probably can store EA (extended atributes) in that field. - } - - item.CTime = Get32(p + 14); - item.CTime2 = p[13]; - item.ADate = Get16(p + 18); - item.MTime = Get32(p + 22); - item.Parent = parent; - - if (attrib == 8) - { - VolItem = item; - VolItemDefined = true; - } - else - if (memcmp(item.DosName, ". ", 11) != 0 && - memcmp(item.DosName, ".. ", 11) != 0) - { - if (!item.IsDir()) - NumCurUsedBytes += Header.GetFilePackSize(item.Size); - Items.Add(item); - PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1))); - } - numLongRecords = -1; - curName.Empty(); - checkSum = -1; - } - } - - int finishIndex = Items.Size(); - for (int i = startIndex; i < finishIndex; i++) - { - const CItem &item = Items[i]; - if (item.IsDir()) - { - PRF(printf("\n%S", GetItemPath(i))); - RINOK(CDatabase::ReadDir(i, item.Cluster, level + 1)); - } - } - return S_OK; -} - -HRESULT CDatabase::Open() -{ - Clear(); - bool numFreeClustersDefined = false; - { - static const UInt32 kHeaderSize = 512; - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)); - if (!Header.Parse(buf)) - return S_FALSE; - UInt64 fileSize; - RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize)); - - /* we comment that check to support truncated images */ - /* - if (fileSize < Header.GetPhySize()) - return S_FALSE; - */ - - if (Header.IsFat32()) - { - SeekToSector(Header.FsInfoSector); - RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)); - if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA) - return S_FALSE; - if (Get32(buf) == 0x41615252 && Get32(buf + 484) == 0x61417272) - { - NumFreeClusters = Get32(buf + 488); - numFreeClustersDefined = (NumFreeClusters <= Header.FatSize); - } - } - } - - // numFreeClustersDefined = false; // to recalculate NumFreeClusters - if (!numFreeClustersDefined) - NumFreeClusters = 0; - - CByteBuffer byteBuf; - Fat = new UInt32[Header.FatSize]; - - RINOK(OpenProgressFat()); - RINOK(SeekToSector(Header.GetFatSector())); - if (Header.NumFatBits == 32) - { - const UInt32 kBufSize = (1 << 15); - byteBuf.SetCapacity(kBufSize); - for (UInt32 i = 0; i < Header.FatSize;) - { - UInt32 size = Header.FatSize - i; - const UInt32 kBufSize32 = kBufSize / 4; - if (size > kBufSize32) - size = kBufSize32; - UInt32 readSize = Header.SizeToSectors(size * 4) << Header.SectorSizeLog; - RINOK(ReadStream_FALSE(InStream, byteBuf, readSize)); - NumCurUsedBytes += readSize; - - const UInt32 *src = (const UInt32 *)(const Byte *)byteBuf; - UInt32 *dest = Fat + i; - if (numFreeClustersDefined) - for (UInt32 j = 0; j < size; j++) - dest[j] = Get32(src + j) & 0x0FFFFFFF; - else - { - UInt32 numFreeClusters = 0; - for (UInt32 j = 0; j < size; j++) - { - UInt32 v = Get32(src + j) & 0x0FFFFFFF; - numFreeClusters += (UInt32)(v - 1) >> 31; - dest[j] = v; - } - NumFreeClusters += numFreeClusters; - } - i += size; - if ((i & 0xFFFFF) == 0) - { - RINOK(OpenProgressFat(!numFreeClustersDefined)); - } - } - } - else - { - const UInt32 kBufSize = (UInt32)Header.CalcFatSizeInSectors() << Header.SectorSizeLog; - NumCurUsedBytes += kBufSize; - byteBuf.SetCapacity(kBufSize); - Byte *p = byteBuf; - RINOK(ReadStream_FALSE(InStream, p, kBufSize)); - UInt32 fatSize = Header.FatSize; - UInt32 *fat = &Fat[0]; - if (Header.NumFatBits == 16) - for (UInt32 j = 0; j < fatSize; j++) - fat[j] = Get16(p + j * 2); - else - for (UInt32 j = 0; j < fatSize; j++) - fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF; - - if (!numFreeClustersDefined) - { - UInt32 numFreeClusters = 0; - for (UInt32 i = 0; i < fatSize; i++) - numFreeClusters += (UInt32)(fat[i] - 1) >> 31; - NumFreeClusters = numFreeClusters; - } - } - - RINOK(OpenProgressFat()); - - if ((Fat[0] & 0xFF) != Header.MediaType) - return S_FALSE; - - return ReadDir(-1, Header.RootCluster, 0); -} - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp, - CDatabase -{ -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - const CItem &item = Items[index]; - CClusterInStream *streamSpec = new CClusterInStream; - CMyComPtr<ISequentialInStream> streamTemp = streamSpec; - streamSpec->Stream = InStream; - streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog; - streamSpec->BlockSizeLog = Header.ClusterSizeLog; - streamSpec->Size = item.Size; - - UInt32 numClusters = Header.GetNumClusters(item.Size); - streamSpec->Vector.Reserve(numClusters); - UInt32 cluster = item.Cluster; - UInt32 size = item.Size; - - if (size == 0) - { - if (cluster != 0) - return S_FALSE; - } - else - { - UInt32 clusterSize = Header.ClusterSize(); - for (;; size -= clusterSize) - { - if (!Header.IsValidCluster(cluster)) - return S_FALSE; - streamSpec->Vector.Add(cluster - 2); - cluster = Fat[cluster]; - if (size <= clusterSize) - break; - } - if (!Header.IsEocAndUnused(cluster)) - return S_FALSE; - } - RINOK(streamSpec->InitAndSeek()); - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -STATPROPSTG kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI8}, - { NULL, kpidShortName, VT_BSTR} -}; - -enum -{ - kpidNumFats = kpidUserDefined - // kpidOemName, - // kpidVolName, - // kpidFileSysType -}; - -STATPROPSTG kArcProps[] = -{ - { NULL, kpidFileSystem, VT_BSTR}, - { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidFreeSpace, VT_UI8}, - { NULL, kpidHeadersSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidVolumeName, VT_BSTR}, - - { L"FATs", kpidNumFats, VT_UI4}, - { NULL, kpidSectorSize, VT_UI4}, - { NULL, kpidId, VT_UI4}, - // { L"OEM Name", kpidOemName, VT_BSTR}, - // { L"Volume Name", kpidVolName, VT_BSTR}, - // { L"File System Type", kpidFileSysType, VT_BSTR} - // { NULL, kpidSectorsPerTrack, VT_UI4}, - // { NULL, kpidNumHeads, VT_UI4}, - // { NULL, kpidHiddenSectors, VT_UI4} -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_WITH_NAME - -static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop) -{ - FILETIME localFileTime, utc; - if (NWindows::NTime::DosTimeToFileTime(dosTime, localFileTime)) - if (LocalFileTimeToFileTime(&localFileTime, &utc)) - { - UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime; - t64 += ms10 * 100000; - utc.dwLowDateTime = (DWORD)t64; - utc.dwHighDateTime = (DWORD)(t64 >> 32); - prop = utc; - } -} - -/* -static void StringToProp(const Byte *src, int size, NWindows::NCOM::CPropVariant &prop) -{ - char dest[32]; - memcpy(dest, src, size); - dest[size] = 0; - prop = FatStringToUnicode(dest); -} - -#define STRING_TO_PROP(s, p) StringToProp(s, sizeof(s), prop) -*/ - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) - { - case kpidFileSystem: - { - wchar_t s[32] = { L'F', L'A', L'T' }; - ConvertUInt32ToString(Header.NumFatBits, s + 3); - prop = s; - break; - } - case kpidClusterSize: prop = Header.ClusterSize(); break; - case kpidPhySize: prop = Header.GetPhySize(); break; - case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break; - case kpidHeadersSize: prop = GetHeadersSize(); break; - case kpidMTime: if (VolItemDefined) FatTimeToProp(VolItem.MTime, 0, prop); break; - case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break; - case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break; - case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; - // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break; - // case kpidNumHeads: prop = Header.NumHeads; break; - // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break; - case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break; - // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break; - // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break; - // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = Items[index]; - switch(propID) - { - case kpidPath: prop = GetItemPath(index); break; - case kpidShortName: prop = item.GetShortName(); break; - case kpidIsDir: prop = item.IsDir(); break; - case kpidMTime: FatTimeToProp(item.MTime, 0, prop); break; - case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break; - case kpidATime: FatTimeToProp(((UInt32)item.ADate << 16), 0, prop); break; - case kpidAttrib: prop = (UInt32)item.Attrib; break; - case kpidSize: if (!item.IsDir()) prop = item.Size; break; - case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - { - OpenCallback = callback; - InStream = stream; - HRESULT res; - try - { - res = CDatabase::Open(); - if (res == S_OK) - return S_OK; - } - catch(...) - { - Close(); - throw; - } - Close(); - return res; - } - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - ClearAndClose(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); - if (allFilesMode) - numItems = Items.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - UInt64 totalSize = 0; - for (i = 0; i < numItems; i++) - { - const CItem &item = Items[allFilesMode ? i : indices[i]]; - if (!item.IsDir()) - totalSize += item.Size; - } - RINOK(extractCallback->SetTotal(totalSize)); - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr<ICompressProgressInfo> progress = lps; - lps->Init(extractCallback, false); - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr<ISequentialOutStream> realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = Items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - - totalPackSize += Header.GetFilePackSize(item.Size); - totalSize += item.Size; - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - - outStreamSpec->SetStream(realOutStream); - realOutStream.Release(); - outStreamSpec->Init(); - - int res = NExtract::NOperationResult::kDataError; - CMyComPtr<ISequentialInStream> inStream; - HRESULT hres = GetStream(index, &inStream); - if (hres != S_FALSE) - { - RINOK(hres); - if (inStream) - { - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - if (copyCoderSpec->TotalSize == item.Size) - res = NExtract::NOperationResult::kOK; - } - } - outStreamSpec->ReleaseStream(); - RINOK(extractCallback->SetOperationResult(res)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = Items.Size(); - return S_OK; -} - -static IInArchive *CreateArc() { return new CHandler; } - -static CArcInfo g_ArcInfo = - { L"FAT", L"fat img", 0, 0xDA, { 0x55, 0xAA }, 2, false, CreateArc, 0 }; - -REGISTER_ARC(Fat) - -}} |