From ccc3cc592b9b55a8824e29bf3edce7989c051c9d Mon Sep 17 00:00:00 2001 From: Sorgelig Date: Tue, 8 Feb 2022 08:28:44 +0800 Subject: [PATCH] adjust new sources and paths. --- MiSTer.vcxproj | 4 + MiSTer.vcxproj.filters | 12 + support/uef/uef_reader.cpp | 1024 ++++++++++++++++++------------------ 3 files changed, 527 insertions(+), 513 deletions(-) diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj index 80231e2..ce268b0 100644 --- a/MiSTer.vcxproj +++ b/MiSTer.vcxproj @@ -99,6 +99,7 @@ + @@ -165,6 +166,9 @@ + + + diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters index 8f8fbbb..5ad48a8 100644 --- a/MiSTer.vcxproj.filters +++ b/MiSTer.vcxproj.filters @@ -217,6 +217,9 @@ Source Files\support + + Source Files\support + @@ -411,5 +414,14 @@ Header Files\support + + Header Files\support + + + Header Files\support + + + Header Files\support + \ No newline at end of file diff --git a/support/uef/uef_reader.cpp b/support/uef/uef_reader.cpp index c7a9541..137da0f 100644 --- a/support/uef/uef_reader.cpp +++ b/support/uef/uef_reader.cpp @@ -1,513 +1,511 @@ -/*-------------------------------------------------------------------- - * Modified for MiSTer by alanswx 2022 - * - * Originally from Replay Firmware -*/ - -/*-------------------------------------------------------------------- - * Replay Firmware - * www.fpgaarcade.com - * All rights reserved. - * - * admin@fpgaarcade.com - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - *-------------------------------------------------------------------- - * - * Copyright (c) 2020, The FPGAArcade community (see AUTHORS.txt) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "zlib.h" - -#include "file_io.h" -#include "user_io.h" -#include "menu.h" - -#define UEF_ChunkHeaderSize (sizeof(uint16_t) + sizeof(uint32_t)) -#define UEF_infoID 0x0000 -#define UEF_tapeID 0x0100 -#define UEF_highToneID 0x0110 -#define UEF_highDummyID 0x0111 -#define UEF_gapID 0x0112 -#define UEF_freqChgID 0x0113 -#define UEF_securityID 0x0114 -#define UEF_floatGapID 0x0116 -#define UEF_startBit 0 -#define UEF_stopBit 1 -#define UEF_Baud (1000000.0/(16.0*52.0)) - -typedef struct { - // UEF header - uint16_t id; - uint32_t length; - // chunk data - uint32_t file_offset; - uint32_t bit_offset_start; - uint32_t bit_offset_end; - uint32_t pre_carrier; -} __attribute__((packed)) ChunkInfo; - -// TODO - allocate this as part of the desc structure -static ChunkInfo s_ChunkData = { 0,0,0,0,0,0 }; - - - -static uint16_t ReadChunkHeader(FILE* f, ChunkInfo* chunk) -{ - chunk->id = -1; - chunk->length = 0; - - if (fread(chunk, 1, UEF_ChunkHeaderSize, f) != UEF_ChunkHeaderSize) { - return (-1); - } - - //fprintf(stderr, "ReadChunkHeader: chunk->id %d chunk->length %d\n", chunk->id,chunk->length); - return chunk->id; -} - -static ChunkInfo* GetChunkAtPosFile(FILE *f, uint32_t* p_bit_pos) -{ - uint32_t bit_pos = *p_bit_pos; - uint8_t length_check = (bit_pos == 0xffffffff); - ChunkInfo* chunk = &s_ChunkData; - - //fprintf(stderr, "Find pos : %d\n", bit_pos); - - if (chunk->bit_offset_start <= bit_pos && bit_pos < chunk->bit_offset_end) { - bit_pos -= chunk->bit_offset_start; - *p_bit_pos = bit_pos; - return chunk; - } - - uint32_t chunk_start = 0; - uint32_t chunk_bitlen = 0; - - if (chunk->bit_offset_end != 0 && bit_pos >= chunk->bit_offset_end) { - fseek(f, chunk->file_offset + chunk->length, SEEK_SET); - chunk_start = chunk->bit_offset_end; - bit_pos -= chunk_start; - - } else { - fseek(f, 12, SEEK_SET); // sizeof(UEF_header) - } - - chunk->bit_offset_end = 0; - - while (!feof(f)) { - uint16_t id = ReadChunkHeader(f, chunk); - - if (id == (uint16_t) - 1) { - break; - } - - //fprintf(stderr, "Parse ChunkID : %04x - Length : %4d bytes (%04x) - Offset = %d\n", chunk->id, chunk->length, chunk->length, (uint32_t)ftell(f)); - chunk->file_offset = ftell(f); - - if (UEF_tapeID == id || UEF_gapID == id || UEF_highToneID == id || UEF_highDummyID == id) { - - if (id == UEF_tapeID) { - chunk_bitlen = chunk->length * 10; - - } else if (id == UEF_gapID || id == UEF_highToneID) { - uint16_t ms; - - if (fread(&ms, 1, sizeof(ms), f) != sizeof(ms)) { - break; - } - - chunk_bitlen = ms * (UEF_Baud / 1000.0); - fseek(f, -sizeof(ms), SEEK_CUR); - - } else if (id == UEF_highDummyID) { - uint16_t ms; - - if (fread(&ms, 1, sizeof(ms), f) != sizeof(ms)) { - break; - } - - chunk->pre_carrier = ms * (UEF_Baud / 1000.0); - - if (fread(&ms, 1, sizeof(ms), f) != sizeof(ms)) { - break; - } - - uint32_t post_carrier = ms * (UEF_Baud / 1000.0); - chunk_bitlen = chunk->pre_carrier + 20 + post_carrier; - fseek(f, -sizeof(ms) * 2, SEEK_CUR); - } - - if (bit_pos < chunk_bitlen) { - chunk->bit_offset_start = chunk_start; - chunk->bit_offset_end = chunk_start + chunk_bitlen; - break; - } - - bit_pos -= chunk_bitlen; - chunk_start += chunk_bitlen; - - } else if (length_check) { - - if (UEF_infoID == id) { - char buffer[64]; - uint32_t length = chunk->length; - - while (length > 0) { - uint32_t read_len = length; - - if (read_len > sizeof(buffer) - 1) { - read_len = sizeof(buffer) - 1; - } - - if (fread(buffer, 1, read_len, f) != read_len) { - break; - } - - buffer[read_len] = '\0'; - fprintf(stderr, "Drv02:UEF Info : '%s'", buffer); - - length -= read_len; - } - - } else if (UEF_freqChgID == id) { - float freq; - - if (fread(&freq, 1, sizeof(freq), f) != sizeof(freq)) { - break; - } - - fprintf(stderr, "Drv02:Ignoring base frequency change : %d", (int)freq); - - } else if (UEF_floatGapID == id) { - float gap; - - if (fread(&gap, 1, sizeof(gap), f) != sizeof(gap)) { - break; - } - - fprintf(stderr, "Drv02:Ignoring floating point gap : %d ms", (int)(gap * 1000.f)); - - } else if (UEF_securityID == id) { - - fprintf(stderr, "Drv02:UEF security block ignored"); - - } else { - fprintf(stderr, "Drv02:Unknown UEF block ID %04x", id); - } - - fseek(f, chunk->file_offset, SEEK_SET); - } - - fseek(f, chunk->length, SEEK_CUR); - } - - /*DEBUG(1, "OK!");*/ - - *p_bit_pos = bit_pos; - return chunk->bit_offset_end ? chunk : 0; -} - -static uint8_t GetBitAtPos(FILE *f, uint32_t bit_pos) -{ - ChunkInfo* info = GetChunkAtPosFile(f, &bit_pos); - - if (!info) { - return 0; - } - - uint16_t id = info->id; - - if (id == UEF_gapID) { - return 0; - - } else if (id == UEF_highToneID) { - return 1; - } - - if (id == UEF_tapeID) { - - uint32_t byte_offset = bit_pos / 10; - uint32_t bit_offset = bit_pos - byte_offset * 10; - - if (bit_offset == 0) { - return UEF_startBit; - } - - if (bit_offset == 9) { - return UEF_stopBit; - } - - uint8_t byte; - fseek(f, info->file_offset + byte_offset, SEEK_SET); - int ret=fread(&byte, 1, sizeof(byte), f); - if (ret<0) fprintf(stderr,"uef: error reading byte\n"); - - bit_offset -= 1; // E (0,7) - assert(bit_offset < 8); - - return (byte & (1 << bit_offset)) ? 1 : 0; - } - - assert(id == UEF_highDummyID); - - if ((bit_pos < info->pre_carrier) || (bit_pos >= info->pre_carrier + 20)) { - return 1; - } - - bit_pos -= info->pre_carrier; - bit_pos %= 10; - - if (bit_pos == 0) { - return UEF_startBit; - } - - if (bit_pos == 9) { - return UEF_stopBit; - } - - bit_pos -= 1; // E (0,7) - assert(bit_pos < 8); - uint8_t byte = 'A'; - - return (byte & (1 << bit_pos)) ? 1 : 0; -} - -#define BUFLEN 16384 -#define CHUNK 16384 - -#define kBufferSize 4096 - -static int uef_copy_file(fileTYPE *source, FILE *dest) -{ -unsigned char in[CHUNK]; -int num_bytes; - - - do { - num_bytes = FileReadAdv(source, in, CHUNK,-1); - fprintf(stderr,"fread: %d\n",num_bytes); - if (num_bytes<0) { - fprintf(stderr,"uef_copy_file: error reading data\n"); - return -1; - } - if (fwrite(in, 1, num_bytes, dest) != (size_t)num_bytes || ferror(dest)) { - fprintf(stderr,"uef_copy_file: error writing data\n"); - return -1; - } - } while (num_bytes!=0); - - return 0; -} - -/* Decompress from file source to file dest until stream ends or EOF. - inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be - allocated for processing, Z_DATA_ERROR if the deflate data is - invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and - the version of the library linked do not match, or Z_ERRNO if there - is an error reading or writing the files. */ -static int uef_inflate_file(fileTYPE *source, FILE *dest) -{ - - int ret; - unsigned have; - z_stream strm; - unsigned char in[CHUNK]; - unsigned char out[CHUNK]; - - /* allocate inflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = 0; - strm.next_in = Z_NULL; - ret = inflateInit2(&strm,MAX_WBITS|16); // make sure to add the 16 to get it to accept gz header - - if (ret != Z_OK) - return ret; - - /* decompress until deflate stream ends or end of file */ - do { - - int res = FileReadAdv(source, in, CHUNK,-1); - strm.avail_in= res; - if (res<0) { - (void)inflateEnd(&strm); - return Z_ERRNO; - } - if (strm.avail_in == 0) - break; - strm.next_in = in; - - /* run inflate() on input until output buffer not full */ - do { - - strm.avail_out = CHUNK; - strm.next_out = out; - - - - ret = inflate(&strm, Z_NO_FLUSH); - assert(ret != Z_STREAM_ERROR); /* state not clobbered */ - switch (ret) { - case Z_NEED_DICT: - ret = Z_DATA_ERROR; /* and fall through */ - (void)inflateEnd(&strm); - return ret; - break; - case Z_DATA_ERROR: - (void)inflateEnd(&strm); - return ret; - break; - case Z_MEM_ERROR: - (void)inflateEnd(&strm); - return ret; - break; - } - - have = CHUNK - strm.avail_out; - if (fwrite(out, 1, have, dest) != have || ferror(dest)) { - (void)inflateEnd(&strm); - return Z_ERRNO; - } - - } while (strm.avail_out == 0); - - /* done when inflate() says it's done */ - } while (ret != Z_STREAM_END); - - /* clean up and return */ - (void)inflateEnd(&strm); - return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; -} - -int UEF_FileSend(fileTYPE *inputfile,int use_progress) -{ - uint32_t buf_size=kBufferSize; - unsigned char fbuf[kBufferSize]; - int addr=0; - - typedef struct { - char ueftag[10]; - uint8_t minor_version; - uint8_t major_version; - } UEF_header; - UEF_header header; - - - - - // the UAE file might be gzipped, if so we need to ungzip it - // gzip : 1f 8b - if ( FileReadAdv(inputfile, &fbuf,2) !=2) - { - fprintf(stderr,"error reading 2 bytes of file\n"); - return 0; - } - // we need to rewind to the beginning - FileSeek(inputfile, 0, SEEK_SET); - - FILE *uncompressed_file= tmpfile(); - - // 1f 8b is the gzip magic number - if (fbuf[0]==0x1f && fbuf[1]==0x8b) { - fprintf(stderr,"UEF is compressed\n"); - uef_inflate_file(inputfile, uncompressed_file); - } - else { - uef_copy_file(inputfile,uncompressed_file); - fprintf(stderr,"UEF is not compressed\n"); - } - - rewind(uncompressed_file); - - if (fread(&header, 1, sizeof(UEF_header), uncompressed_file) != sizeof(UEF_header)) { - fprintf(stderr,"Couldn't read file header\n"); - - } else if (memcmp(header.ueftag, "UEF File!\0", sizeof(header.ueftag)) != 0) { - fprintf(stderr,"UEF file header mismatch\n"); - fprintf(stderr,"File compressed?\n"); - - } else { - fprintf(stderr,"UEF: %s %d %d\n",header.ueftag,header.minor_version,header.major_version); - - // figure out how big the file is - fseek(uncompressed_file, 0L, SEEK_END); - uint32_t size =ftell(uncompressed_file); - fprintf(stderr,"size: %d\n",size); - rewind(uncompressed_file); -//FILE *outfile = fopen("tape.raw","wb"); - - - // - // Read the header to find out how big the audio file should be - // - memset(&s_ChunkData, 0x00, sizeof(ChunkInfo)); - uint32_t numbits = 0xffffffff; - GetChunkAtPosFile(uncompressed_file,&numbits); - - numbits = ~numbits; - - uint32_t bits_per_second = 1225; - fprintf(stderr, "Bit length : %d\n", numbits); - fprintf(stderr, "Wave length : %ds\n", numbits / bits_per_second); - fprintf(stderr, "Byte length : %d\n", (numbits + 7) / 8); - - // size is the output size of the file we are creating (or dynamically sending) - size= (numbits + 7) / 8; - uint32_t orig_size=size; - - fprintf(stderr,"output size: %d\n",size); - - // clear the header - memset(&s_ChunkData, 0x00, sizeof(ChunkInfo)); - uint32_t tot_size=0; - uint32_t cur_size=0; - uint32_t act_size=0; - - while (size) { - cur_size= size; - if (cur_size> buf_size) cur_size=buf_size; - act_size=cur_size; - // artifically clamp size to the end of the bit stream - if (addr + act_size > orig_size) - act_size = orig_size - addr; - - tot_size+=act_size; - // this is a very naive conversion, but it'll have to do for now.. - for (uint32_t pos = 0; pos < act_size; ++pos) { - uint8_t val = 0; - for (uint32_t bit = 0; bit < 8; ++bit) { - val = val << 1; - val = val | GetBitAtPos(uncompressed_file, ((addr + pos) << 3) + bit); - } - - fbuf[pos] = val; - } - if (use_progress) ProgressMessage("Loading", inputfile->name, orig_size-size , orig_size); - user_io_file_tx_data(fbuf, act_size); - if (act_size!=cur_size) - fprintf(stderr,"truncated?\n"); -//fwrite(fbuf,1,act_size,outfile); - size -= cur_size; - addr += cur_size; - } - fclose(uncompressed_file); - -//fclose(outfile); - } - return 0; -} - - +/*-------------------------------------------------------------------- + * Modified for MiSTer by alanswx 2022 + * + * Originally from Replay Firmware +*/ + +/*-------------------------------------------------------------------- + * Replay Firmware + * www.fpgaarcade.com + * All rights reserved. + * + * admin@fpgaarcade.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *-------------------------------------------------------------------- + * + * Copyright (c) 2020, The FPGAArcade community (see AUTHORS.txt) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../file_io.h" +#include "../../user_io.h" +#include "../../menu.h" +#include "zlib.h" + +#define UEF_ChunkHeaderSize (sizeof(uint16_t) + sizeof(uint32_t)) +#define UEF_infoID 0x0000 +#define UEF_tapeID 0x0100 +#define UEF_highToneID 0x0110 +#define UEF_highDummyID 0x0111 +#define UEF_gapID 0x0112 +#define UEF_freqChgID 0x0113 +#define UEF_securityID 0x0114 +#define UEF_floatGapID 0x0116 +#define UEF_startBit 0 +#define UEF_stopBit 1 +#define UEF_Baud (1000000.0/(16.0*52.0)) + +typedef struct { + // UEF header + uint16_t id; + uint32_t length; + // chunk data + uint32_t file_offset; + uint32_t bit_offset_start; + uint32_t bit_offset_end; + uint32_t pre_carrier; +} __attribute__((packed)) ChunkInfo; + +// TODO - allocate this as part of the desc structure +static ChunkInfo s_ChunkData = { 0,0,0,0,0,0 }; + + + +static uint16_t ReadChunkHeader(FILE* f, ChunkInfo* chunk) +{ + chunk->id = -1; + chunk->length = 0; + + if (fread(chunk, 1, UEF_ChunkHeaderSize, f) != UEF_ChunkHeaderSize) { + return (-1); + } + + //fprintf(stderr, "ReadChunkHeader: chunk->id %d chunk->length %d\n", chunk->id,chunk->length); + return chunk->id; +} + +static ChunkInfo* GetChunkAtPosFile(FILE *f, uint32_t* p_bit_pos) +{ + uint32_t bit_pos = *p_bit_pos; + uint8_t length_check = (bit_pos == 0xffffffff); + ChunkInfo* chunk = &s_ChunkData; + + //fprintf(stderr, "Find pos : %d\n", bit_pos); + + if (chunk->bit_offset_start <= bit_pos && bit_pos < chunk->bit_offset_end) { + bit_pos -= chunk->bit_offset_start; + *p_bit_pos = bit_pos; + return chunk; + } + + uint32_t chunk_start = 0; + uint32_t chunk_bitlen = 0; + + if (chunk->bit_offset_end != 0 && bit_pos >= chunk->bit_offset_end) { + fseek(f, chunk->file_offset + chunk->length, SEEK_SET); + chunk_start = chunk->bit_offset_end; + bit_pos -= chunk_start; + + } else { + fseek(f, 12, SEEK_SET); // sizeof(UEF_header) + } + + chunk->bit_offset_end = 0; + + while (!feof(f)) { + uint16_t id = ReadChunkHeader(f, chunk); + + if (id == (uint16_t) - 1) { + break; + } + + //fprintf(stderr, "Parse ChunkID : %04x - Length : %4d bytes (%04x) - Offset = %d\n", chunk->id, chunk->length, chunk->length, (uint32_t)ftell(f)); + chunk->file_offset = ftell(f); + + if (UEF_tapeID == id || UEF_gapID == id || UEF_highToneID == id || UEF_highDummyID == id) { + + if (id == UEF_tapeID) { + chunk_bitlen = chunk->length * 10; + + } else if (id == UEF_gapID || id == UEF_highToneID) { + uint16_t ms; + + if (fread(&ms, 1, sizeof(ms), f) != sizeof(ms)) { + break; + } + + chunk_bitlen = ms * (UEF_Baud / 1000.0); + fseek(f, -sizeof(ms), SEEK_CUR); + + } else if (id == UEF_highDummyID) { + uint16_t ms; + + if (fread(&ms, 1, sizeof(ms), f) != sizeof(ms)) { + break; + } + + chunk->pre_carrier = ms * (UEF_Baud / 1000.0); + + if (fread(&ms, 1, sizeof(ms), f) != sizeof(ms)) { + break; + } + + uint32_t post_carrier = ms * (UEF_Baud / 1000.0); + chunk_bitlen = chunk->pre_carrier + 20 + post_carrier; + fseek(f, -sizeof(ms) * 2, SEEK_CUR); + } + + if (bit_pos < chunk_bitlen) { + chunk->bit_offset_start = chunk_start; + chunk->bit_offset_end = chunk_start + chunk_bitlen; + break; + } + + bit_pos -= chunk_bitlen; + chunk_start += chunk_bitlen; + + } else if (length_check) { + + if (UEF_infoID == id) { + char buffer[64]; + uint32_t length = chunk->length; + + while (length > 0) { + uint32_t read_len = length; + + if (read_len > sizeof(buffer) - 1) { + read_len = sizeof(buffer) - 1; + } + + if (fread(buffer, 1, read_len, f) != read_len) { + break; + } + + buffer[read_len] = '\0'; + fprintf(stderr, "Drv02:UEF Info : '%s'", buffer); + + length -= read_len; + } + + } else if (UEF_freqChgID == id) { + float freq; + + if (fread(&freq, 1, sizeof(freq), f) != sizeof(freq)) { + break; + } + + fprintf(stderr, "Drv02:Ignoring base frequency change : %d", (int)freq); + + } else if (UEF_floatGapID == id) { + float gap; + + if (fread(&gap, 1, sizeof(gap), f) != sizeof(gap)) { + break; + } + + fprintf(stderr, "Drv02:Ignoring floating point gap : %d ms", (int)(gap * 1000.f)); + + } else if (UEF_securityID == id) { + + fprintf(stderr, "Drv02:UEF security block ignored"); + + } else { + fprintf(stderr, "Drv02:Unknown UEF block ID %04x", id); + } + + fseek(f, chunk->file_offset, SEEK_SET); + } + + fseek(f, chunk->length, SEEK_CUR); + } + + /*DEBUG(1, "OK!");*/ + + *p_bit_pos = bit_pos; + return chunk->bit_offset_end ? chunk : 0; +} + +static uint8_t GetBitAtPos(FILE *f, uint32_t bit_pos) +{ + ChunkInfo* info = GetChunkAtPosFile(f, &bit_pos); + + if (!info) { + return 0; + } + + uint16_t id = info->id; + + if (id == UEF_gapID) { + return 0; + + } else if (id == UEF_highToneID) { + return 1; + } + + if (id == UEF_tapeID) { + + uint32_t byte_offset = bit_pos / 10; + uint32_t bit_offset = bit_pos - byte_offset * 10; + + if (bit_offset == 0) { + return UEF_startBit; + } + + if (bit_offset == 9) { + return UEF_stopBit; + } + + uint8_t byte; + fseek(f, info->file_offset + byte_offset, SEEK_SET); + int ret=fread(&byte, 1, sizeof(byte), f); + if (ret<0) fprintf(stderr,"uef: error reading byte\n"); + + bit_offset -= 1; // E (0,7) + assert(bit_offset < 8); + + return (byte & (1 << bit_offset)) ? 1 : 0; + } + + assert(id == UEF_highDummyID); + + if ((bit_pos < info->pre_carrier) || (bit_pos >= info->pre_carrier + 20)) { + return 1; + } + + bit_pos -= info->pre_carrier; + bit_pos %= 10; + + if (bit_pos == 0) { + return UEF_startBit; + } + + if (bit_pos == 9) { + return UEF_stopBit; + } + + bit_pos -= 1; // E (0,7) + assert(bit_pos < 8); + uint8_t byte = 'A'; + + return (byte & (1 << bit_pos)) ? 1 : 0; +} + +#define BUFLEN 16384 +#define CHUNK 16384 + +#define kBufferSize 4096 + +static int uef_copy_file(fileTYPE *source, FILE *dest) +{ +unsigned char in[CHUNK]; +int num_bytes; + + + do { + num_bytes = FileReadAdv(source, in, CHUNK,-1); + fprintf(stderr,"fread: %d\n",num_bytes); + if (num_bytes<0) { + fprintf(stderr,"uef_copy_file: error reading data\n"); + return -1; + } + if (fwrite(in, 1, num_bytes, dest) != (size_t)num_bytes || ferror(dest)) { + fprintf(stderr,"uef_copy_file: error writing data\n"); + return -1; + } + } while (num_bytes!=0); + + return 0; +} + +/* Decompress from file source to file dest until stream ends or EOF. + inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_DATA_ERROR if the deflate data is + invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and + the version of the library linked do not match, or Z_ERRNO if there + is an error reading or writing the files. */ +static int uef_inflate_file(fileTYPE *source, FILE *dest) +{ + + int ret; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm,MAX_WBITS|16); // make sure to add the 16 to get it to accept gz header + + if (ret != Z_OK) + return ret; + + /* decompress until deflate stream ends or end of file */ + do { + + int res = FileReadAdv(source, in, CHUNK,-1); + strm.avail_in= res; + if (res<0) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + if (strm.avail_in == 0) + break; + strm.next_in = in; + + /* run inflate() on input until output buffer not full */ + do { + + strm.avail_out = CHUNK; + strm.next_out = out; + + + + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + (void)inflateEnd(&strm); + return ret; + break; + case Z_DATA_ERROR: + (void)inflateEnd(&strm); + return ret; + break; + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + break; + } + + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + + } while (strm.avail_out == 0); + + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +int UEF_FileSend(fileTYPE *inputfile,int use_progress) +{ + uint32_t buf_size=kBufferSize; + unsigned char fbuf[kBufferSize]; + int addr=0; + + typedef struct { + char ueftag[10]; + uint8_t minor_version; + uint8_t major_version; + } UEF_header; + UEF_header header; + + + + + // the UAE file might be gzipped, if so we need to ungzip it + // gzip : 1f 8b + if ( FileReadAdv(inputfile, &fbuf,2) !=2) + { + fprintf(stderr,"error reading 2 bytes of file\n"); + return 0; + } + // we need to rewind to the beginning + FileSeek(inputfile, 0, SEEK_SET); + + FILE *uncompressed_file= tmpfile(); + + // 1f 8b is the gzip magic number + if (fbuf[0]==0x1f && fbuf[1]==0x8b) { + fprintf(stderr,"UEF is compressed\n"); + uef_inflate_file(inputfile, uncompressed_file); + } + else { + uef_copy_file(inputfile,uncompressed_file); + fprintf(stderr,"UEF is not compressed\n"); + } + + rewind(uncompressed_file); + + if (fread(&header, 1, sizeof(UEF_header), uncompressed_file) != sizeof(UEF_header)) { + fprintf(stderr,"Couldn't read file header\n"); + + } else if (memcmp(header.ueftag, "UEF File!\0", sizeof(header.ueftag)) != 0) { + fprintf(stderr,"UEF file header mismatch\n"); + fprintf(stderr,"File compressed?\n"); + + } else { + fprintf(stderr,"UEF: %s %d %d\n",header.ueftag,header.minor_version,header.major_version); + + // figure out how big the file is + fseek(uncompressed_file, 0L, SEEK_END); + uint32_t size =ftell(uncompressed_file); + fprintf(stderr,"size: %d\n",size); + rewind(uncompressed_file); +//FILE *outfile = fopen("tape.raw","wb"); + + + // + // Read the header to find out how big the audio file should be + // + memset(&s_ChunkData, 0x00, sizeof(ChunkInfo)); + uint32_t numbits = 0xffffffff; + GetChunkAtPosFile(uncompressed_file,&numbits); + + numbits = ~numbits; + + uint32_t bits_per_second = 1225; + fprintf(stderr, "Bit length : %d\n", numbits); + fprintf(stderr, "Wave length : %ds\n", numbits / bits_per_second); + fprintf(stderr, "Byte length : %d\n", (numbits + 7) / 8); + + // size is the output size of the file we are creating (or dynamically sending) + size= (numbits + 7) / 8; + uint32_t orig_size=size; + + fprintf(stderr,"output size: %d\n",size); + + // clear the header + memset(&s_ChunkData, 0x00, sizeof(ChunkInfo)); + uint32_t tot_size=0; + uint32_t cur_size=0; + uint32_t act_size=0; + + while (size) { + cur_size= size; + if (cur_size> buf_size) cur_size=buf_size; + act_size=cur_size; + // artifically clamp size to the end of the bit stream + if (addr + act_size > orig_size) + act_size = orig_size - addr; + + tot_size+=act_size; + // this is a very naive conversion, but it'll have to do for now.. + for (uint32_t pos = 0; pos < act_size; ++pos) { + uint8_t val = 0; + for (uint32_t bit = 0; bit < 8; ++bit) { + val = val << 1; + val = val | GetBitAtPos(uncompressed_file, ((addr + pos) << 3) + bit); + } + + fbuf[pos] = val; + } + if (use_progress) ProgressMessage("Loading", inputfile->name, orig_size-size , orig_size); + user_io_file_tx_data(fbuf, act_size); + if (act_size!=cur_size) + fprintf(stderr,"truncated?\n"); +//fwrite(fbuf,1,act_size,outfile); + size -= cur_size; + addr += cur_size; + } + fclose(uncompressed_file); + +//fclose(outfile); + } + return 0; +} + +