FS#8961 - Anti-Aliased Fonts.
[kugel-rb.git] / utils / zenutils / source / shared / cenc.cpp
blob929a59b64d9f7cd46067094ca5c8dde9e18f1f84
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
19 #include "cenc.h"
20 #include <firmware.h>
21 #include <stdexcept>
24 namespace {
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,
38 int& dstidx)
40 memset(dst + dstidx, val, len);
41 dstidx += 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++)
50 if (bdecode)
52 for (int j = 0; j < len; j++)
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);
60 bdecode = false;
62 memcpy(dst + dstidx, src + srcidx, len);
63 dstidx += len;
65 srcidx += len;
67 }; //namespace
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).");
76 int i = 0, j = 0;
79 word c, d, e;
80 c = src[i++];
81 switch (c & CODE_MASK)
83 case REPEAT_CODE: // 2 bytes
84 d = src[i++];
85 d = d + 2;
87 e = (c & ARGS_MASK) + 2;
89 decode_pattern(src, dst, e, i, j, false, d);
90 break;
92 case BLOCK_CODE: // 1/2/3 bytes
93 d = c & BLOCK_ARGS;
94 if (!(c & BLOCK_MODE))
96 e = src[i++];
97 e = (d << 8) + (e + 0x21);
99 d = static_cast<word>(i ^ j);
101 else
103 e = d + 1;
105 d = static_cast<word>(i ^ j);
107 if (d & 1)
109 i++;
112 decode_pattern(src, dst, e, i, j, true, 1);
113 break;
115 case LONG_RUN_CODE: // 3 bytes
116 d = src[i++];
117 e = ((c & ARGS_MASK) << 8) + (d + 0x42);
119 d = src[i++];
120 d = ((d & 7) << 5) | ((d >> 3) & 0x1F);
122 decode_run(dst, e, static_cast<byte>(d), j);
123 break;
125 case SHORT_RUN_CODE: // 2 bytes
126 d = src[i++];
127 d = ((d & 3) << 6) | ((d >> 2) & 0x3F);
129 e = (c & ARGS_MASK) + 2;
131 decode_run(dst, e, static_cast<byte>(d), j);
132 break;
134 } while (i < srclen && j < dstlen);
136 return j;
139 namespace {
140 int encode_run(byte* dst, int& dstidx, byte val, int len, int dstlen)
142 if (len < 2)
143 throw std::invalid_argument("Length is too small.");
145 int ret = 0;
146 if (len <= 0x41)
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);
154 ret = 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));
165 dst[dstidx++] = b2;
166 dst[dstidx++] = ((val >> 5) & 7) | ((val & 0x1F) << 3);
168 ret = 3;
170 else
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)))
181 run_len--;
182 toosmall = false;
184 int tmp = encode_run(dst, dstidx, val, run_len, dstlen);
185 if (!tmp) return 0;
186 ret += tmp;
187 len -= run_len;
190 if (len)
192 int short_count = len / 0x41;
193 int short_rest = short_count ? (len % 0x41) : 0;
194 toosmall = short_rest == 1;
196 run_len = 0x41;
197 for (int i = 0; i < short_count; i++)
199 if (toosmall && (i == (short_count-1)))
201 run_len--;
202 toosmall = false;
204 int tmp = encode_run(dst, dstidx, val, run_len, dstlen);
205 if (!tmp) return 0;
206 ret += tmp;
207 len -= run_len;
209 int tmp = encode_run(dst, dstidx, val, len, dstlen);
210 if (!tmp) return 0;
211 ret += tmp;
212 len -= len;
216 return ret;
219 int encode_block(byte* dst, int& dstidx, byte* src, int& srcidx, int len,
220 int dstlen)
222 if (len < 1)
223 throw std::invalid_argument("Length is too small.");
225 int startidx = dstidx;
226 if (len < 0x21)
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)
233 dst[dstidx++] = 0;
235 for (int i = 0; i < len; i++)
237 byte c = src[srcidx++];
238 byte d = (c & 7) << 5;
239 c = (c & 0xF8) >> 3;
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)
251 dst[dstidx++] = 0;
253 for (int i = 0; i < len; i++)
255 byte c = src[srcidx++];
256 byte d = (c & 7) << 5;
257 c = (c & 0xF8) >> 3;
258 dst[dstidx++] = c | d;
261 else
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);
268 if (!tmp) return 0;
270 if (rest)
272 int shortblocks = rest / 0x20;
273 for (int i = 0; i < shortblocks; i++)
275 int tmp = encode_block(dst, dstidx, src, srcidx, 0x20, dstlen);
276 if (!tmp) return 0;
278 rest = rest % 0x20;
279 int tmp = encode_block(dst, dstidx, src, srcidx, rest, dstlen);
280 if (!tmp) return 0;
284 return (dstidx - startidx);
286 }; //namespace
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;
296 word c, d, e;
297 int runlen = 0;
298 while (i < srclen && j < dstlen)
300 k = i;
301 c = src[i++];
302 runlen = 1;
303 while (i < srclen && src[i] == c)
305 runlen++;
306 i++;
308 if (runlen >= 2)
310 if (!encode_run(dst, j, c, runlen, dstlen))
311 return 0;
313 else
315 runlen = 0;
316 i = k;
317 while (i < (srclen - 1) && (src[i] != src[i + 1]))
319 runlen++;
320 i++;
322 if (i == (srclen - 1))
324 runlen++;
325 i++;
327 if (!encode_block(dst, j, src, k, runlen, dstlen))
328 return 0;
332 return j;