5
#include "Common/ComTry.h"
6
#include "Windows/PropVariant.h"
7
#include "../../Common/StreamUtils.h"
8
#include "HfsHandler.h"
13
STATPROPSTG kProps[] =
15
{ NULL, kpidPath, VT_BSTR},
16
{ NULL, kpidIsDir, VT_BOOL},
17
{ NULL, kpidSize, VT_UI8},
18
{ NULL, kpidPackSize, VT_UI8},
19
{ NULL, kpidCTime, VT_FILETIME},
20
{ NULL, kpidMTime, VT_FILETIME},
21
{ NULL, kpidATime, VT_FILETIME}
24
STATPROPSTG kArcProps[] =
26
{ NULL, kpidMethod, VT_BSTR},
27
{ NULL, kpidClusterSize, VT_UI4},
28
{ NULL, kpidFreeSpace, VT_UI8},
29
{ NULL, kpidCTime, VT_FILETIME},
30
{ NULL, kpidMTime, VT_FILETIME}
34
IMP_IInArchive_ArcProps
36
static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop)
39
HfsTimeToFileTime(hfsTime, ft);
43
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
46
NWindows::NCOM::CPropVariant prop;
49
case kpidMethod: prop = _db.Header.IsHfsX() ? L"HFSX" : L"HFS+"; break;
50
case kpidClusterSize: prop = (UInt32)1 << _db.Header.BlockSizeLog; break;
51
case kpidFreeSpace: prop = (UInt64)_db.Header.NumFreeBlocks << _db.Header.BlockSizeLog; break;
52
case kpidMTime: HfsTimeToProp(_db.Header.MTime, prop); break;
56
HfsTimeToFileTime(_db.Header.CTime, localFt);
57
if (LocalFileTimeToFileTime(&localFt, &ft))
67
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
70
NWindows::NCOM::CPropVariant prop;
71
const CItem &item = _db.Items[index];
74
case kpidPath: prop = _db.GetItemPath(index); break;
75
case kpidIsDir: prop = item.IsDir(); break;
77
case kpidCTime: HfsTimeToProp(item.CTime, prop); break;
78
case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
79
case kpidATime: HfsTimeToProp(item.ATime, prop); break;
81
case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumBlocks << _db.Header.BlockSizeLog; break;
82
case kpidSize: if (!item.IsDir()) prop = item.Size; break;
89
class CProgressImp: public CProgressVirt
91
CMyComPtr<IArchiveOpenCallback> _callback;
93
HRESULT SetTotal(UInt64 numFiles);
94
HRESULT SetCompleted(UInt64 numFiles);
95
CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}
98
HRESULT CProgressImp::SetTotal(UInt64 numFiles)
101
return _callback->SetTotal(&numFiles, NULL);
105
HRESULT CProgressImp::SetCompleted(UInt64 numFiles)
108
return _callback->SetCompleted(&numFiles, NULL);
112
STDMETHODIMP CHandler::Open(IInStream *inStream,
113
const UInt64 * /* maxCheckStartPosition */,
114
IArchiveOpenCallback *callback)
120
CProgressImp progressImp(callback);
121
HRESULT res = _db.Open(inStream, &progressImp);
128
catch(...) { return S_FALSE; }
133
STDMETHODIMP CHandler::Close()
140
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
141
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
144
bool testMode = (_aTestMode != 0);
145
bool allFilesMode = (numItems == UInt32(-1));
147
numItems = _db.Items.Size();
151
UInt64 totalSize = 0;
152
for (i = 0; i < numItems; i++)
154
const CItem &item = _db.Items[allFilesMode ? i : indices[i]];
156
totalSize += item.Size;
158
RINOK(extractCallback->SetTotal(totalSize));
160
UInt64 currentTotalSize = 0, currentItemSize = 0;
163
const UInt32 kBufSize = (1 << 16);
164
buf.SetCapacity(kBufSize);
166
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
168
RINOK(extractCallback->SetCompleted(¤tTotalSize));
169
Int32 index = allFilesMode ? i : indices[i];
170
const CItem &item = _db.Items[index];
173
currentItemSize = item.Size;
175
CMyComPtr<ISequentialOutStream> realOutStream;
176
Int32 askMode = testMode ?
177
NArchive::NExtract::NAskMode::kTest :
178
NArchive::NExtract::NAskMode::kExtract;
179
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
183
RINOK(extractCallback->PrepareOperation(askMode));
184
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
187
if (!testMode && (!realOutStream))
189
RINOK(extractCallback->PrepareOperation(askMode));
191
int res = NArchive::NExtract::NOperationResult::kOK;
193
for (i = 0; i < item.Extents.Size(); i++)
195
if (item.Size == pos)
197
if (res != NArchive::NExtract::NOperationResult::kOK)
199
const CExtent &e = item.Extents[i];
200
RINOK(_stream->Seek((UInt64)e.Pos << _db.Header.BlockSizeLog, STREAM_SEEK_SET, NULL));
201
UInt64 extentSize = (UInt64)e.NumBlocks << _db.Header.BlockSizeLog;
206
UInt64 rem = item.Size - pos;
209
if (extentSize >= (UInt64)((UInt32)1 << _db.Header.BlockSizeLog))
210
res = NArchive::NExtract::NOperationResult::kDataError;
213
UInt32 curSize = kBufSize;
215
curSize = (UInt32)rem;
216
if (curSize > extentSize)
217
curSize = (UInt32)extentSize;
218
RINOK(ReadStream_FALSE(_stream, buf, curSize));
221
RINOK(WriteStream(realOutStream, buf, curSize));
224
extentSize -= curSize;
225
UInt64 processed = currentTotalSize + pos;
226
RINOK(extractCallback->SetCompleted(&processed));
229
if (i != item.Extents.Size() || item.Size != pos)
230
res = NArchive::NExtract::NOperationResult::kDataError;
231
realOutStream.Release();
232
RINOK(extractCallback->SetOperationResult(res));
238
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
240
*numItems = _db.Items.Size();