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