static libspectrum_error write_128k_sna( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, libspectrum_snap *snap ) { size_t i, page; libspectrum_error error; page = libspectrum_snap_out_128_memoryport( snap ) & 0x07; libspectrum_make_room( buffer, 0xc000 + LIBSPECTRUM_SNA_128_HEADER_LENGTH, ptr, length ); error = write_page( *ptr, snap, 5 ); (*ptr) += 0x4000; if( error ) return error; error = write_page( *ptr, snap, 2 ); (*ptr) += 0x4000; if( error ) return error; error = write_page( *ptr, snap, page ); (*ptr) += 0x4000; if( error ) return error; libspectrum_write_word( ptr, libspectrum_snap_pc( snap ) ); *(*ptr)++ = libspectrum_snap_out_128_memoryport( snap ); *(*ptr)++ = '\0'; for( i = 0; i < 8; i++ ) { /* Already written pages 5, 2 and whatever's paged in */ if( i == 5 || i == 2 || i == page ) continue; libspectrum_make_room( buffer, 0x4000, ptr, length ); error = write_page( *ptr, snap, i ); (*ptr) += 0x4000; if( error ) return error; } return LIBSPECTRUM_ERROR_NONE; }
static void tzx_write_archive_info( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { size_t i, count, total_length; count = libspectrum_tape_block_count( block ); /* 1 count byte, 2 bytes (ID and length) for every string */ total_length = 1 + 2 * count; /* And then the length of all the strings */ for( i = 0; i < count; i++ ) total_length += strlen( (char*)libspectrum_tape_block_texts( block, i ) ); /* Make room for all that, along with ID byte and two bytes storing the total length */ libspectrum_make_room( buffer, total_length + 3, ptr, length ); /* Write out the metadata */ *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO; libspectrum_write_word( ptr, total_length ); *(*ptr)++ = count; /* And the strings */ for( i = 0; i < count; i++ ) { *(*ptr)++ = libspectrum_tape_block_ids( block, i ); tzx_write_string( ptr, libspectrum_tape_block_texts( block, i ) ); } }
static libspectrum_error rzx_write_signed_end( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, ptrdiff_t sign_offset, libspectrum_rzx_dsa_key *key ) { #ifdef HAVE_GCRYPT_H libspectrum_error error; libspectrum_byte *signature; size_t sig_length; /* Get the actual signature */ error = libspectrum_sign_data( &signature, &sig_length, ( *buffer + sign_offset ), (*ptr) - ( *buffer + sign_offset ), key ); if( error ) return error; libspectrum_make_room( buffer, sig_length + 5, ptr, length ); /* Block ID */ *(*ptr)++ = LIBSPECTRUM_RZX_SIGN_END_BLOCK; /* Block length */ libspectrum_write_dword( ptr, sig_length + 5 ); /* Write the signature */ memcpy( *ptr, signature, sig_length ); (*ptr) += sig_length; libspectrum_free( signature ); #endif /* #ifdef HAVE_GCRYPT_H */ return LIBSPECTRUM_ERROR_NONE; }
static void tzx_write_select( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { size_t count, total_length, i; /* The id byte, the total length (2 bytes), the count byte, and ( 2 offset bytes and 1 length byte ) per selection */ count = libspectrum_tape_block_count( block ); total_length = 4 + 3 * count; for( i = 0; i < count; i++ ) total_length += strlen( (char*)libspectrum_tape_block_texts( block, i ) ); libspectrum_make_room( buffer, total_length, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_SELECT; libspectrum_write_word( ptr, total_length ); *(*ptr)++ = count; for( i = 0; i < count; i++ ) { libspectrum_write_word( ptr, libspectrum_tape_block_offsets( block, i ) ); tzx_write_string( ptr, libspectrum_tape_block_texts( block, i ) ); } }
static void rzx_write_header( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, ptrdiff_t *sign_offset, int sign ) { size_t signature_length = strlen( rzx_signature ); libspectrum_make_room( buffer, strlen( rzx_signature ) + 6, ptr, length ); memcpy( *ptr, rzx_signature, signature_length ); *ptr += signature_length; *(*ptr)++ = 0; /* Major version number */ /* Flags */ #ifdef HAVE_GCRYPT_H *(*ptr)++ = sign ? 13 : 12; /* Minor version number: 12 if we're not signing, 13 if we are */ libspectrum_write_dword( ptr, sign ? 0x01 : 0x00 ); /* Store where to start signing data from */ *sign_offset = *ptr - *buffer; #else /* #ifdef HAVE_GCRYPT_H */ *(*ptr)++ = 12; /* Minor version number */ libspectrum_write_dword( ptr, 0 ); #endif /* #ifdef HAVE_GCRYPT_H */ }
static void write_header( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, libspectrum_snap *snap ) { libspectrum_make_room( buffer, LIBSPECTRUM_SNA_HEADER_LENGTH, ptr, length ); *(*ptr)++ = libspectrum_snap_i ( snap ); libspectrum_write_word( ptr, libspectrum_snap_hl_( snap ) ); libspectrum_write_word( ptr, libspectrum_snap_de_( snap ) ); libspectrum_write_word( ptr, libspectrum_snap_bc_( snap ) ); *(*ptr)++ = libspectrum_snap_f_( snap ); *(*ptr)++ = libspectrum_snap_a_( snap ); libspectrum_write_word( ptr, libspectrum_snap_hl ( snap ) ); libspectrum_write_word( ptr, libspectrum_snap_de ( snap ) ); libspectrum_write_word( ptr, libspectrum_snap_bc ( snap ) ); libspectrum_write_word( ptr, libspectrum_snap_iy ( snap ) ); libspectrum_write_word( ptr, libspectrum_snap_ix ( snap ) ); *(*ptr)++ = libspectrum_snap_iff2( snap ) ? 0x04 : 0x00; *(*ptr)++ = libspectrum_snap_r ( snap ); *(*ptr)++ = libspectrum_snap_f ( snap ); *(*ptr)++ = libspectrum_snap_a ( snap ); libspectrum_write_word( ptr, libspectrum_snap_sp ( snap ) ); *(*ptr)++ = libspectrum_snap_im( snap ); *(*ptr)++ = libspectrum_snap_out_ula( snap ) & 0x07; }
static void tzx_write_pause( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { libspectrum_make_room( buffer, 3, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_PAUSE; libspectrum_write_word( ptr, libspectrum_tape_block_pause( block ) ); }
static void tzx_write_loop_start( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { libspectrum_make_room( buffer, 3, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_LOOP_START; libspectrum_write_word( ptr, libspectrum_tape_block_count( block ) ); }
static void tzx_write_empty_block( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, libspectrum_tape_type id ) { /* Make room for the ID byte */ libspectrum_make_room( buffer, 1, ptr, length ); *(*ptr)++ = id; }
static void tzx_write_stop( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { /* Make room for the ID byte and four length bytes */ libspectrum_make_room( buffer, 5, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_STOP48; *(*ptr)++ = '\0'; *(*ptr)++ = '\0'; *(*ptr)++ = '\0'; *(*ptr)++ = '\0'; }
static void tzx_write_pure_tone( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { /* Make room for the ID byte and the data */ libspectrum_make_room( buffer, 5, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_PURE_TONE; libspectrum_write_word( ptr, libspectrum_tape_block_pulse_length( block ) ); libspectrum_write_word( ptr, libspectrum_tape_block_count( block ) ); }
libspectrum_error libspectrum_csw_write( libspectrum_byte **buffer, size_t *length, libspectrum_tape *tape ) { libspectrum_error error; libspectrum_dword sample_rate; size_t length_offset; libspectrum_byte *ptr = *buffer; size_t signature_length = strlen( csw_signature ); /* First, write the .csw signature and the rest of the header */ libspectrum_make_room( buffer, signature_length + 29, &ptr, length ); memcpy( ptr, csw_signature, signature_length ); ptr += signature_length; *ptr++ = 2; /* Major version number */ *ptr++ = 0; /* Minor version number */ /* sample rate */ sample_rate = find_sample_rate( tape ); libspectrum_write_dword( &ptr, sample_rate ); /* Store where the total number of pulses (after decompression) will be written, and skip over those bytes */ length_offset = ptr - *buffer; ptr += sizeof(libspectrum_dword); /* compression type */ #ifdef HAVE_ZLIB_H *ptr++ = 2; /* Z-RLE */ #else *ptr++ = 1; /* RLE */ #endif /* flags */ *ptr++ = 0; /* No flags */ /* header extension length in bytes */ *ptr++ = 0; /* No header extension */ /* encoding application description */ memset( ptr, 0, 16 ); ptr += 16; /* No creator for now */ /* header extension data is zero so on to the data */ error = csw_write_body( buffer, length, tape, sample_rate, length_offset, ptr ); if( error != LIBSPECTRUM_ERROR_NONE ) return error; return LIBSPECTRUM_ERROR_NONE; }
static libspectrum_error tzx_write_generalised_data( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { size_t data_length, bits_per_symbol; libspectrum_error error; libspectrum_tape_generalised_data_symbol_table *pilot_table, *data_table; libspectrum_dword pilot_symbol_count, data_symbol_count, i; data_length = generalised_data_length( block ); libspectrum_make_room( buffer, 5 + data_length, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA; libspectrum_write_dword( ptr, data_length ); libspectrum_write_word( ptr, libspectrum_tape_block_pause( block ) ); pilot_table = libspectrum_tape_block_pilot_table( block ); data_table = libspectrum_tape_block_data_table( block ); error = serialise_generalised_data_table( ptr, pilot_table ); if( error != LIBSPECTRUM_ERROR_NONE ) return error; error = serialise_generalised_data_table( ptr, data_table ); if( error != LIBSPECTRUM_ERROR_NONE ) return error; serialise_generalised_data_symbols( ptr, pilot_table ); pilot_symbol_count = libspectrum_tape_generalised_data_symbol_table_symbols_in_block( pilot_table ); for( i = 0; i < pilot_symbol_count; i++ ) { *(*ptr)++ = libspectrum_tape_block_pilot_symbols( block, i ); libspectrum_write_word( ptr, libspectrum_tape_block_pilot_repeats( block, i ) ); } serialise_generalised_data_symbols( ptr, data_table ); bits_per_symbol = libspectrum_tape_block_bits_per_data_symbol( block ); data_symbol_count = libspectrum_tape_generalised_data_symbol_table_symbols_in_block( data_table ); data_length = ( ( bits_per_symbol * data_symbol_count ) + 7 ) / 8; memcpy( *ptr, libspectrum_tape_block_data( block ), data_length ); (*ptr) += data_length; return LIBSPECTRUM_ERROR_NONE; }
static void tzx_write_rom( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { /* Make room for the ID byte, the pause, the length and the actual data */ libspectrum_make_room( buffer, 5 + libspectrum_tape_block_data_length( block ), ptr, length); /* Write the ID byte and the pause */ *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_ROM; libspectrum_write_word( ptr, libspectrum_tape_block_pause( block ) ); /* Copy the data across */ tzx_write_bytes( ptr, libspectrum_tape_block_data_length( block ), 2, libspectrum_tape_block_data( block ) ); }
static void tzx_write_jump( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { int u_offset; /* Make room for the ID byte and the offset */ libspectrum_make_room( buffer, 3, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_JUMP; u_offset = libspectrum_tape_block_offset( block ); if( u_offset < 0 ) u_offset += 65536; libspectrum_write_word( ptr, u_offset ); }
static void tzx_write_comment( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { char *comment; size_t comment_length; comment = libspectrum_tape_block_text( block ); comment_length = strlen( (char*)comment ); /* Make room for the ID byte, the length byte and the text */ libspectrum_make_room( buffer, 2 + comment_length, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_COMMENT; tzx_write_string( ptr, comment ); }
static void tzx_write_message( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { char *message; size_t text_length; message = libspectrum_tape_block_text( block ); text_length = strlen( (char*)message ); /* Make room for the ID byte, the time byte, length byte and the text */ libspectrum_make_room( buffer, 3 + text_length, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_MESSAGE; *(*ptr)++ = libspectrum_tape_block_pause( block ); tzx_write_string( ptr, message ); }
static void tzx_write_group_start( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { char *name; size_t name_length; name = libspectrum_tape_block_text( block ); name_length = strlen( (char*)name ); /* Make room for the ID byte, the length byte and the name */ libspectrum_make_room( buffer, 2 + name_length, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_GROUP_START; tzx_write_string( ptr, name ); }
static void tzx_write_raw_data( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { size_t data_length; /* Make room for the ID byte, the metadata and the actual data */ data_length = libspectrum_tape_block_data_length( block ); libspectrum_make_room( buffer, 8 + data_length, ptr, length ); /* Write the ID byte and the metadata */ *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_RAW_DATA; libspectrum_write_word( ptr, libspectrum_tape_block_bit_length( block ) ); libspectrum_write_word( ptr, libspectrum_tape_block_pause( block ) ); *(*ptr)++ = libspectrum_tape_block_bits_in_last_byte( block ); tzx_write_bytes( ptr, data_length, 3, libspectrum_tape_block_data( block ) ); }
static void tzx_write_custom( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { size_t data_length; data_length = libspectrum_tape_block_data_length( block ); /* An ID byte, 16 description bytes, 4 length bytes and the data itself */ libspectrum_make_room( buffer, 1 + 16 + 4 + data_length, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_CUSTOM; memcpy( *ptr, libspectrum_tape_block_text( block ), 16 ); *ptr += 16; tzx_write_bytes( ptr, data_length, 4, libspectrum_tape_block_data( block ) ); }
static void tzx_write_pulses( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { size_t i, count, block_length; /* ID byte, count and 2 bytes for length of each pulse */ count = libspectrum_tape_block_count( block ); block_length = 2 + 2 * count; /* Make room for the ID byte, the count and the data */ libspectrum_make_room( buffer, block_length, ptr, length ); *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_PULSES; *(*ptr)++ = count; for( i = 0; i < count; i++ ) libspectrum_write_word( ptr, libspectrum_tape_block_pulse_lengths( block, i ) ); }
static void tzx_write_turbo( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { /* Make room for the ID byte, the metadata and the actual data */ libspectrum_make_room( buffer, 19 + libspectrum_tape_block_data_length( block ), ptr, length); /* Write the ID byte and the metadata */ *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_TURBO; libspectrum_write_word( ptr, libspectrum_tape_block_pilot_length( block ) ); libspectrum_write_word( ptr, libspectrum_tape_block_sync1_length( block ) ); libspectrum_write_word( ptr, libspectrum_tape_block_sync2_length( block ) ); libspectrum_write_word( ptr, libspectrum_tape_block_bit0_length ( block ) ); libspectrum_write_word( ptr, libspectrum_tape_block_bit1_length ( block ) ); libspectrum_write_word( ptr, libspectrum_tape_block_pilot_pulses( block ) ); *(*ptr)++ = libspectrum_tape_block_bits_in_last_byte( block ); libspectrum_write_word( ptr, libspectrum_tape_block_pause ( block ) ); tzx_write_bytes( ptr, libspectrum_tape_block_data_length( block ), 3, libspectrum_tape_block_data( block ) ); }
static void tzx_write_hardware( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { size_t i, count; /* We need one ID byte, one count byte and then three bytes for every entry */ count = libspectrum_tape_block_count( block ); libspectrum_make_room( buffer, 2 + 3 * count, ptr, length ); /* Write out the metadata */ *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_HARDWARE; *(*ptr)++ = count; /* And the info */ for( i = 0; i < count; i++ ) { *(*ptr)++ = libspectrum_tape_block_types( block, i ); *(*ptr)++ = libspectrum_tape_block_ids ( block, i ); *(*ptr)++ = libspectrum_tape_block_values( block, i ); } }
static libspectrum_error rzx_write_signed_start( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, libspectrum_rzx_dsa_key *key, libspectrum_creator *creator ) { #ifdef HAVE_GCRYPT_H libspectrum_make_room( buffer, 13, ptr, length ); /* Block ID */ *(*ptr)++ = LIBSPECTRUM_RZX_SIGN_START_BLOCK; /* Block length */ libspectrum_write_dword( ptr, 13 ); /* Key ID */ if( !key || !key->y || strlen( key->y ) < 8 ) { libspectrum_print_error( LIBSPECTRUM_ERROR_INVALID, "rzx_write_signed_start: invalid key" ); return LIBSPECTRUM_ERROR_INVALID; } libspectrum_write_dword( ptr, strtoul( &key->y[ strlen( key->y ) - 8 ], NULL, 16 ) ); /* Week code */ if( creator ) { libspectrum_write_dword( ptr, libspectrum_creator_competition_code( creator ) ); } else { libspectrum_write_dword( ptr, 0 ); } #endif /* #ifdef HAVE_GCRYPT_H */ return LIBSPECTRUM_ERROR_NONE; }
static void rzx_write_creator( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, libspectrum_creator *creator ) { size_t custom_length, block_length; custom_length = libspectrum_creator_custom_length( creator ); block_length = 29 + custom_length; libspectrum_make_room( buffer, block_length, ptr, length ); *(*ptr)++ = LIBSPECTRUM_RZX_CREATOR_BLOCK; libspectrum_write_dword( ptr, block_length ); /* Block length */ memcpy( *ptr, libspectrum_creator_program( creator ), 20 ); (*ptr) += 20; libspectrum_write_word( ptr, libspectrum_creator_major( creator ) ); libspectrum_write_word( ptr, libspectrum_creator_minor( creator ) ); if( custom_length ) { memcpy( *ptr, libspectrum_creator_custom( creator ), custom_length ); (*ptr) += custom_length; } }
static libspectrum_error write_48k_sna( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, libspectrum_snap *snap ) { libspectrum_error error; libspectrum_byte *stack, *sp; /* Must have somewhere in RAM to store PC */ if( libspectrum_snap_sp( snap ) < 0x4002 ) { libspectrum_print_error( LIBSPECTRUM_ERROR_INVALID, "SP is too low (0x%04x) to stack PC", libspectrum_snap_sp( snap ) ); return LIBSPECTRUM_ERROR_INVALID; } libspectrum_make_room( buffer, 0xc000, ptr, length ); error = write_page( &( (*ptr)[ 0x0000 ] ), snap, 5 ); if( error ) return error; error = write_page( &( (*ptr)[ 0x4000 ] ), snap, 2 ); if( error ) return error; error = write_page( &( (*ptr)[ 0x8000 ] ), snap, 0 ); if( error ) return error; /* Place PC on the stack */ stack = &( (*ptr)[ libspectrum_snap_sp( snap ) - 0x4000 - 2 ] ); libspectrum_write_word( &stack, libspectrum_snap_pc( snap ) ); *ptr += 0xc000; /* Store the new value of SP */ sp = *buffer + SNA_OFFSET_SP; libspectrum_write_word( &sp, libspectrum_snap_sp( snap ) - 2 ); return LIBSPECTRUM_ERROR_NONE; }
libspectrum_error internal_tzx_write( libspectrum_byte **buffer, size_t *length, libspectrum_tape *tape ) { libspectrum_error error; libspectrum_tape_iterator iterator; libspectrum_tape_block *block; libspectrum_byte *ptr = *buffer; size_t signature_length = strlen( libspectrum_tzx_signature ); /* First, write the .tzx signature and the version numbers */ libspectrum_make_room( buffer, signature_length + 2, &ptr, length ); memcpy( ptr, libspectrum_tzx_signature, signature_length ); ptr += signature_length; *ptr++ = 1; /* Major version number */ *ptr++ = 20; /* Minor version number */ for( block = libspectrum_tape_iterator_init( &iterator, tape ); block; block = libspectrum_tape_iterator_next( &iterator ) ) { switch( libspectrum_tape_block_type( block ) ) { case LIBSPECTRUM_TAPE_BLOCK_ROM: tzx_write_rom( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_TURBO: tzx_write_turbo( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE: tzx_write_pure_tone( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_PULSES: tzx_write_pulses( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA: tzx_write_data( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA: tzx_write_raw_data( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA: error = tzx_write_generalised_data( block, buffer, &ptr, length ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( *buffer ); return error; } break; case LIBSPECTRUM_TAPE_BLOCK_PAUSE: tzx_write_pause( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_GROUP_START: tzx_write_group_start( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_GROUP_END: tzx_write_empty_block( buffer, &ptr, length, libspectrum_tape_block_type( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_JUMP: tzx_write_jump( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_LOOP_START: tzx_write_loop_start( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_LOOP_END: tzx_write_empty_block( buffer, &ptr, length, libspectrum_tape_block_type( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_SELECT: tzx_write_select( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_STOP48: tzx_write_stop( buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_COMMENT: tzx_write_comment( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_MESSAGE: tzx_write_message( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO: tzx_write_archive_info( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_HARDWARE: tzx_write_hardware( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_CUSTOM: tzx_write_custom( block, buffer, &ptr, length ); break; case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE: error = tzx_write_rle( block, buffer, &ptr, length, tape, iterator ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( *buffer ); return error; } break; default: libspectrum_free( *buffer ); libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "libspectrum_tzx_write: unknown block type 0x%02x", libspectrum_tape_block_type( block ) ); return LIBSPECTRUM_ERROR_LOGIC; } } (*length) = ptr - *buffer; return LIBSPECTRUM_ERROR_NONE; }
static libspectrum_error rzx_write_input( input_block_t *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, int compress ) { libspectrum_error error; size_t i, size; size_t length_offset, data_offset, flags_offset; libspectrum_byte *length_ptr; libspectrum_make_room( buffer, 18, ptr, length ); *(*ptr)++ = LIBSPECTRUM_RZX_INPUT_BLOCK; /* The length bytes: for uncompressed data, 18 for the block introduction and 4 per frame; the number of bytes in every frame is added in below. If compression is requested (and makes the data shorter), this will be overwritten with the compressed length */ size = 18 + 4 * block->count; /* Store where the length will be written, and skip over those bytes */ length_offset = *ptr - *buffer; (*ptr) += 4; /* How many frames? */ libspectrum_write_dword( ptr, block->count ); /* Each frame has an undefined length, so write a zero */ *(*ptr)++ = 0; /* T-state counter */ libspectrum_write_dword( ptr, block->tstates ); /* Flags */ flags_offset = *ptr - *buffer; libspectrum_write_dword( ptr, compress ? 0x02 : 0 ); /* Write the frames */ data_offset = *ptr - *buffer; for( i = 0; i < block->count; i++ ) { libspectrum_rzx_frame_t *frame = &block->frames[i]; libspectrum_make_room( buffer, 4, ptr, length ); libspectrum_write_word( ptr, frame->instructions ); if( frame->repeat_last ) { libspectrum_write_word( ptr, libspectrum_rzx_repeat_frame ); } else { size += frame->count; /* Keep track of the size */ libspectrum_write_word( ptr, frame->count ); libspectrum_make_room( buffer, frame->count, ptr, length ); memcpy( *ptr, frame->in_bytes, frame->count ); (*ptr) += frame->count; } } /* Write the length in */ length_ptr = *buffer + length_offset; libspectrum_write_dword( &length_ptr, size ); length_ptr -= 4; if( compress ) { #ifdef HAVE_ZLIB_H /* Compress the data the simple way. Really, we should stream the data */ libspectrum_byte *gzsnap = NULL; size_t gzlength; libspectrum_byte *data_ptr = *buffer + data_offset; error = libspectrum_zlib_compress( data_ptr, *ptr - data_ptr, &gzsnap, &gzlength ); if( error != LIBSPECTRUM_ERROR_NONE ) return error; if( (ptrdiff_t)gzlength >= *ptr - data_ptr ) { /* Compression made it bigger :-( */ *(*buffer + flags_offset) &= ~0x02; /* Clear `compressed' bit */ } else { /* Write the compressed data in */ memcpy( data_ptr, gzsnap, gzlength ); /* Correct the length word and the buffer length */ libspectrum_write_dword( &length_ptr, 18 + gzlength ); *ptr = *buffer + data_offset + gzlength; } libspectrum_free( gzsnap ); #else /* #ifdef HAVE_ZLIB_H */ libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, "rzx_write_input: compression needs zlib" ); return LIBSPECTRUM_ERROR_UNKNOWN; #endif /* #ifdef HAVE_ZLIB_H */ } return LIBSPECTRUM_ERROR_NONE; }
static libspectrum_error rzx_write_snapshot( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, libspectrum_snap *snap, libspectrum_id_t snap_format, libspectrum_creator *creator, int compress ) { libspectrum_error error; libspectrum_byte *snap_buffer = NULL; size_t snap_length; libspectrum_byte *gzsnap = NULL; size_t gzlength = 0; int flags, done; snapshot_string_t *type; snap_length = 0; if( snap_format == LIBSPECTRUM_ID_UNKNOWN ) { /* If not given a snap format, try using .z80. If that would result in major information loss, use .szx instead */ snap_format = LIBSPECTRUM_ID_SNAPSHOT_Z80; error = libspectrum_snap_write( &snap_buffer, &snap_length, &flags, snap, snap_format, creator, 0 ); if( error ) return error; if( flags & LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS ) { libspectrum_free( snap_buffer ); snap_length = 0; snap_format = LIBSPECTRUM_ID_SNAPSHOT_SZX; error = libspectrum_snap_write( &snap_buffer, &snap_length, &flags, snap, snap_format, creator, 0 ); if( error ) return error; } } else { error = libspectrum_snap_write( &snap_buffer, &snap_length, &flags, snap, snap_format, creator, 0 ); if( error ) return error; } if( flags & LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS ) { libspectrum_print_error( LIBSPECTRUM_ERROR_WARNING, "%s:rzx_write_snapshot: embedded snapshot has lost a significant amount of information", __FILE__ ); } if( compress ) { #ifdef HAVE_ZLIB_H error = libspectrum_zlib_compress( snap_buffer, snap_length, &gzsnap, &gzlength ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( snap_buffer ); return error; } libspectrum_make_room( buffer, 17 + gzlength, ptr, length ); #else /* #ifdef HAVE_ZLIB_H */ libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, "rzx_write_snapshot: compression needs zlib" ); return LIBSPECTRUM_ERROR_UNKNOWN; #endif /* #ifdef HAVE_ZLIB_H */ } else { libspectrum_make_room( buffer, 17 + snap_length, ptr, length ); } *(*ptr)++ = LIBSPECTRUM_RZX_SNAPSHOT_BLOCK; if( compress ) { /* Block length and flags */ libspectrum_write_dword( ptr, 17 + gzlength ); libspectrum_write_dword( ptr, 2 ); } else { libspectrum_write_dword( ptr, 17 + snap_length ); libspectrum_write_dword( ptr, 0 ); } for( type = snapshot_strings, done = 0; type->format; type++ ) { if( type->format == snap_format ) { memcpy( *ptr, type->string, 4 ); *ptr += 4; done = 1; break; } } if( !done ) { libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, "%s:rzx_write_snapshot: unexpected snap type %d", __FILE__, snap_format ); return LIBSPECTRUM_ERROR_UNKNOWN; } libspectrum_write_dword( ptr, snap_length ); /* Snapshot length */ if( compress ) { memcpy( *ptr, gzsnap, gzlength ); (*ptr) += gzlength; libspectrum_free( gzsnap ); } else { memcpy( *ptr, snap_buffer, snap_length ); (*ptr) += snap_length; } libspectrum_free( snap_buffer ); return LIBSPECTRUM_ERROR_NONE; }
static libspectrum_error csw_write_body( libspectrum_byte **buffer, size_t *length, libspectrum_tape *tape, libspectrum_dword sample_rate, size_t length_offset, libspectrum_byte *ptr ) { libspectrum_error error; int flags = 0; libspectrum_dword pulse_tstates = 0; libspectrum_dword balance_tstates = 0; libspectrum_byte *data = NULL; size_t data_size; size_t data_length = 0; libspectrum_byte *data_ptr = data; long scale = 3500000/sample_rate; libspectrum_tape_block_state it; libspectrum_byte *length_ptr; libspectrum_make_room( &data, 8192, &data_ptr, &data_size ); if( libspectrum_tape_block_internal_init( &it, tape ) ) { while( !(flags & LIBSPECTRUM_TAPE_FLAGS_STOP) ) { 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 ) return error; balance_tstates += pulse_tstates; if( flags & LIBSPECTRUM_TAPE_FLAGS_NO_EDGE ) continue; /* next RLE value is: balance_tstates / scale; */ pulse_length = balance_tstates / scale; balance_tstates = balance_tstates % scale; if( pulse_length ) { if( data_size < (data_length + 1 + sizeof(libspectrum_dword) ) ) libspectrum_make_room( &data, data_size*2, &data_ptr, &data_size ); if( pulse_length <= 0xff ) { *data_ptr++ = pulse_length; data_length++; } else { *data_ptr++ = 0; data_length++; libspectrum_write_dword( &data_ptr, pulse_length ); data_length+=sizeof(libspectrum_dword); } } } } /* Write the length in */ length_ptr = *buffer + length_offset; libspectrum_write_dword( &length_ptr, data_length ); /* compression type */ #ifdef HAVE_ZLIB_H if( data_length ) { libspectrum_byte *compressed_data = NULL; size_t compressed_length; error = libspectrum_zlib_compress( data, data_length, &compressed_data, &compressed_length ); libspectrum_free( data ); if( error ) return error; data = compressed_data; data_length = compressed_length; } #endif if( data_length ) { libspectrum_make_room( buffer, data_length, &ptr, length ); memcpy( ptr, data, data_length ); ptr += data_length; libspectrum_free( data ); } return LIBSPECTRUM_ERROR_NONE; }