From b459c60d5b69539f9f6f00397cdce6c209fe6f7b Mon Sep 17 00:00:00 2001 From: Les De Ridder Date: Sat, 23 Feb 2019 08:29:45 +0100 Subject: [PATCH] Add .arc file stubs --- .gitignore | 2 + .gitmodules | 3 ++ dfuse | 1 + dub.sdl | 1 + dub.selections.json | 5 +- source/app.d | 119 +++++++++++++++++++++++++++++------------ source/cm3d2/arc.d | 90 +++++++++++++++++++++++++++++++ source/cm3d2/menu.d | 7 +-- source/cm3d2/package.d | 3 ++ source/cm3d2/util.d | 23 ++++++-- 10 files changed, 212 insertions(+), 42 deletions(-) create mode 100644 .gitmodules create mode 160000 dfuse create mode 100644 source/cm3d2/arc.d diff --git a/.gitignore b/.gitignore index ef651b4..e28a568 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ cm3d2tool-test-* *.obj *.lst out/ +*.menu +*.txt diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..75e6bf7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "dfuse"] + path = dfuse + url = https://github.com/lesderid/dfuse diff --git a/dfuse b/dfuse new file mode 160000 index 0000000..d92184e --- /dev/null +++ b/dfuse @@ -0,0 +1 @@ +Subproject commit d92184e5ca90730a2aceef469a393eeed9e9c5c7 diff --git a/dub.sdl b/dub.sdl index 59fa1c3..967f4d6 100644 --- a/dub.sdl +++ b/dub.sdl @@ -4,4 +4,5 @@ authors "lesderid" copyright "Copyright © 2019, Les De Ridder" license "NCSA" dependency "sdlang-d" version="~>0.10.4" +dependency "dfuse" version="~>0.3.0" path="dfuse" targetPath "out" diff --git a/dub.selections.json b/dub.selections.json index 15a8934..5630d66 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -1,9 +1,10 @@ { "fileVersion": 1, "versions": { + "dfuse": {"path":"dfuse"}, "libinputvisitor": "1.2.2", - "sdlang-d": "0.10.4", - "taggedalgebraic": "0.10.12", + "sdlang-d": "0.10.5", + "taggedalgebraic": "0.11.2", "unit-threaded": "0.7.55" } } diff --git a/source/app.d b/source/app.d index 400b63d..ad8691c 100644 --- a/source/app.d +++ b/source/app.d @@ -1,51 +1,102 @@ import std.stdio; import std.range; import std.algorithm; +import std.path; +import std.file; + +import dfuse.fuse; import cm3d2; void main(string[] args) { - if (args.length < 2) - { - help(args[0]); - return; - } + if (args.length < 2) + { + help(args[0]); + return; + } - switch (args[1]) - { - case "help": - case "-h": - case "--help": - help(args[0]); - break; - case "menu-to-sdl": - ubyte[] data = stdin.byChunk(4096).joiner.array; - writeln(Menu.fromMenu(data).toSDL()); - break; - case "sdl-to-menu": - throw new Exception("Not implemented yet"); - default: - writeln("Unknown option '" ~ args[1] ~ "'"); - writeln(); - goto case "help"; - } + switch (args[1]) + { + case "help": + case "-h": + case "--help": + help(args[0]); + break; + case "menu-to-sdl": + ubyte[] data = stdin.byChunk(4096).joiner.array; + writeln(Menu.fromMenu(data).toSDL()); + break; + case "sdl-to-menu": + throw new Exception("Not implemented yet"); + case "mount-arc": + string arcPath; + string mountpoint; + + if (args.length < 4 || !(arcPath = args[2]).isValidPath || !(mountpoint = args[3]).isValidPath) + { + goto case "help"; + } + + mountArc(arcPath, mountpoint); + break; + default: + writeln("Unknown option '" ~ args[1] ~ "'"); + writeln(); + goto case "help"; + } } void help(string toolPath) { - writeln("Usage: " ~ toolPath ~ " "); - writeln(); + writeln("usage: " ~ toolPath ~ " [--help] []"); + writeln(); - void showCommandUsage(string command, string description) - { - writeln(" " ~ toolPath ~ " " ~ command); - writeln(" " ~ description); - } + void showCommandUsage(string command, string description) + { + writeln(" " ~ toolPath ~ " " ~ command); + writeln(" " ~ description); + } - showCommandUsage("menu-to-sdl", "Convert .menu to SDL"); - showCommandUsage("sdl-to-menu", "Convert SDL to .menu"); + showCommandUsage("menu-to-sdl", "Convert .menu (from stdin) to SDL (stdout)"); + showCommandUsage("sdl-to-menu", "Convert SDL (from stdin) to .menu (stdout)"); + writeln(); + showCommandUsage("mount-arc ", "FUSE mount arc file(s) on mountpoint"); - writeln(); - writeln("Reads input from stdin and writes output to stdout."); + writeln(); + writeln("Reads input from stdin and writes output to stdout."); +} + +void mountArc(string arcPath, string mountpoint) +{ + if (!arcPath.exists) + { + writeln("Error: .arc path doesn't exist."); + return; + } + + if (!mountpoint.exists || !mountpoint.isDir) + { + writeln("Error: mountpoint doesn't exist or isn't a directory."); + return; + } + + string[] arcFiles; + if (arcPath.isDir) + { + arcFiles ~= arcPath.dirEntries("*.arc", SpanMode.shallow).map!(e => e.name).array; + } + else + { + arcFiles ~= arcPath; + } + + if (arcFiles.length == 0) + { + writeln("Error: no .arc file(s) selected!"); + return; + } + + auto fuse = new Fuse("cm3d2tool-arcfs", true, true); + fuse.mount(new ArcFileSystem(arcFiles), mountpoint, ["ro", "noexec"]); } diff --git a/source/cm3d2/arc.d b/source/cm3d2/arc.d new file mode 100644 index 0000000..7554879 --- /dev/null +++ b/source/cm3d2/arc.d @@ -0,0 +1,90 @@ +module cm3d2.arc; + +import std.file; +import std.mmfile; + +import dfuse.fuse; + +import cm3d2; + +class WarcFile +{ + private MmFile _file; + + this(MmFile file) + { + _file = file; + + readHeader(); + } + + private void readHeader() + { + auto data = cast(ubyte[]) _file[]; + + auto type = cast(string) data.readBytes(4); + assert(type == "warc", "Invalid warc file: " ~ type); + } +} + +class WarpFile +{ + private MmFile _file; + + this(MmFile file) + { + _file = file; + + readHeader(); + } + + private void readHeader() + { + auto data = cast(ubyte[]) _file[]; + + auto type = cast(string) data.readBytes(4); + assert(type == "warp", "Invalid warp file: " ~ type); + } +} + +class ArcFileSystem : Operations +{ + private string[] _arcPaths; + private WarcFile[] _warcFiles; + private WarpFile[] _warpFiles; + + this(string[] arcPaths) + { + import std.stdio; + + foreach (path; arcPaths) + { + assert(path.exists); + + stderr.write(path ~ ": "); + + auto mmfile = new MmFile(path); + auto type = cast(string) mmfile[0 .. 4]; + if (type == "warc") + { + _warcFiles ~= new WarcFile(mmfile); + + stderr.writeln("warc"); + } + else if (type == "warp") + { + _warpFiles ~= new WarpFile(mmfile); + + stderr.writeln("warp"); + } + else + { + assert(false, path ~ ": not a valid .arc file"); + } + } + + stderr.writeln(".arc files checked"); + + throw new Exception("Not implemented yet"); + } +} diff --git a/source/cm3d2/menu.d b/source/cm3d2/menu.d index eed5fef..30669e8 100644 --- a/source/cm3d2/menu.d +++ b/source/cm3d2/menu.d @@ -7,7 +7,7 @@ import std.range; import sdlang; -import cm3d2.util; +import cm3d2; class Menu { @@ -49,7 +49,7 @@ class Menu assert(data.readInt() == data.length, "Unexpected data at end of file"); - while(data.length > 0) + while (data.length > 0) { string[] line; @@ -80,7 +80,8 @@ class Menu auto categoryTag = new Tag(null, "category", [Value(category)]); auto descriptionTag = new Tag(null, "description", [Value(description)]); - auto root = new Tag(null, null, null, null, [versionTag, pathTag, nameTag, categoryTag, descriptionTag]); + auto root = new Tag(null, null, null, null, [versionTag, pathTag, + nameTag, categoryTag, descriptionTag]); Tag[] dataTags; foreach (line; lines) diff --git a/source/cm3d2/package.d b/source/cm3d2/package.d index a6edf2e..364d788 100644 --- a/source/cm3d2/package.d +++ b/source/cm3d2/package.d @@ -1,3 +1,6 @@ module cm3d2; +public import cm3d2.util; + public import cm3d2.menu; +public import cm3d2.arc; diff --git a/source/cm3d2/util.d b/source/cm3d2/util.d index a2721bf..653c9f0 100644 --- a/source/cm3d2/util.d +++ b/source/cm3d2/util.d @@ -5,15 +5,31 @@ import std.range; import std.traits; ubyte readByte(Range)(ref Range data) - if (isRandomAccessRange!(Unqual!(Range)) && is(ElementType!Range == ubyte) && hasSlicing!Range) + if (isRandomAccessRange!(Unqual!(Range)) + && is(ElementType!Range == ubyte) && hasSlicing!Range) { auto value = data[0]; data = data[1 .. $]; return value; } +ubyte[] readBytes(Range)(ref Range data, uint count) + if (isRandomAccessRange!(Unqual!(Range)) + && is(ElementType!Range == ubyte) && hasSlicing!Range) +{ + ubyte[] bytes = new ubyte[count]; + + for (auto i = 0; i < count; i++) + { + bytes[i] = data.readByte(); + } + + return bytes; +} + string readString(Range)(ref Range data) - if (isRandomAccessRange!(Unqual!(Range)) && is(ElementType!Range == ubyte) && hasSlicing!Range) + if (isRandomAccessRange!(Unqual!(Range)) + && is(ElementType!Range == ubyte) && hasSlicing!Range) { auto length = 0; ubyte[] chars; @@ -42,7 +58,8 @@ string readString(Range)(ref Range data) } uint readInt(Range)(ref Range data) - if (isRandomAccessRange!(Unqual!(Range)) && is(ElementType!Range == ubyte) && hasSlicing!Range) + if (isRandomAccessRange!(Unqual!(Range)) + && is(ElementType!Range == ubyte) && hasSlicing!Range) { auto value = littleEndianToNative!uint(data[0 .. 4]); data = data[4 .. $];