dexed/resman/tool/resman.d

224 lines
8.3 KiB
D

module resman;
import std.stdio, std.getopt, std.path;
import std.json, std.file, std.conv, std.string;
import utils, item;
enum ResType {aFile, aFolder}
/**
* Resman main procedure.
* Params:
* args = the options and a list of file.
* - -v or --verbose: detailed messages for each operation.
* - -b or --basepath: a path used to solve relative resource filenames.
* - -files: a list of files produced by the Resman widget.
*/
void main(string[] args)
{
string[] files;
string basePath;
bool verbose;
ResourceItems items;
getopt(args, config.passThrough, "v|verbose", &verbose);
getopt(args, config.passThrough, "b|basepath", &basePath);
files = args[1..$];
if (basePath.length && basePath.exists)
{/*setCUrrentDirectory(basePath) : use to solve relative resource path\name*/}
if (!files.length) return; // + verbose, msg
foreach(f; files)
{
json2Items(f, items);
Items2Module(f, items);
}
//readln;
}
static string fmt_json_err = "invalid JSON format: %s, in file '%s'";
static string fmt_file_skp = "invalid JSON file: %s, '%s' is skipped";
static string fmt_item_skp = "invalid JSON item: %s, '%s' is skipped";
static string fmt_item_rep = "invalid JSON value: %s, has been set to '%s'";
/**
* Transforms the items contained in the JSON file fname to an array of
* ResourceItem.
* Params:
* fname = a valid filename.
* items = container for the ResourceItem found in the file.
*/
void json2Items(string fname, out ResourceItems items)
{
if (!fname.exists) {
writeMessage(true, format(fmt_file_skp, "it does not exists", fname));
return;
}
size_t size = cast(size_t) getSize(fname);
if (size == 0) {
writeMessage(true, format(fmt_file_skp, "empty file", fname));
return;
}
auto json_string = cast(string) std.file.read(fname, size);
JSONValue root = parseJSON(json_string);
if (root.type != JSON_TYPE.OBJECT) {
writeMessage(true, format(fmt_json_err, "first value must be of type OBJECT", fname));
return;
}
JSONValue * itms = ("resources" in root.object);
if (itms == null) {
writeMessage(true, format(fmt_json_err, "the member 'resources' is missing", fname));
return;
}
if (itms.type != JSON_TYPE.ARRAY) {
writeMessage(true, format(fmt_json_err, "'resources' must be of type ARRAY", fname));
return;
}
foreach(itm; itms.array)
{
if (itm.type != JSON_TYPE.OBJECT) {
writeMessage(true, format(fmt_item_skp, "an item must be of type OBJECT", itm.toString));
continue;
}
JSONValue * itm_tpe = ("resourceType" in itm.object);
JSONValue * itm_nme = ("name" in itm.object);
JSONValue * itm_idt = ("identifier" in itm.object);
JSONValue * itm_fmt = ("format" in itm.object);
JSONValue * itm_mdt = ("metadata" in itm.object);
if (itm_tpe == null || itm_nme == null || itm_idt == null ||
itm_fmt == null || itm_mdt == null)
{
writeMessage(true, format(fmt_item_skp, "an item must contain all the properties",
itm.toString));
continue;
}
if (itm_tpe.type != JSON_TYPE.STRING || itm_nme.type != JSON_TYPE.STRING ||
itm_idt.type != JSON_TYPE.STRING || itm_fmt.type != JSON_TYPE.STRING ||
itm_mdt.type != JSON_TYPE.STRING)
{
writeMessage(true, format(fmt_item_skp, "an item value must be of type STRING",
itm.toString));
continue;
}
string[] nme_vs;
string nme_v = itm_nme.str;
string idt_v = itm_idt.str;
string mdt_v = itm_mdt.str;
ResType tpe_v;
ResFormat fmt_v;
if (!nme_v.exists) {
writeMessage(true, format(fmt_item_skp, "the item filename or path is invalid", nme_v));
continue;
}
try tpe_v = to!ResType(itm_tpe.str);
catch (Exception e) {
if (isDir(nme_v)) tpe_v = ResType.aFolder;
else tpe_v = ResType.aFile;
writeMessage(true, format(fmt_item_rep, "resourceType", to!string(tpe_v)));
}
try fmt_v = to!ResFormat(itm_fmt.str);
catch (Exception e) {
fmt_v = ResFormat.bytes;
writeMessage(true, format(fmt_item_rep, "format", to!string(fmt_v)));
}
if (idt_v == "" && tpe_v == ResType.aFile)
writeMessage(true, format(fmt_item_rep, "identifier", "the striped filename"));
if (idt_v != "" && tpe_v == ResType.aFolder)
writeMessage(true, format(fmt_item_rep,
"identifier", "the striped filename of each entry in the direrctory"));
if (nme_v.isDir)
{
foreach(e; dirEntries(nme_v, SpanMode.shallow)) nme_vs ~= e;
idt_v = "";
}
else nme_vs ~= nme_v;
foreach(n; nme_vs)
{
items ~= new ResourceItem(n, fmt_v, idt_v, mdt_v);
}
}
}
/**
* Writes the ResourceItems *items* as valid D code D in a file whose content
* will be imported by the library template activateResman(). The file written
* in this method has the same name as the JSON file analyzed before, but with
* another extension.
* Params:
* fname = the name of the JSON file parsed previously.
* items = an array of *ResourceItem*
*/
void Items2Module(string fname, ref ResourceItems resItems)
{
string outputFname = fname.stripExtension ~ ".resdata";
if (outputFname.exists) std.file.remove(outputFname);
// writes the resource representations to the module
writeMessage(true, "writing the resources data as text...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const resource_txt = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ ",", resItems[i].resText));
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ "\r\n];", resItems[$-1].resText));
// writes the resources identifiers to the module
writeMessage(true, "writing the resources identifiers...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const resource_idt = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ ",", resItems[i].resIdentifier));
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ "\r\n];", resItems[$-1].resIdentifier));
// writes the resources metadata to the module
writeMessage(true, "writing the resources metadata...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const resource_mdt = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ ",", resItems[i].resMetaData));
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ "\r\n];", resItems[$-1].resMetaData));
// writes the resources encoder kind to the module
writeMessage(true, "writing the resources kind...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const resource_enc = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t%s.%s,", ResFormat.stringof, resItems[i].resFormat));
outputFname.append(format("\r\n\t%s.%s \r\n];", ResFormat.stringof, resItems[$-1].resFormat));
// writes the initial sums to the module
writeMessage(true, "writing the resources initial sum...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const uint[] resource_sumi = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t" ~ "%.d" ~ ",", resItems[i].initialSum));
outputFname.append(format("\r\n\t" ~ "%.d" ~ "\r\n];", resItems[$-1].initialSum));
// writes the encoded sums to the module
writeMessage(true, "writing the resources encoded sum...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const uint[] resource_sume = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t" ~ "%.d" ~ ",", resItems[i].encodedSum));
outputFname.append(format("\r\n\t" ~ "%.d" ~ "\r\n];", resItems[$-1].encodedSum));
}