/root/src/xen/xen/common/lzo.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * lzo.c -- LZO1X Compressor from LZO |
3 | | * |
4 | | * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com> |
5 | | * |
6 | | * The full LZO package can be found at: |
7 | | * http://www.oberhumer.com/opensource/lzo/ |
8 | | * |
9 | | * Adapted for Xen (files combined and syntactic/header changes) by: |
10 | | * Dan Magenheimer <dan.magenheimer@oracle.com> |
11 | | * |
12 | | */ |
13 | | |
14 | | /* |
15 | | * lzodefs.h -- architecture, OS and compiler specific defines |
16 | | * |
17 | | * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com> |
18 | | * |
19 | | * The full LZO package can be found at: |
20 | | * http://www.oberhumer.com/opensource/lzo/ |
21 | | * |
22 | | * Changed for Linux kernel use by: |
23 | | * Nitin Gupta <nitingupta910@gmail.com> |
24 | | * Richard Purdie <rpurdie@openedhand.com> |
25 | | */ |
26 | | |
27 | | |
28 | | #define COPY4(dst, src) \ |
29 | 0 | put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst)) |
30 | | #if defined(__x86_64__) |
31 | | #define COPY8(dst, src) \ |
32 | 0 | put_unaligned(get_unaligned((const u64 *)(src)), (u64 *)(dst)) |
33 | | #else |
34 | | #define COPY8(dst, src) \ |
35 | | COPY4(dst, src); COPY4((dst) + 4, (src) + 4) |
36 | | #endif |
37 | | |
38 | | #ifdef __MINIOS__ |
39 | | # include <lib.h> |
40 | | # if __BYTE_ORDER == __LITTLE_ENDIAN |
41 | | # undef __BIG_ENDIAN |
42 | | # endif |
43 | | # if __BYTE_ORDER == __BIG_ENDIAN |
44 | | # undef __LITTLE_ENDIAN |
45 | | # endif |
46 | | #endif |
47 | | |
48 | | #if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) |
49 | | #error "conflicting endian definitions" |
50 | | #elif defined(__x86_64__) |
51 | | #define LZO_USE_CTZ64 1 |
52 | | #define LZO_USE_CTZ32 1 |
53 | | #elif defined(__i386__) || defined(__powerpc__) |
54 | | #define LZO_USE_CTZ32 1 |
55 | | #elif defined(__arm__) && (__LINUX_ARM_ARCH__ >= 5) |
56 | | #define LZO_USE_CTZ32 1 |
57 | | #endif |
58 | | |
59 | | #define M1_MAX_OFFSET 0x0400 |
60 | 0 | #define M2_MAX_OFFSET 0x0800 |
61 | 0 | #define M3_MAX_OFFSET 0x4000 |
62 | 0 | #define M4_MAX_OFFSET 0xbfff |
63 | | |
64 | | #define M1_MIN_LEN 2 |
65 | | #define M1_MAX_LEN 2 |
66 | | #define M2_MIN_LEN 3 |
67 | 0 | #define M2_MAX_LEN 8 |
68 | | #define M3_MIN_LEN 3 |
69 | 0 | #define M3_MAX_LEN 33 |
70 | | #define M4_MIN_LEN 3 |
71 | 0 | #define M4_MAX_LEN 9 |
72 | | |
73 | | #define M1_MARKER 0 |
74 | | #define M2_MARKER 64 |
75 | 0 | #define M3_MARKER 32 |
76 | 0 | #define M4_MARKER 16 |
77 | | |
78 | 0 | #define lzo_dict_t unsigned short |
79 | 0 | #define D_BITS 13 |
80 | 0 | #define D_SIZE (1u << D_BITS) |
81 | 0 | #define D_MASK (D_SIZE - 1) |
82 | | #define D_HIGH ((D_MASK >> 1) + 1) |
83 | | |
84 | | /* |
85 | | * LZO1X Compressor from LZO |
86 | | * |
87 | | * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com> |
88 | | * |
89 | | * The full LZO package can be found at: |
90 | | * http://www.oberhumer.com/opensource/lzo/ |
91 | | * |
92 | | * Changed for Linux kernel use by: |
93 | | * Nitin Gupta <nitingupta910@gmail.com> |
94 | | * Richard Purdie <rpurdie@openedhand.com> |
95 | | */ |
96 | | |
97 | | #ifdef __XEN__ |
98 | | #include <xen/lib.h> |
99 | | #include <asm/byteorder.h> |
100 | | #endif |
101 | | |
102 | | #include <xen/lzo.h> |
103 | 0 | #define get_unaligned(_p) (*(_p)) |
104 | 0 | #define put_unaligned(_val,_p) (*(_p)=_val) |
105 | 0 | #define get_unaligned_le16(_p) (*(u16 *)(_p)) |
106 | 0 | #define get_unaligned_le32(_p) (*(u32 *)(_p)) |
107 | | |
108 | | static noinline size_t |
109 | | lzo1x_1_do_compress(const unsigned char *in, size_t in_len, |
110 | | unsigned char *out, size_t *out_len, |
111 | | size_t ti, void *wrkmem) |
112 | 0 | { |
113 | 0 | const unsigned char *ip; |
114 | 0 | unsigned char *op; |
115 | 0 | const unsigned char * const in_end = in + in_len; |
116 | 0 | const unsigned char * const ip_end = in + in_len - 20; |
117 | 0 | const unsigned char *ii; |
118 | 0 | lzo_dict_t * const dict = (lzo_dict_t *) wrkmem; |
119 | 0 |
|
120 | 0 | op = out; |
121 | 0 | ip = in; |
122 | 0 | ii = ip; |
123 | 0 | ip += ti < 4 ? 4 - ti : 0; |
124 | 0 |
|
125 | 0 | for (;;) { |
126 | 0 | const unsigned char *m_pos; |
127 | 0 | size_t t, m_len, m_off; |
128 | 0 | u32 dv; |
129 | 0 | literal: |
130 | 0 | ip += 1 + ((ip - ii) >> 5); |
131 | 0 | next: |
132 | 0 | if (unlikely(ip >= ip_end)) |
133 | 0 | break; |
134 | 0 | dv = get_unaligned_le32(ip); |
135 | 0 | t = ((dv * 0x1824429d) >> (32 - D_BITS)) & D_MASK; |
136 | 0 | m_pos = in + dict[t]; |
137 | 0 | dict[t] = (lzo_dict_t) (ip - in); |
138 | 0 | if (unlikely(dv != get_unaligned_le32(m_pos))) |
139 | 0 | goto literal; |
140 | 0 |
|
141 | 0 | ii -= ti; |
142 | 0 | ti = 0; |
143 | 0 | t = ip - ii; |
144 | 0 | if (t != 0) { |
145 | 0 | if (t <= 3) { |
146 | 0 | op[-2] |= t; |
147 | 0 | COPY4(op, ii); |
148 | 0 | op += t; |
149 | 0 | } else if (t <= 16) { |
150 | 0 | *op++ = (t - 3); |
151 | 0 | COPY8(op, ii); |
152 | 0 | COPY8(op + 8, ii + 8); |
153 | 0 | op += t; |
154 | 0 | } else { |
155 | 0 | if (t <= 18) { |
156 | 0 | *op++ = (t - 3); |
157 | 0 | } else { |
158 | 0 | size_t tt = t - 18; |
159 | 0 | *op++ = 0; |
160 | 0 | while (unlikely(tt > 255)) { |
161 | 0 | tt -= 255; |
162 | 0 | *op++ = 0; |
163 | 0 | } |
164 | 0 | *op++ = tt; |
165 | 0 | } |
166 | 0 | do { |
167 | 0 | COPY8(op, ii); |
168 | 0 | COPY8(op + 8, ii + 8); |
169 | 0 | op += 16; |
170 | 0 | ii += 16; |
171 | 0 | t -= 16; |
172 | 0 | } while (t >= 16); |
173 | 0 | if (t > 0) do { |
174 | 0 | *op++ = *ii++; |
175 | 0 | } while (--t > 0); |
176 | 0 | } |
177 | 0 | } |
178 | 0 |
|
179 | 0 | m_len = 4; |
180 | 0 | { |
181 | 0 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ64) |
182 | 0 | u64 v; |
183 | 0 | v = get_unaligned((const u64 *) (ip + m_len)) ^ |
184 | 0 | get_unaligned((const u64 *) (m_pos + m_len)); |
185 | 0 | if (unlikely(v == 0)) { |
186 | 0 | do { |
187 | 0 | m_len += 8; |
188 | 0 | v = get_unaligned((const u64 *) (ip + m_len)) ^ |
189 | 0 | get_unaligned((const u64 *) (m_pos + m_len)); |
190 | 0 | if (unlikely(ip + m_len >= ip_end)) |
191 | 0 | goto m_len_done; |
192 | 0 | } while (v == 0); |
193 | 0 | } |
194 | 0 | # if defined(__LITTLE_ENDIAN) |
195 | 0 | m_len += (unsigned) __builtin_ctzll(v) / 8; |
196 | 0 | # elif defined(__BIG_ENDIAN) |
197 | | m_len += (unsigned) __builtin_clzll(v) / 8; |
198 | | # else |
199 | | # error "missing endian definition" |
200 | | # endif |
201 | 0 | #elif defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ32) |
202 | | u32 v; |
203 | | v = get_unaligned((const u32 *) (ip + m_len)) ^ |
204 | | get_unaligned((const u32 *) (m_pos + m_len)); |
205 | | if (unlikely(v == 0)) { |
206 | | do { |
207 | | m_len += 4; |
208 | | v = get_unaligned((const u32 *) (ip + m_len)) ^ |
209 | | get_unaligned((const u32 *) (m_pos + m_len)); |
210 | | if (v != 0) |
211 | | break; |
212 | | m_len += 4; |
213 | | v = get_unaligned((const u32 *) (ip + m_len)) ^ |
214 | | get_unaligned((const u32 *) (m_pos + m_len)); |
215 | | if (unlikely(ip + m_len >= ip_end)) |
216 | | goto m_len_done; |
217 | | } while (v == 0); |
218 | | } |
219 | | # if defined(__LITTLE_ENDIAN) |
220 | | m_len += (unsigned) __builtin_ctz(v) / 8; |
221 | | # elif defined(__BIG_ENDIAN) |
222 | | m_len += (unsigned) __builtin_clz(v) / 8; |
223 | | # else |
224 | | # error "missing endian definition" |
225 | | # endif |
226 | | #else |
227 | | if (unlikely(ip[m_len] == m_pos[m_len])) { |
228 | | do { |
229 | | m_len += 1; |
230 | | if (ip[m_len] != m_pos[m_len]) |
231 | | break; |
232 | | m_len += 1; |
233 | | if (ip[m_len] != m_pos[m_len]) |
234 | | break; |
235 | | m_len += 1; |
236 | | if (ip[m_len] != m_pos[m_len]) |
237 | | break; |
238 | | m_len += 1; |
239 | | if (ip[m_len] != m_pos[m_len]) |
240 | | break; |
241 | | m_len += 1; |
242 | | if (ip[m_len] != m_pos[m_len]) |
243 | | break; |
244 | | m_len += 1; |
245 | | if (ip[m_len] != m_pos[m_len]) |
246 | | break; |
247 | | m_len += 1; |
248 | | if (ip[m_len] != m_pos[m_len]) |
249 | | break; |
250 | | m_len += 1; |
251 | | if (unlikely(ip + m_len >= ip_end)) |
252 | | goto m_len_done; |
253 | | } while (ip[m_len] == m_pos[m_len]); |
254 | | } |
255 | | #endif |
256 | 0 | } |
257 | 0 | m_len_done: |
258 | 0 |
|
259 | 0 | m_off = ip - m_pos; |
260 | 0 | ip += m_len; |
261 | 0 | ii = ip; |
262 | 0 | if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { |
263 | 0 | m_off -= 1; |
264 | 0 | *op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2)); |
265 | 0 | *op++ = (m_off >> 3); |
266 | 0 | } else if (m_off <= M3_MAX_OFFSET) { |
267 | 0 | m_off -= 1; |
268 | 0 | if (m_len <= M3_MAX_LEN) |
269 | 0 | *op++ = (M3_MARKER | (m_len - 2)); |
270 | 0 | else { |
271 | 0 | m_len -= M3_MAX_LEN; |
272 | 0 | *op++ = M3_MARKER | 0; |
273 | 0 | while (unlikely(m_len > 255)) { |
274 | 0 | m_len -= 255; |
275 | 0 | *op++ = 0; |
276 | 0 | } |
277 | 0 | *op++ = (m_len); |
278 | 0 | } |
279 | 0 | *op++ = (m_off << 2); |
280 | 0 | *op++ = (m_off >> 6); |
281 | 0 | } else { |
282 | 0 | m_off -= 0x4000; |
283 | 0 | if (m_len <= M4_MAX_LEN) |
284 | 0 | *op++ = (M4_MARKER | ((m_off >> 11) & 8) |
285 | 0 | | (m_len - 2)); |
286 | 0 | else { |
287 | 0 | m_len -= M4_MAX_LEN; |
288 | 0 | *op++ = (M4_MARKER | ((m_off >> 11) & 8)); |
289 | 0 | while (unlikely(m_len > 255)) { |
290 | 0 | m_len -= 255; |
291 | 0 | *op++ = 0; |
292 | 0 | } |
293 | 0 | *op++ = (m_len); |
294 | 0 | } |
295 | 0 | *op++ = (m_off << 2); |
296 | 0 | *op++ = (m_off >> 6); |
297 | 0 | } |
298 | 0 | goto next; |
299 | 0 | } |
300 | 0 | *out_len = op - out; |
301 | 0 | return in_end - (ii - ti); |
302 | 0 | } |
303 | | |
304 | | int lzo1x_1_compress(const unsigned char *in, size_t in_len, |
305 | | unsigned char *out, size_t *out_len, |
306 | | void *wrkmem) |
307 | 0 | { |
308 | 0 | const unsigned char *ip = in; |
309 | 0 | unsigned char *op = out; |
310 | 0 | size_t l = in_len; |
311 | 0 | size_t t = 0; |
312 | 0 |
|
313 | 0 | while (l > 20) { |
314 | 0 | size_t ll = l <= (M4_MAX_OFFSET + 1) ? l : (M4_MAX_OFFSET + 1); |
315 | 0 | uintptr_t ll_end = (uintptr_t) ip + ll; |
316 | 0 | if ((ll_end + ((t + ll) >> 5)) <= ll_end) |
317 | 0 | break; |
318 | 0 | BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS); |
319 | 0 | memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t)); |
320 | 0 | t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem); |
321 | 0 | ip += ll; |
322 | 0 | op += *out_len; |
323 | 0 | l -= ll; |
324 | 0 | } |
325 | 0 | t += l; |
326 | 0 |
|
327 | 0 | if (t > 0) { |
328 | 0 | const unsigned char *ii = in + in_len - t; |
329 | 0 |
|
330 | 0 | if (op == out && t <= 238) { |
331 | 0 | *op++ = (17 + t); |
332 | 0 | } else if (t <= 3) { |
333 | 0 | op[-2] |= t; |
334 | 0 | } else if (t <= 18) { |
335 | 0 | *op++ = (t - 3); |
336 | 0 | } else { |
337 | 0 | size_t tt = t - 18; |
338 | 0 | *op++ = 0; |
339 | 0 | while (tt > 255) { |
340 | 0 | tt -= 255; |
341 | 0 | *op++ = 0; |
342 | 0 | } |
343 | 0 | *op++ = tt; |
344 | 0 | } |
345 | 0 | if (t >= 16) do { |
346 | 0 | COPY8(op, ii); |
347 | 0 | COPY8(op + 8, ii + 8); |
348 | 0 | op += 16; |
349 | 0 | ii += 16; |
350 | 0 | t -= 16; |
351 | 0 | } while (t >= 16); |
352 | 0 | if (t > 0) do { |
353 | 0 | *op++ = *ii++; |
354 | 0 | } while (--t > 0); |
355 | 0 | } |
356 | 0 |
|
357 | 0 | *op++ = M4_MARKER | 1; |
358 | 0 | *op++ = 0; |
359 | 0 | *op++ = 0; |
360 | 0 |
|
361 | 0 | *out_len = op - out; |
362 | 0 | return LZO_E_OK; |
363 | 0 | } |
364 | | |
365 | | /* |
366 | | * LZO1X Decompressor from LZO |
367 | | * |
368 | | * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com> |
369 | | * |
370 | | * The full LZO package can be found at: |
371 | | * http://www.oberhumer.com/opensource/lzo/ |
372 | | * |
373 | | * Changed for Linux kernel use by: |
374 | | * Nitin Gupta <nitingupta910@gmail.com> |
375 | | * Richard Purdie <rpurdie@openedhand.com> |
376 | | */ |
377 | | |
378 | 0 | #define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) |
379 | 0 | #define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) |
380 | 0 | #define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun |
381 | 0 | #define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun |
382 | 0 | #define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun |
383 | | |
384 | | /* This MAX_255_COUNT is the maximum number of times we can add 255 to a base |
385 | | * count without overflowing an integer. The multiply will overflow when |
386 | | * multiplying 255 by more than MAXINT/255. The sum will overflow earlier |
387 | | * depending on the base count. Since the base count is taken from a u8 |
388 | | * and a few bits, it is safe to assume that it will always be lower than |
389 | | * or equal to 2*255, thus we can always prevent any overflow by accepting |
390 | | * two less 255 steps. See Documentation/lzo.txt for more information. |
391 | | */ |
392 | | #define MAX_255_COUNT ((((size_t)~0) / 255) - 2) |
393 | | |
394 | | int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, |
395 | | unsigned char *out, size_t *out_len) |
396 | 0 | { |
397 | 0 | unsigned char *op; |
398 | 0 | const unsigned char *ip; |
399 | 0 | size_t t, next; |
400 | 0 | size_t state = 0; |
401 | 0 | const unsigned char *m_pos; |
402 | 0 | const unsigned char * const ip_end = in + in_len; |
403 | 0 | unsigned char * const op_end = out + *out_len; |
404 | 0 |
|
405 | 0 | op = out; |
406 | 0 | ip = in; |
407 | 0 |
|
408 | 0 | if (unlikely(in_len < 3)) |
409 | 0 | goto input_overrun; |
410 | 0 | if (*ip > 17) { |
411 | 0 | t = *ip++ - 17; |
412 | 0 | if (t < 4) { |
413 | 0 | next = t; |
414 | 0 | goto match_next; |
415 | 0 | } |
416 | 0 | goto copy_literal_run; |
417 | 0 | } |
418 | 0 |
|
419 | 0 | for (;;) { |
420 | 0 | t = *ip++; |
421 | 0 | if (t < 16) { |
422 | 0 | if (likely(state == 0)) { |
423 | 0 | if (unlikely(t == 0)) { |
424 | 0 | size_t offset; |
425 | 0 | const unsigned char *ip_last = ip; |
426 | 0 |
|
427 | 0 | while (unlikely(*ip == 0)) { |
428 | 0 | ip++; |
429 | 0 | NEED_IP(1); |
430 | 0 | } |
431 | 0 | offset = ip - ip_last; |
432 | 0 | if (unlikely(offset > MAX_255_COUNT)) |
433 | 0 | return LZO_E_ERROR; |
434 | 0 |
|
435 | 0 | offset = (offset << 8) - offset; |
436 | 0 | t += offset + 15 + *ip++; |
437 | 0 | } |
438 | 0 | t += 3; |
439 | 0 | copy_literal_run: |
440 | 0 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) |
441 | 0 | if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) { |
442 | 0 | const unsigned char *ie = ip + t; |
443 | 0 | unsigned char *oe = op + t; |
444 | 0 | do { |
445 | 0 | COPY8(op, ip); |
446 | 0 | op += 8; |
447 | 0 | ip += 8; |
448 | 0 | COPY8(op, ip); |
449 | 0 | op += 8; |
450 | 0 | ip += 8; |
451 | 0 | } while (ip < ie); |
452 | 0 | ip = ie; |
453 | 0 | op = oe; |
454 | 0 | } else |
455 | 0 | #endif |
456 | 0 | { |
457 | 0 | NEED_OP(t); |
458 | 0 | NEED_IP(t + 3); |
459 | 0 | do { |
460 | 0 | *op++ = *ip++; |
461 | 0 | } while (--t > 0); |
462 | 0 | } |
463 | 0 | state = 4; |
464 | 0 | continue; |
465 | 0 | } else if (state != 4) { |
466 | 0 | next = t & 3; |
467 | 0 | m_pos = op - 1; |
468 | 0 | m_pos -= t >> 2; |
469 | 0 | m_pos -= *ip++ << 2; |
470 | 0 | TEST_LB(m_pos); |
471 | 0 | NEED_OP(2); |
472 | 0 | op[0] = m_pos[0]; |
473 | 0 | op[1] = m_pos[1]; |
474 | 0 | op += 2; |
475 | 0 | goto match_next; |
476 | 0 | } else { |
477 | 0 | next = t & 3; |
478 | 0 | m_pos = op - (1 + M2_MAX_OFFSET); |
479 | 0 | m_pos -= t >> 2; |
480 | 0 | m_pos -= *ip++ << 2; |
481 | 0 | t = 3; |
482 | 0 | } |
483 | 0 | } else if (t >= 64) { |
484 | 0 | next = t & 3; |
485 | 0 | m_pos = op - 1; |
486 | 0 | m_pos -= (t >> 2) & 7; |
487 | 0 | m_pos -= *ip++ << 3; |
488 | 0 | t = (t >> 5) - 1 + (3 - 1); |
489 | 0 | } else if (t >= 32) { |
490 | 0 | t = (t & 31) + (3 - 1); |
491 | 0 | if (unlikely(t == 2)) { |
492 | 0 | size_t offset; |
493 | 0 | const unsigned char *ip_last = ip; |
494 | 0 |
|
495 | 0 | while (unlikely(*ip == 0)) { |
496 | 0 | ip++; |
497 | 0 | NEED_IP(1); |
498 | 0 | } |
499 | 0 | offset = ip - ip_last; |
500 | 0 | if (unlikely(offset > MAX_255_COUNT)) |
501 | 0 | return LZO_E_ERROR; |
502 | 0 |
|
503 | 0 | offset = (offset << 8) - offset; |
504 | 0 | t += offset + 31 + *ip++; |
505 | 0 | NEED_IP(2); |
506 | 0 | } |
507 | 0 | m_pos = op - 1; |
508 | 0 | next = get_unaligned_le16(ip); |
509 | 0 | ip += 2; |
510 | 0 | m_pos -= next >> 2; |
511 | 0 | next &= 3; |
512 | 0 | } else { |
513 | 0 | m_pos = op; |
514 | 0 | m_pos -= (t & 8) << 11; |
515 | 0 | t = (t & 7) + (3 - 1); |
516 | 0 | if (unlikely(t == 2)) { |
517 | 0 | size_t offset; |
518 | 0 | const unsigned char *ip_last = ip; |
519 | 0 |
|
520 | 0 | while (unlikely(*ip == 0)) { |
521 | 0 | ip++; |
522 | 0 | NEED_IP(1); |
523 | 0 | } |
524 | 0 | offset = ip - ip_last; |
525 | 0 | if (unlikely(offset > MAX_255_COUNT)) |
526 | 0 | return LZO_E_ERROR; |
527 | 0 |
|
528 | 0 | offset = (offset << 8) - offset; |
529 | 0 | t += offset + 7 + *ip++; |
530 | 0 | NEED_IP(2); |
531 | 0 | } |
532 | 0 | next = get_unaligned_le16(ip); |
533 | 0 | ip += 2; |
534 | 0 | m_pos -= next >> 2; |
535 | 0 | next &= 3; |
536 | 0 | if (m_pos == op) |
537 | 0 | goto eof_found; |
538 | 0 | m_pos -= 0x4000; |
539 | 0 | } |
540 | 0 | TEST_LB(m_pos); |
541 | 0 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) |
542 | 0 | if (op - m_pos >= 8) { |
543 | 0 | unsigned char *oe = op + t; |
544 | 0 | if (likely(HAVE_OP(t + 15))) { |
545 | 0 | do { |
546 | 0 | COPY8(op, m_pos); |
547 | 0 | op += 8; |
548 | 0 | m_pos += 8; |
549 | 0 | COPY8(op, m_pos); |
550 | 0 | op += 8; |
551 | 0 | m_pos += 8; |
552 | 0 | } while (op < oe); |
553 | 0 | op = oe; |
554 | 0 | if (HAVE_IP(6)) { |
555 | 0 | state = next; |
556 | 0 | COPY4(op, ip); |
557 | 0 | op += next; |
558 | 0 | ip += next; |
559 | 0 | continue; |
560 | 0 | } |
561 | 0 | } else { |
562 | 0 | NEED_OP(t); |
563 | 0 | do { |
564 | 0 | *op++ = *m_pos++; |
565 | 0 | } while (op < oe); |
566 | 0 | } |
567 | 0 | } else |
568 | 0 | #endif |
569 | 0 | { |
570 | 0 | unsigned char *oe = op + t; |
571 | 0 | NEED_OP(t); |
572 | 0 | op[0] = m_pos[0]; |
573 | 0 | op[1] = m_pos[1]; |
574 | 0 | op += 2; |
575 | 0 | m_pos += 2; |
576 | 0 | do { |
577 | 0 | *op++ = *m_pos++; |
578 | 0 | } while (op < oe); |
579 | 0 | } |
580 | 0 | match_next: |
581 | 0 | state = next; |
582 | 0 | t = next; |
583 | 0 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) |
584 | 0 | if (likely(HAVE_IP(6) && HAVE_OP(4))) { |
585 | 0 | COPY4(op, ip); |
586 | 0 | op += t; |
587 | 0 | ip += t; |
588 | 0 | } else |
589 | 0 | #endif |
590 | 0 | { |
591 | 0 | NEED_IP(t + 3); |
592 | 0 | NEED_OP(t); |
593 | 0 | while (t > 0) { |
594 | 0 | *op++ = *ip++; |
595 | 0 | t--; |
596 | 0 | } |
597 | 0 | } |
598 | 0 | } |
599 | 0 |
|
600 | 0 | eof_found: |
601 | 0 | *out_len = op - out; |
602 | 0 | return (t != 3 ? LZO_E_ERROR : |
603 | 0 | ip == ip_end ? LZO_E_OK : |
604 | 0 | ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN); |
605 | 0 |
|
606 | 0 | input_overrun: |
607 | 0 | *out_len = op - out; |
608 | 0 | return LZO_E_INPUT_OVERRUN; |
609 | 0 |
|
610 | 0 | output_overrun: |
611 | 0 | *out_len = op - out; |
612 | 0 | return LZO_E_OUTPUT_OVERRUN; |
613 | 0 |
|
614 | 0 | lookbehind_overrun: |
615 | 0 | *out_len = op - out; |
616 | 0 | return LZO_E_LOOKBEHIND_OVERRUN; |
617 | 0 | } |