Root/lib/decompress_unlzo.c

Source at commit b386be689295730688885552666ea40b2e639b14 created 8 years 11 months ago.
By Maarten ter Huurne, Revert "MIPS: JZ4740: reset: Initialize hibernate wakeup counters."
1/*
2 * LZO decompressor for the Linux kernel. Code borrowed from the lzo
3 * implementation by Markus Franz Xaver Johannes Oberhumer.
4 *
5 * Linux kernel adaptation:
6 * Copyright (C) 2009
7 * Albin Tonnerre, Free Electrons <albin.tonnerre@free-electrons.com>
8 *
9 * Original code:
10 * Copyright (C) 1996-2005 Markus Franz Xaver Johannes Oberhumer
11 * All Rights Reserved.
12 *
13 * lzop and the LZO library are free software; you can redistribute them
14 * and/or modify them under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of
16 * the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; see the file COPYING.
25 * If not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 *
28 * Markus F.X.J. Oberhumer
29 * <markus@oberhumer.com>
30 * http://www.oberhumer.com/opensource/lzop/
31 */
32
33#ifdef STATIC
34#include "lzo/lzo1x_decompress.c"
35#else
36#include <linux/decompress/unlzo.h>
37#endif
38
39#include <linux/types.h>
40#include <linux/lzo.h>
41#include <linux/decompress/mm.h>
42
43#include <linux/compiler.h>
44#include <asm/unaligned.h>
45
46static const unsigned char lzop_magic[] = {
47    0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a };
48
49#define LZO_BLOCK_SIZE (256*1024l)
50#define HEADER_HAS_FILTER 0x00000800L
51#define HEADER_SIZE_MIN (9 + 7 + 4 + 8 + 1 + 4)
52#define HEADER_SIZE_MAX (9 + 7 + 1 + 8 + 8 + 4 + 1 + 255 + 4)
53
54STATIC inline int INIT parse_header(u8 *input, int *skip, int in_len)
55{
56    int l;
57    u8 *parse = input;
58    u8 *end = input + in_len;
59    u8 level = 0;
60    u16 version;
61
62    /*
63     * Check that there's enough input to possibly have a valid header.
64     * Then it is possible to parse several fields until the minimum
65     * size may have been used.
66     */
67    if (in_len < HEADER_SIZE_MIN)
68        return 0;
69
70    /* read magic: 9 first bits */
71    for (l = 0; l < 9; l++) {
72        if (*parse++ != lzop_magic[l])
73            return 0;
74    }
75    /* get version (2bytes), skip library version (2),
76     * 'need to be extracted' version (2) and
77     * method (1) */
78    version = get_unaligned_be16(parse);
79    parse += 7;
80    if (version >= 0x0940)
81        level = *parse++;
82    if (get_unaligned_be32(parse) & HEADER_HAS_FILTER)
83        parse += 8; /* flags + filter info */
84    else
85        parse += 4; /* flags */
86
87    /*
88     * At least mode, mtime_low, filename length, and checksum must
89     * be left to be parsed. If also mtime_high is present, it's OK
90     * because the next input buffer check is after reading the
91     * filename length.
92     */
93    if (end - parse < 8 + 1 + 4)
94        return 0;
95
96    /* skip mode and mtime_low */
97    parse += 8;
98    if (version >= 0x0940)
99        parse += 4; /* skip mtime_high */
100
101    l = *parse++;
102    /* don't care about the file name, and skip checksum */
103    if (end - parse < l + 4)
104        return 0;
105    parse += l + 4;
106
107    *skip = parse - input;
108    return 1;
109}
110
111STATIC inline int INIT unlzo(u8 *input, int in_len,
112                int (*fill) (void *, unsigned int),
113                int (*flush) (void *, unsigned int),
114                u8 *output, int *posp,
115                void (*error) (char *x))
116{
117    u8 r = 0;
118    int skip = 0;
119    u32 src_len, dst_len;
120    size_t tmp;
121    u8 *in_buf, *in_buf_save, *out_buf;
122    int ret = -1;
123
124    if (output) {
125        out_buf = output;
126    } else if (!flush) {
127        error("NULL output pointer and no flush function provided");
128        goto exit;
129    } else {
130        out_buf = malloc(LZO_BLOCK_SIZE);
131        if (!out_buf) {
132            error("Could not allocate output buffer");
133            goto exit;
134        }
135    }
136
137    if (input && fill) {
138        error("Both input pointer and fill function provided, don't know what to do");
139        goto exit_1;
140    } else if (input) {
141        in_buf = input;
142    } else if (!fill) {
143        error("NULL input pointer and missing fill function");
144        goto exit_1;
145    } else {
146        in_buf = malloc(lzo1x_worst_compress(LZO_BLOCK_SIZE));
147        if (!in_buf) {
148            error("Could not allocate input buffer");
149            goto exit_1;
150        }
151    }
152    in_buf_save = in_buf;
153
154    if (posp)
155        *posp = 0;
156
157    if (fill) {
158        /*
159         * Start from in_buf + HEADER_SIZE_MAX to make it possible
160         * to use memcpy() to copy the unused data to the beginning
161         * of the buffer. This way memmove() isn't needed which
162         * is missing from pre-boot environments of most archs.
163         */
164        in_buf += HEADER_SIZE_MAX;
165        in_len = fill(in_buf, HEADER_SIZE_MAX);
166    }
167
168    if (!parse_header(in_buf, &skip, in_len)) {
169        error("invalid header");
170        goto exit_2;
171    }
172    in_buf += skip;
173    in_len -= skip;
174
175    if (fill) {
176        /* Move the unused data to the beginning of the buffer. */
177        memcpy(in_buf_save, in_buf, in_len);
178        in_buf = in_buf_save;
179    }
180
181    if (posp)
182        *posp = skip;
183
184    for (;;) {
185        /* read uncompressed block size */
186        if (fill && in_len < 4) {
187            skip = fill(in_buf + in_len, 4 - in_len);
188            if (skip > 0)
189                in_len += skip;
190        }
191        if (in_len < 4) {
192            error("file corrupted");
193            goto exit_2;
194        }
195        dst_len = get_unaligned_be32(in_buf);
196        in_buf += 4;
197        in_len -= 4;
198
199        /* exit if last block */
200        if (dst_len == 0) {
201            if (posp)
202                *posp += 4;
203            break;
204        }
205
206        if (dst_len > LZO_BLOCK_SIZE) {
207            error("dest len longer than block size");
208            goto exit_2;
209        }
210
211        /* read compressed block size, and skip block checksum info */
212        if (fill && in_len < 8) {
213            skip = fill(in_buf + in_len, 8 - in_len);
214            if (skip > 0)
215                in_len += skip;
216        }
217        if (in_len < 8) {
218            error("file corrupted");
219            goto exit_2;
220        }
221        src_len = get_unaligned_be32(in_buf);
222        in_buf += 8;
223        in_len -= 8;
224
225        if (src_len <= 0 || src_len > dst_len) {
226            error("file corrupted");
227            goto exit_2;
228        }
229
230        /* decompress */
231        if (fill && in_len < src_len) {
232            skip = fill(in_buf + in_len, src_len - in_len);
233            if (skip > 0)
234                in_len += skip;
235        }
236        if (in_len < src_len) {
237            error("file corrupted");
238            goto exit_2;
239        }
240        tmp = dst_len;
241
242        /* When the input data is not compressed at all,
243         * lzo1x_decompress_safe will fail, so call memcpy()
244         * instead */
245        if (unlikely(dst_len == src_len))
246            memcpy(out_buf, in_buf, src_len);
247        else {
248            r = lzo1x_decompress_safe((u8 *) in_buf, src_len,
249                        out_buf, &tmp);
250
251            if (r != LZO_E_OK || dst_len != tmp) {
252                error("Compressed data violation");
253                goto exit_2;
254            }
255        }
256
257        if (flush && flush(out_buf, dst_len) != dst_len)
258            goto exit_2;
259        if (output)
260            out_buf += dst_len;
261        if (posp)
262            *posp += src_len + 12;
263
264        in_buf += src_len;
265        in_len -= src_len;
266        if (fill) {
267            /*
268             * If there happens to still be unused data left in
269             * in_buf, move it to the beginning of the buffer.
270             * Use a loop to avoid memmove() dependency.
271             */
272            if (in_len > 0)
273                for (skip = 0; skip < in_len; ++skip)
274                    in_buf_save[skip] = in_buf[skip];
275            in_buf = in_buf_save;
276        }
277    }
278
279    ret = 0;
280exit_2:
281    if (!input)
282        free(in_buf_save);
283exit_1:
284    if (!output)
285        free(out_buf);
286exit:
287    return ret;
288}
289
290#define decompress unlzo
291

Archive Download this file



interactive