/src/lzo-2.10/src/lzo1f_1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* lzo1f_1.c -- implementation of the LZO1F-1 compression algorithm |
2 | | |
3 | | This file is part of the LZO real-time data compression library. |
4 | | |
5 | | Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer |
6 | | All Rights Reserved. |
7 | | |
8 | | The LZO library is free software; you can redistribute it and/or |
9 | | modify it under the terms of the GNU General Public License as |
10 | | published by the Free Software Foundation; either version 2 of |
11 | | the License, or (at your option) any later version. |
12 | | |
13 | | The LZO library is distributed in the hope that it will be useful, |
14 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | GNU General Public License for more details. |
17 | | |
18 | | You should have received a copy of the GNU General Public License |
19 | | along with the LZO library; see the file COPYING. |
20 | | If not, write to the Free Software Foundation, Inc., |
21 | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
22 | | |
23 | | Markus F.X.J. Oberhumer |
24 | | <markus@oberhumer.com> |
25 | | http://www.oberhumer.com/opensource/lzo/ |
26 | | */ |
27 | | |
28 | | |
29 | | #include "lzo_conf.h" |
30 | | #include <lzo/lzo1f.h> |
31 | | |
32 | | |
33 | | /*********************************************************************** |
34 | | // |
35 | | ************************************************************************/ |
36 | | |
37 | 3.82M | #define M2_MAX_OFFSET 0x0800 |
38 | | #define M3_MAX_OFFSET 0x3fff |
39 | 11.7k | #define M3_MARKER 224 |
40 | | |
41 | | |
42 | | #ifndef LZO_HASH |
43 | | #define LZO_HASH LZO_HASH_LZO_INCREMENTAL_A |
44 | | #endif |
45 | | #define D_BITS 14 |
46 | 2.49M | #define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) |
47 | 816k | #define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) |
48 | | #include "lzo_dict.h" |
49 | | |
50 | | |
51 | | /*********************************************************************** |
52 | | // compress a block of data. |
53 | | ************************************************************************/ |
54 | | |
55 | | static __lzo_noinline |
56 | | int do_compress ( const lzo_bytep in , lzo_uint in_len, |
57 | | lzo_bytep out, lzo_uintp out_len, |
58 | | lzo_voidp wrkmem ) |
59 | 420 | { |
60 | 420 | const lzo_bytep ip; |
61 | 420 | lzo_bytep op; |
62 | 420 | const lzo_bytep const in_end = in + in_len; |
63 | 420 | const lzo_bytep const ip_end = in + in_len - 9; |
64 | 420 | const lzo_bytep ii; |
65 | 420 | lzo_dict_p const dict = (lzo_dict_p) wrkmem; |
66 | | |
67 | 420 | op = out; |
68 | 420 | ip = in; |
69 | 420 | ii = ip; |
70 | | |
71 | 420 | ip++; |
72 | 420 | for (;;) |
73 | 2.49M | { |
74 | 2.49M | const lzo_bytep m_pos; |
75 | 2.49M | LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0); |
76 | 2.49M | lzo_uint m_len; |
77 | 2.49M | lzo_uint dindex; |
78 | 2.49M | lzo_uint lit; |
79 | | |
80 | 2.49M | DINDEX1(dindex,ip); |
81 | 2.49M | GINDEX(m_pos,m_off,dict,dindex,in); |
82 | 2.49M | if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M3_MAX_OFFSET)) |
83 | 1.34M | goto literal; |
84 | 1.15M | #if 1 |
85 | 1.15M | if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) |
86 | 334k | goto try_match; |
87 | 816k | DINDEX2(dindex,ip); |
88 | 816k | #endif |
89 | 816k | GINDEX(m_pos,m_off,dict,dindex,in); |
90 | 816k | if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M3_MAX_OFFSET)) |
91 | 84.5k | goto literal; |
92 | 731k | if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) |
93 | 336k | goto try_match; |
94 | 394k | goto literal; |
95 | | |
96 | | |
97 | 670k | try_match: |
98 | | #if 0 && (LZO_OPT_UNALIGNED16) |
99 | | if (UA_GET_NE16(m_pos) != UA_GET_NE16(ip)) |
100 | | #else |
101 | 670k | if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) |
102 | 568k | #endif |
103 | 568k | { |
104 | 568k | } |
105 | 102k | else |
106 | 102k | { |
107 | 102k | if (m_pos[2] == ip[2]) |
108 | 85.3k | { |
109 | 85.3k | m_pos += 3; |
110 | | #if 0 |
111 | | if (m_off <= M2_MAX_OFFSET) |
112 | | goto match; |
113 | | if (lit <= 3) |
114 | | goto match; |
115 | | if (lit == 3) /* better compression, but slower */ |
116 | | { |
117 | | assert(op - 2 > out); op[-2] |= LZO_BYTE(3); |
118 | | *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; |
119 | | goto code_match; |
120 | | } |
121 | | if (*m_pos == ip[3]) |
122 | | #endif |
123 | 85.3k | goto match; |
124 | 85.3k | } |
125 | 102k | } |
126 | | |
127 | | |
128 | | /* a literal */ |
129 | 2.40M | literal: |
130 | 2.40M | UPDATE_I(dict,0,dindex,ip,in); |
131 | 2.40M | if (++ip >= ip_end) |
132 | 164 | break; |
133 | 2.40M | continue; |
134 | | |
135 | | |
136 | | /* a match */ |
137 | 2.40M | match: |
138 | 85.3k | UPDATE_I(dict,0,dindex,ip,in); |
139 | | /* store current literal run */ |
140 | 85.3k | lit = pd(ip,ii); |
141 | 85.3k | if (lit > 0) |
142 | 34.7k | { |
143 | 34.7k | lzo_uint t = lit; |
144 | | |
145 | 34.7k | if (t < 4 && op > out) |
146 | 19.8k | op[-2] = LZO_BYTE(op[-2] | t); |
147 | 14.8k | else if (t <= 31) |
148 | 12.3k | *op++ = LZO_BYTE(t); |
149 | 2.57k | else |
150 | 2.57k | { |
151 | 2.57k | lzo_uint tt = t - 31; |
152 | | |
153 | 2.57k | *op++ = 0; |
154 | 7.80k | while (tt > 255) |
155 | 5.23k | { |
156 | 5.23k | tt -= 255; |
157 | 5.23k | UA_SET1(op, 0); |
158 | 5.23k | op++; |
159 | 5.23k | } |
160 | 2.57k | assert(tt > 0); |
161 | 2.57k | *op++ = LZO_BYTE(tt); |
162 | 2.57k | } |
163 | 1.73M | do *op++ = *ii++; while (--t > 0); |
164 | 34.7k | } |
165 | 85.3k | assert(ii == ip); |
166 | | |
167 | | |
168 | | /* code the match */ |
169 | 85.3k | ip += 3; |
170 | 85.3k | if (*m_pos++ != *ip++ || *m_pos++ != *ip++ || *m_pos++ != *ip++ || |
171 | 85.3k | *m_pos++ != *ip++ || *m_pos++ != *ip++ || *m_pos++ != *ip++) |
172 | 57.1k | { |
173 | 57.1k | --ip; |
174 | 57.1k | m_len = pd(ip, ii); |
175 | 57.1k | assert(m_len >= 3); assert(m_len <= 8); |
176 | | |
177 | 57.1k | if (m_off <= M2_MAX_OFFSET) |
178 | 49.1k | { |
179 | 49.1k | m_off -= 1; |
180 | 49.1k | *op++ = LZO_BYTE(((m_len - 2) << 5) | ((m_off & 7) << 2)); |
181 | 49.1k | *op++ = LZO_BYTE(m_off >> 3); |
182 | 49.1k | } |
183 | 8.08k | else if (m_len == 3 && m_off <= 2*M2_MAX_OFFSET && lit > 0) |
184 | 0 | { |
185 | 0 | m_off -= 1; |
186 | | /* m_off -= M2_MAX_OFFSET; */ |
187 | 0 | *op++ = LZO_BYTE(((m_off & 7) << 2)); |
188 | 0 | *op++ = LZO_BYTE(m_off >> 3); |
189 | 0 | } |
190 | 8.08k | else |
191 | 8.08k | { |
192 | 8.08k | *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); |
193 | 8.08k | *op++ = LZO_BYTE((m_off & 63) << 2); |
194 | 8.08k | *op++ = LZO_BYTE(m_off >> 6); |
195 | 8.08k | } |
196 | 57.1k | } |
197 | 28.1k | else |
198 | 28.1k | { |
199 | 28.1k | { |
200 | 28.1k | const lzo_bytep end; |
201 | 28.1k | end = in_end; |
202 | 7.34M | while (ip < end && *m_pos == *ip) |
203 | 7.31M | { m_pos++; ip++; } |
204 | 28.1k | m_len = pd(ip, ii); |
205 | 28.1k | } |
206 | 28.1k | assert(m_len >= 3); |
207 | | |
208 | 28.1k | if (m_len <= 33) |
209 | 16.8k | *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); |
210 | 11.3k | else |
211 | 11.3k | { |
212 | 11.3k | m_len -= 33; |
213 | 11.3k | *op++ = M3_MARKER | 0; |
214 | 34.6k | while (m_len > 255) |
215 | 23.3k | { |
216 | 23.3k | m_len -= 255; |
217 | 23.3k | UA_SET1(op, 0); |
218 | 23.3k | op++; |
219 | 23.3k | } |
220 | 11.3k | assert(m_len > 0); |
221 | 11.3k | *op++ = LZO_BYTE(m_len); |
222 | 11.3k | } |
223 | 28.1k | *op++ = LZO_BYTE((m_off & 63) << 2); |
224 | 28.1k | *op++ = LZO_BYTE(m_off >> 6); |
225 | 28.1k | } |
226 | | |
227 | 85.3k | ii = ip; |
228 | 85.3k | if (ip >= ip_end) |
229 | 256 | break; |
230 | 85.3k | } |
231 | | |
232 | | |
233 | | /* store final literal run */ |
234 | 420 | if (pd(in_end,ii) > 0) |
235 | 375 | { |
236 | 375 | lzo_uint t = pd(in_end,ii); |
237 | | |
238 | 375 | if (t < 4 && op > out) |
239 | 55 | op[-2] = LZO_BYTE(op[-2] | t); |
240 | 320 | else if (t <= 31) |
241 | 234 | *op++ = LZO_BYTE(t); |
242 | 86 | else |
243 | 86 | { |
244 | 86 | lzo_uint tt = t - 31; |
245 | | |
246 | 86 | *op++ = 0; |
247 | 2.65k | while (tt > 255) |
248 | 2.57k | { |
249 | 2.57k | tt -= 255; |
250 | 2.57k | UA_SET1(op, 0); |
251 | 2.57k | op++; |
252 | 2.57k | } |
253 | 86 | assert(tt > 0); |
254 | 86 | *op++ = LZO_BYTE(tt); |
255 | 86 | } |
256 | 375 | UA_COPYN(op, ii, t); |
257 | 375 | op += t; |
258 | 375 | } |
259 | | |
260 | 420 | *out_len = pd(op, out); |
261 | 420 | return LZO_E_OK; |
262 | 420 | } |
263 | | |
264 | | |
265 | | /*********************************************************************** |
266 | | // public entry point |
267 | | ************************************************************************/ |
268 | | |
269 | | LZO_PUBLIC(int) |
270 | | lzo1f_1_compress ( const lzo_bytep in , lzo_uint in_len, |
271 | | lzo_bytep out, lzo_uintp out_len, |
272 | | lzo_voidp wrkmem ) |
273 | 429 | { |
274 | 429 | lzo_bytep op = out; |
275 | 429 | int r = LZO_E_OK; |
276 | | |
277 | 429 | if (in_len == 0) |
278 | 1 | *out_len = 0; |
279 | 428 | else if (in_len <= 10) |
280 | 8 | { |
281 | 8 | *op++ = LZO_BYTE(in_len); |
282 | 39 | do *op++ = *in++; while (--in_len > 0); |
283 | 8 | *out_len = pd(op, out); |
284 | 8 | } |
285 | 420 | else |
286 | 420 | r = do_compress(in,in_len,out,out_len,wrkmem); |
287 | | |
288 | 429 | if (r == LZO_E_OK) |
289 | 429 | { |
290 | 429 | op = out + *out_len; |
291 | 429 | op[0] = M3_MARKER | 1; |
292 | 429 | op[1] = 0; |
293 | 429 | op[2] = 0; |
294 | 429 | *out_len += 3; |
295 | 429 | } |
296 | | |
297 | 429 | return r; |
298 | 429 | } |
299 | | |
300 | | |
301 | | /* vim:set ts=4 sw=4 et: */ |