diff --git a/src/lib/formats/cassimg.cpp b/src/lib/formats/cassimg.cpp index 599b2698a81..6f8b559f4ba 100644 --- a/src/lib/formats/cassimg.cpp +++ b/src/lib/formats/cassimg.cpp @@ -798,7 +798,7 @@ cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *l /* sanity check the args */ assert(legacy_args->header_samples >= -1); assert(legacy_args->trailer_samples >= 0); - assert(legacy_args->fill_wave); + assert(legacy_args->fill_wave || legacy_args->fill_wave_ext); const uint64_t size = image_size(); @@ -859,22 +859,16 @@ cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *l /* convert the file data to samples */ while ((pos < sample_count) && (offset < size)) { - /* allocate a buffer for the binary data */ - std::vector chunk(args.chunk_size); - image_read(&chunk[0], offset, args.chunk_size); - offset += args.chunk_size; + const int slice = std::min(args.chunk_size, size - offset); - /* - This approach is problematic because we don't have control on incomming image size when processing the data - (at least in tap implementation). - The method sending the size of output (calculated in 'chunk_sample_calc' above) which uses same data as a input but - without knowing how much data available in the image. Having wrong header with size bigger than image couses illegal - access beyond image data. - Desired state is: - length = args.fill_wave(&samples[pos], args.chunk_size, &chunk[0]); - aslo the fix for tap is commented out in 'tap_cas_fill_wave' - */ - length = args.fill_wave(&samples[pos], sample_count - pos, &chunk[0]); + /* allocate a buffer for the binary data */ + std::vector chunk(slice); + image_read(&chunk[0], offset, slice); + offset += slice; + + length = (args.fill_wave_ext != nullptr) + ? args.fill_wave_ext(&samples[pos], sample_count - pos, &chunk[0], slice) + : args.fill_wave(&samples[pos], sample_count - pos, &chunk[0]); if (length < 0) { err = error::INVALID_IMAGE; diff --git a/src/lib/formats/cassimg.h b/src/lib/formats/cassimg.h index 5dd87d0ec18..9aa0476017c 100644 --- a/src/lib/formats/cassimg.h +++ b/src/lib/formats/cassimg.h @@ -127,6 +127,7 @@ public: uint32_t sample_frequency = 0; int header_samples = 0; int trailer_samples = 0; + int (*fill_wave_ext)(int16_t *, int, const uint8_t *, int) = nullptr; }; ~cassette_image(); diff --git a/src/lib/formats/tzx_cas.cpp b/src/lib/formats/tzx_cas.cpp index 8c9d34e44d4..7dbbb3d0bda 100644 --- a/src/lib/formats/tzx_cas.cpp +++ b/src/lib/formats/tzx_cas.cpp @@ -809,16 +809,17 @@ static int tap_cas_to_wav_size( const uint8_t *casdata, int caslen ) int size = 0; const uint8_t *p = casdata; - while (caslen > 0) + while (caslen > 2) { int data_size = get_u16le(&p[0]); int pilot_length = (p[2] == 0x00) ? 8063 : 3223; - caslen -= data_size; - if (caslen < 0) + caslen -= 2; + if (caslen < data_size) { - LOG_FORMATS("tap_cas_to_wav_size: Requested 0x%X byte but only 0x%X available.\n", data_size, data_size + caslen); - data_size += caslen; + LOG_FORMATS("tap_cas_to_wav_size: Requested 0x%X byte but only 0x%X available.\n", data_size, caslen); + data_size = caslen; } + caslen -= data_size; LOG_FORMATS("tap_cas_to_wav_size: Handling TAP block containing 0x%X bytes", data_size); p += 2; size += tzx_cas_handle_block(nullptr, p, 1000, data_size, 2168, pilot_length, 667, 735, 855, 1710, 8); @@ -828,24 +829,22 @@ static int tap_cas_to_wav_size( const uint8_t *casdata, int caslen ) return size; } -static int tap_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes ) +static int tap_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int bytes_length ) { int16_t *p = buffer; int size = 0; - //while (length > 0) - while (size < length) + while (bytes_length > 2) { int data_size = get_u16le(&bytes[0]); int pilot_length = (bytes[2] == 0x00) ? 8063 : 3223; LOG_FORMATS("tap_cas_fill_wave: Handling TAP block containing 0x%X bytes\n", data_size); - /* - length -= data_size; - if (length < 0) + bytes_length -= 2; + if (bytes_length < data_size) { - data_size += length; // Take as much as we can. + data_size = bytes_length; // Take as much as we can. } - */ + bytes_length -= data_size; bytes += 2; size += tzx_cas_handle_block(&p, bytes, 1000, data_size, 2168, pilot_length, 667, 735, 855, 1710, 8); bytes += data_size; @@ -855,35 +854,36 @@ static int tap_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes static const cassette_image::LegacyWaveFiller tzx_legacy_fill_wave = { - tzx_cas_fill_wave, /* fill_wave */ - -1, /* chunk_size */ - 0, /* chunk_samples */ - tzx_cas_to_wav_size, /* chunk_sample_calc */ - TZX_WAV_FREQUENCY, /* sample_frequency */ - 0, /* header_samples */ - 0 /* trailer_samples */ + tzx_cas_fill_wave, // fill_wave + -1, // chunk_size + 0, // chunk_samples + tzx_cas_to_wav_size, // chunk_sample_calc + TZX_WAV_FREQUENCY, // sample_frequency + 0, // header_samples + 0, // trailer_samples }; static const cassette_image::LegacyWaveFiller tap_legacy_fill_wave = { - tap_cas_fill_wave, /* fill_wave */ - -1, /* chunk_size */ - 0, /* chunk_samples */ - tap_cas_to_wav_size, /* chunk_sample_calc */ - TZX_WAV_FREQUENCY, /* sample_frequency */ - 0, /* header_samples */ - 0 /* trailer_samples */ + nullptr, // fill_wave + -1, // chunk_size + 0, // chunk_samples + tap_cas_to_wav_size, // chunk_sample_calc + TZX_WAV_FREQUENCY, // sample_frequency + 0, // header_samples + 0, // trailer_samples + tap_cas_fill_wave // fill_wave_ext }; static const cassette_image::LegacyWaveFiller cdt_legacy_fill_wave = { - cdt_cas_fill_wave, /* fill_wave */ - -1, /* chunk_size */ - 0, /* chunk_samples */ - tzx_cas_to_wav_size, /* chunk_sample_calc */ - TZX_WAV_FREQUENCY, /* sample_frequency */ - 0, /* header_samples */ - 0 /* trailer_samples */ + cdt_cas_fill_wave, // fill_wave + -1, // chunk_size + 0, // chunk_samples + tzx_cas_to_wav_size, // chunk_sample_calc + TZX_WAV_FREQUENCY, // sample_frequency + 0, // header_samples + 0 // trailer_samples }; static cassette_image::error tzx_cassette_identify( cassette_image *cassette, cassette_image::Options *opts )