]>
Commit | Line | Data |
---|---|---|
d0751937 | 1 | /* |
2 | * Copyright (c) 2000-2007 Marc Alexander Lehmann <schmorp@schmorp.de> | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without modifica- | |
5 | * tion, are permitted provided that the following conditions are met: | |
6 | * | |
7 | * 1. Redistributions of source code must retain the above copyright notice, | |
8 | * this list of conditions and the following disclaimer. | |
9 | * | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * | |
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- | |
16 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
17 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- | |
18 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
20 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
21 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- | |
22 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
23 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | * | |
25 | * Alternatively, the contents of this file may be used under the terms of | |
26 | * the GNU General Public License ("GPL") version 2 or any later version, | |
27 | * in which case the provisions of the GPL are applicable instead of | |
28 | * the above. If you wish to allow the use of your version of this file | |
29 | * only under the terms of the GPL and not to allow others to use your | |
30 | * version of this file under the BSD license, indicate your decision | |
31 | * by deleting the provisions above and replace them with the notice | |
32 | * and other provisions required by the GPL. If you do not delete the | |
33 | * provisions above, a recipient may use your version of this file under | |
34 | * either the BSD or the GPL. | |
35 | */ | |
36 | ||
37 | #include "lzfP.h" | |
38 | ||
39 | #if AVOID_ERRNO | |
40 | # define SET_ERRNO(n) | |
41 | #else | |
42 | # include <errno.h> | |
43 | # define SET_ERRNO(n) errno = (n) | |
44 | #endif | |
45 | ||
46 | /* | |
47 | #if (__i386 || __amd64) && __GNUC__ >= 3 | |
48 | # define lzf_movsb(dst, src, len) \ | |
49 | asm ("rep movsb" \ | |
50 | : "=D" (dst), "=S" (src), "=c" (len) \ | |
51 | : "0" (dst), "1" (src), "2" (len)); | |
52 | #endif | |
53 | */ | |
54 | ||
55 | unsigned int | |
56 | lzf_decompress (const void *const in_data, unsigned int in_len, | |
57 | void *out_data, unsigned int out_len) | |
58 | { | |
59 | u8 const *ip = (const u8 *)in_data; | |
60 | u8 *op = (u8 *)out_data; | |
61 | u8 const *const in_end = ip + in_len; | |
62 | u8 *const out_end = op + out_len; | |
63 | ||
64 | do | |
65 | { | |
66 | unsigned int ctrl = *ip++; | |
67 | ||
68 | if (ctrl < (1 << 5)) /* literal run */ | |
69 | { | |
70 | ctrl++; | |
71 | ||
72 | if (op + ctrl > out_end) | |
73 | { | |
74 | SET_ERRNO (E2BIG); | |
75 | return 0; | |
76 | } | |
77 | ||
78 | #if CHECK_INPUT | |
79 | if (ip + ctrl > in_end) | |
80 | { | |
81 | SET_ERRNO (EINVAL); | |
82 | return 0; | |
83 | } | |
84 | #endif | |
85 | ||
86 | #ifdef lzf_movsb | |
87 | lzf_movsb (op, ip, ctrl); | |
88 | #else | |
89 | do | |
90 | *op++ = *ip++; | |
91 | while (--ctrl); | |
92 | #endif | |
93 | } | |
94 | else /* back reference */ | |
95 | { | |
96 | unsigned int len = ctrl >> 5; | |
97 | ||
98 | u8 *ref = op - ((ctrl & 0x1f) << 8) - 1; | |
99 | ||
100 | #if CHECK_INPUT | |
101 | if (ip >= in_end) | |
102 | { | |
103 | SET_ERRNO (EINVAL); | |
104 | return 0; | |
105 | } | |
106 | #endif | |
107 | if (len == 7) | |
108 | { | |
109 | len += *ip++; | |
110 | #if CHECK_INPUT | |
111 | if (ip >= in_end) | |
112 | { | |
113 | SET_ERRNO (EINVAL); | |
114 | return 0; | |
115 | } | |
116 | #endif | |
117 | } | |
118 | ||
119 | ref -= *ip++; | |
120 | ||
121 | if (op + len + 2 > out_end) | |
122 | { | |
123 | SET_ERRNO (E2BIG); | |
124 | return 0; | |
125 | } | |
126 | ||
127 | if (ref < (u8 *)out_data) | |
128 | { | |
129 | SET_ERRNO (EINVAL); | |
130 | return 0; | |
131 | } | |
132 | ||
133 | #ifdef lzf_movsb | |
134 | len += 2; | |
135 | lzf_movsb (op, ref, len); | |
136 | #else | |
137 | *op++ = *ref++; | |
138 | *op++ = *ref++; | |
139 | ||
140 | do | |
141 | *op++ = *ref++; | |
142 | while (--len); | |
143 | #endif | |
144 | } | |
145 | } | |
146 | while (ip < in_end); | |
147 | ||
148 | return op - (u8 *)out_data; | |
149 | } | |
150 |