A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 332 lines 8.7 kB view raw
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 } 213 } 214 215 return ret; 216} 217 218int encode_block(byte* dst, int& dstidx, byte* src, int& srcidx, int len, 219 int dstlen) 220{ 221 if (len < 1) 222 throw std::invalid_argument("Length is too small."); 223 224 int startidx = dstidx; 225 if (len < 0x21) 226 { 227 if ((dstidx + 2 + len) > dstlen) 228 throw std::runtime_error("Not enough space to store block."); 229 230 dst[dstidx++] = BLOCK_CODE | BLOCK_MODE | ((len - 1) & BLOCK_ARGS); 231 if ((dstidx ^ srcidx) & 1) 232 dst[dstidx++] = 0; 233 234 for (int i = 0; i < len; i++) 235 { 236 byte c = src[srcidx++]; 237 byte d = (c & 7) << 5; 238 c = (c & 0xF8) >> 3; 239 dst[dstidx++] = c | d; 240 } 241 } 242 else if (len < 0x2021) 243 { 244 if ((dstidx + 3 + len) > dstlen) 245 throw std::runtime_error("Not enough space to store block."); 246 247 dst[dstidx++] = BLOCK_CODE | (((len - 0x21) >> 8) & BLOCK_ARGS); 248 dst[dstidx++] = (len - 0x21) & 0xFF; 249 if ((dstidx ^ srcidx) & 1) 250 dst[dstidx++] = 0; 251 252 for (int i = 0; i < len; i++) 253 { 254 byte c = src[srcidx++]; 255 byte d = (c & 7) << 5; 256 c = (c & 0xF8) >> 3; 257 dst[dstidx++] = c | d; 258 } 259 } 260 else 261 { 262 int longblocks = len / 0x2020; 263 int rest = len % 0x2020; 264 for (int i = 0; i < longblocks; i++) 265 { 266 int tmp = encode_block(dst, dstidx, src, srcidx, 0x2020, dstlen); 267 if (!tmp) return 0; 268 } 269 if (rest) 270 { 271 int shortblocks = rest / 0x20; 272 for (int i = 0; i < shortblocks; i++) 273 { 274 int tmp = encode_block(dst, dstidx, src, srcidx, 0x20, dstlen); 275 if (!tmp) return 0; 276 } 277 rest = rest % 0x20; 278 int tmp = encode_block(dst, dstidx, src, srcidx, rest, dstlen); 279 if (!tmp) return 0; 280 } 281 } 282 283 return (dstidx - startidx); 284} 285}; //namespace 286 287int zen::cenc_encode(byte* src, int srclen, byte* dst, int dstlen) 288{ 289 if (!src || !srclen || !dst || !dstlen) 290 { 291 throw std::invalid_argument("Invalid argument(s)."); 292 } 293 294 int i = 0, j = 0, k = 0; 295 word c, d, e; 296 int runlen = 0; 297 while (i < srclen && j < dstlen) 298 { 299 k = i; 300 c = src[i++]; 301 runlen = 1; 302 while (i < srclen && src[i] == c) 303 { 304 runlen++; 305 i++; 306 } 307 if (runlen >= 2) 308 { 309 if (!encode_run(dst, j, c, runlen, dstlen)) 310 return 0; 311 } 312 else 313 { 314 runlen = 0; 315 i = k; 316 while (i < (srclen - 1) && (src[i] != src[i + 1])) 317 { 318 runlen++; 319 i++; 320 } 321 if (i == (srclen - 1)) 322 { 323 runlen++; 324 i++; 325 } 326 if (!encode_block(dst, j, src, k, runlen, dstlen)) 327 return 0; 328 } 329 } 330 331 return j; 332}