1 // CabBlockInStream.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../../C/Alloc.h"
6 #include "../../../../C/CpuArch.h"
7
8 #include "../../Common/StreamUtils.h"
9
10 #include "CabBlockInStream.h"
11
12 namespace NArchive {
13 namespace NCab {
14
15 static const UInt32 kBlockSize = 1 << 16;
16 static const unsigned k_OverReadPadZone_Size = 32;
17 static const unsigned kHeaderSize = 8;
18 static const unsigned kReservedMax = 256;
19 static const unsigned kHeaderOffset = kBlockSize + k_OverReadPadZone_Size;
20
Create()21 bool CBlockPackData::Create() throw()
22 {
23 if (!_buf)
24 _buf = (Byte *)z7_AlignedAlloc(kBlockSize + k_OverReadPadZone_Size + kHeaderSize + kReservedMax);
25 return _buf != NULL;
26 }
27
~CBlockPackData()28 CBlockPackData::~CBlockPackData() throw()
29 {
30 z7_AlignedFree(_buf);
31 }
32
CheckSum(const Byte * p,UInt32 size)33 static UInt32 CheckSum(const Byte *p, UInt32 size) throw()
34 {
35 #ifdef MY_CPU_64BIT
36
37 UInt64 sum64 = 0;
38 if (size >= 16)
39 {
40 const Byte *lim = p + (size_t)size - 16;
41 do
42 {
43 sum64 ^= GetUi64(p) ^ GetUi64(p + 8);
44 p += 16;
45 }
46 while (p <= lim);
47 size = (UInt32)(lim + 16 - p);
48 }
49 if (size >= 8)
50 {
51 sum64 ^= GetUi64(p);
52 p += 8;
53 size -= 8;
54 }
55
56 UInt32 sum = (UInt32)(sum64 >> 32) ^ (UInt32)sum64;
57
58 #else
59
60 UInt32 sum = 0;
61 if (size >= 16)
62 {
63 const Byte *lim = p + (size_t)size - 16;
64 do
65 {
66 sum ^= GetUi32(p)
67 ^ GetUi32(p + 4)
68 ^ GetUi32(p + 8)
69 ^ GetUi32(p + 12);
70 p += 16;
71 }
72 while (p <= lim);
73 size = (UInt32)(lim + 16 - p);
74 }
75 if (size >= 8)
76 {
77 sum ^= GetUi32(p + 0) ^ GetUi32(p + 4);
78 p += 8;
79 size -= 8;
80 }
81
82 #endif
83
84 if (size >= 4)
85 {
86 sum ^= GetUi32(p);
87 p += 4;
88 }
89 if (size &= 3)
90 {
91 if (size >= 2)
92 {
93 if (size > 2)
94 sum ^= (UInt32)(*p++) << 16;
95 sum ^= (UInt32)(*p++) << 8;
96 }
97 sum ^= (UInt32)(*p++);
98 }
99 return sum;
100 }
101
102
Read(ISequentialInStream * stream,Byte ReservedSize,UInt32 & packSizeRes,UInt32 & unpackSize)103 HRESULT CBlockPackData::Read(ISequentialInStream *stream, Byte ReservedSize, UInt32 &packSizeRes, UInt32 &unpackSize) throw()
104 {
105 const UInt32 reserved8 = kHeaderSize + ReservedSize;
106 const Byte *header = _buf + kHeaderOffset;
107 RINOK(ReadStream_FALSE(stream, (void *)header, reserved8))
108 unpackSize = GetUi16a(header + 6);
109 const UInt32 packSize = GetUi16a(header + 4);
110 packSizeRes = packSize;
111 if (packSize > kBlockSize - _size)
112 return S_FALSE;
113 RINOK(ReadStream_FALSE(stream, _buf + _size, packSize))
114 memset(_buf + _size + packSize, 0xff, k_OverReadPadZone_Size);
115 if (*(const UInt32 *)(const void *)header != 0) // checkSum
116 if (CheckSum(header, reserved8) != CheckSum(_buf + _size, packSize))
117 return S_FALSE;
118 _size += packSize;
119 return S_OK;
120 }
121
122 }}
123