// license:BSD-3-Clause// copyright-holders:Gordon Jefferyes/*CSW format----------Header DescriptionOffset Value Type Description0x00 (note) ASCII 22 bytes "Compressed Square Wave" signature0x16 0x1A BYTE Terminator code0x17 0x02 BYTE CSW major revision number0x18 0x00 BYTE CSW minor revision number0x19 DWORD Sample rate0x1D DWORD Total number of pulses (after decompression)0x21 BYTE Compression type 0x01: RLE 0x02: Z-RLE0x22 BYTE Flags b0: initial polarity: if set, the signal starts at logical high0x23 HDR BYTE Header extension length in bytes (0x00)0x24 ASCII 16 bytes free use0x34 BYTE Start of Header is HDR>0*/#include<string.h>#include<zlib.h>#include<assert.h>#include"uef_cas.h"#include"csw_cas.h"#define CSW_WAV_FREQUENCY 44100staticconstUINT8CSW_HEADER[]={"Compressed Square Wave"};staticUINT32get_leuint32(constvoid*ptr){UINT32value;memcpy(&value,ptr,sizeof(value));returnLITTLE_ENDIANIZE_INT32(value);}staticintmycaslen;staticintcsw_cas_to_wav_size(constUINT8*casdata,intcaslen){UINT32SampleRate;UINT32NumberOfPulses;UINT8MajorRevision;UINT8MinorRevision;UINT8CompressionType;UINT8Flags;UINT8HeaderExtensionLength;dynamic_buffergz_ptr;inttotal_size;z_streamd_stream;interr;UINT8*in_ptr;intbsize=0;if(memcmp(casdata,CSW_HEADER,sizeof(CSW_HEADER)-1)){LOG_FORMATS("csw_cas_to_wav_size: cassette image has incompatible header\n");gotocleanup;}if(casdata[0x16]!=0x1a){LOG_FORMATS("csw_cas_to_wav_size: Terminator Code Not Found\n");gotocleanup;}MajorRevision=casdata[0x17];MinorRevision=casdata[0x18];LOG_FORMATS("Version %d : %d\n",MajorRevision,MinorRevision);if(casdata[0x17]!=2){LOG_FORMATS("csw_cas_to_wav_size: Unsuported Major Version\n");gotocleanup;}SampleRate=get_leuint32(casdata+0x19);LOG_FORMATS("Sample rate %u\n",SampleRate);NumberOfPulses=get_leuint32(casdata+0x1d);LOG_FORMATS("Number Of Pulses %u\n",NumberOfPulses);CompressionType=casdata[0x21];Flags=casdata[0x22];HeaderExtensionLength=casdata[0x23];LOG_FORMATS("CompressionType %u Flast %u HeaderExtensionLength %u\n",CompressionType,Flags,HeaderExtensionLength);mycaslen=caslen;//from here on down for now I am assuming it is compressed csw file.in_ptr=(UINT8*)casdata+0x34+HeaderExtensionLength;gz_ptr.resize(8);d_stream.next_in=(unsignedchar*)in_ptr;d_stream.avail_in=caslen-(in_ptr-casdata);d_stream.total_in=0;d_stream.next_out=&gz_ptr[0];d_stream.avail_out=1;d_stream.total_out=0;d_stream.zalloc=0;d_stream.zfree=0;d_stream.opaque=0;d_stream.data_type=0;err=inflateInit(&d_stream);if(err!=Z_OK){LOG_FORMATS("inflateInit2 error: %d\n",err);gotocleanup;}total_size=1;do{d_stream.next_out=&gz_ptr[0];d_stream.avail_out=1;err=inflate(&d_stream,Z_SYNC_FLUSH);if(err==Z_OK){bsize=gz_ptr[0];if(bsize==0){d_stream.avail_out=4;d_stream.next_out=&gz_ptr[0];err=inflate(&d_stream,Z_SYNC_FLUSH);bsize=get_leuint32(&gz_ptr[0]);}total_size=total_size+bsize;}}while(err==Z_OK);if(err!=Z_STREAM_END){LOG_FORMATS("inflate error: %d\n",err);gotocleanup;}err=inflateEnd(&d_stream);if(err!=Z_OK){LOG_FORMATS("inflateEnd error: %d\n",err);gotocleanup;}returntotal_size;cleanup:return-1;}staticintcsw_cas_fill_wave(INT16*buffer,intlength,UINT8*bytes){UINT32SampleRate;UINT32NumberOfPulses;UINT8CompressionType;UINT8Flags;UINT8HeaderExtensionLength;INT8Bit;dynamic_buffergz_ptr;inttotal_size;z_streamd_stream;interr;UINT8*in_ptr;intbsize=0;inti;LOG_FORMATS("Length %d\n",length);SampleRate=get_leuint32(bytes+0x19);LOG_FORMATS("Sample rate %u\n",SampleRate);NumberOfPulses=get_leuint32(bytes+0x1d);LOG_FORMATS("Number Of Pulses %u\n",NumberOfPulses);CompressionType=bytes[0x21];Flags=bytes[0x22];HeaderExtensionLength=bytes[0x23];if((Flags&0)==0){Bit=-100;}else{Bit=100;}LOG_FORMATS("CompressionType %u Flast %u HeaderExtensionLength %u\n",CompressionType,Flags,HeaderExtensionLength);//from here on down for now I am assuming it is compressed csw file.in_ptr=(UINT8*)bytes+0x34+HeaderExtensionLength;gz_ptr.resize(8);d_stream.next_in=(unsignedchar*)in_ptr;d_stream.avail_in=mycaslen-(in_ptr-bytes);d_stream.total_in=0;d_stream.next_out=&gz_ptr[0];d_stream.avail_out=1;d_stream.total_out=0;d_stream.zalloc=0;d_stream.zfree=0;d_stream.opaque=0;d_stream.data_type=0;err=inflateInit(&d_stream);if(err!=Z_OK){LOG_FORMATS("inflateInit2 error: %d\n",err);gotocleanup;}total_size=0;do{d_stream.next_out=&gz_ptr[0];d_stream.avail_out=1;err=inflate(&d_stream,Z_SYNC_FLUSH);if(err==Z_OK){bsize=gz_ptr[0];if(bsize==0){d_stream.avail_out=4;d_stream.next_out=&gz_ptr[0];err=inflate(&d_stream,Z_SYNC_FLUSH);bsize=get_leuint32(&gz_ptr[0]);}for(i=0;i<bsize;i++){buffer[total_size++]=Bit;}Bit=-Bit;}}while(err==Z_OK);if(err!=Z_STREAM_END){LOG_FORMATS("inflate error: %d\n",err);gotocleanup;}err=inflateEnd(&d_stream);if(err!=Z_OK){LOG_FORMATS("inflateEnd error: %d\n",err);gotocleanup;}returnlength;cleanup:return-1;}staticconststructCassetteLegacyWaveFillercsw_legacy_fill_wave={csw_cas_fill_wave,/* fill_wave */-1,/* chunk_size */0,/* chunk_samples */csw_cas_to_wav_size,/* chunk_sample_calc */CSW_WAV_FREQUENCY,/* sample_frequency */0,/* header_samples */0/* trailer_samples */};staticcasserr_tcsw_cassette_identify(cassette_image*cassette,structCassetteOptions*opts){returncassette_legacy_identify(cassette,opts,&csw_legacy_fill_wave);}staticcasserr_tcsw_cassette_load(cassette_image*cassette){returncassette_legacy_construct(cassette,&csw_legacy_fill_wave);}staticconststructCassetteFormatcsw_cassette_format={"csw",csw_cassette_identify,csw_cassette_load,NULL};CASSETTE_FORMATLIST_START(csw_cassette_formats)CASSETTE_FORMAT(csw_cassette_format)CASSETTE_FORMATLIST_ENDCASSETTE_FORMATLIST_START(bbc_cassette_formats)CASSETTE_FORMAT(csw_cassette_format)CASSETTE_FORMAT(uef_cassette_format)CASSETTE_FORMATLIST_END