// license:BSD-3-Clause // copyright-holders:Miodrag Milanovic /********************************************************************* 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 #include #include "pool.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 { io_generic *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; struct floppy_image_legacy { struct io_generic io; const struct FloppyFormat *floppy_option; struct FloppyCallbacks format; /* loaded track stuff */ int loaded_track_head; int loaded_track_index; UINT32 loaded_track_size; void *loaded_track_data; UINT8 loaded_track_status; UINT8 flags; /* tagging system */ object_pool *tags; void *tag_data; }; static struct td0dsk_tag *get_tag(floppy_image_legacy *floppy) { struct td0dsk_tag *tag; tag = (td0dsk_tag *)floppy_tag((floppy_image_legacy *)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_possector_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 = 0; 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) { UINT64 image_size = io_generic_size(floppy_file); if (size > image_size - floppy_file_offset) { size = image_size - floppy_file_offset; } io_generic_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; 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==nullptr) { 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->io); 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==nullptr) { 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;idata + 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 = nullptr; return FLOPPY_ERROR_SUCCESS; } /********************************************************************* formats/td0_dsk.h Teledisk disk images *********************************************************************/ #include "td0_dsk.h" td0_format::td0_format() { } const char *td0_format::name() const { return "td0"; } const char *td0_format::description() const { return "Teledisk disk image"; } const char *td0_format::extensions() const { return "td0"; } int td0_format::identify(io_generic *io, UINT32 form_factor) { UINT8 h[7]; io_generic_read(io, h, 0, 7); if(((h[0] == 'T') && (h[1] == 'D')) || ((h[0] == 't') && (h[1] == 'd'))) { return 100; } return 0; } bool td0_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { int track_count = 0; int head_count = 0; int track_spt; int offset = 0; const int max_size = 4*1024*1024; // 4MB ought to be large enough for any floppy dynamic_buffer imagebuf(max_size); UINT8 header[12]; io_generic_read(io, header, 0, 12); head_count = header[9]; if(header[0] == 't') { td0dsk_t disk_decode; disk_decode.floppy_file = io; disk_decode.init_Decode(); disk_decode.floppy_file_offset = 12; disk_decode.Decode(&imagebuf[0], max_size); } else io_generic_read(io, &imagebuf[0], 12, io_generic_size(io)); if(header[7] & 0x80) offset = 10 + imagebuf[2] + (imagebuf[3] << 8); track_spt = imagebuf[offset]; if(track_spt == 255) // Empty file? return false; switch(header[6]) { case 2: if((imagebuf[offset + 2] & 0x7f) == 2) // ? { if(head_count == 2) image->set_variant(floppy_image::DSHD); else return false; // single side hd? break; } /* no break; could be qd, won't know until tracks are counted */ case 1: if(head_count == 2) image->set_variant(floppy_image::DSDD); else image->set_variant(floppy_image::SSDD); break; case 4: if((imagebuf[offset + 2] & 0x7f) == 2) // ? { if(head_count == 2) image->set_variant(floppy_image::DSHD); else return false; // single side 3.5? break; } /* no break */ case 3: if(head_count == 2) { if(form_factor == floppy_image::FF_525) image->set_variant(floppy_image::DSQD); else image->set_variant(floppy_image::DSDD); } else { if(form_factor == floppy_image::FF_525) image->set_variant(floppy_image::SSQD); else return false; // single side 3.5? } break; } static const int rates[3] = { 250000, 300000, 500000 }; int rate = (header[5] & 0x7f) >= 3 ? 500000 : rates[header[5] & 0x7f]; int rpm = form_factor == floppy_image::FF_8 || (form_factor == floppy_image::FF_525 && rate >= 300000) ? 360 : 300; int base_cell_count = rate*60/rpm; while(track_spt != 255) { desc_pc_sector sects[256]; UINT8 sect_data[65536]; int sdatapos = 0; int track = imagebuf[offset + 1]; int head = imagebuf[offset + 2] & 1; bool fm = (header[5] & 0x80) || (imagebuf[offset + 2] & 0x80); // ? offset += 4; for(int i = 0; i < track_spt; i++) { UINT8 *hs = &imagebuf[offset]; UINT16 size; offset += 6; sects[i].track = hs[0]; sects[i].head = hs[1]; sects[i].sector = hs[2]; sects[i].size = hs[3]; sects[i].deleted = (hs[4] & 4) == 4; sects[i].bad_crc = (hs[4] & 2) == 2; if(hs[4] & 0x30) size = 0; else { offset += 3; size = 128 << hs[3]; int j, k; switch(hs[8]) { default: return false; case 0: memcpy(§_data[sdatapos], &imagebuf[offset], size); offset += size; break; case 1: offset += 4; k = (hs[9] + (hs[10] << 8)) * 2; k = (k <= size) ? k : size; for(j = 0; j < k; j += 2) { sect_data[sdatapos + j] = hs[11]; sect_data[sdatapos + j + 1] = hs[12]; } if(k < size) memset(§_data[sdatapos + k], '\0', size - k); break; case 2: k = 0; while(k < size) { UINT16 len = imagebuf[offset]; UINT16 rep = imagebuf[offset + 1]; offset += 2; if(!len) { memcpy(§_data[sdatapos + k], &imagebuf[offset], rep); offset += rep; k += rep; } else { len = (1 << len); rep = len * rep; rep = ((rep + k) <= size) ? rep : (size - k); for(j = 0; j < rep; j += len) memcpy(§_data[sdatapos + j + k], &imagebuf[offset], len); k += rep; offset += len; } } break; } } sects[i].actual_size = size; if(size) { sects[i].data = §_data[sdatapos]; sdatapos += size; } else sects[i].data = nullptr; } track_count = track; if(fm) build_pc_track_fm(track, head, image, base_cell_count, track_spt, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); else build_pc_track_mfm(track, head, image, base_cell_count*2, track_spt, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); track_spt = imagebuf[offset]; } if((track_count > 50) && (form_factor == floppy_image::FF_525)) // ? { if(image->get_variant() == floppy_image::DSDD) image->set_variant(floppy_image::DSQD); else if(image->get_variant() == floppy_image::SSDD) image->set_variant(floppy_image::SSQD); } return true; } bool td0_format::save(io_generic *io, floppy_image *image) { return false; } bool td0_format::supports_save() const { return false; } const floppy_format_type FLOPPY_TD0_FORMAT = &floppy_image_format_creator;