Welcome to mirror list, hosted at ThFree Co, Russian Federation.

CabBlockInStream.cpp « Cab « Archive « 7zip « CPP - github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c193434f9eeab220c5c5cae603a2b704936baf93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// CabBlockInStream.cpp

#include "StdAfx.h"

#include "../../../../C/Alloc.h"
#include "../../../../C/CpuArch.h"

#include "../../Common/StreamUtils.h"

#include "CabBlockInStream.h"

namespace NArchive {
namespace NCab {

static const UInt32 kBlockSize = (1 << 16);

bool CCabBlockInStream::Create()
{
  if (!_buf)
    _buf = (Byte *)::MyAlloc(kBlockSize);
  return _buf != 0;
}

CCabBlockInStream::~CCabBlockInStream()
{
  ::MyFree(_buf);
}

static UInt32 CheckSum(const Byte *p, UInt32 size)
{
  UInt32 sum = 0;
  
  for (; size >= 8; size -= 8)
  {
    sum ^= GetUi32(p) ^ GetUi32(p + 4);
    p += 8;
  }
  
  if (size >= 4)
  {
    sum ^= GetUi32(p);
    p += 4;
  }
  
  size &= 3;
  if (size > 2) sum ^= (UInt32)(*p++) << 16;
  if (size > 1) sum ^= (UInt32)(*p++) << 8;
  if (size > 0) sum ^= (UInt32)(*p++);
  
  return sum;
}

HRESULT CCabBlockInStream::PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize)
{
  const UInt32 kHeaderSize = 8;
  const UInt32 kReservedMax = 256;
  Byte header[kHeaderSize + kReservedMax];
  RINOK(ReadStream_FALSE(stream, header, kHeaderSize + ReservedSize))
  packSize = GetUi16(header + 4);
  unpackSize = GetUi16(header + 6);
  if (packSize > kBlockSize - _size)
    return S_FALSE;
  RINOK(ReadStream_FALSE(stream, _buf + _size, packSize));
  
  if (MsZip)
  {
    if (_size == 0)
    {
      if (packSize < 2 || _buf[0] != 0x43 || _buf[1] != 0x4B)
        return S_FALSE;
      _pos = 2;
    }
    if (_size + packSize > ((UInt32)1 << 15) + 12) /* v9.31 fix. MSZIP specification */
      return S_FALSE;
  }

  if (GetUi32(header) != 0) // checkSum
    if (CheckSum(header, kHeaderSize + ReservedSize) != CheckSum(_buf + _size, packSize))
      return S_FALSE;

  _size += packSize;
  return S_OK;
}

STDMETHODIMP CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{
  if (size != 0)
  {
    UInt32 rem = _size - _pos;
    if (size > rem)
      size = rem;
    memcpy(data, _buf + _pos, size);
    _pos += size;
  }
  if (processedSize)
    *processedSize = size;
  return S_OK;
}

}}