diff --git a/2mg.c b/2mg.c index 3938d01..6e5f99a 100644 --- a/2mg.c +++ b/2mg.c @@ -12,7 +12,9 @@ #include #include #include +#include #include "handle.h" +#include "prodos_types.h" static void doDirectory(uint16_t key, uint8_t *disk, uint32_t disklen, int depth); @@ -20,8 +22,8 @@ static void doEntry(uint8_t *entry, uint8_t *disk, uint32_t disklen, int depth); static void doFile(uint16_t key, uint32_t len, char *name, uint8_t *disk, uint32_t disklen, int type); -static void doGSOS(uint16_t key, char *name, uint8_t *disk, uint32_t disklen, - int depth); +static void doGSOS(uint16_t key, char *name, uint8_t filetype, uint8_t *disk, + uint32_t disklen, int depth); const char *argp_program_version = "2mg 0.2"; const char *argp_program_bug_address = "sean@seancode.com"; @@ -68,6 +70,8 @@ int main(int argc, char **argv) { argp_parse(&argp, argc, argv, 0, 0, &arguments); + setlocale(LC_NUMERIC, ""); + FILE *f = fopen(arguments.diskimage, "rb"); if (!f) { fprintf(stderr, "Failed to open '%s'\n", arguments.diskimage); @@ -184,8 +188,15 @@ static void doDirectory(uint16_t key, uint8_t *disk, uint32_t disklen, } } +static void printDateTime(uint16_t date, uint16_t time) { + printf("%02d-%02d-%02d %02d:%02d", + (date >> 9) & 0x7f, (date >> 5) & 0xf, date & 0x1f, + (time >> 8) & 0x1f, time & 0x3f); +} + static void doEntry(uint8_t *entry, uint8_t *disk, uint32_t disklen, int depth) { + uint8_t filetype = entry[0x10]; uint16_t key = r16(entry + 0x11); uint32_t eof = r24(entry + 0x15); @@ -199,12 +210,33 @@ static void doEntry(uint8_t *entry, uint8_t *disk, uint32_t disklen, if (depth < 0) { doFile(key, eof, filename, disk, disklen, entry[0] >> 4); } else { + uint16_t createDate = r16(entry + 0x18); + uint16_t createTime = r16(entry + 0x1a); + uint16_t aux = r16(entry + 0x1f); + uint16_t modDate = r16(entry + 0x21); + uint16_t modTime = r16(entry + 0x23); indent(depth); - printf("%s %d bytes\n", filename, eof); + printf("%s\n", filename); + indent(depth); + printf(" Size: %'d", eof); + printf(" Created: "); + printDateTime(createDate, createTime); + printf(" Modified: "); + printDateTime(modDate, modTime); + printf("\n"); + indent(depth); + printf(" Type: $%02x Aux: $%04x ", filetype, aux); + uint32_t typeaux = filetype | (aux << 8); + for (int i = 0; i < numTypes; i++) { + if ((typeaux & fileTypes[i].mask) == fileTypes[i].id) { + printf("%s/%s\n", fileTypes[i].ext, fileTypes[i].desc); + break; + } + } } break; case 0x50: - doGSOS(key, filename, disk, disklen, depth); + doGSOS(key, filename, filetype, disk, disklen, depth); break; case 0xd0: doDirectory(key, disk, disklen, depth < 0 ? -1 : depth + 1); @@ -263,7 +295,7 @@ static void dumpTree(uint8_t *index, uint32_t len, FILE *f, uint8_t *disk, } } -static void doGSOS(uint16_t key, char *name, uint8_t *disk, +static void doGSOS(uint16_t key, char *name, uint8_t filetype, uint8_t *disk, uint32_t disklen, int depth) { uint8_t *block = disk + key * 512; int type = *block; diff --git a/prodos_types.h b/prodos_types.h new file mode 100644 index 0000000..a1ad7fe --- /dev/null +++ b/prodos_types.h @@ -0,0 +1,261 @@ +#pragma once + +/** @copyright 2018 Sean Kasun */ + +static const struct { + uint32_t mask, id; + const char *ext; + const char *desc; +} fileTypes[] = { +{0x0000ff, 0x000000, "unk", "Unknown"}, +{0x0000ff, 0x000001, "bad", "Bad Block File"}, +{0x0000ff, 0x000002, "pcd", "Apple /// Pascal Code"}, +{0x0000ff, 0x000003, "ptx", "Apple /// Pascal Text"}, +{0x0000ff, 0x000004, "txt", "Text File"}, +{0x0000ff, 0x000005, "pda", "Apple /// Pascal Data"}, +{0x0000ff, 0x000006, "bin", "Binary File"}, +{0x0000ff, 0x000007, "fnt", "Apple /// Font"}, +{0xffffff, 0x400008, "fot", "Packed HiRes"}, +{0xffffff, 0x400108, "fot", "Packed Double HiRes"}, +{0xffffff, 0x800108, "fot", "Printographer Packed HiRes"}, +{0xffffff, 0x800208, "fot", "Printographer Packed Double HiRes"}, +{0x0000ff, 0x000008, "fot", "Hires Graphics"}, +{0x0000ff, 0x000009, "ba3", "Apple /// Basic Program"}, +{0x0000ff, 0x00000a, "da3", "Apple /// Basic Data"}, +{0x0000ff, 0x00000b, "wpf", "Word Processor File"}, +{0x0000ff, 0x00000c, "sos", "Apple /// SOS System File"}, +{0x0000ff, 0x00000f, "dir", "Directory"}, +{0x0000ff, 0x000010, "rpd", "Apple /// RPS Data"}, +{0x0000ff, 0x000011, "rpi", "Apple /// RPS Index"}, +{0x0000ff, 0x000012, "afd", "Apple /// AppleFile Discard"}, +{0x0000ff, 0x000013, "afm", "Apple /// AppleFile Model"}, +{0x0000ff, 0x000014, "afr", "Apple /// AppleFile Report"}, +{0x0000ff, 0x000015, "scl", "Apple /// Screen Library"}, +{0xffffff, 0x000116, "pfs", "PFS File"}, +{0xffffff, 0x000216, "pfs", "PFS Word Processing"}, +{0xffffff, 0x000316, "pfs", "PFS Graphing"}, +{0xffffff, 0x000416, "pfs", "PFS Planning"}, +{0xffffff, 0x001616, "pfs", "PFS Internal Data"}, +{0x0000ff, 0x000016, "pfs", "PFS Document"}, +{0x0000ff, 0x000019, "adb", "AppleWorks Database"}, +{0x0000ff, 0x00001a, "awp", "AppleWorks Word Processing"}, +{0x0000ff, 0x00001b, "asp", "AppleWorks Spreadsheet"}, +{0x0000ff, 0x000020, "tdm", "Desktop Manager File"}, +{0x0000ff, 0x000021, "ips", "Instant Pascal Source"}, +{0x0000ff, 0x000022, "upv", "UCSD Pascal Volume"}, +{0x0000ff, 0x000029, "3sd", "Apple /// SOS Directory"}, +{0x0000ff, 0x00002a, "8sc", "Source Code"}, +{0xffffff, 0x80012b, "8ob", "GBBS Pro Object Code"}, +{0x0000ff, 0x00002b, "8ob", "Object Code"}, +{0xffffff, 0x80032c, "8ic", "APEX Program File"}, +{0x0000ff, 0x00002c, "8ic", "Interpreted Code"}, +{0x0000ff, 0x00002d, "8ld", "Language Data"}, +{0xffffff, 0x80012e, "p8c", "Davex 8 Command"}, +{0xffffff, 0x80022e, "ptp", "Point-To-Point Driver"}, +{0xffffff, 0x80032e, "ptp", "Point-To-Point Code"}, +{0x0000ff, 0x00002e, "p8c", "ProDOS 8 Code Module"}, +{0xffffff, 0x800141, "ocr", "InWords Font Table"}, +{0x0000ff, 0x000041, "orc", "ORC Data"}, +{0x0000ff, 0x000042, "ftd", "File Type Definitions"}, +{0xffffff, 0x544550, "gwp", "TeachText File"}, +{0xffffff, 0x800150, "gwp", "DeluxeWrite File"}, +{0xffffff, 0x801050, "gwp", "AppleWorks GS Word Processing"}, +{0x0000ff, 0x000050, "gwp", "Apple IIgs Word Processing"}, +{0xffffff, 0x801051, "gss", "AppleWorks GS Spreadsheet"}, +{0x0000ff, 0x000051, "gss", "Apple IIgs Spreadsheet"}, +{0xffffff, 0x800152, "gdb", "GTV"}, +{0xffffff, 0x801052, "gdb", "AppleWorks GS Database"}, +{0xffffff, 0x801152, "gdb", "AppleWorks GS Template"}, +{0xffffff, 0x801352, "gdb", "GSAS"}, +{0x0000ff, 0x000052, "gdb", "Apple IIgs Database"}, +{0xffffff, 0x800253, "drw", "Graphics Disk Labeller"}, +{0xffffff, 0x801053, "drw", "AppleWorks GS Drawing"}, +{0x0000ff, 0x000053, "drw", "Drawing File"}, +{0xffffff, 0x800254, "gdp", "GraphicWriter"}, +{0xffffff, 0x801054, "gdp", "AppleWorks GS Desktop Publishing"}, +{0xffffff, 0xdd3e54, "gdp", "Medley"}, +{0x0000ff, 0x000054, "gdp", "Apple IIgs Desktop Publishing"}, +{0xffffff, 0x000155, "hmd", "HyperCard GS"}, +{0xffffff, 0x800155, "hmd", "Tutor-Tech"}, +{0xffffff, 0x800255, "hmd", "HyperStudio"}, +{0xffffff, 0x800355, "hmd", "Nexus"}, +{0x0000ff, 0x000055, "hmd", "Hypermedia"}, +{0xffffff, 0x800156, "edu", "Tutor-Tech Scores"}, +{0x0000ff, 0x000056, "edu", "Educational Data"}, +{0xffffff, 0x800357, "stn", "Music Writer"}, +{0x0000ff, 0x000057, "stn", "Stationery"}, +{0xffffff, 0x800258, "hlp", "Davex 8 Help"}, +{0x0000ff, 0x000058, "hlp", "Help File"}, +{0xffffff, 0x801059, "com", "AppleWorks GS Communications"}, +{0x0000ff, 0x000059, "com", "Communications"}, +{0xffffff, 0x00025a, "cfg", "Battery RAM"}, +{0xffffff, 0x00035a, "cfg", "AutoLaunch"}, +{0xffffff, 0x00055a, "cfg", "GSBug"}, +{0xffffff, 0x80015a, "cfg", "Master Tracks Jr."}, +{0xffffff, 0x80025a, "cfg", "GraphicWriter"}, +{0xffffff, 0x80035a, "cfg", "Z-Link"}, +{0xffffff, 0x80045a, "cfg", "JumpStart"}, +{0xffffff, 0x80055a, "cfg", "Davex 8"}, +{0xffffff, 0x80065a, "cfg", "Nifty List"}, +{0xffffff, 0x80075a, "cfg", "GTV Videodisc"}, +{0xffffff, 0x80085a, "cfg", "GTV Workshop"}, +{0xffffff, 0x80095a, "ptp", "Point-To-Point Config"}, +{0xffffff, 0x800a5a, "cfg", "ORCA Disassembler"}, +{0xffffff, 0x800b5a, "cfg", "SnowTerm"}, +{0xffffff, 0x800c5a, "cfg", "My Word!"}, +{0xffffff, 0x800d5a, "cfg", "Chipmunk"}, +{0xffffff, 0x80105a, "cfg", "AppleWorks GS Config"}, +{0xffffff, 0x80115a, "cfg", "SDA Shell"}, +{0xffffff, 0x80125a, "cfg", "SDE Editor"}, +{0xffffff, 0x80135a, "cfg", "SDE Ruler"}, +{0xffffff, 0x80145a, "cfg", "Nexus"}, +{0xffffff, 0x80155a, "cfg", "DesignMaster"}, +{0xffffff, 0x801c5a, "cfg", "Platinum Paint"}, +{0xffffff, 0x801e5a, "cfg", "Allison"}, +{0xffffff, 0x80215a, "cfg", "GSAS Accounting"}, +{0x0000ff, 0x00005a, "cfg", "Configuration File"}, +{0xffffff, 0x80015b, "anm", "Cartooners Movie"}, +{0xffffff, 0x80025b, "anm", "Cartooners Actors"}, +{0xffffff, 0x80055b, "anm", "Arcade King Super"}, +{0x0000ff, 0x00005b, "anm", "Animation File"}, +{0xffffff, 0x80015c, "mum", "GTV Playlist"}, +{0x0000ff, 0x00005c, "mum", "Multimedia"}, +{0xffffff, 0x80015d, "ent", "Solitaire"}, +{0xffffff, 0x80025d, "ent", "BattleFront Scene"}, +{0xffffff, 0x80035d, "ent", "BattleFront Game"}, +{0xffffff, 0x80065d, "ent", "Blackjack Tutor"}, +{0x0000ff, 0x00005d, "ent", "Entertainment"}, +{0xffffff, 0x00015e, "dvu", "Resource File"}, +{0xffffff, 0x80015e, "dvu", "ORCA Disassembler Template"}, +{0xffffff, 0x80035e, "dvu", "DesignMaster"}, +{0x0000ff, 0x00005e, "dvu", "Development Utility Document"}, +{0x0000ff, 0x000060, "pre", "PC Pre-Boot"}, +{0x0000ff, 0x000066, "ncf", "ProDOS File Navigator Command"}, +{0x0000ff, 0x00006b, "bio", "PC BIOS"}, +{0x0000ff, 0x00006d, "dvr", "PC Driver"}, +{0x0000ff, 0x00006e, "pre", "PC Pre-Boot"}, +{0x0000ff, 0x00006f, "hdv", "PC Volume"}, +{0x0000ff, 0x0000a0, "wp_", "WordPerfect"}, +{0x0000ff, 0x0000ab, "gsb", "Apple IIgs Basic Program"}, +{0x0000ff, 0x0000ac, "tdf", "Apple IIgs Basic TDF"}, +{0x0000ff, 0x0000ad, "bdf", "Apple IIgs Basic Data"}, +{0xffffff, 0x0001b0, "src", "APW Text"}, +{0xffffff, 0x0003b0, "src", "APW 65816 Assembly Source"}, +{0xffffff, 0x0005b0, "src", "ORCA Pascal Source"}, +{0xffffff, 0x0006b0, "src", "APW Command File"}, +{0xffffff, 0x0008b0, "src", "ORCA C Source"}, +{0xffffff, 0x0009b0, "src", "APW Linker Command File"}, +{0xffffff, 0x000ab0, "src", "APW C Source"}, +{0xffffff, 0x000cb0, "src", "ORCA Desktop Command File"}, +{0xffffff, 0x0015b0, "src", "APW Rez Source"}, +{0xffffff, 0x001eb0, "src", "TML Pascal Source"}, +{0xffffff, 0x0116b0, "src", "ORCA Disassembler Script"}, +{0xffffff, 0x0503b0, "src", "SDE Assembler Source"}, +{0xffffff, 0x0506b0, "src", "SDE Command Script"}, +{0xffffff, 0x0719b0, "src", "PostScript"}, +{0x0000ff, 0x0000b0, "src", "Apple IIgs Source Code"}, +{0x0000ff, 0x0000b1, "obj", "Apple IIgs Object Code"}, +{0x0000ff, 0x0000b2, "lib", "Apple IIgs Library"}, +{0x0000ff, 0x0000b3, "s16", "Apple IIgs Program"}, +{0x0000ff, 0x0000b4, "rtl", "Apple IIgs Runtime Library"}, +{0x0000ff, 0x0000b5, "exe", "Apple IIgs Shell Script"}, +{0x0000ff, 0x0000b6, "pif", "Permanent Initialization File"}, +{0x0000ff, 0x0000b7, "tif", "Temporary Initialization File"}, +{0x0000ff, 0x0000b8, "nda", "New Desk Accessory"}, +{0x0000ff, 0x0000b9, "cda", "Classic Desk Accessory"}, +{0x0000ff, 0x0000ba, "tol", "Apple IIgs Tool"}, +{0xffffff, 0x7f01bb, "drv", "GTV Videodisc Serial Driver"}, +{0xffffff, 0x7f02bb, "drv", "GTV Videodisc Game Port Driver"}, +{0x0000ff, 0x0000bb, "drv", "Apple IIgs Device Driver"}, +{0xffffff, 0x4001bc, "ldf", "Nifty List Module"}, +{0xffffff, 0x4002bc, "ldf", "Super Info Module"}, +{0xffffff, 0x4004bc, "ldf", "Twilight File"}, +{0x0000ff, 0x0000bc, "ldf", "Generic Load File"}, +{0x0000ff, 0x0000bd, "fst", "Apple IIgs File System Translator"}, +{0x0000ff, 0x0000bf, "doc", "Apple IIgs Document"}, +{0xffffff, 0x0000c0, "pnt", "PaintWorks Packed Picture"}, +{0xffffff, 0x0001c0, "pnt", "Packed Super HiRes Graphics"}, +{0xffffff, 0x0002c0, "pnt", "Preferred Format Picture"}, +{0xffffff, 0x0003c0, "pnt", "Packed QuickDraw II PICT File"}, +{0xffffff, 0x8001c0, "pnt", "GTV Background Image"}, +{0x0000ff, 0x0000c0, "pnt", "Apple IIgs Packed Super HiRes"}, +{0xffffff, 0x0000c1, "pic", "Super HiRes Screen"}, +{0xffffff, 0x0001c1, "pic", "QuickDraw PICT File"}, +{0xffffff, 0x0002c1, "pic", "Super HiRes 3200 Colors"}, +{0xffffff, 0x8001c1, "pic", "Allison Raw Image"}, +{0xffffff, 0x8002c1, "pic", "ThunderScan Image"}, +{0x0000ff, 0x0000c1, "pic", "Apple IIgs Super HiRes Graphics"}, +{0x0000ff, 0x0000c2, "ani", "PaintWorks Animation"}, +{0x0000ff, 0x0000c3, "pal", "PaintWorks Palette"}, +{0xffffff, 0x8000c5, "oog", "Draw Plus"}, +{0xffffff, 0xc000c5, "oog", "DYOH Architecture"}, +{0xffffff, 0xc001c5, "oog", "DYOH Predrawn"}, +{0xffffff, 0xc002c5, "oog", "DYOH Custom"}, +{0xffffff, 0xc003c5, "oog", "DYOH Clipboard"}, +{0xffffff, 0xc004c5, "oog", "Reserved"}, +{0xffffff, 0xc005c5, "oog", "Reserved"}, +{0xffffff, 0xc006c6, "oog", "DYOH Landscape"}, +{0x0000ff, 0x0000c6, "oog", "Object-Oriented Graphics"}, +{0xffffff, 0x8001c6, "scr", "Davex 8 Script"}, +{0x0000ff, 0x0000c6, "scr", "Script"}, +{0x0000ff, 0x0000c7, "cdv", "Apple IIgs Control Panel"}, +{0xffffff, 0x0000c8, "fon", "QuickDraw II Font"}, +{0x0000ff, 0x0000c8, "fon", "QuickDraw font"}, +{0x0000ff, 0x0000c9, "fnd", "Finder Data"}, +{0x0000ff, 0x0000ca, "icn", "Apple IIgs Icon"}, +{0xffffff, 0x0000d5, "mus", "Music Construction Set"}, +{0xffffff, 0x0001d5, "mus", "MIDI Synth"}, +{0xffffff, 0x0007d5, "mus", "SoundSmith"}, +{0xffffff, 0x8002d5, "mus", "Diversi-Tune"}, +{0xffffff, 0x8003d5, "mus", "Master Tracks Jr."}, +{0xffffff, 0x8004d5, "mus", "Music Writer"}, +{0xffffff, 0x8005d5, "mus", "Arcade King Super"}, +{0x0000ff, 0x0000d5, "mus", "Music File"}, +{0xffffff, 0x0000d6, "ins", "Music Construction Set Instrument"}, +{0xffffff, 0x0001d6, "ins", "MIDI Synth Instrument"}, +{0xffffff, 0x8002d6, "ins", "Diversi-Tune Instrument"}, +{0x0000ff, 0x0000d6, "ins", "Instrument File"}, +{0xffffff, 0x0000d7, "mdi", "MIDI Standard"}, +{0x0000ff, 0x0000d7, "mdi", "MIDI File"}, +{0xffffff, 0x0000d8, "snd", "AIFF Sound"}, +{0xffffff, 0x0001d8, "snd", "AIFF-C Sound"}, +{0xffffff, 0x0002d8, "snd", "ASIF Instrument"}, +{0xffffff, 0x0003d8, "snd", "Sound Resource"}, +{0xffffff, 0x0004d8, "snd", "MIDI Synth Wave Data"}, +{0xffffff, 0x8001d8, "snd", "HyperStudio Sound"}, +{0xffffff, 0x8002d8, "snd", "Arcade King Super"}, +{0x0000ff, 0x0000d8, "snd", "Sound File"}, +{0x0000ff, 0x0000db, "dbm", "DB Master Document"}, +{0xffffff, 0x0000e0, "lbr", "ALU"}, +{0xffffff, 0x0001e0, "lbr", "AppleSingle"}, +{0xffffff, 0x0002e0, "lbr", "AppleDouble Header"}, +{0xffffff, 0x0003e0, "lbr", "AppleDouble Data"}, +{0xffffff, 0x8000e0, "lbr", "Binary II"}, +{0xffffff, 0x8001e0, "lbr", "AppleLink ACU"}, +{0xffffff, 0x8002e0, "lbr", "ShrinkIt"}, +{0xffffff, 0x8004e0, "lbr", "Davex Archived Volume"}, +{0xffffff, 0x8006e0, "lbr", "EZ Backup Saveset"}, +{0xffffff, 0x8007e0, "lbr", "ELS DOS 3.3 Volume"}, +{0x0000ff, 0x0000e0, "lbr", "Archived Files"}, +{0x0000ff, 0x0000e2, "atk", "AppleTalk Data"}, +{0x0000ff, 0x0000ee, "r16", "EDASM 816 Relocatable Code"}, +{0x0000ff, 0x0000ef, "par", "Pascal Area"}, +{0x0000ff, 0x0000f0, "cmd", "ProDOS Command"}, +{0x0000ff, 0x0000f1, "ovl", "User Defined 1"}, +{0x0000ff, 0x0000f2, "ud2", "User Defined 2"}, +{0x0000ff, 0x0000f3, "ud3", "User Defined 3"}, +{0x0000ff, 0x0000f4, "ud4", "User Defined 4"}, +{0x0000ff, 0x0000f5, "bat", "User Defined 5"}, +{0x0000ff, 0x0000f6, "ud6", "User Defined 6"}, +{0x0000ff, 0x0000f7, "ud7", "User Defined 7"}, +{0x0000ff, 0x0000f8, "prg", "User Defined 8"}, +{0x0000ff, 0x0000f9, "p16", "Apple IIgs System File"}, +{0x0000ff, 0x0000fa, "int", "Integer BASIC Program"}, +{0x0000ff, 0x0000fb, "ivr", "Integer BASIC Variables"}, +{0x0000ff, 0x0000fc, "bas", "Applesoft BASIC Program"}, +{0x0000ff, 0x0000fd, "var", "Applesoft BASIC Variables"}, +{0x0000ff, 0x0000fe, "rel", "EDASM Relocatable Code"}, +{0x0000ff, 0x0000ff, "sys", "ProDOS System File"} +}; + +#define numTypes (sizeof(fileTypes) / sizeof(fileTypes[0]))