summaryrefslogtreecommitdiff
path: root/utils/zenutils/source/shared/cenc.cpp
diff options
context:
space:
mode:
authorMaurus Cuelenaere <mcuelenaere@gmail.com>2008-07-11 15:50:46 +0000
committerMaurus Cuelenaere <mcuelenaere@gmail.com>2008-07-11 15:50:46 +0000
commit14c7f45cdae826f88dc539c8c38dd95caf305731 (patch)
tree832da054b7cfb2dc6fd63339af736625f31d21aa /utils/zenutils/source/shared/cenc.cpp
parent7c84ede3781c27db73403bd6302f320c76a58c8c (diff)
downloadrockbox-14c7f45cdae826f88dc539c8c38dd95caf305731.tar.gz
rockbox-14c7f45cdae826f88dc539c8c38dd95caf305731.zip
Add zook's ZenUtils to SVN
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18010 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/zenutils/source/shared/cenc.cpp')
-rwxr-xr-xutils/zenutils/source/shared/cenc.cpp333
1 files changed, 333 insertions, 0 deletions
diff --git a/utils/zenutils/source/shared/cenc.cpp b/utils/zenutils/source/shared/cenc.cpp
new file mode 100755
index 0000000000..932bee4625
--- /dev/null
+++ b/utils/zenutils/source/shared/cenc.cpp
@@ -0,0 +1,333 @@
1/* zenutils - Utilities for working with creative firmwares.
2 * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#include "cenc.h"
20#include <firmware.h>
21#include <stdexcept>
22
23
24namespace {
25const byte CODE_MASK = 0xC0;
26const byte ARGS_MASK = 0x3F;
27
28const byte REPEAT_CODE = 0x00;
29const byte BLOCK_CODE = 0x40;
30const byte LONG_RUN_CODE = 0x80;
31const byte SHORT_RUN_CODE = 0xC0;
32
33const byte BLOCK_ARGS = 0x1F;
34const byte BLOCK_MODE = 0x20;
35
36
37void decode_run(byte* dst, word len, byte val,
38 int& dstidx)
39{
40 memset(dst + dstidx, val, len);
41 dstidx += len;
42}
43
44void decode_pattern(byte* src, byte* dst,
45 word len, int& srcidx, int& dstidx,
46 bool bdecode, int npasses)
47{
48 for (int i = 0; i < npasses; i++)
49 {
50 if (bdecode)
51 {
52 for (int j = 0; j < len; j++)
53 {
54 word c, d;
55 c = src[srcidx + j];
56 d = (c >> 5) & 7;
57 c = (c << 3) & 0xF8;
58 src[srcidx + j] = static_cast<byte>(c | d);
59 }
60 bdecode = false;
61 }
62 memcpy(dst + dstidx, src + srcidx, len);
63 dstidx += len;
64 }
65 srcidx += len;
66}
67}; //namespace
68
69int zen::cenc_decode(byte* src, int srclen, byte* dst, int dstlen)
70{
71 if (!src || !srclen || !dst || !dstlen)
72 {
73 throw std::invalid_argument("Invalid argument(s).");
74 }
75
76 int i = 0, j = 0;
77 do
78 {
79 word c, d, e;
80 c = src[i++];
81 switch (c & CODE_MASK)
82 {
83 case REPEAT_CODE: // 2 bytes
84 d = src[i++];
85 d = d + 2;
86
87 e = (c & ARGS_MASK) + 2;
88
89 decode_pattern(src, dst, e, i, j, false, d);
90 break;
91
92 case BLOCK_CODE: // 1/2/3 bytes
93 d = c & BLOCK_ARGS;
94 if (!(c & BLOCK_MODE))
95 {
96 e = src[i++];
97 e = (d << 8) + (e + 0x21);
98
99 d = static_cast<word>(i ^ j);
100 }
101 else
102 {
103 e = d + 1;
104
105 d = static_cast<word>(i ^ j);
106 }
107 if (d & 1)
108 {
109 i++;
110 }
111
112 decode_pattern(src, dst, e, i, j, true, 1);
113 break;
114
115 case LONG_RUN_CODE: // 3 bytes
116 d = src[i++];
117 e = ((c & ARGS_MASK) << 8) + (d + 0x42);
118
119 d = src[i++];
120 d = ((d & 7) << 5) | ((d >> 3) & 0x1F);
121
122 decode_run(dst, e, static_cast<byte>(d), j);
123 break;
124
125 case SHORT_RUN_CODE: // 2 bytes
126 d = src[i++];
127 d = ((d & 3) << 6) | ((d >> 2) & 0x3F);
128
129 e = (c & ARGS_MASK) + 2;
130
131 decode_run(dst, e, static_cast<byte>(d), j);
132 break;
133 };
134 } while (i < srclen && j < dstlen);
135
136 return j;
137}
138
139namespace {
140int encode_run(byte* dst, int& dstidx, byte val, int len, int dstlen)
141{
142 if (len < 2)
143 throw std::invalid_argument("Length is too small.");
144
145 int ret = 0;
146 if (len <= 0x41)
147 {
148 if ((dstidx + 2) > dstlen)
149 throw std::runtime_error("Not enough space to store run.");
150
151 dst[dstidx++] = SHORT_RUN_CODE | (((len - 2) & ARGS_MASK));
152 dst[dstidx++] = ((val >> 6) & 3) | ((val & 0x3F) << 2);
153
154 ret = 2;
155 }
156 else if (len <= 0x4041)
157 {
158 if ((dstidx + 3) > dstlen)
159 throw std::runtime_error("Not enough space to store run.");
160
161 byte b1 = (len - 0x42) >> 8;
162 byte b2 = (len - 0x42) & 0xFF;
163
164 dst[dstidx++] = LONG_RUN_CODE | ((b1 & ARGS_MASK));
165 dst[dstidx++] = b2;
166 dst[dstidx++] = ((val >> 5) & 7) | ((val & 0x1F) << 3);
167
168 ret = 3;
169 }
170 else
171 {
172 int long_count = len / 0x4041;
173 int short_len = len % 0x4041;
174 bool toosmall = short_len == 1;
175
176 int run_len = 0x4041;
177 for (int i = 0; i < long_count; i++)
178 {
179 if (toosmall && (i == (long_count-1)))
180 {
181 run_len--;
182 toosmall = false;
183 }
184 int tmp = encode_run(dst, dstidx, val, run_len, dstlen);
185 if (!tmp) return 0;
186 ret += tmp;
187 len -= run_len;
188 }
189
190 if (len)
191 {
192 int short_count = len / 0x41;
193 int short_rest = short_count ? (len % 0x41) : 0;
194 toosmall = short_rest == 1;
195
196 run_len = 0x41;
197 for (int i = 0; i < short_count; i++)
198 {
199 if (toosmall && (i == (short_count-1)))
200 {
201 run_len--;
202 toosmall = false;
203 }
204 int tmp = encode_run(dst, dstidx, val, run_len, dstlen);
205 if (!tmp) return 0;
206 ret += tmp;
207 len -= run_len;
208 }
209 int tmp = encode_run(dst, dstidx, val, len, dstlen);
210 if (!tmp) return 0;
211 ret += tmp;
212 len -= len;
213 }
214 }
215
216 return ret;
217}
218
219int encode_block(byte* dst, int& dstidx, byte* src, int& srcidx, int len,
220 int dstlen)
221{
222 if (len < 1)
223 throw std::invalid_argument("Length is too small.");
224
225 int startidx = dstidx;
226 if (len < 0x21)
227 {
228 if ((dstidx + 2 + len) > dstlen)
229 throw std::runtime_error("Not enough space to store block.");
230
231 dst[dstidx++] = BLOCK_CODE | BLOCK_MODE | ((len - 1) & BLOCK_ARGS);
232 if ((dstidx ^ srcidx) & 1)
233 dst[dstidx++] = 0;
234
235 for (int i = 0; i < len; i++)
236 {
237 byte c = src[srcidx++];
238 byte d = (c & 7) << 5;
239 c = (c & 0xF8) >> 3;
240 dst[dstidx++] = c | d;
241 }
242 }
243 else if (len < 0x2021)
244 {
245 if ((dstidx + 3 + len) > dstlen)
246 throw std::runtime_error("Not enough space to store block.");
247
248 dst[dstidx++] = BLOCK_CODE | (((len - 0x21) >> 8) & BLOCK_ARGS);
249 dst[dstidx++] = (len - 0x21) & 0xFF;
250 if ((dstidx ^ srcidx) & 1)
251 dst[dstidx++] = 0;
252
253 for (int i = 0; i < len; i++)
254 {
255 byte c = src[srcidx++];
256 byte d = (c & 7) << 5;
257 c = (c & 0xF8) >> 3;
258 dst[dstidx++] = c | d;
259 }
260 }
261 else
262 {
263 int longblocks = len / 0x2020;
264 int rest = len % 0x2020;
265 for (int i = 0; i < longblocks; i++)
266 {
267 int tmp = encode_block(dst, dstidx, src, srcidx, 0x2020, dstlen);
268 if (!tmp) return 0;
269 }
270 if (rest)
271 {
272 int shortblocks = rest / 0x20;
273 for (int i = 0; i < shortblocks; i++)
274 {
275 int tmp = encode_block(dst, dstidx, src, srcidx, 0x20, dstlen);
276 if (!tmp) return 0;
277 }
278 rest = rest % 0x20;
279 int tmp = encode_block(dst, dstidx, src, srcidx, rest, dstlen);
280 if (!tmp) return 0;
281 }
282 }
283
284 return (dstidx - startidx);
285}
286}; //namespace
287
288int zen::cenc_encode(byte* src, int srclen, byte* dst, int dstlen)
289{
290 if (!src || !srclen || !dst || !dstlen)
291 {
292 throw std::invalid_argument("Invalid argument(s).");
293 }
294
295 int i = 0, j = 0, k = 0;
296 word c, d, e;
297 int runlen = 0;
298 while (i < srclen && j < dstlen)
299 {
300 k = i;
301 c = src[i++];
302 runlen = 1;
303 while (i < srclen && src[i] == c)
304 {
305 runlen++;
306 i++;
307 }
308 if (runlen >= 2)
309 {
310 if (!encode_run(dst, j, c, runlen, dstlen))
311 return 0;
312 }
313 else
314 {
315 runlen = 0;
316 i = k;
317 while (i < (srclen - 1) && (src[i] != src[i + 1]))
318 {
319 runlen++;
320 i++;
321 }
322 if (i == (srclen - 1))
323 {
324 runlen++;
325 i++;
326 }
327 if (!encode_block(dst, j, src, k, runlen, dstlen))
328 return 0;
329 }
330 }
331
332 return j;
333}