1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2025-06-13 12:54:14 +00:00

Compare commits

..

115 Commits

Author SHA1 Message Date
gnosygnu
2a4abd8f75 Gui: Fix NullPointerException when pressing backspace on empty search box [#841] 2021-03-03 03:37:22 -05:00
gnosygnu
17a3b4e7b3 Parser: Only print value without ± if lo and hi are null [#839] 2021-02-14 08:13:31 -05:00
gnosygnu
659bca3660 Parser: Prepend 0 to all strings starting with ., even just . [#838] 2021-02-13 20:19:16 -05:00
gnosygnu
8684783139 Lang: Rename Pft_fmt_itm_hijri [#837] 2021-02-08 08:03:06 -05:00
gnosygnu
7e53c8462d Lang: Fix misspelling of hijri [#837] 2021-02-07 10:41:56 -05:00
gnosygnu
559503786b Release: Update app version [#833] 2021-01-26 08:03:13 -05:00
gnosygnu
e117823e60 Gui: Manually fire javascript event and exit [#836] 2021-01-25 08:07:23 -05:00
gnosygnu
ff0f92b950 Gui: Encode and decode image sources [#829] 2021-01-11 08:03:10 -05:00
gnosygnu
4187dc4a76 Gui: Strip about: from links during Copy [#823] 2021-01-05 02:06:20 -05:00
gnosygnu
1a6a203cfd Parser: Match for < + onlyinclude to fix false match [#825] 2020-12-17 07:48:28 -05:00
gnosygnu
814e85ea70 Release: Release v4.6.14.2012 to fix about:/wiki/ when doing "Open in new tab" [#823] 2020-12-16 09:02:02 -05:00
gnosygnu
0ef5058cfd Gui: Strip about:/wiki/ from links [#823] 2020-12-16 09:00:45 -05:00
gnosygnu
aeef520228 Dev: Fix failing tests after project rebuild [#826] 2020-12-14 08:53:28 -05:00
gnosygnu
4a7bd19056 Wikibase: Fix failing tests [#792] 2020-12-14 08:50:31 -05:00
gnosygnu
7d357540c7 ParserFunctions: Fail if e0 or pi0 [#819] 2020-11-25 06:34:13 -05:00
gnosygnu
b1c52aa2b2 ParserFunctions: Handle spaces in {{int}} keys [#817] 2020-11-03 07:59:21 -05:00
gnosygnu
845253af79 Mass_parse: Do not reuse json_parser else threading issues with itwiki [#818] 2020-11-03 06:51:31 -05:00
gnosygnu
541f5f6524 Css: Do not preprend selector for body [#815] 2020-11-01 10:45:38 -05:00
gnosygnu
067e62dd03 Release: Release v4.6.13.2010 [#797] 2020-10-19 09:42:18 -04:00
gnosygnu
19a315b8cd Skin: Change to mustache-backed Skin.Vector [#797] 2020-10-18 10:53:38 -04:00
gnosygnu
5c3d6a173b Wikibase: Calc precision by using longitude when precision is null [#792] 2020-09-25 08:42:52 -04:00
gnosygnu
c801e3a20b Scribunto: Allow int for find parameter [#802] 2020-09-23 08:44:58 -04:00
gnosygnu
59d8a42b22 Release: Update to 4.6.12.2009 [#801] 2020-09-23 08:44:14 -04:00
desb42
567e03dc1d Gui: Strip blank: from links [#799] 2020-09-21 19:29:29 -04:00
gnosygnu
7550894dda Release: Update for 4.6.11.2009 [#801] 2020-09-19 12:49:47 -04:00
gnosygnu
caad4145d5 Gui: Strip about: from links [#799] 2020-09-19 12:47:56 -04:00
gnosygnu
de841f8ff2 Wikibase: Reproduce geocoordinate logic of en.w:Module:Wd [#792] 2020-09-07 17:28:20 -04:00
gnosygnu
5f2e9c7514 Parser: Require coefficient for scientific notation [#795] 2020-09-07 08:32:47 -04:00
gnosygnu
d3896bf547 Parser: Remove Tmpl_result_cache, Bld_key, and corresponding code in Xot_invk_tkn [#793] 2020-09-04 08:20:18 -04:00
gnosygnu
316c6c6a58 Map: Compare precision against 4 not 0 [#792] 2020-09-03 08:32:16 -04:00
gnosygnu
72051f4ce9 Wikibase: Default 'null' to 0, not 1 [#792] 2020-09-03 08:23:57 -04:00
gnosygnu
f19228c886 Mass_parse: Add error_filter to ignore logging certain errors [#793] 2020-09-01 09:02:47 -04:00
gnosygnu
1b6324938c Release: Upgrade version to 4.6.10.2008 for Mac OS X fix [#687] 2020-09-01 08:45:14 -04:00
gnosygnu
9b4ea48753 Install: Upgrade to SWT 4.16 [#687] 2020-08-31 09:06:19 -04:00
gnosygnu
6ed7659b4d Core: Parse decimal 'e' as 'E' [#565] 2020-08-27 06:04:17 -04:00
gnosygnu
1eea3682ca SyntaxHighlight: Treat syntaxHighlight inline as enclose=none [#794] 2020-08-27 05:25:59 -04:00
gnosygnu
4f87d1a195 Image: Mark tif orig files as not images [#788] 2020-08-26 09:01:43 -04:00
gnosygnu
ea9b592cfd Html: Do not remove role= attributes from html tags [#785] 2020-08-18 06:14:25 -04:00
gnosygnu
3c9fd50ddc Pagebanner: Show pageBanner for Wikivoyage namespace [#748] 2020-08-17 07:46:44 -04:00
gnosygnu
619d2f9844 Dev: Include baselib in core classpath [#697] 2020-08-14 09:09:17 -04:00
gnosygnu
bdae819908 Scribunto: Trim zeroes when stringifying Doubles [#697] 2020-08-12 08:48:30 -04:00
gnosygnu
f122a8d8a3 Wikibase: Prepend claim_type with "wikibase-" for lexeme, form, sense [#771] 2020-08-09 13:18:19 -04:00
gnosygnu
174e93cbfa Parser: Add namespace to Template title [#784] 2020-08-09 13:03:41 -04:00
gnosygnu
0aced904a5 Edit: Save compiled HTML when editing pages [#699] 2020-08-06 07:09:34 -04:00
gnosygnu
dc374fa7fc Html: Add 'contentSub2' to xowa.gfs [#783] 2020-08-04 08:28:02 -04:00
gnosygnu
95e833d70c Wikibase: Fix NullPointerException on a few fr.w pages [#773] 2020-08-04 07:24:52 -04:00
gnosygnu
afed865c84 Scribunto: Implement'lang argument for mw.ext.data.get [#779] 2020-08-03 08:37:51 -04:00
gnosygnu
7b6b3ed09a Wikibase: Implement lexeme, form, and sense [#771] 2020-07-31 07:44:00 -04:00
gnosygnu
a0c0b5b2fd HTTP Server: Fix broken links in left nav [#768] 2020-07-23 08:19:24 -04:00
gnosygnu
062d308128 Scribunto: Do not return early in Gsub if source is String.empty [#731] 2020-07-20 08:28:08 -04:00
gnosygnu
ad607d952c Release: Bump version to 4.6.9.2007 [#761] 2020-07-17 09:08:55 -04:00
gnosygnu
6592eaf8de Gui: Fix page loading in wrong wiki after switching tab positions [#761] 2020-07-17 09:07:18 -04:00
gnosygnu
45adc036a2 Luaj: Check for error in LoadString [#759] 2020-07-15 08:06:21 -04:00
gnosygnu
6b2e120fc1 Css: Fix top tabs showing vertically instead of horizontally [#754] 2020-07-02 09:08:26 -04:00
gnosygnu
7c0a8c5064 Luaj: Sync LuaString with latest Luaj source [#735] 2020-07-02 08:00:10 -04:00
gnosygnu
35475d631c Http_server: Fix images not downloading on some Portal pages [#686] 2020-06-27 19:28:42 -04:00
gnosygnu
efe415d3a3 Scribunto: Add help text for xowa.app.settings.publish [#737] 2020-06-20 17:55:01 -04:00
gnosygnu
97b1055b4e Scribunto: Add configurable timeout for en.wikipedia.org and 'Authority_control' [#737] 2020-06-20 17:47:42 -04:00
gnosygnu
b51d224f09 Html: Add 'mw-footer' class to 'footer' div [#745] 2020-06-16 09:05:16 -04:00
gnosygnu
b87e4d07cb Scribunto: Hack fix for stopping long-running threads [#737] 2020-06-15 10:18:34 -04:00
gnosygnu
b4516f5060 Luaj: Change table.sort from MergeSort to QuickSort variant with stable sorting [#743] 2020-06-13 09:37:43 -04:00
gnosygnu
49e18a2255 Css: Prepend '.mw-parser-output' to all nested classes [#741] 2020-06-09 08:38:26 -04:00
gnosygnu
026288f809 Css: Change java.lang.String.charAt to JsString_.charAt (with JsString_.charAt) [#741] 2020-06-08 09:00:39 -04:00
gnosygnu
1103674d88 Css: Change java.lang.String.charAt to JsString_.charAt [#741] 2020-06-08 08:58:32 -04:00
gnosygnu
27756f8056 Scribunto: Hack timeout to limit Scribunto execution to 5 seconds [#737] 2020-06-07 21:41:46 -04:00
gnosygnu
398a1c854a Luaj: Use substring.m_bytes, not substring.getBytes() [#735] 2020-06-03 09:21:25 -04:00
gnosygnu
35f2027b20 Scribunto: Create match string using char-indexes, not codepointIndexes (to handle UTF-8 strings) [#726] 2020-05-31 01:19:24 -04:00
gnosygnu
be072de8d9 Luaj: Reinstate next variable for frontier matches [#732] 2020-05-29 09:15:00 -04:00
gnosygnu
f760fd9cd0 Luaj: Do not match end-of-string for frontier patterns [#732] 2020-05-29 07:23:38 -04:00
gnosygnu
3d5ec47aa8 Html: Do not call Xtn property for non-Xtn XML nodes [#730] 2020-05-27 09:18:53 -04:00
gnosygnu
53762288d7 Release: Release embeddable app version (v4.6.7) [#733] 2020-05-27 08:19:26 -04:00
gnosygnu
7a0247417d Embeddable: Do not call hxtn code during embeddable [#733] 2020-05-27 07:29:39 -04:00
gnosygnu
0cdfa0992c Hdump: Serialize / deserialize top-icon [#721] 2020-05-26 08:38:50 -04:00
gnosygnu
dc66b926d3 Release: Change default download server from dumps.wikimedia.your.org to dumps.wikimedia.org [#727] 2020-05-20 20:16:00 -04:00
gnosygnu
8c7c9f88ff Hdump: Show category at bottom of Category pages [#722] 2020-05-17 17:04:25 -04:00
gnosygnu
94b757682a Luaj: Make anypos captures base-1, not base-0 (with fixed test) [#724] 2020-05-17 11:38:06 -04:00
gnosygnu
1ebc9d3488 Luaj: Make anypos captures base-1, not base-0 [#726] 2020-05-17 11:27:38 -04:00
gnosygnu
654810d56c Html: Add 'lang' to <h1> [#724] 2020-05-15 09:34:09 -04:00
gnosygnu
b551c1875b Html: Show Read, Edit, ViewHtml in correct right-to-left order for RTL languages [#723] 2020-05-15 09:02:45 -04:00
gnosygnu
ba1d4e0b7c XOMW: Add Globals and refine XomwMediaWikiServices [#632] 2020-05-14 08:58:45 -04:00
gnosygnu
a2fe75f402 RandomRootPage: Do not fail to find page for some random selections; also, do not show 'Redirected from redirected_title' [#719] 2020-05-13 09:20:46 -04:00
gnosygnu
a6331f5c89 XOMW: Finish XomwServiceContainer [#632] 2020-05-12 08:13:31 -04:00
gnosygnu
43866163b9 XOMW: Add Assert [#632] 2020-05-11 08:38:35 -04:00
gnosygnu
49f8d4b000 Lst: Handle keys with whitespace [#720] 2020-05-10 09:37:04 -04:00
gnosygnu
994d405a26 Release: Increase version number [#694] 2020-05-10 08:33:43 -04:00
gnosygnu
04c499ce3e XOMW: Add PHP array-diff and array-diff-key [#632] 2020-05-10 07:43:30 -04:00
gnosygnu
ebe82bea6a LuaJ: Always format in Locale.US, not current locale [#694] 2020-05-09 16:24:59 -04:00
gnosygnu
a9367eaca8 XOMW: Consolidate XophpArray_ into XophpArray [#632] 2020-05-09 07:21:14 -04:00
gnosygnu
ee68162a4a XOMW: Add more implementation for XomwServiceContainer [#632] 2020-05-08 09:18:46 -04:00
gnosygnu
6663b769d5 Dev: Fix broken 'xowa_get_and_make.sh' due to JDK 8 and new *Test files [#718] 2020-05-07 09:30:48 -04:00
gnosygnu
2dab6a90be XOMW: Start XomwServiceContainer [#632] 2020-05-07 08:58:15 -04:00
gnosygnu
b0e02979ac XOMW: Start XomwRequestContext [#632] 2020-05-05 08:14:21 -04:00
gnosygnu
f9cf49c160 XOMW: Start XomwMessage [#632] 2020-05-04 08:29:37 -04:00
gnosygnu
0d917bccc7 XOMW: Finish XomwHooks - part 2 [#632] 2020-05-03 09:19:47 -04:00
gnosygnu
d1345bf724 XOMW: Finish XomwHooks [#632] 2020-05-03 09:19:19 -04:00
gnosygnu
3d74406a3e XOMW: Add array_filter [#632] 2020-05-02 08:30:47 -04:00
gnosygnu
a6b128422e XOMW: More XomwHooks implementation [#632] 2020-05-01 09:01:40 -04:00
gnosygnu
0c3cb1ba3d HTTP Server: Do not show new logic for SWT/GUI tabs ('wikiName - message' if mainPage, else 'pageName - wikiName') [#715] 2020-05-01 08:55:03 -04:00
gnosygnu
105446f5ca HTTP Server: Show correct tab / html.head name for pages ('wikiName - message' if mainPage, else 'pageName - wikiName') [#715] 2020-05-01 08:45:01 -04:00
gnosygnu
db73b4302d Xomw: Add some implementation for XomwHooks [#632] 2020-04-29 07:32:10 -04:00
gnosygnu
bd71db3ed6 Xomw: Add more implementation near statelessFetchTemplate [#632] 2020-04-27 08:39:30 -04:00
gnosygnu
a4b5f5de5d TemplateStyles: Apply wrapper to each class, not to top only [#712] 2020-04-26 15:51:56 -04:00
gnosygnu
ecbcf1e707 GFLucene: Add lucene binaries [#707] 2020-04-26 08:09:27 -04:00
gnosygnu
7b00918941 XOMW: Rename XomwTitle to XomwTitleOld [#632] 2020-04-26 08:08:39 -04:00
gnosygnu
8807dcfbeb TemplateStyles: Support wrapper argument [#712] 2020-04-23 08:18:03 -04:00
gnosygnu
a6ac592212 TemplateStyles: Add mw-parser-output in XoCssMin, not in TemplateStyles [#704] 2020-04-22 08:17:54 -04:00
gnosygnu
b05e3cd188 File: Add '.stl' and '.webp' as image extensions [#710] 2020-04-21 08:31:40 -04:00
gnosygnu
9c8650a4d9 Dev: Modify .gitignore files for IntelliJ .iml files [#709] 2020-04-20 07:31:23 -04:00
gnosygnu
73a56ffab3 TemplateStyles: Add XoCssMin from @desb42 [#704] 2020-04-19 08:54:54 -04:00
gnosygnu
e9e5724a2a Make: Add baselib to xowa classpath [#706] 2020-04-13 07:23:39 -04:00
gnosygnu
c3c9d4ad1e Html: Do not add '\n' to media anchor links [#703] 2020-04-10 07:53:45 -04:00
gnosygnu
5a35f3b05b TemplateStyles: Scope TemplateStyles css to main content div by adding 'mw-parser-output' [#426] 2020-04-10 07:07:28 -04:00
gnosygnu
7ad1291768 XomwTemplateParser: Port XomwPreprocessor classes as direct translation of MW code [#632] 2020-04-09 08:10:22 -04:00
gnosygnu
17d7a7ebed XomwTemplateParser: Port other XomwPPTemplateFrame classes [#632] 2020-04-03 06:39:35 -04:00
gnosygnu
9809dfd6c7 XomwTemplateParser: Port XomwPPTemplateFrame_Hash [#632] 2020-03-31 07:46:17 -04:00
429 changed files with 96103 additions and 58884 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.iml
**/.idea/**

File diff suppressed because it is too large Load Diff

View File

@ -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,295 +13,309 @@ 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;
import org.junit.*; import gplx.core.primitives.*; import gplx.core.brys.*; import gplx.core.tests.*;
public class Bry__tst {
private final Bry__fxt fxt = new Bry__fxt();
@Test public void new_ascii_() {
fxt.Test_new_a7("a" , Bry_.New_by_ints(97)); // one
fxt.Test_new_a7("abc" , Bry_.New_by_ints(97, 98, 99)); // many
fxt.Test_new_a7("" , Bry_.Empty); // none
fxt.Test_new_a7("¢€𤭢" , Bry_.New_by_ints(63, 63, 63, 63)); // non-ascii -> ?
}
@Test public void new_u8() {
fxt.Test_new_u8("a" , Bry_.New_by_ints(97)); // one
fxt.Test_new_u8("abc" , Bry_.New_by_ints(97, 98, 99)); // many
fxt.Test_new_u8("¢" , Bry_.New_by_ints(194, 162)); // bry_len=2; cent
fxt.Test_new_u8("" , Bry_.New_by_ints(226, 130, 172)); // bry_len=3; euro
fxt.Test_new_u8("𤭢" , Bry_.New_by_ints(240, 164, 173, 162)); // bry_len=4; example from en.w:UTF-8
}
@Test public void Add__bry_plus_byte() {
fxt.Test_add("a" , Byte_ascii.Pipe , "a|"); // basic
fxt.Test_add("" , Byte_ascii.Pipe , "|"); // empty String
}
@Test public void Add__byte_plus_bry() {
fxt.Test_add(Byte_ascii.Pipe , "a" , "|a"); // basic
fxt.Test_add(Byte_ascii.Pipe , "" , "|"); // empty String
}
@Test public void Add_w_dlm() {
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a", "b", "c") , "a|b|c"); // basic
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a") , "a"); // one item
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a", null, "c") , "a||c"); // null
}
@Test public void Add_w_dlm_bry() {
fxt.Test_add_w_dlm("<>", String_.Ary("a","b","c"), "a<>b<>c");
}
@Test public void MidByPos() {
tst_MidByPos("abcba", 0, 1, "a");
tst_MidByPos("abcba", 0, 2, "ab");
tst_MidByPos("abcba", 1, 4, "bcb");
} void tst_MidByPos(String src, int bgn, int end, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Mid(Bry_.new_u8(src), bgn, end)));}
@Test public void Replace_one() {
tst_ReplaceOne("a" , "b" , "c" , "a");
tst_ReplaceOne("b" , "b" , "c" , "c");
tst_ReplaceOne("bb" , "b" , "c" , "cb");
tst_ReplaceOne("abcd" , "bc" , "" , "ad");
tst_ReplaceOne("abcd" , "b" , "ee" , "aeecd");
} void tst_ReplaceOne(String src, String find, String repl, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Replace_one(Bry_.new_u8(src), Bry_.new_u8(find), Bry_.new_u8(repl))));}
@Test public void XtoStrBytesByInt() {
tst_XtoStrBytesByInt(0, 0);
tst_XtoStrBytesByInt(9, 9);
tst_XtoStrBytesByInt(10, 1, 0);
tst_XtoStrBytesByInt(321, 3, 2, 1);
tst_XtoStrBytesByInt(-321, Bry_.Byte_NegSign, 3, 2, 1);
tst_XtoStrBytesByInt(Int_.Max_value, 2,1,4,7,4,8,3,6,4,7);
}
void tst_XtoStrBytesByInt(int val, int... expdAryAsInt) {
byte[] expd = new byte[expdAryAsInt.length];
for (int i = 0; i < expd.length; i++) {
int expdInt = expdAryAsInt[i];
expd[i] = expdInt == Bry_.Byte_NegSign ? Bry_.Byte_NegSign : Byte_ascii.To_a7_str(expdAryAsInt[i]);
}
Tfds.Eq_ary(expd, Bry_.To_a7_bry(val, Int_.DigitCount(val)));
}
@Test public void Has_at_end() {
tst_HasAtEnd("a|bcd|e", "d" , 2, 5, true); // y_basic
tst_HasAtEnd("a|bcd|e", "bcd" , 2, 5, true); // y_many
tst_HasAtEnd("a|bcd|e", "|bcd" , 2, 5, false); // n_long
tst_HasAtEnd("a|bcd|e", "|bc" , 2, 5, false); // n_pos
tst_HasAtEnd("abc", "bc", true); // y
tst_HasAtEnd("abc", "bd", false); // n
tst_HasAtEnd("a", "ab", false); // exceeds_len
}
void tst_HasAtEnd(String src, String find, int bgn, int end, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_end(Bry_.new_u8(src), Bry_.new_u8(find), bgn, end));}
void tst_HasAtEnd(String src, String find, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_end(Bry_.new_u8(src), Bry_.new_u8(find)));}
@Test public void Has_at_bgn() {
tst_HasAtBgn("y_basic" , "a|bcd|e", "b" , 2, 5, true);
tst_HasAtBgn("y_many" , "a|bcd|e", "bcd" , 2, 5, true);
tst_HasAtBgn("n_long" , "a|bcd|e", "bcde" , 2, 5, false);
tst_HasAtBgn("n_pos" , "a|bcd|e", "|bc" , 2, 5, false);
} void tst_HasAtBgn(String tst, String src, String find, int bgn, int end, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_bgn(Bry_.new_u8(src), Bry_.new_u8(find), bgn, end), tst);}
@Test public void Match() {
tst_Match("abc", 0, "abc", true);
tst_Match("abc", 2, "c", true);
tst_Match("abc", 0, "cde", false);
tst_Match("abc", 2, "abc", false); // bounds check
tst_Match("abc", 0, "abcd", false);
tst_Match("a" , 0, "", false);
tst_Match("" , 0, "a", false);
tst_Match("" , 0, "", true);
tst_Match("ab", 0, "a", false); // FIX: "ab" should not match "a" b/c .length is different
} void tst_Match(String src, int srcPos, String find, boolean expd) {Tfds.Eq(expd, Bry_.Match(Bry_.new_u8(src), srcPos, Bry_.new_u8(find)));}
@Test public void ReadCsvStr() {
tst_ReadCsvStr("a|" , "a");
tst_ReadCsvStr("|a|", 1 , "a");
Int_obj_ref bgn = Int_obj_ref.New_zero(); tst_ReadCsvStr("a|b|c|", bgn, "a"); tst_ReadCsvStr("a|b|c|", bgn, "b"); tst_ReadCsvStr("a|b|c|", bgn, "c");
tst_ReadCsvStr("|", "");
tst_ReadCsvStr_err("a");
tst_ReadCsvStr("'a'|" , "a");
tst_ReadCsvStr("'a''b'|" , "a'b");
tst_ReadCsvStr("'a|b'|" , "a|b");
tst_ReadCsvStr("''|", "");
tst_ReadCsvStr_err("''");
tst_ReadCsvStr_err("'a'b'");
tst_ReadCsvStr_err("'a");
tst_ReadCsvStr_err("'a|");
tst_ReadCsvStr_err("'a'");
}
@Test public void XtoIntBy4Bytes() { // test len=1, 2, 3, 4
tst_XtoIntBy4Bytes(32, (byte)32); // space
tst_XtoIntBy4Bytes(8707, (byte)34, (byte)3); // &exist;
tst_XtoIntBy4Bytes(6382179, Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c);
tst_XtoIntBy4Bytes(1633837924, Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c, Byte_ascii.Ltr_d);
}
@Test public void XtoInt() {
tst_XtoInt("1", 1);
tst_XtoInt("123", 123);
tst_XtoInt("a", Int_.Min_value, Int_.Min_value);
tst_XtoInt("-1", Int_.Min_value, -1);
tst_XtoInt("-123", Int_.Min_value, -123);
tst_XtoInt("123-1", Int_.Min_value, Int_.Min_value);
tst_XtoInt("+123", Int_.Min_value, 123);
tst_XtoInt("", -1);
}
void tst_XtoInt(String val, int expd) {tst_XtoInt(val, -1, expd);}
void tst_XtoInt(String val, int or, int expd) {Tfds.Eq(expd, Bry_.To_int_or(Bry_.new_u8(val), or));}
void tst_XtoIntBy4Bytes(int expd, byte... ary) {Tfds.Eq(expd, Bry_.To_int_by_a7(ary), "XtoInt"); Tfds.Eq_ary(ary, Bry_.new_by_int(expd), "XbyInt");}
void tst_ReadCsvStr(String raw, String expd) {tst_ReadCsvStr(raw, Int_obj_ref.New_zero() , expd);}
void tst_ReadCsvStr(String raw, int bgn, String expd) {tst_ReadCsvStr(raw, Int_obj_ref.New(bgn), expd);}
void tst_ReadCsvStr(String raw, Int_obj_ref bgnRef, String expd) {
int bgn = bgnRef.Val();
boolean rawHasQuotes = String_.CharAt(raw, bgn) == '\'';
String actl = String_.Replace(Bry_.ReadCsvStr(Bry_.new_u8(String_.Replace(raw, "'", "\"")), bgnRef, (byte)'|'), "\"", "'");
Tfds.Eq(expd, actl, "rv");
if (rawHasQuotes) {
int quoteAdj = String_.Count(actl, "'");
Tfds.Eq(bgn + 1 + String_.Len(actl) + 2 + quoteAdj, bgnRef.Val(), "pos_quote"); // +1=lkp.Len; +2=bgn/end quotes
}
else
Tfds.Eq(bgn + 1 + String_.Len(actl), bgnRef.Val(), "pos"); // +1=lkp.Len
}
void tst_ReadCsvStr_err(String raw) {
try {Bry_.ReadCsvStr(Bry_.new_u8(String_.Replace(raw, "'", "\"")), Int_obj_ref.New_zero(), (byte)'|');}
catch (Exception e) {Err_.Noop(e); return;}
Tfds.Fail_expdError();
}
@Test public void ReadCsvDte() {
tst_ReadCsvDte("20110801 221435.987");
} void tst_ReadCsvDte(String raw) {Tfds.Eq_date(DateAdp_.parse_fmt(raw, Bry_.Fmt_csvDte), Bry_.ReadCsvDte(Bry_.new_u8(raw + "|"), Int_obj_ref.New_zero(), (byte)'|'));}
@Test public void ReadCsvInt() {
tst_ReadCsvInt("1234567890");
} void tst_ReadCsvInt(String raw) {Tfds.Eq(Int_.Parse(raw), Bry_.ReadCsvInt(Bry_.new_u8(raw + "|"), Int_obj_ref.New_zero(), (byte)'|'));}
@Test public void Trim() {
Trim_tst("a b c", 1, 4, "b");
Trim_tst("a c", 1, 3, "");
Trim_tst(" ", 0, 2, "");
} void Trim_tst(String raw, int bgn, int end, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Trim(Bry_.new_u8(raw), bgn, end)));}
@Test public void Xto_int_lax() {
tst_Xto_int_lax("12a", 12);
tst_Xto_int_lax("1", 1);
tst_Xto_int_lax("123", 123);
tst_Xto_int_lax("a", 0);
tst_Xto_int_lax("-1", -1);
}
private void tst_Xto_int_lax(String val, int expd) {Tfds.Eq(expd, Bry_.To_int_or__lax(Bry_.new_u8(val), 0, String_.Len(val), 0));}
@Test public void To_int_or__trim_ws() {
tst_Xto_int_trim("123 " , 123);
tst_Xto_int_trim(" 123" , 123);
tst_Xto_int_trim(" 123 " , 123);
tst_Xto_int_trim(" 1 3 " , -1);
}
private void tst_Xto_int_trim(String val, int expd) {Tfds.Eq(expd, Bry_.To_int_or__trim_ws(Bry_.new_u8(val), 0, String_.Len(val), -1));}
@Test public void Compare() {
tst_Compare("abcde", 0, 1, "abcde", 0, 1, CompareAble_.Same);
tst_Compare("abcde", 0, 1, "abcde", 1, 2, CompareAble_.Less);
tst_Compare("abcde", 1, 2, "abcde", 0, 1, CompareAble_.More);
tst_Compare("abcde", 0, 1, "abcde", 0, 2, CompareAble_.Less);
tst_Compare("abcde", 0, 2, "abcde", 0, 1, CompareAble_.More);
tst_Compare("abcde", 2, 3, "abçde", 2, 3, CompareAble_.Less);
} void tst_Compare(String lhs, int lhs_bgn, int lhs_end, String rhs, int rhs_bgn, int rhs_end, int expd) {Tfds.Eq(expd, Bry_.Compare(Bry_.new_u8(lhs), lhs_bgn, lhs_end, Bry_.new_u8(rhs), rhs_bgn, rhs_end));}
@Test public void Increment_last() {
tst_IncrementLast(ary_(0), ary_(1));
tst_IncrementLast(ary_(0, 255), ary_(1, 0));
tst_IncrementLast(ary_(104, 111, 112, 101), ary_(104, 111, 112, 102));
}
byte[] ary_(int... ary) {
byte[] rv = new byte[ary.length];
for (int i = 0; i < ary.length; i++)
rv[i] = Byte_.By_int(ary[i]);
return rv;
}
void tst_IncrementLast(byte[] ary, byte[] expd) {Tfds.Eq_ary(expd, Bry_.Increment_last(Bry_.Copy(ary)));}
@Test public void Replace_between() {
tst_Replace_between("a[0]b" , "[", "]", "0", "a0b");
tst_Replace_between("a[0]b[1]c" , "[", "]", "0", "a0b0c");
tst_Replace_between("a[0b" , "[", "]", "0", "a[0b");
} public void tst_Replace_between(String src, String bgn, String end, String repl, String expd) {Tfds.Eq(expd, String_.new_a7(Bry_.Replace_between(Bry_.new_a7(src), Bry_.new_a7(bgn), Bry_.new_a7(end), Bry_.new_a7(repl))));}
@Test public void Replace() {
Bry_bfr tmp_bfr = Bry_bfr_.New();
tst_Replace(tmp_bfr, "a0b" , "0", "00", "a00b"); // 1 -> 1
tst_Replace(tmp_bfr, "a0b0c" , "0", "00", "a00b00c"); // 1 -> 2
tst_Replace(tmp_bfr, "a00b00c" , "00", "0", "a0b0c"); // 2 -> 1
tst_Replace(tmp_bfr, "a0b0" , "0", "00", "a00b00"); // 1 -> 2; EOS
tst_Replace(tmp_bfr, "a00b00" , "00", "0", "a0b0"); // 2 -> 1; EOS
tst_Replace(tmp_bfr, "a0b0" , "1", "2", "a0b0"); // no match
tst_Replace(tmp_bfr, "a0b0" , "b1", "b2", "a0b0"); // false match; EOS
}
public void tst_Replace(Bry_bfr tmp_bfr, String src, String bgn, String repl, String expd) {
Tfds.Eq(expd, String_.new_a7(Bry_.Replace(tmp_bfr, Bry_.new_a7(src), Bry_.new_a7(bgn), Bry_.new_a7(repl))));
}
@Test public void Split_bry() {
Split_bry_tst("a|b|c|" , "|" , String_.Ary("a", "b", "c"));
Split_bry_tst("a|" , "|" , String_.Ary("a"));
}
void Split_bry_tst(String src, String dlm, String[] expd) {
String[] actl = String_.Ary(Bry_split_.Split(Bry_.new_a7(src), Bry_.new_a7(dlm)));
Tfds.Eq_ary_str(expd, actl);
}
@Test public void Split_lines() {
Tst_split_lines("a\nb" , "a", "b"); // basic
Tst_split_lines("a\nb\n" , "a", "b"); // do not create empty trailing lines
Tst_split_lines("a\r\nb" , "a", "b"); // crlf
Tst_split_lines("a\rb" , "a", "b"); // cr only
}
void Tst_split_lines(String src, String... expd) {
Tfds.Eq_ary(expd, New_ary(Bry_split_.Split_lines(Bry_.new_a7(src))));
}
String[] New_ary(byte[][] lines) {
int len = lines.length;
String[] rv = new String[len];
for (int i = 0; i < len; i++)
rv[i] = String_.new_u8(lines[i]);
return rv;
}
@Test public void Match_bwd_any() {
Tst_match_bwd_any("abc", 2, 0, "c", true);
Tst_match_bwd_any("abc", 2, 0, "b", false);
Tst_match_bwd_any("abc", 2, 0, "bc", true);
Tst_match_bwd_any("abc", 2, 0, "abc", true);
Tst_match_bwd_any("abc", 2, 0, "zabc", false);
Tst_match_bwd_any("abc", 1, 0, "ab", true);
}
void Tst_match_bwd_any(String src, int src_end, int src_bgn, String find, boolean expd) {
Tfds.Eq(expd, Bry_.Match_bwd_any(Bry_.new_a7(src), src_end, src_bgn, Bry_.new_a7(find)));
}
@Test public void Trim_end() {
fxt.Test_trim_end("a " , Byte_ascii.Space, "a"); // trim.one
fxt.Test_trim_end("a " , Byte_ascii.Space, "a"); // trim.many
fxt.Test_trim_end("a" , Byte_ascii.Space, "a"); // trim.none
fxt.Test_trim_end("" , Byte_ascii.Space, ""); // empty
}
@Test public void Mid_w_trim() {
fxt.Test_Mid_w_trim("abc", "abc"); // no ws
fxt.Test_Mid_w_trim(" a b c ", "a b c"); // ws at bgn and end
fxt.Test_Mid_w_trim("\r\n\t a\r\n\t b \r\n\t ", "a\r\n\t b"); // space at bgn and end
fxt.Test_Mid_w_trim("", ""); // handle 0 bytes
fxt.Test_Mid_w_trim(" ", ""); // handle all ws
}
@Test public void New_u8_nl_apos() {
fxt.Test__new_u8_nl_apos(String_.Ary("a"), "a");
fxt.Test__new_u8_nl_apos(String_.Ary("a", "b"), "a\nb");
fxt.Test__new_u8_nl_apos(String_.Ary("a", "b'c", "d"), "a\nb\"c\nd");
}
@Test public void Repeat_bry() {
fxt.Test__repeat_bry("abc" , 3, "abcabcabc");
}
@Test public void Xcase__build__all() {
fxt.Test__xcase__build__all(Bool_.N, "abc", "abc");
fxt.Test__xcase__build__all(Bool_.N, "aBc", "abc");
}
}
class Bry__fxt {
private final Bry_bfr tmp = Bry_bfr_.New();
public void Test_trim_end(String raw, byte trim, String expd) {
byte[] raw_bry = Bry_.new_a7(raw);
Tfds.Eq(expd, String_.new_u8(Bry_.Trim_end(raw_bry, trim, raw_bry.length)));
}
public void Test_new_u8(String raw, byte[] expd) {Tfds.Eq_ary(expd, Bry_.new_u8(raw));}
public void Test_new_a7(String raw, byte[] expd) {Tfds.Eq_ary(expd, Bry_.new_a7(raw));}
public void Test_add(String s, byte b, String expd) {Tfds.Eq_str(expd, String_.new_u8(Bry_.Add(Bry_.new_u8(s), b)));}
public void Test_add(byte b, String s, String expd) {Tfds.Eq_str(expd, String_.new_u8(Bry_.Add(b, Bry_.new_u8(s))));}
public void Test_add_w_dlm(String dlm, String[] itms, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Add_w_dlm(Bry_.new_u8(dlm), Bry_.Ary(itms))));}
public void Test_add_w_dlm(byte dlm, String[] itms, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Add_w_dlm(dlm, Bry_.Ary(itms))));}
public void Test_Mid_w_trim(String src, String expd) {byte[] bry = Bry_.new_u8(src); Tfds.Eq(expd, String_.new_u8(Bry_.Mid_w_trim(bry, 0, bry.length)));}
public void Test__new_u8_nl_apos(String[] ary, String expd) {
Tfds.Eq_str_lines(expd, String_.new_u8(Bry_.New_u8_nl_apos(ary)));
}
public void Test__repeat_bry(String s, int count, String expd) {
Gftest.Eq__str(expd, Bry_.Repeat_bry(Bry_.new_u8(s), count));
}
public void Test__xcase__build__all(boolean upper, String src, String expd) {
Gftest.Eq__str(expd, Bry_.Xcase__build__all(tmp, upper, Bry_.new_u8(src)));
}
}
package gplx;
import gplx.core.primitives.Int_obj_ref;
import gplx.core.tests.Gftest;
import org.junit.Test;
public class Bry__tst {
private final Bry__fxt fxt = new Bry__fxt();
@Test public void new_ascii_() {
fxt.Test_new_a7("a" , Bry_.New_by_ints(97)); // one
fxt.Test_new_a7("abc" , Bry_.New_by_ints(97, 98, 99)); // many
fxt.Test_new_a7("" , Bry_.Empty); // none
fxt.Test_new_a7("¢€𤭢" , Bry_.New_by_ints(63, 63, 63, 63)); // non-ascii -> ?
}
@Test public void new_u8() {
fxt.Test_new_u8("a" , Bry_.New_by_ints(97)); // one
fxt.Test_new_u8("abc" , Bry_.New_by_ints(97, 98, 99)); // many
fxt.Test_new_u8("¢" , Bry_.New_by_ints(194, 162)); // bry_len=2; cent
fxt.Test_new_u8("" , Bry_.New_by_ints(226, 130, 172)); // bry_len=3; euro
fxt.Test_new_u8("𤭢" , Bry_.New_by_ints(240, 164, 173, 162)); // bry_len=4; example from en.w:UTF-8
}
@Test public void Add__bry_plus_byte() {
fxt.Test_add("a" , Byte_ascii.Pipe , "a|"); // basic
fxt.Test_add("" , Byte_ascii.Pipe , "|"); // empty String
}
@Test public void Add__byte_plus_bry() {
fxt.Test_add(Byte_ascii.Pipe , "a" , "|a"); // basic
fxt.Test_add(Byte_ascii.Pipe , "" , "|"); // empty String
}
@Test public void Add_w_dlm() {
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a", "b", "c") , "a|b|c"); // basic
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a") , "a"); // one item
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a", null, "c") , "a||c"); // null
}
@Test public void Add_w_dlm_bry() {
fxt.Test_add_w_dlm("<>", String_.Ary("a","b","c"), "a<>b<>c");
}
@Test public void MidByPos() {
tst_MidByPos("abcba", 0, 1, "a");
tst_MidByPos("abcba", 0, 2, "ab");
tst_MidByPos("abcba", 1, 4, "bcb");
} void tst_MidByPos(String src, int bgn, int end, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Mid(Bry_.new_u8(src), bgn, end)));}
@Test public void Replace_one() {
tst_ReplaceOne("a" , "b" , "c" , "a");
tst_ReplaceOne("b" , "b" , "c" , "c");
tst_ReplaceOne("bb" , "b" , "c" , "cb");
tst_ReplaceOne("abcd" , "bc" , "" , "ad");
tst_ReplaceOne("abcd" , "b" , "ee" , "aeecd");
} void tst_ReplaceOne(String src, String find, String repl, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Replace_one(Bry_.new_u8(src), Bry_.new_u8(find), Bry_.new_u8(repl))));}
@Test public void XtoStrBytesByInt() {
tst_XtoStrBytesByInt(0, 0);
tst_XtoStrBytesByInt(9, 9);
tst_XtoStrBytesByInt(10, 1, 0);
tst_XtoStrBytesByInt(321, 3, 2, 1);
tst_XtoStrBytesByInt(-321, Bry_.Byte_NegSign, 3, 2, 1);
tst_XtoStrBytesByInt(Int_.Max_value, 2,1,4,7,4,8,3,6,4,7);
}
void tst_XtoStrBytesByInt(int val, int... expdAryAsInt) {
byte[] expd = new byte[expdAryAsInt.length];
for (int i = 0; i < expd.length; i++) {
int expdInt = expdAryAsInt[i];
expd[i] = expdInt == Bry_.Byte_NegSign ? Bry_.Byte_NegSign : Byte_ascii.To_a7_str(expdAryAsInt[i]);
}
Tfds.Eq_ary(expd, Bry_.To_a7_bry(val, Int_.DigitCount(val)));
}
@Test public void Has_at_end() {
tst_HasAtEnd("a|bcd|e", "d" , 2, 5, true); // y_basic
tst_HasAtEnd("a|bcd|e", "bcd" , 2, 5, true); // y_many
tst_HasAtEnd("a|bcd|e", "|bcd" , 2, 5, false); // n_long
tst_HasAtEnd("a|bcd|e", "|bc" , 2, 5, false); // n_pos
tst_HasAtEnd("abc", "bc", true); // y
tst_HasAtEnd("abc", "bd", false); // n
tst_HasAtEnd("a", "ab", false); // exceeds_len
}
void tst_HasAtEnd(String src, String find, int bgn, int end, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_end(Bry_.new_u8(src), Bry_.new_u8(find), bgn, end));}
void tst_HasAtEnd(String src, String find, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_end(Bry_.new_u8(src), Bry_.new_u8(find)));}
@Test public void Has_at_bgn() {
tst_HasAtBgn("y_basic" , "a|bcd|e", "b" , 2, 5, true);
tst_HasAtBgn("y_many" , "a|bcd|e", "bcd" , 2, 5, true);
tst_HasAtBgn("n_long" , "a|bcd|e", "bcde" , 2, 5, false);
tst_HasAtBgn("n_pos" , "a|bcd|e", "|bc" , 2, 5, false);
} void tst_HasAtBgn(String tst, String src, String find, int bgn, int end, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_bgn(Bry_.new_u8(src), Bry_.new_u8(find), bgn, end), tst);}
@Test public void Match() {
tst_Match("abc", 0, "abc", true);
tst_Match("abc", 2, "c", true);
tst_Match("abc", 0, "cde", false);
tst_Match("abc", 2, "abc", false); // bounds check
tst_Match("abc", 0, "abcd", false);
tst_Match("a" , 0, "", false);
tst_Match("" , 0, "a", false);
tst_Match("" , 0, "", true);
tst_Match("ab", 0, "a", false); // FIX: "ab" should not match "a" b/c .length is different
} void tst_Match(String src, int srcPos, String find, boolean expd) {Tfds.Eq(expd, Bry_.Match(Bry_.new_u8(src), srcPos, Bry_.new_u8(find)));}
@Test public void ReadCsvStr() {
tst_ReadCsvStr("a|" , "a");
tst_ReadCsvStr("|a|", 1 , "a");
Int_obj_ref bgn = Int_obj_ref.New_zero(); tst_ReadCsvStr("a|b|c|", bgn, "a"); tst_ReadCsvStr("a|b|c|", bgn, "b"); tst_ReadCsvStr("a|b|c|", bgn, "c");
tst_ReadCsvStr("|", "");
tst_ReadCsvStr_err("a");
tst_ReadCsvStr("'a'|" , "a");
tst_ReadCsvStr("'a''b'|" , "a'b");
tst_ReadCsvStr("'a|b'|" , "a|b");
tst_ReadCsvStr("''|", "");
tst_ReadCsvStr_err("''");
tst_ReadCsvStr_err("'a'b'");
tst_ReadCsvStr_err("'a");
tst_ReadCsvStr_err("'a|");
tst_ReadCsvStr_err("'a'");
}
@Test public void XtoIntBy4Bytes() { // test len=1, 2, 3, 4
tst_XtoIntBy4Bytes(32, (byte)32); // space
tst_XtoIntBy4Bytes(8707, (byte)34, (byte)3); // &exist;
tst_XtoIntBy4Bytes(6382179, Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c);
tst_XtoIntBy4Bytes(1633837924, Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c, Byte_ascii.Ltr_d);
}
@Test public void XtoInt() {
tst_XtoInt("1", 1);
tst_XtoInt("123", 123);
tst_XtoInt("a", Int_.Min_value, Int_.Min_value);
tst_XtoInt("-1", Int_.Min_value, -1);
tst_XtoInt("-123", Int_.Min_value, -123);
tst_XtoInt("123-1", Int_.Min_value, Int_.Min_value);
tst_XtoInt("+123", Int_.Min_value, 123);
tst_XtoInt("", -1);
}
void tst_XtoInt(String val, int expd) {tst_XtoInt(val, -1, expd);}
void tst_XtoInt(String val, int or, int expd) {Tfds.Eq(expd, Bry_.To_int_or(Bry_.new_u8(val), or));}
void tst_XtoIntBy4Bytes(int expd, byte... ary) {Tfds.Eq(expd, Bry_.To_int_by_a7(ary), "XtoInt"); Tfds.Eq_ary(ary, Bry_.new_by_int(expd), "XbyInt");}
void tst_ReadCsvStr(String raw, String expd) {tst_ReadCsvStr(raw, Int_obj_ref.New_zero() , expd);}
void tst_ReadCsvStr(String raw, int bgn, String expd) {tst_ReadCsvStr(raw, Int_obj_ref.New(bgn), expd);}
void tst_ReadCsvStr(String raw, Int_obj_ref bgnRef, String expd) {
int bgn = bgnRef.Val();
boolean rawHasQuotes = String_.CharAt(raw, bgn) == '\'';
String actl = String_.Replace(Bry_.ReadCsvStr(Bry_.new_u8(String_.Replace(raw, "'", "\"")), bgnRef, (byte)'|'), "\"", "'");
Tfds.Eq(expd, actl, "rv");
if (rawHasQuotes) {
int quoteAdj = String_.Count(actl, "'");
Tfds.Eq(bgn + 1 + String_.Len(actl) + 2 + quoteAdj, bgnRef.Val(), "pos_quote"); // +1=lkp.Len; +2=bgn/end quotes
}
else
Tfds.Eq(bgn + 1 + String_.Len(actl), bgnRef.Val(), "pos"); // +1=lkp.Len
}
void tst_ReadCsvStr_err(String raw) {
try {Bry_.ReadCsvStr(Bry_.new_u8(String_.Replace(raw, "'", "\"")), Int_obj_ref.New_zero(), (byte)'|');}
catch (Exception e) {Err_.Noop(e); return;}
Tfds.Fail_expdError();
}
@Test public void ReadCsvDte() {
tst_ReadCsvDte("20110801 221435.987");
} void tst_ReadCsvDte(String raw) {Tfds.Eq_date(DateAdp_.parse_fmt(raw, Bry_.Fmt_csvDte), Bry_.ReadCsvDte(Bry_.new_u8(raw + "|"), Int_obj_ref.New_zero(), (byte)'|'));}
@Test public void ReadCsvInt() {
tst_ReadCsvInt("1234567890");
} void tst_ReadCsvInt(String raw) {Tfds.Eq(Int_.Parse(raw), Bry_.ReadCsvInt(Bry_.new_u8(raw + "|"), Int_obj_ref.New_zero(), (byte)'|'));}
@Test public void Trim() {
Trim_tst("a b c", 1, 4, "b");
Trim_tst("a c", 1, 3, "");
Trim_tst(" ", 0, 2, "");
} void Trim_tst(String raw, int bgn, int end, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Trim(Bry_.new_u8(raw), bgn, end)));}
@Test public void Xto_int_lax() {
tst_Xto_int_lax("12a", 12);
tst_Xto_int_lax("1", 1);
tst_Xto_int_lax("123", 123);
tst_Xto_int_lax("a", 0);
tst_Xto_int_lax("-1", -1);
}
private void tst_Xto_int_lax(String val, int expd) {Tfds.Eq(expd, Bry_.To_int_or__lax(Bry_.new_u8(val), 0, String_.Len(val), 0));}
@Test public void To_int_or__trim_ws() {
tst_Xto_int_trim("123 " , 123);
tst_Xto_int_trim(" 123" , 123);
tst_Xto_int_trim(" 123 " , 123);
tst_Xto_int_trim(" 1 3 " , -1);
}
private void tst_Xto_int_trim(String val, int expd) {Tfds.Eq(expd, Bry_.To_int_or__trim_ws(Bry_.new_u8(val), 0, String_.Len(val), -1));}
@Test public void Compare() {
tst_Compare("abcde", 0, 1, "abcde", 0, 1, CompareAble_.Same);
tst_Compare("abcde", 0, 1, "abcde", 1, 2, CompareAble_.Less);
tst_Compare("abcde", 1, 2, "abcde", 0, 1, CompareAble_.More);
tst_Compare("abcde", 0, 1, "abcde", 0, 2, CompareAble_.Less);
tst_Compare("abcde", 0, 2, "abcde", 0, 1, CompareAble_.More);
tst_Compare("abcde", 2, 3, "abçde", 2, 3, CompareAble_.Less);
} void tst_Compare(String lhs, int lhs_bgn, int lhs_end, String rhs, int rhs_bgn, int rhs_end, int expd) {Tfds.Eq(expd, Bry_.Compare(Bry_.new_u8(lhs), lhs_bgn, lhs_end, Bry_.new_u8(rhs), rhs_bgn, rhs_end));}
@Test public void Increment_last() {
tst_IncrementLast(ary_(0), ary_(1));
tst_IncrementLast(ary_(0, 255), ary_(1, 0));
tst_IncrementLast(ary_(104, 111, 112, 101), ary_(104, 111, 112, 102));
}
byte[] ary_(int... ary) {
byte[] rv = new byte[ary.length];
for (int i = 0; i < ary.length; i++)
rv[i] = Byte_.By_int(ary[i]);
return rv;
}
void tst_IncrementLast(byte[] ary, byte[] expd) {Tfds.Eq_ary(expd, Bry_.Increment_last(Bry_.Copy(ary)));}
@Test public void Replace_between() {
tst_Replace_between("a[0]b" , "[", "]", "0", "a0b");
tst_Replace_between("a[0]b[1]c" , "[", "]", "0", "a0b0c");
tst_Replace_between("a[0b" , "[", "]", "0", "a[0b");
} public void tst_Replace_between(String src, String bgn, String end, String repl, String expd) {Tfds.Eq(expd, String_.new_a7(Bry_.Replace_between(Bry_.new_a7(src), Bry_.new_a7(bgn), Bry_.new_a7(end), Bry_.new_a7(repl))));}
@Test public void Replace() {
Bry_bfr tmp_bfr = Bry_bfr_.New();
tst_Replace(tmp_bfr, "a0b" , "0", "00", "a00b"); // 1 -> 1
tst_Replace(tmp_bfr, "a0b0c" , "0", "00", "a00b00c"); // 1 -> 2
tst_Replace(tmp_bfr, "a00b00c" , "00", "0", "a0b0c"); // 2 -> 1
tst_Replace(tmp_bfr, "a0b0" , "0", "00", "a00b00"); // 1 -> 2; EOS
tst_Replace(tmp_bfr, "a00b00" , "00", "0", "a0b0"); // 2 -> 1; EOS
tst_Replace(tmp_bfr, "a0b0" , "1", "2", "a0b0"); // no match
tst_Replace(tmp_bfr, "a0b0" , "b1", "b2", "a0b0"); // false match; EOS
}
public void tst_Replace(Bry_bfr tmp_bfr, String src, String bgn, String repl, String expd) {
Tfds.Eq(expd, String_.new_a7(Bry_.Replace(tmp_bfr, Bry_.new_a7(src), Bry_.new_a7(bgn), Bry_.new_a7(repl))));
}
@Test public void Split_bry() {
Split_bry_tst("a|b|c|" , "|" , String_.Ary("a", "b", "c"));
Split_bry_tst("a|" , "|" , String_.Ary("a"));
}
void Split_bry_tst(String src, String dlm, String[] expd) {
String[] actl = String_.Ary(Bry_split_.Split(Bry_.new_a7(src), Bry_.new_a7(dlm)));
Tfds.Eq_ary_str(expd, actl);
}
@Test public void Split_lines() {
Tst_split_lines("a\nb" , "a", "b"); // basic
Tst_split_lines("a\nb\n" , "a", "b"); // do not create empty trailing lines
Tst_split_lines("a\r\nb" , "a", "b"); // crlf
Tst_split_lines("a\rb" , "a", "b"); // cr only
}
void Tst_split_lines(String src, String... expd) {
Tfds.Eq_ary(expd, New_ary(Bry_split_.Split_lines(Bry_.new_a7(src))));
}
String[] New_ary(byte[][] lines) {
int len = lines.length;
String[] rv = new String[len];
for (int i = 0; i < len; i++)
rv[i] = String_.new_u8(lines[i]);
return rv;
}
@Test public void Match_bwd_any() {
Tst_match_bwd_any("abc", 2, 0, "c", true);
Tst_match_bwd_any("abc", 2, 0, "b", false);
Tst_match_bwd_any("abc", 2, 0, "bc", true);
Tst_match_bwd_any("abc", 2, 0, "abc", true);
Tst_match_bwd_any("abc", 2, 0, "zabc", false);
Tst_match_bwd_any("abc", 1, 0, "ab", true);
}
void Tst_match_bwd_any(String src, int src_end, int src_bgn, String find, boolean expd) {
Tfds.Eq(expd, Bry_.Match_bwd_any(Bry_.new_a7(src), src_end, src_bgn, Bry_.new_a7(find)));
}
@Test public void Trim_bgn() {
fxt.Test_trim_bgn(" a" , Byte_ascii.Space, "a"); // trim.one
fxt.Test_trim_bgn(" a" , Byte_ascii.Space, "a"); // trim.many
fxt.Test_trim_bgn("a" , Byte_ascii.Space, "a"); // trim.none
fxt.Test_trim_bgn("" , Byte_ascii.Space, ""); // empty
}
@Test public void Trim_end() {
fxt.Test_trim_end("a " , Byte_ascii.Space, "a"); // trim.one
fxt.Test_trim_end("a " , Byte_ascii.Space, "a"); // trim.many
fxt.Test_trim_end("a" , Byte_ascii.Space, "a"); // trim.none
fxt.Test_trim_end("" , Byte_ascii.Space, ""); // empty
}
@Test public void Mid_w_trim() {
fxt.Test_Mid_w_trim("abc", "abc"); // no ws
fxt.Test_Mid_w_trim(" a b c ", "a b c"); // ws at bgn and end
fxt.Test_Mid_w_trim("\r\n\t a\r\n\t b \r\n\t ", "a\r\n\t b"); // space at bgn and end
fxt.Test_Mid_w_trim("", ""); // handle 0 bytes
fxt.Test_Mid_w_trim(" ", ""); // handle all ws
}
@Test public void New_u8_nl_apos() {
fxt.Test__new_u8_nl_apos(String_.Ary("a"), "a");
fxt.Test__new_u8_nl_apos(String_.Ary("a", "b"), "a\nb");
fxt.Test__new_u8_nl_apos(String_.Ary("a", "b'c", "d"), "a\nb\"c\nd");
}
@Test public void Repeat_bry() {
fxt.Test__repeat_bry("abc" , 3, "abcabcabc");
}
@Test public void Xcase__build__all() {
fxt.Test__xcase__build__all(Bool_.N, "abc", "abc");
fxt.Test__xcase__build__all(Bool_.N, "aBc", "abc");
}
}
class Bry__fxt {
private final Bry_bfr tmp = Bry_bfr_.New();
public void Test_trim_end(String raw, byte trim, String expd) {
byte[] raw_bry = Bry_.new_a7(raw);
Tfds.Eq(expd, String_.new_u8(Bry_.Trim_end(raw_bry, trim, raw_bry.length)));
}
public void Test_trim_bgn(String raw, byte trim, String expd) {
byte[] raw_bry = Bry_.new_a7(raw);
Tfds.Eq(expd, String_.new_u8(Bry_.Trim_bgn(raw_bry, trim, 0)));
}
public void Test_new_u8(String raw, byte[] expd) {Tfds.Eq_ary(expd, Bry_.new_u8(raw));}
public void Test_new_a7(String raw, byte[] expd) {Tfds.Eq_ary(expd, Bry_.new_a7(raw));}
public void Test_add(String s, byte b, String expd) {Tfds.Eq_str(expd, String_.new_u8(Bry_.Add(Bry_.new_u8(s), b)));}
public void Test_add(byte b, String s, String expd) {Tfds.Eq_str(expd, String_.new_u8(Bry_.Add(b, Bry_.new_u8(s))));}
public void Test_add_w_dlm(String dlm, String[] itms, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Add_w_dlm(Bry_.new_u8(dlm), Bry_.Ary(itms))));}
public void Test_add_w_dlm(byte dlm, String[] itms, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Add_w_dlm(dlm, Bry_.Ary(itms))));}
public void Test_Mid_w_trim(String src, String expd) {byte[] bry = Bry_.new_u8(src); Tfds.Eq(expd, String_.new_u8(Bry_.Mid_w_trim(bry, 0, bry.length)));}
public void Test__new_u8_nl_apos(String[] ary, String expd) {
Tfds.Eq_str_lines(expd, String_.new_u8(Bry_.New_u8_nl_apos(ary)));
}
public void Test__repeat_bry(String s, int count, String expd) {
Gftest.Eq__str(expd, Bry_.Repeat_bry(Bry_.new_u8(s), count));
}
public void Test__xcase__build__all(boolean upper, String src, String expd) {
Gftest.Eq__str(expd, Bry_.Xcase__build__all(tmp, upper, Bry_.new_u8(src)));
}
}

View File

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2021 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,57 +13,79 @@ 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;
import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
public class Decimal_adp_ {
public static final String Cls_val_name = "decimal";
public static final Class<?> Cls_ref_type = Decimal_adp.class;
public static Decimal_adp as_(Object obj) {return obj instanceof Decimal_adp ? (Decimal_adp)obj : null;}
public static final Decimal_adp Zero = new Decimal_adp(0);
public static final Decimal_adp One = new Decimal_adp(1);
public static final Decimal_adp Neg1 = new Decimal_adp(-1);
public static final Decimal_adp Const_e = Decimal_adp_.double_(Math_.E);
public static final Decimal_adp Const_pi = Decimal_adp_.double_(Math_.Pi);
public static Decimal_adp base1000_(long v) {return divide_(v, 1000);}
public static Decimal_adp parts_1000_(long num, int frc) {return divide_((num * (1000)) + frc, 1000);}
public static Decimal_adp parts_(long num, int frc) {
// int log10 = frc == 0 ? 0 : (Math_.Log10(frc) + 1);
// int pow10 = (int)Math_.Pow(10, log10);
int pow10 = XtoPow10(frc);
return divide_((num * (pow10)) + frc, pow10);
}
public static Decimal_adp cast(Object obj) {return (Decimal_adp)obj;}
static int XtoPow10(int v) {
if (v > -1 && v < 10) return 10;
else if (v > 9 && v < 100) return 100;
else if (v > 99 && v < 1000) return 1000;
else if (v > 999 && v < 10000) return 10000;
else if (v > 9999 && v < 100000) return 100000;
else if (v > 99999 && v < 1000000) return 1000000;
else if (v > 999999 && v < 10000000) return 10000000;
else if (v > 9999999 && v < 100000000) return 100000000;
else if (v > 99999999 && v < 1000000000) return 1000000000;
else throw Err_.new_wo_type("value must be between 0 and 1 billion", "v", v);
}
public static String CalcPctStr(long dividend, long divisor, String fmt) {
if (divisor == 0) return "%ERR";
return Decimal_adp_.float_(Float_.Div(dividend, divisor) * 100).To_str(fmt) + "%";
}
public static Decimal_adp divide_safe_(long lhs, long rhs) {return rhs == 0 ? Zero : divide_(lhs, rhs);}
public static Decimal_adp divide_(long lhs, long rhs) { return new Decimal_adp(new BigDecimal(lhs).divide(new BigDecimal(rhs), Gplx_rounding_context)); } public static Decimal_adp int_(int v) {return new Decimal_adp(new BigDecimal(v));} public static Decimal_adp long_(long v) {return new Decimal_adp(new BigDecimal(v));}
public static Decimal_adp float_(float v) {return new Decimal_adp(new BigDecimal(v));} public static Decimal_adp double_(double v) {return new Decimal_adp(new BigDecimal(v));}
public static Decimal_adp double_thru_str_(double v) {return new Decimal_adp(BigDecimal.valueOf(v));}
public static Decimal_adp db_(Object v) {return new Decimal_adp((BigDecimal)v);} public static Decimal_adp parse(String raw) {
try {
DecimalFormat nf = (DecimalFormat)NumberFormat.getInstance(Locale.US); // always parse as US format; EX:".9" should not be ",9" in german; DATE:2016-01-31
nf.setParseBigDecimal(true);
BigDecimal bd = (BigDecimal)nf.parse(raw);
return new Decimal_adp(bd);
} catch (ParseException e) {
throw Err_.new_("Decimal_adp_", "parse to decimal failed", "raw", raw);
}
} public static Decimal_adp pow_10_(int v) {return new Decimal_adp(new BigDecimal(1).scaleByPowerOfTen(v));}
public static final MathContext RoundDownContext = new MathContext(0, RoundingMode.DOWN); public static final MathContext Gplx_rounding_context = new MathContext(14, RoundingMode.HALF_UP); // changed from 28 to 14; DATE:2015-07-31 }
package gplx;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
public class Decimal_adp_ {
public static final String Cls_val_name = "decimal";
public static final Class<?> Cls_ref_type = Decimal_adp.class;
public static Decimal_adp as_(Object obj) {return obj instanceof Decimal_adp ? (Decimal_adp)obj : null;}
public static final Decimal_adp Zero = new Decimal_adp(0);
public static final Decimal_adp One = new Decimal_adp(1);
public static final Decimal_adp Neg1 = new Decimal_adp(-1);
public static final Decimal_adp Const_e = Decimal_adp_.double_(Math_.E);
public static final Decimal_adp Const_pi = Decimal_adp_.double_(Math_.Pi);
public static Decimal_adp base1000_(long v) {return divide_(v, 1000);}
public static Decimal_adp parts_1000_(long num, int frc) {return divide_((num * (1000)) + frc, 1000);}
public static Decimal_adp parts_(long num, int frc) {
// int log10 = frc == 0 ? 0 : (Math_.Log10(frc) + 1);
// int pow10 = (int)Math_.Pow(10, log10);
int pow10 = XtoPow10(frc);
return divide_((num * (pow10)) + frc, pow10);
}
public static Decimal_adp cast(Object obj) {return (Decimal_adp)obj;}
static int XtoPow10(int v) {
if (v > -1 && v < 10) return 10;
else if (v > 9 && v < 100) return 100;
else if (v > 99 && v < 1000) return 1000;
else if (v > 999 && v < 10000) return 10000;
else if (v > 9999 && v < 100000) return 100000;
else if (v > 99999 && v < 1000000) return 1000000;
else if (v > 999999 && v < 10000000) return 10000000;
else if (v > 9999999 && v < 100000000) return 100000000;
else if (v > 99999999 && v < 1000000000) return 1000000000;
else throw Err_.new_wo_type("value must be between 0 and 1 billion", "v", v);
}
public static String CalcPctStr(long dividend, long divisor, String fmt) {
if (divisor == 0) return "%ERR";
return Decimal_adp_.float_(Float_.Div(dividend, divisor) * 100).To_str(fmt) + "%";
}
public static Decimal_adp divide_safe_(long lhs, long rhs) {return rhs == 0 ? Zero : divide_(lhs, rhs);}
public static Decimal_adp divide_(long lhs, long rhs) {
return new Decimal_adp(new BigDecimal(lhs).divide(new BigDecimal(rhs), Gplx_rounding_context));
}
public static Decimal_adp int_(int v) {return new Decimal_adp(new BigDecimal(v));}
public static Decimal_adp long_(long v) {return new Decimal_adp(new BigDecimal(v));}
public static Decimal_adp float_(float v) {return new Decimal_adp(new BigDecimal(v));}
public static Decimal_adp double_(double v) {return new Decimal_adp(new BigDecimal(v));}
public static Decimal_adp double_thru_str_(double v) {return new Decimal_adp(BigDecimal.valueOf(v));}
public static Decimal_adp db_(Object v) {return new Decimal_adp((BigDecimal)v);}
public static Decimal_adp parse(String raw) {
try {
DecimalFormat nf = (DecimalFormat)NumberFormat.getInstance(Locale.US); // always parse as US format; EX:".9" should not be ",9" in german; DATE:2016-01-31
nf.setParseBigDecimal(true);
// 2020-08-27|ISSUE#:565|Parse 'e' as 'E'; PAGE:en.w:Huntington_Plaza
if (raw.contains("e")) {
raw = raw.replace("e", "E");
}
// 2021-02-13|ISSUE#:838|Parse '.' as '0.'; PAGE:en.w:2019_FIVB_Volleyball_Women%27s_Challenger_Cup#Pool_A
if (raw.startsWith(".")) {
raw = "0" + raw;
}
BigDecimal bd = (BigDecimal)nf.parse(raw);
return new Decimal_adp(bd);
} catch (ParseException e) {
throw Err_.new_("Decimal_adp_", "parse to decimal failed", "raw", raw);
}
}
public static Decimal_adp pow_10_(int v) {return new Decimal_adp(new BigDecimal(1).scaleByPowerOfTen(v));}
public static final MathContext RoundDownContext = new MathContext(0, RoundingMode.DOWN);
public static final MathContext Gplx_rounding_context = new MathContext(14, RoundingMode.HALF_UP); // changed from 28 to 14; DATE:2015-07-31
}

View File

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2021 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,81 @@ 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;
import org.junit.*;
public class Decimal_adp__tst {
private final Decimal_adp__fxt fxt = new Decimal_adp__fxt();
@Test public void divide_() {
fxt.Test_divide(1, 1000, "0.001");
fxt.Test_divide(1, 3, "0.33333333333333");
fxt.Test_divide(1, 7, "0.14285714285714");
}
@Test public void base1000_() {
fxt.Test_base_1000(1000, "1");
fxt.Test_base_1000(1234, "1.234");
fxt.Test_base_1000(123, "0.123");
}
@Test public void parts_() {
fxt.Test_parts(1, 0, "1");
fxt.Test_parts(1, 2, "1.2");
fxt.Test_parts(1, 23, "1.23");
fxt.Test_parts(123, 4567, "123.4567");
}
@Test public void parse() {
fxt.Test_parse("1", "1");
fxt.Test_parse("1.2", "1.2");
fxt.Test_parse("0.1", "0.1");
fxt.Test_parse("1.2E1", "12");
}
@Test public void Truncate_decimal() {
fxt.Test_truncate_decimal("1", "1");
fxt.Test_truncate_decimal("1.1", "1");
fxt.Test_truncate_decimal("1.9", "1");
}
@Test public void Fraction1000() {
fxt.Test_frac_1000(1, 1000, 1); // 0.001
fxt.Test_frac_1000(1, 3, 333); // 0.33333333
fxt.Test_frac_1000(1234, 1000, 234); // 1.234
fxt.Test_frac_1000(12345, 10000, 234); // 1.2345
}
@Test public void Lt() {
fxt.Test_comp_lt(1,123, 2, true);
fxt.Test_comp_lt(1,99999999, 2, true);
}
@Test public void To_str_fmt() {
fxt.Test_to_str_fmt(1, 2, "0.0", "0.5");
fxt.Test_to_str_fmt(1, 3, "0.0", "0.3");
fxt.Test_to_str_fmt(10000, 7, "0,000.000", "1,428.571");
fxt.Test_to_str_fmt(1, 2, "00.00", "00.50");
}
@Test public void Round() {
fxt.Test_round("123.456", 3, "123.456");
fxt.Test_round("123.456", 2, "123.46");
fxt.Test_round("123.456", 1, "123.5");
fxt.Test_round("123.456", 0, "123");
fxt.Test_round("123.456", -1, "120");
fxt.Test_round("123.456", -2, "100");
fxt.Test_round("123.456", -3, "0");
fxt.Test_round("6", -1, "10");
fxt.Test_round("5", -1, "10");
fxt.Test_round("6", -2, "0");
}
}
class Decimal_adp__fxt {
public void Test_divide(int lhs, int rhs, String expd) {Tfds.Eq(expd, Decimal_adp_.divide_(lhs, rhs).To_str());}
public void Test_base_1000(int val, String expd) {Tfds.Eq(expd, Decimal_adp_.base1000_(val).To_str());}
public void Test_parts(int num, int fracs, String expd) {Tfds.Eq(expd, Decimal_adp_.parts_(num, fracs).To_str());}
public void Test_parse(String raw, String expd) {Tfds.Eq(expd, Decimal_adp_.parse(raw).To_str());}
public void Test_truncate_decimal(String raw, String expd) {Tfds.Eq(Decimal_adp_.parse(expd).To_str(), Decimal_adp_.parse(raw).Truncate().To_str());}
public void Test_frac_1000(int lhs, int rhs, int expd) {Tfds.Eq(expd, Decimal_adp_.divide_(lhs, rhs).Frac_1000());}
public void Test_comp_lt(int lhsNum, int lhsFrc, int rhs, boolean expd) {Tfds.Eq(expd, Decimal_adp_.parts_(lhsNum, lhsFrc).Comp_lt(rhs));}
public void Test_to_str_fmt(int l, int r, String fmt, String expd) {Tfds.Eq(expd, Decimal_adp_.divide_(l, r).To_str(fmt));}
public void Test_round(String raw, int places, String expd) {Tfds.Eq_str(expd, Decimal_adp_.parse(raw).Round(places).To_str(), "round");}
}
package gplx;
import org.junit.*;
public class Decimal_adp__tst {
private final Decimal_adp__fxt fxt = new Decimal_adp__fxt();
@Test public void divide_() {
fxt.Test_divide(1, 1000, "0.001");
fxt.Test_divide(1, 3, "0.33333333333333");
fxt.Test_divide(1, 7, "0.14285714285714");
}
@Test public void base1000_() {
fxt.Test_base_1000(1000, "1");
fxt.Test_base_1000(1234, "1.234");
fxt.Test_base_1000(123, "0.123");
}
@Test public void parts_() {
fxt.Test_parts(1, 0, "1");
fxt.Test_parts(1, 2, "1.2");
fxt.Test_parts(1, 23, "1.23");
fxt.Test_parts(123, 4567, "123.4567");
}
@Test public void parse() {
fxt.Test_parse("1", "1");
fxt.Test_parse("1.2", "1.2");
fxt.Test_parse("0.1", "0.1");
fxt.Test_parse("1.2E1", "12");
fxt.Test_parse("1.2e1", "12"); // 2020-08-27|ISSUE#:565|Parse 'e' as 'E'; PAGE:en.w:Huntington_Plaza
}
@Test public void parse_dot() {
fxt.Test_parse(".", "0"); // 2021-02-13|ISSUE#:838|Parse '.' as '0.'; PAGE:en.w:2019_FIVB_Volleyball_Women%27s_Challenger_Cup#Pool_A
}
@Test public void Truncate_decimal() {
fxt.Test_truncate_decimal("1", "1");
fxt.Test_truncate_decimal("1.1", "1");
fxt.Test_truncate_decimal("1.9", "1");
}
@Test public void Fraction1000() {
fxt.Test_frac_1000(1, 1000, 1); // 0.001
fxt.Test_frac_1000(1, 3, 333); // 0.33333333
fxt.Test_frac_1000(1234, 1000, 234); // 1.234
fxt.Test_frac_1000(12345, 10000, 234); // 1.2345
}
@Test public void Lt() {
fxt.Test_comp_lt(1,123, 2, true);
fxt.Test_comp_lt(1,99999999, 2, true);
}
@Test public void To_str_fmt() {
fxt.Test_to_str_fmt(1, 2, "0.0", "0.5");
fxt.Test_to_str_fmt(1, 3, "0.0", "0.3");
fxt.Test_to_str_fmt(10000, 7, "0,000.000", "1,428.571");
fxt.Test_to_str_fmt(1, 2, "00.00", "00.50");
}
@Test public void Round() {
fxt.Test_round("123.456", 3, "123.456");
fxt.Test_round("123.456", 2, "123.46");
fxt.Test_round("123.456", 1, "123.5");
fxt.Test_round("123.456", 0, "123");
fxt.Test_round("123.456", -1, "120");
fxt.Test_round("123.456", -2, "100");
fxt.Test_round("123.456", -3, "0");
fxt.Test_round("6", -1, "10");
fxt.Test_round("5", -1, "10");
fxt.Test_round("6", -2, "0");
}
}
class Decimal_adp__fxt {
public void Test_divide(int lhs, int rhs, String expd) {Tfds.Eq(expd, Decimal_adp_.divide_(lhs, rhs).To_str());}
public void Test_base_1000(int val, String expd) {Tfds.Eq(expd, Decimal_adp_.base1000_(val).To_str());}
public void Test_parts(int num, int fracs, String expd) {Tfds.Eq(expd, Decimal_adp_.parts_(num, fracs).To_str());}
public void Test_parse(String raw, String expd) {Tfds.Eq(expd, Decimal_adp_.parse(raw).To_str());}
public void Test_truncate_decimal(String raw, String expd) {Tfds.Eq(Decimal_adp_.parse(expd).To_str(), Decimal_adp_.parse(raw).Truncate().To_str());}
public void Test_frac_1000(int lhs, int rhs, int expd) {Tfds.Eq(expd, Decimal_adp_.divide_(lhs, rhs).Frac_1000());}
public void Test_comp_lt(int lhsNum, int lhsFrc, int rhs, boolean expd) {Tfds.Eq(expd, Decimal_adp_.parts_(lhsNum, lhsFrc).Comp_lt(rhs));}
public void Test_to_str_fmt(int l, int r, String fmt, String expd) {Tfds.Eq(expd, Decimal_adp_.divide_(l, r).To_str(fmt));}
public void Test_round(String raw, int places, String expd) {Tfds.Eq_str(expd, Decimal_adp_.parse(raw).Round(places).To_str(), "round");}
}

View File

@ -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,40 +13,43 @@ 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;
package gplx;
public class Double_ {
public static final String Cls_val_name = "double";
public static final Class<?> Cls_ref_type = Double.class;
public static final double
MinValue = Double.MIN_VALUE
, NaN = Double.NaN
, Inf_pos = Double.POSITIVE_INFINITY
;
public static final byte[]
NaN_bry = Bry_.new_a7("NaN")
, Inf_pos_bry = Bry_.new_a7("INF")
;
public static boolean IsNaN(double v) {return Double.isNaN(v);}
public static double cast(Object o) {try {return (Double)o;} catch(Exception e) {throw Err_.new_type_mismatch_w_exc(e, double.class, o);}}
public static double parse(String raw) {try {return Double.parseDouble(raw);} catch(Exception e) {throw Err_.new_parse_exc(e, double.class, raw);}}
public static double parse_or(String raw, double v) {try {return Double.parseDouble(raw);} catch(Exception e) {Err_.Noop(e); return v;}}
public static double coerce_(Object v) {
try {String s = String_.as_(v); return s == null ? Double_.cast(v) : Double_.parse(s);}
catch (Exception e) {throw Err_.new_cast(e, double.class, v);}
}
public static String To_str(double v) {
int v_int = (int)v;
return v - v_int == 0 ? Int_.To_str(v_int) : Double.toString(v);
}
public static String To_str_loose(double v) {
int v_as_int = (int)v;
return v == v_as_int
? Int_.To_str(v_as_int) // convert to int, and call print String to eliminate any trailing decimal places
: Float_.To_str((float)v); // calling ((float)v).toString is better at removing trailing 0s than String.format("%g", v). note that .net .toString() handles it better; EX:2449.600000000000d; DATE:2014-07-29
}
public static int Compare(double lhs, double rhs) {
if (lhs == rhs) return CompareAble_.Same;
else if (lhs < rhs) return CompareAble_.Less;
else return CompareAble_.More;
}
}
public static final String Cls_val_name = "double";
public static final Class<?> Cls_ref_type = Double.class;
public static final double
MinValue = Double.MIN_VALUE
, NaN = Double.NaN
, Inf_pos = Double.POSITIVE_INFINITY
;
public static final byte[]
NaN_bry = Bry_.new_a7("NaN")
, Inf_pos_bry = Bry_.new_a7("INF")
;
public static boolean IsNaN(double v) {return Double.isNaN(v);}
public static double cast(Object o) {try {return (Double)o;} catch(Exception e) {throw Err_.new_type_mismatch_w_exc(e, double.class, o);}}
public static double parse(String raw) {try {return Double.parseDouble(raw);} catch(Exception e) {throw Err_.new_parse_exc(e, double.class, raw);}}
public static double parse_or(String raw, double v) {try {return Double.parseDouble(raw);} catch(Exception e) {Err_.Noop(e); return v;}}
public static double coerce_(Object v) {
try {String s = String_.as_(v); return s == null ? Double_.cast(v) : Double_.parse(s);}
catch (Exception e) {throw Err_.new_cast(e, double.class, v);}
}
public static String To_str(double v) {
int v_int = (int)v;
return v - v_int == 0 ? Int_.To_str(v_int) : Double.toString(v);
}
public static String To_str_loose(double v) {
int v_as_int = (int)v;
return v == v_as_int
? Int_.To_str(v_as_int) // convert to int, and call print String to eliminate any trailing decimal places
// DATE:2014-07-29; calling ((float)v).toString is better at removing trailing 0s than String.format("%g", v). note that .net .toString() handles it better; EX:2449.600000000000d
// DATE:2020-08-12; calling ToStrByPrintF b/c better at removing trailing 0s; ISSUE#:697;
: gplx.objects.primitives.Double_.ToStrByPrintF(v);
}
public static int Compare(double lhs, double rhs) {
if (lhs == rhs) return CompareAble_.Same;
else if (lhs < rhs) return CompareAble_.Less;
else return CompareAble_.More;
}
}

View File

@ -28,6 +28,7 @@ public class Int_ {
, Null = Int_.Min_value
, Base1 = 1 // for super 1 lists / arrays; EX: PHP; [a, b, c]; [1] => a
, Offset_1 = 1 // common symbol for + 1 after current pos; EX: String_.Mid(lhs + Offset_1, rhs)
, Zero = 0
;
public static int Cast(Object obj) {

View File

@ -13,18 +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;
import org.junit.*; import gplx.core.tests.*; import gplx.core.envs.*;
public class Io_url__tst {
@Before public void init() {fxt.Clear();} private final Io_url__fxt fxt = new Io_url__fxt();
@Test public void Basic__lnx() {fxt.Test__New__http_or_null(Bool_.N, "file:///C:/a.txt", "C:/a.txt");}
@Test public void Basic__wnt() {fxt.Test__New__http_or_null(Bool_.Y, "file:///C:/a.txt", "C:\\a.txt");}
@Test public void Null() {fxt.Test__New__http_or_null(Bool_.N, "C:/a.txt", null);}
}
class Io_url__fxt {
public void Clear() {Io_mgr.Instance.InitEngine_mem();}
public void Test__New__http_or_null(boolean os_is_wnt, String raw, String expd) {
Op_sys.Cur_(os_is_wnt ? Op_sys.Tid_wnt : Op_sys.Tid_lnx);
Gftest.Eq__obj_or_null(expd, Io_url_.New__http_or_null(raw));
}
}
package gplx;
import org.junit.*; import gplx.core.tests.*; import gplx.core.envs.*;
public class Io_url__tst {
@Before public void init() {fxt.Clear();} private final Io_url__fxt fxt = new Io_url__fxt();
@Test public void Basic__lnx() {fxt.Test__New__http_or_null(Bool_.N, "file:///C:/a.txt", "C:/a.txt");}
@Test public void Basic__wnt() {fxt.Test__New__http_or_null(Bool_.Y, "file:///C:/a.txt", "C:\\a.txt");}
@Test public void Null() {fxt.Test__New__http_or_null(Bool_.N, "C:/a.txt", null);}
}
class Io_url__fxt {
public void Clear() {Io_mgr.Instance.InitEngine_mem();}
public void Test__New__http_or_null(boolean os_is_wnt, String raw, String expd) {
int curTid = Op_sys.Cur().Tid();
Op_sys.Cur_(os_is_wnt ? Op_sys.Tid_wnt : Op_sys.Tid_lnx);
Gftest.Eq__obj_or_null(expd, Io_url_.New__http_or_null(raw));
Op_sys.Cur_(curTid);
}
}

View File

@ -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,44 +13,50 @@ 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;
public class Type_ {//RF:2017-10-08
public static Class<?> Type_by_obj(Object o) {return o.getClass();}
public static Class<?> Type_by_primitive(Object o) {
Class<?> rv = o.getClass();
if (rv == Integer.class) rv = int.class;
else if (rv == Long.class) rv = long.class;
else if (rv == Byte.class) rv = byte.class;
else if (rv == Short.class) rv = short.class;
return rv;
}
public static boolean Eq_by_obj(Object lhs_obj, Class<?> rhs_type) {
Class<?> lhs_type = lhs_obj == null ? null : lhs_obj.getClass();
return Type_.Eq(lhs_type, rhs_type);
}
public static boolean Eq(Class<?> lhs, Class<?> rhs) {// DUPE_FOR_TRACKING: same as Object_.Eq
if (lhs == null && rhs == null) return true;
else if (lhs == null || rhs == null) return false;
else return lhs.equals(rhs);
}
public static String Canonical_name_by_obj(Object o) {return Canonical_name(o.getClass());}
public static String Canonical_name(Class<?> type) {
return type.getCanonicalName();
}
public static String Name_by_obj(Object obj) {return obj == null ? String_.Null_mark : Name(Type_by_obj(obj));}
public static String Name(Class<?> type) {
return type.getName();
}
public static boolean Is_array(Class<?> t) {
return t.isArray();
}
public static boolean Is_assignable_from_by_obj(Object o, Class<?> generic) {return o == null ? false : Is_assignable_from(generic, o.getClass());}
public static boolean Is_assignable_from(Class<?> generic, Class<?> specific) {
return generic.isAssignableFrom(specific);
}
}
package gplx;
public class Type_ {//RF:2017-10-08
public static Class<?> Type_by_obj(Object o) {return o.getClass();}
public static Class<?> Type_by_primitive(Object o) {
Class<?> rv = o.getClass();
if (rv == Integer.class) rv = int.class;
else if (rv == Long.class) rv = long.class;
else if (rv == Byte.class) rv = byte.class;
else if (rv == Short.class) rv = short.class;
return rv;
}
public static boolean Eq_by_obj(Object lhs_obj, Class<?> rhs_type) {
Class<?> lhs_type = lhs_obj == null ? null : lhs_obj.getClass();
return Type_.Eq(lhs_type, rhs_type);
}
public static boolean Eq(Class<?> lhs, Class<?> rhs) {// DUPE_FOR_TRACKING: same as Object_.Eq
if (lhs == null && rhs == null) return true;
else if (lhs == null || rhs == null) return false;
else return lhs.equals(rhs);
}
public static String Canonical_name_by_obj(Object o) {return Canonical_name(o.getClass());}
public static String Canonical_name(Class<?> type) {
return type.getCanonicalName();
}
public static String Name_by_obj(Object obj) {return obj == null ? String_.Null_mark : Name(Type_by_obj(obj));}
public static String Name(Class<?> type) {
return type.getName();
}
public static String SimpleName_by_obj(Object obj) {return obj == null ? String_.Null_mark : SimpleName(Type_by_obj(obj));}
public static String SimpleName(Class<?> type) {
return type.getSimpleName();
}
public static boolean Is_array(Class<?> t) {
return t.isArray();
}
public static boolean Is_assignable_from_by_obj(Object o, Class<?> generic) {return o == null ? false : Is_assignable_from(generic, o.getClass());}
public static boolean Is_assignable_from(Class<?> generic, Class<?> specific) {
return generic.isAssignableFrom(specific);
}
}

View File

@ -0,0 +1,25 @@
/*
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.core.primitives;
import gplx.Object_;
public class ObjectWrapperRef {
public ObjectWrapperRef() {}
public Object Val() {return val;} public ObjectWrapperRef Val_(Object v) {val = v; return this;} private Object val;
public ObjectWrapperRef Val_null_() {return Val_(null);}
@Override public String toString() {return Object_.Xto_str_strict_or_null(val);}
}

View File

@ -0,0 +1,17 @@
/*
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.core.tests;
public @interface GfoTestMethod {}

View File

@ -1,18 +1,18 @@
/*
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
*/
/*
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.core.tests; import gplx.*; import gplx.core.*;
import gplx.core.brys.*;
public class Gftest {
@ -112,6 +112,7 @@ public class Gftest {
bfr.Add(Bry__line_end);
throw Err_.new_wo_type(bfr.To_str_and_clear());
}
public static void Eq__bool_n(boolean actl) {Eq__bool(Bool_.N, actl, null);}
public static void Eq__bool_y(boolean actl) {Eq__bool(Bool_.Y, actl, null);}
public static void Eq__bool_y(boolean actl, String msg_fmt, Object... msg_args) {Eq__bool(Bool_.Y, actl, msg_fmt, msg_args);}
public static void Eq__bool(boolean expd, boolean actl) {Eq__bool(expd, actl, null);}

View File

@ -1,18 +1,18 @@
/*
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
*/
/*
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.core.texts; import gplx.*; import gplx.core.*;
public class Base64Converter {
private final static char[] ALPHABET = String_.XtoCharAry("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
@ -22,6 +22,11 @@ public class Base64Converter {
for(int i=0; i< ALPHABET.length; i++){
toInt[ALPHABET[i]]= i;
}
}
public static char GetIndexChar(int i) {return ALPHABET[i];}
public static int GetIndexInt(char c) {
if (toInt == null) Init();
return toInt[c];
}
public static String EncodeString(String orig) {return Encode(Bry_.new_u8(orig));}
public static String Encode(byte[] buf){

View File

@ -1,23 +1,32 @@
/*
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.core.threads; import gplx.*; import gplx.core.*;
import java.lang.*;
/*
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.core.threads;
import gplx.Cancelable;
import gplx.Cancelable_;
import gplx.Err_;
import gplx.GfoMsg;
import gplx.GfoMsg_;
import gplx.Gfo_invk;
import gplx.Gfo_invk_;
import gplx.Gfo_log_;
public class Thread_adp implements Runnable {
private final String thread_name; private final Cancelable cxl; private final boolean cxlable;
private final Gfo_invk invk_itm; private final String invk_cmd; private final GfoMsg invk_msg;
private final String thread_name; private final Cancelable cxl; private final boolean cxlable;
private final Gfo_invk invk_itm; private final String invk_cmd; private final GfoMsg invk_msg;
private Thread thread;
@gplx.Internal protected Thread_adp(String thread_name, Cancelable cxl, Gfo_invk invk_itm, String invk_cmd, GfoMsg invk_msg) {
this.thread_name = thread_name; this.cxl = cxl; this.cxlable = cxl != Cancelable_.Never;
@ -28,6 +37,7 @@ public class Thread_adp implements Runnable {
public boolean Thread__cancelable() {return cxlable;}
public boolean Thread__is_alive() {return thread == null ? false : thread.isAlive();}
public void Thread__interrupt() {thread.interrupt();}
public void Thread__stop() {thread.stop();}
public void run() {
try {
Gfo_invk_.Invk_by_msg(invk_itm, invk_cmd, invk_msg);
@ -37,8 +47,8 @@ public class Thread_adp implements Runnable {
}
}
public void Thread__start() {
this.thread = (thread_name == null) ? new Thread(this) : new Thread(this, thread_name);
this.thread = (thread_name == null) ? new Thread(this) : new Thread(this, thread_name);
thread.start();
}
public static final Thread_adp Noop = new Thread_adp(Thread_adp_.Name_null, Cancelable_.Never, Gfo_invk_.Noop, "", GfoMsg_.Null);
}
public static final Thread_adp Noop = new Thread_adp(Thread_adp_.Name_null, Cancelable_.Never, Gfo_invk_.Noop, "", GfoMsg_.Null);
}

View File

@ -1,28 +1,36 @@
/*
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.core.threads; import gplx.*; import gplx.core.*;
/*
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.core.threads;
import gplx.Cancelable;
import gplx.Cancelable_;
import gplx.Err_;
import gplx.GfoMsg;
import gplx.GfoMsg_;
import gplx.Gfo_invk;
public class Thread_adp_ {
public static void Sleep(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
throw Err_.new_exc(e, "core", "thread interrupted", "milliseconds", milliseconds);
}
}
}
public static Thread_adp Start_by_key(String thread_name, Gfo_invk invk_itm, String invk_cmd) {return Start(thread_name, Cancelable_.Never, invk_itm, invk_cmd , GfoMsg_.new_cast_(invk_cmd));}
public static Thread_adp Start_by_key(String thread_name, Gfo_invk invk_itm, String invk_cmd) {return Start(thread_name, Cancelable_.Never, invk_itm, invk_cmd , GfoMsg_.new_cast_(invk_cmd));}
public static Thread_adp Start_by_val(String thread_name, Gfo_invk invk_itm, String invk_cmd, Object val) {return Start(thread_name, Cancelable_.Never, invk_itm, invk_cmd , GfoMsg_.new_cast_(invk_cmd).Add("v", val));}
public static Thread_adp Start_by_msg(String thread_name, Gfo_invk invk_itm, GfoMsg invk_msg) {return Start(thread_name, Cancelable_.Never, invk_itm, invk_msg.Key() , invk_msg);}
public static Thread_adp Start_by_key(String thread_name, Cancelable cxl, Gfo_invk invk_itm, String invk_cmd) {return Start(thread_name, cxl, invk_itm, invk_cmd , GfoMsg_.new_cast_(invk_cmd));}

View File

@ -0,0 +1,78 @@
package gplx.core.tooling.asserts;
import gplx.core.tests.Gftest;
import gplx.core.tooling.dataCollectors.GfoDataCollectorGrp;
import gplx.core.tooling.dataCollectors.GfoDataCollectorMgr;
import gplx.langs.java.util.List_;
import java.util.List;
public interface TestAssert {
void Test(GfoDataCollectorGrp actlItm);
void NotePrepend(String s);
static void Test(String note, GfoDataCollectorMgr mgr, TestAssert.Grp[] itms) {
for (TestAssert.Grp itm : itms) {
itm.NotePrepend(note);
itm.Test(mgr.GetGrp(itm.Key()));
}
}
class Grp implements TestAssert {
private String key;
private TestAssert[] rules;
public Grp(String key, TestAssert... rules) {
this.key = key;
this.rules = rules;
}
public String Key() {return key;}
public void NotePrepend(String s) {
note = s;
for (TestAssert rule : rules) {
rule.NotePrepend(s);
}
} private String note;
public void Test(GfoDataCollectorGrp grp) {
for (TestAssert rule : rules) {
rule.Test(grp);
}
}
}
class StringEq implements TestAssert {
private String key;
private String expdVal;
public StringEq(String key, String expd) {
this.key = key;
this.expdVal = expd;
}
public void NotePrepend(String s) {note = s + "." + key;} private String note;
public void Test(GfoDataCollectorGrp grp) {
String actlVal = (String)grp.Get(key);
Gftest.Eq__str(expdVal, actlVal, note);
}
}
class StringHas implements TestAssert {
private String key;
private String expdVal;
public StringHas(String key, String expd) {
this.key = key;
this.expdVal = expd;
}
public void NotePrepend(String s) {note = s + "." + key;} private String note;
public void Test(GfoDataCollectorGrp grp) {
String actlVal = (String)grp.Get(key);
Gftest.Eq__bool_y(actlVal.contains(expdVal), note);
}
}
class ListEq implements TestAssert {
private String key;
private List<?> expdList;
public ListEq(String key, Object... expd) {
this.key = key;
this.expdList = List_.NewByAry(expd);
}
public void NotePrepend(String s) {note = s + "." + key;} private String note;
public void Test(GfoDataCollectorGrp grp) {
List<?> actlList = (List<?>)grp.Get(key);
Gftest.Eq__ary(expdList.toArray(), actlList.toArray(), note);
}
}
}

View File

@ -0,0 +1,24 @@
package gplx.core.tooling.dataCollectors;
import java.util.LinkedHashMap;
import java.util.List;
public class GfoDataCollectorGrp {
private final String key;
private final LinkedHashMap<String, Object> hash = new LinkedHashMap<>();
public GfoDataCollectorGrp(String key) {
this.key = key;
}
public String Key() {return key;}
public GfoDataCollectorGrp Add(String dataKey, String dataVal) {
hash.put(dataKey, dataVal);
return this;
}
public GfoDataCollectorGrp Add(String dataKey, List<?> dataVal) {
hash.put(dataKey, dataVal);
return this;
}
public Object Get(String dataKey) {
return hash.get(dataKey);
}
}

View File

@ -0,0 +1,13 @@
package gplx.core.tooling.dataCollectors;
import java.util.LinkedHashMap;
public class GfoDataCollectorMgr {
private final LinkedHashMap<String, GfoDataCollectorGrp> hash = new LinkedHashMap<>();
public GfoDataCollectorGrp GetGrp(String grpKey) {return hash.get(grpKey);}
public GfoDataCollectorGrp AddGrp(String grpKey) {
GfoDataCollectorGrp grp = new GfoDataCollectorGrp(grpKey);
hash.put(grpKey, grp);
return grp;
}
}

View File

@ -0,0 +1,13 @@
package gplx.langs.java.util;
import java.util.ArrayList;
import java.util.List;
public class List_ {
public static List<Object> NewByAry(Object[] ary) {
List<Object> rv = new ArrayList<>();
for (Object o : ary)
rv.add(o);
return rv;
}
}

View File

@ -1,31 +1,61 @@
/*
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.dbs; import gplx.*;
import gplx.core.stores.*; import gplx.dbs.metas.*; import gplx.dbs.engines.*; import gplx.dbs.qrys.*; import gplx.dbs.sys.*; import gplx.dbs.conn_props.*; import gplx.dbs.qrys.bats.*;
/*
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.dbs;
import gplx.Bool_;
import gplx.Double_;
import gplx.Err_;
import gplx.Gfo_log_;
import gplx.Gfo_usr_dlg;
import gplx.Gfo_usr_dlg_;
import gplx.Int_;
import gplx.Io_url;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.Rls_able;
import gplx.String_;
import gplx.core.stores.DataRdr;
import gplx.core.stores.DataRdr_;
import gplx.dbs.conn_props.Db_conn_props_mgr;
import gplx.dbs.engines.Db_engine;
import gplx.dbs.metas.Dbmeta_idx_fld;
import gplx.dbs.metas.Dbmeta_tbl_mgr;
import gplx.dbs.qrys.Db_qry__select_in_tbl;
import gplx.dbs.qrys.Db_qry_delete;
import gplx.dbs.qrys.Db_qry_insert;
import gplx.dbs.qrys.Db_qry_sql;
import gplx.dbs.qrys.Db_qry_update;
import gplx.dbs.qrys.bats.Db_batch_mgr;
import gplx.dbs.sys.Db_sys_mgr;
import gplx.dbs.wkrs.SqlWkrMgr;
public class Db_conn {
private final List_adp rls_list = List_adp_.New();
public Db_conn(Db_engine engine) {
this.engine = engine;
this.sys_mgr = new Db_sys_mgr(this);
this.wkrMgr = new SqlWkrMgr(this);
engine.CtorConn(wkrMgr);
}
public Db_conn_info Conn_info() {return engine.Conn_info();}
public Db_conn_props_mgr Props() {return engine.Props();}
public Db_batch_mgr Batch_mgr() {return engine.Batch_mgr();}
public Db_engine Engine() {return engine;} private final Db_engine engine;
public Db_sys_mgr Sys_mgr() {return sys_mgr;} private final Db_sys_mgr sys_mgr; // autonum and other functions
public Db_engine Engine() {return engine;} private final Db_engine engine;
public Db_sys_mgr Sys_mgr() {return sys_mgr;} private final Db_sys_mgr sys_mgr; // autonum and other functions
public SqlWkrMgr WkrMgr() {return wkrMgr;} private final SqlWkrMgr wkrMgr;
public boolean Eq(Db_conn comp) {return String_.Eq(engine.Conn_info().Db_api(), comp.Conn_info().Db_api());}
public void Txn_bgn(String name) {engine.Txn_bgn(name);}
public void Txn_end() {engine.Txn_end();}

View File

@ -1,18 +1,18 @@
/*
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
*/
/*
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.dbs; import gplx.*;
import gplx.core.criterias.*;
public class Db_crt_ {
@ -28,6 +28,7 @@ public class Db_crt_ {
public static Criteria_fld New_between (String key, Comparable lo, Comparable hi) {return Criteria_fld.new_(key, Criteria_.between_(lo, hi));}
public static Criteria_fld New_in (String key, Object... vals) {return Criteria_fld.new_(key, Criteria_.in_(vals));}
public static Criteria_fld New_like (String key, String pattern) {return Criteria_fld.new_(key, Criteria_.like_(pattern));}
public static Criteria_fld New_like_not (String key, String pattern) {return Criteria_fld.new_(key, Criteria_.Not(Criteria_.like_(pattern)));}
public static Criteria eq_many_(String... ary) {
Criteria rv = null;

View File

@ -1,26 +1,44 @@
/*
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.dbs.engines; import gplx.*; import gplx.dbs.*;
import gplx.core.stores.*; import gplx.dbs.metas.*; import gplx.dbs.sqls.*; import gplx.dbs.conn_props.*; import gplx.dbs.qrys.bats.*;
/*
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.dbs.engines;
import gplx.Gfo_usr_dlg;
import gplx.Io_url;
import gplx.core.stores.DataRdr;
import gplx.dbs.Db_conn;
import gplx.dbs.Db_conn_info;
import gplx.dbs.Db_qry;
import gplx.dbs.Db_rdr;
import gplx.dbs.Db_stmt;
import gplx.dbs.Dbmeta_fld_itm;
import gplx.dbs.Dbmeta_idx_itm;
import gplx.dbs.Dbmeta_tbl_itm;
import gplx.dbs.conn_props.Db_conn_props_mgr;
import gplx.dbs.metas.Dbmeta_tbl_mgr;
import gplx.dbs.qrys.bats.Db_batch_mgr;
import gplx.dbs.sqls.Sql_qry_wtr;
import gplx.dbs.wkrs.SqlWkrMgr;
public interface Db_engine {
String Tid();
Db_conn_info Conn_info();
Db_conn_props_mgr Props();
Db_batch_mgr Batch_mgr();
Sql_qry_wtr Sql_wtr();
void CtorConn(SqlWkrMgr wkrMgr);
Db_engine New_clone(Db_conn_info conn_info);
void Conn_open();
void Conn_term();

View File

@ -1,20 +1,22 @@
/*
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
*/
/*
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.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*; import gplx.dbs.metas.*; import gplx.dbs.sqls.*; import gplx.dbs.conn_props.*; import gplx.dbs.qrys.bats.*;
import gplx.dbs.wkrs.SqlWkrMgr;
public class Mem_engine implements Db_engine {
private final Hash_adp tbl_hash = Hash_adp_.New();
Mem_engine(Db_conn_info conn_info) {
@ -27,6 +29,7 @@ public class Mem_engine implements Db_engine {
public Db_batch_mgr Batch_mgr() {return batch_mgr;} private final Db_batch_mgr batch_mgr = new Db_batch_mgr();
public Mem_exec_select Qry_runner() {return qry_runner;} private Mem_exec_select qry_runner;
public Sql_qry_wtr Sql_wtr() {return sql_wtr;} private final Sql_qry_wtr sql_wtr = Sql_qry_wtr_.New__basic();
@Override public void CtorConn(SqlWkrMgr wkrMgr) {}
public Db_engine New_clone(Db_conn_info conn_info) {return new Mem_engine(conn_info);}
public Db_stmt Stmt_by_qry(Db_qry qry) {return new Mem_stmt(this, qry);}
public Mem_tbl Tbls__get(String name) {return (Mem_tbl)tbl_hash.Get_by(name);}

View File

@ -1,24 +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
*/
/*
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.dbs.engines.mysql; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*; import gplx.dbs.engines.*; import gplx.dbs.sqls.*; import gplx.dbs.metas.*;
import java.sql.*;
public class Mysql_engine extends Db_engine_sql_base {
import gplx.dbs.wkrs.SqlWkrMgr;
import java.sql.*;
public class Mysql_engine extends Db_engine_sql_base {
@Override public String Tid() {return Mysql_conn_info.Tid_const;}
@Override public Sql_qry_wtr Sql_wtr() {return Sql_qry_wtr_.New__mysql();}
@Override public void CtorConn(SqlWkrMgr wkrMgr) {}
@Override public Db_engine New_clone(Db_conn_info connectInfo) {
Mysql_engine rv = new Mysql_engine();
rv.Ctor(connectInfo);
@ -33,7 +36,7 @@ public class Mysql_engine extends Db_engine_sql_base {
}
public static final Mysql_engine Instance = new Mysql_engine(); Mysql_engine() {}
}
class Mysql_rdr extends Db_data_rdr {
class Mysql_rdr extends Db_data_rdr {
//PATCH:MYSQL:byte actually returned as int by Jdbc ResultSet (or MYSQL impmentation); convert to byte
@Override public byte ReadByte(String key) {return ReadByteOr(key, Byte.MAX_VALUE);}
@Override public byte ReadByteOr(String key, byte or) {

View File

@ -1,26 +1,29 @@
/*
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
*/
/*
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.dbs.engines.noops; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*; import gplx.dbs.metas.*; import gplx.dbs.sqls.*; import gplx.dbs.conn_props.*; import gplx.dbs.qrys.bats.*;
import gplx.dbs.wkrs.SqlWkrMgr;
public class Noop_engine implements Db_engine {
public String Tid() {return Noop_conn_info.Tid_const;}
public Db_conn_info Conn_info() {return Db_conn_info_.Null;}
public Db_conn_props_mgr Props() {return props;} private final Db_conn_props_mgr props = new Db_conn_props_mgr();
public Db_batch_mgr Batch_mgr() {return batch_mgr;} private final Db_batch_mgr batch_mgr = new Db_batch_mgr();
public Sql_qry_wtr Sql_wtr() {return sql_wtr;} private final Sql_qry_wtr sql_wtr = Sql_qry_wtr_.New__basic();
@Override public void CtorConn(SqlWkrMgr wkrMgr) {}
public void Conn_open() {}
public void Conn_term() {}
public Db_engine New_clone(Db_conn_info url) {return this;}

View File

@ -1,24 +1,29 @@
/*
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
*/
/*
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.dbs.engines.postgres; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*; import gplx.dbs.engines.*; import gplx.dbs.sqls.*; import gplx.dbs.metas.*;
import java.sql.*;
import gplx.dbs.wkrs.SqlWkrMgr;
import java.sql.Connection;
import java.sql.ResultSet;
public class Postgres_engine extends Db_engine_sql_base {
@Override public String Tid() {return Postgres_conn_info.Tid_const;}
@Override public Sql_qry_wtr Sql_wtr() {return Sql_qry_wtr_.New__mysql();}
@Override public void CtorConn(SqlWkrMgr wkrMgr) {}
@Override public Db_engine New_clone(Db_conn_info connectInfo) {
Postgres_engine rv = new Postgres_engine();
rv.Ctor(connectInfo);

View File

@ -1,18 +1,18 @@
/*
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
*/
/*
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.dbs.engines.sqlite; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import java.sql.*;
import gplx.core.stores.*; import gplx.dbs.engines.*; import gplx.dbs.engines.sqlite.*; import gplx.dbs.metas.*; import gplx.dbs.sqls.*;
@ -21,6 +21,8 @@ import gplx.core.consoles.Console_adp_;
import gplx.core.consoles.Console_adp__sys;
import gplx.core.ios.IoItmFil;
import gplx.dbs.wkrs.SqlWkrMgr;
import gplx.dbs.wkrs.randoms.SqliteRandomWkr;
import org.sqlite.SQLiteConnection;
public class Sqlite_engine extends Db_engine_sql_base {
private final Sqlite_txn_mgr txn_mgr; private final Sqlite_schema_mgr schema_mgr;
@ -30,6 +32,10 @@ public class Sqlite_engine extends Db_engine_sql_base {
}
@Override public String Tid() {return Sqlite_conn_info.Key_const;}
@Override public gplx.dbs.sqls.Sql_qry_wtr Sql_wtr() {return Sql_qry_wtr_.New__sqlite();}
public void CtorConn(SqlWkrMgr wkrMgr) {
wkrMgr.Set(new SqliteRandomWkr());
}
@Override public Db_engine New_clone(Db_conn_info connectInfo) {
Sqlite_engine rv = new Sqlite_engine();
rv.Ctor(connectInfo);
@ -89,7 +95,7 @@ public class Sqlite_engine extends Db_engine_sql_base {
catch (SQLException e) {Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to set busy timeout; err=~{0}", Err_.Message_gplx_log(e));}
return rv;
}
public static final Sqlite_engine Instance = new Sqlite_engine();
public static final Sqlite_engine Instance = new Sqlite_engine();
}
class Db_rdr__sqlite extends Db_rdr__basic { @Override public byte Read_byte(String k) {try {return (byte)Int_.Cast(rdr.getObject(k));} catch (Exception e) {throw Err_.new_exc(e, "db", "read failed", "k", k, "type", Byte_.Cls_val_name);}}
@Override public boolean Read_bool_by_byte(String k) {

View File

@ -1,20 +1,22 @@
/*
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
*/
/*
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.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*; import gplx.dbs.metas.*; import gplx.dbs.conn_props.*; import gplx.dbs.qrys.*; import gplx.dbs.sqls.*; import gplx.dbs.qrys.bats.*;
import gplx.dbs.wkrs.SqlWkrMgr;
public class TdbEngine implements Db_engine {
public String Tid() {return Tdb_conn_info.Tid_const;}
public Db_conn_info Conn_info() {return conn_info;} private Db_conn_info conn_info;
@ -22,6 +24,7 @@ public class TdbEngine implements Db_engine {
public Db_batch_mgr Batch_mgr() {return batch_mgr;} private final Db_batch_mgr batch_mgr = new Db_batch_mgr();
public Sql_qry_wtr Sql_wtr() {return sql_wtr;} private final Sql_qry_wtr sql_wtr = Sql_qry_wtr_.New__basic();
public TdbDatabase Db() {return db;} TdbDatabase db;
@Override public void CtorConn(SqlWkrMgr wkrMgr) {}
public void Conn_open() {
Tdb_conn_info tdb_url = (Tdb_conn_info)conn_info;
String url_str = tdb_url.Server();

View File

@ -0,0 +1,20 @@
/*
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.dbs.wkrs;
public interface SqlWkr {
String Key();
}

View File

@ -0,0 +1,43 @@
/*
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.dbs.wkrs;
import gplx.dbs.Db_conn;
import gplx.dbs.wkrs.randoms.SqlRandomWkr;
import java.util.HashMap;
import java.util.Map;
public class SqlWkrMgr {
private final Map<String, SqlWkr> map = new HashMap<>();
private final Db_conn conn;
public SqlWkrMgr(Db_conn conn) {
this.conn = conn;
}
public SqlWkr Get(String key) {
return map.get(key);
}
public void Set(SqlWkr wkr) {
map.put(wkr.Key(), wkr);
}
public Object ExecRandomObj(String select, String from, String where) {
SqlRandomWkr wkr = (SqlRandomWkr)map.get(SqlWkrMgr.WKR_RANDOM);
return wkr.SelectRandomRow(conn, select, from, where)[0];
}
public static final String WKR_RANDOM = "random";
}

View File

@ -0,0 +1,23 @@
/*
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.dbs.wkrs.randoms;
import gplx.dbs.Db_conn;
import gplx.dbs.wkrs.SqlWkr;
public interface SqlRandomWkr extends SqlWkr {
Object[] SelectRandomRow(Db_conn conn, String select, String from, String where);
}

View File

@ -0,0 +1,60 @@
/*
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.dbs.wkrs.randoms;
import gplx.RandomAdp_;
import gplx.dbs.Db_conn;
import gplx.dbs.Db_rdr;
import gplx.dbs.Db_rdr_;
import gplx.dbs.wkrs.SqlWkrMgr;
public class SqliteRandomWkr implements SqlRandomWkr {
@Override public String Key() {return SqlWkrMgr.WKR_RANDOM;}
// NOTE: selects only 1 random row to simplify method signature
// * uses COUNT, LIMIT, OFFSET, so should also work for MySQL
// * to return many rows, look at https://stackoverflow.com/questions/4114940/select-random-rows-in-sqlite
// EX: SELECT * FROM table WHERE id IN (SELECT id FROM table ORDER BY RANDOM() LIMIT x)
// Also, note that SQLite does not support TYPE_FORWARD_ONLY so can't jump back and forth thru ResultSet
@Override public Object[] SelectRandomRow(Db_conn conn, String select, String from, String where) {
Db_rdr rdr = Db_rdr_.Empty;
try {
String sqlSuffix = ("FROM " + from + " WHERE " + where);
// get rowCount of resultSet
rdr = conn.Stmt_sql("SELECT COUNT(*) AS RowCount " + sqlSuffix).Exec_select__rls_auto();
int rowCount = rdr.Read_int("RowCount");
// get random row
int random = RandomAdp_.new_().Next(rowCount);
rdr = conn.Stmt_sql("SELECT " + select + " " + sqlSuffix + " LIMIT 1 OFFSET " + random).Exec_select__rls_auto();
// return result
int fldsLen = rdr.Fld_len();
Object[] rv = new Object[fldsLen];
for (int i = 0; i < fldsLen; i++) {
rv[i] = rdr.Read_at(i);
}
return rv;
}
catch (Exception exc) { // for debugging; should log
throw exc;
}
finally {
rdr.Rls();
}
}
}

View File

@ -0,0 +1,51 @@
/*
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.dbs.wkrs.randoms;
import gplx.dbs.Db_conn;
import gplx.dbs.wkrs.SqlWkrMgr;
import java.util.ArrayList;
import java.util.List;
public class TestRandomWkr implements SqlRandomWkr {
private final List<Object[]> list = new ArrayList<>();
private int index = 0;
public void AddRow(Object... ary) {
list.add(ary);
}
public void Clear() {
list.clear();
index = 0;
}
public String SelectRandomRowSelect() {return selectRandomRowSelect;} private String selectRandomRowSelect;
public String SelectRandomRowFrom() {return selectRandomRowFrom;} private String selectRandomRowFrom;
public String SelectRandomRowWhere() {return selectRandomRowWhere;} private String selectRandomRowWhere;
@Override public String Key() {return SqlWkrMgr.WKR_RANDOM;}
@Override public Object[] SelectRandomRow(Db_conn conn, String select, String from, String where) {
this.selectRandomRowSelect = select;
this.selectRandomRowFrom = from;
this.selectRandomRowWhere = where;
return list.get(index++);
}
public static TestRandomWkr New(Db_conn conn) {
TestRandomWkr wkr = new TestRandomWkr();
conn.WkrMgr().Set(wkr);
return wkr;
}
}

View File

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2021 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,301 +13,341 @@ 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.gfui.kits.swts; import gplx.*; import gplx.gfui.*; import gplx.gfui.kits.*;
import gplx.core.envs.System_;
import gplx.core.primitives.*;
import gplx.core.threads.Thread_adp_;
import gplx.gfui.controls.elems.GfuiElem;
import gplx.gfui.controls.gxws.GxwCbkHost;
import gplx.gfui.controls.gxws.GxwCore_base;
import gplx.gfui.controls.gxws.GxwElem;
import gplx.gfui.controls.gxws.Gxw_html;
import gplx.gfui.controls.gxws.Gxw_html_load_tid_;
import gplx.gfui.controls.standards.Gfui_html;
import gplx.gfui.controls.standards.Gfui_tab_mgr;
import gplx.gfui.draws.ColorAdp;
import gplx.gfui.draws.ColorAdp_;
import gplx.gfui.ipts.*;
import gplx.gfui.kits.core.Swt_kit;
import java.security.acl.Owner;
import gplx.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import java.security.acl.Owner;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
public class Swt_html implements Gxw_html, Swt_control, FocusListener, Gfo_evt_mgr_owner {
private Swt_html_lnr_location lnr_location; private Swt_html_lnr_status lnr_status;
public Swt_html(Swt_kit kit, Swt_control owner_control, Keyval_hash ctorArgs) {
this.kit = kit;
lnr_location = new Swt_html_lnr_location(this);
lnr_status = new Swt_html_lnr_status(this);
Object browser_tid_obj = ctorArgs.Get_val_or(Swt_kit.Cfg_Html_BrowserType, null);
this.browser_tid = browser_tid_obj == null ? Browser_tid_none : Int_.Cast(browser_tid_obj);
browser = new Browser(owner_control.Under_composite(), browser_tid);
core = new Swt_core_cmds_html(this, browser);
browser.addKeyListener(new Swt_lnr_key(this));
browser.addMouseListener(new Swt_html_lnr_mouse(this, browser, kit));
browser.addLocationListener(lnr_location);
browser.addProgressListener(new Swt_html_lnr_progress(this));
browser.addStatusTextListener(lnr_status);
browser.addFocusListener(this);
browser.addTitleListener(new Swt_html_lnr_title(this));
browser.addMouseWheelListener(new Swt_html_lnr_wheel(this));
// browser.addOpenWindowListener(new Swt_open_window_listener(this)); // handle target='blank'
// browser.addTraverseListener(new Swt_html_lnr_Traverse(this));
}
public Swt_kit Kit() {return kit;} private Swt_kit kit;
public Gfo_evt_mgr Evt_mgr() {return ev_mgr;} private Gfo_evt_mgr ev_mgr; public void Evt_mgr_(Gfo_evt_mgr v) {ev_mgr = v;}
@Override public Control Under_control() {return browser;} private Browser browser;
@Override public Composite Under_composite() {return null;}
@Override public Control Under_menu_control() {return browser;}
public int Browser_tid() {return browser_tid;} private final int browser_tid;
public String Load_by_url_path() {return load_by_url_path;} private String load_by_url_path;
public void Html_doc_html_load_by_mem(String html) {
this.html_doc_html_load_tid = Gxw_html_load_tid_.Tid_mem;
this.load_by_url_path = null;
browser.setText(html); // DBG: Io_mgr.I.SaveFilStr(Io_url_.new_fil_("C:\\temp.txt"), s)
}
public void Html_doc_html_load_by_url(Io_url path, String html) {
this.html_doc_html_load_tid = Gxw_html_load_tid_.Tid_url;
this.load_by_url_path = path.To_http_file_str();
Io_mgr.Instance.SaveFilStr(path, html);
browser.setUrl(path.Xto_api());
}
public byte Html_doc_html_load_tid() {return html_doc_html_load_tid;} private byte html_doc_html_load_tid;
public void Html_doc_html_load_tid_(byte v) {html_doc_html_load_tid = v;}
public void Html_js_enabled_(boolean v) {browser.setJavascriptEnabled(v);}
public void Html_js_cbks_add(String func_name, Gfo_invk invk) {new Swt_html_func(browser, func_name, invk);}
public String Html_js_eval_script(String script) {return Eval_script_as_str(script);}
public Object Html_js_eval_script_as_obj(String script) {return Eval_script(script);}
public boolean Html_js_eval_proc_as_bool(String proc, Object... args) {return Bool_.Cast(Html_js_eval_proc_as_obj(proc, args));}
public String Html_js_eval_proc_as_str(String proc, Object... args) {return Object_.Xto_str_strict_or_null(Html_js_eval_proc_as_obj(proc, args));}
public String Html_js_send_json(String name, String data) {
String script = String_.Format("return {0}('{1}');", name, String_.Replace(data, "\n", "") );
return (String)Eval_script(script);
}
private Object Html_js_eval_proc_as_obj(String proc, Object... args) {
Bry_bfr bfr = Bry_bfr_.New();
bfr.Add_str_a7("return ").Add_str_u8(proc).Add_byte(Byte_ascii.Paren_bgn);
int args_len = args.length;
for (int i = 0; i < args_len; ++i) {
Object arg = args[i];
if (i != 0) bfr.Add_byte(Byte_ascii.Comma);
boolean quote_val = true;
if ( Type_.Eq_by_obj(arg, Bool_.Cls_ref_type)
|| Type_.Eq_by_obj(arg, Int_.Cls_ref_type)
|| Type_.Eq_by_obj(arg, Long_.Cls_ref_type)
) {
quote_val = false;
}
if (quote_val) bfr.Add_byte(Byte_ascii.Apos);
if (quote_val)
bfr.Add_str_u8(Escape_quote(Object_.Xto_str_strict_or_null_mark(arg)));
else
bfr.Add_obj_strict(arg);
if (quote_val) bfr.Add_byte(Byte_ascii.Apos);
}
bfr.Add_byte(Byte_ascii.Paren_end).Add_byte(Byte_ascii.Semic);
return Eval_script(bfr.To_str_and_clear());
}
public static String Escape_quote(String v) {
String rv = v;
rv = String_.Replace(rv, "'", "\\'");
rv = String_.Replace(rv, "\"", "\\\"");
rv = String_.Replace(rv, "\n", "\\n");
return rv;
}
public void Html_invk_src_(Gfo_evt_itm invk) {lnr_location.Host_set(invk); lnr_status.Host_set(invk);}
public void Html_dispose() {
browser.dispose();
delete_owner.SubElems().DelOrFail(delete_cur); // NOTE: must delete cur from owner, else new tab will fail after closing one; DATE:2014-07-09
System_.Garbage_collect();
}
private GfuiElem delete_owner, delete_cur;
public void Delete_elems_(GfuiElem delete_owner, GfuiElem delete_cur) {this.delete_owner = delete_owner; this.delete_cur = delete_cur;} // HACK: set owner / cur so delete can work;
@Override public GxwCore_base Core() {return core;} private GxwCore_base core;
@Override public GxwCbkHost Host() {return host;} @Override public void Host_set(GxwCbkHost host) {this.host = host;} GxwCbkHost host;
@Override public String TextVal() {return browser.getText();}
@Override public void TextVal_set(String v) {browser.setText(v);}
@Override public void EnableDoubleBuffering() {}
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return Gfo_invk_.Rv_unhandled;}
private String Eval_script_as_str(String script) {return (String)Eval_script(script);}
public Object Eval_script(String script) {
eval_rslt.Clear();
try {
eval_rslt.Result_set(browser.evaluate(script));
return eval_rslt.Result();
}
catch (Exception e) {eval_rslt.Error_set(e.getMessage()); return eval_rslt.Error();}
} private Swt_html_eval_rslt eval_rslt = new Swt_html_eval_rslt();
@Override public void focusGained(FocusEvent arg0) {}
@Override public void focusLost(FocusEvent arg0) {}
public static final int
Browser_tid_none = SWT.NONE
, Browser_tid_mozilla = SWT.MOZILLA
, Browser_tid_webkit = SWT.WEBKIT
;
}
class Swt_core_cmds_html extends Swt_core__basic {
public Swt_core_cmds_html(Swt_html html_box, Control control) {super(control);}
@Override public void Focus() {
if (Focus_able())
control.forceFocus();
}
@Override public void Select_exec() {
this.Focus();
}
}
class Swt_html_lnr_traverse implements TraverseListener {
public Swt_html_lnr_traverse(Swt_html html_box) {}
@Override public void keyTraversed(TraverseEvent arg0) {}
}
class Swt_html_lnr_title implements TitleListener {
private Swt_html html_box;
public Swt_html_lnr_title(Swt_html html_box) {this.html_box = html_box;}
@Override public void changed(TitleEvent ev) {
try {UsrDlg_.Instance.Note(ev.title);}
catch (Exception e) {html_box.Kit().Ask_ok("xowa.swt.html_box", "title.fail", Err_.Message_gplx_full(e));} // NOTE: must catch error or will cause app to lock; currently called inside displaySync
}
}
class Swt_html_func extends BrowserFunction {
private final Gfo_invk invk;
private final Browser browser;
public Swt_html_func(Browser browser, String name, Gfo_invk invk) {
super (browser, name);
this.browser = browser;
this.invk = invk;
}
public Object function (Object[] args) {
try {
return gplx.gfui.controls.standards.Gfui_html.Js_args_exec(invk, args);
}
catch (Exception e) {
String rv = Err_.Message_gplx_full(e);
browser.execute("alert('" + Swt_html.Escape_quote(rv) + "')");
return rv;
}
}
}
class Swt_html_lnr_status implements StatusTextListener {
public Swt_html_lnr_status(Swt_html html_box) {this.html_box = html_box;} private Swt_html html_box;
public void Host_set(Gfo_evt_itm host) {this.host = host;} Gfo_evt_itm host;
@Override public void changed(StatusTextEvent ev) {
if (html_box.Kit().Kit_mode__term()) return; // shutting down raises status changed events; ignore, else SWT exception thrown; DATE:2014-05-29
String ev_text = ev.text;
String load_by_url_path = html_box.Load_by_url_path();
if (load_by_url_path != null) ev_text = String_.Replace(ev_text, load_by_url_path, ""); // remove "C:/xowa/tab_1.html"
// if (String_.Has(ev_text, "Loading [MathJax]")) return; // suppress MathJax messages; // NOTE: disabled for 2.1 (which no longer outputs messages to status); DATE:2013-05-03
try {if (host != null) Gfo_evt_mgr_.Pub_obj(host, Gfui_html.Evt_link_hover, "v", ev_text);}
catch (Exception e) {html_box.Kit().Ask_ok("xowa.gui.html_box", "status.fail", Err_.Message_gplx_full(e));} // NOTE: must catch error or will cause app to lock; currently called inside displaySync
}
}
class Swt_html_lnr_progress implements ProgressListener {
public Swt_html_lnr_progress(Swt_html html_box) {}
@Override public void changed(ProgressEvent arg0) {}
@Override public void completed(ProgressEvent arg0) {
// UsrDlg_._.Note("done");
}
}
class Swt_html_lnr_location implements LocationListener {
public Swt_html_lnr_location(Swt_html html_box) {this.html_box = html_box;} private Swt_html html_box;
public void Host_set(Gfo_evt_itm host) {this.host = host;} private Gfo_evt_itm host;
@Override public void changed(LocationEvent arg) {Pub_evt(arg, Gfui_html.Evt_location_changed);}
@Override public void changing(LocationEvent arg) {Pub_evt(arg, Gfui_html.Evt_location_changing);}
private void Pub_evt(LocationEvent arg, String evt) {
String location = arg.location;
if (String_.Eq(location, "about:blank")) return; // location changing event fires once when page is loaded; ignore
if ( html_box.Browser_tid() == Swt_html.Browser_tid_webkit // webkit prefixes "about:blank" to anchors; causes TOC to fail when clicking on links; EX:about:blank#TOC1; DATE:2015-06-09
&& String_.Has_at_bgn(location, "about:blank")) {
location = String_.Mid(location, 11); // 11 = "about:blank".length
}
if ( html_box.Html_doc_html_load_tid() == Gxw_html_load_tid_.Tid_url // navigating to file://page.html will fire location event; ignore if url mode
&& String_.Has_at_bgn(location, "file:")
&& String_.Has_at_end(location, ".html")
)
return;
try {
Gfo_evt_mgr_.Pub_obj(host, evt, "v", location);
arg.doit = false; // cancel navigation event, else there will be an error when trying to go to invalid location
}
catch (Exception e) {html_box.Kit().Ask_ok("xowa.gui.html_box", evt, Err_.Message_gplx_full(e));} // NOTE: must catch error or will cause app to lock; currently called inside displaySync
}
}
class Swt_html_lnr_mouse implements MouseListener {
private GxwElem elem; private Browser browser; private Swt_kit kit;
public Swt_html_lnr_mouse(GxwElem elem, Browser browser, Swt_kit kit) {this.elem = elem; this.browser = browser; this.kit = kit;}
@Override public void mouseDown(MouseEvent ev) {
if (Is_at_scrollbar_area()) return;
elem.Host().MouseDownCbk(XtoMouseData(ev));
}
@Override public void mouseUp(MouseEvent ev) {
if (Is_at_scrollbar_area()) return;
elem.Host().MouseUpCbk(XtoMouseData(ev));
}
private boolean Is_at_scrollbar_area() {
// WORKAROUND.SWT: SEE:NOTE_1:browser scrollbar and click
Point browser_size = browser.getSize();
Point click_pos = kit.Swt_display().getCursorLocation();
return click_pos.x >= browser_size.x - 12;
}
@Override public void mouseDoubleClick(MouseEvent ev) {}
IptEvtDataMouse XtoMouseData(MouseEvent ev) {
IptMouseBtn btn = null;
switch (ev.button) {
case 1: btn = IptMouseBtn_.Left; break;
case 2: btn = IptMouseBtn_.Middle; break;
case 3: btn = IptMouseBtn_.Right; break;
case 4: btn = IptMouseBtn_.X1; break;
case 5: btn = IptMouseBtn_.X2; break;
}
return IptEvtDataMouse.new_(btn, IptMouseWheel_.None, ev.x, ev.y);
}
}
class Swt_html_lnr_wheel implements MouseWheelListener {
private final Swt_html html_box;
public Swt_html_lnr_wheel(Swt_html html_box) {
this.html_box = html_box;
}
@Override public void mouseScrolled(MouseEvent evt) {
if (evt.stateMask == SWT.CTRL) { // ctrl held;
Gfo_evt_mgr_.Pub_obj(html_box, Gfui_html.Evt_zoom_changed, "clicks_is_positive", evt.count > 0);
}
}
}
//class Swt_open_window_listener implements OpenWindowListener {
// private final Swt_html html_box;
// public Swt_open_window_listener(Swt_html html_box) {this.html_box = html_box;}
// @Override public void open(WindowEvent arg0) {
// Tfds.Write();
// }
//}
/*
NOTE_1:browser scrollbar and click
a click in the scrollbar area will raise a mouse-down/mouse-up event in content-editable mode
. a click should be consumed by the scrollbar and not have any effect elsewhere on the window
. instead, a click event is raised, and counted twice
1) for the scroll bar this will scroll the area.
2) for the window. if keyboard-focus is set on a link, then it will activate the link.
swt does not expose any scrollbar information (visible, width), b/c the scrollbar is controlled by the underlying browser
so, assume:
. scrollbar is always present
. scrollbar has arbitrary width (currently 12)
. and discard if click is in this scrollbar area
two issues still occur with the workaround
1) even if the scrollbar is not present, any click on the right-hand edge of the screen will be ignored
2) click -> hold -> move mouse over to left -> release; the mouse up should be absorbed, but it is not due to position of release
*/
package gplx.gfui.kits.swts;
import gplx.Bool_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Byte_ascii;
import gplx.Err_;
import gplx.GfoMsg;
import gplx.Gfo_evt_itm;
import gplx.Gfo_evt_mgr;
import gplx.Gfo_evt_mgr_;
import gplx.Gfo_evt_mgr_owner;
import gplx.Gfo_invk;
import gplx.Gfo_invk_;
import gplx.GfsCtx;
import gplx.Int_;
import gplx.Io_mgr;
import gplx.Io_url;
import gplx.Keyval_hash;
import gplx.Long_;
import gplx.Object_;
import gplx.String_;
import gplx.Type_;
import gplx.UsrDlg_;
import gplx.core.envs.System_;
import gplx.gfui.controls.elems.GfuiElem;
import gplx.gfui.controls.gxws.GxwCbkHost;
import gplx.gfui.controls.gxws.GxwCore_base;
import gplx.gfui.controls.gxws.GxwElem;
import gplx.gfui.controls.gxws.Gxw_html;
import gplx.gfui.controls.gxws.Gxw_html_load_tid_;
import gplx.gfui.controls.standards.Gfui_html;
import gplx.gfui.ipts.IptEvtDataMouse;
import gplx.gfui.ipts.IptMouseBtn;
import gplx.gfui.ipts.IptMouseBtn_;
import gplx.gfui.ipts.IptMouseWheel_;
import gplx.gfui.kits.core.Swt_kit;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.BrowserFunction;
import org.eclipse.swt.browser.LocationEvent;
import org.eclipse.swt.browser.LocationListener;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.browser.StatusTextEvent;
import org.eclipse.swt.browser.StatusTextListener;
import org.eclipse.swt.browser.TitleEvent;
import org.eclipse.swt.browser.TitleListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
public class Swt_html implements Gxw_html, Swt_control, FocusListener, Gfo_evt_mgr_owner {
private Swt_html_lnr_location lnr_location; private Swt_html_lnr_status lnr_status;
public Swt_html(Swt_kit kit, Swt_control owner_control, Keyval_hash ctorArgs) {
this.kit = kit;
lnr_location = new Swt_html_lnr_location(this);
lnr_status = new Swt_html_lnr_status(this);
Object browser_tid_obj = ctorArgs.Get_val_or(Swt_kit.Cfg_Html_BrowserType, null);
this.browser_tid = browser_tid_obj == null ? Browser_tid_none : Int_.Cast(browser_tid_obj);
browser = new Browser(owner_control.Under_composite(), browser_tid);
core = new Swt_core_cmds_html(this, browser);
browser.addKeyListener(new Swt_lnr_key(this));
browser.addMouseListener(new Swt_html_lnr_mouse(this, browser, kit));
browser.addLocationListener(lnr_location);
browser.addProgressListener(new Swt_html_lnr_progress(this));
browser.addStatusTextListener(lnr_status);
browser.addFocusListener(this);
browser.addTitleListener(new Swt_html_lnr_title(this));
browser.addMouseWheelListener(new Swt_html_lnr_wheel(this));
// browser.addOpenWindowListener(new Swt_open_window_listener(this)); // handle target='blank'
// browser.addTraverseListener(new Swt_html_lnr_Traverse(this));
}
public Swt_kit Kit() {return kit;} private Swt_kit kit;
public Gfo_evt_mgr Evt_mgr() {return ev_mgr;} private Gfo_evt_mgr ev_mgr; public void Evt_mgr_(Gfo_evt_mgr v) {ev_mgr = v;}
@Override public Control Under_control() {return browser;} private Browser browser;
@Override public Composite Under_composite() {return null;}
@Override public Control Under_menu_control() {return browser;}
public int Browser_tid() {return browser_tid;} private final int browser_tid;
public String Load_by_url_path() {return load_by_url_path;} private String load_by_url_path;
public void Html_doc_html_load_by_mem(String html) {
this.html_doc_html_load_tid = Gxw_html_load_tid_.Tid_mem;
this.load_by_url_path = null;
browser.setText(html); // DBG: Io_mgr.I.SaveFilStr(Io_url_.new_fil_("C:\\temp.txt"), s)
}
public void Html_doc_html_load_by_url(Io_url path, String html) {
this.html_doc_html_load_tid = Gxw_html_load_tid_.Tid_url;
this.load_by_url_path = path.To_http_file_str();
Io_mgr.Instance.SaveFilStr(path, html);
browser.setUrl(path.Xto_api());
}
public byte Html_doc_html_load_tid() {return html_doc_html_load_tid;} private byte html_doc_html_load_tid;
public void Html_doc_html_load_tid_(byte v) {html_doc_html_load_tid = v;}
public void Html_js_enabled_(boolean v) {browser.setJavascriptEnabled(v);}
public void Html_js_cbks_add(String func_name, Gfo_invk invk) {new Swt_html_func(browser, func_name, invk);}
public String Html_js_eval_script(String script) {return Eval_script_as_str(script);}
public Object Html_js_eval_script_as_obj(String script) {return Eval_script(script);}
public boolean Html_js_eval_proc_as_bool(String proc, Object... args) {return Bool_.Cast(Html_js_eval_proc_as_obj(proc, args));}
public String Html_js_eval_proc_as_str(String proc, Object... args) {return Object_.Xto_str_strict_or_null(Html_js_eval_proc_as_obj(proc, args));}
public String Html_js_send_json(String name, String data) {
String script = String_.Format("return {0}('{1}');", name, String_.Replace(data, "\n", "") );
return (String)Eval_script(script);
}
private Object Html_js_eval_proc_as_obj(String proc, Object... args) {
Bry_bfr bfr = Bry_bfr_.New();
bfr.Add_str_a7("return ").Add_str_u8(proc).Add_byte(Byte_ascii.Paren_bgn);
int args_len = args.length;
for (int i = 0; i < args_len; ++i) {
Object arg = args[i];
if (i != 0) bfr.Add_byte(Byte_ascii.Comma);
boolean quote_val = true;
if ( Type_.Eq_by_obj(arg, Bool_.Cls_ref_type)
|| Type_.Eq_by_obj(arg, Int_.Cls_ref_type)
|| Type_.Eq_by_obj(arg, Long_.Cls_ref_type)
) {
quote_val = false;
}
if (quote_val) bfr.Add_byte(Byte_ascii.Apos);
if (quote_val)
bfr.Add_str_u8(Escape_quote(Object_.Xto_str_strict_or_null_mark(arg)));
else
bfr.Add_obj_strict(arg);
if (quote_val) bfr.Add_byte(Byte_ascii.Apos);
}
bfr.Add_byte(Byte_ascii.Paren_end).Add_byte(Byte_ascii.Semic);
return Eval_script(bfr.To_str_and_clear());
}
public static String Escape_quote(String v) {
String rv = v;
rv = String_.Replace(rv, "'", "\\'");
rv = String_.Replace(rv, "\"", "\\\"");
rv = String_.Replace(rv, "\n", "\\n");
return rv;
}
public void Html_invk_src_(Gfo_evt_itm invk) {lnr_location.Host_set(invk); lnr_status.Host_set(invk);}
public void Html_dispose() {
browser.dispose();
delete_owner.SubElems().DelOrFail(delete_cur); // NOTE: must delete cur from owner, else new tab will fail after closing one; DATE:2014-07-09
System_.Garbage_collect();
}
private GfuiElem delete_owner, delete_cur;
public void Delete_elems_(GfuiElem delete_owner, GfuiElem delete_cur) {this.delete_owner = delete_owner; this.delete_cur = delete_cur;} // HACK: set owner / cur so delete can work;
@Override public GxwCore_base Core() {return core;} private GxwCore_base core;
@Override public GxwCbkHost Host() {return host;} @Override public void Host_set(GxwCbkHost host) {this.host = host;} GxwCbkHost host;
@Override public String TextVal() {return browser.getText();}
@Override public void TextVal_set(String v) {browser.setText(v);}
@Override public void EnableDoubleBuffering() {}
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return Gfo_invk_.Rv_unhandled;}
private String Eval_script_as_str(String script) {return (String)Eval_script(script);}
public Object Eval_script(String script) {
eval_rslt.Clear();
try {
eval_rslt.Result_set(browser.evaluate(script));
return eval_rslt.Result();
}
catch (Exception e) {eval_rslt.Error_set(e.getMessage()); return eval_rslt.Error();}
} private Swt_html_eval_rslt eval_rslt = new Swt_html_eval_rslt();
@Override public void focusGained(FocusEvent arg0) {}
@Override public void focusLost(FocusEvent arg0) {}
public static final int
Browser_tid_none = SWT.NONE
, Browser_tid_mozilla = SWT.MOZILLA
, Browser_tid_webkit = SWT.WEBKIT
;
}
class Swt_core_cmds_html extends Swt_core__basic {
public Swt_core_cmds_html(Swt_html html_box, Control control) {super(control);}
@Override public void Focus() {
if (Focus_able())
control.forceFocus();
}
@Override public void Select_exec() {
this.Focus();
}
}
class Swt_html_lnr_traverse implements TraverseListener {
public Swt_html_lnr_traverse(Swt_html html_box) {}
@Override public void keyTraversed(TraverseEvent arg0) {}
}
class Swt_html_lnr_title implements TitleListener {
private Swt_html html_box;
public Swt_html_lnr_title(Swt_html html_box) {this.html_box = html_box;}
@Override public void changed(TitleEvent ev) {
try {UsrDlg_.Instance.Note(ev.title);}
catch (Exception e) {html_box.Kit().Ask_ok("xowa.swt.html_box", "title.fail", Err_.Message_gplx_full(e));} // NOTE: must catch error or will cause app to lock; currently called inside displaySync
}
}
class Swt_html_func extends BrowserFunction {
private final Gfo_invk invk;
private final Browser browser;
public Swt_html_func(Browser browser, String name, Gfo_invk invk) {
super (browser, name);
this.browser = browser;
this.invk = invk;
}
public Object function (Object[] args) {
try {
return gplx.gfui.controls.standards.Gfui_html.Js_args_exec(invk, args);
}
catch (Exception e) {
String rv = Err_.Message_gplx_full(e);
browser.execute("alert('" + Swt_html.Escape_quote(rv) + "')");
return rv;
}
}
}
class Swt_html_lnr_status implements StatusTextListener {
public Swt_html_lnr_status(Swt_html html_box) {this.html_box = html_box;} private Swt_html html_box;
public void Host_set(Gfo_evt_itm host) {this.host = host;} Gfo_evt_itm host;
@Override public void changed(StatusTextEvent ev) {
if (html_box.Kit().Kit_mode__term()) return; // shutting down raises status changed events; ignore, else SWT exception thrown; DATE:2014-05-29
// 2020-09-22|ISSUE#:799|normalize URL due to SWT 4.16
String ev_text = Swt_html_utl.NormalizeSwtUrl(ev.text);
String load_by_url_path = html_box.Load_by_url_path();
if (load_by_url_path != null) ev_text = String_.Replace(ev_text, load_by_url_path, ""); // remove "C:/xowa/tab_1.html"
// if (String_.Has(ev_text, "Loading [MathJax]")) return; // suppress MathJax messages; // NOTE: disabled for 2.1 (which no longer outputs messages to status); DATE:2013-05-03
try {if (host != null) Gfo_evt_mgr_.Pub_obj(host, Gfui_html.Evt_link_hover, "v", ev_text);}
catch (Exception e) {html_box.Kit().Ask_ok("xowa.gui.html_box", "status.fail", Err_.Message_gplx_full(e));} // NOTE: must catch error or will cause app to lock; currently called inside displaySync
}
}
class Swt_html_lnr_progress implements ProgressListener {
public Swt_html_lnr_progress(Swt_html html_box) {}
@Override public void changed(ProgressEvent arg0) {}
@Override public void completed(ProgressEvent arg0) {
// UsrDlg_._.Note("done");
}
}
class Swt_html_lnr_location implements LocationListener {
public Swt_html_lnr_location(Swt_html html_box) {this.html_box = html_box;} private Swt_html html_box;
public void Host_set(Gfo_evt_itm host) {this.host = host;} private Gfo_evt_itm host;
@Override public void changed(LocationEvent arg) {Pub_evt(arg, Gfui_html.Evt_location_changed);}
@Override public void changing(LocationEvent arg) {Pub_evt(arg, Gfui_html.Evt_location_changing);}
private void Pub_evt(LocationEvent arg, String evt) {
// 2020-09-22|ISSUE#:799|normalize URL due to SWT 4.16
String location = Swt_html_utl.NormalizeSwtUrl(arg.location);
// location_changing fires once when page is loaded -> ignore
if (String_.Eq(location, String_.Empty)) {
return;
}
// navigating to file://page.html will fire location event; ignore if url mode (loading pages from file)
if (html_box.Html_doc_html_load_tid() == Gxw_html_load_tid_.Tid_url
&& String_.Has_at_bgn(location, "file:")
&& String_.Has_at_end(location, ".html")
) {
return;
}
if (String_.Has_at_bgn(location, "javascript:")) {
html_box.Html_js_eval_script(location);
arg.doit = false;
return;
}
try {
Gfo_evt_mgr_.Pub_obj(host, evt, "v", location);
arg.doit = false; // cancel navigation event, else there will be an error when trying to go to invalid location
}
catch (Exception e) {html_box.Kit().Ask_ok("xowa.gui.html_box", evt, Err_.Message_gplx_full(e));} // NOTE: must catch error or will cause app to lock; currently called inside displaySync
}
}
class Swt_html_lnr_mouse implements MouseListener {
private GxwElem elem; private Browser browser; private Swt_kit kit;
public Swt_html_lnr_mouse(GxwElem elem, Browser browser, Swt_kit kit) {this.elem = elem; this.browser = browser; this.kit = kit;}
@Override public void mouseDown(MouseEvent ev) {
if (Is_at_scrollbar_area()) return;
elem.Host().MouseDownCbk(XtoMouseData(ev));
}
@Override public void mouseUp(MouseEvent ev) {
if (Is_at_scrollbar_area()) return;
elem.Host().MouseUpCbk(XtoMouseData(ev));
}
private boolean Is_at_scrollbar_area() {
// WORKAROUND.SWT: SEE:NOTE_1:browser scrollbar and click
Point browser_size = browser.getSize();
Point click_pos = kit.Swt_display().getCursorLocation();
return click_pos.x >= browser_size.x - 12;
}
@Override public void mouseDoubleClick(MouseEvent ev) {}
IptEvtDataMouse XtoMouseData(MouseEvent ev) {
IptMouseBtn btn = null;
switch (ev.button) {
case 1: btn = IptMouseBtn_.Left; break;
case 2: btn = IptMouseBtn_.Middle; break;
case 3: btn = IptMouseBtn_.Right; break;
case 4: btn = IptMouseBtn_.X1; break;
case 5: btn = IptMouseBtn_.X2; break;
}
return IptEvtDataMouse.new_(btn, IptMouseWheel_.None, ev.x, ev.y);
}
}
class Swt_html_lnr_wheel implements MouseWheelListener {
private final Swt_html html_box;
public Swt_html_lnr_wheel(Swt_html html_box) {
this.html_box = html_box;
}
@Override public void mouseScrolled(MouseEvent evt) {
if (evt.stateMask == SWT.CTRL) { // ctrl held;
Gfo_evt_mgr_.Pub_obj(html_box, Gfui_html.Evt_zoom_changed, "clicks_is_positive", evt.count > 0);
}
}
}
//class Swt_open_window_listener implements OpenWindowListener {
// private final Swt_html html_box;
// public Swt_open_window_listener(Swt_html html_box) {this.html_box = html_box;}
// @Override public void open(WindowEvent arg0) {
// Tfds.Write();
// }
//}
/*
NOTE_1:browser scrollbar and click
a click in the scrollbar area will raise a mouse-down/mouse-up event in content-editable mode
. a click should be consumed by the scrollbar and not have any effect elsewhere on the window
. instead, a click event is raised, and counted twice
1) for the scroll bar this will scroll the area.
2) for the window. if keyboard-focus is set on a link, then it will activate the link.
swt does not expose any scrollbar information (visible, width), b/c the scrollbar is controlled by the underlying browser
so, assume:
. scrollbar is always present
. scrollbar has arbitrary width (currently 12)
. and discard if click is in this scrollbar area
two issues still occur with the workaround
1) even if the scrollbar is not present, any click on the right-hand edge of the screen will be ignored
2) click -> hold -> move mouse over to left -> release; the mouse up should be absorbed, but it is not due to position of release
*/

View File

@ -0,0 +1,40 @@
/*
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.gfui.kits.swts;
import gplx.String_;
public class Swt_html_utl {
private static final String URL_PREFIX_ABOUT = "about:";
private static final String URL_PREFIX_BLANK = "blank";
public static String NormalizeSwtUrl(String url) {
String rv = url;
// 2020-09-19|ISSUE#:799|strip "about:" from url due to SWT 4.16
rv = String_.Has_at_bgn(rv, URL_PREFIX_ABOUT)
? String_.Mid(rv, URL_PREFIX_ABOUT.length())
: rv;
// 2015-06-09|webkit prefixes "about:blank" to anchors; causes TOC to fail when clicking on links; EX:about:blank#TOC1
// 2020-09-22|removed webkit check due to SWT 4.16; `html_box.Browser_tid() == Swt_html.Browser_tid_webkit`
// still strip "blank"; note that SWT 4.16 changes anchors from "file:///#anchor" to "en.w/wiki/page/#anchor"
rv = String_.Has_at_bgn(rv, URL_PREFIX_BLANK)
? String_.Mid(rv, URL_PREFIX_BLANK.length())
: rv;
return rv;
}
}

View File

@ -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,78 +13,94 @@ 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.core.gfobjs; import gplx.*; import gplx.core.*;
import gplx.langs.jsons.*;
public class Gfobj_rdr__json {
private final Json_parser parser = new Json_parser();
public Gfobj_grp Load(Io_url url) {
byte[] src = Io_mgr.Instance.LoadFilBryOrNull(url); if (src == null) return null;
return this.Parse(src);
}
public Gfobj_grp Parse(byte[] src) {
Json_doc jdoc = parser.Parse(src);
if (jdoc.Root_grp().Tid() == Json_itm_.Tid__nde) {
Gfobj_nde rv_nde = Gfobj_nde.New();
Parse_nde((Json_nde)jdoc.Root_grp(), rv_nde);
return rv_nde;
}
else {
Gfobj_ary rv_ary = new Gfobj_ary(null);
Parse_ary((Json_ary)jdoc.Root_grp(), rv_ary);
return rv_ary;
}
}
private void Parse_nde(Json_nde jnde, Gfobj_nde gnde) {
int len = jnde.Len();
for (int i = 0; i < len; ++i) {
Json_kv kv = jnde.Get_at_as_kv(i);
String key_str = kv.Key_as_str();
Json_itm val = kv.Val();
byte val_tid = val.Tid();
switch (val_tid) {
case Json_itm_.Tid__str: gnde.Add_str (key_str, ((Json_itm_str)val).Data_as_str()); break;
case Json_itm_.Tid__bool: gnde.Add_bool (key_str, ((Json_itm_bool)val).Data_as_bool()); break;
case Json_itm_.Tid__int: gnde.Add_int (key_str, ((Json_itm_int)val).Data_as_int()); break;
case Json_itm_.Tid__long: gnde.Add_long (key_str, ((Json_itm_long)val).Data_as_long()); break;
case Json_itm_.Tid__decimal: gnde.Add_double (key_str, ((Json_itm_decimal)val).Data_as_decimal().To_double()); break;
case Json_itm_.Tid__null: gnde.Add_str (key_str, null); break;
case Json_itm_.Tid__ary:
Gfobj_ary sub_ary = new Gfobj_ary(null);
gnde.Add_ary(key_str, sub_ary);
Parse_ary(Json_ary.cast(val), sub_ary);
break;
case Json_itm_.Tid__nde:
Gfobj_nde sub_gnde = Gfobj_nde.New();
gnde.Add_nde(key_str, sub_gnde);
Parse_nde(Json_nde.cast(val), sub_gnde);
break;
default: throw Err_.new_unhandled_default(val_tid);
}
}
}
private void Parse_ary(Json_ary jry, Gfobj_ary gry) {
int len = jry.Len();
Object[] ary = new Object[len];
gry.Ary_(ary);
for (int i = 0; i < len; ++i) {
Json_itm jsub = jry.Get_at(i);
switch (jsub.Tid()) {
case Json_itm_.Tid__ary: {
Gfobj_ary sub_ary = new Gfobj_ary(null);
Parse_ary(Json_ary.cast(jsub), sub_ary);
ary[i] = sub_ary;
break;
}
case Json_itm_.Tid__nde: {
Gfobj_nde sub_ary = Gfobj_nde.New();
Parse_nde(Json_nde.cast(jsub), sub_ary);
ary[i] = sub_ary;
break;
}
default:
ary[i] = jsub.Data();
break;
}
}
}
}
package gplx.core.gfobjs;
import gplx.Err_;
import gplx.Io_mgr;
import gplx.Io_url;
import gplx.langs.jsons.Json_ary;
import gplx.langs.jsons.Json_doc;
import gplx.langs.jsons.Json_itm;
import gplx.langs.jsons.Json_itm_;
import gplx.langs.jsons.Json_itm_bool;
import gplx.langs.jsons.Json_itm_decimal;
import gplx.langs.jsons.Json_itm_int;
import gplx.langs.jsons.Json_itm_long;
import gplx.langs.jsons.Json_itm_str;
import gplx.langs.jsons.Json_kv;
import gplx.langs.jsons.Json_nde;
import gplx.langs.jsons.Json_parser;
public class Gfobj_rdr__json {
private final Json_parser parser = new Json_parser();
public Gfobj_grp Load(Io_url url) {
byte[] src = Io_mgr.Instance.LoadFilBryOrNull(url); if (src == null) return null;
return this.Parse(src);
}
public Gfobj_grp Parse(byte[] src) {
Json_doc jdoc = parser.Parse(src);
if (jdoc.Root_grp().Tid() == Json_itm_.Tid__nde) {
Gfobj_nde rv_nde = Gfobj_nde.New();
Parse_nde((Json_nde)jdoc.Root_grp(), rv_nde);
return rv_nde;
}
else {
Gfobj_ary rv_ary = new Gfobj_ary(null);
Parse_ary((Json_ary)jdoc.Root_grp(), rv_ary);
return rv_ary;
}
}
private void Parse_nde(Json_nde jnde, Gfobj_nde gnde) {
int len = jnde.Len();
for (int i = 0; i < len; ++i) {
Json_kv kv = jnde.Get_at_as_kv(i);
String key_str = kv.Key_as_str();
Json_itm val = kv.Val();
byte val_tid = val.Tid();
switch (val_tid) {
case Json_itm_.Tid__str: gnde.Add_str (key_str, ((Json_itm_str)val).Data_as_str()); break;
case Json_itm_.Tid__bool: gnde.Add_bool (key_str, ((Json_itm_bool)val).Data_as_bool()); break;
case Json_itm_.Tid__int: gnde.Add_int (key_str, ((Json_itm_int)val).Data_as_int()); break;
case Json_itm_.Tid__long: gnde.Add_long (key_str, ((Json_itm_long)val).Data_as_long()); break;
case Json_itm_.Tid__decimal: gnde.Add_double (key_str, ((Json_itm_decimal)val).Data_as_decimal().To_double()); break;
case Json_itm_.Tid__null: gnde.Add_str (key_str, null); break;
case Json_itm_.Tid__ary:
Gfobj_ary sub_ary = new Gfobj_ary(null);
gnde.Add_ary(key_str, sub_ary);
Parse_ary(Json_ary.cast(val), sub_ary);
break;
case Json_itm_.Tid__nde:
Gfobj_nde sub_gnde = Gfobj_nde.New();
gnde.Add_nde(key_str, sub_gnde);
Parse_nde(Json_nde.Cast(val), sub_gnde);
break;
default: throw Err_.new_unhandled_default(val_tid);
}
}
}
private void Parse_ary(Json_ary jry, Gfobj_ary gry) {
int len = jry.Len();
Object[] ary = new Object[len];
gry.Ary_(ary);
for (int i = 0; i < len; ++i) {
Json_itm jsub = jry.Get_at(i);
switch (jsub.Tid()) {
case Json_itm_.Tid__ary: {
Gfobj_ary sub_ary = new Gfobj_ary(null);
Parse_ary(Json_ary.cast(jsub), sub_ary);
ary[i] = sub_ary;
break;
}
case Json_itm_.Tid__nde: {
Gfobj_nde sub_ary = Gfobj_nde.New();
Parse_nde(Json_nde.Cast(jsub), sub_ary);
ary[i] = sub_ary;
break;
}
default:
ary[i] = jsub.Data();
break;
}
}
}
}

View File

@ -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,173 +13,181 @@ 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.core.primitives; import gplx.*; import gplx.core.*;
public class Gfo_number_parser {
public int Rv_as_int() {return (int)num_val;} private long num_val = 0;
public long Rv_as_long() {return num_val;}
public Decimal_adp Rv_as_dec() {return dec_val == null ? Decimal_adp_.long_(num_val) : dec_val;} private Decimal_adp dec_val = null;
public boolean Is_int() {return dec_val == null && (num_val >= Int_.Min_value && num_val <= Int_.Max_value);}
public boolean Has_err() {return has_err;} private boolean has_err;
public boolean Has_frac() {return has_frac;} private boolean has_frac;
public boolean Hex_enabled() {return hex_enabled;} public Gfo_number_parser Hex_enabled_(boolean v) {hex_enabled = v; return this;} private boolean hex_enabled;
public Gfo_number_parser Ignore_chars_(byte[] v) {this.ignore_chars = v; return this;} private byte[] ignore_chars;
public Gfo_number_parser Ignore_space_at_end_y_() {this.ignore_space_at_end = true; return this;} private boolean ignore_space_at_end;
public void Clear() {
ignore_chars = null;
}
public Gfo_number_parser Parse(byte[] src) {return Parse(src, 0, src.length);}
public Gfo_number_parser Parse(byte[] ary, int bgn, int end) {
int loop_bgn = end - 1, loop_end = bgn - 1, exp_multiplier = 1, factor = 10;
long multiplier = 1, frc_multiplier = 1;
num_val = 0; dec_val = null; boolean comma_nil = true;
long frc_int = 0;
has_err = false; has_frac = false; boolean has_exp = false, has_neg = false, exp_neg = false, has_plus = false, has_num = false;
boolean input_is_hex = false;
if (hex_enabled) {
if (loop_end + 2 < end) { // ArrayOutOfBounds check
byte b_2 = ary[loop_end + 2];
switch (b_2) {
case Byte_ascii.Ltr_x:
case Byte_ascii.Ltr_X: // is 2nd char x?
if (ary[loop_end + 1] == Byte_ascii.Num_0) { // is 1st char 0?
factor = 16;
input_is_hex = true;
}
break;
default:
break;
}
}
}
for (int i = loop_bgn; i > loop_end; i--) {
byte cur = ary[i];
switch (cur) {
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:
num_val += (cur - Byte_ascii.Num_0) * multiplier;
multiplier *= factor;
has_num = true;
break;
case Byte_ascii.Dot:
if (has_frac) return Has_err_y_();
frc_int = num_val;
num_val = 0;
frc_multiplier = multiplier;
multiplier = 1;
has_frac = true;
break;
case Byte_ascii.Comma:
if (comma_nil)
comma_nil = false;
else
return Has_err_y_();
break;
case Byte_ascii.Dash:
if (has_neg) return Has_err_y_();
has_neg = true;
break;
case Byte_ascii.Space:
if (i == bgn) {} // space at bgn
else if (i == end - 1 && ignore_space_at_end) {} // ignore space at end; DATE:2015-04-29
else
return Has_err_y_();
break;
case Byte_ascii.Plus:
if (has_plus) return Has_err_y_();
has_plus = true;
break;
case Byte_ascii.Ltr_e:
case Byte_ascii.Ltr_E:
if (input_is_hex) {
num_val += 14 * multiplier; // NOTE: 14=value of e/E
multiplier *= factor;
has_num = true;
}
else {
if (has_exp) return Has_err_y_();
exp_neg = has_neg;
exp_multiplier = (int)Math_.Pow(10, num_val);
num_val = 0;
multiplier = 1;
has_exp = true;
has_neg = false;
has_plus = false; // allow +1E+2
}
break;
case Byte_ascii.Ltr_A:
case Byte_ascii.Ltr_B:
case Byte_ascii.Ltr_C:
case Byte_ascii.Ltr_D:
case Byte_ascii.Ltr_F:
if (input_is_hex) {
num_val += (cur - Byte_ascii.Ltr_A + 10) * multiplier;
multiplier *= factor;
has_num = true;
}
else
return Has_err_y_();
break;
case Byte_ascii.Ltr_a:
case Byte_ascii.Ltr_b:
case Byte_ascii.Ltr_c:
case Byte_ascii.Ltr_d:
case Byte_ascii.Ltr_f:
if (input_is_hex) {
num_val += (cur - Byte_ascii.Ltr_a + 10) * multiplier;
multiplier *= factor;
has_num = true;
}
else
return Has_err_y_();
break;
case Byte_ascii.Ltr_x:
case Byte_ascii.Ltr_X:
if (input_is_hex)
return (factor == 16) ? this : Has_err_y_(); // check for '0x'
else
return Has_err_y_();
default:
if (ignore_chars != null) {
int ignore_chars_len = ignore_chars.length;
boolean ignored = false;
for (int j = 0; j < ignore_chars_len; ++j) {
if (cur == ignore_chars[j]) {
ignored = true;
break;
}
}
if (ignored) continue;
}
return Has_err_y_();
}
}
if (!has_num) return Has_err_y_(); // handles situations wherein just symbols; EX: "+", ".", "-.", " , " etc.
if (has_frac) {
long full_val = (((num_val * frc_multiplier) + frc_int));
if (has_neg) full_val *= -1;
if (has_exp) {
if (exp_neg) frc_multiplier *= exp_multiplier; // divide, so apply to frc
else full_val *= exp_multiplier; // multiply, so apply to full_val
}
dec_val = Decimal_adp_.divide_(full_val, frc_multiplier);
}
else {
if (has_neg) num_val *= -1;
if (has_exp) {
num_val = exp_neg
? num_val / exp_multiplier
: num_val * exp_multiplier;
}
}
return this;
}
private Gfo_number_parser Has_err_y_() {has_err = true; return this;}
}
package gplx.core.primitives;
import gplx.Byte_ascii;
import gplx.Decimal_adp;
import gplx.Decimal_adp_;
import gplx.Int_;
import gplx.Math_;
public class Gfo_number_parser {
public int Rv_as_int() {return (int)num_val;} private long num_val = 0;
public long Rv_as_long() {return num_val;}
public Decimal_adp Rv_as_dec() {return dec_val == null ? Decimal_adp_.long_(num_val) : dec_val;} private Decimal_adp dec_val = null;
public boolean Is_int() {return dec_val == null && (num_val >= Int_.Min_value && num_val <= Int_.Max_value);}
public boolean Has_err() {return has_err;} private boolean has_err;
public boolean Has_frac() {return has_frac;} private boolean has_frac;
public boolean Hex_enabled() {return hex_enabled;} public Gfo_number_parser Hex_enabled_(boolean v) {hex_enabled = v; return this;} private boolean hex_enabled;
public Gfo_number_parser Ignore_chars_(byte[] v) {this.ignore_chars = v; return this;} private byte[] ignore_chars;
public Gfo_number_parser Ignore_space_at_end_y_() {this.ignore_space_at_end = true; return this;} private boolean ignore_space_at_end;
public void Clear() {
ignore_chars = null;
}
public Gfo_number_parser Parse(byte[] src) {return Parse(src, 0, src.length);}
public Gfo_number_parser Parse(byte[] ary, int bgn, int end) {
int loop_bgn = end - 1, loop_end = bgn - 1, exp_multiplier = 1, factor = 10;
long multiplier = 1, frc_multiplier = 1;
num_val = 0; dec_val = null; boolean comma_nil = true;
long frc_int = 0;
has_err = false; has_frac = false; boolean has_exp = false, has_neg = false, exp_neg = false, has_plus = false, has_num = false;
boolean input_is_hex = false;
if (hex_enabled) {
if (loop_end + 2 < end) { // ArrayOutOfBounds check
byte b_2 = ary[loop_end + 2];
switch (b_2) {
case Byte_ascii.Ltr_x:
case Byte_ascii.Ltr_X: // is 2nd char x?
if (ary[loop_end + 1] == Byte_ascii.Num_0) { // is 1st char 0?
factor = 16;
input_is_hex = true;
}
break;
default:
break;
}
}
}
for (int i = loop_bgn; i > loop_end; i--) {
byte cur = ary[i];
switch (cur) {
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:
num_val += (cur - Byte_ascii.Num_0) * multiplier;
multiplier *= factor;
has_num = true;
break;
case Byte_ascii.Dot:
if (has_frac) return Has_err_y_();
frc_int = num_val;
num_val = 0;
frc_multiplier = multiplier;
multiplier = 1;
has_frac = true;
break;
case Byte_ascii.Comma:
if (comma_nil)
comma_nil = false;
else
return Has_err_y_();
break;
case Byte_ascii.Dash:
if (has_neg) return Has_err_y_();
has_neg = true;
break;
case Byte_ascii.Space:
if (i == bgn) {} // space at bgn
else if (i == end - 1 && ignore_space_at_end) {} // ignore space at end; DATE:2015-04-29
else
return Has_err_y_();
break;
case Byte_ascii.Plus:
if (has_plus) return Has_err_y_();
has_plus = true;
break;
case Byte_ascii.Ltr_e:
case Byte_ascii.Ltr_E:
if (input_is_hex) {
num_val += 14 * multiplier; // NOTE: 14=value of e/E
multiplier *= factor;
has_num = true;
}
else {
if (has_exp) return Has_err_y_();
exp_neg = has_neg;
exp_multiplier = (int)Math_.Pow(10, num_val);
num_val = 0;
multiplier = 1;
has_exp = true;
has_neg = false;
has_plus = false; // allow +1E+2
has_num = false; // 2020-09-07|ISSUE#:795|scientific notation requires coefficient; set has_num to false which will fail below if no coefficient
}
break;
case Byte_ascii.Ltr_A:
case Byte_ascii.Ltr_B:
case Byte_ascii.Ltr_C:
case Byte_ascii.Ltr_D:
case Byte_ascii.Ltr_F:
if (input_is_hex) {
num_val += (cur - Byte_ascii.Ltr_A + 10) * multiplier;
multiplier *= factor;
has_num = true;
}
else
return Has_err_y_();
break;
case Byte_ascii.Ltr_a:
case Byte_ascii.Ltr_b:
case Byte_ascii.Ltr_c:
case Byte_ascii.Ltr_d:
case Byte_ascii.Ltr_f:
if (input_is_hex) {
num_val += (cur - Byte_ascii.Ltr_a + 10) * multiplier;
multiplier *= factor;
has_num = true;
}
else
return Has_err_y_();
break;
case Byte_ascii.Ltr_x:
case Byte_ascii.Ltr_X:
if (input_is_hex)
return (factor == 16) ? this : Has_err_y_(); // check for '0x'
else
return Has_err_y_();
default:
if (ignore_chars != null) {
int ignore_chars_len = ignore_chars.length;
boolean ignored = false;
for (int j = 0; j < ignore_chars_len; ++j) {
if (cur == ignore_chars[j]) {
ignored = true;
break;
}
}
if (ignored) continue;
}
return Has_err_y_();
}
}
if (!has_num) return Has_err_y_(); // handles situations wherein just symbols; EX: "+", ".", "-.", " , " etc.
if (has_frac) {
long full_val = (((num_val * frc_multiplier) + frc_int));
if (has_neg) full_val *= -1;
if (has_exp) {
if (exp_neg) frc_multiplier *= exp_multiplier; // divide, so apply to frc
else full_val *= exp_multiplier; // multiply, so apply to full_val
}
dec_val = Decimal_adp_.divide_(full_val, frc_multiplier);
}
else {
if (has_neg) num_val *= -1;
if (has_exp) {
num_val = exp_neg
? num_val / exp_multiplier
: num_val * exp_multiplier;
}
}
return this;
}
private Gfo_number_parser Has_err_y_() {has_err = true; return this;}
}

View File

@ -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,95 +13,103 @@ 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.core.primitives; import gplx.*; import gplx.core.*;
import org.junit.*;
public class Gfo_number_parser_tst {
@Before public void init() {fxt.Clear();} private final Gfo_number_parser_fxt fxt = new Gfo_number_parser_fxt();
@Test public void Integer() {
fxt.Test_int("1", 1);
fxt.Test_int("1234", 1234);
fxt.Test_int("1234567890", 1234567890);
fxt.Test_int("-1234", -1234);
fxt.Test_int("+1", 1);
fxt.Test_int("00001", 1);
}
@Test public void Long() {
fxt.Test_long("9876543210", 9876543210L);
}
@Test public void Decimal() {
fxt.Test_dec("1.23", Decimal_adp_.parse("1.23"));
fxt.Test_dec("1.023", Decimal_adp_.parse("1.023"));
fxt.Test_dec("-1.23", Decimal_adp_.parse("-1.23"));
}
@Test public void Double_long() {
fxt.Test_dec(".42190046219457", Decimal_adp_.parse(".42190046219457"));
}
@Test public void Exponent() {
fxt.Test_int("1E2", 100);
fxt.Test_dec("1.234E2", Decimal_adp_.parse("123.4"));
fxt.Test_dec("1.234E-2", Decimal_adp_.parse(".01234"));
fxt.Test_dec("123.4E-2", Decimal_adp_.parse("1.234"));
fxt.Test_dec("+6.0E-3", Decimal_adp_.parse(".006"));
}
@Test public void Err() {
fxt.Test_err("+", true);
fxt.Test_err("-", true);
fxt.Test_err("a", true);
fxt.Test_err("1-2", false);
fxt.Test_err("1..1", true);
fxt.Test_err("1,,1", true);
fxt.Test_err("1", false);
}
@Test public void Hex() {
fxt.Test_hex("0x1" , 1);
fxt.Test_hex("0xF" , 15);
fxt.Test_hex("0x20" , 32);
fxt.Test_hex("x20" , 0, false);
fxt.Test_hex("d" , 0, false); // PURPOSE: d was being converted to 13; no.w:Hovedbanen; DATE:2014-04-13
}
@Test public void Ignore() {
fxt.Init_ignore("\n\t");
fxt.Test_int("1" , 1);
fxt.Test_int("1\n" , 1);
fxt.Test_int("1\t" , 1);
fxt.Test_int("1\n2" , 12);
fxt.Test_err("1\r" , true);
}
}
class Gfo_number_parser_fxt {
private final Gfo_number_parser parser = new Gfo_number_parser();
public void Clear() {parser.Clear();}
public void Init_ignore(String chars) {parser.Ignore_chars_(Bry_.new_a7(chars));}
public void Test_int(String raw, int expd) {
byte[] raw_bry = Bry_.new_a7(raw);
int actl = parser.Parse(raw_bry, 0, raw_bry.length).Rv_as_int();
Tfds.Eq(expd, actl, raw);
}
public void Test_long(String raw, long expd) {
byte[] raw_bry = Bry_.new_a7(raw);
Tfds.Eq(expd, parser.Parse(raw_bry, 0, raw_bry.length).Rv_as_long(), raw);
}
public void Test_dec(String raw, Decimal_adp expd) {
byte[] raw_bry = Bry_.new_a7(raw);
Decimal_adp actl = parser.Parse(raw_bry, 0, raw_bry.length).Rv_as_dec();
Tfds.Eq(expd.To_double(), actl.To_double(), raw);
}
public void Test_err(String raw, boolean expd) {
byte[] raw_bry = Bry_.new_a7(raw);
boolean actl = parser.Parse(raw_bry, 0, raw_bry.length).Has_err();
Tfds.Eq(expd, actl, raw);
}
public void Test_hex(String raw, int expd_val) {Test_hex(raw, expd_val, true);}
public void Test_hex(String raw, int expd_val, boolean expd_pass) {
parser.Hex_enabled_(true);
byte[] raw_bry = Bry_.new_a7(raw);
int actl = parser.Parse(raw_bry, 0, raw_bry.length).Rv_as_int();
if (expd_pass) {
Tfds.Eq(expd_val, actl, raw);
Tfds.Eq(true, !parser.Has_err());
}
else
Tfds.Eq(false, !parser.Has_err());
parser.Hex_enabled_(false);
}
}
package gplx.core.primitives;
import gplx.Bry_;
import gplx.Decimal_adp;
import gplx.Decimal_adp_;
import gplx.Tfds;
import org.junit.Before;
import org.junit.Test;
public class Gfo_number_parser_tst {
@Before public void init() {fxt.Clear();} private final Gfo_number_parser_fxt fxt = new Gfo_number_parser_fxt();
@Test public void Integer() {
fxt.Test_int("1", 1);
fxt.Test_int("1234", 1234);
fxt.Test_int("1234567890", 1234567890);
fxt.Test_int("-1234", -1234);
fxt.Test_int("+1", 1);
fxt.Test_int("00001", 1);
}
@Test public void Long() {
fxt.Test_long("9876543210", 9876543210L);
}
@Test public void Decimal() {
fxt.Test_dec("1.23", Decimal_adp_.parse("1.23"));
fxt.Test_dec("1.023", Decimal_adp_.parse("1.023"));
fxt.Test_dec("-1.23", Decimal_adp_.parse("-1.23"));
}
@Test public void Double_long() {
fxt.Test_dec(".42190046219457", Decimal_adp_.parse(".42190046219457"));
}
@Test public void Exponent() {
fxt.Test_int("1E2", 100);
fxt.Test_dec("1.234E2", Decimal_adp_.parse("123.4"));
fxt.Test_dec("1.234E-2", Decimal_adp_.parse(".01234"));
fxt.Test_dec("123.4E-2", Decimal_adp_.parse("1.234"));
fxt.Test_dec("+6.0E-3", Decimal_adp_.parse(".006"));
fxt.Test_err("e24", true); // 2020-09-07|ISSUE#:795|scientific notation requires coefficient
}
@Test public void Err() {
fxt.Test_err("+", true);
fxt.Test_err("-", true);
fxt.Test_err("a", true);
fxt.Test_err("1-2", false);
fxt.Test_err("1..1", true);
fxt.Test_err("1,,1", true);
fxt.Test_err("1", false);
}
@Test public void Hex() {
fxt.Test_hex("0x1" , 1);
fxt.Test_hex("0xF" , 15);
fxt.Test_hex("0x20" , 32);
fxt.Test_hex("x20" , 0, false);
fxt.Test_hex("d" , 0, false); // PURPOSE: d was being converted to 13; no.w:Hovedbanen; DATE:2014-04-13
}
@Test public void Ignore() {
fxt.Init_ignore("\n\t");
fxt.Test_int("1" , 1);
fxt.Test_int("1\n" , 1);
fxt.Test_int("1\t" , 1);
fxt.Test_int("1\n2" , 12);
fxt.Test_err("1\r" , true);
}
}
class Gfo_number_parser_fxt {
private final Gfo_number_parser parser = new Gfo_number_parser();
public void Clear() {parser.Clear();}
public void Init_ignore(String chars) {parser.Ignore_chars_(Bry_.new_a7(chars));}
public void Test_int(String raw, int expd) {
byte[] raw_bry = Bry_.new_a7(raw);
int actl = parser.Parse(raw_bry, 0, raw_bry.length).Rv_as_int();
Tfds.Eq(expd, actl, raw);
}
public void Test_long(String raw, long expd) {
byte[] raw_bry = Bry_.new_a7(raw);
Tfds.Eq(expd, parser.Parse(raw_bry, 0, raw_bry.length).Rv_as_long(), raw);
}
public void Test_dec(String raw, Decimal_adp expd) {
byte[] raw_bry = Bry_.new_a7(raw);
Decimal_adp actl = parser.Parse(raw_bry, 0, raw_bry.length).Rv_as_dec();
Tfds.Eq(expd.To_double(), actl.To_double(), raw);
}
public void Test_err(String raw, boolean expd) {
byte[] raw_bry = Bry_.new_a7(raw);
boolean actl = parser.Parse(raw_bry, 0, raw_bry.length).Has_err();
Tfds.Eq(expd, actl, raw);
}
public void Test_hex(String raw, int expd_val) {Test_hex(raw, expd_val, true);}
public void Test_hex(String raw, int expd_val, boolean expd_pass) {
parser.Hex_enabled_(true);
byte[] raw_bry = Bry_.new_a7(raw);
int actl = parser.Parse(raw_bry, 0, raw_bry.length).Rv_as_int();
if (expd_pass) {
Tfds.Eq(expd_val, actl, raw);
Tfds.Eq(true, !parser.Has_err());
}
else
Tfds.Eq(false, !parser.Has_err());
parser.Hex_enabled_(false);
}
}

View File

@ -0,0 +1,46 @@
package gplx.core.serials.binarys;
import gplx.Bry_;
import gplx.core.serials.core.SerialLoadMgr;
import gplx.core.serials.core.SerialLoadWkr;
import gplx.core.texts.Base64Converter;
public class BinaryLoadMgr implements SerialLoadMgr {
public static final int CORE_VERSION = 0;
private byte[] data;
private int headerEnd;
private int dataVersion;
@Override
public int CoreVersion() {
return CORE_VERSION;
}
@Override
public int DataVersion() {return dataVersion;}
@Override
public void ReadHeader(byte[] data) {
this.data = data;
this.dataVersion = Base64Converter.GetIndexInt((char)data[1]);
this.headerEnd = 3; // 1=coreVersion; 2=dataVersion; 3=\n
}
@Override
public byte[] Data() {
return data;
}
@Override
public int HeaderEnd() {
return headerEnd;
}
@Override
public SerialLoadWkr NewLoadWkr() {
return new BinaryLoadWkr().Ctor(this);
}
public byte[] FldDlm() {return fldDlm;} private final byte[] fldDlm = Bry_.new_a7("|");
public byte[] RowDlm() {return rowDlm;} private final byte[] rowDlm = Bry_.new_a7("\n");
}

View File

@ -0,0 +1,75 @@
package gplx.core.serials.binarys;
import gplx.Bry_;
import gplx.Bry_find_;
import gplx.Err_;
import gplx.String_;
import gplx.core.serials.core.SerialLoadMgr;
import gplx.core.serials.core.SerialLoadWkr;
public class BinaryLoadWkr implements SerialLoadWkr {
private BinaryLoadMgr mgr;
private byte[] fldDlm;
private byte[] rowDlm;
private byte[] src;
private int srcLen;
private int cur;
@Override
public SerialLoadWkr Ctor(SerialLoadMgr mgrObj) {
this.mgr = (BinaryLoadMgr)mgrObj;
this.fldDlm = mgr.FldDlm();
this.rowDlm = mgr.RowDlm();
return this;
}
@Override
public void Init(byte[] src, int cur) {
this.src = src;
this.srcLen = src.length;
this.cur = cur;
}
@Override
public String LoadStr() {
return String_.new_u8(LoadBry());
}
@Override
public int LoadInt() {
return LoadInt(rowDlm);
}
@Override
public byte[] LoadBry() {
int bryLen = LoadInt(fldDlm);
// extract bry
int bryBgn = cur;
int bryEnd = bryBgn + bryLen;
if (bryEnd > srcLen) {
throw Err_.new_wo_type(String_.Format("End position is out of bounds; src={0} currentPosition={1} byteArrayLength={2} remainder={3}", src, cur, bryLen, Bry_.Mid(src, bryBgn, bryEnd)));
}
cur = bryEnd + rowDlm.length;
return Bry_.Mid(src, bryBgn, bryEnd);
}
private int LoadInt(byte[] dlm) {
int bgn = cur;
// find position of delimiter
int end = Bry_find_.Find_fwd(src, dlm, cur, srcLen);
if (end == Bry_find_.Not_found) {
throw Err_.new_wo_type(String_.Format("Failed to find delimiter for integer's end position; src={0} currentPosition={1} delimiter={2}", src, cur, fldDlm));
}
cur = end + dlm.length;
// parse int
int val = Bry_.To_int_or(src, bgn, end, -1);
if (val == -1) {
throw Err_.new_wo_type(String_.Format("Failed to parse integer; src={0} currentPosition={1} string={2}", src, cur, Bry_.Mid(src, bgn, end)));
}
return val;
}
}

View File

@ -0,0 +1,16 @@
package gplx.core.serials.binarys;
import gplx.Bry_;
import gplx.core.serials.core.SerialSaveMgr;
import gplx.core.serials.core.SerialSaveWkr;
public class BinarySaveMgr implements SerialSaveMgr {
public int CoreVersion() {return BinaryLoadMgr.CORE_VERSION;}
public byte[] FldDlm() {return fldDlm;} private final byte[] fldDlm = Bry_.new_a7("|");
public byte[] RowDlm() {return rowDlm;} private final byte[] rowDlm = Bry_.new_a7("\n");
@Override
public SerialSaveWkr NewSaveWkr() {
return new BinarySaveWkr().Ctor(this);
}
}

View File

@ -0,0 +1,60 @@
package gplx.core.serials.binarys;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.core.serials.core.SerialSaveMgr;
import gplx.core.serials.core.SerialSaveWkr;
import gplx.core.texts.Base64Converter;
public class BinarySaveWkr implements SerialSaveWkr {
private byte[] fldDlm;
private byte[] rowDlm;
private BinarySaveMgr mgr;
private final Bry_bfr bfr = Bry_bfr_.New();
@Override
public SerialSaveWkr Ctor(SerialSaveMgr mgrObj) {
this.mgr = (BinarySaveMgr)mgrObj;
this.fldDlm = mgr.FldDlm();
this.rowDlm = mgr.RowDlm();
return this;
}
@Override
public void Init() {
bfr.Clear();
}
@Override
public void SaveHdr(int dataVersion) {
// EX: AA -> SerialCoreMgrID+DataVersionID
bfr.Add_byte((byte)Base64Converter.GetIndexChar(mgr.CoreVersion()));
bfr.Add_byte((byte)Base64Converter.GetIndexChar(dataVersion)).Add(rowDlm);
}
@Override
public void SaveInt(int val) {
SaveInt(val, rowDlm);
}
@Override
public void SaveStr(String val) {
this.SaveBry(Bry_.new_u8(val));
}
@Override
public void SaveBry(byte[] val) {
SaveInt(val.length, fldDlm);
bfr.Add(val).Add(rowDlm);
}
private void SaveInt(int val, byte[] dlm) {
bfr.Add_int_variable(val).Add(dlm);
}
@Override
public byte[] ToBry() {
return bfr.To_bry();
}
}

View File

@ -0,0 +1,24 @@
package gplx.core.serials.core;
import gplx.Err_;
import gplx.core.serials.binarys.BinaryLoadMgr;
import gplx.core.serials.binarys.BinarySaveMgr;
import gplx.core.texts.Base64Converter;
public class SerialCoreFactory {
public static SerialSaveMgr NewSaveMgr(int coreVersion) {
if (coreVersion == BinaryLoadMgr.CORE_VERSION) {
return new BinarySaveMgr();
}
throw Err_.new_unhandled_default(coreVersion);
}
public static SerialLoadMgr NewLoadMgr(byte[] data) {
int coreVersion = Base64Converter.GetIndexInt((char)data[0]);
if (coreVersion == BinaryLoadMgr.CORE_VERSION) {
BinaryLoadMgr loadMgr = new BinaryLoadMgr();
loadMgr.ReadHeader(data);
return loadMgr;
}
throw Err_.new_unhandled_default(coreVersion);
}
}

View File

@ -0,0 +1,10 @@
package gplx.core.serials.core;
public interface SerialLoadMgr {
int CoreVersion();
int DataVersion();
SerialLoadWkr NewLoadWkr();
void ReadHeader(byte[] data);
byte[] Data();
int HeaderEnd();
}

View File

@ -0,0 +1,9 @@
package gplx.core.serials.core;
public interface SerialLoadWkr {
SerialLoadWkr Ctor(SerialLoadMgr mgr);
void Init(byte[] src, int cur);
int LoadInt();
byte[] LoadBry();
String LoadStr();
}

View File

@ -0,0 +1,6 @@
package gplx.core.serials.core;
public interface SerialSaveMgr {
int CoreVersion();
SerialSaveWkr NewSaveWkr();
}

View File

@ -0,0 +1,11 @@
package gplx.core.serials.core;
public interface SerialSaveWkr {
SerialSaveWkr Ctor(SerialSaveMgr mgr);
void Init();
void SaveHdr(int dataVersion);
void SaveInt(int val);
void SaveStr(String val);
void SaveBry(byte[] val);
byte[] ToBry();
}

View File

@ -1,18 +1,18 @@
/*
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
*/
/*
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.gfs; import gplx.*; import gplx.langs.*;
import gplx.core.btries.*;
public class Gfs_parser {

View File

@ -0,0 +1,157 @@
package gplx.langs.javascripts;
import gplx.Err_;
import gplx.String_;
import gplx.langs.javascripts.util.regex.JsPattern_;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JsString_ {
public static boolean charAtEq(String s, int i, char m) {
int len = s.length();
if (i < 0 || i >= len) {
return false;
} else {
return s.charAt(i) == m;
}
}
public static boolean charAtEqNot(String s, int i, char m) {
int len = s.length();
if (i < 0 || i >= len) {
return false;
} else {
return s.charAt(i) != m;
}
}
public static String charAt(String s, int i) {
int len = s.length();
if (i < 0 || i >= len) {
return String_.Empty;
} else {
return Character.toString(s.charAt(i));
}
}
public static String slice(String str, int beginIndex) {
return slice(str, beginIndex, str.length());
}
// REF.JOS:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice
public static String slice(String str, int beginIndex, int endIndex) {
int srcLen = str.length();
// bgn
if (beginIndex < 0) {
beginIndex = srcLen + beginIndex;
if (beginIndex < 0) {
beginIndex = 0;
}
}
else if (beginIndex > srcLen) {
return "";
}
// end
if (endIndex < 0) {
endIndex = srcLen + endIndex;
if (endIndex < 0) {
endIndex = 0;
}
}
else if (endIndex > srcLen) {
endIndex = srcLen;
}
if (endIndex < beginIndex) {
return "";
}
return str.substring(beginIndex, endIndex);
}
private static final int
REPLACE_TYPE_STR = 0
, REPLACE_TYPE_MATCHER = 1
, REPLACE_TYPE_ARG1 = 2
, REPLACE_TYPE_ARG2 = 3
, REPLACE_TYPE_ARG3 = 4
;
public interface JsStringReplaceArg1 {
String processMatcher(String all);
}
public interface JsStringReplaceArg2 {
String processMatcher(String all, String arg1);
}
public interface JsStringReplaceArg3 {
String processMatcher(String all, String arg1, String arg2);
}
public interface JsStringReplaceMatcher {
String processMatcher(Matcher m);
}
public static String replace(String s, ConcurrentHashMap<String, Pattern> map, String p, String repl) {
return replace(s, map, p, JsPattern_.NONE, repl);
}
public static String replace(String src, ConcurrentHashMap<String, Pattern> map, String pat, int patFlags, String repl) {
return replaceObject(src, map, pat, patFlags, repl, REPLACE_TYPE_STR);
}
public static String replaceArg1(String src, ConcurrentHashMap<String, Pattern> map, String pat, JsStringReplaceArg1 func) {
return replaceObject(src, map, pat, JsPattern_.NONE, func, REPLACE_TYPE_ARG1);
}
public static String replaceArg1(String src, ConcurrentHashMap<String, Pattern> map, String pat, int patFlags, JsStringReplaceArg1 func) {
return replaceObject(src, map, pat, patFlags, func, REPLACE_TYPE_ARG1);
}
public static String replaceArg2(String src, ConcurrentHashMap<String, Pattern> map, String pat, JsStringReplaceArg2 func) {
return replaceObject(src, map, pat, JsPattern_.NONE, func, REPLACE_TYPE_ARG2);
}
public static String replaceArg2(String src, ConcurrentHashMap<String, Pattern> map, String pat, int patFlags, JsStringReplaceArg2 func) {
return replaceObject(src, map, pat, patFlags, func, REPLACE_TYPE_ARG2);
}
public static String replaceArg3(String src, ConcurrentHashMap<String, Pattern> map, String pat, int patFlags, JsStringReplaceArg3 func) {
return replaceObject(src, map, pat, patFlags, func, REPLACE_TYPE_ARG3);
}
public static String replaceMatcher(String src, ConcurrentHashMap<String, Pattern> map, String pat, int patFlags, JsStringReplaceMatcher func) {
return replaceObject(src, map, pat, patFlags, func, REPLACE_TYPE_MATCHER);
}
private static String replaceObject(String src, ConcurrentHashMap<String, Pattern> map, String pat, int patFlags, Object replObj, int replType) {
Pattern pattern = JsPattern_.getOrCompile(map, pat, patFlags);
// match
Matcher m = pattern.matcher(src);
StringBuffer sb = null;
while (m.find()) {
// get repl
String repl = null;
switch (replType) {
case REPLACE_TYPE_STR:
repl = (String)replObj;
break;
case REPLACE_TYPE_MATCHER:
repl = ((JsStringReplaceMatcher)replObj).processMatcher(m);
break;
case REPLACE_TYPE_ARG1:
repl = ((JsStringReplaceArg1)replObj).processMatcher(m.group(0));
break;
case REPLACE_TYPE_ARG2:
repl = ((JsStringReplaceArg2)replObj).processMatcher(m.group(0), m.group(1));
break;
case REPLACE_TYPE_ARG3:
repl = ((JsStringReplaceArg3)replObj).processMatcher(m.group(0), m.group(1), m.group(2));
break;
default:
throw Err_.new_unhandled_default(replType);
}
if (sb == null) {
sb = new StringBuffer();
}
m.appendReplacement(sb, repl);
}
// return
if (sb != null) {
m.appendTail(sb);
return sb.toString();
}
else {
return src;
}
}
}

View File

@ -0,0 +1,18 @@
package gplx.langs.javascripts.util.regex;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
public class JsPattern_ {
public static final int NONE = 0;
public static Pattern getOrCompile(ConcurrentHashMap<String, Pattern> map, String pat) {return getOrCompile(map, pat, NONE);}
public static Pattern getOrCompile(ConcurrentHashMap<String, Pattern> map, String pat, int patFlags) {
// get pattern
Pattern pattern = map.get(pat);
if (pattern == null) {
pattern = Pattern.compile(pat, patFlags);
map.put(pat, pattern);
}
return pattern;
}
}

View 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);}
}

View File

@ -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();}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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("\\\"");
}

View File

@ -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);}
}

View File

@ -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();
}

View File

@ -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;}
}

View File

@ -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;}
}

View File

@ -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);}
}

View File

@ -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;}
}

View File

@ -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;}
}

View File

@ -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);}
}

View File

@ -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));}
}

View File

@ -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;}
}

View File

@ -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());}
}

View File

@ -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,157 +13,205 @@ 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_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(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 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;}
}
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;}
}

View File

@ -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,172 +13,185 @@ 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 {
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");
}
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);
}
}

View File

@ -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) {}
}

View File

@ -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();
}
}

View 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;}
}

View File

@ -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);
}

View File

@ -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}}", "&lt;");
}
@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}}", "&lt;");
}
@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);
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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}} -> &lt;a&gt;
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}} -> &lt;a&gt;
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}} -> &lt;a&gt;
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}} -> &lt;a&gt;
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);}
}

View File

@ -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;
}
}
}

View File

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2021 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,36 +13,46 @@ 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; import gplx.*;
import gplx.core.log_msgs.*;
import gplx.xowa.guis.views.boots.*; import gplx.xowa.apps.boots.*;
public class Xoa_app_ {
public static void Run(String... args) {
Xoa_cmd_arg_mgr arg_mgr = Xoa_cmd_arg_mgr.new_();
try {
Xoa_boot_mgr boot_mgr = new Xoa_boot_mgr();
boot_mgr.Run(args, arg_mgr);
} catch (Error e) {
if (arg_mgr.App_type().Tid_is_gui())
Xog_error_win.Run(Err_.Message_lang(e), Err_.Trace_lang(e));
else
throw e;
}
}
public static final String Name = "xowa";
public static final int Version_id = 551;
public static final String Version = "4.6.5.1911";
public static String Build_date = "2012-12-30 00:00:00";
public static String Build_date_fmt = "yyyy-MM-dd HH:mm:ss";
public static String Op_sys_str;
public static String User_agent = "";
public static Gfo_usr_dlg Usr_dlg() {return usr_dlg;} public static void Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v;} private static Gfo_usr_dlg usr_dlg;
public static Gfo_usr_dlg New__usr_dlg__console() {
Gfo_usr_dlg rv = new Gfo_usr_dlg_base(new Gfo_usr_dlg__log_base(), Gfo_usr_dlg__gui_.Console);
rv.Log_wkr().Queue_enabled_(true);
return rv;
}
public static final Gfo_msg_grp Nde = Gfo_msg_grp_.prj_(Name);
}
package gplx.xowa;
import gplx.Err_;
import gplx.Gfo_usr_dlg;
import gplx.Gfo_usr_dlg__gui_;
import gplx.Gfo_usr_dlg__log_base;
import gplx.Gfo_usr_dlg_base;
import gplx.core.log_msgs.Gfo_msg_grp;
import gplx.core.log_msgs.Gfo_msg_grp_;
import gplx.xowa.apps.boots.Xoa_boot_mgr;
import gplx.xowa.apps.boots.Xoa_cmd_arg_mgr;
import gplx.xowa.guis.views.boots.Xog_error_win;
public class Xoa_app_ {
public static void Run(String... args) {
Xoa_cmd_arg_mgr arg_mgr = Xoa_cmd_arg_mgr.new_();
try {
Xoa_boot_mgr boot_mgr = new Xoa_boot_mgr();
boot_mgr.Run(args, arg_mgr);
} catch (Error e) {
if (arg_mgr.App_type().Tid_is_gui())
Xog_error_win.Run(Err_.Message_lang(e), Err_.Trace_lang(e));
else
throw e;
}
}
public static final String Name = "xowa";
public static final int Version_id = 560;
public static final String Version = "4.6.15.2101";
public static final String Build_date_fmt = "yyyy-MM-dd HH:mm:ss";
public static String Build_date = "2012-12-30 00:00:00";
public static String User_agent = "";
public static String Op_sys_str;
public static Gfo_usr_dlg Usr_dlg() {return usr_dlg;} public static void Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v;} private static Gfo_usr_dlg usr_dlg;
public static Gfo_usr_dlg New__usr_dlg__console() {
Gfo_usr_dlg rv = new Gfo_usr_dlg_base(new Gfo_usr_dlg__log_base(), Gfo_usr_dlg__gui_.Console);
rv.Log_wkr().Queue_enabled_(true);
return rv;
}
public static final Gfo_msg_grp Nde = Gfo_msg_grp_.prj_(Name);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,32 @@
/*
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.addons; import gplx.*; import gplx.xowa.*;
import gplx.xowa.addons.wikis.searchs.gui.urlbars.*; import gplx.xowa.addons.wikis.searchs.gui.htmlbars.*; import gplx.xowa.addons.wikis.searchs.specials.*;
/*
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.xowa.addons;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.Ordered_hash;
import gplx.Ordered_hash_;
import gplx.Type_;
import gplx.xowa.Xoa_app;
import gplx.xowa.Xoae_app;
import gplx.xowa.Xow_wiki;
import gplx.xowa.addons.wikis.searchs.gui.htmlbars.Srch_htmlbar_mgr;
import gplx.xowa.addons.wikis.searchs.gui.urlbars.Srch_urlbar_mgr;
import gplx.xowa.addons.wikis.searchs.specials.Srch_special_cfg;
public class Xoax_addon_mgr {
private final Ordered_hash hash = Ordered_hash_.New(); // LOCK: must synchronized else two search tabs will fail on startup
public Xoax_addon_itm Itms__get_or_null(String key) {synchronized (hash) {return (Xoax_addon_itm)hash.Get_by(key);}}
@ -57,12 +69,16 @@ public class Xoax_addon_mgr {
, new gplx.xowa.addons.wikis.ctgs.bldrs .Xoax_ctg_bldr_addon()
, new gplx.xowa.xtns.wbases.imports .Xowb_bldr_addon()
// app infrastructure
, new gplx.xowa.addons.apps.settings .SettingsAddon()
// xtns
, new gplx.xowa.xtns.math .Xomath_addon()
, new gplx.xowa.xtns.template_styles .Template_styles_addon()
, new gplx.xowa.xtns.hieros .Hiero_addon()
, new gplx.xowa.xtns.imaps .Imap_addon()
, new gplx.xowa.xtns.graphs .Graph_addon()
, new gplx.xowa.xtns.indicators .Indicator_addon()
// specials
, new gplx.xowa.addons.wikis.registrys .Wiki_registry_addon()

View File

@ -1,23 +1,33 @@
/*
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.addons.apps.cfgs.specials.edits.objs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*; import gplx.xowa.addons.apps.cfgs.specials.*; import gplx.xowa.addons.apps.cfgs.specials.edits.*;
import gplx.langs.mustaches.*;
import gplx.core.gfobjs.*; import gplx.langs.jsons.*;
import gplx.xowa.addons.apps.cfgs.mgrs.types.*; import gplx.xowa.addons.apps.cfgs.enums.*;
import gplx.langs.htmls.*;
/*
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.xowa.addons.apps.cfgs.specials.edits.objs;
import gplx.Bool_;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.String_;
import gplx.core.gfobjs.Gfobj_nde;
import gplx.langs.htmls.Gfh_utl;
import gplx.langs.mustaches.Mustache_bfr;
import gplx.langs.mustaches.Mustache_doc_itm;
import gplx.langs.mustaches.Mustache_doc_itm_;
import gplx.xowa.addons.apps.cfgs.Xocfg_mgr;
import gplx.xowa.addons.apps.cfgs.enums.Xoitm_type_enum;
import gplx.xowa.addons.apps.cfgs.mgrs.types.Xocfg_type_mgr;
public class Xoedit_itm implements Xoedit_nde, Mustache_doc_itm {
private boolean edited;
private String type, html_atrs, html_cls, lang, name, ctx, date;
@ -36,7 +46,7 @@ public class Xoedit_itm implements Xoedit_nde, Mustache_doc_itm {
public int Sort() {return sort;} private final int sort;
public void Load_by_meta(Bry_bfr tmp_bfr, String type, String dflt_str, String html_atrs, String html_cls) {
this.type = type;
this.dflt = Gfh_utl.Escape_html_as_bry(tmp_bfr, Bry_.new_u8(dflt_str), Bool_.N, Bool_.N, Bool_.N, Bool_.Y, Bool_.N);
this.dflt = Escape(tmp_bfr, type, dflt_str);
this.html_atrs = html_atrs;
this.html_cls = html_cls;
}
@ -47,7 +57,7 @@ public class Xoedit_itm implements Xoedit_nde, Mustache_doc_itm {
}
public void Load_by_data(Bry_bfr tmp_bfr, String ctx, String val_str, String date) {
this.ctx = ctx;
this.val = Gfh_utl.Escape_html_as_bry(tmp_bfr, Bry_.new_u8(val_str), Bool_.N, Bool_.N, Bool_.N, Bool_.Y, Bool_.N);
this.val = Escape(tmp_bfr, type, val_str);
this.date = date;
this.edited = true;
if ( String_.Has(html_cls, "read"+"only")
@ -98,4 +108,14 @@ public class Xoedit_itm implements Xoedit_nde, Mustache_doc_itm {
if (String_.Eq(k, "edited")) return Mustache_doc_itm_.Ary__bool(edited);
return Mustache_doc_itm_.Ary__empty;
}
private static byte[] Escape(Bry_bfr tmp_bfr, String type, String val_str) {
// NOTE: do not escape quotes for memo because it uses <textarea> which can use quotes;
// contrast with <input> which uses quotes for `value` property;
// EX: <input value="a&quot;b"> vs <textarea>a"b</textarea>
boolean escapeQuotes = Xoitm_type_enum.To_uid(type) == Xoitm_type_enum.Tid__memo
? Bool_.N
: Bool_.Y;
return Gfh_utl.Escape_html_as_bry(tmp_bfr, Bry_.new_u8(val_str), Bool_.N, Bool_.N, Bool_.N, escapeQuotes, Bool_.N);
}
}

View File

@ -1,23 +1,45 @@
/*
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.addons.apps.cfgs.specials.edits.services; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*; import gplx.xowa.addons.apps.cfgs.specials.*; import gplx.xowa.addons.apps.cfgs.specials.edits.*;
import gplx.dbs.*;
import gplx.xowa.addons.apps.cfgs.dbs.*; import gplx.xowa.addons.apps.cfgs.dbs.tbls.*;
import gplx.xowa.addons.apps.cfgs.specials.edits.objs.*;
import gplx.xowa.addons.apps.cfgs.mgrs.*; import gplx.xowa.addons.apps.cfgs.mgrs.dflts.*; import gplx.xowa.addons.apps.cfgs.mgrs.types.*;
/*
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.xowa.addons.apps.cfgs.specials.edits.services;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Err_;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.Ordered_hash;
import gplx.Ordered_hash_;
import gplx.String_;
import gplx.dbs.Db_rdr;
import gplx.dbs.Db_sql_;
import gplx.xowa.Xoa_app;
import gplx.xowa.addons.apps.cfgs.dbs.Xocfg_db_app;
import gplx.xowa.addons.apps.cfgs.dbs.Xocfg_db_usr;
import gplx.xowa.addons.apps.cfgs.dbs.tbls.Xocfg_grp_row;
import gplx.xowa.addons.apps.cfgs.mgrs.dflts.Xocfg_dflt_mgr;
import gplx.xowa.addons.apps.cfgs.mgrs.types.Xocfg_type_mgr;
import gplx.xowa.addons.apps.cfgs.specials.edits.objs.Xoedit_grp;
import gplx.xowa.addons.apps.cfgs.specials.edits.objs.Xoedit_itm;
import gplx.xowa.addons.apps.cfgs.specials.edits.objs.Xoedit_nav_itm;
import gplx.xowa.addons.apps.cfgs.specials.edits.objs.Xoedit_nav_mgr;
import gplx.xowa.addons.apps.cfgs.specials.edits.objs.Xoedit_nde;
import gplx.xowa.addons.apps.cfgs.specials.edits.objs.Xoedit_nde_hash;
import gplx.xowa.addons.apps.cfgs.specials.edits.objs.Xoedit_root;
import gplx.xowa.addons.apps.cfgs.specials.edits.objs.Xogui_nde_iter;
public class Xocfg_edit_loader {
private final Xocfg_db_app db_app;
private final Xocfg_db_usr db_usr;

View File

@ -0,0 +1,25 @@
/*
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.xowa.addons.apps.settings;
import gplx.langs.jsons.Json_doc;
import gplx.xowa.Xow_wiki;
public interface CfgResolver {
String Key();
void WhenCfgChanged(Json_doc jdoc);
void WhenWikiCreated(Xow_wiki wikii);
}

View File

@ -0,0 +1,83 @@
/*
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.xowa.addons.apps.settings;
import gplx.GfoMsg;
import gplx.Gfo_invk;
import gplx.GfsCtx;
import gplx.Ordered_hash;
import gplx.Ordered_hash_;
import gplx.langs.jsons.Json_doc;
import gplx.langs.jsons.Json_parser;
import gplx.objects.errs.Err_;
import gplx.xowa.Xoa_app;
import gplx.xowa.Xow_wiki;
import gplx.xowa.addons.Xoax_addon_itm;
import gplx.xowa.addons.Xoax_addon_itm__init;
import gplx.xowa.xtns.scribunto.cfgs.ScribCfgResolverApp;
public class SettingsAddon implements Xoax_addon_itm, Xoax_addon_itm__init, Gfo_invk {
private final Ordered_hash hash = Ordered_hash_.New();
private Json_doc jdoc;
private boolean init = true;
public String Addon__key() {return ADDON_KEY;} public static final String ADDON_KEY = "xowa.app.settings";
@Override
public void Init_addon_by_app(Xoa_app app) {
// NOTE: should move to addon_mgr and create a new interface for settings
this.Add(new ScribCfgResolverApp(app));
}
private void Add(CfgResolver mgr) {
hash.Add(mgr.Key(), mgr);
}
@Override
public void Init_addon_by_wiki(Xow_wiki wiki) {
if (init) { // NOTE: cannot `init` in `Init_addon_by_app` b/c `Bind_many` will try to load from db, and dbEngine is not set yet
Update(wiki.App().Cfg().Get_str_app_or(CFG_PUBLISH, null));
}
else {
if (jdoc == null) return;
for (int i = 0; i < hash.Len(); i++) {
CfgResolver resolver = (CfgResolver)hash.Get_at(i);
resolver.WhenWikiCreated(wiki);
}
}
}
private void Update(String json) {
init = false;
if (json == null) return;
this.jdoc = Json_parser.ParseToJdoc(json);
if (jdoc == null) return;
for (int i = 0; i < hash.Len(); i++) {
CfgResolver resolver = (CfgResolver)hash.Get_at(i);
resolver.WhenCfgChanged(jdoc);
}
}
@Override
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
switch (k) {
case CFG_PUBLISH:
Update(m.ReadStrOr("v", null));
break;
default:
throw Err_.New_unhandled_default(k);
}
return null;
}
private static final String CFG_PUBLISH = "xowa.app.settings.publish";
}

View File

@ -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,84 +13,99 @@ 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.addons.bldrs.mass_parses.parses.mgrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.bldrs.*; import gplx.xowa.addons.bldrs.mass_parses.*; import gplx.xowa.addons.bldrs.mass_parses.parses.*;
import gplx.core.ios.streams.*;
public class Xomp_parse_mgr_cfg implements Gfo_invk {
public int Num_wkrs() {return num_wkrs;} private int num_wkrs = -1;
public int Num_pages_in_pool() {return num_pages_in_pool;} private int num_pages_in_pool = -1;
public int Num_pages_per_wkr() {return num_pages_per_wkr;} private int num_pages_per_wkr = 1000;
public int Progress_interval() {return progress_interval;} private int progress_interval = 1000;
public int Perf_interval() {return perf_interval;} private int perf_interval = 10000;
public int Commit_interval() {return commit_interval;} private int commit_interval = 10000;
public int Cleanup_interval() {return cleanup_interval;} private int cleanup_interval = 50; // setting at 1000 uses lots of memory
public boolean Hdump_enabled() {return hdump_enabled;} private boolean hdump_enabled = true;
public boolean Hdump_catboxs() {return hdump_catboxs;} private boolean hdump_catboxs = false;
public boolean Hzip_enabled() {return hzip_enabled;} private boolean hzip_enabled = true;
public boolean Hdiff_enabled() {return hdiff_enabled;} private boolean hdiff_enabled = true;
public boolean Log_file_lnkis() {return log_file_lnkis;} private boolean log_file_lnkis = true;
public boolean Load_all_templates() {return load_all_templates;} private boolean load_all_templates = true;
public boolean Load_all_imglinks() {return load_all_imglinks;} private boolean load_all_imglinks = true;
public String Load_ifexists_ns() {return load_ifexists_ns;} private String load_ifexists_ns = null;
public boolean Log_math() {return log_math;} private boolean log_math = false;
public byte Zip_tid() {return zip_tid;} private byte zip_tid = Io_stream_tid_.Tid__gzip;
public Io_url Mgr_url() {return mgr_url;} private Io_url mgr_url;
public String Wkr_machine_name() {return wkr_machine_name;} private String wkr_machine_name;
public boolean Show_msg__fetched_pool() {return show_msg__fetched_pool;} private boolean show_msg__fetched_pool;
public boolean Indexer_enabled() {return indexer_enabled;} private boolean indexer_enabled;
public String Indexer_opt() {return indexer_opt;} private String indexer_opt = gplx.gflucene.indexers.Gflucene_idx_opt.Docs_and_freqs.Key();
public String Wbase_cache_mru_type() {return wbase_cache_mru_type;} private String wbase_cache_mru_type = "mru";
public long Wbase_cache_mru_size() {return wbase_cache_mru_size;} private long wbase_cache_mru_size = 100;
public long Wbase_cache_mru_weight() {return wbase_cache_mru_weight;} private long wbase_cache_mru_weight = 10;
public long Wbase_cache_mru_compress_size() {return wbase_cache_mru_compress_size;} private long wbase_cache_mru_compress_size = 70;
public long Page_cache_min() {return page_cache_min;} private long page_cache_min = 1500 * Io_mgr.Len_mb_long;
public long Page_cache_max() {return page_cache_max;} private long page_cache_max = 2000 * Io_mgr.Len_mb_long;
public void Init(Xowe_wiki wiki) {
if (num_wkrs == -1) num_wkrs = gplx.core.envs.Runtime_.Cpu_count();
if (num_pages_in_pool == -1) num_pages_in_pool = num_wkrs * 1000;
if (mgr_url == null) mgr_url = wiki.Fsys_mgr().Root_dir().GenSubDir_nest("tmp", "xomp");
if (wkr_machine_name == null) wkr_machine_name = gplx.core.envs.System_.Env__machine_name();
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__num_wkrs_)) num_wkrs = m.ReadInt("v");
else if (ctx.Match(k, Invk__num_pages_in_pool_)) num_pages_in_pool = m.ReadInt("v");
else if (ctx.Match(k, Invk__num_pages_per_wkr_)) num_pages_per_wkr = m.ReadInt("v");
else if (ctx.Match(k, Invk__progress_interval_)) progress_interval = m.ReadInt("v");
else if (ctx.Match(k, "perf_interval_")) perf_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk__commit_interval_)) commit_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk__cleanup_interval_)) cleanup_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk__hdump_enabled_)) hdump_enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk__hzip_enabled_)) hzip_enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk__hdiff_enabled_)) hdiff_enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk__zip_tid_)) zip_tid = m.ReadByte("v");
else if (ctx.Match(k, Invk__load_all_templates_)) load_all_templates = m.ReadYn("v");
else if (ctx.Match(k, Invk__load_all_imglinks_)) load_all_imglinks = m.ReadYn("v");
else if (ctx.Match(k, Invk__load_ifexists_ns_)) load_ifexists_ns = m.ReadStr("v");
else if (ctx.Match(k, Invk__manual_now_)) Datetime_now.Manual_and_freeze_(m.ReadDate("v"));
else if (ctx.Match(k, Invk__mgr_url_)) mgr_url = m.ReadIoUrl("v");
else if (ctx.Match(k, Invk__wkr_machine_name_)) wkr_machine_name = m.ReadStr("v");
else if (ctx.Match(k, Invk__show_msg__fetched_pool_)) show_msg__fetched_pool = m.ReadYn("v");
else if (ctx.Match(k, Invk__hdump_catboxes_)) hdump_catboxs = m.ReadYn("v");
else if (ctx.Match(k, Invk__log_math_)) log_math = m.ReadYn("v");
else if (ctx.Match(k, "indexer_enabled_")) indexer_enabled = m.ReadYn("v");
else if (ctx.Match(k, "indexer_opt_")) indexer_opt = m.ReadStr("v");
else if (ctx.Match(k, "wbase_cache_mru_type_")) wbase_cache_mru_type = m.ReadStr("v");
else if (ctx.Match(k, "wbase_cache_mru_size_")) wbase_cache_mru_size = m.ReadLong("v");
else if (ctx.Match(k, "wbase_cache_mru_weight_")) wbase_cache_mru_weight = m.ReadLong("v");
else if (ctx.Match(k, "wbase_cache_mru_compress_size_")) wbase_cache_mru_compress_size = m.ReadLong("v");
else if (ctx.Match(k, "page_cache_min_")) page_cache_min = gplx.core.ios.Io_size_.parse_or(m.ReadStr("v"), page_cache_min);
else if (ctx.Match(k, "page_cache_max_")) page_cache_max = gplx.core.ios.Io_size_.parse_or(m.ReadStr("v"), page_cache_max);
else return Gfo_invk_.Rv_unhandled;
return this;
}
private static final String
Invk__num_wkrs_ = "num_wkrs_", Invk__num_pages_in_pool_ = "num_pages_in_pool_", Invk__num_pages_per_wkr_ = "num_pages_per_wkr_"
, Invk__progress_interval_ = "progress_interval_", Invk__commit_interval_ = "commit_interval_", Invk__cleanup_interval_ = "cleanup_interval_"
, Invk__hdump_enabled_ = "hdump_enabled_", Invk__hzip_enabled_ = "hzip_enabled_", Invk__hdiff_enabled_ = "hdiff_enabled_", Invk__zip_tid_ = "zip_tid_"
, Invk__load_all_templates_ = "load_all_templates_", Invk__load_all_imglinks_ = "load_all_imglinks_", Invk__load_ifexists_ns_ = "load_ifexists_ns_", Invk__manual_now_ = "manual_now_"
, Invk__hdump_catboxes_ = "hdump_catboxes_"
, Invk__log_math_ = "log_math_"
, Invk__mgr_url_ = "mgr_url_", Invk__wkr_machine_name_ = "wkr_machine_name_"
, Invk__show_msg__fetched_pool_ = "show_msg__fetched_pool_"
;
}
package gplx.xowa.addons.bldrs.mass_parses.parses.mgrs;
import gplx.Datetime_now;
import gplx.GfoMsg;
import gplx.Gfo_invk;
import gplx.Gfo_invk_;
import gplx.GfsCtx;
import gplx.Io_mgr;
import gplx.Io_url;
import gplx.core.ios.streams.Io_stream_tid_;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.parsers.logs.Xop_log_invoke_wkr;
import gplx.xowa.xtns.scribunto.Scrib_err_filter_mgr;
public class Xomp_parse_mgr_cfg implements Gfo_invk {
public int Num_wkrs() {return num_wkrs;} private int num_wkrs = -1;
public int Num_pages_in_pool() {return num_pages_in_pool;} private int num_pages_in_pool = -1;
public int Num_pages_per_wkr() {return num_pages_per_wkr;} private int num_pages_per_wkr = 1000;
public int Progress_interval() {return progress_interval;} private int progress_interval = 1000;
public int Perf_interval() {return perf_interval;} private int perf_interval = 10000;
public int Commit_interval() {return commit_interval;} private int commit_interval = 10000;
public int Cleanup_interval() {return cleanup_interval;} private int cleanup_interval = 50; // setting at 1000 uses lots of memory
public boolean Hdump_enabled() {return hdump_enabled;} private boolean hdump_enabled = true;
public boolean Hdump_catboxs() {return hdump_catboxs;} private boolean hdump_catboxs = false;
public boolean Hzip_enabled() {return hzip_enabled;} private boolean hzip_enabled = true;
public boolean Hdiff_enabled() {return hdiff_enabled;} private boolean hdiff_enabled = true;
public boolean Log_file_lnkis() {return log_file_lnkis;} private boolean log_file_lnkis = true;
public boolean Load_all_templates() {return load_all_templates;} private boolean load_all_templates = true;
public boolean Load_all_imglinks() {return load_all_imglinks;} private boolean load_all_imglinks = true;
public String Load_ifexists_ns() {return load_ifexists_ns;} private String load_ifexists_ns = null;
public boolean Log_math() {return log_math;} private boolean log_math = false;
public byte Zip_tid() {return zip_tid;} private byte zip_tid = Io_stream_tid_.Tid__gzip;
public Io_url Mgr_url() {return mgr_url;} private Io_url mgr_url;
public String Wkr_machine_name() {return wkr_machine_name;} private String wkr_machine_name;
public boolean Show_msg__fetched_pool() {return show_msg__fetched_pool;} private boolean show_msg__fetched_pool;
public boolean Indexer_enabled() {return indexer_enabled;} private boolean indexer_enabled;
public String Indexer_opt() {return indexer_opt;} private String indexer_opt = gplx.gflucene.indexers.Gflucene_idx_opt.Docs_and_freqs.Key();
public String Wbase_cache_mru_type() {return wbase_cache_mru_type;} private String wbase_cache_mru_type = "mru";
public long Wbase_cache_mru_size() {return wbase_cache_mru_size;} private long wbase_cache_mru_size = 100;
public long Wbase_cache_mru_weight() {return wbase_cache_mru_weight;} private long wbase_cache_mru_weight = 10;
public long Wbase_cache_mru_compress_size() {return wbase_cache_mru_compress_size;} private long wbase_cache_mru_compress_size = 70;
public long Page_cache_min() {return page_cache_min;} private long page_cache_min = 1500 * Io_mgr.Len_mb_long;
public long Page_cache_max() {return page_cache_max;} private long page_cache_max = 2000 * Io_mgr.Len_mb_long;
public void Init(Xowe_wiki wiki) {
if (num_wkrs == -1) num_wkrs = gplx.core.envs.Runtime_.Cpu_count();
if (num_pages_in_pool == -1) num_pages_in_pool = num_wkrs * 1000;
if (mgr_url == null) mgr_url = wiki.Fsys_mgr().Root_dir().GenSubDir_nest("tmp", "xomp");
if (wkr_machine_name == null) wkr_machine_name = gplx.core.envs.System_.Env__machine_name();
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__num_wkrs_)) num_wkrs = m.ReadInt("v");
else if (ctx.Match(k, Invk__num_pages_in_pool_)) num_pages_in_pool = m.ReadInt("v");
else if (ctx.Match(k, Invk__num_pages_per_wkr_)) num_pages_per_wkr = m.ReadInt("v");
else if (ctx.Match(k, Invk__progress_interval_)) progress_interval = m.ReadInt("v");
else if (ctx.Match(k, "perf_interval_")) perf_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk__commit_interval_)) commit_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk__cleanup_interval_)) cleanup_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk__hdump_enabled_)) hdump_enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk__hzip_enabled_)) hzip_enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk__hdiff_enabled_)) hdiff_enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk__zip_tid_)) zip_tid = m.ReadByte("v");
else if (ctx.Match(k, Invk__load_all_templates_)) load_all_templates = m.ReadYn("v");
else if (ctx.Match(k, Invk__load_all_imglinks_)) load_all_imglinks = m.ReadYn("v");
else if (ctx.Match(k, Invk__load_ifexists_ns_)) load_ifexists_ns = m.ReadStr("v");
else if (ctx.Match(k, Invk__manual_now_)) Datetime_now.Manual_and_freeze_(m.ReadDate("v"));
else if (ctx.Match(k, Invk__mgr_url_)) mgr_url = m.ReadIoUrl("v");
else if (ctx.Match(k, Invk__wkr_machine_name_)) wkr_machine_name = m.ReadStr("v");
else if (ctx.Match(k, Invk__show_msg__fetched_pool_)) show_msg__fetched_pool = m.ReadYn("v");
else if (ctx.Match(k, Invk__hdump_catboxes_)) hdump_catboxs = m.ReadYn("v");
else if (ctx.Match(k, Invk__log_math_)) log_math = m.ReadYn("v");
else if (ctx.Match(k, "indexer_enabled_")) indexer_enabled = m.ReadYn("v");
else if (ctx.Match(k, "indexer_opt_")) indexer_opt = m.ReadStr("v");
else if (ctx.Match(k, "wbase_cache_mru_type_")) wbase_cache_mru_type = m.ReadStr("v");
else if (ctx.Match(k, "wbase_cache_mru_size_")) wbase_cache_mru_size = m.ReadLong("v");
else if (ctx.Match(k, "wbase_cache_mru_weight_")) wbase_cache_mru_weight = m.ReadLong("v");
else if (ctx.Match(k, "wbase_cache_mru_compress_size_")) wbase_cache_mru_compress_size = m.ReadLong("v");
else if (ctx.Match(k, "page_cache_min_")) page_cache_min = gplx.core.ios.Io_size_.parse_or(m.ReadStr("v"), page_cache_min);
else if (ctx.Match(k, "page_cache_max_")) page_cache_max = gplx.core.ios.Io_size_.parse_or(m.ReadStr("v"), page_cache_max);
else if (ctx.Match(k, Invk__err_filter)) return Scrib_err_filter_mgr.INSTANCE;
else return Gfo_invk_.Rv_unhandled;
return this;
}
private Xop_log_invoke_wkr invoke_wkr;
private static final String
Invk__num_wkrs_ = "num_wkrs_", Invk__num_pages_in_pool_ = "num_pages_in_pool_", Invk__num_pages_per_wkr_ = "num_pages_per_wkr_"
, Invk__progress_interval_ = "progress_interval_", Invk__commit_interval_ = "commit_interval_", Invk__cleanup_interval_ = "cleanup_interval_"
, Invk__hdump_enabled_ = "hdump_enabled_", Invk__hzip_enabled_ = "hzip_enabled_", Invk__hdiff_enabled_ = "hdiff_enabled_", Invk__zip_tid_ = "zip_tid_"
, Invk__load_all_templates_ = "load_all_templates_", Invk__load_all_imglinks_ = "load_all_imglinks_", Invk__load_ifexists_ns_ = "load_ifexists_ns_", Invk__manual_now_ = "manual_now_"
, Invk__hdump_catboxes_ = "hdump_catboxes_"
, Invk__log_math_ = "log_math_"
, Invk__mgr_url_ = "mgr_url_", Invk__wkr_machine_name_ = "wkr_machine_name_"
, Invk__show_msg__fetched_pool_ = "show_msg__fetched_pool_"
, Invk__err_filter = "err_filter"
;
}

View File

@ -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,208 +13,235 @@ 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.addons.bldrs.mass_parses.parses.wkrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.bldrs.*; import gplx.xowa.addons.bldrs.mass_parses.*; import gplx.xowa.addons.bldrs.mass_parses.parses.*;
import gplx.dbs.*; import gplx.xowa.addons.bldrs.mass_parses.dbs.*;
import gplx.xowa.files.origs.*;
import gplx.xowa.htmls.core.htmls.*; import gplx.xowa.htmls.core.bldrs.*; import gplx.xowa.htmls.hxtns.pages.*; import gplx.xowa.htmls.core.hzips.*;
import gplx.xowa.wikis.pages.*;
import gplx.xowa.parsers.*; import gplx.xowa.parsers.logs.*;
import gplx.xowa.addons.bldrs.mass_parses.parses.mgrs.*; import gplx.xowa.addons.bldrs.mass_parses.parses.utls.*; import gplx.xowa.addons.bldrs.mass_parses.parses.*; import gplx.xowa.addons.bldrs.mass_parses.parses.pools.*;
import gplx.xowa.addons.wikis.fulltexts.indexers.bldrs.*;
public class Xomp_parse_wkr implements Gfo_invk {
// mgr vars
private final Xomp_parse_mgr mgr;
private final Xomp_mgr_db mgr_db;
private final Xomp_prog_mgr prog_mgr;
private final Xomp_page_pool page_pool;
private final Xof_orig_wkr file_orig_wkr;
private final Xomp_ns_ord_mgr ns_ord_mgr;
// cfg vars
private final Xomp_parse_mgr_cfg cfg;
private int cleanup_interval, commit_interval;
private boolean log_file_lnkis;
// wkr vars
private final Xowe_wiki wiki;
private final Xob_hdump_bldr hdump_bldr = new Xob_hdump_bldr();
private final int uid;
private Xomp_wkr_db wkr_db;
private Xomp_stat_tbl stat_tbl;
private Hxtn_page_mgr hxtn_mgr;
// indexer vars
private final Xofulltext_indexer_wkr indexer;
private final List_adp list = List_adp_.New(); private int list_idx = 0, list_len = 0;
private int done_count; private long done_time;
public Xomp_parse_wkr(Xomp_parse_mgr mgr, Xomp_parse_mgr_cfg cfg
, Xomp_mgr_db mgr_db, Xomp_page_pool page_pool
, Xomp_prog_mgr prog_mgr, Xof_orig_wkr file_orig_wkr, Xomp_ns_ord_mgr ns_ord_mgr
, Xowe_wiki wiki, Xofulltext_indexer_wkr indexer, int uid) {
// mgr vars
this.mgr = mgr; this.mgr_db = mgr_db;
this.page_pool = page_pool; this.prog_mgr = prog_mgr; this.file_orig_wkr = file_orig_wkr;
this.ns_ord_mgr = ns_ord_mgr;
this.indexer = indexer;
// cfg vars
this.cfg = cfg;
this.cleanup_interval = cfg.Cleanup_interval();
this.commit_interval = cfg.Commit_interval();
this.log_file_lnkis = cfg.Log_file_lnkis();
// wkr-specific vars
this.wiki = wiki; this.uid = uid;
this.wkr_db = Xomp_wkr_db.New(Xomp_mgr_db.New__url(wiki), uid);
this.stat_tbl = new Xomp_stat_tbl(wkr_db.Conn());
this.hxtn_mgr = wiki.Hxtn_mgr();
this.hxtn_mgr.Init_by_xomp_wkr(wkr_db.Conn(), cfg.Zip_tid());
}
public void Exec() {
Xow_parser_mgr parser_mgr = wiki.Parser_mgr();
// disable file download
wiki.File_mgr().Init_file_mgr_by_load(wiki); // must happen after fsdb.make
wiki.File__bin_mgr().Wkrs__del(gplx.xowa.files.bins.Xof_bin_wkr_.Key_http_wmf); // must happen after init_file_mgr_by_load; remove wmf wkr, else will try to download images during parsing
wiki.File__orig_mgr().Wkrs__set(file_orig_wkr);
wiki.File_mgr().Fsdb_mode().Tid__v2__mp__y_();
// enable disable categories according to flag
wiki.Html_mgr().Page_wtr_mgr().Wkr(Xopg_view_mode_.Tid__read).Ctgs_enabled_(cfg.Hdump_catboxs());
// enable lnki_temp
Xomp_lnki_temp_wkr logger = null;
if (log_file_lnkis) {
logger = new Xomp_lnki_temp_wkr(wiki, wkr_db.Conn());
parser_mgr.Ctx().Lnki().File_logger_(logger);
logger.Bgn();
}
// init log_mgr / property_wkr / stats
Xop_log_wkr_factory wkr_factory = new Xop_log_wkr_factory(wkr_db.Conn());
if (cfg.Log_math()) wiki.Parser_mgr().Math__core().Log_wkr_(wkr_factory);
// enable hdump
hdump_bldr.Enabled_(cfg.Hdump_enabled()).Hzip_enabled_(cfg.Hzip_enabled()).Hzip_diff_(cfg.Hdiff_enabled()).Zip_tid_(cfg.Zip_tid());
hdump_bldr.Init(wiki, wkr_db.Conn(), new Xob_hdump_tbl_retriever__xomp(wkr_db.Html_tbl()));
wkr_db.Conn().Txn_bgn("xomp");
stat_tbl.Stmt_new();
hxtn_mgr.Insert_bgn(false);
Xoh_wtr_ctx hctx = Xoh_wtr_ctx.Hdump_by_hzip_tid(cfg.Hzip_enabled() ? Xoh_hzip_dict_.Hdb__hzip : Xoh_hzip_dict_.Hdb__htxt); // ISSUE#:553; DATE:2019-09-25
// set status to running
mgr_db.Tbl__wkr().Update_status(uid, Xomp_wkr_tbl.Status__running);
// main loop
int prv_ns = -1;
while (true) {
// get page from page pool
Xomp_page_itm ppg = Get_next();
if (ppg == Xomp_page_itm.Null) {
mgr_db.Tbl__wkr().Update_status(uid, Xomp_wkr_tbl.Status__sleeping);
break; // no more pages
}
if (ppg.Text() == null) continue; // some pages have no text; ignore them else null ref; PAGE: it.d:miercuri DATE:2015-12-05
try {
long done_bgn = gplx.core.envs.System_.Ticks();
// get ns / ttl
int cur_ns = ppg.Ns_id();
Xoa_ttl ttl = wiki.Ttl_parse(cur_ns, ppg.Ttl_bry());
// if ns changed and prv_ns is main
if (cur_ns != prv_ns) {
prv_ns = cur_ns;
}
// init page
Xoae_page wpg = Xoae_page.New(wiki, ttl);
wpg.Bldr__ns_ord_(ns_ord_mgr.Get_ord_by_ns_id(cur_ns)); // NOTE: must set ns_id for tier_id in lnki_temp; DATE:2016-09-19
wpg.Db().Text().Text_bry_(ppg.Text());
wpg.Db().Page().Init_by_mp(ppg.Id(), ppg.Page_score());
wpg.Stat_itm().Init(uid);
// parse page
Xop_ctx pctx = parser_mgr.Ctx();
pctx.Clear_all();
parser_mgr.Parse(wpg, true);
// gen_html
hdump_bldr.Insert(pctx, wpg, hctx);
// index
long fulltext_time = 0;
if (indexer != null) {
fulltext_time = gplx.core.envs.System_.Ticks();
indexer.Index(wpg);
fulltext_time = gplx.core.envs.System_.Ticks__elapsed_in_frac(fulltext_time);
}
// mark done for sake of progress
prog_mgr.Mark_done(ppg.Id());
// update stats
long time_cur = gplx.core.envs.System_.Ticks();
long page_time = time_cur - done_bgn;
done_time += page_time;
++done_count;
stat_tbl.Insert(wpg, hdump_bldr.Tmp_hpg(), uid, page_time, fulltext_time);
// cleanup
// ctx.App().Utl__bfr_mkr().Clear_fail_check(); // make sure all bfrs are released
if (wiki.Cache_mgr().Tmpl_result_cache().Count() > 50000)
wiki.Cache_mgr().Tmpl_result_cache().Clear();
if (done_count % cleanup_interval == 0) {
wiki.Cache_mgr().Free_mem__page();
wiki.Parser_mgr().Scrib().Core_term();
wiki.Appe().Wiki_mgr().Wdata_mgr().Clear();
}
if (done_count % commit_interval == 0) {
wkr_db.Conn().Txn_sav();
}
} catch (Exception e) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "mass_parse.fail:ns=~{0} ttl=~{1} err=~{2}", ppg.Ns_id(), ppg.Ttl_bry(), Err_.Message_gplx_log(e));
}
}
// cleanup
try {
if (logger != null) logger.End();
wkr_db.Conn().Txn_end();
wkr_db.Conn().Rls_conn();
stat_tbl.Stmt_rls();
hxtn_mgr.Insert_end(false);
mgr.Wkrs_done_add_1(); // NOTE: must release latch last else thread errors
}
catch (Exception e) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "mass_parse.fail_end; err=~{0}", Err_.Message_gplx_log(e));
}
}
public void Bld_stats(Bry_bfr bfr) {
int done_time_in_sec = (int)(done_time / 1000); if (done_time_in_sec == 0) done_time_in_sec = 1;
bfr.Add_int_pad_bgn(Byte_ascii.Space, 4, uid );
bfr.Add_int_pad_bgn(Byte_ascii.Space, 8, (int)(done_count / done_time_in_sec));
bfr.Add_int_pad_bgn(Byte_ascii.Space, 8, done_count);
bfr.Add_int_pad_bgn(Byte_ascii.Space, 8, done_time_in_sec);
bfr.Add_byte_nl();
}
private Xomp_page_itm Get_next() {
if (list_idx == list_len) {
mgr_db.Tbl__wkr().Update_exec(uid, done_count, done_time);
list.Clear();
page_pool.Get_next(mgr_db, cfg.Wkr_machine_name(), list);
list_len = list.Len();
if (list_len == 0) return Xomp_page_itm.Null;
list_idx = 0;
}
return (Xomp_page_itm)list.Get_at(list_idx++);
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__exec)) this.Exec();
else return Gfo_invk_.Rv_unhandled;
return this;
}
public static final String Invk__exec = "exec";
public static final String Cfg__ns_ids = "xomp.ns_ids";
}
package gplx.xowa.addons.bldrs.mass_parses.parses.wkrs;
import gplx.Bry_bfr;
import gplx.Byte_ascii;
import gplx.Err_;
import gplx.GfoMsg;
import gplx.Gfo_invk;
import gplx.Gfo_invk_;
import gplx.Gfo_usr_dlg_;
import gplx.GfsCtx;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.addons.bldrs.mass_parses.dbs.Xomp_mgr_db;
import gplx.xowa.addons.bldrs.mass_parses.dbs.Xomp_stat_tbl;
import gplx.xowa.addons.bldrs.mass_parses.dbs.Xomp_wkr_db;
import gplx.xowa.addons.bldrs.mass_parses.dbs.Xomp_wkr_tbl;
import gplx.xowa.addons.bldrs.mass_parses.parses.mgrs.Xomp_parse_mgr;
import gplx.xowa.addons.bldrs.mass_parses.parses.mgrs.Xomp_parse_mgr_cfg;
import gplx.xowa.addons.bldrs.mass_parses.parses.mgrs.Xomp_prog_mgr;
import gplx.xowa.addons.bldrs.mass_parses.parses.pools.Xomp_page_itm;
import gplx.xowa.addons.bldrs.mass_parses.parses.pools.Xomp_page_pool;
import gplx.xowa.addons.bldrs.mass_parses.parses.utls.Xomp_lnki_temp_wkr;
import gplx.xowa.addons.bldrs.mass_parses.parses.utls.Xomp_ns_ord_mgr;
import gplx.xowa.addons.wikis.fulltexts.indexers.bldrs.Xofulltext_indexer_wkr;
import gplx.xowa.files.origs.Xof_orig_wkr;
import gplx.xowa.htmls.core.bldrs.Xob_hdump_bldr;
import gplx.xowa.htmls.core.htmls.Xoh_wtr_ctx;
import gplx.xowa.htmls.core.hzips.Xoh_hzip_dict_;
import gplx.xowa.htmls.hxtns.pages.Hxtn_page_mgr;
import gplx.xowa.parsers.Xop_ctx;
import gplx.xowa.parsers.Xow_parser_mgr;
import gplx.xowa.parsers.logs.Xop_log_wkr_factory;
import gplx.xowa.wikis.pages.Xopg_view_mode_;
public class Xomp_parse_wkr implements Gfo_invk {
// mgr vars
private final Xomp_parse_mgr mgr;
private final Xomp_mgr_db mgr_db;
private final Xomp_prog_mgr prog_mgr;
private final Xomp_page_pool page_pool;
private final Xof_orig_wkr file_orig_wkr;
private final Xomp_ns_ord_mgr ns_ord_mgr;
// cfg vars
private final Xomp_parse_mgr_cfg cfg;
private int cleanup_interval, commit_interval;
private boolean log_file_lnkis;
// wkr vars
private final Xowe_wiki wiki;
private final Xob_hdump_bldr hdump_bldr = new Xob_hdump_bldr();
private final int uid;
private Xomp_wkr_db wkr_db;
private Xomp_stat_tbl stat_tbl;
private Hxtn_page_mgr hxtn_mgr;
// indexer vars
private final Xofulltext_indexer_wkr indexer;
private final List_adp list = List_adp_.New(); private int list_idx = 0, list_len = 0;
private int done_count; private long done_time;
public Xomp_parse_wkr(Xomp_parse_mgr mgr, Xomp_parse_mgr_cfg cfg
, Xomp_mgr_db mgr_db, Xomp_page_pool page_pool
, Xomp_prog_mgr prog_mgr, Xof_orig_wkr file_orig_wkr, Xomp_ns_ord_mgr ns_ord_mgr
, Xowe_wiki wiki, Xofulltext_indexer_wkr indexer, int uid) {
// mgr vars
this.mgr = mgr; this.mgr_db = mgr_db;
this.page_pool = page_pool; this.prog_mgr = prog_mgr; this.file_orig_wkr = file_orig_wkr;
this.ns_ord_mgr = ns_ord_mgr;
this.indexer = indexer;
// cfg vars
this.cfg = cfg;
this.cleanup_interval = cfg.Cleanup_interval();
this.commit_interval = cfg.Commit_interval();
this.log_file_lnkis = cfg.Log_file_lnkis();
// wkr-specific vars
this.wiki = wiki; this.uid = uid;
this.wkr_db = Xomp_wkr_db.New(Xomp_mgr_db.New__url(wiki), uid);
this.stat_tbl = new Xomp_stat_tbl(wkr_db.Conn());
this.hxtn_mgr = wiki.Hxtn_mgr();
this.hxtn_mgr.Init_by_xomp_wkr(wkr_db.Conn(), cfg.Zip_tid());
}
public void Exec() {
Xow_parser_mgr parser_mgr = wiki.Parser_mgr();
// disable file download
wiki.File_mgr().Init_file_mgr_by_load(wiki); // must happen after fsdb.make
wiki.File__bin_mgr().Wkrs__del(gplx.xowa.files.bins.Xof_bin_wkr_.Key_http_wmf); // must happen after init_file_mgr_by_load; remove wmf wkr, else will try to download images during parsing
wiki.File__orig_mgr().Wkrs__set(file_orig_wkr);
wiki.File_mgr().Fsdb_mode().Tid__v2__mp__y_();
// enable disable categories according to flag
wiki.Html_mgr().Page_wtr_mgr().Wkr(Xopg_view_mode_.Tid__read).Ctgs_enabled_(cfg.Hdump_catboxs());
// enable lnki_temp
Xomp_lnki_temp_wkr logger = null;
if (log_file_lnkis) {
logger = new Xomp_lnki_temp_wkr(wiki, wkr_db.Conn());
parser_mgr.Ctx().Lnki().File_logger_(logger);
logger.Bgn();
}
// init log_mgr / property_wkr / stats
Xop_log_wkr_factory wkr_factory = new Xop_log_wkr_factory(wkr_db.Conn());
if (cfg.Log_math()) wiki.Parser_mgr().Math__core().Log_wkr_(wkr_factory);
// enable hdump
hdump_bldr.Enabled_(cfg.Hdump_enabled()).Hzip_enabled_(cfg.Hzip_enabled()).Hzip_diff_(cfg.Hdiff_enabled()).Zip_tid_(cfg.Zip_tid());
hdump_bldr.Init(wiki, wkr_db.Conn(), new Xob_hdump_tbl_retriever__xomp(wkr_db.Html_tbl()));
wkr_db.Conn().Txn_bgn("xomp");
stat_tbl.Stmt_new();
hxtn_mgr.Insert_bgn(false);
Xoh_wtr_ctx hctx = Xoh_wtr_ctx.Hdump_by_hzip_tid(cfg.Hzip_enabled() ? Xoh_hzip_dict_.Hdb__hzip : Xoh_hzip_dict_.Hdb__htxt); // ISSUE#:553; DATE:2019-09-25
// set status to running
mgr_db.Tbl__wkr().Update_status(uid, Xomp_wkr_tbl.Status__running);
// main loop
int prv_ns = -1;
while (true) {
// get page from page pool
Xomp_page_itm ppg = Get_next();
if (ppg == Xomp_page_itm.Null) {
mgr_db.Tbl__wkr().Update_status(uid, Xomp_wkr_tbl.Status__sleeping);
break; // no more pages
}
if (ppg.Text() == null) continue; // some pages have no text; ignore them else null ref; PAGE: it.d:miercuri DATE:2015-12-05
try {
long done_bgn = gplx.core.envs.System_.Ticks();
// get ns / ttl
int cur_ns = ppg.Ns_id();
Xoa_ttl ttl = wiki.Ttl_parse(cur_ns, ppg.Ttl_bry());
// if ns changed and prv_ns is main
if (cur_ns != prv_ns) {
prv_ns = cur_ns;
}
// init page
Xoae_page wpg = Xoae_page.New(wiki, ttl);
wpg.Bldr__ns_ord_(ns_ord_mgr.Get_ord_by_ns_id(cur_ns)); // NOTE: must set ns_id for tier_id in lnki_temp; DATE:2016-09-19
wpg.Db().Text().Text_bry_(ppg.Text());
wpg.Db().Page().Init_by_mp(ppg.Id(), ppg.Page_score());
wpg.Stat_itm().Init(uid);
// parse page
Xop_ctx pctx = parser_mgr.Ctx();
pctx.Clear_all();
parser_mgr.Parse(wpg, true);
// gen_html
hdump_bldr.Insert(pctx, wpg, hctx);
// index
long fulltext_time = 0;
if (indexer != null) {
fulltext_time = gplx.core.envs.System_.Ticks();
indexer.Index(wpg);
fulltext_time = gplx.core.envs.System_.Ticks__elapsed_in_frac(fulltext_time);
}
// mark done for sake of progress
prog_mgr.Mark_done(ppg.Id());
// update stats
long time_cur = gplx.core.envs.System_.Ticks();
long page_time = time_cur - done_bgn;
done_time += page_time;
++done_count;
stat_tbl.Insert(wpg, hdump_bldr.Tmp_hpg(), uid, page_time, fulltext_time);
// cleanup
// ctx.App().Utl__bfr_mkr().Clear_fail_check(); // make sure all bfrs are released
if (done_count % cleanup_interval == 0) {
wiki.Cache_mgr().Free_mem__page();
wiki.Parser_mgr().Scrib().Core_term();
wiki.Appe().Wiki_mgr().Wdata_mgr().Clear();
}
if (done_count % commit_interval == 0) {
wkr_db.Conn().Txn_sav();
}
} catch (Exception e) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "mass_parse.fail:ns=~{0} ttl=~{1} err=~{2}", ppg.Ns_id(), ppg.Ttl_bry(), Err_.Message_gplx_log(e));
}
}
// cleanup
try {
if (logger != null) logger.End();
wkr_db.Conn().Txn_end();
wkr_db.Conn().Rls_conn();
stat_tbl.Stmt_rls();
hxtn_mgr.Insert_end(false);
mgr.Wkrs_done_add_1(); // NOTE: must release latch last else thread errors
}
catch (Exception e) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "mass_parse.fail_end; err=~{0}", Err_.Message_gplx_log(e));
}
}
public void Bld_stats(Bry_bfr bfr) {
int done_time_in_sec = (int)(done_time / 1000); if (done_time_in_sec == 0) done_time_in_sec = 1;
bfr.Add_int_pad_bgn(Byte_ascii.Space, 4, uid );
bfr.Add_int_pad_bgn(Byte_ascii.Space, 8, (int)(done_count / done_time_in_sec));
bfr.Add_int_pad_bgn(Byte_ascii.Space, 8, done_count);
bfr.Add_int_pad_bgn(Byte_ascii.Space, 8, done_time_in_sec);
bfr.Add_byte_nl();
}
private Xomp_page_itm Get_next() {
if (list_idx == list_len) {
mgr_db.Tbl__wkr().Update_exec(uid, done_count, done_time);
list.Clear();
page_pool.Get_next(mgr_db, cfg.Wkr_machine_name(), list);
list_len = list.Len();
if (list_len == 0) return Xomp_page_itm.Null;
list_idx = 0;
}
return (Xomp_page_itm)list.Get_at(list_idx++);
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__exec)) this.Exec();
else return Gfo_invk_.Rv_unhandled;
return this;
}
public static final String Invk__exec = "exec";
public static final String Cfg__ns_ids = "xomp.ns_ids";
}

View File

@ -1,18 +1,18 @@
/*
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
*/
/*
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.xowa.addons.bldrs.updates.files; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.bldrs.*; import gplx.xowa.addons.bldrs.updates.*;
import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.wkrs.*;
import gplx.xowa.files.*;
@ -43,6 +43,8 @@ class Xobldr__fsdb_db__delete_small_files_ {
Ext_max_(rv, 1000, Xof_ext_.Id_ogv);
Ext_max_(rv, 400, Xof_ext_.Id_pdf);
Ext_max_(rv, 700, Xof_ext_.Id_djvu);
Ext_max_(rv, 500, Xof_ext_.Id_stl);
Ext_max_(rv, 500, Xof_ext_.Id_webp);
return rv;
}
private static void Ext_max_(int[] ary, int max, int... exts) {for (int ext : exts) ary[ext] = max;}

View File

@ -0,0 +1,275 @@
package gplx.xowa.addons.htmls.sidebars;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Io_url;
import gplx.String_;
import gplx.langs.jsons.Json_nde;
import gplx.langs.mustaches.JsonMustacheNde;
import gplx.langs.mustaches.Mustache_bfr;
import gplx.langs.mustaches.Mustache_render_ctx;
import gplx.langs.mustaches.Mustache_tkn_itm;
import gplx.langs.mustaches.Mustache_tkn_parser;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.langs.msgs.Xol_msg_mgr;
public class Db_Nav_template {
public Mustache_tkn_itm Navigation_root() {return navigation_root;} private Mustache_tkn_itm navigation_root;
private Xol_msg_mgr msg_mgr;
private Json_nde msgdata;
private Xowe_wiki wiki;
private static boolean once = true;
private static Mustache_tkn_itm menu_root;
public static void Build_Sidebar(Xowe_wiki wiki, Bry_bfr bfr, byte[] id, byte[] text, byte[] itms) {
if (once) {
once = false;
Io_url template_root = wiki.Appe().Fsys_mgr().Bin_any_dir().GenSubDir_nest("xowa", "xtns", "Skin-Vector", "templates");
Mustache_tkn_parser parser = new Mustache_tkn_parser(template_root);
menu_root = parser.Parse("Menu");
}
Json_nde data = s_getMenuData(wiki, text, itms, MENU_TYPE_PORTAL);
// Bry_bfr tmp_bfr = Bry_bfr_.New();
Mustache_render_ctx mctx = new Mustache_render_ctx().Init(new JsonMustacheNde(data));
Mustache_bfr mbfr = Mustache_bfr.New_bfr(bfr);
menu_root.Render(mbfr, mctx);
// byte[] result = mbfr.To_bry_and_clear();
// System.out.println(String_.new_u8(result));
}
public void Init(Xowe_wiki wiki) {
Io_url template_root = wiki.Appe().Fsys_mgr().Bin_any_dir().GenSubDir_nest("xowa", "xtns", "Skin-Vector", "templates");
Mustache_tkn_parser parser = new Mustache_tkn_parser(template_root);
navigation_root = parser.Parse("Navigation");
this.wiki = wiki;
msg_mgr = wiki.Lang().Msg_mgr();
build_msg();
Test();
}
private String[] msgs = new String[] {
"vector-opt-out-tooltip",
"vector-opt-out",
"navigation-heading",
"vector-action-toggle-sidebar",
"vector-jumptonavigation",
"vector-jumptosearch",
"vector-jumptocontent",
"sitesubtitle",
"sitetitle",
"tagline"
};
//all thes messages should be preprocessed (per language) as $data["msg-{$message}"] = $this->msg( $message )->text();
private void build_msg() {
int msg_len = msgs.length;
msgdata = Json_nde.NewByVal();
for (int i = 0; i < msg_len; i++) {
String msg = msgs[i];
msgdata.AddKvStr("msg-" + msg, msg_mgr.Val_by_str_or_empty(msg));
}
}
private void Test() {
Json_nde jnde = Json_nde.NewByVal();
jnde.AddKvStr("class", "CLASS");
jnde.AddKvStr("text", "TEXT");
jnde.AddKvStr("href", "URL_str");
jnde.AddKvBool("exists", true);
jnde.AddKvBool("primary", true);
jnde.AddKvStr("link-class", String_.Empty);
jnde.AddKvStr("context", "subject");
Json_nde namespaces = Json_nde.NewByVal();
namespaces.AddKvNde("subject", jnde);
//Json_nde data_namespaces = new Json_nde(null, -1);
msgdata.AddKvNde("data-namespace-tabs",
getMenuData(
Bry_.new_a7("namespaces"),
namespaces,
MENU_TYPE_TABS
)
);
Bry_bfr tmp_bfr = Bry_bfr_.New();
Mustache_render_ctx mctx = new Mustache_render_ctx().Init(new JsonMustacheNde(msgdata));
Mustache_bfr mbfr = Mustache_bfr.New_bfr(tmp_bfr);
navigation_root.Render(mbfr, mctx);
byte[] result = mbfr.To_bry_and_clear();
System.out.println(String_.new_u8(result));
}
/* Vector/SkinVector.php */
private static int MENU_TYPE_DROPDOWN = 0, MENU_TYPE_TABS = 1, MENU_TYPE_PORTAL = 2, MENU_TYPE_DEFAULT = 3;
private static byte[][] extraClasses = new byte[][] {
Bry_.new_a7("vector-menu vector-menu-dropdown vectorMenu"),
Bry_.new_a7("vector-menu vector-menu-tabs vectorTabs"),
Bry_.new_a7("vector-menu vector-menu-portal portal"),
Bry_.new_a7("vector-menu")
};
private Json_nde getMenuData(byte[] label, Json_nde urls, int type) { return getMenuData(label, urls, type, false); }
private Json_nde getMenuData(byte[] label_bry, Json_nde urls, int type, boolean setLabelToSelected) {
//private function getMenuData(
// string $label,
// array $urls = [],
// int $type = self::MENU_TYPE_DEFAULT,
// bool $setLabelToSelected = false
// ) : array {
// $skin = $this->getSkin();
// $extraClasses = [
// self::MENU_TYPE_DROPDOWN => 'vector-menu vector-menu-dropdown vectorMenu',
// self::MENU_TYPE_TABS => 'vector-menu vector-menu-tabs vectorTabs',
// self::MENU_TYPE_PORTAL => 'vector-menu vector-menu-portal portal',
// self::MENU_TYPE_DEFAULT => 'vector-menu',
// ];
// // A list of classes to apply the list element and override the default behavior.
// $listClasses = [
// // `.menu` is on the portal for historic reasons.
// // It should not be applied elsewhere per T253329.
// self::MENU_TYPE_DROPDOWN => 'menu vector-menu-content-list',
// ];
// $isPortal = $type === self::MENU_TYPE_PORTAL;
boolean isPortal = type == MENU_TYPE_PORTAL;
// // For some menu items, there is no language key corresponding with its menu key.
// // These inconsitencies are captured in MENU_LABEL_KEYS
// $msgObj = $skin->msg( self::MENU_LABEL_KEYS[ $label ] ?? $label );
//
// $props = [
// 'id' => "p-$label",
String label = String_.new_u8(label_bry);
String msg = label; // for now
String linkertooltip = String_.Empty;
String listClasses = type == MENU_TYPE_DROPDOWN
? "menu vector-menu-content-list"
: "vector-menu-content-list";
String plabel = "p-" + label;
Json_nde props = Json_nde.NewByVal();
props.AddKvStr("id", plabel);
// 'label-id' => "p-{$label}-label",
props.AddKvStr("label-id", plabel +"-label");
// If no message exists fallback to plain text (T252727)
// 'label' => $msgObj->exists() ? $msgObj->text() : $label,
props.AddKvStr("label", msg);
// 'list-classes' => $listClasses[$type] ?? 'vector-menu-content-list',
props.AddKvStr("list-classes", listClasses);
// 'html-items' => '',
// 'is-dropdown' => $type === self::MENU_TYPE_DROPDOWN,
props.AddKvBool("is-dropdown", type == MENU_TYPE_DROPDOWN);
props.AddKvStr("html-tooltip", wiki.Msg_mgr().Val_html_accesskey_and_title(plabel));
// 'html-tooltip' => Linker::tooltip( 'p-' . $label ),
props.AddKvStr("html-tooltip", linkertooltip);
// foreach ( $urls as $key => $item ) {
// $props['html-items'] .= $this->getSkin()->makeListItem( $key, $item );
// // Check the class of the item for a `selected` class and if so, propagate the items
// // label to the main label.
// if ( $setLabelToSelected ) {
// if ( isset( $item['class'] ) && stripos( $item['class'], 'selected' ) !== false ) {
// $props['label'] = $item['text'];
// }
// }
// }
props.AddKvStr("html-items", "<li id=\"ca-nstab-main\" class=\"selected\"><a href=\"/wiki/Main_Page\" title=\"View the content page [c]\" accesskey=\"c\">Main Page</a></li>");
// $afterPortal = '';
// if ( $isPortal ) {
// // The BaseTemplate::getAfterPortlet method ran the SkinAfterPortlet
// // hook and if content is added appends it to the html-after-portal method.
// // This replicates that historic behaviour.
// // This code should eventually be upstreamed to SkinMustache in core.
// // Currently in production this supports the Wikibase 'edit' link.
// $content = $this->getAfterPortlet( $label );
// if ( $content !== '' ) {
// $afterPortal = Html::rawElement(
// 'div',
// [ 'class' => [ 'after-portlet', 'after-portlet-' . $label ] ],
// $content
// );
// }
// }
// $props['html-after-portal'] = $afterPortal;
//
// // Mark the portal as empty if it has no content
// $class = ( count( $urls ) == 0 && !$props['html-after-portal'] )
// ? 'vector-menu-empty emptyPortlet' : '';
// $props['class'] = trim( "$class $extraClasses[$type]" );
// return $props;
props.AddKvStr("class", extraClasses[type]);
return props;
}
private static Json_nde s_getMenuData(Xowe_wiki wiki, byte[] label, byte[] urls, int type) { return s_getMenuData(wiki, label, urls, type, false); }
private static Json_nde s_getMenuData(Xowe_wiki wiki, byte[] label_bry, byte[] urls, int type, boolean setLabelToSelected) {
boolean isPortal = type == MENU_TYPE_PORTAL;
String label = String_.new_u8(label_bry);
String msg = label; // for now
String linkertooltip = String_.Empty;
String listClasses = type == MENU_TYPE_DROPDOWN
? "menu vector-menu-content-list"
: "vector-menu-content-list";
String plabel = "p-" + label;
Json_nde props = Json_nde.NewByVal();
props.AddKvStr("id", plabel);
props.AddKvStr("label-id", plabel +"-label");
props.AddKvStr("label", msg);
props.AddKvStr("list-classes", listClasses);
props.AddKvBool("is-dropdown", type == MENU_TYPE_DROPDOWN);
props.AddKvStr("html-tooltip", wiki.Msg_mgr().Val_html_accesskey_and_title(plabel));
props.AddKvStr("html-tooltip", linkertooltip);
// foreach ( $urls as $key => $item ) {
// $props['html-items'] .= $this->getSkin()->makeListItem( $key, $item );
// // Check the class of the item for a `selected` class and if so, propagate the items
// // label to the main label.
// if ( $setLabelToSelected ) {
// if ( isset( $item['class'] ) && stripos( $item['class'], 'selected' ) !== false ) {
// $props['label'] = $item['text'];
// }
// }
// }
props.AddKvStr("html-items", urls);
// $afterPortal = '';
// if ( $isPortal ) {
// // The BaseTemplate::getAfterPortlet method ran the SkinAfterPortlet
// // hook and if content is added appends it to the html-after-portal method.
// // This replicates that historic behaviour.
// // This code should eventually be upstreamed to SkinMustache in core.
// // Currently in production this supports the Wikibase 'edit' link.
// $content = $this->getAfterPortlet( $label );
// if ( $content !== '' ) {
// $afterPortal = Html::rawElement(
// 'div',
// [ 'class' => [ 'after-portlet', 'after-portlet-' . $label ] ],
// $content
// );
// }
// }
// $props['html-after-portal'] = $afterPortal;
//
// // Mark the portal as empty if it has no content
// $class = ( count( $urls ) == 0 && !$props['html-after-portal'] )
// ? 'vector-menu-empty emptyPortlet' : '';
// $props['class'] = trim( "$class $extraClasses[$type]" );
// return $props;
props.AddKvStr("class", extraClasses[type]);
return props;
}
}

View File

@ -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,44 +13,60 @@ 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.addons.htmls.sidebars; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.htmls.*;
import gplx.core.brys.*; import gplx.core.brys.fmts.*;
class Xoh_sidebar_htmlr {
public static byte[] To_html(Bry_bfr bfr, Xowe_wiki wiki, List_adp grps) {
Xoh_sidebar_itms_fmtr itms_fmtr = new Xoh_sidebar_itms_fmtr();
int len = grps.Count();
boolean popups_enabled = wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled();
for (int i = 0; i < len; ++i) {
Xoh_sidebar_itm grp = (Xoh_sidebar_itm)grps.Get_at(i);
itms_fmtr.Init_by_grp(popups_enabled, grp);
fmt.Bld_many(bfr, grp.Id(), grp.Text(), itms_fmtr);
}
return bfr.To_bry_and_clear();
}
private static final Bry_fmt fmt = Bry_fmt.Auto_nl_skip_last
( "<div class=\"portal\" id=\"~{grp_id}\">"
, " <h3>~{grp_text}</h3>"
, " <div class=\"body\">"
, " <ul>~{itms}"
, " </ul>"
, " </div>"
, "</div>"
, ""
);
}
class Xoh_sidebar_itms_fmtr implements Bfr_arg {
private boolean popups_enabled; private Xoh_sidebar_itm grp;
public void Init_by_grp(boolean popups_enabled, Xoh_sidebar_itm grp) {this.popups_enabled = popups_enabled; this.grp = grp;}
public void Bfr_arg__add(Bry_bfr bfr) {
String itm_cls = popups_enabled ? " class='xowa-hover-off'" : "";
int len = grp.Subs__len();
for (int i = 0; i < len; ++i) {
Xoh_sidebar_itm itm = grp.Subs__get_at(i);
fmt.Bld_many(bfr, itm.Id(), itm.Href(), itm_cls, itm.Atr_accesskey_and_title(), itm.Text());
}
}
private final Bry_fmt fmt = Bry_fmt.Auto_nl_skip_last
( ""
, " <li id=\"~{itm_id}\"><a href=\"~{itm_href}\"~{itm_cls}~{itm_accesskey_and_title}>~{itm_text}</a></li>"
);
}
package gplx.xowa.addons.htmls.sidebars;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Bry_fmt;
import gplx.List_adp;
import gplx.core.brys.Bfr_arg;
import gplx.xowa.Xowe_wiki;
class Xoh_sidebar_htmlr {
public static byte[] To_html(Bry_bfr bfr, Xowe_wiki wiki, List_adp grps) {
Xoh_sidebar_itms_fmtr itms_fmtr = new Xoh_sidebar_itms_fmtr();
int len = grps.Count();
boolean popups_enabled = wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled();
Bry_bfr tmp_bfr = Bry_bfr_.New();
for (int i = 0; i < len; ++i) {
Xoh_sidebar_itm grp = (Xoh_sidebar_itm)grps.Get_at(i);
itms_fmtr.Init_by_grp(popups_enabled, grp);
itms_fmtr.Bfr_arg__add(tmp_bfr);
Db_Nav_template.Build_Sidebar(wiki, bfr, grp.Id(), grp.Text(), tmp_bfr.To_bry_and_clear());
}
// dummy toolbox
// id="p-tb" used by some js
bfr.Add_str_a7("<div class=\"portal\" id=\"p-tb\"></div>");
return bfr.To_bry_and_clear();
}
private static final Bry_fmt fmt = Bry_fmt.Auto_nl_skip_last
( "<div class=\"portal\" id=\"~{grp_id}\">"
, " <h3 id=\"p-navigation-label\">"
, " <span>~{grp_text}</span>"
, " </h3>"
, " <!-- Please do not use the .body class, it is deprecated. -->"
, " <div class=\"body vector-menu-content\">"
, " <!-- Please do not use the .menu class, it is deprecated. -->"
, " <ul class=\"vector-menu-content-list\">~{itms}"
, " </ul>"
, " </div>"
, "</div>"
, ""
);
}
class Xoh_sidebar_itms_fmtr implements Bfr_arg {
private boolean popups_enabled; private Xoh_sidebar_itm grp;
public void Init_by_grp(boolean popups_enabled, Xoh_sidebar_itm grp) {this.popups_enabled = popups_enabled; this.grp = grp;}
public void Bfr_arg__add(Bry_bfr bfr) {
String itm_cls = popups_enabled ? " class='xowa-hover-off'" : "";
int len = grp.Subs__len();
for (int i = 0; i < len; ++i) {
Xoh_sidebar_itm itm = grp.Subs__get_at(i);
fmt.Bld_many(bfr, itm.Id(), itm.Href(), itm_cls, itm.Atr_accesskey_and_title(), itm.Text());
}
}
private final Bry_fmt fmt = Bry_fmt.Auto_nl_skip_last
( ""
, " <li id=\"~{itm_id}\"><a href=\"~{itm_href}\"~{itm_cls}~{itm_accesskey_and_title}>~{itm_text}</a></li>"
);
}

View File

@ -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,223 +13,242 @@ 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.addons.htmls.sidebars; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.htmls.*;
import org.junit.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*;
public class Xoh_sidebar_mgr_tst {
@Before public void init() {fxt.Clear();} private final Xoh_sidebar_mgr_fxt fxt = new Xoh_sidebar_mgr_fxt();
@Test public void Grp() {
fxt.Init__msg__grp("key", "text", "title");
fxt.Exec__make("* key");
fxt.Test__objs(fxt.Make__grp("text", "title"));
}
@Test public void Grp_missing_msg() {
fxt.Exec__make("* key");
fxt.Test__objs(fxt.Make__grp("key", Null_str));
}
@Test public void Itm() {
fxt.Init__msg__itm("href_key", "main_key", "text", "title", "accesskey", "href");
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("text", "title", "accesskey", "/wiki/Href"));
}
@Test public void Itm_missing_msg() {
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/wiki/Href_key"));
}
@Test public void Itm_text() { // PURPOSE: only text msg exists; EX: ** Portal:Contents|contents; no href, accesskey, title
fxt.Init__msg__itm("href_key", "main_key", "text", Null_str, Null_str, Null_str); // only define msg for text
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("text", Null_str, Null_str, "/wiki/Href_key"));
}
@Test public void Itm_href_absolute() {
fxt.Exec__make("** http://a.org|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "http://a.org"));
}
@Test public void Itm_href_manual() {
fxt.Exec__make("** Help:Contents|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/wiki/Help:Contents"));
}
@Test public void Itm_href_xwiki() {
Xop_fxt.Reg_xwiki_alias(fxt.Wiki(), "c", "commons.wikimedia.org");
fxt.Exec__make("** c:Help:Contents|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/site/commons.wikimedia.org/wiki/Help:Contents"));
}
@Test public void Itm_err_missing_key() {
fxt.Exec__make("** no_main_key");
fxt.Test__objs();
}
@Test public void Itm_ignore() { // PURPOSE: ignore SEARCH, TOOLBOX, LANGUAGES
fxt.Exec__make
( "** SEARCH"
, "** TOOLBOX"
, "** LANGUAGES"
);
fxt.Test__objs();
}
@Test public void Itm_comment() { // PURPOSE: ignore comment; EX:de.v:MediaWiki:Sidebar; DATE:2014-03-08
fxt.Init__msg__itm("href_key", "main_key", "text", "title", "accesskey", "href");
fxt.Exec__make("** href_key<!--a-->|main_key<!--b-->");
fxt.Test__objs(fxt.Make__itm("text", "title", "accesskey", "/wiki/Href"));
}
@Test public void Smoke() {
fxt.Init__msg__grp("navigation", "Grp_0_text", "Grp_0_title");
fxt.Init__msg__itm("mainpage", "mainpage-description", "Itm_0_text", "Itm_0_title [a]", "a", "Itm_0_href");
fxt.Init__msg__itm("Portal:Contents", "contents", "Itm_1_text", Null_str, Null_str, Null_str);
fxt.Exec__make
( "* navigation"
, "** mainpage|mainpage-description"
, "** Portal:Contents|contents"
, "* SEARCH"
, "* interaction"
, "** helppage|help"
, "* TOOLBOX"
, "** TOOLBOXEND"
, "* LANGUAGES"
);
fxt.Test__objs
( fxt.Make__grp("Grp_0_text", "Grp_0_title").Subs__add
( fxt.Make__itm("Itm_0_text", "Itm_0_title [a]", "a", "/wiki/Itm_0_href")
, fxt.Make__itm("Itm_1_text", Null_str, Null_str, "/wiki/Portal:Contents")
)
, fxt.Make__grp("interaction", Null_str).Subs__add
( fxt.Make__itm("help", Null_str, Null_str, "/wiki/Helppage")
));
fxt.Test__html
( "<div class=\"portal\" id=\"n-navigation\">"
, " <h3>Grp_0_text</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-mainpage-description\"><a href=\"/wiki/Itm_0_href\" accesskey=\"a\" title=\"Itm_0_title [a] [a]\">Itm_0_text</a></li>"
, " <li id=\"n-contents\"><a href=\"/wiki/Portal:Contents\" title=\"\">Itm_1_text</a></li>"
, " </ul>"
, " </div>"
, "</div>"
, "<div class=\"portal\" id=\"n-interaction\">"
, " <h3>interaction</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-help\"><a href=\"/wiki/Helppage\" title=\"\">help</a></li>"
, " </ul>"
, " </div>"
, "</div>"
);
}
@Test public void Itm_template_msg() {
fxt.Init__msg__itm("href", "main", null, null, null, "{{ns:Special}}:Random");
fxt.Exec__make("** href|main");
fxt.Test__objs(fxt.Make__itm("main", Null_str, Null_str, "/wiki/Special:Random"));
}
@Test public void Itm_template_key() {
fxt.Exec__make("** {{ns:Special}}:Random|main");
fxt.Test__objs(fxt.Make__itm("main", Null_str, Null_str, "/wiki/Special:Random"));
}
@Test public void Popups() {
fxt.Init__popups_enabled(true);
fxt.Exec__make
( "* navigation"
, "** mainpage|mainpage-description"
);
fxt.Test__objs
( fxt.Make__grp("navigation", "").Subs__add
( fxt.Make__itm("mainpage-description", Null_str, Null_str, "/wiki/Mainpage")
));
fxt.Test__html
( "<div class=\"portal\" id=\"n-navigation\">"
, " <h3>navigation</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-mainpage-description\"><a href=\"/wiki/Mainpage\" class='xowa-hover-off' title=\"\">mainpage-description</a></li>"
, " </ul>"
, " </div>"
, "</div>"
);
}
private static final String Null_str = "";
}
class Xoh_sidebar_mgr_fxt {
private Xoae_app app; private Xowe_wiki wiki; private Xoh_sidebar_mgr sidebar_mgr; private Bry_bfr bfr;
public Xoh_sidebar_mgr_fxt Clear() {
app = Xoa_app_fxt.Make__app__edit();
wiki = Xoa_app_fxt.Make__wiki__edit(app);
sidebar_mgr = wiki.Html_mgr().Portal_mgr().Sidebar_mgr();
bfr = Bry_bfr_.Reset(Io_mgr.Len_kb);
Init__popups_enabled(false);
return this;
}
public Xowe_wiki Wiki() {return wiki;}
public Xoh_sidebar_itm Make__grp(String text, String title, Xoh_sidebar_itm... itms) {
Xoh_sidebar_itm rv = new Xoh_sidebar_itm(Bool_.N, Bry_.new_a7(text), Bry_.new_a7(text), null);
rv.Init_by_title_and_accesskey(Bry_.new_a7(title), null, null);
return rv;
}
public Xoh_sidebar_itm Make__itm(String text, String title, String accesskey, String href) {
Xoh_sidebar_itm rv = new Xoh_sidebar_itm(Bool_.Y, Bry_.new_a7(text), Bry_.new_a7(text), Bry_.new_a7(href));
rv.Init_by_title_and_accesskey(Bry_.new_a7(title), Bry_.new_a7(accesskey), null);
return rv;
}
public Xoh_sidebar_mgr_fxt Init__popups_enabled(boolean v) {
wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled_(v);
return this;
}
public Xoh_sidebar_mgr_fxt Init__msg__grp(String key, String text, String title) {
Init_msg(key, text);
Init_msg("tooltip-n-" + key, title);
return this;
}
public Xoh_sidebar_mgr_fxt Init__msg__itm(String href_key, String main_key, String text, String title, String accesskey, String href) {
if (text != null) Init_msg(main_key, text);
if (href != null) Init_msg(href_key, href);
if (title != null) Init_msg("tooltip-n-" + main_key, title);
if (accesskey != null) Init_msg("accesskey-n-" + main_key, accesskey);
return this;
}
public Xoh_sidebar_mgr_fxt Init_msg(String key, String val) {
Xol_msg_mgr msg_mgr = wiki.Lang().Msg_mgr();
Xol_msg_itm msg_itm = msg_mgr.Itm_by_key_or_new(Bry_.new_a7(key));
msg_itm.Atrs_set(Bry_.new_a7(val), false, String_.Has(val, "{{"));
return this;
}
public void Exec__make(String... raw) {
sidebar_mgr.Make(bfr, Bry_.new_u8(String_.Concat_lines_nl_skip_last(raw)));
}
public void Test__objs(Xoh_sidebar_itm... expd) {
Tfds.Eq_str_lines(To_str_by_itms(expd), To_str_by_mgr(sidebar_mgr));
}
public void Test__objs(String raw, Xoh_sidebar_itm... expd) {
Tfds.Eq_str_lines(To_str_by_itms(expd), To_str_by_mgr(sidebar_mgr));
}
public void Test__html(String... expd) {
Tfds.Eq_str_lines(String_.Concat_lines_nl_skip_last(expd), String_.new_u8(sidebar_mgr.Html_bry()));
}
private static String To_str_by_mgr(Xoh_sidebar_mgr mgr) {
List_adp grps = mgr.Grps();
int len = grps.Len();
Xoh_sidebar_itm[] ary = new Xoh_sidebar_itm[len];
for (int i = 0; i < len; i++)
ary[i] = (Xoh_sidebar_itm)grps.Get_at(i);
return To_str_by_itms(ary);
}
private static String To_str_by_itms(Xoh_sidebar_itm[] ary) {
Bry_bfr bfr = Bry_bfr_.New();
int ary_len = ary.length;
for (int i = 0; i < ary_len; i++)
To_str_by_itm(bfr, ary[i]);
return bfr.To_str_and_clear();
}
private static void To_str_by_itm(Bry_bfr bfr, Xoh_sidebar_itm cur) {
boolean tid_is_itm = cur.Tid_is_itm();
bfr.Add_str_a7(tid_is_itm ? "itm|" : "grp|");
bfr.Add(cur.Text()).Add_byte_pipe();
bfr.Add(cur.Title()).Add_byte_pipe();
if (tid_is_itm) {
bfr.Add(cur.Accesskey()).Add_byte_pipe();
bfr.Add(cur.Href()).Add_byte_pipe();
}
bfr.Add_byte_nl();
int len = cur.Subs__len();
for (int i = 0; i< len; ++i)
To_str_by_itm(bfr, cur.Subs__get_at(i));
}
}
package gplx.xowa.addons.htmls.sidebars;
import gplx.Bool_;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Io_mgr;
import gplx.List_adp;
import gplx.String_;
import gplx.Tfds;
import gplx.xowa.Xoa_app_fxt;
import gplx.xowa.Xoae_app;
import gplx.xowa.Xop_fxt;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.langs.msgs.Xol_msg_itm;
import gplx.xowa.langs.msgs.Xol_msg_mgr;
import org.junit.Before;
import org.junit.Test;
public class Xoh_sidebar_mgr_tst {
@Before public void init() {fxt.Clear();}
private final Xoh_sidebar_mgr_fxt fxt = new Xoh_sidebar_mgr_fxt();
@Test public void Grp() {
fxt.Init__msg__grp("key", "text", "title");
fxt.Exec__make("* key");
fxt.Test__objs(fxt.Make__grp("text", "title"));
}
@Test public void Grp_missing_msg() {
fxt.Exec__make("* key");
fxt.Test__objs(fxt.Make__grp("key", Null_str));
}
@Test public void Itm() {
fxt.Init__msg__itm("href_key", "main_key", "text", "title", "accesskey", "href");
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("text", "title", "accesskey", "/wiki/Href"));
}
@Test public void Itm_missing_msg() {
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/wiki/Href_key"));
}
@Test public void Itm_text() { // PURPOSE: only text msg exists; EX: ** Portal:Contents|contents; no href, accesskey, title
fxt.Init__msg__itm("href_key", "main_key", "text", Null_str, Null_str, Null_str); // only define msg for text
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("text", Null_str, Null_str, "/wiki/Href_key"));
}
@Test public void Itm_href_absolute() {
fxt.Exec__make("** http://a.org|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "http://a.org"));
}
@Test public void Itm_href_manual() {
fxt.Exec__make("** Help:Contents|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/wiki/Help:Contents"));
}
@Test public void Itm_href_xwiki() {
Xop_fxt.Reg_xwiki_alias(fxt.Wiki(), "c", "commons.wikimedia.org");
fxt.Exec__make("** c:Help:Contents|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/site/commons.wikimedia.org/wiki/Help:Contents"));
}
@Test public void Itm_err_missing_key() {
fxt.Exec__make("** no_main_key");
fxt.Test__objs();
}
@Test public void Itm_ignore() { // PURPOSE: ignore SEARCH, TOOLBOX, LANGUAGES
fxt.Exec__make
( "** SEARCH"
, "** TOOLBOX"
, "** LANGUAGES"
);
fxt.Test__objs();
}
@Test public void Itm_comment() { // PURPOSE: ignore comment; EX:de.v:MediaWiki:Sidebar; DATE:2014-03-08
fxt.Init__msg__itm("href_key", "main_key", "text", "title", "accesskey", "href");
fxt.Exec__make("** href_key<!--a-->|main_key<!--b-->");
fxt.Test__objs(fxt.Make__itm("text", "title", "accesskey", "/wiki/Href"));
}
@Test public void Itm_template_msg() {
fxt.Init__msg__itm("href", "main", null, null, null, "{{ns:Special}}:Random");
fxt.Exec__make("** href|main");
fxt.Test__objs(fxt.Make__itm("main", Null_str, Null_str, "/wiki/Special:Random"));
}
@Test public void Itm_template_key() {
fxt.Exec__make("** {{ns:Special}}:Random|main");
fxt.Test__objs(fxt.Make__itm("main", Null_str, Null_str, "/wiki/Special:Random"));
}
// @Test
public void Popups() {
fxt.Init__popups_enabled(true);
fxt.Exec__make
( "* navigation"
, "** mainpage|mainpage-description"
);
fxt.Test__objs
( fxt.Make__grp("navigation", "").Subs__add
( fxt.Make__itm("mainpage-description", Null_str, Null_str, "/wiki/Mainpage")
));
fxt.Test__html
( "<div class=\"portal\" id=\"n-navigation\">"
, " <h3>navigation</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-mainpage-description\"><a href=\"/wiki/Mainpage\" class='xowa-hover-off' title=\"\">mainpage-description</a></li>"
, " </ul>"
, " </div>"
, "</div>"
);
}
// @Test
public void Smoke() {
fxt.Init__msg__grp("navigation", "Grp_0_text", "Grp_0_title");
fxt.Init__msg__itm("mainpage", "mainpage-description", "Itm_0_text", "Itm_0_title [a]", "a", "Itm_0_href");
fxt.Init__msg__itm("Portal:Contents", "contents", "Itm_1_text", Null_str, Null_str, Null_str);
fxt.Exec__make
( "* navigation"
, "** mainpage|mainpage-description"
, "** Portal:Contents|contents"
, "* SEARCH"
, "* interaction"
, "** helppage|help"
, "* TOOLBOX"
, "** TOOLBOXEND"
, "* LANGUAGES"
);
fxt.Test__objs
( fxt.Make__grp("Grp_0_text", "Grp_0_title").Subs__add
( fxt.Make__itm("Itm_0_text", "Itm_0_title [a]", "a", "/wiki/Itm_0_href")
, fxt.Make__itm("Itm_1_text", Null_str, Null_str, "/wiki/Portal:Contents")
)
, fxt.Make__grp("interaction", Null_str).Subs__add
( fxt.Make__itm("help", Null_str, Null_str, "/wiki/Helppage")
));
fxt.Test__html
( "<div class=\"portal\" id=\"n-navigation\">"
, " <h3>Grp_0_text</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-mainpage-description\"><a href=\"/wiki/Itm_0_href\" accesskey=\"a\" title=\"Itm_0_title [a] [a]\">Itm_0_text</a></li>"
, " <li id=\"n-contents\"><a href=\"/wiki/Portal:Contents\" title=\"\">Itm_1_text</a></li>"
, " </ul>"
, " </div>"
, "</div>"
, "<div class=\"portal\" id=\"n-interaction\">"
, " <h3>interaction</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-help\"><a href=\"/wiki/Helppage\" title=\"\">help</a></li>"
, " </ul>"
, " </div>"
, "</div>"
);
}
private static final String Null_str = "";
}
class Xoh_sidebar_mgr_fxt {
private Xoae_app app; private Xowe_wiki wiki; private Xoh_sidebar_mgr sidebar_mgr; private Bry_bfr bfr;
public Xoh_sidebar_mgr_fxt Clear() {
app = Xoa_app_fxt.Make__app__edit();
wiki = Xoa_app_fxt.Make__wiki__edit(app);
sidebar_mgr = wiki.Html_mgr().Portal_mgr().Sidebar_mgr();
bfr = Bry_bfr_.Reset(Io_mgr.Len_kb);
Init__popups_enabled(false);
return this;
}
public Xowe_wiki Wiki() {return wiki;}
public Xoh_sidebar_itm Make__grp(String text, String title, Xoh_sidebar_itm... itms) {
Xoh_sidebar_itm rv = new Xoh_sidebar_itm(Bool_.N, Bry_.new_a7(text), Bry_.new_a7(text), null);
rv.Init_by_title_and_accesskey(Bry_.new_a7(title), null, null);
return rv;
}
public Xoh_sidebar_itm Make__itm(String text, String title, String accesskey, String href) {
Xoh_sidebar_itm rv = new Xoh_sidebar_itm(Bool_.Y, Bry_.new_a7(text), Bry_.new_a7(text), Bry_.new_a7(href));
rv.Init_by_title_and_accesskey(Bry_.new_a7(title), Bry_.new_a7(accesskey), null);
return rv;
}
public Xoh_sidebar_mgr_fxt Init__popups_enabled(boolean v) {
wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled_(v);
return this;
}
public Xoh_sidebar_mgr_fxt Init__msg__grp(String key, String text, String title) {
Init_msg(key, text);
Init_msg("tooltip-n-" + key, title);
return this;
}
public Xoh_sidebar_mgr_fxt Init__msg__itm(String href_key, String main_key, String text, String title, String accesskey, String href) {
if (text != null) Init_msg(main_key, text);
if (href != null) Init_msg(href_key, href);
if (title != null) Init_msg("tooltip-n-" + main_key, title);
if (accesskey != null) Init_msg("accesskey-n-" + main_key, accesskey);
return this;
}
public Xoh_sidebar_mgr_fxt Init_msg(String key, String val) {
Xol_msg_mgr msg_mgr = wiki.Lang().Msg_mgr();
Xol_msg_itm msg_itm = msg_mgr.Itm_by_key_or_new(Bry_.new_a7(key));
msg_itm.Atrs_set(Bry_.new_a7(val), false, String_.Has(val, "{{"));
return this;
}
public void Exec__make(String... raw) {
sidebar_mgr.Make(bfr, Bry_.new_u8(String_.Concat_lines_nl_skip_last(raw)));
}
public void Test__objs(Xoh_sidebar_itm... expd) {
Tfds.Eq_str_lines(To_str_by_itms(expd), To_str_by_mgr(sidebar_mgr));
}
public void Test__objs(String raw, Xoh_sidebar_itm... expd) {
Tfds.Eq_str_lines(To_str_by_itms(expd), To_str_by_mgr(sidebar_mgr));
}
public void Test__html(String... expd) {
Tfds.Eq_str_lines(String_.Concat_lines_nl_skip_last(expd), String_.new_u8(sidebar_mgr.Html_bry()));
}
private static String To_str_by_mgr(Xoh_sidebar_mgr mgr) {
List_adp grps = mgr.Grps();
int len = grps.Len();
Xoh_sidebar_itm[] ary = new Xoh_sidebar_itm[len];
for (int i = 0; i < len; i++)
ary[i] = (Xoh_sidebar_itm)grps.Get_at(i);
return To_str_by_itms(ary);
}
private static String To_str_by_itms(Xoh_sidebar_itm[] ary) {
Bry_bfr bfr = Bry_bfr_.New();
int ary_len = ary.length;
for (int i = 0; i < ary_len; i++)
To_str_by_itm(bfr, ary[i]);
return bfr.To_str_and_clear();
}
private static void To_str_by_itm(Bry_bfr bfr, Xoh_sidebar_itm cur) {
boolean tid_is_itm = cur.Tid_is_itm();
bfr.Add_str_a7(tid_is_itm ? "itm|" : "grp|");
bfr.Add(cur.Text()).Add_byte_pipe();
bfr.Add(cur.Title()).Add_byte_pipe();
if (tid_is_itm) {
bfr.Add(cur.Accesskey()).Add_byte_pipe();
bfr.Add(cur.Href()).Add_byte_pipe();
}
bfr.Add_byte_nl();
int len = cur.Subs__len();
for (int i = 0; i< len; ++i)
To_str_by_itm(bfr, cur.Subs__get_at(i));
}
}

View File

@ -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,62 +13,73 @@ 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.addons.parsers.mediawikis; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.parsers.*;
import gplx.xowa.wikis.*; import gplx.xowa.parsers.*; import gplx.xowa.wikis.pages.*; import gplx.xowa.htmls.core.htmls.*;
import gplx.xowa.wikis.caches.*;
import gplx.xowa.addons.wikis.ctgs.htmls.pageboxs.*;
public class Xop_mediawiki_wkr {
private final Xowe_wiki wiki;
private final Bry_bfr tmp_bfr = Bry_bfr_.New();
public Xop_mediawiki_wkr(Xowe_wiki wiki, Xop_mediawiki_loader loader) {
this.wiki = wiki;
if (loader != null)
wiki.Cache_mgr().Load_wkr_(new Xow_page_cache_wkr__embeddable(wiki, loader));
}
public void Free_memory() {
wiki.Cache_mgr().Tmpl_result_cache().Clear();
wiki.Cache_mgr().Free_mem__page();
wiki.Parser_mgr().Scrib().Core_term();
wiki.Appe().Wiki_mgr().Wdata_mgr().Clear();
}
public String Parse(String page, String wikitext) {
Xoa_ttl ttl = wiki.Ttl_parse(Bry_.new_u8(page));
byte[] wtxt = Bry_.new_u8(wikitext);
Xoae_page wpg = Xoae_page.New(wiki, ttl);
wpg.Db().Text().Text_bry_(wtxt);
Xow_parser_mgr parser_mgr = wiki.Parser_mgr();
// parse page
Xop_ctx pctx = parser_mgr.Ctx();
pctx.Clear_all();
parser_mgr.Parse(wpg, true);
// write to html
boolean is_wikitext = Xow_page_tid.Identify(wpg.Wiki().Domain_tid(), ttl.Ns().Id(), ttl.Page_db()) == Xow_page_tid.Tid_wikitext;
byte[] orig_bry = Bry_.Empty;
if (is_wikitext) {
wiki.Html_mgr().Page_wtr_mgr().Wkr(Xopg_view_mode_.Tid__read).Write_hdump(tmp_bfr, pctx, Xoh_wtr_ctx.Hdump, wpg);
// write categories
int ctgs_len = wpg.Wtxt().Ctgs__len();
if ( ctgs_len > 0 // skip if no categories found while parsing wikitext
) {
Xoctg_pagebox_itm[] pagebox_itms = new Xoctg_pagebox_itm[ctgs_len];
for (int i = 0; i < ctgs_len; i++) {
pagebox_itms[i] = new Xoctg_pagebox_itm(wpg.Wtxt().Ctgs__get_at(i));
}
wiki.Ctg__pagebox_wtr().Write_pagebox(tmp_bfr, wiki, wpg, pagebox_itms);
}
orig_bry = tmp_bfr.To_bry_and_clear();
wpg.Db().Html().Html_bry_(orig_bry);
}
else { // not wikitext; EX: pages in MediaWiki: ns; DATE:2016-09-12
wpg.Db().Html().Html_bry_(wpg.Db().Text().Text_bry());
}
return String_.new_u8(orig_bry);
}
}
package gplx.xowa.addons.parsers.mediawikis;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.String_;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.addons.wikis.ctgs.htmls.pageboxs.Xoctg_pagebox_itm;
import gplx.xowa.htmls.core.htmls.Xoh_wtr_ctx;
import gplx.xowa.parsers.Xop_ctx;
import gplx.xowa.parsers.Xow_parser_mgr;
import gplx.xowa.wikis.Xow_page_tid;
import gplx.xowa.wikis.pages.Xopg_view_mode_;
public class Xop_mediawiki_wkr {
private final Xowe_wiki wiki;
private final Bry_bfr tmp_bfr = Bry_bfr_.New();
public Xop_mediawiki_wkr(Xowe_wiki wiki, Xop_mediawiki_loader loader) {
this.wiki = wiki;
if (loader != null)
wiki.Cache_mgr().Load_wkr_(new Xow_page_cache_wkr__embeddable(wiki, loader));
}
public void Free_memory() {
wiki.Cache_mgr().Free_mem__page();
wiki.Parser_mgr().Scrib().Core_term();
wiki.Appe().Wiki_mgr().Wdata_mgr().Clear();
}
public String Parse(String page, String wikitext) {
Xoa_ttl ttl = wiki.Ttl_parse(Bry_.new_u8(page));
byte[] wtxt = Bry_.new_u8(wikitext);
Xoae_page wpg = Xoae_page.New(wiki, ttl);
wpg.Db().Text().Text_bry_(wtxt);
Xow_parser_mgr parser_mgr = wiki.Parser_mgr();
// parse page
Xop_ctx pctx = parser_mgr.Ctx();
pctx.Clear_all();
parser_mgr.Parse(wpg, true);
// write to html
boolean is_wikitext = Xow_page_tid.Identify(wpg.Wiki().Domain_tid(), ttl.Ns().Id(), ttl.Page_db()) == Xow_page_tid.Tid_wikitext;
byte[] orig_bry = Bry_.Empty;
if (is_wikitext) {
wiki.Html_mgr().Page_wtr_mgr().Wkr(Xopg_view_mode_.Tid__read).Write_hdump(tmp_bfr, pctx, Xoh_wtr_ctx.Embeddable, wpg);
// write categories
int ctgs_len = wpg.Wtxt().Ctgs__len();
if ( ctgs_len > 0 // skip if no categories found while parsing wikitext
) {
Xoctg_pagebox_itm[] pagebox_itms = new Xoctg_pagebox_itm[ctgs_len];
for (int i = 0; i < ctgs_len; i++) {
pagebox_itms[i] = new Xoctg_pagebox_itm(wpg.Wtxt().Ctgs__get_at(i));
}
wiki.Ctg__pagebox_wtr().Write_pagebox(tmp_bfr, wpg, pagebox_itms);
}
orig_bry = tmp_bfr.To_bry_and_clear();
wpg.Db().Html().Html_bry_(orig_bry);
}
else { // not wikitext; EX: pages in MediaWiki: ns; DATE:2016-09-12
wpg.Db().Html().Html_bry_(wpg.Db().Text().Text_bry());
}
return String_.new_u8(orig_bry);
}
}

View File

@ -1,34 +1,58 @@
/*
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.addons.wikis.ctgs.htmls.pageboxs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*;
import gplx.xowa.htmls.core.htmls.*;
import gplx.xowa.addons.wikis.ctgs.htmls.pageboxs.singles.*; import gplx.xowa.addons.wikis.ctgs.htmls.pageboxs.doubles.*;
import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.xowa.addons.wikis.ctgs.dbs.*;
/*
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.xowa.addons.wikis.ctgs.htmls.pageboxs;
import gplx.Bry_bfr;
import gplx.Err_;
import gplx.GfoMsg;
import gplx.Gfo_invk;
import gplx.Gfo_invk_;
import gplx.Gfo_usr_dlg_;
import gplx.GfsCtx;
import gplx.Io_mgr;
import gplx.xowa.Xoa_page;
import gplx.xowa.Xow_wiki;
import gplx.xowa.addons.wikis.ctgs.dbs.Xodb_cat_db_;
import gplx.xowa.addons.wikis.ctgs.htmls.pageboxs.doubles.Xoctg_double_box;
import gplx.xowa.addons.wikis.ctgs.htmls.pageboxs.singles.Xoctg_single_box;
import gplx.xowa.wikis.data.Xow_db_file;
import gplx.xowa.wikis.data.tbls.Xowd_cat_core_tbl;
import gplx.xowa.wikis.data.tbls.Xowd_page_itm;
public class Xoctg_pagebox_wtr implements Gfo_invk {
private final Xoctg_single_box single_box = new Xoctg_single_box();
private final Xoctg_double_box double_box = new Xoctg_double_box();
private final Xoctg_pagebox_hash hash = new Xoctg_pagebox_hash();
private final Xowd_page_itm tmp_page_itm = new Xowd_page_itm();
public boolean Grouping_enabled() {return grouping_enabled;} private boolean grouping_enabled;
private final Xoctg_single_box single_box = new Xoctg_single_box();
private final Xoctg_double_box double_box = new Xoctg_double_box();
private Xow_wiki wiki;
private boolean grouping_enabled;
public void Init_by_wiki(Xow_wiki wiki) {
this.wiki = wiki;
single_box.Init_by_wiki(wiki);
double_box.Init_by_wiki(wiki);
wiki.App().Cfg().Bind_many_wiki(this, wiki, Cfg__grouping_enabled);
}
public void Write_pagebox(Bry_bfr bfr, Xow_wiki wiki, Xoa_page page, Xoctg_pagebox_itm[] pagebox_itms) {
public void Write_pagebox(Bry_bfr bfr, Xoa_page page) {
Xoctg_pagebox_itm[] itms = Get_catlinks_by_page(page);
if (itms.length > 0) {
this.Write_pagebox(bfr, page, itms);
}
}
public void Write_pagebox(Bry_bfr bfr, Xoa_page page, Xoctg_pagebox_itm[] pagebox_itms) {
try {
if (grouping_enabled)
double_box.Write_pagebox(bfr, pagebox_itms);
@ -38,20 +62,22 @@ public class Xoctg_pagebox_wtr implements Gfo_invk {
Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to write pagebox categories; page=~{0} err=~{1}", page.Url_bry_safe(), Err_.Message_gplx_log(e));
}
}
public Xoctg_pagebox_itm[] Get_catlinks_by_page(Xow_wiki wiki, Xoa_page page) {
private Xoctg_pagebox_itm[] Get_catlinks_by_page(Xoa_page page) {
// NOTE: db load is necessary b/c page.Wtxt().Ctgs__len() is insufficient
// html_dbs will always be 0 since they do not parse ctgs;
// wtxt_dbs may have page.Wtxt().Ctgs__len() > 0 but these items don't have Id / Hidden
Xoctg_pagebox_hash hash = new Xoctg_pagebox_hash();
Xoctg_pagebox_loader select_cbk = new Xoctg_pagebox_loader(hash, page.Url_bry_safe());
// get cat_db_id from page
tmp_page_itm.Clear();
boolean exists = wiki.Data__core_mgr().Tbl__page().Select_by_ttl(tmp_page_itm, page.Ttl().Ns(), page.Ttl().Page_db());
int cat_db_id = tmp_page_itm.Cat_db_id();
Xowd_page_itm pageRow = new Xowd_page_itm();
boolean exists = wiki.Data__core_mgr().Tbl__page().Select_by_ttl(pageRow, page.Ttl().Ns(), page.Ttl().Page_db());
int cat_db_id = pageRow.Cat_db_id();
if (exists && cat_db_id != -1) {// note that wtxt_dbs can have 0 ctgs but will have cat_db_id == -1
Xow_db_file cat_link_db = wiki.Data__core_mgr().Dbs__get_by_id_or_null(cat_db_id);
if (cat_link_db != null && Io_mgr.Instance.ExistsFil(cat_link_db.Url())) { // make sure cat_db_id exists
select_cbk.Select_catlinks_by_page(wiki, cat_link_db.Conn(), hash, tmp_page_itm.Id());
select_cbk.Select_catlinks_by_page(wiki, cat_link_db.Conn(), hash, pageRow.Id());
}
}
@ -63,6 +89,7 @@ public class Xoctg_pagebox_wtr implements Gfo_invk {
}
return hash.To_ary_and_clear();
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Cfg__grouping_enabled)) this.grouping_enabled = m.ReadYn("v");
else return Gfo_invk_.Rv_unhandled;

View File

@ -1,27 +1,40 @@
/*
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.addons.wikis.fulltexts.searchers.mgrs.gflucenes; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.fulltexts.*; import gplx.xowa.addons.wikis.fulltexts.searchers.*; import gplx.xowa.addons.wikis.fulltexts.searchers.mgrs.*;
import gplx.gflucene.*;
import gplx.gflucene.core.*;
import gplx.gflucene.indexers.*;
import gplx.gflucene.searchers.*;
import gplx.gflucene.highlighters.*;
import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.addons.wikis.fulltexts.searchers.mgrs.uis.*;
import gplx.xowa.addons.wikis.fulltexts.searchers.caches.*;
/*
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.addons.wikis.fulltexts.searchers.mgrs.gflucenes;
import gplx.Gfo_usr_dlg_;
import gplx.Ordered_hash;
import gplx.Ordered_hash_;
import gplx.String_;
import gplx.gflucene.core.Gflucene_analyzer_data;
import gplx.gflucene.core.Gflucene_doc_data;
import gplx.gflucene.core.Gflucene_index_data;
import gplx.gflucene.searchers.Gflucene_searcher_mgr;
import gplx.gflucene.searchers.Gflucene_searcher_qry;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xow_wiki;
import gplx.xowa.addons.wikis.fulltexts.Xosearch_fulltext_addon;
import gplx.xowa.addons.wikis.fulltexts.searchers.caches.Xofulltext_cache_qry;
import gplx.xowa.addons.wikis.fulltexts.searchers.mgrs.Xofulltext_args_qry;
import gplx.xowa.addons.wikis.fulltexts.searchers.mgrs.Xofulltext_args_wiki;
import gplx.xowa.addons.wikis.fulltexts.searchers.mgrs.Xofulltext_searcher;
import gplx.xowa.addons.wikis.fulltexts.searchers.mgrs.uis.Xofulltext_searcher_page;
import gplx.xowa.addons.wikis.fulltexts.searchers.mgrs.uis.Xofulltext_searcher_ui;
import gplx.xowa.wikis.data.tbls.Xowd_page_itm;
import gplx.xowa.wikis.data.tbls.Xowd_page_tbl;
public class Xofulltext_searcher__lucene implements Xofulltext_searcher {
private final Gflucene_searcher_mgr searcher = new Gflucene_searcher_mgr();
public boolean Type_is_lucene() {return true;}

View File

@ -1,33 +1,66 @@
/*
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.addons.wikis.pages.randoms.specials; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.pages.*; import gplx.xowa.addons.wikis.pages.randoms.*;
import gplx.xowa.wikis.nss.*; import gplx.xowa.specials.*;
/*
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.xowa.addons.wikis.pages.randoms.specials;
import gplx.Bry_;
import gplx.String_;
import gplx.xowa.Xoa_page;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoa_url;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xow_wiki;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.specials.Xow_special_meta;
import gplx.xowa.specials.Xow_special_meta_;
import gplx.xowa.specials.Xow_special_page;
import gplx.xowa.wikis.data.tbls.Xowd_page_tbl;
import gplx.xowa.wikis.nss.Xow_ns;
public class Rndm_root_special implements Xow_special_page {
public void Special__gen(Xow_wiki wikii, Xoa_page pagei, Xoa_url url, Xoa_ttl ttl) {
@Override public Xow_special_meta Special__meta() {return new Xow_special_meta(Xow_special_meta_.Src__mw, SPECIAL_KEY);}
@Override public Xow_special_page Special__clone() {return this;}
@Override public void Special__gen(Xow_wiki wikii, Xoa_page pagei, Xoa_url url, Xoa_ttl ttl) {
// get ns
Xowe_wiki wiki = (Xowe_wiki)wikii; Xoae_page page = (Xoae_page)pagei;
Xow_ns ns = wiki.Ns_mgr().Names_get_or_main(ttl.Rest_txt());
// Rndm_addon.Get(wiki).Mgr().Regy().Get_rndm_page_by_ns(ns);
byte[] random_ttl_bry = wiki.Db_mgr().Load_mgr().Find_random_ttl(ns);
byte[] root_bry = Xoa_ttl.Parse(wiki, random_ttl_bry).Root_txt();
wiki.Data_mgr().Redirect(page, ns.Gen_ttl(root_bry));
// get random ttl
String randomTitleString = selectRandomTitle(wiki, ns.Id());
wiki.Data_mgr().RedirectWithoutLoading(page, ns.Gen_ttl(Bry_.new_u8(randomTitleString)));
}
private String selectRandomTitle(Xow_wiki wiki, int ns_id) {
// ISSUE#:719; find pages without "/" and not redirect
// REF.MW:https://github.com/wikimedia/mediawiki/blob/master/includes/specials/SpecialRandomrootpage.php
Xowd_page_tbl pageTbl = wiki.Data__core_mgr().Db__core().Tbl__page();
String where = String_.Format
("p.{0} = {1} AND p.{2} = {3} AND p.{4} NOT LIKE '%/%'"
, pageTbl.Fld_page_ns(), ns_id
, pageTbl.Fld_redirect_id(), Xowd_page_tbl.INVALID_PAGE_ID
, pageTbl.Fld_page_title()
);
return (String)pageTbl.Conn().WkrMgr().ExecRandomObj
( pageTbl.Fld_page_title()
, pageTbl.Tbl_name() + " p"
, where
);
}
public static final String SPECIAL_KEY = "RandomRootPage";
public static final byte[] Display_ttl = Bry_.new_a7("Random Root Page");
public Xow_special_meta Special__meta() {return new Xow_special_meta(Xow_special_meta_.Src__mw, SPECIAL_KEY);}
public static final Xow_special_page Prototype = new Rndm_root_special();
public Xow_special_page Special__clone() {return this;}
public static final byte[] Display_ttl = Bry_.new_a7("Random Root Page");
public static final Xow_special_page Prototype = new Rndm_root_special();
}

View File

@ -1,54 +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.xowa.addons.wikis.pages.randoms.specials; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.pages.*; import gplx.xowa.addons.wikis.pages.randoms.*;
import org.junit.*; import gplx.xowa.specials.*;
public class Rndm_root_special_tst {
@Before public void init() {fxt.Clear();} private Rndm_root_special_fxt fxt = new Rndm_root_special_fxt();
@Test public void Ns_main() {
fxt.Init_create_page("A");
fxt.Init_create_page("A/B/C");
fxt.Test_open("Special:RandomRootPage/Main", "A"); // NOTE: result will always be "A"; "A" -> "A"; "A/B/C" -> "A"
}
@Test public void Ns_help() {
fxt.Init_create_page("Help:A");
fxt.Init_create_page("Help:A/B/C");
fxt.Test_open("Special:RandomRootPage/Help", "Help:A");
}
}
class Rndm_root_special_fxt {
private Xop_fxt parser_fxt; private Rndm_root_special special_page; private Xowe_wiki wiki;
public void Clear() {
parser_fxt = new Xop_fxt();
parser_fxt.Reset();
wiki = parser_fxt.Wiki();
special_page = new gplx.xowa.addons.wikis.pages.randoms.specials.Rndm_root_special();
}
public void Init_create_page(String page) {parser_fxt.Init_page_create(page, page);}
public void Test_open(String special_url, String expd) {
Xoae_page page = Test_special_open(wiki, special_page, special_url);
Tfds.Eq(expd, String_.new_a7(page.Url().Page_bry()));
Tfds.Eq(expd, String_.new_a7(page.Db().Text().Text_bry()));
}
public static Xoae_page Test_special_open(Xowe_wiki wiki, Xow_special_page special_page, String special_url) {
Xoae_page page = wiki.Parser_mgr().Ctx().Page();
Xoa_url url = wiki.Utl__url_parser().Parse(Bry_.new_u8(special_url));
page.Url_(url);
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, Bry_.new_a7(special_url));
page.Ttl_(ttl);
special_page.Special__gen(wiki, page, url, ttl);
return page;
}
}

View File

@ -1,22 +1,36 @@
/*
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.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
import gplx.core.envs.*;
import gplx.xowa.guis.views.*;
import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.errors.*;
/*
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.xowa.apps.servers.http;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Io_mgr;
import gplx.String_;
import gplx.core.envs.Runtime_;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoa_url;
import gplx.xowa.Xoae_app;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.Xowe_wiki_;
import gplx.xowa.apps.servers.Gxw_html_server;
import gplx.xowa.guis.views.Xog_tab_itm;
import gplx.xowa.specials.Xow_special_meta_;
import gplx.xowa.specials.xowa.errors.Xoerror_special;
public class Http_server_page {
private final Xoae_app app;
public Http_server_page(Xoae_app app) {
@ -97,26 +111,22 @@ public class Http_server_page {
this.html = wiki.Html_mgr().Head_mgr().Popup_mgr().Show_init(popup_id, ttl_bry, ttl_bry);
}
else {
// NOTE: generates HTML, but substitutes xoimg tags for <img>; ISSUE#:686; DATE:2020-06-27
byte[] page_html = wiki.Html_mgr().Page_wtr_mgr().Gen(page, mode);
page_html = Bry_.Replace_many(page_html, app.Fsys_mgr().Root_dir().To_http_file_bry(), Http_server_wkr.Url__fsys);
this.html = String_.new_u8(page_html); // NOTE: must generate HTML now in order for "wait" and "async_server" to work with text_dbs; DATE:2016-07-10
boolean rebuild_html = false;
switch (retrieve_mode) {
case File_retrieve_mode.Mode_skip: // noop
break;
case File_retrieve_mode.Mode_async_server:
rebuild_html = true;
app.Gui_mgr().Browser_win().Page__async__bgn(tab);
break;
case File_retrieve_mode.Mode_wait:
rebuild_html = true;
gplx.xowa.guis.views.Xog_async_wkr.Async(page, tab.Html_itm());
this.page = wiki.Page_mgr().Load_page(url, ttl, tab); // HACK: fetch page again so that HTML will now include img data
break;
}
if (rebuild_html)
this.html = String_.new_u8(wiki.Html_mgr().Page_wtr_mgr().Gen(page, mode));
// NOTE: substitutes xoimg tags for actual file; ISSUE#:686; DATE:2020-06-27
this.html = String_.new_u8(wiki.Html__hdump_mgr().Load_mgr().Parse(page_html, this.page));
}
}
}

View File

@ -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,114 +13,129 @@ 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.apps.site_cfgs; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*;
import gplx.core.net.*; import gplx.langs.jsons.*; import gplx.xowa.apps.gfs.*;
import gplx.xowa.langs.*;
import gplx.xowa.wikis.domains.*; import gplx.xowa.wikis.xwikis.*;
class Xoa_site_cfg_itm__interwikimap extends Xoa_site_cfg_itm__base {
private final Bry_bfr tmp_bfr = Bry_bfr_.New();
private final Gfo_url_parser url_parser = new Gfo_url_parser();
public Xoa_site_cfg_itm__interwikimap() {this.Ctor(Xoa_site_cfg_loader__inet.Qarg__interwikimap);}
@Override public void Parse_json_ary_itm(Bry_bfr bfr, Xow_wiki wiki, int i, Json_itm itm) {
Json_nde nde = Json_nde.cast(itm);
if (i != 0) bfr.Add_byte_nl();
byte[] iw_key = nde.Get_bry_or_null("prefix"); if (iw_key == null) throw Err_.new_("site_meta", "invalid interwiki", "key", iw_key);
byte[] iw_url = nde.Get_bry_or_null("url"); if (iw_url == null) throw Err_.new_("site_meta", "invalid interwiki", "url", iw_key);
bfr.Add(iw_key).Add_byte_pipe().Add(Gfs_php_converter.To_gfs(tmp_bfr, iw_url));
}
@Override public void Exec_csv(Xow_wiki wiki, int loader_tid, byte[] dsv_bry) {
if (loader_tid == Xoa_site_cfg_loader_.Tid__fallback)
Exec_csv__fallback(wiki);
else {
byte[][] lines = Bry_split_.Split_lines(dsv_bry);
int lines_len = lines.length;
for (int i = 0; i < lines_len; ++i) {
byte[] line = lines[i]; if (Bry_.Len_eq_0(line)) continue; // ignore blank lines
byte[][] flds = Bry_split_.Split(line, Byte_ascii.Pipe);
byte[] url_fmt = flds[1];
byte[] domain_bry = Xow_xwiki_mgr.Get_domain_from_url(url_parser, url_fmt);
wiki.Xwiki_mgr().Add_by_site_interwikimap
( flds[0], domain_bry, url_fmt
, Bry_.Replace(url_fmt, Arg0_xo, Arg0_wm) // NOTE: interwiki items are stored in wiki.core.xowa_cfg as https://en.wikipedia.org/wiki/~{0}
);
}
}
}
private void Exec_csv__fallback(Xow_wiki wiki) {
Xow_xwiki_mgr xwiki_mgr = wiki.Xwiki_mgr();
int domain_tid = wiki.Domain_tid();
xwiki_mgr.Add_by_csv(Csv__manual); // adds manual xwikis that should exist in all wikis; EX: 'commons', 'wikidata', 'oldwikisource', 'wmf'
switch (domain_tid) {
case Xow_domain_tid_.Tid__wikipedia: case Xow_domain_tid_.Tid__wiktionary: case Xow_domain_tid_.Tid__wikisource: case Xow_domain_tid_.Tid__wikivoyage:
case Xow_domain_tid_.Tid__wikiquote: case Xow_domain_tid_.Tid__wikibooks: case Xow_domain_tid_.Tid__wikiversity: case Xow_domain_tid_.Tid__wikinews:
xwiki_mgr.Add_by_sitelink_mgr(); // lang: EX: [[fr:]] -> fr.wikipedia.org
xwiki_mgr.Add_by_csv(Csv__peers__lang); // peer: EX: [[wikt]] -> en.wiktionary.org
break;
case Xow_domain_tid_.Tid__commons: case Xow_domain_tid_.Tid__wikidata:
case Xow_domain_tid_.Tid__wikimedia: case Xow_domain_tid_.Tid__species: case Xow_domain_tid_.Tid__meta:
case Xow_domain_tid_.Tid__incubator: case Xow_domain_tid_.Tid__wikimania: case Xow_domain_tid_.Tid__wikisource_org:
case Xow_domain_tid_.Tid__mediawiki: case Xow_domain_tid_.Tid__wmfblog:
case Xow_domain_tid_.Tid__home: case Xow_domain_tid_.Tid__other:
xwiki_mgr.Add_by_sitelink_mgr(Xow_domain_tid_.Tid__wikipedia); // lang: hardcode to wikipedia; EX: "[[en:]] -> "en.wikipedia.org"
xwiki_mgr.Add_by_csv(Csv__peers__english); // peer: hardcode to english
break;
}
// wikivoyage
switch (domain_tid) {
case Xow_domain_tid_.Tid__wikivoyage: case Xow_domain_tid_.Tid__home: // NOTE: home needed for diagnostic; DATE:2015-10-13
xwiki_mgr.Add_by_csv(Csv__wikivoyage);
break;
}
// if simplewiki, add "w" -> "enwiki"
if (Bry_.Eq(wiki.Domain_bry(), Xow_domain_itm_.Bry__simplewiki))
xwiki_mgr.Add_by_csv(Csv__enwiki);
}
private static final byte[]
Csv__manual = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "1|commons;c|commons.wikimedia.org|Commons"
, "1|m;metawikipedia|meta.wikipedia.org"
, "1|species;wikispecies|species.wikimedia.org"
, "1|d;wikidata|www.wikidata.org"
, "1|mw;mediawikiwiki|www.mediawiki.org"
, "1|wmf;wikimedia;foundation|foundation.wikimedia.org"
, "1|incubator|incubator.wikimedia.org"
, "1|wikimania|wikimania.wikimedia.org"
, "1|sourceswiki|wikisource.org"
, "0|oldwikisource|https://wikisource.org/wiki/~{0}|Old Wikisoure"
, "0|mail|https://lists.wikimedia.org/mailman/listinfo/~{0}|Wikitech Mailing List"
))
, Csv__peers__lang = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "2|w;wikipedia|wikipedia"
, "2|wikt;wiktionary|wiktionary"
, "2|s;wikisource|wikisource"
, "2|b;wikibooks|wikibooks"
, "2|v;wikiversity|wikiversity"
, "2|q;wikiquote|wikiquote"
, "2|n;wikinews|wikinews"
, "2|voy;wikivoyage|wikivoyage"
))
, Csv__peers__english = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "1|w|en.wikipedia.org"
, "1|wikt|en.wiktionary.org"
, "1|s|en.wikisource.org"
, "1|b|en.wikibooks.org"
, "1|v|en.wikiversity.org"
, "1|q|en.wikiquote.org"
, "1|n|en.wikinews.org"
, "1|voy|en.wikivoyage.org"
))
, Csv__wikivoyage = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "0|commons|commons.wikimedia.org|Wikimedia Commons"
, "2|wikipedia|wikipedia|Wikipedia"
, "0|dmoz|http://www.dmoz.org/~{0}|DMOZ"
))
, Csv__enwiki = Bry_.new_a7("2|w|wikipedia")
;
private static final byte[]
Arg0_xo = Bry_.new_a7("~{0}")
, Arg0_wm = Bry_.new_a7("$1")
;
}
package gplx.xowa.apps.site_cfgs;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Bry_split_;
import gplx.Byte_ascii;
import gplx.Err_;
import gplx.String_;
import gplx.core.net.Gfo_url_parser;
import gplx.langs.jsons.Json_itm;
import gplx.langs.jsons.Json_nde;
import gplx.xowa.Xow_wiki;
import gplx.xowa.apps.gfs.Gfs_php_converter;
import gplx.xowa.wikis.domains.Xow_domain_itm_;
import gplx.xowa.wikis.domains.Xow_domain_tid_;
import gplx.xowa.wikis.xwikis.Xow_xwiki_mgr;
class Xoa_site_cfg_itm__interwikimap extends Xoa_site_cfg_itm__base {
private final Bry_bfr tmp_bfr = Bry_bfr_.New();
private final Gfo_url_parser url_parser = new Gfo_url_parser();
public Xoa_site_cfg_itm__interwikimap() {
this.Ctor(Xoa_site_cfg_loader__inet.Qarg__interwikimap);
}
@Override public void Parse_json_ary_itm(Bry_bfr bfr, Xow_wiki wiki, int i, Json_itm itm) {
Json_nde nde = Json_nde.Cast(itm);
if (i != 0) bfr.Add_byte_nl();
byte[] iw_key = nde.Get_bry_or_null("prefix"); if (iw_key == null) throw Err_.new_("site_meta", "invalid interwiki", "key", iw_key);
byte[] iw_url = nde.Get_bry_or_null("url"); if (iw_url == null) throw Err_.new_("site_meta", "invalid interwiki", "url", iw_key);
bfr.Add(iw_key).Add_byte_pipe().Add(Gfs_php_converter.To_gfs(tmp_bfr, iw_url));
}
@Override public void Exec_csv(Xow_wiki wiki, int loader_tid, byte[] dsv_bry) {
if (loader_tid == Xoa_site_cfg_loader_.Tid__fallback)
Exec_csv__fallback(wiki);
else {
byte[][] lines = Bry_split_.Split_lines(dsv_bry);
int lines_len = lines.length;
for (int i = 0; i < lines_len; ++i) {
byte[] line = lines[i]; if (Bry_.Len_eq_0(line)) continue; // ignore blank lines
byte[][] flds = Bry_split_.Split(line, Byte_ascii.Pipe);
byte[] url_fmt = flds[1];
byte[] domain_bry = Xow_xwiki_mgr.Get_domain_from_url(url_parser, url_fmt);
wiki.Xwiki_mgr().Add_by_site_interwikimap
( flds[0], domain_bry, url_fmt
, Bry_.Replace(url_fmt, Arg0_xo, Arg0_wm) // NOTE: interwiki items are stored in wiki.core.xowa_cfg as https://en.wikipedia.org/wiki/~{0}
);
}
}
}
private void Exec_csv__fallback(Xow_wiki wiki) {
Xow_xwiki_mgr xwiki_mgr = wiki.Xwiki_mgr();
int domain_tid = wiki.Domain_tid();
xwiki_mgr.Add_by_csv(Csv__manual); // adds manual xwikis that should exist in all wikis; EX: 'commons', 'wikidata', 'oldwikisource', 'wmf'
switch (domain_tid) {
case Xow_domain_tid_.Tid__wikipedia: case Xow_domain_tid_.Tid__wiktionary: case Xow_domain_tid_.Tid__wikisource: case Xow_domain_tid_.Tid__wikivoyage:
case Xow_domain_tid_.Tid__wikiquote: case Xow_domain_tid_.Tid__wikibooks: case Xow_domain_tid_.Tid__wikiversity: case Xow_domain_tid_.Tid__wikinews:
xwiki_mgr.Add_by_sitelink_mgr(); // lang: EX: [[fr:]] -> fr.wikipedia.org
xwiki_mgr.Add_by_csv(Csv__peers__lang); // peer: EX: [[wikt]] -> en.wiktionary.org
break;
case Xow_domain_tid_.Tid__commons: case Xow_domain_tid_.Tid__wikidata:
case Xow_domain_tid_.Tid__wikimedia: case Xow_domain_tid_.Tid__species: case Xow_domain_tid_.Tid__meta:
case Xow_domain_tid_.Tid__incubator: case Xow_domain_tid_.Tid__wikimania: case Xow_domain_tid_.Tid__wikisource_org:
case Xow_domain_tid_.Tid__mediawiki: case Xow_domain_tid_.Tid__wmfblog:
case Xow_domain_tid_.Tid__home: case Xow_domain_tid_.Tid__other:
xwiki_mgr.Add_by_sitelink_mgr(Xow_domain_tid_.Tid__wikipedia); // lang: hardcode to wikipedia; EX: "[[en:]] -> "en.wikipedia.org"
xwiki_mgr.Add_by_csv(Csv__peers__english); // peer: hardcode to english
break;
}
// wikivoyage
switch (domain_tid) {
case Xow_domain_tid_.Tid__wikivoyage: case Xow_domain_tid_.Tid__home: // NOTE: home needed for diagnostic; DATE:2015-10-13
xwiki_mgr.Add_by_csv(Csv__wikivoyage);
break;
}
// if simplewiki, add "w" -> "enwiki"
if (Bry_.Eq(wiki.Domain_bry(), Xow_domain_itm_.Bry__simplewiki))
xwiki_mgr.Add_by_csv(Csv__enwiki);
}
private static final byte[]
Csv__manual = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "1|commons;c|commons.wikimedia.org|Commons"
, "1|m;metawikipedia|meta.wikipedia.org"
, "1|species;wikispecies|species.wikimedia.org"
, "1|d;wikidata|www.wikidata.org"
, "1|mw;mediawikiwiki|www.mediawiki.org"
, "1|wmf;wikimedia;foundation|foundation.wikimedia.org"
, "1|incubator|incubator.wikimedia.org"
, "1|wikimania|wikimania.wikimedia.org"
, "1|sourceswiki|wikisource.org"
, "0|oldwikisource|https://wikisource.org/wiki/~{0}|Old Wikisoure"
, "0|mail|https://lists.wikimedia.org/mailman/listinfo/~{0}|Wikitech Mailing List"
))
, Csv__peers__lang = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "2|w;wikipedia|wikipedia"
, "2|wikt;wiktionary|wiktionary"
, "2|s;wikisource|wikisource"
, "2|b;wikibooks|wikibooks"
, "2|v;wikiversity|wikiversity"
, "2|q;wikiquote|wikiquote"
, "2|n;wikinews|wikinews"
, "2|voy;wikivoyage|wikivoyage"
))
, Csv__peers__english = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "1|w|en.wikipedia.org"
, "1|wikt|en.wiktionary.org"
, "1|s|en.wikisource.org"
, "1|b|en.wikibooks.org"
, "1|v|en.wikiversity.org"
, "1|q|en.wikiquote.org"
, "1|n|en.wikinews.org"
, "1|voy|en.wikivoyage.org"
))
, Csv__wikivoyage = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "0|commons|commons.wikimedia.org|Wikimedia Commons"
, "2|wikipedia|wikipedia|Wikipedia"
, "0|dmoz|http://www.dmoz.org/~{0}|DMOZ"
))
, Csv__enwiki = Bry_.new_a7("2|w|wikipedia")
;
private static final byte[]
Arg0_xo = Bry_.new_a7("~{0}")
, Arg0_wm = Bry_.new_a7("$1")
;
}

View File

@ -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,314 +13,347 @@ 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.bldrs.cmds; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import gplx.core.envs.*;
import gplx.dbs.*; import gplx.xowa.wikis.caches.*; import gplx.xowa.addons.bldrs.files.*; import gplx.xowa.files.origs.*;
import gplx.xowa.bldrs.wkrs.*;
import gplx.xowa.wikis.nss.*;
import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.dbs.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.addons.bldrs.files.utls.*;
import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*;
public abstract class Xob_dump_mgr_base extends Xob_itm_basic_base implements Xob_cmd, Gfo_invk {
private Xob_dump_src_id page_src;
private Xow_db_mgr db_fsys_mgr; protected Xop_parser parser; protected Xop_ctx ctx; protected Xop_root_tkn root;
private int[] ns_ary; private Xow_db_file[] db_ary;
private int ns_bgn = -1, db_bgn = -1, pg_bgn = -1;
private int ns_end = -1, db_end = -1, pg_end = Int_.Max_value;
private int commit_interval = 1000, progress_interval = 250, cleanup_interval = 2500, select_size = 10 * Io_mgr.Len_mb;
private int exec_count, exec_count_max = Int_.Max_value;
private boolean reset_db = false, exit_after_commit = false, exit_now = false;
private boolean load_tmpls;
private Xob_dump_bmk_mgr bmk_mgr = new Xob_dump_bmk_mgr();
private Xobu_poll_mgr poll_mgr; private int poll_interval = 5000;
private Xob_rate_mgr rate_mgr = new Xob_rate_mgr();
public abstract String Cmd_key();
@Override protected void Cmd_ctor_end(Xob_bldr bldr, Xowe_wiki wiki) {
poll_mgr = new Xobu_poll_mgr(bldr.App()); // init in ctor so gfs can invoke methods
}
public void Cmd_bgn(Xob_bldr bldr) {
parser = wiki.Parser_mgr().Main();
ctx = wiki.Parser_mgr().Ctx();
root = ctx.Tkn_mkr().Root(Bry_.Empty);
wiki.Init_assert(); // NOTE: must init wiki for db_mgr_as_sql
// assert by calling Db_mgr_as_sql
wiki.Db_mgr_as_sql().Core_data_mgr();
// load db_mgr
Xow_db_mgr.Init_by_load(wiki, gplx.xowa.wikis.data.Xow_db_file__core_.Find_core_fil_or_null(wiki)); // NOTE: must reinit providers as previous steps may have rls'd (and left member variable conn which is closed)
wiki.File__orig_mgr().Wkrs__del(Xof_orig_wkr_.Tid_wmf_api);
db_fsys_mgr = wiki.Db_mgr_as_sql().Core_data_mgr();
db_ary = Xob_dump_mgr_base_.Init_text_files_ary(db_fsys_mgr);
poll_interval = poll_mgr.Poll_interval();
page_src = new Xob_dump_src_id().Init(wiki, this.Init_redirect(), select_size);
ns_ary = Init_ns_ary();
Db_conn conn = Init_db_file();
Io_url wiki_dir = wiki.Fsys_mgr().Root_dir();
bmk_mgr.Cfg_url_(wiki_dir.GenSubFil("xowa.file.make.cfg.gfs"));
rate_mgr.Log_file_(wiki_dir.GenSubFil("xowa.file.make.log.csv"));
if (reset_db) {
bmk_mgr.Reset();
Init_reset(conn);
}
bmk_mgr.Load(wiki.Appe(), this);
Cmd_bgn_end();
}
protected abstract void Cmd_bgn_end();
public abstract byte Init_redirect();
public abstract int[] Init_ns_ary();
protected abstract void Init_reset(Db_conn p);
protected abstract Db_conn Init_db_file();
private long time_bgn;
public void Cmd_run() {Exec_ns_ary();}
private void Exec_ns_ary() {
if (pg_bgn == Int_.Max_value) return;
if (load_tmpls) Xob_dump_mgr_base_.Load_all_tmpls(usr_dlg, wiki, page_src);
time_bgn = System_.Ticks();
Xob_dump_bmk dump_bmk = new Xob_dump_bmk();
rate_mgr.Init();
int ns_ary_len = ns_ary.length;
for (int i = 0; i < ns_ary_len; i++) {
int ns_id = ns_ary[i];
if (ns_bgn != -1) { // ns_bgn set
if (ns_id == ns_bgn) // ns_id is ns_bgn; null out ns_bgn and continue
ns_bgn = -1;
else // ns_id is not ns_bgn; keep looking
continue;
}
dump_bmk.Ns_id_(ns_id);
Exec_db_ary(i, dump_bmk, ns_id);
if (ns_id == ns_end) exit_now = true; // ns_end set; exit
if (exit_now) break; // exit_now b/c of pg_bgn, db_bgn or something else
}
Exec_commit(dump_bmk.Ns_id(), dump_bmk.Db_id(), dump_bmk.Pg_id(), Bry_.Empty);
}
private void Exec_db_ary(int ns_ord, Xob_dump_bmk dump_bmk, int ns_id) {
int db_ary_len = db_ary.length;
for (int i = 0; i < db_ary_len; i++) {
int db_id = db_ary[i].Id();
if (db_bgn != -1) { // db_bgn set
if (db_id == db_bgn) // db_id is db_bgn; null out db_bgn and continue
db_bgn = -1;
else // db_id is not db_bgn; keep looking
continue;
}
dump_bmk.Db_id_(db_id);
Exec_db_itm(dump_bmk, ns_ord, ns_id, db_id);
if (db_id == db_end) exit_now = true; // db_end set; exit;
if (exit_now) return; // exit_now b/c of pg_bgn, db_bgn or something else
}
}
private void Exec_db_itm(Xob_dump_bmk dump_bmk, int ns_ord, int ns_id, int db_id) {
List_adp pages = List_adp_.New();
Xow_ns ns = wiki.Ns_mgr().Ids_get_or_null(ns_id);
int pg_id = pg_bgn;
while (true) {
page_src.Get_pages(wiki.Appe(), pages, db_id, ns_id, pg_id);
int pages_len = pages.Count();
if (pages_len == 0) { // no more pages in db;
if (pg_id > pg_bgn) // reset pg_bgn to 0 only if pg_bgn seen;
pg_bgn = 0;
return;
}
usr_dlg.Prog_many("", "", "fetched pages: ~{0}", pages_len);
for (int i = 0; i < pages_len; i++) {
Xowd_page_itm page = (Xowd_page_itm)pages.Get_at(i);
dump_bmk.Pg_id_(pg_id);
Exec_pg_itm(ns_ord, ns, db_id, page);
if ( pg_id >= pg_end
|| exec_count >= exec_count_max) {
exit_now = true;
}
if (exit_now) return;
pg_id = page.Id();
}
}
}
private void Exec_pg_itm(int ns_ord, Xow_ns ns, int db_id, Xowd_page_itm page) {
try {
if ((exec_count % progress_interval) == 0)
usr_dlg.Prog_many("", "", "parsing: ns=~{0} db=~{1} pg=~{2} count=~{3} time=~{4} rate=~{5} ttl=~{6}"
, ns.Id(), db_id, page.Id(), exec_count
, System_.Ticks__elapsed_in_sec(time_bgn), rate_mgr.Rate_as_str(), String_.new_u8(page.Ttl_page_db()));
ctx.Clear_all();
byte[] page_src = page.Text();
if (page_src != null) // some pages have no text; ignore them else null ref; PAGE: it.d:miercuri DATE:2015-12-05
Exec_pg_itm_hook(ns_ord, ns, page, page_src);
ctx.Wiki().Utl__bfr_mkr().Clear_fail_check(); // make sure all bfrs are released
if (ctx.Wiki().Cache_mgr().Tmpl_result_cache().Count() > 50000)
ctx.Wiki().Cache_mgr().Tmpl_result_cache().Clear();
++exec_count;
rate_mgr.Increment();
if ((exec_count % poll_interval) == 0)
poll_mgr.Poll();
if ((exec_count % commit_interval) == 0)
Exec_commit(ns.Id(), db_id, page.Id(), page.Ttl_page_db());
if ((exec_count % cleanup_interval) == 0)
Free();
}
catch (Exception exc) {
bldr.Usr_dlg().Warn_many("", "", "parse failed: wiki=~{0} ttl=~{1} err=~{2}", wiki.Domain_str(), page.Ttl_full_db(), Err_.Message_gplx_log(exc));
ctx.Wiki().Utl__bfr_mkr().Clear();
this.Free();
}
}
public abstract void Exec_pg_itm_hook(int ns_ord, Xow_ns ns, Xowd_page_itm page, byte[] page_text);
private void Exec_commit(int ns_id, int db_id, int pg_id, byte[] ttl) {
usr_dlg.Prog_many("", "", "committing: ns=~{0} db=~{1} pg=~{2} count=~{3} ttl=~{4}", ns_id, db_id, pg_id, exec_count, String_.new_u8(ttl));
Exec_commit_hook();
bmk_mgr.Save(ns_id, db_id, pg_id);
if (exit_after_commit) exit_now = true;
}
public abstract void Exec_commit_hook();
public abstract void Exec_end_hook();
public void Cmd_init(Xob_bldr bldr) {}
public void Cmd_term() {}
public void Cmd_end() {
if (!exit_now)
pg_bgn = Int_.Max_value;
Exec_commit(-1, -1, -1, Bry_.Empty);
Exec_end_hook();
Free();
usr_dlg.Note_many("", "", "done: ~{0} ~{1}", exec_count, Decimal_adp_.divide_safe_(exec_count, System_.Ticks__elapsed_in_sec(time_bgn)).To_str("#,###.000"));
}
private void Free() {
Xowe_wiki_.Rls_mem(wiki, true);
}
protected void Reset_db_y_() {this.reset_db = true;}
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_commit_interval_)) commit_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk_progress_interval_)) progress_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk_rate_interval_)) rate_mgr.Reset_interval_(m.ReadInt("v"));
else if (ctx.Match(k, Invk_cleanup_interval_)) cleanup_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk_select_size_)) select_size = m.ReadInt("v") * Io_mgr.Len_mb;
else if (ctx.Match(k, Invk_ns_bgn_)) {ns_bgn = m.ReadInt("v"); Notify_restoring("ns", ns_bgn);}
else if (ctx.Match(k, Invk_db_bgn_)) {db_bgn = m.ReadInt("v"); Notify_restoring("db", db_bgn);}
else if (ctx.Match(k, Invk_pg_bgn_)) {pg_bgn = m.ReadInt("v"); Notify_restoring("pg", pg_bgn);}
else if (ctx.Match(k, Invk_ns_end_)) ns_end = m.ReadInt("v");
else if (ctx.Match(k, Invk_db_end_)) db_end = m.ReadInt("v");
else if (ctx.Match(k, Invk_pg_end_)) pg_end = m.ReadInt("v");
else if (ctx.Match(k, Invk_load_tmpls_)) load_tmpls = m.ReadYn("v");
else if (ctx.Match(k, Invk_poll_mgr)) return poll_mgr;
else if (ctx.Match(k, Invk_reset_db_)) reset_db = m.ReadYn("v");
else if (ctx.Match(k, Invk_exec_count_max_)) exec_count_max = m.ReadInt("v");
else if (ctx.Match(k, Invk_exit_now_)) exit_now = m.ReadYn("v");
else if (ctx.Match(k, Invk_exit_after_commit_)) exit_after_commit = m.ReadYn("v");
else if (ctx.Match(k, Invk__manual_now_)) Datetime_now.Manual_and_freeze_(m.ReadDate("v"));
else return Gfo_invk_.Rv_unhandled;
return this;
}
private void Notify_restoring(String itm, int val) {
usr_dlg.Note_many("", "", "restoring: itm=~{0} val=~{1}", itm, val);
}
public static final String
Invk_progress_interval_ = "progress_interval_", Invk_commit_interval_ = "commit_interval_", Invk_cleanup_interval_ = "cleanup_interval_", Invk_rate_interval_ = "rate_interval_"
, Invk_select_size_ = "select_size_"
, Invk_ns_bgn_ = "ns_bgn_", Invk_db_bgn_ = "db_bgn_", Invk_pg_bgn_ = "pg_bgn_"
, Invk_ns_end_ = "ns_end_", Invk_db_end_ = "db_end_", Invk_pg_end_ = "pg_end_"
, Invk_load_tmpls_ = "load_tmpls_"
, Invk_poll_mgr = "poll_mgr", Invk_reset_db_ = "reset_db_"
, Invk_exec_count_max_ = "exec_count_max_", Invk_exit_now_ = "exit_now_", Invk_exit_after_commit_ = "exit_after_commit_"
, Invk__manual_now_ = "manual_now_"
;
}
class Xob_dump_mgr_base_ {
public static void Load_all_tmpls(Gfo_usr_dlg usr_dlg, Xowe_wiki wiki, Xob_dump_src_id page_src) {
List_adp pages = List_adp_.New();
Xow_ns ns_tmpl = wiki.Ns_mgr().Ns_template();
Xow_defn_cache defn_cache = wiki.Cache_mgr().Defn_cache();
int cur_page_id = -1;
int load_count = 0;
usr_dlg.Note_many("", "", "tmpl_load init");
while (true) {
page_src.Get_pages(wiki.Appe(), pages, 0, Xow_ns_.Tid__template, cur_page_id); // 0 is always template db
int page_count = pages.Count();
if (page_count == 0) break; // no more pages in db;
Xowd_page_itm page = null;
for (int i = 0; i < page_count; i++) {
page = (Xowd_page_itm)pages.Get_at(i);
Xot_defn_tmpl defn = new Xot_defn_tmpl();
defn.Init_by_new(ns_tmpl, ns_tmpl.Gen_ttl(page.Ttl_page_db()), page.Text(), null, false); // NOTE: passing null, false; will be overriden later when Parse is called
defn_cache.Add(defn, ns_tmpl.Case_match());
++load_count;
if ((load_count % 10000) == 0) usr_dlg.Prog_many("", "", "tmpl_loading: ~{0}", load_count);
}
cur_page_id = page.Id();
}
usr_dlg.Note_many("", "", "tmpl_load done: ~{0}", load_count);
}
public static Xow_db_file[] Init_text_files_ary(Xow_db_mgr core_data_mgr) {
List_adp text_files_list = List_adp_.New();
int len = core_data_mgr.Dbs__len();
if (len == 1) return new Xow_db_file[] {core_data_mgr.Dbs__get_at(0)}; // single file: return core; note that there are no Tid = Text
for (int i = 0; i < len; i++) {
Xow_db_file file = core_data_mgr.Dbs__get_at(i);
switch (file.Tid()) {
case Xow_db_file_.Tid__text:
case Xow_db_file_.Tid__text_solo:
text_files_list.Add(file);
break;
}
}
return (Xow_db_file[])text_files_list.To_ary_and_clear(Xow_db_file.class);
}
}
class Xob_dump_bmk_mgr {
private Bry_bfr save_bfr = Bry_bfr_.Reset(1024);
public Io_url Cfg_url() {return cfg_url;} public Xob_dump_bmk_mgr Cfg_url_(Io_url v) {cfg_url = v; return this;} private Io_url cfg_url;
public void Reset() {Io_mgr.Instance.DeleteFil(cfg_url);}
public void Load(Xoae_app app, Xob_dump_mgr_base dump_mgr) {
app.Gfs_mgr().Run_url_for(dump_mgr, cfg_url);
}
public void Save(int ns_id, int db_id, int pg_id) {
Save_itm(save_bfr, Xob_dump_mgr_base.Invk_ns_bgn_, ns_id);
Save_itm(save_bfr, Xob_dump_mgr_base.Invk_db_bgn_, db_id);
Save_itm(save_bfr, Xob_dump_mgr_base.Invk_pg_bgn_, pg_id);
Io_mgr.Instance.SaveFilBfr(cfg_url, save_bfr);
}
private void Save_itm(Bry_bfr save_bfr, String key, int val) {
String fmt = "{0}('{1}');\n";
String str = String_.Format(fmt, key, val);
save_bfr.Add_str_u8(str);
}
}
class Xob_rate_mgr {
private long time_bgn;
private int item_len;
private Bry_bfr save_bfr = Bry_bfr_.Reset(255);
public int Reset_interval() {return reset_interval;} public Xob_rate_mgr Reset_interval_(int v) {reset_interval = v; return this;} private int reset_interval = 10000;
public Io_url Log_file_url() {return log_file;} public Xob_rate_mgr Log_file_(Io_url v) {log_file = v; return this;} private Io_url log_file;
public void Init() {time_bgn = System_.Ticks();}
public void Increment() {
++item_len;
if (item_len % reset_interval == 0) {
long time_end = System_.Ticks();
Save(item_len, time_bgn, time_end);
time_bgn = time_end;
item_len = 0;
}
}
private void Save(int count, long bgn, long end) {
int dif = (int)(end - bgn) / 1000;
Decimal_adp rate = Decimal_adp_.divide_safe_(count, dif);
save_bfr
.Add_str_a7(rate.To_str("#,##0.000")).Add_byte_pipe()
.Add_int_variable(count).Add_byte_pipe()
.Add_int_variable(dif).Add_byte_nl()
;
Io_mgr.Instance.AppendFilByt(log_file, save_bfr.To_bry_and_clear());
}
public String Rate_as_str() {return Int_.To_str(Rate());}
public int Rate() {
int elapsed = System_.Ticks__elapsed_in_sec(time_bgn);
return Math_.Div_safe_as_int(item_len, elapsed);
}
}
class Xob_dump_bmk {
public int Ns_id() {return ns_id;} public Xob_dump_bmk Ns_id_(int v) {ns_id = v; return this;} private int ns_id;
public int Db_id() {return db_id;} public Xob_dump_bmk Db_id_(int v) {db_id = v; return this;} private int db_id;
public int Pg_id() {return pg_id;} public Xob_dump_bmk Pg_id_(int v) {pg_id = v; return this;} private int pg_id;
}
package gplx.xowa.bldrs.cmds;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Datetime_now;
import gplx.Decimal_adp;
import gplx.Decimal_adp_;
import gplx.Err_;
import gplx.GfoMsg;
import gplx.Gfo_invk;
import gplx.Gfo_invk_;
import gplx.Gfo_usr_dlg;
import gplx.GfsCtx;
import gplx.Int_;
import gplx.Io_mgr;
import gplx.Io_url;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.Math_;
import gplx.String_;
import gplx.core.envs.System_;
import gplx.dbs.Db_conn;
import gplx.xowa.Xoae_app;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.Xowe_wiki_;
import gplx.xowa.addons.bldrs.files.utls.Xobu_poll_mgr;
import gplx.xowa.bldrs.Xob_bldr;
import gplx.xowa.bldrs.wkrs.Xob_cmd;
import gplx.xowa.bldrs.wkrs.Xob_itm_basic_base;
import gplx.xowa.files.origs.Xof_orig_wkr_;
import gplx.xowa.parsers.Xop_ctx;
import gplx.xowa.parsers.Xop_parser;
import gplx.xowa.parsers.Xop_root_tkn;
import gplx.xowa.parsers.tmpls.Xot_defn_tmpl;
import gplx.xowa.wikis.caches.Xow_defn_cache;
import gplx.xowa.wikis.data.Xow_db_file;
import gplx.xowa.wikis.data.Xow_db_file_;
import gplx.xowa.wikis.data.Xow_db_mgr;
import gplx.xowa.wikis.data.tbls.Xowd_page_itm;
import gplx.xowa.wikis.nss.Xow_ns;
import gplx.xowa.wikis.nss.Xow_ns_;
public abstract class Xob_dump_mgr_base extends Xob_itm_basic_base implements Xob_cmd, Gfo_invk {
private Xob_dump_src_id page_src;
private Xow_db_mgr db_fsys_mgr; protected Xop_parser parser; protected Xop_ctx ctx; protected Xop_root_tkn root;
private int[] ns_ary; private Xow_db_file[] db_ary;
private int ns_bgn = -1, db_bgn = -1, pg_bgn = -1;
private int ns_end = -1, db_end = -1, pg_end = Int_.Max_value;
private int commit_interval = 1000, progress_interval = 250, cleanup_interval = 2500, select_size = 10 * Io_mgr.Len_mb;
private int exec_count, exec_count_max = Int_.Max_value;
private boolean reset_db = false, exit_after_commit = false, exit_now = false;
private boolean load_tmpls;
private Xob_dump_bmk_mgr bmk_mgr = new Xob_dump_bmk_mgr();
private Xobu_poll_mgr poll_mgr; private int poll_interval = 5000;
private Xob_rate_mgr rate_mgr = new Xob_rate_mgr();
public abstract String Cmd_key();
@Override protected void Cmd_ctor_end(Xob_bldr bldr, Xowe_wiki wiki) {
poll_mgr = new Xobu_poll_mgr(bldr.App()); // init in ctor so gfs can invoke methods
}
public void Cmd_bgn(Xob_bldr bldr) {
parser = wiki.Parser_mgr().Main();
ctx = wiki.Parser_mgr().Ctx();
root = ctx.Tkn_mkr().Root(Bry_.Empty);
wiki.Init_assert(); // NOTE: must init wiki for db_mgr_as_sql
// assert by calling Db_mgr_as_sql
wiki.Db_mgr_as_sql().Core_data_mgr();
// load db_mgr
Xow_db_mgr.Init_by_load(wiki, gplx.xowa.wikis.data.Xow_db_file__core_.Find_core_fil_or_null(wiki)); // NOTE: must reinit providers as previous steps may have rls'd (and left member variable conn which is closed)
wiki.File__orig_mgr().Wkrs__del(Xof_orig_wkr_.Tid_wmf_api);
db_fsys_mgr = wiki.Db_mgr_as_sql().Core_data_mgr();
db_ary = Xob_dump_mgr_base_.Init_text_files_ary(db_fsys_mgr);
poll_interval = poll_mgr.Poll_interval();
page_src = new Xob_dump_src_id().Init(wiki, this.Init_redirect(), select_size);
ns_ary = Init_ns_ary();
Db_conn conn = Init_db_file();
Io_url wiki_dir = wiki.Fsys_mgr().Root_dir();
bmk_mgr.Cfg_url_(wiki_dir.GenSubFil("xowa.file.make.cfg.gfs"));
rate_mgr.Log_file_(wiki_dir.GenSubFil("xowa.file.make.log.csv"));
if (reset_db) {
bmk_mgr.Reset();
Init_reset(conn);
}
bmk_mgr.Load(wiki.Appe(), this);
Cmd_bgn_end();
}
protected abstract void Cmd_bgn_end();
public abstract byte Init_redirect();
public abstract int[] Init_ns_ary();
protected abstract void Init_reset(Db_conn p);
protected abstract Db_conn Init_db_file();
private long time_bgn;
public void Cmd_run() {Exec_ns_ary();}
private void Exec_ns_ary() {
if (pg_bgn == Int_.Max_value) return;
if (load_tmpls) Xob_dump_mgr_base_.Load_all_tmpls(usr_dlg, wiki, page_src);
time_bgn = System_.Ticks();
Xob_dump_bmk dump_bmk = new Xob_dump_bmk();
rate_mgr.Init();
int ns_ary_len = ns_ary.length;
for (int i = 0; i < ns_ary_len; i++) {
int ns_id = ns_ary[i];
if (ns_bgn != -1) { // ns_bgn set
if (ns_id == ns_bgn) // ns_id is ns_bgn; null out ns_bgn and continue
ns_bgn = -1;
else // ns_id is not ns_bgn; keep looking
continue;
}
dump_bmk.Ns_id_(ns_id);
Exec_db_ary(i, dump_bmk, ns_id);
if (ns_id == ns_end) exit_now = true; // ns_end set; exit
if (exit_now) break; // exit_now b/c of pg_bgn, db_bgn or something else
}
Exec_commit(dump_bmk.Ns_id(), dump_bmk.Db_id(), dump_bmk.Pg_id(), Bry_.Empty);
}
private void Exec_db_ary(int ns_ord, Xob_dump_bmk dump_bmk, int ns_id) {
int db_ary_len = db_ary.length;
for (int i = 0; i < db_ary_len; i++) {
int db_id = db_ary[i].Id();
if (db_bgn != -1) { // db_bgn set
if (db_id == db_bgn) // db_id is db_bgn; null out db_bgn and continue
db_bgn = -1;
else // db_id is not db_bgn; keep looking
continue;
}
dump_bmk.Db_id_(db_id);
Exec_db_itm(dump_bmk, ns_ord, ns_id, db_id);
if (db_id == db_end) exit_now = true; // db_end set; exit;
if (exit_now) return; // exit_now b/c of pg_bgn, db_bgn or something else
}
}
private void Exec_db_itm(Xob_dump_bmk dump_bmk, int ns_ord, int ns_id, int db_id) {
List_adp pages = List_adp_.New();
Xow_ns ns = wiki.Ns_mgr().Ids_get_or_null(ns_id);
int pg_id = pg_bgn;
while (true) {
page_src.Get_pages(wiki.Appe(), pages, db_id, ns_id, pg_id);
int pages_len = pages.Count();
if (pages_len == 0) { // no more pages in db;
if (pg_id > pg_bgn) // reset pg_bgn to 0 only if pg_bgn seen;
pg_bgn = 0;
return;
}
usr_dlg.Prog_many("", "", "fetched pages: ~{0}", pages_len);
for (int i = 0; i < pages_len; i++) {
Xowd_page_itm page = (Xowd_page_itm)pages.Get_at(i);
dump_bmk.Pg_id_(pg_id);
Exec_pg_itm(ns_ord, ns, db_id, page);
if ( pg_id >= pg_end
|| exec_count >= exec_count_max) {
exit_now = true;
}
if (exit_now) return;
pg_id = page.Id();
}
}
}
private void Exec_pg_itm(int ns_ord, Xow_ns ns, int db_id, Xowd_page_itm page) {
try {
if ((exec_count % progress_interval) == 0)
usr_dlg.Prog_many("", "", "parsing: ns=~{0} db=~{1} pg=~{2} count=~{3} time=~{4} rate=~{5} ttl=~{6}"
, ns.Id(), db_id, page.Id(), exec_count
, System_.Ticks__elapsed_in_sec(time_bgn), rate_mgr.Rate_as_str(), String_.new_u8(page.Ttl_page_db()));
ctx.Clear_all();
byte[] page_src = page.Text();
if (page_src != null) // some pages have no text; ignore them else null ref; PAGE: it.d:miercuri DATE:2015-12-05
Exec_pg_itm_hook(ns_ord, ns, page, page_src);
ctx.Wiki().Utl__bfr_mkr().Clear_fail_check(); // make sure all bfrs are released
++exec_count;
rate_mgr.Increment();
if ((exec_count % poll_interval) == 0)
poll_mgr.Poll();
if ((exec_count % commit_interval) == 0)
Exec_commit(ns.Id(), db_id, page.Id(), page.Ttl_page_db());
if ((exec_count % cleanup_interval) == 0)
Free();
}
catch (Exception exc) {
bldr.Usr_dlg().Warn_many("", "", "parse failed: wiki=~{0} ttl=~{1} err=~{2}", wiki.Domain_str(), page.Ttl_full_db(), Err_.Message_gplx_log(exc));
ctx.Wiki().Utl__bfr_mkr().Clear();
this.Free();
}
}
public abstract void Exec_pg_itm_hook(int ns_ord, Xow_ns ns, Xowd_page_itm page, byte[] page_text);
private void Exec_commit(int ns_id, int db_id, int pg_id, byte[] ttl) {
usr_dlg.Prog_many("", "", "committing: ns=~{0} db=~{1} pg=~{2} count=~{3} ttl=~{4}", ns_id, db_id, pg_id, exec_count, String_.new_u8(ttl));
Exec_commit_hook();
bmk_mgr.Save(ns_id, db_id, pg_id);
if (exit_after_commit) exit_now = true;
}
public abstract void Exec_commit_hook();
public abstract void Exec_end_hook();
public void Cmd_init(Xob_bldr bldr) {}
public void Cmd_term() {}
public void Cmd_end() {
if (!exit_now)
pg_bgn = Int_.Max_value;
Exec_commit(-1, -1, -1, Bry_.Empty);
Exec_end_hook();
Free();
usr_dlg.Note_many("", "", "done: ~{0} ~{1}", exec_count, Decimal_adp_.divide_safe_(exec_count, System_.Ticks__elapsed_in_sec(time_bgn)).To_str("#,###.000"));
}
private void Free() {
Xowe_wiki_.Rls_mem(wiki, true);
}
protected void Reset_db_y_() {this.reset_db = true;}
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_commit_interval_)) commit_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk_progress_interval_)) progress_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk_rate_interval_)) rate_mgr.Reset_interval_(m.ReadInt("v"));
else if (ctx.Match(k, Invk_cleanup_interval_)) cleanup_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk_select_size_)) select_size = m.ReadInt("v") * Io_mgr.Len_mb;
else if (ctx.Match(k, Invk_ns_bgn_)) {ns_bgn = m.ReadInt("v"); Notify_restoring("ns", ns_bgn);}
else if (ctx.Match(k, Invk_db_bgn_)) {db_bgn = m.ReadInt("v"); Notify_restoring("db", db_bgn);}
else if (ctx.Match(k, Invk_pg_bgn_)) {pg_bgn = m.ReadInt("v"); Notify_restoring("pg", pg_bgn);}
else if (ctx.Match(k, Invk_ns_end_)) ns_end = m.ReadInt("v");
else if (ctx.Match(k, Invk_db_end_)) db_end = m.ReadInt("v");
else if (ctx.Match(k, Invk_pg_end_)) pg_end = m.ReadInt("v");
else if (ctx.Match(k, Invk_load_tmpls_)) load_tmpls = m.ReadYn("v");
else if (ctx.Match(k, Invk_poll_mgr)) return poll_mgr;
else if (ctx.Match(k, Invk_reset_db_)) reset_db = m.ReadYn("v");
else if (ctx.Match(k, Invk_exec_count_max_)) exec_count_max = m.ReadInt("v");
else if (ctx.Match(k, Invk_exit_now_)) exit_now = m.ReadYn("v");
else if (ctx.Match(k, Invk_exit_after_commit_)) exit_after_commit = m.ReadYn("v");
else if (ctx.Match(k, Invk__manual_now_)) Datetime_now.Manual_and_freeze_(m.ReadDate("v"));
else return Gfo_invk_.Rv_unhandled;
return this;
}
private void Notify_restoring(String itm, int val) {
usr_dlg.Note_many("", "", "restoring: itm=~{0} val=~{1}", itm, val);
}
public static final String
Invk_progress_interval_ = "progress_interval_", Invk_commit_interval_ = "commit_interval_", Invk_cleanup_interval_ = "cleanup_interval_", Invk_rate_interval_ = "rate_interval_"
, Invk_select_size_ = "select_size_"
, Invk_ns_bgn_ = "ns_bgn_", Invk_db_bgn_ = "db_bgn_", Invk_pg_bgn_ = "pg_bgn_"
, Invk_ns_end_ = "ns_end_", Invk_db_end_ = "db_end_", Invk_pg_end_ = "pg_end_"
, Invk_load_tmpls_ = "load_tmpls_"
, Invk_poll_mgr = "poll_mgr", Invk_reset_db_ = "reset_db_"
, Invk_exec_count_max_ = "exec_count_max_", Invk_exit_now_ = "exit_now_", Invk_exit_after_commit_ = "exit_after_commit_"
, Invk__manual_now_ = "manual_now_"
;
}
class Xob_dump_mgr_base_ {
public static void Load_all_tmpls(Gfo_usr_dlg usr_dlg, Xowe_wiki wiki, Xob_dump_src_id page_src) {
List_adp pages = List_adp_.New();
Xow_ns ns_tmpl = wiki.Ns_mgr().Ns_template();
Xow_defn_cache defn_cache = wiki.Cache_mgr().Defn_cache();
int cur_page_id = -1;
int load_count = 0;
usr_dlg.Note_many("", "", "tmpl_load init");
while (true) {
page_src.Get_pages(wiki.Appe(), pages, 0, Xow_ns_.Tid__template, cur_page_id); // 0 is always template db
int page_count = pages.Count();
if (page_count == 0) break; // no more pages in db;
Xowd_page_itm page = null;
for (int i = 0; i < page_count; i++) {
page = (Xowd_page_itm)pages.Get_at(i);
Xot_defn_tmpl defn = new Xot_defn_tmpl();
defn.Init_by_new(ns_tmpl, ns_tmpl.Gen_ttl(page.Ttl_page_db()), page.Text(), null, false); // NOTE: passing null, false; will be overriden later when Parse is called
defn_cache.Add(defn, ns_tmpl.Case_match());
++load_count;
if ((load_count % 10000) == 0) usr_dlg.Prog_many("", "", "tmpl_loading: ~{0}", load_count);
}
cur_page_id = page.Id();
}
usr_dlg.Note_many("", "", "tmpl_load done: ~{0}", load_count);
}
public static Xow_db_file[] Init_text_files_ary(Xow_db_mgr core_data_mgr) {
List_adp text_files_list = List_adp_.New();
int len = core_data_mgr.Dbs__len();
if (len == 1) return new Xow_db_file[] {core_data_mgr.Dbs__get_at(0)}; // single file: return core; note that there are no Tid = Text
for (int i = 0; i < len; i++) {
Xow_db_file file = core_data_mgr.Dbs__get_at(i);
switch (file.Tid()) {
case Xow_db_file_.Tid__text:
case Xow_db_file_.Tid__text_solo:
text_files_list.Add(file);
break;
}
}
return (Xow_db_file[])text_files_list.To_ary_and_clear(Xow_db_file.class);
}
}
class Xob_dump_bmk_mgr {
private Bry_bfr save_bfr = Bry_bfr_.Reset(1024);
public Io_url Cfg_url() {return cfg_url;} public Xob_dump_bmk_mgr Cfg_url_(Io_url v) {cfg_url = v; return this;} private Io_url cfg_url;
public void Reset() {Io_mgr.Instance.DeleteFil(cfg_url);}
public void Load(Xoae_app app, Xob_dump_mgr_base dump_mgr) {
app.Gfs_mgr().Run_url_for(dump_mgr, cfg_url);
}
public void Save(int ns_id, int db_id, int pg_id) {
Save_itm(save_bfr, Xob_dump_mgr_base.Invk_ns_bgn_, ns_id);
Save_itm(save_bfr, Xob_dump_mgr_base.Invk_db_bgn_, db_id);
Save_itm(save_bfr, Xob_dump_mgr_base.Invk_pg_bgn_, pg_id);
Io_mgr.Instance.SaveFilBfr(cfg_url, save_bfr);
}
private void Save_itm(Bry_bfr save_bfr, String key, int val) {
String fmt = "{0}('{1}');\n";
String str = String_.Format(fmt, key, val);
save_bfr.Add_str_u8(str);
}
}
class Xob_rate_mgr {
private long time_bgn;
private int item_len;
private Bry_bfr save_bfr = Bry_bfr_.Reset(255);
public int Reset_interval() {return reset_interval;} public Xob_rate_mgr Reset_interval_(int v) {reset_interval = v; return this;} private int reset_interval = 10000;
public Io_url Log_file_url() {return log_file;} public Xob_rate_mgr Log_file_(Io_url v) {log_file = v; return this;} private Io_url log_file;
public void Init() {time_bgn = System_.Ticks();}
public void Increment() {
++item_len;
if (item_len % reset_interval == 0) {
long time_end = System_.Ticks();
Save(item_len, time_bgn, time_end);
time_bgn = time_end;
item_len = 0;
}
}
private void Save(int count, long bgn, long end) {
int dif = (int)(end - bgn) / 1000;
Decimal_adp rate = Decimal_adp_.divide_safe_(count, dif);
save_bfr
.Add_str_a7(rate.To_str("#,##0.000")).Add_byte_pipe()
.Add_int_variable(count).Add_byte_pipe()
.Add_int_variable(dif).Add_byte_nl()
;
Io_mgr.Instance.AppendFilByt(log_file, save_bfr.To_bry_and_clear());
}
public String Rate_as_str() {return Int_.To_str(Rate());}
public int Rate() {
int elapsed = System_.Ticks__elapsed_in_sec(time_bgn);
return Math_.Div_safe_as_int(item_len, elapsed);
}
}
class Xob_dump_bmk {
public int Ns_id() {return ns_id;} public Xob_dump_bmk Ns_id_(int v) {ns_id = v; return this;} private int ns_id;
public int Db_id() {return db_id;} public Xob_dump_bmk Db_id_(int v) {db_id = v; return this;} private int db_id;
public int Pg_id() {return pg_id;} public Xob_dump_bmk Pg_id_(int v) {pg_id = v; return this;} private int pg_id;
}

View File

@ -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,41 +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.xowa.bldrs.wms.revs; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.wms.*;
import gplx.langs.jsons.*; import gplx.core.net.*;
class Xowm_rev_wkr__meta__wm implements Xowm_rev_wkr__meta {
private final Json_parser json_parser = new Json_parser();
private final Xowm_json_parser__page json_page_parser = new Xowm_json_parser__page();
private final Bry_bfr tmp_bfr = Bry_bfr_.New_w_size(255);
private final Wmapi_itm__pge tmp_pge = new Wmapi_itm__pge();
public Xowm_rev_wkr__meta__wm() {
tmp_pge.Rvn_ary_(new Wmapi_itm__rvn());
}
public Gfo_inet_conn Inet_conn() {return inet_conn;} public void Inet_conn_(Gfo_inet_conn v) {this.inet_conn = v;} private Gfo_inet_conn inet_conn;
public void Fetch_meta(String domain_str, Ordered_hash hash, int bgn, int end) {
for (int i = bgn; i < end; ++i) {
Wmapi_itm__pge itm = (Wmapi_itm__pge)hash.Get_at(i);
if (i != bgn) tmp_bfr.Add_byte(Byte_ascii.Pipe);
tmp_bfr.Add(itm.Page_ttl());
}
byte[] json = inet_conn.Download_as_bytes_or_null(Xowm_api_mgr.Bld_api_url(domain_str, "action=query&prop=revisions&rvprop=size|ids|timestamp|user|comment&format=json&rawcontinue=titles=" + tmp_bfr.To_str_and_clear()));
Parse_doc(hash, json);
}
private void Parse_doc(Ordered_hash hash, byte[] json) {
Json_doc jdoc = json_parser.Parse(json);
Json_nde pages_nde = Json_nde.cast(jdoc.Get_grp_many(Jpath__query_pages));
int len = pages_nde.Len();
for (int i = 0; i < len; ++i) {
Parse_page(hash, pages_nde.Get_at_as_kv(i).Val_as_nde());
}
}
private void Parse_page(Ordered_hash hash, Json_nde page_nde) {
json_page_parser.Parse("update", tmp_pge, page_nde); // have to pass tmp_pge, b/c don't know which itm is in hash
Wmapi_itm__pge hash_itm = (Wmapi_itm__pge)hash.Get_by(tmp_pge.Page_ttl()); if (hash_itm == null) return;
hash_itm.Init_id(tmp_pge.Page_id());
Wmapi_itm__rvn tmp_rvn = tmp_pge.Rvn_itm_last();
hash_itm.Rvn_ary_(new Wmapi_itm__rvn());
hash_itm.Rvn_itm_last().Init(tmp_rvn.Rvn_id(), tmp_rvn.Rvn_len(), tmp_rvn.Rvn_time(), tmp_rvn.Rvn_user(), tmp_rvn.Rvn_note());
}
private static final byte[][] Jpath__query_pages = Bry_.Ary("query", "pages");
}
package gplx.xowa.bldrs.wms.revs;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Byte_ascii;
import gplx.Ordered_hash;
import gplx.core.net.Gfo_inet_conn;
import gplx.langs.jsons.Json_doc;
import gplx.langs.jsons.Json_nde;
import gplx.langs.jsons.Json_parser;
import gplx.xowa.bldrs.wms.Xowm_api_mgr;
class Xowm_rev_wkr__meta__wm implements Xowm_rev_wkr__meta {
private final Json_parser json_parser = new Json_parser();
private final Xowm_json_parser__page json_page_parser = new Xowm_json_parser__page();
private final Bry_bfr tmp_bfr = Bry_bfr_.New_w_size(255);
private final Wmapi_itm__pge tmp_pge = new Wmapi_itm__pge();
public Xowm_rev_wkr__meta__wm() {
tmp_pge.Rvn_ary_(new Wmapi_itm__rvn());
}
public Gfo_inet_conn Inet_conn() {return inet_conn;} public void Inet_conn_(Gfo_inet_conn v) {this.inet_conn = v;} private Gfo_inet_conn inet_conn;
public void Fetch_meta(String domain_str, Ordered_hash hash, int bgn, int end) {
for (int i = bgn; i < end; ++i) {
Wmapi_itm__pge itm = (Wmapi_itm__pge)hash.Get_at(i);
if (i != bgn) tmp_bfr.Add_byte(Byte_ascii.Pipe);
tmp_bfr.Add(itm.Page_ttl());
}
byte[] json = inet_conn.Download_as_bytes_or_null(Xowm_api_mgr.Bld_api_url(domain_str, "action=query&prop=revisions&rvprop=size|ids|timestamp|user|comment&format=json&rawcontinue=titles=" + tmp_bfr.To_str_and_clear()));
Parse_doc(hash, json);
}
private void Parse_doc(Ordered_hash hash, byte[] json) {
Json_doc jdoc = json_parser.Parse(json);
Json_nde pages_nde = Json_nde.Cast(jdoc.Get_grp_many(Jpath__query_pages));
int len = pages_nde.Len();
for (int i = 0; i < len; ++i) {
Parse_page(hash, pages_nde.Get_at_as_kv(i).Val_as_nde());
}
}
private void Parse_page(Ordered_hash hash, Json_nde page_nde) {
json_page_parser.Parse("update", tmp_pge, page_nde); // have to pass tmp_pge, b/c don't know which itm is in hash
Wmapi_itm__pge hash_itm = (Wmapi_itm__pge)hash.Get_by(tmp_pge.Page_ttl()); if (hash_itm == null) return;
hash_itm.Init_id(tmp_pge.Page_id());
Wmapi_itm__rvn tmp_rvn = tmp_pge.Rvn_itm_last();
hash_itm.Rvn_ary_(new Wmapi_itm__rvn());
hash_itm.Rvn_itm_last().Init(tmp_rvn.Rvn_id(), tmp_rvn.Rvn_len(), tmp_rvn.Rvn_time(), tmp_rvn.Rvn_user(), tmp_rvn.Rvn_note());
}
private static final byte[][] Jpath__query_pages = Bry_.Ary("query", "pages");
}

View File

@ -1,27 +1,37 @@
/*
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.files; import gplx.*; import gplx.xowa.*;
import gplx.core.primitives.*;
public class Xof_ext_ {
/*
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.xowa.files;
import gplx.Bry_;
import gplx.Bry_find_;
import gplx.Byte_ascii;
import gplx.Err_;
import gplx.Hash_adp;
import gplx.Hash_adp_bry;
import gplx.core.primitives.Int_obj_val;
public class Xof_ext_ {
public static final int Id_unknown = 0 // SERIALIZED; ids are saved to fsdb;
, Id_png = 1, Id_jpg = 2, Id_jpeg = 3, Id_gif = 4, Id_tif = 5, Id_tiff = 6
, Id_svg = 7, Id_djvu = 8, Id_pdf = 9
, Id_mid = 10, Id_ogg = 11, Id_oga = 12, Id_ogv = 13, Id_webm = 14
, Id_flac = 15, Id_bmp = 16, Id_xcf = 17, Id_wav = 18, Id_opus = 19;
public static final int Id__max = 20;
, Id_flac = 15, Id_bmp = 16, Id_xcf = 17, Id_wav = 18, Id_opus = 19
, Id_stl = 20, Id_webp = 21;
;
public static final int Id__max = 22;
public static final byte[]
Bry_png = Bry_.new_a7("png"), Bry_jpg = Bry_.new_a7("jpg"), Bry_jpeg = Bry_.new_a7("jpeg")
, Bry_gif = Bry_.new_a7("gif"), Bry_tif = Bry_.new_a7("tif"), Bry_tiff = Bry_.new_a7("tiff")
@ -29,6 +39,7 @@ public class Xof_ext_ {
, Bry_mid = Bry_.new_a7("mid"), Bry_ogg = Bry_.new_a7("ogg"), Bry_oga = Bry_.new_a7("oga")
, Bry_ogv = Bry_.new_a7("ogv"), Bry_webm = Bry_.new_a7("webm"), Bry_flac = Bry_.new_a7("flac")
, Bry_bmp = Bry_.new_a7("bmp"), Bry_xcf = Bry_.new_a7("xcf"), Bry_wav = Bry_.new_a7("wav"), Bry_opus = Bry_.new_a7("opus")
, Bry_stl = Bry_.new_a7("stl"), Bry_webp = Bry_.new_a7("webp")
;
public static final byte[][] Bry__ary = new byte[][]
{ Bry_.Empty, Bry_png, Bry_jpg, Bry_jpeg
@ -37,6 +48,7 @@ public class Xof_ext_ {
, Bry_mid, Bry_ogg, Bry_oga
, Bry_ogv, Bry_webm, Bry_flac
, Bry_bmp, Bry_xcf, Bry_wav, Bry_opus
, Bry_stl, Bry_webp
};
public static final byte[][] Mime_type__ary = new byte[][]
{ Bry_.new_a7("application/octet-stream"), Bry_.new_a7("image/png"), Bry_.new_a7("image/jpg"), Bry_.new_a7("image/jpeg")
@ -44,7 +56,10 @@ public class Xof_ext_ {
, Bry_.new_a7("image/svg+xml"), Bry_.new_a7("image/x.djvu"), Bry_.new_a7("application/pdf")
, Bry_.new_a7("application/x-midi"), Bry_.new_a7("video/ogg"), Bry_.new_a7("audio/oga")
, Bry_.new_a7("video/ogg"), Bry_.new_a7("video/webm"), Bry_.new_a7("audio/flac")
, Bry_.new_a7("image/bmp"), Bry_.new_a7("image/xcf"), Bry_.new_a7("audio/x-wav"), Bry_.new_a7("audio/opus")
, Bry_.new_a7("image/bmp")
, Bry_.new_a7("image/x-xcf") // changed from "/xcf"; DATE:2020-04-21
, Bry_.new_a7("audio/x-wav"), Bry_.new_a7("audio/opus")
, Bry_.new_a7("model/stl"), Bry_.new_a7("video/webp")
};
private static final Hash_adp id_hash = id_hash_new_();
private static Hash_adp id_hash_new_() {
@ -55,7 +70,7 @@ public class Xof_ext_ {
id_hash_new_(rv, Bry_mid, Id_mid); id_hash_new_(rv, Bry_ogg, Id_ogg); id_hash_new_(rv, Bry_oga, Id_oga);
id_hash_new_(rv, Bry_ogv, Id_ogv); id_hash_new_(rv, Bry_webm, Id_webm); id_hash_new_(rv, Bry_flac, Id_flac);
id_hash_new_(rv, Bry_bmp, Id_bmp); id_hash_new_(rv, Bry_xcf, Id_xcf); id_hash_new_(rv, Bry_wav, Id_wav);
id_hash_new_(rv, Bry_opus, Id_opus);
id_hash_new_(rv, Bry_opus, Id_opus); id_hash_new_(rv, Bry_stl, Id_stl); id_hash_new_(rv, Bry_webp, Id_webp);
return rv;
}
private static void id_hash_new_(Hash_adp hash, byte[] key, int val) {hash.Add(key, new Int_obj_val(val));}
@ -67,7 +82,7 @@ public class Xof_ext_ {
.Add_bry_bry(Bry_mid).Add_bry_bry(Bry_ogg).Add_bry_bry(Bry_oga)
.Add_bry_bry(Bry_ogv).Add_bry_bry(Bry_webm).Add_bry_bry(Bry_flac)
.Add_bry_bry(Bry_bmp).Add_bry_bry(Bry_xcf).Add_bry_bry(Bry_wav)
.Add_bry_bry(Bry_opus)
.Add_bry_bry(Bry_opus).Add_bry_bry(Bry_stl).Add_bry_bry(Bry_webp)
;
private static final Xof_ext[] Ary = new Xof_ext[Id__max];
@ -111,9 +126,14 @@ public class Xof_ext_ {
}
public static boolean Orig_file_is_img(int v) { // identifies if orig_file can be used for <img src>; EX: png is valid, but svg, ogv, pdf is not
switch (v) {
case Id_png: case Id_jpg: case Id_jpeg:
case Id_gif: case Id_tif: case Id_tiff: return true;
default: return false;
case Id_png:
case Id_jpg: case Id_jpeg:
case Id_gif:
return true;
// 2020-08-25|ISSUE#:788|tif files cannot be rendered natively by Firefox / Chrome
case Id_tif: case Id_tiff:
default:
return false;
}
}
public static boolean Id_supports_page(int v) { // identifies if tid supports page in lnki; EX: [[File:A.pdf|page=1]]; REF: https://en.wikipedia.org/wiki/Wikipedia:Picture_tutorial; DATE:2014-01-18
@ -134,6 +154,7 @@ public class Xof_ext_ {
case Xof_ext_.Id_gif: case Xof_ext_.Id_tif: case Xof_ext_.Id_tiff:
case Xof_ext_.Id_svg:
case Xof_ext_.Id_bmp: case Xof_ext_.Id_xcf:
case Xof_ext_.Id_stl: case Xof_ext_.Id_webp:
return true;
default:
return false;
@ -144,6 +165,7 @@ public class Xof_ext_ {
case Xof_ext_.Id_png: case Xof_ext_.Id_jpg: case Xof_ext_.Id_jpeg:
case Xof_ext_.Id_gif: case Xof_ext_.Id_tif: case Xof_ext_.Id_tiff:
case Xof_ext_.Id_bmp: case Xof_ext_.Id_xcf:
case Xof_ext_.Id_stl: case Xof_ext_.Id_webp:
return true;
default:
return false;
@ -155,6 +177,7 @@ public class Xof_ext_ {
case Xof_ext_.Id_gif: case Xof_ext_.Id_tif: case Xof_ext_.Id_tiff:
case Xof_ext_.Id_svg: case Xof_ext_.Id_djvu: case Xof_ext_.Id_pdf:
case Xof_ext_.Id_bmp: case Xof_ext_.Id_xcf:
case Xof_ext_.Id_stl: case Xof_ext_.Id_webp:
return true;
default:
return false;
@ -196,10 +219,23 @@ public class Xof_ext_ {
}
public static int Id_view(int id) {
switch (id) {
case Xof_ext_.Id_svg: case Xof_ext_.Id_bmp: case Xof_ext_.Id_xcf: return Xof_ext_.Id_png;
case Xof_ext_.Id_tif: case Xof_ext_.Id_tiff: case Xof_ext_.Id_djvu: case Xof_ext_.Id_pdf:
case Xof_ext_.Id_ogg: case Xof_ext_.Id_ogv: case Xof_ext_.Id_webm: return Xof_ext_.Id_jpg;
default: return id;
// example image is rendered as .png; see wiki articles
case Xof_ext_.Id_svg:
case Xof_ext_.Id_bmp:
case Xof_ext_.Id_xcf:
case Xof_ext_.Id_stl: // https://en.wikipedia.org/wiki/STL_(file_format)
case Xof_ext_.Id_webp:// https://en.wikipedia.org/wiki/WebP
return Xof_ext_.Id_png;
case Xof_ext_.Id_tif:
case Xof_ext_.Id_tiff:
case Xof_ext_.Id_djvu:
case Xof_ext_.Id_pdf:
case Xof_ext_.Id_ogg:
case Xof_ext_.Id_ogv:
case Xof_ext_.Id_webm:
return Xof_ext_.Id_jpg;
default:
return id;
}
}
}

Some files were not shown because too many files have changed in this diff Show More