Mercurial > repos > blastem
view system.c @ 2488:bfd09d3367ba
Fix crash when enabling VGM recording while running Pico or Copera software
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 15 Apr 2024 23:07:18 -0700 |
parents | cb62730d5c99 |
children | 8cf7cadc17ee |
line wrap: on
line source
#include <string.h> #include <stdlib.h> #include "system.h" #include "genesis.h" #include "gen_player.h" #include "sms.h" #include "mediaplayer.h" #include "coleco.h" #include "paths.h" #include "util.h" uint8_t safe_cmp(char *str, long offset, uint8_t *buffer, long filesize) { long len = strlen(str); return filesize >= offset+len && !memcmp(str, buffer + offset, len); } system_type detect_system_type(system_media *media) { static char *pico_names[] = { "SEGA PICO", "SEGATOYS PICO", "SEGA TOYS PICO", "SAMSUNG PICO", "SEGA IAC", "IMA IKUNOUJYUKU", "IMA IKUNOJYUKU" }; static const int num_pico = sizeof(pico_names)/sizeof(*pico_names); for (int i = 0; i < num_pico; i++) { if (safe_cmp(pico_names[i], 0x100, media->buffer, media->size)) { return SYSTEM_PICO; } } if (safe_cmp("SEGA", 0x100, media->buffer, media->size)) { //TODO: support other bootable identifiers if (safe_cmp("SEGADISCSYSTEM", 0, media->buffer, media->size)) { return SYSTEM_SEGACD; } //TODO: Differentiate between vanilla Genesis and 32X games return SYSTEM_GENESIS; } if (safe_cmp("TMR SEGA", 0x1FF0, media->buffer, media->size) || safe_cmp("TMR SEGA", 0x3FF0, media->buffer, media->size) || safe_cmp("TMR SEGA", 0x7FF0, media->buffer, media->size) ) { return SYSTEM_SMS; } if (media->size > 400) { uint8_t *buffer = media->buffer; if (!memcmp(buffer + 4, "\x00\x00\x04\x00", 4) && (buffer[0x80] == 0 || buffer[0x80] == 0xFF)) { int i = 0x81; for(; i < 0x400; i++) { if (buffer[i] != buffer[0x80]) { break; } } if (i == 0x400) { return SYSTEM_COPERA; } } } if (safe_cmp("BLSTEL\x02", 0, media->buffer, media->size)) { uint8_t *buffer = media->buffer; if (media->size > 9 && buffer[7] == 0) { return buffer[8] + 1; } } if ( safe_cmp("Vgm ", 0, media->buffer, media->size) || safe_cmp("RIFF", 0, media->buffer, media->size) || safe_cmp("fLaC", 0, media->buffer, media->size)) { return SYSTEM_MEDIA_PLAYER; } if ( (safe_cmp("\xAA\x55", 0, media->buffer, media->size) || safe_cmp("\x55\xAA", 0, media->buffer, media->size)) && media->size > 0xB) { uint8_t *buffer = media->buffer; if (((buffer[0xB] << 8) | buffer[0xA]) > 0x8000) { return SYSTEM_COLECOVISION; } } //TODO: Detect Jaguar ROMs here //Header based detection failed, examine filename for clues if (media->extension) { if (!strcmp("md", media->extension) || !strcmp("gen", media->extension)) { return SYSTEM_GENESIS; } if (!strcmp("sms", media->extension) || !strcmp("sg", media->extension) || !strcmp("gg", media->extension)) { return SYSTEM_SMS; } if (!strcmp("j64", media->extension)) { return SYSTEM_JAGUAR; } if (!strcmp("col", media->extension)) { return SYSTEM_COLECOVISION; } } //More certain checks failed, look for a valid 68K reset vector if (media->size >= 8) { char *rom = media->buffer; uint32_t reset = rom[5] << 16 | rom[6] << 8 | rom[7]; if (!(reset & 1) && reset < media->size) { //we have a valid looking reset vector, assume it's a Genesis ROM return SYSTEM_GENESIS; } } return SYSTEM_UNKNOWN; } system_header *alloc_config_system(system_type stype, system_media *media, uint32_t opts, uint8_t force_region) { void *lock_on = NULL; uint32_t lock_on_size = 0; if (media->chain) { lock_on = media->chain->buffer; lock_on_size = media->chain->size; } switch (stype) { case SYSTEM_GENESIS: return &(alloc_config_genesis(media->buffer, media->size, lock_on, lock_on_size, opts, force_region))->header; case SYSTEM_GENESIS_PLAYER: return &(alloc_config_gen_player(media->buffer, media->size))->header; case SYSTEM_SEGACD: return &(alloc_config_genesis_cdboot(media, opts, force_region))->header; #ifndef NO_Z80 case SYSTEM_SMS: return &(alloc_configure_sms(media, opts, force_region))->header; case SYSTEM_COLECOVISION: return &(alloc_configure_coleco(media))->header; #endif case SYSTEM_MEDIA_PLAYER: return &(alloc_media_player(media, opts))->header; case SYSTEM_PICO: case SYSTEM_COPERA: return &(alloc_config_pico(media->buffer, media->size, lock_on, lock_on_size, opts, force_region, stype))->header; default: return NULL; } } system_header *alloc_config_player(system_type stype, event_reader *reader) { switch(stype) { case SYSTEM_GENESIS: return &(alloc_config_gen_player_reader(reader))->header; } return NULL; } void system_request_exit(system_header *system, uint8_t force_release) { system->force_release = force_release; system->request_exit(system); } void* load_media_subfile(const system_media *media, char *path, uint32_t *sizeout) { #ifdef IS_LIB //TODO: Figure out how to handle Pico artwork and similar cases in libretro builds return NULL; #else char *to_free = NULL; void *buffer = NULL; uint32_t size = 0; if (media->zip) { uint32_t i; for (i = 0; i < media->zip->num_entries; i++) { if (!strcasecmp(media->zip->entries[i].name, path)) { break; } } if (i < media->zip->num_entries) { size_t zsize = media->zip->entries[i].size + 1; buffer = zip_read(media->zip, i, &zsize); size = zsize; if (buffer) { ((uint8_t *)buffer)[size] = 0; } goto end; } } if (!is_absolute_path(path)) { to_free = path = path_append(media->dir, path); } FILE *f = fopen(path, "rb"); if (!f) { goto end; } size = file_size(f); buffer = calloc(1, size + 1); size = fread(buffer, 1, size, f); fclose(f); end: if (sizeout) { *sizeout = size; } free(to_free); return buffer; #endif }