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