5 #include "Common/ComTry.h"
\r
6 #include "Common/StringConvert.h"
\r
7 #include "Common/StringToInt.h"
\r
9 #include "Windows/PropVariant.h"
\r
10 #include "Windows/Time.h"
\r
12 #include "../Common/LimitedStreams.h"
\r
13 #include "../Common/ProgressUtils.h"
\r
14 #include "../Common/RegisterArc.h"
\r
15 #include "../Common/StreamUtils.h"
\r
17 #include "../Compress/CopyCoder.h"
\r
19 #include "Common/ItemNameUtils.h"
\r
21 using namespace NWindows;
\r
22 using namespace NTime;
\r
24 namespace NArchive {
\r
29 const int kSignatureLen = 8;
\r
31 const char *kSignature = "!<arch>\n";
\r
33 const int kNameSize = 16;
\r
34 const int kTimeSize = 12;
\r
35 const int kModeSize = 8;
\r
36 const int kSizeSize = 10;
\r
41 char Name[kNameSize];
\r
42 char MTime[kTimeSize];
\r
45 char Mode[kModeSize];
\r
46 char Size[kSizeSize];
\r
51 const int kHeaderSize = kNameSize + kTimeSize + 6 + 6 + kModeSize + kSizeSize + 1 + 1;
\r
62 UInt64 GetDataPos() const { return HeaderPos + NHeader::kHeaderSize; };
\r
63 // UInt64 GetFullSize() const { return NFileHeader::kRecordSize + Size; };
\r
68 CMyComPtr<IInStream> m_Stream;
\r
70 HRESULT GetNextItemReal(bool &filled, CItem &itemInfo);
\r
73 HRESULT Open(IInStream *inStream);
\r
74 HRESULT GetNextItem(bool &filled, CItem &itemInfo);
\r
75 HRESULT SkipData(UInt64 dataSize);
\r
78 HRESULT CInArchive::Open(IInStream *inStream)
\r
80 RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
\r
81 char signature[NHeader::kSignatureLen];
\r
82 RINOK(ReadStream_FALSE(inStream, signature, NHeader::kSignatureLen));
\r
83 m_Position += NHeader::kSignatureLen;
\r
84 if (memcmp(signature, NHeader::kSignature, NHeader::kSignatureLen) != 0)
\r
86 m_Stream = inStream;
\r
90 static void MyStrNCpy(char *dest, const char *src, int size)
\r
92 for (int i = 0; i < size; i++)
\r
101 static bool OctalToNumber(const char *s, int size, UInt64 &res)
\r
104 MyStrNCpy(sz, s, size);
\r
108 for (i = 0; sz[i] == ' '; i++);
\r
109 res = ConvertOctStringToUInt64(sz + i, &end);
\r
110 return (*end == ' ' || *end == 0);
\r
113 static bool OctalToNumber32(const char *s, int size, UInt32 &res)
\r
116 if (!OctalToNumber(s, size, res64))
\r
118 res = (UInt32)res64;
\r
119 return (res64 <= 0xFFFFFFFF);
\r
122 static bool DecimalToNumber(const char *s, int size, UInt64 &res)
\r
125 MyStrNCpy(sz, s, size);
\r
129 for (i = 0; sz[i] == ' '; i++);
\r
130 res = ConvertStringToUInt64(sz + i, &end);
\r
131 return (*end == ' ' || *end == 0);
\r
134 static bool DecimalToNumber32(const char *s, int size, UInt32 &res)
\r
137 if (!DecimalToNumber(s, size, res64))
\r
139 res = (UInt32)res64;
\r
140 return (res64 <= 0xFFFFFFFF);
\r
143 #define RIF(x) { if (!(x)) return S_FALSE; }
\r
146 HRESULT CInArchive::GetNextItemReal(bool &filled, CItem &item)
\r
150 char header[NHeader::kHeaderSize];
\r
151 const char *cur = header;
\r
153 size_t processedSize = sizeof(header);
\r
154 item.HeaderPos = m_Position;
\r
155 RINOK(ReadStream(m_Stream, header, &processedSize));
\r
156 if (processedSize != sizeof(header))
\r
158 m_Position += processedSize;
\r
160 char tempString[NHeader::kNameSize + 1];
\r
161 MyStrNCpy(tempString, cur, NHeader::kNameSize);
\r
162 cur += NHeader::kNameSize;
\r
163 tempString[NHeader::kNameSize] = '\0';
\r
164 item.Name = tempString;
\r
167 for (int i = 0; i < item.Name.Length(); i++)
\r
168 if (((Byte)item.Name[i]) < 0x20)
\r
171 RIF(DecimalToNumber32(cur, NHeader::kTimeSize, item.MTime));
\r
172 cur += NHeader::kTimeSize;
\r
176 RIF(OctalToNumber32(cur, NHeader::kModeSize, item.Mode));
\r
177 cur += NHeader::kModeSize;
\r
179 RIF(DecimalToNumber(cur, NHeader::kSizeSize, item.Size));
\r
180 cur += NHeader::kSizeSize;
\r
186 HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
\r
190 RINOK(GetNextItemReal(filled, item));
\r
193 if (item.Name.Compare("debian-binary") != 0)
\r
195 if (item.Size != 4)
\r
197 SkipData(item.Size);
\r
201 HRESULT CInArchive::SkipData(UInt64 dataSize)
\r
203 return m_Stream->Seek((dataSize + 1) & (~((UInt64)0x1)), STREAM_SEEK_CUR, &m_Position);
\r
208 public IInArchiveGetStream,
\r
209 public CMyUnknownImp
\r
211 CObjectVector<CItem> _items;
\r
212 CMyComPtr<IInStream> _stream;
\r
213 Int32 _mainSubfile;
\r
216 MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
\r
217 INTERFACE_IInArchive(;)
\r
218 STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
\r
221 static STATPROPSTG kArcProps[] =
\r
223 { NULL, kpidPhySize, VT_UI8}
\r
226 static STATPROPSTG kProps[] =
\r
228 { NULL, kpidPath, VT_BSTR},
\r
229 { NULL, kpidSize, VT_UI8},
\r
230 { NULL, kpidMTime, VT_FILETIME}
\r
233 IMP_IInArchive_Props
\r
234 IMP_IInArchive_ArcProps
\r
236 STDMETHODIMP CHandler::Open(IInStream *stream,
\r
237 const UInt64 * /* maxCheckStartPosition */,
\r
238 IArchiveOpenCallback *openArchiveCallback)
\r
243 CInArchive archive;
\r
244 if (archive.Open(stream) != S_OK)
\r
248 if (openArchiveCallback != NULL)
\r
250 RINOK(openArchiveCallback->SetTotal(NULL, NULL));
\r
251 UInt64 numFiles = _items.Size();
\r
252 RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
\r
259 HRESULT result = archive.GetNextItem(filled, item);
\r
260 if (result == S_FALSE)
\r
262 if (result != S_OK)
\r
266 if (item.Name.Left(5) == "data.")
\r
267 _mainSubfile = _items.Size();
\r
269 archive.SkipData(item.Size);
\r
270 if (openArchiveCallback != NULL)
\r
272 UInt64 numFiles = _items.Size();
\r
273 RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
\r
277 _phySize = archive.m_Position;
\r
283 STDMETHODIMP CHandler::Close()
\r
290 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
\r
292 *numItems = _items.Size();
\r
296 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
\r
298 NCOM::CPropVariant prop;
\r
301 case kpidPhySize: prop = _phySize; break;
\r
302 case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
\r
304 prop.Detach(value);
\r
308 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
\r
311 NWindows::NCOM::CPropVariant prop;
\r
312 const CItem &item = _items[index];
\r
316 case kpidPath: prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
\r
323 if (item.MTime != 0)
\r
326 NTime::UnixTimeToFileTime(item.MTime, fileTime);
\r
332 prop.Detach(value);
\r
337 STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
\r
338 Int32 testMode, IArchiveExtractCallback *extractCallback)
\r
341 bool allFilesMode = (numItems == (UInt32)-1);
\r
343 numItems = _items.Size();
\r
346 UInt64 totalSize = 0;
\r
348 for (i = 0; i < numItems; i++)
\r
349 totalSize += _items[allFilesMode ? i : indices[i]].Size;
\r
350 extractCallback->SetTotal(totalSize);
\r
352 UInt64 currentTotalSize = 0;
\r
354 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
\r
355 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
\r
357 CLocalProgress *lps = new CLocalProgress;
\r
358 CMyComPtr<ICompressProgressInfo> progress = lps;
\r
359 lps->Init(extractCallback, false);
\r
361 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
\r
362 CMyComPtr<ISequentialInStream> inStream(streamSpec);
\r
363 streamSpec->SetStream(_stream);
\r
365 for (i = 0; i < numItems; i++)
\r
367 lps->InSize = lps->OutSize = currentTotalSize;
\r
368 RINOK(lps->SetCur());
\r
369 CMyComPtr<ISequentialOutStream> realOutStream;
\r
370 Int32 askMode = testMode ?
\r
371 NExtract::NAskMode::kTest :
\r
372 NExtract::NAskMode::kExtract;
\r
373 Int32 index = allFilesMode ? i : indices[i];
\r
374 const CItem &item = _items[index];
\r
375 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
\r
376 currentTotalSize += item.Size;
\r
378 if (!testMode && !realOutStream)
\r
380 RINOK(extractCallback->PrepareOperation(askMode));
\r
383 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
\r
386 RINOK(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL));
\r
387 streamSpec->Init(item.Size);
\r
388 RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
\r
389 realOutStream.Release();
\r
390 RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
\r
391 NExtract::NOperationResult::kOK:
\r
392 NExtract::NOperationResult::kDataError));
\r
398 STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
\r
401 const CItem &item = _items[index];
\r
402 return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream);
\r
406 static IInArchive *CreateArc() { return new NArchive::NDeb::CHandler; }
\r
408 static CArcInfo g_ArcInfo =
\r
409 { L"Deb", L"deb", 0, 0xEC, { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' }, 8, false, CreateArc, 0 };
\r