diff --git a/source/app.d b/source/app.d index 040190a..400b63d 100644 --- a/source/app.d +++ b/source/app.d @@ -1,4 +1,6 @@ import std.stdio; +import std.range; +import std.algorithm; import cm3d2; @@ -18,7 +20,9 @@ void main(string[] args) help(args[0]); break; case "menu-to-sdl": - throw new Exception("Not implemented yet"); + ubyte[] data = stdin.byChunk(4096).joiner.array; + writeln(Menu.fromMenu(data).toSDL()); + break; case "sdl-to-menu": throw new Exception("Not implemented yet"); default: diff --git a/source/cm3d2/menu.d b/source/cm3d2/menu.d index a545dde..60c9f93 100644 --- a/source/cm3d2/menu.d +++ b/source/cm3d2/menu.d @@ -1,15 +1,96 @@ module cm3d2.menu; +import std.bitmanip; +import std.conv; +import std.math; + class Menu { + uint fileVersion; + string path; + + string name; + string category; + string description; + + string[][] lines; + public static Menu fromSDL(string sdl) { throw new Exception("Not implemented yet"); } - public static Menu fromMenu(string menu) + public static Menu fromMenu(ubyte[] data) { - throw new Exception("Not implemented yet"); + auto menu = new Menu(); + + ubyte readByte() + { + auto value = data[0]; + data = data[1 .. $]; + return value; + } + + string readString() + { + auto length = 0; + ubyte[] chars; + + while (true) + { + auto lengthByte = readByte(); + + if (length != 0 && lengthByte < 128) + { + break; + } + + length = length << 8 | lengthByte; + + if (lengthByte < 128) + { + break; + } + } + + auto value = cast(string) data[0 .. length]; + data = data[length .. $]; + + return value; + } + + uint readInt() + { + auto value = littleEndianToNative!uint(data[0 .. 4]); + data = data[4 .. $]; + return value; + } + + assert(readString() == "CM3D2_MENU", "Not a valid .menu file"); + + menu.fileVersion = readInt(); + menu.path = readString(); + menu.name = readString(); + menu.category = readString(); + menu.description = readString(); + + assert(readInt() == data.length, "Unexpected data at end of file"); + + while(data.length > 0) + { + string[] line; + + foreach (_; 0 .. readByte()) + { + line ~= readString(); + } + + menu.lines ~= line; + } + + std.stdio.writeln(menu.lines); + + return menu; } public string toMenu()