1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00
This commit is contained in:
gnosygnu
2015-07-12 21:10:02 -04:00
commit 794b5a232f
3099 changed files with 238212 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class App_cmd_arg {
App_cmd_arg(byte tid, byte val_tid, String key, boolean reqd) {this.tid = tid; this.val_tid = val_tid; this.key = key; this.reqd = reqd;}
public byte Tid() {return tid;} private byte tid;
public byte Val_tid() {return val_tid;} public App_cmd_arg Val_tid_(byte v) {val_tid = v; return this;} private byte val_tid;
public String Val_tid_str() {
switch (val_tid) {
case Val_tid_string: return "string";
case Val_tid_yn: return "yes_no";
case Val_tid_url: return "path";
default: return "unknown";
}
}
public String Key() {return key;} private String key;
public boolean Reqd() {return reqd;} private boolean reqd;
public String Reqd_str() {return reqd ? "required" : "optional";}
public boolean Dirty() {return dirty;} public App_cmd_arg Dirty_(boolean v) {this.dirty = v; return this;} private boolean dirty;
public String Note() {return note;} public App_cmd_arg Note_(String v) {note = v; return this;} private String note;
public String Example() {return example;}
public App_cmd_arg Example_(String v) {example = v; return this;} private String example;
public App_cmd_arg Example_url_(String v) {
Example_(v);
val_tid = Val_tid_url;
return this;
}
public App_cmd_arg Example_list_str_(String v) {
example = String_.ConcatWith_any(" ", v);
val_tid = Val_tid_list_string;
return this;
}
public Object Val() {return val;} public App_cmd_arg Val_(Object v) {this.val = v; return this;} Object val;
public Object Dflt() {return dflt;} public App_cmd_arg Dflt_(Object v) {dflt = v; return this;} Object dflt;
public boolean Val_as_bool() {return Bool_.cast_(val);}
public String Val_as_str_or(String or) {return val == null ? or : (String)val;}
public String Val_as_str() {return (String)val;}
public int Val_as_int_or(int or) {return val == null ? or : Int_.parse_or_((String)val, or);}
public Io_url Val_as_url_rel_dir_or(Io_url owner_dir, Io_url or) {return Val_as_url_rel_url_or(owner_dir, or, true);}
public Io_url Val_as_url_rel_fil_or(Io_url owner_dir, Io_url or) {return Val_as_url_rel_url_or(owner_dir, or, false);}
public Io_url Val_as_url_rel_url_or(Io_url owner_dir, Io_url or, boolean dir) {return Val_as_url_rel_url_or(Val_as_str(), owner_dir, or, dir);}
public boolean Parse(App_cmd_mgr mgr, String[] s_ary) {
dirty = true;
String s = s_ary.length == 0 ? "" : s_ary[0];
switch (val_tid) {
case Val_tid_string:
val = s;
break;
case Val_tid_url: // NOTE: do not parse urls as it can either be absolute (C:\dir\fil.txt) or relative (fil.txt). relative cannot be parsed without knowing owner dir
val = s;
break;
case Val_tid_yn:
int v_int = Yn.parse_as_int(s);
if (v_int == Bool_.__int) {return mgr.Errs_add(Err_parse_yn, "value must be either y or n: ~{0}", s);}
val = v_int == Bool_.Y_int;
break;
}
return true;
} public static final String Err_parse_yn = "parse_yn";
public App_cmd_arg Clone() {
App_cmd_arg rv = new App_cmd_arg(tid, val_tid, key, reqd);
rv.val = val;
rv.dflt = dflt;
rv.note = note;
rv.example = example;
return rv;
}
public static App_cmd_arg req_(String key) {return new App_cmd_arg(Tid_general, Val_tid_string, key, true);}
public static App_cmd_arg opt_(String key) {return new App_cmd_arg(Tid_general, Val_tid_string, key, false);}
public static App_cmd_arg new_(String key, boolean reqd) {return new App_cmd_arg(Tid_general, Val_tid_string, key, reqd);}
public static App_cmd_arg sys_help_() {return sys_help_("help");}
public static App_cmd_arg sys_help_(String key) {return new App_cmd_arg(Tid_help, Val_tid_string, key, false);}
public static App_cmd_arg sys_header_(String key) {return new App_cmd_arg(Tid_header, Val_tid_yn, key, false);}
public static App_cmd_arg sys_args_(String key) {return new App_cmd_arg(Tid_args, Val_tid_yn, key, false);}
public static final byte Tid_general = 0, Tid_help = 1, Tid_header = 2, Tid_args = 3;
public static final byte Val_tid_string = 0, Val_tid_yn = 1, Val_tid_url = 2, Val_tid_list_string = 3;
public static Io_url Val_as_url_rel_url_or(String val_str, Io_url owner_dir, Io_url or, boolean dir) {
if (val_str == null) return or;
byte val_has_dir = Op_sys.Tid_nil; // if val_str is dir, use it literally (only checking for closing dir_spr); if it's just a name, assume a simple relative path
if (String_.Has(val_str, Op_sys.Lnx.Fsys_dir_spr_str()))
val_has_dir = Op_sys.Tid_lnx;
else if (String_.Has(val_str, Op_sys.Wnt.Fsys_dir_spr_str()))
val_has_dir = Op_sys.Tid_wnt;
if (val_has_dir != Op_sys.Tid_nil) {
if (dir) { // NOTE: need to do extra logic to guarantee trailing "/"; JAVA:7 apparently strips "/dir/" to "/dir" when passed in as argument; DATE:2013-03-20
String val_dir_spr = val_has_dir == Op_sys.Tid_lnx ? Op_sys.Lnx.Fsys_dir_spr_str() : Op_sys.Wnt.Fsys_dir_spr_str();
if (!String_.Has_at_end(val_str, val_dir_spr))
val_str += val_dir_spr;
return Io_url_.new_dir_(val_str);
}
else
return Io_url_.new_fil_(val_str);
}
else
return dir ? owner_dir.GenSubDir(val_str) : owner_dir.GenSubFil(val_str);
}
}

View File

@@ -0,0 +1,162 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import gplx.core.strings.*;
public class App_cmd_mgr {
private Ordered_hash expd_args = Ordered_hash_.new_(), actl_args = Ordered_hash_.new_();
private List_adp tmp_vals = List_adp_.new_(); private String[] orig_ary;
public App_cmd_mgr Msg_root_(Gfo_msg_root v) {msg_root = v; return this;} private Gfo_msg_root msg_root = Gfo_msg_root._;
public String Arg_prefix() {return arg_prefix;} public App_cmd_mgr Arg_prefix_(String v) {arg_prefix = v; prefix_len = String_.Len(v); return this;} private String arg_prefix = "--"; int prefix_len = 2;
public void Clear() {expd_args.Clear(); actl_args.Clear(); errs.Clear(); key_help = key_header = null;}
public int Actl_len() {return actl_args.Count();}
public App_cmd_arg[] Actl_ary() {return (App_cmd_arg[])actl_args.To_ary(App_cmd_arg.class);}
public App_cmd_mgr Expd_add_many(App_cmd_arg... ary) {for (App_cmd_arg o : ary) Expd_add(o); return this;}
public App_cmd_mgr Expd_add(App_cmd_arg prm) {
expd_args.Add(prm.Key(), prm);
switch (prm.Tid()) {
case App_cmd_arg.Tid_help: key_help = prm.Key(); break;
case App_cmd_arg.Tid_header: key_header = prm.Key(); break;
case App_cmd_arg.Tid_args: key_args = prm.Key(); break;
}
return this;
} String key_help, key_header, key_args;
public boolean Args_process(String[] ary) {Args_parse(ary); return errs.Count() == 0;}
private void Args_parse(String[] ary) {
this.orig_ary = ary;
App_cmd_arg arg = null;
int ary_len = ary.length;
actl_args = Expd_copy();
errs.Clear(); tmp_vals.Clear();
for (int i = 0; i < ary_len; i++) {
String itm = ary[i];
if (String_.Has_at_bgn(itm, arg_prefix)) { // key
if (arg != null) {
String[] tmp_ary = tmp_vals.To_str_ary();
if (!arg.Parse(this, tmp_ary)) {continue;}
tmp_vals.Clear();
}
String key = String_.Mid(itm, prefix_len);
Object o = actl_args.Get_by(key);
if (o == null) {Errs_add(Err_argument_is_unknown, "unknown argument: '~{0}'", key); continue;}
arg = (App_cmd_arg)o;
if (arg.Dirty()) {Errs_add(Err_argument_is_duplicate, "duplicate argument: '~{0}'", key); continue;}
arg.Dirty_(true);
}
else {
if (arg == null) {Errs_add(Err_argument_is_invalid_key, "argument key must be prefixed with '~{0}'; EX: '~{0}~{1}'", arg_prefix, itm); continue;} // should only happen if 1st itm is not "--%"
// if (arg.Val() != null) return Errs_add("argument_is_already_valued", "argument can only take one value: '{0}'", itm);
tmp_vals.Add(itm);
}
}
if (arg != null) {
String[] tmp_ary = tmp_vals.To_str_ary();
arg.Parse(this, tmp_ary);
tmp_vals.Clear();
}
int len = actl_args.Count();
for (int i = 0; i < len; i++) {
arg = (App_cmd_arg)actl_args.Get_at(i);
if (arg.Reqd() && !arg.Dirty()) {Errs_add(Err_argument_is_required, "argument is required: '~{0}'", arg.Key()); continue;}
if (!arg.Dirty() && arg.Dflt() != null) arg.Val_(arg.Dflt());
}
} public static final String Err_argument_is_duplicate = "argument_is_duplicate", Err_argument_is_required = "argument_is_required", Err_argument_is_unknown = "argument_is_unknown", Err_argument_is_invalid_key = "argument_is_invalid_key";
public String Fmt_hdr() {return fmt_hdr;} public App_cmd_mgr Fmt_hdr_(String v) {fmt_hdr = v; return this;} private String fmt_hdr = "";
public App_cmd_arg Args_get(String key) {return (App_cmd_arg)actl_args.Get_by(key);}
public boolean Args_has_help() {
App_cmd_arg arg = (App_cmd_arg)actl_args.Get_by(key_help);
return arg != null && arg.Dirty();
}
public App_cmd_mgr Print_header(Gfo_usr_dlg usr_dlg) {
App_cmd_arg arg_hdr = (App_cmd_arg)actl_args.Get_by(key_header);
if (arg_hdr == null) return this; // no key_header specified; assume header shouldn't be printed
if (!arg_hdr.Val_as_bool()) return this; // key_header specified as false; return;
usr_dlg.Note_gui_none(GRP_KEY, "print.header", fmt_hdr);
return this;
}
public void Print_args(Gfo_usr_dlg usr_dlg) {
sb.Add_char_crlf();
sb.Add_str_w_crlf("arguments:");
int len = orig_ary.length;
if (len == 0) {
sb.Add_fmt_line(" **** NONE ****");
sb.Add_fmt_line(" use --help to show help");
}
else {
for (int i = 0; i < len; i++)
sb.Add_fmt_line(" [{0}] = '{1}'", i, orig_ary[i]);
}
usr_dlg.Note_none(GRP_KEY, "print.args", sb.Xto_str_and_clear());
} String_bldr sb = String_bldr_.new_();
public void Print_fail(Gfo_usr_dlg usr_dlg) {
sb.Add("** error: ").Add_char_crlf();
int len = errs.Count();
for (int i = 0; i < len; i++) {
Gfo_msg_data data = (Gfo_msg_data)errs.Get_at(i);
sb.Add_fmt_line(" " + data.Gen_str_ary());
}
sb.Add_char_crlf();
sb.Add_str_w_crlf(String_.Repeat("-", 80));
usr_dlg.Note_none(GRP_KEY, "print.fail", sb.Xto_str_and_clear());
}
public void Print_help(Gfo_usr_dlg usr_dlg, String app_name) {
sb.Add_str_w_crlf("example:");
sb.Add_fmt(" java -jar {0}.jar", app_name);
int key_max = 0, tid_max = 0;
int len = expd_args.Count();
for (int i = 0; i < len; i++) {
App_cmd_arg arg = (App_cmd_arg)expd_args.Get_at(i);
if (arg.Tid() != App_cmd_arg.Tid_general) continue; // skip header, help
sb.Add(" ").Add(arg_prefix).Add(arg.Key()).Add(" ").Add(arg.Example());
int key_len = String_.Len(arg.Key()); if (key_len > key_max) key_max = key_len;
int tid_len = String_.Len(String_.Format("[{0}:{1}]", arg.Reqd_str(), arg.Val_tid_str())); if (tid_len > tid_max) tid_max = tid_len;
} sb.Add_char_crlf();
sb.Add_char_crlf();
sb.Add_str_w_crlf("detail:");
for (int i = 0; i < len; i++) {
App_cmd_arg arg = (App_cmd_arg)expd_args.Get_at(i);
// if (arg.Tid() != App_cmd_arg.Tid_general) continue; // skip header, help
sb.Add(" ").Add(arg_prefix).Add(String_.PadEnd(arg.Key(), key_max + 1, " ")).Add(String_.PadEnd(String_.Format("[{0}:{1}]", arg.Reqd_str(), arg.Val_tid_str()), tid_max, " "));
if (arg.Dflt() != null)
sb.Add_fmt(" default={0}", arg.Dflt());
sb.Add_char_crlf();
if (arg.Note() != null)
sb.Add(" ").Add(arg.Note()).Add_char_crlf();
// for (int j = 0; j < arg.Itms().Count(); j++) {
// App_arg_info expdInf = (App_arg_info)arg.Itms().Get_at(j);
// sb.Add(" ").Add(String_.PadEnd(expdInf.Key(), key_max + 1, " ")).Add_str_w_crlf(expdInf.Descrip());
// }
}
usr_dlg.Note_gui_none(GRP_KEY, "print.info", sb.Xto_str_and_clear());
}
private Ordered_hash Expd_copy() {
Ordered_hash rv = Ordered_hash_.new_();
int expd_len = expd_args.Count();
for (int i = 0 ; i < expd_len; i++) {
App_cmd_arg arg = (App_cmd_arg)expd_args.Get_at(i);
rv.Add(arg.Key(), arg.Clone());
}
return rv;
}
public boolean Errs_add(String key, String fmt, Object... vals) {
errs.Add(msg_root.Data_new_many(Gfo_msg_itm_.Cmd_warn, GRP_KEY, key, fmt, vals));
return false;
}
public int Errs_len() {return errs.Count();} private List_adp errs = List_adp_.new_();
public Gfo_msg_data Errs_get(int i) {return (Gfo_msg_data)errs.Get_at(i);}
private static final String GRP_KEY = "gplx.app.app_cmd_mgr";
}

View File

@@ -0,0 +1,142 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import org.junit.*;
public class App_cmd_mgr_tst {
App_cmd_mgr_fxt fxt = new App_cmd_mgr_fxt();
@Before public void init() {fxt.Clear();}
@Test public void Basic() {
fxt .Expd_(fxt.arg_("a"), fxt.arg_("b"))
.Args_process("--a", "0", "--b", "1")
.Tst_errs_none()
.Tst_actl(fxt.chkr_("a", "0"), fxt.chkr_("b", "1"));
;
}
@Test public void Dflt() {
fxt .Expd_(fxt.arg_("a").Val_tid_(App_cmd_arg.Val_tid_yn).Dflt_(true));
fxt .Args_process("--a", "n").Tst_actl(fxt.chkr_("a", false)); // if val, use it
fxt .Args_process().Tst_actl(fxt.chkr_("a", true)); // if no val, use default
}
@Test public void Header_y() {
fxt.Expd_(App_cmd_arg.sys_header_("print_license")).Args_process("--print_license", "y");
fxt.Mgr().Fmt_hdr_("test_hdr").Print_header(fxt.Usr_dlg());
fxt.tst_write("test_hdr");
fxt.Clear();
}
@Test public void Header_n() {
fxt.Expd_(App_cmd_arg.sys_header_("print_license")).Args_process("--print_license", "n");
fxt.Mgr().Fmt_hdr_("test_hdr").Print_header(fxt.Usr_dlg());
fxt.tst_write();
}
// @Test public void Help_y() {
// fxt.Expd_(App_cmd_arg.sys_header_("help")).Args_process("--help");
//// fxt.Mgr().Fmt_help_grp("bgn ~{args} end").Fmt_help_itm_("~{0} ~{1}").Print_header(fxt.Status_mgr());
//// fxt.Tst_write("test_hdr");
// fxt.Clear();
// }
@Test public void Err_parse_yn() {
fxt .Expd_(fxt.arg_("a").Val_tid_(App_cmd_arg.Val_tid_yn))
.Args_process("--a", "x")
.Tst_errs(App_cmd_arg.Err_parse_yn);
;
}
@Test public void Err_reqd() {
fxt .Expd_(fxt.arg_("a", true), fxt.arg_("b", false))
.Args_process("--b", "1")
.Tst_errs(App_cmd_mgr.Err_argument_is_required);
;
}
@Test public void Err_dupe() {
fxt .Expd_(fxt.arg_("a"))
.Args_process("--a", "0", "--a", "0")
.Tst_errs(App_cmd_mgr.Err_argument_is_duplicate);
;
}
@Test public void Err_unknown() {
fxt .Expd_(fxt.arg_("a"))
.Args_process("--b")
.Tst_errs(App_cmd_mgr.Err_argument_is_unknown);
;
}
@Test public void Err_key_invalid() {
fxt .Expd_(fxt.arg_("a"))
.Args_process("a")
.Tst_errs(App_cmd_mgr.Err_argument_is_invalid_key);
;
}
@Test public void Val_as_url_rel_dir_or() { // PURPOSE: "/xowa" -> "/xowa/"
String root_dir = Op_sys.Cur().Tid_is_wnt() ? "C:\\" : "/", dir_spr = Op_sys.Cur().Fsys_dir_spr_str();
Tst_val_as_url_rel_dir_or(root_dir, dir_spr, root_dir + "sub" , root_dir + "sub" + dir_spr); // /sub -> /sub/
Tst_val_as_url_rel_dir_or(root_dir, dir_spr, root_dir + "sub" + dir_spr , root_dir + "sub" + dir_spr); // /sub/ -> /sub/
Tst_val_as_url_rel_dir_or(root_dir, dir_spr, "sub" , root_dir + "dir" + dir_spr + "sub" + dir_spr); // sub -> /dir/sub/
}
private void Tst_val_as_url_rel_dir_or(String root_dir, String dir_spr, String val, String expd) {
Io_url actl = fxt.arg_("key").Val_(val).Val_as_url_rel_dir_or(Io_url_.new_dir_(root_dir).GenSubDir("dir"), null);
Tfds.Eq(expd, actl.Raw());
}
}
class App_cmd_mgr_fxt {
public Gfo_usr_dlg Usr_dlg() {return usr_dlg;} Gfo_usr_dlg usr_dlg;
public App_cmd_mgr Mgr() {return mgr;} App_cmd_mgr mgr = new App_cmd_mgr(); Tst_mgr tst_mgr = new Tst_mgr();
public App_cmd_mgr_fxt Clear() {
if (usr_dlg == null) {
usr_dlg = Gfo_usr_dlg_.Test();
}
mgr.Clear();
usr_dlg.Gui_wkr().Clear();
return this;
}
public App_cmd_arg arg_(String key) {return arg_(key, false);}
public App_cmd_arg arg_(String key, boolean reqd) {return App_cmd_arg.new_(key, reqd);}
public App_cmd_arg_chkr chkr_(String key, Object val) {return new App_cmd_arg_chkr(key, val);}
public App_cmd_mgr_fxt Expd_(App_cmd_arg... v) {mgr.Expd_add_many(v); return this;}
public App_cmd_mgr_fxt Args_process(String... v) {mgr.Args_process(v); return this;}
public App_cmd_mgr_fxt Tst_actl_len(int v) {Tfds.Eq(v, mgr.Actl_len()); return this;}
public App_cmd_mgr_fxt Tst_actl(App_cmd_arg_chkr... expd) {
App_cmd_arg[] actl = mgr.Actl_ary();
tst_mgr.Tst_ary("", expd, actl);
return this;
}
public App_cmd_mgr_fxt Tst_errs_none() {return Tst_errs(String_.Ary_empty);}
public App_cmd_mgr_fxt Tst_errs(String... expd) {
int len = mgr.Errs_len();
String[] actl = new String[len];
for (int i = 0; i < len; i++) {
Gfo_msg_data data = mgr.Errs_get(i);
actl[i] = data.Item().Key_str();
}
Tfds.Eq_ary_str(expd, actl);
return this;
}
public App_cmd_mgr_fxt tst_write(String... expd) {
String[] actl = ((Gfo_usr_dlg__gui_test)usr_dlg.Gui_wkr()).Xto_str_ary();
Tfds.Eq_ary_str(expd, actl);
return this;
}
}
class App_cmd_arg_chkr implements Tst_chkr {
public App_cmd_arg_chkr(String key, Object val) {this.key = key; this.val = val;} private String key; Object val;
public Class<?> TypeOf() {return App_cmd_arg.class;}
public int Chk(Tst_mgr mgr, String path, Object actl_obj) {
App_cmd_arg actl = (App_cmd_arg)actl_obj;
int err = 0;
err += mgr.Tst_val(false, path, "key", key, actl.Key());
err += mgr.Tst_val(false, path, "val", val, actl.Val());
return err;
}
}

View File

@@ -0,0 +1,35 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import gplx.core.primitives.*;
public class Bry_cache {
public byte[] Get_or_new(String v) {return Get_or_new(Bry_.new_u8(v));}
public byte[] Get_or_new(byte[] v) {
if (v.length == 0) return Bry_.Empty;
Object rv = hash.Get_by(hash_ref.Val_(v));
if (rv == null) {
Bry_obj_ref bry = Bry_obj_ref.new_(v);
hash.Add_as_key_and_val(bry);
return v;
}
else
return ((Bry_obj_ref)rv).Val();
}
Hash_adp hash = Hash_adp_.new_(); Bry_obj_ref hash_ref = Bry_obj_ref.null_();
public static final Bry_cache _ = new Bry_cache(); Bry_cache() {}
}

View File

@@ -0,0 +1,34 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class ByteAryAry_chkr implements Tst_chkr {
public Class<?> TypeOf() {return byte[][].class;}
public ByteAryAry_chkr Val_(byte[][] v) {ary = v; return this;} byte[][] ary;
public int Chk(Tst_mgr mgr, String path, Object actl_obj) {
byte[][] actl = (byte[][])actl_obj;
int actl_len = actl.length;
int expd_len = ary.length;
int err = 0;
err += mgr.Tst_val(true, path, "len", ary.length, actl_len);
for (int i = 0; i < expd_len; i++) {
byte[] actl_itm = i >= actl_len ? null : actl[i];
err += mgr.Tst_val(false, path, "ary:" + Int_.Xto_str(i), String_.new_u8(ary[i]), String_.new_u8(actl_itm));
}
return err;
}
}

View File

@@ -0,0 +1,66 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import org.junit.*;
public class GfoCacheMgr_tst {
@Before public void init() {fxt = new GfoCacheMgr_fxt();} GfoCacheMgr_fxt fxt;
@Test public void teardown() {Env_.TickCount_Test = -1;}
@Test public void Basic() {fxt.run_Add("a").Expd_curSize_(1).Expd_itms_("a").tst();}
// @Test public void Reduce() {fxt.run_Add("a", "b", "c", "d", "e").Expd_curSize_(3).Expd_itms_("c", "d", "e").tst();}
// @Test public void Access() {fxt.run_Add("a", "b", "c", "d").run_Get("b", "a").run_Add("e").Expd_curSize_(3).Expd_itms_("b", "a", "e").tst();}
// @Test public void Sizes() {fxt.run_Add("abc", "d", "e").Expd_curSize_(2).Expd_itms_("d", "e").tst();}
}
class GfoCacheMgr_fxt {
Gfo_cache_mgr mgr = new Gfo_cache_mgr().Max_size_(4).Reduce_by_(2);
public GfoCacheMgr_fxt() {
Env_.TickCount_Test = 1;
}
public GfoCacheMgr_fxt run_Add(String... ary) {
for (int i = 0; i < ary.length; i++) {
String s = ary[i];
mgr.Add(Bry_.new_u8(s), new GfoCacheItm_mock(s), String_.Len(s));
Env_.TickCount_Test++;
}
return this;
}
public GfoCacheMgr_fxt run_Get(String... ary) {
for (int i = 0; i < ary.length; i++) {
String s = ary[i];
mgr.Get_by_key(Bry_.new_u8(s));
Env_.TickCount_Test++;
}
return this;
}
public GfoCacheMgr_fxt Expd_curSize_(int v) {expd_curSize = v; return this;} private int expd_curSize = -1;
public GfoCacheMgr_fxt Expd_itms_(String... v) {expd_itms = v; return this;} private String[] expd_itms;
public GfoCacheMgr_fxt tst() {
if (expd_curSize != -1) Tfds.Eq(expd_curSize, mgr.Cur_size(), "curSize");
if (expd_itms != null) {
String[] actl = new String[mgr.Count()];
for (int i = 0; i < actl.length; i++)
actl[i] = ((GfoCacheItm_mock)mgr.Get_at(i)).S();
Tfds.Eq_ary_str(expd_itms, actl, "itms");
}
return this;
}
}
class GfoCacheItm_mock implements RlsAble {
public void Rls() {}
public String S() {return s;} private String s;
public GfoCacheItm_mock(String s) {this.s = s;}
}

View File

@@ -0,0 +1,122 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class Gfo_cache_mgr {
private Ordered_hash hash = Ordered_hash_.new_bry_();
private Ordered_hash recent = Ordered_hash_.new_bry_();
public int Max_size() {return max_size;} public Gfo_cache_mgr Max_size_(int v) {max_size = v; return this;} private int max_size;
public int Reduce_by() {return reduce_by;} public Gfo_cache_mgr Reduce_by_(int v) {reduce_by = v; return this;} private int reduce_by;
public int Cur_size() {return cur_size;} private int cur_size;
public int Count() {return hash.Count();}
public void Clear() {hash.Clear(); recent.Clear(); cur_size = 0;}
@gplx.Internal protected Object Get_at(int i) {
Gfo_cache_itm rv = (Gfo_cache_itm)hash.Get_at(i);
return rv.Val();
}
public Object Get_by_key(byte[] key) {
Object o = hash.Get_by(key); if (o == null) return null;
Gfo_cache_itm rv = (Gfo_cache_itm)o;
rv.Timestamp_update();
Object recent_itm = recent.Get_by(key);
if (recent_itm == null) recent.Add(key, rv);
return rv.Val();
}
public void Del(byte[] key) {
Object o = hash.Get_by(key); if (o == null) return;
Gfo_cache_itm itm = (Gfo_cache_itm)o;
cur_size -= itm.Size();
hash.Del(itm.Key());
itm.Rls();
}
public void Add_replace(byte[] key, RlsAble val, int size) {
// Del(key);
// Add(key, val, size);
Object o = hash.Get_by(key);
if (o == null)
Add(key, val, size);
else {
Gfo_cache_itm itm = (Gfo_cache_itm)o;
cur_size -= itm.Size();
cur_size += size;
itm.Replace(val, size);
}
}
public void Add(byte[] key, RlsAble val, int size) {
// if (cur_size + size > 600000000) ReduceCache();
cur_size += size;
// ++cur_size;
Gfo_cache_itm itm = new Gfo_cache_itm(key, val, size);
hash.Add(key, itm);
}
public void Reduce_recent() {
// ConsoleAdp._.WriteLine("reducing");
int len = recent.Count();
for (int i = 0; i < len; i++) {
Gfo_cache_itm itm = (Gfo_cache_itm)recent.Get_at(i);
itm.Rls(); // releases root
}
recent.Clear();
}
public void Reduce_cache() {
ConsoleAdp._.WriteLine("compacting:");
// hash.Sort();
// int len = hash.Count();
// List_adp deleted = List_adp_.new_();
// int deleted_size = 0, deleted_count = 0;
// for (int i = 0; i < len; i++) {
// Gfo_cache_itm itm = (Gfo_cache_itm)hash.Get_at(i);
// int new_deleted_size = deleted_size + 1;//itm.Size();
// if (new_deleted_size > 4000 && deleted_count > 0) break;
// deleted.Add(itm);
// deleted_count++;
// deleted_size = new_deleted_size;
// }
// len = deleted.Count();
// for (int i = 0; i < len; i++) {
// Gfo_cache_itm itm = (Gfo_cache_itm)deleted.Get_at(i);
// cur_size --;
// hash.Del(bry_ref.Val_(itm.Key()));
// itm.Rls();
// }
// deleted.Clear();
int len = hash.Count();
for (int i = 0; i < len; i++) {
Gfo_cache_itm itm = (Gfo_cache_itm)hash.Get_at(i);
// hash.Del(bry_ref.Val_(itm.Key()));
itm.Rls();
}
}
}
class Gfo_cache_itm implements gplx.CompareAble, RlsAble {
public Gfo_cache_itm(byte[] key, RlsAble val, int size) {this.key = key; this.val = val; this.size = size; this.timestamp = Env_.TickCount();}
public byte[] Key() {return key;} private byte[] key;
public RlsAble Val() {return val;} private RlsAble val;
public int Size() {return size;} private int size;
public void Replace(RlsAble val, int size) {this.val = val; this.size = size;}
public long Timestamp() {return timestamp;} public void Timestamp_update() {timestamp = Env_.TickCount();} private long timestamp;
public int compareTo(Object obj) {
Gfo_cache_itm comp = (Gfo_cache_itm)obj;
return Long_.Compare(timestamp, comp.timestamp);
}
public void Rls() {
val.Rls();
// val = null;
// key = null;
}
}

View File

@@ -0,0 +1,46 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import gplx.xowa.net.*;
public class Gfo_url {
public byte[] Raw() {return raw;} private byte[] raw;
public boolean Protocol_is_relative() {return protocol_is_relative;} public Gfo_url Protocol_is_relative_(boolean v) {protocol_is_relative = v; return this;} private boolean protocol_is_relative;
public byte Protocol_tid() {return protocol_tid;} public Gfo_url Protocol_tid_(byte v) {protocol_tid = v; return this;} private byte protocol_tid;
public byte[] Protocol_bry() {return protocol_bry;} public Gfo_url Protocol_bry_(byte[] v) {protocol_bry = v; return this;} private byte[] protocol_bry;
public byte[] Site() {return site;} public Gfo_url Site_(byte[] v) {site = v; return this;} private byte[] site;
public byte[] Site_sub() {return site_sub;} public Gfo_url Site_sub_(byte[] v) {site_sub = v; return this;} private byte[] site_sub;
public byte[] Site_name() {return site_name;} public Gfo_url Site_name_(byte[] v) {site_name = v; return this;} private byte[] site_name;
public byte[] Site_domain() {return site_domain;} public Gfo_url Site_domain_(byte[] v) {site_domain = v; return this;} private byte[] site_domain;
public byte[] Page() {return page;} public Gfo_url Page_(byte[] v) {page = v; return this;} private byte[] page;
public byte[] Anchor() {return anchor;} public Gfo_url Anchor_(byte[] v) {anchor = v; return this;} private byte[] anchor;
public byte[][] Segs() {return segs;} public Gfo_url Segs_(byte[][] v) {segs = v; return this;} private byte[][] segs;
public Gfo_url_arg[] Args() {return args;} public Gfo_url Args_(Gfo_url_arg[] v) {args = v; return this;} Gfo_url_arg[] args;
public int Args_bgn() {return args_bgn;} public Gfo_url Args_bgn_(int v) {args_bgn = v; return this;} private int args_bgn = -1;
public byte Err() {return err;} public Gfo_url Err_(byte v) {err = v; return this;} private byte err;
public Gfo_url Ini_(byte[] v) {
raw = v;
protocol_tid = Xoo_protocol_itm.Tid_null; protocol_is_relative = false;
protocol_bry = site = site_sub = site_name = site_domain = page = anchor = null;
segs = Bry_.Ary_empty;
args = Gfo_url_arg.Ary_empty;
err = Err_none;
args_bgn = -1;
return this;
}
public static final byte Err_none = 0, Err_protocol_missing = 1, Err_site_missing = 2;
}

View File

@@ -0,0 +1,41 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class Gfo_url_arg {
public Gfo_url_arg(byte[] key_bry, byte[] val_bry) {this.key_bry = key_bry; this.val_bry = val_bry;}
public byte[] Key_bry() {return key_bry;} private byte[] key_bry;
public byte[] Val_bry() {return val_bry;} private byte[] val_bry;
public Gfo_url_arg Val_bry_(byte[] v) {val_bry = v; return this;}
public static final Gfo_url_arg[] Ary_empty = new Gfo_url_arg[0];
public static Gfo_url_arg new_key_(String key) {
return new Gfo_url_arg(Bry_.new_u8(key), Bry_.Empty);
}
public static Gfo_url_arg[] Ary(String... kvs) {
int len = kvs.length;
Gfo_url_arg[] rv = new Gfo_url_arg[len / 2];
String key = null;
for (int i = 0; i < len; ++i) {
String s = kvs[i];
if (i % 2 == 0)
key = s;
else
rv[i / 2] = new Gfo_url_arg(Bry_.new_u8(key), Bry_.new_u8(s));
}
return rv;
}
}

View File

@@ -0,0 +1,312 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import gplx.xowa.net.*;
public class Gfo_url_parser {
private boolean pass = true;
private Gfo_url url;
private List_adp segs = List_adp_.new_(), args = List_adp_.new_();
private Url_encoder encoder = Url_encoder.new_html_href_mw_().Itms_raw_same_many(Byte_ascii.Underline); private Hash_adp_bry protocols = Hash_adp_bry.ci_ascii_(); // ASCII:url_protocol; EX:"http:", "ftp:", etc
public Gfo_url_parser() {
Init_protocols(Xoo_protocol_itm.Ary());
Init_protocol(Xoo_protocol_itm.Tid_file, Xoo_protocol_itm.Str_file);
}
public void Init_protocol(byte tid, String protocol) {Init_protocols(new Xoo_protocol_itm(tid, protocol));}
public void Init_protocols(Xoo_protocol_itm... itms) {
int len = itms.length;
for (int i = 0; i < len; i++) {
Xoo_protocol_itm itm = itms[i];
byte[] key = itm.Key_w_colon_bry();
if (protocols.Has(key)) continue; // NOTE: must check if protocol exists, else test will fail
protocols.Add(key, itm);
}
}
public byte Relative_url_protocol() {return relative_url_protocol;} public Gfo_url_parser Relative_url_protocol_(byte v) {relative_url_protocol = v; return this;} private byte relative_url_protocol = Xoo_protocol_itm.Tid_http;
public byte[] Relative_url_protocol_bry() {return Xoo_protocol_itm.Ary()[relative_url_protocol].Key_w_colon_bry();}
public void Parse_site_fast(Gfo_url_site_data site_data, byte[] src, int bgn, int end) {
int pos = bgn; boolean rel = false;
if (pos + 1 < end && src[pos] == Byte_ascii.Slash && src[pos + 1] == Byte_ascii.Slash) { // starts with "//"
pos += 2;
rel = true;
}
if (!rel) { // search for ":"; NOTE: only search if not rel; i.e.: "//"
int colon_pos = Bry_finder.Find_fwd(src, Byte_ascii.Colon, pos, end); // no colon found; EX: "//a.org/b"; "a.org/b"
if (colon_pos != Bry_.NotFound) // colon found; EX: "http://" or "https://"
pos = colon_pos + Int_.Const_dlm_len;
if (pos < end && src[pos] == Byte_ascii.Slash) { // skip slash after colon
pos += 1;
if (pos < end && src[pos] == Byte_ascii.Slash) // skip 2nd slash after colon
pos += 1;
}
}
int slash_pos = Bry_finder.Find_fwd(src, Byte_ascii.Slash, pos, end);
if (slash_pos == Bry_.NotFound) // no terminating slash; EX: http://a.org
slash_pos = end;
slash_pos = Bry_.Trim_end_pos(src, slash_pos);
site_data.Atrs_set(rel, pos, slash_pos);
}
public Gfo_url Parse(byte[] src) {Gfo_url rv = new Gfo_url(); this.Parse(rv, src, 0, src.length); return rv;}
public boolean Parse(Gfo_url url, byte[] src, int bgn, int end) {
this.url = url;
url.Ini_(src);
pass = true;
segs.Clear();
args.Clear();
int colon_pos = Bry_finder.Find_fwd(src, Byte_ascii.Colon, bgn, end);
Object protocol_obj = colon_pos == Bry_.NotFound ? null : protocols.Get_by_mid(src, bgn, colon_pos + 1); // +1 to include colon
if (protocol_obj != null) {
Xoo_protocol_itm protocol_itm = (Xoo_protocol_itm)protocol_obj;
url.Protocol_bry_(protocol_itm.Key_w_colon_bry());
url.Protocol_tid_(protocol_itm.Tid());
Parse_site(src, protocol_itm.Key_w_colon_bry().length, end);
}
else {
int pos = bgn;
boolean loop = true;
while (loop) {
if (pos == end) {
encoder.Decode(src, bgn, end, tmp_bfr, false);
url.Site_(tmp_bfr.Xto_bry_and_clear());
url.Err_(Gfo_url.Err_protocol_missing); pass = false;
break;
}
byte b = src[pos];
switch (b) {
case Byte_ascii.Colon:
// Segs_add(src, bgn, end);
Parse_segs(src, bgn, end);
loop = false;
url.Err_(Gfo_url.Err_protocol_missing); pass = false;
loop = false;
break;
case Byte_ascii.Question:
Segs_add(src, bgn, pos);
Parse_args(src, pos + 1, end);
loop = false;
url.Err_(Gfo_url.Err_protocol_missing); pass = false;
break;
case Byte_ascii.Hash:
Segs_add(src, bgn, pos);
Parse_anchor(src, pos + 1, end);
slash_prv = pos;
loop = false;
url.Err_(Gfo_url.Err_protocol_missing); pass = false;
break;
case Byte_ascii.Slash:
if (pos == 0 && pos + 1 < end && src[pos + 1] == Byte_ascii.Slash) { // starts with "//"
encoder.Decode(src, bgn, pos, tmp_bfr, false);
url.Site_(tmp_bfr.Xto_bry_and_clear());
url.Protocol_is_relative_(true);
url.Protocol_tid_(relative_url_protocol);
byte[] protocol_bry = Xoo_protocol_itm.Ary()[relative_url_protocol].Key_w_colon_bry();
url.Protocol_bry_(protocol_bry);
Parse_site(src, 2, end); // 2=//
loop = false;
}
else { // has "/"
encoder.Decode(src, bgn, pos, tmp_bfr, false);
url.Site_(tmp_bfr.Xto_bry_and_clear());
Parse_segs(src, pos + 1, end);
loop = false;
url.Err_(Gfo_url.Err_protocol_missing); pass = false;
}
break;
default:
break;
}
++pos;
}
}
return pass;
}
private void Parse_site(byte[] src, int bgn, int end) {
int dot_count = 0, dot_pos_0 = -1, dot_pos_1 = -1;
boolean loop = true;
byte b = Byte_ascii.Nil;
while (loop) {
if (bgn == end) {
url.Err_(Gfo_url.Err_site_missing);
break;
}
b = src[bgn];
if (b == Byte_ascii.Slash)
++bgn;
else
break;
}
int pos = bgn;
while (loop) {
switch (b) {
case Byte_ascii.Dot:
switch (dot_count) {
case 0: dot_pos_0 = pos; break;
case 1: dot_pos_1 = pos; break;
}
++dot_count;
break;
case Byte_ascii.Slash:
Site_set(src, bgn, pos, dot_count, dot_pos_0, dot_pos_1);
Parse_segs(src, pos + 1, end);
loop = false;
break;
default:
break;
}
if (!loop) break;
++pos;
if (pos >= end) { // NOTE: >= needed b/c sometimes "xowa-cmd:", 5 passed in
Site_set(src, bgn, end, dot_count, dot_pos_0, dot_pos_1);
break;
}
b = src[pos];
}
}
int slash_prv;
private void Parse_segs(byte[] src, int bgn, int end) {
if (bgn == end) return;
int pos = bgn;
slash_prv = bgn;
boolean loop = true;
while (loop) {
if (pos == end) {
if (slash_prv < pos) Segs_add(src, slash_prv, end);
break;
}
byte b = src[pos];
switch (b) {
case Byte_ascii.Question:
Segs_add(src, slash_prv, pos);
Parse_args(src, pos + 1, end);
loop = false;
break;
case Byte_ascii.Hash:
Segs_add(src, slash_prv, pos);
Parse_anchor(src, pos + 1, end);
slash_prv = pos;
loop = false;
break;
case Byte_ascii.Slash:
if (slash_prv != pos) // HACK: handles urls of form "/wiki//A"; treat 2nd / as part of "/A"
Segs_add(src, slash_prv, pos);
break;
default:
break;
}
++pos;
}
url.Segs_((byte[][])segs.To_ary(byte[].class));
}
private void Parse_anchor(byte[] src, int bgn, int end) {
if (bgn == end) return;
int pos = bgn;
boolean loop = true;
while (loop) {
if (pos == end) {
Anchor_set(src, bgn, pos);
break;
}
byte b = src[pos];
switch (b) {
case Byte_ascii.Question:
Anchor_set(src, bgn, pos);
Parse_args(src, pos + 1, end);
loop = false;
break;
//case Byte_ascii.Slash: // NOTE: do not handle slash (by trying to parse segs); will cause anchor to fail; EX:A/b#c/d
// case Byte_ascii.Slash:
// Anchor_set(src, bgn, pos);
// Parse_segs(src, pos + 1, end);
// break;
default:
break;
}
++pos;
}
}
private void Parse_args(byte[] src, int bgn, int end) {
// if (bgn == end) return; // make "A?" -> "A" DATE:2014-01-19
int pos = bgn;
boolean loop = true;
int key_bgn = pos, key_end = pos, val_bgn = pos;
while (loop) {
if (pos == end) {
Args_add(src, key_bgn, key_end, val_bgn, pos);
break;
}
byte b = src[pos];
switch (b) {
case Byte_ascii.Amp:
Args_add(src, key_bgn, key_end, val_bgn, pos);
key_bgn = pos + 1;
break;
case Byte_ascii.Eq:
key_end = pos;
val_bgn = pos + 1; // +1 to set after eq
break;
default:
break;
}
++pos;
}
url.Args_bgn_(bgn - 1); // NOTE: bgn is 1st char after ?; -1 to place at ?
url.Args_((Gfo_url_arg[])args.To_ary(Gfo_url_arg.class));
}
private void Args_add(byte[] src, int key_bgn, int key_end, int val_bgn, int val_end) {
encoder.Decode(src, key_bgn, key_end, tmp_bfr, false);
byte[] key = tmp_bfr.Xto_bry_and_clear();
encoder.Decode(src, val_bgn, val_end, tmp_bfr, false);
byte[] val = tmp_bfr.Xto_bry_and_clear();
Gfo_url_arg arg = new Gfo_url_arg(key, val);
args.Add(arg);
}
private void Site_set(byte[] src, int bgn, int end, int dot_count, int dot_pos_0, int dot_pos_1) {
encoder.Decode(src, bgn, end, tmp_bfr, false);
url.Site_(tmp_bfr.Xto_bry_and_clear());
switch (dot_count) {
default:
case 2:
encoder.Decode(src, bgn, dot_pos_0, tmp_bfr, false);
url.Site_sub_(tmp_bfr.Xto_bry_and_clear());
encoder.Decode(src, dot_pos_0 + 1, dot_pos_1, tmp_bfr, false);
url.Site_name_(tmp_bfr.Xto_bry_and_clear());
encoder.Decode(src, dot_pos_1 + 1, end, tmp_bfr, false);
url.Site_domain_(tmp_bfr.Xto_bry_and_clear());
break;
case 1:
encoder.Decode(src, bgn, dot_pos_0, tmp_bfr, false);
url.Site_name_(tmp_bfr.Xto_bry_and_clear());
encoder.Decode(src, dot_pos_0 + 1, end, tmp_bfr, false);
url.Site_domain_(tmp_bfr.Xto_bry_and_clear());
break;
}
}
private void Segs_add(byte[] src, int bgn, int end) {
encoder.Decode(src, bgn, end, tmp_bfr, false);
byte[] seg = tmp_bfr.Xto_bry_and_clear();
if (url.Page() != null)
segs.Add(url.Page());
url.Page_(seg);
slash_prv = end + 1; // +1 to position after /
}
private void Anchor_set(byte[] src, int bgn, int end) {
encoder.Decode(src, bgn, end, tmp_bfr, false);
url.Anchor_(tmp_bfr.Xto_bry_and_clear());
}
private static final Bry_bfr tmp_bfr = Bry_bfr.reset_(500);
public static final byte[] Bry_double_slash = new byte[] {Byte_ascii.Slash, Byte_ascii.Slash};
}

View File

@@ -0,0 +1,153 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import org.junit.*;
import gplx.xowa.net.*;
public class Gfo_url_parser_tst {
Gfo_url_parser_chkr fxt = new Gfo_url_parser_chkr();
@Before public void init() {fxt.Reset();}
@Test public void All() {
fxt.Raw_("http://en.wikipedia.org/wiki/mock/Page 0#a?b=c&d=e")
.Protocol_tid_(Xoo_protocol_itm.Tid_http)
.Site_("en.wikipedia.org")
.Site_sub_("en")
.Site_name_("wikipedia")
.Site_domain_("org")
.Segs_("wiki")
.Segs_("mock")
.Page_("Page 0")
.Anchor_("a")
.Args_("b", "c")
.Args_("d", "e")
.tst_();
}
@Test public void Site_slash_none() {
fxt.Raw_("http:en.wikipedia.org").Protocol_tid_(Xoo_protocol_itm.Tid_http).Site_("en.wikipedia.org").tst_();
}
@Test public void Site_slash_many() {
fxt.Raw_("http:////en.wikipedia.org").Protocol_tid_(Xoo_protocol_itm.Tid_http).Site_("en.wikipedia.org").tst_();
}
@Test public void Site_slash_trailing() {
fxt.Raw_("http://en.wikipedia.org/").Protocol_tid_(Xoo_protocol_itm.Tid_http).Site_("en.wikipedia.org").tst_();
}
@Test public void Site_dot_1() {
fxt.Raw_("http://wikipedia.org").Site_("wikipedia.org").Site_name_("wikipedia").Site_domain_("org").tst_();
}
@Test public void Page_encoded() {
fxt.Raw_("http://site/A%27s").Site_("site").Page_("A's").tst_();
}
@Test public void Args() {
fxt.Raw_("http://site/page?a=b").Site_("site").Args_("a", "b").tst_();
}
@Test public void Args_protocol_less() {
fxt.Raw_("Special:Search/Earth?fulltext=yes").Segs_("Special:Search").Page_("Earth").Args_("fulltext", "yes").tst_();
}
@Test public void Err_protocol_missing() {
fxt.Raw_("httpen.wikipedia.org").Err_(Gfo_url.Err_protocol_missing).tst_();
}
@Test public void Err_protocol_missing__site_only() {
fxt.Raw_("site").Site_("site").Err_(Gfo_url.Err_protocol_missing).tst_();
}
@Test public void Err_protocol_missing__site_and_page() {
fxt.Raw_("site/page").Site_("site").Page_("page").Err_(Gfo_url.Err_protocol_missing).tst_();
}
@Test public void Err_protocol_missing__page_anchor() {
fxt.Raw_("page#a").Page_("page").Anchor_("a").Err_(Gfo_url.Err_protocol_missing).tst_();
}
@Test public void Legacy() {
fxt.Reset().Raw_("http://en.wikipedia.org/wiki/A" ).Page_("A").tst_();
fxt.Reset().Raw_("http://en.wikipedia.org/wiki/A?").Page_("A").Args_("", "").tst_();
fxt.Reset().Raw_("http://en.wikipedia.org/wiki/A#").Page_("A").tst_();
fxt.Reset().Raw_("http://en.wikipedia.org/wiki/A%27s").Page_("A's").tst_();
fxt.Reset().Raw_("https://en.wikipedia.org/wiki/A").Page_("A").tst_();
fxt.Reset().Raw_("http://en.m.wikipedia.org/wiki/A").Page_("A").tst_();
fxt.Reset().Raw_("http://en.wikipedia.org/w/index.php?title=A").Args_("title", "A").tst_();
}
@Test public void Relative() {
fxt.Raw_("//en.wikipedia.org").Protocol_tid_(Xoo_protocol_itm.Tid_http).Site_("en.wikipedia.org").tst_();
}
@Test public void Parse_site_fast() {
fxt.Parse_site_fast_tst("http://a.org/B" , "a.org");
fxt.Parse_site_fast_tst("http://a.org" , "a.org");
fxt.Parse_site_fast_tst("//a.org/B" , "a.org");
fxt.Parse_site_fast_tst("//a.org/B:C" , "a.org");
}
}
class Gfo_url_parser_chkr implements Tst_chkr {
public Class<?> TypeOf() {return Gfo_url.class;}
public Gfo_url_parser_chkr Protocol_tid_(byte v) {this.protocol_tid = v; return this;} private byte protocol_tid;
public Gfo_url_parser_chkr Site_(String v) {this.site = v; return this;} private String site;
public Gfo_url_parser_chkr Site_sub_(String v) {this.site_sub = v; return this;} private String site_sub;
public Gfo_url_parser_chkr Site_name_(String v) {this.site_name = v; return this;} private String site_name;
public Gfo_url_parser_chkr Site_domain_(String v) {this.site_domain = v; return this;} private String site_domain;
public Gfo_url_parser_chkr Segs_(String v) {segs.Add(v); return this;} List_adp segs = List_adp_.new_();
public Gfo_url_parser_chkr Page_(String v) {this.page = v; return this;} private String page;
public Gfo_url_parser_chkr Anchor_(String v) {this.anchor = v; return this;} private String anchor;
public Gfo_url_parser_chkr Args_(String k, String v) {args.Add(new Gfo_url_arg_chkr(k, v)); return this;} List_adp args = List_adp_.new_();
public Gfo_url_parser_chkr Err_(byte v) {err = v; return this;} private byte err;
public Gfo_url_parser_chkr Reset() {
protocol_tid = Xoo_protocol_itm.Tid_null;
site = site_sub = site_name = site_domain = page = anchor = null;
err = Gfo_url.Err_none;
segs.Clear();
args.Clear();
return this;
}
ByteAryAry_chkr bry_ary_chkr = new ByteAryAry_chkr();
public int Chk(Tst_mgr mgr, String path, Object actl_obj) {
Gfo_url actl = (Gfo_url)actl_obj;
int rv = 0;
rv += mgr.Tst_val(err == Gfo_url.Err_none, path, "err", err, actl.Err());
rv += mgr.Tst_val(protocol_tid == Xoo_protocol_itm.Tid_null, path, "protocol_tid", protocol_tid, actl.Protocol_tid());
rv += mgr.Tst_val(site == null, path, "site", site, String_.new_u8(actl.Site()));
rv += mgr.Tst_val(site_sub == null, path, "site_sub", site_sub, String_.new_u8(actl.Site_sub()));
rv += mgr.Tst_val(site_name == null, path, "site_name", site_name, String_.new_u8(actl.Site_name()));
rv += mgr.Tst_val(site_domain == null, path, "site_domain", site_domain, String_.new_u8(actl.Site_domain()));
bry_ary_chkr.Val_(Bry_.Ary(segs.To_str_ary()));
rv += bry_ary_chkr.Chk(mgr, "segs", actl.Segs());
rv += mgr.Tst_val(page == null, path, "page", page, String_.new_u8(actl.Page()));
rv += mgr.Tst_val(anchor == null, path, "anchor", anchor, String_.new_u8(actl.Anchor()));
mgr.Tst_sub_ary((Gfo_url_arg_chkr[])args.To_ary(Gfo_url_arg_chkr.class), actl.Args(), "args", rv);
return rv;
}
public Gfo_url_parser_chkr Raw_(String v) {this.raw = v; return this;} private String raw;
public void tst_() {
byte[] bry = Bry_.new_u8(raw);
Gfo_url url = new Gfo_url();
parser.Parse(url, bry, 0, bry.length);
Tst_mgr tst_mgr = new Tst_mgr();
tst_mgr.Tst_obj(this, url);
} Gfo_url_parser parser = new Gfo_url_parser();
public void Parse_site_fast_tst(String raw, String expd) {
byte[] raw_bry = Bry_.new_u8(raw);
parser.Parse_site_fast(site_data, raw_bry, 0, raw_bry.length);
String actl = String_.new_u8(raw_bry, site_data.Site_bgn(), site_data.Site_end());
Tfds.Eq(expd, actl);
} Gfo_url_site_data site_data = new Gfo_url_site_data();
}
class Gfo_url_arg_chkr implements Tst_chkr {
public Gfo_url_arg_chkr(String key, String val) {this.key = key; this.val = val;} private String key; String val;
public Class<?> TypeOf() {return Gfo_url_arg.class;}
public int Chk(Tst_mgr mgr, String path, Object actl_obj) {
Gfo_url_arg actl = (Gfo_url_arg)actl_obj;
int rv = 0;
rv += mgr.Tst_val(key == null, path, "key", key, String_.new_u8(actl.Key_bry()));
rv += mgr.Tst_val(val == null, path, "val", val, String_.new_u8(actl.Val_bry()));
return rv;
}
}

View File

@@ -0,0 +1,24 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class Gfo_url_site_data {
public boolean Rel() {return rel;} private boolean rel;
public int Site_bgn() {return site_bgn;} private int site_bgn;
public int Site_end() {return site_end;} private int site_end;
public void Atrs_set(boolean rel, int bgn, int end) {this.rel = rel; this.site_bgn = bgn; this.site_end = end;}
}

View File

@@ -0,0 +1,22 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public interface Gfo_usr_dlg__gui__opt {
boolean Warn_enabled();
boolean Note_enabled();
}

View File

@@ -0,0 +1,50 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import gplx.core.strings.*; import gplx.gfui.*;
public class Gfo_usr_dlg__gui__swt implements Gfo_usr_dlg__gui, GfoInvkAble {
private final GfuiInvkCmd cmd_sync; private final GfuiTextBox prog_box, info_box; private final Gfo_usr_dlg__gui__opt opt;
public Gfo_usr_dlg__gui__swt(Gfui_kit kit, GfuiTextBox prog_box, GfuiTextBox info_box, GfuiTextBox warn_box, Gfo_usr_dlg__gui__opt opt) {
this.cmd_sync = kit.New_cmd_sync(this); // NOTE: cmd_sync needed else progress messages may be sent out of order
this.prog_box = prog_box; this.info_box = info_box;
this.opt = opt;
}
public void Clear() {Write(Invk_write_prog, ""); info_box.Text_(""); info_box.ForeColor_(ColorAdp_.Black); info_box.BackColor_(ColorAdp_.White); info_box.Redraw(); info_box_is_warn = false;}
public String_ring Prog_msgs() {return prog_msgs;} String_ring prog_msgs = new String_ring().Max_(128);
public void Write_prog(String text) {Write(Invk_write_prog, text);}
public void Write_note(String text) {if (opt.Note_enabled()) Write(Invk_write_note, text);}
public void Write_warn(String text) {if (opt.Warn_enabled()) Write(Invk_write_warn, text);}
public void Write_stop(String text) {Write(Invk_write_stop, text);}
private void Write(String invk, String text) {
GfoMsg m = GfoMsg_.new_cast_(invk).Add("v", text);
GfoInvkAble_.InvkCmd_msg(cmd_sync, invk, m);
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_write_prog)) {String v = m.ReadStr("v"); prog_box.Text_(v); prog_box.Redraw(); if (!String_.Eq(v, "")) prog_msgs.Push(v);}
else if (ctx.Match(k, Invk_write_note)) {Info_box_write(m.ReadStr("v"), false); info_box.Redraw();}
else if (ctx.Match(k, Invk_write_warn)) {Info_box_write(m.ReadStr("v"), true); info_box.ForeColor_(ColorAdp_.White); info_box.BackColor_(ColorAdp_.Red); info_box.Redraw();}
else return GfoInvkAble_.Rv_unhandled;
return this;
}
private void Info_box_write(String v, boolean warn) {
if (info_box_is_warn) return;
info_box.Text_(v);
info_box_is_warn = warn;
} boolean info_box_is_warn;
static final String Invk_write_prog = "write_prog", Invk_write_note = "write_note", Invk_write_warn = "write_warn", Invk_write_stop = "write_stop";
}

View File

@@ -0,0 +1,34 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class Gfo_usr_dlg_fmt {
public boolean Write_prog_cur(int cur, Gfo_usr_dlg usr_dlg) {
if (cur < prog_prv + prog_interval) return usr_dlg.Canceled();
prog_prv = cur;
String pct = DecimalAdp_.CalcPctStr(cur + List_adp_.Base1, end, "00.00");
usr_dlg.Prog_many(grp_key, msg_key, fmt, Int_.Xto_str_pad_bgn_zero(cur + List_adp_.Base1, endLen), end, pct);
return usr_dlg.Canceled();
} String fmt; int end, endLen;
public static Gfo_usr_dlg_fmt fmt_(String grp_key, String msg_key, String fmt, int end, float pct) {
Gfo_usr_dlg_fmt rv = new Gfo_usr_dlg_fmt();
rv.grp_key = grp_key; rv.msg_key = msg_key;
rv.fmt = fmt; rv.end = end; rv.endLen = Int_.DigitCount(end); rv.prog_interval = (int)((float)end * (float)(pct / (float)100));;
return rv;
} String grp_key, msg_key;
int prog_interval; int prog_prv = Int_.MinValue;
}

View File

@@ -0,0 +1,61 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import gplx.core.strings.*;
public class HierPosAryBldr {
public void Init() {
int ary_max = ary.length;
for (int i = 0; i < ary_max; i++)
ary[i] = 0;
aryIdx = -1;
root = 0;
}
public void MoveDown() {
aryIdx += 1;
if (aryIdx == 0)
ary[aryIdx] = root;
else
ary[aryIdx] = 0;
}
public void MoveUp() {
aryIdx -= 1;
MoveNext();
}
public void MoveNext() {
if (aryIdx == -1)
root += 1;
else
ary[aryIdx] += 1;
}
public boolean Dirty() {return aryIdx > -1 || root > 0;}
public int[] XtoIntAry() {
if (aryIdx == -1) return Int_.Ary_empty;
int[] rv = new int[aryIdx + 1];
for (int i = 0; i < aryIdx + 1; i++)
rv[i] = ary[i];
return rv;
}
public String XtoStr() {
String_bldr sb = String_bldr_.new_();
for (int i = 0; i < aryIdx; i++)
sb.Add_spr_unless_first(Int_.Xto_str(ary[i]), " ", i);
return sb.XtoStr();
}
int[] ary; int aryIdx = -1; int root = -1;
public HierPosAryBldr(int ary_max) {ary = new int[ary_max]; this.Init();}
}

View File

@@ -0,0 +1,65 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import org.junit.*;
public class HierPosAryBldr_tst {
@Before public void init() {bldr.Init();} HierPosAryBldr bldr = new HierPosAryBldr(256);
@Test public void Basic() {
tst_ary(Int_.Ary_empty);
}
@Test public void Move_d() {
bldr.MoveDown();
tst_ary(0);
}
@Test public void Move_dd() {
bldr.MoveDown();
bldr.MoveDown();
tst_ary(0, 0);
}
@Test public void Move_ddu() {
bldr.MoveDown();
bldr.MoveDown();
bldr.MoveUp();
tst_ary(1);
}
@Test public void Move_ddud() {
bldr.MoveDown();
bldr.MoveDown();
bldr.MoveUp();
bldr.MoveDown();
tst_ary(1, 0);
}
@Test public void Move_dud() {
bldr.MoveDown();
bldr.MoveUp();
bldr.MoveDown();
tst_ary(1);
}
@Test public void Move_dn() {
bldr.MoveDown();
bldr.MoveNext();
tst_ary(1);
}
@Test public void Move_ddn() {
bldr.MoveDown();
bldr.MoveDown();
bldr.MoveNext();
tst_ary(0, 1);
}
private void tst_ary(int... expd) {Tfds.Eq_ary(expd, bldr.XtoIntAry());}
}

View File

@@ -0,0 +1,58 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class Int_2_ref {
public Int_2_ref() {}
public Int_2_ref(int v0, int v1) {Val_all_(v0, v1);}
public int Val_0() {return val_0;} public Int_2_ref Val_0_(int v) {val_0 = v; return this;} private int val_0;
public int Val_1() {return val_1;} public Int_2_ref Val_1_(int v) {val_1 = v; return this;} private int val_1;
public Int_2_ref Val_all_(int v0, int v1) {val_0 = v0; val_1 = v1; return this;}
@Override public int hashCode() {
int hash = 23;
hash = (hash * 31) + val_0;
hash = (hash * 31) + val_1;
return hash;
}
@Override public boolean equals(Object obj) {
if (obj == null) return false;
Int_2_ref comp = (Int_2_ref)obj;
return val_0 == comp.val_0 && val_1 == comp.val_1;
}
public static Int_2_ref parse_(String raw) {
try {
String[] itms = String_.Split(raw, ",");
int v0 = Int_.parse_(itms[0]);
int v1 = Int_.parse_(itms[1]);
return new Int_2_ref(v0, v1);
} catch (Exception e) {Exc_.Noop(e); throw Exc_.new_parse("Int_2_ref", raw);}
}
public static Int_2_ref[] parse_ary_(String raw) {
try {
String[] itms = String_.Split(raw, ";");
int itms_len = itms.length;
Int_2_ref[] rv = new Int_2_ref[itms_len];
for (int i = 0; i < itms_len; i++) {
String[] vals = String_.Split(itms[i], ",");
int v0 = Int_.parse_(vals[0]);
int v1 = Int_.parse_(vals[1]);
rv[i] = new Int_2_ref(v0, v1);
}
return rv;
} catch (Exception e) {Exc_.Noop(e); throw Exc_.new_parse("Int_2_ref[]", raw);}
}
}

View File

@@ -0,0 +1,33 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class Int_2_val {
public Int_2_val(int v0, int v1) {val_0 = v0; val_1 = v1;}
public int Val_0() {return val_0;} final int val_0;
public int Val_1() {return val_1;} final int val_1;
public String Xto_str(Bry_bfr bfr) {return Xto_str(bfr, val_0, val_1);}
public static final Int_2_val Null_ptr = null;
public static Int_2_val parse_(String raw) {
String[] itms = String_.Split(raw, ',');
if (itms.length != 2) return Null_ptr;
int v0 = Int_.parse_or_(itms[0], Int_.MinValue); if (v0 == Int_.MinValue) return Null_ptr;
int v1 = Int_.parse_or_(itms[1], Int_.MinValue); if (v1 == Int_.MinValue) return Null_ptr;
return new Int_2_val(v0, v1);
}
public static String Xto_str(Bry_bfr bfr, int x, int y) {return bfr.Add_int_variable(x).Add_byte_comma().Add_int_variable(y).Xto_str_and_clear();}
}

View File

@@ -0,0 +1,39 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class Int_ary_parser extends Obj_ary_parser_base {
Number_parser parser = new Number_parser(); int[] ary; int ary_idx;
public int[] Parse_ary(String str, byte dlm) {byte[] bry = Bry_.new_u8(str); return Parse_ary(bry, 0, bry.length, dlm);}
public int[] Parse_ary(byte[] bry, int bgn, int end, byte dlm) {
Parse_core(bry, bgn, end, dlm, Byte_ascii.Nil);
return ary;
}
@Override protected void Ary_len_(int v) {
if (v == 0)
ary = Int_.Ary_empty;
else {
ary = new int[v]; // NOTE: always create new array; never reuse;
ary_idx = 0;
}
}
@Override protected void Parse_itm(byte[] bry, int bgn, int end) {
parser.Parse(bry, bgn, end); if (parser.Has_err() || parser.Has_frac()) throw Exc_.new_("failed to parse number", "val", String_.new_u8(bry, bgn, end));
ary[ary_idx++] = parser.Rv_as_int();
}
public static final Int_ary_parser _ = new Int_ary_parser();
}

View File

@@ -0,0 +1,28 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import org.junit.*;
public class Int_ary_parser_tst {
@Test public void Many() {tst_ints("1,2,3,4,5" , 0, 9, Int_.Ary(1, 2, 3, 4, 5));}
@Test public void One() {tst_ints("1" , 0, 1, Int_.Ary(1));}
@Test public void None() {tst_ints("" , 0, 0, Int_.Ary());}
private void tst_ints(String raw, int bgn, int end, int[] expd) {
int[] actl = Int_ary_parser._.Parse_ary(Bry_.new_a7(raw), bgn, end, Byte_ascii.Comma);
Tfds.Eq_ary(expd, actl);
}
}

View File

@@ -0,0 +1,44 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class Int_list {
private int[] ary = Int_.Ary_empty; private int ary_len, ary_max;
public void Add(int uid) {
int new_len = ary_len + 1;
if (new_len > ary_max) {
ary_max += 16;
int[] new_ary = new int[ary_max];
Int_.Ary_copy_to(ary, ary_len, new_ary);
ary = new_ary;
}
ary[ary_len] = uid;
ary_len = new_len;
}
public int Len() {return ary_len;}
public int Get_at(int i) {return ary[i];}
public void Clear() {
ary = Int_.Ary_empty;
ary_len = ary_max = 0;
}
public static Int_list new_(int... ary) {
Int_list rv = new Int_list();
int len = ary.length;
rv.ary = ary; rv.ary_len = len; rv.ary_max = len;
return rv;
}
}

View File

@@ -0,0 +1,25 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public interface Io_zip_mgr {
void Zip_fil(Io_url src_fil, Io_url trg_fil);
byte[] Zip_bry(byte[] src, int bgn, int len);
byte[] Unzip_bry(byte[] src, int bgn, int len);
void Unzip_to_dir(Io_url src_fil, Io_url trg_dir);
void Zip_dir(Io_url src_dir, Io_url trg_fil);
}

View File

@@ -0,0 +1,119 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import java.io.*;
import java.util.zip.*;
public class Io_zip_mgr_base implements Io_zip_mgr {
public void Zip_fil(Io_url src_fil, Io_url trg_fil) {
byte[] src_bry = Io_mgr.I.LoadFilBry(src_fil);
byte[] trg_bry = Zip_bry(src_bry, 0, src_bry.length);
Io_mgr.I.SaveFilBry(trg_fil, trg_bry);
}
public void Zip_dir(Io_url src_dir, Io_url trg_fil) {
try {
byte[] bry = new byte[4096];
FileOutputStream fil_strm = new FileOutputStream(trg_fil.Raw());
ZipOutputStream zip_strm = new ZipOutputStream(fil_strm);
Zip_dir__add_dir(zip_strm, bry, "", src_dir, Zip_dir__get_subs(src_dir));
zip_strm.flush();
zip_strm.close();
} catch(IOException e) {Exc_.new_exc(e, "io", "error duing zip", "src", src_dir.Raw(), "trg", trg_fil.Raw());}
}
private void Zip_dir__add_dir(ZipOutputStream zip_strm, byte[] bry, String zip_path, Io_url owner_dir, Io_url[] subs) {
int len = subs.length;
for (int i = 0; i < len; i++) {
Io_url sub = subs[i];
String sub_path = zip_path + sub.NameAndExt_noDirSpr();
if (sub.Type_dir())
Zip_dir__add_dir(zip_strm, bry, sub_path + "/", sub, Zip_dir__get_subs(sub));
else
Zip_dir__add_fil(zip_strm, bry, sub_path, sub);
}
}
private void Zip_dir__add_fil(ZipOutputStream zip_strm, byte[] bry, String zip_path, Io_url fil_url) {
try {
int len;
FileInputStream fil_strm = new FileInputStream(fil_url.Raw());
zip_strm.putNextEntry(new ZipEntry(zip_path));
while ((len = fil_strm.read(bry)) > 0)
zip_strm.write(bry, 0, len);
fil_strm.close();
} catch(IOException e) {throw Exc_.new_exc(e, "io", "error duing zip", "src", zip_path);}
}
private Io_url[] Zip_dir__get_subs(Io_url url) {
return Io_mgr.I.QueryDir_args(url).DirInclude_().ExecAsUrlAry();
}
public byte[] Zip_bry(byte[] src, int bgn, int len) {
ByteArrayInputStream src_stream = new ByteArrayInputStream(src, bgn, len);
ByteArrayOutputStream trg_stream = new ByteArrayOutputStream(len);
try {
ZipOutputStream trgZip = new ZipOutputStream(trg_stream);
ZipEntry entry = new ZipEntry("file");
trgZip.putNextEntry(entry);
int count;
while((count = src_stream.read(tmp, 0, tmpLen)) != -1) {
trgZip.write(tmp, 0, count);
}
trgZip.close();
} catch(Exception e) {throw Exc_.new_("failed to zip", "err", e.getMessage());}
return trg_stream.toByteArray();
}
public byte[] Unzip_bry(byte[] src, int bgn, int len) {
ByteArrayInputStream src_stream = new ByteArrayInputStream(src, bgn, len);
ByteArrayOutputStream trg_stream = new ByteArrayOutputStream(len);
try {
ZipInputStream srcZip = new ZipInputStream(src_stream);
int count;
while(srcZip.getNextEntry() != null) {
while ((count = srcZip.read(tmp, 0, tmpLen)) != -1) {
trg_stream.write(tmp, 0, count);
}
}
} catch(Exception e) {throw Exc_.new_("failed to unzip", "err", e.getMessage());}
return trg_stream.toByteArray();
}
public void Unzip_to_dir(Io_url src_fil, Io_url trg_dir) {
byte[] buffer = new byte[4096];
try{
Io_mgr.I.CreateDirIfAbsent(trg_dir);
ZipInputStream zip_strm = new ZipInputStream(new FileInputStream(src_fil.Raw()));
ZipEntry zip_eny = zip_strm.getNextEntry();
while (zip_eny != null) {
String itm_name = zip_eny.getName();
if (Op_sys.Cur().Tid_is_wnt()) itm_name = String_.Replace(itm_name, "/", "\\");
Io_url itm_url = Io_url_.new_any_(trg_dir.GenSubFil(itm_name).Raw());
Io_mgr.I.CreateDirIfAbsent(itm_url.OwnerDir()); // make sure owner dir exists
if (itm_url.Type_fil()) {
Io_mgr.I.SaveFilStr_args(itm_url, "").Exec();
File itm_file = new File(itm_url.Raw());
FileOutputStream itm_strm = new FileOutputStream(itm_file);
int len;
while ((len = zip_strm.read(buffer)) > 0)
itm_strm.write(buffer, 0, len);
itm_strm.close();
}
zip_eny = zip_strm.getNextEntry();
}
zip_strm.closeEntry();
zip_strm.close();
} catch(IOException e) {throw Exc_.new_exc(e, "io", "error duing unzip", "src", src_fil.Raw(), "trg", trg_dir.Raw());}
}
byte[] tmp = new byte[4096]; int tmpLen = 4096;
public static final Io_zip_mgr _ = new Io_zip_mgr_base();
}

View File

@@ -0,0 +1,36 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class Io_zip_mgr_mok implements Io_zip_mgr {
public void Zip_fil(Io_url src_fil, Io_url trg_fil) {
byte[] src_bry = Io_mgr.I.LoadFilBry(src_fil);
byte[] zip_bry = Zip_bry(src_bry, 0, src_bry.length);
Io_mgr.I.SaveFilBry(trg_fil, zip_bry);
}
public void Zip_dir(Io_url src_dir, Io_url trg_fil) {}
public byte[] Zip_bry(byte[] src, int bgn, int len) {return Bry_.Add(Bry_zipped, Bry_.Mid(src, bgn, len));}
public byte[] Unzip_bry(byte[] src, int bgn, int len) {
if (src == Bry_.Empty) return src;
byte[] section = Bry_.Mid(src, bgn, bgn + len);
if (!Bry_.Has_at_bgn(section, Bry_zipped, 0, section.length)) throw Exc_.new_("src not zipped", "section", String_.new_u8(section));
return Bry_.Mid(section, Bry_zipped.length, section.length);
}
public void Unzip_to_dir(Io_url src_fil, Io_url trg_dir) {}
private static final byte[] Bry_zipped = Bry_.new_u8("zipped:");
public static final Io_zip_mgr_mok _ = new Io_zip_mgr_mok(); Io_zip_mgr_mok() {}
}

View File

@@ -0,0 +1,31 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import org.junit.*;
public class Io_zip_mgr_tst {
@Test public void Zip_unzip() {
Zip_unzip_tst("abcdefghijklmnopqrstuvwxyz");
}
private void Zip_unzip_tst(String s) {
Io_zip_mgr zip_mgr = Io_zip_mgr_base._;
byte[] src = Bry_.new_a7(s);
byte[] zip = zip_mgr.Zip_bry(src, 0, src.length);
byte[] unz = zip_mgr.Unzip_bry(zip, 0, zip.length);
Tfds.Eq_ary(src, unz);
}
}

View File

@@ -0,0 +1,181 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public class Number_parser {
public int Rv_as_int() {return (int)int_val;} long int_val = 0;
public DecimalAdp Rv_as_dec() {return dec_val == null ? DecimalAdp_.long_(int_val) : dec_val;} DecimalAdp dec_val = null;
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 Number_parser Hex_enabled_(boolean v) {hex_enabled = v; return this;} private boolean hex_enabled;
public Number_parser Ignore_chars_(byte[] v) {this.ignore_chars = v; return this;} private byte[] ignore_chars;
public 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 Number_parser Parse(byte[] src) {return Parse(src, 0, src.length);}
public 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;
int_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:
int_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 = int_val;
int_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) {
int_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, int_val);
int_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) {
int_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) {
int_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 = (((int_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 = DecimalAdp_.divide_(full_val, frc_multiplier);
}
else {
if (has_neg) int_val *= -1;
if (has_exp) int_val = exp_neg ? int_val / exp_multiplier : int_val * exp_multiplier;
}
return this;
}
private Number_parser Has_err_y_() {has_err = true; return this;}
}

View File

@@ -0,0 +1,103 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import org.junit.*;
public class Number_parser_tst {
private final Number_parser_fxt fxt = new Number_parser_fxt();
@Before public void init() {fxt.Clear();}
@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 Decimal() {
fxt.Test_dec("1.23", DecimalAdp_.parse_("1.23"));
fxt.Test_dec("1.023", DecimalAdp_.parse_("1.023"));
fxt.Test_dec("-1.23", DecimalAdp_.parse_("-1.23"));
}
@Test public void Double_long() {
fxt.Test_dec(".42190046219457", DecimalAdp_.parse_(".42190046219457"));
}
@Test public void Exponent() {
fxt.Test_int("1E2", 100);
fxt.Test_dec("1.234E2", DecimalAdp_.parse_("123.4"));
fxt.Test_dec("1.234E-2", DecimalAdp_.parse_(".01234"));
fxt.Test_dec("123.4E-2", DecimalAdp_.parse_("1.234"));
fxt.Test_dec("+6.0E-3", DecimalAdp_.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 Number_parser_fxt {
private final Number_parser parser = new 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_dec(String raw, DecimalAdp expd) {
byte[] raw_bry = Bry_.new_a7(raw);
DecimalAdp actl = parser.Parse(raw_bry, 0, raw_bry.length).Rv_as_dec();
Tfds.Eq(expd.Xto_decimal(), actl.Xto_decimal(), 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,58 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public abstract class Obj_ary_parser_base {
int pos_len = 4; int[] pos;
protected abstract void Ary_len_(int v);
protected abstract void Parse_itm(byte[] bry, int bgn, int end);
protected void Parse_core(byte[] bry, int bgn, int end, byte dlm_1, byte dlm_2) {
if (pos == null) pos = new int[pos_len];
if (end - bgn == 0) {
this.Ary_len_(0);
return;
}
int pos_idx = 0;
int dlm_last = -1; // NOTE: -1 b/c dlm_2 can be 0 (Byte_ascii.Nil) and need to do dlm_last != dlm_2 check below
for (int i = bgn; i < end; i++) {
byte b = bry[i];
if (b == dlm_1 || b == dlm_2) {
if (pos_idx == pos_len - 1) { // -1 b/c pos[] will always be count_of_dlm + 1
pos_len *= 2;
int[] pos_new = new int[pos_len];
Array_.Copy(pos, pos_new);
pos = pos_new;
}
pos[pos_idx++] = i;
dlm_last = b;
}
}
if (dlm_last != dlm_2)
pos[pos_idx++] = end;
this.Ary_len_(pos_idx);
int parse_bgn = bgn;
for (int i = 0; i < pos_idx; i++) {
int parse_end = pos[i];
this.Parse_itm(bry, parse_bgn, parse_end);
parse_bgn = parse_end + 1;
}
if (pos_len > 255) { // reset
pos_len = 4;
pos = null;
}
}
}

View File

@@ -0,0 +1,142 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
class StatRng_fxt {
StatRng rng;
public StatRng_fxt ini_(int lo_ary_len, int hi_ary_len, int... slot_hi_ary) {
rng = new StatRng(lo_ary_len, hi_ary_len, slot_hi_ary);
return this;
}
public StatRng_fxt tst_(int... vals) {
for (int i = 0; i < vals.length; i++) {
int val = vals[i];
rng.Assign(val, val);
}
Tfds.Eq(expd_count, rng.Count, "Count");
Tfds.Eq(expd_lo, rng.Lo, "Lo");
Tfds.Eq(expd_hi, rng.Hi, "Hi");
Tfds.Eq_float(expd_avg, rng.Avg());
Tfds.Eq_ary(expd_lo_ary, XtoIntAry(rng.Lo_ary), "Lo_ary");
Tfds.Eq_ary(expd_hi_ary, XtoIntAry(rng.Hi_ary), "Hi_ary");
Tfds.Eq_ary(expd_slots, XtoIntAry(rng.Slot_ary), "Slots");
return this;
}
int[] XtoIntAry(StatItm[] ary) {
int[] rv = new int[ary.length];
for (int i = 0; i < rv.length; i++)
rv[i] = ary[i].Val;
return rv;
}
int[] XtoIntAry(StatRng[] ary) {
int[] rv = new int[ary.length];
for (int i = 0; i < rv.length; i++)
rv[i] = ary[i].Count;
return rv;
}
public StatRng_fxt Count_(int v) {expd_count = v; return this;} private int expd_count;
public StatRng_fxt Lo_(int v) {expd_lo = v; return this;} private int expd_lo;
public StatRng_fxt Hi_(int v) {expd_hi = v; return this;} private int expd_hi;
public StatRng_fxt Avg_(float v) {expd_avg = v; return this;} float expd_avg;
public StatRng_fxt Lo_ary_(int... v) {expd_lo_ary = v; return this;} private int[] expd_lo_ary;
public StatRng_fxt Hi_ary_(int... v) {expd_hi_ary = v; return this;} private int[] expd_hi_ary;
public StatRng_fxt Slots_(int... v) {expd_slots = v; return this;} private int[] expd_slots;
}
class StatRng {
// public String Key;
public int Lo = Int_.MaxValue;
public int Hi = Int_.MinValue;
public long Sum = 0;
public int Count = 0;
public float Avg() {return Sum / Count;}
public final StatItm[] Lo_ary;
public int Lo_ary_bound;
public int Lo_ary_len;
public final StatItm[] Hi_ary;
public int Hi_ary_bound;
public int Hi_ary_len;
public StatRng[] Slot_ary;
public int Slot_ary_len;
public StatRng(int lo_ary_len, int hi_ary_len, int... slot_hi_ary) {
this.Lo_ary_len = lo_ary_len;
this.Lo_ary_bound = Int_.MaxValue;
this.Lo_ary = NewBoundAry(lo_ary_len, Int_.MaxValue);
this.Hi_ary_len = hi_ary_len;
this.Hi_ary_bound = Int_.MinValue;
this.Hi_ary = NewBoundAry(hi_ary_len, Int_.MinValue);
if (slot_hi_ary != null && slot_hi_ary.length > 0) {
Slot_ary_len = slot_hi_ary.length + 1; // + 1 to hold max value
Slot_ary = new StatRng[Slot_ary_len];
int slot_lo = Int_.MinValue;
for (int i = 0; i < Slot_ary_len - 1; i++) {
int slot_hi = slot_hi_ary[i];
Slot_ary[i] = NewSlot(slot_lo, slot_hi);
slot_lo = slot_hi;
}
Slot_ary[Slot_ary_len - 1] = NewSlot(slot_lo, Int_.MaxValue);
}
}
public void Assign(Object key, int val) {
if (val < Lo) Lo = val;
if (val > Hi) Hi = val;
Sum += val;
++Count;
if (Slot_ary_len > 0) {
for (int i = 0; i < Slot_ary_len; i++) {
StatRng slot = Slot_ary[i];
if (val >= slot.Lo && val < slot.Hi)
slot.Assign(key, val);
}
}
if (val < Lo_ary_bound) {
Lo_ary_bound = CalcCutoff(Lo_ary, CompareAble_.More, Int_.MinValue, key, val);
}
if (val > Hi_ary_bound) {
Hi_ary_bound = CalcCutoff(Hi_ary, CompareAble_.Less, Int_.MaxValue, key, val);
}
}
int CalcCutoff(StatItm[] ary, int comp, int bgn_bound, Object key, int val) {
int new_bound = bgn_bound;
for (int i = 0; i < ary.length; i++) {
StatItm itm = ary[i];
if (Int_.Compare(itm.Val, val) == comp) {
itm = new StatItm(key, val);
ary[i] = itm;
}
if (Int_.Compare(itm.Val, new_bound) == comp) new_bound = itm.Val;
}
return new_bound;
}
StatRng NewSlot(int lo, int hi) {
StatRng rv = new StatRng(0, 0);
rv.Lo = lo;
rv.Hi = hi;
return rv;
}
StatItm[] NewBoundAry(int len, int dflt) {
StatItm[] rv = new StatItm[len];
for (int i = 0; i < len; i++)
rv[i] = new StatItm(null, dflt);
return rv;
}
}
class StatItm {
public Object Key;
public int Val;
public StatItm(Object key, int val) {this.Key = key; this.Val = val;}
}

View File

@@ -0,0 +1,39 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import org.junit.*;
public class StatRng_tst {
// Mwl_parser_fxt fx = new Mwl_parser_fxt(); Pf_func_lang_rsc rsc = Pf_func_lang_rsc._;
StatRng_fxt fx = new StatRng_fxt();
@Test public void Empty() {
fx.ini_(1, 1, 5);
fx.Count_(7).Lo_(2).Hi_(8).Avg_(5)
.Lo_ary_(2)
.Hi_ary_(8)
.Slots_(3, 4);
fx.tst_(5,7,2,8,3,4,6);
}
//@Test public void Basic() {fx.Test_parse_tmpl_str_test("{{#switch:{{{1}}}|a=1|b=2|3}}", "{{test|a}}", "1");}
//@Test public void Basic() {fx.Test_parse_tmpl_str_test("{{#switch:{{{1}}}|b=2|#default=3|a=1}}", "{{test|a}}", "1");}
//@Test public void Basic() {fx.Test_parse_tmpl_str_test("{{#switch:{{{1}}}|a|b|c=1|d=2}}", "{{test|a}}", "1");}
}
/*
public class Pf_func_switch_tst {
// Mwl_parser_fxt fx = new Mwl_parser_fxt(); Pf_func_lang_rsc rsc = Pf_func_lang_rsc._;
*/

View File

@@ -0,0 +1,30 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
public interface Tst_chkr {
Class<?> TypeOf();
int Chk(Tst_mgr mgr, String path, Object actl);
}
class Tst_chkr_null implements Tst_chkr {
public Class<?> TypeOf() {return Object.class;}
public int Chk(Tst_mgr mgr, String path, Object actl) {
mgr.Results().Add(Tst_itm.fail_("!=", path, "<cast type>", "<NULL TYPE>", ClassAdp_.NameOf_obj(actl)));
// mgr.Results().Add(Tst_itm.fail_("!=", path, "<cast value>", "<NULL VAL>", Object_.Xto_str_strict_or_null(actl)));
return 1;
}
}

View File

@@ -0,0 +1,134 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import gplx.core.strings.*;
public class Tst_mgr {
public Tst_mgr ThrowError_n_() {throwError = false; return this;} private boolean throwError = true;
public List_adp Results() {return results;} List_adp results = List_adp_.new_();
public KeyValHash Vars() {return vars;} KeyValHash vars = KeyValHash.new_();
public Object Vars_get_by_key(String key) {return vars.FetchValOr(key, null);}
public String Vars_get_bry_as_str(String key, int bgn, int end) {
byte[] bry = (byte[])vars.FetchValOr(key, null); if (bry == null) return String_.Empty;
if (bgn < 0 || end > bry.length || end < bgn || end < 0) return "<<OUT OF BOUNDS>>";
return String_.new_u8(Bry_.Mid(bry, bgn, end));
}
public int Tst_val(boolean skip, String path, String name, Object expd, Object actl) {
Tst_itm itm = Tst_itm.eq_(skip, path, name, expd, actl);
results.Add(itm);
return itm.Pass() ? 0 : 1;
}
public int Tst_val_ary(boolean skip, String path, String name, Object expd, Object actl) {
Tst_itm itm = Tst_itm.eq_(skip, path, name, XtoStr(expd), XtoStr(actl));
results.Add(itm);
return itm.Pass() ? 0 : 1;
}
public void Tst_obj(Tst_chkr expd, Object actl) {
results.Clear();
int err = Tst_sub_obj(expd, actl, "", 0);
if (throwError && err > 0) throw Exc_.new_(Build());
}
public void Tst_ary(String ownerPath, Tst_chkr[] expd_ary, Object[] actl_ary) {
results.Clear();
Tst_ary_inner(ownerPath, expd_ary, actl_ary);
}
private void Tst_ary_inner(String ownerPath, Tst_chkr[] expd_ary, Object[] actl_ary) {
int expd_ary_len = expd_ary.length, actl_ary_len = actl_ary.length;
int max_len = expd_ary_len > actl_ary_len ? expd_ary_len : actl_ary_len;
int err = 0;
for (int i = 0; i < max_len; i++) {
String path = ownerPath + Int_.Xto_str(i);
Tst_chkr expd_obj = i < expd_ary_len ? expd_ary[i] : Tst_mgr.Null_chkr;
Object actl_obj = i < actl_ary_len ? actl_ary[i] : "<NULL OBJ>";
String actl_type = i < actl_ary_len ? ClassAdp_.NameOf_obj(actl_obj) : "<NULL TYPE>";
err += Tst_inner(expd_obj, actl_obj, actl_type, path, err);
}
if (throwError && err > 0) {
String s = Build();
throw Exc_.new_(s);
}
}
public int Tst_sub_obj(Tst_chkr expd, Object actl, String path, int err) {
return Tst_inner(expd, actl, actl == null ? "<NULL>" : ClassAdp_.NameOf_obj(actl), path, err);
}
public int Tst_sub_ary(Tst_chkr[] expd_subs, Object[] actl_subs, String path, int err) {
Tst_ary_inner(path + ".", expd_subs, actl_subs);
return err;
}
int Tst_inner(Tst_chkr expd_obj, Object actl_obj, String actl_type, String path, int err) {
if (actl_obj == null || !ClassAdp_.IsAssignableFrom(expd_obj.TypeOf(), actl_obj.getClass())) {
results.Add(Tst_itm.fail_("!=", path, "<cast type>", ClassAdp_.NameOf_type(expd_obj.TypeOf()), actl_type));
return 1;
// results.Add(Tst_itm.fail_("!=", path, "<cast value>", Object_.Xto_str_strict_or_null(expd_obj.ValueOf()), Object_.Xto_str_strict_or_null(actl_obj)));
}
else {
return expd_obj.Chk(this, path, actl_obj);
}
}
String XtoStr(Object ary) {
if (ary == null) return "<NULL>";
int len = Array_.Len(ary);
for (int i = 0; i < len; i++) {
Object itm = Array_.Get_at(ary, i);
ary_sb.Add(Object_.Xto_str_strict_or_null_mark(itm)).Add(",");
}
return ary_sb.Xto_str_and_clear();
} String_bldr ary_sb = String_bldr_.new_();
String Build() {
String_bldr sb = String_bldr_.new_();
int comp_max = 0, path_max =0, name_max = 0;
int len = results.Count();
for (int i = 0; i < len; i++) {
Tst_itm itm = (Tst_itm)results.Get_at(i);
comp_max = Max(comp_max, itm.Comp());
path_max = Max(path_max, itm.Path());
name_max = Max(name_max, itm.Name());
}
for (int i = 0; i < len; i++) {
Tst_itm itm = (Tst_itm)results.Get_at(i);
sb.Add_fmt("\n{0} {1} {2} '{3}'", String_.PadEnd(itm.Comp(), comp_max, " "), "#" + String_.PadEnd(itm.Path(), path_max, " "), "@" + String_.PadEnd(itm.Name(), name_max, " ") + ":", itm.Expd());
if (!itm.Pass())
sb.Add_fmt("\n{0} {1} {2} '{3}'", String_.PadEnd("", comp_max, " "), " " + String_.PadEnd("", path_max, " "), " " + String_.PadEnd("", name_max, " ") + " ", itm.Actl());
}
return sb.Xto_str_and_clear();
}
int Max(int max, String s) {int len = String_.Len(s); return len > max ? len : max;}
public static final Tst_chkr Null_chkr = new Tst_chkr_null();
}
class Tst_itm {
public boolean Pass() {return pass;} private boolean pass;
public boolean Skip() {return skip;} private boolean skip;
public String Comp() {return comp;} public Tst_itm Comp_(String v) {comp = v; return this;} private String comp = "";
public String Path() {return path;} public Tst_itm Path_(String v) {path = v; return this;} private String path = "";
public String Name() {return name;} public Tst_itm Name_(String v) {name = v; return this;} private String name = "";
public String Expd() {return expd;} public Tst_itm Expd_(String v) {expd = v; return this;} private String expd = "";
public String Actl() {return actl;} public Tst_itm Actl_(String v) {actl = v; return this;} private String actl = "";
public static Tst_itm eq_(boolean skip, String path, String name, Object expd, Object actl) {
boolean pass = skip ? true : Object_.Eq(expd, actl);
String comp = pass ? "==" : "!=";
String expd_str = Object_.Xto_str_strict_or_null_mark(expd);
String actl_str = Object_.Xto_str_strict_or_null_mark(actl);
if (skip) expd_str = actl_str;
return new_(skip, pass, comp, path, name, expd_str, actl_str);
}
public static Tst_itm fail_(String comp, String path, String name, String expd, String actl) {return new_(false, false, comp, path, name, expd, actl);}
public static Tst_itm new_(boolean skip, boolean pass, String comp, String path, String name, String expd, String actl) {
Tst_itm rv = new Tst_itm();
rv.skip = skip; rv.pass = pass; rv.comp = comp; rv.path = path; rv.name = name;; rv.expd = expd; rv.actl = actl;
return rv;
}
}

View File

@@ -0,0 +1,309 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import gplx.core.btries.*;
import gplx.xowa.parsers.amps.*;
public class Url_encoder implements Url_encoder_interface {
private Url_encoder_itm[] encode_ary = new Url_encoder_itm[256], decode_ary = new Url_encoder_itm[256];
private Bry_bfr tmp_bfr = Bry_bfr.reset_(255);
private Url_encoder anchor_encoder = null;
private Object thread_lock = new Object();
public void Itms_ini(byte primary_encode_marker) {
Url_encoder_itm_hex hex = new Url_encoder_itm_hex(primary_encode_marker);
for (int i = 0; i < 256; i++) {
encode_ary[i] = hex; // default encode to hex
decode_ary[i] = Url_encoder_itm_same._; // default decode to same; needed for files; EX: A!%21.png -> A!!.png;
}
decode_ary[primary_encode_marker] = hex;
}
public void Itms_raw_diff_many(byte primary_encode_marker, int... ary) {
Url_encoder_itm_hex hex = new Url_encoder_itm_hex(primary_encode_marker);
int ary_len = ary.length;
for (int i = 0; i < ary_len; i++) {
encode_ary[ary[i]] = hex;
decode_ary[ary[i]] = hex;
}
decode_ary[primary_encode_marker] = hex;
}
public void Itms_decode_marker(byte decode_marker) {
Url_encoder_itm_hex hex = new Url_encoder_itm_hex(decode_marker);
decode_ary[decode_marker & 0xff] = hex;// PATCH.JAVA:need to convert to unsigned byte
}
public void Itms_decode_diff(byte orig, byte repl) {
decode_ary[orig & 0xff] = new Url_encoder_itm_diff(orig, repl);// PATCH.JAVA:need to convert to unsigned byte
}
public void Itms_raw_same_rng(int bgn, int end) {
for (int i = bgn; i <= end; i++) {
encode_ary[i] = Url_encoder_itm_same._;
decode_ary[i] = Url_encoder_itm_same._;
}
}
public Url_encoder Itms_raw_same_many(int... ary) {
int ary_len = ary.length;
for (int i = 0; i < ary_len; i++) {
encode_ary[ary[i]] = Url_encoder_itm_same._;
decode_ary[ary[i]] = Url_encoder_itm_same._;
}
return this;
}
public void Itms_raw_html_ent(byte src, Btrie_slim_mgr trie) {
Url_encoder_itm_html_ent itm = new Url_encoder_itm_html_ent(trie);
encode_ary[src] = itm;
}
public Url_encoder Itms_raw_diff(byte src, byte trg) {
Url_encoder_itm_diff itm = new Url_encoder_itm_diff(src, trg);
encode_ary[src] = itm;
decode_ary[trg] = itm;
return this;
}
public byte[] Encode_http(Io_url url) {
synchronized (thread_lock) {
tmp_bfr.Add(Io_url.Http_file_bry);
Encode(tmp_bfr, url.RawBry());
return tmp_bfr.Xto_bry_and_clear();
}
}
public String Encode_str(String str) {
synchronized (thread_lock) {
byte[] bry = Bry_.new_u8(str); Encode(tmp_bfr, bry, 0, bry.length); return tmp_bfr.Xto_str_and_clear();
}
}
public byte[] Encode_bry(String str) {
synchronized (thread_lock) {
byte[] bry = Bry_.new_u8(str); Encode(tmp_bfr, bry, 0, bry.length); return tmp_bfr.Xto_bry_and_clear();
}
}
public byte[] Encode(byte[] bry) {Encode(tmp_bfr, bry, 0, bry.length); return tmp_bfr.Xto_bry_and_clear();}
public Bry_bfr Encode(Bry_bfr bfr, byte[] bry) {Encode(bfr, bry, 0, bry.length); return bfr;}
public void Encode(Bry_bfr bfr, byte[] bry, int bgn, int end) {
synchronized (thread_lock) {
for (int i = bgn; i < end; i++) {
byte b = bry[i];
if (anchor_encoder != null && b == Byte_ascii.Hash) {
bfr.Add_byte(Byte_ascii.Hash);
anchor_encoder.Encode(bfr, bry, i + 1, end);
break;
}
Url_encoder_itm itm = encode_ary[b & 0xff];// PATCH.JAVA:need to convert to unsigned byte
i += itm.Encode(bfr, bry, end, i, b);
}
}
}
public String Decode_str(String str) {
synchronized (thread_lock) {
byte[] bry = Bry_.new_u8(str); Decode(bry, 0, bry.length, tmp_bfr, true); return tmp_bfr.Xto_str_and_clear();
}
}
public byte[] Decode(byte[] bry) {
synchronized (thread_lock) {
Decode(bry, 0, bry.length, tmp_bfr, false); return tmp_bfr.Xto_bry_and_clear();
}
}
public byte[] Decode_lax(byte[] bry) {
synchronized (thread_lock) {
Decode(bry, 0, bry.length, tmp_bfr, false); return tmp_bfr.Xto_bry_and_clear();
}
}
public void Decode(byte[] bry, int bgn, int end, Bry_bfr bfr, boolean fail_when_invalid) {
synchronized (thread_lock) {
for (int i = bgn; i < end; i++) {
byte b = bry[i];
if (anchor_encoder != null && b == Byte_ascii.Hash) {
bfr.Add_byte(Byte_ascii.Hash);
anchor_encoder.Decode(bry, i + 1, end, bfr, false);
break;
}
Url_encoder_itm itm = decode_ary[b & 0xff];// PATCH.JAVA:need to convert to unsigned byte
i += itm.Decode(bfr, bry, end, i, b, fail_when_invalid);
}
}
}
private static void mediawiki_base(Url_encoder rv, boolean encode_colon) {
rv.Itms_raw_same_rng(Byte_ascii.Num_0, Byte_ascii.Num_9);
rv.Itms_raw_same_rng(Byte_ascii.Ltr_A, Byte_ascii.Ltr_Z);
rv.Itms_raw_same_rng(Byte_ascii.Ltr_a, Byte_ascii.Ltr_z);
rv.Itms_raw_same_many(Byte_ascii.Dash, Byte_ascii.Dot, Byte_ascii.Underline);
if (encode_colon)
rv.Itms_raw_same_many(Byte_ascii.Colon);
}
public static Url_encoder new_html_id_() {
Url_encoder rv = new Url_encoder();
rv.Itms_ini(Byte_ascii.Dot);
mediawiki_base(rv, true);
rv.Itms_decode_marker(Byte_ascii.Dot);
rv.Itms_raw_diff(Byte_ascii.Space, Byte_ascii.Underline);
rv.Itms_raw_html_ent(Byte_ascii.Amp, Xop_amp_trie._);
return rv;
}
public static Url_encoder new_http_url_() {
Url_encoder rv = new Url_encoder();
rv.Itms_ini(Byte_ascii.Percent);
mediawiki_base(rv, false);
rv.Itms_raw_diff(Byte_ascii.Space, Byte_ascii.Plus);
return rv;
}
public static Url_encoder new_http_url_ttl_() {
Url_encoder rv = new Url_encoder();
rv.Itms_ini(Byte_ascii.Percent);
mediawiki_base(rv, true);
return rv;
}
public static Url_encoder new_http_url_space_is_space() {
Url_encoder rv = new Url_encoder();
rv.Itms_ini(Byte_ascii.Percent);
mediawiki_base(rv, true);
return rv;
}
public static Url_encoder new_fsys_lnx_() {
Url_encoder rv = new Url_encoder();
rv.Itms_ini(Byte_ascii.Percent);
mediawiki_base(rv, true);
rv.Itms_raw_same_many(Byte_ascii.Slash);
rv.Itms_raw_diff(Byte_ascii.Backslash, Byte_ascii.Slash);
return rv;
}
public static Url_encoder new_fsys_wnt_() {
Url_encoder rv = new Url_encoder();
rv.Itms_ini(Byte_ascii.Percent);
rv.Itms_raw_same_rng(Byte_ascii.Num_0, Byte_ascii.Num_9);
rv.Itms_raw_same_rng(Byte_ascii.Ltr_A, Byte_ascii.Ltr_Z);
rv.Itms_raw_same_rng(Byte_ascii.Ltr_a, Byte_ascii.Ltr_z);
rv.Itms_raw_same_many
( Byte_ascii.Bang, Byte_ascii.At, Byte_ascii.Hash, Byte_ascii.Dollar, Byte_ascii.Percent, Byte_ascii.Pow, Byte_ascii.Amp
, Byte_ascii.Plus, Byte_ascii.Eq, Byte_ascii.Underline, Byte_ascii.Dash
, Byte_ascii.Dot, Byte_ascii.Comma
, Byte_ascii.Tick, Byte_ascii.Tilde, Byte_ascii.Brack_bgn, Byte_ascii.Brack_end, Byte_ascii.Curly_bgn, Byte_ascii.Curly_end);
return rv;
}
public static Url_encoder new_file_() {
Url_encoder rv = new Url_encoder();
rv.Itms_ini(Byte_ascii.Percent);
mediawiki_base(rv, true);
return rv;
}
public static Url_encoder new_gfs_() {
Url_encoder rv = new Url_encoder();
rv.Itms_ini(Byte_ascii.Percent);
rv.Itms_raw_same_many(Byte_ascii.Paren_bgn, Byte_ascii.Paren_end, Byte_ascii.Apos, Byte_ascii.Semic);
mediawiki_base(rv, true);
return rv;
}
public static Url_encoder new_html_href_mw_() {
Url_encoder rv = new Url_encoder();
rv.Itms_ini(Byte_ascii.Percent);
mediawiki_base(rv, true);
rv.Itms_raw_diff(Byte_ascii.Space, Byte_ascii.Underline);
rv.Itms_raw_same_many(Byte_ascii.Semic, Byte_ascii.At, Byte_ascii.Dollar, Byte_ascii.Bang, Byte_ascii.Star
, Byte_ascii.Paren_bgn, Byte_ascii.Paren_end, Byte_ascii.Comma, Byte_ascii.Slash, Byte_ascii.Colon
, Byte_ascii.Hash// NOTE: not part of wfUrlEncode; not sure where this is specified; needed for A#b
);
rv.anchor_encoder = new_html_id_();
return rv;
}
public static Url_encoder new_html_href_quotes_() {
Url_encoder rv = new Url_encoder();
rv.Itms_ini(Byte_ascii.Percent);
rv.Itms_raw_same_rng(0, 255); // default everything to same;
rv.Itms_raw_diff_many(Byte_ascii.Percent
, Byte_ascii.Apos, Byte_ascii.Quote, Byte_ascii.Lt, Byte_ascii.Gt); // encode ', ", <, >
rv.Itms_raw_diff(Byte_ascii.Space, Byte_ascii.Underline); // convert " " to "_"
return rv;
}
}
interface Url_encoder_itm {
int Encode(Bry_bfr bfr, byte[] src, int end, int idx, byte b);
int Decode(Bry_bfr bfr, byte[] src, int end, int idx, byte b, boolean fail_when_invalid);
}
class Url_encoder_itm_same implements Url_encoder_itm {
public int Encode(Bry_bfr bfr, byte[] src, int end, int idx, byte b) {bfr.Add_byte(b); return 0;}
public int Decode(Bry_bfr bfr, byte[] src, int end, int idx, byte b, boolean fail_when_invalid) {bfr.Add_byte(b); return 0;}
public static final Url_encoder_itm _ = new Url_encoder_itm_same();
}
class Url_encoder_itm_diff implements Url_encoder_itm {
public Url_encoder_itm_diff(byte orig, byte repl) {this.orig = orig; this.repl = repl;} private byte orig, repl;
public int Encode(Bry_bfr bfr, byte[] src, int end, int idx, byte b) {bfr.Add_byte(repl); return 0;}
public int Decode(Bry_bfr bfr, byte[] src, int end, int idx, byte b, boolean fail_when_invalid) {bfr.Add_byte(orig); return 0;}
}
class Url_encoder_itm_hex implements Url_encoder_itm {
public Url_encoder_itm_hex(byte encode_marker) {this.encode_marker = encode_marker;} private byte encode_marker;
public int Encode(Bry_bfr bfr, byte[] src, int end, int idx, byte b) {Encode_byte(b, bfr, encode_marker); return 0;}
public static void Encode_byte(byte b, Bry_bfr bfr, byte encode_marker) {
int b_int = b & 0xFF;// PATCH.JAVA:need to convert to unsigned byte
bfr.Add_byte(encode_marker);
bfr.Add_byte(HexBytes[b_int >> 4]);
bfr.Add_byte(HexBytes[b_int & 15]);
}
public int Decode(Bry_bfr bfr, byte[] src, int end, int idx, byte b, boolean fail_when_invalid) {
if (idx + 2 >= end) {
if (fail_when_invalid) throw Exc_.new_("decode needs 3 bytes", "idx", idx, "len", end, "snip", String_.new_u8(Bry_.Mid_by_len_safe(src, idx, 3)));
else {
bfr.Add_byte(b);
return 0;
}
}
int hex_val = Int_.Xto_int_hex(src[idx + 1]);
if (hex_val == -1) { // invalid hex byte; EX: %GC; DATE:2014-04-10
bfr.Add_byte(b);
return 0;
}
int v_0 = hex_val * 16;
if (v_0 != -1) {
int v_1 = Int_.Xto_int_hex(src[idx + 2]);
if (v_1 != -1) {
bfr.Add_byte((byte)(v_0 + v_1));
return 2;
}
}
if (fail_when_invalid)
throw Exc_.new_("decode is invalid", "idx", idx, "snip", String_.new_u8(Bry_.Mid_by_len_safe(src, idx, 3)));
else {
bfr.Add_byte(b);
return 0;
}
}
public static final byte[] HexBytes = new byte[]
{ Byte_ascii.Num_0, Byte_ascii.Num_1, Byte_ascii.Num_2, Byte_ascii.Num_3, Byte_ascii.Num_4, Byte_ascii.Num_5, Byte_ascii.Num_6, Byte_ascii.Num_7
, Byte_ascii.Num_8, Byte_ascii.Num_9, Byte_ascii.Ltr_A, Byte_ascii.Ltr_B, Byte_ascii.Ltr_C, Byte_ascii.Ltr_D, Byte_ascii.Ltr_E, Byte_ascii.Ltr_F
};
}
class Url_encoder_itm_html_ent implements Url_encoder_itm {
public Url_encoder_itm_html_ent(Btrie_slim_mgr amp_trie) {this.amp_trie = amp_trie;} Btrie_slim_mgr amp_trie;
public int Encode(Bry_bfr bfr, byte[] src, int end, int idx, byte b) {
++idx; // b is &; get next character afterwards
if (idx == end) { // & is last char; return
Url_encoder_itm_hex.Encode_byte(Byte_ascii.Amp, bfr, Byte_ascii.Dot);
return 0;
}
b = src[idx];
Object o = amp_trie.Match_bgn_w_byte(b, src, idx, end);
if (o == null) { // unknown entity (EX:&unknown;); return &;
Url_encoder_itm_hex.Encode_byte(Byte_ascii.Amp, bfr, Byte_ascii.Dot);
return 0;
}
else {
Xop_amp_trie_itm itm = (Xop_amp_trie_itm)o;
byte[] bry_utf8 = itm.Utf8_bry(); // NOTE: must utf8 encode val; EX: &nbsp; is 160 but must become 192,160
for (int i = 0; i < bry_utf8.length; i++)
Url_encoder_itm_hex.Encode_byte(bry_utf8[i], bfr, Byte_ascii.Dot);
return itm.Xml_name_bry().length - 1; // -1 to ignore & in XmlEntityName
}
}
public int Decode(Bry_bfr bfr, byte[] src, int end, int idx, byte b, boolean fail_when_invalid) {
bfr.Add_byte(b); return 0;
}
}

View File

@@ -0,0 +1,72 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import org.junit.*;
public class Url_encoder_tst {
@Before public void init() {fxt = new Url_encoder_fxt();} Url_encoder_fxt fxt;
@Test public void Id_nums() {fxt.Encoder_id().Test_encode_decode("0123456789", "0123456789");}
@Test public void Id_ltrs_lower() {fxt.Encoder_id().Test_encode_decode("abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");}
@Test public void Id_ltrs_upper() {fxt.Encoder_id().Test_encode_decode("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");}
@Test public void Id_syms() {fxt.Encoder_id().Test_encode("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", ".21.22.23.24.25.26.27.28.29.2A.2B.2C-..2F:.3B.3C.3D.3E.3F.40.5B.5C.5D.5E_.60.7B.7C.7D.7E");} // NOTE: not reversible since "." is encode_marker but not encoded
@Test public void Id_foreign() {fxt.Encoder_id().Test_encode_decode("aéb", "a.C3.A9b");}
@Test public void Id_space() {fxt.Encoder_id().Test_encode_decode("a b", "a_b");}
@Test public void Id_err() {
byte[] raw = Bry_.new_a7("0%.jpg");
Bry_bfr tmp_bfr = Bry_bfr.new_();
fxt.Encoder_id().Encoder().Decode(raw, 0, raw.length, tmp_bfr, false);
Tfds.Eq("0%.jpg", tmp_bfr.Xto_str_and_clear());
}
@Test public void Id_nbsp() {fxt.Encoder_id().Test_encode("a&nbsp;b", "a.C2.A0b");} // NOTE: not just .A0 (160) but utf8-encoded .C2.A0
@Test public void Url_syms() {fxt.Encoder_url().Test_encode_decode("!?^~", "%21%3F%5E%7E");}
@Test public void Url_foreign() {fxt.Encoder_url().Test_encode_decode("aéb", "a%C3%A9b");}
@Test public void Url_space() {fxt.Encoder_url().Test_encode_decode("a b", "a+b");}
@Test public void File_space() {
fxt.Encoder_href().Test_encode("a b", "a_b");
// fxt.Encoder_url().tst_decode("a_b", "a_b");
}
@Test public void Href_special_and_anchor() { // PURPOSE: MediaWiki encodes with % for ttls, but . for anchors; REF:Title.php!(before-anchor)getLocalUrl;wfUrlencode (after-anchor)escapeFragmentForURL
fxt.Encoder_href().Test_encode("^#^", "%5E#.5E");
fxt.Encoder_href().Test_encode("A#", "A#");
fxt.Encoder_href().tst_decode("%5E#.5E", "^#^");
}
@Test public void Fsys_wnt() {
fxt.Encoder_fsys_safe().Test_encode("Help:Options/HTML", "Help%3AOptions%2FHTML");
}
@Test public void Invalid_url_decode() { // PURPOSE: check that invalid url decodings are rendered literally; DATE:2014-04-10
fxt.Encoder_href().Test_encode("%GC", "%25GC");
}
}
class Url_encoder_fxt {
public Url_encoder Encoder() {return encoder;} Url_encoder encoder;
public Url_encoder_fxt Encoder_id() {encoder = Url_encoder.new_html_id_(); return this;}
public Url_encoder_fxt Encoder_href() {encoder = Url_encoder.new_html_href_mw_(); return this;}
public Url_encoder_fxt Encoder_url() {encoder = Url_encoder.new_http_url_(); return this;}
public Url_encoder_fxt Encoder_fsys_safe() {encoder = Url_encoder.new_fsys_wnt_(); return this;}
public void Test_encode_decode(String raw, String encoded) {
Test_encode(raw, encoded);
tst_decode(encoded, raw);
}
public void Test_encode(String raw, String expd) {
byte[] bry = encoder.Encode(Bry_.new_u8(raw));
Tfds.Eq(expd, String_.new_u8(bry));
}
public void tst_decode(String raw, String expd) {
byte[] bry = encoder.Decode(Bry_.new_u8(raw));
Tfds.Eq(expd, String_.new_u8(bry));
}
}