mirror of
https://github.com/gnosygnu/xowa.git
synced 2026-03-02 03:49:30 +00:00
Skin: Change to mustache-backed Skin.Vector [#797]
This commit is contained in:
69
400_xowa/src/gplx/langs/jsons/JsonDocBldr.java
Normal file
69
400_xowa/src/gplx/langs/jsons/JsonDocBldr.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_;
|
||||
import gplx.List_adp;
|
||||
import gplx.List_adp_;
|
||||
import gplx.String_;
|
||||
|
||||
public class JsonDocBldr {
|
||||
private final List_adp stack = List_adp_.New();
|
||||
private final Json_doc doc = new Json_doc();
|
||||
private Json_grp root;
|
||||
private Json_grp cur;
|
||||
JsonDocBldr() {}
|
||||
public JsonDocBldr Clear(boolean isRootNode) {
|
||||
this.root = isRootNode ? Json_nde.NewByDoc(doc, 0) : Json_ary.NewByDoc(doc, 0, 0);
|
||||
doc.Ctor(Bry_.Empty, root);
|
||||
this.cur = root;
|
||||
stack.Clear();
|
||||
return this;
|
||||
}
|
||||
public JsonDocBldr NdeBgn(String key) {
|
||||
Json_nde nde = Json_nde.NewByDoc(doc, 1);
|
||||
if (cur.Tid() == Json_itm_.Tid__nde) {
|
||||
Json_kv kv = new Json_kv(Json_itm_str.NewByVal(key), nde);
|
||||
cur.Add(kv);
|
||||
}
|
||||
else {
|
||||
cur.Add(nde);
|
||||
}
|
||||
stack.Add(cur);
|
||||
cur = nde;
|
||||
return this;
|
||||
}
|
||||
public JsonDocBldr NdeEnd() {
|
||||
this.cur = (Json_grp)List_adp_.Pop_last(stack);
|
||||
return this;
|
||||
}
|
||||
public JsonDocBldr KvBool(String key, boolean val) {return Kv(key, Json_itm_bool.Get(val));}
|
||||
public JsonDocBldr KvInt(String key, int val) {return Kv(key, Json_itm_int.NewByVal(val));}
|
||||
public JsonDocBldr KvStr(String key, byte[] val) {return Kv(key, Json_itm_str.NewByVal(String_.new_u8(val)));}
|
||||
public JsonDocBldr KvStr(String key, String val) {return Kv(key, Json_itm_str.NewByVal(val));}
|
||||
private JsonDocBldr Kv(String key, Json_itm val) {
|
||||
Json_kv rv = new Json_kv(Json_itm_str.NewByVal(key), val);
|
||||
cur.Add(rv);
|
||||
return this;
|
||||
}
|
||||
public Json_doc ToDoc() {
|
||||
return doc;
|
||||
}
|
||||
public Json_nde ToRootNde() {
|
||||
return doc.Root_nde();
|
||||
}
|
||||
public static JsonDocBldr NewRootNde() {return new JsonDocBldr().Clear(true);}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,66 +13,75 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public class Json_ary extends Json_itm_base implements Json_grp {
|
||||
public Json_ary(int src_bgn, int src_end) {this.Ctor(src_bgn, src_end);}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__ary;}
|
||||
public void Src_end_(int v) {this.src_end = v;}
|
||||
@Override public Object Data() {return null;}
|
||||
@Override public byte[] Data_bry() {return null;}
|
||||
public int Len() {return subs_len;} private int subs_len = 0, subs_max = 0;
|
||||
public Json_nde Get_at_as_nde(int i) {
|
||||
Json_itm rv = subs[i]; if (rv.Tid() != Json_itm_.Tid__nde) throw Err_.new_("json", "itm is not nde", "type", rv.Tid(), "i", i);
|
||||
return (Json_nde)rv;
|
||||
}
|
||||
public Json_itm Get_at(int i) {return subs[i];}
|
||||
public Json_nde Get_as_nde(int i) {return Json_nde.cast(subs[i]);}
|
||||
public Json_ary Add_many(Json_itm... ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
Add(ary[i]);
|
||||
return this;
|
||||
}
|
||||
public void Add(Json_itm itm) {
|
||||
int new_len = subs_len + 1;
|
||||
if (new_len > subs_max) { // ary too small >>> expand
|
||||
subs_max = new_len * 2;
|
||||
Json_itm[] new_subs = new Json_itm[subs_max];
|
||||
Array_.Copy_to(subs, 0, new_subs, 0, subs_len);
|
||||
subs = new_subs;
|
||||
}
|
||||
subs[subs_len] = itm;
|
||||
subs_len = new_len;
|
||||
}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
if (subs_len == 0) { // empty grp; print on one line (rather than printing across 3)
|
||||
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Brack_end);
|
||||
return;
|
||||
}
|
||||
bfr.Add_byte_nl();
|
||||
Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Space);
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
if (i != 0) {
|
||||
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
|
||||
}
|
||||
subs[i].Print_as_json(bfr, depth + 1);
|
||||
}
|
||||
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Brack_end).Add_byte_nl();
|
||||
}
|
||||
public byte[][] Xto_bry_ary() {
|
||||
if (subs_len == 0) return Bry_.Ary_empty;
|
||||
byte[][] rv = new byte[subs_len][];
|
||||
for (int i = 0; i < subs_len; ++i)
|
||||
rv[i] = subs[i].Data_bry();
|
||||
return rv;
|
||||
}
|
||||
private Json_itm[] subs = Json_itm_.Ary_empty;
|
||||
public static Json_ary cast_or_null(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__ary ? null : (Json_ary)v;}
|
||||
public static Json_ary cast(Json_itm v) {
|
||||
if (v == null || v.Tid() != Json_itm_.Tid__ary) throw Err_.new_("json", "itm is not array");
|
||||
return (Json_ary)v;
|
||||
}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Array_;
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Byte_ascii;
|
||||
import gplx.Err_;
|
||||
|
||||
public class Json_ary extends Json_itm_base implements Json_grp {
|
||||
private Json_ary() {}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__ary;}
|
||||
public void Src_end_(int v) {}
|
||||
@Override public Object Data() {return null;}
|
||||
@Override public byte[] Data_bry() {return null;}
|
||||
public int Len() {return subs_len;} private int subs_len = 0, subs_max = 0;
|
||||
public Json_nde Get_at_as_nde(int i) {
|
||||
Json_itm rv = subs[i]; if (rv.Tid() != Json_itm_.Tid__nde) throw Err_.new_("json", "itm is not nde", "type", rv.Tid(), "i", i);
|
||||
return (Json_nde)rv;
|
||||
}
|
||||
public Json_itm Get_at(int i) {return subs[i];}
|
||||
public Json_nde Get_as_nde(int i) {return Json_nde.Cast(subs[i]);}
|
||||
public Json_ary Add_many(Json_itm... ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
Add(ary[i]);
|
||||
return this;
|
||||
}
|
||||
public void Add(Json_itm itm) {
|
||||
int new_len = subs_len + 1;
|
||||
if (new_len > subs_max) { // ary too small >>> expand
|
||||
subs_max = new_len * 2;
|
||||
Json_itm[] new_subs = new Json_itm[subs_max];
|
||||
Array_.Copy_to(subs, 0, new_subs, 0, subs_len);
|
||||
subs = new_subs;
|
||||
}
|
||||
subs[subs_len] = itm;
|
||||
subs_len = new_len;
|
||||
}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
if (subs_len == 0) { // empty grp; print on one line (rather than printing across 3)
|
||||
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Brack_end);
|
||||
return;
|
||||
}
|
||||
bfr.Add_byte_nl();
|
||||
Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Space);
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
if (i != 0) {
|
||||
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
|
||||
}
|
||||
subs[i].Print_as_json(bfr, depth + 1);
|
||||
}
|
||||
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Brack_end).Add_byte_nl();
|
||||
}
|
||||
public byte[][] Xto_bry_ary() {
|
||||
if (subs_len == 0) return Bry_.Ary_empty;
|
||||
byte[][] rv = new byte[subs_len][];
|
||||
for (int i = 0; i < subs_len; ++i)
|
||||
rv[i] = subs[i].Data_bry();
|
||||
return rv;
|
||||
}
|
||||
private Json_itm[] subs = Json_itm_.Ary_empty;
|
||||
public static Json_ary cast_or_null(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__ary ? null : (Json_ary)v;}
|
||||
public static Json_ary cast(Json_itm v) {
|
||||
if (v == null || v.Tid() != Json_itm_.Tid__ary) throw Err_.new_("json", "itm is not array");
|
||||
return (Json_ary)v;
|
||||
}
|
||||
public static Json_ary NewByDoc(Json_doc doc, int src_bgn, int src_end) {return new Json_ary();}
|
||||
public static Json_ary NewByVal() {return new Json_ary();}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,75 +13,82 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
import gplx.core.primitives.*;
|
||||
public class Json_doc {
|
||||
private final byte[][] tmp_qry_bry = new byte[1][];
|
||||
public void Ctor(byte[] src, Json_grp new_root) {
|
||||
this.src = src;
|
||||
this.root_grp = new_root;
|
||||
switch (root_grp.Tid()) {
|
||||
case Json_itm_.Tid__nde: this.root_ary = null; this.root_nde = (Json_nde)root_grp; break;
|
||||
case Json_itm_.Tid__ary: this.root_nde = null; this.root_ary = (Json_ary)root_grp; break;
|
||||
default: throw Err_.new_unhandled(root_grp.Tid());
|
||||
}
|
||||
}
|
||||
public byte[] Src() {return src;} private byte[] src;
|
||||
public Json_grp Root_grp() {return root_grp;} private Json_grp root_grp;
|
||||
public Json_nde Root_nde() {return root_nde;} private Json_nde root_nde;
|
||||
public Json_ary Root_ary() {return root_ary;} private Json_ary root_ary;
|
||||
public Bry_bfr Bfr() {return bfr;} private final Bry_bfr bfr = Bry_bfr_.New();
|
||||
public Gfo_number_parser Utl_num_parser() {return utl_num_parser;} private final Gfo_number_parser utl_num_parser = new Gfo_number_parser();
|
||||
public byte[] Tmp_u8_bry() {return tmp_u8_bry;} private final byte[] tmp_u8_bry = new byte[6]; // tmp bry[] for decoding sequences like \u0008
|
||||
public byte[] Get_val_as_bry_or(byte[] qry_bry, byte[] or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_bry_or(tmp_qry_bry, or);}
|
||||
public byte[] Get_val_as_bry_or(byte[][] qry_bry, byte[] or) {
|
||||
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
|
||||
return nde == null || nde.Tid() != Json_itm_.Tid__str ? or : nde.Data_bry();
|
||||
}
|
||||
public String Get_val_as_str_or(byte[] qry_bry, String or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_str_or(tmp_qry_bry, or);}
|
||||
public String Get_val_as_str_or(byte[][] qry_bry, String or) {
|
||||
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
|
||||
return nde == null || nde.Tid() != Json_itm_.Tid__str ? or : (String)nde.Data();
|
||||
}
|
||||
public int Get_val_as_int_or(byte[] qry_bry, int or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_int_or(tmp_qry_bry, or);}
|
||||
public int Get_val_as_int_or(byte[][] qry_bry, int or) {
|
||||
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
|
||||
return nde == null || nde.Tid() != Json_itm_.Tid__int ? or : Bry_.To_int(nde.Data_bry());
|
||||
}
|
||||
public Json_grp Get_grp(byte[] qry_bry) {
|
||||
tmp_qry_bry[0] = qry_bry;
|
||||
Json_itm rv = Find_nde(root_nde, tmp_qry_bry, 0, 0); if (rv == null) return null;
|
||||
return (Json_grp)rv;
|
||||
}
|
||||
public Json_grp Get_grp_many(String... qry_ary) {return Get_grp_many(Bry_.Ary(qry_ary));}
|
||||
public Json_grp Get_grp_many(byte[]... qry_bry) {
|
||||
Json_itm rv = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0); if (rv == null) return null;
|
||||
return (Json_grp)rv;
|
||||
}
|
||||
public Json_itm Find_nde(byte[] key) {
|
||||
tmp_qry_bry[0] = key;
|
||||
return Find_nde(root_nde, tmp_qry_bry, 0, 0);
|
||||
}
|
||||
private Json_itm Find_nde(Json_nde owner, byte[][] paths, int paths_last, int paths_idx) {
|
||||
byte[] path = paths[paths_idx];
|
||||
int subs_len = owner.Len();
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
Json_kv itm = Json_kv.cast(owner.Get_at(i)); if (itm == null) continue; // ignore simple props, arrays, ndes
|
||||
if (!itm.Key_eq(path)) continue;
|
||||
if (paths_idx == paths_last) return itm.Val();
|
||||
Json_nde sub_nde = Json_nde.cast(itm.Val()); if (sub_nde == null) return null; // match, but has not a nde; exit
|
||||
return Find_nde(sub_nde, paths, paths_last, paths_idx + 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static String Make_str_by_apos(String... ary) {return String_.Replace(String_.Concat_lines_nl_skip_last(ary), "'", "\"");}
|
||||
public static String[] Make_str_ary_by_apos(String... ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
String itm = ary[i];
|
||||
if (String_.Has(itm, "'"))
|
||||
ary[i] = String_.Replace(itm, "'", "\"");
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Bry_bfr_;
|
||||
import gplx.Err_;
|
||||
import gplx.String_;
|
||||
import gplx.core.primitives.Gfo_number_parser;
|
||||
|
||||
public class Json_doc {
|
||||
private final byte[][] tmp_qry_bry = new byte[1][];
|
||||
public void Ctor(byte[] src, Json_grp new_root) {
|
||||
this.src = src;
|
||||
this.root_grp = new_root;
|
||||
switch (root_grp.Tid()) {
|
||||
case Json_itm_.Tid__nde: this.root_ary = null; this.root_nde = (Json_nde)root_grp; break;
|
||||
case Json_itm_.Tid__ary: this.root_nde = null; this.root_ary = (Json_ary)root_grp; break;
|
||||
default: throw Err_.new_unhandled(root_grp.Tid());
|
||||
}
|
||||
}
|
||||
public byte[] Src() {return src;} private byte[] src;
|
||||
public Json_grp Root_grp() {return root_grp;} private Json_grp root_grp;
|
||||
public Json_nde Root_nde() {return root_nde;} private Json_nde root_nde;
|
||||
public Json_ary Root_ary() {return root_ary;} private Json_ary root_ary;
|
||||
public Bry_bfr Bfr() {return bfr;} private final Bry_bfr bfr = Bry_bfr_.New();
|
||||
public Gfo_number_parser Utl_num_parser() {return utl_num_parser;} private final Gfo_number_parser utl_num_parser = new Gfo_number_parser();
|
||||
public byte[] Tmp_u8_bry() {return tmp_u8_bry;} private final byte[] tmp_u8_bry = new byte[6]; // tmp bry[] for decoding sequences like \u0008
|
||||
public byte[] Get_val_as_bry_or(byte[] qry_bry, byte[] or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_bry_or(tmp_qry_bry, or);}
|
||||
public byte[] Get_val_as_bry_or(byte[][] qry_bry, byte[] or) {
|
||||
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
|
||||
return nde == null || nde.Tid() != Json_itm_.Tid__str ? or : nde.Data_bry();
|
||||
}
|
||||
public String Get_val_as_str_or(byte[] qry_bry, String or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_str_or(tmp_qry_bry, or);}
|
||||
public String Get_val_as_str_or(byte[][] qry_bry, String or) {
|
||||
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
|
||||
return nde == null || nde.Tid() != Json_itm_.Tid__str ? or : (String)nde.Data();
|
||||
}
|
||||
public int Get_val_as_int_or(byte[] qry_bry, int or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_int_or(tmp_qry_bry, or);}
|
||||
public int Get_val_as_int_or(byte[][] qry_bry, int or) {
|
||||
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
|
||||
return nde == null || nde.Tid() != Json_itm_.Tid__int ? or : Bry_.To_int(nde.Data_bry());
|
||||
}
|
||||
public Json_grp Get_grp(byte[] qry_bry) {
|
||||
tmp_qry_bry[0] = qry_bry;
|
||||
Json_itm rv = Find_nde(root_nde, tmp_qry_bry, 0, 0); if (rv == null) return null;
|
||||
return (Json_grp)rv;
|
||||
}
|
||||
public Json_grp Get_grp_many(String... qry_ary) {return Get_grp_many(Bry_.Ary(qry_ary));}
|
||||
public Json_grp Get_grp_many(byte[]... qry_bry) {
|
||||
Json_itm rv = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0); if (rv == null) return null;
|
||||
return (Json_grp)rv;
|
||||
}
|
||||
public Json_itm Find_nde(byte[] key) {
|
||||
tmp_qry_bry[0] = key;
|
||||
return Find_nde(root_nde, tmp_qry_bry, 0, 0);
|
||||
}
|
||||
private Json_itm Find_nde(Json_nde owner, byte[][] paths, int paths_last, int paths_idx) {
|
||||
byte[] path = paths[paths_idx];
|
||||
int subs_len = owner.Len();
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
Json_kv itm = Json_kv.Cast(owner.Get_at(i)); if (itm == null) continue; // ignore simple props, arrays, ndes
|
||||
if (!itm.Key_eq(path)) continue;
|
||||
if (paths_idx == paths_last) return itm.Val();
|
||||
Json_nde sub_nde = Json_nde.Cast(itm.Val()); if (sub_nde == null) return null; // match, but has not a nde; exit
|
||||
return Find_nde(sub_nde, paths, paths_last, paths_idx + 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static String Make_str_by_apos(String... ary) {return String_.Replace(String_.Concat_lines_nl_skip_last(ary), "'", "\"");}
|
||||
public static String[] Make_str_ary_by_apos(String... ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
String itm = ary[i];
|
||||
if (String_.Has(itm, "'"))
|
||||
ary[i] = String_.Replace(itm, "'", "\"");
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public class Json_doc_bldr {
|
||||
public Json_nde Nde(Json_doc jdoc) {return factory.Nde(jdoc, -1);}
|
||||
public Json_nde Nde(Json_doc jdoc, Json_grp owner) {
|
||||
Json_nde rv = factory.Nde(jdoc, -1);
|
||||
owner.Add(rv);
|
||||
return rv;
|
||||
}
|
||||
public Json_itm Str(byte[] v) {return Str(String_.new_u8(v));}
|
||||
public Json_itm Str(String v) {return Json_itm_tmp.new_str_(v);}
|
||||
public Json_itm Int(int v) {return Json_itm_tmp.new_int_(v);}
|
||||
public Json_kv Kv_int(Json_grp owner, String key, int val) {Json_kv rv = factory.Kv(Json_itm_tmp.new_str_(key), Json_itm_tmp.new_int_(val)); owner.Add(rv); return rv;}
|
||||
public Json_kv Kv_str(Json_grp owner, String key, String val) {Json_kv rv = factory.Kv(Json_itm_tmp.new_str_(key), Json_itm_tmp.new_str_(val)); owner.Add(rv); return rv;}
|
||||
public Json_ary Kv_ary(Json_grp owner, String key, Json_itm... subs) {
|
||||
Json_itm key_itm = Json_itm_tmp.new_str_(key);
|
||||
Json_ary val_ary = factory.Ary(-1, -1);
|
||||
Json_kv kv = factory.Kv(key_itm, val_ary);
|
||||
owner.Add(kv);
|
||||
int len = subs.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
val_ary.Add(subs[i]);
|
||||
return val_ary;
|
||||
}
|
||||
Json_doc doc = new Json_doc(); Json_factory factory = new Json_factory();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,140 +13,155 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
import gplx.objects.strings.unicodes.*;
|
||||
import gplx.core.encoders.*;
|
||||
public class Json_doc_wtr {
|
||||
private int indent = -2;
|
||||
private Bry_bfr bfr = Bry_bfr_.Reset(255);
|
||||
public void Opt_unicode_y_() {opt_unicode = true;} private boolean opt_unicode;
|
||||
public Json_doc_wtr Indent() {return Indent(indent);}
|
||||
private Json_doc_wtr Indent(int v) {if (v > 0) bfr.Add_byte_repeat(Byte_ascii.Space, v); return this;}
|
||||
public Json_doc_wtr Indent_add() {indent += 2; return this;}
|
||||
public Json_doc_wtr Indent_del() {indent -= 2; return this;}
|
||||
public Json_doc_wtr Nde_bgn() {Indent_add(); Indent(); bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte_nl(); return this;}
|
||||
public Json_doc_wtr Nde_end() { Indent(); bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl(); Indent_del(); return this;}
|
||||
public Json_doc_wtr Ary_bgn() {Indent_add(); Indent(); bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte_nl(); return this;}
|
||||
public Json_doc_wtr Ary_end() { Indent(); bfr.Add_byte(Byte_ascii.Brack_end).Add_byte_nl(); Indent_del(); return this;}
|
||||
public Json_doc_wtr New_line() {bfr.Add_byte_nl(); return this;}
|
||||
public Json_doc_wtr Str(byte[] v) {
|
||||
if (v == null)
|
||||
bfr.Add(Object_.Bry__null);
|
||||
else {
|
||||
bfr.Add_byte(Byte_ascii.Quote);
|
||||
if (opt_unicode) {
|
||||
Ustring ustr = Ustring_.New_codepoints(String_.new_u8(v));
|
||||
int ustr_len = ustr.Len_in_data();
|
||||
for (int i = 0; i < ustr_len; i++) {
|
||||
int cp = ustr.Get_data(i);
|
||||
Write_str_codepoint(bfr, cp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bfr.Add_bry_escape(Byte_ascii.Quote, Escaped__quote, v, 0, v.length);
|
||||
}
|
||||
bfr.Add_byte(Byte_ascii.Quote);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
private void Write_str_codepoint(Bry_bfr bfr, int val) {
|
||||
switch (val) { // REF: https://www.json.org/
|
||||
case Byte_ascii.Quote:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Quote);
|
||||
break;
|
||||
case Byte_ascii.Backslash:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Backslash);
|
||||
break;
|
||||
case Byte_ascii.Backfeed:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_b);
|
||||
break;
|
||||
case Byte_ascii.Formfeed:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_f);
|
||||
break;
|
||||
case Byte_ascii.Nl:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_n);
|
||||
break;
|
||||
case Byte_ascii.Cr:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_r);
|
||||
break;
|
||||
case Byte_ascii.Tab:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_t);
|
||||
break;
|
||||
default:
|
||||
if ( val < Byte_ascii.Space // control characters
|
||||
|| val == 160 // nbsp
|
||||
|| val == 8206 // left to right
|
||||
|| val == 8207 // right to left
|
||||
) {
|
||||
// convert to \u1234
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_u).Add_str_a7(Hex_utl_.To_str(val, 4));
|
||||
}
|
||||
else {
|
||||
bfr.Add_u8_int(val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
public Json_doc_wtr Int(int v) {bfr.Add_int_variable(v); return this;}
|
||||
public Json_doc_wtr Double(double v) {bfr.Add_double(v); return this;}
|
||||
public Json_doc_wtr Comma() {Indent(); bfr.Add_byte(Byte_ascii.Comma).Add_byte_nl(); return this;}
|
||||
public Json_doc_wtr Kv_ary_empty(boolean comma, byte[] key) {
|
||||
Key_internal(comma, key);
|
||||
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Brack_end);
|
||||
bfr.Add_byte_nl();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Kv(boolean comma, byte[] key, byte[] val) {
|
||||
Key_internal(comma, key);
|
||||
Str(val);
|
||||
bfr.Add_byte_nl();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Kv_double(boolean comma, byte[] key, double v) {
|
||||
Key_internal(comma, key);
|
||||
Double(v);
|
||||
bfr.Add_byte_nl();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Kv(boolean comma, byte[] key, int v) {
|
||||
Key_internal(comma, key);
|
||||
Int(v);
|
||||
bfr.Add_byte_nl();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Key(boolean comma, String key) {return Key(comma, Bry_.new_u8(key));}
|
||||
public Json_doc_wtr Key(boolean comma, byte[] key) {
|
||||
Key_internal(comma, key);
|
||||
bfr.Add_byte_nl();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Val(boolean comma, int v) {
|
||||
Val_internal(comma);
|
||||
Int(v);
|
||||
New_line();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Val(boolean comma, byte[] v) {
|
||||
Val_internal(comma);
|
||||
Str(v);
|
||||
New_line();
|
||||
return this;
|
||||
}
|
||||
Json_doc_wtr Val_internal(boolean comma) {
|
||||
Indent();
|
||||
bfr.Add_byte(comma ? Byte_ascii.Comma : Byte_ascii.Space);
|
||||
bfr.Add_byte(Byte_ascii.Space);
|
||||
return this;
|
||||
}
|
||||
Json_doc_wtr Key_internal(boolean comma, byte[] key) {
|
||||
Indent();
|
||||
bfr.Add_byte(comma ? Byte_ascii.Comma : Byte_ascii.Space);
|
||||
bfr.Add_byte(Byte_ascii.Space);
|
||||
Str(key);
|
||||
bfr.Add_byte(Byte_ascii.Colon);
|
||||
return this;
|
||||
}
|
||||
public byte[] Bld() {return bfr.To_bry_and_clear();}
|
||||
public String Bld_as_str() {return bfr.To_str_and_clear();}
|
||||
private static final byte[] Escaped__quote = Bry_.new_a7("\\\"");
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bool_;
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Bry_bfr_;
|
||||
import gplx.Byte_ascii;
|
||||
import gplx.Double_;
|
||||
import gplx.Object_;
|
||||
import gplx.String_;
|
||||
import gplx.core.encoders.Hex_utl_;
|
||||
import gplx.objects.strings.unicodes.Ustring;
|
||||
import gplx.objects.strings.unicodes.Ustring_;
|
||||
|
||||
public class Json_doc_wtr {
|
||||
private int indent = -2;
|
||||
private Bry_bfr bfr = Bry_bfr_.Reset(255);
|
||||
public void Opt_unicode_y_() {opt_unicode = true;} private boolean opt_unicode;
|
||||
public Json_doc_wtr Indent() {return Indent(indent);}
|
||||
private Json_doc_wtr Indent(int v) {if (v > 0) bfr.Add_byte_repeat(Byte_ascii.Space, v); return this;}
|
||||
public Json_doc_wtr Indent_add() {indent += 2; return this;}
|
||||
public Json_doc_wtr Indent_del() {indent -= 2; return this;}
|
||||
public Json_doc_wtr Nde_bgn() {Indent_add(); Indent(); bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte_nl(); return this;}
|
||||
public Json_doc_wtr Nde_end() { Indent(); bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl(); Indent_del(); return this;}
|
||||
public Json_doc_wtr Ary_bgn() {Indent_add(); Indent(); bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte_nl(); return this;}
|
||||
public Json_doc_wtr Ary_end() { Indent(); bfr.Add_byte(Byte_ascii.Brack_end).Add_byte_nl(); Indent_del(); return this;}
|
||||
public Json_doc_wtr New_line() {bfr.Add_byte_nl(); return this;}
|
||||
public Json_doc_wtr Str(byte[] v) {
|
||||
if (v == null)
|
||||
bfr.Add(Object_.Bry__null);
|
||||
else {
|
||||
bfr.Add_byte(Byte_ascii.Quote);
|
||||
if (opt_unicode) {
|
||||
Ustring ustr = Ustring_.New_codepoints(String_.new_u8(v));
|
||||
int ustr_len = ustr.Len_in_data();
|
||||
for (int i = 0; i < ustr_len; i++) {
|
||||
int cp = ustr.Get_data(i);
|
||||
Write_str_codepoint(bfr, cp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bfr.Add_bry_escape(Byte_ascii.Quote, Escaped__quote, v, 0, v.length);
|
||||
}
|
||||
bfr.Add_byte(Byte_ascii.Quote);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
private void Write_str_codepoint(Bry_bfr bfr, int val) {
|
||||
switch (val) { // REF: https://www.json.org/
|
||||
case Byte_ascii.Quote:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Quote);
|
||||
break;
|
||||
case Byte_ascii.Backslash:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Backslash);
|
||||
break;
|
||||
case Byte_ascii.Backfeed:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_b);
|
||||
break;
|
||||
case Byte_ascii.Formfeed:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_f);
|
||||
break;
|
||||
case Byte_ascii.Nl:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_n);
|
||||
break;
|
||||
case Byte_ascii.Cr:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_r);
|
||||
break;
|
||||
case Byte_ascii.Tab:
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_t);
|
||||
break;
|
||||
default:
|
||||
if ( val < Byte_ascii.Space // control characters
|
||||
|| val == 160 // nbsp
|
||||
|| val == 8206 // left to right
|
||||
|| val == 8207 // right to left
|
||||
) {
|
||||
// convert to \u1234
|
||||
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_u).Add_str_a7(Hex_utl_.To_str(val, 4));
|
||||
}
|
||||
else {
|
||||
bfr.Add_u8_int(val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
public Json_doc_wtr Int(int v) {bfr.Add_int_variable(v); return this;}
|
||||
public Json_doc_wtr Double(double v) {bfr.Add_double(v); return this;}
|
||||
public Json_doc_wtr Comma() {Indent(); bfr.Add_byte(Byte_ascii.Comma).Add_byte_nl(); return this;}
|
||||
public Json_doc_wtr Kv_ary_empty(boolean comma, byte[] key) {
|
||||
Key_internal(comma, key);
|
||||
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Brack_end);
|
||||
bfr.Add_byte_nl();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Kv(boolean comma, String key, byte[] val) {return Kv(comma, Bry_.new_u8(key), val);}
|
||||
public Json_doc_wtr Kv(boolean comma, byte[] key, byte[] val) {
|
||||
Key_internal(comma, key);
|
||||
Str(val);
|
||||
bfr.Add_byte_nl();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Kv_double(boolean comma, byte[] key, double v) {
|
||||
Key_internal(comma, key);
|
||||
Double(v);
|
||||
bfr.Add_byte_nl();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Kv(boolean comma, String key, int v) {return Kv(comma, Bry_.new_u8(key), v);}
|
||||
public Json_doc_wtr Kv(boolean comma, byte[] key, int v) {
|
||||
Key_internal(comma, key);
|
||||
Int(v);
|
||||
bfr.Add_byte_nl();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Kv(boolean comma, String key, double v) {return Kv(comma, Bry_.new_u8(key), Bry_.new_u8(Double_.To_str(v)));}
|
||||
public Json_doc_wtr Kv(boolean comma, String key, boolean v) {return Kv(comma, Bry_.new_u8(key), v ? Bool_.Y_bry : Bool_.N_bry);}
|
||||
public Json_doc_wtr Key(boolean comma, String key) {return Key(comma, Bry_.new_u8(key));}
|
||||
public Json_doc_wtr Key(boolean comma, byte[] key) {
|
||||
Key_internal(comma, key);
|
||||
bfr.Add_byte_nl();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Val(boolean comma, int v) {
|
||||
Val_internal(comma);
|
||||
Int(v);
|
||||
New_line();
|
||||
return this;
|
||||
}
|
||||
public Json_doc_wtr Val(boolean comma, byte[] v) {
|
||||
Val_internal(comma);
|
||||
Str(v);
|
||||
New_line();
|
||||
return this;
|
||||
}
|
||||
Json_doc_wtr Val_internal(boolean comma) {
|
||||
Indent();
|
||||
bfr.Add_byte(comma ? Byte_ascii.Comma : Byte_ascii.Space);
|
||||
bfr.Add_byte(Byte_ascii.Space);
|
||||
return this;
|
||||
}
|
||||
Json_doc_wtr Key_internal(boolean comma, byte[] key) {
|
||||
Indent();
|
||||
bfr.Add_byte(comma ? Byte_ascii.Comma : Byte_ascii.Space);
|
||||
bfr.Add_byte(Byte_ascii.Space);
|
||||
Str(key);
|
||||
bfr.Add_byte(Byte_ascii.Colon);
|
||||
return this;
|
||||
}
|
||||
public byte[] Bld() {return bfr.To_bry_and_clear();}
|
||||
public String Bld_as_str() {return bfr.To_str_and_clear();}
|
||||
private static final byte[] Escaped__quote = Bry_.new_a7("\\\"");
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public class Json_factory {
|
||||
public Json_itm Null() {return Json_itm_null.Null;}
|
||||
public Json_itm Bool_n() {return Json_itm_bool.Bool_n;}
|
||||
public Json_itm Bool_y() {return Json_itm_bool.Bool_y;}
|
||||
public Json_itm_int Int(Json_doc doc, int bgn, int end) {return new Json_itm_int(doc, bgn, end);}
|
||||
public Json_itm_long Long(Json_doc doc, int bgn, int end) {return new Json_itm_long(doc, bgn, end);}
|
||||
public Json_itm Decimal(Json_doc doc, int bgn, int end) {return new Json_itm_decimal(doc, bgn, end);}
|
||||
public Json_itm Str(Json_doc doc, int bgn, int end, boolean exact) {return new Json_itm_str(doc, bgn, end, exact);}
|
||||
public Json_kv Kv(Json_itm key, Json_itm val) {return new Json_kv(key, val);}
|
||||
public Json_ary Ary(int bgn, int end) {return new Json_ary(bgn, end);}
|
||||
public Json_nde Nde(Json_doc doc, int bgn) {return new Json_nde(doc, bgn);}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,21 +13,23 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public interface Json_itm {
|
||||
byte Tid();
|
||||
int Src_bgn();
|
||||
int Src_end();
|
||||
Object Data();
|
||||
byte[] Data_bry();
|
||||
void Print_as_json(Bry_bfr bfr, int depth);
|
||||
boolean Data_eq(byte[] comp);
|
||||
}
|
||||
class Json_itm_null extends Json_itm_base {
|
||||
Json_itm_null() {this.Ctor(-1, -1);}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__null;}
|
||||
@Override public Object Data() {return null;}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add(Object_.Bry__null);}
|
||||
@Override public byte[] Data_bry() {return Object_.Bry__null;}
|
||||
public static final Json_itm_null Null = new Json_itm_null();
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Object_;
|
||||
|
||||
public interface Json_itm {
|
||||
byte Tid();
|
||||
Object Data();
|
||||
byte[] Data_bry();
|
||||
boolean Data_eq(byte[] comp);
|
||||
void Print_as_json(Bry_bfr bfr, int depth);
|
||||
}
|
||||
class Json_itm_null extends Json_itm_base {
|
||||
Json_itm_null() {}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__null;}
|
||||
@Override public Object Data() {return null;}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add(Object_.Bry__null);}
|
||||
@Override public byte[] Data_bry() {return Object_.Bry__null;}
|
||||
public static final Json_itm_null Null = new Json_itm_null();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,15 +13,20 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public abstract class Json_itm_base implements Json_itm {
|
||||
public abstract byte Tid();
|
||||
public void Ctor(int src_bgn, int src_end) {this.src_bgn = src_bgn; this.src_end = src_end;}
|
||||
public int Src_bgn() {return src_bgn;} private int src_bgn;
|
||||
public int Src_end() {return src_end;} protected int src_end;
|
||||
public abstract Object Data();
|
||||
public abstract byte[] Data_bry();
|
||||
public String Print_as_json() {Bry_bfr bfr = Bry_bfr_.New(); Print_as_json(bfr, 0); return bfr.To_str_and_clear();}
|
||||
public abstract void Print_as_json(Bry_bfr bfr, int depth);
|
||||
@gplx.Virtual public boolean Data_eq(byte[] comp) {return false;}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Bry_bfr_;
|
||||
|
||||
public abstract class Json_itm_base implements Json_itm {
|
||||
public abstract byte Tid();
|
||||
public abstract Object Data();
|
||||
public abstract byte[] Data_bry();
|
||||
public String Print_as_json() {
|
||||
Bry_bfr bfr = Bry_bfr_.New();
|
||||
Print_as_json(bfr, 0);
|
||||
return bfr.To_str_and_clear();
|
||||
}
|
||||
public abstract void Print_as_json(Bry_bfr bfr, int depth);
|
||||
@gplx.Virtual public boolean Data_eq(byte[] comp) {return false;}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,14 +13,22 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public class Json_itm_bool extends Json_itm_base {
|
||||
private boolean data;
|
||||
public Json_itm_bool(boolean data) {this.data = data; this.Ctor(-1, -1);}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__bool;}
|
||||
public boolean Data_as_bool() {return data;}
|
||||
@Override public Object Data() {return data;}
|
||||
@Override public byte[] Data_bry() {return data ? Json_itm_.Bry__true : Json_itm_.Bry__false;}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add(data ? Json_itm_.Bry__true: Json_itm_.Bry__false);}
|
||||
public static final Json_itm_bool Bool_n = new Json_itm_bool(false), Bool_y = new Json_itm_bool(true);
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_bfr;
|
||||
|
||||
public class Json_itm_bool extends Json_itm_base {
|
||||
private boolean data;
|
||||
private Json_itm_bool(boolean data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override public byte Tid() {return Json_itm_.Tid__bool;}
|
||||
public boolean Data_as_bool() {return data;}
|
||||
@Override public Object Data() {return data;}
|
||||
@Override public byte[] Data_bry() {return data ? Json_itm_.Bry__true : Json_itm_.Bry__false;}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add(data ? Json_itm_.Bry__true: Json_itm_.Bry__false);}
|
||||
|
||||
public static final Json_itm_bool Bool_n = new Json_itm_bool(false), Bool_y = new Json_itm_bool(true);
|
||||
public static final Json_itm_bool Get(boolean v) {return v ? Bool_y : Bool_n;}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,23 +13,54 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public class Json_itm_decimal extends Json_itm_base {
|
||||
private final Json_doc doc; private Decimal_adp data; private byte[] data_bry;
|
||||
public Json_itm_decimal(Json_doc doc, int src_bgn, int src_end) {this.Ctor(src_bgn, src_end); this.doc = doc;}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__decimal;}
|
||||
@Override public Object Data() {return this.Data_as_decimal();}
|
||||
@Override public byte[] Data_bry() {
|
||||
if (data_bry == null) data_bry = Bry_.Mid(doc.Src(), this.Src_bgn(), this.Src_end());
|
||||
return data_bry;
|
||||
}
|
||||
public Decimal_adp Data_as_decimal() {
|
||||
if (data == null) {
|
||||
String s = String_.new_a7(this.Data_bry());
|
||||
s = String_.Replace(s, "e", "E"); // exponent can be either "e" or "E" in JSON, but Java decimal parse only takes "E"; ISSUE#:565; DATE:2020-03-25
|
||||
data = Decimal_adp_.parse(s);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_mid(doc.Src(), this.Src_bgn(), this.Src_end());}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Decimal_adp;
|
||||
import gplx.Decimal_adp_;
|
||||
import gplx.Double_;
|
||||
import gplx.String_;
|
||||
|
||||
public class Json_itm_decimal extends Json_itm_base {
|
||||
private final Json_doc doc;
|
||||
private final int src_bgn, src_end;
|
||||
private Decimal_adp data;
|
||||
private byte[] data_bry;
|
||||
|
||||
private Json_itm_decimal(Json_doc doc, int src_bgn, int src_end, Decimal_adp data) {
|
||||
this.doc = doc;
|
||||
this.src_bgn = src_bgn;
|
||||
this.src_end = src_end;
|
||||
this.data = data;
|
||||
}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__decimal;}
|
||||
@Override public Object Data() {return this.Data_as_decimal();}
|
||||
@Override public byte[] Data_bry() {
|
||||
if (data_bry == null) {
|
||||
data_bry = data == null
|
||||
? Bry_.Mid(doc.Src(), src_bgn, src_end)
|
||||
: Bry_.new_u8(Double_.To_str_loose(data.To_double()));
|
||||
}
|
||||
return data_bry;
|
||||
}
|
||||
public Decimal_adp Data_as_decimal() {
|
||||
if (data == null) {
|
||||
String s = String_.new_a7(this.Data_bry());
|
||||
s = String_.Replace(s, "e", "E"); // exponent can be either "e" or "E" in JSON, but Java decimal parse only takes "E"; ISSUE#:565; DATE:2020-03-25
|
||||
data = Decimal_adp_.parse(s);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
if (doc == null) {
|
||||
bfr.Add_str_a7(Double_.To_str_loose(data.To_double()));
|
||||
}
|
||||
else {
|
||||
bfr.Add_mid(doc.Src(), src_bgn, src_end);
|
||||
}
|
||||
}
|
||||
|
||||
public static Json_itm_decimal NewByDoc(Json_doc doc, int src_bgn, int src_end) {return new Json_itm_decimal(doc, src_bgn, src_end, null);}
|
||||
public static Json_itm_decimal NewByVal(Decimal_adp val) {return new Json_itm_decimal(null, -1, -1, val);}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,21 +13,52 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public class Json_itm_int extends Json_itm_base {
|
||||
private final Json_doc doc;
|
||||
private byte[] data_bry; private int data; private boolean data_is_null = true;
|
||||
public Json_itm_int(Json_doc doc, int src_bgn, int src_end) {this.Ctor(src_bgn, src_end); this.doc = doc;}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__int;}
|
||||
public int Data_as_int() {
|
||||
if (data_is_null) {
|
||||
data = doc.Utl_num_parser().Parse(doc.Src(), Src_bgn(), Src_end()).Rv_as_int();
|
||||
data_is_null = false;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@Override public Object Data() {return Data_as_int();}
|
||||
@Override public byte[] Data_bry() {if (data_bry == null) data_bry = Bry_.Mid(doc.Src(), this.Src_bgn(), this.Src_end()); return data_bry;}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_mid(doc.Src(), this.Src_bgn(), this.Src_end());}
|
||||
public static Json_itm_int cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__int ? null : (Json_itm_int)v;}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Int_;
|
||||
|
||||
public class Json_itm_int extends Json_itm_base {
|
||||
private final Json_doc doc;
|
||||
private final int src_bgn, src_end;
|
||||
private byte[] data_bry;
|
||||
private int data;
|
||||
private boolean data_needs_making;
|
||||
|
||||
private Json_itm_int(Json_doc doc, int src_bgn, int src_end, boolean data_needs_making, int data) {
|
||||
this.doc = doc;
|
||||
this.src_bgn = src_bgn;
|
||||
this.src_end = src_end;
|
||||
this.data_needs_making = data_needs_making;
|
||||
if (!data_needs_making)
|
||||
this.data = data;
|
||||
}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__int;}
|
||||
@Override public Object Data() {return Data_as_int();}
|
||||
@Override public byte[] Data_bry() {
|
||||
if (data_bry == null) {
|
||||
data_bry = doc == null
|
||||
? Int_.To_bry(data)
|
||||
: Bry_.Mid(doc.Src(), src_bgn, src_end);
|
||||
}
|
||||
return data_bry;
|
||||
}
|
||||
public int Data_as_int() {
|
||||
if (data_needs_making) {
|
||||
data = doc.Utl_num_parser().Parse(doc.Src(), src_bgn, src_end).Rv_as_int();
|
||||
data_needs_making = false;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
if (doc == null)
|
||||
bfr.Add_int_variable(data);
|
||||
else
|
||||
bfr.Add_mid(doc.Src(), src_bgn, src_end);
|
||||
}
|
||||
|
||||
public static Json_itm_int NewByDoc(Json_doc doc, int src_bgn, int src_end) {return new Json_itm_int(doc, src_bgn, src_end, true, -1);}
|
||||
public static Json_itm_int NewByVal(int val) {return new Json_itm_int(null, -1, -1, false, val);}
|
||||
public static Json_itm_int Cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__int ? null : (Json_itm_int)v;}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,21 +13,51 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public class Json_itm_long extends Json_itm_base {
|
||||
private final Json_doc doc;
|
||||
private byte[] data_bry; private long data; private boolean data_is_null = true;
|
||||
public Json_itm_long(Json_doc doc, int src_bgn, int src_end) {this.Ctor(src_bgn, src_end); this.doc = doc;}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__long;}
|
||||
public long Data_as_long() {
|
||||
if (data_is_null) {
|
||||
data = doc.Utl_num_parser().Parse(doc.Src(), Src_bgn(), Src_end()).Rv_as_long();
|
||||
data_is_null = false;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@Override public Object Data() {return Data_as_long();}
|
||||
@Override public byte[] Data_bry() {if (data_bry == null) data_bry = Bry_.Mid(doc.Src(), this.Src_bgn(), this.Src_end()); return data_bry;}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_mid(doc.Src(), this.Src_bgn(), this.Src_end());}
|
||||
public static Json_itm_long cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__long ? null : (Json_itm_long)v;}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Long_;
|
||||
|
||||
public class Json_itm_long extends Json_itm_base {
|
||||
private final Json_doc doc;
|
||||
private final int src_bgn, src_end;
|
||||
private byte[] data_bry;
|
||||
private long data;
|
||||
private boolean data_needs_making = true;
|
||||
private Json_itm_long(Json_doc doc, int src_bgn, int src_end, boolean data_needs_making, long data) {
|
||||
this.doc = doc;
|
||||
this.src_bgn = src_bgn;
|
||||
this.src_end = src_end;
|
||||
this.data_needs_making = data_needs_making;
|
||||
if (!data_needs_making)
|
||||
this.data = data;
|
||||
}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__long;}
|
||||
@Override public Object Data() {return Data_as_long();}
|
||||
@Override public byte[] Data_bry() {
|
||||
if (data_bry == null) {
|
||||
data_bry = doc == null
|
||||
? Bry_.new_u8(Long_.To_str(data))
|
||||
: Bry_.Mid(doc.Src(), src_bgn, src_end);
|
||||
}
|
||||
return data_bry;
|
||||
}
|
||||
public long Data_as_long() {
|
||||
if (data_needs_making) {
|
||||
data = doc.Utl_num_parser().Parse(doc.Src(), src_bgn, src_end).Rv_as_long();
|
||||
data_needs_making = false;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
if (doc == null)
|
||||
bfr.Add_long_variable(data);
|
||||
else
|
||||
bfr.Add_mid(doc.Src(), src_bgn, src_end);
|
||||
}
|
||||
|
||||
public static Json_itm_long NewByDoc(Json_doc doc, int src_bgn, int src_end) {return new Json_itm_long(doc, src_bgn, src_end, true, -1);}
|
||||
public static Json_itm_long NewByVal(long val) {return new Json_itm_long(null, -1, -1, false, val);}
|
||||
public static Json_itm_long Cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__long ? null : (Json_itm_long)v;}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,83 +13,153 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
import gplx.core.intls.*;
|
||||
public class Json_itm_str extends Json_itm_base {
|
||||
private final boolean exact; private final Json_doc doc;
|
||||
private String data_str; private byte[] data_bry = null;
|
||||
public Json_itm_str(Json_doc doc, int src_bgn, int src_end, boolean exact) {this.Ctor(src_bgn + 1, src_end - 1); this.doc = doc; this.exact = exact;}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__str;}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
bfr.Add_byte(Byte_ascii.Quote);
|
||||
gplx.langs.htmls.Gfh_utl.Escape_html_to_bfr(bfr, doc.Src(), this.Src_bgn(), this.Src_end(), true, true, true, true, false); // false to apos for backwards compatibility
|
||||
bfr.Add_byte(Byte_ascii.Quote);
|
||||
}
|
||||
@Override public Object Data() {return this.Data_as_str();}
|
||||
public String Data_as_str() {
|
||||
if (data_str == null) {
|
||||
if (data_bry == null)
|
||||
data_bry = Data_make_bry();
|
||||
data_str = String_.new_u8(data_bry);
|
||||
}
|
||||
return data_str;
|
||||
}
|
||||
@Override public byte[] Data_bry() {if (data_bry == null) data_bry = Data_make_bry(); return data_bry;}
|
||||
@Override public boolean Data_eq(byte[] comp) {
|
||||
if (exact) return Bry_.Eq(doc.Src(), this.Src_bgn(), this.Src_end(), comp);
|
||||
if (data_bry == null) data_bry = Data_make_bry();
|
||||
return Bry_.Match(data_bry, comp);
|
||||
}
|
||||
private byte[] Data_make_bry() {
|
||||
byte[] src = doc.Src(); int bgn = this.Src_bgn(), end = this.Src_end();
|
||||
if (exact) return Bry_.Mid(src, bgn, end);
|
||||
Bry_bfr bfr = doc.Bfr();
|
||||
byte[] utf8_bry = doc.Tmp_u8_bry();
|
||||
for (int i = bgn; i < end; i++) {
|
||||
byte b = src[i];
|
||||
switch (b) {
|
||||
case Byte_ascii.Backslash:
|
||||
b = src[++i];
|
||||
switch (b) { // NOTE: must properly unescape chars; EX:wd.q:2; DATE:2014-04-23
|
||||
case Byte_ascii.Ltr_t: bfr.Add_byte(Byte_ascii.Tab); break;
|
||||
case Byte_ascii.Ltr_n: bfr.Add_byte(Byte_ascii.Nl); break;
|
||||
case Byte_ascii.Ltr_r: bfr.Add_byte(Byte_ascii.Cr); break;
|
||||
case Byte_ascii.Ltr_b: bfr.Add_byte(Byte_ascii.Backfeed); break;
|
||||
case Byte_ascii.Ltr_f: bfr.Add_byte(Byte_ascii.Formfeed); break;
|
||||
case Byte_ascii.Ltr_u:
|
||||
i += 1; // +1 to skip "u"
|
||||
int utf8_val = gplx.core.encoders.Hex_utl_.Parse_or(src, i, i + 4, -1);
|
||||
// check for UTF surrogate-pairs; ISSUE#:487; DATE:2019-06-02
|
||||
// hi: 0xD800-0xDBFF; 55,296-56,319
|
||||
if (utf8_val >= Utf16_.Surrogate_hi_bgn && utf8_val <= Utf16_.Surrogate_hi_end) {
|
||||
int lo_bgn = i + 4; // +4 to skip 4 hex-dec chars
|
||||
if (lo_bgn + 6 <= end // +6 to handle encoded String; EX: '\u0022'
|
||||
&& src[lo_bgn] == Byte_ascii.Backslash
|
||||
&& src[lo_bgn + 1] == Byte_ascii.Ltr_u) {
|
||||
lo_bgn = lo_bgn + 2; // +2 to skip '\' and 'u'
|
||||
int lo = gplx.core.encoders.Hex_utl_.Parse_or(src, lo_bgn, lo_bgn + 4, -1);
|
||||
// lo: 0xDC00-0xDFFF; 56,320-57,343
|
||||
if (lo >= Utf16_.Surrogate_lo_bgn && lo <= Utf16_.Surrogate_lo_end) {
|
||||
utf8_val = Utf16_.Surrogate_merge(utf8_val, lo);
|
||||
i += 6; // +6 to skip entire lo-String; EX: '\u0022'
|
||||
}
|
||||
}
|
||||
}
|
||||
int len = gplx.core.intls.Utf16_.Encode_int(utf8_val, utf8_bry, 0);
|
||||
bfr.Add_mid(utf8_bry, 0, len);
|
||||
i += 3; // +3 b/c for-loop will do another +1 to bring total to 4; EX: '0022'
|
||||
break;
|
||||
case Byte_ascii.Backslash:
|
||||
case Byte_ascii.Slash:
|
||||
default:
|
||||
bfr.Add_byte(b); break; // \? " \ / b f n r t
|
||||
}
|
||||
break;
|
||||
default:
|
||||
bfr.Add_byte(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bfr.To_bry_and_clear();
|
||||
}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Bry_bfr_;
|
||||
import gplx.Byte_ascii;
|
||||
import gplx.String_;
|
||||
import gplx.core.intls.Utf16_;
|
||||
import gplx.langs.htmls.Gfh_utl;
|
||||
|
||||
public class Json_itm_str extends Json_itm_base {
|
||||
private final Json_doc doc;
|
||||
private final int src_bgn, src_end;
|
||||
private String data_str;
|
||||
private byte[] data_bry;
|
||||
private boolean data_needs_making;
|
||||
private boolean escaped;
|
||||
|
||||
private Json_itm_str(Json_doc doc, int src_bgn, int src_end, String data_str, boolean escaped) {
|
||||
this.doc = doc;
|
||||
this.src_bgn = src_bgn;
|
||||
this.src_end = src_end;
|
||||
this.data_str = data_str;
|
||||
this.data_bry = null;
|
||||
this.data_needs_making = true;
|
||||
this.escaped = escaped;
|
||||
}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__str;}
|
||||
@Override public Object Data() {return this.Data_as_str();}
|
||||
public void Overwrite_bry(byte[] v) {
|
||||
this.data_bry = v; //needed by MapLink/MapFrame
|
||||
this.data_needs_making = false;
|
||||
}
|
||||
@Override public byte[] Data_bry() {
|
||||
if (data_bry == null) {
|
||||
data_bry = Data_make_bry();
|
||||
}
|
||||
return data_bry;
|
||||
}
|
||||
public String Data_as_str() {
|
||||
if (data_str == null) {
|
||||
data_bry = Data_make_bry();
|
||||
data_str = String_.new_u8(data_bry);
|
||||
}
|
||||
return data_str;
|
||||
}
|
||||
@Override public boolean Data_eq(byte[] comp) {
|
||||
return Bry_.Match(this.Data_bry(), comp);
|
||||
}
|
||||
private byte[] Data_make_bry() {
|
||||
// data already made; return it;
|
||||
if (!data_needs_making)
|
||||
return data_bry;
|
||||
|
||||
// mark data as made
|
||||
this.data_needs_making = false;
|
||||
|
||||
// get src, bgn, end, depending on whether or not itm is from jdoc or standalone
|
||||
byte[] src;
|
||||
int bgn;
|
||||
int end;
|
||||
if (doc == null) {
|
||||
src = Bry_.new_u8_safe(this.data_str);
|
||||
bgn = 0;
|
||||
end = src == null ? 0 : src.length;
|
||||
}
|
||||
else {
|
||||
src = doc.Src();
|
||||
bgn = src_bgn;
|
||||
end = src_end;
|
||||
}
|
||||
|
||||
// not escaped -> return the src
|
||||
if (!escaped) {
|
||||
this.data_bry = Bry_.Mid(src, bgn, end);
|
||||
return data_bry;
|
||||
}
|
||||
|
||||
// escaped; get some temp vars
|
||||
Bry_bfr bfr;
|
||||
byte[] utf8_bry;
|
||||
if (doc == null) {
|
||||
bfr = Bry_bfr_.New();
|
||||
utf8_bry = new byte[6];
|
||||
}
|
||||
else { // PERF:reuse bfr / bry on jdoc itself
|
||||
bfr = doc.Bfr();
|
||||
utf8_bry = doc.Tmp_u8_bry();
|
||||
}
|
||||
|
||||
// loop and unescape
|
||||
for (int i = bgn; i < end; i++) {
|
||||
byte b = src[i];
|
||||
switch (b) {
|
||||
case Byte_ascii.Backslash:
|
||||
b = src[++i];
|
||||
switch (b) { // NOTE: must properly unescape chars; EX:wd.q:2; DATE:2014-04-23
|
||||
case Byte_ascii.Ltr_t: bfr.Add_byte(Byte_ascii.Tab); break;
|
||||
case Byte_ascii.Ltr_n: bfr.Add_byte(Byte_ascii.Nl); break;
|
||||
case Byte_ascii.Ltr_r: bfr.Add_byte(Byte_ascii.Cr); break;
|
||||
case Byte_ascii.Ltr_b: bfr.Add_byte(Byte_ascii.Backfeed); break;
|
||||
case Byte_ascii.Ltr_f: bfr.Add_byte(Byte_ascii.Formfeed); break;
|
||||
case Byte_ascii.Ltr_u:
|
||||
i += 1; // +1 to skip "u"
|
||||
int utf8_val = gplx.core.encoders.Hex_utl_.Parse_or(src, i, i + 4, -1);
|
||||
// check for UTF surrogate-pairs; ISSUE#:487; DATE:2019-06-02
|
||||
// hi: 0xD800-0xDBFF; 55,296-56,319
|
||||
if (utf8_val >= Utf16_.Surrogate_hi_bgn && utf8_val <= Utf16_.Surrogate_hi_end) {
|
||||
int lo_bgn = i + 4; // +4 to skip 4 hex-dec chars
|
||||
if (lo_bgn + 6 <= end // +6 to handle encoded String; EX: '\u0022'
|
||||
&& src[lo_bgn] == Byte_ascii.Backslash
|
||||
&& src[lo_bgn + 1] == Byte_ascii.Ltr_u) {
|
||||
lo_bgn = lo_bgn + 2; // +2 to skip '\' and 'u'
|
||||
int lo = gplx.core.encoders.Hex_utl_.Parse_or(src, lo_bgn, lo_bgn + 4, -1);
|
||||
// lo: 0xDC00-0xDFFF; 56,320-57,343
|
||||
if (lo >= Utf16_.Surrogate_lo_bgn && lo <= Utf16_.Surrogate_lo_end) {
|
||||
utf8_val = Utf16_.Surrogate_merge(utf8_val, lo);
|
||||
i += 6; // +6 to skip entire lo-String; EX: '\u0022'
|
||||
}
|
||||
}
|
||||
}
|
||||
int len = gplx.core.intls.Utf16_.Encode_int(utf8_val, utf8_bry, 0);
|
||||
bfr.Add_mid(utf8_bry, 0, len);
|
||||
i += 3; // +3 b/c for-loop will do another +1 to bring total to 4; EX: '0022'
|
||||
break;
|
||||
case Byte_ascii.Backslash:
|
||||
case Byte_ascii.Slash:
|
||||
default:
|
||||
bfr.Add_byte(b); break; // \? " \ / b f n r t
|
||||
}
|
||||
break;
|
||||
default:
|
||||
bfr.Add_byte(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.data_bry = bfr.To_bry_and_clear();
|
||||
return data_bry;
|
||||
}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
bfr.Add_byte(Byte_ascii.Quote);
|
||||
byte[] data_bry = this.Data_bry();
|
||||
int data_len = data_bry.length;
|
||||
Gfh_utl.Escape_html_to_bfr(bfr, data_bry, 0, data_len, true, true, true, true, false); // false to apos for backwards compatibility
|
||||
bfr.Add_byte(Byte_ascii.Quote);
|
||||
}
|
||||
|
||||
public static Json_itm_str NewByDoc(Json_doc doc, int src_bgn, int src_end, boolean escaped) {return new Json_itm_str(doc, src_bgn + 1, src_end - 1, null, escaped);}
|
||||
public static Json_itm_str NewByVal(String val) {return new Json_itm_str(null, -1, -1, val, false);}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public class Json_itm_tmp implements Json_itm { // TEST:
|
||||
public Json_itm_tmp(byte tid, String data) {this.tid = tid; this.data = data;}
|
||||
public byte Tid() {return tid;} private byte tid;
|
||||
public byte[] Data_bry() {return Bry_.new_u8(Object_.Xto_str_strict_or_empty(data));}
|
||||
public int Src_bgn() {return -1;}
|
||||
public int Src_end() {return -1;}
|
||||
public Object Data() {return data;} private String data;
|
||||
public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_str_u8(data);}
|
||||
public boolean Data_eq(byte[] comp) {return false;}
|
||||
public void Clear() {}
|
||||
public static Json_itm new_str_(String v) {return new Json_itm_tmp(Json_itm_.Tid__str, "\"" + v + "\"");}
|
||||
public static Json_itm new_int_(int v) {return new Json_itm_tmp(Json_itm_.Tid__int, Int_.To_str(v));}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,25 +13,29 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
public class Json_kv extends Json_itm_base {
|
||||
public Json_kv(Json_itm key, Json_itm val) {this.key = key; this.val = val;}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__kv;}
|
||||
public Json_itm Key() {return key;} private final Json_itm key;
|
||||
public Json_itm Val() {return val;} private final Json_itm val;
|
||||
public byte[] Key_as_bry() {return key.Data_bry();}
|
||||
public String Key_as_str() {return (String)key.Data();}
|
||||
public byte[] Val_as_bry() {return val.Data_bry();}
|
||||
public Json_nde Val_as_nde() {return Json_nde.cast(val);}
|
||||
public Json_ary Val_as_ary() {return Json_ary.cast(val);}
|
||||
public boolean Key_eq(byte[] comp) {return ((Json_itm_str)key).Data_eq(comp);}
|
||||
@Override public Object Data() {return null;}
|
||||
@Override public byte[] Data_bry() {return null;}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
key.Print_as_json(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Colon);
|
||||
val.Print_as_json(bfr, depth);
|
||||
}
|
||||
public static final Json_kv[] Ary_empty = new Json_kv[0];
|
||||
public static Json_kv cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__kv ? null : (Json_kv)v;}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Byte_ascii;
|
||||
|
||||
public class Json_kv extends Json_itm_base {
|
||||
public Json_kv(Json_itm key, Json_itm val) {this.key = key; this.val = val;}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__kv;}
|
||||
public Json_itm Key() {return key;} private final Json_itm key;
|
||||
public Json_itm Val() {return val;} private final Json_itm val;
|
||||
public byte[] Key_as_bry() {return key.Data_bry();}
|
||||
public String Key_as_str() {return (String)key.Data();}
|
||||
public byte[] Val_as_bry() {return val.Data_bry();}
|
||||
public Json_nde Val_as_nde() {return Json_nde.Cast(val);}
|
||||
public Json_ary Val_as_ary() {return Json_ary.cast(val);}
|
||||
public boolean Key_eq(byte[] comp) {return ((Json_itm_str)key).Data_eq(comp);}
|
||||
@Override public Object Data() {return null;}
|
||||
@Override public byte[] Data_bry() {return null;}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
key.Print_as_json(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Colon);
|
||||
val.Print_as_json(bfr, depth);
|
||||
}
|
||||
public static final Json_kv[] Ary_empty = new Json_kv[0];
|
||||
public static Json_kv Cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__kv ? null : (Json_kv)v;}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,37 +13,42 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
import org.junit.*;
|
||||
public class Json_kv_ary_srl_tst {
|
||||
@Before public void init() {fxt.Clear();} private Json_kv_ary_srl_fxt fxt = new Json_kv_ary_srl_fxt();
|
||||
@Test public void Null() {fxt.Test_parse("{'k0':null}" , fxt.ary_(fxt.kv_str_("k0", null)));}
|
||||
@Test public void Bool_n() {fxt.Test_parse("{'k0':false}" , fxt.ary_(fxt.kv_bool_("k0", false)));}
|
||||
@Test public void Num() {fxt.Test_parse("{'k0':123}" , fxt.ary_(fxt.kv_int_("k0", 123)));}
|
||||
@Test public void Num_exp() {fxt.Test_parse("{'k0':1.23e2}" , fxt.ary_(fxt.kv_int_("k0", 123)));} // exponent can be either "e" or "E" in JSON, but Java decimal parse only takes "E"; ISSUE#:565; DATE:2020-03-25
|
||||
@Test public void Str() {fxt.Test_parse("{'k0':'v0'}" , fxt.ary_(fxt.kv_str_("k0", "v0")));}
|
||||
@Test public void Num_dec() {fxt.Test_parse("{'k0':1.23}" , fxt.ary_(fxt.kv_dec_("k0", Decimal_adp_.parse("1.23"))));}
|
||||
@Test public void Ary_int() {fxt.Test_parse("{'k0':[1,2,3]}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_(fxt.kv_int_("1", 1), fxt.kv_int_("2", 2), fxt.kv_int_("3", 3)))));}
|
||||
@Test public void Ary_empty() {fxt.Test_parse("{'k0':[]}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_())));}
|
||||
@Test public void Subs_int() {fxt.Test_parse("{'k0':{'k00':1,'k01':2}}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_(fxt.kv_int_("k00", 1), fxt.kv_int_("k01", 2)))));}
|
||||
@Test public void Subs_empty() {fxt.Test_parse("{'k0':{}}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_())));}
|
||||
}
|
||||
class Json_kv_ary_srl_fxt {
|
||||
public void Clear() {
|
||||
if (parser == null) {
|
||||
parser = new Json_parser();
|
||||
}
|
||||
} private Json_parser parser;
|
||||
public void Test_parse(String raw_str, Keyval[] expd) {
|
||||
byte[] raw_bry = Json_parser_tst.Replace_apos(Bry_.new_u8(raw_str));
|
||||
Json_doc doc = parser.Parse(raw_bry);
|
||||
Keyval[] actl = Json_kv_ary_srl.Val_by_itm_nde(doc.Root_nde());
|
||||
Tfds.Eq_str_lines(Keyval_.Ary_to_str(expd), Keyval_.Ary_to_str(actl));
|
||||
}
|
||||
public Keyval[] ary_(Keyval... ary) {return ary;}
|
||||
public Keyval kv_obj_(String key, Object val) {return Keyval_.new_(key, val);}
|
||||
public Keyval kv_str_(String key, String val) {return Keyval_.new_(key, val);}
|
||||
public Keyval kv_int_(String key, int val) {return Keyval_.new_(key, val);}
|
||||
public Keyval kv_bool_(String key, boolean val) {return Keyval_.new_(key, Bool_.To_str_lower(val));}
|
||||
public Keyval kv_dec_(String key, Decimal_adp val) {return Keyval_.new_(key, val.To_str());}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bool_;
|
||||
import gplx.Bry_;
|
||||
import gplx.Decimal_adp;
|
||||
import gplx.Decimal_adp_;
|
||||
import gplx.Keyval;
|
||||
import gplx.Keyval_;
|
||||
import gplx.Tfds;
|
||||
import org.junit.Test;
|
||||
|
||||
public class Json_kv_ary_srl_tst {
|
||||
private final Json_kv_ary_srl_fxt fxt = new Json_kv_ary_srl_fxt();
|
||||
@Test public void Null() {fxt.Test_parse("{'k0':null}" , fxt.ary_(fxt.New_kv_str("k0", null)));}
|
||||
@Test public void Bool_n() {fxt.Test_parse("{'k0':false}" , fxt.ary_(fxt.New_kv_bool("k0", false)));}
|
||||
@Test public void Num() {fxt.Test_parse("{'k0':123}" , fxt.ary_(fxt.New_kv_int("k0", 123)));}
|
||||
@Test public void Num_exp() {fxt.Test_parse("{'k0':1.23e2}" , fxt.ary_(fxt.New_kv_int("k0", 123)));} // exponent can be either "e" or "E" in JSON, but Java decimal parse only takes "E"; ISSUE#:565; DATE:2020-03-25
|
||||
@Test public void Str() {fxt.Test_parse("{'k0':'v0'}" , fxt.ary_(fxt.New_kv_str("k0", "v0")));}
|
||||
@Test public void Num_dec() {fxt.Test_parse("{'k0':1.23}" , fxt.ary_(fxt.New_kv_dec("k0", Decimal_adp_.parse("1.23"))));}
|
||||
@Test public void Ary_int() {fxt.Test_parse("{'k0':[1,2,3]}" , fxt.ary_(fxt.New_kv_obj("k0", fxt.ary_(fxt.New_kv_int("1", 1), fxt.New_kv_int("2", 2), fxt.New_kv_int("3", 3)))));}
|
||||
@Test public void Ary_empty() {fxt.Test_parse("{'k0':[]}" , fxt.ary_(fxt.New_kv_obj("k0", fxt.ary_())));}
|
||||
@Test public void Subs_int() {fxt.Test_parse("{'k0':{'k00':1,'k01':2}}" , fxt.ary_(fxt.New_kv_obj("k0", fxt.ary_(fxt.New_kv_int("k00", 1), fxt.New_kv_int("k01", 2)))));}
|
||||
@Test public void Subs_empty() {fxt.Test_parse("{'k0':{}}" , fxt.ary_(fxt.New_kv_obj("k0", fxt.ary_())));}
|
||||
}
|
||||
class Json_kv_ary_srl_fxt {
|
||||
private final Json_parser parser = new Json_parser();
|
||||
public void Test_parse(String raw_str, Keyval[] expd) {
|
||||
byte[] raw_bry = Bry_.new_u8(Json_doc.Make_str_by_apos(raw_str));
|
||||
Json_doc doc = parser.Parse(raw_bry);
|
||||
Keyval[] actl = Json_kv_ary_srl.Val_by_itm_nde(doc.Root_nde());
|
||||
Tfds.Eq_str_lines(Keyval_.Ary_to_str(expd), Keyval_.Ary_to_str(actl));
|
||||
}
|
||||
public Keyval[] ary_(Keyval... ary) {return ary;}
|
||||
public Keyval New_kv_obj(String key, Object val) {return Keyval_.new_(key, val);}
|
||||
public Keyval New_kv_str(String key, String val) {return Keyval_.new_(key, val);}
|
||||
public Keyval New_kv_int(String key, int val) {return Keyval_.new_(key, val);}
|
||||
public Keyval New_kv_bool(String key, boolean val) {return Keyval_.new_(key, Bool_.To_str_lower(val));}
|
||||
public Keyval New_kv_dec(String key, Decimal_adp val) {return Keyval_.new_(key, val.To_str());}
|
||||
}
|
||||
|
||||
@@ -1,191 +1,217 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Array_;
|
||||
import gplx.Bool_;
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Byte_ascii;
|
||||
import gplx.DateAdp;
|
||||
import gplx.DateAdp_;
|
||||
import gplx.Err_;
|
||||
import gplx.Hash_adp_bry;
|
||||
import gplx.Int_;
|
||||
import gplx.Long_;
|
||||
import gplx.String_;
|
||||
|
||||
public class Json_nde extends Json_itm_base implements Json_grp {
|
||||
private Json_itm[] subs = Json_itm_.Ary_empty; private int subs_len = 0, subs_max = 0;
|
||||
private Hash_adp_bry subs_hash;
|
||||
public Json_nde(Json_doc jdoc, int src_bgn) {this.jdoc = jdoc; this.Ctor(src_bgn, -1);}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__nde;}
|
||||
public Json_doc Doc() {return jdoc;} private final Json_doc jdoc;
|
||||
public void Src_end_(int v) {this.src_end = v;}
|
||||
@Override public Object Data() {return null;}
|
||||
@Override public byte[] Data_bry() {return null;}
|
||||
public int Len() {return subs_len;}
|
||||
public Json_itm Get_at(int i) {return subs[i];}
|
||||
public Json_itm Get_as_itm_or_null(String key) {return Get_as_itm_or_null(Bry_.new_u8(key));}
|
||||
public Json_itm Get_as_itm_or_null(byte[] key) {if (subs_hash == null) subs_hash = subs_hash_init(); return (Json_itm)subs_hash.Get_by_bry(key);}
|
||||
public Json_ary Get_as_ary(int idx) {return Json_ary.cast(Get_at(idx));}
|
||||
public Json_nde Get_as_nde(String key) {return Json_nde.cast(Get_as_itm_or_null(Bry_.new_u8(key)));}
|
||||
public Json_nde Get_as_nde(int idx) {return Json_nde.cast(Get_at(idx));}
|
||||
public Json_ary Get_as_ary(String key) {return Get_as_ary(Bry_.new_u8(key));}
|
||||
public Json_ary Get_as_ary(byte[] key) {
|
||||
Json_itm rv = Get_as_itm_or_null(key); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
|
||||
return Json_ary.cast(rv);
|
||||
}
|
||||
public Json_ary Get_as_ary_or_null(String key) {return Get_as_ary_or_null(Bry_.new_u8(key));}
|
||||
public Json_ary Get_as_ary_or_null(byte[] key) {
|
||||
Json_itm rv = Get_as_itm_or_null(key);
|
||||
return rv == null
|
||||
? null
|
||||
: Json_ary.cast(rv);
|
||||
}
|
||||
public byte[] Get_as_bry(String key) {
|
||||
byte[] rv = Get_as_bry_or(Bry_.new_u8(key), null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public byte[] Get_as_bry_or(byte[] key, byte[] or) {
|
||||
Json_itm rv = Get_as_itm_or_null(key);
|
||||
return rv == null ? or : rv.Data_bry();
|
||||
}
|
||||
public String Get_as_str(String key) {
|
||||
String rv = Get_as_str_or(key, null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public String Get_as_str_or(String key, String or) {return Get_as_str_or(Bry_.new_u8(key), or);}
|
||||
public String Get_as_str_or(byte[] key, String or) {
|
||||
byte[] rv = Get_as_bry_or(key, null);
|
||||
return rv == null ? or : String_.new_u8(rv);
|
||||
}
|
||||
public int Get_as_int(String key) {
|
||||
int rv = Get_as_int_or(key, Int_.Min_value); if (rv == Int_.Min_value) throw Err_.new_("json", "key missing", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public int Get_as_int_or(String key, int or) {return Get_as_int_or(Bry_.new_u8(key), or);}
|
||||
public int Get_as_int_or(byte[] key, int or) {
|
||||
byte[] rv = Get_as_bry_or(key, null);
|
||||
return rv == null ? or : Bry_.To_int(rv);
|
||||
}
|
||||
public long Get_as_long(String key) {
|
||||
long rv = Get_as_long_or(key, Long_.Min_value); if (rv == Long_.Min_value) throw Err_.new_("json", "key missing", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public long Get_as_long_or(String key, long or) {return Get_as_long_or(Bry_.new_u8(key), or);}
|
||||
public long Get_as_long_or(byte[] key, long or) {
|
||||
byte[] rv = Get_as_bry_or(key, null);
|
||||
return rv == null ? or : Bry_.To_long_or(rv, or);
|
||||
}
|
||||
public boolean Get_as_bool_or(String key, boolean or) {return Get_as_bool_or(Bry_.new_u8(key), or);}
|
||||
public boolean Get_as_bool_or(byte[] key, boolean or) {
|
||||
byte[] rv = Get_as_bry_or(key, null);
|
||||
return rv == null ? or : Bry_.Eq(rv, Bool_.True_bry);
|
||||
}
|
||||
public DateAdp Get_as_date_by_utc(String key) {
|
||||
byte[] rv = Get_as_bry_or(Bry_.new_u8(key), null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
|
||||
return DateAdp_.parse_gplx(String_.new_u8(rv));
|
||||
}
|
||||
|
||||
// to convert
|
||||
public boolean Has(byte[] key) {return Get_bry(key, null) != null;}
|
||||
public Json_kv Get_at_as_kv(int i) {
|
||||
Json_itm rv_itm = Get_at(i);
|
||||
Json_kv rv = Json_kv.cast(rv_itm); if (rv == null) throw Err_.new_("json", "sub is not kv", "i", i, "src", Bry_.Mid(jdoc.Src(), this.Src_bgn(), src_end));
|
||||
return rv;
|
||||
}
|
||||
|
||||
public Json_kv Get_kv(byte[] key) {return Json_kv.cast(Get_itm(key));}
|
||||
public Json_nde Get(String key) {return Get(Bry_.new_u8(key));}
|
||||
public Json_nde Get(byte[] key) {
|
||||
Json_kv kv = Json_kv.cast(this.Get_itm(key)); if (kv == null) throw Err_.new_("json", "kv not found", "key", key);
|
||||
Json_nde rv = Json_nde.cast(kv.Val()); if (rv == null) throw Err_.new_("json", "nde not found", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public Json_itm Get_itm(byte[] key) {
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
Json_itm itm = subs[i];
|
||||
if (itm.Tid() == Json_itm_.Tid__kv) {
|
||||
Json_kv itm_as_kv = (Json_kv)itm;
|
||||
if (Bry_.Eq(key, itm_as_kv.Key().Data_bry()))
|
||||
return itm;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Json_ary Get_ary(String key) {return Get_ary(Bry_.new_u8(key));}
|
||||
public Json_ary Get_ary(byte[] key) {return Json_ary.cast(Get_kv(key).Val_as_ary());}
|
||||
public String Get_str(String key) {return String_.new_u8(Get_bry(Bry_.new_u8(key)));}
|
||||
public byte[] Get_bry(byte[] key) {
|
||||
byte[] rv = Get_bry(key, null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public byte[] Get_bry_or_null(String key) {return Get_bry(Bry_.new_u8(key), null);}
|
||||
public byte[] Get_bry_or_null(byte[] key) {return Get_bry(key, null);}
|
||||
public byte[] Get_bry(byte[] key, byte[] or) {
|
||||
Json_itm kv_obj = Get_itm(key);
|
||||
if (kv_obj == null) return or; // key not found;
|
||||
if (kv_obj.Tid() != Json_itm_.Tid__kv) return or; // key is not a key_val
|
||||
Json_kv kv = (Json_kv)kv_obj;
|
||||
Json_itm val = kv.Val();
|
||||
return (val == null) ? or : val.Data_bry();
|
||||
}
|
||||
public Json_nde Add_many(Json_itm... ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
Add(ary[i]);
|
||||
return this;
|
||||
}
|
||||
public void Add(Json_itm itm) {
|
||||
int new_len = subs_len + 1;
|
||||
if (new_len > subs_max) { // ary too small >>> expand
|
||||
subs_max = new_len * 2;
|
||||
Json_itm[] new_subs = new Json_itm[subs_max];
|
||||
Array_.Copy_to(subs, 0, new_subs, 0, subs_len);
|
||||
subs = new_subs;
|
||||
}
|
||||
subs[subs_len] = (Json_itm)itm;
|
||||
subs_len = new_len;
|
||||
subs_hash = null;
|
||||
}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
if (bfr.Len() != 0) bfr.Add_byte_nl();
|
||||
Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte(Byte_ascii.Space);
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
if (i != 0) {
|
||||
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
|
||||
}
|
||||
subs[i].Print_as_json(bfr, depth + 1);
|
||||
}
|
||||
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl();
|
||||
}
|
||||
private Hash_adp_bry subs_hash_init() {
|
||||
Hash_adp_bry rv = Hash_adp_bry.cs();
|
||||
for (int i = 0; i < subs_len; ++i) {
|
||||
Json_itm itm = subs[i];
|
||||
if (itm.Tid() == Json_itm_.Tid__kv) {
|
||||
Json_kv itm_as_kv = (Json_kv)itm;
|
||||
rv.Add(itm_as_kv.Key().Data_bry(), itm_as_kv.Val());
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public static Json_nde cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__nde ? null : (Json_nde)v;}
|
||||
}
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Array_;
|
||||
import gplx.Bool_;
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Byte_ascii;
|
||||
import gplx.DateAdp;
|
||||
import gplx.DateAdp_;
|
||||
import gplx.Decimal_adp_;
|
||||
import gplx.Err_;
|
||||
import gplx.Hash_adp_bry;
|
||||
import gplx.Int_;
|
||||
import gplx.Long_;
|
||||
import gplx.String_;
|
||||
|
||||
public class Json_nde extends Json_itm_base implements Json_grp {
|
||||
private final int src_bgn;
|
||||
private int src_end;
|
||||
private Json_itm[] subs = Json_itm_.Ary_empty;
|
||||
private int subs_len = 0, subs_max = 0;
|
||||
private Hash_adp_bry subs_hash;
|
||||
|
||||
private Json_nde(Json_doc jdoc, int src_bgn) {
|
||||
this.jdoc = jdoc;
|
||||
this.src_bgn = src_bgn;
|
||||
}
|
||||
@Override public byte Tid() {return Json_itm_.Tid__nde;}
|
||||
public Json_doc Doc() {return jdoc;} private final Json_doc jdoc;
|
||||
public void Src_end_(int v) {this.src_end = v;}
|
||||
@Override public Object Data() {return null;}
|
||||
@Override public byte[] Data_bry() {return null;}
|
||||
public int Len() {return subs_len;}
|
||||
public Json_itm Get_at(int i) {return subs[i];}
|
||||
public Json_itm Get_as_itm_or_null(String key) {return Get_as_itm_or_null(Bry_.new_u8(key));}
|
||||
public Json_itm Get_as_itm_or_null(byte[] key) {if (subs_hash == null) subs_hash = subs_hash_init(); return (Json_itm)subs_hash.Get_by_bry(key);}
|
||||
public Json_ary Get_as_ary(int idx) {return Json_ary.cast(Get_at(idx));}
|
||||
public Json_nde Get_as_nde(String key) {return Json_nde.Cast(Get_as_itm_or_null(Bry_.new_u8(key)));}
|
||||
public Json_nde Get_as_nde(int idx) {return Json_nde.Cast(Get_at(idx));}
|
||||
public Json_ary Get_as_ary(String key) {return Get_as_ary(Bry_.new_u8(key));}
|
||||
public Json_ary Get_as_ary(byte[] key) {
|
||||
Json_itm rv = Get_as_itm_or_null(key); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
|
||||
return Json_ary.cast(rv);
|
||||
}
|
||||
public Json_ary Get_as_ary_or_null(String key) {return Get_as_ary_or_null(Bry_.new_u8(key));}
|
||||
public Json_ary Get_as_ary_or_null(byte[] key) {
|
||||
Json_itm rv = Get_as_itm_or_null(key);
|
||||
return rv == null
|
||||
? null
|
||||
: Json_ary.cast(rv);
|
||||
}
|
||||
public byte[] Get_as_bry(String key) {
|
||||
byte[] rv = Get_as_bry_or(Bry_.new_u8(key), null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public byte[] Get_as_bry_or(byte[] key, byte[] or) {
|
||||
Json_itm rv = Get_as_itm_or_null(key);
|
||||
return rv == null ? or : rv.Data_bry();
|
||||
}
|
||||
public String Get_as_str(String key) {
|
||||
String rv = Get_as_str_or(key, null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public String Get_as_str_or(String key, String or) {return Get_as_str_or(Bry_.new_u8(key), or);}
|
||||
public String Get_as_str_or(byte[] key, String or) {
|
||||
byte[] rv = Get_as_bry_or(key, null);
|
||||
return rv == null ? or : String_.new_u8(rv);
|
||||
}
|
||||
public int Get_as_int(String key) {
|
||||
int rv = Get_as_int_or(key, Int_.Min_value); if (rv == Int_.Min_value) throw Err_.new_("json", "key missing", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public int Get_as_int_or(String key, int or) {return Get_as_int_or(Bry_.new_u8(key), or);}
|
||||
public int Get_as_int_or(byte[] key, int or) {
|
||||
byte[] rv = Get_as_bry_or(key, null);
|
||||
return rv == null ? or : Bry_.To_int(rv);
|
||||
}
|
||||
public long Get_as_long(String key) {
|
||||
long rv = Get_as_long_or(key, Long_.Min_value); if (rv == Long_.Min_value) throw Err_.new_("json", "key missing", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public long Get_as_long_or(String key, long or) {return Get_as_long_or(Bry_.new_u8(key), or);}
|
||||
public long Get_as_long_or(byte[] key, long or) {
|
||||
byte[] rv = Get_as_bry_or(key, null);
|
||||
return rv == null ? or : Bry_.To_long_or(rv, or);
|
||||
}
|
||||
public boolean Get_as_bool_or(String key, boolean or) {return Get_as_bool_or(Bry_.new_u8(key), or);}
|
||||
public boolean Get_as_bool_or(byte[] key, boolean or) {
|
||||
byte[] rv = Get_as_bry_or(key, null);
|
||||
return rv == null ? or : Bry_.Eq(rv, Bool_.True_bry);
|
||||
}
|
||||
public DateAdp Get_as_date_by_utc(String key) {
|
||||
byte[] rv = Get_as_bry_or(Bry_.new_u8(key), null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
|
||||
return DateAdp_.parse_gplx(String_.new_u8(rv));
|
||||
}
|
||||
|
||||
// to convert
|
||||
public boolean Has(byte[] key) {return Get_bry(key, null) != null;}
|
||||
public Json_kv Get_at_as_kv(int i) {
|
||||
Json_itm rv_itm = Get_at(i);
|
||||
Json_kv rv = Json_kv.Cast(rv_itm);
|
||||
if (rv == null) {
|
||||
byte[] snip = jdoc == null ? Bry_.new_a7("no source") : Bry_.Mid(jdoc.Src(), src_bgn, src_end);
|
||||
throw Err_.new_("json", "sub is not kv", "i", i, "src", snip);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
public Json_kv Get_kv(byte[] key) {return Json_kv.Cast(Get_itm(key));}
|
||||
public Json_nde Get(String key) {return Get(Bry_.new_u8(key));}
|
||||
public Json_nde Get(byte[] key) {
|
||||
Json_kv kv = Json_kv.Cast(this.Get_itm(key)); if (kv == null) throw Err_.new_("json", "kv not found", "key", key);
|
||||
Json_nde rv = Json_nde.Cast(kv.Val()); if (rv == null) throw Err_.new_("json", "nde not found", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public Json_itm Get_itm(byte[] key) {
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
Json_itm itm = subs[i];
|
||||
if (itm != null && itm.Tid() == Json_itm_.Tid__kv) {
|
||||
Json_kv itm_as_kv = (Json_kv)itm;
|
||||
if (Bry_.Eq(key, itm_as_kv.Key().Data_bry()))
|
||||
return itm;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Json_ary Get_ary(String key) {return Get_ary(Bry_.new_u8(key));}
|
||||
public Json_ary Get_ary(byte[] key) {return Json_ary.cast(Get_kv(key).Val_as_ary());}
|
||||
public String Get_str(String key) {return String_.new_u8(Get_bry(Bry_.new_u8(key)));}
|
||||
public byte[] Get_bry(byte[] key) {
|
||||
byte[] rv = Get_bry(key, null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
|
||||
return rv;
|
||||
}
|
||||
public byte[] Get_bry_or_null(String key) {return Get_bry(Bry_.new_u8(key), null);}
|
||||
public byte[] Get_bry_or_null(byte[] key) {return Get_bry(key, null);}
|
||||
public byte[] Get_bry(byte[] key, byte[] or) {
|
||||
Json_itm kv_obj = Get_itm(key);
|
||||
if (kv_obj == null) return or; // key not found;
|
||||
if (kv_obj.Tid() != Json_itm_.Tid__kv) return or; // key is not a key_val
|
||||
Json_kv kv = (Json_kv)kv_obj;
|
||||
Json_itm val = kv.Val();
|
||||
return (val == null) ? or : val.Data_bry();
|
||||
}
|
||||
public void AddKvBool(String key, boolean val) {AddKv(key, Json_itm_bool.Get(val));}
|
||||
public void AddKvInt(String key, int val) {AddKv(key, Json_itm_int.NewByVal(val));}
|
||||
public void AddKvDouble(String key, double val) {AddKv(key, Json_itm_decimal.NewByVal(Decimal_adp_.double_(val)));}
|
||||
public void AddKvStr(String key, byte[] val) {AddKv(key, Json_itm_str.NewByVal(String_.new_u8(val)));}
|
||||
public void AddKvStr(String key, String val) {AddKv(key, Json_itm_str.NewByVal(val));}
|
||||
public void AddKvNde(String key, Json_nde val) {AddKv(key, val);}
|
||||
public void AddKvAry(String key, Json_ary val) {AddKv(key, val);}
|
||||
private void AddKv(String key, Json_itm val) {
|
||||
Json_kv rv = new Json_kv(Json_itm_str.NewByVal(key), val);
|
||||
Add(rv);
|
||||
}
|
||||
public Json_nde Add_many(Json_itm... ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
Add(ary[i]);
|
||||
return this;
|
||||
}
|
||||
public void Add(Json_itm itm) {
|
||||
int new_len = subs_len + 1;
|
||||
if (new_len > subs_max) { // ary too small >>> expand
|
||||
subs_max = new_len * 2;
|
||||
Json_itm[] new_subs = new Json_itm[subs_max];
|
||||
Array_.Copy_to(subs, 0, new_subs, 0, subs_len);
|
||||
subs = new_subs;
|
||||
}
|
||||
subs[subs_len] = (Json_itm)itm;
|
||||
subs_len = new_len;
|
||||
subs_hash = null;
|
||||
}
|
||||
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
|
||||
if (bfr.Len() != 0) bfr.Add_byte_nl();
|
||||
Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte(Byte_ascii.Space);
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
if (i != 0) {
|
||||
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
|
||||
}
|
||||
subs[i].Print_as_json(bfr, depth + 1);
|
||||
}
|
||||
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
|
||||
bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl();
|
||||
}
|
||||
private Hash_adp_bry subs_hash_init() {
|
||||
Hash_adp_bry rv = Hash_adp_bry.cs();
|
||||
for (int i = 0; i < subs_len; ++i) {
|
||||
Json_itm itm = subs[i];
|
||||
if (itm.Tid() == Json_itm_.Tid__kv) {
|
||||
Json_kv itm_as_kv = (Json_kv)itm;
|
||||
rv.Add(itm_as_kv.Key().Data_bry(), itm_as_kv.Val());
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static Json_nde NewByDoc(Json_doc doc, int src_bgn) {return new Json_nde(doc, src_bgn);}
|
||||
public static Json_nde NewByVal() {return new Json_nde(null, -1);}
|
||||
public static Json_nde Cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__nde ? null : (Json_nde)v;}
|
||||
}
|
||||
|
||||
@@ -1,198 +1,197 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bool_;
|
||||
import gplx.Bry_;
|
||||
import gplx.Byte_ascii;
|
||||
import gplx.Char_;
|
||||
import gplx.Err;
|
||||
import gplx.Err_;
|
||||
import gplx.Int_;
|
||||
import gplx.String_;
|
||||
import gplx.core.primitives.Gfo_number_parser;
|
||||
|
||||
public class Json_parser {
|
||||
private byte[] src; private int src_len, pos; private final Gfo_number_parser num_parser = new Gfo_number_parser();
|
||||
public Json_factory Factory() {return factory;} private final Json_factory factory = new Json_factory();
|
||||
public Json_doc Parse_by_apos_ary(String... ary) {return Parse_by_apos(String_.Concat_lines_nl(ary));}
|
||||
public Json_doc Parse_by_apos(String s) {return Parse(Bry_.Replace(Bry_.new_u8(s), Byte_ascii.Apos, Byte_ascii.Quote));}
|
||||
public Json_doc Parse(String src) {return Parse(Bry_.new_u8(src));}
|
||||
public Json_doc Parse(byte[] src) {
|
||||
synchronized (factory) {
|
||||
this.src = src; if (src == null) return null;
|
||||
this.src_len = src.length; if (src_len == 0) return null;
|
||||
this.pos = 0;
|
||||
Skip_ws();
|
||||
boolean root_is_nde = true;
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Curly_bgn: root_is_nde = Bool_.Y; break;
|
||||
case Byte_ascii.Brack_bgn: root_is_nde = Bool_.N; break;
|
||||
default: return null;
|
||||
}
|
||||
Skip_ws();
|
||||
Json_doc doc = new Json_doc();
|
||||
Json_grp root = null;
|
||||
if (root_is_nde)
|
||||
root = Make_nde(doc);
|
||||
else
|
||||
root = Make_ary(doc);
|
||||
doc.Ctor(src, root);
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
private Json_nde Make_nde(Json_doc doc) {
|
||||
++pos; // brack_bgn
|
||||
Json_nde nde = new Json_nde(doc, pos);
|
||||
while (pos < src_len) {
|
||||
Skip_ws();
|
||||
if (src[pos] == Byte_ascii.Curly_end) {++pos; return nde;}
|
||||
else nde.Add(Make_kv(doc));
|
||||
Skip_ws();
|
||||
switch (src[pos++]) {
|
||||
case Byte_ascii.Comma: break;
|
||||
case Byte_ascii.Curly_end: return nde;
|
||||
default: throw Err_.new_unhandled(src[pos - 1]);
|
||||
}
|
||||
}
|
||||
throw Err_.new_wo_type("eos inside nde");
|
||||
}
|
||||
private Json_itm Make_kv(Json_doc doc) {
|
||||
Json_itm key = Make_string(doc);
|
||||
Skip_ws();
|
||||
Chk(Byte_ascii.Colon);
|
||||
Skip_ws();
|
||||
Json_itm val = Make_val(doc);
|
||||
return new Json_kv(key, val);
|
||||
}
|
||||
private Json_itm Make_val(Json_doc doc) {
|
||||
while (pos < src_len) {
|
||||
byte b = src[pos];
|
||||
switch (b) {
|
||||
case Byte_ascii.Ltr_n: return Make_literal(Bry_null_ull , 3, factory.Null());
|
||||
case Byte_ascii.Ltr_f: return Make_literal(Bry_bool_alse , 4, factory.Bool_n());
|
||||
case Byte_ascii.Ltr_t: return Make_literal(Bry_bool_rue , 3, factory.Bool_y());
|
||||
case Byte_ascii.Quote: return Make_string(doc);
|
||||
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
|
||||
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
|
||||
case Byte_ascii.Dash: return Make_num(doc);
|
||||
case Byte_ascii.Brack_bgn: return Make_ary(doc);
|
||||
case Byte_ascii.Curly_bgn: return Make_nde(doc);
|
||||
}
|
||||
throw Err_.new_unhandled(Char_.To_str(b));
|
||||
}
|
||||
throw Err_.new_wo_type("eos reached in val");
|
||||
}
|
||||
private Json_itm Make_literal(byte[] remainder, int remainder_len, Json_itm singleton) {
|
||||
++pos; // 1st char
|
||||
int literal_end = pos + remainder_len;
|
||||
if (Bry_.Eq(src, pos, literal_end, remainder)) {
|
||||
pos = literal_end;
|
||||
return singleton;
|
||||
}
|
||||
throw Err_.new_("json.parser", "invalid literal", "excerpt", Bry_.Mid_by_len_safe(src, pos - 1, 16));
|
||||
}
|
||||
private Json_itm Make_string(Json_doc doc) {
|
||||
int bgn = pos++; // ++: quote_bgn
|
||||
boolean exact = true;
|
||||
while (pos < src_len) {
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Backslash:
|
||||
++pos; // backslash
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Ltr_u: pos += 5; break; // \uFFFF 1 u + 4 hex-dec; ISSUE#:486; DATE:2019-06-02
|
||||
default: ++pos; break; // \? " \ / b f n r t
|
||||
}
|
||||
exact = false;
|
||||
break;
|
||||
case Byte_ascii.Quote:
|
||||
return factory.Str(doc, bgn, ++pos, exact); // ++: quote_end
|
||||
default:
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw Err_.new_wo_type("eos reached inside quote");
|
||||
}
|
||||
private Json_itm Make_num(Json_doc doc) {
|
||||
int num_bgn = pos;
|
||||
boolean loop = true;
|
||||
while (loop) {
|
||||
if (pos == src_len) throw Err_.new_wo_type("eos reached inside num");
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
|
||||
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
|
||||
++pos;
|
||||
break;
|
||||
case Byte_ascii.Dot:
|
||||
case Byte_ascii.Dash: case Byte_ascii.Plus:
|
||||
case Byte_ascii.Ltr_E: case Byte_ascii.Ltr_e: // e e+ e- E E+ E-
|
||||
++pos;
|
||||
break;
|
||||
default:
|
||||
loop = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
num_parser.Parse(src, num_bgn, pos);
|
||||
if (num_parser.Has_frac())
|
||||
return factory.Decimal(doc, num_bgn, pos);
|
||||
else {
|
||||
if (num_parser.Is_int())
|
||||
return factory.Int(doc, num_bgn, pos);
|
||||
else
|
||||
return factory.Long(doc, num_bgn, pos);
|
||||
}
|
||||
}
|
||||
private Json_ary Make_ary(Json_doc doc) {
|
||||
Json_ary rv = factory.Ary(pos++, pos); // brack_bgn
|
||||
while (pos < src_len) {
|
||||
Skip_ws();
|
||||
if (src[pos] == Byte_ascii.Brack_end) {++pos; return rv;}
|
||||
else rv.Add(Make_val(doc));
|
||||
Skip_ws();
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Comma: ++pos; break;
|
||||
case Byte_ascii.Brack_end: ++pos; return rv;
|
||||
}
|
||||
}
|
||||
throw Err_.new_wo_type("eos inside ary");
|
||||
}
|
||||
private void Skip_ws() {
|
||||
while (pos < src_len) {
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Space: case Byte_ascii.Nl: case Byte_ascii.Tab: case Byte_ascii.Cr: ++pos; break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void Chk(byte expd) {
|
||||
if (src[pos] == expd)
|
||||
++pos;
|
||||
else
|
||||
throw err_(src, pos, "expected '{0}' but got '{1}'", Char_.To_str(expd), Char_.To_str(src[pos]));
|
||||
}
|
||||
private Err err_(byte[] src, int bgn, String fmt, Object... args) {return err_(src, bgn, src.length, fmt, args);}
|
||||
private Err err_(byte[] src, int bgn, int src_len, String fmt, Object... args) {
|
||||
String msg = String_.Format(fmt, args) + " " + Int_.To_str(bgn) + " " + String_.new_u8__by_len(src, bgn, 20);
|
||||
return Err_.new_wo_type(msg);
|
||||
}
|
||||
private static final byte[] Bry_bool_rue = Bry_.new_a7("rue"), Bry_bool_alse = Bry_.new_a7("alse"), Bry_null_ull = Bry_.new_a7("ull");
|
||||
public static Json_doc ParseToJdoc(String src) {
|
||||
Json_parser parser = new Json_parser();
|
||||
return parser.Parse(src);
|
||||
}
|
||||
}
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bool_;
|
||||
import gplx.Bry_;
|
||||
import gplx.Byte_ascii;
|
||||
import gplx.Char_;
|
||||
import gplx.Err;
|
||||
import gplx.Err_;
|
||||
import gplx.Int_;
|
||||
import gplx.String_;
|
||||
import gplx.core.primitives.Gfo_number_parser;
|
||||
|
||||
public class Json_parser {
|
||||
private byte[] src;
|
||||
private int src_len, pos;
|
||||
private final Gfo_number_parser num_parser = new Gfo_number_parser();
|
||||
public Json_doc Parse_by_apos_ary(String... ary) {return Parse_by_apos(String_.Concat_lines_nl(ary));}
|
||||
public Json_doc Parse_by_apos(String s) {return Parse(Bry_.Replace(Bry_.new_u8(s), Byte_ascii.Apos, Byte_ascii.Quote));}
|
||||
public Json_doc Parse(String src) {return Parse(Bry_.new_u8(src));}
|
||||
public Json_doc Parse(byte[] src) {
|
||||
this.src = src; if (src == null) return null;
|
||||
this.src_len = src.length; if (src_len == 0) return null;
|
||||
this.pos = 0;
|
||||
Skip_ws();
|
||||
boolean root_is_nde = true;
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Curly_bgn: root_is_nde = Bool_.Y; break;
|
||||
case Byte_ascii.Brack_bgn: root_is_nde = Bool_.N; break;
|
||||
default: return null;
|
||||
}
|
||||
Skip_ws();
|
||||
Json_doc doc = new Json_doc();
|
||||
Json_grp root = null;
|
||||
if (root_is_nde)
|
||||
root = Make_nde(doc);
|
||||
else
|
||||
root = Make_ary(doc);
|
||||
doc.Ctor(src, root);
|
||||
return doc;
|
||||
}
|
||||
private Json_nde Make_nde(Json_doc doc) {
|
||||
++pos; // brack_bgn
|
||||
Json_nde nde = Json_nde.NewByDoc(doc, pos);
|
||||
while (pos < src_len) {
|
||||
Skip_ws();
|
||||
if (src[pos] == Byte_ascii.Curly_end) {++pos; return nde;}
|
||||
else nde.Add(Make_kv(doc));
|
||||
Skip_ws();
|
||||
switch (src[pos++]) {
|
||||
case Byte_ascii.Comma: break;
|
||||
case Byte_ascii.Curly_end: return nde;
|
||||
default: throw Err_.new_unhandled(src[pos - 1]);
|
||||
}
|
||||
}
|
||||
throw Err_.new_wo_type("eos inside nde");
|
||||
}
|
||||
private Json_itm Make_kv(Json_doc doc) {
|
||||
Json_itm key = Make_string(doc);
|
||||
Skip_ws();
|
||||
Chk(Byte_ascii.Colon);
|
||||
Skip_ws();
|
||||
Json_itm val = Make_val(doc);
|
||||
return new Json_kv(key, val);
|
||||
}
|
||||
private Json_itm Make_val(Json_doc doc) {
|
||||
while (pos < src_len) {
|
||||
byte b = src[pos];
|
||||
switch (b) {
|
||||
case Byte_ascii.Ltr_n: return Make_literal(Bry_null_ull , 3, Json_itm_null.Null);
|
||||
case Byte_ascii.Ltr_f: return Make_literal(Bry_bool_alse , 4, Json_itm_bool.Bool_n);
|
||||
case Byte_ascii.Ltr_t: return Make_literal(Bry_bool_rue , 3, Json_itm_bool.Bool_y);
|
||||
case Byte_ascii.Quote: return Make_string(doc);
|
||||
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
|
||||
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
|
||||
case Byte_ascii.Dash: return Make_num(doc);
|
||||
case Byte_ascii.Brack_bgn: return Make_ary(doc);
|
||||
case Byte_ascii.Curly_bgn: return Make_nde(doc);
|
||||
}
|
||||
throw Err_.new_unhandled(Char_.To_str(b));
|
||||
}
|
||||
throw Err_.new_wo_type("eos reached in val");
|
||||
}
|
||||
private Json_itm Make_literal(byte[] remainder, int remainder_len, Json_itm singleton) {
|
||||
++pos; // 1st char
|
||||
int literal_end = pos + remainder_len;
|
||||
if (Bry_.Eq(src, pos, literal_end, remainder)) {
|
||||
pos = literal_end;
|
||||
return singleton;
|
||||
}
|
||||
throw Err_.new_("json.parser", "invalid literal", "excerpt", Bry_.Mid_by_len_safe(src, pos - 1, 16));
|
||||
}
|
||||
private Json_itm Make_string(Json_doc doc) {
|
||||
int bgn = pos++; // ++: quote_bgn
|
||||
boolean escaped = false;
|
||||
while (pos < src_len) {
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Backslash:
|
||||
++pos; // backslash
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Ltr_u: pos += 5; break; // \uFFFF 1 u + 4 hex-dec; ISSUE#:486; DATE:2019-06-02
|
||||
default: ++pos; break; // \? " \ / b f n r t
|
||||
}
|
||||
escaped = true;
|
||||
break;
|
||||
case Byte_ascii.Quote:
|
||||
return Json_itm_str.NewByDoc(doc, bgn, ++pos, escaped); // ++: quote_end
|
||||
default:
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw Err_.new_wo_type("eos reached inside quote");
|
||||
}
|
||||
private Json_itm Make_num(Json_doc doc) {
|
||||
int num_bgn = pos;
|
||||
boolean loop = true;
|
||||
while (loop) {
|
||||
if (pos == src_len) throw Err_.new_wo_type("eos reached inside num");
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
|
||||
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
|
||||
++pos;
|
||||
break;
|
||||
case Byte_ascii.Dot:
|
||||
case Byte_ascii.Dash: case Byte_ascii.Plus:
|
||||
case Byte_ascii.Ltr_E: case Byte_ascii.Ltr_e: // e e+ e- E E+ E-
|
||||
++pos;
|
||||
break;
|
||||
default:
|
||||
loop = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
num_parser.Parse(src, num_bgn, pos);
|
||||
if (num_parser.Has_frac())
|
||||
return Json_itm_decimal.NewByDoc(doc, num_bgn, pos);
|
||||
else {
|
||||
if (num_parser.Is_int())
|
||||
return Json_itm_int.NewByDoc(doc, num_bgn, pos);
|
||||
else
|
||||
return Json_itm_long.NewByDoc(doc, num_bgn, pos);
|
||||
}
|
||||
}
|
||||
private Json_ary Make_ary(Json_doc doc) {
|
||||
Json_ary rv = Json_ary.NewByDoc(doc, pos++, pos); // brack_bgn
|
||||
while (pos < src_len) {
|
||||
Skip_ws();
|
||||
if (src[pos] == Byte_ascii.Brack_end) {++pos; return rv;}
|
||||
else rv.Add(Make_val(doc));
|
||||
Skip_ws();
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Comma: ++pos; break;
|
||||
case Byte_ascii.Brack_end: ++pos; return rv;
|
||||
}
|
||||
}
|
||||
throw Err_.new_wo_type("eos inside ary");
|
||||
}
|
||||
private void Skip_ws() {
|
||||
while (pos < src_len) {
|
||||
switch (src[pos]) {
|
||||
case Byte_ascii.Space: case Byte_ascii.Nl: case Byte_ascii.Tab: case Byte_ascii.Cr: ++pos; break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void Chk(byte expd) {
|
||||
if (src[pos] == expd)
|
||||
++pos;
|
||||
else
|
||||
throw err_(src, pos, "expected '{0}' but got '{1}'", Char_.To_str(expd), Char_.To_str(src[pos]));
|
||||
}
|
||||
private Err err_(byte[] src, int bgn, String fmt, Object... args) {return err_(src, bgn, src.length, fmt, args);}
|
||||
private Err err_(byte[] src, int bgn, int src_len, String fmt, Object... args) {
|
||||
String msg = String_.Format(fmt, args) + " " + Int_.To_str(bgn) + " " + String_.new_u8__by_len(src, bgn, 20);
|
||||
return Err_.new_wo_type(msg);
|
||||
}
|
||||
private static final byte[] Bry_bool_rue = Bry_.new_a7("rue"), Bry_bool_alse = Bry_.new_a7("alse"), Bry_null_ull = Bry_.new_a7("ull");
|
||||
public static Json_doc ParseToJdoc(String src) {
|
||||
Json_parser parser = new Json_parser();
|
||||
return parser.Parse(src);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,56 +13,61 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
import gplx.core.primitives.*;
|
||||
public class Json_parser__list_nde__base extends Json_parser__itm__base {
|
||||
public void Parse_grp(String context, Json_grp grp) {
|
||||
this.context = context;
|
||||
int len = grp.Len();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Json_nde sub = null;
|
||||
if (grp.Tid() == Json_itm_.Tid__nde) {
|
||||
Json_kv kv = Json_nde.cast(grp).Get_at_as_kv(i);
|
||||
sub = kv.Val_as_nde();
|
||||
}
|
||||
else {
|
||||
sub = Json_nde.cast(grp.Get_at(i));
|
||||
}
|
||||
Parse_nde(context, sub);
|
||||
}
|
||||
}
|
||||
public void Parse_nde(String context, Json_nde nde) {
|
||||
this.cur_itm = nde;
|
||||
for (int j = 0; j < keys_len; ++j)
|
||||
atrs[j] = null;
|
||||
int atr_len = nde.Len();
|
||||
for (int j = 0; j < atr_len; ++j) {
|
||||
Json_kv atr = nde.Get_at_as_kv(j);
|
||||
Object idx_obj = hash.Get_by_bry(atr.Key_as_bry());
|
||||
if (idx_obj == null) {Warn("unknown json parser key", atr); continue;}
|
||||
int idx_int = ((Int_obj_val)idx_obj).Val();
|
||||
atrs[idx_int] = atr;
|
||||
}
|
||||
Parse_hook_nde(nde, atrs);
|
||||
}
|
||||
public void Parse_to_list_as_bry(String context, Json_ary ary, Ordered_hash list) {
|
||||
this.cur_itm = ary;
|
||||
int len = ary.Len();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
byte[] val = ary.Get_at(i).Data_bry();
|
||||
list.Add(val, val);
|
||||
}
|
||||
}
|
||||
public void Parse_to_list_as_kv(String context, Json_nde nde, Ordered_hash list) {
|
||||
this.cur_itm = nde;
|
||||
int len = nde.Len();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Json_kv sub = nde.Get_at_as_kv(i);
|
||||
byte[] key = sub.Key_as_bry();
|
||||
byte[] val = Parse_to_list_as_kv__get_val(sub, key);
|
||||
list.Add(key, Keyval_.new_(String_.new_u8(key), String_.new_u8(val)));
|
||||
}
|
||||
}
|
||||
@gplx.Virtual protected byte[] Parse_to_list_as_kv__get_val(Json_kv sub, byte[] key) {return sub.Val_as_bry();}
|
||||
@Override protected void Parse_hook_nde(Json_nde sub, Json_kv[] atrs) {}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Keyval_;
|
||||
import gplx.Ordered_hash;
|
||||
import gplx.String_;
|
||||
import gplx.core.primitives.Int_obj_val;
|
||||
|
||||
public class Json_parser__list_nde__base extends Json_parser__itm__base {
|
||||
public void Parse_grp(String context, Json_grp grp) {
|
||||
this.context = context;
|
||||
int len = grp.Len();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Json_nde sub = null;
|
||||
if (grp.Tid() == Json_itm_.Tid__nde) {
|
||||
Json_kv kv = Json_nde.Cast(grp).Get_at_as_kv(i);
|
||||
sub = kv.Val_as_nde();
|
||||
}
|
||||
else {
|
||||
sub = Json_nde.Cast(grp.Get_at(i));
|
||||
}
|
||||
Parse_nde(context, sub);
|
||||
}
|
||||
}
|
||||
public void Parse_nde(String context, Json_nde nde) {
|
||||
this.cur_itm = nde;
|
||||
for (int j = 0; j < keys_len; ++j)
|
||||
atrs[j] = null;
|
||||
int atr_len = nde.Len();
|
||||
for (int j = 0; j < atr_len; ++j) {
|
||||
Json_kv atr = nde.Get_at_as_kv(j);
|
||||
Object idx_obj = hash.Get_by_bry(atr.Key_as_bry());
|
||||
if (idx_obj == null) {Warn("unknown json parser key", atr); continue;}
|
||||
int idx_int = ((Int_obj_val)idx_obj).Val();
|
||||
atrs[idx_int] = atr;
|
||||
}
|
||||
Parse_hook_nde(nde, atrs);
|
||||
}
|
||||
public void Parse_to_list_as_bry(String context, Json_ary ary, Ordered_hash list) {
|
||||
this.cur_itm = ary;
|
||||
int len = ary.Len();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
byte[] val = ary.Get_at(i).Data_bry();
|
||||
list.Add(val, val);
|
||||
}
|
||||
}
|
||||
public void Parse_to_list_as_kv(String context, Json_nde nde, Ordered_hash list) {
|
||||
this.cur_itm = nde;
|
||||
int len = nde.Len();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Json_kv sub = nde.Get_at_as_kv(i);
|
||||
byte[] key = sub.Key_as_bry();
|
||||
byte[] val = Parse_to_list_as_kv__get_val(sub, key);
|
||||
list.Add(key, Keyval_.new_(String_.new_u8(key), String_.new_u8(val)));
|
||||
}
|
||||
}
|
||||
@gplx.Virtual protected byte[] Parse_to_list_as_kv__get_val(Json_kv sub, byte[] key) {return sub.Val_as_bry();}
|
||||
@Override protected void Parse_hook_nde(Json_nde sub, Json_kv[] atrs) {}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,87 +13,96 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
|
||||
import org.junit.*;
|
||||
public class Json_parser_tst {
|
||||
private final Json_parser_fxt fxt = new Json_parser_fxt();
|
||||
@Before public void init() {fxt.Clear();}
|
||||
@Test public void Null() {fxt.Test_parse_val0("{'k0':null}" , null);}
|
||||
@Test public void Bool_n() {fxt.Test_parse_val0("{'k0':false}" , false);}
|
||||
@Test public void Bool_y() {fxt.Test_parse_val0("{'k0':true}" , true);}
|
||||
@Test public void Num() {fxt.Test_parse_val0("{'k0':123}" , 123);}
|
||||
@Test public void Num_neg() {fxt.Test_parse_val0("{'k0':-123}" , -123);}
|
||||
@Test public void Str() {fxt.Test_parse_val0("{'k0':'v0'}" , "v0");}
|
||||
@Test public void Str_esc_quote() {fxt.Test_parse_val0("{'k0':'a\\\"b'}" , "a\"b");}
|
||||
@Test public void Str_encoded_basic() {fxt.Test_parse_val0("{'k0':'a\\u0021b'}" , "a!b");}
|
||||
@Test public void Str_encoded_surrogate() {fxt.Test_parse_val0("{'k0':'a\\ud83c\\udf0eb'}", "a🌎b");} // check for UTF surrogate-pairs; symbol is earth globe americas (U+1F30E); ISSUE#:487; DATE:2019-06-02
|
||||
@Test public void Num_dec() {fxt.Test_parse("{'k0':1.23}" , fxt.itm_nde_().Add_many(fxt.itm_kv_dec_("k0", "1.23")));}
|
||||
@Test public void Num_exp() {fxt.Test_parse("{'k0':1e+2}" , fxt.itm_nde_().Add_many(fxt.itm_kv_dec_("k0", "1e+2")));}
|
||||
@Test public void Num_mix() {fxt.Test_parse("{'k0':-1.23e-1}" , fxt.itm_nde_().Add_many(fxt.itm_kv_dec_("k0", "-1.23e-1")));}
|
||||
@Test public void Str_many() {fxt.Test_parse("{'k0':'v0','k1':'v1','k2':'v2'}", fxt.itm_nde_().Add_many(fxt.itm_kv_("k0", "v0"), fxt.itm_kv_("k1", "v1"), fxt.itm_kv_("k2", "v2")));}
|
||||
@Test public void Ary_empty() {fxt.Test_parse("{'k0':[]}", fxt.itm_nde_().Add_many(fxt.itm_kv_ary_int_("k0")));}
|
||||
@Test public void Ary_int() {fxt.Test_parse("{'k0':[1,2,3]}", fxt.itm_nde_().Add_many(fxt.itm_kv_ary_int_("k0", 1, 2, 3)));}
|
||||
@Test public void Ary_str() {fxt.Test_parse("{'k0':['a','b','c']}", fxt.itm_nde_().Add_many(fxt.itm_kv_ary_str_("k0", "a", "b", "c")));}
|
||||
@Test public void Ary_ws() {fxt.Test_parse("{'k0': [ 1 , 2 , 3 ] }", fxt.itm_nde_().Add_many(fxt.itm_kv_ary_int_("k0", 1, 2, 3)));}
|
||||
@Test public void Subs_int() {fxt.Test_parse("{'k0':{'k00':1}}", fxt.itm_nde_().Add_many(fxt.itm_kv_("k0", fxt.itm_nde_().Add_many(fxt.itm_kv_("k00", 1)))));}
|
||||
@Test public void Subs_empty() {fxt.Test_parse("{'k0':{}}", fxt.itm_nde_().Add_many(fxt.itm_kv_("k0", fxt.itm_nde_())));}
|
||||
@Test public void Subs_ws() {fxt.Test_parse("{'k0': { 'k00' : 1 } }", fxt.itm_nde_().Add_many(fxt.itm_kv_("k0", fxt.itm_nde_().Add_many(fxt.itm_kv_("k00", 1)))));}
|
||||
@Test public void Ws() {fxt.Test_parse(" { 'k0' : 'v0' } ", fxt.itm_nde_().Add_many(fxt.itm_kv_("k0", "v0")));}
|
||||
@Test public void Root_is_ary() {fxt.Test_parse("[ 1 , 2 , 3 ]", fxt.itm_ary_().Add_many(fxt.itm_int_(1), fxt.itm_int_(2), fxt.itm_int_(3)));}
|
||||
public static String Replace_apos_as_str(String v) {return String_.new_u8(Replace_apos(Bry_.new_u8(v)));}
|
||||
public static byte[] Replace_apos(byte[] v) {return Bry_.Replace(v, Byte_ascii.Apos, Byte_ascii.Quote);}
|
||||
}
|
||||
class Json_parser_fxt {
|
||||
public void Clear() {
|
||||
if (parser == null) {
|
||||
parser = new Json_parser();
|
||||
factory = parser.Factory();
|
||||
}
|
||||
} Json_parser parser; Json_factory factory; Bry_bfr tmp_bfr = Bry_bfr_.Reset(255);
|
||||
public Json_itm itm_int_(int v) {return Json_itm_tmp.new_int_(v);}
|
||||
Json_itm itm_str_(String v) {return Json_itm_tmp.new_str_(v);}
|
||||
public Json_ary itm_ary_() {return factory.Ary(-1, -1);}
|
||||
public Json_nde itm_nde_() {return factory.Nde(null, -1);}
|
||||
public Json_kv itm_kv_null_(String k) {return factory.Kv(itm_str_(k), factory.Null());}
|
||||
public Json_kv itm_kv_(String k, String v) {return factory.Kv(itm_str_(k), itm_str_(v));}
|
||||
public Json_kv itm_kv_(String k, int v) {return factory.Kv(itm_str_(k), itm_int_(v));}
|
||||
public Json_kv itm_kv_(String k, boolean v) {return factory.Kv(itm_str_(k), v ? factory.Bool_y() : factory.Bool_n());}
|
||||
public Json_kv itm_kv_dec_(String k, String v) {return factory.Kv(itm_str_(k), new Json_itm_tmp(Json_itm_.Tid__decimal, v));}
|
||||
public Json_kv itm_kv_(String k, Json_nde v) {return factory.Kv(itm_str_(k), v);}
|
||||
public Json_kv itm_kv_ary_int_(String k, int... v) {
|
||||
Json_ary ary = factory.Ary(-1, -1);
|
||||
int len = v.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
ary.Add(itm_int_(v[i]));
|
||||
return factory.Kv(itm_str_(k), ary);
|
||||
}
|
||||
public Json_kv itm_kv_ary_str_(String k, String... v) {
|
||||
Json_ary ary = factory.Ary(-1, -1);
|
||||
int len = v.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
ary.Add(itm_str_(v[i]));
|
||||
return factory.Kv(itm_str_(k), ary);
|
||||
}
|
||||
public void Test_parse(String raw_str, Json_itm... expd_ary) {
|
||||
byte[] raw = Json_parser_tst.Replace_apos(Bry_.new_u8(raw_str));
|
||||
Json_doc doc = parser.Parse(raw);
|
||||
doc.Root_grp().Print_as_json(tmp_bfr, 0);
|
||||
String actl = tmp_bfr.To_str_and_clear();
|
||||
String expd = Xto_str(raw, doc, expd_ary, 0, expd_ary.length);
|
||||
Tfds.Eq_str_lines(expd, actl, actl);
|
||||
}
|
||||
public void Test_parse_val0(String raw_str, Object expd) {
|
||||
byte[] raw = Json_parser_tst.Replace_apos(Bry_.new_u8(raw_str));
|
||||
Json_doc doc = parser.Parse(raw);
|
||||
Json_kv kv = Json_kv.cast(doc.Root_nde().Get_at(0)); // assume root has kv as first sub; EX: {"a":"b"}
|
||||
Object actl = kv.Val().Data(); // NOTE: Data_bry is escaped val; EX: a\"b has DataBry of a"b
|
||||
Tfds.Eq(expd, actl);
|
||||
}
|
||||
String Xto_str(byte[] raw, Json_doc doc, Json_itm[] ary, int bgn, int end) {
|
||||
for (int i = bgn; i < end; i++) {
|
||||
Json_itm itm = ary[i];
|
||||
itm.Print_as_json(tmp_bfr, 0);
|
||||
}
|
||||
return tmp_bfr.To_str_and_clear();
|
||||
}
|
||||
}
|
||||
package gplx.langs.jsons;
|
||||
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_bfr;
|
||||
import gplx.Bry_bfr_;
|
||||
import gplx.Decimal_adp;
|
||||
import gplx.Decimal_adp_;
|
||||
import gplx.Tfds;
|
||||
import gplx.core.tests.Gftest;
|
||||
import org.junit.Test;
|
||||
|
||||
public class Json_parser_tst {
|
||||
private final Json_parser_fxt fxt = new Json_parser_fxt();
|
||||
@Test public void Null() {fxt.Test_parse_obj("{'k0':null}" , null);}
|
||||
@Test public void Bool_n() {fxt.Test_parse_obj("{'k0':false}" , false);}
|
||||
@Test public void Bool_y() {fxt.Test_parse_obj("{'k0':true}" , true);}
|
||||
@Test public void Num() {fxt.Test_parse_obj("{'k0':123}" , 123);}
|
||||
@Test public void Num_neg() {fxt.Test_parse_obj("{'k0':-123}" , -123);}
|
||||
@Test public void Str() {fxt.Test_parse_obj("{'k0':'v0'}" , "v0");}
|
||||
@Test public void Str_esc_quote() {fxt.Test_parse_obj("{'k0':'a\\\"b'}" , "a\"b");}
|
||||
@Test public void Str_encoded_basic() {fxt.Test_parse_obj("{'k0':'a\\u0021b'}" , "a!b");}
|
||||
@Test public void Str_encoded_surrogate() {fxt.Test_parse_obj("{'k0':'a\\ud83c\\udf0eb'}", "a🌎b");} // check for UTF surrogate-pairs; symbol is earth globe americas (U+1F30E); ISSUE#:487; DATE:2019-06-02
|
||||
@Test public void Num_dec() {fxt.Test_parse_dec("{'k0':1.23}" , Decimal_adp_.parse("1.23"));}
|
||||
@Test public void Num_exp() {fxt.Test_parse_obj("{'k0':1e+2}" , 100);}
|
||||
@Test public void Num_mix() {fxt.Test_parse_dec("{'k0':-1.23e-1}" , Decimal_adp_.parse("-1.23e-1"));}
|
||||
@Test public void Str_many() {fxt.Test_parse("{'k0':'v0','k1':'v1','k2':'v2'}" , fxt.Init_nde().Add_many(fxt.Init_kv("k0", "v0"), fxt.Init_kv("k1", "v1"), fxt.Init_kv("k2", "v2")));}
|
||||
@Test public void Ary_empty() {fxt.Test_parse("{'k0':[]}" , fxt.Init_nde().Add_many(fxt.Init_kv_ary_int("k0")));}
|
||||
@Test public void Ary_int() {fxt.Test_parse("{'k0':[1,2,3]}" , fxt.Init_nde().Add_many(fxt.Init_kv_ary_int("k0", 1, 2, 3)));}
|
||||
@Test public void Ary_str() {fxt.Test_parse("{'k0':['a','b','c']}" , fxt.Init_nde().Add_many(fxt.Init_kvary_str_("k0", "a", "b", "c")));}
|
||||
@Test public void Ary_ws() {fxt.Test_parse("{'k0': [ 1 , 2 , 3 ] }" , fxt.Init_nde().Add_many(fxt.Init_kv_ary_int("k0", 1, 2, 3)));}
|
||||
@Test public void Subs_int() {fxt.Test_parse("{'k0':{'k00':1}}" , fxt.Init_nde().Add_many(fxt.Init_kv("k0", fxt.Init_nde().Add_many(fxt.Init_kv("k00", 1)))));}
|
||||
@Test public void Subs_empty() {fxt.Test_parse("{'k0':{}}" , fxt.Init_nde().Add_many(fxt.Init_kv("k0", fxt.Init_nde())));}
|
||||
@Test public void Subs_ws() {fxt.Test_parse("{'k0': { 'k00' : 1 } }" , fxt.Init_nde().Add_many(fxt.Init_kv("k0", fxt.Init_nde().Add_many(fxt.Init_kv("k00", 1)))));}
|
||||
@Test public void Ws() {fxt.Test_parse(" { 'k0' : 'v0' } " , fxt.Init_nde().Add_many(fxt.Init_kv("k0", "v0")));}
|
||||
@Test public void Root_is_ary() {fxt.Test_parse("[1,2,3]" , fxt.Init_ary().Add_many(fxt.Init_int(1), fxt.Init_int(2), fxt.Init_int(3)));}
|
||||
}
|
||||
class Json_parser_fxt {
|
||||
private final Json_parser parser = new Json_parser();
|
||||
private final Bry_bfr tmp_bfr = Bry_bfr_.Reset(255);
|
||||
public Json_itm Init_int(int v) {return Json_itm_int.NewByVal(v);}
|
||||
public Json_itm Init_str(String v) {return Json_itm_str.NewByVal(v);}
|
||||
public Json_ary Init_ary() {return Json_ary.NewByVal();}
|
||||
public Json_nde Init_nde() {return Json_nde.NewByVal();}
|
||||
public Json_kv Init_kv_null(String k) {return new Json_kv(Init_str(k), Json_itm_null.Null);}
|
||||
public Json_kv Init_kv(String k, String v) {return new Json_kv(Init_str(k), Init_str(v));}
|
||||
public Json_kv Init_kv(String k, int v) {return new Json_kv(Init_str(k), Init_int(v));}
|
||||
public Json_kv Init_kv(String k, boolean v) {return new Json_kv(Init_str(k), v ? Json_itm_bool.Bool_y : Json_itm_bool.Bool_n);}
|
||||
public Json_kv Init_kv(String k, Json_nde v) {return new Json_kv(Init_str(k), v);}
|
||||
public Json_kv Init_kv_ary_int(String k, int... v) {
|
||||
Json_ary ary = Json_ary.NewByVal();
|
||||
int len = v.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
ary.Add(Init_int(v[i]));
|
||||
return new Json_kv(Init_str(k), ary);
|
||||
}
|
||||
public Json_kv Init_kvary_str_(String k, String... v) {
|
||||
Json_ary ary = Json_ary.NewByVal();
|
||||
int len = v.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
ary.Add(Init_str(v[i]));
|
||||
return new Json_kv(Init_str(k), ary);
|
||||
}
|
||||
public void Test_parse(String raw_str, Json_itm... expd_ary) {
|
||||
byte[] raw = Bry_.new_u8(Json_doc.Make_str_by_apos(raw_str));
|
||||
Json_doc doc = parser.Parse(raw);
|
||||
doc.Root_grp().Print_as_json(tmp_bfr, 0);
|
||||
String actl = tmp_bfr.To_str_and_clear();
|
||||
String expd = Xto_str(raw, doc, expd_ary, 0, expd_ary.length);
|
||||
Tfds.Eq_str_lines(expd, actl, actl);
|
||||
}
|
||||
public void Test_parse_obj(String raw_str, Object expd) {
|
||||
Json_kv kv = Parse_and_get_kv0(raw_str);
|
||||
Object actl = kv.Val().Data(); // NOTE: Data_bry is escaped val; EX: a\"b has DataBry of a"b
|
||||
Gftest.Eq__obj_or_null(expd, actl);
|
||||
}
|
||||
public void Test_parse_dec(String raw_str, Decimal_adp expd) {
|
||||
Json_kv kv = Parse_and_get_kv0(raw_str);
|
||||
Json_itm_decimal decimal_itm = (Json_itm_decimal)kv.Val();
|
||||
Gftest.Eq__bool(true, decimal_itm.Data_as_decimal().Eq(expd));
|
||||
}
|
||||
private Json_kv Parse_and_get_kv0(String raw_str) {
|
||||
byte[] raw = Bry_.new_u8(Json_doc.Make_str_by_apos(raw_str));
|
||||
Json_doc doc = parser.Parse(raw);
|
||||
return Json_kv.Cast(doc.Root_nde().Get_at(0)); // assume root has kv as first sub; EX: {"a":"b"}
|
||||
}
|
||||
private String Xto_str(byte[] raw, Json_doc doc, Json_itm[] ary, int bgn, int end) {
|
||||
for (int i = bgn; i < end; i++) {
|
||||
Json_itm itm = ary[i];
|
||||
itm.Print_as_json(tmp_bfr, 0);
|
||||
}
|
||||
return tmp_bfr.To_str_and_clear();
|
||||
}
|
||||
}
|
||||
|
||||
112
400_xowa/src/gplx/langs/mustaches/JsonMustacheNde.java
Normal file
112
400_xowa/src/gplx/langs/mustaches/JsonMustacheNde.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.mustaches;
|
||||
|
||||
import gplx.Bool_;
|
||||
import gplx.Bry_;
|
||||
import gplx.String_;
|
||||
import gplx.langs.jsons.Json_ary;
|
||||
import gplx.langs.jsons.Json_itm;
|
||||
import gplx.langs.jsons.Json_itm_;
|
||||
import gplx.langs.jsons.Json_kv;
|
||||
import gplx.langs.jsons.Json_nde;
|
||||
import gplx.objects.Object_;
|
||||
|
||||
public class JsonMustacheNde implements Mustache_doc_itm {
|
||||
private final Json_nde nde;
|
||||
public JsonMustacheNde(Json_nde nde) {this.nde = nde;}
|
||||
public boolean Mustache__write(String key, Mustache_bfr bfr) {
|
||||
Json_itm itm = nde.Get_itm(Bry_.new_u8(key));
|
||||
if (itm == null) { // mustacheKey does not exist in current jsonNde
|
||||
return false;
|
||||
}
|
||||
else { // mustacheKey exists
|
||||
switch (itm.Tid()) {
|
||||
// array / bool node -> ignore; EX: `{{#person}}Never shown{{/person}}`
|
||||
case Json_itm_.Tid__bool:
|
||||
case Json_itm_.Tid__ary:
|
||||
case Json_itm_.Tid__nde:
|
||||
return false;
|
||||
// item node -> render it; EX: `Hello {{name}}`
|
||||
default:
|
||||
bfr.Add_bry(Json_kv.Cast(itm).Val_as_bry());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
public Mustache_doc_itm[] Mustache__subs(String key) {
|
||||
Json_itm itm = nde.Get_itm(Bry_.new_u8(key));
|
||||
if (itm == null) { // mustacheKey does not exist in current jsonNde
|
||||
return Mustache_doc_itm_.Ary__bool__n;
|
||||
}
|
||||
else { // mustacheKey exists
|
||||
if (itm.Tid() == Json_itm_.Tid__kv) {
|
||||
Json_kv kv = Json_kv.Cast(itm);
|
||||
switch (kv.Val().Tid()) {
|
||||
// bool node -> render; EX: `{{#person}}Never shown{{/person}}`
|
||||
case Json_itm_.Tid__bool:
|
||||
boolean dataVal = Bool_.Cast(kv.Val().Data());
|
||||
return dataVal ? Mustache_doc_itm_.Ary__bool__y : Mustache_doc_itm_.Ary__bool__n;
|
||||
// array node -> render; EX: `{{#repo}} <b>{{name}}</b>{{/repo}}`
|
||||
case Json_itm_.Tid__ary:
|
||||
return ToJsonMustachNdeAry(itm);
|
||||
// item node -> render only if key matchers
|
||||
default:
|
||||
return new Mustache_doc_itm[] {new JsonMustacheVal(true, key, kv.Val().Data())};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return Mustache_doc_itm_.Ary__bool__n;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static Mustache_doc_itm[] ToJsonMustachNdeAry(Json_itm itm) {
|
||||
Json_ary dataAry = Json_ary.cast_or_null(Json_kv.Cast(itm).Val());
|
||||
int subs_len = dataAry.Len();
|
||||
Mustache_doc_itm[] rv = new Mustache_doc_itm[subs_len];
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
Json_itm sub = dataAry.Get_at(i);
|
||||
if (sub.Tid() == Json_itm_.Tid__nde) {
|
||||
rv[i] = new JsonMustacheNde((Json_nde)sub);
|
||||
}
|
||||
else {
|
||||
rv[i] = new JsonMustacheVal(false, Mustache_tkn_def.ItemString, sub.Data());
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
class JsonMustacheVal implements Mustache_doc_itm {
|
||||
private final boolean fromArray;
|
||||
private final String jsonKey;
|
||||
private final Object jsonVal;
|
||||
public JsonMustacheVal(boolean fromArray, String jsonKey, Object jsonVal) {
|
||||
this.fromArray = fromArray;
|
||||
this.jsonKey = jsonKey;
|
||||
this.jsonVal = jsonVal;
|
||||
}
|
||||
public boolean Mustache__write(String mustacheKey, Mustache_bfr bfr) {
|
||||
if ( (String_.Eq(mustacheKey, jsonKey)) // print if `{{match}}`; EX: `{{#prop}}{{prop}}{{/prop}}`
|
||||
|| (String_.Eq(mustacheKey, Mustache_tkn_def.ItemString) && fromArray)) { // print if `{{.}}` and from array; EX: `{{#array}}{{.}}{{/array}}`
|
||||
bfr.Add_bry(Bry_.new_u8(Object_.To_str(jsonVal)));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public Mustache_doc_itm[] Mustache__subs(String key) {return Mustache_doc_itm_.Ary__empty;}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,9 +13,9 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.mustaches; import gplx.*; import gplx.langs.*;
|
||||
import gplx.langs.jsons.*;
|
||||
public interface Mustache_doc_itm {
|
||||
boolean Mustache__write(String key, Mustache_bfr bfr);
|
||||
Mustache_doc_itm[] Mustache__subs(String key);
|
||||
}
|
||||
package gplx.langs.mustaches;
|
||||
|
||||
public interface Mustache_doc_itm {
|
||||
boolean Mustache__write(String key, Mustache_bfr bfr);
|
||||
Mustache_doc_itm[] Mustache__subs(String key);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,150 +13,177 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.mustaches; import gplx.*; import gplx.langs.*;
|
||||
import org.junit.*; import gplx.core.primitives.*;
|
||||
public class Mustache_itm_render_tst {
|
||||
private final Mustache_itm_render_fxt fxt = new Mustache_itm_render_fxt();
|
||||
@Test public void Text() {
|
||||
fxt.Test__parse("a b c", "a b c");
|
||||
}
|
||||
@Test public void Variable() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_prop("prop1", "1").Add_prop("prop2", "2"));
|
||||
fxt.Test__parse("{{prop1}}", "1");
|
||||
fxt.Test__parse("a{{prop1}}b{{prop2}}c", "a1b2c");
|
||||
}
|
||||
@Test public void Escape() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_prop("prop1", "<"));
|
||||
fxt.Test__parse("{{{prop1}}}", "<");
|
||||
fxt.Test__parse("{{prop1}}", "<");
|
||||
}
|
||||
@Test public void Section_bool() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y").Add_bool_n("bool_n"));
|
||||
fxt.Test__parse("a{{#bool_y}}b{{/bool_y}}c", "abc");
|
||||
fxt.Test__parse("a{{#bool_n}}b{{/bool_n}}c", "ac");
|
||||
fxt.Test__parse("a{{#bool_y}}b{{/bool_y}}c{{#bool_n}}d{{/bool_n}}e", "abce");
|
||||
}
|
||||
@Test public void Section_not() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y").Add_bool_n("bool_n"));
|
||||
fxt.Test__parse("a{{^bool_y}}b{{/bool_y}}c", "ac");
|
||||
fxt.Test__parse("a{{^bool_n}}b{{/bool_n}}c", "abc");
|
||||
fxt.Test__parse("a{{^bool_y}}b{{/bool_y}}c{{^bool_n}}d{{/bool_n}}e", "acde");
|
||||
}
|
||||
@Test public void Section_ws() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y"));
|
||||
fxt.Test__parse("a\n {{#bool_y}} \nb\n {{/bool_y}} \nc", "a\nb\nc");
|
||||
}
|
||||
@Test public void Section_subs_flat() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "1").Add_subs("subs2")
|
||||
, fxt.Make_mock(2).Add_prop("prop1", "2").Add_subs("subs2")
|
||||
));
|
||||
fxt.Test__parse("a{{#subs1}}({{prop1}}){{/subs1}}d", "a(1)(2)d");
|
||||
}
|
||||
@Test public void Section_subs_nest_1() {
|
||||
fxt.Init__root
|
||||
( fxt.Make_mock(0).Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
|
||||
, fxt.Make_mock(11).Add_prop("prop2", "1")
|
||||
, fxt.Make_mock(12).Add_prop("prop2", "2"))
|
||||
));
|
||||
fxt.Test__parse
|
||||
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{/subs1}}"
|
||||
, "a12"
|
||||
);
|
||||
}
|
||||
@Test public void Section_subs_nest_2() {
|
||||
fxt.Init__root
|
||||
( fxt.Make_mock(0).Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
|
||||
, fxt.Make_mock(11).Add_prop("prop2", "1")
|
||||
, fxt.Make_mock(12).Add_prop("prop2", "2")
|
||||
)
|
||||
, fxt.Make_mock(2).Add_prop("prop1", "b")
|
||||
)
|
||||
);
|
||||
fxt.Test__parse
|
||||
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{/subs1}}"
|
||||
, "a12b"
|
||||
);
|
||||
}
|
||||
@Test public void Section_subs_nest_3() {
|
||||
fxt.Init__root
|
||||
( fxt.Make_mock(0).Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
|
||||
, fxt.Make_mock(11).Add_prop("prop2", "1")
|
||||
, fxt.Make_mock(12).Add_prop("prop2", "2")
|
||||
)
|
||||
, fxt.Make_mock(2).Add_prop("prop1", "b").Add_subs("subs2"
|
||||
, fxt.Make_mock(21).Add_prop("prop2", "3")
|
||||
, fxt.Make_mock(22).Add_prop("prop2", "4")
|
||||
)
|
||||
)
|
||||
);
|
||||
fxt.Test__parse
|
||||
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{prop1}}{{/subs1}}"
|
||||
, "a12ab34b"
|
||||
);
|
||||
}
|
||||
@Test public void Section_bool_subs() { // handle prop written after boolean; should not pick up inner prop
|
||||
fxt.Init__root
|
||||
( fxt.Make_mock(0).Add_bool_y("bool1").Add_prop("prop2", "2").Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "11")
|
||||
, fxt.Make_mock(2).Add_prop("prop1", "12")
|
||||
));
|
||||
fxt.Test__parse
|
||||
( "a{{#bool1}}b{{#subs1}}c{{prop1}}d{{/subs1}}e{{/bool1}}f{{prop2}}g"
|
||||
, "abc11dc12def2g"
|
||||
);
|
||||
}
|
||||
@Test public void Section_owner() {
|
||||
fxt.Init__root
|
||||
( fxt.Make_mock(0).Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
|
||||
, fxt.Make_mock(11).Add_prop("prop2", "1")
|
||||
)
|
||||
));
|
||||
fxt.Test__parse
|
||||
( "{{#subs1}}{{#subs2}}{{prop1}}{{prop2}}{{/subs2}}{{/subs1}}" // prop1 is cited in subs2, but value belongs to subs1
|
||||
, "a1"
|
||||
);
|
||||
}
|
||||
}
|
||||
class Mustache_itm_render_fxt {
|
||||
private final Mustache_tkn_parser parser = new Mustache_tkn_parser();
|
||||
private final Mustache_render_ctx ctx = new Mustache_render_ctx();
|
||||
private final Mustache_bfr bfr = Mustache_bfr.New();
|
||||
private Mustache_doc_itm__mock root;
|
||||
public Mustache_doc_itm__mock Make_mock(int id) {return new Mustache_doc_itm__mock(id);}
|
||||
public void Init__root(Mustache_doc_itm__mock v) {this.root = v;}
|
||||
public void Test__parse(String src_str, String expd) {
|
||||
byte[] src_bry = Bry_.new_a7(src_str);
|
||||
Mustache_tkn_itm actl_itm = parser.Parse(src_bry, 0, src_bry.length);
|
||||
ctx.Init(root);
|
||||
actl_itm.Render(bfr, ctx);
|
||||
Tfds.Eq_str_lines(expd, bfr.To_str_and_clear());
|
||||
}
|
||||
}
|
||||
class Mustache_doc_itm__mock implements Mustache_doc_itm {
|
||||
private final Hash_adp hash_prop = Hash_adp_.New(), hash_bool = Hash_adp_.New(), hash_subs = Hash_adp_.New();
|
||||
public Mustache_doc_itm__mock(int id) {this.id = id;}
|
||||
public int id;
|
||||
public Mustache_doc_itm__mock Add_prop(String key, String val) {hash_prop.Add(key, Bry_.new_u8(val)); return this;}
|
||||
public Mustache_doc_itm__mock Add_bool_y(String key) {hash_bool.Add(key, Bool_obj_ref.y_()); return this;}
|
||||
public Mustache_doc_itm__mock Add_bool_n(String key) {hash_bool.Add(key, Bool_obj_ref.n_()); return this;}
|
||||
public Mustache_doc_itm__mock Add_subs(String key, Mustache_doc_itm__mock... ary) {hash_subs.Add(key, ary); return this;}
|
||||
public boolean Mustache__write(String key, Mustache_bfr bfr) {
|
||||
byte[] rv = (byte[])hash_prop.Get_by(key);
|
||||
if (rv == null) return false;
|
||||
bfr.Add_bry(rv);
|
||||
return true;
|
||||
}
|
||||
public Mustache_doc_itm[] Mustache__subs(String key) {
|
||||
Object rv = hash_bool.Get_by(key);
|
||||
if (rv != null) {
|
||||
boolean bool_val = ((Bool_obj_ref)rv).Val();
|
||||
return bool_val ? Mustache_doc_itm_.Ary__bool__y : Mustache_doc_itm_.Ary__bool__n;
|
||||
}
|
||||
return (Mustache_doc_itm__mock[])hash_subs.Get_by(key);
|
||||
}
|
||||
}
|
||||
package gplx.langs.mustaches;
|
||||
|
||||
import gplx.Bry_;
|
||||
import gplx.Hash_adp;
|
||||
import gplx.Hash_adp_;
|
||||
import gplx.Tfds;
|
||||
import gplx.core.primitives.Bool_obj_ref;
|
||||
import gplx.langs.jsons.Json_doc;
|
||||
import gplx.langs.jsons.Json_nde;
|
||||
import gplx.langs.jsons.Json_parser;
|
||||
import org.junit.Test;
|
||||
|
||||
public class Mustache_itm_render_tst {
|
||||
private final Mustache_itm_render_fxt fxt = new Mustache_itm_render_fxt();
|
||||
@Test public void Text() {
|
||||
fxt.Test__parse("a b c", "a b c");
|
||||
}
|
||||
@Test public void Variable() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_prop("prop1", "1").Add_prop("prop2", "2"));
|
||||
fxt.Test__parse("{{prop1}}", "1");
|
||||
fxt.Test__parse("a{{prop1}}b{{prop2}}c", "a1b2c");
|
||||
}
|
||||
@Test public void Escape() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_prop("prop1", "<"));
|
||||
fxt.Test__parse("{{{prop1}}}", "<");
|
||||
fxt.Test__parse("{{prop1}}", "<");
|
||||
}
|
||||
@Test public void Section_bool() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y").Add_bool_n("bool_n"));
|
||||
fxt.Test__parse("a{{#bool_y}}b{{/bool_y}}c", "abc");
|
||||
fxt.Test__parse("a{{#bool_n}}b{{/bool_n}}c", "ac");
|
||||
fxt.Test__parse("a{{#bool_y}}b{{/bool_y}}c{{#bool_n}}d{{/bool_n}}e", "abce");
|
||||
}
|
||||
@Test public void Section_not() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y").Add_bool_n("bool_n"));
|
||||
fxt.Test__parse("a{{^bool_y}}b{{/bool_y}}c", "ac");
|
||||
fxt.Test__parse("a{{^bool_n}}b{{/bool_n}}c", "abc");
|
||||
fxt.Test__parse("a{{^bool_y}}b{{/bool_y}}c{{^bool_n}}d{{/bool_n}}e", "acde");
|
||||
}
|
||||
@Test public void Section_ws() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y"));
|
||||
fxt.Test__parse("a\n {{#bool_y}} \nb\n {{/bool_y}} \nc", "a\nb\nc");
|
||||
}
|
||||
@Test public void Section_subs_flat() {
|
||||
fxt.Init__root(fxt.Make_mock(0).Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "1").Add_subs("subs2")
|
||||
, fxt.Make_mock(2).Add_prop("prop1", "2").Add_subs("subs2")
|
||||
));
|
||||
fxt.Test__parse("a{{#subs1}}({{prop1}}){{/subs1}}d", "a(1)(2)d");
|
||||
}
|
||||
@Test public void Section_subs_nest_1() {
|
||||
fxt.Init__root
|
||||
( fxt.Make_mock(0).Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
|
||||
, fxt.Make_mock(11).Add_prop("prop2", "1")
|
||||
, fxt.Make_mock(12).Add_prop("prop2", "2"))
|
||||
));
|
||||
fxt.Test__parse
|
||||
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{/subs1}}"
|
||||
, "a12"
|
||||
);
|
||||
}
|
||||
@Test public void Section_subs_nest_2() {
|
||||
fxt.Init__root
|
||||
( fxt.Make_mock(0).Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
|
||||
, fxt.Make_mock(11).Add_prop("prop2", "1")
|
||||
, fxt.Make_mock(12).Add_prop("prop2", "2")
|
||||
)
|
||||
, fxt.Make_mock(2).Add_prop("prop1", "b")
|
||||
)
|
||||
);
|
||||
fxt.Test__parse
|
||||
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{/subs1}}"
|
||||
, "a12b"
|
||||
);
|
||||
}
|
||||
@Test public void Section_subs_nest_3() {
|
||||
fxt.Init__root
|
||||
( fxt.Make_mock(0).Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
|
||||
, fxt.Make_mock(11).Add_prop("prop2", "1")
|
||||
, fxt.Make_mock(12).Add_prop("prop2", "2")
|
||||
)
|
||||
, fxt.Make_mock(2).Add_prop("prop1", "b").Add_subs("subs2"
|
||||
, fxt.Make_mock(21).Add_prop("prop2", "3")
|
||||
, fxt.Make_mock(22).Add_prop("prop2", "4")
|
||||
)
|
||||
)
|
||||
);
|
||||
fxt.Test__parse
|
||||
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{prop1}}{{/subs1}}"
|
||||
, "a12ab34b"
|
||||
);
|
||||
}
|
||||
@Test public void Section_bool_subs() { // handle prop written after boolean; should not pick up inner prop
|
||||
fxt.Init__root
|
||||
( fxt.Make_mock(0).Add_bool_y("bool1").Add_prop("prop2", "2").Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "11")
|
||||
, fxt.Make_mock(2).Add_prop("prop1", "12")
|
||||
));
|
||||
fxt.Test__parse
|
||||
( "a{{#bool1}}b{{#subs1}}c{{prop1}}d{{/subs1}}e{{/bool1}}f{{prop2}}g"
|
||||
, "abc11dc12def2g"
|
||||
);
|
||||
}
|
||||
@Test public void Section_owner() {
|
||||
fxt.Init__root
|
||||
( fxt.Make_mock(0).Add_subs("subs1"
|
||||
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
|
||||
, fxt.Make_mock(11).Add_prop("prop2", "1")
|
||||
)
|
||||
));
|
||||
fxt.Test__parse
|
||||
( "{{#subs1}}{{#subs2}}{{prop1}}{{prop2}}{{/subs2}}{{/subs1}}" // prop1 is cited in subs2, but value belongs to subs1
|
||||
, "a1"
|
||||
);
|
||||
}
|
||||
@Test public void Dot() {
|
||||
fxt.Test__parse
|
||||
( "{'subs':['a', 'b', 'c', 'd']}"
|
||||
, "{{#subs}}{{.}},{{/subs}}"
|
||||
, "a,b,c,d,"
|
||||
);
|
||||
}
|
||||
}
|
||||
class Mustache_itm_render_fxt {
|
||||
private final Mustache_tkn_parser parser = new Mustache_tkn_parser();
|
||||
private final Mustache_render_ctx ctx = new Mustache_render_ctx();
|
||||
private final Mustache_bfr bfr = Mustache_bfr.New();
|
||||
private Mustache_doc_itm__mock root;
|
||||
public Mustache_doc_itm__mock Make_mock(int id) {return new Mustache_doc_itm__mock(id);}
|
||||
public void Init__root(Mustache_doc_itm__mock v) {this.root = v;}
|
||||
public void Test__parse(String src_str, String expd) {
|
||||
byte[] src_bry = Bry_.new_a7(src_str);
|
||||
Mustache_tkn_itm actl_itm = parser.Parse(src_bry, 0, src_bry.length);
|
||||
ctx.Init(root);
|
||||
actl_itm.Render(bfr, ctx);
|
||||
Tfds.Eq_str_lines(expd, bfr.To_str_and_clear());
|
||||
}
|
||||
public void Test__parse(String jdoc, String src_str, String expd) {
|
||||
Json_nde jnde = Json_parser.ParseToJdoc(Json_doc.Make_str_by_apos(jdoc)).Root_nde();
|
||||
JsonMustacheNde nde = new JsonMustacheNde(jnde);
|
||||
|
||||
byte[] src_bry = Bry_.new_a7(src_str);
|
||||
Mustache_tkn_itm actl_itm = parser.Parse(src_bry, 0, src_bry.length);
|
||||
ctx.Init(nde);
|
||||
actl_itm.Render(bfr, ctx);
|
||||
Tfds.Eq_str_lines(expd, bfr.To_str_and_clear());
|
||||
}
|
||||
}
|
||||
class Mustache_doc_itm__mock implements Mustache_doc_itm {
|
||||
private final Hash_adp hash_prop = Hash_adp_.New(), hash_bool = Hash_adp_.New(), hash_subs = Hash_adp_.New();
|
||||
public Mustache_doc_itm__mock(int id) {this.id = id;}
|
||||
public int id;
|
||||
public Mustache_doc_itm__mock Add_prop(String key, String val) {hash_prop.Add(key, Bry_.new_u8(val)); return this;}
|
||||
public Mustache_doc_itm__mock Add_bool_y(String key) {hash_bool.Add(key, Bool_obj_ref.y_()); return this;}
|
||||
public Mustache_doc_itm__mock Add_bool_n(String key) {hash_bool.Add(key, Bool_obj_ref.n_()); return this;}
|
||||
public Mustache_doc_itm__mock Add_subs(String key, Mustache_doc_itm__mock... ary) {hash_subs.Add(key, ary); return this;}
|
||||
public boolean Mustache__write(String key, Mustache_bfr bfr) {
|
||||
byte[] rv = (byte[])hash_prop.Get_by(key);
|
||||
if (rv == null) return false;
|
||||
bfr.Add_bry(rv);
|
||||
return true;
|
||||
}
|
||||
public Mustache_doc_itm[] Mustache__subs(String key) {
|
||||
Object rv = hash_bool.Get_by(key);
|
||||
if (rv != null) {
|
||||
boolean bool_val = ((Bool_obj_ref)rv).Val();
|
||||
return bool_val ? Mustache_doc_itm_.Ary__bool__y : Mustache_doc_itm_.Ary__bool__n;
|
||||
}
|
||||
return (Mustache_doc_itm__mock[])hash_subs.Get_by(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,86 +13,100 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.mustaches; import gplx.*; import gplx.langs.*;
|
||||
public class Mustache_render_ctx {
|
||||
private final List_adp stack = List_adp_.New();
|
||||
private Mustache_doc_itm cur;
|
||||
private Mustache_doc_itm[] subs; private int subs_idx, subs_len; private byte cur_is_bool;
|
||||
public Mustache_render_ctx Init(Mustache_doc_itm cur) {
|
||||
this.cur = cur;
|
||||
this.subs = null;
|
||||
this.subs_idx = subs_len = 0; this.cur_is_bool = Bool_.__byte;
|
||||
return this;
|
||||
}
|
||||
public boolean Render_variable(Mustache_bfr bfr, String key) {
|
||||
boolean rv = false;
|
||||
int stack_pos = stack.Len();
|
||||
Mustache_doc_itm itm = cur;
|
||||
while (itm != Mustache_doc_itm_.Null_itm) {
|
||||
boolean resolved = itm.Mustache__write(key, bfr);
|
||||
if (resolved) {
|
||||
rv = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
--stack_pos;
|
||||
if (stack_pos == -1) // nothing else in stack
|
||||
break;
|
||||
else
|
||||
itm = ((Mustache_stack_itm)stack.Get_at(stack_pos)).cur;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public void Section_bgn(String key) {
|
||||
Mustache_stack_itm stack_itm = new Mustache_stack_itm(cur, subs, subs_idx, subs_len, cur_is_bool); // note that cur is "owner" since subs_idx == 0
|
||||
stack.Add(stack_itm);
|
||||
subs = cur.Mustache__subs(key); if (subs == null) subs = Mustache_doc_itm_.Ary__empty; // subs == null if property does not exist; EX: "folder{{#files}}file{{/files}}" and folder = new Folder(File[0]);
|
||||
subs_len = subs.length;
|
||||
subs_idx = -1;
|
||||
}
|
||||
public boolean Section_do(boolean inverted) {
|
||||
if (++subs_idx >= subs_len) return false;
|
||||
Mustache_doc_itm sub = subs[subs_idx];
|
||||
if (subs_idx == 0) { // special logic to handle 1st item; note that there always be at least one item
|
||||
if (sub == Mustache_doc_itm_.Itm__bool__n) {
|
||||
boolean rv = Bool_.N;
|
||||
if (inverted) rv = !rv;
|
||||
cur_is_bool = Bool_.To_byte(rv);
|
||||
return rv;
|
||||
}
|
||||
else if (sub == Mustache_doc_itm_.Itm__bool__y) {
|
||||
boolean rv = Bool_.Y;
|
||||
if (inverted) rv = !rv;
|
||||
cur_is_bool = Bool_.To_byte(rv);
|
||||
return rv;
|
||||
}
|
||||
else
|
||||
cur_is_bool = Bool_.__byte;
|
||||
}
|
||||
cur = sub;
|
||||
return true;
|
||||
}
|
||||
public void Section_end() {
|
||||
Mustache_stack_itm itm = (Mustache_stack_itm)List_adp_.Pop(stack);
|
||||
subs = itm.subs;
|
||||
subs_len = itm.subs_len;
|
||||
subs_idx = itm.subs_idx;
|
||||
cur = itm.cur;
|
||||
cur_is_bool = itm.cur_is_bool;
|
||||
}
|
||||
}
|
||||
class Mustache_stack_itm {
|
||||
public Mustache_stack_itm(Mustache_doc_itm cur, Mustache_doc_itm[] subs, int subs_idx, int subs_len, byte cur_is_bool) {
|
||||
this.cur = cur;
|
||||
this.cur_is_bool = cur_is_bool;
|
||||
this.subs = subs;
|
||||
this.subs_idx = subs_idx;
|
||||
this.subs_len = subs_len;
|
||||
}
|
||||
public final Mustache_doc_itm cur;
|
||||
public final byte cur_is_bool;
|
||||
public final Mustache_doc_itm[] subs;
|
||||
public final int subs_idx;
|
||||
public final int subs_len;
|
||||
}
|
||||
package gplx.langs.mustaches;
|
||||
|
||||
import gplx.Bool_;
|
||||
import gplx.List_adp;
|
||||
import gplx.List_adp_;
|
||||
|
||||
public class Mustache_render_ctx {
|
||||
private final List_adp stack = List_adp_.New();
|
||||
private Mustache_doc_itm cur;
|
||||
private Mustache_doc_itm[] subs;
|
||||
private int subs_idx, subs_len;
|
||||
private byte cur_is_bool;
|
||||
|
||||
public Mustache_render_ctx Init(Mustache_doc_itm cur) {
|
||||
this.cur = cur;
|
||||
this.subs = null;
|
||||
this.subs_idx = subs_len = 0;
|
||||
this.cur_is_bool = Bool_.__byte;
|
||||
return this;
|
||||
}
|
||||
public boolean Render_variable(Mustache_bfr bfr, String key) {
|
||||
boolean rv = false;
|
||||
int stack_pos = stack.Len();
|
||||
Mustache_doc_itm itm = cur;
|
||||
while (itm != Mustache_doc_itm_.Null_itm) {
|
||||
boolean resolved = itm.Mustache__write(key, bfr);
|
||||
// current itm handles key -> exit
|
||||
if (resolved) {
|
||||
rv = true;
|
||||
break;
|
||||
}
|
||||
// current itm does not handle key -> go up stack
|
||||
else {
|
||||
--stack_pos;
|
||||
if (stack_pos == -1) // nothing else in stack
|
||||
break;
|
||||
else
|
||||
itm = ((Mustache_stack_itm)stack.Get_at(stack_pos)).cur;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public void Section_bgn(String key) {
|
||||
Mustache_stack_itm stack_itm = new Mustache_stack_itm(cur, subs, subs_idx, subs_len, cur_is_bool); // note that cur is "owner" since subs_idx == 0
|
||||
stack.Add(stack_itm);
|
||||
subs = cur.Mustache__subs(key);
|
||||
if (subs == null) // subs == null if property does not exist; EX: "folder{{#files}}file{{/files}}" and folder = new Folder(File[0]);
|
||||
subs = Mustache_doc_itm_.Ary__empty;
|
||||
subs_len = subs.length;
|
||||
subs_idx = -1;
|
||||
}
|
||||
public boolean Section_do(boolean inverted) {
|
||||
if (++subs_idx >= subs_len)
|
||||
return false;
|
||||
Mustache_doc_itm sub = subs[subs_idx];
|
||||
if (subs_idx == 0) { // special logic to handle 1st item; note that there always be at least one item
|
||||
if (sub == Mustache_doc_itm_.Itm__bool__n) {
|
||||
boolean rv = Bool_.N;
|
||||
if (inverted) rv = !rv;
|
||||
cur_is_bool = Bool_.To_byte(rv);
|
||||
return rv;
|
||||
}
|
||||
else if (sub == Mustache_doc_itm_.Itm__bool__y) {
|
||||
boolean rv = Bool_.Y;
|
||||
if (inverted) rv = !rv;
|
||||
cur_is_bool = Bool_.To_byte(rv);
|
||||
return rv;
|
||||
}
|
||||
else
|
||||
cur_is_bool = Bool_.__byte;
|
||||
}
|
||||
cur = sub;
|
||||
return true;
|
||||
}
|
||||
public void Section_end() {
|
||||
Mustache_stack_itm itm = (Mustache_stack_itm)List_adp_.Pop(stack);
|
||||
subs = itm.subs;
|
||||
subs_len = itm.subs_len;
|
||||
subs_idx = itm.subs_idx;
|
||||
cur = itm.cur;
|
||||
cur_is_bool = itm.cur_is_bool;
|
||||
}
|
||||
}
|
||||
class Mustache_stack_itm {
|
||||
public Mustache_stack_itm(Mustache_doc_itm cur, Mustache_doc_itm[] subs, int subs_idx, int subs_len, byte cur_is_bool) {
|
||||
this.cur = cur;
|
||||
this.cur_is_bool = cur_is_bool;
|
||||
this.subs = subs;
|
||||
this.subs_idx = subs_idx;
|
||||
this.subs_len = subs_len;
|
||||
}
|
||||
public final Mustache_doc_itm cur;
|
||||
public final byte cur_is_bool;
|
||||
public final Mustache_doc_itm[] subs;
|
||||
public final int subs_idx;
|
||||
public final int subs_len;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,30 +13,40 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.mustaches; import gplx.*; import gplx.langs.*;
|
||||
class Mustache_tkn_def {
|
||||
public byte[] Variable_lhs = Dflt_variable_lhs;
|
||||
public byte[] Variable_rhs = Dflt_variable_rhs;
|
||||
public int Variable_lhs_len;
|
||||
public int Variable_rhs_len;
|
||||
public static final byte[]
|
||||
Dflt_variable_lhs = Bry_.new_a7("{{")
|
||||
, Dflt_variable_rhs = Bry_.new_a7("}}")
|
||||
;
|
||||
public static final byte
|
||||
Variable = Byte_ascii.Curly_end // {{=<% %>=}}
|
||||
, Escape_bgn = Byte_ascii.Curly_bgn // {{{escape}}}
|
||||
, Escape_end = Byte_ascii.Curly_end // {{{escape}}}
|
||||
, Section = Byte_ascii.Hash // {{#section}}
|
||||
, Grp_end = Byte_ascii.Slash // {{/section}}
|
||||
, Inverted = Byte_ascii.Pow // {{^inverted}}
|
||||
, Comment = Byte_ascii.Bang // {{!comment}}
|
||||
, Partial = Byte_ascii.Angle_bgn // {{>partial}}
|
||||
, Delimiter_bgn = Byte_ascii.Eq // {{=<% %>=}}
|
||||
, Delimiter_end = Byte_ascii.Curly_end // {{=<% %>=}}
|
||||
;
|
||||
public Mustache_tkn_def() {
|
||||
Variable_lhs_len = Variable_lhs.length;
|
||||
Variable_rhs_len = Variable_rhs.length;
|
||||
}
|
||||
}
|
||||
package gplx.langs.mustaches;
|
||||
|
||||
import gplx.Bry_;
|
||||
import gplx.Byte_;
|
||||
import gplx.Byte_ascii;
|
||||
import gplx.String_;
|
||||
|
||||
class Mustache_tkn_def {
|
||||
public byte[] Variable_lhs = Dflt_variable_lhs;
|
||||
public byte[] Variable_rhs = Dflt_variable_rhs;
|
||||
public int Variable_lhs_len;
|
||||
public int Variable_rhs_len;
|
||||
public static final byte[]
|
||||
Dflt_variable_lhs = Bry_.new_a7("{{")
|
||||
, Dflt_variable_rhs = Bry_.new_a7("}}")
|
||||
;
|
||||
public static final byte
|
||||
Variable = Byte_ascii.Curly_end // {{=<% %>=}}
|
||||
, Escape_bgn = Byte_ascii.Curly_bgn // {{{escape}}}
|
||||
, Escape_end = Byte_ascii.Curly_end // {{{escape}}}
|
||||
, Section = Byte_ascii.Hash // {{#section}}
|
||||
, Grp_end = Byte_ascii.Slash // {{/section}}
|
||||
, Inverted = Byte_ascii.Pow // {{^inverted}}
|
||||
, Comment = Byte_ascii.Bang // {{!comment}}
|
||||
, Partial = Byte_ascii.Angle_end // {{>partial}}
|
||||
, Delimiter_bgn = Byte_ascii.Eq // {{=<% %>=}}
|
||||
, Delimiter_end = Byte_ascii.Curly_end // {{=<% %>=}}
|
||||
, Item = Byte_ascii.Dot // {{.}}
|
||||
;
|
||||
public static final String
|
||||
ItemString = String_.new_u8(Byte_.To_bry(Item))
|
||||
;
|
||||
public Mustache_tkn_def() {
|
||||
Variable_lhs_len = Variable_lhs.length;
|
||||
Variable_rhs_len = Variable_rhs.length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,98 +13,114 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.mustaches; import gplx.*; import gplx.langs.*;
|
||||
public interface Mustache_tkn_itm {
|
||||
int Tid();
|
||||
String Key();
|
||||
Mustache_tkn_itm[] Subs_ary();
|
||||
void Subs_ary_(Mustache_tkn_itm[] v);
|
||||
void Render(Mustache_bfr bfr, Mustache_render_ctx ctx);
|
||||
}
|
||||
class Mustache_tkn_itm_ {// for types, see http://mustache.github.io/mustache.5.html
|
||||
public static final int Tid__root = 0, Tid__text = 1, Tid__variable = 2, Tid__escape = 3, Tid__section = 4, Tid__inverted = 5, Tid__comment = 6, Tid__partial = 7, Tid__delimiter = 8;
|
||||
public static final Mustache_tkn_itm[] Ary_empty = new Mustache_tkn_itm[0];
|
||||
}
|
||||
abstract class Mustache_tkn_base implements Mustache_tkn_itm {
|
||||
public Mustache_tkn_base(int tid, byte[] key_bry) {this.tid = tid; this.key = String_.new_u8(key_bry);}
|
||||
public int Tid() {return tid;} private final int tid;
|
||||
public String Key() {return key;} private final String key;
|
||||
@gplx.Virtual public Mustache_tkn_itm[] Subs_ary() {return Mustache_tkn_itm_.Ary_empty;}
|
||||
@gplx.Virtual public void Subs_ary_(Mustache_tkn_itm[] v) {throw Err_.new_unsupported();} // fail if trying to set and not overridden
|
||||
@gplx.Virtual public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {throw Err_.new_unsupported();} // should be abstract
|
||||
}
|
||||
class Mustache_tkn_root extends Mustache_tkn_base { // EX: {{variable}} -> <a>
|
||||
private Mustache_tkn_itm[] subs_ary;
|
||||
public Mustache_tkn_root() {super(Mustache_tkn_itm_.Tid__root, Bry_.Empty);}
|
||||
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
|
||||
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
int subs_len = subs_ary.length;
|
||||
for (int i = 0; i < subs_len; ++i) {
|
||||
Mustache_tkn_itm sub = subs_ary[i];
|
||||
sub.Render(bfr, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_text extends Mustache_tkn_base { // EX: text -> text
|
||||
private final byte[] src; private final int src_bgn, src_end;
|
||||
public Mustache_tkn_text(byte[] src, int src_bgn, int src_end) {super(Mustache_tkn_itm_.Tid__text, Bry_.Empty);
|
||||
this.src = src;
|
||||
this.src_bgn = src_bgn;
|
||||
this.src_end = src_end;
|
||||
}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
bfr.Add_mid(src, src_bgn, src_end);
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_comment extends Mustache_tkn_base { // EX: {{!section}}comment{{/section}} ->
|
||||
public Mustache_tkn_comment() {super(Mustache_tkn_itm_.Tid__comment, Bry_.Empty);}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {}
|
||||
}
|
||||
class Mustache_tkn_variable extends Mustache_tkn_base { // EX: {{variable}} -> <a>
|
||||
public Mustache_tkn_variable(byte[] key) {super(Mustache_tkn_itm_.Tid__variable, key);}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
String key = this.Key();
|
||||
ctx.Render_variable(bfr.Escape_(Bool_.Y), key);
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_escape extends Mustache_tkn_base { // EX: {{{variable}}} -> <a>
|
||||
public Mustache_tkn_escape(byte[] key) {super(Mustache_tkn_itm_.Tid__escape, key);}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
String key = this.Key();
|
||||
ctx.Render_variable(bfr.Escape_(Bool_.N), key);
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_section extends Mustache_tkn_base { // EX: {{#section}}val{{/section}} -> val (if boolean) or valvalval (if list)
|
||||
private Mustache_tkn_itm[] subs_ary;
|
||||
public Mustache_tkn_section(byte[] key) {super(Mustache_tkn_itm_.Tid__section, key);}
|
||||
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
|
||||
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {Render_static(Bool_.N, this, bfr, ctx);}
|
||||
public static void Render_static(boolean inverted, Mustache_tkn_base tkn, Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
String key = tkn.Key();
|
||||
Mustache_tkn_itm[] subs_ary = tkn.Subs_ary();
|
||||
ctx.Section_bgn(key);
|
||||
while (ctx.Section_do(inverted)) {
|
||||
int subs_len = subs_ary.length;
|
||||
for (int i = 0; i < subs_len; ++i) {
|
||||
Mustache_tkn_itm sub = subs_ary[i];
|
||||
sub.Render(bfr, ctx);
|
||||
}
|
||||
}
|
||||
ctx.Section_end();
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_inverted extends Mustache_tkn_base { // EX: {{^section}}missing{{/section}} -> missing
|
||||
private Mustache_tkn_itm[] subs_ary;
|
||||
public Mustache_tkn_inverted(byte[] key) {super(Mustache_tkn_itm_.Tid__inverted, key);}
|
||||
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
|
||||
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {Mustache_tkn_section.Render_static(Bool_.Y, this, bfr, ctx);}
|
||||
}
|
||||
class Mustache_tkn_partial extends Mustache_tkn_base { // EX: {{>a}} -> abc (deferred eval)
|
||||
public Mustache_tkn_partial(byte[] key) {super(Mustache_tkn_itm_.Tid__partial, key);}
|
||||
}
|
||||
class Mustache_tkn_delimiter extends Mustache_tkn_base {// EX: {{=<% %>=}} -> <% variable %>
|
||||
public Mustache_tkn_delimiter(byte[] key) {super(Mustache_tkn_itm_.Tid__delimiter, key);}
|
||||
}
|
||||
package gplx.langs.mustaches;
|
||||
|
||||
import gplx.Bool_;
|
||||
import gplx.Bry_;
|
||||
import gplx.Byte_ascii;
|
||||
import gplx.Err_;
|
||||
import gplx.Io_url;
|
||||
import gplx.String_;
|
||||
|
||||
public interface Mustache_tkn_itm {
|
||||
int Tid();
|
||||
String Key();
|
||||
Mustache_tkn_itm[] Subs_ary();
|
||||
void Subs_ary_(Mustache_tkn_itm[] v);
|
||||
void Render(Mustache_bfr bfr, Mustache_render_ctx ctx);
|
||||
}
|
||||
class Mustache_tkn_itm_ {// for types, see http://mustache.github.io/mustache.5.html
|
||||
public static final int Tid__root = 0, Tid__text = 1, Tid__variable = 2, Tid__escape = 3, Tid__section = 4, Tid__inverted = 5, Tid__comment = 6, Tid__partial = 7, Tid__delimiter = 8;
|
||||
public static final Mustache_tkn_itm[] Ary_empty = new Mustache_tkn_itm[0];
|
||||
}
|
||||
abstract class Mustache_tkn_base implements Mustache_tkn_itm {
|
||||
public Mustache_tkn_base(int tid, byte[] key_bry) {this.tid = tid; this.key = String_.new_u8(key_bry);}
|
||||
public int Tid() {return tid;} private final int tid;
|
||||
public String Key() {return key;} private final String key;
|
||||
@gplx.Virtual public Mustache_tkn_itm[] Subs_ary() {return Mustache_tkn_itm_.Ary_empty;}
|
||||
@gplx.Virtual public void Subs_ary_(Mustache_tkn_itm[] v) {throw Err_.new_unsupported();} // fail if trying to set and not overridden
|
||||
@gplx.Virtual public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {throw Err_.new_unsupported();} // should be abstract
|
||||
}
|
||||
class Mustache_tkn_root extends Mustache_tkn_base { // EX: {{variable}} -> <a>
|
||||
private Mustache_tkn_itm[] subs_ary;
|
||||
public Mustache_tkn_root() {super(Mustache_tkn_itm_.Tid__root, Bry_.Empty);}
|
||||
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
|
||||
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
int subs_len = subs_ary.length;
|
||||
for (int i = 0; i < subs_len; ++i) {
|
||||
Mustache_tkn_itm sub = subs_ary[i];
|
||||
sub.Render(bfr, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_text extends Mustache_tkn_base { // EX: text -> text
|
||||
private final byte[] src; private final int src_bgn, src_end;
|
||||
public Mustache_tkn_text(byte[] src, int src_bgn, int src_end) {super(Mustache_tkn_itm_.Tid__text, Bry_.Empty);
|
||||
this.src = src;
|
||||
this.src_bgn = src_bgn;
|
||||
this.src_end = src_end;
|
||||
}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
bfr.Add_mid(src, src_bgn, src_end);
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_comment extends Mustache_tkn_base { // EX: {{!section}}comment{{/section}} ->
|
||||
public Mustache_tkn_comment() {super(Mustache_tkn_itm_.Tid__comment, Bry_.Empty);}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {}
|
||||
}
|
||||
class Mustache_tkn_variable extends Mustache_tkn_base { // EX: {{variable}} -> <a>
|
||||
public Mustache_tkn_variable(byte[] key) {super(Mustache_tkn_itm_.Tid__variable, key);}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
String key = this.Key();
|
||||
ctx.Render_variable(bfr.Escape_(Bool_.Y), key);
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_escape extends Mustache_tkn_base { // EX: {{{variable}}} -> <a>
|
||||
public Mustache_tkn_escape(byte[] key) {super(Mustache_tkn_itm_.Tid__escape, key);}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
String key = this.Key();
|
||||
ctx.Render_variable(bfr.Escape_(Bool_.N), key);
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_section extends Mustache_tkn_base { // EX: {{#section}}val{{/section}} -> val (if boolean) or valvalval (if list)
|
||||
private Mustache_tkn_itm[] subs_ary;
|
||||
public Mustache_tkn_section(byte[] key) {super(Mustache_tkn_itm_.Tid__section, key);}
|
||||
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
|
||||
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {Render_static(Bool_.N, this, bfr, ctx);}
|
||||
public static void Render_static(boolean inverted, Mustache_tkn_base tkn, Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
String key = tkn.Key();
|
||||
Mustache_tkn_itm[] subs_ary = tkn.Subs_ary();
|
||||
ctx.Section_bgn(key);
|
||||
while (ctx.Section_do(inverted)) {
|
||||
int subs_len = subs_ary.length;
|
||||
for (int i = 0; i < subs_len; ++i) {
|
||||
Mustache_tkn_itm sub = subs_ary[i];
|
||||
sub.Render(bfr, ctx);
|
||||
}
|
||||
}
|
||||
ctx.Section_end();
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_inverted extends Mustache_tkn_base { // EX: {{^section}}missing{{/section}} -> missing
|
||||
private Mustache_tkn_itm[] subs_ary;
|
||||
public Mustache_tkn_inverted(byte[] key) {super(Mustache_tkn_itm_.Tid__inverted, key);}
|
||||
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
|
||||
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {Mustache_tkn_section.Render_static(Bool_.Y, this, bfr, ctx);}
|
||||
}
|
||||
class Mustache_tkn_partial extends Mustache_tkn_base { // EX: {{>a}} -> abc (deferred eval)
|
||||
private Mustache_tkn_itm template_root;
|
||||
public Mustache_tkn_partial(byte[] key, Io_url dir) {
|
||||
super(Mustache_tkn_itm_.Tid__partial, key);
|
||||
Mustache_tkn_parser parser = new Mustache_tkn_parser(dir);
|
||||
template_root = parser.Parse(String_.new_a7(Bry_.Trim_bgn(key, Byte_ascii.Space, 0)));
|
||||
}
|
||||
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
|
||||
template_root.Render(bfr, ctx);
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_delimiter extends Mustache_tkn_base { // EX: {{=<% %>=}} -> <% variable %>
|
||||
public Mustache_tkn_delimiter(byte[] key) {super(Mustache_tkn_itm_.Tid__delimiter, key);}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
@@ -13,140 +13,162 @@ The terms of each license can be found in the source code repository:
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.langs.mustaches; import gplx.*; import gplx.langs.*;
|
||||
public class Mustache_tkn_parser {
|
||||
private byte[] src; private int src_end;
|
||||
private final Mustache_tkn_def tkn_def = new Mustache_tkn_def();
|
||||
public Mustache_tkn_itm Parse(byte[] src) {return Parse(src, 0, src.length);}
|
||||
public Mustache_tkn_itm Parse(byte[] src, int src_bgn, int src_end) {
|
||||
this.src = src; this.src_end = src_end;
|
||||
Mustache_tkn_root root = new Mustache_tkn_root();
|
||||
Parse_grp(root, src_bgn);
|
||||
return root;
|
||||
}
|
||||
private int Parse_grp(Mustache_tkn_itm owner, int src_bgn) {
|
||||
List_adp subs_list = List_adp_.New();
|
||||
int txt_bgn = src_bgn;
|
||||
boolean end_grp = false;
|
||||
while (true) {// loop for "{{"
|
||||
int lhs_bgn = Bry_find_.Find_fwd(src, tkn_def.Variable_lhs, txt_bgn, src_end); // next "{{"
|
||||
if (lhs_bgn == Bry_find_.Not_found) { // no more "{{"
|
||||
subs_list.Add(new Mustache_tkn_text(src, txt_bgn, src_end)); // add everything between prv "}}" and cur "{{"
|
||||
break;
|
||||
}
|
||||
int lhs_end = lhs_bgn + tkn_def.Variable_lhs_len;
|
||||
|
||||
Mustache_tkn_data tkn_data = new Mustache_tkn_data(src[lhs_end]); // preview tkn
|
||||
lhs_end += tkn_data.lhs_end_adj;
|
||||
|
||||
int rhs_bgn = Bry_find_.Find_fwd(src, tkn_def.Variable_rhs, lhs_end, src_end); // next "}}"
|
||||
if (rhs_bgn == Bry_find_.Not_found) throw Fail(lhs_bgn, "unclosed tag"); // fail if no "}}"
|
||||
int rhs_end = rhs_bgn + tkn_def.Variable_rhs_len;
|
||||
if (tkn_data.rhs_bgn_chk != Byte_ascii.Null) {
|
||||
if (src[rhs_bgn] != tkn_data.rhs_bgn_chk) throw Fail(lhs_end, "invalid check byte");
|
||||
++rhs_end; // skip the chk_byte; note that bottom of function will skip "}}" by adding +2
|
||||
}
|
||||
|
||||
|
||||
int txt_end = lhs_bgn; // get text tkn
|
||||
if (tkn_data.ws_ignore) {
|
||||
int new_txt_bgn = Trim_bwd_to_nl(src, txt_bgn, txt_end);
|
||||
if (new_txt_bgn != -1) {
|
||||
int new_txt_end = Trim_fwd_to_nl(src, rhs_end, src_end);
|
||||
if (new_txt_end != -1) {
|
||||
txt_end = new_txt_bgn;
|
||||
rhs_end = new_txt_end == src_end ? src_end : new_txt_end + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (txt_end > txt_bgn) // ignore 0-byte text tkns; occurs when consecutive tkns; EX: {{v1}}{{v2}} will try to create text tkn between "}}{{"
|
||||
subs_list.Add(new Mustache_tkn_text(src, txt_bgn, txt_end)); // add everything between prv "}}" and cur "{{"
|
||||
|
||||
txt_bgn = Parse_itm(tkn_data, subs_list, lhs_end, rhs_bgn, rhs_end); // do parse
|
||||
if (txt_bgn < 0) { // NOTE: txt_bgn < 0 means end grp
|
||||
txt_bgn *= -1;
|
||||
end_grp = true;
|
||||
}
|
||||
if (end_grp) break;
|
||||
}
|
||||
if (subs_list.Count() > 0) // don't create subs if no members
|
||||
owner.Subs_ary_((Mustache_tkn_itm[])subs_list.To_ary_and_clear(Mustache_tkn_itm.class));
|
||||
return txt_bgn;
|
||||
}
|
||||
private int Parse_itm(Mustache_tkn_data tkn_data, List_adp subs_list, int lhs_end, int rhs_bgn, int rhs_end) {
|
||||
byte[] val_bry = Bry_.Mid(src, lhs_end, rhs_bgn);
|
||||
Mustache_tkn_base tkn = null;
|
||||
switch (tkn_data.tid) {
|
||||
default: throw Err_.new_unhandled(tkn_data.tid);
|
||||
case Mustache_tkn_def.Variable: tkn = new Mustache_tkn_variable(val_bry); break;
|
||||
case Mustache_tkn_def.Comment: tkn = new Mustache_tkn_comment(); break;
|
||||
case Mustache_tkn_def.Partial: tkn = new Mustache_tkn_partial(val_bry); break;
|
||||
case Mustache_tkn_def.Delimiter_bgn: tkn = new Mustache_tkn_delimiter(val_bry); break; // TODO_OLD: implement delimiter; EX: {{=<% %>=}}
|
||||
case Mustache_tkn_def.Escape_bgn: tkn = new Mustache_tkn_escape(val_bry); break;
|
||||
case Mustache_tkn_def.Section: tkn = new Mustache_tkn_section(val_bry); break;
|
||||
case Mustache_tkn_def.Inverted: tkn = new Mustache_tkn_inverted(val_bry); break;
|
||||
case Mustache_tkn_def.Grp_end: {
|
||||
return -(rhs_end); // pop the stack
|
||||
}
|
||||
}
|
||||
subs_list.Add(tkn);
|
||||
if (tkn_data.parse_grp) {
|
||||
return Parse_grp(tkn, rhs_end);
|
||||
}
|
||||
else
|
||||
return rhs_end;
|
||||
}
|
||||
private Err Fail(int pos, String fmt, Object... args) {
|
||||
return Err_.new_("mustache", fmt, "excerpt", Bry_.Mid_by_len_safe(src, pos, 32));
|
||||
}
|
||||
private static int Trim_bwd_to_nl(byte[] src, int txt_bgn, int txt_end) {
|
||||
int stop = txt_bgn - 1;
|
||||
int pos = txt_end - 1;
|
||||
while (pos > stop) {
|
||||
byte b = src[pos];
|
||||
switch (b) {
|
||||
case Byte_ascii.Tab:
|
||||
case Byte_ascii.Space: --pos; break;
|
||||
case Byte_ascii.Nl: return pos + 1; // 1 char after \n
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private static int Trim_fwd_to_nl(byte[] src, int txt_bgn, int txt_end) {
|
||||
int pos = txt_bgn;
|
||||
while (pos < txt_end) {
|
||||
byte b = src[pos];
|
||||
switch (b) {
|
||||
case Byte_ascii.Tab:
|
||||
case Byte_ascii.Space: ++pos; break;
|
||||
case Byte_ascii.Nl: return pos;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_data {
|
||||
public int tid;
|
||||
public int lhs_end_adj;
|
||||
public byte rhs_bgn_chk;
|
||||
public boolean parse_grp;
|
||||
public boolean ws_ignore;
|
||||
public Mustache_tkn_data(byte b) {
|
||||
tid = b;
|
||||
parse_grp = ws_ignore = false;
|
||||
lhs_end_adj = 1;
|
||||
rhs_bgn_chk = Byte_ascii.Null;
|
||||
switch (b) {
|
||||
default: lhs_end_adj = 0; tid = Mustache_tkn_def.Variable; break;
|
||||
case Mustache_tkn_def.Comment:
|
||||
case Mustache_tkn_def.Partial:
|
||||
case Mustache_tkn_def.Grp_end: ws_ignore = true; break;
|
||||
case Mustache_tkn_def.Delimiter_bgn: rhs_bgn_chk = Mustache_tkn_def.Delimiter_end; break; // check for "=}}"; TODO_OLD: implement delimiter; EX: {{=<% %>=}}
|
||||
case Mustache_tkn_def.Escape_bgn: rhs_bgn_chk = Mustache_tkn_def.Escape_end; break; // check for ""
|
||||
case Mustache_tkn_def.Section:
|
||||
case Mustache_tkn_def.Inverted: ws_ignore = true; parse_grp = true; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
package gplx.langs.mustaches;
|
||||
|
||||
import gplx.Bry_;
|
||||
import gplx.Bry_find_;
|
||||
import gplx.Byte_ascii;
|
||||
import gplx.Err;
|
||||
import gplx.Err_;
|
||||
import gplx.Io_mgr;
|
||||
import gplx.Io_url;
|
||||
import gplx.List_adp;
|
||||
import gplx.List_adp_;
|
||||
|
||||
public class Mustache_tkn_parser {
|
||||
private byte[] src; private int src_end;
|
||||
private Io_url template_root;
|
||||
private final Mustache_tkn_def tkn_def = new Mustache_tkn_def();
|
||||
public Mustache_tkn_parser() {
|
||||
}
|
||||
public Mustache_tkn_parser(Io_url template_root) {
|
||||
this.template_root = template_root;
|
||||
}
|
||||
public Mustache_tkn_itm Parse(String template) { return Parse(template, Bry_.Empty); }
|
||||
public Mustache_tkn_itm Parse(String template, byte[] default_text) {
|
||||
byte[] template_data = Io_mgr.Instance.LoadFilBryOr(template_root.GenSubFil_nest(template + ".mustache"), default_text);
|
||||
return Parse(template_data, 0, template_data.length);
|
||||
}
|
||||
public Mustache_tkn_itm Parse(byte[] src) {return Parse(src, 0, src.length);}
|
||||
public Mustache_tkn_itm Parse(byte[] src, int src_bgn, int src_end) {
|
||||
this.src = src; this.src_end = src_end;
|
||||
Mustache_tkn_root root = new Mustache_tkn_root();
|
||||
Parse_grp(root, src_bgn);
|
||||
return root;
|
||||
}
|
||||
private int Parse_grp(Mustache_tkn_itm owner, int src_bgn) {
|
||||
List_adp subs_list = List_adp_.New();
|
||||
int txt_bgn = src_bgn;
|
||||
boolean end_grp = false;
|
||||
while (true) {// loop for "{{"
|
||||
int lhs_bgn = Bry_find_.Find_fwd(src, tkn_def.Variable_lhs, txt_bgn, src_end); // next "{{"
|
||||
if (lhs_bgn == Bry_find_.Not_found) { // no more "{{"
|
||||
subs_list.Add(new Mustache_tkn_text(src, txt_bgn, src_end)); // add everything between prv "}}" and cur "{{"
|
||||
break;
|
||||
}
|
||||
int lhs_end = lhs_bgn + tkn_def.Variable_lhs_len;
|
||||
|
||||
Mustache_tkn_data tkn_data = new Mustache_tkn_data(src[lhs_end]); // preview tkn
|
||||
lhs_end += tkn_data.lhs_end_adj;
|
||||
|
||||
int rhs_bgn = Bry_find_.Find_fwd(src, tkn_def.Variable_rhs, lhs_end, src_end); // next "}}"
|
||||
if (rhs_bgn == Bry_find_.Not_found) throw Fail(lhs_bgn, "unclosed tag"); // fail if no "}}"
|
||||
int rhs_end = rhs_bgn + tkn_def.Variable_rhs_len;
|
||||
if (tkn_data.rhs_bgn_chk != Byte_ascii.Null) {
|
||||
if (src[rhs_bgn] != tkn_data.rhs_bgn_chk) throw Fail(lhs_end, "invalid check byte");
|
||||
++rhs_end; // skip the chk_byte; note that bottom of function will skip "}}" by adding +2
|
||||
}
|
||||
|
||||
|
||||
int txt_end = lhs_bgn; // get text tkn
|
||||
if (tkn_data.ws_ignore) {
|
||||
int new_txt_bgn = Trim_bwd_to_nl(src, txt_bgn, txt_end);
|
||||
if (new_txt_bgn != -1) {
|
||||
int new_txt_end = Trim_fwd_to_nl(src, rhs_end, src_end);
|
||||
if (new_txt_end != -1) {
|
||||
txt_end = new_txt_bgn;
|
||||
rhs_end = new_txt_end == src_end ? src_end : new_txt_end + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (txt_end > txt_bgn) // ignore 0-byte text tkns; occurs when consecutive tkns; EX: {{v1}}{{v2}} will try to create text tkn between "}}{{"
|
||||
subs_list.Add(new Mustache_tkn_text(src, txt_bgn, txt_end)); // add everything between prv "}}" and cur "{{"
|
||||
|
||||
txt_bgn = Parse_itm(tkn_data, subs_list, lhs_end, rhs_bgn, rhs_end); // do parse
|
||||
if (txt_bgn < 0) { // NOTE: txt_bgn < 0 means end grp
|
||||
txt_bgn *= -1;
|
||||
end_grp = true;
|
||||
}
|
||||
if (end_grp) break;
|
||||
}
|
||||
if (subs_list.Count() > 0) // don't create subs if no members
|
||||
owner.Subs_ary_((Mustache_tkn_itm[])subs_list.To_ary_and_clear(Mustache_tkn_itm.class));
|
||||
return txt_bgn;
|
||||
}
|
||||
private int Parse_itm(Mustache_tkn_data tkn_data, List_adp subs_list, int lhs_end, int rhs_bgn, int rhs_end) {
|
||||
byte[] val_bry = Bry_.Mid(src, lhs_end, rhs_bgn);
|
||||
Mustache_tkn_base tkn = null;
|
||||
switch (tkn_data.tid) {
|
||||
default: throw Err_.new_unhandled(tkn_data.tid);
|
||||
case Mustache_tkn_def.Variable: tkn = new Mustache_tkn_variable(val_bry); break;
|
||||
case Mustache_tkn_def.Comment: tkn = new Mustache_tkn_comment(); break;
|
||||
case Mustache_tkn_def.Partial: tkn = new Mustache_tkn_partial(val_bry, template_root); break;
|
||||
case Mustache_tkn_def.Delimiter_bgn: tkn = new Mustache_tkn_delimiter(val_bry); break; // TODO_OLD: implement delimiter; EX: {{=<% %>=}}
|
||||
case Mustache_tkn_def.Escape_bgn: tkn = new Mustache_tkn_escape(val_bry); break;
|
||||
case Mustache_tkn_def.Section: tkn = new Mustache_tkn_section(val_bry); break;
|
||||
case Mustache_tkn_def.Inverted: tkn = new Mustache_tkn_inverted(val_bry); break;
|
||||
case Mustache_tkn_def.Grp_end: {
|
||||
return -(rhs_end); // pop the stack
|
||||
}
|
||||
}
|
||||
subs_list.Add(tkn);
|
||||
if (tkn_data.parse_grp) {
|
||||
return Parse_grp(tkn, rhs_end);
|
||||
}
|
||||
else
|
||||
return rhs_end;
|
||||
}
|
||||
private Err Fail(int pos, String fmt, Object... args) {
|
||||
return Err_.new_("mustache", fmt, "excerpt", Bry_.Mid_by_len_safe(src, pos, 32));
|
||||
}
|
||||
private static int Trim_bwd_to_nl(byte[] src, int txt_bgn, int txt_end) {
|
||||
int stop = txt_bgn - 1;
|
||||
int pos = txt_end - 1;
|
||||
while (pos > stop) {
|
||||
byte b = src[pos];
|
||||
switch (b) {
|
||||
case Byte_ascii.Tab:
|
||||
case Byte_ascii.Space: --pos; break;
|
||||
case Byte_ascii.Nl: return pos + 1; // 1 char after \n
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private static int Trim_fwd_to_nl(byte[] src, int txt_bgn, int txt_end) {
|
||||
int pos = txt_bgn;
|
||||
while (pos < txt_end) {
|
||||
byte b = src[pos];
|
||||
switch (b) {
|
||||
case Byte_ascii.Tab:
|
||||
case Byte_ascii.Space: ++pos; break;
|
||||
case Byte_ascii.Nl: return pos;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
class Mustache_tkn_data {
|
||||
public int tid;
|
||||
public int lhs_end_adj;
|
||||
public byte rhs_bgn_chk;
|
||||
public boolean parse_grp;
|
||||
public boolean ws_ignore;
|
||||
public Mustache_tkn_data(byte b) {
|
||||
tid = b;
|
||||
parse_grp = ws_ignore = false;
|
||||
lhs_end_adj = 1;
|
||||
rhs_bgn_chk = Byte_ascii.Null;
|
||||
switch (b) {
|
||||
default: lhs_end_adj = 0; tid = Mustache_tkn_def.Variable; break;
|
||||
case Mustache_tkn_def.Comment:
|
||||
case Mustache_tkn_def.Partial:
|
||||
case Mustache_tkn_def.Grp_end: ws_ignore = true; break;
|
||||
case Mustache_tkn_def.Delimiter_bgn: rhs_bgn_chk = Mustache_tkn_def.Delimiter_end; break; // check for "=}}"; TODO_OLD: implement delimiter; EX: {{=<% %>=}}
|
||||
case Mustache_tkn_def.Escape_bgn: rhs_bgn_chk = Mustache_tkn_def.Escape_end; break; // check for ""
|
||||
case Mustache_tkn_def.Section:
|
||||
case Mustache_tkn_def.Inverted: ws_ignore = true; parse_grp = true; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user