filename | src/dreamcast.c |
changeset | 477:9a373f2ff009 |
prev | 466:a6935f46ed78 |
next | 480:d28c2992f5ee |
author | nkeynes |
date | Wed Oct 31 09:10:23 2007 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Add save/restore of render buffers in save states Gzip memory blocks in save states Move front-buffer management back to pvr2 Add screenshot preview when loading save states Various minor fixes and cleanups |
file | annotate | diff | log | raw |
1.1 --- a/src/dreamcast.c Sat Oct 27 05:47:55 2007 +00001.2 +++ b/src/dreamcast.c Wed Oct 31 09:10:23 2007 +00001.3 @@ -1,5 +1,5 @@1.4 /**1.5 - * $Id: dreamcast.c,v 1.26 2007-10-27 05:47:55 nkeynes Exp $1.6 + * $Id: dreamcast.c,v 1.27 2007-10-31 09:10:23 nkeynes Exp $1.7 * Central switchboard for the system. This pulls all the individual modules1.8 * together into some kind of coherent structure. This is also where you'd1.9 * add Naomi support, if I ever get a board to play with...1.10 @@ -220,62 +220,137 @@1.11 uint32_t module_count;1.12 };1.14 +struct chunk_header {1.15 + char marker[4]; /* Always BLCK */1.16 + char name[8]; /* Block (module) name */1.17 + uint32_t block_length;1.18 +};1.19 +1.20 +/**1.21 + * Check the save state header to ensure that it is a valid, supported1.22 + * file.1.23 + * @return the number of blocks following, or 0 if the file is invalid.1.24 + */1.25 +int dreamcast_read_save_state_header( FILE *f )1.26 +{1.27 + struct save_state_header header;1.28 + if( fread( &header, sizeof(header), 1, f ) != 1 ) {1.29 + return 0;1.30 + }1.31 + if( strncmp( header.magic, DREAMCAST_SAVE_MAGIC, 16 ) != 0 ) {1.32 + ERROR( "Not a %s save state file", APP_NAME );1.33 + return 0;1.34 + }1.35 + if( header.version != DREAMCAST_SAVE_VERSION ) {1.36 + ERROR( "%s save state version not supported", APP_NAME );1.37 + return 0;1.38 + }1.39 + if( header.module_count > MAX_MODULES ) {1.40 + ERROR( "%s save state is corrupted (bad module count)", APP_NAME );1.41 + return 0;1.42 + }1.43 + return header.module_count;1.44 +}1.45 +1.46 +int dreamcast_write_chunk_header( const gchar *name, uint32_t length, FILE *f )1.47 +{1.48 + struct chunk_header head;1.49 +1.50 + memcpy( head.marker, "BLCK", 4 );1.51 + memset( head.name, 0, 8 );1.52 + memcpy( head.name, name, strlen(name) );1.53 + head.block_length = length;1.54 + return fwrite( &head, sizeof(head), 1, f );1.55 +}1.56 +1.57 +1.58 +frame_buffer_t dreamcast_load_preview( const gchar *filename )1.59 +{1.60 + int i;1.61 + FILE *f = fopen( filename, "r" );1.62 + if( f == NULL ) return NULL;1.63 +1.64 + int module_count = dreamcast_read_save_state_header(f);1.65 + if( module_count <= 0 ) {1.66 + fclose(f);1.67 + return NULL;1.68 + }1.69 + for( i=0; i<module_count; i++ ) {1.70 + struct chunk_header head;1.71 + if( fread( &head, sizeof(head), 1, f ) != 1 ) {1.72 + fclose(f);1.73 + return NULL;1.74 + }1.75 + if( memcmp("BLCK", head.marker, 4) != 0 ) {1.76 + fclose(f);1.77 + return NULL;1.78 + }1.79 +1.80 + if( strcmp("PVR2", head.name) == 0 ) {1.81 + uint32_t buf_count;1.82 + int has_front;1.83 + fread( &buf_count, sizeof(buf_count), 1, f );1.84 + fread( &has_front, sizeof(has_front), 1, f );1.85 + if( buf_count != 0 && has_front ) {1.86 + frame_buffer_t result = read_png_from_stream(f);1.87 + fclose(f);1.88 + return result;1.89 + }1.90 + break;1.91 + } else {1.92 + fseek( f, head.block_length, SEEK_CUR );1.93 + }1.94 + }1.95 + return NULL;1.96 +}1.97 +1.98 int dreamcast_load_state( const gchar *filename )1.99 {1.100 int i,j;1.101 uint32_t len;1.102 + int module_count;1.103 int have_read[MAX_MODULES];1.104 - char tmp[64];1.105 - struct save_state_header header;1.106 - FILE *f;1.108 - f = fopen( filename, "r" );1.109 + FILE *f = fopen( filename, "r" );1.110 if( f == NULL ) return errno;1.112 - fread( &header, sizeof(header), 1, f );1.113 - if( strncmp( header.magic, DREAMCAST_SAVE_MAGIC, 16 ) != 0 ) {1.114 - ERROR( "Not a %s save state file", APP_NAME );1.115 + module_count = dreamcast_read_save_state_header(f);1.116 + if( module_count <= 0 ) {1.117 + fclose(f);1.118 return 1;1.119 }1.120 - if( header.version != DREAMCAST_SAVE_VERSION ) {1.121 - ERROR( "%s save state version not supported", APP_NAME );1.122 - return 1;1.123 - }1.124 - if( header.module_count > MAX_MODULES ) {1.125 - ERROR( "%s save state is corrupted (bad module count)", APP_NAME );1.126 - return 1;1.127 - }1.128 +1.129 for( i=0; i<MAX_MODULES; i++ ) {1.130 have_read[i] = 0;1.131 }1.133 - for( i=0; i<header.module_count; i++ ) {1.134 - fread(tmp, 4, 1, f );1.135 - if( strncmp(tmp, "BLCK", 4) != 0 ) {1.136 + for( i=0; i<module_count; i++ ) {1.137 + struct chunk_header chunk;1.138 + fread( &chunk, sizeof(chunk), 1, f );1.139 + if( strncmp(chunk.marker, "BLCK", 4) != 0 ) {1.140 ERROR( "%s save state is corrupted (missing block header %d)", APP_NAME, i );1.141 - return 2;1.142 - }1.143 - len = fread_string(tmp, sizeof(tmp), f );1.144 - if( len > 64 || len < 1 ) {1.145 - ERROR( "%s save state is corrupted (bad string)", APP_NAME );1.146 + fclose(f);1.147 return 2;1.148 }1.150 /* Find the matching module by name */1.151 for( j=0; j<num_modules; j++ ) {1.152 - if( strcmp(modules[j]->name,tmp) == 0 ) {1.153 + if( strcmp(modules[j]->name,chunk.name) == 0 ) {1.154 have_read[j] = 1;1.155 if( modules[j]->load == NULL ) {1.156 ERROR( "%s save state is corrupted (no loader for %s)", APP_NAME, modules[j]->name );1.157 + fclose(f);1.158 return 2;1.159 } else if( modules[j]->load(f) != 0 ) {1.160 ERROR( "%s save state is corrupted (%s failed)", APP_NAME, modules[j]->name );1.161 + fclose(f);1.162 return 2;1.163 }1.164 break;1.165 }1.166 }1.167 if( j == num_modules ) {1.168 + fclose(f);1.169 ERROR( "%s save state contains unrecognized section", APP_NAME );1.170 return 2;1.171 }1.172 @@ -315,9 +390,15 @@1.173 fwrite( &header, sizeof(header), 1, f );1.174 for( i=0; i<num_modules; i++ ) {1.175 if( modules[i]->save != NULL ) {1.176 - fwrite( "BLCK", 4, 1, f );1.177 - fwrite_string( modules[i]->name, f );1.178 + uint32_t blocklen, posn1, posn2;1.179 + dreamcast_write_chunk_header( modules[i]->name, 0, f );1.180 + posn1 = ftell(f);1.181 modules[i]->save(f);1.182 + posn2 = ftell(f);1.183 + blocklen = posn2 - posn1;1.184 + fseek( f, posn1-4, SEEK_SET );1.185 + fwrite( &blocklen, sizeof(blocklen), 1, f );1.186 + fseek( f, posn2, SEEK_SET );1.187 }1.188 }1.189 fclose( f );
.