Add .arc file stubs
This commit is contained in:
parent
1b83e18cc4
commit
b459c60d5b
|
@ -14,3 +14,5 @@ cm3d2tool-test-*
|
||||||
*.obj
|
*.obj
|
||||||
*.lst
|
*.lst
|
||||||
out/
|
out/
|
||||||
|
*.menu
|
||||||
|
*.txt
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "dfuse"]
|
||||||
|
path = dfuse
|
||||||
|
url = https://github.com/lesderid/dfuse
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit d92184e5ca90730a2aceef469a393eeed9e9c5c7
|
1
dub.sdl
1
dub.sdl
|
@ -4,4 +4,5 @@ authors "lesderid"
|
||||||
copyright "Copyright © 2019, Les De Ridder"
|
copyright "Copyright © 2019, Les De Ridder"
|
||||||
license "NCSA"
|
license "NCSA"
|
||||||
dependency "sdlang-d" version="~>0.10.4"
|
dependency "sdlang-d" version="~>0.10.4"
|
||||||
|
dependency "dfuse" version="~>0.3.0" path="dfuse"
|
||||||
targetPath "out"
|
targetPath "out"
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{
|
{
|
||||||
"fileVersion": 1,
|
"fileVersion": 1,
|
||||||
"versions": {
|
"versions": {
|
||||||
|
"dfuse": {"path":"dfuse"},
|
||||||
"libinputvisitor": "1.2.2",
|
"libinputvisitor": "1.2.2",
|
||||||
"sdlang-d": "0.10.4",
|
"sdlang-d": "0.10.5",
|
||||||
"taggedalgebraic": "0.10.12",
|
"taggedalgebraic": "0.11.2",
|
||||||
"unit-threaded": "0.7.55"
|
"unit-threaded": "0.7.55"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
119
source/app.d
119
source/app.d
|
@ -1,51 +1,102 @@
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.range;
|
import std.range;
|
||||||
import std.algorithm;
|
import std.algorithm;
|
||||||
|
import std.path;
|
||||||
|
import std.file;
|
||||||
|
|
||||||
|
import dfuse.fuse;
|
||||||
|
|
||||||
import cm3d2;
|
import cm3d2;
|
||||||
|
|
||||||
void main(string[] args)
|
void main(string[] args)
|
||||||
{
|
{
|
||||||
if (args.length < 2)
|
if (args.length < 2)
|
||||||
{
|
{
|
||||||
help(args[0]);
|
help(args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (args[1])
|
switch (args[1])
|
||||||
{
|
{
|
||||||
case "help":
|
case "help":
|
||||||
case "-h":
|
case "-h":
|
||||||
case "--help":
|
case "--help":
|
||||||
help(args[0]);
|
help(args[0]);
|
||||||
break;
|
break;
|
||||||
case "menu-to-sdl":
|
case "menu-to-sdl":
|
||||||
ubyte[] data = stdin.byChunk(4096).joiner.array;
|
ubyte[] data = stdin.byChunk(4096).joiner.array;
|
||||||
writeln(Menu.fromMenu(data).toSDL());
|
writeln(Menu.fromMenu(data).toSDL());
|
||||||
break;
|
break;
|
||||||
case "sdl-to-menu":
|
case "sdl-to-menu":
|
||||||
throw new Exception("Not implemented yet");
|
throw new Exception("Not implemented yet");
|
||||||
default:
|
case "mount-arc":
|
||||||
writeln("Unknown option '" ~ args[1] ~ "'");
|
string arcPath;
|
||||||
writeln();
|
string mountpoint;
|
||||||
goto case "help";
|
|
||||||
}
|
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)
|
void help(string toolPath)
|
||||||
{
|
{
|
||||||
writeln("Usage: " ~ toolPath ~ " <command>");
|
writeln("usage: " ~ toolPath ~ " [--help] <command> [<args>]");
|
||||||
writeln();
|
writeln();
|
||||||
|
|
||||||
void showCommandUsage(string command, string description)
|
void showCommandUsage(string command, string description)
|
||||||
{
|
{
|
||||||
writeln(" " ~ toolPath ~ " " ~ command);
|
writeln(" " ~ toolPath ~ " " ~ command);
|
||||||
writeln(" " ~ description);
|
writeln(" " ~ description);
|
||||||
}
|
}
|
||||||
|
|
||||||
showCommandUsage("menu-to-sdl", "Convert .menu to SDL");
|
showCommandUsage("menu-to-sdl", "Convert .menu (from stdin) to SDL (stdout)");
|
||||||
showCommandUsage("sdl-to-menu", "Convert SDL to .menu");
|
showCommandUsage("sdl-to-menu", "Convert SDL (from stdin) to .menu (stdout)");
|
||||||
|
writeln();
|
||||||
|
showCommandUsage("mount-arc <path> <mountpoint>", "FUSE mount arc file(s) on mountpoint");
|
||||||
|
|
||||||
writeln();
|
writeln();
|
||||||
writeln("Reads input from stdin and writes output to stdout.");
|
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"]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import std.range;
|
||||||
|
|
||||||
import sdlang;
|
import sdlang;
|
||||||
|
|
||||||
import cm3d2.util;
|
import cm3d2;
|
||||||
|
|
||||||
class Menu
|
class Menu
|
||||||
{
|
{
|
||||||
|
@ -49,7 +49,7 @@ class Menu
|
||||||
|
|
||||||
assert(data.readInt() == data.length, "Unexpected data at end of file");
|
assert(data.readInt() == data.length, "Unexpected data at end of file");
|
||||||
|
|
||||||
while(data.length > 0)
|
while (data.length > 0)
|
||||||
{
|
{
|
||||||
string[] line;
|
string[] line;
|
||||||
|
|
||||||
|
@ -80,7 +80,8 @@ class Menu
|
||||||
auto categoryTag = new Tag(null, "category", [Value(category)]);
|
auto categoryTag = new Tag(null, "category", [Value(category)]);
|
||||||
auto descriptionTag = new Tag(null, "description", [Value(description)]);
|
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;
|
Tag[] dataTags;
|
||||||
foreach (line; lines)
|
foreach (line; lines)
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
module cm3d2;
|
module cm3d2;
|
||||||
|
|
||||||
|
public import cm3d2.util;
|
||||||
|
|
||||||
public import cm3d2.menu;
|
public import cm3d2.menu;
|
||||||
|
public import cm3d2.arc;
|
||||||
|
|
|
@ -5,15 +5,31 @@ import std.range;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
|
|
||||||
ubyte readByte(Range)(ref Range data)
|
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];
|
auto value = data[0];
|
||||||
data = data[1 .. $];
|
data = data[1 .. $];
|
||||||
return value;
|
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)
|
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;
|
auto length = 0;
|
||||||
ubyte[] chars;
|
ubyte[] chars;
|
||||||
|
@ -42,7 +58,8 @@ string readString(Range)(ref Range data)
|
||||||
}
|
}
|
||||||
|
|
||||||
uint readInt(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]);
|
auto value = littleEndianToNative!uint(data[0 .. 4]);
|
||||||
data = data[4 .. $];
|
data = data[4 .. $];
|
||||||
|
|
Loading…
Reference in New Issue