/* tzxlist.c: Produce a listing of the blocks in a .tzx file Copyright (c) 2001-2002 Philip Kendall, Darren Salt $Id$ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Author contact information: E-mail: pak21-fuse@srcf.ucam.org Postal address: 15 Crescent Road, Wokingham, Berks, RG40 2DB, England */ #include #include #include #include #include #include #include #include #include #include "utils.h" #define DESCRIPTION_LENGTH 80 const char *progname; static const char* hardware_desc( int type, int id ) { switch( type ) { case 0: switch( id ) { case 0: return "16K Spectrum"; case 1: return "48K Spectrum/Spectrum +"; case 2: return "48K Spectrum (Issue 1)"; case 3: return "128K Spectrum"; case 4: return "Spectrum +2"; case 5: return "Spectrum +2A/+3"; default: return "Unknown machine"; } case 3: switch( id ) { case 0: return "AY-3-8192"; default: return "Unknown sound device"; } case 4: switch( id ) { case 0: return "Kempston joystick"; case 1: return "Cursor/Protek/AGF joystick"; case 2: return "Sinclair joystick (Left)"; case 3: return "Sinclair joystick (Right)"; case 4: return "Fuller joystick"; default: return "Unknown joystick"; } default: return "Unknown type"; } } static int process_tzx( char *filename ) { int error; unsigned char *buffer; size_t length; libspectrum_tape *tape; GSList *ptr; size_t i; error = mmap_file( filename, &buffer, &length ); if( error ) return error; error = libspectrum_tape_alloc( &tape ); if( error != LIBSPECTRUM_ERROR_NONE ) { munmap( buffer, length ); return 1; } error = libspectrum_tzx_read( tape, buffer, length ); if( error != LIBSPECTRUM_ERROR_NONE ) { munmap( buffer, length ); libspectrum_tape_free( tape ); return error; } if( munmap( buffer, length ) == -1 ) { fprintf( stderr, "%s: couldn't munmap `%s': %s\n", progname, filename, strerror( errno ) ); return 1; } printf("Listing of `%s':\n\n", filename ); ptr = tape->blocks; while( ptr ) { libspectrum_tape_block *block = (libspectrum_tape_block*)ptr->data; char description[ DESCRIPTION_LENGTH ]; error = libspectrum_tape_block_description( description, DESCRIPTION_LENGTH, block ); if( error ) return 1; printf( "Block type 0x%02x (%s)\n", libspectrum_tape_block_type( block ), description ); switch( libspectrum_tape_block_type( block ) ) { case LIBSPECTRUM_TAPE_BLOCK_ROM: printf(" Data length: %ld bytes\n", (unsigned long)libspectrum_tape_block_data_length( block ) ); printf(" Pause length: %d ms\n", libspectrum_tape_block_pause( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_TURBO: printf(" %ld pilot pulses of %d tstates\n", (unsigned long)libspectrum_tape_block_pilot_pulses( block ), libspectrum_tape_block_pilot_length( block ) ); printf(" Sync pulses of %d and %d tstates\n", libspectrum_tape_block_sync1_length( block ), libspectrum_tape_block_sync2_length( block ) ); /* Fall through */ case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA: printf(" Data bits are %d (reset) and %d (set) tstates\n", libspectrum_tape_block_bit0_length( block ), libspectrum_tape_block_bit1_length( block ) ); printf(" Data length: %ld bytes (%ld bits in last byte used)\n", (unsigned long)libspectrum_tape_block_data_length( block ), (unsigned long)libspectrum_tape_block_bits_in_last_byte(block) ); printf(" Pause length: %d ms\n", libspectrum_tape_block_pause( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE: printf(" %ld pulses of %ld tstates\n", (unsigned long)libspectrum_tape_block_count( block ), (unsigned long)libspectrum_tape_block_pulse_length( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_PULSES: for( i=0; i < libspectrum_tape_block_count( block ); i++ ) printf(" Pulse %3ld: length %d tstates\n", (unsigned long)i, libspectrum_tape_block_pulse_lengths( block, i ) ); break; case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA: printf(" Length: %ld bytes\n", (unsigned long) libspectrum_tape_block_data_length( block ) ); printf(" Bits in last byte: %ld\n", (unsigned long)libspectrum_tape_block_bits_in_last_byte(block) ); printf(" Each bit is %d tstates\n", libspectrum_tape_block_bit_length( block ) ); printf(" Pause length: %d ms\n", libspectrum_tape_block_pause( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_PAUSE: printf(" Length: %d ms\n", libspectrum_tape_block_pause( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_GROUP_START: printf(" Name: %s\n", libspectrum_tape_block_text( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_GROUP_END: case LIBSPECTRUM_TAPE_BLOCK_LOOP_END: case LIBSPECTRUM_TAPE_BLOCK_STOP48: /* Do nothing */ break; case LIBSPECTRUM_TAPE_BLOCK_JUMP: printf(" Offset: %d\n", libspectrum_tape_block_offset( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_LOOP_START: printf(" Count: %lu\n", (unsigned long)libspectrum_tape_block_count( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_SELECT: for( i = 0; i < libspectrum_tape_block_count( block ); i++ ) { printf(" Choice %2ld: Offset %d: %s\n", (unsigned long)i, libspectrum_tape_block_offsets( block, i ), libspectrum_tape_block_texts( block, i ) ); } break; case LIBSPECTRUM_TAPE_BLOCK_MESSAGE: printf(" Display for %d seconds\n", libspectrum_tape_block_pause( block ) ); /* Fall through */ case LIBSPECTRUM_TAPE_BLOCK_COMMENT: printf(" Comment: %s\n", libspectrum_tape_block_text( block ) ); break; case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO: for( i = 0; i < libspectrum_tape_block_count( block ); i++ ) { printf(" "); switch( libspectrum_tape_block_ids( block, i ) ) { case 0: printf("Full Title:"); break; case 1: printf(" Publisher:"); break; case 2: printf(" Author:"); break; case 3: printf(" Year:"); break; case 4: printf(" Langugage:"); break; case 5: printf(" Category:"); break; case 6: printf(" Price:"); break; case 7: printf(" Loader:"); break; case 8: printf(" Origin:"); break; case 255: printf(" Comment:"); break; default: printf("(Unknown string): "); break; } printf(" %s\n", libspectrum_tape_block_texts( block, i ) ); } break; case LIBSPECTRUM_TAPE_BLOCK_HARDWARE: for( i = 0; i < libspectrum_tape_block_count( block ); i++ ) { printf( " %s: ", hardware_desc( libspectrum_tape_block_types( block, i ), libspectrum_tape_block_ids( block, i ) ) ); switch( libspectrum_tape_block_values( block, i ) ) { case 0: printf("runs"); break; case 1: printf("runs, using hardware"); break; case 2: printf("runs, does not use hardware"); break; case 3: printf("does not run"); break; } printf("\n"); } break; case LIBSPECTRUM_TAPE_BLOCK_CUSTOM: printf( " Description: %s\n", libspectrum_tape_block_text( block ) ); printf( " Length: %ld bytes\n", (unsigned long)libspectrum_tape_block_data_length( block ) ); break; default: printf(" (Sorry -- %s can't handle that kind of block. Skipping it)\n", progname ); break; } ptr = ptr->next; } error = libspectrum_tape_free( tape ); if( error != LIBSPECTRUM_ERROR_NONE ) { munmap( buffer, length ); return error; } return 0; } int main( int argc, char **argv ) { int ret = 0; int arg = 0; progname = argv[0]; if( argc < 2 ) { fprintf( stderr, "%s: usage: %s ...\n", progname, progname ); return 1; } while( ++arg < argc ) ret |= process_tzx( argv[arg] ); return ret; }