summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/formats/td0_dsk.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/formats/td0_dsk.c')
-rw-r--r--trunk/src/lib/formats/td0_dsk.c766
1 files changed, 766 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/td0_dsk.c b/trunk/src/lib/formats/td0_dsk.c
new file mode 100644
index 00000000000..363d996d633
--- /dev/null
+++ b/trunk/src/lib/formats/td0_dsk.c
@@ -0,0 +1,766 @@
+/*********************************************************************
+
+ formats/td0_dsk.c
+
+ TD0 disk images
+
+*********************************************************************/
+/*
+ * Based on Japanese version 29-NOV-1988
+ * LZSS coded by Haruhiko OKUMURA
+ * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
+ * Edited and translated to English by Kenji RIKITAKE
+ */
+
+#include <string.h>
+#include "flopimg.h"
+
+#define BUFSZ 512 // new input buffer
+
+/* LZSS Parameters */
+
+#define N 4096 /* Size of string buffer */
+#define F 60 /* Size of look-ahead buffer */
+#define THRESHOLD 2
+#define NIL N /* End of tree's node */
+
+
+/* Huffman coding parameters */
+
+#define N_CHAR (256 - THRESHOLD + F)
+ /* character code (= 0..N_CHAR-1) */
+#define T (N_CHAR * 2 - 1) /* Size of table */
+#define R (T - 1) /* root position */
+#define MAX_FREQ 0x8000
+ /* update when cumulative frequency */
+ /* reaches to this value */
+
+struct td0dsk_tag
+{
+ int heads;
+ int tracks;
+ int sector_size;
+ UINT64 track_offsets[84*2]; /* offset within data for each track */
+ UINT8 *data;
+};
+
+struct tdlzhuf {
+ UINT16 r,
+ bufcnt,bufndx,bufpos, // string buffer
+ // the following to allow block reads from input in next_word()
+ ibufcnt,ibufndx; // input buffer counters
+ UINT8 inbuf[BUFSZ]; // input buffer
+};
+
+
+struct td0dsk_t
+{
+ floppy_image_legacy *floppy_file;
+ UINT64 floppy_file_offset;
+
+ struct tdlzhuf tdctl;
+ UINT8 text_buf[N + F - 1];
+ UINT16 freq[T + 1]; /* cumulative freq table */
+
+/*
+ * pointing parent nodes.
+ * area [T..(T + N_CHAR - 1)] are pointers for leaves
+ */
+ INT16 prnt[T + N_CHAR];
+
+ /* pointing children nodes (son[], son[] + 1)*/
+ INT16 son[T];
+
+ UINT16 getbuf;
+ UINT8 getlen;
+
+ int data_read(UINT8 *buf, UINT16 size);
+ int next_word();
+ int GetBit();
+ int GetByte();
+ void StartHuff();
+ void reconst();
+ void update(int c);
+ INT16 DecodeChar();
+ INT16 DecodePosition();
+ void init_Decode();
+ int Decode(UINT8 *buf, int len);
+};
+
+static td0dsk_t td0dsk;
+
+
+static struct td0dsk_tag *get_tag(floppy_image_legacy *floppy)
+{
+ struct td0dsk_tag *tag;
+ tag = (td0dsk_tag *)floppy_tag(floppy);
+ return tag;
+}
+
+
+
+FLOPPY_IDENTIFY( td0_dsk_identify )
+{
+ UINT8 header[2];
+
+ floppy_image_read(floppy, header, 0, 2);
+ if (header[0]=='T' && header[1]=='D') {
+ *vote = 100;
+ } else if (header[0]=='t' && header[1]=='d') {
+ *vote = 100;
+ } else {
+ *vote = 0;
+ }
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+static int td0_get_heads_per_disk(floppy_image_legacy *floppy)
+{
+ return get_tag(floppy)->heads;
+}
+
+static int td0_get_tracks_per_disk(floppy_image_legacy *floppy)
+{
+ return get_tag(floppy)->tracks;
+}
+
+static UINT64 td0_get_track_offset(floppy_image_legacy *floppy, int head, int track)
+{
+ return get_tag(floppy)->track_offsets[(track<<1) + head];
+}
+
+static floperr_t get_offset(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, UINT64 *offset)
+{
+ UINT64 offs;
+ UINT8 *header;
+ UINT8 sectors_per_track;
+ int i;
+
+ if ((head < 0) || (head >= get_tag(floppy)->heads) || (track < 0) || (track >= get_tag(floppy)->tracks)
+ || (sector < 0) )
+ return FLOPPY_ERROR_SEEKERROR;
+
+ // position on beginning of track data
+ offs = td0_get_track_offset(floppy, head, track);
+
+ // read track header
+ header = get_tag(floppy)->data + offs - 4;
+
+ // take number of sectors per track
+ sectors_per_track = header[0];
+
+ if (!sector_is_index) {
+ // when taking ID's return seek error if number is over counter
+ if (sector > sectors_per_track) {
+ return FLOPPY_ERROR_SEEKERROR;
+ }
+ }
+
+ // move trought sectors
+ for(i=0;i < sector-1;i++) {
+ header = get_tag(floppy)->data + offs;
+ offs+= 6;
+ if ((header[4] & 0x30)==0) {
+ offs+= 2;
+ offs+= header[6] + (header[7]<<8);
+ }
+ }
+ // read size of sector
+ header = get_tag(floppy)->data + offs;
+ get_tag(floppy)->sector_size = 1 << (header[3] + 7);
+
+ if (offset)
+ *offset = offs;
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+static floperr_t internal_td0_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, void *buffer, size_t buflen)
+{
+ UINT64 offset;
+ floperr_t err;
+ UINT8 *header;
+ int size,realsize,i;
+ int buff_pos;
+ int data_pos;
+ UINT8 *data;
+ UINT8 *buf;
+
+ buf = (UINT8*)buffer;
+ // take sector offset
+ err = get_offset(floppy, head, track, sector, sector_is_index, &offset);
+ if (err)
+ return err;
+
+ // read sector header
+ header = get_tag(floppy)->data + offset;
+ offset+=6;
+ // if there is no date just jump out
+ if ((header[4] & 0x30)!=0) return FLOPPY_ERROR_SUCCESS;
+
+ offset+=3;
+ // take data size
+ size = header[6] + (header[7]<<8)-1;
+ // take real sector size
+ realsize = 1 << (header[3] + 7);
+
+ // read sector data
+ data = get_tag(floppy)->data + offset;
+ buff_pos = 0;
+ data_pos = 0;
+
+ switch(header[8]) {
+ case 0:
+ // encoding type 0
+ // - plain data
+ memcpy(buffer,data,size);
+ break;
+ case 1:
+ // encoding type 1
+ // - 2 bytes size
+ // - 2 bytes of data
+ // data is reapeted specified number of times
+ while(buff_pos<realsize) {
+ for (i=0;i<data[data_pos]+(data[data_pos+1] << 8);i++) {
+ buf[buff_pos] = data[data_pos+2];buff_pos++;
+ buf[buff_pos] = data[data_pos+3];buff_pos++;
+ }
+ data_pos+=4;
+ }
+ break;
+ case 2:
+ // encoding type 2
+ // - if first byte is zero next byte represent size of
+ // plain data after it
+ // - if different then zero when multiply by 2 represent
+ // size of data that should be reapeted next byte times
+ while(buff_pos<realsize) {
+ if (data[data_pos]==0x00) {
+ int size_ = data[data_pos+1];
+ memcpy(buf+buff_pos,data + data_pos + 2,size_);
+ data_pos += 2 + size_;
+ buff_pos += size_;
+ } else {
+ int size_ = 2*data[data_pos];
+ int repeat = data[data_pos+1];
+ data_pos+=2;
+
+ for (i=0;i<repeat;i++) {
+ memcpy(buf + buff_pos,data + data_pos,size_);
+ buff_pos += size_;
+ }
+ data_pos += size_;
+ }
+ }
+ break;
+ default:
+ return FLOPPY_ERROR_INTERNAL;
+ }
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+static floperr_t td0_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
+{
+ return internal_td0_read_sector(floppy, head, track, sector, FALSE, buffer, buflen);
+}
+
+static floperr_t td0_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
+{
+ return internal_td0_read_sector(floppy, head, track, sector, TRUE, buffer, buflen);
+}
+
+static floperr_t td0_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, UINT32 *sector_length)
+{
+ floperr_t err;
+ err = get_offset(floppy, head, track, sector, FALSE, NULL);
+ if (err)
+ return err;
+
+ if (sector_length) {
+ *sector_length = get_tag(floppy)->sector_size;
+ }
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+static floperr_t td0_get_indexed_sector_info(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags)
+{
+ floperr_t retVal;
+ UINT64 offset;
+ UINT8 *sector_info;
+
+ retVal = get_offset(floppy, head, track, sector_index, FALSE, &offset);
+ sector_info = get_tag(floppy)->data + offset;
+ if (cylinder)
+ *cylinder = sector_info[0];
+ if (side)
+ *side = sector_info[1];
+ if (sector)
+ *sector = sector_info[2];
+ if (sector_length) {
+ *sector_length = 1 << (sector_info[3] + 7);
+ }
+ if (flags) {
+ *flags = 0;
+ if (sector_info[4] & 0x02) *flags |= ID_FLAG_CRC_ERROR_IN_DATA_FIELD;
+ if (sector_info[4] & 0x04) *flags |= ID_FLAG_DELETED_DATA;
+ }
+
+ return retVal;
+}
+
+int td0dsk_t::data_read(UINT8 *buf, UINT16 size)
+{
+ if (floppy_file_offset + size > floppy_image_size(floppy_file) ) {
+ size = floppy_image_size(floppy_file) - floppy_file_offset;
+ }
+ floppy_image_read(floppy_file,buf,floppy_file_offset,size);
+ floppy_file_offset += size;
+ return size;
+}
+
+
+/*
+ * Tables for encoding/decoding upper 6 bits of
+ * sliding dictionary pointer
+ */
+
+/* decoder table */
+static const UINT8 d_code[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+ 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+ 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
+ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+ 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
+ 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+ 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
+ 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
+ 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
+ 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
+ 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
+ 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+};
+
+static const UINT8 d_len[256] = {
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+};
+
+int td0dsk_t::next_word()
+{
+ if(tdctl.ibufndx >= tdctl.ibufcnt)
+ {
+ tdctl.ibufndx = 0;
+ tdctl.ibufcnt = data_read(tdctl.inbuf,BUFSZ);
+ if(tdctl.ibufcnt <= 0)
+ return(-1);
+ }
+ while (getlen <= 8) { // typically reads a word at a time
+ getbuf |= tdctl.inbuf[tdctl.ibufndx++] << (8 - getlen);
+ getlen += 8;
+ }
+ return(0);
+}
+
+
+int td0dsk_t::GetBit() /* get one bit */
+{
+ INT16 i;
+ if(next_word() < 0)
+ return(-1);
+ i = getbuf;
+ getbuf <<= 1;
+ getlen--;
+ if(i < 0)
+ return(1);
+ else
+ return(0);
+}
+
+int td0dsk_t::GetByte() /* get a byte */
+{
+ UINT16 i;
+ if(next_word() != 0)
+ return(-1);
+ i = getbuf;
+ getbuf <<= 8;
+ getlen -= 8;
+ i = i >> 8;
+ return((int) i);
+}
+
+
+
+/* initialize freq tree */
+
+void td0dsk_t::StartHuff()
+{
+ int i, j;
+
+ for (i = 0; i < N_CHAR; i++) {
+ freq[i] = 1;
+ son[i] = i + T;
+ prnt[i + T] = i;
+ }
+ i = 0; j = N_CHAR;
+ while (j <= R) {
+ freq[j] = freq[i] + freq[i + 1];
+ son[j] = i;
+ prnt[i] = prnt[i + 1] = j;
+ i += 2; j++;
+ }
+ freq[T] = 0xffff;
+ prnt[R] = 0;
+}
+
+
+/* reconstruct freq tree */
+
+void td0dsk_t::reconst()
+{
+ INT16 i, j, k;
+ UINT16 f, l;
+
+ /* halven cumulative freq for leaf nodes */
+ j = 0;
+ for (i = 0; i < T; i++) {
+ if (son[i] >= T) {
+ freq[j] = (freq[i] + 1) / 2;
+ son[j] = son[i];
+ j++;
+ }
+ }
+ /* make a tree : first, connect children nodes */
+ for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
+ k = i + 1;
+ f = freq[j] = freq[i] + freq[k];
+ for (k = j - 1; f < freq[k]; k--);
+ k++;
+ l = (j - k) * 2;
+
+ /* movmem() is Turbo-C dependent
+ rewritten to memmove() by Kenji */
+
+ /* movmem(&freq[k], &freq[k + 1], l); */
+ (void)memmove(&freq[k + 1], &freq[k], l);
+ freq[k] = f;
+ /* movmem(&son[k], &son[k + 1], l); */
+ (void)memmove(&son[k + 1], &son[k], l);
+ son[k] = i;
+ }
+ /* connect parent nodes */
+ for (i = 0; i < T; i++) {
+ if ((k = son[i]) >= T) {
+ prnt[k] = i;
+ } else {
+ prnt[k] = prnt[k + 1] = i;
+ }
+ }
+}
+
+
+/* update freq tree */
+
+void td0dsk_t::update(int c)
+{
+ int i, j, k, l;
+
+ if (freq[R] == MAX_FREQ) {
+ reconst();
+ }
+ c = prnt[c + T];
+ do {
+ k = ++freq[c];
+
+ /* swap nodes to keep the tree freq-ordered */
+ if (k > freq[l = c + 1]) {
+ while (k > freq[++l]);
+ l--;
+ freq[c] = freq[l];
+ freq[l] = k;
+
+ i = son[c];
+ prnt[i] = l;
+ if (i < T) prnt[i + 1] = l;
+
+ j = son[l];
+ son[l] = i;
+
+ prnt[j] = c;
+ if (j < T) prnt[j + 1] = c;
+ son[c] = j;
+
+ c = l;
+ }
+ } while ((c = prnt[c]) != 0); /* do it until reaching the root */
+}
+
+
+INT16 td0dsk_t::DecodeChar()
+{
+ int ret;
+ UINT16 c;
+
+ c = son[R];
+
+ /*
+ * start searching tree from the root to leaves.
+ * choose node #(son[]) if input bit == 0
+ * else choose #(son[]+1) (input bit == 1)
+ */
+ while (c < T) {
+ if((ret = GetBit()) < 0)
+ return(-1);
+ c += (unsigned) ret;
+ c = son[c];
+ }
+ c -= T;
+ update(c);
+ return c;
+}
+
+INT16 td0dsk_t::DecodePosition()
+{
+ INT16 bit;
+ UINT16 i, j, c;
+
+ /* decode upper 6 bits from given table */
+ if((bit=GetByte()) < 0)
+ return(-1);
+ i = (UINT16) bit;
+ c = (UINT16)d_code[i] << 6;
+ j = d_len[i];
+
+ /* input lower 6 bits directly */
+ j -= 2;
+ while (j--) {
+ if((bit = GetBit()) < 0)
+ return(-1);
+ i = (i << 1) + bit;
+ }
+ return(c | (i & 0x3f));
+}
+
+/* DeCompression
+
+split out initialization code to init_Decode()
+
+*/
+
+void td0dsk_t::init_Decode()
+{
+ int i;
+ getbuf = 0;
+ getlen = 0;
+ tdctl.ibufcnt= tdctl.ibufndx = 0; // input buffer is empty
+ tdctl.bufcnt = 0;
+ StartHuff();
+ for (i = 0; i < N - F; i++)
+ text_buf[i] = ' ';
+ tdctl.r = N - F;
+}
+
+
+int td0dsk_t::Decode(UINT8 *buf, int len) /* Decoding/Uncompressing */
+{
+ INT16 c,pos;
+ int count; // was an unsigned long, seems unnecessary
+ for (count = 0; count < len; ) {
+ if(tdctl.bufcnt == 0) {
+ if((c = DecodeChar()) < 0)
+ return(count); // fatal error
+ if (c < 256) {
+ *(buf++) = c;
+ text_buf[tdctl.r++] = c;
+ tdctl.r &= (N - 1);
+ count++;
+ }
+ else {
+ if((pos = DecodePosition()) < 0)
+ return(count); // fatal error
+ tdctl.bufpos = (tdctl.r - pos - 1) & (N - 1);
+ tdctl.bufcnt = c - 255 + THRESHOLD;
+ tdctl.bufndx = 0;
+ }
+ }
+ else { // still chars from last string
+ while( tdctl.bufndx < tdctl.bufcnt && count < len ) {
+ c = text_buf[(tdctl.bufpos + tdctl.bufndx) & (N - 1)];
+ *(buf++) = c;
+ tdctl.bufndx++;
+ text_buf[tdctl.r++] = c;
+ tdctl.r &= (N - 1);
+ count++;
+ }
+ // reset bufcnt after copy string from text_buf[]
+ if(tdctl.bufndx >= tdctl.bufcnt)
+ tdctl.bufndx = tdctl.bufcnt = 0;
+ }
+ }
+ return(count); // count == len, success
+}
+
+
+FLOPPY_CONSTRUCT( td0_dsk_construct )
+{
+ td0dsk_t *state = &td0dsk;
+ struct FloppyCallbacks *callbacks;
+ struct td0dsk_tag *tag;
+ UINT8 *header;
+ int number_of_sectors;
+ int position;
+ int i;
+ int track;
+
+ if(params)
+ {
+ // create
+ return FLOPPY_ERROR_UNSUPPORTED;
+ }
+
+ tag = (struct td0dsk_tag *) floppy_create_tag(floppy, sizeof(struct td0dsk_tag));
+ if (!tag)
+ return FLOPPY_ERROR_OUTOFMEMORY;
+
+ tag->data = (UINT8*)malloc(floppy_image_size(floppy));
+ if (tag->data==NULL) {
+ return FLOPPY_ERROR_OUTOFMEMORY;
+ }
+ floppy_image_read(floppy, tag->data, 0, floppy_image_size(floppy));
+ header = tag->data;
+
+ if (header[0]=='t') {
+ UINT8 obuf[BUFSZ];
+ int rd;
+ int off = 12;
+ int size = 0;
+ state->floppy_file = floppy;
+ state->init_Decode();
+ state->floppy_file_offset = 12;
+ do
+ {
+ if((rd = state->Decode(obuf, BUFSZ)) > 0) size += rd;
+ } while(rd == BUFSZ);
+ memcpy(obuf,tag->data,12);
+ free(tag->data);
+ tag->data = (UINT8*)malloc(size+12);
+ if (tag->data==NULL) {
+ return FLOPPY_ERROR_OUTOFMEMORY;
+ }
+ memcpy(tag->data,obuf,12);
+ state->floppy_file_offset = 12;
+ state->init_Decode();
+ do
+ {
+ if((rd = state->Decode(obuf, BUFSZ)) > 0) {
+ memcpy(tag->data+off,obuf,rd);
+ off += rd;
+ }
+ } while(rd == BUFSZ);
+ }
+ header = tag->data;
+ tag->heads = header[9];
+ if (tag->heads > 1) {
+ tag->heads = 2;
+ }
+
+ // header len + comment header + comment len
+ position = 12;
+ if (header[7] & 0x80) {
+ position += 10 + header[14] + (header[15]<<8);
+ }
+ tag->tracks = 0;
+ do {
+ // read track header
+ header = tag->data + position;
+ track = header[1];
+ number_of_sectors = header[0];
+ if (number_of_sectors!=0xff){
+ position+=4;
+ tag->track_offsets[(track<<1) + (header[2] & 1)] = position;
+ for(i=0;i<number_of_sectors;i++) {
+ // read sector header
+ header = tag->data + position;
+ position+=6;
+ // read sector size
+ if ((header[4] & 0x30)==0) {
+ // if there is sector data
+ header = tag->data + position;
+ position+=2;
+ // skip sector data
+ position+= header[0] + (header[1]<<8);
+ }
+ }
+ tag->tracks++;
+ }
+ } while(number_of_sectors!=0xff);
+ tag->tracks++;
+
+ callbacks = floppy_callbacks(floppy);
+ callbacks->read_sector = td0_read_sector;
+ callbacks->read_indexed_sector = td0_read_indexed_sector;
+ callbacks->get_sector_length = td0_get_sector_length;
+ callbacks->get_heads_per_disk = td0_get_heads_per_disk;
+ callbacks->get_tracks_per_disk = td0_get_tracks_per_disk;
+ callbacks->get_indexed_sector_info = td0_get_indexed_sector_info;
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+FLOPPY_DESTRUCT( td0_dsk_destruct )
+{
+ struct td0dsk_tag *tag = get_tag(floppy);
+ free(tag->data);
+ tag->data = NULL;
+ return FLOPPY_ERROR_SUCCESS;
+}