summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/uef_cas.c
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
commit7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch)
treef310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/lib/formats/uef_cas.c
parenta57b46ae933badd7441ce1644711dbb851e2b504 (diff)
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/lib/formats/uef_cas.c')
-rw-r--r--src/lib/formats/uef_cas.c335
1 files changed, 0 insertions, 335 deletions
diff --git a/src/lib/formats/uef_cas.c b/src/lib/formats/uef_cas.c
deleted file mode 100644
index f078ae776c4..00000000000
--- a/src/lib/formats/uef_cas.c
+++ /dev/null
@@ -1,335 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Wilbert Pol
-/*
-
-UEF format support (for electron driver)
-
-The UEF format supports gzipped images, i'm doing the gunzip step during uef_cas_to_wav_size
-because that is when the length of the original file is known. This is needed to determine
-the size of memory to alloc for the decoding.
-
-Not nice, but it works...
-
-*/
-
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-
-#include <zlib.h>
-#include "uef_cas.h"
-
-
-#define UEF_WAV_FREQUENCY 4800
-#define WAVE_LOW -32768
-#define WAVE_HIGH 32767
-#define WAVE_NULL 0
-
-static const UINT8 UEF_HEADER[10] = { 0x55, 0x45, 0x46, 0x20, 0x46, 0x69, 0x6c, 0x65, 0x21, 0x00 };
-
-/*
- bytes are stored as
- start bit 1 * 0
- data bits 8 * X
- stop bit 1 * 1
-*/
-
-/* gzip flag byte */
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
-#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
-#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
-#define COMMENT 0x10 /* bit 4 set: file comment present */
-#define RESERVED 0xE0 /* bits 5..7: reserved */
-
-static const UINT8* skip_gz_header( const UINT8 *p ) {
- UINT8 method, flags;
- /* skip initial 1f 8b header */
- p += 2;
- /* get method and flags */
- method = *p; p++;
- flags = *p; p++;
- if ( method != Z_DEFLATED || ( flags & RESERVED ) != 0 ) {
- return NULL;
- }
- /* Skip time, xflags and OS code */
- p += 6;
-
- /* Skip the extra field */
- if ( ( flags & EXTRA_FIELD ) != 0 ) {
- int len = ( p[1] << 8 ) | p[0];
- p += 2 + len;
- }
- /* Skip the original file name */
- if ( ( flags & ORIG_NAME ) != 0 ) {
- for ( ; *p; p++ );
- }
- /* Skip the .gz file comment */
- if ( ( flags & COMMENT ) != 0 ) {
- for( ; *p; p++ );
- }
- /* Skip the header crc */
- if ( ( flags & HEAD_CRC ) != 0 ) {
- p += 2;
- }
- return p;
-}
-
-static UINT8 *gz_ptr = NULL;
-
-static float get_uef_float( const UINT8 *Float)
-{
- int Mantissa;
- float Result;
- int Exponent;
-
- /* assume a four byte array named Float exists, where Float[0]
- was the first byte read from the UEF, Float[1] the second, etc */
-
- /* decode mantissa */
- Mantissa = Float[0] | (Float[1] << 8) | ((Float[2]&0x7f)|0x80) << 16;
-
- Result = (float)Mantissa;
- Result = (float)ldexp(Result, -23);
-
- /* decode exponent */
- Exponent = ((Float[2]&0x80) >> 7) | (Float[3]&0x7f) << 1;
- Exponent -= 127;
- Result = (float)ldexp(Result, Exponent);
-
- /* flip sign if necessary */
- if(Float[3]&0x80)
- Result = -Result;
-
- /* floating point number is now in 'Result' */
- return Result;
-}
-
-static int uef_cas_to_wav_size( const UINT8 *casdata, int caslen ) {
- int pos, size;
-
- if ( casdata[0] == 0x1f && casdata[1] == 0x8b ) {
- int err;
- z_stream d_stream;
- int inflate_size = ( casdata[ caslen - 1 ] << 24 ) | ( casdata[ caslen - 2 ] << 16 ) | ( casdata[ caslen - 3 ] << 8 ) | casdata[ caslen - 4 ];
- const UINT8 *in_ptr = skip_gz_header( casdata );
-
- if ( in_ptr == NULL ) {
- goto cleanup;
- }
- gz_ptr = (UINT8 *)malloc( inflate_size );
-
- d_stream.zalloc = 0;
- d_stream.zfree = 0;
- d_stream.opaque = 0;
- d_stream.next_in = (unsigned char *)in_ptr;
- d_stream.avail_in = caslen - ( in_ptr - casdata );
- d_stream.next_out = gz_ptr;
- d_stream.avail_out = inflate_size;
-
- err = inflateInit2( &d_stream, -MAX_WBITS );
- if ( err != Z_OK ) {
- LOG_FORMATS( "inflateInit2 error: %d\n", err );
- goto cleanup;
- }
- err = inflate( &d_stream, Z_NO_FLUSH );
- if ( err != Z_STREAM_END && err != Z_OK ) {
- LOG_FORMATS( "inflate error: %d\n", err );
- goto cleanup;
- }
- err = inflateEnd( &d_stream );
- if ( err != Z_OK ) {
- LOG_FORMATS( "inflateEnd error: %d\n", err );
- goto cleanup;
- }
- caslen = inflate_size;
- casdata = gz_ptr;
- }
-
- if ( caslen < 18 ) {
- LOG_FORMATS( "uef_cas_to_wav_size: cassette image too small\n" );
- goto cleanup;
- }
- if ( memcmp( casdata, UEF_HEADER, sizeof(UEF_HEADER) ) ) {
- LOG_FORMATS( "uef_cas_to_wav_size: cassette image has incompatible header\n" );
- goto cleanup;
- }
-
- LOG_FORMATS( "UEF: Determinig tape size\n" );
- size = 0;
- pos = sizeof(UEF_HEADER) + 2;
- while( pos < caslen ) {
- int chunk_type = ( casdata[pos+1] << 8 ) | casdata[pos];
- int chunk_length = ( casdata[pos+5] << 24 ) | ( casdata[pos+4] << 16 ) | ( casdata[pos+3] << 8 ) | casdata[pos+2];
- int baud_length;
-
- pos += 6;
- switch( chunk_type ) {
- case 0x0100: /* implicit start/stop bit data block */
- size += ( chunk_length * 10 ) * 4;
- break;
- case 0x0101: /* multiplexed data block */
- case 0x0103:
- LOG_FORMATS( "Unsupported chunk type: %04x\n", chunk_type );
- break;
- case 0x0102: /* explicit tape data block */
- size += ( ( chunk_length * 10 ) - casdata[pos] ) * 4;
- break;
- case 0x0104:
- LOG_FORMATS( "Unsupported chunk type: %04x\n", chunk_type );
- break;
- case 0x0110:
- baud_length = ( casdata[pos+1] << 8 ) | casdata[pos];
- size += baud_length * 2;
- break;
- case 0x0111:
- LOG_FORMATS( "Unsupported chunk type: %04x\n", chunk_type );
- break;
- case 0x0112:
- baud_length = ( casdata[pos+1] << 8 ) | casdata[pos];
- size += baud_length * 2 ;
- break;
- case 0x0116:
- size += get_uef_float(casdata+pos)*UEF_WAV_FREQUENCY;
- break;
- case 0x0113:
- case 0x0114:
- case 0x0115:
- case 0x0120:
- LOG_FORMATS( "Unsupported chunk type: %04x\n", chunk_type );
- break;
- }
- pos += chunk_length;
- }
- size = 2 * size;
- return size;
-
-cleanup:
- if ( gz_ptr ) {
- free( gz_ptr );
- gz_ptr = NULL;
- }
- return -1;
-}
-
-static INT16* uef_cas_fill_bit( INT16 *buffer, int bit ) {
- if ( bit ) {
- *buffer = WAVE_LOW; buffer++;
- *buffer = WAVE_HIGH; buffer++;
- *buffer = WAVE_LOW; buffer++;
- *buffer = WAVE_HIGH; buffer++;
- } else {
- *buffer = WAVE_LOW; buffer++;
- *buffer = WAVE_LOW; buffer++;
- *buffer = WAVE_HIGH; buffer++;
- *buffer = WAVE_HIGH; buffer++;
- }
- return buffer;
-}
-
-static int uef_cas_fill_wave( INT16 *buffer, int length, UINT8 *bytes ) {
- int pos;
- INT16 *p = buffer;
-
- if ( bytes[0] == 0x1f && bytes[1] == 0x8b ) {
- if ( gz_ptr == NULL ) {
- return 1;
- }
- bytes = gz_ptr;
- }
-
- pos = sizeof(UEF_HEADER) + 2;
- length = length / 2;
- while( length > 0 ) {
- int chunk_type = ( bytes[pos+1] << 8 ) | bytes[pos];
- int chunk_length = ( bytes[pos+5] << 24 ) | ( bytes[pos+4] << 16 ) | ( bytes[pos+3] << 8 ) | bytes[pos+2];
-
- int baud_length, i, j;
- UINT8 *c;
- pos += 6;
- switch( chunk_type ) {
- case 0x0100: /* implicit start/stop bit data block */
- for( j = 0; j < chunk_length; j++ ) {
- UINT8 byte = bytes[pos+j];
- p = uef_cas_fill_bit( p, 0 );
- for( i = 0; i < 8; i++ ) {
- p = uef_cas_fill_bit( p, byte & 1 );
- byte = byte >> 1;
- }
- p = uef_cas_fill_bit( p, 1 );
- length -= ( 10 * 4 );
- }
- break;
- case 0x0101: /* multiplexed data block */
- case 0x0103:
- LOG_FORMATS( "Unsupported chunk type: %04x\n", chunk_type );
- break;
- case 0x0102: /* explicit tape data block */
- j = ( chunk_length * 10 ) - bytes[pos];
- c = bytes + pos;
- while( j ) {
- UINT8 byte = *c;
- for( i = 0; i < 8 && i < j; i++ ) {
- p = uef_cas_fill_bit( p, byte & 1 );
- byte = byte >> 1;
- j--;
- }
- c++;
- }
- break;
- case 0x0110:
- for( baud_length = ( ( bytes[pos+1] << 8 ) | bytes[pos] ) ; baud_length; baud_length-- ) {
- *p = WAVE_LOW; p++;
- *p = WAVE_HIGH; p++;
- length -= 2;
- }
- break;
- case 0x0112:
- for( baud_length = ( ( bytes[pos+1] << 8 ) | bytes[pos] ) ; baud_length; baud_length-- ) {
- *p = WAVE_NULL; p++;
- *p = WAVE_NULL; p++;
- length -= 2;
- }
- break;
- case 0x0116:
- for( baud_length = (get_uef_float(bytes+pos)*UEF_WAV_FREQUENCY); baud_length; baud_length-- ) {
- *p = WAVE_NULL; p++;
- length -= 1;
- }
- break;
-
-
- }
- pos += chunk_length;
- }
- return p - buffer;
-}
-
-static const struct CassetteLegacyWaveFiller uef_legacy_fill_wave = {
- uef_cas_fill_wave, /* fill_wave */
- -1, /* chunk_size */
- 0, /* chunk_samples */
- uef_cas_to_wav_size, /* chunk_sample_calc */
- UEF_WAV_FREQUENCY, /* sample_frequency */
- 0, /* header_samples */
- 0 /* trailer_samples */
-};
-
-static casserr_t uef_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
- return cassette_legacy_identify( cassette, opts, &uef_legacy_fill_wave );
-}
-
-static casserr_t uef_cassette_load( cassette_image *cassette ) {
- return cassette_legacy_construct( cassette, &uef_legacy_fill_wave );
-}
-
-const struct CassetteFormat uef_cassette_format = {
- "uef",
- uef_cassette_identify,
- uef_cassette_load,
- NULL
-};
-
-CASSETTE_FORMATLIST_START(uef_cassette_formats)
- CASSETTE_FORMAT(uef_cassette_format)
-CASSETTE_FORMATLIST_END