Root/
1 | /* |
2 | * LZO1X Decompressor from MiniLZO |
3 | * |
4 | * Copyright (C) 1996-2005 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 | * Changed for kernel use by: |
10 | * Nitin Gupta <nitingupta910@gmail.com> |
11 | * Richard Purdie <rpurdie@openedhand.com> |
12 | */ |
13 | |
14 | #ifndef STATIC |
15 | #include <linux/module.h> |
16 | #include <linux/kernel.h> |
17 | #endif |
18 | |
19 | #include <asm/unaligned.h> |
20 | #include <linux/lzo.h> |
21 | #include "lzodefs.h" |
22 | |
23 | #define HAVE_IP(x, ip_end, ip) ((size_t)(ip_end - ip) < (x)) |
24 | #define HAVE_OP(x, op_end, op) ((size_t)(op_end - op) < (x)) |
25 | #define HAVE_LB(m_pos, out, op) (m_pos < out || m_pos >= op) |
26 | |
27 | #define COPY4(dst, src) \ |
28 | put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst)) |
29 | |
30 | int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, |
31 | unsigned char *out, size_t *out_len) |
32 | { |
33 | const unsigned char * const ip_end = in + in_len; |
34 | unsigned char * const op_end = out + *out_len; |
35 | const unsigned char *ip = in, *m_pos; |
36 | unsigned char *op = out; |
37 | size_t t; |
38 | |
39 | *out_len = 0; |
40 | |
41 | if (*ip > 17) { |
42 | t = *ip++ - 17; |
43 | if (t < 4) |
44 | goto match_next; |
45 | if (HAVE_OP(t, op_end, op)) |
46 | goto output_overrun; |
47 | if (HAVE_IP(t + 1, ip_end, ip)) |
48 | goto input_overrun; |
49 | do { |
50 | *op++ = *ip++; |
51 | } while (--t > 0); |
52 | goto first_literal_run; |
53 | } |
54 | |
55 | while ((ip < ip_end)) { |
56 | t = *ip++; |
57 | if (t >= 16) |
58 | goto match; |
59 | if (t == 0) { |
60 | if (HAVE_IP(1, ip_end, ip)) |
61 | goto input_overrun; |
62 | while (*ip == 0) { |
63 | t += 255; |
64 | ip++; |
65 | if (HAVE_IP(1, ip_end, ip)) |
66 | goto input_overrun; |
67 | } |
68 | t += 15 + *ip++; |
69 | } |
70 | if (HAVE_OP(t + 3, op_end, op)) |
71 | goto output_overrun; |
72 | if (HAVE_IP(t + 4, ip_end, ip)) |
73 | goto input_overrun; |
74 | |
75 | COPY4(op, ip); |
76 | op += 4; |
77 | ip += 4; |
78 | if (--t > 0) { |
79 | if (t >= 4) { |
80 | do { |
81 | COPY4(op, ip); |
82 | op += 4; |
83 | ip += 4; |
84 | t -= 4; |
85 | } while (t >= 4); |
86 | if (t > 0) { |
87 | do { |
88 | *op++ = *ip++; |
89 | } while (--t > 0); |
90 | } |
91 | } else { |
92 | do { |
93 | *op++ = *ip++; |
94 | } while (--t > 0); |
95 | } |
96 | } |
97 | |
98 | first_literal_run: |
99 | t = *ip++; |
100 | if (t >= 16) |
101 | goto match; |
102 | m_pos = op - (1 + M2_MAX_OFFSET); |
103 | m_pos -= t >> 2; |
104 | m_pos -= *ip++ << 2; |
105 | |
106 | if (HAVE_LB(m_pos, out, op)) |
107 | goto lookbehind_overrun; |
108 | |
109 | if (HAVE_OP(3, op_end, op)) |
110 | goto output_overrun; |
111 | *op++ = *m_pos++; |
112 | *op++ = *m_pos++; |
113 | *op++ = *m_pos; |
114 | |
115 | goto match_done; |
116 | |
117 | do { |
118 | match: |
119 | if (t >= 64) { |
120 | m_pos = op - 1; |
121 | m_pos -= (t >> 2) & 7; |
122 | m_pos -= *ip++ << 3; |
123 | t = (t >> 5) - 1; |
124 | if (HAVE_LB(m_pos, out, op)) |
125 | goto lookbehind_overrun; |
126 | if (HAVE_OP(t + 3 - 1, op_end, op)) |
127 | goto output_overrun; |
128 | goto copy_match; |
129 | } else if (t >= 32) { |
130 | t &= 31; |
131 | if (t == 0) { |
132 | if (HAVE_IP(1, ip_end, ip)) |
133 | goto input_overrun; |
134 | while (*ip == 0) { |
135 | t += 255; |
136 | ip++; |
137 | if (HAVE_IP(1, ip_end, ip)) |
138 | goto input_overrun; |
139 | } |
140 | t += 31 + *ip++; |
141 | } |
142 | m_pos = op - 1; |
143 | m_pos -= get_unaligned_le16(ip) >> 2; |
144 | ip += 2; |
145 | } else if (t >= 16) { |
146 | m_pos = op; |
147 | m_pos -= (t & 8) << 11; |
148 | |
149 | t &= 7; |
150 | if (t == 0) { |
151 | if (HAVE_IP(1, ip_end, ip)) |
152 | goto input_overrun; |
153 | while (*ip == 0) { |
154 | t += 255; |
155 | ip++; |
156 | if (HAVE_IP(1, ip_end, ip)) |
157 | goto input_overrun; |
158 | } |
159 | t += 7 + *ip++; |
160 | } |
161 | m_pos -= get_unaligned_le16(ip) >> 2; |
162 | ip += 2; |
163 | if (m_pos == op) |
164 | goto eof_found; |
165 | m_pos -= 0x4000; |
166 | } else { |
167 | m_pos = op - 1; |
168 | m_pos -= t >> 2; |
169 | m_pos -= *ip++ << 2; |
170 | |
171 | if (HAVE_LB(m_pos, out, op)) |
172 | goto lookbehind_overrun; |
173 | if (HAVE_OP(2, op_end, op)) |
174 | goto output_overrun; |
175 | |
176 | *op++ = *m_pos++; |
177 | *op++ = *m_pos; |
178 | goto match_done; |
179 | } |
180 | |
181 | if (HAVE_LB(m_pos, out, op)) |
182 | goto lookbehind_overrun; |
183 | if (HAVE_OP(t + 3 - 1, op_end, op)) |
184 | goto output_overrun; |
185 | |
186 | if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { |
187 | COPY4(op, m_pos); |
188 | op += 4; |
189 | m_pos += 4; |
190 | t -= 4 - (3 - 1); |
191 | do { |
192 | COPY4(op, m_pos); |
193 | op += 4; |
194 | m_pos += 4; |
195 | t -= 4; |
196 | } while (t >= 4); |
197 | if (t > 0) |
198 | do { |
199 | *op++ = *m_pos++; |
200 | } while (--t > 0); |
201 | } else { |
202 | copy_match: |
203 | *op++ = *m_pos++; |
204 | *op++ = *m_pos++; |
205 | do { |
206 | *op++ = *m_pos++; |
207 | } while (--t > 0); |
208 | } |
209 | match_done: |
210 | t = ip[-2] & 3; |
211 | if (t == 0) |
212 | break; |
213 | match_next: |
214 | if (HAVE_OP(t, op_end, op)) |
215 | goto output_overrun; |
216 | if (HAVE_IP(t + 1, ip_end, ip)) |
217 | goto input_overrun; |
218 | |
219 | *op++ = *ip++; |
220 | if (t > 1) { |
221 | *op++ = *ip++; |
222 | if (t > 2) |
223 | *op++ = *ip++; |
224 | } |
225 | |
226 | t = *ip++; |
227 | } while (ip < ip_end); |
228 | } |
229 | |
230 | *out_len = op - out; |
231 | return LZO_E_EOF_NOT_FOUND; |
232 | |
233 | eof_found: |
234 | *out_len = op - out; |
235 | return (ip == ip_end ? LZO_E_OK : |
236 | (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); |
237 | input_overrun: |
238 | *out_len = op - out; |
239 | return LZO_E_INPUT_OVERRUN; |
240 | |
241 | output_overrun: |
242 | *out_len = op - out; |
243 | return LZO_E_OUTPUT_OVERRUN; |
244 | |
245 | lookbehind_overrun: |
246 | *out_len = op - out; |
247 | return LZO_E_LOOKBEHIND_OVERRUN; |
248 | } |
249 | #ifndef STATIC |
250 | EXPORT_SYMBOL_GPL(lzo1x_decompress_safe); |
251 | |
252 | MODULE_LICENSE("GPL"); |
253 | MODULE_DESCRIPTION("LZO1X Decompressor"); |
254 | |
255 | #endif |
256 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9