diff --git a/400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue.java b/400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue.java
index af59b32ed..2cb339d20 100644
--- a/400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue.java
+++ b/400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue.java
@@ -27,6 +27,7 @@ public class Xof_xfer_queue {
xfer_list.Clear();
html_uid.Val_neg1_();
}
+ public Xof_file_itm Get_at(int i) {return (Xof_file_itm)xfer_list.Get_at(i);} // TEST
public void Add(Xof_file_itm xfer_itm) {xfer_list.Add(xfer_itm);}
public void Exec(Xowe_wiki wiki, Xoae_page page) {
if (wiki.File_mgr().Version() == Xow_file_mgr.Version_2)
diff --git a/400_xowa/src/gplx/xowa/xtns/graphs/Graph_addon.java b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_addon.java
new file mode 100644
index 000000000..0d6e5f718
--- /dev/null
+++ b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_addon.java
@@ -0,0 +1,27 @@
+/*
+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.xowa.xtns.graphs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
+import gplx.xowa.addons.*;
+import gplx.xowa.bldrs.wkrs.*;
+public class Graph_addon implements Xoax_addon_itm, Xoax_addon_itm__init {
+ public void Init_addon_by_app(Xoa_app app) {}
+ public void Init_addon_by_wiki(Xow_wiki wiki) {
+ Graph_json_load_mgr hdump_wkr = new Graph_json_load_mgr();
+ wiki.Html__hdump_mgr().Wkrs().Add(hdump_wkr.Key(), hdump_wkr);
+ }
+
+ public String Addon__key() {return "xowa.graphs";}
+}
diff --git a/400_xowa/src/gplx/xowa/xtns/graphs/Graph_html_fxt.java b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_html_fxt.java
new file mode 100644
index 000000000..4cdafa506
--- /dev/null
+++ b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_html_fxt.java
@@ -0,0 +1,111 @@
+/*
+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.xowa.xtns.graphs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
+import gplx.core.tests.*;
+import gplx.xowa.htmls.core.htmls.*; import gplx.xowa.htmls.core.makes.tests.*;
+class Graph_html_fxt {
+ private final Xoh_make_fxt make_fxt = new Xoh_make_fxt();
+ private final Xop_fxt parser_fxt;
+ private final List_adp expd_lnr_list = List_adp_.New();
+ private String hdump_atr;
+ public Graph_html_fxt() {
+ parser_fxt = make_fxt.Parser_fxt(); // NOTE: do not create multiple parser_fxts b/c of wiki registration issues;
+ }
+ public void Reset() {
+ parser_fxt.Reset();
+ expd_lnr_list.Clear();
+ hdump_wkr_lnr = null;
+ }
+ public Xop_fxt Parser_fxt() {return parser_fxt;}
+ public Graph_html_fxt Hdump_n_() {return Hdump_(Bool_.N);}
+ public Graph_html_fxt Hdump_y_() {return Hdump_(Bool_.Y);}
+ private Graph_html_fxt Hdump_(boolean v) {
+ this.hdump_atr = v ? " " + String_.new_u8(Graph_json_load_mgr.HDUMP_ATR) : "";
+ return this;
+ }
+ public void Test__hview(String wtxt, String expd) {
+ parser_fxt.Hctx_(Xoh_wtr_ctx.Basic);
+ parser_fxt.Test_html_full_str(wtxt, expd);
+ }
+ public void Test__hdump(String wtxt, String save, String load) {
+ parser_fxt.Hctx_(Xoh_wtr_ctx.Hdump);
+ parser_fxt.Test_html_full_str(wtxt, save);
+ make_fxt.Test__make(save, make_fxt.Page_chkr().Body_(load));
+ if (hdump_wkr_lnr != null) {
+ hdump_wkr_lnr.Test();
+ }
+ }
+ public void Test__hload(String html) {Test__hload(html, html);}
+ public void Test__hload(String load, String expd) {
+ make_fxt.Test__make(false, expd, make_fxt.Page_chkr().Body_(load));
+ }
+
+ private Gfo_test_lnr_base hdump_wkr_lnr = Gfo_test_lnr_base.New__keys("is_commons", "is_orig", "ttl");
+ public String Wikirawupload__wtxt() {
+ Graph_json_load_mgr hdump_wkr = (Graph_json_load_mgr)parser_fxt.Wiki().Html__hdump_mgr().Wkrs().Get_by(Graph_json_load_mgr.KEY);
+ hdump_wkr_lnr = Gfo_test_lnr_base.New__keys("is_commons", "is_orig", "ttl");
+ hdump_wkr.Test_lnr_(hdump_wkr_lnr);
+
+ hdump_wkr_lnr.Expd().Add(Gfo_test_itm.New__expd().Add("is_commons", true).Add("is_orig", true).Add("ttl", "A.png"));
+ return String_.Concat_lines_nl_skip_last
+ ( ""
+ , "{"
+ , " \"version\":2,"
+ , " \"path\":\"wikirawupload:file:///mem/xowa/file/commons.wikimedia.org/orig/7/0/1/c/A.png\","
+ , " \"width\":300"
+ , "}"
+ , ""
+ );
+ }
+ public String Wikirawupload__html(boolean dir_has_value) {
+ String dir = Dir_str(dir_has_value);
+ return String_.Concat_lines_nl_skip_last
+ ( "
"
+ , "{"
+ , " \"version\":2,"
+ , " \"path\":\"wikirawupload:" + dir + "file/commons.wikimedia.org/orig/7/0/1/c/A.png\","
+ , " \"width\":300"
+ , "}"
+ , "
"
+ );
+ }
+ public String Literal_XOWA_ROOT__wtxt() {
+ return String_.Concat_lines_nl_skip_last
+ ( ""
+ , "{"
+ , " \"version\":2,"
+ , " \"data\":\"{XOWA_ROOT}\","
+ , " \"width\":300"
+ , "}"
+ , ""
+ );
+ }
+ public String Literal_XOWA_ROOT__html(boolean dir_has_value) {
+ String xowa_root = dir_has_value ? "{XOWA_ROOT}" : "{XOWA_ROOT}{XOWA_ROOT}";
+ return String_.Concat_lines_nl_skip_last
+ ( ""
+ , "{"
+ , " \"version\":2,"
+ , " \"data\":\"" + xowa_root + "\","
+ , " \"width\":300"
+ , "}"
+ , "
"
+ );
+ }
+ private String Dir_str(boolean dir_has_value) {
+ return dir_has_value ? "file:///mem/xowa/" : "{XOWA_ROOT}/";
+ }
+}
diff --git a/400_xowa/src/gplx/xowa/xtns/graphs/Graph_html_tst.java b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_html_tst.java
new file mode 100644
index 000000000..e465e9099
--- /dev/null
+++ b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_html_tst.java
@@ -0,0 +1,73 @@
+/*
+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.xowa.xtns.graphs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
+import org.junit.*; import gplx.core.tests.*;
+public class Graph_html_tst {
+ private final Graph_html_fxt fxt = new Graph_html_fxt();
+ @Before public void init() {
+ fxt.Reset();
+ }
+ @Test public void Basic() {
+ fxt.Parser_fxt().Test_html_full_str(String_.Concat_lines_nl_skip_last
+ ( ""
+ , "{"
+ , "// COMMENT \n"
+ , " \"version\":2,"
+ , " \"width\":300"
+ , "}"
+ , ""
+ ), String_.Concat_lines_nl_skip_last
+ ( ""
+ , "{"
+ , ""
+ , " \"version\":2,"
+ , " \"width\":300"
+ , "}"
+ , "
"
+ ));
+ }
+ @Test public void Wikirawupload() {
+ String wtxt = fxt.Wikirawupload__wtxt();
+ fxt.Test__hview(wtxt, fxt.Hdump_n_().Wikirawupload__html(Bool_.Y));
+ fxt.Test__hdump(wtxt, fxt.Hdump_y_().Wikirawupload__html(Bool_.N), fxt.Wikirawupload__html(Bool_.Y));
+ }
+ @Test public void Literal_XOWA_ROOT() {
+ String wtxt = fxt.Literal_XOWA_ROOT__wtxt();
+ fxt.Test__hview(wtxt, fxt.Hdump_n_().Literal_XOWA_ROOT__html(Bool_.Y));
+ fxt.Test__hdump(wtxt, fxt.Hdump_y_().Literal_XOWA_ROOT__html(Bool_.N), fxt.Literal_XOWA_ROOT__html(Bool_.Y));
+ }
+ @Test public void Error__missing_endquote() {
+ fxt.Test__hload(String_.Concat_lines_nl_skip_last
+ ( ""
+ , "{"
+ , " \"version\":2,"
+ , " \"path\":\"wikirawupload:{XOWA_ROOT}"
+ , "}"
+ , "
"
+ ));
+ }
+ @Test public void Error__invalid() {
+ fxt.Test__hload(String_.Concat_lines_nl_skip_last
+ ( ""
+ , "{"
+ , " \"version\":2,"
+ , " \"path\":\"wikirawupload:{XOWA_ROOT}/invalid/commons.wikimedia.org/orig/7/0/1/c/A.png\","
+ , " \"width\":300"
+ , "}"
+ , "
"
+ ));
+ }
+}
diff --git a/400_xowa/src/gplx/xowa/xtns/graphs/Graph_json_load_mgr.java b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_json_load_mgr.java
new file mode 100644
index 000000000..af8d4849c
--- /dev/null
+++ b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_json_load_mgr.java
@@ -0,0 +1,114 @@
+/*
+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.xowa.xtns.graphs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
+import gplx.core.tests.*;
+import gplx.core.brys.*;
+import gplx.langs.htmls.*; import gplx.langs.htmls.docs.*;
+import gplx.xowa.wikis.domains.*;
+import gplx.xowa.files.*;
+import gplx.xowa.htmls.*; import gplx.xowa.htmls.hdumps.*; import gplx.xowa.htmls.core.wkrs.*;
+import gplx.xowa.htmls.core.wkrs.imgs.atrs.*; import gplx.xowa.parsers.lnkis.*;
+class Graph_json_load_mgr implements Xoh_hdump_wkr {
+ public byte[] Key() {return KEY;}
+ public int Process(Bry_bfr bfr, Xoh_hdoc_ctx hctx, Xoh_hdoc_wkr hdoc_wkr, Gfh_tag_rdr tag_rdr, byte[] src, Gfh_tag tag) {
+ // add opening
+ bfr.Add_mid(src, tag.Src_bgn(), tag.Src_end());
+
+ // find
+ int src_bgn = tag.Src_end();
+ Gfh_tag div_end = tag_rdr.Tag__move_fwd_tail(Gfh_tag_.Id__div);
+
+ // declare json vars
+ int src_end = div_end.Src_bgn();
+ int bfr_prv = src_bgn;
+
+ // init err_wkr
+ Bry_err_wkr err_wkr = new Bry_err_wkr();
+ err_wkr.Init_by_page(String_.new_u8(hctx.Page__url()), src);
+ err_wkr.Init_by_sect("graph", src_bgn);
+
+ Xow_domain_itm domain_itm = hctx.Wiki__domain_itm();
+ Xoh_img_src_data img_src_parser = new Xoh_img_src_data();
+
+ int pos = src_bgn;
+ while (true) {
+ // find {XOWA_ROOT}
+ int find_bgn = Bry_find_.Find_fwd(src, Graph_json_save_mgr.Bry__xowa_root, pos);
+
+ // not found, or outside JSON range
+ if (find_bgn == Bry_find_.Not_found || find_bgn > src_end)
+ break;
+
+ // {XOWA_ROOT} found; add everything up to it
+ bfr.Add_mid(src, bfr_prv, find_bgn);
+
+ // check for {XOWA_ROOT}{XOWA_ROOT}
+ int find_end = find_bgn + Graph_json_save_mgr.Bry__xowa_root.length;
+ int double_end = find_end + Graph_json_save_mgr.Bry__xowa_root.length;
+ if (double_end < src_end
+ && Bry_.Match(src, find_end, double_end, Graph_json_save_mgr.Bry__xowa_root)) {
+ bfr.Add(Graph_json_save_mgr.Bry__xowa_root);
+ bfr_prv = pos = double_end;
+ continue;
+ }
+
+ // get url_end by searching for '\"'
+ int url_bgn = find_bgn + Graph_json_save_mgr.Bry__xowa_root.length;
+ int url_end = Bry_find_.Find_fwd(src, Byte_ascii.Quote, find_bgn, src_end);
+ if (url_end == Bry_find_.Not_found) {
+ err_wkr.Warn("Graph_json_save_mgr: missing endquote");
+ bfr.Add_mid(src, find_bgn, find_end);
+ bfr_prv = pos = find_end;
+ continue;
+ }
+
+ // parse everything between url_bgn and url_end
+ img_src_parser.Clear();
+ if (!img_src_parser.Parse(err_wkr, hctx.Wiki__domain_bry(), src, url_bgn, url_end)) { // -1 b/c find_bgn starts at "file/commons" and parser needs to start at "/file/commons"
+ err_wkr.Warn("", "", "Graph_json_save_mgr: invalid file_path");
+ bfr.Add_mid(src, find_bgn, find_end);
+ bfr_prv = pos = find_end;
+ continue;
+ }
+
+ // register image for show
+ Xoh_page hpg = ((Xoh_page)hctx.Page());
+ Xof_fsdb_itm fsdb_itm = hpg.Img_mgr().Make_img(false);
+ fsdb_itm.Init_at_lnki(Xof_exec_tid.Tid_wiki_page, domain_itm.Abrv_xo(), img_src_parser.File_ttl_bry(), Xop_lnki_type.Id_none
+ , Xop_lnki_tkn.Upright_null, img_src_parser.File_w(), Xop_lnki_tkn.Height_null, Xof_lnki_time.Null, Xof_lnki_page.Null, Xof_patch_upright_tid_.Tid_all);
+ hctx.Cache_mgr().Find(hpg.Wiki(), hpg.Url_bry_safe(), fsdb_itm);
+
+ if (test_lnr != null)
+ test_lnr.Add_actl_args(img_src_parser.Repo_is_commons(), img_src_parser.File_is_orig(), img_src_parser.File_ttl_bry());
+
+ // add root_dir
+ bfr.Add(hctx.App().Fsys_mgr().Root_dir().To_http_file_bry());
+ bfr.Add_mid(src, url_bgn + 1, url_end); // + 1 to skip slash in "/file/"
+ bfr_prv = pos = url_end;
+ }
+
+ // add rest of json
+ bfr.Add_mid(src, bfr_prv, src_end);
+
+ // add
+ bfr.Add_mid(src, div_end.Src_bgn(), div_end.Src_end());
+ return div_end.Src_end();
+ }
+ public void Test_lnr_(Gfo_test_lnr_base v) {this.test_lnr = v;} private Gfo_test_lnr_base test_lnr;
+
+ public static byte[] KEY = Bry_.new_a7("graph-json");
+ public static byte[] HDUMP_ATR = Xoh_hdump_wkr_utl.Build_hdump_atr(KEY);
+}
diff --git a/400_xowa/src/gplx/xowa/xtns/graphs/Graph_json_save_mgr.java b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_json_save_mgr.java
new file mode 100644
index 000000000..123cd0c23
--- /dev/null
+++ b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_json_save_mgr.java
@@ -0,0 +1,132 @@
+/*
+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.xowa.xtns.graphs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
+import gplx.core.tests.*;
+import gplx.core.btries.*; import gplx.core.brys.*;
+import gplx.xowa.apps.fsys.*;
+import gplx.xowa.htmls.core.wkrs.imgs.atrs.*;
+import gplx.xowa.htmls.*; import gplx.xowa.files.*; import gplx.xowa.wikis.domains.*;
+import gplx.xowa.parsers.*; import gplx.xowa.parsers.lnkis.*; import gplx.xowa.parsers.lnkis.files.*;
+import gplx.xowa.wikis.nss.*;
+class Graph_json_save_mgr {
+ private final Btrie_slim_mgr trie = Btrie_slim_mgr.cs().Add_bry_byte(Bry__xowa_root, Tid__text);
+ public Graph_json_save_mgr(Xoa_fsys_mgr fsys_mgr) {
+ trie.Add_bry_byte(fsys_mgr.Root_dir().To_http_file_bry(), Tid__root);
+ }
+ public boolean Root_dir_found() {return root_dir_found;} private boolean root_dir_found;
+ public byte[] Save(Xoae_page page, Xop_ctx ctx, byte[] domain_bry, String page_ttl, byte[] src, int src_bgn, int src_end) {
+ // init err_wkr
+ Bry_err_wkr err_wkr = new Bry_err_wkr();
+ err_wkr.Init_by_page(page_ttl, src);
+ err_wkr.Init_by_sect("graph", src_bgn);
+
+ // init other helpers
+ Xowe_wiki wiki = page.Wikie();
+ Bry_bfr bfr = Bry_bfr_.New();
+ Btrie_rv trv = new Btrie_rv();
+ Xoh_img_src_data img_src_parser = new Xoh_img_src_data();
+
+ // init pos
+ int find_bgn = src_bgn;
+ int prv_bfr = src_bgn;
+ while (find_bgn < src_end) {
+ // match byte against trie
+ byte tid = trie.Match_byte_or(trv, src, find_bgn, src_end, Byte_.Max_value_127);
+
+ // file:/// or {XOWA_ROOT} not found; look at next byte
+ if (tid == Byte_.Max_value_127) {
+ find_bgn++;
+ continue;
+ }
+
+ // file:/// or {XOWA_ROOT} found
+ int find_end = trv.Pos();
+ switch (tid) {
+ // {XOWA_ROOT} found; double up;
+ case Tid__text:
+ bfr.Add_mid(src, prv_bfr, find_end);
+ bfr.Add(Bry__xowa_root);
+ prv_bfr = find_bgn = find_end;
+ break;
+ // root found
+ case Tid__root:
+ // check for '"wikirawupload:'
+ int wikirawupload_bgn = find_bgn - Bry__wikirawupload.length;
+ if (wikirawupload_bgn < 0) wikirawupload_bgn = 0;
+ if (!Bry_.Match(src, wikirawupload_bgn, find_bgn, Bry__wikirawupload)) {
+ err_wkr.Warn("Graph_json_save_mgr: missing wikirawupload");
+ find_bgn++;
+ continue;
+ }
+
+ // get url_end by searching for '\"'
+ int url_bgn = find_bgn;
+ int url_end = Bry_find_.Find_fwd(src, Byte_ascii.Quote, find_bgn, src_end);
+ if (url_end == Bry_find_.Not_found) {
+ err_wkr.Warn("Graph_json_save_mgr: missing endquote");
+ find_bgn++;
+ continue;
+ }
+
+ // parse everything between url_bgn and url_end
+ img_src_parser.Clear();
+ if (!img_src_parser.Parse(err_wkr, domain_bry, src, url_bgn - 1, url_end)) { // -1 b/c find_bgn starts at "file/commons" and parser needs to start at "/file/commons"
+ err_wkr.Warn("", "", "Graph_json_save_mgr: invalid file_path");
+ find_bgn++;
+ continue;
+ }
+
+ bfr.Add_mid(src, prv_bfr, find_bgn);
+ bfr.Add(Bry__xowa_root);
+ bfr.Add_byte_slash(); // add / to make load_mgr easier since img_src_parser looks for /file/; EX: "{XOWA_ROOT}file/" vs "{XOWA_ROOT}/file/"
+
+ if (test_lnr != null)
+ test_lnr.Add_actl_args(img_src_parser.Repo_is_commons(), img_src_parser.File_is_orig(), img_src_parser.File_ttl_bry());
+
+ // register image for show
+ wiki.Html_mgr().Html_wtr().Lnki_wtr().File_wtr().Lnki_eval(Xof_exec_tid.Tid_wiki_page, ctx, page, page.File_queue()
+ , img_src_parser.File_ttl_bry(), Xop_lnki_type.Id_none, Xop_lnki_tkn.Upright_null, img_src_parser.File_w(), Xop_lnki_tkn.Height_null
+ , Xof_lnki_time.Null, Xof_lnki_page.Null, false);
+
+ // register image for fsdb
+ Xoa_ttl ttl = wiki.Ttl_parse(Xow_ns_.Tid__file, img_src_parser.File_ttl_bry());
+ ctx.Lnki().File_logger().Log_file(Xop_file_logger_.Tid__graph, ctx, ttl, Xow_ns_.Tid__file, Xop_lnki_type.Id_none, img_src_parser.File_w(), Xop_lnki_tkn.Height_null, Xop_lnki_tkn.Upright_null, Xof_lnki_time.Null, Xof_lnki_page.Null);
+
+ prv_bfr = find_bgn = find_end;
+ break;
+ default:
+ throw Err_.new_unhandled_default(tid);
+ }
+ }
+
+ // unchanged
+ if (prv_bfr == src_bgn) {
+ return Bry_.Mid(src, src_bgn, src_end);
+ }
+ // changed
+ else {
+ root_dir_found = true;
+ bfr.Add_mid(src, prv_bfr, src_end);
+ return bfr.To_bry_and_clear();
+ }
+ }
+ public void Test_lnr_(Gfo_test_lnr_base v) {this.test_lnr = v;} private Gfo_test_lnr_base test_lnr;
+ public static final byte Tid__root = 0, Tid__text = 1;
+ public static final byte[]
+ Bry__wikirawupload = Bry_.new_a7("\"wikirawupload:")
+ , Bry__xowa_root = Bry_.new_a7("{XOWA_ROOT}")
+ ;
+}
diff --git a/400_xowa/src/gplx/xowa/xtns/graphs/Graph_json_save_mgr__tst.java b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_json_save_mgr__tst.java
new file mode 100644
index 000000000..1c3f5efb7
--- /dev/null
+++ b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_json_save_mgr__tst.java
@@ -0,0 +1,125 @@
+/*
+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.xowa.xtns.graphs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
+import org.junit.*; import gplx.core.tests.*;
+import gplx.xowa.files.*; import gplx.xowa.parsers.*;
+import gplx.xowa.parsers.lnkis.*; import gplx.xowa.parsers.lnkis.files.*;
+public class Graph_json_save_mgr__tst {
+ private final Graph_json_save_mgr__fxt fxt = new Graph_json_save_mgr__fxt();
+ @Before public void init() {fxt.Clear();}
+ @Test public void Xowa_file() {
+ fxt.Test__parse("a-{XOWA_ROOT}-z", "a-{XOWA_ROOT}{XOWA_ROOT}-z");
+ }
+ @Test public void Missing_wikirawupload() {
+ fxt .Expd__err("missing wikirawupload")
+ .Test__parse("a-file:///mem/xowa/-z");
+ }
+ @Test public void Missing_endquote() {
+ fxt .Expd__err("missing endquote")
+ .Test__parse("a-\"wikirawupload:file:///mem/xowa/-z");
+ }
+ @Test public void Invalid_img_src() {
+ fxt .Expd__err("invalid file_path")
+ .Test__parse("a-\"wikirawupload:file:///mem/xowa/invalid-z\"");
+ }
+ @Test public void File() {
+ fxt .Expd__file(Bool_.Y, Bool_.Y, "A.png")
+ .Test__parse
+ ( "a-\"wikirawupload:file:///mem/xowa/file/commons.wikimedia.org/orig/7/0/1/c/A.png\"-z"
+ , "a-\"wikirawupload:{XOWA_ROOT}/file/commons.wikimedia.org/orig/7/0/1/c/A.png\"-z"
+ );
+ }
+}
+class Graph_json_save_mgr__fxt {
+ private final Xop_fxt fxt = new Xop_fxt();
+ private final Graph_json_save_mgr json_parser;
+ private final Gfo_test_lnr_base json_parser_lnr = Gfo_test_lnr_base.New__keys("is_commons", "is_orig", "ttl");
+ private final Gfo_test_err_mgr err_mgr = new Gfo_test_err_mgr();
+ public Graph_json_save_mgr__fxt() {
+ json_parser = new Graph_json_save_mgr(fxt.App().Fsys_mgr());
+ json_parser.Test_lnr_(json_parser_lnr);
+ }
+ public void Clear() {
+ json_parser_lnr.Clear();
+ err_mgr.Init();
+ }
+ public Graph_json_save_mgr__fxt Expd__err(String err) {
+ err_mgr.Add_expd(true, err);
+ return this;
+ }
+ public Graph_json_save_mgr__fxt Expd__file(boolean is_commons, boolean is_orig, String ttl) {
+ json_parser_lnr.Expd().Add(Gfo_test_itm.New__expd().Add("is_commons", is_commons).Add("is_orig", is_orig).Add("ttl", ttl));
+ return this;
+ }
+ public void Test__parse(String src) {Test__parse(src, src);}
+ public void Test__parse(String src, String expd) {
+ try {
+ // init file logger
+ Xop_file_logger__mok file_logger = new Xop_file_logger__mok();
+ fxt.Ctx().Lnki().File_logger_(file_logger);
+
+ // run it
+ byte[] src_as_bry = Bry_.new_u8(src);
+ byte[] actl = json_parser.Save(fxt.Page(), fxt.Ctx(), fxt.Wiki().Domain_bry(), fxt.Page().Ttl().Page_db_as_str(), src_as_bry, 0, src_as_bry.length);
+
+ // verify errs
+ err_mgr.Test();
+
+ // verify output
+ Gftest.Eq__str(expd, actl);
+
+ // verify files
+ Graph_save_mgr_itm_cbk cbk = new Graph_save_mgr_itm_cbk(fxt, file_logger);
+ json_parser_lnr.Test(cbk);
+ } finally {
+ err_mgr.Term();
+ fxt.Ctx().Lnki().File_logger_(Xop_file_logger_.Noop);
+ }
+ }
+}
+class Graph_save_mgr_itm_cbk implements Gfo_test_lnr_itm_cbk {
+ private final Xop_fxt fxt;
+ private final Xop_file_logger__mok file_logger;
+ public Graph_save_mgr_itm_cbk(Xop_fxt fxt, Xop_file_logger__mok file_logger) {
+ this.fxt = fxt;
+ this.file_logger = file_logger;
+ }
+ public void Test_itm(int i, int len, Gfo_test_itm expd_itm, Gfo_test_itm actl_itm) {
+ Xof_file_itm file_itm = fxt.Page().File_queue().Get_at(i);
+ Gftest.Eq__str(String_.new_u8(file_itm.Lnki_ttl()), actl_itm.Get_str("ttl"));
+
+ Gfo_test_itm file_logger_itm = (Gfo_test_itm)file_logger.Actl().Get_at(i);
+ file_logger_itm.Test_bry("ttl_bry", file_itm.Lnki_ttl());
+ }
+}
+class Xop_file_logger__mok extends Gfo_test_lnr_base implements Xop_file_logger {
+ public void Log_file(byte caller_tid, Xop_ctx ctx, Xop_lnki_tkn lnki) {
+ Log_file(caller_tid, ctx, lnki.Ttl(), lnki.Ns_id(), lnki.Lnki_type(), lnki.W(), lnki.H(), lnki.Upright(), lnki.Time(), lnki.Page());
+ }
+ public void Log_file(byte caller_tid, Xop_ctx ctx, Xoa_ttl lnki_ttl, int ns_id, byte lnki_type, int lnki_w, int lnki_h, double lnki_upright, double lnki_time, int lnki_page) {
+ Gfo_test_itm itm = Gfo_test_itm.New__actl()
+ .Add("caller_tid", caller_tid)
+ .Add("ttl_bry", lnki_ttl.Page_db())
+ .Add("ns_id", ns_id)
+ .Add("lnki_type", lnki_type)
+ .Add("lnki_w", lnki_w)
+ .Add("lnki_h", lnki_h)
+ .Add("lnki_upright", lnki_upright)
+ .Add("lnki_time", lnki_time)
+ .Add("lnki_page", lnki_page);
+ this.Actl().Add(itm);
+ }
+}
diff --git a/400_xowa/src/gplx/xowa/xtns/graphs/Graph_xnde.java b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_xnde.java
index 8c3fc6d77..c9c24141e 100644
--- a/400_xowa/src/gplx/xowa/xtns/graphs/Graph_xnde.java
+++ b/400_xowa/src/gplx/xowa/xtns/graphs/Graph_xnde.java
@@ -31,6 +31,12 @@ public class Graph_xnde implements Xox_xnde {
Bry_bfr tmp_bfr = Bry_bfr_.New();
json = Json_fmtr.clean(tmp_bfr, json);
+ // swap out fsys_root; ISSUE#:553; DATE:2019-09-25
+ Graph_json_save_mgr json_save_mgr = new Graph_json_save_mgr(app.Fsys_mgr());
+ if (hctx.Mode_is_hdump()) {
+ json = json_save_mgr.Save(wpg, ctx, wpg.Wiki().Domain_bry(), wpg.Url().To_str(), json, 0, json.length);
+ }
+
// enable graph
Xoh_head_itm__graph itm_graph = ctx.Page().Html_data().Head_mgr().Itm__graph();
itm_graph.Enabled_y_();
@@ -48,6 +54,8 @@ public class Graph_xnde implements Xox_xnde {
// add to bfr
bfr.Add(Html__div_lhs_bgn);
bfr.Add_int_fixed(version, 1);
+ if (json_save_mgr.Root_dir_found())
+ bfr.Add_byte_space().Add(Graph_json_load_mgr.HDUMP_ATR);
bfr.Add(Html__div_lhs_end);
bfr.Add(json);
bfr.Add(Html__div_rhs);
@@ -55,7 +63,7 @@ public class Graph_xnde implements Xox_xnde {
public static Xop_log_basic_wkr Log_wkr = Xop_log_basic_wkr.Null;
private static final byte[]
Html__div_lhs_bgn = Bry_.new_a7("\n")
+ , Html__div_lhs_end = Bry_.new_a7(">")
, Html__div_rhs = Bry_.new_a7("
\n")
;
}