mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-13 20:11:35 -06:00
4.59 beta
This commit is contained in:
committed by
Kornel Lesiński
parent
3901bf0ab8
commit
173c07e166
244
CPP/7zip/Archive/Hfs/HfsHandler.cpp
Executable file
244
CPP/7zip/Archive/Hfs/HfsHandler.cpp
Executable file
@@ -0,0 +1,244 @@
|
||||
// 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 _aTestMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool testMode = (_aTestMode != 0);
|
||||
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(¤tTotalSize));
|
||||
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 ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
|
||||
if (item.IsDir())
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
if (!testMode && (!realOutStream))
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
UInt64 pos = 0;
|
||||
int res = NArchive::NExtract::NOperationResult::kOK;
|
||||
int i;
|
||||
for (i = 0; i < item.Extents.Size(); i++)
|
||||
{
|
||||
if (item.Size == pos)
|
||||
break;
|
||||
if (res != NArchive::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 = NArchive::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 = NArchive::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;
|
||||
}
|
||||
|
||||
}}
|
||||
26
CPP/7zip/Archive/Hfs/HfsHandler.h
Executable file
26
CPP/7zip/Archive/Hfs/HfsHandler.h
Executable file
@@ -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
|
||||
480
CPP/7zip/Archive/Hfs/HfsIn.cpp
Executable file
480
CPP/7zip/Archive/Hfs/HfsIn.cpp
Executable file
@@ -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;
|
||||
}
|
||||
|
||||
}}
|
||||
154
CPP/7zip/Archive/Hfs/HfsIn.h
Executable file
154
CPP/7zip/Archive/Hfs/HfsIn.h
Executable file
@@ -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
|
||||
13
CPP/7zip/Archive/Hfs/HfsRegister.cpp
Executable file
13
CPP/7zip/Archive/Hfs/HfsRegister.cpp
Executable file
@@ -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)
|
||||
Reference in New Issue
Block a user