Mercurial > libavutil.hg
annotate lzo.c @ 644:8bcaa41403bd libavutil
Move doxygen documentation from lzo.c to lzo.h
author | reimar |
---|---|
date | Mon, 02 Feb 2009 20:30:36 +0000 |
parents | db8f45986cff |
children | 8e5654be3500 |
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" | |
633 | 22 //! Avoid e.g. MPlayers fast_memcpy, it slows things down here. |
234 | 23 #undef memcpy |
24 #include <string.h> | |
25 #include "lzo.h" | |
26 | |
633 | 27 //! Define if we may write up to 12 bytes beyond the output buffer. |
234 | 28 #define OUTBUF_PADDED 1 |
633 | 29 //! Define if we may read up to 8 bytes beyond the input buffer. |
234 | 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 /** | |
636 | 38 * \brief Reads one byte from the input buffer, avoiding an overrun. |
234 | 39 * \return byte read |
40 */ | |
41 static inline int get_byte(LZOContext *c) { | |
42 if (c->in < c->in_end) | |
43 return *c->in++; | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
44 c->error |= AV_LZO_INPUT_DEPLETED; |
234 | 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 /** | |
633 | 55 * \brief Decodes a length value in the coding used by lzo. |
234 | 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 /** | |
633 | 83 * \brief Copies bytes from input to output buffer with checking. |
234 | 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); | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
91 c->error |= AV_LZO_INPUT_DEPLETED; |
234 | 92 } |
93 if (cnt > c->out_end - dst) { | |
94 cnt = FFMAX(c->out_end - dst, 0); | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
95 c->error |= AV_LZO_OUTPUT_FULL; |
234 | 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 /** |
633 | 112 * \brief Copies previously decoded bytes to current position. |
234 | 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) { | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
123 c->error |= AV_LZO_INVALID_BACKPTR; |
234 | 124 return; |
125 } | |
126 if (cnt > c->out_end - dst) { | |
127 cnt = FFMAX(c->out_end - dst, 0); | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
128 c->error |= AV_LZO_OUTPUT_FULL; |
234 | 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 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
|
169 memcpy_backptr(dst, back, cnt); |
234 | 170 } |
171 | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
172 int av_lzo1x_decode(void *out, int *outlen, const void *in, int *inlen) { |
234 | 173 int state= 0; |
174 int x; | |
175 LZOContext c; | |
176 c.in = in; | |
445 | 177 c.in_end = (const uint8_t *)in + *inlen; |
234 | 178 c.out = c.out_start = out; |
179 c.out_end = (uint8_t *)out + * outlen; | |
180 c.error = 0; | |
181 x = GETB(c); | |
182 if (x > 17) { | |
183 copy(&c, x - 17); | |
184 x = GETB(c); | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
185 if (x < 16) c.error |= AV_LZO_ERROR; |
234 | 186 } |
187 if (c.in > c.in_end) | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
188 c.error |= AV_LZO_INPUT_DEPLETED; |
234 | 189 while (!c.error) { |
190 int cnt, back; | |
191 if (x > 15) { | |
192 if (x > 63) { | |
193 cnt = (x >> 5) - 1; | |
194 back = (GETB(c) << 3) + ((x >> 2) & 7) + 1; | |
195 } else if (x > 31) { | |
196 cnt = get_len(&c, x, 31); | |
197 x = GETB(c); | |
198 back = (GETB(c) << 6) + (x >> 2) + 1; | |
199 } else { | |
200 cnt = get_len(&c, x, 7); | |
201 back = (1 << 14) + ((x & 8) << 11); | |
202 x = GETB(c); | |
203 back += (GETB(c) << 6) + (x >> 2); | |
204 if (back == (1 << 14)) { | |
205 if (cnt != 1) | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
206 c.error |= AV_LZO_ERROR; |
234 | 207 break; |
208 } | |
209 } | |
210 } else if(!state){ | |
211 cnt = get_len(&c, x, 15); | |
212 copy(&c, cnt + 3); | |
213 x = GETB(c); | |
214 if (x > 15) | |
215 continue; | |
216 cnt = 1; | |
217 back = (1 << 11) + (GETB(c) << 2) + (x >> 2) + 1; | |
218 } else { | |
219 cnt = 0; | |
220 back = (GETB(c) << 2) + (x >> 2) + 1; | |
221 } | |
222 copy_backptr(&c, back, cnt + 2); | |
223 state= | |
224 cnt = x & 3; | |
225 copy(&c, cnt); | |
226 x = GETB(c); | |
227 } | |
228 *inlen = c.in_end - c.in; | |
229 if (c.in > c.in_end) | |
230 *inlen = 0; | |
231 *outlen = c.out_end - c.out; | |
232 return c.error; | |
233 } | |
234 | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
235 #if LIBAVUTIL_VERSION_MAJOR < 50 |
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
236 int lzo1x_decode(void *out, int *outlen, const void *in, int *inlen) { |
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
237 return av_lzo1x_decode(out, outlen, in, inlen); |
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
238 } |
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
239 #endif |
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
240 |
234 | 241 #ifdef TEST |
242 #include <stdio.h> | |
243 #include <lzo/lzo1x.h> | |
244 #include "log.h" | |
245 #define MAXSZ (10*1024*1024) | |
246 int main(int argc, char *argv[]) { | |
247 FILE *in = fopen(argv[1], "rb"); | |
248 uint8_t *orig = av_malloc(MAXSZ + 16); | |
249 uint8_t *comp = av_malloc(2*MAXSZ + 16); | |
250 uint8_t *decomp = av_malloc(MAXSZ + 16); | |
251 size_t s = fread(orig, 1, MAXSZ, in); | |
252 lzo_uint clen = 0; | |
253 long tmp[LZO1X_MEM_COMPRESS]; | |
254 int inlen, outlen; | |
255 int i; | |
256 av_log_level = AV_LOG_DEBUG; | |
257 lzo1x_999_compress(orig, s, comp, &clen, tmp); | |
258 for (i = 0; i < 300; i++) { | |
259 START_TIMER | |
260 inlen = clen; outlen = MAXSZ; | |
261 #ifdef LIBLZO | |
262 if (lzo1x_decompress_safe(comp, inlen, decomp, &outlen, NULL)) | |
263 #elif defined(LIBLZO_UNSAFE) | |
264 if (lzo1x_decompress(comp, inlen, decomp, &outlen, NULL)) | |
265 #else | |
643
db8f45986cff
Add av_ prefix to LZO stuff and thus make it officially part of the public API.
reimar
parents:
636
diff
changeset
|
266 if (av_lzo1x_decode(decomp, &outlen, comp, &inlen)) |
234 | 267 #endif |
268 av_log(NULL, AV_LOG_ERROR, "decompression error\n"); | |
269 STOP_TIMER("lzod") | |
270 } | |
271 if (memcmp(orig, decomp, s)) | |
272 av_log(NULL, AV_LOG_ERROR, "decompression incorrect\n"); | |
273 else | |
633 | 274 av_log(NULL, AV_LOG_ERROR, "decompression OK\n"); |
234 | 275 return 0; |
276 } | |
277 #endif |