1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // T64 (Commodore 64 "tape"-like format)
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_t64
);
11 typedef struct localctx_struct
{
17 static void do_extract_file(deark
*c
, lctx
*d
, i64 dir_pos
,
18 u8 filetype_c64s
, u8 filetype
)
24 i64 payload_size
; // = file_size-2
25 de_ucstring
*fname
= NULL
;
31 load_addr
= de_getu16le(dir_pos
+2);
32 end_addr
= de_getu16le(dir_pos
+4);
33 offset
= de_getu32le(dir_pos
+8);
34 de_dbg(c
, "load_addr=%d end_addr=%d offset=%d", (int)load_addr
,
35 (int)end_addr
, (int)offset
);
37 // File name at pos+16
41 // Find the length of the (space-padded) filename.
43 for(i
=15; i
>=0; i
--) {
44 if(de_getbyte(fnpos
+i
)!=' ') {
49 de_dbg2(c
, "filename length: %d", (int)fname_len
);
51 fname
= ucstring_create(c
);
52 dbuf_read_to_ucstring(c
->infile
, fnpos
, fname_len
, fname
, 0, DE_ENCODING_PETSCII
);
53 de_dbg(c
, "filename: \"%s\"", ucstring_getpsz(fname
));
55 ucstring_append_sz(fname
, ".prg", DE_ENCODING_LATIN1
);
57 fi
= de_finfo_create(c
);
58 de_finfo_set_name_from_ucstring(c
, fi
, fname
, 0);
59 fi
->original_filename_flag
= 1;
61 payload_size
= end_addr
- load_addr
;
62 if(payload_size
< 0) {
63 // TODO: Try to support files that don't have end_addr set properly.
64 de_err(c
, "This type of T64 file is not supported.");
68 f
= dbuf_create_output_file(c
, NULL
, fi
, 0);
69 dbuf_copy(c
->infile
, dir_pos
+2, 2, f
);
70 dbuf_copy(c
->infile
, offset
, payload_size
, f
);
74 de_finfo_destroy(c
, fi
);
75 ucstring_destroy(fname
);
78 static void do_dir_entry(deark
*c
, lctx
*d
, i64 entry_num
, i64 pos
)
83 filetype_c64s
= de_getbyte(pos
);
84 if(filetype_c64s
==0) {
85 de_dbg2(c
, "unused entry #%d at %d", (int)entry_num
, (int)pos
);
88 de_dbg(c
, "entry #%d at %d", (int)entry_num
, (int)pos
);
92 filetype
= de_getbyte(pos
+1);
93 de_dbg(c
, "c64s filetype=%d, filetype=0x%02x", (int)filetype_c64s
, (int)filetype
);
96 de_err(c
, "Unsupported file type (0x%02x)", (int)filetype
);
99 do_extract_file(c
, d
, pos
, filetype_c64s
, filetype
);
102 de_dbg_indent(c
, -1);
105 static void de_run_t64(deark
*c
, de_module_params
*mparams
)
111 d
= de_malloc(c
, sizeof(lctx
));
114 d
->version
= de_getu16le(pos
);
115 de_dbg(c
, "version: 0x%04x", (int)d
->version
);
116 if(d
->version
!=0x100 && d
->version
!=0x101) {
117 de_warn(c
, "Unexpected version number. This might not be a T64 file.");
120 d
->max_dir_entries
= de_getu16le(pos
+2);
121 d
->used_dir_entries
= de_getu16le(pos
+4);
122 de_dbg(c
, "max dir entries = %d, files = %d", (int)d
->max_dir_entries
, (int)d
->used_dir_entries
);
125 for(i
=0; i
<d
->max_dir_entries
; i
++) {
126 do_dir_entry(c
, d
, i
, pos
+32*i
);
132 static int de_identify_t64(deark
*c
)
134 if(!dbuf_memcmp(c
->infile
, 0, "C64", 3)) return 80;
138 void de_module_t64(deark
*c
, struct deark_module_info
*mi
)
141 mi
->desc
= "T64 (C64 tape format)";
142 mi
->run_fn
= de_run_t64
;
143 mi
->identify_fn
= de_identify_t64
;