1 #include "lz4.h"
2 
3 namespace Upp {
4 
Open(Stream & out_)5 void LZ4CompressStream::Open(Stream& out_)
6 {
7 	out = &out_;
8 	ClearError();
9 	pos = 0;
10 	xxh.Reset();
11 	Alloc();
12 	pos = 0;
13 	byte h[7];
14 	Poke32le(h, LZ4F_MAGIC);
15 	h[4] = LZ4F_VERSION | LZ4F_BLOCKINDEPENDENCE | LZ4F_CONTENTCHECKSUM;
16 	h[5] = LZ4F_MAXSIZE_1024KB;
17 	h[6] = xxHash(h + 4, 2) >> 8;
18 	out->Put(h, 7);
19 }
20 
Alloc()21 void LZ4CompressStream::Alloc()
22 {
23 	int N = 16;
24 	int sz = concurrent ? N * BLOCK_BYTES : BLOCK_BYTES;
25 	buffer.Alloc(sz);
26 	outbuf.Alloc(N * LZ4_compressBound(BLOCK_BYTES));
27 	outsz.Alloc(N);
28 	Stream::buffer = ~buffer;
29 	wrlim = ~buffer + sz;
30 	ptr = ~buffer;
31 }
32 
Co(bool b)33 void LZ4CompressStream::Co(bool b)
34 {
35 	FlushOut();
36 	concurrent = b;
37 	Alloc();
38 }
39 
FlushOut()40 void LZ4CompressStream::FlushOut()
41 {
42 	if(ptr == (byte *)~buffer)
43 		return;
44 
45 	CoWork co;
46 
47 	int osz = LZ4_compressBound(BLOCK_BYTES);
48 	byte *t = ~outbuf;
49 	int   ii = 0;
50 	for(byte *s = ~buffer; s < ptr; s += BLOCK_BYTES) {
51 		int origsize = min((int)BLOCK_BYTES, int(ptr - s));
52 		if(concurrent)
53 			co & [=] {
54 				outsz[ii] = LZ4_compress_default((char *)s, (char *)t, origsize, osz);
55 			};
56 		else
57 			outsz[ii] = LZ4_compress_default((char *)s, (char *)t, origsize, osz);
58 		ii++;
59 		t += osz;
60 	}
61 
62 	if(concurrent)
63 		co.Finish();
64 
65 	byte *s = ~buffer;
66 	t = ~outbuf;
67 	for(int i = 0; i < ii; i++) {
68 		int origsize = min((int)BLOCK_BYTES, int(ptr - s));
69 		int clen = outsz[i];
70 		if(clen < 0) {
71 			SetError();
72 			return;
73 		}
74 		if(clen >= origsize || clen == 0) {
75 			out->Put32le(0x80000000 | origsize);
76 			out->Put(s, origsize);
77 		}
78 		else {
79 			out->Put32le(clen);
80 			out->Put(t, clen);
81 		}
82 		s += BLOCK_BYTES;
83 		t += osz;
84 	}
85 
86 	int origsize = int(ptr - ~buffer);
87 	xxh.Put(~buffer, origsize);
88 	pos += origsize;
89 	ptr = ~buffer;
90 }
91 
Close()92 void LZ4CompressStream::Close()
93 {
94 	if(out) {
95 		FlushOut();
96 		out->Put32le(0);
97 		out->Put32le(xxh.Finish());
98 		out = NULL;
99 	}
100 }
101 
IsOpen() const102 bool LZ4CompressStream::IsOpen() const
103 {
104 	return out && out->IsOpen();
105 }
106 
_Put(int w)107 void LZ4CompressStream::_Put(int w)
108 {
109 	FlushOut();
110 	*ptr++ = w;
111 }
112 
_Put(const void * data,dword size)113 void LZ4CompressStream::_Put(const void *data, dword size)
114 {
115 	const char *s = reinterpret_cast<const char *>(data);
116 
117 	while(size > 0) {
118 		if(IsError() || out && out->IsError())
119 			return;
120 		dword n = dword(wrlim - ptr);
121 		if(size >= n) {
122 			memcpy(ptr, s, n);
123 			ptr = wrlim;
124 			FlushOut();
125 			size -= n;
126 			s += n;
127 		}
128 		else {
129 			memcpy(ptr, s, size);
130 			ptr += size;
131 			break;
132 		}
133 	}
134 }
135 
LZ4CompressStream()136 LZ4CompressStream::LZ4CompressStream()
137 {
138 	style = STRM_WRITE;
139 	concurrent = false;
140 	out = NULL;
141 }
142 
~LZ4CompressStream()143 LZ4CompressStream::~LZ4CompressStream()
144 {
145 	Close();
146 }
147 
148 };
149