Add .arc file stubs

This commit is contained in:
Les De Ridder 2019-02-23 08:29:45 +01:00
parent 1b83e18cc4
commit b459c60d5b
10 changed files with 212 additions and 42 deletions

2
.gitignore vendored
View File

@ -14,3 +14,5 @@ cm3d2tool-test-*
*.obj
*.lst
out/
*.menu
*.txt

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "dfuse"]
path = dfuse
url = https://github.com/lesderid/dfuse

1
dfuse Submodule

@ -0,0 +1 @@
Subproject commit d92184e5ca90730a2aceef469a393eeed9e9c5c7

View File

@ -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"

View File

@ -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"
}
}

View File

@ -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 ~ " <command>");
writeln();
writeln("usage: " ~ toolPath ~ " [--help] <command> [<args>]");
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 <path> <mountpoint>", "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"]);
}

90
source/cm3d2/arc.d Normal file
View File

@ -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");
}
}

View File

@ -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)

View File

@ -1,3 +1,6 @@
module cm3d2;
public import cm3d2.util;
public import cm3d2.menu;
public import cm3d2.arc;

View File

@ -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 .. $];