Mercurial > libavutil.hg
annotate lzo.c @ 574:5e52a169969c libavutil
Allow using DECLARE_ALIGNED with Sun cc.
author | cehoyos |
---|---|
date | Thu, 02 Oct 2008 10:47:05 +0000 |
parents | b8574db98875 |
children | 8c48a1b999a3 |
rev | line source |
---|---|
234 | 1 /* |
2 * LZO 1x decompression | |
3 * Copyright (c) 2006 Reimar Doeffinger | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
7 * FFmpeg is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * FFmpeg is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with FFmpeg; if not, write to the Free Software | |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 #include "common.h" | |
22 //! avoid e.g. MPlayers fast_memcpy, it slows things down here | |
23 #undef memcpy | |
24 #include <string.h> | |
25 #include "lzo.h" | |
26 | |
27 //! define if we may write up to 12 bytes beyond the output buffer | |
28 #define OUTBUF_PADDED 1 | |
29 //! define if we may read up to 8 bytes beyond the input buffer | |
30 #define INBUF_PADDED 1 | |
31 typedef struct LZOContext { | |
445 | 32 const uint8_t *in, *in_end; |
234 | 33 uint8_t *out_start, *out, *out_end; |
34 int error; | |
35 } LZOContext; | |
36 | |
37 /** | |
38 * \brief read one byte from input buffer, avoiding overrun | |
39 * \return byte read | |
40 */ | |
41 static inline int get_byte(LZOContext *c) { | |
42 if (c->in < c->in_end) | |
43 return *c->in++; | |
44 c->error |= LZO_INPUT_DEPLETED; | |
45 return 1; | |
46 } | |
47 | |
48 #ifdef INBUF_PADDED | |
49 #define GETB(c) (*(c).in++) | |
50 #else | |
51 #define GETB(c) get_byte(&(c)) | |
52 #endif | |
53 | |
54 /** | |
55 * \brief decode a length value in the coding used by lzo | |
56 * \param x previous byte value | |
57 * \param mask bits used from x | |
58 * \return decoded length value | |
59 */ | |
60 static inline int get_len(LZOContext *c, int x, int mask) { | |
61 int cnt = x & mask; | |
62 if (!cnt) { | |
63 while (!(x = get_byte(c))) cnt += 255; | |
64 cnt += mask + x; | |
65 } | |
66 return cnt; | |
67 } | |
68 | |
69 //#define UNALIGNED_LOADSTORE | |
70 #define BUILTIN_MEMCPY | |
71 #ifdef UNALIGNED_LOADSTORE | |
72 #define COPY2(d, s) *(uint16_t *)(d) = *(uint16_t *)(s); | |
73 #define COPY4(d, s) *(uint32_t *)(d) = *(uint32_t *)(s); | |
74 #elif defined(BUILTIN_MEMCPY) | |
75 #define COPY2(d, s) memcpy(d, s, 2); | |
76 #define COPY4(d, s) memcpy(d, s, 4); | |
77 #else | |
78 #define COPY2(d, s) (d)[0] = (s)[0]; (d)[1] = (s)[1]; | |
79 #define COPY4(d, s) (d)[0] = (s)[0]; (d)[1] = (s)[1]; (d)[2] = (s)[2]; (d)[3] = (s)[3]; | |
80 #endif | |
81 | |
82 /** | |
83 * \brief copy bytes from input to output buffer with checking | |
84 * \param cnt number of bytes to copy, must be >= 0 | |
85 */ | |
86 static inline void copy(LZOContext *c, int cnt) { | |
445 | 87 register const uint8_t *src = c->in; |
234 | 88 register uint8_t *dst = c->out; |
89 if (cnt > c->in_end - src) { | |
90 cnt = FFMAX(c->in_end - src, 0); | |
91 c->error |= LZO_INPUT_DEPLETED; | |
92 } | |
93 if (cnt > c->out_end - dst) { | |
94 cnt = FFMAX(c->out_end - dst, 0); | |
95 c->error |= LZO_OUTPUT_FULL; | |
96 } | |
97 #if defined(INBUF_PADDED) && defined(OUTBUF_PADDED) | |
98 COPY4(dst, src); | |
99 src += 4; | |
100 dst += 4; | |
101 cnt -= 4; | |
102 if (cnt > 0) | |
103 #endif | |
104 memcpy(dst, src, cnt); | |
105 c->in = src + cnt; | |
106 c->out = dst + cnt; | |
107 } | |
108 | |
541
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
109 static inline void memcpy_backptr(uint8_t *dst, int back, int cnt); |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
110 |
234 | 111 /** |
112 * \brief copy previously decoded bytes to current position | |
113 * \param back how many bytes back we start | |
114 * \param cnt number of bytes to copy, must be >= 0 | |
115 * | |
116 * cnt > back is valid, this will copy the bytes we just copied, | |
117 * thus creating a repeating pattern with a period length of back. | |
118 */ | |
119 static inline void copy_backptr(LZOContext *c, int back, int cnt) { | |
445 | 120 register const uint8_t *src = &c->out[-back]; |
234 | 121 register uint8_t *dst = c->out; |
122 if (src < c->out_start || src > dst) { | |
123 c->error |= LZO_INVALID_BACKPTR; | |
124 return; | |
125 } | |
126 if (cnt > c->out_end - dst) { | |
127 cnt = FFMAX(c->out_end - dst, 0); | |
128 c->error |= LZO_OUTPUT_FULL; | |
129 } | |
541
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
130 memcpy_backptr(dst, back, cnt); |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
131 c->out = dst + cnt; |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
132 } |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
133 |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
134 static inline void memcpy_backptr(uint8_t *dst, int back, int cnt) { |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
135 const uint8_t *src = &dst[-back]; |
234 | 136 if (back == 1) { |
137 memset(dst, *src, cnt); | |
138 } else { | |
139 #ifdef OUTBUF_PADDED | |
140 COPY2(dst, src); | |
141 COPY2(dst + 2, src + 2); | |
142 src += 4; | |
143 dst += 4; | |
144 cnt -= 4; | |
145 if (cnt > 0) { | |
146 COPY2(dst, src); | |
147 COPY2(dst + 2, src + 2); | |
148 COPY2(dst + 4, src + 4); | |
149 COPY2(dst + 6, src + 6); | |
150 src += 8; | |
151 dst += 8; | |
152 cnt -= 8; | |
153 } | |
154 #endif | |
155 if (cnt > 0) { | |
156 int blocklen = back; | |
157 while (cnt > blocklen) { | |
158 memcpy(dst, src, blocklen); | |
159 dst += blocklen; | |
160 cnt -= blocklen; | |
161 blocklen <<= 1; | |
162 } | |
163 memcpy(dst, src, cnt); | |
164 } | |
165 } | |
541
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
166 } |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
167 |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
168 /** |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
169 * \brief deliberately overlapping memcpy implementation |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
170 * \param dst destination buffer; must be padded with 12 additional bytes |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
171 * \param back how many bytes back we start (the initial size of the overlapping window) |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
172 * \param cnt number of bytes to copy, must be >= 0 |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
173 * |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
174 * cnt > back is valid, this will copy the bytes we just copied, |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
175 * thus creating a repeating pattern with a period length of back. |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
176 */ |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
177 void av_memcpy_backptr(uint8_t *dst, int back, int cnt) { |
b8574db98875
Add av_memcpy_backptr(): deliberately overlapping memcpy variant.
pross
parents:
445
diff
changeset
|
178 memcpy_backptr(dst, back, cnt); |
234 | 179 } |
180 | |
181 /** | |
182 * \brief decode LZO 1x compressed data | |
183 * \param out output buffer | |
184 * \param outlen size of output buffer, number of bytes left are returned here | |
185 * \param in input buffer | |
186 * \param inlen size of input buffer, number of bytes left are returned here | |
187 * \return 0 on success, otherwise error flags, see lzo.h | |
188 * | |
189 * make sure all buffers are appropriately padded, in must provide | |
190 * LZO_INPUT_PADDING, out must provide LZO_OUTPUT_PADDING additional bytes | |
191 */ | |
445 | 192 int lzo1x_decode(void *out, int *outlen, const void *in, int *inlen) { |
234 | 193 int state= 0; |
194 int x; | |
195 LZOContext c; | |
196 c.in = in; | |
445 | 197 c.in_end = (const uint8_t *)in + *inlen; |
234 | 198 c.out = c.out_start = out; |
199 c.out_end = (uint8_t *)out + * outlen; | |
200 c.error = 0; | |
201 x = GETB(c); | |
202 if (x > 17) { | |
203 copy(&c, x - 17); | |
204 x = GETB(c); | |
205 if (x < 16) c.error |= LZO_ERROR; | |
206 } | |
207 if (c.in > c.in_end) | |
208 c.error |= LZO_INPUT_DEPLETED; | |
209 while (!c.error) { | |
210 int cnt, back; | |
211 if (x > 15) { | |
212 if (x > 63) { | |
213 cnt = (x >> 5) - 1; | |
214 back = (GETB(c) << 3) + ((x >> 2) & 7) + 1; | |
215 } else if (x > 31) { | |
216 cnt = get_len(&c, x, 31); | |
217 x = GETB(c); | |
218 back = (GETB(c) << 6) + (x >> 2) + 1; | |
219 } else { | |
220 cnt = get_len(&c, x, 7); | |
221 back = (1 << 14) + ((x & 8) << 11); | |
222 x = GETB(c); | |
223 back += (GETB(c) << 6) + (x >> 2); | |
224 if (back == (1 << 14)) { | |
225 if (cnt != 1) | |
226 c.error |= LZO_ERROR; | |
227 break; | |
228 } | |
229 } | |
230 } else if(!state){ | |
231 cnt = get_len(&c, x, 15); | |
232 copy(&c, cnt + 3); | |
233 x = GETB(c); | |
234 if (x > 15) | |
235 continue; | |
236 cnt = 1; | |
237 back = (1 << 11) + (GETB(c) << 2) + (x >> 2) + 1; | |
238 } else { | |
239 cnt = 0; | |
240 back = (GETB(c) << 2) + (x >> 2) + 1; | |
241 } | |
242 copy_backptr(&c, back, cnt + 2); | |
243 state= | |
244 cnt = x & 3; | |
245 copy(&c, cnt); | |
246 x = GETB(c); | |
247 } | |
248 *inlen = c.in_end - c.in; | |
249 if (c.in > c.in_end) | |
250 *inlen = 0; | |
251 *outlen = c.out_end - c.out; | |
252 return c.error; | |
253 } | |
254 | |
255 #ifdef TEST | |
256 #include <stdio.h> | |
257 #include <lzo/lzo1x.h> | |
258 #include "log.h" | |
259 #define MAXSZ (10*1024*1024) | |
260 int main(int argc, char *argv[]) { | |
261 FILE *in = fopen(argv[1], "rb"); | |
262 uint8_t *orig = av_malloc(MAXSZ + 16); | |
263 uint8_t *comp = av_malloc(2*MAXSZ + 16); | |
264 uint8_t *decomp = av_malloc(MAXSZ + 16); | |
265 size_t s = fread(orig, 1, MAXSZ, in); | |
266 lzo_uint clen = 0; | |
267 long tmp[LZO1X_MEM_COMPRESS]; | |
268 int inlen, outlen; | |
269 int i; | |
270 av_log_level = AV_LOG_DEBUG; | |
271 lzo1x_999_compress(orig, s, comp, &clen, tmp); | |
272 for (i = 0; i < 300; i++) { | |
273 START_TIMER | |
274 inlen = clen; outlen = MAXSZ; | |
275 #ifdef LIBLZO | |
276 if (lzo1x_decompress_safe(comp, inlen, decomp, &outlen, NULL)) | |
277 #elif defined(LIBLZO_UNSAFE) | |
278 if (lzo1x_decompress(comp, inlen, decomp, &outlen, NULL)) | |
279 #else | |
280 if (lzo1x_decode(decomp, &outlen, comp, &inlen)) | |
281 #endif | |
282 av_log(NULL, AV_LOG_ERROR, "decompression error\n"); | |
283 STOP_TIMER("lzod") | |
284 } | |
285 if (memcmp(orig, decomp, s)) | |
286 av_log(NULL, AV_LOG_ERROR, "decompression incorrect\n"); | |
287 else | |
288 av_log(NULL, AV_LOG_ERROR, "decompression ok\n"); | |
289 return 0; | |
290 } | |
291 #endif |