1 // license:BSD-3-Clause
2 // copyright-holders:Olivier Galibert
3 #include "ipf_dsk.h"
4
5 #include <cassert>
6
7
8 const floppy_format_type FLOPPY_IPF_FORMAT = &floppy_image_format_creator<ipf_format>;
9
ipf_format()10 ipf_format::ipf_format() :
11 tinfos(),
12 tcount(0),
13 type(0),
14 release(0),
15 revision(0),
16 encoder_type(0),
17 encoder_revision(0),
18 origin(0),
19 min_cylinder(0),
20 max_cylinder(0),
21 min_head(0),
22 max_head(0),
23 credit_day(0),
24 credit_time(0)
25 {
26 }
27
name() const28 const char *ipf_format::name() const
29 {
30 return "ipf";
31 }
32
description() const33 const char *ipf_format::description() const
34 {
35 return "SPS floppy disk image";
36 }
37
extensions() const38 const char *ipf_format::extensions() const
39 {
40 return "ipf";
41 }
42
supports_save() const43 bool ipf_format::supports_save() const
44 {
45 return false;
46 }
47
identify(io_generic * io,uint32_t form_factor)48 int ipf_format::identify(io_generic *io, uint32_t form_factor)
49 {
50 static const uint8_t refh[12] = { 0x43, 0x41, 0x50, 0x53, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0xd5, 0x73, 0xba };
51 uint8_t h[12];
52 io_generic_read(io, h, 0, 12);
53
54 if(!memcmp(h, refh, 12))
55 return 100;
56
57 return 0;
58 }
59
load(io_generic * io,uint32_t form_factor,floppy_image * image)60 bool ipf_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
61 {
62 uint64_t size = io_generic_size(io);
63 std::vector<uint8_t> data(size);
64 io_generic_read(io, &data[0], 0, size);
65 bool res = parse(data, image);
66 return res;
67 }
68
r32(const uint8_t * p)69 uint32_t ipf_format::r32(const uint8_t *p)
70 {
71 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
72 }
73
74
rb(const uint8_t * & p,int count)75 uint32_t ipf_format::rb(const uint8_t *&p, int count)
76 {
77 uint32_t v = 0;
78 for(int i=0; i<count; i++)
79 v = (v << 8) | *p++;
80 return v;
81 }
82
crc32r(const uint8_t * data,uint32_t size)83 uint32_t ipf_format::crc32r(const uint8_t *data, uint32_t size)
84 {
85 // Reversed crc32
86 uint32_t crc = 0xffffffff;
87 for(uint32_t i=0; i != size; i++) {
88 crc = crc ^ data[i];
89 for(int j=0; j<8; j++)
90 if(crc & 1)
91 crc = (crc >> 1) ^ 0xedb88320;
92 else
93 crc = crc >> 1;
94 }
95 return ~crc;
96 }
97
parse(std::vector<uint8_t> & data,floppy_image * image)98 bool ipf_format::parse(std::vector<uint8_t> &data, floppy_image *image)
99 {
100 image->set_variant(floppy_image::DSDD); // Not handling anything else yet
101 tcount = 84*2+1; // Usual max
102 tinfos.resize(tcount);
103 bool res = scan_all_tags(data);
104 if(res)
105 res = generate_tracks(image);
106 tinfos.clear();
107 return res;
108 }
109
parse_info(const uint8_t * info)110 bool ipf_format::parse_info(const uint8_t *info)
111 {
112 type = r32(info+12);
113 if(type != 1)
114 return false;
115 encoder_type = r32(info+16); // 1 for CAPS, 2 for SPS
116 encoder_revision = r32(info+20); // 1 always
117 release = r32(info+24);
118 revision = r32(info+28);
119 origin = r32(info+32); // Original source reference
120 min_cylinder = r32(info+36);
121 max_cylinder = r32(info+40);
122 min_head = r32(info+44);
123 max_head = r32(info+48);
124 credit_day = r32(info+52); // year*1e4 + month*1e2 + day
125 credit_time = r32(info+56); // hour*1e7 + min*1e5 + sec*1e3 + msec
126 for(int i=0; i<4; i++)
127 platform[i] = r32(info+60+4*i);
128 for(int i=0; i<5; i++)
129 extra[i] = r32(info+76+4*i);
130 return true;
131 }
132
get_index(uint32_t idx)133 ipf_format::track_info *ipf_format::get_index(uint32_t idx)
134 {
135 if(idx > 1000)
136 return nullptr;
137 if(idx >= tcount) {
138 tinfos.resize(idx+1);
139 tcount = idx+1;
140 }
141
142 return &tinfos[idx];
143 }
144
parse_imge(const uint8_t * imge)145 bool ipf_format::parse_imge(const uint8_t *imge)
146 {
147 track_info *t = get_index(r32(imge+64));
148 if(!t)
149 return false;
150
151 t->info_set = true;
152
153 t->cylinder = r32(imge+12);
154 if(t->cylinder < min_cylinder || t->cylinder > max_cylinder)
155 return false;
156
157 t->head = r32(imge+16);
158 if(t->head < min_head || t->head > max_head)
159 return false;
160
161 t->type = r32(imge+20);
162 t->sigtype = r32(imge+24); // 1 for 2us cells, no other value valid
163 t->size_bytes = r32(imge+28);
164 t->index_bytes = r32(imge+32);
165 t->index_cells = r32(imge+36);
166 t->datasize_cells = r32(imge+40);
167 t->gapsize_cells = r32(imge+44);
168 t->size_cells = r32(imge+48);
169 t->block_count = r32(imge+52);
170 t->process = r32(imge+56); // encoder process, always 0
171 t->weak_bits = r32(imge+60);
172 t->reserved[0] = r32(imge+68);
173 t->reserved[1] = r32(imge+72);
174 t->reserved[2] = r32(imge+76);
175
176 return true;
177 }
178
parse_data(const uint8_t * data,uint32_t & pos,uint32_t max_extra_size)179 bool ipf_format::parse_data(const uint8_t *data, uint32_t &pos, uint32_t max_extra_size)
180 {
181 track_info *t = get_index(r32(data+24));
182 if(!t)
183 return false;
184
185 t->data_size_bits = r32(data+16);
186 t->data = data+28;
187 t->data_size = r32(data+12);
188 if(t->data_size > max_extra_size)
189 return false;
190 if(crc32r(t->data, t->data_size) != r32(data+20))
191 return false;
192 pos += t->data_size;
193 return true;
194 }
195
scan_one_tag(std::vector<uint8_t> & data,uint32_t & pos,uint8_t * & tag,uint32_t & tsize)196 bool ipf_format::scan_one_tag(std::vector<uint8_t> &data, uint32_t &pos, uint8_t *&tag, uint32_t &tsize)
197 {
198 if(data.size()-pos < 12)
199 return false;
200 tag = &data[pos];
201 tsize = r32(tag+4);
202 if(data.size()-pos < tsize)
203 return false;
204 uint32_t crc = r32(tag+8);
205 tag[8] = tag[9] = tag[10] = tag[11] = 0;
206 if(crc32r(tag, tsize) != crc)
207 return false;
208 pos += tsize;
209 return true;
210 }
211
scan_all_tags(std::vector<uint8_t> & data)212 bool ipf_format::scan_all_tags(std::vector<uint8_t> &data)
213 {
214 uint32_t pos = 0;
215 uint32_t size = data.size();
216 while(pos != size) {
217 uint8_t *tag;
218 uint32_t tsize;
219
220 if(!scan_one_tag(data, pos, tag, tsize))
221 return false;
222
223 switch(r32(tag)) {
224 case 0x43415053: // CAPS
225 if(tsize != 12)
226 return false;
227 break;
228
229 case 0x494e464f: // INFO
230 if(tsize != 96)
231 return false;
232 if(!parse_info(tag))
233 return false;
234 break;
235
236 case 0x494d4745: // IMGE
237 if(tsize != 80)
238 return false;
239 if(!parse_imge(tag))
240 return false;
241 break;
242
243 case 0x44415441: // DATA
244 if(tsize != 28)
245 return false;
246 if(!parse_data(tag, pos, size-pos))
247 return false;
248 break;
249
250 default:
251 return false;
252 }
253 }
254 return true;
255 }
256
generate_tracks(floppy_image * image)257 bool ipf_format::generate_tracks(floppy_image *image)
258 {
259 for(uint32_t i = 0; i != tcount; i++) {
260 track_info *t = &tinfos[i];
261 if(t->info_set && t->data) {
262 if(!generate_track(t, image))
263 return false;
264
265 } else if(t->info_set || t->data)
266 return false;
267 }
268 return true;
269 }
270
rotate(std::vector<uint32_t> & track,uint32_t offset,uint32_t size)271 void ipf_format::rotate(std::vector<uint32_t> &track, uint32_t offset, uint32_t size)
272 {
273 uint32_t done = 0;
274 for(uint32_t bpos=0; done < size; bpos++) {
275 uint32_t pos = bpos;
276 uint32_t hold = track[pos];
277 for(;;) {
278 uint32_t npos = pos+offset;
279 if(npos >= size)
280 npos -= size;
281 if(npos == bpos)
282 break;
283 track[pos] = track[npos];
284 pos = npos;
285 done++;
286 }
287 track[pos] = hold;
288 done++;
289 }
290 }
291
mark_track_splice(std::vector<uint32_t> & track,uint32_t offset,uint32_t size)292 void ipf_format::mark_track_splice(std::vector<uint32_t> &track, uint32_t offset, uint32_t size)
293 {
294 for(int i=0; i<3; i++) {
295 uint32_t pos = (offset + i) % size;
296 uint32_t v = track[pos];
297 if((v & floppy_image::MG_MASK) == MG_0)
298 v = (v & floppy_image::TIME_MASK) | MG_1;
299 else if((v & floppy_image::MG_MASK) == MG_1)
300 v = (v & floppy_image::TIME_MASK) | MG_0;
301 track[pos] = v;
302 }
303 }
304
timing_set(std::vector<uint32_t> & track,uint32_t start,uint32_t end,uint32_t time)305 void ipf_format::timing_set(std::vector<uint32_t> &track, uint32_t start, uint32_t end, uint32_t time)
306 {
307 for(uint32_t i=start; i != end; i++)
308 track[i] = (track[i] & floppy_image::MG_MASK) | time;
309 }
310
generate_timings(track_info * t,std::vector<uint32_t> & track,const std::vector<uint32_t> & data_pos,const std::vector<uint32_t> & gap_pos)311 bool ipf_format::generate_timings(track_info *t, std::vector<uint32_t> &track, const std::vector<uint32_t> &data_pos, const std::vector<uint32_t> &gap_pos)
312 {
313 timing_set(track, 0, t->size_cells, 2000);
314
315 switch(t->type) {
316 case 2: break;
317
318 case 3:
319 if(t->block_count >= 4)
320 timing_set(track, gap_pos[3], data_pos[4], 1890);
321 if(t->block_count >= 5) {
322 timing_set(track, data_pos[4], gap_pos[4], 1890);
323 timing_set(track, gap_pos[4], data_pos[5], 1990);
324 }
325 if(t->block_count >= 6) {
326 timing_set(track, data_pos[5], gap_pos[5], 1990);
327 timing_set(track, gap_pos[5], data_pos[6], 2090);
328 }
329 if(t->block_count >= 7)
330 timing_set(track, data_pos[6], gap_pos[6], 2090);
331 break;
332
333 case 4:
334 timing_set(track, gap_pos[t->block_count-1], data_pos[0], 1890);
335 timing_set(track, data_pos[0], gap_pos[0], 1890);
336 timing_set(track, gap_pos[0], data_pos[1], 1990);
337 if(t->block_count >= 2) {
338 timing_set(track, data_pos[1], gap_pos[1], 1990);
339 timing_set(track, gap_pos[1], data_pos[2], 2090);
340 }
341 if(t->block_count >= 3)
342 timing_set(track, data_pos[2], gap_pos[2], 2090);
343 break;
344
345 case 5:
346 if(t->block_count >= 6)
347 timing_set(track, data_pos[5], gap_pos[5], 2100);
348 break;
349
350 case 6:
351 if(t->block_count >= 2)
352 timing_set(track, data_pos[1], gap_pos[1], 2200);
353 if(t->block_count >= 3)
354 timing_set(track, data_pos[2], gap_pos[2], 1800);
355 break;
356
357 case 7:
358 if(t->block_count >= 2)
359 timing_set(track, data_pos[1], gap_pos[1], 2100);
360 break;
361
362 case 8:
363 if(t->block_count >= 2)
364 timing_set(track, data_pos[1], gap_pos[1], 2200);
365 if(t->block_count >= 3)
366 timing_set(track, data_pos[2], gap_pos[2], 2100);
367 if(t->block_count >= 5)
368 timing_set(track, data_pos[4], gap_pos[4], 1900);
369 if(t->block_count >= 6)
370 timing_set(track, data_pos[5], gap_pos[5], 1800);
371 if(t->block_count >= 7)
372 timing_set(track, data_pos[6], gap_pos[6], 1700);
373 break;
374
375 case 9: {
376 uint32_t mask = r32(t->data + 32*t->block_count + 12);
377 for(uint32_t i=1; i<t->block_count; i++)
378 timing_set(track, data_pos[i], gap_pos[i], mask & (1 << (i-1)) ? 1900 : 2100);
379 break;
380 }
381
382 default:
383 return false;
384 }
385
386 return true;
387 }
388
generate_track(track_info * t,floppy_image * image)389 bool ipf_format::generate_track(track_info *t, floppy_image *image)
390 {
391 if(!t->size_cells)
392 return true;
393
394 if(t->data_size < 32*t->block_count)
395 return false;
396
397 // Annoyingly enough, too small gaps are ignored, changing the
398 // total track size. Artifact stemming from the byte-only support
399 // of old times?
400 t->size_cells = block_compute_real_size(t);
401
402 if(t->index_cells >= t->size_cells)
403 return false;
404
405 std::vector<uint32_t> track(t->size_cells);
406 std::vector<uint32_t> data_pos(t->block_count+1);
407 std::vector<uint32_t> gap_pos(t->block_count);
408 std::vector<uint32_t> splice_pos(t->block_count);
409
410 bool context = false;
411 uint32_t pos = 0;
412 for(uint32_t i = 0; i != t->block_count; i++) {
413 if(!generate_block(t, i, i == t->block_count-1 ? t->size_cells - t->index_cells : 0xffffffff, track, pos, data_pos[i], gap_pos[i], splice_pos[i], context)) {
414 return false;
415 }
416 }
417 if(pos != t->size_cells) {
418 return false;
419 }
420
421 data_pos[t->block_count] = pos;
422
423 mark_track_splice(track, splice_pos[t->block_count-1], t->size_cells);
424
425 if(!generate_timings(t, track, data_pos, gap_pos)) {
426 return false;
427 }
428
429 if(t->index_cells)
430 rotate(track, t->size_cells - t->index_cells, t->size_cells);
431
432 generate_track_from_levels(t->cylinder, t->head, track, splice_pos[t->block_count-1] + t->index_cells, image);
433
434 return true;
435 }
436
track_write_raw(std::vector<uint32_t>::iterator & tpos,const uint8_t * data,uint32_t cells,bool & context)437 void ipf_format::track_write_raw(std::vector<uint32_t>::iterator &tpos, const uint8_t *data, uint32_t cells, bool &context)
438 {
439 for(uint32_t i=0; i != cells; i++)
440 *tpos++ = data[i>>3] & (0x80 >> (i & 7)) ? MG_1 : MG_0;
441 if(cells)
442 context = tpos[-1] == MG_1;
443 }
444
track_write_mfm(std::vector<uint32_t>::iterator & tpos,const uint8_t * data,uint32_t start_offset,uint32_t patlen,uint32_t cells,bool & context)445 void ipf_format::track_write_mfm(std::vector<uint32_t>::iterator &tpos, const uint8_t *data, uint32_t start_offset, uint32_t patlen, uint32_t cells, bool &context)
446 {
447 patlen *= 2;
448 for(uint32_t i=0; i != cells; i++) {
449 uint32_t pos = (i + start_offset) % patlen;
450 bool bit = data[pos>>4] & (0x80 >> ((pos >> 1) & 7));
451 if(pos & 1) {
452 *tpos++ = bit ? MG_1 : MG_0;
453 context = bit;
454 } else
455 *tpos++ = context || bit ? MG_0 : MG_1;
456 }
457 }
458
track_write_weak(std::vector<uint32_t>::iterator & tpos,uint32_t cells)459 void ipf_format::track_write_weak(std::vector<uint32_t>::iterator &tpos, uint32_t cells)
460 {
461 for(uint32_t i=0; i != cells; i++)
462 *tpos++ = floppy_image::MG_N;
463 }
464
generate_block_data(const uint8_t * data,const uint8_t * dlimit,std::vector<uint32_t>::iterator tpos,std::vector<uint32_t>::iterator tlimit,bool & context)465 bool ipf_format::generate_block_data(const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator tpos, std::vector<uint32_t>::iterator tlimit, bool &context)
466 {
467 for(;;) {
468 if(data >= dlimit)
469 return false;
470 uint8_t val = *data++;
471 if((val >> 5) > dlimit-data)
472 return false;
473 uint32_t param = rb(data, val >> 5);
474 uint32_t tleft = tlimit - tpos;
475 switch(val & 0x1f) {
476 case 0: // End of description
477 return !tleft;
478
479 case 1: // Raw bytes
480 if(8*param > tleft)
481 return false;
482 track_write_raw(tpos, data, 8*param, context);
483 data += param;
484 break;
485
486 case 2: // MFM-decoded data bytes
487 case 3: // MFM-decoded gap bytes
488 if(16*param > tleft)
489 return false;
490 track_write_mfm(tpos, data, 0, 8*param, 16*param, context);
491 data += param;
492 break;
493
494 case 5: // Weak bytes
495 if(16*param > tleft)
496 return false;
497 track_write_weak(tpos, 16*param);
498 context = 0;
499 break;
500
501 default:
502 return false;
503 }
504 }
505 }
506
generate_block_gap_0(uint32_t gap_cells,uint8_t pattern,uint32_t & spos,uint32_t ipos,std::vector<uint32_t>::iterator & tpos,bool & context)507 bool ipf_format::generate_block_gap_0(uint32_t gap_cells, uint8_t pattern, uint32_t &spos, uint32_t ipos, std::vector<uint32_t>::iterator &tpos, bool &context)
508 {
509 spos = ipos >= 16 && ipos+16 <= gap_cells ? ipos : gap_cells >> 1;
510 track_write_mfm(tpos, &pattern, 0, 8, spos, context);
511 uint32_t delta = 0;
512 if(gap_cells & 1) {
513 *tpos++ = MG_0;
514 delta++;
515 }
516 track_write_mfm(tpos, &pattern, spos+delta-gap_cells, 8, gap_cells-spos-delta, context);
517 return true;
518 }
519
gap_description_to_reserved_size(const uint8_t * & data,const uint8_t * dlimit,uint32_t & res_size)520 bool ipf_format::gap_description_to_reserved_size(const uint8_t *&data, const uint8_t *dlimit, uint32_t &res_size)
521 {
522 res_size = 0;
523 for(;;) {
524 if(data >= dlimit)
525 return false;
526 uint8_t val = *data++;
527 if((val >> 5) > dlimit-data)
528 return false;
529 uint32_t param = rb(data, val >> 5);
530 switch(val & 0x1f) {
531 case 0:
532 return true;
533 case 1:
534 res_size += param*2;
535 break;
536 case 2:
537 data += (param+7)/8;
538 break;
539 default:
540 return false;
541 }
542 }
543 }
544
generate_gap_from_description(const uint8_t * & data,const uint8_t * dlimit,std::vector<uint32_t>::iterator tpos,uint32_t size,bool pre,bool & context)545 bool ipf_format::generate_gap_from_description(const uint8_t *&data, const uint8_t *dlimit, std::vector<uint32_t>::iterator tpos, uint32_t size, bool pre, bool &context)
546 {
547 const uint8_t *data1 = data;
548 uint32_t res_size;
549 if(!gap_description_to_reserved_size(data1, dlimit, res_size))
550 return false;
551
552 if(res_size > size)
553 return false;
554 uint8_t pattern[16];
555 memset(pattern, 0, sizeof(pattern));
556 uint32_t pattern_size = 0;
557
558 uint32_t pos = 0, block_size = 0;
559 for(;;) {
560 uint8_t val = *data++;
561 uint32_t param = rb(data, val >> 5);
562 switch(val & 0x1f) {
563 case 0:
564 return size == pos;
565
566 case 1:
567 if(block_size)
568 return false;
569 block_size = param*2;
570 pattern_size = 0;
571 break;
572
573 case 2:
574 // You can't have a pattern at the start of a pre-slice
575 // gap if there's a size afterwards
576 if(pre && res_size && !block_size)
577 return false;
578 // You can't have two consecutive patterns
579 if(pattern_size)
580 return false;
581 pattern_size = param;
582 if(pattern_size > sizeof(pattern)*8)
583 return false;
584
585 memcpy(pattern, data, (pattern_size+7)/8);
586 data += (pattern_size+7)/8;
587 if(pre) {
588 if(!block_size)
589 block_size = size;
590 else if(pos + block_size == res_size)
591 block_size = size - pos;
592 if(pos + block_size > size)
593 return false;
594 // printf("pat=%02x size=%d pre\n", pattern[0], block_size);
595 track_write_mfm(tpos, pattern, 0, pattern_size, block_size, context);
596 pos += block_size;
597 } else {
598 if(pos == 0 && block_size && res_size != size)
599 block_size = size - (res_size-block_size);
600 if(!block_size)
601 block_size = size - res_size;
602 if(pos + block_size > size)
603 return false;
604 // printf("pat=%02x block_size=%d size=%d res_size=%d post\n", pattern[0], block_size, size, res_size);
605 track_write_mfm(tpos, pattern, -block_size, pattern_size, block_size, context);
606 pos += block_size;
607 }
608 block_size = 0;
609 break;
610 }
611 }
612 }
613
614
generate_block_gap_1(uint32_t gap_cells,uint32_t & spos,uint32_t ipos,const uint8_t * data,const uint8_t * dlimit,std::vector<uint32_t>::iterator & tpos,bool & context)615 bool ipf_format::generate_block_gap_1(uint32_t gap_cells, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator &tpos, bool &context)
616 {
617 if(ipos >= 16 && ipos < gap_cells-16)
618 spos = ipos;
619 else
620 spos = 0;
621 return generate_gap_from_description(data, dlimit, tpos, gap_cells, true, context);
622 }
623
generate_block_gap_2(uint32_t gap_cells,uint32_t & spos,uint32_t ipos,const uint8_t * data,const uint8_t * dlimit,std::vector<uint32_t>::iterator & tpos,bool & context)624 bool ipf_format::generate_block_gap_2(uint32_t gap_cells, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator &tpos, bool &context)
625 {
626 if(ipos >= 16 && ipos < gap_cells-16)
627 spos = ipos;
628 else
629 spos = gap_cells;
630 return generate_gap_from_description(data, dlimit, tpos, gap_cells, false, context);
631 }
632
generate_block_gap_3(uint32_t gap_cells,uint32_t & spos,uint32_t ipos,const uint8_t * data,const uint8_t * dlimit,std::vector<uint32_t>::iterator & tpos,bool & context)633 bool ipf_format::generate_block_gap_3(uint32_t gap_cells, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator &tpos, bool &context)
634 {
635 if(ipos >= 16 && ipos < gap_cells-16)
636 spos = ipos;
637 else {
638 uint32_t presize, postsize;
639 const uint8_t *data1 = data;
640 if(!gap_description_to_reserved_size(data1, dlimit, presize))
641 return false;
642 if(!gap_description_to_reserved_size(data1, dlimit, postsize))
643 return false;
644 if(presize+postsize > gap_cells)
645 return false;
646
647 spos = presize + (gap_cells - presize - postsize)/2;
648 }
649 if(!generate_gap_from_description(data, dlimit, tpos, spos, true, context))
650 return false;
651 uint32_t delta = 0;
652 if(gap_cells & 1) {
653 tpos[spos] = MG_0;
654 delta++;
655 }
656
657 return generate_gap_from_description(data, dlimit, tpos+spos+delta, gap_cells - spos - delta, false, context);
658 }
659
generate_block_gap(uint32_t gap_type,uint32_t gap_cells,uint8_t pattern,uint32_t & spos,uint32_t ipos,const uint8_t * data,const uint8_t * dlimit,std::vector<uint32_t>::iterator tpos,bool & context)660 bool ipf_format::generate_block_gap(uint32_t gap_type, uint32_t gap_cells, uint8_t pattern, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator tpos, bool &context)
661 {
662 switch(gap_type) {
663 case 0:
664 return generate_block_gap_0(gap_cells, pattern, spos, ipos, tpos, context);
665 case 1:
666 return generate_block_gap_1(gap_cells, spos, ipos, data, dlimit, tpos, context);
667 case 2:
668 return generate_block_gap_2(gap_cells, spos, ipos, data, dlimit, tpos, context);
669 case 3:
670 return generate_block_gap_3(gap_cells, spos, ipos, data, dlimit, tpos, context);
671 default:
672 return false;
673 }
674 }
675
generate_block(track_info * t,uint32_t idx,uint32_t ipos,std::vector<uint32_t> & track,uint32_t & pos,uint32_t & dpos,uint32_t & gpos,uint32_t & spos,bool & context)676 bool ipf_format::generate_block(track_info *t, uint32_t idx, uint32_t ipos, std::vector<uint32_t> &track, uint32_t &pos, uint32_t &dpos, uint32_t &gpos, uint32_t &spos, bool &context)
677 {
678 const uint8_t *data = t->data;
679 const uint8_t *data_end = t->data + t->data_size;
680 const uint8_t *thead = data + 32*idx;
681 uint32_t data_cells = r32(thead);
682 uint32_t gap_cells = r32(thead+4);
683
684 if(gap_cells < 8)
685 gap_cells = 0;
686
687 // +8 = gap description offset / datasize in bytes (when gap type = 0)
688 // +12 = 1 / gap size in bytes (when gap type = 0)
689 // +16 = 1
690 // +20 = gap type
691 // +24 = type 0 gap pattern (8 bits) / speed mask for sector 0 track type 9
692 // +28 = data description offset
693
694 dpos = pos;
695 gpos = dpos + data_cells;
696 pos = gpos + gap_cells;
697 if(pos > t->size_cells)
698 return false;
699 if(!generate_block_data(data + r32(thead+28), data_end, track.begin()+dpos, track.begin()+gpos, context))
700 return false;
701 if(!generate_block_gap(r32(thead+20), gap_cells, r32(thead+24), spos, ipos > gpos ? ipos-gpos : 0, data + r32(thead+8), data_end, track.begin()+gpos, context))
702 return false;
703 spos += gpos;
704
705 return true;
706 }
707
block_compute_real_size(track_info * t)708 uint32_t ipf_format::block_compute_real_size(track_info *t)
709 {
710 uint32_t size = 0;
711 const uint8_t *thead = t->data;
712 for(unsigned int i=0; i != t->block_count; i++) {
713 uint32_t data_cells = r32(thead);
714 uint32_t gap_cells = r32(thead+4);
715 if(gap_cells < 8)
716 gap_cells = 0;
717
718 size += data_cells + gap_cells;
719 thead += 32;
720 }
721 return size;
722 }
723