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 *.obj
*.lst *.lst
out/ 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" 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"

View File

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

View File

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

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

View File

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

View File

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