1 /* zenutils - Utilities for working with creative firmwares.
2 * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com>
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.
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.
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
25 const byte CODE_MASK
= 0xC0;
26 const byte ARGS_MASK
= 0x3F;
28 const byte REPEAT_CODE
= 0x00;
29 const byte BLOCK_CODE
= 0x40;
30 const byte LONG_RUN_CODE
= 0x80;
31 const byte SHORT_RUN_CODE
= 0xC0;
33 const byte BLOCK_ARGS
= 0x1F;
34 const byte BLOCK_MODE
= 0x20;
37 void decode_run(byte
* dst
, word len
, byte val
,
40 memset(dst
+ dstidx
, val
, len
);
44 void decode_pattern(byte
* src
, byte
* dst
,
45 word len
, int& srcidx
, int& dstidx
,
46 bool bdecode
, int npasses
)
48 for (int i
= 0; i
< npasses
; i
++)
52 for (int j
= 0; j
< len
; j
++)
58 src
[srcidx
+ j
] = static_cast<byte
>(c
| d
);
62 memcpy(dst
+ dstidx
, src
+ srcidx
, len
);
69 int zen::cenc_decode(byte
* src
, int srclen
, byte
* dst
, int dstlen
)
71 if (!src
|| !srclen
|| !dst
|| !dstlen
)
73 throw std::invalid_argument("Invalid argument(s).");
81 switch (c
& CODE_MASK
)
83 case REPEAT_CODE
: // 2 bytes
87 e
= (c
& ARGS_MASK
) + 2;
89 decode_pattern(src
, dst
, e
, i
, j
, false, d
);
92 case BLOCK_CODE
: // 1/2/3 bytes
94 if (!(c
& BLOCK_MODE
))
97 e
= (d
<< 8) + (e
+ 0x21);
99 d
= static_cast<word
>(i
^ j
);
105 d
= static_cast<word
>(i
^ j
);
112 decode_pattern(src
, dst
, e
, i
, j
, true, 1);
115 case LONG_RUN_CODE
: // 3 bytes
117 e
= ((c
& ARGS_MASK
) << 8) + (d
+ 0x42);
120 d
= ((d
& 7) << 5) | ((d
>> 3) & 0x1F);
122 decode_run(dst
, e
, static_cast<byte
>(d
), j
);
125 case SHORT_RUN_CODE
: // 2 bytes
127 d
= ((d
& 3) << 6) | ((d
>> 2) & 0x3F);
129 e
= (c
& ARGS_MASK
) + 2;
131 decode_run(dst
, e
, static_cast<byte
>(d
), j
);
134 } while (i
< srclen
&& j
< dstlen
);
140 int encode_run(byte
* dst
, int& dstidx
, byte val
, int len
, int dstlen
)
143 throw std::invalid_argument("Length is too small.");
148 if ((dstidx
+ 2) > dstlen
)
149 throw std::runtime_error("Not enough space to store run.");
151 dst
[dstidx
++] = SHORT_RUN_CODE
| (((len
- 2) & ARGS_MASK
));
152 dst
[dstidx
++] = ((val
>> 6) & 3) | ((val
& 0x3F) << 2);
156 else if (len
<= 0x4041)
158 if ((dstidx
+ 3) > dstlen
)
159 throw std::runtime_error("Not enough space to store run.");
161 byte b1
= (len
- 0x42) >> 8;
162 byte b2
= (len
- 0x42) & 0xFF;
164 dst
[dstidx
++] = LONG_RUN_CODE
| ((b1
& ARGS_MASK
));
166 dst
[dstidx
++] = ((val
>> 5) & 7) | ((val
& 0x1F) << 3);
172 int long_count
= len
/ 0x4041;
173 int short_len
= len
% 0x4041;
174 bool toosmall
= short_len
== 1;
176 int run_len
= 0x4041;
177 for (int i
= 0; i
< long_count
; i
++)
179 if (toosmall
&& (i
== (long_count
-1)))
184 int tmp
= encode_run(dst
, dstidx
, val
, run_len
, dstlen
);
192 int short_count
= len
/ 0x41;
193 int short_rest
= short_count
? (len
% 0x41) : 0;
194 toosmall
= short_rest
== 1;
197 for (int i
= 0; i
< short_count
; i
++)
199 if (toosmall
&& (i
== (short_count
-1)))
204 int tmp
= encode_run(dst
, dstidx
, val
, run_len
, dstlen
);
209 int tmp
= encode_run(dst
, dstidx
, val
, len
, dstlen
);
219 int encode_block(byte
* dst
, int& dstidx
, byte
* src
, int& srcidx
, int len
,
223 throw std::invalid_argument("Length is too small.");
225 int startidx
= dstidx
;
228 if ((dstidx
+ 2 + len
) > dstlen
)
229 throw std::runtime_error("Not enough space to store block.");
231 dst
[dstidx
++] = BLOCK_CODE
| BLOCK_MODE
| ((len
- 1) & BLOCK_ARGS
);
232 if ((dstidx
^ srcidx
) & 1)
235 for (int i
= 0; i
< len
; i
++)
237 byte c
= src
[srcidx
++];
238 byte d
= (c
& 7) << 5;
240 dst
[dstidx
++] = c
| d
;
243 else if (len
< 0x2021)
245 if ((dstidx
+ 3 + len
) > dstlen
)
246 throw std::runtime_error("Not enough space to store block.");
248 dst
[dstidx
++] = BLOCK_CODE
| (((len
- 0x21) >> 8) & BLOCK_ARGS
);
249 dst
[dstidx
++] = (len
- 0x21) & 0xFF;
250 if ((dstidx
^ srcidx
) & 1)
253 for (int i
= 0; i
< len
; i
++)
255 byte c
= src
[srcidx
++];
256 byte d
= (c
& 7) << 5;
258 dst
[dstidx
++] = c
| d
;
263 int longblocks
= len
/ 0x2020;
264 int rest
= len
% 0x2020;
265 for (int i
= 0; i
< longblocks
; i
++)
267 int tmp
= encode_block(dst
, dstidx
, src
, srcidx
, 0x2020, dstlen
);
272 int shortblocks
= rest
/ 0x20;
273 for (int i
= 0; i
< shortblocks
; i
++)
275 int tmp
= encode_block(dst
, dstidx
, src
, srcidx
, 0x20, dstlen
);
279 int tmp
= encode_block(dst
, dstidx
, src
, srcidx
, rest
, dstlen
);
284 return (dstidx
- startidx
);
288 int zen::cenc_encode(byte
* src
, int srclen
, byte
* dst
, int dstlen
)
290 if (!src
|| !srclen
|| !dst
|| !dstlen
)
292 throw std::invalid_argument("Invalid argument(s).");
295 int i
= 0, j
= 0, k
= 0;
298 while (i
< srclen
&& j
< dstlen
)
303 while (i
< srclen
&& src
[i
] == c
)
310 if (!encode_run(dst
, j
, c
, runlen
, dstlen
))
317 while (i
< (srclen
- 1) && (src
[i
] != src
[i
+ 1]))
322 if (i
== (srclen
- 1))
327 if (!encode_block(dst
, j
, src
, k
, runlen
, dstlen
))