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;
+}
+
+