libspectrum_error libspectrum_tape_block_read_symbol_table( libspectrum_tape_generalised_data_symbol_table *table, const libspectrum_byte **ptr, size_t length ) { if( table->symbols_in_block ) { libspectrum_tape_generalised_data_symbol *symbol; size_t i, j; /* Sanity check */ if( length < ( 2 * table->max_pulses + 1 ) * table->symbols_in_table ) { libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "%s: not enough data in buffer", __func__ ); return LIBSPECTRUM_ERROR_CORRUPT; } table->symbols = libspectrum_malloc( table->symbols_in_table * sizeof( *table->symbols ) ); for( i = 0, symbol = table->symbols; i < table->symbols_in_table; i++, symbol++ ) { symbol->edge_type = **ptr; (*ptr)++; symbol->lengths = libspectrum_malloc( table->max_pulses * sizeof( *symbol->lengths ) ); for( j = 0; j < table->max_pulses; j++ ) { symbol->lengths[ j ] = (*ptr)[0] + (*ptr)[1] * 0x100; (*ptr) += 2; } } } return LIBSPECTRUM_ERROR_NONE; }
`proper' glib */ #include <string.h> #include "internals.h" GArray* g_array_new( gboolean zero_terminated, gboolean clear, guint element_size ) { GArray *array; /* Don't support these options */ if( zero_terminated || clear ) { fprintf( stderr, "%s: zero_terminated and clear options not supported\n", __func__ ); abort(); } array = libspectrum_malloc( sizeof( *array ) ); array->element_size = element_size; array->data = NULL; array->len = array->allocated = 0; return array; }
void* libspectrum_malloc_n( size_t nmemb, size_t size ) { if( nmemb > SIZE_MAX / size ) abort(); return libspectrum_malloc( nmemb * size ); }
libspectrum_tape_block* libspectrum_tape_block_alloc( libspectrum_tape_type type ) { libspectrum_tape_block *block = libspectrum_malloc( sizeof( *block ) ); libspectrum_tape_block_set_type( block, type ); return block; }
static GHashNode* g_hash_node_new (gpointer key, gpointer value) { GHashNode *hash_node; guint i; if (!node_free_list) { node_free_list = libspectrum_malloc (1024 * sizeof (GHashNode)); node_allocated_list = node_free_list; for(i = 0; i < 1023; i++ ) node_free_list[i].next = &node_free_list[i+1]; node_free_list[1023].next = NULL; } hash_node = node_free_list; node_free_list = node_free_list->next; hash_node->key = key; hash_node->value = value; hash_node->next = NULL; return hash_node; }
libspectrum_rzx* libspectrum_rzx_alloc( void ) { libspectrum_rzx *rzx = libspectrum_malloc( sizeof( *rzx ) ); rzx->blocks = NULL; rzx->current_block = NULL; rzx->current_input = NULL; rzx->signed_start = NULL; return rzx; }
static libspectrum_error rzx_read_frames( input_block_t *block, const libspectrum_byte **ptr, const libspectrum_byte *end ) { size_t i, j; /* And read in the frames */ for( i=0; i < block->count; i++ ) { /* Check the two length bytes exist */ if( end - (*ptr) < 4 ) { libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "rzx_read_frames: not enough data in buffer" ); for( j=0; j<i; j++ ) { if( !block->frames[i].repeat_last ) libspectrum_free( block->frames[j].in_bytes ); } return LIBSPECTRUM_ERROR_CORRUPT; } block->frames[i].instructions = libspectrum_read_word( ptr ); block->frames[i].count = libspectrum_read_word( ptr ); if( block->frames[i].count == libspectrum_rzx_repeat_frame ) { block->frames[i].repeat_last = 1; continue; } block->frames[i].repeat_last = 0; if( end - (*ptr) < (ptrdiff_t)block->frames[i].count ) { libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "rzx_read_frames: not enough data in buffer" ); for( j=0; j<i; j++ ) { if( !block->frames[i].repeat_last ) libspectrum_free( block->frames[j].in_bytes ); } return LIBSPECTRUM_ERROR_CORRUPT; } if( block->frames[i].count ) { block->frames[i].in_bytes = libspectrum_malloc( block->frames[i].count * sizeof( libspectrum_byte ) ); memcpy( block->frames[i].in_bytes, *ptr, block->frames[i].count ); } else { block->frames[i].in_bytes = NULL; } (*ptr) += block->frames[i].count; } return LIBSPECTRUM_ERROR_NONE; }
GHashTable* g_hash_table_new_full (GHashFunc hash_func, GCompareFunc key_equal_func, GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func) { GHashTable *hash_table; guint i; hash_table = libspectrum_malloc (sizeof (GHashTable)); hash_table->nnodes = 0; hash_table->hash_func = hash_func? hash_func : g_direct_hash; hash_table->key_equal_func = key_equal_func; hash_table->key_destroy_func = key_destroy_func; hash_table->value_destroy_func = value_destroy_func; hash_table->nodes = libspectrum_malloc (HASH_TABLE_SIZE * sizeof (GHashNode*)); for (i = 0; i < HASH_TABLE_SIZE; i++) hash_table->nodes[i] = NULL; return hash_table; }
static libspectrum_error serialise_mpis( libspectrum_byte **signature, size_t *signature_length, gcry_mpi_t r, gcry_mpi_t s ) { gcry_error_t error; size_t length, length_s; unsigned char *ptr; error = gcry_mpi_print( GCRYMPI_FMT_PGP, NULL, 0, &length, r ); if( error ) { libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "serialise_mpis: length of r: %s", gcry_strerror( error ) ); return LIBSPECTRUM_ERROR_LOGIC; } error = gcry_mpi_print( GCRYMPI_FMT_PGP, NULL, 0, &length_s, s ); if( error ) { libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "serialise_mpis: length of s: %s", gcry_strerror( error ) ); return LIBSPECTRUM_ERROR_LOGIC; } length += length_s; *signature_length = length; *signature = libspectrum_malloc( length ); error = gcry_mpi_print( GCRYMPI_FMT_PGP, *signature, length, &length, r ); if( error ) { libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "serialise_mpis: printing r: %s", gcry_strerror( error ) ); libspectrum_free( *signature ); return LIBSPECTRUM_ERROR_LOGIC; } ptr = *signature + length; length = *signature_length - length; error = gcry_mpi_print( GCRYMPI_FMT_PGP, ptr, length, NULL, s ); if( error ) { libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "serialise_mpis: printing s: %s", gcry_strerror( error ) ); libspectrum_free( *signature ); return LIBSPECTRUM_ERROR_LOGIC; } return LIBSPECTRUM_ERROR_NONE; }
static libspectrum_error get_hash( gcry_sexp_t *hash, const libspectrum_byte *data, size_t data_length ) { gcry_error_t error; unsigned char *digest; size_t digest_length; gcry_mpi_t hash_mpi; digest_length = gcry_md_get_algo_dlen( HASH_ALGORITHM ); digest = libspectrum_malloc( digest_length ); gcry_md_hash_buffer( HASH_ALGORITHM, digest, data, data_length ); error = gcry_mpi_scan( &hash_mpi, GCRYMPI_FMT_USG, digest, digest_length, NULL ); if( error ) { libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "get_hash: error creating hash MPI: %s", gcry_strerror( error ) ); libspectrum_free( digest ); return LIBSPECTRUM_ERROR_LOGIC; } libspectrum_free( digest ); error = gcry_sexp_build( hash, NULL, hash_format, hash_mpi ); if( error ) { libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "get_hash: error creating hash sexp: %s", gcry_strerror( error ) ); gcry_mpi_release( hash_mpi ); return LIBSPECTRUM_ERROR_LOGIC; } gcry_mpi_release( hash_mpi ); return LIBSPECTRUM_ERROR_NONE; }
int utils_read_fd( compat_fd fd, const char *filename, utils_file *file ) { file->length = compat_file_get_length( fd ); if( file->length == -1 ) return 1; file->buffer = libspectrum_malloc( file->length ); if( compat_file_read( fd, file ) ) { libspectrum_free( file->buffer ); compat_file_close( fd ); return 1; } if( compat_file_close( fd ) ) { ui_error( UI_ERROR_ERROR, "Couldn't close '%s': %s", filename, strerror( errno ) ); libspectrum_free( file->buffer ); return 1; } return 0; }
libspectrum_error libspectrum_rzx_store_frame( libspectrum_rzx *rzx, size_t instructions, size_t count, libspectrum_byte *in_bytes ) { input_block_t *input; libspectrum_rzx_frame_t *frame; input = rzx->current_input; /* Check we've got an IRB to record to */ if( !input ) { libspectrum_print_error( LIBSPECTRUM_ERROR_INVALID, "libspectrum_rzx_store_frame called with no active input block" ); return LIBSPECTRUM_ERROR_INVALID; } /* Get more space if we need it; allocate twice as much as we currently have, with a minimum of 50 */ if( input->count == input->allocated ) { libspectrum_rzx_frame_t *ptr; size_t new_allocated; new_allocated = input->allocated >= 25 ? 2 * input->allocated : 50; ptr = realloc( input->frames, new_allocated * sizeof( *ptr ) ); if( !ptr ) return LIBSPECTRUM_ERROR_MEMORY; input->frames = ptr; input->allocated = new_allocated; } frame = &input->frames[ input->count ]; frame->instructions = instructions; /* Check for repeated frames */ if( input->count != 0 && count != 0 && count == input->frames[ input->non_repeat ].count && !memcmp( in_bytes, input->frames[ input->non_repeat ].in_bytes, count ) ) { frame->repeat_last = 1; } else { frame->repeat_last = 0; frame->count = count; /* Note this as the last non-repeated frame */ input->non_repeat = input->count; if( count ) { frame->in_bytes = libspectrum_malloc( count * sizeof( *( frame->in_bytes ) ) ); memcpy( frame->in_bytes, in_bytes, count * sizeof( *( frame->in_bytes ) ) ); } else { frame->in_bytes = NULL; } } /* Move along to the next frame */ input->count++; return 0; }
static void block_alloc( rzx_block_t **block, libspectrum_rzx_block_id type ) { *block = libspectrum_malloc( sizeof( **block ) ); (*block)->type = type; }
/* Initialise a libspectrum_snap structure */ libspectrum_snap* libspectrum_snap_alloc_internal( void ) { return libspectrum_malloc( sizeof( libspectrum_snap ) ); }
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; }
static libspectrum_error inflate_block( libspectrum_byte **uncompressed, size_t *uncompressed_length, const libspectrum_byte **compressed, size_t compressed_length ) { #ifdef HAVE_ZLIB_H libspectrum_dword header_length, expected_crc32, actual_crc32; libspectrum_byte *zlib_buffer; unsigned long actual_length; int error; /* First, look at the compression header */ header_length = libspectrum_read_dword( compressed ); if( header_length != 12 ) { libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, "zxs_inflate_block: unknown header length %lu", (unsigned long)header_length ); return LIBSPECTRUM_ERROR_UNKNOWN; } compressed_length -= 12; expected_crc32 = libspectrum_read_dword( compressed ); *uncompressed_length = libspectrum_read_dword( compressed ); /* Some space to put the zlib header for decompression */ zlib_buffer = libspectrum_malloc( ( compressed_length + 6 ) * sizeof( *zlib_buffer ) ); /* zlib's header */ zlib_buffer[0] = 0x78; zlib_buffer[1] = 0xda; memcpy( &zlib_buffer[2], *compressed, compressed_length ); *compressed += compressed_length; *uncompressed = libspectrum_malloc( *uncompressed_length * sizeof( **uncompressed ) ); actual_length = *uncompressed_length; error = uncompress( *uncompressed, &actual_length, zlib_buffer, compressed_length + 6 ); /* At this point, we expect to get a Z_DATA_ERROR, as we don't have the Adler-32 checksum of the data. There is a 1 in 65521 chance that the random bytes will match, so we might (very rarely) get Z_OK */ if( error != Z_DATA_ERROR && error != Z_OK ) { libspectrum_free( *uncompressed ); libspectrum_free( zlib_buffer ); libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "zxs_inflate_block: unexpected zlib error" ); return LIBSPECTRUM_ERROR_CORRUPT; } if( *uncompressed_length != actual_length ) { libspectrum_free( *uncompressed ); libspectrum_free( zlib_buffer ); libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "zxs_inflate_block: block expanded to 0x%04lx, not the expected 0x%04lx bytes", actual_length, (unsigned long)*uncompressed_length ); return LIBSPECTRUM_ERROR_CORRUPT; } libspectrum_free( zlib_buffer ); actual_crc32 = crc32( 0, Z_NULL, 0 ); actual_crc32 = crc32( actual_crc32, *uncompressed, *uncompressed_length ); if( actual_crc32 != expected_crc32 ) { libspectrum_free( *uncompressed ); libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "zxs_inflate_block: crc 0x%08x does not match expected 0x%08x", actual_crc32, expected_crc32 ); return LIBSPECTRUM_ERROR_CORRUPT; } return LIBSPECTRUM_ERROR_NONE; #else /* #ifdef HAVE_ZLIB_H */ /* No zlib, so can't inflate the block */ return LIBSPECTRUM_ERROR_UNKNOWN; #endif /* #ifdef HAVE_ZLIB_H */ }
/* Convert RLE block to a TZX DRB as TZX CSW block support is limited :/ */ static libspectrum_error tzx_write_rle( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, libspectrum_tape *tape, libspectrum_tape_iterator iterator ) { libspectrum_error error; libspectrum_tape_block_state it; libspectrum_dword scale = libspectrum_tape_block_scale( block ); libspectrum_dword pulse_tstates = 0; libspectrum_dword balance_tstates = 0; int flags = 0; libspectrum_tape_block *raw_block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RAW_DATA ); libspectrum_tape_block_set_bit_length( raw_block, scale ); libspectrum_tape_block_set_pause ( raw_block, 0 ); rle_state.bits_used = 0; rle_state.level = 0; rle_state.length = 0; rle_state.tape_length = 8192; rle_state.tape_buffer = libspectrum_malloc( rle_state.tape_length ); *rle_state.tape_buffer = 0; it.current_block = iterator; error = libspectrum_tape_block_init( block, &it ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( rle_state.tape_buffer ); libspectrum_tape_block_free( raw_block ); return error; } while( !(flags & LIBSPECTRUM_TAPE_FLAGS_BLOCK) ) { libspectrum_dword pulse_length = 0; /* Use internal version of this that doesn't bugger up the external tape status */ error = libspectrum_tape_get_next_edge_internal( &pulse_tstates, &flags, tape, &it ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( rle_state.tape_buffer ); libspectrum_tape_block_free( raw_block ); return error; } balance_tstates += pulse_tstates; /* next set of pulses is: balance_tstates / scale; */ pulse_length = balance_tstates / scale; balance_tstates = balance_tstates % scale; /* write pulse_length bits of the current level into the buffer */ write_pulse( pulse_length ); } if( rle_state.length || rle_state.bits_used ) { if( rle_state.bits_used ) { rle_state.length++; } else { rle_state.bits_used = 8; } error = libspectrum_tape_block_set_bits_in_last_byte( raw_block, rle_state.bits_used ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( rle_state.tape_buffer ); libspectrum_tape_block_free( raw_block ); return error; } error = libspectrum_tape_block_set_data_length( raw_block, rle_state.length ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( rle_state.tape_buffer ); libspectrum_tape_block_free( raw_block ); return error; } error = libspectrum_tape_block_set_data( raw_block, rle_state.tape_buffer ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( rle_state.tape_buffer ); libspectrum_tape_block_free( raw_block ); return error; } /* now have tzx_write_raw_data finish the job */ tzx_write_raw_data( raw_block, buffer, ptr, length ); } else { libspectrum_free( rle_state.tape_buffer ); } return libspectrum_tape_block_free( raw_block ); }