Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_lzf_compression.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005-2006 Ariya Hidayat <ariya@kde.org>
3 * SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
9#include "kis_debug.h"
10
11
12#define HASH_LOG 12
13#define HASH_SIZE (1<< HASH_LOG)
14#define HASH_MASK (HASH_SIZE-1)
15
16#if !defined _MSC_VER
17#pragma GCC diagnostic ignored "-Wcast-align"
18#endif
19#define UPDATE_HASH(v,p) { v = *((quint16*)p); v ^= *((quint16*)(p+1))^(v>>(16-HASH_LOG)); }
20
21#define MAX_COPY 32
22#define MAX_LEN 264 /* 256 + 8 */
23#define MAX_DISTANCE 8192
24
25
26// Lossless compression using LZF algorithm, this is faster on modern CPU than
27// the original implementation in http://liblzf.plan9.de/
28int lzff_compress(const void* input, int length, void* output, int /*maxout*/)
29{
30 const quint8* ip = (const quint8*) input;
31 const quint8* ip_limit = ip + length - MAX_COPY - 4;
32 quint8* op = (quint8*) output;
33
34 const quint8* htab[HASH_SIZE];
35 const quint8** hslot;
36 quint32 hval;
37
38 quint8* ref;
39 qint32 copy;
40 qint32 len;
41 qint32 distance;
42 quint8* anchor;
43
44 /* initializes hash table */
45 for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
46 *hslot = ip;
47
48 /* we start with literal copy */
49 copy = 0;
50 *op++ = MAX_COPY - 1;
51
52 /* main loop */
53 while (ip < ip_limit) {
54 /* find potential match */
55 UPDATE_HASH(hval, ip);
56 hslot = htab + (hval & HASH_MASK);
57 ref = (quint8*) * hslot;
58
59 /* update hash table */
60 *hslot = ip;
61
62 /* find itself? then it's no match */
63 if (ip == ref)
64 goto literal;
65
66 /* is this a match? check the first 2 bytes */
67 if (*((quint16*)ref) != *((quint16*)ip))
68 goto literal;
69
70 /* now check the 3rd byte */
71 if (ref[2] != ip[2])
72 goto literal;
73
74 /* calculate distance to the match */
75 distance = ip - ref;
76
77 /* skip if too far away */
79 goto literal;
80
81 /* here we have 3-byte matches */
82 anchor = (quint8*)ip;
83 len = 3;
84 ref += 3;
85 ip += 3;
86
87 /* now we have to check how long the match is */
88 if (ip < ip_limit - MAX_LEN) {
89 while (len < MAX_LEN - 8) {
90 /* unroll 8 times */
91 if (*ref++ != *ip++) break;
92 if (*ref++ != *ip++) break;
93 if (*ref++ != *ip++) break;
94 if (*ref++ != *ip++) break;
95 if (*ref++ != *ip++) break;
96 if (*ref++ != *ip++) break;
97 if (*ref++ != *ip++) break;
98 if (*ref++ != *ip++) break;
99 len += 8;
100 }
101 ip--;
102 }
103 len = ip - anchor;
104
105 /* just before the last non-matching byte */
106 ip = anchor + len;
107
108 /* if we have copied something, adjust the copy count */
109 if (copy) {
110 /* copy is biased, '0' means 1 byte copy */
111 anchor = anchor - copy - 1;
112 *(op - copy - 1) = copy - 1;
113 copy = 0;
114 } else
115 /* back, to overwrite the copy count */
116 op--;
117
118 /* length is biased, '1' means a match of 3 bytes */
119 len -= 2;
120
121 /* distance is also biased */
122 distance--;
123
124 /* encode the match */
125 if (len < 7)
126 *op++ = (len << 5) + (distance >> 8);
127 else {
128 *op++ = (7 << 5) + (distance >> 8);
129 *op++ = len - 7;
130 }
131 *op++ = (distance & 255);
132
133 /* assuming next will be literal copy */
134 *op++ = MAX_COPY - 1;
135
136 /* update the hash at match boundary */
137 --ip;
138 UPDATE_HASH(hval, ip);
139 htab[hval & HASH_MASK] = ip;
140 ip++;
141
142 continue;
143
144 literal:
145 *op++ = *ip++;
146 copy++;
147 if (copy >= MAX_COPY) {
148 copy = 0;
149 *op++ = MAX_COPY - 1;
150 }
151 }
152
153 /* left-over as literal copy */
154 ip_limit = (const quint8*)input + length;
155 while (ip < ip_limit) {
156 *op++ = *ip++;
157 copy++;
158 if (copy == MAX_COPY) {
159 copy = 0;
160 *op++ = MAX_COPY - 1;
161 }
162 }
163
164 /* if we have copied something, adjust the copy length */
165 if (copy)
166 *(op - copy - 1) = copy - 1;
167 else
168 op--;
169
170 return op - (quint8*)output;
171}
172
173int lzff_decompress(const void* input, int length, void* output, int maxout)
174{
175 const quint8* ip = (const quint8*) input;
176 const quint8* ip_limit = ip + length - 1;
177 quint8* op = (quint8*) output;
178 quint8* op_limit = op + maxout;
179 quint8* ref;
180
181 while (ip < ip_limit) {
182 quint32 ctrl = (*ip) + 1;
183 quint32 ofs = ((*ip) & 31) << 8;
184 quint32 len = (*ip++) >> 5;
185
186 if (ctrl < 33) {
187 /* literal copy */
188 if (op + ctrl > op_limit)
189 return 0;
190
191 /* crazy unrolling */
192 if (ctrl) {
193 *op++ = *ip++;
194 ctrl--;
195
196 if (ctrl) {
197 *op++ = *ip++;
198 ctrl--;
199
200 if (ctrl) {
201 *op++ = *ip++;
202 ctrl--;
203
204 for (; ctrl; ctrl--)
205 *op++ = *ip++;
206 }
207 }
208 }
209 } else {
210 /* back reference */
211 len--;
212 ref = op - ofs;
213 ref--;
214
215 if (len == 7 - 1)
216 len += *ip++;
217
218 ref -= *ip++;
219
220 if (op + len + 3 > op_limit)
221 return 0;
222
223 if (ref < (quint8 *)output)
224 return 0;
225
226 *op++ = *ref++;
227 *op++ = *ref++;
228 *op++ = *ref++;
229 if (len)
230 for (; len; --len)
231 *op++ = *ref++;
232 }
233 }
234
235 return op - (quint8*)output;
236}
237
238
239
248
252
253qint32 KisLzfCompression::compress(const quint8* input, qint32 inputLength, quint8* output, qint32 outputLength)
254{
255 return lzff_compress(input, inputLength, output, outputLength);
256}
257
258qint32 KisLzfCompression::decompress(const quint8* input, qint32 inputLength, quint8* output, qint32 outputLength)
259{
260 return lzff_decompress(input, inputLength, output, outputLength);
261}
262
264{
265 // WARNING: Copy-pasted from LZO samples, do not know how to prove it
266 return dataSize + dataSize / 16 + 64 + 3;
267}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
qreal distance(const QPointF &p1, const QPointF &p2)
qint32 compress(const quint8 *input, qint32 inputLength, quint8 *output, qint32 outputLength) override
qint32 decompress(const quint8 *input, qint32 inputLength, quint8 *output, qint32 outputLength) override
qint32 outputBufferSize(qint32 dataSize) override
#define MAX_DISTANCE
int lzff_decompress(const void *input, int length, void *output, int maxout)
int lzff_compress(const void *input, int length, void *output, int)
#define HASH_MASK
#define MAX_COPY
#define MAX_LEN
#define UPDATE_HASH(v, p)
#define HASH_SIZE