Skip to content

Commit a4eb9d4

Browse files
authored
Merge pull request #3 from CromFr/rework-json-format
nwn-gff: changed GffStruct children JSON from object to list
2 parents b63354d + 798244d commit a4eb9d4

File tree

3 files changed

+69
-24
lines changed

3 files changed

+69
-24
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ __[Download nwn-lib-d tools](https://github.com/CromFr/nwn-lib-d/releases)__
2424
| Format | Parsing | Serialization | Comment |
2525
| :-------------: | :----------------: | :----------------: | -------------------------------------------------------------------------------------------------- |
2626
| `gff` | :white_check_mark: | :white_check_mark: | NWN binary. Generated binary file match exactly official NWN2 files (needs to be tested with NWN1) |
27-
| `json` | :white_check_mark: | :white_check_mark: | Json, compatible with [Niv nwn-lib](https://github.com/niv/nwn-lib) |
27+
| `json` | :white_check_mark: | :white_check_mark: | Json |
2828
| `json_minified` | :white_check_mark: | :white_check_mark: | Same as `json` but minified |
29+
| `json_legacy` | :white_check_mark: | :white_check_mark: | Json, compatible with [Niv nwn-lib](https://github.com/niv/nwn-lib) |
2930
| `pretty` | :x: | :white_check_mark: | Human-readable |
3031

3132
+ Pros

source/nwn/gff.d

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -452,21 +452,47 @@ struct GffStruct {
452452
this(in nwnlibd.orderedjson.JSONValue json){
453453
enforce(json.type == JSONType.object, "json value " ~ json.toPrettyString ~ " is not an object");
454454
enforce(json["type"].str == "struct", "json .type "~ json.toPrettyString ~" is not a sruct");
455-
enforce(json["value"].type == JSONType.object, "json .value "~ json.toPrettyString ~" is not an object");
455+
enforce(json["value"].type == JSONType.object || json["value"].type == JSONType.array,
456+
"json .value "~ json.toPrettyString ~" must be an object or a list");
456457
if(auto structId = ("__struct_id" in json))
457458
id = structId.get!uint32_t;
458-
foreach(ref label ; json["value"].objectKeyOrder){
459-
children[label] = GffValue(json["value"][label]);
459+
460+
if(json["value"].type == JSONType.array){
461+
foreach(ref entry ; json["value"].array){
462+
auto label = entry["label"].str;
463+
children.dirtyAppendKeyValue(label, GffValue(entry));
464+
}
465+
}
466+
else{
467+
foreach(ref label ; json["value"].objectKeyOrder){
468+
children[label] = GffValue(json["value"][label]);
469+
}
460470
}
461471
}
462472
/// GffStruct to JSON
463-
nwnlibd.orderedjson.JSONValue toJson() const {
473+
nwnlibd.orderedjson.JSONValue toJson(bool structAsList = true) const {
464474
JSONValue ret;
465475
ret["type"] = "struct";
466476
ret["__struct_id"] = id;
467-
ret["value"] = JSONValue(cast(JSONValue[string])null);
468-
foreach(ref kv ; children.byKeyValue){
469-
ret["value"][kv.key] = kv.value.toJson();
477+
if(structAsList){
478+
ret["value"] = JSONValue(cast(JSONValue[])null);
479+
foreach(ref kv ; children.byKeyValue){
480+
auto value = kv.value.toJson();
481+
value["label"] = kv.key;
482+
483+
// Reorder label
484+
const idx = value.objectKeyOrder[$ - 1];
485+
value.objectKeyOrder = idx ~ value.objectKeyOrder[0 .. $ - 1];
486+
487+
ret["value"].array ~= value;
488+
//ret["value"].array ~= JSONValue(["label": JSONValue(kv.key), "value": kv.value.toJson()]);
489+
}
490+
}
491+
else{
492+
ret["value"] = JSONValue(cast(JSONValue[string])null);
493+
foreach(ref kv ; children.byKeyValue){
494+
ret["value"][kv.key] = kv.value.toJson();
495+
}
470496
}
471497
return ret;
472498
}
@@ -529,13 +555,13 @@ struct GffList {
529555
}
530556
}
531557
/// GffList to JSON
532-
nwnlibd.orderedjson.JSONValue toJson() const {
558+
nwnlibd.orderedjson.JSONValue toJson(bool structAsList = true) const {
533559
JSONValue ret;
534560
ret["type"] = "list";
535561
ret["value"] = JSONValue(cast(JSONValue[])null);
536562
ret["value"].array.length = children.length;
537563
foreach(i, ref child ; children){
538-
ret["value"][i] = child.toJson();
564+
ret["value"][i] = child.toJson(structAsList);
539565
}
540566
return ret;
541567
}
@@ -701,7 +727,7 @@ struct GffValue {
701727
}
702728
}
703729
/// Converts to JSON
704-
nwnlibd.orderedjson.JSONValue toJson() const {
730+
nwnlibd.orderedjson.JSONValue toJson(bool structAsList = true) const {
705731
JSONValue ret;
706732
final switch(type) with(GffType) {
707733
case Byte: ret["value"] = get!GffByte; break;
@@ -718,8 +744,8 @@ struct GffValue {
718744
case ResRef: ret["value"] = get!GffResRef.value; break;
719745
case LocString: return get!GffLocString.toJson;
720746
case Void: ret["value"] = Base64.encode(get!GffVoid).to!string; break;
721-
case Struct: return get!GffStruct.toJson;
722-
case List: return get!GffList.toJson;
747+
case Struct: return get!GffStruct.toJson(structAsList);
748+
case List: return get!GffList.toJson(structAsList);
723749
case Invalid: assert(0, "No type set");
724750
}
725751
ret["type"] = type.gffTypeToCompatStr;
@@ -796,8 +822,8 @@ class Gff{
796822
}
797823

798824
/// Convert to JSON
799-
nwnlibd.orderedjson.JSONValue toJson() const {
800-
auto ret = root.toJson();
825+
nwnlibd.orderedjson.JSONValue toJson(bool structAsList = true) const {
826+
auto ret = root.toJson(structAsList);
801827
ret["__data_type"] = fileType;
802828
ret["__data_version"] = fileVersion;
803829
return ret;

tools/nwn-gff/source/nwn-gff.d

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ int _main(string[] args){
6161
"Parsing and serialization tool for GFF files like ifo, are, bic, uti, ...",
6262
res.options,
6363
multilineStr!`
64+
===============| Formats |===============
65+
Formats supported by the -i and -k arguments:
66+
67+
Name R W
68+
detect x x Guess based on file extension
69+
gff x x Binary GFF (standard NWN GFF file)
70+
json x x JSON
71+
json_minified x x Compact JSON
72+
json_legacy x x JSON compatible with Niv nwn-gff
73+
json_legacy_minified x x Compact JSON compatible with Niv nwn-gff
74+
pretty x Easy to read text format
75+
dump x Dump internal GFF information
76+
6477
===============| Setting nodes |===============
6578
There are 3 ways to set a GFF value:
6679
@@ -172,19 +185,20 @@ int _main(string[] args){
172185
Gff gff;
173186
File inputFile = inputPath == "-"? stdin : File(inputPath, "r");
174187

175-
switch(inputFormat){
188+
final switch(inputFormat){
176189
case Format.gff:
177190
gff = new Gff(inputFile);
178191
break;
179-
case Format.json, Format.json_minified:
192+
case Format.json, Format.json_minified, Format.json_legacy, Format.json_legacy_minified:
180193
import nwnlibd.orderedjson;
181194
gff = new Gff(parseJSON(cast(string)inputFile.readAll.idup, -1, JSONOptions.specialFloatLiterals));
182195
break;
183196
case Format.pretty:
197+
case Format.dump:
184198
enforce(0, inputFormat.to!string~" parsing not supported");
185199
break;
186-
default:
187-
enforce(0, inputFormat.to!string~" parsing not implemented");
200+
case Format.detect:
201+
assert(0);
188202
}
189203
inputFile.close();
190204

@@ -588,15 +602,19 @@ int _main(string[] args){
588602

589603
//Serialization
590604
File outputFile = outputPath is null || outputPath == "-" ? stdout : File(outputPath, "w");
591-
switch(outputFormat){
605+
final switch(outputFormat){
592606
case Format.gff:
593607
outputFile.rawWrite(gff.serialize());
594608
break;
595609
case Format.pretty:
596610
outputFile.writeln(gff.toPrettyString());
597611
break;
598612
case Format.json, Format.json_minified:
599-
auto json = gff.toJson;
613+
auto json = gff.toJson();
614+
outputFile.writeln(outputFormat==Format.json? json.toPrettyString(JSONOptions.specialFloatLiterals) : json.toString(JSONOptions.specialFloatLiterals));
615+
break;
616+
case Format.json_legacy, Format.json_legacy_minified:
617+
auto json = gff.toJson(false);
600618
outputFile.writeln(outputFormat==Format.json? json.toPrettyString(JSONOptions.specialFloatLiterals) : json.toString(JSONOptions.specialFloatLiterals));
601619
break;
602620
case Format.dump:
@@ -605,13 +623,13 @@ int _main(string[] args){
605623
auto fastGff = new FastGff(outData);
606624
outputFile.writeln(fastGff.dump());
607625
break;
608-
default:
609-
assert(0, outputFormat.to!string~" serialization not implemented");
626+
case Format.detect:
627+
assert(0);
610628
}
611629
return 0;
612630
}
613631

614-
enum Format{ detect, gff, json, json_minified, pretty, dump }
632+
enum Format{ detect, gff, json, json_minified, json_legacy, json_legacy_minified, pretty, dump }
615633

616634
Format guessFormat(in string fileName){
617635
import std.path: extension;

0 commit comments

Comments
 (0)