static libspectrum_dword
generalised_data_block_length(
                    libspectrum_tape_generalised_data_block *generalised_data )
{
  libspectrum_dword length = 0;
  libspectrum_tape_generalised_data_block_state state;
  libspectrum_dword tstates = 0;
  /* Assume no special flags by default */
  int flags = 0;
  /* Has this edge ended the block? */
  int end_of_block = 0;
  libspectrum_error error = generalised_data_init( generalised_data, &state );

  if( error ) return -1;

  /* just reuse tape iteration for this as it is so nasty */
  while( !end_of_block ) {
    error = generalised_data_edge( generalised_data, &state, &tstates,
                                   &end_of_block, &flags );
    if( error ) return -1;

    length += tstates;
  }

  return length;
}
Exemple #2
0
libspectrum_error
libspectrum_tape_get_next_edge_internal( libspectrum_dword *tstates,
                                         int *flags,
                                         libspectrum_tape *tape,
                                         libspectrum_tape_block_state *it )
{
  int error;

  libspectrum_tape_block *block =
    libspectrum_tape_iterator_current( it->current_block );

  /* Has this edge ended the block? */
  int end_of_block = 0;

  /* After getting a new block, do we want to advance to the next one? */
  int no_advance = 0;

  /* Assume no special flags by default */
  *flags = 0;

  if( block ) {
    switch( block->type ) {
    case LIBSPECTRUM_TAPE_BLOCK_ROM:
      error = rom_edge( &(block->types.rom), &(it->block_state.rom), tstates,
                        &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_TURBO:
      error = turbo_edge( &(block->types.turbo), &(it->block_state.turbo), tstates,
                          &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
      error = tone_edge( &(block->types.pure_tone), &(it->block_state.pure_tone),
                         tstates, &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PULSES:
      error = pulses_edge( &(block->types.pulses), &(it->block_state.pulses),
                           tstates, &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
      error = pure_data_edge( &(block->types.pure_data),
                              &(it->block_state.pure_data), tstates, &end_of_block);
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
      error = raw_data_edge( &(block->types.raw_data), &(it->block_state.raw_data),
                             tstates, &end_of_block );
      if( error ) return error;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
      error = generalised_data_edge( &(block->types.generalised_data),
                                     &(it->block_state.generalised_data),
                                     tstates, &end_of_block, flags );
      if( error ) return error;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
      *tstates = ( block->types.pause.length * 69888 ) / 20; end_of_block = 1;
      /* 0 ms pause => stop tape */
      if( *tstates == 0 ) { *flags |= LIBSPECTRUM_TAPE_FLAGS_STOP; }
      break;

    case LIBSPECTRUM_TAPE_BLOCK_JUMP:
      error = jump_blocks( tape, block->types.jump.offset );
      if( error ) return error;
      *tstates = 0; end_of_block = 1; no_advance = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
      if( it->current_block->next && block->types.loop_start.count ) {
        it->loop_block = it->current_block->next;
        it->loop_count = block->types.loop_start.count;
      }
      *tstates = 0; end_of_block = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
      if( it->loop_block ) {
        if( --(it->loop_count) ) {
          it->current_block = it->loop_block;
          no_advance = 1;
        } else {
          it->loop_block = NULL;
        }
      }
      *tstates = 0; end_of_block = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_STOP48:
      *tstates = 0; *flags |= LIBSPECTRUM_TAPE_FLAGS_STOP48; end_of_block = 1;
      break;

    /* For blocks which contain no Spectrum-readable data, return zero
       tstates and set end of block set so we instantly get the next block */
    case LIBSPECTRUM_TAPE_BLOCK_GROUP_START: 
    case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
    case LIBSPECTRUM_TAPE_BLOCK_SELECT:
    case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
    case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
    case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
    case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
    case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
      *tstates = 0; end_of_block = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
      error = rle_pulse_edge( &(block->types.rle_pulse),
                              &(it->block_state.rle_pulse), tstates, &end_of_block);
      if( error ) return error;
      break;

    default:
      *tstates = 0;
      libspectrum_print_error(
        LIBSPECTRUM_ERROR_LOGIC,
        "libspectrum_tape_get_next_edge: unknown block type 0x%02x",
        block->type
      );
      return LIBSPECTRUM_ERROR_LOGIC;
    }
  } else {
    *tstates = 0;
    end_of_block = 1;
  }

  /* If that ended the block, move onto the next block */
  if( end_of_block ) {

    *flags |= LIBSPECTRUM_TAPE_FLAGS_BLOCK;

    /* Advance to the next block, unless we've been told not to */
    if( !no_advance ) {

      libspectrum_tape_iterator_next( &(it->current_block) );

      /* If we've just hit the end of the tape, stop the tape (and
	 then `rewind' to the start) */
      if( libspectrum_tape_iterator_current( it->current_block ) == NULL ) {
	*flags |= LIBSPECTRUM_TAPE_FLAGS_STOP;
        libspectrum_tape_iterator_init( &(it->current_block), tape );
      }
    }

    /* Initialise the new block */
    error = libspectrum_tape_block_init(
                      libspectrum_tape_iterator_current( it->current_block ),
                      it );
    if( error ) return error;

  }

  return LIBSPECTRUM_ERROR_NONE;
}