~ubuntu-branches/ubuntu/precise/p7zip/precise-updates

« back to all changes in this revision

Viewing changes to CPP/7zip/Archive/DebHandler.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mohammed Adnène Trojette
  • Date: 2009-02-14 20:12:27 UTC
  • mfrom: (1.1.11 upstream) (2.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090214201227-go63qxm9ozfdma60
Tags: 4.65~dfsg.1-1
* New upstream release.
* Remove wx2.8 Build-Depends added by mistakes (7zG is not yet
  intended to be built).
* Use dh_clean without -k.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// DebHandler.cpp
 
2
 
 
3
#include "StdAfx.h"
 
4
 
 
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"
 
10
 
 
11
#include "Windows/PropVariant.h"
 
12
#include "Windows/Time.h"
 
13
 
 
14
#include "../Common/LimitedStreams.h"
 
15
#include "../Common/ProgressUtils.h"
 
16
#include "../Common/RegisterArc.h"
 
17
#include "../Common/StreamUtils.h"
 
18
 
 
19
#include "../Compress/CopyCoder.h"
 
20
 
 
21
#include "Common/ItemNameUtils.h"
 
22
 
 
23
using namespace NWindows;
 
24
using namespace NTime;
 
25
 
 
26
namespace NArchive {
 
27
namespace NDeb {
 
28
 
 
29
namespace NHeader
 
30
{
 
31
  const int kSignatureLen = 8;
 
32
  
 
33
  const char *kSignature  = "!<arch>\n";
 
34
 
 
35
  const int kNameSize = 16;
 
36
  const int kTimeSize = 12;
 
37
  const int kModeSize = 8;
 
38
  const int kSizeSize = 10;
 
39
 
 
40
  /*
 
41
  struct CHeader
 
42
  {
 
43
    char Name[kNameSize];
 
44
    char MTime[kTimeSize];
 
45
    char Number0[6];
 
46
    char Number1[6];
 
47
    char Mode[kModeSize];
 
48
    char Size[kSizeSize];
 
49
    char Quote;
 
50
    char NewLine;
 
51
  };
 
52
  */
 
53
  const int kHeaderSize = kNameSize + kTimeSize + 6 + 6 + kModeSize + kSizeSize + 1 + 1;
 
54
}
 
55
 
 
56
class CItem
 
57
{
 
58
public:
 
59
  AString Name;
 
60
  UInt64 Size;
 
61
  UInt32 MTime;
 
62
  UInt32 Mode;
 
63
};
 
64
 
 
65
class CItemEx: public CItem
 
66
{
 
67
public:
 
68
  UInt64 HeaderPosition;
 
69
  UInt64 GetDataPosition() const { return HeaderPosition + NHeader::kHeaderSize; };
 
70
  // UInt64 GetFullSize() const { return NFileHeader::kRecordSize + Size; };
 
71
};
 
72
 
 
73
class CInArchive
 
74
{
 
75
  CMyComPtr<IInStream> m_Stream;
 
76
  UInt64 m_Position;
 
77
  
 
78
  HRESULT GetNextItemReal(bool &filled, CItemEx &itemInfo);
 
79
  HRESULT Skeep(UInt64 numBytes);
 
80
public:
 
81
  HRESULT Open(IInStream *inStream);
 
82
  HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
 
83
  HRESULT SkeepData(UInt64 dataSize);
 
84
};
 
85
 
 
86
HRESULT CInArchive::Open(IInStream *inStream)
 
87
{
 
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)
 
93
    return S_FALSE;
 
94
  m_Stream = inStream;
 
95
  return S_OK;
 
96
}
 
97
 
 
98
static void MyStrNCpy(char *dest, const char *src, int size)
 
99
{
 
100
  for (int i = 0; i < size; i++)
 
101
  {
 
102
    char c = src[i];
 
103
    dest[i] = c;
 
104
    if (c == 0)
 
105
      break;
 
106
  }
 
107
}
 
108
 
 
109
static bool OctalToNumber(const char *s, int size, UInt64 &res)
 
110
{
 
111
  char sz[32];
 
112
  MyStrNCpy(sz, s, size);
 
113
  sz[size] = 0;
 
114
  const char *end;
 
115
  int i;
 
116
  for (i = 0; sz[i] == ' '; i++);
 
117
  res = ConvertOctStringToUInt64(sz + i, &end);
 
118
  return (*end == ' ' || *end == 0);
 
119
}
 
120
 
 
121
static bool OctalToNumber32(const char *s, int size, UInt32 &res)
 
122
{
 
123
  UInt64 res64;
 
124
  if (!OctalToNumber(s, size, res64))
 
125
    return false;
 
126
  res = (UInt32)res64;
 
127
  return (res64 <= 0xFFFFFFFF);
 
128
}
 
129
 
 
130
static bool DecimalToNumber(const char *s, int size, UInt64 &res)
 
131
{
 
132
  char sz[32];
 
133
  MyStrNCpy(sz, s, size);
 
134
  sz[size] = 0;
 
135
  const char *end;
 
136
  int i;
 
137
  for (i = 0; sz[i] == ' '; i++);
 
138
  res = ConvertStringToUInt64(sz + i, &end);
 
139
  return (*end == ' ' || *end == 0);
 
140
}
 
141
 
 
142
static bool DecimalToNumber32(const char *s, int size, UInt32 &res)
 
143
{
 
144
  UInt64 res64;
 
145
  if (!DecimalToNumber(s, size, res64))
 
146
    return false;
 
147
  res = (UInt32)res64;
 
148
  return (res64 <= 0xFFFFFFFF);
 
149
}
 
150
 
 
151
#define RIF(x) { if (!(x)) return S_FALSE; }
 
152
 
 
153
 
 
154
HRESULT CInArchive::GetNextItemReal(bool &filled, CItemEx &item)
 
155
{
 
156
  filled = false;
 
157
 
 
158
  char header[NHeader::kHeaderSize];
 
159
  const char *cur = header;
 
160
 
 
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))
 
166
    return S_OK;
 
167
  
 
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;
 
173
  item.Name.Trim();
 
174
 
 
175
  for (int i = 0; i < item.Name.Length(); i++)
 
176
    if (((Byte)item.Name[i]) < 0x20)
 
177
      return S_FALSE;
 
178
 
 
179
  RIF(DecimalToNumber32(cur, NHeader::kTimeSize, item.MTime));
 
180
  cur += NHeader::kTimeSize;
 
181
 
 
182
  cur += 6 + 6;
 
183
  
 
184
  RIF(OctalToNumber32(cur, NHeader::kModeSize, item.Mode));
 
185
  cur += NHeader::kModeSize;
 
186
 
 
187
  RIF(DecimalToNumber(cur, NHeader::kSizeSize, item.Size));
 
188
  cur += NHeader::kSizeSize;
 
189
 
 
190
  filled = true;
 
191
  return S_OK;
 
192
}
 
193
 
 
194
HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
 
195
{
 
196
  for (;;)
 
197
  {
 
198
    RINOK(GetNextItemReal(filled, item));
 
199
    if (!filled)
 
200
      return S_OK;
 
201
    if (item.Name.Compare("debian-binary") != 0)
 
202
      return S_OK;
 
203
    if (item.Size != 4)
 
204
      return S_OK;
 
205
    SkeepData(item.Size);
 
206
  }
 
207
}
 
208
 
 
209
HRESULT CInArchive::Skeep(UInt64 numBytes)
 
210
{
 
211
  UInt64 newPostion;
 
212
  RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
 
213
  m_Position += numBytes;
 
214
  if (m_Position != newPostion)
 
215
    return E_FAIL;
 
216
  return S_OK;
 
217
}
 
218
 
 
219
HRESULT CInArchive::SkeepData(UInt64 dataSize)
 
220
{
 
221
  return Skeep((dataSize + 1) & (~((UInt64)0x1)));
 
222
}
 
223
 
 
224
 
 
225
class CHandler:
 
226
  public IInArchive,
 
227
  public CMyUnknownImp
 
228
{
 
229
public:
 
230
  MY_UNKNOWN_IMP1(IInArchive)
 
231
 
 
232
  INTERFACE_IInArchive(;)
 
233
 
 
234
private:
 
235
  CObjectVector<CItemEx> _items;
 
236
  CMyComPtr<IInStream> _inStream;
 
237
};
 
238
 
 
239
 
 
240
STATPROPSTG kProps[] =
 
241
{
 
242
  { NULL, kpidPath, VT_BSTR},
 
243
  { NULL, kpidSize, VT_UI8},
 
244
  { NULL, kpidPackSize, VT_UI8},
 
245
  { NULL, kpidMTime, VT_FILETIME}
 
246
};
 
247
 
 
248
IMP_IInArchive_Props
 
249
IMP_IInArchive_ArcProps_NO
 
250
 
 
251
STDMETHODIMP CHandler::Open(IInStream *stream,
 
252
    const UInt64 * /* maxCheckStartPosition */,
 
253
    IArchiveOpenCallback *openArchiveCallback)
 
254
{
 
255
  COM_TRY_BEGIN
 
256
  {
 
257
    CInArchive archive;
 
258
    if(archive.Open(stream) != S_OK)
 
259
      return S_FALSE;
 
260
    _items.Clear();
 
261
 
 
262
    if (openArchiveCallback != NULL)
 
263
    {
 
264
      RINOK(openArchiveCallback->SetTotal(NULL, NULL));
 
265
      UInt64 numFiles = _items.Size();
 
266
      RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
 
267
    }
 
268
 
 
269
    for (;;)
 
270
    {
 
271
      CItemEx item;
 
272
      bool filled;
 
273
      HRESULT result = archive.GetNextItem(filled, item);
 
274
      if (result == S_FALSE)
 
275
        return S_FALSE;
 
276
      if (result != S_OK)
 
277
        return S_FALSE;
 
278
      if (!filled)
 
279
        break;
 
280
      _items.Add(item);
 
281
      archive.SkeepData(item.Size);
 
282
      if (openArchiveCallback != NULL)
 
283
      {
 
284
        UInt64 numFiles = _items.Size();
 
285
        RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
 
286
      }
 
287
    }
 
288
    _inStream = stream;
 
289
  }
 
290
  return S_OK;
 
291
  COM_TRY_END
 
292
}
 
293
 
 
294
STDMETHODIMP CHandler::Close()
 
295
{
 
296
  _inStream.Release();
 
297
  _items.Clear();
 
298
  return S_OK;
 
299
}
 
300
 
 
301
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
 
302
{
 
303
  *numItems = _items.Size();
 
304
  return S_OK;
 
305
}
 
306
 
 
307
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
 
308
{
 
309
  COM_TRY_BEGIN
 
310
  NWindows::NCOM::CPropVariant prop;
 
311
  const CItemEx &item = _items[index];
 
312
 
 
313
  switch(propID)
 
314
  {
 
315
    case kpidPath: prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
 
316
    case kpidSize:
 
317
    case kpidPackSize:
 
318
      prop = item.Size;
 
319
      break;
 
320
    case kpidMTime:
 
321
    {
 
322
      if (item.MTime != 0)
 
323
      {
 
324
        FILETIME fileTime;
 
325
        NTime::UnixTimeToFileTime(item.MTime, fileTime);
 
326
        prop = fileTime;
 
327
      }
 
328
      break;
 
329
    }
 
330
  }
 
331
  prop.Detach(value);
 
332
  return S_OK;
 
333
  COM_TRY_END
 
334
}
 
335
 
 
336
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
 
337
    Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
 
338
{
 
339
  COM_TRY_BEGIN
 
340
  bool testMode = (_aTestMode != 0);
 
341
  bool allFilesMode = (numItems == UInt32(-1));
 
342
  if (allFilesMode)
 
343
    numItems = _items.Size();
 
344
  if (numItems == 0)
 
345
    return S_OK;
 
346
  UInt64 totalSize = 0;
 
347
  UInt32 i;
 
348
  for (i = 0; i < numItems; i++)
 
349
    totalSize += _items[allFilesMode ? i : indices[i]].Size;
 
350
  extractCallback->SetTotal(totalSize);
 
351
 
 
352
  UInt64 currentTotalSize = 0;
 
353
  UInt64 currentItemSize;
 
354
  
 
355
  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
 
356
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
 
357
 
 
358
  CLocalProgress *lps = new CLocalProgress;
 
359
  CMyComPtr<ICompressProgressInfo> progress = lps;
 
360
  lps->Init(extractCallback, false);
 
361
 
 
362
  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
 
363
  CMyComPtr<ISequentialInStream> inStream(streamSpec);
 
364
  streamSpec->SetStream(_inStream);
 
365
 
 
366
  for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
 
367
  {
 
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;
 
378
    
 
379
    
 
380
    
 
381
    
 
382
    
 
383
    
 
384
    if (!testMode && (!realOutStream))
 
385
      continue;
 
386
    RINOK(extractCallback->PrepareOperation(askMode));
 
387
    if (testMode)
 
388
    {
 
389
      RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
 
390
      continue;
 
391
    }
 
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));
 
399
  }
 
400
  return S_OK;
 
401
  COM_TRY_END
 
402
}
 
403
 
 
404
static IInArchive *CreateArc() { return new NArchive::NDeb::CHandler;  }
 
405
 
 
406
static CArcInfo g_ArcInfo =
 
407
  { L"Deb", L"deb", 0, 0xEC, { '!', '<', 'a', 'r', 'c', 'h', '>', '\n'  }, 8, false, CreateArc, 0 };
 
408
 
 
409
REGISTER_ARC(Deb)
 
410
 
 
411
}}