summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp')
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp996
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)
-
-}}