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(&sect_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(&sect_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(&sect_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(&sect_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 = &sect_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