static libspectrum_error rzx_read_snapshot( libspectrum_rzx *rzx, const libspectrum_byte **ptr, const libspectrum_byte *end ) { rzx_block_t *block; libspectrum_snap *snap; size_t blocklength, snaplength; libspectrum_error error = LIBSPECTRUM_ERROR_NONE; libspectrum_dword flags; const libspectrum_byte *snap_ptr; int done; snapshot_string_t *type; /* For deflated snapshot data: */ int compressed; libspectrum_byte *gzsnap = NULL; size_t uncompressed_length = 0; if( end - (*ptr) < 16 ) { libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "rzx_read_snapshot: not enough data in buffer" ); return LIBSPECTRUM_ERROR_CORRUPT; } blocklength = libspectrum_read_dword( ptr ); if( end - (*ptr) < (ptrdiff_t)blocklength - 5 ) { libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "rzx_read_snapshot: not enough data in buffer" ); return LIBSPECTRUM_ERROR_CORRUPT; } /* See if we want a compressed snap */ flags = libspectrum_read_dword( ptr ); /* We don't handle 'links' to external snapshots. I really think these are just more trouble than they're worth */ if( flags & 0x01 ) { libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, "rzx_read_snapshot: skipping external snapshot" ); (*ptr) += blocklength - 9; return LIBSPECTRUM_ERROR_NONE; } /* Do we have a compressed snapshot? */ compressed = flags & 0x02; /* How long is the (uncompressed) snap? */ (*ptr) += 4; snaplength = libspectrum_read_dword( ptr ); (*ptr) -= 8; /* If compressed, uncompress the data */ if( compressed ) { #ifdef HAVE_ZLIB_H error = libspectrum_zlib_inflate( (*ptr) + 8, blocklength - 17, &gzsnap, &uncompressed_length ); if( error != LIBSPECTRUM_ERROR_NONE ) return error; if( uncompressed_length != snaplength ) { libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "rzx_read_snapshot: compressed snapshot has wrong length" ); libspectrum_free( gzsnap ); return LIBSPECTRUM_ERROR_CORRUPT; } snap_ptr = gzsnap; #else /* #ifdef HAVE_ZLIB_H */ libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, "rzx_read_snapshot: zlib needed for decompression\n" ); return LIBSPECTRUM_ERROR_UNKNOWN; #endif /* #ifdef HAVE_ZLIB_H */ } else { /* If not compressed, check things are consistent */ if( blocklength != snaplength + 17 ) { libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "rzx_read_snapshot: inconsistent snapshot lengths" ); return LIBSPECTRUM_ERROR_CORRUPT; } snap_ptr = (*ptr) + 8; uncompressed_length = snaplength; } block_alloc( &block, LIBSPECTRUM_RZX_SNAPSHOT_BLOCK ); block->types.snap.snap = libspectrum_snap_alloc(); block->types.snap.automatic = 0; snap = block->types.snap.snap; for( done = 0, type = snapshot_strings; type->format; type++ ) { if( !strncasecmp( (char*)*ptr, type->string, 4 ) ) { error = libspectrum_snap_read( snap, snap_ptr, uncompressed_length, type->format, NULL ); done = 1; } } if( !done ) { libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, "%s:rzx_read_snapshot: unrecognised snapshot format", __FILE__ ); if( compressed ) libspectrum_free( gzsnap ); block_free( block ); return LIBSPECTRUM_ERROR_UNKNOWN; } if( error != LIBSPECTRUM_ERROR_NONE ) { if( compressed ) libspectrum_free( gzsnap ); block_free( block ); return error; } /* Free the decompressed data (if we created it) */ if( compressed ) libspectrum_free( gzsnap ); /* Skip over the data */ (*ptr) += blocklength - 9; rzx->blocks = g_slist_append( rzx->blocks, block ); return LIBSPECTRUM_ERROR_NONE; }
static libspectrum_error rzx_read_input( libspectrum_rzx *rzx, const libspectrum_byte **ptr, const libspectrum_byte *end ) { size_t blocklength; libspectrum_dword flags; int compressed; libspectrum_error error; rzx_block_t *rzx_block; input_block_t *block; /* Check we've got enough data for the block */ if( end - (*ptr) < 18 ) { libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "rzx_read_input: not enough data in buffer" ); return LIBSPECTRUM_ERROR_CORRUPT; } block_alloc( &rzx_block, LIBSPECTRUM_RZX_INPUT_BLOCK ); block = &( rzx_block->types.input ); /* Get the length and number of frames */ blocklength = libspectrum_read_dword( ptr ); block->count = libspectrum_read_dword( ptr ); /* Frame size is undefined, so just skip it */ (*ptr)++; /* Allocate memory for the frames */ block->frames = libspectrum_malloc( block->count * sizeof( *block->frames ) ); block->allocated = block->count; /* Fetch the T-state counter and the flags */ block->tstates = libspectrum_read_dword( ptr ); flags = libspectrum_read_dword( ptr ); compressed = flags & 0x02; if( compressed ) { #ifdef HAVE_ZLIB_H libspectrum_byte *data; const libspectrum_byte *data_ptr; size_t data_length = 0; /* Discount the block intro */ blocklength -= 18; /* Check that we've got enough compressed data */ if( end - (*ptr) < (ptrdiff_t)blocklength ) { libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "rzx_read_input: not enough data in buffer" ); libspectrum_free( rzx_block ); return LIBSPECTRUM_ERROR_CORRUPT; } error = libspectrum_zlib_inflate( *ptr, blocklength, &data, &data_length ); if( error != LIBSPECTRUM_ERROR_NONE ) { block_free( rzx_block ); return error; } *ptr += blocklength; data_ptr = data; error = rzx_read_frames( block, &data_ptr, data + data_length ); if( error ) { libspectrum_free( rzx_block ); libspectrum_free( data ); return error; } libspectrum_free( data ); #else /* #ifdef HAVE_ZLIB_H */ libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, "rzx_read_input: zlib needed for decompression" ); libspectrum_free( rzx_block ); return LIBSPECTRUM_ERROR_UNKNOWN; #endif /* #ifdef HAVE_ZLIB_H */ } else { /* Data not compressed */ error = rzx_read_frames( block, ptr, end ); if( error ) { libspectrum_free( rzx_block ); return error; } } rzx->blocks = g_slist_append( rzx->blocks, rzx_block ); return LIBSPECTRUM_ERROR_NONE; }
libspectrum_error libspectrum_csw_read( libspectrum_tape *tape, const libspectrum_byte *buffer, size_t length ) { libspectrum_tape_block *block = NULL; libspectrum_tape_rle_pulse_block *csw_block; int compressed; size_t signature_length = strlen( csw_signature ); if( length < signature_length + 2 ) goto csw_short; if( memcmp( csw_signature, buffer, signature_length ) ) { libspectrum_print_error( LIBSPECTRUM_ERROR_SIGNATURE, "libspectrum_csw_read: wrong signature" ); return LIBSPECTRUM_ERROR_SIGNATURE; } /* Claim memory for the block */ block = libspectrum_new( libspectrum_tape_block, 1 ); /* Set the block type */ block->type = LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE; csw_block = &block->types.rle_pulse; buffer += signature_length; length -= signature_length; switch( buffer[0] ) { case 1: if( length < 9 ) goto csw_short; csw_block->scale = buffer[2] | buffer[3] << 8; if( buffer[4] != 1 ) goto csw_bad_compress; compressed = 0; buffer += 9; length -= 9; break; case 2: if( length < 29 ) goto csw_short; csw_block->scale = buffer[2] | buffer[3] << 8 | buffer[4] << 16 | buffer[5] << 24; compressed = buffer[10] - 1; if( compressed != 0 && compressed != 1 ) goto csw_bad_compress; if( length < 29 - buffer[12] ) goto csw_short; length -= 29 - buffer[12]; buffer += 29 + buffer[12]; break; default: libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY, "libspectrum_csw_read: unknown CSW version" ); return LIBSPECTRUM_ERROR_SIGNATURE; } if (csw_block->scale) csw_block->scale = 3500000 / csw_block->scale; /* approximate CPU speed */ if( csw_block->scale < 0 || csw_block->scale >= 0x80000 ) { libspectrum_print_error (LIBSPECTRUM_ERROR_MEMORY, "libspectrum_csw_read: bad sample rate" ); return LIBSPECTRUM_ERROR_UNKNOWN; } if( !length ) goto csw_empty; if( compressed ) { /* Compressed data... */ #ifdef HAVE_ZLIB_H libspectrum_error error; csw_block->data = NULL; csw_block->length = 0; error = libspectrum_zlib_inflate( buffer, length, &csw_block->data, &csw_block->length ); if( error != LIBSPECTRUM_ERROR_NONE ) return error; #else libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, "zlib not available to decompress gzipped file" ); return LIBSPECTRUM_ERROR_UNKNOWN; #endif } else { /* Claim memory for the data (it's one big lump) */ csw_block->length = length; csw_block->data = libspectrum_new( libspectrum_byte, length ); /* Copy the data across */ memcpy( csw_block->data, buffer, length ); } libspectrum_tape_append_block( tape, block ); /* Successful completion */ return LIBSPECTRUM_ERROR_NONE; /* Error returns */ csw_bad_compress: libspectrum_free( block ); libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY, "libspectrum_csw_read: unknown compression type" ); return LIBSPECTRUM_ERROR_CORRUPT; csw_short: libspectrum_free( block ); libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "libspectrum_csw_read: not enough data in buffer" ); return LIBSPECTRUM_ERROR_CORRUPT; csw_empty: libspectrum_free( block ); /* Successful completion */ return LIBSPECTRUM_ERROR_NONE; }