summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/common/ucl_decompress.c192
-rw-r--r--firmware/export/ucl_decompress.h32
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
39int 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
108static 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 */
119int 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
26extern int ucl_nrv2e_decompress_8(const uint8_t* src, uint32_t src_len,
27 uint8_t* dst, uint32_t* dst_len);
28
29extern 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 */