1 #include "lz4.h"
2
3 #define LLOG(x) // LOG(x)
4
5 namespace Upp {
6
Init()7 void LZ4DecompressStream::Init()
8 {
9 for(int i = 0; i < 16; i++)
10 wb[i].Clear();
11 ii = 0;
12 count = 0;
13 dlen = 0;
14 pos = 0;
15 eof = false;
16 static byte h;
17 ptr = rdlim = buffer = &h;
18 xxh.Reset();
19 ClearError();
20 }
21
Open(Stream & in_)22 bool LZ4DecompressStream::Open(Stream& in_)
23 {
24 Init();
25
26 in = &in_;
27 String header_data = in->Get(7);
28 if(header_data.GetCount() < 7) {
29 SetError();
30 return false;
31 }
32
33 if(Peek32le(~header_data) != LZ4F_MAGIC) {
34 SetError();
35 return false;
36 }
37 lz4hdr = header_data[4];
38 if((lz4hdr & LZ4F_VERSIONMASK) != LZ4F_VERSION) {
39 SetError();
40 return false;
41 }
42 if(!(lz4hdr & LZ4F_BLOCKINDEPENDENCE)) { // dependent blocks not supported
43 SetError();
44 return false;
45 }
46 maxblock = header_data[5];
47 maxblock = decode(maxblock & LZ4F_MAXSIZEMASK,
48 LZ4F_MAXSIZE_64KB, 1024 * 64,
49 LZ4F_MAXSIZE_256KB, 1024 * 256,
50 LZ4F_MAXSIZE_1024KB, 1024 * 1024,
51 LZ4F_MAXSIZE_4096KB, 1024 * 4096,
52 -1);
53 if(maxblock < 0) {
54 SetError();
55 return false;
56 }
57
58 if((lz4hdr & LZ4F_CONTENTSIZE) && in->Get(8).GetCount() != 8) {
59 SetError();
60 return false;
61 }
62
63 return true;
64 }
65
Next()66 bool LZ4DecompressStream::Next()
67 {
68 pos += ptr - buffer;
69 ptr = rdlim = buffer;
70 if(ii < count) {
71 ptr = (byte *)~wb[ii].d;
72 Stream::buffer = ptr;
73 rdlim = ptr + wb[ii].dlen;
74 ii++;
75 return true;
76 }
77 return false;
78 }
79
80
Fetch()81 void LZ4DecompressStream::Fetch()
82 {
83 if(Next())
84 return;
85 if(eof)
86 return;
87 CoWork co;
88 bool error = false;
89 bool last = false;
90 ii = 0;
91 count = concurrent ? 16 : 1;
92 for(int i = 0; i < count; i++) {
93 Workblock& t = wb[i];
94 int blksz = in->Get32le();
95 if(blksz == 0) { // This is EOF
96 last = true;
97 count = i;
98 break;
99 }
100 t.clen = blksz & 0x7fffffff;
101 if(t.clen > maxblock) {
102 SetError();
103 return;
104 }
105 if(!t.c) {
106 t.c.Alloc(maxblock);
107 t.d.Alloc(maxblock);
108 }
109 if(blksz & 0x80000000) { // block is not compressed
110 t.dlen = t.clen;
111 if(!in->GetAll(~t.d, t.clen)) {
112 SetError();
113 return;
114 }
115 }
116 else {
117 if(!in->GetAll(~t.c, t.clen)) {
118 SetError();
119 return;
120 }
121 if(concurrent)
122 co & [=, &error] {
123 Workblock& t = wb[i];
124 t.dlen = LZ4_decompress_safe(~t.c, ~t.d, t.clen, maxblock);
125 CoWork::FinLock();
126 if(t.dlen < 0)
127 error = true;
128 };
129 else {
130 t.dlen = LZ4_decompress_safe(~t.c, ~t.d, t.clen, maxblock);
131 if(t.dlen < 0)
132 error = true;
133 }
134 }
135 if(lz4hdr & LZ4F_BLOCKCHECKSUM)
136 in->Get32le(); // just skip it
137 }
138 if(concurrent)
139 co.Finish();
140 if(error)
141 SetError();
142 else {
143 for(int i = 0; i < count; i++)
144 xxh.Put(wb[i].d, wb[i].dlen);
145 if(last) {
146 if(in->Get32le() != xxh.Finish())
147 SetError();
148 eof = true;
149 }
150 Next();
151 }
152 }
153
IsOpen() const154 bool LZ4DecompressStream::IsOpen() const
155 {
156 return in->IsOpen() && !IsError();
157 }
158
_Term()159 int LZ4DecompressStream::_Term()
160 {
161 if(Ended())
162 return -1;
163 Fetch();
164 return ptr == rdlim ? -1 : *ptr;
165 }
166
_Get()167 int LZ4DecompressStream::_Get()
168 {
169 if(Ended())
170 return -1;
171 Fetch();
172 return ptr == rdlim ? -1 : *ptr++;
173 }
174
_Get(void * data,dword size)175 dword LZ4DecompressStream::_Get(void *data, dword size)
176 {
177 byte *t = (byte *)data;
178 while(size) {
179 if(Ended())
180 break;
181 dword n = dword(rdlim - ptr);
182 if(size < n) {
183 memcpy(t, ptr, size);
184 t += size;
185 ptr += size;
186 break;
187 }
188 else {
189 memcpy(t, ptr, n);
190 t += n;
191 size -= n;
192 ptr = rdlim;
193 Fetch();
194 }
195 }
196
197 return dword(t - (byte *)data);
198 }
199
LZ4DecompressStream()200 LZ4DecompressStream::LZ4DecompressStream()
201 {
202 style = STRM_READ|STRM_LOADING;
203 in = NULL;
204 concurrent = false;
205 }
206
~LZ4DecompressStream()207 LZ4DecompressStream::~LZ4DecompressStream()
208 {
209 }
210
IsLZ4(Stream & s)211 bool IsLZ4(Stream& s)
212 {
213 int64 pos = s.GetPos();
214 bool b = s.Get32le() == LZ4F_MAGIC;
215 s.Seek(pos);
216 return b;
217 }
218
219 };
220