5
#include "Common/ComTry.h"
6
#include "Common/Defs.h"
7
#include "Common/NewHandler.h"
8
#include "Common/StringConvert.h"
9
#include "Common/StringToInt.h"
11
#include "Windows/PropVariant.h"
12
#include "Windows/Time.h"
14
#include "../Common/LimitedStreams.h"
15
#include "../Common/ProgressUtils.h"
16
#include "../Common/RegisterArc.h"
17
#include "../Common/StreamUtils.h"
19
#include "../Compress/CopyCoder.h"
21
#include "Common/ItemNameUtils.h"
23
using namespace NWindows;
24
using namespace NTime;
31
const int kSignatureLen = 8;
33
const char *kSignature = "!<arch>\n";
35
const int kNameSize = 16;
36
const int kTimeSize = 12;
37
const int kModeSize = 8;
38
const int kSizeSize = 10;
44
char MTime[kTimeSize];
53
const int kHeaderSize = kNameSize + kTimeSize + 6 + 6 + kModeSize + kSizeSize + 1 + 1;
65
class CItemEx: public CItem
68
UInt64 HeaderPosition;
69
UInt64 GetDataPosition() const { return HeaderPosition + NHeader::kHeaderSize; };
70
// UInt64 GetFullSize() const { return NFileHeader::kRecordSize + Size; };
75
CMyComPtr<IInStream> m_Stream;
78
HRESULT GetNextItemReal(bool &filled, CItemEx &itemInfo);
79
HRESULT Skeep(UInt64 numBytes);
81
HRESULT Open(IInStream *inStream);
82
HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
83
HRESULT SkeepData(UInt64 dataSize);
86
HRESULT CInArchive::Open(IInStream *inStream)
88
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
89
char signature[NHeader::kSignatureLen];
90
RINOK(ReadStream_FALSE(inStream, signature, NHeader::kSignatureLen));
91
m_Position += NHeader::kSignatureLen;
92
if (memcmp(signature, NHeader::kSignature, NHeader::kSignatureLen) != 0)
98
static void MyStrNCpy(char *dest, const char *src, int size)
100
for (int i = 0; i < size; i++)
109
static bool OctalToNumber(const char *s, int size, UInt64 &res)
112
MyStrNCpy(sz, s, size);
116
for (i = 0; sz[i] == ' '; i++);
117
res = ConvertOctStringToUInt64(sz + i, &end);
118
return (*end == ' ' || *end == 0);
121
static bool OctalToNumber32(const char *s, int size, UInt32 &res)
124
if (!OctalToNumber(s, size, res64))
127
return (res64 <= 0xFFFFFFFF);
130
static bool DecimalToNumber(const char *s, int size, UInt64 &res)
133
MyStrNCpy(sz, s, size);
137
for (i = 0; sz[i] == ' '; i++);
138
res = ConvertStringToUInt64(sz + i, &end);
139
return (*end == ' ' || *end == 0);
142
static bool DecimalToNumber32(const char *s, int size, UInt32 &res)
145
if (!DecimalToNumber(s, size, res64))
148
return (res64 <= 0xFFFFFFFF);
151
#define RIF(x) { if (!(x)) return S_FALSE; }
154
HRESULT CInArchive::GetNextItemReal(bool &filled, CItemEx &item)
158
char header[NHeader::kHeaderSize];
159
const char *cur = header;
161
size_t processedSize = sizeof(header);
162
item.HeaderPosition = m_Position;
163
RINOK(ReadStream(m_Stream, header, &processedSize));
164
m_Position += processedSize;
165
if (processedSize != sizeof(header))
168
char tempString[NHeader::kNameSize + 1];
169
MyStrNCpy(tempString, cur, NHeader::kNameSize);
170
cur += NHeader::kNameSize;
171
tempString[NHeader::kNameSize] = '\0';
172
item.Name = tempString;
175
for (int i = 0; i < item.Name.Length(); i++)
176
if (((Byte)item.Name[i]) < 0x20)
179
RIF(DecimalToNumber32(cur, NHeader::kTimeSize, item.MTime));
180
cur += NHeader::kTimeSize;
184
RIF(OctalToNumber32(cur, NHeader::kModeSize, item.Mode));
185
cur += NHeader::kModeSize;
187
RIF(DecimalToNumber(cur, NHeader::kSizeSize, item.Size));
188
cur += NHeader::kSizeSize;
194
HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
198
RINOK(GetNextItemReal(filled, item));
201
if (item.Name.Compare("debian-binary") != 0)
205
SkeepData(item.Size);
209
HRESULT CInArchive::Skeep(UInt64 numBytes)
212
RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
213
m_Position += numBytes;
214
if (m_Position != newPostion)
219
HRESULT CInArchive::SkeepData(UInt64 dataSize)
221
return Skeep((dataSize + 1) & (~((UInt64)0x1)));
230
MY_UNKNOWN_IMP1(IInArchive)
232
INTERFACE_IInArchive(;)
235
CObjectVector<CItemEx> _items;
236
CMyComPtr<IInStream> _inStream;
240
STATPROPSTG kProps[] =
242
{ NULL, kpidPath, VT_BSTR},
243
{ NULL, kpidSize, VT_UI8},
244
{ NULL, kpidPackSize, VT_UI8},
245
{ NULL, kpidMTime, VT_FILETIME}
249
IMP_IInArchive_ArcProps_NO
251
STDMETHODIMP CHandler::Open(IInStream *stream,
252
const UInt64 * /* maxCheckStartPosition */,
253
IArchiveOpenCallback *openArchiveCallback)
258
if(archive.Open(stream) != S_OK)
262
if (openArchiveCallback != NULL)
264
RINOK(openArchiveCallback->SetTotal(NULL, NULL));
265
UInt64 numFiles = _items.Size();
266
RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
273
HRESULT result = archive.GetNextItem(filled, item);
274
if (result == S_FALSE)
281
archive.SkeepData(item.Size);
282
if (openArchiveCallback != NULL)
284
UInt64 numFiles = _items.Size();
285
RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
294
STDMETHODIMP CHandler::Close()
301
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
303
*numItems = _items.Size();
307
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
310
NWindows::NCOM::CPropVariant prop;
311
const CItemEx &item = _items[index];
315
case kpidPath: prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
325
NTime::UnixTimeToFileTime(item.MTime, fileTime);
336
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
337
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
340
bool testMode = (_aTestMode != 0);
341
bool allFilesMode = (numItems == UInt32(-1));
343
numItems = _items.Size();
346
UInt64 totalSize = 0;
348
for (i = 0; i < numItems; i++)
349
totalSize += _items[allFilesMode ? i : indices[i]].Size;
350
extractCallback->SetTotal(totalSize);
352
UInt64 currentTotalSize = 0;
353
UInt64 currentItemSize;
355
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
356
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
358
CLocalProgress *lps = new CLocalProgress;
359
CMyComPtr<ICompressProgressInfo> progress = lps;
360
lps->Init(extractCallback, false);
362
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
363
CMyComPtr<ISequentialInStream> inStream(streamSpec);
364
streamSpec->SetStream(_inStream);
366
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
368
lps->InSize = lps->OutSize = currentTotalSize;
369
RINOK(lps->SetCur());
370
CMyComPtr<ISequentialOutStream> realOutStream;
371
Int32 askMode = testMode ?
372
NArchive::NExtract::NAskMode::kTest :
373
NArchive::NExtract::NAskMode::kExtract;
374
Int32 index = allFilesMode ? i : indices[i];
375
const CItemEx &item = _items[index];
376
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
377
currentItemSize = item.Size;
384
if (!testMode && (!realOutStream))
386
RINOK(extractCallback->PrepareOperation(askMode));
389
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
392
RINOK(_inStream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
393
streamSpec->Init(item.Size);
394
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
395
realOutStream.Release();
396
RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
397
NArchive::NExtract::NOperationResult::kOK:
398
NArchive::NExtract::NOperationResult::kDataError));
404
static IInArchive *CreateArc() { return new NArchive::NDeb::CHandler; }
406
static CArcInfo g_ArcInfo =
407
{ L"Deb", L"deb", 0, 0xEC, { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' }, 8, false, CreateArc, 0 };