A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 464 lines 13 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * 9 * Copyright (C) 2009 by Karl Kurbjun 10 * based on work by Shirour: 11 * http://www.mrobe.org/forum/viewtopic.php?f=6&t=2176 12 * $Id$ 13 * 14 * All files in this archive are subject to the GNU General Public License. 15 * See the file COPYING in the source tree root for full license agreement. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include <stdio.h> 23#include <string.h> 24#include <stdlib.h> 25#include <fcntl.h> 26#include <errno.h> 27#include <unistd.h> 28#include <inttypes.h> 29#include <sys/stat.h> 30#include "mr500.h" 31#ifdef __APPLE__ 32#include <libkern/OSByteOrder.h> 33#define htole32(x) OSSwapHostToLittleInt32(x) 34#define htole16(x) OSSwapHostToLittleInt16(x) 35#define le32toh(x) OSSwapLittleToHostInt32(x) 36#define le16toh(x) OSSwapLittleToHostInt16(x) 37#endif 38 39/* Notes about firmware: 40 * These notes are based on the work and observations of Shirour on the M:Robe 41 * forums. 42 * 43 * The firmware for the M:Robe has basic encryption on it. The data is XORed 44 * and scrambled. The mr500_save_data function provides an implemenation of the 45 * encryption/decryption. 46 * 47 * When a firmware update is done the "{#4F494D4346575550#}" folder is stored 48 * in the system folder on the player. The "{#4F494D4346575550#}" should only 49 * contain the encrypted N5002-BD.BIN file. At the end of a firmware update 50 * the "{#4F494D4346575550#}" folder and it's contents are removed from the 51 * player. 52 * 53 * An interesting note is that the name "{#4F494D4346575550#}" is actually the 54 * Hex representation of the magic text found at the beginning of the firmware 55 * image "OIMCFWUP". 56 */ 57 58/* These two arrays are used for descrambling or scrambling the data */ 59int decrypt_array[16]={2, 0, 3, 1, 5, 7, 4, 6, 11, 10, 9, 8, 14, 12, 13, 15}; 60int encrypt_array[16]; 61 62/* mr500_patch_file: This function modifies the specified file with the patches 63 * struct. 64 * 65 * Parameters: 66 * filename: text filename 67 * patches: pointer to structure array of patches 68 * num_patches: number of patches to apply (applied in reverse order) 69 * 70 * Returns: 71 * Returns 0 if there was no error, -1 if there was an error 72 */ 73int mr500_patch_file(char *filename, struct patch_single *patches, 74 int num_patches) { 75 int fdo; 76 int ret=0; 77 uint32_t endian_int; 78 79 /* Open the file write only. */ 80 fdo = open(filename, O_WRONLY); 81 82 if(fdo<0) { 83 ret=-1; 84 } 85 86 while(num_patches--) { 87 /* seek to patch offset */ 88 if(lseek(fdo, patches[num_patches].offset, SEEK_SET) 89 != patches[num_patches].offset) { 90 ret=-1; 91 break; 92 } 93 94 /* Make sure patch is written in little endian format */ 95 endian_int = htole32(patches[num_patches].value); 96 97 /* Write the patch value to the file */ 98 if(write(fdo, (void *) &endian_int, sizeof(endian_int)) < 0) { 99 ret = -1; 100 break; 101 } 102 } 103 104 /* Close the file and check for errors */ 105 if(close (fdo) < 0) { 106 ret = -1; 107 } 108 109 return ret; 110} 111 112/* mr500_save_header: This function saves the Olympus header to the firmware 113 * image. The values stored in the header are explained above. Note that this 114 * will truncate a file. The header is stored in little endian format. 115 * 116 * Parameters: 117 * filename: text filename 118 * header: pointer to header structure to be saved 119 * 120 * Returns: 121 * Returns 0 if there was no error, -1 if there was an error 122 */ 123int mr500_save_header(char *filename, struct olympus_header *header) { 124 int fdo; 125 int ret=0; 126 127 /* Temporary header used for storing the header in little endian. */ 128 struct olympus_header save; 129 130 /* Open the file write only and truncate it. If it doesn't exist create. */ 131 fdo = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 132 133 if(fdo<0) { 134 ret=-1; 135 } 136 137 /* Header is stored at offset 0 (Not really needed) */ 138 if(lseek(fdo, 0, SEEK_SET) != 0) { 139 ret=-1; 140 } 141 142 /* Convert header to Little Endian */ 143 memcpy(&save.magic_name, &header->magic_name, 8*sizeof(int8_t)); 144 save.unknown = htole32(header->unknown); 145 save.header_length = htole16(header->header_length); 146 save.flags = htole16(header->flags); 147 save.unknown_zeros = htole32(header->unknown_zeros); 148 save.image_length = htole32(header->image_length); 149 150 /* Write the header to the file */ 151 if(write(fdo, (void *) &save, sizeof(save)) < 0) { 152 ret = -1; 153 } 154 155 /* Close the file and check for errors */ 156 if(close (fdo) < 0) { 157 ret = -1; 158 } 159 160 return ret; 161} 162 163/* mr500_read_header: This function reads the Olympus header and converts it to 164 * the host endian format. The values stored in the header are explained above. 165 * The header is stored in little endian format. 166 * 167 * Parameters: 168 * filename: text filename 169 * header: pointer to header structure to store header read from file 170 * 171 * Returns: 172 * Returns 0 if there was no error, -1 if there was an error 173 */ 174int mr500_read_header(char *filename, struct olympus_header *header) { 175 int fdi; 176 int ret = 0; 177 178 /* Open the file read only */ 179 fdi = open(filename, O_RDONLY); 180 181 if(fdi<0) { 182 ret=-1; 183 } 184 185 /* Header is stored at offset 0 (Not really needed) */ 186 if(lseek(fdi, 0, SEEK_SET) != 0) { 187 ret=-1; 188 } 189 190 /* Read in the header */ 191 if(read(fdi, (void *) header, sizeof(*header)) < 0) { 192 ret = -1; 193 } 194 195 /* Convert header to system endian */ 196 header->unknown = le32toh(header->unknown); 197 header->header_length = le16toh(header->header_length); 198 header->flags = le16toh(header->flags); 199 header->unknown_zeros = le32toh(header->unknown_zeros); 200 header->image_length = le32toh(header->image_length); 201 202 /* Close the file and check for errors */ 203 if(close (fdi) < 0) { 204 ret = -1; 205 } 206 207 return ret; 208} 209 210/* mr500_save_crc: This function saves the 'CRC' of the Olympus firmware image. 211 * Note that the 'CRC' must be calculated on the decrytped image. It is stored 212 * in little endian. 213 * 214 * Parameters: 215 * filename: text filename 216 * offset: Offset to store the 'CRC' (header size + data size) 217 * crc_value: pointer to crc value to save 218 * 219 * Returns: 220 * Returns 0 if there was no error, -1 if there was an error 221 */ 222int mr500_save_crc(char *filename, off_t offset, uint32_t *crc_value) { 223 int fdo; 224 int ret = 0; 225 uint32_t save_crc; 226 227 /* Open the file write only */ 228 fdo = open(filename, O_WRONLY); 229 230 if(fdo<0) { 231 ret=-1; 232 } 233 234 /* Seek to offset and check for errors */ 235 if(lseek(fdo, offset, SEEK_SET) != offset) { 236 ret=-1; 237 } 238 239 /* Convert 'CRC' to little endian from system native endian */ 240 save_crc = htole32(*crc_value); 241 242 /* Write the 'CRC' and check for errors */ 243 if(write(fdo, (void *) &save_crc, sizeof(unsigned int)) < 0) { 244 ret = -1; 245 } 246 247 /* Close the file and check for errors */ 248 if(close (fdo) < 0) { 249 ret = -1; 250 } 251 252 return ret; 253} 254 255/* mr500_read_crc: This function reads the 'CRC' of the Olympus firmware image. 256 * Note that the 'CRC' is calculated on the decrytped values. It is stored 257 * in little endian. 258 * 259 * Parameters: 260 * filename: text filename 261 * offset: Offset to read the 'CRC' (header size + data size) 262 * crc_value: pointer to crc value to save 263 * 264 * Returns: 265 * Returns 0 if there was no error, -1 if there was an error 266 */ 267int mr500_read_crc(char *filename, off_t offset, uint32_t *crc_value) { 268 int fdi; 269 int ret = 0; 270 271 /* Open the file read only */ 272 fdi = open(filename, O_RDONLY); 273 274 if(fdi<0) { 275 ret = -1; 276 } 277 278 /* Seek to offset and check for errors */ 279 if(lseek(fdi, offset, SEEK_SET) != offset) { 280 ret=-1; 281 } 282 283 /* Read in the 'CRC' */ 284 if(read(fdi, (void *) crc_value, sizeof(uint32_t)) < 0) { 285 ret = -1; 286 } 287 288 /* Convert the 'CRC' from little endian to system native format */ 289 *crc_value = le32toh(*crc_value); 290 291 /* Close the file and check for errors */ 292 if(close (fdi) < 0) { 293 ret = -1; 294 } 295 296 return ret; 297} 298 299/* mr500_calculate_crc: This function calculates the 'CRC' of the Olympus 300 * firmware image. Note that the 'CRC' must be calculated on decrytped values. 301 * It is stored in little endian. 302 * 303 * Parameters: 304 * filename: text filename 305 * offset: Offset to the start of the data (header size) 306 * length: Length of data to calculate 307 * crc_value: pointer to crc value to save 308 * 309 * Returns: 310 * Returns 0 if there was no error, -1 if there was an error 311 */ 312int mr500_calculate_crc( char *filename, off_t offset, unsigned int length, 313 uint32_t *crc_value){ 314 uint32_t temp; 315 int fdi; 316 int ret = 0; 317 318 /* Open the file read only */ 319 fdi = open(filename, O_RDONLY); 320 321 if(fdi<0) { 322 ret = -1; 323 } 324 325 /* Seek to offset and check for errors */ 326 if(lseek(fdi, offset, SEEK_SET) != offset) { 327 ret=-1; 328 } 329 330 /* Initialize the crc_value to make sure this starts at 0 */ 331 *crc_value = 0; 332 /* Run this loop till the entire sum is created */ 333 do { 334 /* Read an integer at a time */ 335 if(read(fdi, &temp, sizeof(uint32_t)) < 0) { 336 ret = -1; 337 break; 338 } 339 340 /* Keep summing the values */ 341 *crc_value+=temp; 342 } while (length-=4); 343 344 /* Close the file and check for errors */ 345 if(close (fdi) < 0) { 346 ret = -1; 347 } 348 349 return ret; 350} 351 352/* mr500_save_data: This function encypts or decrypts the Olympus firmware 353 * image based on the dictionary passed to it. 354 * 355 * Parameters: 356 * source_filename: text filename where data is read from 357 * dest_filename: text filename where data is written to 358 * offset: Offset to the start of the data (header size) 359 * length: Length of data to modify 360 * dictionary: pointer to dictionary used for scrambling 361 * 362 * Returns: 363 * Returns 0 if there was no error, -1 if there was an error 364 */ 365int mr500_save_data( 366 char *source_filename, char *dest_filename, off_t offset, 367 unsigned int length, int* dictionary) { 368 int fdi, fdo; 369 int ret = 0; 370 int i; 371 372 /* read_count stores the number of bytes actually read */ 373 int read_count; 374 375 /* read_request stores the number of bytes to be requested */ 376 int read_request; 377 378 /* These two buffers are used for reading data and scrambling or 379 * descrambling 380 */ 381 int8_t buffer_original[16]; 382 int8_t buffer_modified[16]; 383 384 /* Open input read only, output write only */ 385 fdi = open(source_filename, O_RDONLY); 386 fdo = open(dest_filename, O_WRONLY); 387 388 /* If there was an error loading the files set ret appropriately */ 389 if(fdi<0 || fdo < 0) { 390 ret = -1; 391 } 392 393 /* Input file: Seek to offset and check for errors */ 394 if(lseek(fdi, offset, SEEK_SET) != offset) { 395 ret=-1; 396 } 397 398 /* Output file: Seek to offset and check for errors */ 399 if(lseek(fdo, offset, SEEK_SET) != offset) { 400 ret=-1; 401 } 402 403 /* Run this loop till size is 0 */ 404 do { 405 /* Choose the amount of data to read - normally in 16 byte chunks, but 406 * when the end of the file is near may be less. 407 */ 408 if( length > sizeof(buffer_original)){ 409 read_request = sizeof(buffer_original); 410 } else { 411 read_request = length; 412 } 413 414 /* Read in the data */ 415 read_count = read(fdi, (void *) &buffer_original, read_request); 416 417 /* If there was an error set the flag and break */ 418 if(read_count < 0) { 419 ret = -1; 420 break; 421 } 422 423 for(i=0; i<read_count; i++) { 424 /* XOR all of the bits to de/encrypt them */ 425 buffer_original[i] ^= 0xFF; 426 /* Handle byte scrambling */ 427 buffer_modified[dictionary[i]] = buffer_original[i]; 428 } 429 430 /* write the data: If there was an error set the flag and break */ 431 if(write(fdo, (void *) &buffer_modified, read_count) < 0) { 432 ret = -1; 433 break; 434 } 435 } while (length -= read_count); 436 437 /* Close the files and check for errors */ 438 if(close (fdi) < 0) { 439 ret = -1; 440 } 441 if(close (fdo) < 0) { 442 ret = -1; 443 } 444 445 return ret; 446} 447 448/* mr500_init: This function initializes the encryption array 449 * 450 * Parameters: 451 * None 452 * 453 * Returns: 454 * Returns 0 455 */ 456int mr500_init(void) { 457 int i; 458 /* Initialize the encryption array */ 459 for(i=0; i<16; i++) { 460 encrypt_array[decrypt_array[i]]=i; 461 } 462 return 0; 463} 464