summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/win/CPP/7zip/Archive/Hfs
diff options
context:
space:
mode:
authorkh1 <karsten.heimrich@nokia.com>2012-03-15 14:53:47 +0100
committerKarsten Heimrich <karsten.heimrich@nokia.com>2012-03-19 16:14:04 +0100
commitbe3b47d0d504a3409ce66bd77bb8c0acff87c4f5 (patch)
tree09dfb02d484a4f395991972b828da71400fb761a /src/libs/7zip/win/CPP/7zip/Archive/Hfs
parent9fd62353cf7f973d78cd2093328ac15b5c4980b6 (diff)
Reorganize the tree, have better ifw.pri. Shadow build support.
Change-Id: I01fb12537f863ed0744979973c7e4153889cc5cb Reviewed-by: Tim Jenssen <tim.jenssen@nokia.com>
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/Hfs')
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.cpp243
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.h26
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.cpp480
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.h154
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsRegister.cpp13
5 files changed, 916 insertions, 0 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.cpp
new file mode 100644
index 000000000..f226458d4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.cpp
@@ -0,0 +1,243 @@
+// HfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Windows/PropVariant.h"
+#include "../../Common/StreamUtils.h"
+#include "HfsHandler.h"
+
+namespace NArchive {
+namespace NHfs {
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidFreeSpace, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop)
+{
+ FILETIME ft;
+ HfsTimeToFileTime(hfsTime, ft);
+ prop = ft;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod: prop = _db.Header.IsHfsX() ? L"HFSX" : L"HFS+"; break;
+ case kpidClusterSize: prop = (UInt32)1 << _db.Header.BlockSizeLog; break;
+ case kpidFreeSpace: prop = (UInt64)_db.Header.NumFreeBlocks << _db.Header.BlockSizeLog; break;
+ case kpidMTime: HfsTimeToProp(_db.Header.MTime, prop); break;
+ case kpidCTime:
+ {
+ FILETIME localFt, ft;
+ HfsTimeToFileTime(_db.Header.CTime, localFt);
+ if (LocalFileTimeToFileTime(&localFt, &ft))
+ prop = ft;
+ 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 = _db.Items[index];
+ switch(propID)
+ {
+ case kpidPath: prop = _db.GetItemPath(index); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+
+ case kpidCTime: HfsTimeToProp(item.CTime, prop); break;
+ case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
+ case kpidATime: HfsTimeToProp(item.ATime, prop); break;
+
+ case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumBlocks << _db.Header.BlockSizeLog; break;
+ case kpidSize: if (!item.IsDir()) prop = item.Size; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+public:
+ HRESULT SetTotal(UInt64 numFiles);
+ HRESULT SetCompleted(UInt64 numFiles);
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}
+};
+
+HRESULT CProgressImp::SetTotal(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetTotal(&numFiles, NULL);
+ return S_OK;
+}
+
+HRESULT CProgressImp::SetCompleted(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetCompleted(&numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ CProgressImp progressImp(callback);
+ HRESULT res = _db.Open(inStream, &progressImp);
+ if (res == E_ABORT)
+ return res;
+ if (res != S_OK)
+ return S_FALSE;
+ _stream = inStream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _db.Clear();
+ 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 = _db.Items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = _db.Items[allFilesMode ? i : indices[i]];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 currentTotalSize = 0, currentItemSize = 0;
+
+ CByteBuffer buf;
+ const UInt32 kBufSize = (1 << 16);
+ buf.SetCapacity(kBufSize);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ RINOK(extractCallback->SetCompleted(&currentTotalSize));
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _db.Items[index];
+ currentItemSize = 0;
+ if (!item.IsDir())
+ currentItemSize = item.Size;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ UInt64 pos = 0;
+ int res = NExtract::NOperationResult::kOK;
+ int i;
+ for (i = 0; i < item.Extents.Size(); i++)
+ {
+ if (item.Size == pos)
+ break;
+ if (res != NExtract::NOperationResult::kOK)
+ break;
+ const CExtent &e = item.Extents[i];
+ RINOK(_stream->Seek((UInt64)e.Pos << _db.Header.BlockSizeLog, STREAM_SEEK_SET, NULL));
+ UInt64 extentSize = (UInt64)e.NumBlocks << _db.Header.BlockSizeLog;
+ for (;;)
+ {
+ if (extentSize == 0)
+ break;
+ UInt64 rem = item.Size - pos;
+ if (rem == 0)
+ {
+ if (extentSize >= (UInt64)((UInt32)1 << _db.Header.BlockSizeLog))
+ res = NExtract::NOperationResult::kDataError;
+ break;
+ }
+ UInt32 curSize = kBufSize;
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ if (curSize > extentSize)
+ curSize = (UInt32)extentSize;
+ RINOK(ReadStream_FALSE(_stream, buf, curSize));
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, buf, curSize));
+ }
+ pos += curSize;
+ extentSize -= curSize;
+ UInt64 processed = currentTotalSize + pos;
+ RINOK(extractCallback->SetCompleted(&processed));
+ }
+ }
+ if (i != item.Extents.Size() || item.Size != pos)
+ res = NExtract::NOperationResult::kDataError;
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _db.Items.Size();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.h
new file mode 100644
index 000000000..269af218e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.h
@@ -0,0 +1,26 @@
+// HfsHandler.h
+
+#ifndef __ARCHIVE_HFS_HANDLER_H
+#define __ARCHIVE_HFS_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+#include "HfsIn.h"
+
+namespace NArchive {
+namespace NHfs {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CDatabase _db;
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.cpp
new file mode 100644
index 000000000..8391dd936
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.cpp
@@ -0,0 +1,480 @@
+// HfsIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/StreamUtils.h"
+#include "Common/IntToString.h"
+
+#include "HfsIn.h"
+
+#include "../../../../C/CpuArch.h"
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+namespace NArchive {
+namespace NHfs {
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareIdToIndex(const CIdIndexPair *p1, const CIdIndexPair *p2, void * /* param */)
+{
+ RINOZ(MyCompare(p1->ID, p2->ID));
+ return MyCompare(p1->Index, p2->Index);
+}
+
+bool operator< (const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID < a2.ID); }
+bool operator> (const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID > a2.ID); }
+bool operator==(const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID == a2.ID); }
+bool operator!=(const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID != a2.ID); }
+
+static UString GetSpecName(const UString &name, UInt32 /* id */)
+{
+ UString name2 = name;
+ name2.Trim();
+ if (name2.IsEmpty())
+ {
+ /*
+ wchar_t s[32];
+ ConvertUInt64ToString(id, s);
+ return L"[" + (UString)s + L"]";
+ */
+ return L"[]";
+ }
+ return name;
+}
+
+UString CDatabase::GetItemPath(int index) const
+{
+ const CItem *item = &Items[index];
+ UString name = GetSpecName(item->Name, item->ID);
+
+ for (int i = 0; i < 1000; i++)
+ {
+ if (item->ParentID < 16 && item->ParentID != 2)
+ {
+ if (item->ParentID != 1)
+ break;
+ return name;
+ }
+ CIdIndexPair pair;
+ pair.ID = item->ParentID;
+ pair.Index = 0;
+ int indexInMap = IdToIndexMap.FindInSorted(pair);
+ if (indexInMap < 0)
+ break;
+ item = &Items[IdToIndexMap[indexInMap].Index];
+ name = GetSpecName(item->Name, item->ID) + WCHAR_PATH_SEPARATOR + name;
+ }
+ return (UString)L"Unknown" + WCHAR_PATH_SEPARATOR + name;
+}
+
+void CFork::Parse(const Byte *p)
+{
+ Size = Get64(p);
+ // ClumpSize = Get32(p + 8);
+ NumBlocks = Get32(p + 0xC);
+ for (int i = 0; i < 8; i++)
+ {
+ CExtent &e = Extents[i];
+ e.Pos = Get32(p + 0x10 + i * 8);
+ e.NumBlocks = Get32(p + 0x10 + i * 8 + 4);
+ }
+}
+
+static HRESULT ReadExtent(int blockSizeLog, IInStream *inStream, Byte *buf, const CExtent &e)
+{
+ RINOK(inStream->Seek((UInt64)e.Pos << blockSizeLog, STREAM_SEEK_SET, NULL));
+ return ReadStream_FALSE(inStream, buf, (size_t)e.NumBlocks << blockSizeLog);
+}
+
+HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream)
+{
+ if (fork.NumBlocks >= Header.NumBlocks)
+ return S_FALSE;
+ size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog;
+ if ((totalSize >> Header.BlockSizeLog) != fork.NumBlocks)
+ return S_FALSE;
+ buf.SetCapacity(totalSize);
+ UInt32 curBlock = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (curBlock >= fork.NumBlocks)
+ break;
+ const CExtent &e = fork.Extents[i];
+ if (fork.NumBlocks - curBlock < e.NumBlocks || e.Pos >= Header.NumBlocks)
+ return S_FALSE;
+ RINOK(ReadExtent(Header.BlockSizeLog, inStream,
+ (Byte *)buf + ((size_t)curBlock << Header.BlockSizeLog), e));
+ curBlock += e.NumBlocks;
+ }
+ return S_OK;
+}
+
+struct CNodeDescriptor
+{
+ UInt32 fLink;
+ UInt32 bLink;
+ Byte Kind;
+ Byte Height;
+ UInt16 NumRecords;
+ // UInt16 Reserved;
+ void Parse(const Byte *p);
+};
+
+void CNodeDescriptor::Parse(const Byte *p)
+{
+ fLink = Get32(p);
+ bLink = Get32(p + 4);
+ Kind = p[8];
+ Height = p[9];
+ NumRecords = Get16(p + 10);
+}
+
+struct CHeaderRec
+{
+ // UInt16 TreeDepth;
+ // UInt32 RootNode;
+ // UInt32 LeafRecords;
+ UInt32 FirstLeafNode;
+ // UInt32 LastLeafNode;
+ int NodeSizeLog;
+ // UInt16 MaxKeyLength;
+ UInt32 TotalNodes;
+ // UInt32 FreeNodes;
+ // UInt16 Reserved1;
+ // UInt32 ClumpSize;
+ // Byte BtreeType;
+ // Byte KeyCompareType;
+ // UInt32 Attributes;
+ // UInt32 Reserved3[16];
+
+ HRESULT Parse(const Byte *p);
+};
+
+HRESULT CHeaderRec::Parse(const Byte *p)
+{
+ // TreeDepth = Get16(p);
+ // RootNode = Get32(p + 2);
+ // LeafRecords = Get32(p + 6);
+ FirstLeafNode = Get32(p + 0xA);
+ // LastLeafNode = Get32(p + 0xE);
+ UInt32 nodeSize = Get16(p + 0x12);
+
+ int i;
+ for (i = 9; ((UInt32)1 << i) != nodeSize; i++)
+ if (i == 16)
+ return S_FALSE;
+ NodeSizeLog = i;
+
+ // MaxKeyLength = Get16(p + 0x14);
+ TotalNodes = Get32(p + 0x16);
+ // FreeNodes = Get32(p + 0x1A);
+ // Reserved1 = Get16(p + 0x1E);
+ // ClumpSize = Get32(p + 0x20);
+ // BtreeType = p[0x24];
+ // KeyCompareType = p[0x25];
+ // Attributes = Get32(p + 0x26);
+ /*
+ for (int i = 0; i < 16; i++)
+ Reserved3[i] = Get32(p + 0x2A + i * 4);
+ */
+ return S_OK;
+}
+
+
+enum ENodeType
+{
+ NODE_TYPE_LEAF = 0xFF,
+ NODE_TYPE_INDEX = 0,
+ NODE_TYPE_HEADER = 1,
+ NODE_TYPE_MODE = 2
+};
+
+HRESULT CDatabase::LoadExtentFile(IInStream *inStream)
+{
+ // FileExtents.Clear();
+ // ResExtents.Clear();
+
+ CByteBuffer extents;
+ RINOK(ReadFile(Header.ExtentsFile, extents, inStream));
+
+ const Byte *p = (const Byte *)extents;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ RINOK(hr.Parse(p + 14));
+
+ UInt32 node = hr.FirstLeafNode;
+ if (node != 0)
+ return S_FALSE;
+ /*
+ while (node != 0)
+ {
+ size_t nodeOffset = node * hr.NodeSize;
+ if ((node + 1)* hr.NodeSize > CatalogBuf.GetCapacity())
+ return S_FALSE;
+ CNodeDescriptor desc;
+ desc.Parse(p + nodeOffset);
+ if (desc.Kind != NODE_TYPE_LEAF)
+ return S_FALSE;
+ UInt32 ptr = hr.NodeSize;
+ for (int i = 0; i < desc.NumRecords; i++)
+ {
+ UInt32 offs = Get16(p + nodeOffset + hr.NodeSize - (i + 1) * 2);
+ UInt32 offsNext = Get16(p + nodeOffset + hr.NodeSize - (i + 2) * 2);
+
+ const Byte *r = p + nodeOffset + offs;
+ int keyLength = Get16(r);
+ Byte forkType = r[2];
+ UInt32 id = Get16(r + 4);
+ UInt32 startBlock = Get16(r + 4);
+ CObjectVector<CIdExtents> *extents = (forkType == 0) ? &FileExtents : &ResExtents;
+ if (extents->Size() == 0)
+ extents->Add(CIdExtents());
+ else
+ {
+ CIdExtents &e = extents->Back();
+ if (e.ID != id)
+ {
+ if (e.ID > id)
+ return S_FALSE;
+ extents->Add(CIdExtents());
+ }
+ }
+ CIdExtents &e = extents->Back();
+ for (UInt32 k = offs + 10 + 2; k + 8 <= offsNext; k += 8)
+ {
+ CExtent ee;
+ ee.Pos = Get32(p + nodeOffset + k);
+ ee.NumBlocks = Get32(p + nodeOffset + k * 4);
+ e.Extents.Add(ee);
+ }
+ }
+ node = desc.fLink;
+ }
+ */
+ return S_OK;
+}
+
+
+HRESULT CDatabase::LoadCatalog(IInStream *inStream, CProgressVirt *progress)
+{
+ Items.Clear();
+ IdToIndexMap.ClearAndFree();
+
+ CByteBuffer catalogBuf;
+ RINOK(ReadFile(Header.CatalogFile, catalogBuf, inStream));
+ const Byte *p = (const Byte *)catalogBuf;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ hr.Parse(p + 14);
+
+ // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
+
+ if ((catalogBuf.GetCapacity() >> hr.NodeSizeLog) < hr.TotalNodes)
+ return S_FALSE;
+
+ CByteBuffer usedBuf;
+ usedBuf.SetCapacity(hr.TotalNodes);
+ for (UInt32 i = 0; i < hr.TotalNodes; i++)
+ usedBuf[i] = 0;
+
+ UInt32 node = hr.FirstLeafNode;
+ while (node != 0)
+ {
+ if (node >= hr.TotalNodes)
+ return S_FALSE;
+ if (usedBuf[node])
+ return S_FALSE;
+ usedBuf[node] = 1;
+ size_t nodeOffset = (size_t)node << hr.NodeSizeLog;
+ CNodeDescriptor desc;
+ desc.Parse(p + nodeOffset);
+ if (desc.Kind != NODE_TYPE_LEAF)
+ return S_FALSE;
+ for (int i = 0; i < desc.NumRecords; i++)
+ {
+ UInt32 nodeSize = (1 << hr.NodeSizeLog);
+ UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2);
+ UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2);
+ UInt32 recSize = offsNext - offs;
+ if (offsNext >= nodeSize || offsNext < offs || recSize < 6)
+ return S_FALSE;
+
+ CItem item;
+
+ const Byte *r = p + nodeOffset + offs;
+ UInt32 keyLength = Get16(r);
+ item.ParentID = Get32(r + 2);
+ UString name;
+ if (keyLength < 6 || (keyLength & 1) != 0 || keyLength + 2 > recSize)
+ return S_FALSE;
+ r += 6;
+ recSize -= 6;
+ keyLength -= 6;
+
+ int nameLength = Get16(r);
+ if (nameLength * 2 != (int)keyLength)
+ return S_FALSE;
+ r += 2;
+ recSize -= 2;
+
+ wchar_t *pp = name.GetBuffer(nameLength + 1);
+
+ int j;
+ for (j = 0; j < nameLength; j++)
+ pp[j] = ((wchar_t)r[j * 2] << 8) | r[j * 2 + 1];
+ pp[j] = 0;
+ name.ReleaseBuffer();
+ r += j * 2;
+ recSize -= j * 2;
+
+ if (recSize < 2)
+ return S_FALSE;
+ item.Type = Get16(r);
+
+ if (item.Type != RECORD_TYPE_FOLDER && item.Type != RECORD_TYPE_FILE)
+ continue;
+ if (recSize < 0x58)
+ return S_FALSE;
+
+ // item.Flags = Get16(r + 2);
+ // item.Valence = Get32(r + 4);
+ item.ID = Get32(r + 8);
+ item.CTime = Get32(r + 0xC);
+ item.MTime = Get32(r + 0x10);
+ // item.AttrMTime = Get32(r + 0x14);
+ item.ATime = Get32(r + 0x18);
+ // item.BackupDate = Get32(r + 0x1C);
+
+ /*
+ item.OwnerID = Get32(r + 0x20);
+ item.GroupID = Get32(r + 0x24);
+ item.AdminFlags = r[0x28];
+ item.OwnerFlags = r[0x29];
+ item.FileMode = Get16(r + 0x2A);
+ item.special.iNodeNum = Get16(r + 0x2C);
+ */
+
+ item.Name = name;
+
+ if (item.IsDir())
+ {
+ CIdIndexPair pair;
+ pair.ID = item.ID;
+ pair.Index = Items.Size();
+ IdToIndexMap.Add(pair);
+ }
+ else
+ {
+ CFork fd;
+ recSize -= 0x58;
+ r += 0x58;
+ if (recSize < 0x50 * 2)
+ return S_FALSE;
+ fd.Parse(r);
+ item.Size = fd.Size;
+ item.NumBlocks = fd.NumBlocks;
+ UInt32 curBlock = 0;
+ for (int j = 0; j < 8; j++)
+ {
+ if (curBlock >= fd.NumBlocks)
+ break;
+ const CExtent &e = fd.Extents[j];
+ item.Extents.Add(e);
+ curBlock += e.NumBlocks;
+ }
+ }
+ Items.Add(item);
+ if (progress && Items.Size() % 100 == 0)
+ {
+ RINOK(progress->SetCompleted(Items.Size()));
+ }
+ }
+ node = desc.fLink;
+ }
+ IdToIndexMap.Sort(CompareIdToIndex, NULL);
+ return S_OK;
+}
+
+HRESULT CDatabase::Open(IInStream *inStream, CProgressVirt *progress)
+{
+ static const UInt32 kHeaderSize = 1024 + 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize));
+ int i;
+ for (i = 0; i < 1024; i++)
+ if (buf[i] != 0)
+ return S_FALSE;
+ const Byte *p = buf + 1024;
+ CVolHeader &h = Header;
+
+ h.Header[0] = p[0];
+ h.Header[1] = p[1];
+ if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X'))
+ return S_FALSE;
+ h.Version = Get16(p + 2);
+ if (h.Version < 4 || h.Version > 5)
+ return S_FALSE;
+
+ // h.Attr = Get32(p + 4);
+ // h.LastMountedVersion = Get32(p + 8);
+ // h.JournalInfoBlock = Get32(p + 0xC);
+
+ h.CTime = Get32(p + 0x10);
+ h.MTime = Get32(p + 0x14);
+ // h.BackupTime = Get32(p + 0x18);
+ // h.CheckedTime = Get32(p + 0x1C);
+
+ // h.NumFiles = Get32(p + 0x20);
+ // h.NumFolders = Get32(p + 0x24);
+
+ UInt32 numFiles = Get32(p + 0x20);
+ UInt32 numFolders = Get32(p + 0x24);;
+ if (progress)
+ {
+ RINOK(progress->SetTotal(numFolders + numFiles));
+ }
+
+ UInt32 blockSize = Get32(p + 0x28);
+
+ for (i = 9; ((UInt32)1 << i) != blockSize; i++)
+ if (i == 31)
+ return S_FALSE;
+ h.BlockSizeLog = i;
+
+ h.NumBlocks = Get32(p + 0x2C);
+ h.NumFreeBlocks = Get32(p + 0x30);
+
+ /*
+ h.WriteCount = Get32(p + 0x44);
+ for (i = 0; i < 6; i++)
+ h.FinderInfo[i] = Get32(p + 0x50 + i * 4);
+ h.VolID = Get64(p + 0x68);
+ */
+
+ UInt64 endPos;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
+ if ((endPos >> h.BlockSizeLog) < h.NumBlocks)
+ return S_FALSE;
+
+ // h.AllocationFile.Parse(p + 0x70 + 0x50 * 0);
+ h.ExtentsFile.Parse( p + 0x70 + 0x50 * 1);
+ h.CatalogFile.Parse( p + 0x70 + 0x50 * 2);
+ // h.AttributesFile.Parse(p + 0x70 + 0x50 * 3);
+ // h.StartupFile.Parse( p + 0x70 + 0x50 * 4);
+
+ RINOK(LoadExtentFile(inStream));
+ RINOK(LoadCatalog(inStream, progress));
+
+ // if (Header.NumFiles + Header.NumFolders != (UInt32)Items.Size()) return S_OK;
+
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.h
new file mode 100644
index 000000000..c19539057
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.h
@@ -0,0 +1,154 @@
+// HfsIn.h
+
+#ifndef __ARCHIVE_HFS_IN_H
+#define __ARCHIVE_HFS_IN_H
+
+#include "Common/MyString.h"
+#include "Common/Buffer.h"
+
+namespace NArchive {
+namespace NHfs {
+
+struct CExtent
+{
+ UInt32 Pos;
+ UInt32 NumBlocks;
+};
+
+struct CFork
+{
+ UInt64 Size;
+ // UInt32 ClumpSize;
+ UInt32 NumBlocks;
+ CExtent Extents[8];
+ void Parse(const Byte *p);
+};
+
+struct CVolHeader
+{
+ Byte Header[2];
+ UInt16 Version;
+ // UInt32 Attr;
+ // UInt32 LastMountedVersion;
+ // UInt32 JournalInfoBlock;
+
+ UInt32 CTime;
+ UInt32 MTime;
+ // UInt32 BackupTime;
+ // UInt32 CheckedTime;
+
+ // UInt32 NumFiles;
+ // UInt32 NumFolders;
+ int BlockSizeLog;
+ UInt32 NumBlocks;
+ UInt32 NumFreeBlocks;
+
+ // UInt32 WriteCount;
+ // UInt32 FinderInfo[8];
+ // UInt64 VolID;
+
+ // CFork AllocationFile;
+ CFork ExtentsFile;
+ CFork CatalogFile;
+ // CFork AttributesFile;
+ // CFork StartupFile;
+
+ bool IsHfsX() const { return Version > 4; }
+};
+
+inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft)
+{
+ UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+enum ERecordType
+{
+ RECORD_TYPE_FOLDER = 1,
+ RECORD_TYPE_FILE = 2,
+ RECORD_TYPE_FOLDER_THREAD = 3,
+ RECORD_TYPE_FILE_THREAD = 4
+};
+
+struct CItem
+{
+ UString Name;
+
+ UInt32 ParentID;
+
+ UInt16 Type;
+ // UInt16 Flags;
+ // UInt32 Valence;
+ UInt32 ID;
+ UInt32 CTime;
+ UInt32 MTime;
+ // UInt32 AttrMTime;
+ UInt32 ATime;
+ // UInt32 BackupDate;
+
+ /*
+ UInt32 OwnerID;
+ UInt32 GroupID;
+ Byte AdminFlags;
+ Byte OwnerFlags;
+ UInt16 FileMode;
+ union
+ {
+ UInt32 iNodeNum;
+ UInt32 LinkCount;
+ UInt32 RawDevice;
+ } special;
+ */
+
+ UInt64 Size;
+ UInt32 NumBlocks;
+ CRecordVector<CExtent> Extents;
+
+ bool IsDir() const { return Type == RECORD_TYPE_FOLDER; }
+ CItem(): Size(0), NumBlocks(0) {}
+};
+
+struct CIdIndexPair
+{
+ UInt32 ID;
+ int Index;
+};
+
+struct CProgressVirt
+{
+ virtual HRESULT SetTotal(UInt64 numFiles) PURE;
+ virtual HRESULT SetCompleted(UInt64 numFiles) PURE;
+};
+
+class CDatabase
+{
+ // CObjectVector<CIdExtents> FileExtents;
+ // CObjectVector<CIdExtents> ResExtents;
+ CRecordVector<CIdIndexPair> IdToIndexMap;
+
+ HRESULT LoadExtentFile(IInStream *inStream);
+ HRESULT LoadCatalog(IInStream *inStream, CProgressVirt *progress);
+
+ HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream);
+public:
+ CVolHeader Header;
+ CObjectVector<CItem> Items;
+ // bool CaseSensetive;
+
+ void Clear()
+ {
+ // CaseSensetive = false;
+ Items.Clear();
+ // FileExtents.Clear();
+ // ResExtents.Clear();
+ IdToIndexMap.Clear();
+ }
+
+ UString GetItemPath(int index) const;
+ HRESULT Open(IInStream *inStream, CProgressVirt *progress);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsRegister.cpp
new file mode 100644
index 000000000..51c3c2b15
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsRegister.cpp
@@ -0,0 +1,13 @@
+// HfsRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "HfsHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NHfs::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"HFS", L"hfs", 0, 0xE3, { 'H', '+', 0, 4 }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Hfs)