1 // license:BSD-3-Clause
2 // copyright-holders:Miodrag Milanovic
3 /*********************************************************************
4
5 formats/td0_dsk.c
6
7 TD0 disk images
8
9 *********************************************************************/
10 /*
11 * Based on Japanese version 29-NOV-1988
12 * LZSS coded by Haruhiko OKUMURA
13 * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
14 * Edited and translated to English by Kenji RIKITAKE
15 */
16
17 #include <cstring>
18 #include <cassert>
19 #include "pool.h"
20 #include "flopimg.h"
21
22 #define BUFSZ 512 // new input buffer
23
24 /* LZSS Parameters */
25
26 #define N 4096 /* Size of string buffer */
27 #define F 60 /* Size of look-ahead buffer */
28 #define THRESHOLD 2
29 #define NIL N /* End of tree's node */
30
31
32 /* Huffman coding parameters */
33
34 #define N_CHAR (256 - THRESHOLD + F)
35 /* character code (= 0..N_CHAR-1) */
36 #define T (N_CHAR * 2 - 1) /* Size of table */
37 #define R (T - 1) /* root position */
38 #define MAX_FREQ 0x8000
39 /* update when cumulative frequency */
40 /* reaches to this value */
41
42 struct td0dsk_tag
43 {
44 int heads;
45 int tracks;
46 int sector_size;
47 uint64_t track_offsets[84*2]; /* offset within data for each track */
48 uint8_t *data;
49 };
50
51 struct tdlzhuf {
52 uint16_t r,
53 bufcnt,bufndx,bufpos, // string buffer
54 // the following to allow block reads from input in next_word()
55 ibufcnt,ibufndx; // input buffer counters
56 uint8_t inbuf[BUFSZ]; // input buffer
57 };
58
59
60 struct td0dsk_t
61 {
62 io_generic *floppy_file;
63 uint64_t floppy_file_offset;
64
65 struct tdlzhuf tdctl;
66 uint8_t text_buf[N + F - 1];
67 uint16_t freq[T + 1]; /* cumulative freq table */
68
69 /*
70 * pointing parent nodes.
71 * area [T..(T + N_CHAR - 1)] are pointers for leaves
72 */
73 int16_t prnt[T + N_CHAR];
74
75 /* pointing children nodes (son[], son[] + 1)*/
76 int16_t son[T];
77
78 uint16_t getbuf;
79 uint8_t getlen;
80
81 int data_read(uint8_t *buf, uint16_t size);
82 int next_word();
83 int GetBit();
84 int GetByte();
85 void StartHuff();
86 void reconst();
87 void update(int c);
88 int16_t DecodeChar();
89 int16_t DecodePosition();
90 void init_Decode();
91 int Decode(uint8_t *buf, int len);
92 };
93
94 //static td0dsk_t td0dsk;
95
96 struct floppy_image_legacy
97 {
98 struct io_generic io;
99
100 const struct FloppyFormat *floppy_option;
101 struct FloppyCallbacks format;
102
103 /* loaded track stuff */
104 int loaded_track_head;
105 int loaded_track_index;
106 uint32_t loaded_track_size;
107 void *loaded_track_data;
108 uint8_t loaded_track_status;
109 uint8_t flags;
110
111 /* tagging system */
112 object_pool *tags;
113 void *tag_data;
114 };
115
116
get_tag(floppy_image_legacy * floppy)117 static struct td0dsk_tag *get_tag(floppy_image_legacy *floppy)
118 {
119 struct td0dsk_tag *tag;
120 tag = (td0dsk_tag *)floppy_tag((floppy_image_legacy *)floppy);
121 return tag;
122 }
123
124
125
FLOPPY_IDENTIFY(td0_dsk_identify)126 FLOPPY_IDENTIFY( td0_dsk_identify )
127 {
128 uint8_t header[2];
129
130 floppy_image_read(floppy, header, 0, 2);
131 if (header[0]=='T' && header[1]=='D') {
132 *vote = 100;
133 } else if (header[0]=='t' && header[1]=='d') {
134 *vote = 100;
135 } else {
136 *vote = 0;
137 }
138 return FLOPPY_ERROR_SUCCESS;
139 }
140
td0_get_heads_per_disk(floppy_image_legacy * floppy)141 static int td0_get_heads_per_disk(floppy_image_legacy *floppy)
142 {
143 return get_tag(floppy)->heads;
144 }
145
td0_get_tracks_per_disk(floppy_image_legacy * floppy)146 static int td0_get_tracks_per_disk(floppy_image_legacy *floppy)
147 {
148 return get_tag(floppy)->tracks;
149 }
150
td0_get_track_offset(floppy_image_legacy * floppy,int head,int track)151 static uint64_t td0_get_track_offset(floppy_image_legacy *floppy, int head, int track)
152 {
153 return get_tag(floppy)->track_offsets[(track<<1) + head];
154 }
155
get_offset(floppy_image_legacy * floppy,int head,int track,int sector,bool sector_is_index,uint64_t * offset)156 static floperr_t get_offset(floppy_image_legacy *floppy, int head, int track, int sector, bool sector_is_index, uint64_t *offset)
157 {
158 uint64_t offs;
159 uint8_t *header;
160 uint8_t sectors_per_track;
161 int i;
162
163 if ((head < 0) || (head >= get_tag(floppy)->heads) || (track < 0) || (track >= get_tag(floppy)->tracks)
164 || (sector < 0) )
165 return FLOPPY_ERROR_SEEKERROR;
166
167 // position on beginning of track data
168 offs = td0_get_track_offset(floppy, head, track);
169
170 // read track header
171 header = get_tag(floppy)->data + offs - 4;
172
173 // take number of sectors per track
174 sectors_per_track = header[0];
175
176 if (!sector_is_index) {
177 // when taking ID's return seek error if number is over counter
178 if (sector > sectors_per_track) {
179 return FLOPPY_ERROR_SEEKERROR;
180 }
181 }
182
183 // move trought sectors
184 for(i=0;i < sector-1;i++) {
185 header = get_tag(floppy)->data + offs;
186 offs+= 6;
187 if ((header[4] & 0x30)==0) {
188 offs+= 2;
189 offs+= header[6] + (header[7]<<8);
190 }
191 }
192 // read size of sector
193 header = get_tag(floppy)->data + offs;
194 get_tag(floppy)->sector_size = 1 << (header[3] + 7);
195
196 if (offset)
197 *offset = offs;
198 return FLOPPY_ERROR_SUCCESS;
199 }
200
201
202
internal_td0_read_sector(floppy_image_legacy * floppy,int head,int track,int sector,bool sector_is_index,void * buffer,size_t buflen)203 static floperr_t internal_td0_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, bool sector_is_index, void *buffer, size_t buflen)
204 {
205 uint64_t offset;
206 floperr_t err;
207 uint8_t *header;
208 int size,realsize,i;
209 int buff_pos;
210 int data_pos;
211 uint8_t *data;
212 uint8_t *buf;
213
214 buf = (uint8_t*)buffer;
215 // take sector offset
216 err = get_offset(floppy, head, track, sector, sector_is_index, &offset);
217 if (err)
218 return err;
219
220 // read sector header
221 header = get_tag(floppy)->data + offset;
222 offset+=6;
223 // if there is no date just jump out
224 if ((header[4] & 0x30)!=0) return FLOPPY_ERROR_SUCCESS;
225
226 offset+=3;
227 // take data size
228 size = header[6] + (header[7]<<8)-1;
229 // take real sector size
230 realsize = 1 << (header[3] + 7);
231
232 // read sector data
233 data = get_tag(floppy)->data + offset;
234 buff_pos = 0;
235 data_pos = 0;
236
237 switch(header[8]) {
238 case 0:
239 // encoding type 0
240 // - plain data
241 memcpy(buffer,data,size);
242 break;
243 case 1:
244 // encoding type 1
245 // - 2 bytes size
246 // - 2 bytes of data
247 // data is reapeted specified number of times
248 while(buff_pos<realsize) {
249 for (i=0;i<data[data_pos]+(data[data_pos+1] << 8);i++) {
250 buf[buff_pos] = data[data_pos+2];buff_pos++;
251 buf[buff_pos] = data[data_pos+3];buff_pos++;
252 }
253 data_pos+=4;
254 }
255 break;
256 case 2:
257 // encoding type 2
258 // - if first byte is zero next byte represent size of
259 // plain data after it
260 // - if different then zero when multiply by 2 represent
261 // size of data that should be reapeted next byte times
262 while(buff_pos<realsize) {
263 if (data[data_pos]==0x00) {
264 int size_ = data[data_pos+1];
265 memcpy(buf+buff_pos,data + data_pos + 2,size_);
266 data_pos += 2 + size_;
267 buff_pos += size_;
268 } else {
269 int size_ = 2*data[data_pos];
270 int repeat = data[data_pos+1];
271 data_pos+=2;
272
273 for (i=0;i<repeat;i++) {
274 memcpy(buf + buff_pos,data + data_pos,size_);
275 buff_pos += size_;
276 }
277 data_pos += size_;
278 }
279 }
280 break;
281 default:
282 return FLOPPY_ERROR_INTERNAL;
283 }
284 return FLOPPY_ERROR_SUCCESS;
285 }
286
287
td0_read_sector(floppy_image_legacy * floppy,int head,int track,int sector,void * buffer,size_t buflen)288 static floperr_t td0_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
289 {
290 return internal_td0_read_sector(floppy, head, track, sector, false, buffer, buflen);
291 }
292
td0_read_indexed_sector(floppy_image_legacy * floppy,int head,int track,int sector,void * buffer,size_t buflen)293 static floperr_t td0_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
294 {
295 return internal_td0_read_sector(floppy, head, track, sector, true, buffer, buflen);
296 }
297
td0_get_sector_length(floppy_image_legacy * floppy,int head,int track,int sector,uint32_t * sector_length)298 static floperr_t td0_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, uint32_t *sector_length)
299 {
300 floperr_t err;
301 err = get_offset(floppy, head, track, sector, false, nullptr);
302 if (err)
303 return err;
304
305 if (sector_length) {
306 *sector_length = get_tag(floppy)->sector_size;
307 }
308 return FLOPPY_ERROR_SUCCESS;
309 }
310
td0_get_indexed_sector_info(floppy_image_legacy * floppy,int head,int track,int sector_index,int * cylinder,int * side,int * sector,uint32_t * sector_length,unsigned long * flags)311 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_t *sector_length, unsigned long *flags)
312 {
313 floperr_t retVal;
314 uint64_t offset = 0;
315 uint8_t *sector_info;
316
317 retVal = get_offset(floppy, head, track, sector_index, false, &offset);
318 sector_info = get_tag(floppy)->data + offset;
319 if (cylinder)
320 *cylinder = sector_info[0];
321 if (side)
322 *side = sector_info[1];
323 if (sector)
324 *sector = sector_info[2];
325 if (sector_length) {
326 *sector_length = 1 << (sector_info[3] + 7);
327 }
328 if (flags) {
329 *flags = 0;
330 if (sector_info[4] & 0x02) *flags |= ID_FLAG_CRC_ERROR_IN_DATA_FIELD;
331 if (sector_info[4] & 0x04) *flags |= ID_FLAG_DELETED_DATA;
332 }
333
334 return retVal;
335 }
336
data_read(uint8_t * buf,uint16_t size)337 int td0dsk_t::data_read(uint8_t *buf, uint16_t size)
338 {
339 uint64_t image_size = io_generic_size(floppy_file);
340 if (size > image_size - floppy_file_offset) {
341 size = image_size - floppy_file_offset;
342 }
343 io_generic_read(floppy_file,buf,floppy_file_offset,size);
344 floppy_file_offset += size;
345 return size;
346 }
347
348
349 /*
350 * Tables for encoding/decoding upper 6 bits of
351 * sliding dictionary pointer
352 */
353
354 /* decoder table */
355 static const uint8_t d_code[256] = {
356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
361 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
362 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
363 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
364 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
365 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
366 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
367 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
368 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
369 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
370 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
371 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
372 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
373 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
374 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
375 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
376 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
377 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
378 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
379 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
380 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
381 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
382 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
383 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
384 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
385 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
386 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
387 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
388 };
389
390 static const uint8_t d_len[256] = {
391 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
392 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
393 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
394 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
395 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
396 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
397 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
398 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
399 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
400 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
401 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
402 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
403 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
404 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
405 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
406 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
407 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
408 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
409 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
410 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
411 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
412 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
413 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
414 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
415 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
416 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
417 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
418 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
419 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
420 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
421 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
422 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
423 };
424
next_word()425 int td0dsk_t::next_word()
426 {
427 if(tdctl.ibufndx >= tdctl.ibufcnt)
428 {
429 tdctl.ibufndx = 0;
430 tdctl.ibufcnt = data_read(tdctl.inbuf,BUFSZ);
431 if(tdctl.ibufcnt <= 0)
432 return(-1);
433 }
434 while (getlen <= 8) { // typically reads a word at a time
435 getbuf |= tdctl.inbuf[tdctl.ibufndx++] << (8 - getlen);
436 getlen += 8;
437 }
438 return(0);
439 }
440
441
GetBit()442 int td0dsk_t::GetBit() /* get one bit */
443 {
444 int16_t i;
445 if(next_word() < 0)
446 return(-1);
447 i = getbuf;
448 getbuf <<= 1;
449 getlen--;
450 if(i < 0)
451 return(1);
452 else
453 return(0);
454 }
455
GetByte()456 int td0dsk_t::GetByte() /* get a byte */
457 {
458 uint16_t i;
459 if(next_word() != 0)
460 return(-1);
461 i = getbuf;
462 getbuf <<= 8;
463 getlen -= 8;
464 i = i >> 8;
465 return((int) i);
466 }
467
468
469
470 /* initialize freq tree */
471
StartHuff()472 void td0dsk_t::StartHuff()
473 {
474 int i, j;
475
476 for (i = 0; i < N_CHAR; i++) {
477 freq[i] = 1;
478 son[i] = i + T;
479 prnt[i + T] = i;
480 }
481 i = 0; j = N_CHAR;
482 while (j <= R) {
483 freq[j] = freq[i] + freq[i + 1];
484 son[j] = i;
485 prnt[i] = prnt[i + 1] = j;
486 i += 2; j++;
487 }
488 freq[T] = 0xffff;
489 prnt[R] = 0;
490 }
491
492
493 /* reconstruct freq tree */
494
reconst()495 void td0dsk_t::reconst()
496 {
497 int16_t i, j, k;
498 uint16_t f, l;
499
500 /* halven cumulative freq for leaf nodes */
501 j = 0;
502 for (i = 0; i < T; i++) {
503 if (son[i] >= T) {
504 freq[j] = (freq[i] + 1) / 2;
505 son[j] = son[i];
506 j++;
507 }
508 }
509 /* make a tree : first, connect children nodes */
510 for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
511 k = i + 1;
512 f = freq[j] = freq[i] + freq[k];
513 for (k = j - 1; f < freq[k]; k--) {};
514 k++;
515 l = (j - k) * 2;
516
517 /* movmem() is Turbo-C dependent
518 rewritten to memmove() by Kenji */
519
520 /* movmem(&freq[k], &freq[k + 1], l); */
521 (void)memmove(&freq[k + 1], &freq[k], l);
522 freq[k] = f;
523 /* movmem(&son[k], &son[k + 1], l); */
524 (void)memmove(&son[k + 1], &son[k], l);
525 son[k] = i;
526 }
527 /* connect parent nodes */
528 for (i = 0; i < T; i++) {
529 if ((k = son[i]) >= T) {
530 prnt[k] = i;
531 } else {
532 prnt[k] = prnt[k + 1] = i;
533 }
534 }
535 }
536
537
538 /* update freq tree */
539
update(int c)540 void td0dsk_t::update(int c)
541 {
542 int i, j, k, l;
543
544 if (freq[R] == MAX_FREQ) {
545 reconst();
546 }
547 c = prnt[c + T];
548 do {
549 k = ++freq[c];
550
551 /* swap nodes to keep the tree freq-ordered */
552 if (k > freq[l = c + 1]) {
553 while (k > freq[++l]) {};
554 l--;
555 freq[c] = freq[l];
556 freq[l] = k;
557
558 i = son[c];
559 prnt[i] = l;
560 if (i < T) prnt[i + 1] = l;
561
562 j = son[l];
563 son[l] = i;
564
565 prnt[j] = c;
566 if (j < T) prnt[j + 1] = c;
567 son[c] = j;
568
569 c = l;
570 }
571 } while ((c = prnt[c]) != 0); /* do it until reaching the root */
572 }
573
574
DecodeChar()575 int16_t td0dsk_t::DecodeChar()
576 {
577 int ret;
578 uint16_t c;
579
580 c = son[R];
581
582 /*
583 * start searching tree from the root to leaves.
584 * choose node #(son[]) if input bit == 0
585 * else choose #(son[]+1) (input bit == 1)
586 */
587 while (c < T) {
588 if((ret = GetBit()) < 0)
589 return(-1);
590 c += (unsigned) ret;
591 c = son[c];
592 }
593 c -= T;
594 update(c);
595 return c;
596 }
597
DecodePosition()598 int16_t td0dsk_t::DecodePosition()
599 {
600 int16_t bit;
601 uint16_t i, j, c;
602
603 /* decode upper 6 bits from given table */
604 if((bit=GetByte()) < 0)
605 return(-1);
606 i = (uint16_t) bit;
607 c = (uint16_t)d_code[i] << 6;
608 j = d_len[i];
609
610 /* input lower 6 bits directly */
611 j -= 2;
612 while (j--) {
613 if((bit = GetBit()) < 0)
614 return(-1);
615 i = (i << 1) + bit;
616 }
617 return(c | (i & 0x3f));
618 }
619
620 /* DeCompression
621
622 split out initialization code to init_Decode()
623
624 */
625
init_Decode()626 void td0dsk_t::init_Decode()
627 {
628 int i;
629 getbuf = 0;
630 getlen = 0;
631 tdctl.ibufcnt= tdctl.ibufndx = 0; // input buffer is empty
632 tdctl.bufcnt = 0;
633 StartHuff();
634 for (i = 0; i < N - F; i++)
635 text_buf[i] = ' ';
636 tdctl.r = N - F;
637 }
638
639
Decode(uint8_t * buf,int len)640 int td0dsk_t::Decode(uint8_t *buf, int len) /* Decoding/Uncompressing */
641 {
642 int16_t c,pos;
643 int count; // was an unsigned long, seems unnecessary
644 for (count = 0; count < len; ) {
645 if(tdctl.bufcnt == 0) {
646 if((c = DecodeChar()) < 0)
647 return(count); // fatal error
648 if (c < 256) {
649 *(buf++) = c;
650 text_buf[tdctl.r++] = c;
651 tdctl.r &= (N - 1);
652 count++;
653 }
654 else {
655 if((pos = DecodePosition()) < 0)
656 return(count); // fatal error
657 tdctl.bufpos = (tdctl.r - pos - 1) & (N - 1);
658 tdctl.bufcnt = c - 255 + THRESHOLD;
659 tdctl.bufndx = 0;
660 }
661 }
662 else { // still chars from last string
663 while( tdctl.bufndx < tdctl.bufcnt && count < len ) {
664 c = text_buf[(tdctl.bufpos + tdctl.bufndx) & (N - 1)];
665 *(buf++) = c;
666 tdctl.bufndx++;
667 text_buf[tdctl.r++] = c;
668 tdctl.r &= (N - 1);
669 count++;
670 }
671 // reset bufcnt after copy string from text_buf[]
672 if(tdctl.bufndx >= tdctl.bufcnt)
673 tdctl.bufndx = tdctl.bufcnt = 0;
674 }
675 }
676 return(count); // count == len, success
677 }
678
679
FLOPPY_CONSTRUCT(td0_dsk_construct)680 FLOPPY_CONSTRUCT( td0_dsk_construct )
681 {
682 td0dsk_t state;
683 struct FloppyCallbacks *callbacks;
684 struct td0dsk_tag *tag;
685 uint8_t *header;
686 int number_of_sectors;
687 int position;
688 int i;
689 int track;
690
691 if(params)
692 {
693 // create
694 return FLOPPY_ERROR_UNSUPPORTED;
695 }
696
697 tag = (struct td0dsk_tag *) floppy_create_tag(floppy, sizeof(struct td0dsk_tag));
698 if (!tag)
699 return FLOPPY_ERROR_OUTOFMEMORY;
700
701 tag->data = (uint8_t*)malloc(floppy_image_size(floppy));
702 if (tag->data==nullptr) {
703 return FLOPPY_ERROR_OUTOFMEMORY;
704 }
705 floppy_image_read(floppy, tag->data, 0, floppy_image_size(floppy));
706 header = tag->data;
707
708 if (header[0]=='t') {
709 uint8_t obuf[BUFSZ];
710 int rd;
711 int off = 12;
712 int size = 0;
713 state.floppy_file = &(floppy->io);
714 state.init_Decode();
715 state.floppy_file_offset = 12;
716 do
717 {
718 if((rd = state.Decode(obuf, BUFSZ)) > 0) size += rd;
719 } while(rd == BUFSZ);
720 memcpy(obuf,tag->data,12);
721 free(tag->data);
722 tag->data = (uint8_t*)malloc(size+12);
723 if (tag->data==nullptr) {
724 return FLOPPY_ERROR_OUTOFMEMORY;
725 }
726 memcpy(tag->data,obuf,12);
727 state.floppy_file_offset = 12;
728 state.init_Decode();
729 do
730 {
731 if((rd = state.Decode(obuf, BUFSZ)) > 0) {
732 memcpy(tag->data+off,obuf,rd);
733 off += rd;
734 }
735 } while(rd == BUFSZ);
736 }
737 header = tag->data;
738 tag->heads = header[9];
739 if (tag->heads > 1) {
740 tag->heads = 2;
741 }
742
743 // header len + comment header + comment len
744 position = 12;
745 if (header[7] & 0x80) {
746 position += 10 + header[14] + (header[15]<<8);
747 }
748 tag->tracks = 0;
749 do {
750 // read track header
751 header = tag->data + position;
752 track = header[1];
753 number_of_sectors = header[0];
754 if (number_of_sectors!=0xff){
755 position+=4;
756 tag->track_offsets[(track<<1) + (header[2] & 1)] = position;
757 for(i=0;i<number_of_sectors;i++) {
758 // read sector header
759 header = tag->data + position;
760 position+=6;
761 // read sector size
762 if ((header[4] & 0x30)==0) {
763 // if there is sector data
764 header = tag->data + position;
765 position+=2;
766 // skip sector data
767 position+= header[0] + (header[1]<<8);
768 }
769 }
770 tag->tracks++;
771 }
772 } while(number_of_sectors!=0xff);
773 tag->tracks++;
774
775 callbacks = floppy_callbacks(floppy);
776 callbacks->read_sector = td0_read_sector;
777 callbacks->read_indexed_sector = td0_read_indexed_sector;
778 callbacks->get_sector_length = td0_get_sector_length;
779 callbacks->get_heads_per_disk = td0_get_heads_per_disk;
780 callbacks->get_tracks_per_disk = td0_get_tracks_per_disk;
781 callbacks->get_indexed_sector_info = td0_get_indexed_sector_info;
782 return FLOPPY_ERROR_SUCCESS;
783 }
784
FLOPPY_DESTRUCT(td0_dsk_destruct)785 FLOPPY_DESTRUCT( td0_dsk_destruct )
786 {
787 struct td0dsk_tag *tag = get_tag(floppy);
788 free(tag->data);
789 tag->data = nullptr;
790 return FLOPPY_ERROR_SUCCESS;
791 }
792
793 /*********************************************************************
794
795 formats/td0_dsk.h
796
797 Teledisk disk images
798
799 *********************************************************************/
800
801 #include "td0_dsk.h"
802
td0_format()803 td0_format::td0_format()
804 {
805 }
806
name() const807 const char *td0_format::name() const
808 {
809 return "td0";
810 }
811
description() const812 const char *td0_format::description() const
813 {
814 return "Teledisk disk image";
815 }
816
extensions() const817 const char *td0_format::extensions() const
818 {
819 return "td0";
820 }
821
identify(io_generic * io,uint32_t form_factor)822 int td0_format::identify(io_generic *io, uint32_t form_factor)
823 {
824 uint8_t h[7];
825
826 io_generic_read(io, h, 0, 7);
827 if(((h[0] == 'T') && (h[1] == 'D')) || ((h[0] == 't') && (h[1] == 'd')))
828 {
829 return 100;
830 }
831 return 0;
832 }
833
load(io_generic * io,uint32_t form_factor,floppy_image * image)834 bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
835 {
836 int track_count = 0;
837 int head_count = 0;
838 int track_spt;
839 int offset = 0;
840 const int max_size = 4*1024*1024; // 4MB ought to be large enough for any floppy
841 std::vector<uint8_t> imagebuf(max_size);
842 uint8_t header[12];
843
844 io_generic_read(io, header, 0, 12);
845 head_count = header[9];
846
847 if(header[0] == 't')
848 {
849 td0dsk_t disk_decode;
850
851 disk_decode.floppy_file = io;
852 disk_decode.init_Decode();
853 disk_decode.floppy_file_offset = 12;
854 disk_decode.Decode(&imagebuf[0], max_size);
855 }
856 else
857 io_generic_read(io, &imagebuf[0], 12, io_generic_size(io));
858
859 if(header[7] & 0x80)
860 offset = 10 + imagebuf[2] + (imagebuf[3] << 8);
861
862 track_spt = imagebuf[offset];
863 if(track_spt == 255) // Empty file?
864 return false;
865
866 switch(header[6])
867 {
868 case 2:
869 if((imagebuf[offset + 2] & 0x7f) == 2) // ?
870 {
871 if(head_count == 2)
872 image->set_variant(floppy_image::DSHD);
873 else
874 return false; // single side hd?
875 break;
876 }
877 /* no break; could be qd, won't know until tracks are counted */
878 case 1:
879 if(head_count == 2)
880 image->set_variant(floppy_image::DSDD);
881 else
882 image->set_variant(floppy_image::SSDD);
883 break;
884 case 4:
885 if((imagebuf[offset + 2] & 0x7f) == 2) // ?
886 {
887 if(head_count == 2)
888 image->set_variant(floppy_image::DSHD);
889 else
890 return false; // single side 3.5?
891 break;
892 } else
893 image->set_variant(floppy_image::SSDD);
894 break;
895 /* no break */
896 case 3:
897 if(head_count == 2)
898 {
899 if(form_factor == floppy_image::FF_525)
900 image->set_variant(floppy_image::DSQD);
901 else
902 image->set_variant(floppy_image::DSDD);
903 }
904 else
905 {
906 if(form_factor == floppy_image::FF_525)
907 image->set_variant(floppy_image::SSQD);
908 else
909 return false; // single side 3.5?
910 }
911 break;
912 case 5:
913 if (form_factor != floppy_image::FF_8)
914 return false; // 8" drive form factor is expected
915 break;
916 }
917
918 static const int rates[3] = { 250000, 300000, 500000 };
919 int rate = (header[5] & 0x7f) >= 3 ? 500000 : rates[header[5] & 0x7f];
920 int rpm = form_factor == floppy_image::FF_8 || (form_factor == floppy_image::FF_525 && rate >= 300000) ? 360 : 300;
921 int base_cell_count = rate*60/rpm;
922
923 while(track_spt != 255)
924 {
925 desc_pc_sector sects[256];
926 uint8_t sect_data[65536];
927 int sdatapos = 0;
928 int track = imagebuf[offset + 1];
929 int head = imagebuf[offset + 2] & 1;
930 bool fm = (header[5] & 0x80) || (imagebuf[offset + 2] & 0x80); // ?
931 offset += 4;
932 for(int i = 0; i < track_spt; i++)
933 {
934 uint8_t *hs = &imagebuf[offset];
935 uint16_t size;
936 offset += 6;
937
938 sects[i].track = hs[0];
939 sects[i].head = hs[1];
940 sects[i].sector = hs[2];
941 sects[i].size = hs[3];
942 sects[i].deleted = (hs[4] & 4) == 4;
943 sects[i].bad_crc = (hs[4] & 2) == 2;
944
945 if(hs[4] & 0x30)
946 size = 0;
947 else
948 {
949 offset += 3;
950 size = 128 << hs[3];
951 int j, k;
952 switch(hs[8])
953 {
954 default:
955 return false;
956 case 0:
957 memcpy(§_data[sdatapos], &imagebuf[offset], size);
958 offset += size;
959 break;
960 case 1:
961 offset += 4;
962 k = (hs[9] + (hs[10] << 8)) * 2;
963 k = (k <= size) ? k : size;
964 for(j = 0; j < k; j += 2)
965 {
966 sect_data[sdatapos + j] = hs[11];
967 sect_data[sdatapos + j + 1] = hs[12];
968 }
969 if(k < size)
970 memset(§_data[sdatapos + k], '\0', size - k);
971 break;
972 case 2:
973 k = 0;
974 while(k < size)
975 {
976 uint16_t len = imagebuf[offset];
977 uint16_t rep = imagebuf[offset + 1];
978 offset += 2;
979 if(!len)
980 {
981 memcpy(§_data[sdatapos + k], &imagebuf[offset], rep);
982 offset += rep;
983 k += rep;
984 }
985 else
986 {
987 len = (1 << len);
988 rep = len * rep;
989 rep = ((rep + k) <= size) ? rep : (size - k);
990 for(j = 0; j < rep; j += len)
991 memcpy(§_data[sdatapos + j + k], &imagebuf[offset], len);
992 k += rep;
993 offset += len;
994 }
995 }
996 break;
997 }
998 }
999
1000 sects[i].actual_size = size;
1001
1002 if(size)
1003 {
1004 sects[i].data = §_data[sdatapos];
1005 sdatapos += size;
1006 }
1007 else
1008 sects[i].data = nullptr;
1009 }
1010 track_count = track;
1011
1012 if(fm)
1013 build_pc_track_fm(track, head, image, base_cell_count, track_spt, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size));
1014 else
1015 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));
1016
1017 track_spt = imagebuf[offset];
1018 }
1019 if((track_count > 50) && (form_factor == floppy_image::FF_525)) // ?
1020 {
1021 if(image->get_variant() == floppy_image::DSDD)
1022 image->set_variant(floppy_image::DSQD);
1023 else if(image->get_variant() == floppy_image::SSDD)
1024 image->set_variant(floppy_image::SSQD);
1025 }
1026 return true;
1027 }
1028
1029
save(io_generic * io,floppy_image * image)1030 bool td0_format::save(io_generic *io, floppy_image *image)
1031 {
1032 return false;
1033 }
1034
supports_save() const1035 bool td0_format::supports_save() const
1036 {
1037 return false;
1038 }
1039
1040 const floppy_format_type FLOPPY_TD0_FORMAT = &floppy_image_format_creator<td0_format>;
1041