1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 #include <deark-private.h>
6 DE_DECLARE_MODULE(de_module_atari_cas
);
7 DE_DECLARE_MODULE(de_module_atr
);
8 DE_DECLARE_MODULE(de_module_msa
);
9 DE_DECLARE_MODULE(de_module_pasti
);
11 typedef struct localctx_struct
{
15 static void do_cas(deark
*c
)
24 if(pos
>= c
->infile
->len
-8) break; // Reached end of file
26 de_read(chunk_id
, pos
, 4);
27 chunk_len
= de_getu16le(pos
+4);
28 chunk_extra
= de_getu16le(pos
+6);
30 de_dbg(c
, "chunk at %d, data_len=%d, extra=%d", (int)pos
, (int)chunk_len
,
39 static void de_run_cas(deark
*c
, de_module_params
*mparams
)
42 de_err(c
, "Atari CAS format is not supported");
45 static int de_identify_cas(deark
*c
)
50 if(!de_memcmp(buf
, "FUJI", 4)) {
51 // Note - Make sure Fujifilm RAF has higher confidence.
57 void de_module_atari_cas(deark
*c
, struct deark_module_info
*mi
)
60 mi
->desc
= "Atari CAS tape image";
61 mi
->run_fn
= de_run_cas
;
62 mi
->identify_fn
= de_identify_cas
;
63 mi
->flags
|= DE_MODFLAG_NONWORKING
;
66 // --------------------------------------------
68 static int get_sector_offset_and_size(deark
*c
, lctx
*d
,
69 i64 sector_num
, i64
*sector_offset
, i64
*sector_size
)
71 if(sector_num
<1) return 0;
73 *sector_size
= d
->sector_size
;
74 *sector_offset
= (sector_num
-1) * d
->sector_size
;
76 if(d
->sector_size
==256) {
77 // The first 3 sectors are 128 bytes
80 *sector_offset
= (sector_num
-1) * 128;
83 *sector_offset
-= 3*128;
90 static void do_extract_file_contents(deark
*c
, lctx
*d
, dbuf
*inf
, dbuf
*outf
,
91 i64 starting_sector
, i64 sector_count
)
93 i64 sectors_extracted
= 0;
101 cur_sector
= starting_sector
;
102 while(sectors_extracted
< sector_count
) {
103 get_sector_offset_and_size(c
, d
, cur_sector
, §or_pos
, §or_size
);
104 de_dbg(c
, "sector %d, #%d, at %d", (int)sectors_extracted
, (int)cur_sector
, (int)sector_pos
);
107 dbuf_read(inf
, mdata
, sector_pos
+ sector_size
-3, 3);
108 next_sector
= ((mdata
[0]&0x3) << 8) | mdata
[1];
110 // TODO: Some documentation says the high bit of mdata[2] is a
111 // "short flag" that indicates that the other bits are valid. But I haven't
112 // found any files that use it. And it can't work with sectors > 128 bytes.
113 nbytes
= (i64
)mdata
[2];
115 nbytes
= nbytes
& 0x7f;
117 de_dbg(c
, "byte count: %d, next sector: %d", (int)nbytes
, (int)next_sector
);
119 dbuf_copy(inf
, sector_pos
, nbytes
, outf
);
121 de_dbg_indent(c
, -1);
123 cur_sector
= next_sector
;
124 if(next_sector
<1) break;
128 static void do_directory_entry(deark
*c
, lctx
*d
, dbuf
*f
, i64 pos
)
133 de_ucstring
*fn_u
= NULL
;
134 de_ucstring
*fn_ext
= NULL
;
137 de_ext_encoding fn_encoding
;
139 flags
= dbuf_getbyte(f
, pos
);
140 de_dbg(c
, "flags: 0x%02x", (unsigned int)flags
);
141 if((flags
&0x40)==0) {
142 // Unused or deleted directory entry
146 sector_count
= dbuf_getu16le(f
, pos
+1);
147 starting_sector
= dbuf_getu16le(f
, pos
+3);
148 de_dbg(c
, "sector start: %d, count: %d", (int)starting_sector
, (int)sector_count
);
150 if(starting_sector
<1) goto done
;
152 if(starting_sector
> 720) {
153 de_err(c
, "Bad starting sector: %d", (int)starting_sector
);
156 if(sector_count
> 720) {
157 de_err(c
, "Bad file size: %d blocks", (int)sector_count
);
161 fn_u
= ucstring_create(c
);
162 fn_ext
= ucstring_create(c
);
164 // TODO: Use correct Atari encoding.
165 fn_encoding
= DE_EXTENC_MAKE(DE_ENCODING_ASCII
, DE_ENCSUBTYPE_PRINTABLE
);
166 dbuf_read_to_ucstring(f
, pos
+5, 8, fn_u
, 0,fn_encoding
);
167 dbuf_read_to_ucstring(f
, pos
+13, 3, fn_ext
, 0, fn_encoding
);
168 de_dbg(c
, "filename: \"%s.%s\"",
169 ucstring_getpsz(fn_u
), ucstring_getpsz(fn_ext
));
170 ucstring_strip_trailing_spaces(fn_u
);
171 ucstring_strip_trailing_spaces(fn_ext
);
173 ucstring_append_char(fn_u
, '_');
175 if(ucstring_isnonempty(fn_ext
)) {
176 ucstring_append_char(fn_u
, '.');
177 ucstring_append_ucstring(fn_u
, fn_ext
);
180 fi
= de_finfo_create(c
);
181 de_finfo_set_name_from_ucstring(c
, fi
, fn_u
, 0);
182 fi
->original_filename_flag
= 1;
184 outf
= dbuf_create_output_file(c
, NULL
, fi
, 0);
186 do_extract_file_contents(c
, d
, f
, outf
, starting_sector
, sector_count
);
189 de_finfo_destroy(c
, fi
);
190 ucstring_destroy(fn_u
);
191 ucstring_destroy(fn_ext
);
195 static void do_atr_disk_image(deark
*c
, lctx
*d
, dbuf
*f
)
202 i64 entries_per_sector
;
205 if(d
->sector_size
!=128 && d
->sector_size
!=256) {
206 de_err(c
, "Unsupported sector size: %d", (int)d
->sector_size
);
209 entries_per_sector
= d
->sector_size
/ 16;
211 for(sector_index
=0; sector_index
<8; sector_index
++) {
212 get_sector_offset_and_size(c
, d
, 361+sector_index
, §or_pos
, §or_size
);
213 if(sector_pos
+ sector_size
> f
->len
) break;
214 de_dbg(c
, "directory sector %d at %d", (int)sector_index
, (int)sector_pos
);
216 for(entry_index
=0; entry_index
<entries_per_sector
; entry_index
++) {
217 entrypos
= sector_pos
+ 16*entry_index
;
219 // Peek at the flags byte, just to avoid printing debugging info
220 // about nonexistent files
221 flags
= dbuf_getbyte(f
, entrypos
);
222 if(flags
==0x00) continue;
224 de_dbg(c
, "directory sector %d entry %d at %d", (int)sector_index
,
225 (int)entry_index
, (int)entrypos
);
227 do_directory_entry(c
, d
, f
, entrypos
);
228 de_dbg_indent(c
, -1);
230 de_dbg_indent(c
, -1);
234 static void do_atr(deark
*c
, lctx
*d
)
237 i64 image_size_hi
, image_size_lo
; // In 16-byte "paragraphs"
238 i64 image_size_bytes
;
239 dbuf
*diskimg
= NULL
;
243 image_size_lo
= de_getu16le(pos
+2);
244 d
->sector_size
= de_getu16le(pos
+4);
245 image_size_hi
= de_getu16le(pos
+6);
246 image_size_bytes
= 16*(image_size_lo
+ 65536*image_size_hi
);
248 de_dbg(c
, "image size=%d bytes, sector size=%d", (int)image_size_bytes
, (int)d
->sector_size
);
250 diskimg
= dbuf_open_input_subfile(c
->infile
, 16, c
->infile
->len
-16);
252 do_atr_disk_image(c
, d
, diskimg
);
257 static void de_run_atr(deark
*c
, de_module_params
*mparams
)
261 d
= de_malloc(c
, sizeof(lctx
));
268 static int de_identify_atr(deark
*c
)
273 if(buf
[0]==0x96 && buf
[1]==0x02) {
279 void de_module_atr(deark
*c
, struct deark_module_info
*mi
)
282 mi
->desc
= "ATR Atari floppy disk image";
283 mi
->run_fn
= de_run_atr
;
284 mi
->identify_fn
= de_identify_atr
;
287 ////////////////////////////////////////////////////////
288 // MSA - Magic Shadow Archiver - Atari ST disk image
290 enum atarist_outfmt
{
291 ATARIST_OUTFMT_FILES
= 0,
293 ATARIST_OUTFMT_UNCMSA
297 de_encoding input_encoding
;
298 enum atarist_outfmt outfmt
;
299 i64 sectors_per_track
;
303 i64 num_tracks_per_side
;
304 i64 num_tracks_total
;
305 i64 track_size
; // bytes per track per side
307 i64 total_track_sides
;
308 i64 total_track_sides_cmpr
;
309 i64 total_cmpr_bytes
;
310 i64 total_uncmpr_bytes
;
313 // Decompress one track
314 static int msa_decompress_rle(deark
*c
, struct msactx
*d
, i64 pos1
, i64 dlen
,
317 i64 endpos
= pos1
+dlen
;
326 if(outcount
>= d
->track_size
) {
328 goto done
; // Have enough output
335 b
= de_getbyte_p(&pos
);
337 dbuf_writebyte(outf
, b
);
345 b
= de_getbyte_p(&pos
);
346 count
= de_getu16be_p(&pos
);
347 if(outcount
+count
> d
->track_size
) {
348 count
= d
->track_size
- outcount
;
350 dbuf_write_run(outf
, b
, count
);
356 de_err(c
, "Decompression failed");
361 static int do_msa_track(deark
*c
, struct msactx
*d
, i64 tk
, i64 sd
, i64 pos1
, i64 dlen
, dbuf
*outf
)
365 i64 outf_startsize
= outf
->len
;
367 de_dbg2(c
, "track (t=%d, s=%d) at %"I64_FMT
", dlen=%"I64_FMT
, (int)tk
, (int)sd
, pos1
, dlen
);
369 if(dlen
> d
->track_size
) {
370 de_err(c
, "Invalid compressed track size");
373 is_compressed
= (dlen
!=d
->track_size
);
374 de_dbg2(c
, "compressed: %d", is_compressed
);
377 if(!msa_decompress_rle(c
, d
, pos1
+2, dlen
, outf
)) goto done
;
378 d
->total_track_sides_cmpr
++;
381 dbuf_copy(c
->infile
, pos1
+2, dlen
, outf
);
383 d
->total_cmpr_bytes
+= dlen
;
384 d
->total_track_sides
++;
386 dbuf_truncate(outf
, outf_startsize
+ d
->track_size
);
391 de_dbg_indent(c
, -1);
395 static int do_msa_header(deark
*c
, struct msactx
*d
, i64 pos1
)
400 de_dbg(c
, "header at %"I64_FMT
, pos1
);
403 d
->sectors_per_track
= de_getu16be_p(&pos
);
404 de_dbg(c
, "sectors/track: %d", (int)d
->sectors_per_track
);
405 d
->sides
= 1 + de_getu16be_p(&pos
);
406 de_dbg(c
, "sides: %d", (int)d
->sides
);
407 d
->first_track
= de_getu16be_p(&pos
);
408 de_dbg(c
, "first track: %d", (int)d
->first_track
);
409 d
->last_track
= de_getu16be_p(&pos
);
410 de_dbg(c
, "last track: %d", (int)d
->last_track
);
412 d
->num_tracks_per_side
= d
->last_track
- d
->first_track
+ 1;
413 if(d
->sides
<1 || d
->sides
>2) goto done
;
414 if(d
->sectors_per_track
<1 || d
->sectors_per_track
>30) goto done
;
415 d
->num_tracks_total
= d
->num_tracks_per_side
* d
->sides
;
416 if(d
->num_tracks_total
<1 || d
->num_tracks_total
>200) goto done
;
417 d
->track_size
= d
->sectors_per_track
* 512;
418 d
->disk_size
= d
->track_size
* d
->num_tracks_total
;
423 de_err(c
, "Bad or unsupported disk layout");
425 de_dbg_indent(c
, -1);
429 static int do_msa_tracks(deark
*c
, struct msactx
*d
, i64 pos1
, dbuf
*diskbuf
)
435 de_dbg(c
, "tracks at %"I64_FMT
, pos1
);
438 for(tk
=d
->first_track
; tk
<=d
->last_track
; tk
++) {
439 for(sd
=0; sd
<d
->sides
; sd
++) {
443 if(pos
+2 >= c
->infile
->len
) {
444 de_err(c
, "Unexpected end of file");
445 goto after_decompress
;
448 dlen
= de_getu16be_p(&pos
);
449 if(!do_msa_track(c
, d
, tk
, sd
, tkpos
, dlen
, diskbuf
)) goto done
;
456 de_dbg_indent(c
, -1);
460 static void msa_decode_fat(deark
*c
, struct msactx
*d
, dbuf
*diskbuf
)
462 de_module_params
*mparams
= NULL
;
464 mparams
= de_malloc(c
, sizeof(de_module_params
));
465 de_dbg(c
, "decoding as FAT");
467 mparams
->in_params
.codes
= "A";
468 mparams
->in_params
.input_encoding
= d
->input_encoding
;
469 de_run_module_by_id_on_slice(c
, "fat", mparams
, diskbuf
, 0, diskbuf
->len
);
470 if(mparams
->out_params
.flags
& 0x1) {
471 de_info(c
, "Note: Use \"-opt msa:toraw\" to decompress to a raw .ST file");
474 de_dbg_indent(c
, -1);
477 static void msa_extract_to_raw(deark
*c
, struct msactx
*d
, dbuf
*diskbuf
)
481 outf
= dbuf_create_output_file(c
, "st", NULL
, 0);
482 dbuf_copy(diskbuf
, 0, d
->disk_size
, outf
);
486 static void msa_extract_to_uncmsa(deark
*c
, struct msactx
*d
, dbuf
*diskbuf
)
491 outf
= dbuf_create_output_file(c
, "msa", NULL
, 0);
492 dbuf_copy(c
->infile
, 0, 10, outf
);
494 for(i
=0; i
<d
->num_tracks_total
; i
++) {
495 dbuf_writeu16be(outf
, d
->track_size
);
496 dbuf_copy(diskbuf
, i
*d
->track_size
, d
->track_size
, outf
);
502 static void de_run_msa(deark
*c
, de_module_params
*mparams
)
504 struct msactx
*d
= NULL
;
505 dbuf
*diskbuf
= NULL
;
507 d
= de_malloc(c
, sizeof(struct msactx
));
508 d
->input_encoding
= de_get_input_encoding(c
, NULL
, DE_ENCODING_ATARIST
);
510 if(de_get_ext_option_bool(c
, "msa:touncmsa", 0)) {
511 d
->outfmt
= ATARIST_OUTFMT_UNCMSA
;
513 else if(de_get_ext_option_bool(c
, "msa:toraw", 0)) {
514 d
->outfmt
= ATARIST_OUTFMT_ST
;
517 d
->outfmt
= ATARIST_OUTFMT_FILES
;
520 if(!do_msa_header(c
, d
, 0)) goto done
;
522 diskbuf
= dbuf_create_membuf(c
, d
->disk_size
, 0x1);
523 dbuf_enable_wbuffer(diskbuf
);
525 if(!do_msa_tracks(c
, d
, 10, diskbuf
)) goto done
;
527 d
->total_uncmpr_bytes
= diskbuf
->len
;
528 de_dbg(c
, "totals: %u track-sides, %u compressed",
529 (UI
)d
->total_track_sides
, (UI
)d
->total_track_sides_cmpr
);
530 de_dbg(c
, "totals: decompressed %"I64_FMT
" bytes to %"I64_FMT
,
531 d
->total_cmpr_bytes
, d
->total_uncmpr_bytes
);
533 if(d
->outfmt
==ATARIST_OUTFMT_ST
) {
534 msa_extract_to_raw(c
, d
, diskbuf
);
536 else if(d
->outfmt
==ATARIST_OUTFMT_UNCMSA
) {
537 msa_extract_to_uncmsa(c
, d
, diskbuf
);
540 msa_decode_fat(c
, d
, diskbuf
);
547 static int de_identify_msa(deark
*c
)
552 sig
= de_getu16be(0);
553 if(sig
!= 0x0e0f) return 0;
554 has_ext
= de_input_file_has_ext(c
, "msa");
555 if(has_ext
) return 100;
559 static void de_help_msa(deark
*c
)
561 de_msg(c
, "-opt msa:toraw : Extract to raw .ST format");
562 de_msg(c
, "-opt msa:touncmsa : Convert to uncompressed MSA");
565 void de_module_msa(deark
*c
, struct deark_module_info
*mi
)
568 mi
->desc
= "MSA - Atari ST floppy disk image";
569 mi
->run_fn
= de_run_msa
;
570 mi
->identify_fn
= de_identify_msa
;
571 mi
->help_fn
= de_help_msa
;
574 ////////////////////////////////////////////////////////
575 // Pasti / (.STX) - Atari ST disk image
577 #define PASTI_MAX_SECTORS_PER_TRACK 100
578 #define PASTI_MAX_TRACK_NUM 255
580 struct pasti_sector_ctx
{
583 i64 n_track
, n_head
, n_secnum
; // The sector's self-reported data
588 struct pasti_track_ctx
{
595 #define TRK_SYNC 0x0080
596 #define TRK_IMAGE 0x0040
597 #define TRK_PROT 0x0020
598 #define TRK_SECT 0x0001
602 i64 sector_descriptors_pos
;
603 i64 track_data_record_pos
;
607 de_encoding input_encoding
;
608 enum atarist_outfmt outfmt
;
614 i64 fat_bytes_per_sector
;
615 i64 fat_sectors_per_track
;
618 // Set if we can't convert the format to FAT, but maybe can continue decoding
619 // the Pasti structure.
622 i64 num_nonempty_sectors_found
;
623 i64 oob_sector_count
;
628 static void pasti_save_sector_data(deark
*c
, struct pastictx
*d
,
629 struct pasti_sector_ctx
*secctx
, i64 trknum
, i64 sidenum
)
634 if(d
->convert_errflag
|| secctx
->size_in_bytes
<=0) goto done
;
635 de_dbg2(c
, "[recording sector %d,%d,%d]", (int)trknum
, (int)sidenum
,
636 (int)secctx
->n_secnum
);
638 d
->num_nonempty_sectors_found
++;
639 if(trknum
<0 || trknum
>PASTI_MAX_TRACK_NUM
||
640 sidenum
<0 || sidenum
>=d
->fat_num_heads
||
641 secctx
->n_secnum
<1 || secctx
->n_secnum
>d
->fat_sectors_per_track
)
643 de_dbg2(c
, "[sector out of bounds]");
644 d
->oob_sector_count
++;
649 d
->diskbuf
= dbuf_create_membuf(c
, 0, 0);
653 (d
->fat_bytes_per_sector
* d
->fat_sectors_per_track
* d
->fat_num_heads
) * trknum
+
654 (d
->fat_bytes_per_sector
* d
->fat_sectors_per_track
) * sidenum
+
655 (d
->fat_bytes_per_sector
) * (secctx
->n_secnum
-1);
657 if(secctx
->size_in_bytes
> d
->fat_bytes_per_sector
) {
658 de_warn(c
, "Oversized sector");
659 len_to_copy
= d
->fat_bytes_per_sector
;
662 len_to_copy
= secctx
->size_in_bytes
;
665 dbuf_copy_at(c
->infile
, secctx
->data_offset_abs
, len_to_copy
, d
->diskbuf
, dstpos
);
671 static int do_pasti_sectors(deark
*c
, struct pastictx
*d
, struct pasti_track_ctx
*tctx
)
673 int saved_indent_level
;
677 de_dbg_indent_save(c
, &saved_indent_level
);
679 de_dbg(c
, "[%d sector descriptors at %"I64_FMT
"]", (int)tctx
->sector_count
,
680 tctx
->sector_descriptors_pos
);
683 for(secnum
=0; secnum
<tctx
->sector_count
; secnum
++) {
686 i64 pos
= tctx
->sector_descriptors_pos
+ secnum
*16;
687 struct pasti_sector_ctx secctx
;
689 de_dbg2(c
, "sector[%d] descriptor at %"I64_FMT
, (int)secnum
, pos
);
691 de_zeromem(&secctx
, sizeof(struct pasti_sector_ctx
));
692 data_offset_rel
= de_getu32le_p(&pos
);
693 secctx
.data_offset_abs
= tctx
->track_data_record_pos
+ data_offset_rel
;
694 de_dbg2(c
, "dataOffset: %"I64_FMT
" (+%"I64_FMT
"=%"I64_FMT
")", data_offset_rel
,
695 tctx
->track_data_record_pos
, secctx
.data_offset_abs
);
696 pos
+= 2; // bitPosition
697 pos
+= 2; // readTime
699 secctx
.n_track
= (i64
)de_getbyte_p(&pos
);
700 secctx
.n_head
= (i64
)de_getbyte_p(&pos
);
701 secctx
.n_secnum
= (i64
)de_getbyte_p(&pos
);
702 de_dbg2(c
, "track %d, side %d, sector %d", (int)secctx
.n_track
,
703 (int)secctx
.n_head
, (int)secctx
.n_secnum
);
704 // TODO: What should we do if the track and head are not the expected values?
707 size_code
= de_getbyte_p(&pos
);
708 if(size_code
>4) goto done
;
709 secctx
.size_in_bytes
= ((i64
)128)<<(UI
)size_code
;
710 de_dbg2(c
, "size: 0x%02x (%"I64_FMT
" bytes)", (UI
)size_code
, secctx
.size_in_bytes
);
712 secctx
.crc_reported
= (u32
)de_getu16le_p(&pos
);
713 de_dbg2(c
, "sector crc (reported): 0x%04x", (UI
)secctx
.crc_reported
);
714 secctx
.fdcFlags
= de_getbyte_p(&pos
);
715 de_dbg2(c
, "fdcFlags: 0x%02x", (UI
)secctx
.fdcFlags
);
716 pos
+= 1; // reserved
718 pasti_save_sector_data(c
, d
, &secctx
, tctx
->track_num
, tctx
->side_num
);
719 de_dbg_indent(c
, -1);
724 de_dbg_indent_restore(c
, saved_indent_level
);
728 // There's a chicken-and-egg problem, as we need information contained
729 // in the boot sector (especially the number of sectors per track),
730 // before we can effectively process the sectors.
731 // This function looks ahead to get the information. It duplicates some of
732 // the code in this module, and in the "fat" module.
733 static void pasti_find_and_read_boot_sector(deark
*c
, struct pastictx
*d
,
734 struct pasti_track_ctx
*tctx
)
737 i64 s1pos
= 0; // sector 1 abs pos, 0 if unknown
739 for(secnum
=0; secnum
<tctx
->sector_count
; secnum
++) {
742 i64 pos
= tctx
->sector_descriptors_pos
+ secnum
*16;
744 n_secnum
= (i64
)de_getbyte(pos
+ 10);
746 data_offset_rel
= de_getu32le(pos
);
747 s1pos
= tctx
->track_data_record_pos
+ data_offset_rel
;
753 de_err(c
, "Could not find boot sector");
754 d
->convert_errflag
= 1;
758 de_dbg(c
, "found boot sector; data at %"I64_FMT
, s1pos
);
760 d
->fat_bytes_per_sector
= de_getu16le(s1pos
+11);
761 de_dbg(c
, "bytes per sector: %d", (int)d
->fat_bytes_per_sector
);
762 d
->fat_sectors_per_track
= de_getu16le(s1pos
+24);
763 de_dbg(c
, "sectors per track: %d", (int)d
->fat_sectors_per_track
);
764 d
->fat_num_heads
= de_getu16le(s1pos
+26);
765 de_dbg(c
, "number of heads: %d", (int)d
->fat_num_heads
);
767 de_dbg_indent(c
, -1);
769 if(d
->fat_bytes_per_sector
<128 || d
->fat_bytes_per_sector
>2048 ||
770 d
->fat_sectors_per_track
<1 || d
->fat_sectors_per_track
>32 ||
771 d
->fat_num_heads
<1 || d
->fat_num_heads
>2)
773 de_err(c
, "Invalid or unsupported disk geometry (%d sectors/track, "
774 "%d heads, %d bytes/sector)", (int)d
->fat_sectors_per_track
,
775 (int)d
->fat_num_heads
, (int)d
->fat_bytes_per_sector
);
776 d
->convert_errflag
= 1;
784 static int do_pasti_track(deark
*c
, struct pastictx
*d
, i64 trkidx
, i64 pos1
, i64 len
)
788 struct pasti_track_ctx
*tctx
= NULL
;
791 de_dbg(c
, "track record[%d] at %"I64_FMT
", len=%"I64_FMT
, (int)trkidx
, pos1
, len
);
794 tctx
= de_malloc(c
, sizeof(struct pasti_track_ctx
));
796 pos
+= 4; // record size, already read
798 tctx
->fuzzy_count
= de_getu32le_p(&pos
);
799 de_dbg(c
, "fuzzyCount: %"I64_FMT
, tctx
->fuzzy_count
);
800 tctx
->sector_count
= de_getu16le_p(&pos
);
801 de_dbg(c
, "sectorCount: %"I64_FMT
, tctx
->sector_count
);
802 if(tctx
->sector_count
> PASTI_MAX_SECTORS_PER_TRACK
) {
806 tctx
->track_flags
= (UI
)de_getu16le_p(&pos
);
807 de_dbg(c
, "trackFlags: 0x%02x", tctx
->track_flags
);
809 tctx
->track_length
= de_getu16le_p(&pos
);
810 de_dbg(c
, "trackLength: %"I64_FMT
, tctx
->track_length
);
812 track_number_raw
= de_getbyte_p(&pos
);
813 tctx
->track_num
= (i64
)(track_number_raw
& 0x7f);
814 tctx
->side_num
= (i64
)(track_number_raw
>>7);
815 de_dbg(c
, "trackNumber: 0x%02x (track %u, side %u)", (UI
)track_number_raw
,
816 (UI
)tctx
->track_num
, (UI
)tctx
->side_num
);
818 pos
+= 1; // trackType, unused
820 if(tctx
->track_flags
& TRK_SECT
) {
821 tctx
->sector_descriptors_pos
= pos
;
822 pos
+= 16 * tctx
->sector_count
;
825 pos
+= tctx
->fuzzy_count
;
827 tctx
->track_data_record_pos
= pos
;
829 if(!(tctx
->track_flags
& TRK_SECT
)) {
830 // TODO: Support this
831 de_err(c
, "Pasti files without sector descriptors are not supported");
836 // Special handling for the first track in the file
838 if(track_number_raw
== 0x00) {
839 pasti_find_and_read_boot_sector(c
, d
, tctx
);
842 de_err(c
, "First track in file is not track 0/side 0; can't convert this file");
843 d
->convert_errflag
= 1;
847 if(tctx
->sector_count
>0) {
848 if(!do_pasti_sectors(c
, d
, tctx
)) goto done
;
856 de_dbg_indent(c
, -1);
860 static int do_pasti_tracks(deark
*c
, struct pastictx
*d
, i64 pos1
)
866 for(trkidx
=0; trkidx
<d
->track_count
; trkidx
++) {
869 if(pos
+16 > c
->infile
->len
) goto done
;
870 recsize
= de_getu32le(pos
);
871 if(recsize
<16) goto done
;
872 if(!do_pasti_track(c
, d
, trkidx
, pos
, recsize
)) goto done
;
878 de_err(c
, "Bad data or unexpected end of file");
883 static int do_pasti_header(deark
*c
, struct pastictx
*d
, i64 pos1
)
888 de_dbg(c
, "file descriptor at %"I64_FMT
, pos1
);
890 pos
+= 4; // signature
891 d
->version
= (UI
)de_getu16le_p(&pos
);
892 de_dbg(c
, "version: %u", d
->version
);
894 pos
+= 2; // reserved_1
895 d
->track_count
= (i64
)de_getbyte_p(&pos
);
896 de_dbg(c
, "track count: %d", (int)d
->track_count
);
897 d
->revision
= (UI
)de_getbyte_p(&pos
);
898 de_dbg(c
, "revision: %u", d
->revision
);
899 if(d
->version
!=3 || d
->revision
!=2) {
900 de_err(c
, "Unsupported format version: %ur%u", d
->version
, d
->revision
);
906 de_dbg_indent(c
, -1);
910 static void pasti_decode_fat(deark
*c
, struct pastictx
*d
)
912 de_module_params
*mparams
= NULL
;
914 mparams
= de_malloc(c
, sizeof(de_module_params
));
915 de_dbg(c
, "decoding as FAT");
917 mparams
->in_params
.codes
= "A";
918 mparams
->in_params
.input_encoding
= d
->input_encoding
;
919 de_run_module_by_id_on_slice(c
, "fat", mparams
, d
->diskbuf
, 0, d
->diskbuf
->len
);
920 if(mparams
->out_params
.flags
& 0x1) {
921 de_info(c
, "Note: Use \"-opt pasti:toraw\" to decompress to a raw .ST file");
924 de_dbg_indent(c
, -1);
927 static void pasti_extract_to_raw(deark
*c
, struct pastictx
*d
)
931 outf
= dbuf_create_output_file(c
, "st", NULL
, 0);
932 dbuf_copy(d
->diskbuf
, 0, d
->diskbuf
->len
, outf
);
936 static void de_run_pasti(deark
*c
, de_module_params
*mparams
)
938 struct pastictx
*d
= NULL
;
940 d
= de_malloc(c
, sizeof(struct pastictx
));
941 d
->input_encoding
= de_get_input_encoding(c
, NULL
, DE_ENCODING_ATARIST
);
943 if(de_get_ext_option_bool(c
, "pasti:toraw", 0)) {
944 d
->outfmt
= ATARIST_OUTFMT_ST
;
947 d
->outfmt
= ATARIST_OUTFMT_FILES
;
950 if(!do_pasti_header(c
, d
, 0)) goto done
;
952 if(!do_pasti_tracks(c
, d
, 16)) goto done
;
953 if(!d
->diskbuf
) goto done
;
955 if(d
->oob_sector_count
>0) {
956 de_warn(c
, "%d of %d sectors are outside the bounds of the disk geometry, and will "
957 "be ignored.", (int)d
->oob_sector_count
, (int)d
->num_nonempty_sectors_found
);
960 if(d
->num_nonempty_sectors_found
<=0) goto done
;
962 if(d
->outfmt
==ATARIST_OUTFMT_ST
) {
963 pasti_extract_to_raw(c
, d
);
966 pasti_decode_fat(c
, d
);
971 dbuf_close(d
->diskbuf
);
976 static int de_identify_pasti(deark
*c
)
978 if(!dbuf_memcmp(c
->infile
, 0, "RSY\0", 4))
983 static void de_help_pasti(deark
*c
)
985 de_msg(c
, "-opt pasti:toraw : Extract to raw .ST format");
988 void de_module_pasti(deark
*c
, struct deark_module_info
*mi
)
991 mi
->desc
= "Pasti - Atari ST floppy disk image";
992 mi
->run_fn
= de_run_pasti
;
993 mi
->identify_fn
= de_identify_pasti
;
994 mi
->help_fn
= de_help_pasti
;