diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/common/ucl_decompress.c | 192 | ||||
-rw-r--r-- | firmware/export/ucl_decompress.h | 32 |
2 files changed, 224 insertions, 0 deletions
diff --git a/firmware/common/ucl_decompress.c b/firmware/common/ucl_decompress.c new file mode 100644 index 0000000000..3b43d76f9d --- /dev/null +++ b/firmware/common/ucl_decompress.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* Standalone version of ucl_nrv2e_decompress_8 from UCL library | ||
2 | * Original copyright notice: | ||
3 | */ | ||
4 | /* n2e_d.c -- implementation of the NRV2E decompression algorithm | ||
5 | |||
6 | This file is part of the UCL data compression library. | ||
7 | |||
8 | Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer | ||
9 | All Rights Reserved. | ||
10 | |||
11 | The UCL library is free software; you can redistribute it and/or | ||
12 | modify it under the terms of the GNU General Public License as | ||
13 | published by the Free Software Foundation; either version 2 of | ||
14 | the License, or (at your option) any later version. | ||
15 | |||
16 | The UCL library is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with the UCL library; see the file COPYING. | ||
23 | If not, write to the Free Software Foundation, Inc., | ||
24 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
25 | |||
26 | Markus F.X.J. Oberhumer | ||
27 | <markus@oberhumer.com> | ||
28 | http://www.oberhumer.com/opensource/ucl/ | ||
29 | */ | ||
30 | |||
31 | #include "ucl_decompress.h" | ||
32 | |||
33 | #define UCL_UINT32_C(c) c ## U | ||
34 | #define fail(x, r) do if(x) { *dst_len = olen; return r; } while(0) | ||
35 | |||
36 | #define getbit(bb) \ | ||
37 | (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1) | ||
38 | |||
39 | int ucl_nrv2e_decompress_8(const uint8_t* src, uint32_t src_len, | ||
40 | uint8_t* dst, uint32_t* dst_len) | ||
41 | { | ||
42 | uint32_t bb = 0; | ||
43 | uint32_t ilen = 0, olen = 0, last_m_off = 1; | ||
44 | uint32_t oend = *dst_len; | ||
45 | |||
46 | for (;;) | ||
47 | { | ||
48 | uint32_t m_off, m_len; | ||
49 | |||
50 | while (getbit(bb)) | ||
51 | { | ||
52 | fail(ilen >= src_len, UCL_E_INPUT_OVERRUN); | ||
53 | fail(olen >= oend, UCL_E_OUTPUT_OVERRUN); | ||
54 | dst[olen++] = src[ilen++]; | ||
55 | } | ||
56 | m_off = 1; | ||
57 | for (;;) | ||
58 | { | ||
59 | m_off = m_off*2 + getbit(bb); | ||
60 | fail(ilen >= src_len, UCL_E_INPUT_OVERRUN); | ||
61 | fail(m_off > UCL_UINT32_C(0xffffff) + 3, UCL_E_LOOKBEHIND_OVERRUN); | ||
62 | if (getbit(bb)) break; | ||
63 | m_off = (m_off-1)*2 + getbit(bb); | ||
64 | } | ||
65 | if (m_off == 2) | ||
66 | { | ||
67 | m_off = last_m_off; | ||
68 | m_len = getbit(bb); | ||
69 | } | ||
70 | else | ||
71 | { | ||
72 | fail(ilen >= src_len, UCL_E_INPUT_OVERRUN); | ||
73 | m_off = (m_off-3)*256 + src[ilen++]; | ||
74 | if (m_off == UCL_UINT32_C(0xffffffff)) | ||
75 | break; | ||
76 | m_len = (m_off ^ UCL_UINT32_C(0xffffffff)) & 1; | ||
77 | m_off >>= 1; | ||
78 | last_m_off = ++m_off; | ||
79 | } | ||
80 | if (m_len) | ||
81 | m_len = 1 + getbit(bb); | ||
82 | else if (getbit(bb)) | ||
83 | m_len = 3 + getbit(bb); | ||
84 | else | ||
85 | { | ||
86 | m_len++; | ||
87 | do { | ||
88 | m_len = m_len*2 + getbit(bb); | ||
89 | fail(ilen >= src_len, UCL_E_INPUT_OVERRUN); | ||
90 | fail(m_len >= oend, UCL_E_OUTPUT_OVERRUN); | ||
91 | } while (!getbit(bb)); | ||
92 | m_len += 3; | ||
93 | } | ||
94 | m_len += (m_off > 0x500); | ||
95 | fail(olen + m_len > oend, UCL_E_OUTPUT_OVERRUN); | ||
96 | fail(m_off > olen, UCL_E_LOOKBEHIND_OVERRUN); | ||
97 | { | ||
98 | const uint8_t *m_pos; | ||
99 | m_pos = dst + olen - m_off; | ||
100 | dst[olen++] = *m_pos++; | ||
101 | do dst[olen++] = *m_pos++; while (--m_len > 0); | ||
102 | } | ||
103 | } | ||
104 | *dst_len = olen; | ||
105 | return ilen == src_len ? UCL_E_OK : (ilen < src_len ? UCL_E_INPUT_NOT_CONSUMED : UCL_E_INPUT_OVERRUN); | ||
106 | } | ||
107 | |||
108 | static uint32_t xread32(const uint8_t* d) | ||
109 | { | ||
110 | uint32_t r = 0; | ||
111 | r |= d[0] << 24; | ||
112 | r |= d[1] << 16; | ||
113 | r |= d[2] << 8; | ||
114 | r |= d[3] << 0; | ||
115 | return r; | ||
116 | } | ||
117 | |||
118 | /* From uclpack.c */ | ||
119 | int ucl_unpack(const uint8_t* src, uint32_t src_len, | ||
120 | uint8_t* dst, uint32_t* dst_len) | ||
121 | { | ||
122 | static const uint8_t magic[8] = | ||
123 | {0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a}; | ||
124 | |||
125 | /* make sure there are enough bytes for the header */ | ||
126 | if(src_len < 18) | ||
127 | return UCL_E_BAD_MAGIC; | ||
128 | |||
129 | /* avoid memcmp for reasons of code size */ | ||
130 | for(size_t i = 0; i < sizeof(magic); ++i) | ||
131 | if(src[i] != magic[i]) | ||
132 | return UCL_E_BAD_MAGIC; | ||
133 | |||
134 | /* read the other header fields */ | ||
135 | /* uint32_t flags = xread32(&src[8]); */ | ||
136 | uint8_t method = src[12]; | ||
137 | /* uint8_t level = src[13]; */ | ||
138 | uint32_t block_size = xread32(&src[14]); | ||
139 | |||
140 | /* check supported compression method */ | ||
141 | if(method != 0x2e) | ||
142 | return UCL_E_UNSUPPORTED_METHOD; | ||
143 | |||
144 | /* validate */ | ||
145 | if(block_size < 1024 || block_size > 8*1024*1024) | ||
146 | return UCL_E_BAD_BLOCK_SIZE; | ||
147 | |||
148 | /* process the blocks */ | ||
149 | src += 18; | ||
150 | src_len -= 18; | ||
151 | uint32_t dst_ilen = *dst_len; | ||
152 | while(1) { | ||
153 | if(src_len < 4) | ||
154 | return UCL_E_TRUNCATED; | ||
155 | |||
156 | uint32_t out_len = xread32(src); src += 4, src_len -= 4; | ||
157 | if(out_len == 0) | ||
158 | break; | ||
159 | |||
160 | if(src_len < 4) | ||
161 | return UCL_E_TRUNCATED; | ||
162 | |||
163 | uint32_t in_len = xread32(src); src += 4, src_len -= 4; | ||
164 | if(in_len > block_size || out_len > block_size || | ||
165 | in_len == 0 || in_len > out_len) | ||
166 | return UCL_E_CORRUPTED; | ||
167 | |||
168 | if(src_len < in_len) | ||
169 | return UCL_E_TRUNCATED; | ||
170 | |||
171 | if(in_len < out_len) { | ||
172 | uint32_t actual_out_len = dst_ilen; | ||
173 | int rc = ucl_nrv2e_decompress_8(src, in_len, dst, &actual_out_len); | ||
174 | if(rc != UCL_E_OK) | ||
175 | return rc; | ||
176 | if(actual_out_len != out_len) | ||
177 | return UCL_E_CORRUPTED; | ||
178 | } else { | ||
179 | for(size_t i = 0; i < in_len; ++i) | ||
180 | dst[i] = src[i]; | ||
181 | } | ||
182 | |||
183 | src += in_len; | ||
184 | src_len -= in_len; | ||
185 | dst += out_len; | ||
186 | dst_ilen -= out_len; | ||
187 | } | ||
188 | |||
189 | /* subtract leftover number of bytes to get size of compressed output */ | ||
190 | *dst_len -= dst_ilen; | ||
191 | return UCL_E_OK; | ||
192 | } | ||
diff --git a/firmware/export/ucl_decompress.h b/firmware/export/ucl_decompress.h new file mode 100644 index 0000000000..bea7564a94 --- /dev/null +++ b/firmware/export/ucl_decompress.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* Standalone UCL decompressor and uclpack-compatible unpacker, | ||
2 | * adapted for Rockbox from the libucl code. | ||
3 | * | ||
4 | * Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer | ||
5 | * All Rights Reserved. | ||
6 | * | ||
7 | * See firmware/common/ucl_decompress.c for full copyright notice | ||
8 | */ | ||
9 | #ifndef UCL_DECOMPRESS_H | ||
10 | #define UCL_DECOMPRESS_H | ||
11 | |||
12 | #include <stdint.h> | ||
13 | #include <stdlib.h> | ||
14 | |||
15 | #define UCL_E_OK 0 | ||
16 | #define UCL_E_INPUT_OVERRUN 1 | ||
17 | #define UCL_E_OUTPUT_OVERRUN 2 | ||
18 | #define UCL_E_LOOKBEHIND_OVERRUN 3 | ||
19 | #define UCL_E_INPUT_NOT_CONSUMED 4 | ||
20 | #define UCL_E_BAD_MAGIC 5 | ||
21 | #define UCL_E_BAD_BLOCK_SIZE 6 | ||
22 | #define UCL_E_UNSUPPORTED_METHOD 7 | ||
23 | #define UCL_E_TRUNCATED 8 | ||
24 | #define UCL_E_CORRUPTED 9 | ||
25 | |||
26 | extern int ucl_nrv2e_decompress_8(const uint8_t* src, uint32_t src_len, | ||
27 | uint8_t* dst, uint32_t* dst_len); | ||
28 | |||
29 | extern int ucl_unpack(const uint8_t* src, uint32_t src_len, | ||
30 | uint8_t* dst, uint32_t* dst_len); | ||
31 | |||
32 | #endif /* UCL_DECOMPRESS_H */ | ||