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-05-10 23:00:43 -04:00
parent 0b5aa9aefe
commit 6eec99a713
157 changed files with 2148 additions and 975 deletions

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.core.html.parsers; import gplx.*; import gplx.core.*; import gplx.core.html.*;
class Gfo_html_node {
public Gfo_html_node(byte[] src, int bgn, int end) {this.src = src; this.bgn = bgn; this.end = end;}
public byte[] Src() {return src;} private final byte[] src;
public int Bgn() {return bgn;} private final int bgn;
public int End() {return end;} private final int end;
}

View File

@@ -0,0 +1,68 @@
/*
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.core.html.parsers; import gplx.*; import gplx.core.*; import gplx.core.html.*;
import gplx.core.btries.*; import gplx.core.primitives.*;
import gplx.xowa.*;
class Gfo_html_parser {
private final Gfo_msg_log msg_log = Gfo_msg_log.Test();
private final Xop_xatr_parser xatr_parser = new Xop_xatr_parser();
public void Parse(Gfo_html_wkr handler, byte[] src, int bgn, int end) {
// int src_len = src.length;
// int prv_pos = 0;
// int css_find_bgn_len = Css_find_bgn.length;
// byte[] protocol_prefix_bry = Bry_.new_utf8_(protocol_prefix);
// while (true) {
// int url_bgn = Bry_finder.Find_fwd(src, Css_find_bgn, prv_pos); if (url_bgn == Bry_.NotFound) break; // nothing left; stop
// url_bgn += css_find_bgn_len;
// int url_end = Bry_finder.Find_fwd(src, Byte_ascii.Quote, url_bgn, src_len); if (url_end == Bry_.NotFound) {usr_dlg.Warn_many("", "main_page.css_parse", "could not find css; pos='~{0}' text='~{1}'", url_bgn, String_.new_utf8_len_safe_(src, url_bgn, url_bgn + 32)); break;}
// byte[] css_url_bry = Bry_.Mid(src, url_bgn, url_end);
// css_url_bry = Bry_.Replace(css_url_bry, Css_amp_find, Css_amp_repl); // &amp; -> &
// css_url_bry = url_encoder.Decode(css_url_bry); // %2C -> %7C -> |
// css_url_bry = Bry_.Add(protocol_prefix_bry, css_url_bry);
// rv.Add(String_.new_utf8_(css_url_bry));
// prv_pos = url_end;
// }
// return rv.XtoStrAry();
int src_len = src.length; int pos = 0;
while (pos < src_len) {
byte b = src[pos];
switch (b) {
case Byte_ascii.Angle_bgn:
pos = Parse_node(handler, src, end, pos, pos + 1);
break;
default:
++pos;
break;
}
}
}
private int Parse_node(Gfo_html_wkr handler, byte[] src, int end, int tkn_bgn, int tkn_end) {
int name_bgn = tkn_end;
int name_end = Bry_finder.Find_fwd_until_ws(src, name_bgn, end);
if (name_end == Bry_finder.Not_found) return end; // EOS; EX: "<abcEOS"
if (name_bgn == name_end) return tkn_end; // ws; EX: "< "
Object o = handler.Get_or_null(src, name_bgn, name_end);
if (o == null) return name_end; // unknown name: EX: "<unknown >"
int node_end = Bry_finder.Find_fwd(src, Byte_ascii.Angle_end, name_end, end);
if (node_end == Bry_finder.Not_found) return end; // EOS; EX: "<name lots_of_text_but_no_gt EOS"
Xop_xatr_itm[] xatr_ary = xatr_parser.Parse(msg_log, src, name_end, node_end);
Gfo_html_tkn tkn = (Gfo_html_tkn)o;
tkn.Process(src, Xop_xatr_hash.new_ary(src, xatr_ary));
return node_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.core.html.parsers; import gplx.*; import gplx.core.*; import gplx.core.html.*;
interface Gfo_html_wkr {
Gfo_html_tkn Get_or_null(byte[] src, int bgn, int end);
void Process(Gfo_html_node node);
}

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.core.html.parsers; import gplx.*; import gplx.core.*; import gplx.core.html.*;
import gplx.xowa.*;
interface Gfo_html_tkn {
int Tid();
byte[] Key();
void Process(byte[] src, Xop_xatr_hash hash);
}
class Gfo_html_tkn_ {
public static final int Tid_link = 1;
public static final byte[] Key_link = Bry_.new_ascii_("link");
}
class Gfo_html_tkn__link implements Gfo_html_tkn {
public int Tid() {return Gfo_html_tkn_.Tid_link;}
public byte[] Key() {return Gfo_html_tkn_.Key_link;}
@gplx.Virtual public void Process(byte[] src, Xop_xatr_hash hash) {}
}

View File

@@ -21,7 +21,7 @@ public class Gfo_thread_pool implements GfoInvkAble {
private ListAdp queue = ListAdp_.new_();
private GfoMsg run_msg = GfoMsg_.new_cast_(Invk_run_wkr);
private boolean running = false;
public Gfo_usr_dlg Usr_dlg() {return usr_dlg;} public Gfo_thread_pool Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v; return this;} private Gfo_usr_dlg usr_dlg = Gfo_usr_dlg_.Null;
public Gfo_usr_dlg Usr_dlg() {return usr_dlg;} public Gfo_thread_pool Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v; return this;} private Gfo_usr_dlg usr_dlg = Gfo_usr_dlg_.Noop;
public void Clear() {synchronized (thread_lock) {queue.Clear(); running = false;}}
public Gfo_thread_pool Add_at_end(Gfo_thread_wkr wkr) {
synchronized (thread_lock) {queue.Add(wkr);}

View File

@@ -24,7 +24,7 @@ public class Fsm_cfg_mgr {
}
public void Ctor_by_load() {
Db_cfg_hash hash = Grps_get_or_load(Grp_core);
this.next_id = hash.Get(Key_next_id).To_int_or(-1); if (next_id == -1) throw Err_.new_("next_id not found in cfg");
this.next_id = hash.Get(Key_next_id).To_int_or(-1); if (next_id == -1) throw Err_.new_("next_id not found in cfg; url={0}", tbl.Conn().Conn_info().Xto_api());
this.schema_thm_page = hash.Get(Key_schema_thm_page).To_yn_or_n();
this.patch__next_id = hash.Get(Key_patch__next_id).To_yn_or_n();
this.patch__page_gt_1 = hash.Get(Key_patch__page_gt_1).To_yn_or_n();

View File

@@ -46,8 +46,8 @@ public class Gfui_bnd_parser {
private String Convert(boolean src_is_gfui, String src_str) {
this.src = Bry_.new_utf8_(src_str); this.src_len = src.length;
tkns.Clear(); mod_val = Mod_val_null;
int pos = 0; int itm_bgn = -1, itm_end = -1;
while (pos <= src_len) { // loop over bytes and break up tkns by symbols
int pos = 0; int itm_bgn = -1, itm_end = -1; boolean is_numeric = false;
while (pos <= src_len) { // loop over bytes and break up tkns by symbols
byte b = pos == src_len ? Byte_ascii.NewLine: src[pos]; // treat eos as "\n" for purpose of separating tokens
Gfui_bnd_tkn sym_tkn = null;
switch (b) {
@@ -68,6 +68,11 @@ public class Gfui_bnd_parser {
itm_end = pos;
++pos;
continue;
case Byte_ascii.Hash:
if (is_numeric) throw Err_.new_("multiple numeric symbols in keycode");
is_numeric = true;
++pos;
continue;
default: // letter / number; continue
if (itm_bgn == -1) // no word started; start it
itm_bgn = pos;
@@ -76,7 +81,8 @@ public class Gfui_bnd_parser {
}
if (itm_end == -1) // end not set by space; char before symbol is end
itm_end = pos;
Process_sym(src_is_gfui, sym_tkn, itm_bgn, itm_end);
Process_sym(src_is_gfui, is_numeric, sym_tkn, itm_bgn, itm_end);
is_numeric = false;
if (sym_tkn.Tid() == Gfui_bnd_tkn.Tid_sym_eos)
break;
else
@@ -90,9 +96,21 @@ public class Gfui_bnd_parser {
}
return tmp_bfr.Xto_str_and_clear();
}
private void Process_sym(boolean src_is_gfui, Gfui_bnd_tkn sym_tkn, int itm_bgn, int itm_end) {
private void Process_sym(boolean src_is_gfui, boolean is_numeric, Gfui_bnd_tkn sym_tkn, int itm_bgn, int itm_end) {
Hash_adp_bry regy = src_is_gfui ? gfui_regy : norm_regy;
Gfui_bnd_tkn tkn = (Gfui_bnd_tkn)regy.Get_by_mid(src, itm_bgn, itm_end);
Gfui_bnd_tkn tkn = null;
if (is_numeric) { // EX: "key.#10" or "#10"
int tkn_bgn = itm_bgn;
if (src_is_gfui) { // remove "key." in "key.#10"
tkn_bgn = Bry_finder.Move_fwd(src, Byte_ascii.Dot, itm_bgn, itm_end);
if (tkn_bgn == -1) throw Err_.new_("invalid keycode.dot: keycode={0}", Bry_.Mid(src, tkn_bgn, itm_end));
++tkn_bgn; // skip #
}
int keycode = Bry_.Xto_int_or(src, tkn_bgn, itm_end, -1); if (keycode == -1) throw Err_.new_("invalid keycode: keycode={0}", Bry_.Mid(src, tkn_bgn, itm_end));
tkn = new Gfui_bnd_tkn(Gfui_bnd_tkn.Tid_key, keycode, Bry_.Empty, Bry_.Empty);
}
else
tkn = (Gfui_bnd_tkn)regy.Get_by_mid(src, itm_bgn, itm_end);
if (tkn == null) return;
int mod_adj = Mod_val_null;
switch (tkn.Tid()) {
@@ -103,7 +121,7 @@ public class Gfui_bnd_parser {
case Gfui_bnd_tkn.Tid_mod_as: mod_adj = Gfui_bnd_tkn.Tid_mod_as; break;
case Gfui_bnd_tkn.Tid_mod_ca: mod_adj = Gfui_bnd_tkn.Tid_mod_ca; break;
case Gfui_bnd_tkn.Tid_mod_cas: mod_adj = Gfui_bnd_tkn.Tid_mod_cas; break;
case Gfui_bnd_tkn.Tid_key: break;
case Gfui_bnd_tkn.Tid_key: break;
default: throw Err_.unhandled(tkn.Tid());
}
switch (sym_tkn.Tid()) {
@@ -187,6 +205,7 @@ public class Gfui_bnd_parser {
Init_itm("key.tab", "Tab");
Init_itm("key.clear", "Clear");
Init_itm("key.enter", "Enter");
Init_itm("key.keypad_enter", "Keypad Enter");
Init_itm("key.shiftKey", "ShiftKey");
Init_itm("key.ctrlKey", "CtrlKey");
Init_itm("key.altKey", "AltKey");
@@ -232,21 +251,30 @@ public class Gfui_bnd_parser {
private void Init_itm(byte tid, String gfui, String norm) {
byte[] gfui_bry = Bry_.new_utf8_(gfui);
byte[] norm_bry = Bry_.new_utf8_(norm);
Gfui_bnd_tkn itm = new Gfui_bnd_tkn(tid, gfui_bry, norm_bry);
Gfui_bnd_tkn itm = new Gfui_bnd_tkn(tid, Gfui_bnd_tkn.Keycode_null, gfui_bry, norm_bry);
gfui_regy.Add(gfui_bry, itm);
norm_regy.Add_if_new(norm_bry, itm);
}
private static final int Mod_val_null = 0;
public static Gfui_bnd_parser new_en_() {return new Gfui_bnd_parser().Init_en();} Gfui_bnd_parser() {}
private static Gfui_bnd_tkn new_sym_(byte tid, byte[] bry) {return new Gfui_bnd_tkn(tid, bry, bry);}
private static Gfui_bnd_tkn new_mod_(byte tid, String gfui, String norm) {return new Gfui_bnd_tkn(tid, Bry_.new_ascii_(gfui), Bry_.new_ascii_(norm));}
private static Gfui_bnd_tkn new_sym_(byte tid, byte[] bry) {return new Gfui_bnd_tkn(tid, Gfui_bnd_tkn.Keycode_null, bry, bry);}
private static Gfui_bnd_tkn new_mod_(byte tid, String gfui, String norm) {return new Gfui_bnd_tkn(tid, Gfui_bnd_tkn.Keycode_null, Bry_.new_ascii_(gfui), Bry_.new_ascii_(norm));}
}
class Gfui_bnd_tkn {
public Gfui_bnd_tkn(byte tid, byte[] gfui, byte[] norm) {this.tid = tid; this.bry_gfui = gfui; this.bry_norm = norm;}
public byte Tid() {return tid;} private byte tid;
public byte[] Bry_gfui() {return bry_gfui;} private byte[] bry_gfui;
public byte[] Bry_norm() {return bry_norm;} private byte[] bry_norm;
public Gfui_bnd_tkn(byte tid, int keycode, byte[] gfui, byte[] norm) {
this.tid = tid; this.keycode = keycode; ; this.bry_gfui = gfui; this.bry_norm = norm;
}
public byte Tid() {return tid;} private final byte tid;
public int Keycode() {return keycode;} private final int keycode;
public byte[] Bry_gfui() {return bry_gfui;} private final byte[] bry_gfui;
public byte[] Bry_norm() {return bry_norm;} private final byte[] bry_norm;
public void Write(Bry_bfr bfr, boolean src_is_gfui) {
if (keycode != Gfui_bnd_tkn.Keycode_null) {
if (src_is_gfui)
bfr.Add(Bry_key_prefix);
bfr.Add_byte(Byte_ascii.Hash).Add_int_variable(keycode);
return;
}
byte[] bry = src_is_gfui ? bry_gfui : bry_norm;
switch (tid) {
case Tid_mod_c: case Tid_mod_a: case Tid_mod_s:
@@ -283,4 +311,6 @@ class Gfui_bnd_tkn {
, Tid_sym_plus = 8 , Tid_sym_pipe = 9 , Tid_sym_comma = 10, Tid_sym_eos = 11
, Tid_key = 12
;
public static final int Keycode_null = 0;
private static final byte[] Bry_key_prefix = Bry_.new_ascii_("key.");
}

View File

@@ -41,6 +41,10 @@ public class Gfui_bnd_parser_tst {
fxt.Test_x_to_gfui("Ctrl + Shift + A" , "mod.cs+key.a");
fxt.Test_x_to_gfui("Ctrl + Alt + Shift + A" , "mod.cas+key.a");
}
@Test public void Keypad_enter() {
fxt.Test_x_to_norm("key.keypad_enter" , "Keypad Enter");
fxt.Test_x_to_norm("mod.c+key.keypad_enter" , "Ctrl + Keypad Enter");
}
}
class Gfui_bnd_parser_fxt {
private Gfui_bnd_parser parser;

View File

@@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa; import gplx.*;
import gplx.xowa.apps.*; import gplx.xowa.apps.fsys.*;
import gplx.xowa.bldrs.css.*;
import gplx.xowa.files.caches.*; import gplx.xowa.files.imgs.*;
import gplx.xowa.urls.encoders.*;
import gplx.xowa.wmfs.*;

View File

@@ -26,16 +26,14 @@ public class Xoa_app_ {
boot_mgr.Run(args);
}
public static final String Name = "xowa";
public static final String Version = "2.5.1.1";
public static final String Version = "2.5.2.1";
public static String Build_date = "2012-12-30 00:00:00";
public static String Op_sys;
public static String User_agent = "";
public static final Gfo_msg_grp Nde = Gfo_msg_grp_.prj_(Name);
public static Gfo_usr_dlg usr_dlg_console_() {
Gfo_usr_dlg rv = new Gfo_usr_dlg_base();
rv.Ui_wkr_(Gfo_usr_dlg_ui_.Console);
rv.Log_wtr_(new Gfo_log_wtr_base());
rv.Log_wtr().Queue_enabled_(true);
Gfo_usr_dlg rv = new Gfo_usr_dlg_base(new Gfo_usr_dlg__log_base(), Gfo_usr_dlg__gui_.Console);
rv.Log_wkr().Queue_enabled_(true);
return rv;
}
public static Gfo_usr_dlg Usr_dlg() {return usr_dlg;} public static void Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v;} private static Gfo_usr_dlg usr_dlg;
@@ -45,7 +43,7 @@ public class Xoa_app_ {
public static Xoa_gfs_mgr Gfs_mgr() {return gfs_mgr;} public static void Gfs_mgr_(Xoa_gfs_mgr v) {gfs_mgr = v;} private static Xoa_gfs_mgr gfs_mgr;
}
class Xoa_app_boot_mgr {
private Gfo_usr_dlg usr_dlg; private Gfo_log_wtr log_wtr; private String chkpoint = "null";
private Gfo_usr_dlg usr_dlg; private Gfo_usr_dlg__log log_wtr; private String chkpoint = "null";
public void Run(String[] args) {
try {
if (!Init_env(args)) return;
@@ -54,7 +52,7 @@ class Xoa_app_boot_mgr {
}
catch (Exception e) {
String err_str = Err_.Message_gplx(e);
log_wtr.Log_err(err_str);
log_wtr.Log_to_err(err_str);
ConsoleAdp._.WriteLine(err_str);
if (log_wtr.Log_dir() == null) log_wtr.Log_dir_(Env_.AppUrl().OwnerDir().GenSubFil("xowa.log"));
log_wtr.Queue_enabled_(false);
@@ -62,12 +60,12 @@ class Xoa_app_boot_mgr {
}
private boolean Init_env(String[] args) {
Gfo_usr_dlg_.I = usr_dlg = Xoa_app_.usr_dlg_console_();
log_wtr = usr_dlg.Log_wtr(); log_wtr.Log_msg_to_session_fmt("env.init: version=~{0}", Xoa_app_.Version);
log_wtr = usr_dlg.Log_wkr(); log_wtr.Log_to_session_fmt("env.init: version=~{0}", Xoa_app_.Version);
GfuiEnv_.Init_swt(args, Xoa_app_.class);
Io_url jar_url = Env_.AppUrl();
Xoa_app_.Build_date = Io_mgr._.QueryFil(jar_url).ModifiedTime().XtoUtc().XtoStr_fmt("yyyy-MM-dd HH:mm");
log_wtr.Log_msg_to_session_fmt("env.init: jar_url=~{0}; build_date=~{1}", jar_url.NameAndExt(), Xoa_app_.Build_date);
log_wtr.Log_msg_to_session_fmt("env.init: op_sys=~{0}", Op_sys.Cur().Xto_str());
log_wtr.Log_to_session_fmt("env.init: jar_url=~{0}; build_date=~{1}", jar_url.NameAndExt(), Xoa_app_.Build_date);
log_wtr.Log_to_session_fmt("env.init: op_sys=~{0}", Op_sys.Cur().Xto_str());
chkpoint = "init_env";
return true;
}
@@ -142,7 +140,7 @@ class Xoa_app_boot_mgr {
// init app
Db_conn_bldr.I.Reg_default_sqlite();
app = new Xoae_app(usr_dlg, app_type, root_dir, wiki_dir, root_dir.GenSubDir("file"), user_dir, root_dir.GenSubDir_nest("user", "anonymous", "wiki"), Xoa_app_.Op_sys);
usr_dlg.Log_wtr().Queue_enabled_(false); log_wtr.Log_msg_to_session_fmt("app.init");
usr_dlg.Log_wkr().Queue_enabled_(false); log_wtr.Log_to_session_fmt("app.init");
try {
app.Sys_cfg().Lang_(System_lang());
if (launch_url != null)
@@ -153,7 +151,7 @@ class Xoa_app_boot_mgr {
app.Init_by_app(); chkpoint = "init_gfs";
}
catch (Exception e) {usr_dlg.Warn_many("", "", "app init failed: ~{0} ~{1}", chkpoint, Err_.Message_gplx(e));}
app.Usr_dlg().Log_wtr_(app.Log_wtr()); // NOTE: log_wtr must be set for cmd-line (else process will fail);
app.Usr_dlg().Log_wkr_(app.Log_wtr()); // NOTE: log_wtr must be set for cmd-line (else process will fail);
// run gfs
gplx.xowa.users.prefs.Prefs_rename_mgr._.Check(app.User().Fsys_mgr().App_data_cfg_user_fil());

View File

@@ -25,8 +25,8 @@ public class Xoa_app_fxt {
}
public static Xoae_app app_(String op_sys, Io_url root_dir) {
Io_url user_dir = root_dir.GenSubDir_nest("user", "test_user");
Gfo_log_wtr_base._.Log_dir_(user_dir.GenSubDir_nest("tmp", "current"));
Xoae_app app = new Xoae_app(Gfo_usr_dlg_base.test_(), Xoa_app_type.Itm_cmd, root_dir, root_dir.GenSubDir("wiki"), root_dir.GenSubDir("file"), user_dir, root_dir.GenSubDir_nest("user", "anonymous", "wiki"), op_sys);
Gfo_usr_dlg__log_base._.Log_dir_(user_dir.GenSubDir_nest("tmp", "current"));
Xoae_app app = new Xoae_app(Gfo_usr_dlg_.Test(), Xoa_app_type.Itm_cmd, root_dir, root_dir.GenSubDir("wiki"), root_dir.GenSubDir("file"), user_dir, root_dir.GenSubDir_nest("user", "anonymous", "wiki"), op_sys);
app.Setup_mgr().Dump_mgr().Data_storage_format_(gplx.ios.Io_stream_.Tid_raw); // TEST: set data_storage_format to file, else bldr tests will fails (expects plain text)
GfsCore._.Clear(); // NOTE: must clear
GfsCore._.AddCmd(app, Xoae_app.Invk_app); // NOTE: must add app to GfsCore; app.Gfs_mgr() always adds current app to GfsCore; note this causes old test to leave behind GfsCore for new test

View File

@@ -19,6 +19,7 @@ package gplx.xowa; import gplx.*;
import gplx.core.btries.*; import gplx.core.flds.*; import gplx.ios.*; import gplx.core.threads.*;
import gplx.xowa.apps.*; import gplx.xowa.apps.caches.*; import gplx.xowa.apps.fsys.*; import gplx.xowa.apis.*; import gplx.xowa.urls.encoders.*; import gplx.xowa.apps.progs.*;
import gplx.xowa.langs.*; import gplx.xowa.specials.*; import gplx.xowa.cfgs2.*;
import gplx.xowa.bldrs.css.*;
import gplx.xowa.files.caches.*; import gplx.xowa.files.imgs.*;
import gplx.xowa.wikis.*; import gplx.xowa.users.*; import gplx.xowa.gui.*; import gplx.xowa.cfgs.*; import gplx.xowa.ctgs.*; import gplx.xowa.html.tocs.*; import gplx.xowa.fmtrs.*; import gplx.xowa.html.*;
import gplx.xowa.html.wtrs.*;
@@ -32,7 +33,7 @@ public class Xoae_app implements Xoa_app, GfoInvkAble {
this.app_type = app_type;
Io_url.Http_file_str_encoder = Xoa_app_.Utl__encoder_mgr().Fsys();
fsys_mgr = new Xoa_fsys_mgr(bin_dir_name, root_dir, wiki_dir, file_dir, css_dir);
log_wtr = usr_dlg.Log_wtr();
log_wtr = usr_dlg.Log_wkr();
cfg_mgr = new Xoa_cfg_mgr(this);
api_root = new Xoapi_root(this);
user = new Xou_user(this, user_dir);
@@ -84,7 +85,7 @@ public class Xoae_app implements Xoa_app, GfoInvkAble {
public Xoapi_root Api_root() {return api_root;} private Xoapi_root api_root;
public Xop_tkn_mkr Tkn_mkr() {return tkn_mkr;} private Xop_tkn_mkr tkn_mkr = new Xop_tkn_mkr();
public Gfo_usr_dlg Usr_dlg() {return Xoa_app_.Usr_dlg();}
public Gfo_log_wtr Log_wtr() {return log_wtr;} private Gfo_log_wtr log_wtr;
public Gfo_usr_dlg__log Log_wtr() {return log_wtr;} private Gfo_usr_dlg__log log_wtr;
public Xoa_gfs_mgr Gfs_mgr() {return Xoa_app_.Gfs_mgr();}
public Xoa_special_mgr Special_mgr() {return special_mgr;} private Xoa_special_mgr special_mgr = new gplx.xowa.specials.Xoa_special_mgr();
public Xoh_html_mgr Html_mgr() {return html_mgr;} private Xoh_html_mgr html_mgr;
@@ -131,7 +132,6 @@ public class Xoae_app implements Xoa_app, GfoInvkAble {
stage = Xoa_stage_.Tid_init;
prog_mgr.Init_by_app(url_cmd_eval);
xtn_mgr.Init_by_app(this);
log_wtr.Init();
gui_mgr.Init_by_app();
user.Init_by_app(this);
file_mgr.Init_by_app(this);
@@ -162,7 +162,7 @@ public class Xoae_app implements Xoa_app, GfoInvkAble {
if (!gui_mgr.Browser_win().Tab_mgr().Tabs__pub_close_all()) return false;
gui_mgr.Browser_win().Usr_dlg().Canceled_y_();
user.App_term(); usr_dlg.Log_many("", "", "term:app_term");
log_wtr.Term(); usr_dlg.Log_many("", "", "term:log_wtr");
log_wtr.Log_term(); usr_dlg.Log_many("", "", "term:log_wtr");
log_mgr.Rls(); usr_dlg.Log_many("", "", "term:log_mgr");
if (Scrib_core.Core() != null) {Scrib_core.Core().Term(); usr_dlg.Log_many("", "", "term:scrib");}
wiki_mgr.Rls(); usr_dlg.Log_many("", "", "term:wiki_mgr");

View File

@@ -17,11 +17,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.apis.xowa.gui.browsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.apis.*; import gplx.xowa.apis.xowa.*; import gplx.xowa.apis.xowa.gui.*;
import gplx.gfui.*; import gplx.xowa.gui.views.*;
public class Xoapi_info implements Gfo_usr_dlg_ui_opt, GfoInvkAble {
public class Xoapi_info implements Gfo_usr_dlg__gui__opt, GfoInvkAble {
public void Init_by_kit(Xoae_app app) {this.app = app;} private Xoae_app app;
private Xog_win_itm Win() {return app.Gui_mgr().Browser_win();}
public void Focus() {this.Win().Info_box().Focus();}
public void Clear() {app.Usr_dlg().Ui_wkr().Clear();}
public void Clear() {app.Usr_dlg().Gui_wkr().Clear();}
public void Launch() {
Io_url session_fil = app.Log_wtr().Session_fil();
app.Prog_mgr().App_view_text().Run(session_fil);

View File

@@ -48,7 +48,7 @@ public class Xoa_gfs_mgr implements GfoInvkAble, GfoInvkRootWkr {
public Gfs_wtr Wtr() {return wtr;} private Gfs_wtr wtr = new Gfs_wtr();
public void Run_url(Io_url url) {
Run_url_for(GfsCore._.Root(), url);
Gfo_usr_dlg_.I.Log_wtr().Log_msg_to_session_fmt("gfs.done: ~{0}", url.Raw());
Gfo_usr_dlg_.I.Log_wkr().Log_to_session_fmt("gfs.done: ~{0}", url.Raw());
}
public void Run_url_for(GfoInvkAble invk, Io_url url) {
String raw = Io_mgr._.LoadFilStr_args(url).MissingIgnored_().Exec(); if (String_.Len_eq_0(raw)) return;

View File

@@ -30,7 +30,7 @@ class Xoa_setup_mgr_fxt {
public void Test_delete_old_dir(String dir_str, String version_prv, String version_del, boolean expd) {
Io_url dir = Io_url_.new_fil_(dir_str);
Io_mgr._.CreateDirIfAbsent(dir);
Xoa_setup_mgr.Delete_old_dir(Gfo_usr_dlg_.Null, version_prv, version_del, dir);
Xoa_setup_mgr.Delete_old_dir(Gfo_usr_dlg_.Noop, version_prv, version_del, dir);
Tfds.Eq(expd, !Io_mgr._.ExistsDir(dir), version_prv + "|" + version_del);
}
}

View File

@@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.bldrs.cmds.texts; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.cmds.*;
import gplx.xowa.wikis.*; import gplx.xowa.xtns.wdatas.*; import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.xmls.*;
import gplx.xowa.bldrs.css.*;
public abstract class Xob_init_base implements Xob_cmd, GfoInvkAble {
private Xob_bldr bldr; private Xowe_wiki wiki; private Gfo_usr_dlg usr_dlg;
private byte wbase_enabled = Bool_.__byte;

View File

@@ -35,22 +35,22 @@ public abstract class Xob_search_base extends Xob_itm_dump_base implements Xobd_
public void Wkr_run(Xowd_page_itm page) {
// if (page.Ns_id() != Xow_ns_.Id_main) return; // limit to main ns for now
try {
byte[] ttl = page.Ttl_page_db();
byte[][] words = Split_ttl_into_words(lang, list, dump_bfr, ttl);
Xob_tmp_wtr wtr = tmp_wtr_mgr.Get_or_new(ns_main == null ? page.Ns() : ns_main);
int words_len = words.length;
int row_len = 0;
for (int i = 0; i < words_len; i++) {
byte[] word = words[i];
row_len += word.length + 13; // 13=5(id) + 5(page_len) + 3(dlms)
}
if (wtr.FlushNeeded(row_len)) wtr.Flush(bldr.Usr_dlg());
for (int i = 0; i < words_len; i++) {
byte[] word = words[i];
wtr.Bfr() .Add(word) .Add_byte(Byte_ascii.Pipe)
.Add_base85_len_5(page.Id()) .Add_byte(Byte_ascii.Semic)
.Add_base85_len_5(page.Text().length) .Add_byte(Byte_ascii.NewLine);
}
byte[] ttl = page.Ttl_page_db();
byte[][] words = Split_ttl_into_words(lang, list, dump_bfr, ttl);
Xob_tmp_wtr wtr = tmp_wtr_mgr.Get_or_new(ns_main == null ? page.Ns() : ns_main);
int words_len = words.length;
int row_len = 0;
for (int i = 0; i < words_len; i++) {
byte[] word = words[i];
row_len += word.length + 13; // 13=5(id) + 5(page_len) + 3(dlms)
}
if (wtr.FlushNeeded(row_len)) wtr.Flush(bldr.Usr_dlg());
for (int i = 0; i < words_len; i++) {
byte[] word = words[i];
wtr.Bfr() .Add(word) .Add_byte(Byte_ascii.Pipe)
.Add_base85_len_5(page.Id()) .Add_byte(Byte_ascii.Semic)
.Add_base85_len_5(page.Text().length) .Add_byte(Byte_ascii.NewLine);
}
} catch (Exception e) {bldr.Usr_dlg().Warn_many("", "", "search_index:fatal error: err=~{0}", Err_.Message_gplx_brief(e));} // never let single page crash entire import
}
public void Wkr_end() {

View File

@@ -1,118 +0,0 @@
/*
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.xowa.bldrs.cmds.texts; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.cmds.*;
import gplx.core.btries.*; import gplx.xowa.langs.cases.*;
class Xob_word_parser {
private final Btrie_slim_mgr trie = Btrie_slim_mgr.cs_();
private final Bry_bfr bfr = Bry_bfr.new_(32);
private Xob_word_mgr word_mgr; private Xol_case_mgr case_mgr;
private byte[] src; // private int bgn, end, src_len;
private boolean dirty; private int word_bgn;
public void Init_for_ttl(Xob_word_mgr word_mgr, Xol_case_mgr case_mgr) {
this.word_mgr = word_mgr; this.case_mgr = case_mgr;
trie.Clear();
Init_tkn(Xob_word_tkn.new_(" ").Split_y_());
Init_tkn(Xob_word_tkn.new_("_").Split_y_());
Init_tkn(Xob_word_tkn.new_("..").Split_y_().Extend_y_());
}
private void Init_tkn(Xob_word_tkn tkn) {trie.Add_obj(tkn.Key(), tkn);}
private void Mgr__add(int word_end) {
byte[] word = dirty ? bfr.Xto_bry_and_clear() : Bry_.Mid(src, word_bgn, word_end);
word_mgr.Add(word);
word_bgn = -1;
}
public void Parse(byte[] src, int bgn, int end, int src_len) {
this.src = src; // this.bgn = bgn; this.end = end; this.src_len = src_len;
this.dirty = false; this.word_bgn = -1;
this.src = case_mgr.Case_build_lower(src);
int pos = bgn;
while (true) {
boolean add_to_word = false;
boolean is_last = pos == end;
if (is_last) { // do split
Mgr__add(end);
break;
}
byte b = src[pos];
Object o = trie.Match_bgn_w_byte(b, src, pos, end);
int new_pos = -1;
if (o == null) { // unknown sequence; word-char
add_to_word = true;
new_pos = pos + 1;
}
else {
int tkn_end = trie.Match_pos();
Xob_word_tkn tkn = (Xob_word_tkn)o;
if (tkn.Split()) { // "A b" -> "A", "b"
add_to_word = false;
if (word_bgn != -1) // handle sequences like "... " where "..." sets word_bgn to -1
Mgr__add(pos);
tkn_end = Bry_finder.Find_fwd_while(src, tkn_end, end, tkn.Key_last_byte());
if (tkn.Extend()) {
word_bgn = pos;
Mgr__add(tkn_end);
}
pos = tkn_end;
continue;
}
add_to_word = true;
new_pos = tkn_end;
}
if (add_to_word) {
if (dirty)
bfr.Add_byte(src[pos]);
else {
if (word_bgn == -1)
word_bgn = pos;
}
}
pos = new_pos;
}
}
}
class Xob_word_tkn {
public Xob_word_tkn(byte[] key) {this.key = key; this.key_last_byte = key[key.length - 1];}
public byte[] Key() {return key;} private final byte[] key;
public byte Key_last_byte() {return key_last_byte;} private final byte key_last_byte;
public boolean Split() {return split;} public Xob_word_tkn Split_y_() {split = true; return this;} private boolean split;
public boolean Extend() {return extend;} public Xob_word_tkn Extend_y_() {extend = true; return this;} private boolean extend;
public static Xob_word_tkn new_(String v) {return new Xob_word_tkn(Bry_.new_utf8_(v));}
}
class Xob_word_mgr {
private final OrderedHash hash = OrderedHash_.new_bry_();
public void Clear() {hash.Clear();}
public int Len() {return hash.Count();}
public Xob_word_itm Get_at(int i) {return (Xob_word_itm)hash.FetchAt(i);}
public void Add(byte[] word) {
Xob_word_itm itm = (Xob_word_itm)hash.Fetch(word);
if (itm == null) {
itm = new Xob_word_itm(word);
hash.Add(word, itm);
}
itm.Count_add_1_();
}
}
class Xob_word_itm {
public Xob_word_itm(byte[] word) {
this.word = word;
this.count = 0;
}
public byte[] Word() {return word;} private final byte[] word;
public int Count() {return count;} private int count; public void Count_add_1_() {++count;}
@gplx.Internal protected Xob_word_itm Count_(int v) {this.count = v; return this;}
}

View File

@@ -1,102 +0,0 @@
/*
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.xowa.bldrs.cmds.texts; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.cmds.*;
import org.junit.*; import gplx.xowa.langs.cases.*;
public class Xob_word_parser_tst {
private final Xob_word_parser_fxt fxt = new Xob_word_parser_fxt();
@Before public void init() {fxt.Init();}
@Test public void Basic_1() {
fxt.Clear().Test_split("abcd", "abcd");
}
@Test public void Basic_many() {
fxt.Clear().Test_split("abc d ef", "abc", "d", "ef");
}
@Test public void Split_many() {
fxt.Clear().Test_split("a b", "a", "b");
}
@Test public void Lowercase() {
fxt.Clear().Test_split("A B C", "a", "b", "c");
}
@Test public void Dupe() {
fxt.Clear().Test_split("a a a", fxt.Make_word("a", 3));
}
@Test public void Dupe_lowercase() {
fxt.Clear().Test_split("a A", fxt.Make_word("a", 2));
}
@Test public void Dot_acronym() { // EX: "History of U.S.A. Science "
fxt.Clear().Test_split("abc D.E.F. ghi", "abc", "d.e.f.", "ghi");
}
@Test public void Dot_name() { // EX: "H. G. Wells"
fxt.Clear().Test_split("a. b. last", "a.", "b.", "last");
}
@Test public void Dot_internet() { // EX: "en.wikipedia.org"
fxt.Clear().Test_split("a.com", "a.com");
}
@Test public void Dot_ellipsis() { // EX: "Nights into Dreams..."
fxt.Clear().Test_split("a... bc d", "a", "...", "bc", "d");
}
// tst_Split("a-b.c", "a", "b", "c");
// tst_Split("a A", "a");
// tst_Split("a_b", "a", "b");
// tst_Split("a (b)", "a", "b");
}
class Xob_word_parser_fxt {
private final Xob_word_parser word_parser = new Xob_word_parser();
private final Xob_word_mgr word_mgr = new Xob_word_mgr();
private final Bry_bfr tmp_bfr = Bry_bfr.new_(32);
private Xol_case_mgr case_mgr;
public void Init() {
case_mgr = Xol_case_mgr_.Ascii();
word_parser.Init_for_ttl(word_mgr, case_mgr);
}
public Xob_word_parser_fxt Clear() {
word_mgr.Clear();
return this;
}
public Xob_word_itm Make_word(String raw, int count) {return new Xob_word_itm(Bry_.new_utf8_(raw)).Count_(count);}
public void Test_split(String src, String... expd_words) {
int len = expd_words.length;
Xob_word_itm[] ary = new Xob_word_itm[len];
for (int i = 0; i < len; ++i) {
ary[i] = Make_word(expd_words[i], 1);
}
Test_split(src, ary);
}
public void Test_split(String src, Xob_word_itm... expd_words) {
byte[] src_bry = Bry_.new_utf8_(src);
word_parser.Parse(src_bry, 0, src_bry.length, src_bry.length);
Tfds.Eq_str_lines(To_str(expd_words), To_str(word_mgr));
}
private String To_str(Xob_word_itm[] word_ary) {
int len = word_ary.length;
for (int i = 0; i < len; ++i) {
if (i != 0) tmp_bfr.Add_byte_nl();
Xob_word_itm word = word_ary[i];
tmp_bfr.Add(word.Word()).Add_byte_pipe();
tmp_bfr.Add_int_variable(word.Count());
}
return tmp_bfr.Xto_str_and_clear();
}
private String To_str(Xob_word_mgr word_mgr) {
int len = word_mgr.Len();
Xob_word_itm[] ary = new Xob_word_itm[len];
for (int i = 0; i < len; ++i)
ary[i] = word_mgr.Get_at(i);
return To_str(ary);
}
}

View File

@@ -36,7 +36,7 @@ public class Xob_css_cmd implements Xob_cmd {
core_db.Tbl__css_core().Create_tbl();
core_db.Tbl__css_file().Create_tbl();
gplx.xowa.html.css.Xowd_css_core_mgr.Set(core_db.Tbl__css_core(), core_db.Tbl__css_file(), css_dir, css_key);
core_db.Tbl__cfg().Update_yn(Xow_cfg_consts.Grp__wiki_schema, Xowd_db_file_schema_props.Key__tbl_css_core, Bool_.Y);
core_db.Tbl__cfg().Upsert_yn(Xow_cfg_consts.Grp__wiki_schema, Xowd_db_file_schema_props.Key__tbl_css_core, Bool_.Y);
core_db.Conn().Txn_end();
usr_dlg.Plog_many("", "", Cmd_key() + ":end;");
}

View File

@@ -25,7 +25,7 @@ public class Xob_search_sql_cmd extends Xob_itm_basic_base implements Xob_cmd {
public void Cmd_bgn(Xob_bldr bldr) {}
public void Cmd_run() {this.Exec(wiki);}
public void Cmd_end() {}
public void Cmd_term() {}
public void Cmd_term() {}
public void Exec(Xowe_wiki wiki) {
if (!Env_.Mode_testing()) wiki.Init_assert();
Xowd_db_mgr db_mgr = wiki.Db_mgr_as_sql().Core_data_mgr();

View File

@@ -54,3 +54,40 @@ public class Xob_search_sql_wkr extends Xob_search_base implements Io_make_cmd {
search_word_tbl.Ddl__page_count__cfg(search_db.Tbl__cfg());
}
}
class Xob_search_wkr extends Xob_itm_basic_base implements Xobd_wkr {
private Xowd_db_file search_db; private Xowd_search_temp_tbl search_temp_tbl;
private Xol_lang lang; private final Bry_bfr tmp_bfr = Bry_bfr.new_(255); private final OrderedHash list = OrderedHash_.new_bry_();
public String Wkr_key() {return Xob_cmd_keys.Key_text_search_wkr;}
public void Wkr_ini(Xob_bldr bldr) {}
public void Wkr_bgn(Xob_bldr bldr) {
if (!Env_.Mode_testing()) wiki.Init_assert();
this.lang = wiki.Lang();
Xowd_db_mgr db_mgr = wiki.Db_mgr_as_sql().Core_data_mgr();
this.search_db = Xob_search_sql_cmd.Dbs__get_or_make(db_mgr);
this.search_temp_tbl = new Xowd_search_temp_tbl(search_db.Conn(), db_mgr.Props().Schema_is_1());
search_temp_tbl.Create_tbl();
search_temp_tbl.Insert_bgn();
}
public void Wkr_run(Xowd_page_itm page) {
try {
int page_id = page.Id();
byte[] ttl = page.Ttl_page_db();
byte[][] words = Xob_search_base.Split_ttl_into_words(lang, list, tmp_bfr, ttl);
int len = words.length;
for (int i = 0; i < len; ++i) {
byte[] word = words[i];
search_temp_tbl.Insert_cmd_by_batch(page_id, word);
}
} catch (Exception e) {bldr.Usr_dlg().Warn_many("", "", "search_index:fatal error: err=~{0}", Err_.Message_gplx_brief(e));} // never let single page crash entire import
}
public void Wkr_end() {
search_temp_tbl.Make_data(usr_dlg, search_db.Tbl__search_link(), search_db.Tbl__search_word());
search_temp_tbl.Insert_end();
}
public void Wkr_print() {}
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_set)) {}
else return GfoInvkAble_.Rv_unhandled;
return this;
} private static final String Invk_set = "set";
}

View File

@@ -174,7 +174,7 @@ public class Xob_tst {
Io_mgr._.SaveFilStr(url, raw);
Xotdb_page_raw_parser parser = new Xotdb_page_raw_parser();
Xowe_wiki wiki = Xoa_app_fxt.wiki_tst_(app);
parser.Load(Gfo_usr_dlg_base.test_(), wiki, new Xow_ns(Xow_ns_.Id_template, Xow_ns_case_.Id_1st, Bry_.new_utf8_("Template"), false), new Io_url[] {url}, 1 * Io_mgr.Len_kb);
parser.Load(Gfo_usr_dlg_.Test(), wiki, new Xow_ns(Xow_ns_.Id_template, Xow_ns_case_.Id_1st, Bry_.new_utf8_("Template"), false), new Io_url[] {url}, 1 * Io_mgr.Len_kb);
ListAdp actl = ListAdp_.new_();
Xowd_page_itm page = new Xowd_page_itm();
while (parser.Read(page)) {

View File

@@ -57,7 +57,7 @@ public class Xob_image_cmd extends Xob_itm_dump_base implements Xob_cmd, GfoInvk
case Fld_img_media_type: cur_media_type = Bry_.Mid(src, fld_bgn, fld_end); break;
case Fld_img_minor_mime: cur_minor_mime = Bry_.Mid(src, fld_bgn, fld_end); break;
case Fld_img_timestamp: cur_timestamp = Bry_.Mid(src, fld_bgn, fld_end);
cur_ext_id = Calc_ext_id(show_issues ? app.Usr_dlg() : Gfo_usr_dlg_.Null, cur_ttl, cur_media_type, cur_minor_mime, cur_width, cur_height);
cur_ext_id = Calc_ext_id(show_issues ? app.Usr_dlg() : Gfo_usr_dlg_.Noop, cur_ttl, cur_media_type, cur_minor_mime, cur_width, cur_height);
tbl_image.Insert(stmt, cur_ttl, cur_media_type, cur_minor_mime, cur_size, cur_width, cur_height, cur_bits, cur_ext_id, cur_timestamp);
++commit_count;
if ((commit_count % 10000) == 0) {

View File

@@ -45,7 +45,7 @@ class Xob_image_cmd_fxt {
public Xob_image_cmd_fxt W_(int v) {w = v; return this;}
public Xob_image_cmd_fxt H_(int v) {h = v; return this;}
public Xob_image_cmd_fxt Test(int expd) {
Tfds.Eq(expd, Xob_image_cmd.Calc_ext_id(Gfo_usr_dlg_.Null, name, media_type, minor_mime, w, h));
Tfds.Eq(expd, Xob_image_cmd.Calc_ext_id(Gfo_usr_dlg_.Noop, name, media_type, minor_mime, w, h));
return this;
}
}

View File

@@ -0,0 +1,27 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import gplx.core.html.parsers.*;
// class Gfo_html_tkn__link_css : Gfo_html_tkn__link { // private final Xob_mirror_mgr mgr;
// public Gfo_html_tkn__link_css(Xob_mirror_mgr mgr) {this.mgr = mgr;}
// public override void Process(byte[] src, Xop_xatr_hash xatr_hash) {
// if (!xatr_hash.Match("rel", "stylesheet")) return;
// byte[] href = xatr_hash.Get_as_bry_or("href", null); if (href == null) return;
// mgr.Code_add(href);
// }
// }

View File

@@ -0,0 +1,262 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import gplx.ios.*; import gplx.xowa.html.*;
import gplx.xowa.wikis.*; import gplx.xowa.wikis.data.*;
import gplx.xowa.files.downloads.*;
public class Xoa_css_extractor {
public IoEngine_xrg_downloadFil Download_xrg() {return download_xrg;} private IoEngine_xrg_downloadFil download_xrg = Io_mgr._.DownloadFil_args("", Io_url_.Null);
public Xoa_css_extractor Wiki_domain_(byte[] v) {wiki_domain = v; return this;} private byte[] wiki_domain;
public Xoa_css_extractor Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v; return this;} private Gfo_usr_dlg usr_dlg;
public Xoa_css_extractor Failover_dir_(Io_url v) {failover_dir = v; return this;} private Io_url failover_dir;
public Xoa_css_extractor Wiki_html_dir_(Io_url v) {wiki_html_dir = v; return this;} private Io_url wiki_html_dir;
public Xoa_css_extractor Mainpage_url_(String v) {mainpage_url = v; return this;} private String mainpage_url;
public Xoa_css_extractor Protocol_prefix_(String v) {protocol_prefix = v; return this;} private String protocol_prefix = "https:";// NOTE: changed from http to https; DATE:2015-02-17
public Xoa_css_extractor Page_fetcher_(Xow_page_fetcher v) {page_fetcher = v; return this;} private Xow_page_fetcher page_fetcher;
public Xoa_css_extractor Css_img_downloader_(Xoa_css_img_downloader v) {this.css_img_downloader = v; return this;} private Xoa_css_img_downloader css_img_downloader;
public Xoa_css_extractor Opt_download_css_common_(boolean v) {opt_download_css_common = v; return this;} private boolean opt_download_css_common;
public Xoa_css_extractor Url_encoder_(Url_encoder v) {url_encoder = v; return this;} private Url_encoder url_encoder;
public Xoa_css_extractor Wiki_code_(byte[] v) {this.wiki_code = v; return this;} private byte[] wiki_code = null;
private byte[] mainpage_html; private boolean lang_is_ltr = true;
public void Init_by_app(Xoae_app app) {
this.usr_dlg = app.Usr_dlg();
Xof_download_wkr download_wkr = app.Wmf_mgr().Download_wkr();
this.download_xrg = download_wkr.Download_xrg();
css_img_downloader = new Xoa_css_img_downloader().Ctor(usr_dlg, download_wkr, Bry_.new_utf8_(protocol_prefix));
failover_dir = app.Fsys_mgr().Bin_any_dir().GenSubDir_nest("html", "xowa", "import");
url_encoder = Xoa_app_.Utl__encoder_mgr().Url();
}
public void Install(Xow_wiki wiki, String css_key) {
try {
this.wiki_html_dir = wiki.App().Fsys_mgr().Wiki_css_dir(wiki.Domain_str()); // EX: /xowa/user/anonymous/wiki/en.wikipedia.org
Io_url css_comm_fil = wiki_html_dir.GenSubFil(Css_common_name);
Io_url css_wiki_fil = wiki_html_dir.GenSubFil(Css_wiki_name);
wiki.Html__page_wtr_mgr().Init_css_urls(css_comm_fil, css_wiki_fil);
if (wiki.Domain_tid() == Xow_domain_.Tid_int_home || Env_.Mode_testing()) return; // NOTE: do not download if home_wiki; also needed for TEST
if (Io_mgr._.ExistsFil(css_wiki_fil)) return; // css file exists; nothing to generate
wiki.App().Usr_dlg().Log_many("", "", "generating css for '~{0}'", wiki.Domain_str());
if (css_key != null) {
if (Install_by_db(wiki, wiki_html_dir, css_key)) return;
}
if (wiki.Type_is_edit())
this.Install_by_wmf((Xowe_wiki)wiki, wiki_html_dir);
}
catch (Exception e) { // if error, failover; paranoia catch for outliers like bad network connectivity fail, or MediaWiki: message not existing; DATE:2013-11-21
wiki.App().Usr_dlg().Warn_many("", "", "failed while trying to generate css; failing over; wiki='~{0}' err=~{1}", wiki.Domain_str(), Err_.Message_gplx(e));
Css_common_failover(); // only failover xowa_common.css; xowa_wiki.css comes from MediaWiki:Common.css / Vector.css
}
}
private void Install_by_wmf(Xowe_wiki wiki, Io_url wiki_html_dir) {
opt_download_css_common = wiki.Appe().Setup_mgr().Dump_mgr().Css_commons_download();
if (!wiki.Appe().User().Cfg_mgr().Security_mgr().Web_access_enabled()) opt_download_css_common = false; // if !web_access_enabled, don't download
this.wiki_domain = wiki.Domain_bry();
mainpage_url = "https://" + wiki.Domain_str(); // NOTE: cannot reuse protocol_prefix b/c "//" needs to be added manually; protocol_prefix is used for logo and images which have form of "//domain/image.png"; changed to https; DATE:2015-02-17
if (page_fetcher == null) page_fetcher = new Xow_page_fetcher_wiki();
page_fetcher.Wiki_(wiki);
this.wiki_html_dir = wiki_html_dir;
this.lang_is_ltr = wiki.Lang().Dir_ltr();
this.wiki_code = wiki.Domain_abrv();
mainpage_html = Mainpage_download_html();
Css_common_setup();
Css_wiki_setup();
Logo_setup();
}
private boolean Install_by_db(Xow_wiki wiki, Io_url wiki_html_dir, String css_key) {
Xowd_db_mgr core_db_mgr = wiki.Data_mgr__core_mgr();
if ( core_db_mgr == null
|| core_db_mgr.Props() == null
|| core_db_mgr.Props().Schema_is_1()
|| !core_db_mgr.Tbl__cfg().Select_yn_or(Xow_cfg_consts.Grp__wiki_schema, Xowd_db_file_schema_props.Key__tbl_css_core, Bool_.N)
) {
Xoa_app_.Usr_dlg().Warn_many("", "", "css.db not found; wiki=~{0} css_dir=~{1}", wiki.Domain_str(), wiki_html_dir.Raw());
return false;
}
Xowd_db_file core_db = core_db_mgr.Db__core();
gplx.xowa.html.css.Xowd_css_core_mgr.Get(core_db.Tbl__css_core(), core_db.Tbl__css_file(), wiki_html_dir, css_key);
return true;
}
public void Css_common_setup() {
if (opt_download_css_common)
Css_common_download();
else
Css_common_failover();
}
private void Css_common_failover() {
Io_url trg_fil = wiki_html_dir.GenSubFil(Css_common_name);
Io_mgr._.CopyFil(Css_common_failover_url(), trg_fil, true);
css_img_downloader.Chk(wiki_domain, trg_fil);
}
private void Css_common_download() {
boolean css_stylesheet_common_missing = true;
Io_url trg_fil = wiki_html_dir.GenSubFil(Css_common_name);
css_stylesheet_common_missing = !Css_scrape_setup();
if (css_stylesheet_common_missing)
Io_mgr._.CopyFil(Css_common_failover_url(), trg_fil, true);
else
css_img_downloader.Chk(wiki_domain, trg_fil);
}
private Io_url Css_common_failover_url() {
Io_url css_commons_url = failover_dir.GenSubDir("xowa_common_override").GenSubFil_ary("xowa_common_", String_.new_utf8_(wiki_code), ".css");
if (Io_mgr._.ExistsFil(css_commons_url)) return css_commons_url; // specific css exists for wiki; use it; EX: xowa_common_wiki_mediawikiwiki.css
return failover_dir.GenSubFil(lang_is_ltr ? Css_common_name_ltr : Css_common_name_rtl);
}
public void Css_wiki_setup() {
boolean css_stylesheet_wiki_missing = true;
Io_url trg_fil = wiki_html_dir.GenSubFil(Css_wiki_name);
if (Io_mgr._.ExistsFil(trg_fil)) return; // don't download if already there
css_stylesheet_wiki_missing = !Css_wiki_generate(trg_fil);
if (css_stylesheet_wiki_missing)
Failover(trg_fil);
else
css_img_downloader.Chk(wiki_domain, trg_fil);
}
private boolean Css_wiki_generate(Io_url trg_fil) {
Bry_bfr bfr = Bry_bfr.new_();
Css_wiki_generate_section(bfr, Ttl_common_css);
Css_wiki_generate_section(bfr, Ttl_vector_css);
byte[] bry = bfr.Xto_bry_and_clear();
bry = Bry_.Replace(bry, gplx.xowa.bldrs.xmls.Xob_xml_parser_.Bry_tab_ent, gplx.xowa.bldrs.xmls.Xob_xml_parser_.Bry_tab);
Io_mgr._.SaveFilBry(trg_fil, bry);
return true;
} private static final byte[] Ttl_common_css = Bry_.new_ascii_("Common.css"), Ttl_vector_css = Bry_.new_ascii_("Vector.css");
private boolean Css_wiki_generate_section(Bry_bfr bfr, byte[] ttl) {
byte[] page = page_fetcher.Fetch(Xow_ns_.Id_mediawiki, ttl);
if (page == null) return false;
if (bfr.Len() != 0) bfr.Add_byte_nl().Add_byte_nl(); // add "\n\n" between sections; !=0 checks against first
Css_wiki_section_hdr.Bld_bfr_many(bfr, ttl); // add "/*XOWA:MediaWiki:Common.css*/\n"
bfr.Add(page); // add page
return true;
} static final Bry_fmtr Css_wiki_section_hdr = Bry_fmtr.new_("/*XOWA:MediaWiki:~{ttl}*/\n", "ttl");
public void Logo_setup() {
boolean logo_missing = true;
Io_url logo_url = wiki_html_dir.GenSubFil("logo.png");
if (Io_mgr._.ExistsFil(logo_url)) return; // don't download if already there
logo_missing = !Logo_download(logo_url);
if (logo_missing)
Failover(logo_url);
}
private boolean Logo_download(Io_url trg_fil) {
String src_fil = Logo_find_src();
if (src_fil == null) {
if (Logo_copy_from_css(trg_fil)) return true;
usr_dlg.Warn_many("", "", "failed to extract logo: trg_fil=~{0};", trg_fil.Raw());
return false;
}
String log_msg = usr_dlg.Prog_many("", "", "downloading logo: '~{0}'", src_fil);
boolean rv = download_xrg.Prog_fmt_hdr_(log_msg).Src_(src_fil).Trg_(trg_fil).Exec();
if (!rv)
usr_dlg.Warn_many("", "", "failed to download logo: src_url=~{0};", src_fil);
return rv;
}
private boolean Logo_copy_from_css(Io_url trg_fil) {
Io_url commons_file = wiki_html_dir.GenSubFil(Css_common_name);
byte[] commons_src = Io_mgr._.LoadFilBry(commons_file);
int bgn_pos = Bry_finder.Find_fwd(commons_src, Bry_mw_wiki_logo); if (bgn_pos == Bry_finder.Not_found) return false;
bgn_pos += Bry_mw_wiki_logo.length;
int end_pos = Bry_finder.Find_fwd(commons_src, Byte_ascii.Quote, bgn_pos + 1); if (end_pos == Bry_finder.Not_found) return false;
byte[] src_bry = Bry_.Mid(commons_src, bgn_pos, end_pos);
src_bry = Xob_url_fixer.Fix(wiki_domain, src_bry, src_bry.length);
if (wiki_html_dir.Info().DirSpr_byte() == Byte_ascii.Backslash)
src_bry = Bry_.Replace(src_bry, Byte_ascii.Slash, Byte_ascii.Backslash);
Io_url src_fil = wiki_html_dir.GenSubFil(String_.new_utf8_(src_bry));
Io_mgr._.CopyFil(src_fil, trg_fil, true);
return true;
} private static final byte[] Bry_mw_wiki_logo = Bry_.new_ascii_(".mw-wiki-logo{background-image:url(\"");
private String Logo_find_src() {
if (mainpage_html == null) return null;
int main_page_html_len = mainpage_html.length;
int logo_bgn = Bry_finder.Find_fwd(mainpage_html, Logo_find_bgn, 0); if (logo_bgn == Bry_.NotFound) return null;
logo_bgn += Logo_find_bgn.length;
logo_bgn = Bry_finder.Find_fwd(mainpage_html, Logo_find_end, logo_bgn); if (logo_bgn == Bry_.NotFound) return null;
logo_bgn += Logo_find_end.length;
int logo_end = Bry_finder.Find_fwd(mainpage_html, Byte_ascii.Paren_end, logo_bgn, main_page_html_len); if (logo_bgn == Bry_.NotFound) return null;
byte[] logo_bry = Bry_.Mid(mainpage_html, logo_bgn, logo_end);
return protocol_prefix + String_.new_utf8_(logo_bry);
}
private static final byte[] Logo_find_bgn = Bry_.new_ascii_("<div id=\"p-logo\""), Logo_find_end = Bry_.new_ascii_("background-image: url(");
public boolean Mainpage_download() {
mainpage_html = Mainpage_download_html();
return mainpage_html != null;
}
private byte[] Mainpage_download_html() {
String main_page_url_temp = mainpage_url;
if (Bry_.Eq(wiki_domain, Xow_domain_.Domain_bry_wikidata)) // if wikidata, download css for a Q* page; Main_Page has less css; DATE:2014-09-30
main_page_url_temp = main_page_url_temp + "/wiki/Q2";
String log_msg = usr_dlg.Prog_many("", "main_page.download", "downloading main page for '~{0}'", main_page_url_temp);
byte[] main_page_html = download_xrg.Prog_fmt_hdr_(log_msg).Exec_as_bry(main_page_url_temp);
if (main_page_html == null) usr_dlg.Warn_many("", "", "failed to download main_page: src_url=~{0};", main_page_url_temp);
return main_page_html;
}
private void Failover(Io_url trg_fil) {
usr_dlg.Note_many("", "", "copying failover file: trg_fil=~{0};", trg_fil.Raw());
Io_mgr._.CopyFil(failover_dir.GenSubFil(trg_fil.NameAndExt()), trg_fil, true);
}
public boolean Css_scrape_setup() {
Io_url trg_fil = wiki_html_dir.GenSubFil(Css_common_name);
// if (Io_mgr._.ExistsFil(trg_fil)) return; // don't download if already there; DELETED: else main_page is not scraped for all stylesheet links; simple.d: fails; DATE:2014-02-11
byte[] css_url = Css_scrape();
if (css_url == null) {
Css_common_failover();
return false;
}
else {
Io_mgr._.SaveFilBry(trg_fil, css_url);
css_img_downloader.Chk(wiki_domain, trg_fil);
return true;
}
}
private byte[] Css_scrape() {
if (mainpage_html == null) return null;
String[] css_urls = Css_scrape_urls(mainpage_html); if (css_urls.length == 0) return null;
return Css_scrape_download(css_urls);
}
private String[] Css_scrape_urls(byte[] raw) {
ListAdp rv = ListAdp_.new_();
int raw_len = raw.length;
int prv_pos = 0;
int css_find_bgn_len = Css_find_bgn.length;
byte[] protocol_prefix_bry = Bry_.new_utf8_(protocol_prefix);
while (true) {
int url_bgn = Bry_finder.Find_fwd(raw, Css_find_bgn, prv_pos); if (url_bgn == Bry_.NotFound) break; // nothing left; stop
url_bgn += css_find_bgn_len;
int url_end = Bry_finder.Find_fwd(raw, Byte_ascii.Quote, url_bgn, raw_len); if (url_end == Bry_.NotFound) {usr_dlg.Warn_many("", "main_page.css_parse", "could not find css; pos='~{0}' text='~{1}'", url_bgn, String_.new_utf8_len_safe_(raw, url_bgn, url_bgn + 32)); break;}
byte[] css_url_bry = Bry_.Mid(raw, url_bgn, url_end);
css_url_bry = Bry_.Replace(css_url_bry, Css_amp_find, Css_amp_repl); // &amp; -> &
css_url_bry = url_encoder.Decode(css_url_bry); // %2C -> %7C -> |
css_url_bry = Bry_.Add(protocol_prefix_bry, css_url_bry);
rv.Add(String_.new_utf8_(css_url_bry));
prv_pos = url_end;
}
return rv.XtoStrAry();
} private static final byte[] Css_find_bgn = Bry_.new_ascii_("<link rel=\"stylesheet\" href=\""), Css_amp_find = Bry_.new_ascii_("&amp;"), Css_amp_repl = Bry_.new_ascii_("&");
private byte[] Css_scrape_download(String[] css_urls) {
int css_urls_len = css_urls.length;
Bry_bfr tmp_bfr = Bry_bfr.new_();
for (int i = 0; i < css_urls_len; i++) {
String css_url = css_urls[i];
usr_dlg.Prog_many("", "main_page.css_download", "downloading css for '~{0}'", css_url);
download_xrg.Prog_fmt_hdr_(css_url);
byte[] css_bry = download_xrg.Exec_as_bry(css_url); if (css_bry == null) continue; // css not found; continue
tmp_bfr.Add(Xoa_css_img_downloader.Bry_comment_bgn).Add_str(css_url).Add(Xoa_css_img_downloader.Bry_comment_end).Add_byte_nl();
tmp_bfr.Add(css_bry).Add_byte_nl().Add_byte_nl();
}
return tmp_bfr.Xto_bry_and_clear();
}
public static final String Css_common_name = "xowa_common.css", Css_wiki_name = "xowa_wiki.css"
, Css_common_name_ltr = "xowa_common_ltr.css", Css_common_name_rtl = "xowa_common_rtl.css";
}

View File

@@ -0,0 +1,130 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import org.junit.*; import gplx.ios.*; import gplx.xowa.wikis.data.*; import gplx.xowa.files.downloads.*;
public class Xoa_css_extractor_basic_tst {
@Before public void init() {fxt.Clear();} private Xoa_css_extractor_fxt fxt = new Xoa_css_extractor_fxt();
@Test public void Logo_download() {
fxt.Init_fil("mem/http/en.wikipedia.org" , Xoa_css_extractor_fxt.Main_page_html);
fxt.Init_fil("mem/http/wiki.png" , "download");
fxt.Exec_logo_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/logo.png", "download");
}
@Test public void Logo_download_mw_wiki_logo() {
fxt.Init_fil("mem/http/en.wikipedia.org" , "");
fxt.Init_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/a/wiki.png" , "download");
fxt.Init_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/xowa_common.css" , ".mw-wiki-logo{background-image:url(\"//a/wiki.png\");");
fxt.Exec_logo_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/logo.png" , "download");
}
@Test public void Logo_failover() {
fxt.Init_fil("mem/xowa/bin/any/html/xowa/import/logo.png" , "failover");
fxt.Exec_logo_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/logo.png", "failover");
}
@Test public void Css_common_download_failover() {
fxt.Css_installer().Opt_download_css_common_(true);
fxt.Init_fil("mem/xowa/bin/any/html/xowa/import/xowa_common_ltr.css", "failover");
fxt.Exec_css_common_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/xowa_common.css", "failover");
}
@Test public void Css_common_copy() {
fxt.Css_installer().Opt_download_css_common_(false);
fxt.Init_fil("mem/xowa/bin/any/html/xowa/import/xowa_common_ltr.css", "failover");
fxt.Exec_css_common_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/xowa_common.css", "failover");
}
@Test public void Css_common_copy_specific_wiki() { // PURPOSE: css for specific wiki
fxt.Css_installer().Opt_download_css_common_(false).Wiki_code_(Bry_.new_ascii_("enwiki"));
fxt.Init_fil("mem/xowa/bin/any/html/xowa/import/xowa_common_override/xowa_common_enwiki.css", "failover");
fxt.Exec_css_common_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/xowa_common.css", "failover");
}
@Test public void Css_scrape_download() {
fxt.Css_installer().Url_encoder_(Url_encoder.new_http_url_());
fxt.Init_fil("mem/http/en.wikipedia.org" , Xoa_css_extractor_fxt.Main_page_html);
fxt.Init_fil("mem/http/en.wikipedia.org/common.css" , "download");
fxt.Init_fil("mem/http/www/a&0|b,c" , "data=css_0");
fxt.Init_fil("mem/http/www/a&1|b,c" , "data=css_1");
fxt.Exec_css_mainpage_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/xowa_common.css", String_.Concat_lines_nl
( "/*XOWA:mem/http/www/a&0|b,c*/"
, "data=css_0"
, ""
, "/*XOWA:mem/http/www/a&1|b,c*/"
, "data=css_1"
));
}
@Test public void Css_scrape_failover() {
fxt.Init_fil("mem/xowa/bin/any/html/xowa/import/xowa_common_ltr.css", "failover");
fxt.Exec_css_mainpage_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/xowa_common.css", "failover");
}
}
class Xoa_css_extractor_fxt {
public void Clear() {
Io_mgr._.InitEngine_mem();
Gfo_usr_dlg usr_dlg = Gfo_usr_dlg_.Test();
css_installer = new Xoa_css_extractor();
css_installer.Download_xrg().Trg_engine_key_(IoEngine_.MemKey);
css_installer
.Usr_dlg_(usr_dlg)
.Wiki_domain_(Bry_.new_ascii_("en.wikipedia.org"))
.Protocol_prefix_("mem/http/")
.Mainpage_url_("mem/http/en.wikipedia.org")
.Failover_dir_(Io_url_.new_any_("mem/xowa/bin/any/html/xowa/import/")) // "mem/xowa/user/anonymous/wiki/home/html/"
.Wiki_html_dir_(Io_url_.new_any_("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/"))
;
page_fetcher = new Xow_page_fetcher_test();
css_installer.Page_fetcher_(page_fetcher);
Xoa_css_img_downloader css_img_downloader = new Xoa_css_img_downloader();
css_img_downloader.Ctor(usr_dlg, new Xof_download_wkr_test(), Bry_.new_ascii_("mem/http/"));
css_installer.Css_img_downloader_(css_img_downloader);
} private Xow_page_fetcher_test page_fetcher;
public Xoa_css_extractor Css_installer() {return css_installer;} private Xoa_css_extractor css_installer;
public void Init_page(int ns_id, String ttl, String text) {
page_fetcher.Add(ns_id, Bry_.new_ascii_(ttl), Bry_.new_ascii_(text));
}
public void Init_fil_empty(String url) {Init_fil(url, "");}
public void Init_fil(String url, String text) {Io_mgr._.SaveFilStr(url, text);}
public void Test_fil(String url, String expd) {Tfds.Eq_str_lines(expd, Io_mgr._.LoadFilStr(Io_url_.new_any_(url)));}
public void Exec_logo_setup() {
css_installer.Mainpage_download();
css_installer.Logo_setup();
}
public void Exec_css_common_setup() {
css_installer.Mainpage_download();
css_installer.Css_common_setup();
}
public void Exec_css_wiki_setup() {css_installer.Css_wiki_setup();}
public void Exec_css_mainpage_setup() {
css_installer.Mainpage_download();
css_installer.Css_scrape_setup();
}
public static String Main_page_html = String_.Concat_lines_nl
( "<html>"
, " <head>"
, " <link rel=\"stylesheet\" href=\"www/a&amp;0%7Cb%2Cc\" />"
, " <link rel=\"stylesheet\" href=\"www/a&amp;1%7Cb%2Cc\" />"
, " </head>"
, " <body>"
, " <div id=\"p-logo\" role=\"banner\"><a style=\"background-image: url(wiki.png);\""
, " </body>"
, "</html>"
);
}

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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import org.junit.*; import gplx.ios.*;
public class Xoa_css_extractor_wiki_tst {
@Before public void init() {fxt.Clear();} private Xoa_css_extractor_fxt fxt = new Xoa_css_extractor_fxt();
@Test public void Css_wiki_generate() {
fxt.Init_page(Xow_ns_.Id_mediawiki, "Common.css" , "css_0");
fxt.Init_page(Xow_ns_.Id_mediawiki, "Vector.css" , "css_1");
fxt.Exec_css_wiki_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/xowa_wiki.css", String_.Concat_lines_nl
( "/*XOWA:MediaWiki:Common.css*/"
, "css_0"
, ""
, "/*XOWA:MediaWiki:Vector.css*/"
, "css_1"
));
}
@Test public void Css_wiki_missing() {
fxt.Exec_css_wiki_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/xowa_wiki.css", "");
}
@Test public void Css_wiki_tab() { // PURPOSE: swap out &#09; for xdat files
fxt.Init_page(Xow_ns_.Id_mediawiki, "Common.css" , "a&#09;b");
fxt.Exec_css_wiki_setup();
fxt.Test_fil("mem/xowa/user/anonymous/wiki/en.wikipedia.org/html/xowa_wiki.css", String_.Concat_lines_nl
( "/*XOWA:MediaWiki:Common.css*/"
, "a\tb"
));
}
}

View File

@@ -0,0 +1,188 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import gplx.xowa.files.downloads.*;
public class Xoa_css_img_downloader {
private byte[] wiki_domain;
public Xoa_css_img_downloader Ctor(Gfo_usr_dlg usr_dlg, Xof_download_wkr download_wkr, byte[] stylesheet_prefix) {
this.usr_dlg = usr_dlg; this.download_wkr = download_wkr; this.stylesheet_prefix = stylesheet_prefix;
return this;
} private Gfo_usr_dlg usr_dlg; private Xof_download_wkr download_wkr;
public Xoa_css_img_downloader Stylesheet_prefix_(byte[] v) {stylesheet_prefix = v; return this;} private byte[] stylesheet_prefix; // TEST: setter exposed b/c tests can handle "mem/" but not "//mem"
public void Chk(byte[] wiki_domain, Io_url css_fil) {
this.wiki_domain = wiki_domain;
ListAdp img_list = ListAdp_.new_();
byte[] old_bry = Io_mgr._.LoadFilBry(css_fil);
byte[] rel_url_prefix = Bry_.Add(Bry_fwd_slashes, wiki_domain);
byte[] new_bry = Convert_to_local_urls(rel_url_prefix, old_bry, img_list);
Io_url img_dir = css_fil.OwnerDir();
Download_fils(img_dir, img_list.XtoStrAry());
Io_mgr._.SaveFilBry(css_fil, new_bry);
}
public byte[] Convert_to_local_urls(byte[] rel_url_prefix, byte[] src, ListAdp list) {
try {
int src_len = src.length;
int prv_pos = 0;
Bry_bfr bfr = Bry_bfr.new_(src_len);
HashAdp img_hash = HashAdp_.new_bry_();
while (true) {
int url_pos = Bry_finder.Find_fwd(src, Bry_url, prv_pos);
if (url_pos == Bry_.NotFound) {bfr.Add_mid(src, prv_pos, src_len); break;} // no more "url("; exit;
int bgn_pos = url_pos + Bry_url_len; // set bgn_pos after "url("
byte bgn_byte = src[bgn_pos];
byte end_byte = Byte_ascii.Nil;
boolean quoted = true;
switch (bgn_byte) { // find end_byte
case Byte_ascii.Quote: case Byte_ascii.Apos: // quoted; end_byte is ' or "
end_byte = bgn_byte;
++bgn_pos;
break;
default: // not quoted; end byte is ")"
end_byte = Byte_ascii.Paren_end;
quoted = false;
break;
}
int end_pos = Bry_finder.Find_fwd(src, end_byte, bgn_pos, src_len);
if (end_pos == Bry_.NotFound) { // unclosed "url("; exit since nothing else will be found
usr_dlg.Warn_many(GRP_KEY, "parse.invalid_url.end_missing", "could not find end_sequence for 'url(': bgn='~{0}' end='~{1}'", prv_pos, String_.new_utf8_len_safe_(src, prv_pos, prv_pos + 25));
bfr.Add_mid(src, prv_pos, src_len);
break;
}
if (end_pos - bgn_pos == 0) { // empty; "url()"; ignore
usr_dlg.Warn_many(GRP_KEY, "parse.invalid_url.empty", "'url(' is empty: bgn='~{0}' end='~{1}'", prv_pos, String_.new_utf8_len_safe_(src, prv_pos, prv_pos + 25));
bfr.Add_mid(src, prv_pos, bgn_pos);
prv_pos = bgn_pos;
continue;
}
byte[] img_raw = Bry_.Mid(src, bgn_pos, end_pos); int img_raw_len = img_raw.length;
if (Bry_.HasAtBgn(img_raw, Bry_data_image, 0, img_raw_len)) { // base64
bfr.Add_mid(src, prv_pos, end_pos); // nothing to download; just add entire String
prv_pos = end_pos;
continue;
}
int import_url_end = Import_url_chk(rel_url_prefix, src, src_len, prv_pos, url_pos, img_raw, bfr); // check for embedded stylesheets via @import tag
if (import_url_end != Bry_.NotFound) {
prv_pos = import_url_end;
continue;
}
byte[] img_cleaned = Xob_url_fixer.Fix(wiki_domain, img_raw, img_raw_len);
if (img_cleaned == null) { // could not clean img
usr_dlg.Warn_many(GRP_KEY, "parse.invalid_url.clean_failed", "could not extract valid http src: bgn='~{0}' end='~{1}'", prv_pos, String_.new_utf8_(img_raw));
bfr.Add_mid(src, prv_pos, bgn_pos); prv_pos = bgn_pos; continue;
}
if (!img_hash.Has(img_cleaned)) {// only add unique items for download;
img_hash.AddKeyVal(img_cleaned);
list.Add(String_.new_utf8_(img_cleaned));
}
img_cleaned = Replace_invalid_chars(Bry_.Copy(img_cleaned)); // NOTE: must call ByteAry.Copy else img_cleaned will change *inside* hash
bfr.Add_mid(src, prv_pos, bgn_pos);
if (!quoted) bfr.Add_byte(Byte_ascii.Quote);
bfr.Add(img_cleaned);
if (!quoted) bfr.Add_byte(Byte_ascii.Quote);
prv_pos = end_pos;
}
return bfr.Xto_bry_and_clear();
}
catch (Exception e) {
usr_dlg.Warn_many("", "", "failed to convert local_urls: ~{0} ~{1}", String_.new_utf8_(rel_url_prefix), Err_.Message_gplx(e));
return src;
}
}
public static byte[] Import_url_build(byte[] stylesheet_prefix, byte[] rel_url_prefix, byte[] css_url) {
return Bry_.HasAtBgn(css_url, Bry_http_protocol) // css_url already starts with "http"; return self; PAGE:tr.n:Main_Page; DATE:2014-06-04
? css_url
: Bry_.Add(stylesheet_prefix, css_url)
;
}
private int Import_url_chk(byte[] rel_url_prefix, byte[] src, int src_len, int old_pos, int find_bgn, byte[] url_raw, Bry_bfr bfr) {
if (find_bgn < Bry_import_len) return Bry_.NotFound;
if (!Bry_.Match(src, find_bgn - Bry_import_len, find_bgn, Bry_import)) return Bry_.NotFound;
byte[] css_url = url_raw; int css_url_len = css_url.length;
if (css_url_len > 0 && css_url[0] == Byte_ascii.Slash) { // css_url starts with "/"; EX: "/page" or "//site/page" DATE:2014-02-03
if (css_url_len > 1 && css_url[1] != Byte_ascii.Slash) // skip if css_url starts with "//"; EX: "//site/page"
css_url = Bry_.Add(rel_url_prefix, css_url); // "/w/a.css" -> "//en.wikipedia.org/w/a.css"
}
css_url = Bry_.Replace(css_url, Byte_ascii.Space, Byte_ascii.Underline); // NOTE: must replace spaces with underlines else download will fail; EX:https://it.wikivoyage.org/w/index.php?title=MediaWiki:Container e Infobox.css&action=raw&ctype=text/css; DATE:2015-03-08
byte[] css_src_bry = Import_url_build(stylesheet_prefix, rel_url_prefix, css_url);
String css_src_str = String_.new_utf8_(css_src_bry);
download_wkr.Download_xrg().Prog_fmt_hdr_(usr_dlg.Log_many(GRP_KEY, "logo.download", "downloading import for '~{0}'", css_src_str));
byte[] css_trg_bry = download_wkr.Download_xrg().Exec_as_bry(css_src_str);
if (css_trg_bry == null) {
usr_dlg.Warn_many("", "", "could not import css: url=~{0}", css_src_str);
return Bry_.NotFound; // css not found
}
bfr.Add_mid(src, old_pos, find_bgn - Bry_import_len).Add_byte_nl();
bfr.Add(Bry_comment_bgn).Add(css_url).Add(Bry_comment_end).Add_byte_nl();
if (Bry_finder.Find_fwd(css_url, Wikisource_dynimg_ttl) != -1) css_trg_bry = Bry_.Replace(css_trg_bry, Wikisource_dynimg_find, Wikisource_dynimg_repl); // FreedImg hack; PAGE:en.s:Page:Notes_on_Osteology_of_Baptanodon._With_a_Description_of_a_New_Species.pdf/3 DATE:2014-09-06
bfr.Add(css_trg_bry).Add_byte_nl();
bfr.Add_byte_nl();
int semic_pos = Bry_finder.Find_fwd(src, Byte_ascii.Semic, find_bgn + url_raw.length, src_len);
return semic_pos + Int_.Const_dlm_len;
}
private static final byte[]
Wikisource_dynimg_ttl = Bry_.new_ascii_("en.wikisource.org/w/index.php?title=MediaWiki:Dynimg.css")
, Wikisource_dynimg_find = Bry_.new_ascii_(".freedImg img[src*=\"wikipedia\"], .freedImg img[src*=\"wikisource\"], .freedImg img[src*=\"score\"], .freedImg img[src*=\"math\"] {")
, Wikisource_dynimg_repl = Bry_.new_ascii_(".freedImg img[src*=\"wikipedia\"], .freedImg img[src*=\"wikisource\"], /*XOWA:handle file:// paths which will have /commons.wikimedia.org/ but not /wikipedia/ */ .freedImg img[src*=\"wikimedia\"], .freedImg img[src*=\"score\"], .freedImg img[src*=\"math\"] {")
;
public byte[] Clean_img_url(byte[] raw, int raw_len) {
int pos_bgn = 0;
if (Bry_.HasAtBgn(raw, Bry_fwd_slashes, 0, raw_len)) pos_bgn = Bry_fwd_slashes.length;
if (Bry_.HasAtBgn(raw, Bry_http, 0, raw_len)) pos_bgn = Bry_http.length;
int pos_slash = Bry_finder.Find_fwd(raw, Byte_ascii.Slash, pos_bgn, raw_len);
if (pos_slash == Bry_.NotFound) return null; // first segment is site_name; at least one slash must be present for image name; EX: site.org/img_name.jpg
if (pos_slash == raw_len - 1) return null; // "site.org/" is invalid
int pos_end = raw_len;
int pos_question = Bry_finder.Find_bwd(raw, Byte_ascii.Question);
if (pos_question != Bry_.NotFound)
pos_end = pos_question; // remove query params; EX: img_name?key=val
return Bry_.Mid(raw, pos_bgn, pos_end);
}
private void Download_fils(Io_url css_dir, String[] ary) {
int ary_len = ary.length;
for (int i = 0; i < ary_len; i++) {
String src = ary[i];
Io_url trg = css_dir.GenSubFil_nest(Op_sys.Cur().Fsys_http_frag_to_url_str(Replace_invalid_chars_str(src)));
if (Io_mgr._.ExistsFil(trg)) continue;
download_wkr.Download(true, "http://" + src, trg, "download: " + src); // ILN
}
}
String Replace_invalid_chars_str(String raw_str) {return String_.new_utf8_(Replace_invalid_chars(Bry_.new_utf8_(raw_str)));}
byte[] Replace_invalid_chars(byte[] raw_bry) {
int raw_len = raw_bry.length;
for (int i = 0; i < raw_len; i++) { // convert invalid wnt chars to underscores
byte b = raw_bry[i];
switch (b) {
//case Byte_ascii.Slash:
case Byte_ascii.Backslash: case Byte_ascii.Colon: case Byte_ascii.Asterisk: case Byte_ascii.Question:
case Byte_ascii.Quote: case Byte_ascii.Lt: case Byte_ascii.Gt: case Byte_ascii.Pipe:
raw_bry[i] = Byte_ascii.Underline;
break;
}
}
return raw_bry;
}
private static final byte[]
Bry_url = Bry_.new_ascii_("url("), Bry_data_image = Bry_.new_ascii_("data:image/")
, Bry_http = Bry_.new_ascii_("http://"), Bry_fwd_slashes = Bry_.new_ascii_("//"), Bry_import = Bry_.new_ascii_("@import ")
, Bry_http_protocol = Bry_.new_ascii_("http")
;
public static final byte[]
Bry_comment_bgn = Bry_.new_ascii_("/*XOWA:"), Bry_comment_end = Bry_.new_ascii_("*/");
private static final int Bry_url_len = Bry_url.length, Bry_import_len = Bry_import.length;
static final String GRP_KEY = "xowa.wikis.init.css";
}

View File

@@ -0,0 +1,183 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import org.junit.*; import gplx.xowa.files.downloads.*;
public class Xoa_css_img_downloader_tst {
@Before public void init() {fxt.Clear();} private Xoa_css_img_downloader_fxt fxt = new Xoa_css_img_downloader_fxt();
@Test public void Basic() {
fxt.Test_css_convert
( "x {url(\"//site/a.jpg\")} y {url(\"//site/b.jpg\")}"
, "x {url(\"site/a.jpg\")} y {url(\"site/b.jpg\")}"
, "site/a.jpg"
, "site/b.jpg"
);
}
@Test public void Unquoted() {
fxt.Test_css_convert
( "x {url(//site/a.jpg)}"
, "x {url(\"site/a.jpg\")}"
, "site/a.jpg"
);
}
@Test public void Http() {
fxt.Test_css_convert
( "x {url(http://site/a.jpg)}"
, "x {url(\"site/a.jpg\")}"
, "site/a.jpg"
);
}
@Test public void Base64() {
fxt.Test_css_convert
( "x {url(\"//site/a.jpg\")} y {url(\"data:image/png;base64,BASE64DATA;ABC=\")} z {}"
, "x {url(\"site/a.jpg\")} y {url(\"data:image/png;base64,BASE64DATA;ABC=\")} z {}"
, "site/a.jpg"
);
}
@Test public void Exc_missing_quote() {
fxt.Test_css_convert
( "x {url(\"//site/a.jpg\")} y {url(\"//site/b.jpg} z {}"
, "x {url(\"site/a.jpg\")} y {url(\"//site/b.jpg} z {}"
, "site/a.jpg"
);
}
@Test public void Exc_empty() {
fxt.Test_css_convert
( "x {url(\"//site/a.jpg\")} y {url(\"\"} z {}"
, "x {url(\"site/a.jpg\")} y {url(\"\"} z {}"
, "site/a.jpg"
);
}
// @Test public void Exc_name_only() { // COMMENTED: not sure how to handle "b.jpg" (automatically add "current" path?); RESTORE: when example found
// fxt.Test_css_convert
// ( "x {url(\"//site/a.jpg\")} y {url(\"b.jpg\"} z {}"
// , "x {url(\"site/a.jpg\")} y {url(\"b.jpg\"} z {}"
// , "site/a.jpg"
// );
// }
@Test public void Repeat() {// PURPOSE.fix: exact same item was being added literally
fxt.Test_css_convert
( "x {url(\"//site/a.jpg?a=b\")} y {url(\"//site/a.jpg?a=b\"}"
, "x {url(\"site/a.jpg\")} y {url(\"site/a.jpg\"}"
, "site/a.jpg"
);
}
@Test public void Clean_basic() {fxt.Test_clean_img_url("//site/a.jpg" , "site/a.jpg");}
@Test public void Clean_query() {fxt.Test_clean_img_url("//site/a.jpg?key=val" , "site/a.jpg");}
@Test public void Clean_dir() {fxt.Test_clean_img_url("//site/a/b/c.jpg?key=val" , "site/a/b/c.jpg");}
@Test public void Clean_exc_site_only() {fxt.Test_clean_img_url("//site" , null);}
@Test public void Clean_exc_site_only_2() {fxt.Test_clean_img_url("//site/" , null);}
@Test public void Import_url() {
Io_mgr._.InitEngine_mem();
Io_mgr._.SaveFilStr("mem/www/b.css", "imported_css");
fxt.Test_css_convert
( "x @import url(\"mem/www/b.css\") screen; z"
, String_.Concat_lines_nl
( "x "
, "/*XOWA:mem/www/b.css*/"
, "imported_css"
, ""
, " z"
)
);
}
@Test public void Import_url_make() {
fxt.Test_import_url("a.org/b" , "http:a.org/b"); // add "stylesheet_prefix"
fxt.Test_import_url("http://a.org" , "http://a.org"); // unless it starts with http
fxt.Test_import_url("https://a.org" , "https://a.org"); // unless starts with https EX:: handle @import(https://...); PAGE:tr.n:Main_Page; DATE:2014-06-04
}
@Test public void Import_url_relative() { // PURPOSE: if directory, add domain; "/a/b.css" -> "//domain/a/b.css"; DATE:2014-02-03
Io_mgr._.InitEngine_mem();
Io_mgr._.SaveFilStr("mem/en.wikipedia.org/www/b.css", "imported_css");
fxt.Test_css_convert
( "x @import url(\"/www/b.css\") screen; z" // starts with "/"
, String_.Concat_lines_nl
( "x "
, "/*XOWA:mem/en.wikipedia.org/www/b.css*/"
, "imported_css"
, ""
, " z"
)
);
}
@Test public void Import_url_relative_skip() { // PURPOSE: if rel path, skip; "//site/a/b.css"; DATE:2014-02-03
fxt.Downloader().Stylesheet_prefix_(Bry_.new_utf8_("mem")); // stylesheet prefix prefix defaults to ""; set to "mem", else test will try to retrieve "//url" which will fail
Io_mgr._.InitEngine_mem();
Io_mgr._.SaveFilStr("mem//en.wikipedia.org/a/b.css", "imported_css");
fxt.Test_css_convert
( "x @import url(\"//en.wikipedia.org/a/b.css\") screen; z" // starts with "//"
, String_.Concat_lines_nl
( "x "
, "/*XOWA://en.wikipedia.org/a/b.css*/"
, "imported_css"
, ""
, " z"
)
);
}
@Test public void Import_url_space() { // PURPOSE: some css has spaces; replace with underlines else fails when downloaded; EX: https://it.wikivoyage.org/w/index.php?title=MediaWiki:Container e Infobox.css&action=raw&ctype=text/css; DATE:2015-03-08
Io_mgr._.InitEngine_mem();
Io_mgr._.SaveFilStr("mem/www/b_c.css", "imported_css");
fxt.Test_css_convert
( "x @import url(\"mem/www/b c.css\") screen; z"
, String_.Concat_lines_nl
( "x "
, "/*XOWA:mem/www/b_c.css*/"
, "imported_css"
, ""
, " z"
)
);
}
@Test public void Wikisource_freedimg() { // PURPOSE: check that "wikimedia" is replaced for FreedImg hack; PAGE:en.s:Page:Notes_on_Osteology_of_Baptanodon._With_a_Description_of_a_New_Species.pdf/3 DATE:2014-09-06
fxt.Downloader().Stylesheet_prefix_(Bry_.new_utf8_("mem")); // stylesheet prefix prefix defaults to ""; set to "mem", else test will try to retrieve "//url" which will fail
Io_mgr._.InitEngine_mem();
Io_mgr._.SaveFilStr("mem//en.wikisource.org/w/index.php?title=MediaWiki:Dynimg.css", ".freedImg img[src*=\"wikipedia\"], .freedImg img[src*=\"wikisource\"], .freedImg img[src*=\"score\"], .freedImg img[src*=\"math\"] {");
fxt.Test_css_convert
( "x @import url(\"//en.wikisource.org/w/index.php?title=MediaWiki:Dynimg.css\") screen; z" // starts with "//"
, String_.Concat_lines_nl
( "x "
, "/*XOWA://en.wikisource.org/w/index.php?title=MediaWiki:Dynimg.css*/"
, ".freedImg img[src*=\"wikipedia\"], .freedImg img[src*=\"wikisource\"], /*XOWA:handle file:// paths which will have /commons.wikimedia.org/ but not /wikipedia/ */ .freedImg img[src*=\"wikimedia\"], .freedImg img[src*=\"score\"], .freedImg img[src*=\"math\"] {"
, ""
, " z"
)
);
}
}
class Xoa_css_img_downloader_fxt {
public Xoa_css_img_downloader Downloader() {return downloader;} private Xoa_css_img_downloader downloader;
public void Clear() {
downloader = new Xoa_css_img_downloader();
downloader.Ctor(Gfo_usr_dlg_.Test(), new Xof_download_wkr_test(), Bry_.Empty);
}
public void Test_css_convert(String raw, String expd, String... expd_img_ary) {
ListAdp actl_img_list = ListAdp_.new_();
byte[] actl_bry = downloader.Convert_to_local_urls(Bry_.new_ascii_("mem/en.wikipedia.org"), Bry_.new_utf8_(raw), actl_img_list);
Tfds.Eq_str_lines(expd, String_.new_utf8_(actl_bry));
Tfds.Eq_ary_str(expd_img_ary, actl_img_list.XtoStrAry());
}
public void Test_clean_img_url(String raw_str, String expd) {
byte[] raw = Bry_.new_ascii_(raw_str);
byte[] actl = downloader.Clean_img_url(raw, raw.length);
Tfds.Eq(expd, actl == null ? null : String_.new_ascii_(actl));
}
public void Test_import_url(String raw, String expd) {
byte[] actl = Xoa_css_img_downloader.Import_url_build(Bry_.new_ascii_("http:"), Bry_.new_ascii_("//en.wikipedia.org"), Bry_.new_utf8_(raw));
Tfds.Eq(expd, String_.new_utf8_(actl));
}
}

View File

@@ -0,0 +1,56 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import gplx.core.btries.*; import gplx.core.primitives.*;
class Xob_css_parser {
private final Bry_bfr bfr = Bry_bfr.new_(255);
private final Xob_mirror_mgr mgr;
private final Xob_css_parser__url url_parser; private final Xob_css_parser__import import_parser;
public Xob_css_parser(Xob_mirror_mgr mgr) {
this.mgr = mgr;
this.url_parser = new Xob_css_parser__url(mgr.Site_url());
this.import_parser = new Xob_css_parser__import(url_parser);
}
public void Parse(byte[] src) {
int src_len = src.length; int pos = 0;
while (pos < src_len) {
byte b = src[pos];
Object o = tkns_trie.Match_bgn_w_byte(b, src, pos, src_len);
if (o == null) {
bfr.Add_byte(b);
++pos;
}
else {
byte tkn_tid = ((Byte_obj_val)o).Val();
int match_pos = tkns_trie.Match_pos();
Xob_css_tkn__base tkn = null;
switch (tkn_tid) {
case Tkn_url: tkn = url_parser.Parse(src, src_len, pos, match_pos); break;
case Tkn_import: tkn = import_parser.Parse(src, src_len, pos, match_pos); break;
}
tkn.Process(mgr);
pos = tkn.Write(bfr, src);
}
}
}
private static final byte Tkn_import = 1, Tkn_url = 2;
private static final Btrie_slim_mgr tkns_trie = Btrie_slim_mgr.ci_ascii_()
.Add_str_byte("@import" , Tkn_import)
.Add_str_byte(" url(" , Tkn_url)
;
}

View File

@@ -0,0 +1,43 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import gplx.xowa.files.downloads.*;
class Xob_css_parser__import {
// // "//id.wikibooks.org/w/index.php?title=MediaWiki:Common.css&oldid=43393&action=raw&ctype=text/css";
private final Xob_css_parser__url url_parser;
public Xob_css_parser__import(Xob_css_parser__url url_parser) {this.url_parser = url_parser;}
public Xob_css_tkn__base Parse(byte[] src, int src_len, int tkn_bgn, int tkn_end) { // " @import"
int bgn_pos = Bry_finder.Find_fwd_while_ws(src, tkn_end, src_len); // skip any ws after " @import"
if (bgn_pos == src_len) return Xob_css_tkn__warn.new_(tkn_bgn, tkn_end, "mirror.parser.import:EOS after import; bgn=~{0}", tkn_bgn);
if (!Bry_.HasAtBgn(src, Tkn_url_bry, bgn_pos, src_len)) return Xob_css_tkn__warn.new_(tkn_bgn, tkn_end, "mirror.parser.import:url missing; bgn=~{0}", tkn_bgn);
tkn_end = bgn_pos + Tkn_url_bry.length;
Xob_css_tkn__base frag = url_parser.Parse(src, src_len, bgn_pos, tkn_end);
if (frag.Tid() != Xob_css_tkn__url.Tid_url) return Xob_css_tkn__warn.new_(tkn_bgn, frag.Pos_end(), "mirror.parser.import:url invalid; bgn=~{0}", tkn_bgn);
Xob_css_tkn__url url_frag = (Xob_css_tkn__url)frag;
byte[] src_url = url_frag.Src_url();
src_url = Bry_.Replace(src_url, Byte_ascii.Space, Byte_ascii.Underline); // NOTE: must replace spaces with underlines else download will fail; EX:https://it.wikivoyage.org/w/index.php?title=MediaWiki:Container e Infobox.css&action=raw&ctype=text/css; DATE:2015-03-08
int semic_pos = Bry_finder.Find_fwd(src, Byte_ascii.Semic, frag.Pos_end(), src_len);
return Xob_css_tkn__import.new_(tkn_bgn, semic_pos + 1, src_url, url_frag.Trg_url(), url_frag.Quote_byte());
}
private static final byte[] Tkn_url_bry = Bry_.new_ascii_("url(");
public static final byte[]
Wikisource_dynimg_ttl = Bry_.new_ascii_("en.wikisource.org/w/index.php?title=MediaWiki:Dynimg.css")
, Wikisource_dynimg_find = Bry_.new_ascii_(".freedImg img[src*=\"wikipedia\"], .freedImg img[src*=\"wikisource\"], .freedImg img[src*=\"score\"], .freedImg img[src*=\"math\"] {")
, Wikisource_dynimg_repl = Bry_.new_ascii_(".freedImg img[src*=\"wikipedia\"], .freedImg img[src*=\"wikisource\"], /*XOWA:handle file:// paths which will have /commons.wikimedia.org/ but not /wikipedia/ */ .freedImg img[src*=\"wikimedia\"], .freedImg img[src*=\"score\"], .freedImg img[src*=\"math\"] {")
;
}

View File

@@ -0,0 +1,38 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import org.junit.*;
public class Xob_css_parser__import_tst {
@Before public void init() {fxt.Clear();} private Xob_css_parser__import_fxt fxt = new Xob_css_parser__import_fxt();
@Test public void Basic() {fxt.Test_parse_import (" @import url(//site/a.png)" , " @import url('site/a.png')");}
@Test public void Warn_eos() {fxt.Test_parse_warn (" @import" , " @import" , "EOS");}
@Test public void Warn_missing() {fxt.Test_parse_warn (" @import ('//site/a.png')" , " @import" , "missing");} // no "url("
@Test public void Warn_invalid() {fxt.Test_parse_warn (" @import url('//site')" , " @import url('//site')" , "invalid");} // invalid
}
class Xob_css_parser__import_fxt extends Xob_css_parser__url_fxt { private Xob_css_parser__import import_parser;
@Override public void Clear() {
super.Clear();
this.import_parser = new Xob_css_parser__import(url_parser);
}
@Override protected void Exec_parse_hook() {
this.cur_frag = import_parser.Parse(src_bry, src_bry.length, 0, 8); // 8=" @import".length
}
public void Test_parse_import(String src_str, String expd) {
Exec_parse(src_str, Xob_css_tkn__base.Tid_import, expd);
}
}

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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
class Xob_css_parser__url {
private final byte[] site;
public Xob_css_parser__url(byte[] site) {this.site = site;}
public Xob_css_tkn__base Parse(byte[] src, int src_len, int tkn_bgn, int tkn_end) { // " url"
int bgn_pos = Bry_finder.Find_fwd_while_ws(src, tkn_end, src_len); // skip any ws after " url("
if (bgn_pos == src_len) return Xob_css_tkn__warn.new_(tkn_bgn, tkn_end, "mirror.parser.url:EOS; bgn=~{0}", tkn_bgn);
byte end_byte = src[bgn_pos]; // note that first non-ws byte should determine end_byte
byte quote_byte = end_byte;
switch (end_byte) {
case Byte_ascii.Quote: case Byte_ascii.Apos: // quoted; increment position; EX: ' url("a.png")'
++bgn_pos;
break;
default: // not quoted; end byte is ")"; EX: ' url(a.png)'
end_byte = Byte_ascii.Paren_end;
quote_byte = Byte_ascii.Nil;
break;
}
int end_pos = Bry_finder.Find_fwd(src, end_byte, bgn_pos, src_len);
if (end_pos == Bry_.NotFound) // unclosed "url("; exit since nothing else will be found
return Xob_css_tkn__warn.new_(tkn_bgn, tkn_end, "mirror.parser.url:dangling; bgn=~{0} excerpt=~{1}", bgn_pos, String_.new_utf8_len_safe_(src, tkn_bgn, tkn_bgn + 128));
if (end_pos - bgn_pos == 0) // empty; "url()"; ignore
return Xob_css_tkn__warn.new_(tkn_bgn, tkn_end, "mirror.parser.url:empty; bgn=~{0} excerpt=~{1}", bgn_pos, String_.new_utf8_len_safe_(src, tkn_bgn, tkn_bgn + 128));
byte[] url_orig = Bry_.Mid(src, bgn_pos, end_pos); int url_orig_len = url_orig.length;
++end_pos; // increment end_pos so rv will be after it;
if ( end_byte != Byte_ascii.Paren_end) { // end_byte is apos / quote
if ( end_pos < src_len
&& src[end_pos] == Byte_ascii.Paren_end)
++end_pos;
else
return Xob_css_tkn__warn.new_(tkn_bgn, end_pos, "mirror.parser.url:base64 dangling; bgn=~{0} excerpt=~{1}", bgn_pos, String_.new_utf8_(url_orig));
}
if (Bry_.HasAtBgn(url_orig, Bry_data_image)) // base64
return Xob_css_tkn__base64.new_(tkn_bgn, end_pos);
byte[] src_url = Xob_url_fixer.Fix(site, url_orig, url_orig_len);
if (src_url == null) // could not convert
return Xob_css_tkn__warn.new_(tkn_bgn, end_pos, "mirror.parser.url:invalid url; bgn=~{0} excerpt=~{1}", tkn_bgn, String_.new_utf8_(url_orig));
return Xob_css_tkn__url.new_(tkn_bgn, end_pos, src_url, quote_byte);
}
private static final byte[] Bry_data_image = Bry_.new_ascii_("data:image/");
}

View File

@@ -0,0 +1,60 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import org.junit.*;
public class Xob_css_parser__url_tst {
@Before public void init() {fxt.Clear();} private Xob_css_parser__url_fxt fxt = new Xob_css_parser__url_fxt();
@Test public void Quote_none() {fxt.Test_parse_url(" url(//site/A.png) b" , " url('site/A.png')");}
@Test public void Quote_apos() {fxt.Test_parse_url(" url('//site/A.png') b" , " url('site/A.png')");}
@Test public void Quote_quote() {fxt.Test_parse_url(" url(\"//site/A.png\") b" , " url(\"site/A.png\")");}
@Test public void Base64() {fxt.Test_parse_base64(" url('data:image/png;base64,BASE64DATA;ABC=') b", " url('data:image/png;base64,BASE64DATA;ABC=')");}
@Test public void Base64_dangling() {fxt.Test_parse_warn(" url('data:image/png;base64,BASE64DATA;ABC=' ", " url('data:image/png;base64,BASE64DATA;ABC='", "base64 dangling");}
@Test public void Warn_eos() {fxt.Test_parse_warn(" url(" , " url(" , "EOS");}
@Test public void Warn_dangling() {fxt.Test_parse_warn(" url(a" , " url(" , "dangling");}
@Test public void Warn_empty() {fxt.Test_parse_warn(" url()" , " url(" , "empty");}
@Test public void Warn_site() {fxt.Test_parse_warn(" url('//site')" , " url('//site')" , "invalid");}
}
class Xob_css_parser__url_fxt {
protected Xob_css_parser__url url_parser; private final Bry_bfr bfr = Bry_bfr.new_(32);
protected Xob_css_tkn__base cur_frag; protected byte[] src_bry;
@gplx.Virtual public void Clear() {
url_parser = new Xob_css_parser__url(Bry_.new_ascii_("site"));
}
protected void Exec_parse(String src_str, int expd_tid, String expd_str) {
this.src_bry = Bry_.new_utf8_(src_str);
this.Exec_parse_hook();
cur_frag.Write(bfr, src_bry);
String actl_str = bfr.Xto_str_and_clear();
Tfds.Eq(expd_tid, cur_frag.Tid(), "wrong tid; expd={0}, actl={1}", expd_tid, cur_frag.Tid());
Tfds.Eq(expd_str, actl_str);
}
@gplx.Virtual protected void Exec_parse_hook() {
this.cur_frag = url_parser.Parse(src_bry, src_bry.length, 0, 5); // 5=" url(".length
}
public void Test_parse_url(String src_str, String expd) {
Exec_parse(src_str, Xob_css_tkn__base.Tid_url, expd);
}
public void Test_parse_base64(String src_str, String expd) {
Exec_parse(src_str, Xob_css_tkn__base.Tid_base64, expd);
}
public void Test_parse_warn(String src_str, String expd, String warn) {
Exec_parse(src_str, Xob_css_tkn__base.Tid_warn, expd);
Xob_css_tkn__warn sub_frag = (Xob_css_tkn__warn)cur_frag;
Tfds.Eq(true, String_.Has(sub_frag.Fail_msg(), warn));
}
}

View File

@@ -0,0 +1,117 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
abstract class Xob_css_tkn__base {
public void Init(int tid, int pos_bgn, int pos_end) {
this.tid = tid; this.pos_bgn = pos_bgn; this.pos_end = pos_end;
}
public int Tid() {return tid;} protected int tid;
public int Pos_bgn() {return pos_bgn;} protected int pos_bgn;
public int Pos_end() {return pos_end;} protected int pos_end;
@gplx.Virtual public void Process(Xob_mirror_mgr mgr) {}
public abstract int Write(Bry_bfr bfr, byte[] src);
public static final int Tid_warn = 1, Tid_base64 = 2, Tid_url = 3, Tid_import = 4;
}
class Xob_css_tkn__warn extends Xob_css_tkn__base {
public String Fail_msg() {return fail_msg;} private String fail_msg;
@Override public void Process(Xob_mirror_mgr mgr) {
mgr.Usr_dlg().Warn_many("", "", fail_msg);
}
@Override public int Write(Bry_bfr bfr, byte[] src) {
bfr.Add_mid(src, pos_bgn, pos_end);
return pos_end;
}
public static Xob_css_tkn__warn new_(int pos_bgn, int pos_end, String fmt, Object... fmt_args) {
Xob_css_tkn__warn rv = new Xob_css_tkn__warn();
rv.Init(Tid_warn, pos_bgn, pos_end);
rv.fail_msg = String_.Format(fmt, fmt_args);
return rv;
}
}
class Xob_css_tkn__base64 extends Xob_css_tkn__base {
@Override public int Write(Bry_bfr bfr, byte[] src) {
bfr.Add_mid(src, pos_bgn, pos_end);
return pos_end;
}
public static Xob_css_tkn__base64 new_(int pos_bgn, int pos_end) {
Xob_css_tkn__base64 rv = new Xob_css_tkn__base64();
rv.Init(Tid_base64, pos_bgn, pos_end);
return rv;
}
}
class Xob_css_tkn__url extends Xob_css_tkn__base {
public byte Quote_byte() {return quote_byte;} private byte quote_byte;
public byte[] Src_url() {return src_url;} private byte[] src_url;
public byte[] Trg_url() {return trg_url;} private byte[] trg_url;
@Override public void Process(Xob_mirror_mgr mgr) {
mgr.File_hash().Add_if_new(src_url, new Xobc_download_itm(Xobc_download_itm.Tid_file, String_.new_utf8_(src_url), trg_url));
}
@Override public int Write(Bry_bfr bfr, byte[] src) {
byte quote = quote_byte; if (quote == Byte_ascii.Nil) quote = Byte_ascii.Apos;
bfr.Add_str_ascii(" url("); // EX: ' url('
bfr.Add_byte(quote).Add(trg_url).Add_byte(quote); // EX: '"a.png"'
bfr.Add_byte(Byte_ascii.Paren_end); // EX: ')'
return pos_end;
}
public static Xob_css_tkn__url new_(int pos_bgn, int pos_end, byte[] src_url, byte quote_byte) {
Xob_css_tkn__url rv = new Xob_css_tkn__url();
rv.Init(Tid_url, pos_bgn, pos_end);
rv.src_url = src_url; rv.trg_url = To_fsys(src_url); rv.quote_byte = quote_byte;
return rv;
}
public static byte[] To_fsys(byte[] src) {
if (!Op_sys.Cur().Tid_is_wnt()) return src;
src = Bry_.Copy(src); // NOTE: must call ByteAry.Copy else url_actl will change *inside* bry
int len = src.length;
for (int i = 0; i < len; ++i) {
byte b = src[i];
switch (b) {
case Byte_ascii.Slash:
case Byte_ascii.Backslash:
break;
case Byte_ascii.Lt: case Byte_ascii.Gt: case Byte_ascii.Colon: case Byte_ascii.Pipe: case Byte_ascii.Question: case Byte_ascii.Asterisk: case Byte_ascii.Quote:
src[i] = Byte_ascii.Underline;
break;
default:
break;
}
}
return src;
}
}
class Xob_css_tkn__import extends Xob_css_tkn__base {
public byte Quote_byte() {return quote_byte;} private byte quote_byte;
public byte[] Src_url() {return src_url;} private byte[] src_url;
public byte[] Trg_url() {return trg_url;} private byte[] trg_url;
@Override public void Process(Xob_mirror_mgr mgr) {
mgr.Code_add(src_url);
}
@Override public int Write(Bry_bfr bfr, byte[] src) {
byte quote = quote_byte; if (quote == Byte_ascii.Nil) quote = Byte_ascii.Apos;
bfr.Add_str_ascii(" @import url("); // EX: ' @import url('
bfr.Add_byte(quote).Add(trg_url).Add_byte(quote); // EX: '"a.png"'
bfr.Add_byte(Byte_ascii.Paren_end); // EX: ')'
return pos_end;
}
public static Xob_css_tkn__import new_(int pos_bgn, int pos_end, byte[] src_url, byte[] trg_url, byte quote_byte) {
Xob_css_tkn__import rv = new Xob_css_tkn__import();
rv.Init(Tid_import, pos_bgn, pos_end);
rv.src_url = src_url; rv.trg_url = trg_url; rv.quote_byte = quote_byte;
return rv;
}
}

View File

@@ -0,0 +1,59 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import gplx.ios.*; import gplx.xowa.files.downloads.*;
public class Xob_mirror_mgr {
private final Xof_download_wkr download_wkr; private final Xob_css_parser css_parser;
private final byte[] page_url; private final Io_url fsys_root;
public Xob_mirror_mgr(Gfo_usr_dlg usr_dlg, Xof_download_wkr download_wkr, byte[] site_url, byte[] page_url, Io_url fsys_root) {
this.usr_dlg = usr_dlg; this.download_wkr = download_wkr;
this.site_url = site_url; this.page_url = page_url; this.fsys_root = fsys_root;
this.css_parser = new Xob_css_parser(this);
}
public Gfo_usr_dlg Usr_dlg() {return usr_dlg;} private final Gfo_usr_dlg usr_dlg;
public byte[] Site_url() {return site_url;} private final byte[] site_url;
public void Code_add(byte[] src_url) {
byte[] trg_url = Xob_css_tkn__url.To_fsys(src_url);
code_hash.Add_if_new(src_url, new Xobc_download_itm(Xobc_download_itm.Tid_css, String_.new_utf8_(src_url), trg_url));
}
public OrderedHash Code_hash() {return code_hash;} private final OrderedHash code_hash = OrderedHash_.new_();
public OrderedHash File_hash() {return file_hash;} private final OrderedHash file_hash = OrderedHash_.new_();
public void Exec() {
usr_dlg.Plog_many("", "", "html_mirror:download.root_page; url=~{0}", page_url);
IoEngine_xrg_downloadFil download_xrg = download_wkr.Download_xrg();
css_parser.Parse(download_xrg.Exec_as_bry(String_.new_utf8_(page_url)));
while (true) {
Xobc_download_itm[] code_ary = (Xobc_download_itm[])code_hash.Xto_ary_and_clear(Xobc_download_itm.class);
int code_ary_len = code_ary.length;
if (code_ary_len == 0) break;
for (int i = 0; i < code_ary_len; ++i) {
Xobc_download_itm code = code_ary[i];
byte[] code_src = download_xrg.Exec_as_bry(code.Http_str());
Io_mgr._.SaveFilBry(fsys_root.Gen_sub_path_for_os(String_.new_utf8_(code.Fsys_url())), code_src);
css_parser.Parse(code_src);
}
}
Xobc_download_itm[] file_ary = (Xobc_download_itm[])file_hash.Xto_ary_and_clear(Xobc_download_itm.class);
int file_ary_len = file_ary.length;
for (int i = 0; i < file_ary_len; ++i) {
Xobc_download_itm file = file_ary[i];
download_xrg.Init(file.Http_str(), Io_url_.new_fil_(fsys_root.Gen_sub_path_for_os(String_.new_utf8_(file.Fsys_url()))));
download_xrg.Exec();
}
}
}

View File

@@ -0,0 +1,63 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import org.junit.*;
import gplx.xowa.files.downloads.*;
public class Xob_mirror_mgr_tst {
@Before public void init() {fxt.Clear();} private Xob_mirror_mgr_fxt fxt = new Xob_mirror_mgr_fxt();
@Test public void Download_1() {
fxt.Fsys().Init_fil("mem/http/enwiki/file/a.png");
fxt.Fsys().Init_fil("mem/http/enwiki/wiki/Main_Page", "url('//enwiki/wiki/a.png')");
// fxt.Test_css();
// fxt.Fsys().Test_fil("url('//enwiki/wiki/a.png')", "url('enwiki/wiki/a.png')"); // remove "//"
// fxt.Fsys().Test_fil("mem/fsys/enwiki/file/a.png");
}
}
class Xob_mirror_mgr_fxt {
// private Xob_mirror_mgr mirror_mgr;
public Io_fsys_fxt Fsys() {return fsys;} private final Io_fsys_fxt fsys = new Io_fsys_fxt();
public void Clear() {
fsys.Clear();
// mirror_mgr = new Xob_mirror_mgr(Gfo_usr_dlg_.Noop, new Xof_download_wkr_test(), Bry_.new_ascii_("mem/http/enwiki"), Bry_.new_ascii_("mem/http/enwiki/wiki/Main_Page"), Io_url_.new_dir_("mem/fsys"));
}
public void Test_css(String raw, String expd) {
// byte[] raw_bry = Bry_.new_utf8_(raw);
// mirror_mgr.Exec();
}
}
class Io_fsys_fxt {
public void Clear() {
Io_mgr._.InitEngine_mem();
}
public void Init_fil(String url_str) {
Io_url url = Io_url_.new_fil_(url_str);
Init_fil(url, url.NameAndExt());
}
public void Init_fil(String url_str, String text) {Init_fil(Io_url_.new_fil_(url_str), text);}
public void Init_fil(Io_url url, String text) {
Io_mgr._.SaveFilStr(url, text);
}
public void Test_fil(String url_str) {
Io_url url = Io_url_.new_fil_(url_str);
Test_fil(url, url.NameAndExt());
}
public void Test_fil(String url, String expd) {Test_fil(Io_url_.new_fil_(url), expd);}
public void Test_fil(Io_url url, String expd) {
Tfds.Eq_str_lines(expd, Io_mgr._.LoadFilStr(url));
}
}

View File

@@ -0,0 +1,99 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import gplx.core.primitives.*; import gplx.core.btries.*;
class Xob_url_fixer {
public static byte[] Fix(byte[] site, byte[] src, int src_len) { // return "site/img.png" if "//site/img.png" or "http://site/img.png"; also, handle "img.png?key=val"
int bgn = 0; int bgn_tkn_tid = 0;
Object o = Xob_url_fixer_tkn.Bgn_trie().Match_bgn(src, bgn, src_len);
if (o != null) {
Xob_url_fixer_tkn tkn = (Xob_url_fixer_tkn)o;
bgn_tkn_tid = tkn.Tid();
switch (bgn_tkn_tid) {
case Xob_url_fixer_tkn.Tid_bgn_slash_2:
case Xob_url_fixer_tkn.Tid_bgn_http:
case Xob_url_fixer_tkn.Tid_bgn_https:
bgn = tkn.Raw_len(); // remove "//", "http://", "https://"
break;
case Xob_url_fixer_tkn.Tid_bgn_slash_1: // convert "/a" to "site/a"
src = Bry_.Add(site, src);
src_len = src.length;
break;
}
}
int pos = bgn, end = src_len; boolean no_slashes = true;
Btrie_slim_mgr mid_trie = Xob_url_fixer_tkn.Mid_trie();
while (pos < src_len) {
byte b = src[pos];
o = mid_trie.Match_bgn_w_byte(b, src, pos, src_len);
if (o != null) {
Xob_url_fixer_tkn tkn = (Xob_url_fixer_tkn)o;
switch (tkn.Tid()) {
case Xob_url_fixer_tkn.Tid_mid_slash: if (no_slashes) no_slashes = false; break;
case Xob_url_fixer_tkn.Tid_mid_question: end = pos; pos = src_len; break;
case Xob_url_fixer_tkn.Tid_mid_rel_1:
case Xob_url_fixer_tkn.Tid_mid_rel_2:
Bry_bfr tmp_bfr = Bry_bfr.new_(src_len);
byte[] to_rel_root = Bry_.Mid(src, bgn, pos);
byte[] to_rel_qry = Bry_.Mid(src, pos, src_len);
src = gplx.xowa.xtns.pfuncs.ttls.Pfunc_rel2abs.Rel2abs(tmp_bfr, to_rel_qry, to_rel_root, Int_obj_ref.neg1_());
bgn = pos = 0;
end = src_len = src.length;
no_slashes = true;
break;
}
}
++pos;
}
if (no_slashes) return null; // invalid; EX: "//site"
return Bry_.Mid(src, bgn, end);
}
}
class Xob_url_fixer_tkn {
public Xob_url_fixer_tkn(int tid, byte[] raw) {this.tid = tid; this.raw = raw; this.raw_len = raw.length;}
public int Tid() {return tid;} private int tid;
public byte[] Raw() {return raw;} private byte[] raw;
public int Raw_len() {return raw_len;} private int raw_len;
public static Xob_url_fixer_tkn new_(int tid, String raw) {return new Xob_url_fixer_tkn(tid, Bry_.new_utf8_(raw));}
private static void trie_add(Btrie_slim_mgr trie, int tid, String s) {trie.Add_obj(s, new_(tid, s));}
public static final int Tid_bgn_slash_1 = 1, Tid_bgn_slash_2 = 2, Tid_bgn_http = 3, Tid_bgn_https = 4;
private static Btrie_slim_mgr bgn_trie;
public static Btrie_slim_mgr Bgn_trie() {
if (bgn_trie == null) {
bgn_trie = Btrie_slim_mgr.ci_ascii_();
trie_add(bgn_trie, Tid_bgn_slash_1 , "/");
trie_add(bgn_trie, Tid_bgn_slash_2 , "//");
trie_add(bgn_trie, Tid_bgn_http , "http://");
trie_add(bgn_trie, Tid_bgn_https , "https://");
}
return bgn_trie;
}
public static final int Tid_mid_rel_1 = 1, Tid_mid_rel_2 = 2, Tid_mid_slash = 3, Tid_mid_question = 4;
private static Btrie_slim_mgr mid_trie;
public static Btrie_slim_mgr Mid_trie() {
if (mid_trie == null) {
mid_trie = Btrie_slim_mgr.ci_ascii_();
trie_add(mid_trie, Tid_mid_rel_1 , "/../");
trie_add(mid_trie, Tid_mid_rel_2 , "/./");
trie_add(mid_trie, Tid_mid_slash , "/");
trie_add(mid_trie, Tid_mid_question , "?");
}
return mid_trie;
}
}

View File

@@ -0,0 +1,42 @@
/*
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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
import org.junit.*;
public class Xob_url_fixer_tst {
@Before public void init() {fxt.Clear();} private Xob_url_fixer_fxt fxt = new Xob_url_fixer_fxt();
@Test public void Slash2() {fxt.Test_fix("//site/a.png" , "site/a.png");}
@Test public void Http() {fxt.Test_fix("http://site/a.png" , "site/a.png");}
@Test public void Https() {fxt.Test_fix("https://site/a.png" , "site/a.png");}
@Test public void Qarg() {fxt.Test_fix("//site/a.png?key=val" , "site/a.png");}
@Test public void Qarg_dir() {fxt.Test_fix("//site/a/b/c.png?key=val" , "site/a/b/c.png");}
@Test public void Root() {fxt.Test_fix("/a/b.png" , "site/a/b.png");} // EX:/static/images/project-logos/wikivoyage.png; DATE:2015-05-09
@Test public void Rel_dot2() {fxt.Test_fix("//site/a/../b/c.png" , "site/b/c.png");} // DATE:2015-05-09
@Test public void Rel_dot2_mult() {fxt.Test_fix("//site/a/../b/../c/d.png" , "site/c/d.png");} // DATE:2015-05-09
@Test public void Rel_dot1() {fxt.Test_fix("//site/a/./b/c.png" , "site/a/b/c.png");} // DATE:2015-05-09
@Test public void Site_only() {fxt.Test_fix("//site" , null);}
}
class Xob_url_fixer_fxt {
public void Site_(String v) {site_bry = Bry_.new_utf8_(v);} private byte[] site_bry;
public void Clear() {
this.Site_("site");
}
public void Test_fix(String raw, String expd) {
byte[] raw_bry = Bry_.new_utf8_(raw);
Tfds.Eq(expd, String_.new_utf8_(Xob_url_fixer.Fix(site_bry, raw_bry, raw_bry.length)));
}
}

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.xowa.bldrs.css; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*;
class Xobc_download_itm {
public Xobc_download_itm(int tid, String http_str, byte[] fsys_url) {this.tid = tid; this.http_str = http_str; this.fsys_url = fsys_url;}
public int Tid() {return tid;} private final int tid;
public String Http_str() {return http_str;} private final String http_str;
public byte[] Fsys_url() {return fsys_url;} private final byte[] fsys_url;
public static final int Tid_file = 1, Tid_html = 2, Tid_css = 3;
}

View File

@@ -116,7 +116,7 @@ public class Xob_xml_parser_tst {
private static final String Date_1 = "2012-01-01T01:01:01Z", Date_2 = "2012-02-02T02:02:02Z"; DateAdp_parser dateParser = DateAdp_parser.new_();
Bry_bfr bfr = Bry_bfr.new_();
Xob_xml_page_bldr page_bldr = new Xob_xml_page_bldr(); Io_buffer_rdr fil; Xob_xml_parser page_parser = new Xob_xml_parser(); Xob_bldr bldr;
Gfo_usr_dlg usr_dlg = Gfo_usr_dlg_base.test_();
Gfo_usr_dlg usr_dlg = Gfo_usr_dlg_.Test();
int tst_parse(Io_buffer_rdr fil, Xowd_page_itm expd, int cur_pos) {
Xowd_page_itm actl = new Xowd_page_itm();
int rv = page_parser.Parse_page(actl, usr_dlg, fil, fil.Bfr(), cur_pos, ns_mgr);

View File

@@ -87,11 +87,11 @@ class Xoctg_idx_mgr_fxt {
}
return bfr.Xto_bry_and_clear();
}
public Xoctg_idx_mgr_fxt Init_itms(int block_len, byte[] src) {idx_mgr.Block_len_(block_len); idx_mgr.Index(Gfo_usr_dlg_base.test_(), Ctg_name, src); return this;}
public Xoctg_idx_mgr_fxt Init_itms(int block_len, byte[] src) {idx_mgr.Block_len_(block_len); idx_mgr.Index(Gfo_usr_dlg_.Test(), Ctg_name, src); return this;}
public Xoctg_idx_mgr_fxt Init_block_len(int block_len) {idx_mgr.Block_len_(block_len); return this;}
public Xoctg_idx_mgr_fxt Init_src(byte[] v) {src = v; src_len = v.length; return this;} private byte[] src; int src_len;
public Xoctg_idx_mgr_fxt Test_index(byte[] src, String... expd) {
idx_mgr.Index(Gfo_usr_dlg_base.test_(), Ctg_name, src);
idx_mgr.Index(Gfo_usr_dlg_.Test(), Ctg_name, src);
Tfds.Eq_ary_str(expd, Idx_mgr_itms(idx_mgr));
return this;
}
@@ -118,7 +118,7 @@ class Xoctg_idx_mgr_fxt {
}
public Xoctg_idx_mgr_fxt Test_find(String find, boolean fill_at_bgn, String[] expd_ary, String last_plus_one) {
if (tmp_list == null) tmp_list = ListAdp_.new_();
idx_mgr.Index(Gfo_usr_dlg_base.test_(), Bry_.Empty, src);
idx_mgr.Index(Gfo_usr_dlg_.Test(), Bry_.Empty, src);
tmp_list.Clear();
idx_mgr.Find(tmp_list, src, fill_at_bgn, Bry_.new_ascii_(find), 3, tmp_last_plus_one);
Tfds.Eq_ary(expd_ary, To_str_ary(tmp_list));

View File

@@ -38,7 +38,7 @@ class Xoctg_url_fxt {
} private Xoa_url_parser parser; Xoa_url page_url; Xoctg_url ctg_url;
public void Test_parse(String url_str, Xoctg_url_chkr expd) {
parser.Parse(page_url, Bry_.new_utf8_(url_str));
ctg_url.Parse(Gfo_usr_dlg_base.test_(), page_url);
ctg_url.Parse(Gfo_usr_dlg_.Test(), page_url);
expd.Chk(ctg_url);
expd.Clear();
}

View File

@@ -29,7 +29,7 @@ public class Xodb_save_mgr_sql implements Xodb_save_mgr {
int ns_id = ttl.Ns().Id();
Xowd_db_file db_file = db_mgr.Core_data_mgr().Db__core();
int ns_count = db_file.Tbl__ns().Select_ns_count(ns_id) + 1;
int page_id = db_file.Tbl__cfg().Select_int_or("db", "page.id_nxt", -1);
int page_id = db_file.Tbl__cfg().Select_int_or("db", "page.id_next", -1);
if (page_id == -1) { // HACK: changed for tests; was dbs.qrys.Db_qry_sql.rdr_("SELECT (Max(page_id) + 1) AS max_page_id FROM page;")
// Db_rdr rdr = db_mgr.Core_data_mgr().Tbl__page().Conn().Stmt_new(Db_qry_sql.rdr_("SELECT (Max(page_id) + 1) AS max_page_id FROM page;")).Exec_select__rls_manual();
Db_rdr rdr = db_mgr.Core_data_mgr().Tbl__page().Conn().Stmt_select(db_file.Tbl__page().Tbl_name(), String_.Ary(db_file.Tbl__page().Fld_page_id()), Db_meta_fld.Ary_empy).Exec_select__rls_auto();
@@ -64,11 +64,15 @@ public class Xodb_save_mgr_sql implements Xodb_save_mgr {
public void Data_update(Xoae_page page, byte[] text_raw) {
boolean redirect = db_mgr.Wiki().Redirect_mgr().Is_redirect(text_raw, text_raw.length);
DateAdp modified = update_modified_on_enabled ? DateAdp_.Now() : page.Revision_data().Modified_on();
db_mgr.Core_data_mgr().Tbl__page().Update__redirect__modified(page.Revision_data().Id(), redirect, modified);
int page_id = page.Revision_data().Id();
db_mgr.Core_data_mgr().Tbl__page().Update__redirect__modified(page_id, redirect, modified);
Xowd_page_itm db_page = new Xowd_page_itm();
db_mgr.Load_mgr().Load_by_id(db_page, page.Revision_data().Id());
Xowd_text_tbl text_tbl = db_mgr.Core_data_mgr().Dbs__get_at(db_page.Text_db_id()).Tbl__text();
text_tbl.Update(page.Revision_data().Id(), text_raw);
int html_db_id = db_page.Html_db_id();
if (html_db_id != -1)
db_mgr.Core_data_mgr().Tbl__page().Update__html_db_id(page_id, -1); // zap html_db_id so that next load will repopulate it
}
public void Data_rename(Xoae_page page, int trg_ns, byte[] trg_ttl) {
db_mgr.Core_data_mgr().Tbl__page().Update__ns__ttl(page.Revision_data().Id(), trg_ns, trg_ttl);

View File

@@ -0,0 +1,23 @@
/*
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.xowa.files.downloads; import gplx.*; import gplx.xowa.*; import gplx.xowa.files.*;
import gplx.ios.*;
public interface Xof_download_wkr {
byte Download(boolean src_is_web, String src, Io_url trg, String prog_fmt_hdr);
IoEngine_xrg_downloadFil Download_xrg();
}

View File

@@ -0,0 +1,40 @@
/*
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.xowa.files.downloads; import gplx.*; import gplx.xowa.*; import gplx.xowa.files.*;
import gplx.ios.*;
public class Xof_download_wkr_io implements Xof_download_wkr {
IoEngine_xrg_downloadFil xrg = Io_mgr._.DownloadFil_args("", Io_url_.Null);
public IoEngine_xrg_downloadFil Download_xrg() {return xrg;}
public String Download_err() {return download_err;} private String download_err = "";
public byte Download(boolean src_is_web, String src_str, Io_url trg_url, String prog_fmt_hdr) {
download_err = "";
if (src_is_web) {
xrg.Prog_fmt_hdr_(prog_fmt_hdr);
xrg.Init(src_str, trg_url);
xrg.Exec();
return xrg.Rslt();
}
else {
Io_url src_url = Io_url_.new_fil_(src_str);
if (!Io_mgr._.ExistsFil(src_url)) return IoEngine_xrg_downloadFil.Rslt_fail_file_not_found;
try {Io_mgr._.CopyFil(src_url, trg_url, true);}
catch (Exception exc) {Err_.Noop(exc); return IoEngine_xrg_downloadFil.Rslt_fail_unknown;}
return IoEngine_xrg_downloadFil.Rslt_pass;
}
}
}

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.xowa.files.downloads; import gplx.*; import gplx.xowa.*; import gplx.xowa.files.*;
import gplx.ios.*;
public class Xof_download_wkr_test implements Xof_download_wkr {
public IoEngine_xrg_downloadFil Download_xrg() {return IoEngine_xrg_downloadFil.new_("", Io_url_.Null).Trg_engine_key_(IoEngine_.MemKey);}
public byte Download(boolean src_is_web, String src_str, Io_url trg_url, String prog_fmt_hdr) {
Io_mgr._.CreateDirIfAbsent(trg_url.OwnerDir());
Io_url src_url = Io_url_.new_fil_(src_str);
if (!Io_mgr._.ExistsFil(src_url)) return IoEngine_xrg_downloadFil.Rslt_fail_file_not_found;
try {Io_mgr._.CopyFil(src_url, trg_url, true);}
catch (Exception exc) {Err_.Noop(exc); return IoEngine_xrg_downloadFil.Rslt_fail_unknown;}
return IoEngine_xrg_downloadFil.Rslt_pass;
}
}

View File

@@ -47,7 +47,7 @@ class Fs_root_dir_fxt {
root_dir = new Fs_root_dir();
orig_fil_tbl = new Orig_fil_tbl();
Xof_img_wkr_query_img_size img_size_wkr = new Xof_img_wkr_query_img_size_test();
root_dir.Init(url, orig_fil_tbl, Gfo_usr_dlg_.Null, img_size_wkr);
root_dir.Init(url, orig_fil_tbl, Gfo_usr_dlg_.Noop, img_size_wkr);
}
public Orig_fil_mok itm_() {return new Orig_fil_mok();}
public void Init_fs(String url, int w, int h) {Save_img(url, w, h);}

View File

@@ -27,7 +27,7 @@ public class Js_img_mgr {
Js_img_mgr.Update_img(page, js_wkr, itm.Html_img_wkr(), itm.Html_uid(), itm.Lnki_type(), itm.Html_elem_tid(), itm.Html_w(), itm.Html_h(), itm.Html_view_url().To_http_file_str(), itm.Orig_w(), itm.Orig_h(), itm.Html_orig_url().To_http_file_str(), itm.Lnki_ttl(), itm.Gallery_mgr_h());
}
public static void Update_link_missing(Xog_html_itm html_itm, String html_id) {
html_itm.Html_elem_atr_set_append(html_id, "class", " new");
html_itm.Html_redlink(html_id);
}
private static void Update_img(Xoa_page page, Xog_js_wkr js_wkr, Js_img_wkr img_wkr, int uid, byte lnki_type, byte elem_tid, int html_w, int html_h, String html_src, int orig_w, int orig_h, String orig_src, byte[] lnki_ttl, int gallery_mgr_h) {
if (!page.Wiki().App().App_type().Uid_is_gui()) return; // do not update html widget unless app is gui; null ref on http server; DATE:2014-09-17

View File

@@ -19,6 +19,7 @@ package gplx.xowa.files.gui; import gplx.*; import gplx.xowa.*; import gplx.xowa
public interface Xog_js_wkr {
void Html_img_update (String uid, String src, int w, int h);
void Html_redlink (String html_uid);
boolean Html_doc_loaded ();
void Html_atr_set (String uid, String key, String val);
void Html_elem_replace_html (String uid, String html);

View File

@@ -25,4 +25,5 @@ class Xog_js_wkr__noop implements Xog_js_wkr {
public void Html_elem_replace_html (String uid, String html) {}
public void Html_elem_append_above (String uid, String html) {}
public void Html_redlink (String html_uid) {}
public boolean Html_doc_loaded () {return true;}
}

View File

@@ -23,10 +23,11 @@ public class Xog_js_wkr__log implements Xog_js_wkr {
public void Html_redlink (String uid) {log_list.Add(Object_.Ary(Proc_redlink, uid));}
public void Html_elem_replace_html (String uid, String html) {log_list.Add(Object_.Ary(Proc_replace_html, uid, html));}
public void Html_elem_append_above (String uid, String html) {log_list.Add(Object_.Ary(Proc_append_above, uid, html));}
public boolean Html_doc_loaded () {log_list.Add(Object_.Ary(Proc_doc_loaded)); return true;}
public void Log__clear() {log_list.Clear();}
public int Log__len() {return log_list.Count();}
public Object[] Log__get_at(int i) {return (Object[])log_list.FetchAt(i);}
public static final String Proc_img_update = "img_update", Proc_atr_set = "atr_set", Proc_redlink = "redlink", Proc_replace_html = "replace_html", Proc_append_above = "append_above";
public static final String Proc_img_update = "img_update", Proc_atr_set = "atr_set", Proc_redlink = "redlink", Proc_replace_html = "replace_html", Proc_append_above = "append_above", Proc_doc_loaded = "doc_loaded";
}

View File

@@ -17,7 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.files.origs; import gplx.*; import gplx.xowa.*; import gplx.xowa.files.*;
import gplx.core.primitives.*; import gplx.dbs.*;
import gplx.xowa.files.repos.*; import gplx.xowa.files.fsdb.*; import gplx.xowa.wmfs.apis.*;
import gplx.xowa.files.repos.*; import gplx.xowa.files.fsdb.*; import gplx.xowa.wmfs.apis.*; import gplx.xowa.files.downloads.*;
public class Xof_orig_mgr {
private Xof_orig_wkr[] wkrs; private int wkrs_len;
private Xof_url_bldr url_bldr; private Xow_repo_mgr repo_mgr; private final Xof_img_size img_size = new Xof_img_size();

View File

@@ -16,7 +16,7 @@ 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.xowa.files.origs; import gplx.*; import gplx.xowa.*; import gplx.xowa.files.*;
import gplx.xowa.files.repos.*; import gplx.xowa.files.fsdb.*; import gplx.xowa.wmfs.apis.*;
import gplx.xowa.files.repos.*; import gplx.xowa.files.fsdb.*; import gplx.xowa.wmfs.apis.*; import gplx.xowa.files.downloads.*;
public class Xof_orig_wkr__wmf_api implements Xof_orig_wkr {
private final Xoapi_orig_base orig_api; private final Xof_download_wkr download_wkr; private final Xow_repo_mgr repo_mgr; private final byte[] wiki_domain;
private final Xoapi_orig_rslts api_rv = new Xoapi_orig_rslts();

View File

@@ -48,7 +48,7 @@ public class Xoa_gui_mgr implements GfoEvObj, GfoInvkAble {
RectAdp prog_box_rect = browser_win.Prog_box().Rect();
memo_win.Rect_set(RectAdp_.new_(prog_box_rect.X(), prog_box_rect.Y() - 75, prog_box_rect.Width(), 100));
memo_txt.Size_(memo_win.Size().Op_add(-8, -30));
memo_txt.Text_(String_.Concat_lines_nl(browser_win.Usr_dlg().Ui_wkr().Prog_msgs().Xto_str_ary()));
memo_txt.Text_(String_.Concat_lines_nl(browser_win.Usr_dlg().Gui_wkr().Prog_msgs().Xto_str_ary()));
memo_win.Show();
memo_win.Focus();
}
@@ -109,7 +109,7 @@ public class Xoa_gui_mgr implements GfoEvObj, GfoInvkAble {
Xog_win_itm main_win = ui_mgr.Browser_win();
Xog_win_itm_.Show_win(main_win); log_bfr.Add("app.gui.win_load.done");
Xog_tab_itm_read_mgr.Launch(main_win);
app.Log_wtr().Log_msg_to_session_direct(log_bfr.Xto_str());
app.Log_wtr().Log_to_session_direct(log_bfr.Xto_str());
kit.Kit_run(); // NOTE: enters thread-loop
} catch (Exception e) {
app.Usr_dlg().Warn_many("", "", "run_failed: ~{0} ~{1}", log_bfr.Xto_str(), Err_.Message_gplx(e));

View File

@@ -142,12 +142,12 @@ public class Xog_bnd_mgr {
Init_itm(Xog_cmd_itm_.Key_gui_edit_exec , Xog_bnd_box_.Tid_browser , "mod.c+key.e,mod.c+key.g");
Init_itm(Xog_cmd_itm_.Key_gui_browser_url_focus , Xog_bnd_box_.Tid_browser , "mod.a+key.d", "mod.c+key.l");
Init_itm(Xog_cmd_itm_.Key_gui_browser_url_exec , Xog_bnd_box_.Tid_browser_url , "key.enter");
Init_itm(Xog_cmd_itm_.Key_gui_browser_url_exec_new_tab_by_paste , Xog_bnd_box_.Tid_browser_url , "mod.c+key.enter");
Init_itm(Xog_cmd_itm_.Key_gui_browser_url_exec_by_paste , Xog_bnd_box_.Tid_browser_url , "mouse.middle", "mod.a+key.enter");
Init_itm(Xog_cmd_itm_.Key_gui_browser_url_exec , Xog_bnd_box_.Tid_browser_url , "key.enter", "key.keypad_enter");
Init_itm(Xog_cmd_itm_.Key_gui_browser_url_exec_new_tab_by_paste , Xog_bnd_box_.Tid_browser_url , "mod.c+key.enter", "mod.c+key.keypad_enter");
Init_itm(Xog_cmd_itm_.Key_gui_browser_url_exec_by_paste , Xog_bnd_box_.Tid_browser_url , "mouse.middle", "mod.a+key.enter", "mod.a+key.keypad_enter");
Init_itm(Xog_cmd_itm_.Key_gui_browser_url_restore , Xog_bnd_box_.Tid_browser_url , "mod.c+key.u");
Init_itm(Xog_cmd_itm_.Key_gui_browser_search_focus , Xog_bnd_box_.Tid_browser , "mod.ca+key.s");
Init_itm(Xog_cmd_itm_.Key_gui_browser_search_exec , Xog_bnd_box_.Tid_browser_search , "key.enter");
Init_itm(Xog_cmd_itm_.Key_gui_browser_search_exec , Xog_bnd_box_.Tid_browser_search , "key.enter", "key.keypad_enter");
Init_itm(Xog_cmd_itm_.Key_gui_browser_tabs_new_dflt__at_dflt__focus_y , Xog_bnd_box_.Tid_browser , "mod.c+key.t");
Init_itm(Xog_cmd_itm_.Key_gui_browser_tabs_new_link__at_dflt__focus_n , Xog_bnd_box_.Tid_browser_html , "mouse.middle");
Init_itm(Xog_cmd_itm_.Key_gui_browser_tabs_new_href__at_dflt__focus_y , Xog_bnd_box_.Tid_browser , "mod.c+key.g,mod.c+key.f");
@@ -178,7 +178,7 @@ public class Xog_bnd_mgr {
Init_itm(Xog_cmd_itm_.Key_gui_browser_find_show , Xog_bnd_box_.Tid_browser , "mod.c+key.f");
Init_itm(Xog_cmd_itm_.Key_gui_browser_find_show_by_paste , Xog_bnd_box_.Tid_browser , "");
Init_itm(Xog_cmd_itm_.Key_gui_browser_find_hide , Xog_bnd_box_.Tid_browser_find , "key.escape");
Init_itm(Xog_cmd_itm_.Key_gui_browser_find_exec , Xog_bnd_box_.Tid_browser_find , "key.enter");
Init_itm(Xog_cmd_itm_.Key_gui_browser_find_exec , Xog_bnd_box_.Tid_browser_find , "key.enter", "key.keypad_enter");
Init_itm(Xog_cmd_itm_.Key_gui_browser_find_find_fwd , Xog_bnd_box_.Tid_browser_find , "mod.a+key.n");
Init_itm(Xog_cmd_itm_.Key_gui_browser_find_find_bwd , Xog_bnd_box_.Tid_browser_find , "mod.a+key.p");
Init_itm(Xog_cmd_itm_.Key_gui_browser_find_case_toggle , Xog_bnd_box_.Tid_browser_find , "mod.a+key.c");

View File

@@ -63,8 +63,8 @@ public class Load_page_wkr implements Gfo_thread_wkr {
Thread_adp_.Sleep(10);
}
if (wiki.Html__hdump_enabled() && html_db_id != -1) {
wiki.ParsePage(page, false);
// wiki.Html__hdump_rdr().Get_by_ttl(page);
// wiki.ParsePage(page, false);
wiki.Html__hdump_rdr().Get_by_ttl(page);
}
else
wiki.ParsePage(page, false);

View File

@@ -105,7 +105,7 @@ public class Xog_html_itm implements Xog_js_wkr, GfoInvkAble, GfoEvObj {
GfoInvkAble_.InvkCmd_msg(cmd_sync, Invk_html_elem_atr_set, m);
}
}
public void Html_redlink(String html_uid) {Html_elem_atr_set_append(html_uid, "class", "new");}
public void Html_redlink(String html_uid) {Html_elem_atr_set_append(html_uid, "class", gplx.xowa.html.lnkis.Xoh_redlink_utl.New_str);}
public void Html_elem_atr_set_append(String elem_id, String atr_key, String atr_val) {
GfoMsg m = GfoMsg_.new_cast_(Invk_html_elem_atr_set_append).Add("elem_id", elem_id).Add("atr_key", atr_key).Add("atr_val", atr_val);
GfoInvkAble_.InvkCmd_msg(cmd_sync, Invk_html_elem_atr_set_append, m);
@@ -122,6 +122,10 @@ public class Xog_html_itm implements Xog_js_wkr, GfoInvkAble, GfoEvObj {
GfoInvkAble_.InvkCmd_msg(cmd_sync, Invk_html_elem_append_above, m);
}
}
public boolean Html_doc_loaded() {
GfoMsg m = GfoMsg_.new_cast_(Invk_html_doc_loaded);
return Bool_.cast_(GfoInvkAble_.InvkCmd_msg(cmd_sync, Invk_html_doc_loaded, m));
}
public void Html_gallery_packed_exec() {
if (!String_.Eq(owner_tab.Tab_key(), owner_tab.Tab_mgr().Active_tab().Tab_key())) return; // do not exec unless active;
GfoMsg m = GfoMsg_.new_cast_(Invk_html_gallery_packed_exec);
@@ -187,6 +191,7 @@ public class Xog_html_itm implements Xog_js_wkr, GfoInvkAble, GfoEvObj {
else if (ctx.Match(k, Invk_html_elem_append_above)) html_box.Html_elem_append_above(m.ReadStr("id"), m.ReadStr("html"));
else if (ctx.Match(k, Invk_html_gallery_packed_exec)) html_box.Html_gallery_packed_exec();
else if (ctx.Match(k, Invk_html_popups_bind_hover_to_doc)) html_box.Html_js_eval_script("xowa_popups_bind_doc();");
else if (ctx.Match(k, Invk_html_doc_loaded)) return html_box.Html_doc_loaded();
else if (ctx.Match(k, Invk_scroll_page_by_bmk)) Scroll_page_by_bmk();
else if (ctx.Match(k, Invk_scroll_page_by_id)) Scroll_page_by_id(m.ReadStr("v"));
else if (ctx.Match(k, Invk_html_elem_focus)) html_box.Html_elem_focus(m.ReadStr("v"));
@@ -198,7 +203,7 @@ public class Xog_html_itm implements Xog_js_wkr, GfoInvkAble, GfoEvObj {
Invk_html_gallery_packed_exec = "html_gallery_packed_exec", Invk_html_popups_bind_hover_to_doc = "html_popups_bind_hover_to_doc"
, Invk_html_img_update = "html_img_update", Invk_html_elem_atr_set = "html_elem_atr_set"
, Invk_html_elem_atr_set_append = "html_elem_atr_set_append", Invk_html_elem_delete = "html_elem_delete", Invk_html_elem_replace_html = "html_elem_replace_html", Invk_html_elem_append_above = "html_elem_append_above"
, Invk_scroll_page_by_bmk = "scroll_page_by_bmk", Invk_scroll_page_by_id = "scroll_page_by_id"
, Invk_scroll_page_by_bmk = "scroll_page_by_bmk", Invk_scroll_page_by_id = "scroll_page_by_id", Invk_html_doc_loaded = "html_doc_loaded"
;
public static final String
Elem_id__xowa_edit_data_box = "xowa_edit_data_box"

View File

@@ -30,7 +30,7 @@ class Xog_launcher_tabs {
// tab.Html_itm().Html_box().Focus(); // focus the html_box so wheel scroll works; DATE:2013-02-08
app.Usr_dlg().Prog_none("", "", "");
log_bfr.Add("app.launch.page.end");
app.Usr_dlg().Log_wtr().Log_msg_to_session_direct(log_bfr.Xto_str());
app.Usr_dlg().Log_wkr().Log_to_session_direct(log_bfr.Xto_str());
}
private boolean Restore_tabs(Xoae_app app, Xowe_wiki home_wiki, Xog_win_itm win, Io_fil_marker fil_marker) {
String[] launch_urls = app.Api_root().App().Startup().Tabs().Calc_startup_strs(app);

View File

@@ -113,7 +113,7 @@ public class Xog_tab_itm implements GfoInvkAble {
app.Gui_mgr().Search_suggest_mgr().Cancel(); // cancel pending search_suggest calls
if (page != null) page.Tab_data().Close_mgr().When_close(this, url); // cancel any current search cmds
app.Log_wtr().Queue_enabled_(true);
usr_dlg.Clear();
usr_dlg.Gui_wkr().Clear();
this.wiki = app.Wiki_mgr().Get_by_key_or_null(url.Wiki_bry()); // NOTE: must update wiki
wiki.Init_assert(); // NOTE: assert wiki.Init before parsing; needed b/c lang (with lang-specific ns) is only loaded on init, and parse Xoa_ttl.parse_ will fail below; EX:pt.wikipedia.org/wiki/Wikipedia:P<>gina principal
Xoa_ttl ttl = Xoa_ttl.parse_(wiki, url.Page_bry());
@@ -160,14 +160,14 @@ public class Xog_tab_itm implements GfoInvkAble {
app.User().Data_mgr().History_mgr().Update_async(app.Async_mgr(), ttl, url);
}
usr_dlg.Prog_none("", "", "rendering html");
html_itm.Html_box().Size_(tab_mgr.Tab_mgr().Size()); // NOTE: must resize tab here, else scrolling to anchor in background tab doesn't work (html_box has size of 0, 0) DATE:2015-05-03
// html_itm.Html_box().Size_(tab_mgr.Tab_mgr().Size()); // COMMENTED: causes clicks on macosx to be off by 4 px; NOTE: must resize tab here, else scrolling to anchor in background tab doesn't work (html_box has size of 0, 0) DATE:2015-05-03
// win.Page__async__bgn(this);
Gfo_thread_wkr async_wkr = null;
Gfo_thread_wkr async_wkr = null;
if (wkr.Hdump_enabled()) {
wiki.File_mgr().Init_file_mgr_by_load(wiki);
Xof_fsdb_mgr fsdb_mgr = wiki.File_mgr().Fsdb_mgr();
async_wkr = new Xof_file_wkr(wiki.File__orig_mgr(), fsdb_mgr.Bin_mgr(), fsdb_mgr.Mnt_mgr(), app.File__cache_mgr(), wiki.File__repo_mgr(), html_itm, page, page.Hdump_data().Imgs(), gplx.xowa.files.Xof_exec_tid.Tid_wiki_page);
if (wiki.Html__hdump_enabled()) {
if (wiki.Html__hdump_enabled() && page.Revision_data().Html_db_id() == -1) {
wiki.Html__hdump_wtr().Save(page);
}
}

View File

@@ -303,6 +303,6 @@ public class Xog_win_itm implements GfoInvkAble, GfoEvObj {
if ( !Env_.Mode_testing()
&& app.App_type().Uid_is_gui()) // only run for gui; do not run for tcp/http server; DATE:2014-05-03
app.Usr_dlg().Ui_wkr_(new Gfo_usr_dlg_ui_swt(kit, prog_box, info_box, info_box, app.Api_root().Gui().Browser().Info()));
app.Usr_dlg().Gui_wkr_(new Gfo_usr_dlg__gui__swt(kit, prog_box, info_box, info_box, app.Api_root().Gui().Browser().Info()));
}
}

View File

@@ -52,7 +52,7 @@ public class Xohd_hdump_rdr {
}
Bry_bfr bfr = bfr_mkr.Get_m001();
byte[] body_bry = abrv_mgr.Parse(bfr, rv);
body_bry = hzip_mgr.Parse(bfr, ttl.Page_db(), body_bry);
body_bry = hzip_mgr.Parse(bfr, ttl.Page_db(), body_bry, rv.Redlink_uids());
bfr.Mkr_rls();
rv.Page_body_(body_bry);
}

View File

@@ -43,7 +43,7 @@ public class Xohd_hdump_wtr {
else {
hdump_db = core_data_mgr.Dbs__get_at(html_db_id);
html_db_id = hdump_db.Id();
// return;
return;
}
save_mgr.Update(tmp_bfr, hdump_db.Tbl__html(), page);
tmp_bfr.Mkr_rls();
@@ -51,7 +51,7 @@ public class Xohd_hdump_wtr {
public void Generate_hdump(Bry_bfr tmp_bfr, Xoae_page page) {
page.File_queue().Clear(); // need to reset uid to 0, else xowa_file_# will resume from last
page_wtr_mgr.Wkr(Xopg_view_mode.Tid_read).Write_body(tmp_bfr, Xoh_wtr_ctx.Hdump, page);
// page.Wikie().Html_mgr().Hzip_mgr().Write(tmp_bfr, new Xodump_stats_itm(), page.Url().Xto_full_bry(), tmp_bfr.Xto_bry_and_clear()); // hzip data
if (!Env_.Mode_testing()) page.Wikie().Html_mgr().Hzip_mgr().Write(tmp_bfr, new Xodump_stats_itm(), page.Url().Xto_full_bry(), tmp_bfr.Xto_bry_and_clear()); // hzip data;
page.Hdump_data().Body_(tmp_bfr.Xto_bry_and_clear()); // write to body bry
}
}

View File

@@ -16,7 +16,7 @@ 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.xowa.html.hdumps.abrvs; import gplx.*; import gplx.xowa.*; import gplx.xowa.html.*; import gplx.xowa.html.hdumps.*;
import gplx.core.brys.*; import gplx.core.btries.*;
import gplx.core.primitives.*; import gplx.core.brys.*; import gplx.core.btries.*;
import gplx.html.*; import gplx.xowa.html.*; import gplx.xowa.html.hdumps.core.*; import gplx.xowa.html.lnkis.*;
import gplx.xowa.files.*; import gplx.xowa.files.repos.*; import gplx.xowa.xtns.gallery.*;
import gplx.xowa.wikis.*; import gplx.xowa.apps.fsys.*;
@@ -73,7 +73,7 @@ public class Xohd_abrv_mgr {
byte tid = itm.Tid();
switch (tid) {
case Xohd_abrv_.Tid_dir: bfr.Add(root_dir); return rv;
case Xohd_abrv_.Tid_hiero_dir: bfr.Add(hiero_img_dir); return rv;
case Xohd_abrv_.Tid_hiero_dir: bfr.Add(hiero_img_dir); return rv;
case Xohd_abrv_.Tid_redlink: return Write_redlink(bfr, hpg, uid, rv);
}
if (itm.Elem_is_xnde()) rv += 2; // if xnde, skip "/>"
@@ -131,14 +131,12 @@ public class Xohd_abrv_mgr {
return rv;
}
private int Write_redlink(Bry_bfr bfr, Xog_page hpg, int uid, int rv) {
int[] redlink_uids = hpg.Redlink_uids(); if (redlink_uids == null) return rv;
int redlink_uid_max = redlink_uids.length;
if (uid < redlink_uid_max && redlink_uids[uid] == 1)
bfr.Add(Redlink_cls_new);
if (hpg.Redlink_uids().Has(redlink_key.Val_(uid)))
bfr.Add(Xoh_redlink_utl.Cls_bry);
else
bfr.Del_by_1();
return rv;
} private static final byte[] Redlink_cls_new = Bry_.new_ascii_("class='new'");
} private final Int_obj_ref redlink_key = Int_obj_ref.neg1_();
public static final Bry_fmtr fmtr_img = Bry_fmtr.new_("src='~{src}' width='~{w}' height='~{h}'", "src", "w", "h");
private static final Btrie_slim_mgr trie = Xohd_abrv_.new_trie();
}

View File

@@ -16,7 +16,7 @@ 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.xowa.html.hdumps.abrvs; import gplx.*; import gplx.xowa.*; import gplx.xowa.html.*; import gplx.xowa.html.hdumps.*;
import org.junit.*; import gplx.xowa.html.hdumps.core.*; import gplx.xowa.html.hdumps.data.*; import gplx.xowa.files.*;
import org.junit.*; import gplx.core.primitives.*; import gplx.xowa.html.hdumps.core.*; import gplx.xowa.html.hdumps.data.*; import gplx.xowa.files.*;
import gplx.xowa2.gui.*;
public class Xohd_abrv_mgr_tst {
@Before public void init() {
@@ -88,7 +88,7 @@ public class Xohd_abrv_mgr_tst {
));
}
@Test public void Redlink() {
fxt .Init_data_redlink(2, 1, 2);
fxt .Init_data_redlink(1, 2);
fxt .Init_body(String_.Concat_lines_nl_skip_last
( "<a href=\"/wiki/A\" xowa_redlink='1'>A</a>"
, "<a href=\"/wiki/B\" xowa_redlink='2'>B</a>"
@@ -136,14 +136,12 @@ class Xohd_abrv_mgr_fxt {
img_list.Add(img);
return this;
}
public Xohd_abrv_mgr_fxt Init_data_redlink(int max, int... uids) {
int[] ary = new int[max + ListAdp_.Base1];
public Xohd_abrv_mgr_fxt Init_data_redlink(int... uids) {
int uids_len = uids.length;
for (int i = 0; i < uids_len; ++i) {
int uid = uids[i];
ary[uid] = 1;
Int_obj_ref redlink_uid = Int_obj_ref.new_(uids[i]);
hpg.Redlink_uids().Add(redlink_uid, redlink_uid);
}
hpg.Redlink_uids_(ary);
return this;
}
public Xohd_abrv_mgr_fxt Test_html(String expd) {

View File

@@ -35,7 +35,8 @@ public class Xob_link_dump_cmd {
Db_attach_cmd.new_(conn, "page_db", page_db_url)
.Add_fmt("update trg_page_id", String_.Concat_lines_nl_skip_last
( "REPLACE INTO link_dump"
, "SELECT r.src_page_id"
, "SELECT r.uid"
, ", r.src_page_id"
, ", r.src_html_uid"
, ", Coalesce(p.page_id, -1)"
, ", r.trg_ns"

View File

@@ -20,7 +20,8 @@ import gplx.dbs.*;
class Xob_link_dump_tbl implements RlsAble {
public static final String Tbl_name = "link_dump"; private static final Db_meta_fld_list flds = Db_meta_fld_list.new_();
public static final String
Fld_src_page_id = flds.Add_int("src_page_id")
Fld_uid = flds.Add_int_pkey_autonum("uid")
, Fld_src_page_id = flds.Add_int("src_page_id")
, Fld_src_html_uid = flds.Add_int("src_html_uid")
, Fld_trg_page_id = flds.Add_int_dflt("trg_page_id", -1)
, Fld_trg_ns = flds.Add_int("trg_ns")
@@ -47,9 +48,10 @@ class Xob_link_dump_tbl implements RlsAble {
public void Rls() {
stmt_insert = Db_stmt_.Rls(stmt_insert);
}
public void Insert_bgn() {conn.Txn_bgn(); stmt_insert = conn.Stmt_insert(Tbl_name, flds);}
public void Insert_bgn() {conn.Txn_bgn();}
public void Insert_end() {conn.Txn_end(); stmt_insert = Db_stmt_.Rls(stmt_insert);}
public void Insert_cmd_by_batch(int src_page_id, int src_html_uid, int trg_ns, byte[] trg_ttl) {
if (stmt_insert == null) stmt_insert = conn.Stmt_insert(Tbl_name, flds.To_str_ary_wo_autonum());
stmt_insert.Clear().Val_int(Fld_src_page_id, src_page_id)
.Val_int(Fld_src_html_uid, src_html_uid).Val_int(Fld_trg_page_id, -1).Val_int(Fld_trg_ns, trg_ns).Val_bry_as_str(Fld_trg_ttl, trg_ttl)
.Exec_insert();

View File

@@ -47,6 +47,7 @@ public class Xob_redlink_mkr_cmd extends Xob_itm_basic_base implements Xob_cmd {
int page_id = rdr.Read_int(page_tbl.Fld_page_id());
if (cur_page_id != page_id) {
if (cur_page_id != -1) Commit(html_dump_tbl, cur_page_id, bfr);
bfr.Add_int_variable(gplx.xowa.html.hdumps.core.Xohd_data_tid.Tid_redlink).Add_byte_pipe();
cur_page_id = page_id;
}
// add html_uid to cur_page's bfr

View File

@@ -16,14 +16,12 @@ 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.xowa.html.hdumps.data; import gplx.*; import gplx.xowa.*; import gplx.xowa.html.*; import gplx.xowa.html.hdumps.*;
import gplx.core.brys.*; import gplx.core.btries.*; import gplx.dbs.*; import gplx.ios.*;
import gplx.core.primitives.*; import gplx.core.brys.*; import gplx.core.btries.*; import gplx.dbs.*; import gplx.ios.*;
import gplx.xowa.dbs.*; import gplx.xowa.pages.*; import gplx.xowa.html.hdumps.core.*; import gplx.xowa.html.hdumps.data.*; import gplx.xowa.html.hdumps.pages.*; import gplx.xowa.pages.skins.*; import gplx.xowa.html.hdumps.data.srl.*;
import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.xowa2.gui.*;
public class Xohd_page_html_mgr__load {
private final Xohd_page_srl_mgr srl_mgr = Xohd_page_srl_mgr.I;
private final Bry_rdr rdr = new Bry_rdr(); private final ListAdp rows = ListAdp_.new_(), imgs = ListAdp_.new_();
private static final int redlink_list_max = 1024;
private final int[] redlink_list = new int[redlink_list_max];
private final Bry_rdr rdr = new Bry_rdr(); private final ListAdp rows = ListAdp_.new_(), imgs = ListAdp_.new_();
public void Load_page(Xow_wiki wiki, Xog_page hpg, Xowd_html_tbl tbl, int page_id, Xoa_ttl page_ttl) {
tbl.Select_by_page(rows, page_id);
Parse_rows(wiki, hpg, page_id, Xoa_url.blank_(), page_ttl, rows);
@@ -61,7 +59,7 @@ public class Xohd_page_html_mgr__load {
switch (tid) {
case Xohd_data_itm__base.Tid_basic : img_itm = new Xohd_data_itm__img(); break;
case Xohd_data_itm__base.Tid_gallery : img_itm = new Xohd_data_itm__gallery_itm(); break;
default: return null; // TODO: remove; needed for redlink
default : throw Err_.unhandled(tid);
}
img_itm.Data_parse(rdr);
rdr.Pos_add_one();
@@ -73,10 +71,11 @@ public class Xohd_page_html_mgr__load {
imgs.Add(img);
}
private void Load_data_redlink(Xog_page hpg) {
int len = 0;
while (!rdr.Pos_is_eos() && len < redlink_list_max)
redlink_list[len++] = rdr.Read_int_to_pipe();
hpg.Redlink_uids_(Int_.Ary_copy(redlink_list, len));
OrderedHash redlink_hash = hpg.Redlink_uids();
while (!rdr.Pos_is_eos()) {
Int_obj_ref redlink_uid = Int_obj_ref.new_(rdr.Read_int_to_pipe());
redlink_hash.Add(redlink_uid, redlink_uid);
}
}
private void Load_data_gallery(Xog_page hpg) {
int uid = rdr.Read_int_to_pipe();

View File

@@ -33,7 +33,7 @@ public class Xodump_stats_tbl implements RlsAble {
public Xodump_stats_tbl(Db_conn conn) {
this.conn = conn;
this.Create_tbl();
conn.Stmt_delete(tbl_name); // always zap table
conn.Stmt_delete(tbl_name).Exec_delete(); // always zap table
conn.Rls_reg(this);
}
public void Create_tbl() {conn.Ddl_create_tbl(Db_meta_tbl.new_(tbl_name, flds, Db_meta_idx.new_unique_by_tbl(tbl_name, "pkey", fld_page_id)));}

View File

@@ -57,34 +57,38 @@ public class Xow_hzip_itm__anchor {
return bry_rdr.Pos() + 2; // +2=/>
}
public int Save_lnki(Bry_bfr bfr, Xodump_stats_itm stats, byte[] src, int src_len, int bgn, int pos, boolean caption) {
// href
int ttl_bgn = Bry_finder.Find_fwd(src, Find_href_bry, pos, src_len); if (ttl_bgn == Bry_finder.Not_found) return Xow_hzip_mgr.Unhandled;//hzip_mgr.Warn_by_pos_add_dflt("a.ttl_bgn_missing", bgn, pos);
ttl_bgn += Find_href_bry.length;
// get site
// site or wiki; EX: "/site/" or "/wiki/"
byte[] site = null;
Object href_tid_obj = btrie_href.Match_bgn(src, ttl_bgn, src_len);
if (href_tid_obj == null) return Xow_hzip_mgr.Unhandled; // not "/wiki/" or "/site/"
if (((Byte_obj_val)href_tid_obj).Val() == Href_tid_site) {
// /site/en.wiktionary.org/
if (((Byte_obj_val)href_tid_obj).Val() == Href_tid_site) { // site; EX:"/site/en.wiktionary.org/"
int site_bgn = ttl_bgn + Href_bry_len; int site_end = Bry_finder.Find_fwd(src, Byte_ascii.Slash, site_bgn);
byte[] site_domain = Bry_.Mid(src, site_bgn, site_end);
site = site_domain;
}
else
else // page; EX: "/wiki/Page"
ttl_bgn += Href_bry_len;
int ttl_end = Bry_finder.Find_fwd(src, Byte_ascii.Quote, ttl_bgn , src_len); if (ttl_end == Bry_finder.Not_found) return hzip_mgr.Warn_by_pos_add_dflt("a.ttl_end_missing", bgn, ttl_bgn);
Xoa_ttl ttl = ttl_parser.Ttl_parse(Bry_.Mid(src, ttl_bgn, ttl_end)); if (ttl == null) return hzip_mgr.Warn_by_pos("a.ttl_invalid", ttl_bgn, ttl_end);
// int id_bgn = Bry_finder.Find_fwd(src, Find_id_bry, ttl_end, src_len); if (id_bgn == Bry_finder.Not_found) return Xow_hzip_mgr.Unhandled;
// id_bgn += Find_id_bry.length;
// int id_end = Bry_finder.Find_fwd(src, Byte_ascii.Quote, id_bgn, src_len); if (id_end == Bry_finder.Not_found) return Xow_hzip_mgr.Unhandled;
// int id = Bry_.Xto_int_or(src, id_bgn, id_end, -1); if (id == Bry_finder.Not_found) return Xow_hzip_mgr.Unhandled;
int a_lhs_end = Bry_finder.Find_fwd(src, Byte_ascii.Gt, ttl_end, src_len); if (a_lhs_end == Bry_finder.Not_found) return hzip_mgr.Warn_by_pos_add_dflt("a.a_lhs_end_missing", bgn, ttl_end);
++a_lhs_end; // skip >
// id
int id_bgn = Bry_finder.Find_fwd(src, Find_id_bry, ttl_end, src_len); if (id_bgn == Bry_finder.Not_found) return Xow_hzip_mgr.Unhandled;
if (id_bgn > a_lhs_end) return Xow_hzip_mgr.Unhandled;
id_bgn += Find_id_bry.length + gplx.xowa.parsers.lnkis.redlinks.Xopg_redlink_lnki_list.Lnki_id_prefix_len;
int id_end = Bry_finder.Find_fwd(src, Byte_ascii.Quote, id_bgn, src_len); if (id_end == Bry_finder.Not_found) return Xow_hzip_mgr.Unhandled;
int id = Bry_.Xto_int_or(src, id_bgn, id_end, -1); if (id == Bry_finder.Not_found) return Xow_hzip_mgr.Unhandled;
int a_rhs_bgn = Bry_finder.Find_fwd(src, Find_a_rhs_bgn_bry, a_lhs_end, src_len); if (a_rhs_bgn == Bry_finder.Not_found) return hzip_mgr.Warn_by_pos_add_dflt("a.a_rhs_bgn_missing", bgn, ttl_end);
// caption
if (caption)
bfr.Add(Xow_hzip_dict.Bry_lnki_text_y);
else
bfr.Add(Xow_hzip_dict.Bry_lnki_text_n);
bfr.Add_byte((byte)ttl.Ns().Ord()); // ASSUME:NS_MAX_255; no more than 255 ns in wiki; note that ids > 255 still supported
Xow_hzip_int_.Save_bin_int_abrv(bfr, id);
if (site != null) {
bfr.Add_byte_pipe().Add(site).Add_byte_pipe();
}
@@ -158,17 +162,23 @@ public class Xow_hzip_itm__anchor {
return hzip_mgr.Warn_by_pos("a.xtid_unknown", href_bgn, href_end);
}
}
public int Load_lnki(Bry_bfr bfr, byte[] src, int src_len, int bgn, byte tid) {
private final Int_obj_ref id_count_ref = Int_obj_ref.neg1_();
public int Load_lnki(Bry_bfr bfr, byte[] src, int src_len, int bgn, byte tid, OrderedHash redlink_uids) {
// ns; 255 max
byte ns_ord = src[bgn];
Xow_ns ns = ttl_parser.Ns_mgr().Ords_get_at(ns_ord);
// id
int id = Xow_hzip_int_.Load_bin_int_abrv(src, src_len, bgn + 1, id_count_ref);
// site
byte[] site_bry = null;
int ttl_bgn = bgn + 1;
if (src[ttl_bgn] == Byte_ascii.Pipe) { // site
int ttl_bgn = bgn + 1 + id_count_ref.Val();
if (src[ttl_bgn] == Byte_ascii.Pipe) { // if "|" after ns, then site is present; EX: "0|enwiki" vs. "0page"
int site_bgn = ttl_bgn + 1;
int site_end = Bry_finder.Find_fwd(src, Byte_ascii.Pipe, site_bgn, src_len);
site_bry = Bry_.Mid(src, site_bgn, site_end);
ttl_bgn = site_end + 1;
}
// page
int ttl_end = Bry_finder.Find_fwd(src, Xow_hzip_dict.Escape, ttl_bgn, src_len); if (ttl_end == Bry_finder.Not_found) return hzip_mgr.Warn_by_pos_add_dflt("a.ttl_end_missing", bgn, ttl_bgn);
byte[] ttl_bry = Bry_.Mid(src, ttl_bgn, ttl_end);
Xoa_ttl ttl = ttl_parser.Ttl_parse(ns.Id(), ttl_bry);
@@ -179,7 +189,11 @@ public class Xow_hzip_itm__anchor {
bfr.Add(site_bry);
}
bfr.Add_str_ascii("/wiki/");
bfr.Add(Html_utl.Escape_html_as_bry(ttl_full)).Add_str("' title='");
bfr.Add(Html_utl.Escape_html_as_bry(ttl_full));
if (redlink_uids.Has(id_count_ref.Val_(id)))
bfr.Add_str_ascii("' class='xowa_disabled");
bfr.Add_str_ascii("' id='").Add_str_ascii(gplx.xowa.parsers.lnkis.redlinks.Xopg_redlink_lnki_list.Lnki_id_prefix).Add_int_variable(id);
bfr.Add_str_ascii("' title='");
int rv = ttl_end + 1;
if (tid == Xow_hzip_dict.Tid_lnki_text_n) {
if (ns.Id() != 0) ttl_bry = ttl_full;
@@ -201,7 +215,7 @@ public class Xow_hzip_itm__anchor {
}
private static final byte[]
Find_href_bry = Bry_.new_ascii_(" href=\"")
// , Find_id_bry = Bry_.new_ascii_(" id=\"")
, Find_id_bry = Bry_.new_ascii_(" id=\"")
, Find_a_rhs_bgn_bry = Bry_.new_ascii_("</a>")
, Find_img_xatrs = Bry_.new_ascii_("xatrs='")
;

View File

@@ -20,52 +20,61 @@ import org.junit.*; import gplx.xowa.html.*;
public class Xow_hzip_itm__anchor_tst {
@Before public void init() {fxt.Clear();} private Xow_hzip_mgr_fxt fxt = new Xow_hzip_mgr_fxt();
@Test public void Srl_lnki_text_n() {
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(2), Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry); // 2=ns_ord for Main
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/wiki/A\" id='xowa_lnki_0' title='A'>A</a>");
fxt.Test_load(brys, "<a href='/wiki/A' title='A'>A</a>");
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(2), fxt.Make_int(3), Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry); // 2=ns_ord for Main
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/wiki/A\" id=\"xowa_lnki_3\" title='A'>A</a>");
fxt.Test_load(brys, "<a href='/wiki/A' id='xowa_lnki_3' title='A'>A</a>");
}
@Test public void Srl_lnki_text_n_alt_case() {
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(2), Bry_.new_ascii_("a"), Xow_hzip_dict.Escape_bry);
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/wiki/A\" id='xowa_lnki_0' title='A'>a</a>");
fxt.Test_load(brys, "<a href='/wiki/A' title='a'>a</a>");
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(2), fxt.Make_int(3), Bry_.new_ascii_("a"), Xow_hzip_dict.Escape_bry);
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/wiki/A\" id=\"xowa_lnki_3\" title='A'>a</a>");
fxt.Test_load(brys, "<a href='/wiki/A' id='xowa_lnki_3' title='a'>a</a>");
}
@Test public void Srl_lnki_text_n_ns() {
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(12), Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry);
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/wiki/Template:A\" id='xowa_lnki_0' title='Template:A'>Template:A</a>");
fxt.Test_load(brys, "<a href='/wiki/Template:A' title='Template:A'>Template:A</a>");
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(12), fxt.Make_int(3), Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry);
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/wiki/Template:A\" id=\"xowa_lnki_3\" title='Template:A'>Template:A</a>");
fxt.Test_load(brys, "<a href='/wiki/Template:A' id='xowa_lnki_3' title='Template:A'>Template:A</a>");
}
@Test public void Srl_lnki_text_n_apos() {
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(12), Bry_.new_ascii_("A'b"), Xow_hzip_dict.Escape_bry);
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/wiki/Template:A'b\" id='xowa_lnki_0' title='Template:A'b'>Template:A'b</a>");
fxt.Test_load(brys, "<a href='/wiki/Template:A&#39;b' title='Template:A&#39;b'>Template:A'b</a>");
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(12), fxt.Make_int(3), Bry_.new_ascii_("A'b"), Xow_hzip_dict.Escape_bry);
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/wiki/Template:A'b\" id=\"xowa_lnki_3\" title='Template:A'b'>Template:A'b</a>");
fxt.Test_load(brys, "<a href='/wiki/Template:A&#39;b' id='xowa_lnki_3' title='Template:A&#39;b'>Template:A'b</a>");
}
@Test public void Srl_lnki_text_n_xwiki() {
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(2), Byte_ascii.Pipe_bry, Bry_.new_ascii_("en.wiktionary.org"), Byte_ascii.Pipe_bry, Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry);
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/site/en.wiktionary.org/wiki/A\" id='xowa_lnki_0' title='A'>A</a>");
fxt.Test_load(brys, "<a href='/site/en.wiktionary.org/wiki/A' title='A'>A</a>");
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(2), fxt.Make_int(3), Byte_ascii.Pipe_bry, Bry_.new_ascii_("en.wiktionary.org"), Byte_ascii.Pipe_bry, Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry);
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/site/en.wiktionary.org/wiki/A\" id=\"xowa_lnki_3\" title='A'>A</a>");
fxt.Test_load(brys, "<a href='/site/en.wiktionary.org/wiki/A' id='xowa_lnki_3' title='A'>A</a>");
}
@Test public void Srl_lnki_text_n_smoke() {
byte[][] brys = Bry_.Ary(Bry_.new_ascii_("a_1"), Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(2), Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry, Bry_.new_ascii_("a_2"));
fxt.Test_save(brys, "a_1<a xtid='a_lnki_text_n' href=\"/wiki/A\" id='xowa_lnki_0' title='A'>A</a>a_2");
fxt.Test_load(brys, "a_1<a href='/wiki/A' title='A'>A</a>a_2");
byte[][] brys = Bry_.Ary(Bry_.new_ascii_("a_1"), Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(2), fxt.Make_int(3), Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry, Bry_.new_ascii_("a_2"));
fxt.Test_save(brys, "a_1<a xtid='a_lnki_text_n' href=\"/wiki/A\" id=\"xowa_lnki_3\" title='A'>A</a>a_2");
fxt.Test_load(brys, "a_1<a href='/wiki/A' id='xowa_lnki_3' title='A'>A</a>a_2");
}
@Test public void Srl_lnki_text_y() {
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_y, Bry_.ints_(2), Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry, Bry_.new_ascii_("A1"), Xow_hzip_dict.Bry_a_rhs);
fxt.Test_save(brys, "<a xtid='a_lnki_text_y' href=\"/wiki/A\" id='xowa_lnki_0' title='A'>A1</a>");
fxt.Test_load(brys, "<a href='/wiki/A' title='A'>A1</a>");
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnki_text_y, Bry_.ints_(2), fxt.Make_int(3), Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry, Bry_.new_ascii_("A1"), Xow_hzip_dict.Bry_a_rhs);
fxt.Test_save(brys, "<a xtid='a_lnki_text_y' href=\"/wiki/A\" id=\"xowa_lnki_3\" title='A'>A1</a>");
fxt.Test_load(brys, "<a href='/wiki/A' id='xowa_lnki_3' title='A'>A1</a>");
}
@Test public void Srl_lnki_text_y_nest() {
byte[][] brys = Bry_.Ary
( Xow_hzip_dict.Bry_lnki_text_y, Bry_.ints_(2), Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry
, Bry_.new_ascii_("B"), Xow_hzip_dict.Bry_lnki_text_y, Bry_.ints_(2), Bry_.new_ascii_("C"), Xow_hzip_dict.Escape_bry, Bry_.new_ascii_("C1"), Xow_hzip_dict.Bry_a_rhs, Bry_.new_ascii_("D")
( Xow_hzip_dict.Bry_lnki_text_y, Bry_.ints_(2), fxt.Make_int(3), Bry_.new_ascii_("A"), Xow_hzip_dict.Escape_bry
, Bry_.new_ascii_("B"), Xow_hzip_dict.Bry_lnki_text_y, Bry_.ints_(2), fxt.Make_int(3), Bry_.new_ascii_("C"), Xow_hzip_dict.Escape_bry, Bry_.new_ascii_("C1"), Xow_hzip_dict.Bry_a_rhs, Bry_.new_ascii_("D")
, Xow_hzip_dict.Bry_a_rhs
);
fxt.Test_save(brys, "<a xtid='a_lnki_text_y' href=\"/wiki/A\">B<a xtid='a_lnki_text_y' href=\"/wiki/C\">C1</a>D</a>");
fxt.Test_load(brys, "<a href='/wiki/A' title='A'>B<a href='/wiki/C' title='C'>C1</a>D</a>");
fxt.Test_save(brys, "<a xtid='a_lnki_text_y' href=\"/wiki/A\" id=\"xowa_lnki_3\">B<a xtid='a_lnki_text_y' href=\"/wiki/C\" id=\"xowa_lnki_3\">C1</a>D</a>");
fxt.Test_load(brys, "<a href='/wiki/A' id='xowa_lnki_3' title='A'>B<a href='/wiki/C' id='xowa_lnki_3' title='C'>C1</a>D</a>");
}
@Test public void Srl_noop() {
byte[][] brys = Bry_.Ary(Bry_.new_utf8_("<a href='/wiki/A'>A"), Xow_hzip_dict.Bry_a_rhs);
byte[][] brys = Bry_.Ary(Bry_.new_utf8_("<a href='/wiki/A'>A"), Xow_hzip_dict.Bry_a_rhs); // NOTE: still converts "</a>" to hzip
fxt.Test_save(brys, "<a href='/wiki/A'>A</a>");
fxt.Test_load(brys, "<a href='/wiki/A'>A</a>");
}
@Test public void Srl_lnki_text_y__multiple() { // PURPOSE: if id is missing from 1st anchor, do not get from second
byte[][] brys = Bry_.Ary(Bry_.new_utf8_("<a xtid='a_lnki_text_n' href=\"/wiki/A\" title=\"A\">A")
, Xow_hzip_dict.Bry_a_rhs
, Xow_hzip_dict.Bry_lnki_text_n, Bry_.ints_(2), fxt.Make_int(3), Bry_.new_ascii_("B"), Xow_hzip_dict.Escape_bry
);
fxt.Test_save(brys, "<a xtid='a_lnki_text_n' href=\"/wiki/A\" title=\"A\">A</a><a xtid='a_lnki_text_n' href=\"/wiki/B\" id=\"xowa_lnki_3\" title=\"B\">B</a>");
fxt.Test_load(brys, "<a xtid='a_lnki_text_n' href=\"/wiki/A\" title=\"A\">A</a><a href='/wiki/B' id='xowa_lnki_3' title='B'>B</a>");
}
@Test public void Srl_lnke_txt() {
byte[][] brys = Bry_.Ary(Xow_hzip_dict.Bry_lnke_txt, Bry_.new_ascii_("http://a.org"), Xow_hzip_dict.Escape_bry);
@@ -93,7 +102,7 @@ public class Xow_hzip_itm__anchor_tst {
}
@Test public void Html_lnki_xwiki() {
fxt.Init_xwiki("wikt", "en.wiktionary.org");
fxt.Test_html("[[wikt:A]]", "<a xtid='a_lnki_text_n' href=\"/site/en.wiktionary.org/wiki/A\" xowa_redlink='0'>wikt:A</a>");
fxt.Test_html("[[wikt:A]]", "<a xtid='a_lnki_text_n' href=\"/site/en.wiktionary.org/wiki/A\" xowa_redlink='1'>wikt:A</a>");
}
@Test public void Html_lnke_txt() {
fxt.Test_html("http://a.org", "<a xtid='a_lnke_txt' href=\"http://a.org\" class=\"external text\" rel=\"nofollow\">http://a.org</a>");

View File

@@ -57,7 +57,7 @@ public class Xow_hzip_mgr {
}
if (add_bgn != -1) bfr.Add_mid(src, add_bgn, src_len);
}
public byte[] Parse(Bry_bfr rv, byte[] page_url, byte[] src) {
public byte[] Parse(Bry_bfr rv, byte[] page_url, byte[] src, OrderedHash redlink_uids) {
this.page_url = page_url; this.src = src;
this.src_len = src.length;
int pos = 0, add_bgn = -1;
@@ -71,7 +71,7 @@ public class Xow_hzip_mgr {
byte tid = src[tid_pos];
switch (tid) {
case Xow_hzip_dict.Tid_lnki_text_n:
case Xow_hzip_dict.Tid_lnki_text_y: pos = itm__anchor.Load_lnki(rv, src, src_len, itm_pos, tid); break;
case Xow_hzip_dict.Tid_lnki_text_y: pos = itm__anchor.Load_lnki(rv, src, src_len, itm_pos, tid, redlink_uids); break;
case Xow_hzip_dict.Tid_lnke_txt:
case Xow_hzip_dict.Tid_lnke_brk_text_n:
case Xow_hzip_dict.Tid_lnke_brk_text_y: pos = itm__anchor.Load_lnke(rv, src, src_len, itm_pos, tid); break;

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package gplx.xowa.html.hzips; import gplx.*; import gplx.xowa.*; import gplx.xowa.html.*;
class Xow_hzip_mgr_fxt {
private Bry_bfr bfr = Bry_bfr.reset_(Io_mgr.Len_mb); private Xow_hzip_mgr hzip_mgr; private Xowe_wiki wiki;
private Xodump_stats_itm stats = new Xodump_stats_itm();
private Xodump_stats_itm stats = new Xodump_stats_itm(); private final OrderedHash redlink_uids = OrderedHash_.new_();
public void Clear() {
if (hzip_mgr == null) {
Xoae_app app = Xoa_app_fxt.app_();
@@ -31,6 +31,7 @@ class Xow_hzip_mgr_fxt {
wiki.Xwiki_mgr().Add_full(alias, domain);
wiki.Appe().User().Wiki().Xwiki_mgr().Add_full(domain, domain);
}
public byte[] Make_int(int v) {return Xow_hzip_int_.Save_bin_int_abrv(v);}
public void Test_save(byte[][] expd_brys, String html) {Test_save(html, expd_brys);}
public void Test_save(String html, byte[]... expd_brys) {
byte[] expd = Bry_.Add(expd_brys);
@@ -39,7 +40,7 @@ class Xow_hzip_mgr_fxt {
}
public void Test_load(byte[][] src_brys, String expd) {
byte[] src = Bry_.Add(src_brys);
src = hzip_mgr.Parse(bfr, Bry_.Empty, src);
src = hzip_mgr.Parse(bfr, Bry_.Empty, src, redlink_uids);
Tfds.Eq(expd, String_.new_utf8_(src));
}
public void Test_html(String html, String expd) {

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.xowa.html.lnkis; import gplx.*; import gplx.xowa.*; import gplx.xowa.html.*;
public class Xoh_redlink_utl {
public static final byte[] Cls_bry = Bry_.new_ascii_("class='new'");
public static final String New_str = "new";
}

View File

@@ -27,7 +27,7 @@ public class Xog_redlink_mgr implements GfoInvkAble {
this.redlink_lnki_list = page.Redlink_lnki_list();
this.lnki_list = redlink_lnki_list.Lnki_list();
this.thread_id = redlink_lnki_list.Thread_id();
this.log_enabled = log_enabled; this.usr_dlg = log_enabled ? Gfo_usr_dlg_.I : Gfo_usr_dlg_.Null;
this.log_enabled = log_enabled; this.usr_dlg = log_enabled ? Gfo_usr_dlg_.I : Gfo_usr_dlg_.Noop;
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_run)) Redlink();

View File

@@ -35,6 +35,7 @@ public class Xopg_redlink_lnki_list {
if (disabled) return;
Xoa_ttl ttl = lnki.Ttl(); if (ttl == null) return; // occurs for invalid links
Xow_ns ns = ttl.Ns();
lnki.Html_id_(lnki_idx); // NOTE: set html_id in order html to print out "id='xowa_lnki_1'; want to print out id for consistency's sake, even if these links won't be check for redlinks; DATE:2015-05-07
if ( ns.Id_file_or_media() // ignore files which will usually not be in local wiki (most are in commons), and whose html is built up separately
|| (ns.Id_ctg() && !ttl.ForceLiteralLink()) // ignore ctgs which have their own html builder, unless it is literal; EX: [[:Category:A]]; DATE:2014-02-24
|| ns.Id_special() // ignore special, especially Search; EX: Special:Search/Earth
@@ -42,9 +43,9 @@ public class Xopg_redlink_lnki_list {
|| ttl.Wik_itm() != null // xwiki lnki; EX: simplewiki links in homewiki; [[simplewiki:Earth]]
)
return;
lnki.Html_id_(lnki_idx);
lnki_list.Add(lnki);
++lnki_idx;
}
public static final String Lnki_id_prefix = "xowa_lnki_";
public static final int Lnki_id_prefix_len = String_.Len(Lnki_id_prefix);
}

View File

@@ -39,6 +39,7 @@ public class Gxw_html_server implements Gxw_html {
public boolean Html_doc_find(String id, String find, boolean dir_fwd, boolean case_match, boolean wrap_find) {throw Err_.not_implemented_();}
public void Html_doc_body_focus() {Exec(cfg.Doc_body_focus());}
public void Html_doc_selection_focus_toggle() {Exec(cfg.Doc_selection_focus_toggle());}
public boolean Html_doc_loaded() {return Bool_.cast_(Exec(cfg.Doc_loaded()));}
public String Html_elem_atr_get_str (String id, String atr_key) {return Exec(cfg.Elem_atr_get(id, atr_key));}
public boolean Html_elem_atr_get_bool (String id, String atr_key) {return Bool_.parse_(Exec(cfg.Elem_atr_get(id, atr_key)));}
public boolean Html_elem_atr_set (String id, String atr_key, String val) {return Exec_as_bool(cfg.Elem_atr_set(id, atr_key, val));}

View File

@@ -16,7 +16,7 @@ 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.xowa.setup.maints; import gplx.*; import gplx.xowa.*; import gplx.xowa.setup.*;
import gplx.ios.*; import gplx.xowa.wikis.*;
import gplx.ios.*; import gplx.xowa.wikis.*; import gplx.xowa.files.downloads.*;
public class Xoa_maint_mgr implements GfoInvkAble {
public Xoa_maint_mgr(Xoae_app app) {
this.app = app;

View File

@@ -16,7 +16,7 @@ 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.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.xowa.specials.search.parsers.*;
import gplx.xowa.specials.search.parsers_old.*;
class Xows_db_cache { // one cache per search term; EX: "Earth* AND (History OR Future) AND -"middle earth"" is one cache
private final OrderedHash hash = OrderedHash_.new_bry_();
public Xows_db_word[] Words() {return words;} private Xows_db_word[] words; // words in cache; EX: earth, history, future but not "middle earth" (since not'ed)

View File

@@ -0,0 +1,68 @@
/*
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.xowa.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
import gplx.core.primitives.*;
class Xows_text_parser__v1 {
private Xol_lang lang; private Bry_bfr bfr = Bry_bfr.new_(255);
private final OrderedHash list = OrderedHash_.new_bry_();
public void Init(Xol_lang lang) {this.lang = lang;}
public void Parse(byte[] src, int src_len, int bgn, int end) {
if (lang != null) { // null lang passed in by searcher
src = lang.Case_mgr().Case_build_lower(src);
src_len = src.length;
}
int i = 0; boolean word_done = false;
while (true) {
if (word_done || i == src_len) {
if (bfr.Len() > 0) {
byte[] word = bfr.Xto_bry_and_clear();
if (!list.Has(word)) list.Add(word, word); // don't add same word twice; EX: Title of "Can Can" should only have "Can" in index
}
if (i == src_len) break;
word_done = false;
}
byte b = src[i];
switch (b) {
case Byte_ascii.Underline: // underline is word-breaking; EX: A_B -> A, B
case Byte_ascii.Space: // should not occur, but just in case (only underscores)
case Byte_ascii.Tab: case Byte_ascii.NewLine: case Byte_ascii.CarriageReturn: // should not occur in titles, but just in case
case Byte_ascii.Dash: // treat hypenated words separately
case Byte_ascii.Dot: // treat abbreviations as separate words; EX: A.B.C.
case Byte_ascii.Bang: case Byte_ascii.Hash: case Byte_ascii.Dollar: case Byte_ascii.Percent:
case Byte_ascii.Amp: case Byte_ascii.Paren_bgn: case Byte_ascii.Paren_end: case Byte_ascii.Asterisk:
case Byte_ascii.Comma: case Byte_ascii.Slash:
case Byte_ascii.Colon: case Byte_ascii.Semic: case Byte_ascii.Gt:
case Byte_ascii.Question: case Byte_ascii.At: case Byte_ascii.Brack_bgn: case Byte_ascii.Brack_end:
case Byte_ascii.Pow: case Byte_ascii.Tick:
case Byte_ascii.Curly_bgn: case Byte_ascii.Pipe: case Byte_ascii.Curly_end: case Byte_ascii.Tilde:
case Byte_ascii.Quote: case Byte_ascii.Apos: // FUTURE: apos will split "Earth's" to Earth and s; should remove latter
++i;
word_done = true;
break;
default:
bfr.Add_byte(b);
++i;
break;
}
}
// byte[][] rv = (byte[][])list.Xto_ary(typeof(byte[]));
// list.Clear(); list.ResizeBounds(16);
// return rv;
}
}

View File

@@ -0,0 +1,107 @@
/*
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.xowa.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
import gplx.core.btries.*; import gplx.xowa.langs.cases.*;
class Xows_text_parser__v2 {
private final Btrie_slim_mgr trie = Btrie_slim_mgr.cs_();
private final Bry_bfr bfr = Bry_bfr.new_(32);
private Xob_word_mgr word_mgr; private Xol_case_mgr case_mgr;
private byte[] src; private int end; // bgn,
private boolean dirty; private Xows_text_tkn__split parser__ws;
public void Init_for_ttl(Xob_word_mgr word_mgr, Xol_case_mgr case_mgr) {
this.word_mgr = word_mgr; this.case_mgr = case_mgr;
trie.Clear();
this.parser__ws = Xows_text_tkn__split.new_(trie, Bool_.N, " ", "\t", "\n", "\r", "_");
Xows_text_tkn__split.new_(trie, Bool_.N, "!", "?");
Xows_text_tkn__split.new_(trie, Bool_.N, "(", ")");
Xows_text_tkn__split.new_(trie, Bool_.N, "/");
Xows_text_tkn__ellipsis.new_(trie, "..");
Xows_text_tkn__apos.new_(trie, "'", Byte_ascii.Ltr_s);
}
public void Parse(byte[] src, int src_len, int bgn, int end) {
this.src = src; this.end = end; // this.bgn = bgn;
this.dirty = false; this.bgn__ws = bgn__dash = bgn__slash = -1;
this.src = case_mgr.Case_build_lower(src); src_len = this.src.length;
int pos = bgn;
while (true) {
boolean is_last = pos == end;
if (is_last) { // do split
Word__add(bgn__ws, end);
break;
}
byte b = src[pos];
Object o = trie.Match_bgn_w_byte(b, src, pos, end);
if (o == null) { // unknown sequence; word-char
Char__add(b, pos);
++pos;
}
else {
Xows_text_tkn parser = (Xows_text_tkn)o;
pos = parser.Parse(this, src, end, pos, trie.Match_pos());
}
}
}
public int Bgn__ws() {return bgn__ws;} private int bgn__ws;
public int Bgn__dash() {return bgn__dash;} private int bgn__dash;
public int Bgn__slash() {return bgn__slash;} private int bgn__slash;
public void Bgn__ws_clear() {this.bgn__ws = -1;}
public void Bgn__dash_(int v) {this.bgn__dash = v;}
public void Bgn__slash_(int v) {this.bgn__slash= v;}
public void Word__add(int bgn__ws, int word_end) {
if (bgn__ws == word_end) return; // handle situations like "A!" where sym is at eos
if (bgn__ws == -1) return; // handle situations like "A... " where " " is different than "..."
byte[] word = dirty ? bfr.Xto_bry_and_clear() : Bry_.Mid(src, bgn__ws, word_end);
word_mgr.Add(word);
if (bgn__dash != -1) {
word_mgr.Add(Bry_.Mid(src, bgn__dash, word_end));
bgn__dash = -1;
}
}
public void Char__add(byte b, int pos) {
if (dirty)
bfr.Add_byte(b);
else {
if (bgn__ws == -1)
bgn__ws = pos;
}
}
public boolean Ws__is_word_end(int pos) {return parser__ws.Is_word_end(src, end, pos);}
}
class Xob_word_mgr {
private final OrderedHash hash = OrderedHash_.new_bry_();
public void Clear() {hash.Clear();}
public int Len() {return hash.Count();}
public Xob_word_itm Get_at(int i) {return (Xob_word_itm)hash.FetchAt(i);}
public void Add(byte[] word) {
Xob_word_itm itm = (Xob_word_itm)hash.Fetch(word);
if (itm == null) {
itm = new Xob_word_itm(word);
hash.Add(word, itm);
}
itm.Count_add_1_();
}
}
class Xob_word_itm {
public Xob_word_itm(byte[] word) {
this.word = word;
this.count = 0;
}
public byte[] Word() {return word;} private final byte[] word;
public int Count() {return count;} private int count; public void Count_add_1_() {++count;}
@gplx.Internal protected Xob_word_itm Count_(int v) {this.count = v; return this;}
}

View File

@@ -0,0 +1,156 @@
/*
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.xowa.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
import org.junit.*; import gplx.xowa.langs.cases.*;
public class Xows_text_parser__v2_tst {
private final Xows_text_parser__v2_fxt fxt = new Xows_text_parser__v2_fxt();
@Before public void init() {fxt.Init();}
@Test public void Word__one() {
fxt.Clear().Test_split("abcd", "abcd");
}
@Test public void Word__many() {
fxt.Clear().Test_split("abc d ef", "abc", "d", "ef");
}
@Test public void Ws__many() {
fxt.Clear().Test_split("a b", "a", "b");
}
@Test public void Ws__bgn() {
fxt.Clear().Test_split(" a", "a");
}
@Test public void Ws__end() {
fxt.Clear().Test_split(" a", "a");
}
@Test public void Under() {
fxt.Clear().Test_split("a_b", "a", "b");
}
@Test public void Lowercase() {
fxt.Clear().Test_split("A B C", "a", "b", "c");
}
@Test public void Dupe() {
fxt.Clear().Test_split("a a a", fxt.Make_word("a", 3));
}
@Test public void Dupe__lowercase() {
fxt.Clear().Test_split("a A", fxt.Make_word("a", 2));
}
@Test public void Dot__acronym() { // EX: "History of U.S.A. Science "
fxt.Clear().Test_split("abc D.E.F. ghi", "abc", "d.e.f.", "ghi");
}
@Test public void Dot__initials() { // EX: "H. G. Wells"
fxt.Clear().Test_split("a. b. cde", "a.", "b.", "cde");
}
@Test public void Dot__abrv() { // EX: "vs.", "no."
fxt.Clear().Test_split("a vs. b", "a", "vs.", "b");
}
@Test public void Dot__internet() { // EX: "en.wikipedia.org"
fxt.Clear().Test_split("a.com", "a.com");
}
@Test public void Ellipsis__basic() { // EX: "Nights into Dreams..."
fxt.Clear().Test_split("a... bc d", "a", "...", "bc", "d");
}
@Test public void Ellipsis__bgn() {
fxt.Clear().Test_split("...a", "...", "a");
}
@Test public void Ellipsis__end() {
fxt.Clear().Test_split("a...", "a", "...");
}
@Test public void Ellipsis__no_ws() {
fxt.Clear().Test_split("a...b", "a", "...", "b");
}
@Test public void Apos__contraction() { // EX: "I'm"
fxt.Clear().Test_split("i'm", "i'm");
}
@Test public void Apos__multiple() {
fxt.Clear().Test_split("a''b", "a''b");
}
@Test public void Apos__possessive_singular_eos() {// EX: "wiki's"
fxt.Clear().Test_split("a's", "a", "a's");
}
@Test public void Apos__possessive_singular_word() {
fxt.Clear().Test_split("a's b", "a", "a's", "b");
}
@Test public void Apos__possessive_plural_eos() {// EX: "wiki'"
fxt.Clear().Test_split("a'", "a", "a'");
}
@Test public void Apos__possessive_plural_word() {
fxt.Clear().Test_split("a' b", "a", "a'", "b");
}
@Test public void Bang__lone() {
fxt.Clear().Test_split("! a", "a");
}
@Test public void Bang__word() {
fxt.Clear().Test_split("a!", "a");
}
@Test public void Bang__sentence() {// EX: "A!"
fxt.Clear().Test_split("a b!", "a", "b");
}
@Test public void Question__sentence() {// EX: "A?"
fxt.Clear().Test_split("a?", "a");
}
@Test public void Parens_both() {// EX: "A (letter)"
fxt.Clear().Test_split("a (b)", "a", "b");
}
@Test public void Slash__word() {// EX: "Good_cop/bad_cop"
fxt.Clear().Test_split("a/b", "a", "b");
}
// apos: 'Some apostrophe sentence' ?
}
class Xows_text_parser__v2_fxt {
private final Xows_text_parser__v2 word_parser = new Xows_text_parser__v2();
private final Xob_word_mgr word_mgr = new Xob_word_mgr();
private final Bry_bfr tmp_bfr = Bry_bfr.new_(32);
private Xol_case_mgr case_mgr;
public void Init() {
case_mgr = Xol_case_mgr_.Ascii();
word_parser.Init_for_ttl(word_mgr, case_mgr);
}
public Xows_text_parser__v2_fxt Clear() {
word_mgr.Clear();
return this;
}
public Xob_word_itm Make_word(String raw, int count) {return new Xob_word_itm(Bry_.new_utf8_(raw)).Count_(count);}
public void Test_split(String src, String... expd_words) {
int len = expd_words.length;
Xob_word_itm[] ary = new Xob_word_itm[len];
for (int i = 0; i < len; ++i) {
ary[i] = Make_word(expd_words[i], 1);
}
Test_split(src, ary);
}
public void Test_split(String src, Xob_word_itm... expd_words) {
byte[] src_bry = Bry_.new_utf8_(src);
word_parser.Parse(src_bry, src_bry.length, 0, src_bry.length);
Tfds.Eq_str_lines(To_str(expd_words), To_str(word_mgr));
}
private String To_str(Xob_word_itm[] word_ary) {
int len = word_ary.length;
for (int i = 0; i < len; ++i) {
if (i != 0) tmp_bfr.Add_byte_nl();
Xob_word_itm word = word_ary[i];
tmp_bfr.Add(word.Word()).Add_byte_pipe();
tmp_bfr.Add_int_variable(word.Count());
}
return tmp_bfr.Xto_str_and_clear();
}
private String To_str(Xob_word_mgr word_mgr) {
int len = word_mgr.Len();
Xob_word_itm[] ary = new Xob_word_itm[len];
for (int i = 0; i < len; ++i)
ary[i] = word_mgr.Get_at(i);
return To_str(ary);
}
}

View File

@@ -0,0 +1,146 @@
/*
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.xowa.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
import gplx.core.btries.*; import gplx.core.primitives.*;
interface Xows_text_tkn {
int Parse(Xows_text_parser__v2 mgr, byte[] src, int src_end, int tkn_bgn, int tkn_end);
}
class Xows_text_tkn__split implements Xows_text_tkn {
private final boolean add_sym_as_word;
private final Btrie_slim_mgr trie = Btrie_slim_mgr.cs_();
public Xows_text_tkn__split(boolean add_sym_as_word, byte[][] ary) {
this.add_sym_as_word = add_sym_as_word;
int len = ary.length;
for (int i = 0; i < len; ++i) {
byte[] itm = ary[i];
trie.Add_obj(itm, Int_obj_val.new_(itm.length));
}
}
public int Parse(Xows_text_parser__v2 mgr, byte[] src, int src_end, int tkn_bgn, int tkn_end) {
if (mgr.Bgn__ws() != -1) // pending word
mgr.Word__add(mgr.Bgn__ws(), tkn_bgn); // make word; EX: "B" in "A B C"
mgr.Bgn__ws_clear();
if (add_sym_as_word)
mgr.Word__add(tkn_bgn, tkn_end);
int rv = tkn_end;
while (rv < src_end) { // skip ws; EX: "a b"
byte b = src[rv];
Object o = trie.Match_bgn_w_byte(b, src, rv, src_end);
if (o == null) break;
Int_obj_val itm_len = (Int_obj_val)o;
rv += itm_len.Val();
}
return rv;
}
public boolean Is_word_end(byte[] src, int end, int pos) {
if (pos >= end) return true;
byte b = src[pos];
Object o = trie.Match_bgn_w_byte(b, src, pos, end);
return o != null;
}
public static Xows_text_tkn__split new_(Btrie_slim_mgr trie, boolean add_sym_as_word, String... str_ary) {
byte[][] bry_ary = Bry_.Ary(str_ary);
Xows_text_tkn__split rv = new Xows_text_tkn__split(add_sym_as_word, bry_ary);
int len = bry_ary.length;
for (int i = 0; i < len; ++i)
trie.Add_obj(bry_ary[i], rv);
return rv;
}
}
class Xows_text_tkn__ellipsis implements Xows_text_tkn {
private final byte ellipsis_byte;
public Xows_text_tkn__ellipsis(byte ellipsis_byte) {
this.ellipsis_byte = ellipsis_byte;
}
public int Parse(Xows_text_parser__v2 mgr, byte[] src, int src_end, int tkn_bgn, int tkn_end) {
int bgn__ws = mgr.Bgn__ws();
if (bgn__ws != -1) {
mgr.Word__add(bgn__ws, tkn_bgn); // add word; EX: "Dreams" in "Dreams..."
mgr.Bgn__ws_clear(); // clear ws flag, else space will create word; EX: "A... B"
}
int rv = Bry_finder.Find_fwd_while(src, tkn_end, src_end, ellipsis_byte);
mgr.Word__add(tkn_bgn, rv); // add ellipssis
return rv;
}
public static Xows_text_tkn new_(Btrie_slim_mgr trie, String ellipsis) {
byte[] bry = Bry_.new_utf8_(ellipsis);
Xows_text_tkn rv = new Xows_text_tkn__ellipsis(Bry_.Get_at_end_or_fail(bry));
trie.Add_obj(bry, rv);
return rv;
}
}
class Xows_text_tkn__apos implements Xows_text_tkn {
private final byte possessive_byte;
public Xows_text_tkn__apos(byte possessive_byte) {this.possessive_byte = possessive_byte;}
public int Parse(Xows_text_parser__v2 mgr, byte[] src, int src_end, int tkn_bgn, int tkn_end) {
int rv = tkn_end;
byte apos_mode = Apos_contraction;
if (tkn_end == src_end) { // EX: "A'<EOS>"
apos_mode = Apos_possessive_plural;
rv = src_end;
}
else if (mgr.Ws__is_word_end(tkn_end)) { // EX: "A' "
apos_mode = Apos_possessive_plural;
rv = tkn_end;
}
else if ( src[tkn_end] == possessive_byte // EX: "A's "
&& mgr.Ws__is_word_end(tkn_end + 1))
{
apos_mode = Apos_possessive_singular;
rv = tkn_end + 1;
}
switch (apos_mode) {
case Apos_possessive_plural:
case Apos_possessive_singular:
int word_bgn = mgr.Bgn__ws();
mgr.Word__add(word_bgn, tkn_bgn); // add noun; EX: "wiki";
mgr.Word__add(word_bgn, rv); // add full; EX: "wiki's"
mgr.Bgn__ws_clear();
return rv;
case Apos_contraction:
break;
}
return rv;
}
private static final byte Apos_contraction = 1, Apos_possessive_plural = 2, Apos_possessive_singular = 3;
public static Xows_text_tkn new_(Btrie_slim_mgr trie, String apos, byte possessive_byte) {
byte[] bry = Bry_.new_utf8_(apos);
Xows_text_tkn rv = new Xows_text_tkn__apos(possessive_byte);
trie.Add_obj(bry, rv);
return rv;
}
}
// class Xows_text_tkn__slash : Xows_text_tkn {
// public int Parse(Xows_text_parser__v2 mgr, byte[] src, int src_end, int tkn_bgn, int tkn_end) {
// int bgn__dash = mgr.Bgn__dash();
// // add part;
// int part_bgn = mgr.Bgn__dash();
// if (part_bgn == -1) // no dash
// part_bgn = mgr.Bgn__ws();
// if (part_bgn != -1)
// mgr.Word__add(part_bgn, tkn_bgn); // add word; EX: "a" in "a-b"
// mgr.Bgn__dash_(tkn_end);
// return tkn_end;
// }
// public static Xows_text_tkn new_(Btrie_slim_mgr trie, String dash) {
// byte[] bry = Bry_.new_utf8_(dash);
// Xows_text_tkn rv = new Xows_text_tkn__slash();
// trie.Add_obj(bry, rv);
// return rv;
// }
// }

View File

@@ -15,7 +15,7 @@ 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.xowa.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
package gplx.xowa.specials.search.parsers_old; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
public class Xow_search_parser {
private Xow_search_parser_ctx parse_ctx = new Xow_search_parser_ctx(); private byte[] src;
public Xows_db_matcher Parse(byte[] src) {

View File

@@ -15,7 +15,7 @@ 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.xowa.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
package gplx.xowa.specials.search.parsers_old; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
import gplx.core.primitives.*; import gplx.core.btries.*;
class Xow_search_scanner {
private final ListAdp tkns = ListAdp_.new_(); private byte[] src; private int src_len, pos, txt_bgn;

View File

@@ -15,7 +15,7 @@ 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.xowa.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
package gplx.xowa.specials.search.parsers_old; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
class Xow_search_tkn {
private final int val_bgn, val_end;
private final byte[] val_bry;

View File

@@ -32,7 +32,7 @@ public class Prefs_converter {
Io_mgr._.SaveFilStr(trg_fil, new_str);
app.Cfg_mgr().Db_load_txt();
app.Cfg_mgr().Set_by_app("app.setup.dumps.wiki_storage_type", "sqlite");
app.Log_wtr().Log_msg_to_session_fmt("converted options to v2");
app.Log_wtr().Log_to_session_fmt("converted options to v2");
}
}
}

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.xowa.wikis.data; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*;
import gplx.xowa.wikis.data.tbls.*;
public interface Xow_page_fetcher {
Xow_page_fetcher Wiki_(Xowe_wiki v);
byte[] Fetch(int ns_id, byte[] ttl);
void Clear();
}

View File

@@ -0,0 +1,32 @@
/*
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.xowa.wikis.data; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*;
import gplx.xowa.wikis.data.tbls.*;
public class Xow_page_fetcher_test implements Xow_page_fetcher {
public Xow_page_fetcher Wiki_(Xowe_wiki v) {return this;}
public void Clear() {pages.Clear();} private HashAdp pages = HashAdp_.new_();
public void Add(int ns_id, byte[] ttl, byte[] text) {
Xowd_page_itm page = new Xowd_page_itm().Ns_id_(ns_id).Ttl_page_db_(ttl).Text_(text);
pages.Add(Make_key(ns_id, ttl), page);
}
public byte[] Fetch(int ns_id, byte[] ttl) {
Xowd_page_itm rv = (Xowd_page_itm)pages.Fetch(Make_key(ns_id, ttl));
return rv == null ? null : rv.Text();
}
String Make_key(int ns_id, byte[] ttl) {return Int_.Xto_str(ns_id) + "|" + String_.new_utf8_(ttl);}
}

View File

@@ -0,0 +1,27 @@
/*
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.xowa.wikis.data; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*;
public class Xow_page_fetcher_wiki implements Xow_page_fetcher {
public Xow_page_fetcher Wiki_(Xowe_wiki v) {this.wiki = v; return this;} private Xowe_wiki wiki;
public void Clear() {}
public byte[] Fetch(int ns_id, byte[] ttl_bry) {
Xoa_ttl ttl = Xoa_ttl.parse_(wiki, ns_id, ttl_bry);
Xoae_page page = wiki.Data_mgr().Get_page(ttl, false); // go through data_mgr in case of redirects
return page.Missing() ? null : page.Data_raw();
}
}

View File

@@ -16,7 +16,7 @@ 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.xowa.wmfs; import gplx.*; import gplx.xowa.*;
import gplx.xowa.wmfs.apis.*;
import gplx.xowa.wmfs.apis.*; import gplx.xowa.files.downloads.*;
public class Xowmf_mgr {
public Xowmf_mgr() {
Gfo_usr_dlg usr_dlg = Xoa_app_.Usr_dlg();

View File

@@ -16,7 +16,7 @@ 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.xowa.wmfs.apis; import gplx.*; import gplx.xowa.*; import gplx.xowa.wmfs.*;
import gplx.ios.*; import gplx.xowa.files.repos.*;
import gplx.ios.*; import gplx.xowa.files.repos.*; import gplx.xowa.files.downloads.*;
public abstract class Xoapi_orig_base {
public boolean Api_query_size(Xoapi_orig_rslts rv, Xof_download_wkr download_wkr, Xow_repo_mgr repo_mgr, byte[] ttl, int width, int height) {
if (!gplx.ios.IoEngine_system.Web_access_enabled) return false; // don't check api if download disabled else "download_failed" messages in log (particularly during pkg_make) DATE:2015-02-12

View File

@@ -16,6 +16,7 @@ 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.xowa.wmfs.apis; import gplx.*; import gplx.xowa.*; import gplx.xowa.wmfs.*;
import gplx.xowa.files.downloads.*;
public class Xoapi_orig_mok extends Xoapi_orig_base {
private String wiki_str = "", ttl_str = "", redirect_str = ""; private int orig_w, orig_h; private boolean fail = false;
public Xoapi_orig_mok Ini(String wiki_str, String ttl_str, String redirect_str, int orig_w, int orig_h, boolean pass) {

View File

@@ -16,6 +16,7 @@ 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.xowa.wmfs.apis; import gplx.*; import gplx.xowa.*; import gplx.xowa.wmfs.*;
import gplx.xowa.files.downloads.*;
public class Xoapi_orig_wmf extends Xoapi_orig_base {
@Override public boolean Api_query_size_exec(Xoapi_orig_rslts rv, Xof_download_wkr download_wkr, byte[] ttl, int width, int height, Gfo_usr_dlg usr_dlg, byte[] repo_wiki_key) {
if (Env_.Mode_testing()) return false; // TEST: disable during tests else scrib_lib_title will try to call WMF API; DATE:2015-03-20

View File

@@ -188,7 +188,7 @@ class Dpl_xnde_fxt {
next_id = 100;
fxt.Reset();
warns = String_.Ary_empty;
fxt.App().Usr_dlg().Ui_wkr().Clear();
fxt.App().Usr_dlg().Gui_wkr().Clear();
fxt.Wiki().Hive_mgr().Clear();
fxt.Wiki().Db_mgr().Save_mgr().Clear(); // NOTE: must clear to reset next_id to 0; Ctg_create assumes clean slate from 0
fxt.Wiki().Xtn_mgr().Xtn_proofread().Enabled_y_();

View File

@@ -69,7 +69,7 @@ class Imap_parser_fxt extends Imap_fxt_base {
Xoa_url url = Xoa_url.new_(wiki.Domain_bry(), Bry_.new_ascii_("Test_1"));
Imap_xtn_mgr xtn_mgr = new Imap_xtn_mgr();
parser = new Imap_parser(xtn_mgr);
parser.Init(wiki, url, Gfo_usr_dlg_.Null);
parser.Init(wiki, url, Gfo_usr_dlg_.Noop);
parser.Clear();
imap = new Imap_map(1);
}

View File

@@ -176,7 +176,7 @@ given qry = "../C/./D" and src = "A/B"
. iterate over every slash to create "segs_ary"
A -> [A] add
B -> [A, B] add
.. -> [A] pop
.. -> [A] pop
C -> [A, C] add
. -> [A, C] noop
D -> [A, C, D] add

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