A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 443 lines 13 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2004 by Dave Hooper 11 * 12 * This particular source code file is licensed under the X11 license. See the 13 * bottom of the COPYING file for details on this license. 14 * 15 * Original code from http://www.beermex.com/@spc/ihpfirm.src.zip 16 * Details at http://www.rockbox.org/wiki/IriverToolsGuide 17 * 18 ****************************************************************************/ 19#include <stdio.h> 20#include <stdlib.h> 21#include <string.h> 22 23#include "iriver.h" 24 25const unsigned char munge[] = { 26 0x7a, 0x36, 0xc4, 0x43, 0x49, 0x6b, 0x35, 0x4e, 0xa3, 0x46, 0x25, 0x84, 27 0x4d, 0x73, 0x74, 0x61 28}; 29 30const unsigned char header_modify[] = "* IHPFIRM-DECODED "; 31 32const char * const models[] = { "iHP-100", "iHP-120/iHP-140", "H300 series", 33 NULL }; 34 35/* aligns with models array; expected min firmware size */ 36const unsigned int firmware_minsize[] = { 0x100000, 0x100000, 0x200000 }; 37/* aligns with models array; expected max firmware size */ 38const unsigned int firmware_maxsize[] = { 0x200000, 0x200000, 0x400000 }; 39 40const unsigned char header[][16] = { 41 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 42 { 0x20, 0x03, 0x08, 0x27, 0x24, 0x00, 0x02, 0x30, 0x19, 0x17, 0x65, 0x73, 43 0x85, 0x32, 0x83, 0x22 }, 44 { 0x20, 0x04, 0x03, 0x27, 0x20, 0x50, 0x01, 0x70, 0x80, 0x30, 0x80, 0x06, 45 0x30, 0x19, 0x17, 0x65 } 46}; 47 48static int testheader( const unsigned char * const data ) 49{ 50 const unsigned char * const d = data+16; 51 const char * const * m = models; 52 int ind = 0; 53 while( *m ) 54 { 55 if( memcmp( header[ ind ], d, 16 ) == 0 ) 56 return ind; 57 ind++; 58 m++; 59 }; 60 return -1; 61} 62 63static void modifyheader( unsigned char * data ) 64{ 65 const unsigned char * h = header_modify; 66 int i; 67 for( i=0; i<512; i++ ) 68 { 69 if( *h == '\0' ) 70 h = header_modify; 71 *data++ ^= *h++; 72 }; 73} 74 75static FILE * openinfile( const char * filename ) 76{ 77 FILE * F = fopen( filename, "rb" ); 78 if( F == NULL ) 79 { 80 fprintf( stderr, "Couldn't open input file %s\n", filename ); 81 perror( "Error was " ); 82 exit( -1 ); 83 }; 84 return F; 85} 86 87static FILE * openoutfile( const char * filename ) 88{ 89 FILE * F = fopen( filename, "wb" ); 90 if( F == NULL ) 91 { 92 fprintf( stderr, "Couldn't open output file %s\n", filename ); 93 perror( "Error was " ); 94 exit( -1 ); 95 }; 96 return F; 97} 98 99int iriver_decode(const char *infile_name, const char *outfile_name, BOOL modify, 100 enum striptype stripmode ) 101{ 102 int rv = 0; 103 FILE * infile = NULL; 104 FILE * outfile = NULL; 105 int i = -1; 106 unsigned char headerdata[512]; 107 unsigned int dwLength1, dwLength2, dwLength3, fp = 0; 108 unsigned int minsize, maxsize, sizes[2]; 109 unsigned char blockdata[16+16]; 110 unsigned char out[16]; 111 unsigned char newmunge; 112 signed long lenread; 113 int s = 0; 114 unsigned char * pChecksums = NULL, * ppChecksums = NULL; 115 unsigned char ck; 116 117 infile = openinfile(infile_name); 118 outfile = openoutfile(outfile_name); 119 120 lenread = fread( headerdata, 1, 512, infile ); 121 if( lenread != 512 ) 122 { 123 fprintf( stderr, "This doesn't look like a valid encrypted iHP " 124 "firmware - reason: header length\n" ); 125 rv = -1; 126 goto bail; 127 }; 128 129 i = testheader( headerdata ); 130 if( i == -1 ) 131 { 132 fprintf( stderr, "This firmware is for an unknown model, or is not" 133 " a valid encrypted iHP firmware\n" ); 134 rv = -2; 135 goto bail; 136 }; 137 fprintf( stderr, "Model %s\n", models[ i ] ); 138 139 dwLength1 = headerdata[0] | (headerdata[1]<<8) | 140 (headerdata[2]<<16) | (headerdata[3]<<24); 141 dwLength2 = headerdata[4] | (headerdata[5]<<8) | 142 (headerdata[6]<<16) | (headerdata[7]<<24); 143 dwLength3 = headerdata[8] | (headerdata[9]<<8) | 144 (headerdata[10]<<16) | (headerdata[11]<<24); 145 146 if( dwLength2 > dwLength1 || 147 dwLength3 > dwLength1 || 148 dwLength2>>9 != dwLength3 || 149 dwLength2+dwLength3+512 != dwLength1 ) 150 { 151 fprintf( stderr, "This doesn't look like a valid encrypted " 152 "iHP firmware - reason: file 'length' data\n" ); 153 rv = -3; 154 goto bail; 155 }; 156 157 minsize = firmware_minsize[i]; 158 maxsize = firmware_maxsize[i]; 159 sizes[0] = sizes[1] = 0; 160 161 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) ); 162 163 if( modify ) 164 { 165 modifyheader( headerdata ); 166 }; 167 168 if( stripmode == STRIP_NONE ) 169 fwrite( headerdata, 512, 1, outfile ); 170 171 memset( blockdata, 0, 16 ); 172 173 ck = 0; 174 while( ( fp < dwLength2 ) && 175 ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 ) 176 { 177 fp += 16; 178 179 for( i=0; i<16; ++i ) 180 { 181 newmunge = blockdata[16+i] ^ munge[i]; 182 out[i] = newmunge ^ blockdata[i]; 183 blockdata[i] = newmunge; 184 ck += out[i]; 185 } 186 187 if (fp <= 32) 188 sizes[fp / 16 - 1] = (out[0] << 24) | 189 (out[1] << 16) | 190 (out[2] << 8) | 191 (out[3] << 0); 192 193 if( fp > ESTF_SIZE || stripmode != STRIP_HEADER_CHECKSUM_ESTF ) 194 { 195 fwrite( out+4, 1, 12, outfile ); 196 fwrite( out, 1, 4, outfile ); 197 } 198 else 199 { 200 if( ESTF_SIZE - fp < 16 ) 201 { 202 memcpy( out+4, blockdata+16, 12 ); 203 memcpy( out, blockdata+28, 4 ); 204 fwrite( blockdata+16+ESTF_SIZE-fp, 1, ESTF_SIZE-fp, outfile ); 205 } 206 } 207 208 209 if( s == 496 ) 210 { 211 s = 0; 212 memset( blockdata, 0, 16 ); 213 *ppChecksums++ = ck; 214 ck = 0; 215 } 216 else 217 s+=16; 218 }; 219 220 if( sizes[0] < minsize || 221 sizes[1] < minsize || 222 sizes[0] > maxsize || 223 sizes[1] > maxsize ) 224 { 225 fprintf( stderr, "This doesn't look like a valid encrypted " 226 "iHP firmware - reason: ESTFBINR 'length' data\n" ); 227 rv = -4; 228 goto bail; 229 }; 230 231 if( fp != dwLength2 ) 232 { 233 fprintf( stderr, "This doesn't look like a valid encrypted " 234 "iHP firmware - reason: 'length2' mismatch\n" ); 235 rv = -5; 236 goto bail; 237 }; 238 239 fp = 0; 240 ppChecksums = pChecksums; 241 while( ( fp < dwLength3 ) && 242 ( lenread = fread( blockdata, 1, 32, infile ) ) > 0 ) 243 { 244 fp += lenread; 245 if( stripmode == STRIP_NONE ) 246 fwrite( blockdata, 1, lenread, outfile ); 247 if( memcmp( ppChecksums, blockdata, lenread ) != 0 ) 248 { 249 fprintf( stderr, "This doesn't look like a valid encrypted " 250 "iHP firmware - reason: Checksum mismatch!" ); 251 rv = -6; 252 goto bail; 253 }; 254 ppChecksums += lenread; 255 }; 256 257 if( fp != dwLength3 ) 258 { 259 fprintf( stderr, "This doesn't look like a valid encrypted " 260 "iHP firmware - reason: 'length3' mismatch\n" ); 261 rv = -7; 262 goto bail; 263 }; 264 265 266 fprintf( stderr, "File decoded correctly and all checksums matched!\n" ); 267 switch( stripmode ) 268 { 269 default: 270 case STRIP_NONE: 271 fprintf(stderr, "Output file contains all headers and " 272 "checksums\n"); 273 break; 274 case STRIP_HEADER_CHECKSUM: 275 fprintf( stderr, "NB: output file contains only ESTFBINR header" 276 " and decoded firmware code\n" ); 277 break; 278 case STRIP_HEADER_CHECKSUM_ESTF: 279 fprintf( stderr, "NB: output file contains only raw decoded " 280 "firmware code\n" ); 281 break; 282 }; 283 284bail: 285 if (infile != NULL) 286 fclose(infile); 287 if (outfile != NULL) 288 fclose(outfile); 289 free(pChecksums); 290 return rv; 291} 292 293int iriver_encode(const char *infile_name, const char *outfile_name, BOOL modify ) 294{ 295 int rv = 0; 296 FILE * infile = NULL; 297 FILE * outfile = NULL; 298 int i = -1; 299 unsigned char headerdata[512]; 300 unsigned int dwLength1, dwLength2, dwLength3, fp = 0; 301 unsigned int minsize, maxsize, sizes[2]; 302 unsigned char blockdata[16+16]; 303 unsigned char out[16]; 304 unsigned char newmunge; 305 signed long lenread; 306 int s = 0; 307 unsigned char * pChecksums = NULL, * ppChecksums = NULL; 308 unsigned char ck; 309 310 infile = openinfile(infile_name); 311 outfile = openoutfile(outfile_name); 312 313 lenread = fread( headerdata, 1, 512, infile ); 314 if( lenread != 512 ) 315 { 316 fprintf( stderr, "This doesn't look like a valid decoded " 317 "iHP firmware - reason: header length\n" ); 318 rv = -1; 319 goto bail; 320 }; 321 322 if( modify ) 323 { 324 modifyheader( headerdata ); /* reversible */ 325 }; 326 327 i = testheader( headerdata ); 328 if( i == -1 ) 329 { 330 fprintf( stderr, "This firmware is for an unknown model, or is not" 331 " a valid decoded iHP firmware\n" ); 332 rv = -2; 333 goto bail; 334 }; 335 fprintf( stderr, "Model %s\n", models[ i ] ); 336 337 dwLength1 = headerdata[0] | (headerdata[1]<<8) | 338 (headerdata[2]<<16) | (headerdata[3]<<24); 339 dwLength2 = headerdata[4] | (headerdata[5]<<8) | 340 (headerdata[6]<<16) | (headerdata[7]<<24); 341 dwLength3 = headerdata[8] | (headerdata[9]<<8) | 342 (headerdata[10]<<16) | (headerdata[11]<<24); 343 344 if( dwLength2 > dwLength1 || 345 dwLength3 > dwLength1 || 346 dwLength2+dwLength3+512 != dwLength1 ) 347 { 348 fprintf( stderr, "This doesn't look like a valid decoded iHP" 349 " firmware - reason: file 'length' data\n" ); 350 rv = -3; 351 goto bail; 352 }; 353 354 minsize = firmware_minsize[i]; 355 maxsize = firmware_maxsize[i]; 356 sizes[0] = sizes[1] = 0; 357 358 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) ); 359 360 fwrite( headerdata, 512, 1, outfile ); 361 362 memset( blockdata, 0, 16 ); 363 ck = 0; 364 while( ( fp < dwLength2 ) && 365 ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 ) 366 { 367 fp += 16; 368 369 if (fp <= 32) 370 sizes[fp / 16 - 1] = (blockdata[28] << 24) | 371 (blockdata[29] << 16) | 372 (blockdata[30] << 8) | 373 (blockdata[31] << 0); 374 375 for( i=0; i<16; ++i ) 376 { 377 newmunge = blockdata[16+((12+i)&0xf)] ^ blockdata[i]; 378 out[i] = newmunge ^ munge[i]; 379 ck += blockdata[16+i]; 380 blockdata[i] = newmunge; 381 }; 382 fwrite( out, 1, 16, outfile ); 383 384 if( s == 496 ) 385 { 386 s = 0; 387 memset( blockdata, 0, 16 ); 388 *ppChecksums++ = ck; 389 ck = 0; 390 } 391 else 392 s+=16; 393 }; 394 395 if( sizes[0] < minsize || 396 sizes[1] < minsize || 397 sizes[0] > maxsize || 398 sizes[1] > maxsize ) 399 { 400 fprintf( stderr, "This doesn't look like a valid decoded iHP" 401 " firmware - reason: ESTFBINR 'length' data\n" ); 402 rv = -4; 403 goto bail; 404 }; 405 406 if( fp != dwLength2 ) 407 { 408 fprintf( stderr, "This doesn't look like a valid decoded " 409 "iHP firmware - reason: 'length1' mismatch\n" ); 410 rv = -5; 411 goto bail; 412 }; 413 414 /* write out remainder w/out applying descrambler */ 415 fp = 0; 416 lenread = dwLength3; 417 ppChecksums = pChecksums; 418 while( ( fp < dwLength3) && 419 ( lenread = fwrite( ppChecksums, 1, lenread, outfile ) ) > 0 ) 420 { 421 fp += lenread; 422 ppChecksums += lenread; 423 lenread = dwLength3 - fp; 424 }; 425 426 if( fp != dwLength3 ) 427 { 428 fprintf( stderr, "This doesn't look like a valid decoded " 429 "iHP firmware - reason: 'length2' mismatch\n" ); 430 rv = -6; 431 goto bail; 432 }; 433 434 fprintf( stderr, "File encoded successfully and checksum table built!\n" ); 435 436bail: 437 if (infile != NULL) 438 fclose(infile); 439 if (outfile != NULL) 440 fclose(outfile); 441 free(pChecksums); 442 return rv; 443}