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
2014-06-30 00:04:32 -04:00
parent 85594d3cdd
commit bae88e739c
2482 changed files with 198730 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
/*
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.cache; import gplx.*;
public class Gfo_cache_mgr_base {
private OrderedHash hash = OrderedHash_.new_bry_();
public int Compress_max() {return compress_max;} public void Compress_max_(int v) {compress_max = v;} private int compress_max = 16;
public int Compress_to() {return compress_to;} public void Compress_to_(int v) {compress_to = v;} private int compress_to = 8;
protected Object Base_get_or_null(byte[] key) {
Object rv_obj = hash.Fetch(key);
return rv_obj == null ? null : ((Gfo_cache_itm)rv_obj).Val();
}
protected void Base_add(byte[] key, Object val) {
if (hash.Count() >= compress_max) Compress();
Gfo_cache_itm itm = new Gfo_cache_itm(key, val);
hash.Add(key, itm);
}
protected void Base_del(byte[] key) {
hash.Del(key);
}
public void Compress() {
hash.SortBy(Gfo_cache_itm_comparer.Touched_asc);
int del_len = hash.Count() - compress_to;
ListAdp del_list = ListAdp_.new_();
for (int i = 0; i < del_len; i++) {
Gfo_cache_itm itm = (Gfo_cache_itm)hash.FetchAt(i);
del_list.Add(itm);
}
for (int i = 0; i < del_len; i++) {
Gfo_cache_itm itm = (Gfo_cache_itm)del_list.FetchAt(i);
hash.Del(itm.Key());
}
}
}

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.cache; import gplx.*;
public class Gfo_cache_mgr_bry extends Gfo_cache_mgr_base {
public Object Get_or_null(byte[] key) {return Base_get_or_null(key);}
public void Add(byte[] key, Object val) {Base_add(key, val);}
public void Del(byte[] key) {Base_del(key);}
}
class Gfo_cache_itm {
public Gfo_cache_itm(Object key, Object val) {this.key = key; this.val = val; this.Touched_update();}
public Object Key() {return key;} private Object key;
public Object Val() {return val;} private Object val;
public long Touched() {return touched;} private long touched;
public Gfo_cache_itm Touched_update() {touched = Env_.TickCount(); return this;}
}
class Gfo_cache_itm_comparer implements gplx.lists.ComparerAble {
public int compare(Object lhsObj, Object rhsObj) {
Gfo_cache_itm lhs = (Gfo_cache_itm)lhsObj;
Gfo_cache_itm rhs = (Gfo_cache_itm)rhsObj;
return Long_.Compare(lhs.Touched(), rhs.Touched());
}
public static final Gfo_cache_itm_comparer Touched_asc = new Gfo_cache_itm_comparer();
}

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.core.bytes; import gplx.*; import gplx.core.*;
public class Bry_bldr {
public byte[] Val() {return val;} private byte[] val;
public Bry_bldr New_256() {return New(256);}
public Bry_bldr New(int len) {val = new byte[len]; return this;}
public Bry_bldr Set_rng_ws(byte v) {return Set_many(v, Byte_ascii.Space, Byte_ascii.Tab, Byte_ascii.NewLine, Byte_ascii.CarriageReturn);}
public Bry_bldr Set_rng_xml_identifier(byte v) {return Set_rng_alpha_lc(v).Set_rng_alpha_uc(v).Set_rng_num(v).Set_many(v, Byte_ascii.Underline, Byte_ascii.Dash);}
public Bry_bldr Set_rng_alpha(byte v) {return Set_rng_alpha_lc(v).Set_rng_alpha_uc(v);}
public Bry_bldr Set_rng_alpha_lc(byte v) {return Set_rng(v, Byte_ascii.Ltr_a, Byte_ascii.Ltr_z);}
public Bry_bldr Set_rng_alpha_uc(byte v) {return Set_rng(v, Byte_ascii.Ltr_A, Byte_ascii.Ltr_Z);}
public Bry_bldr Set_rng_num(byte v) {return Set_rng(v, Byte_ascii.Num_0, Byte_ascii.Num_9);}
public Bry_bldr Set_rng(byte v, int bgn, int end) {
for (int i = bgn; i <= end; i++)
val[i] = v;
return this;
}
public Bry_bldr Set_many(byte v, int... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
val[ary[i]] = v;
return this;
}
}

View File

@@ -0,0 +1,54 @@
/*
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.enums; import gplx.*; import gplx.core.*;
class Gfo_enum_grp {
// private OrderedHash itms = OrderedHash_.new_();
public Gfo_enum_grp(UuidAdp uid, String key, int id, String name, int sort, String xtn) {
this.uid = uid; this.key = key; this.id = id; this.name = name; this.sort = sort; this.xtn = xtn;
}
public UuidAdp Uid() {return uid;} private UuidAdp uid;
public String Key() {return key;} private String key;
public int Id() {return id;} private int id;
public String Name() {return name;} private String name;
public int Sort() {return sort;} private int sort;
public String Xtn() {return xtn;} private String xtn;
}
class Gfo_enum_itm {
public Gfo_enum_itm(UuidAdp uid, String key, int id, String name, int sort, String xtn) {
this.uid = uid; this.key = key; this.id = id; this.name = name; this.sort = sort; this.xtn = xtn;
}
public UuidAdp Uid() {return uid;} private UuidAdp uid;
public String Key() {return key;} private String key;
public int Id() {return id;} private int id;
public String Name() {return name;} private String name;
public int Sort() {return sort;} private int sort;
public String Xtn() {return xtn;} private String xtn;
}
/*
enum_grps
grp_guid,grp_key,grp_int,grp_name,grp_sort,grp_xtn
0-1-2-3,xowa.wiki,0,wiki,,
enum_itms
grp_int,itm_guid,itm_key,itm_int,itm_name,itm_sort,itm_xtn
1,0-1-2-3,0,en.wikipedia.org,0,enwiki,0,''
class Gfo_enum_mgr {
// public Gui
}
*/

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.core.ints; import gplx.*; import gplx.core.*;
public class Int_ary_bldr {
public Int_ary_bldr(int len) {ary = new int[len];}
public Int_ary_bldr Set(int idx, int val) {ary[idx] = val; return this;}
public int[] Xto_int_ary() {return ary;} private int[] ary;
}

View File

@@ -0,0 +1,52 @@
/*
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.fsdb; import gplx.*;
public class Binary_search_ {
public static int Search(CompareAble[] ary, int ary_len, CompareAble val) {
if (ary_len == 1) return 0;
int interval = ary_len / 2;
int pos = interval - ListAdp_.Base1;
int pos_last = ary_len - 1;
int pos_prv = -1;
int loop_count = 0;
while (loop_count++ < 32) { // 32 bit integer
CompareAble lo = ary[pos];
CompareAble hi = pos + 1 == ary_len ? null : ary[pos + 1];
int adj = 0;
int lo_comp = val.compareTo(lo);
if (lo_comp == CompareAble_.Less) // val is < lo; search slots below
adj = -1;
else {
if (hi == null) return pos; // hi is null when at last slot in ary
int hi_comp = val.compareTo(hi);
if (hi_comp == CompareAble_.More) // val is > hi; search slots above
adj = 1;
else
return pos; // val is > lo and < hi; return slot
}
interval /= 2;
if (interval == 0) interval = 1; // do not allow 0 intervals; pos must always change;
pos += (interval * adj);
if (pos == 0 && pos_prv == 0) break; // NOTE: this will only happen when 1st member is not ""
if (pos < 0) pos = 0;
else if (pos > pos_last) pos = pos_last;
pos_prv = pos;
}
return Int_.MinValue; // should only occur if (a) ary's 0th slot is not ""; or (b) some unknown error
}
}

View File

@@ -0,0 +1,47 @@
/*
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.fsdb; import gplx.*;
import org.junit.*;
public class Binary_search__tst {
private Binary_search__fxt fxt = new Binary_search__fxt();
@Test public void Basic() {
fxt.Init_ary("", "e", "j", "o", "t", "y");
fxt.Test_binary_search("a", 0);
fxt.Test_binary_search("f", 1);
fxt.Test_binary_search("k", 2);
fxt.Test_binary_search("p", 3);
fxt.Test_binary_search("u", 4);
fxt.Test_binary_search("z", 5);
}
@Test public void One() {
fxt.Init_ary("");
fxt.Test_binary_search("a", 0);
}
}
class Binary_search__fxt {
public void Init_ary(String... v) {
int ary_len = v.length;
ary = new String_obj_val[ary_len];
for (int i = 0; i < ary_len; i++)
ary[i] = String_obj_val.new_(v[i]);
} private String_obj_val[] ary;
public void Test_binary_search(String val, int expd) {
int actl = Binary_search_.Search(ary, ary.length, String_obj_val.new_(val));
Tfds.Eq(expd, actl, val);
}
}

View File

@@ -0,0 +1,131 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*; import gplx.ios.*;
public class Fsdb_bin_tbl {
public static void Create_table(Db_provider p) {Sqlite_engine_.Tbl_create(p, Tbl_name, Tbl_sql);}
public static Db_stmt Insert_stmt(Db_provider p) {return Db_stmt_.new_insert_(p, Tbl_name, Fld_bin_owner_id, Fld_bin_owner_tid, Fld_bin_part_id, Fld_bin_data_url, Fld_bin_data);}
public static void Insert_rdr(Db_provider p, int id, byte tid, long bin_len, Io_stream_rdr bin_rdr) {
Db_stmt stmt = Insert_stmt(p);
try {Insert_rdr(stmt, id, tid, bin_len, bin_rdr);}
finally {stmt.Rls();}
}
public static long Insert_rdr(Db_stmt stmt, int id, byte tid, long bin_len, Io_stream_rdr bin_rdr) {
long rv = bin_len;
stmt.Clear()
.Val_int_(id)
.Val_byte_(tid)
.Val_int_(Null_part_id)
.Val_str_(Null_data_url)
;
if (Sqlite_engine_.Supports_read_binary_stream)
stmt.Val_rdr_(bin_rdr, bin_len);
else {
byte[] bin_ary = Io_stream_rdr_.Load_all_as_bry(Bry_bfr.new_(), bin_rdr);
stmt.Val_bry_(bin_ary);
rv = bin_ary.length;
}
stmt.Exec_insert();
return rv;
}
public static void Delete(Db_provider p, int id) {
Db_stmt stmt = Delete_stmt(p);
try {Delete(stmt, id);}
finally {stmt.Rls();}
}
private static Db_stmt Delete_stmt(Db_provider p) {return Db_stmt_.new_delete_(p, Tbl_name, Fld_bin_owner_id);}
private static void Delete(Db_stmt stmt, int id) {
stmt.Clear()
.Val_int_(id)
.Exec_delete();
}
public static Io_stream_rdr Select_as_rdr(Db_provider p, int owner) {
Db_qry qry = Db_qry_.select_().From_(Tbl_name).Cols_(Fld_bin_data).Where_(Db_crt_.eq_(Fld_bin_owner_id, owner));
DataRdr rdr = DataRdr_.Null;
try {
rdr = p.Exec_qry_as_rdr(qry);
if (rdr.MoveNextPeer()) {
if (Sqlite_engine_.Supports_read_binary_stream)
return rdr.ReadRdr(Fld_bin_data);
else
return gplx.ios.Io_stream_rdr_.mem_(Read_bin_data(rdr));
}
else
return gplx.ios.Io_stream_rdr_.Null;
}
finally {rdr.Rls();}
}
public static boolean Select_to_url(Db_provider p, int owner, Io_url url, byte[] bin_bfr, int bin_flush_when) {
Db_qry qry = Db_qry_.select_().From_(Tbl_name).Cols_(Fld_bin_data).Where_(Db_crt_.eq_(Fld_bin_owner_id, owner));
DataRdr rdr = DataRdr_.Null;
try {
rdr = p.Exec_qry_as_rdr(qry);
if (rdr.MoveNextPeer()) {
if (Sqlite_engine_.Supports_read_binary_stream)
return Select_to_fsys__stream(rdr, url, bin_bfr, bin_flush_when);
else {
byte[] bry = Read_bin_data(rdr);
Io_mgr._.SaveFilBry(url, bry);
return true;
}
}
else
return false;
}
finally {rdr.Rls();}
}
public static boolean Select_to_fsys__stream(DataRdr rdr, Io_url url, byte[] bin_bfr, int bin_flush_when) {
Io_stream_rdr db_stream = Io_stream_rdr_.Null;
IoStream fs_stream = IoStream_.Null;
try {
db_stream = rdr.ReadRdr(Fld_bin_data); if (db_stream == Io_stream_rdr_.Null) return false;
fs_stream = Io_mgr._.OpenStreamWrite(url);
int pos = 0, flush_nxt = bin_flush_when;
while (true) {
int read = db_stream.Read(bin_bfr, pos, bin_bfr.length); if (read == Io_stream_rdr_.Read_done) break;
fs_stream.Write(bin_bfr, 0, read);
if (pos > flush_nxt) {
fs_stream.Flush();
flush_nxt += bin_flush_when;
}
}
fs_stream.Flush();
return true;
} finally {
db_stream.Rls();
fs_stream.Rls();
}
}
private static byte[] Read_bin_data(DataRdr rdr) {
byte[] rv = rdr.ReadBry(Fld_bin_data);
return rv == null ? Bry_.Empty : rv; // NOTE: bug in v0.10.1 where .ogg would save as null; return Bry_.Empty instead, else java.io.ByteArrayInputStream would fail on null
}
public static final String Tbl_name = "fsdb_bin", Fld_bin_owner_id = "bin_owner_id", Fld_bin_owner_tid = "bin_owner_tid", Fld_bin_part_id = "bin_part_id", Fld_bin_data_url = "bin_data_url", Fld_bin_data = "bin_data";
private static final String Tbl_sql = String_.Concat_lines_nl
( "CREATE TABLE IF NOT EXISTS fsdb_bin"
, "( bin_owner_id integer NOT NULL PRIMARY KEY"
, ", bin_owner_tid byte NOT NULL"
, ", bin_part_id integer NOT NULL"
, ", bin_data_url varchar(255) NOT NULL"
, ", bin_data mediumblob NOT NULL"
, ");"
);
public static final byte Owner_tid_fil = 1, Owner_tid_thm = 2;
public static final int Null_db_bin_id = -1, Null_size = -1, Null_part_id = -1;
public static final String Null_data_url = "";
}

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.fsdb; import gplx.*;
public class Fsdb_cfg_grp {
private OrderedHash itms = OrderedHash_.new_();
public Fsdb_cfg_grp(String grp) {this.grp = grp;}
public String Grp() {return grp;} private String grp;
public void Insert(String key, String val) {
if (itms.Has(key)) throw Err_.new_fmt_("cfg_grp.Insert failed; key={0}", key);
Fsdb_cfg_itm itm = new Fsdb_cfg_itm(grp, key, val);
itms.Add(key, itm);
}
public void Update(String key, String val) {
Fsdb_cfg_itm itm = (Fsdb_cfg_itm)itms.Fetch(key);
if (itm == null) throw Err_.new_fmt_("cfg_grp.Update failed; key={0}", key);
itm.Val_(val);
}
public void Upsert(String key, String val) {
Fsdb_cfg_itm itm = (Fsdb_cfg_itm)itms.Fetch(key);
if (itm == null) {
itm = new Fsdb_cfg_itm(grp, key, val);
itms.Add(key, itm);
}
else
itm.Val_(val);
}
public boolean Get_yn_or_y(String key) {return Get_yn_or(key, Bool_.Y);}
public boolean Get_yn_or_n(String key) {return Get_yn_or(key, Bool_.N);}
public boolean Get_yn_or(String key, boolean or) {
String rv = Get_str_or(key, null);
return rv == null ? or : Yn.parse_(rv);
}
public int Get_int_or(String key, int or) {
String rv = Get_str_or(key, null);
return rv == null ? or : Int_.parse_(rv);
}
public String Get_str_or(String key, String or) {
Fsdb_cfg_itm itm = (Fsdb_cfg_itm)itms.Fetch(key);
return itm == null ? or : itm.Val();
}
public static final Fsdb_cfg_grp Null = new Fsdb_cfg_grp(); Fsdb_cfg_grp() {}
}
class Fsdb_cfg_itm {
public Fsdb_cfg_itm(String grp, String key, String val) {this.grp = grp; this.key = key; this.val = val;}
public String Grp() {return grp;} private String grp;
public String Key() {return key;} private String key;
public String Val() {return val;} public Fsdb_cfg_itm Val_(String v) {val = v; return this;} private String val;
}

View File

@@ -0,0 +1,79 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*;
public class Fsdb_cfg_mgr {
private HashAdp grps = HashAdp_.new_();
private Fsdb_cfg_tbl cfg_tbl;
public int Next_id() {return next_id++;} private int next_id = 1;
public boolean Schema_thm_page() {return schema_thm_page;} private boolean schema_thm_page = true;
public boolean Patch_next_id() {return patch_next_id;} private boolean patch_next_id = true;
public void Patch_next_id_exec(int last_id) {
if (last_id >= next_id)
next_id = last_id + 1;
cfg_tbl.Insert(Grp_core, Key_patch_next_id, "y");
}
public void Txn_save() {
this.Update_next_id();
}
public void Rls() {cfg_tbl.Rls();}
private void Update_next_id() {cfg_tbl.Update("core", "next_id", Int_.XtoStr(next_id));}
public Fsdb_cfg_mgr Update(String grp, String key, String new_val) {
String cur_val = cfg_tbl.Select_as_str_or(grp, key, null);
if (cur_val == null)
cfg_tbl.Insert(grp, key, new_val);
else
cfg_tbl.Update(grp, key, new_val);
return this;
}
public Fsdb_cfg_grp Grps_get_or_load(String grp_key) {
Fsdb_cfg_grp grp = (Fsdb_cfg_grp)grps.Fetch(grp_key);
if (grp == null) {
grp = cfg_tbl.Select_as_grp(grp_key);
grps.Add(grp_key, grp);
}
return grp;
}
public Fsdb_cfg_grp Grps_get_or_add(String grp_key) { // TEST:
Fsdb_cfg_grp grp = (Fsdb_cfg_grp)grps.Fetch(grp_key);
if (grp == null) {
grp = new Fsdb_cfg_grp(grp_key);
grps.Add(grp_key, grp);
}
return grp;
}
public static Fsdb_cfg_mgr load_(Fsdb_db_abc_mgr abc_mgr, Db_provider p) {return new Fsdb_cfg_mgr().Init_by_load(p);}
public static Fsdb_cfg_mgr make_(Fsdb_db_abc_mgr abc_mgr, Db_provider p) {return new Fsdb_cfg_mgr().Init_by_make(p);}
private Fsdb_cfg_mgr Init_by_load(Db_provider p) {
this.cfg_tbl = new Fsdb_cfg_tbl_sql().Ctor(p, false);
Fsdb_cfg_grp core_grp = Grps_get_or_load(Grp_core);
this.next_id = core_grp.Get_int_or(Key_next_id, -1); if (next_id == -1) throw Err_.new_("next_id not found in fsdb_cfg");
this.schema_thm_page = core_grp.Get_yn_or_n(Key_schema_thm_page);
this.patch_next_id = core_grp.Get_yn_or_n(Key_patch_next_id);
return this;
}
private Fsdb_cfg_mgr Init_by_make(Db_provider p) {
this.cfg_tbl = new Fsdb_cfg_tbl_sql().Ctor(p, true);
this.cfg_tbl.Insert(Grp_core, Key_next_id , "1"); // start next_id at 1
this.cfg_tbl.Insert(Grp_core, Key_schema_thm_page , "y"); // new dbs automatically have page and time in fsdb_xtn_tm
this.cfg_tbl.Insert(Grp_core, Key_patch_next_id , "y"); // new dbs automatically have correct next_id
return this;
}
public static final String Grp_core = "core";
public static final String Key_next_id = "next_id", Key_schema_thm_page = "schema.thm.page", Key_patch_next_id = "patch.next_id";
}

View File

@@ -0,0 +1,143 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*;
public interface Fsdb_cfg_tbl extends RlsAble {
Fsdb_cfg_tbl Ctor(Db_provider provider, boolean created);
void Insert(String grp, String key, String val);
void Update(String grp, String key, String val);
int Select_as_int_or(String grp, String key, int or);
int Select_as_int_or_fail(String grp, String key);
String Select_as_str_or(String grp, String key, String or);
Fsdb_cfg_grp Select_as_grp(String grp);
}
abstract class Fsdb_cfg_tbl_base {
public abstract int Select_as_int_or(String grp, String key, int or);
public int Select_as_int_or_fail(String grp, String key) {
int rv = Select_as_int_or(grp, key, Int_.MinValue);
if (rv == Int_.MinValue) throw Err_.new_fmt_("fsdb_cfg did not have itm: grp={0} key={1}", grp, key);
return rv;
}
}
class Fsdb_cfg_tbl_mem extends Fsdb_cfg_tbl_base implements Fsdb_cfg_tbl {
private HashAdp grps = HashAdp_.new_();
public Fsdb_cfg_tbl Ctor(Db_provider provider, boolean created) {return this;}
public void Insert(String grp, String key, String val) {
Fsdb_cfg_grp grp_itm = Grps_get_or_make(grp);
grp_itm.Insert(key, val);
}
public void Update(String grp, String key, String val) {
Fsdb_cfg_grp grp_itm = Grps_get_or_make(grp);
grp_itm.Update(key, val);
}
@Override public int Select_as_int_or(String grp, String key, int or) {
Fsdb_cfg_grp grp_itm = Grps_get_or_null(grp);
return grp_itm == null ? or : grp_itm.Get_int_or(grp, or);
}
public String Select_as_str_or(String grp, String key, String or) {
Fsdb_cfg_grp grp_itm = Grps_get_or_null(grp);
return grp_itm == null ? or : grp_itm.Get_str_or(grp, or);
}
public Fsdb_cfg_grp Select_as_grp(String grp) {return Grps_get_or_null(grp);}
public void Rls() {}
private Fsdb_cfg_grp Grps_get_or_make(String grp) {
Fsdb_cfg_grp rv = (Fsdb_cfg_grp)grps.Fetch(grp);
if (rv == null) {
rv = new Fsdb_cfg_grp(grp);
grps.Add(grp, rv);
}
return rv;
}
public Fsdb_cfg_grp Grps_get_or_null(String grp) {return (Fsdb_cfg_grp)grps.Fetch(grp);}
}
class Fsdb_cfg_tbl_sql extends Fsdb_cfg_tbl_base implements Fsdb_cfg_tbl {
private Db_provider provider;
private Db_stmt stmt_insert, stmt_update, stmt_select;
public Fsdb_cfg_tbl Ctor(Db_provider provider, boolean created) {
this.provider = provider;
if (created) Create_table();
return this;
}
private void Create_table() {
Sqlite_engine_.Tbl_create(provider, Tbl_name, Tbl_sql);
Sqlite_engine_.Idx_create(provider, Idx_main);
}
private Db_stmt Insert_stmt() {return Db_stmt_.new_insert_(provider, Tbl_name, Fld_cfg_grp, Fld_cfg_key, Fld_cfg_val);}
public void Insert(String grp, String key, String val) {
if (stmt_insert == null) stmt_insert = Insert_stmt();
stmt_insert.Clear()
.Val_str_(grp)
.Val_str_(key)
.Val_str_(val)
.Exec_insert();
}
private Db_stmt Update_stmt() {return Db_stmt_.new_update_(provider, Tbl_name, String_.Ary(Fld_cfg_grp, Fld_cfg_key), Fld_cfg_val);}
public void Update(String grp, String key, String val) {
if (stmt_update == null) stmt_update = Update_stmt();
stmt_update.Clear()
.Val_str_(val)
.Val_str_(grp)
.Val_str_(key)
.Exec_update();
}
private Db_stmt Select_stmt() {
Db_qry_select qry = Db_qry_.select_val_(Tbl_name, Fld_cfg_val, gplx.criterias.Criteria_.And_many(Db_crt_.eq_(Fld_cfg_grp, ""), Db_crt_.eq_(Fld_cfg_key, "")));
return provider.Prepare(qry);
}
@Override public int Select_as_int_or(String grp, String key, int or) {return Int_.parse_or_(Select_as_str_or(grp, key, null), or);}
public String Select_as_str_or(String grp, String key, String or) {
if (stmt_select == null) stmt_select = Select_stmt();
Object rv = (String)stmt_select.Clear()
.Val_str_(grp)
.Val_str_(key)
.Exec_select_val();
return rv == null ? or : (String)rv;
}
public Fsdb_cfg_grp Select_as_grp(String grp) {
Fsdb_cfg_grp rv = null;
Db_qry_select qry = Db_qry_.select_cols_(Tbl_name, gplx.criterias.Criteria_.And_many(Db_crt_.eq_(Fld_cfg_grp, "")), Fld_cfg_key, Fld_cfg_val);
DataRdr rdr = DataRdr_.Null;
try {
rdr = provider.Prepare(qry).Clear().Val_str_(grp).Exec_select();
while (rdr.MoveNextPeer()) {
if (rv == null) rv = new Fsdb_cfg_grp(grp);
String key = rdr.ReadStr(Fld_cfg_key);
String val = rdr.ReadStr(Fld_cfg_val);
rv.Upsert(key, val);
}
}
finally {rdr.Rls();}
return rv == null ? Fsdb_cfg_grp.Null : rv;
}
public void Rls() {
if (stmt_insert != null) {stmt_insert.Rls(); stmt_insert = null;}
if (stmt_update != null) {stmt_update.Rls(); stmt_update = null;}
if (stmt_select != null) {stmt_select.Rls(); stmt_select = null;}
}
private static final String Tbl_name = "fsdb_cfg", Fld_cfg_grp = "cfg_grp", Fld_cfg_key = "cfg_key", Fld_cfg_val = "cfg_val";
private static final String Tbl_sql = String_.Concat_lines_nl
( "CREATE TABLE IF NOT EXISTS fsdb_cfg"
, "( cfg_grp varchar(255) NOT NULL"
, ", cfg_key varchar(255) NOT NULL"
, ", cfg_val varchar(1024) NOT NULL"
, ");"
);
private static final Db_idx_itm
Idx_main = Db_idx_itm.sql_("CREATE INDEX IF NOT EXISTS fsdb_cfg__main ON fsdb_cfg (cfg_grp, cfg_key, cfg_val);")
;
}

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.fsdb; import gplx.*;
public class Fsdb_cfg_tbl_ {
public static Fsdb_cfg_tbl new_sql_() {return new Fsdb_cfg_tbl_sql();}
public static Fsdb_cfg_tbl new_mem_() {return new Fsdb_cfg_tbl_mem();}
}

View File

@@ -0,0 +1,112 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*;
public class Fsdb_db_abc_mgr implements RlsAble {
private Db_provider boot_provider;
public int Next_id() {return cfg_mgr.Next_id();}
public Fsdb_mnt_mgr Mnt_mgr() {return mnt_mgr;} private Fsdb_mnt_mgr mnt_mgr;
public Fsdb_db_abc_mgr(Fsdb_mnt_mgr mnt_mgr) {this.mnt_mgr = mnt_mgr;}
public Fsdb_db_atr_mgr Atr_mgr() {return atr_mgr;} private Fsdb_db_atr_mgr atr_mgr;
public Fsdb_db_bin_mgr Bin_mgr() {return bin_mgr;} private Fsdb_db_bin_mgr bin_mgr;
public Fsdb_cfg_mgr Cfg_mgr() {return cfg_mgr;} private Fsdb_cfg_mgr cfg_mgr;
public Fsdb_db_abc_mgr Init(Io_url dir) {
Io_url url = dir.GenSubFil("fsdb.abc.sqlite3");
if (Io_mgr._.ExistsFil(url))
Init_load(dir, url);
else
Init_make(dir, url);
return this;
}
public void Fil_insert(Fsdb_fil_itm rv , byte[] dir, byte[] fil, int ext_id, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
int bin_db_id = bin_mgr.Get_id_for_insert(bin_len);
rv.Db_bin_id_(bin_db_id);
int fil_id = atr_mgr.Fil_insert(rv, dir, fil, ext_id, modified, hash, bin_db_id, bin_len, bin_rdr);
bin_len = bin_mgr.Insert(bin_db_id, fil_id, Fsdb_bin_tbl.Owner_tid_fil, bin_len, bin_rdr);
bin_mgr.Increment(bin_len);
}
public void Thm_insert(Fsdb_xtn_thm_itm rv, byte[] dir, byte[] fil, int ext_id, int w, int h, double thumbtime, int page, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
int bin_db_id = bin_mgr.Get_id_for_insert(bin_len);
rv.Db_bin_id_(bin_db_id);
int thm_id = atr_mgr.Thm_insert(rv, dir, fil, ext_id, w, h, thumbtime, page, modified, hash, bin_db_id, bin_len, bin_rdr);
bin_len = bin_mgr.Insert(bin_db_id, thm_id, Fsdb_bin_tbl.Owner_tid_thm, bin_len, bin_rdr);
bin_mgr.Increment(bin_len);
}
public void Img_insert(Fsdb_xtn_img_itm rv, byte[] dir, byte[] fil, int ext_id, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr, int img_w, int img_h) {
int bin_db_id = bin_mgr.Get_id_for_insert(bin_len);
rv.Db_bin_id_(bin_db_id);
int fil_id = atr_mgr.Img_insert(rv, String_.new_utf8_(dir), String_.new_utf8_(fil), ext_id, img_w, img_h, modified, hash, bin_db_id, bin_len, bin_rdr);
bin_len = bin_mgr.Insert(bin_db_id, fil_id, Fsdb_bin_tbl.Owner_tid_fil, bin_len, bin_rdr);
bin_mgr.Increment(bin_len);
}
public boolean Thm_select_bin(byte[] dir, byte[] fil, Fsdb_xtn_thm_itm thm) {
Fsdb_fil_itm fil_itm = atr_mgr.Fil_select(dir, fil);
return atr_mgr.Thm_select(fil_itm.Id(), thm);
}
public Fsdb_fil_itm Fil_select_bin(byte[] dir, byte[] fil, boolean is_thumb, int width, double thumbtime) {
return atr_mgr.Fil_select(dir, fil);
}
public void Txn_open() {
boot_provider.Txn_mgr().Txn_bgn_if_none();
atr_mgr.Txn_open();
bin_mgr.Txn_open();
}
public void Txn_save() {
atr_mgr.Txn_save(boot_provider);
bin_mgr.Txn_save();
cfg_mgr.Txn_save();
}
public void Rls() {
atr_mgr.Rls();
bin_mgr.Rls();
cfg_mgr.Rls();
boot_provider.Rls();
}
private void Init_load(Io_url dir, Io_url boot_url) {
Db_connect connect = Db_connect_sqlite.load_(boot_url);
boot_provider = Db_provider_.new_(connect);
atr_mgr = Fsdb_db_atr_mgr.load_(this, boot_provider, dir);
bin_mgr = Fsdb_db_bin_mgr.load_(boot_provider, dir);
cfg_mgr = Fsdb_cfg_mgr.load_(this, boot_provider);
if (!cfg_mgr.Patch_next_id()) Fsdb_db_abc_mgr_.Patch_next_id(this, dir);
}
private void Init_make(Io_url dir, Io_url boot_url) {
Db_connect connect = Db_connect_sqlite.make_(boot_url);
boot_provider = Db_provider_.new_(connect);
Sqlite_engine_.Pragma_page_size_4096(boot_provider);
atr_mgr = Fsdb_db_atr_mgr.make_(this, boot_provider, dir);
bin_mgr = Fsdb_db_bin_mgr.make_(boot_provider, dir);
cfg_mgr = Fsdb_cfg_mgr.make_(this, boot_provider);
this.Txn_save(); // immediately save new entries in atr,cfg
}
}
class Fsdb_db_abc_mgr_ {
public static void Patch_next_id(Fsdb_db_abc_mgr abc_mgr, Io_url dir) {
if (!String_.Eq(dir.NameOnly(), "fsdb.user")) return;
Fsdb_db_atr_mgr atr_mgr = abc_mgr.Atr_mgr();
Fsdb_cfg_mgr cfg_mgr = abc_mgr.Cfg_mgr();
int last_id = -1;
if (atr_mgr.Len() > 0) {
Fsdb_db_atr_fil atr_fil = atr_mgr.Get_at(0);
int max_fil_id = Db_provider_.Select_fld0_as_int_or(atr_fil.Provider(), "SELECT Max(fil_id) AS MaxId FROM fsdb_fil;", -1);
int max_thm_id = Db_provider_.Select_fld0_as_int_or(atr_fil.Provider(), "SELECT Max(thm_id) AS MaxId FROM fsdb_xtn_thm;", -1);
last_id = max_fil_id > max_thm_id ? max_fil_id : max_thm_id;
}
cfg_mgr.Patch_next_id_exec(last_id);
}
}

View File

@@ -0,0 +1,150 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*; import gplx.cache.*;
public class Fsdb_db_atr_fil implements RlsAble {
private Gfo_cache_mgr_bry dir_cache = new Gfo_cache_mgr_bry();
private Fsdb_dir_tbl tbl_dir; private Fsdb_fil_tbl tbl_fil; private Fsdb_xtn_thm_tbl tbl_thm; private Fsdb_xtn_img_tbl tbl_img; private Bool_obj_ref img_needs_create = Bool_obj_ref.n_();
public Fsdb_db_atr_fil(Fsdb_db_abc_mgr abc_mgr, Io_url url, boolean create) {
this.abc_mgr = abc_mgr;
Db_connect connect = create ? Db_connect_sqlite.make_(url) : Db_connect_sqlite.load_(url);
provider = Db_provider_.new_(connect);
Sqlite_engine_.Pragma_page_size_4096(provider);
tbl_dir = new Fsdb_dir_tbl(provider, create);
tbl_fil = new Fsdb_fil_tbl(provider, create);
tbl_thm = new Fsdb_xtn_thm_tbl(this, provider, create);
tbl_img = new Fsdb_xtn_img_tbl(provider, create);
}
public Fsdb_db_abc_mgr Abc_mgr() {return abc_mgr;} private Fsdb_db_abc_mgr abc_mgr;
public Db_provider Provider() {return provider;} private Db_provider provider;
public int Id() {return id;} private int id;
public Io_url Url() {return url;} private Io_url url;
public String Path_bgn() {return path_bgn;} private String path_bgn;
public byte Cmd_mode() {return cmd_mode;} public Fsdb_db_atr_fil Cmd_mode_(byte v) {cmd_mode = v; return this;} private byte cmd_mode;
public void Rls() {
tbl_dir.Rls();
tbl_fil.Rls();
tbl_img.Rls();
tbl_thm.Rls();
provider.Txn_mgr().Txn_end_all();
provider.Rls();
}
public void Txn_open() {
provider.Txn_mgr().Txn_bgn_if_none();
}
public void Txn_save() {
provider.Txn_mgr().Txn_end_all();
}
public Fsdb_fil_itm Fil_select(byte[] dir, byte[] fil) {
Int_obj_ref dir_id_obj = (Int_obj_ref)dir_cache.Get_or_null(dir);
int dir_id = -1;
if (dir_id_obj == null) {
Fsdb_dir_itm dir_itm = tbl_dir.Select_itm(String_.new_utf8_(dir));
dir_id = dir_itm == Fsdb_dir_itm.Null ? -1 : dir_itm.Id();
dir_cache.Add(dir, Int_obj_ref.new_(dir_id));
}
else
dir_id = dir_id_obj.Val();
if (dir_id == Int_.Neg1) return Fsdb_fil_itm.Null;
return tbl_fil.Select_itm_by_name(dir_id, String_.new_utf8_(fil));
}
public boolean Thm_select(int owner_id, Fsdb_xtn_thm_itm thm) {
return tbl_thm.Select_itm_by_fil_width(owner_id, thm);
}
public int Fil_insert(Fsdb_fil_itm rv, String dir, String fil, int ext_id, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
int dir_id = Dir_id__get_or_insert(dir);
int fil_id = Fil_id__get_or_insert(Fsdb_xtn_tid_.Tid_none, dir_id, fil, ext_id, modified, hash, bin_db_id, bin_len);
rv.Id_(fil_id).Owner_(dir_id);
return fil_id;
}
public int Img_insert(Fsdb_xtn_img_itm rv, String dir, String fil, int ext_id, int img_w, int img_h, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
int dir_id = Dir_id__get_or_insert(dir);
img_needs_create.Val_(false);
int fil_id = Fil_id__get_or_insert(Fsdb_xtn_tid_.Tid_img, dir_id, fil, ext_id, modified, hash, bin_db_id, bin_len);
if (img_needs_create.Val()) // NOTE: fsdb_fil row can already exist; EX: thm gets inserted -> fsdb_fil row gets created with -1 bin_db_id; orig gets inserted -> fsdb_fil row already exists
tbl_img.Insert(fil_id, img_w, img_h);
rv.Id_(fil_id);
return fil_id;
}
public int Thm_insert(Fsdb_xtn_thm_itm rv, String dir, String fil, int ext_id, int thm_w, int thm_h, double thumbtime, int page, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
int dir_id = Dir_id__get_or_insert(dir);
int fil_id = Fil_id__get_or_insert(Fsdb_xtn_tid_.Tid_thm, dir_id, fil, ext_id, modified, hash, Fsdb_bin_tbl.Null_db_bin_id, Fsdb_bin_tbl.Null_size); // NOTE: bin_db_id must be set to NULL
int thm_id = abc_mgr.Next_id();
tbl_thm.Insert(thm_id, fil_id, thm_w, thm_h, thumbtime, page, bin_db_id, bin_len, modified, hash);
rv.Id_(thm_id).Owner_id_(fil_id).Dir_id_(dir_id);
return thm_id;
}
public static Fsdb_db_atr_fil load_(Fsdb_db_abc_mgr abc_mgr, DataRdr rdr, Io_url dir) {
Io_url url = dir.GenSubFil(rdr.ReadStr(Fsdb_db_atr_tbl.Fld_url));
Fsdb_db_atr_fil rv = new Fsdb_db_atr_fil(abc_mgr, url, false);
rv.id = rdr.ReadInt(Fsdb_db_atr_tbl.Fld_uid);
rv.url = url;
rv.path_bgn = rdr.ReadStr(Fsdb_db_atr_tbl.Fld_path_bgn);
rv.cmd_mode = Db_cmd_mode.Ignore;
return rv;
}
public static Fsdb_db_atr_fil make_(Fsdb_db_abc_mgr abc_mgr, int id, Io_url url, String path_bgn) {
Fsdb_db_atr_fil rv = new Fsdb_db_atr_fil(abc_mgr, url, true);
rv.id = id;
rv.url = url;
rv.path_bgn = path_bgn;
rv.cmd_mode = Db_cmd_mode.Create;
return rv;
}
private int Dir_id__get_or_insert(String dir_str) {
byte[] dir_bry = Bry_.new_utf8_(dir_str);
Object rv_obj = dir_cache.Get_or_null(dir_bry);
int rv = -1;
if (rv_obj != null) { // item found
rv = ((Int_obj_ref)rv_obj).Val();
if (rv == -1) // dir was previously -1; occurs when doing select on empty db (no dir, so -1 added) and then doing insert (-1 now needs to be dropped)
dir_cache.Del(dir_bry);
}
if (rv == -1) {
Fsdb_dir_itm itm = tbl_dir.Select_itm(dir_str);
if (itm == Fsdb_dir_itm.Null) {
rv = abc_mgr.Next_id();
tbl_dir.Insert(rv, dir_str, 0); // 0: always assume root owner
}
else {
rv = itm.Id();
}
dir_cache.Add(dir_bry, Int_obj_ref.new_(rv));
}
return rv;
}
private int Fil_id__get_or_insert(int xtn_tid, int dir_id, String fil, int ext_id, DateAdp modified, String hash, int bin_db_id, long bin_len) {
Fsdb_fil_itm fil_itm = tbl_fil.Select_itm_by_name(dir_id, fil);
int fil_id = fil_itm.Id();
if (fil_id == Fsdb_fil_itm.Null_id) { // new item
fil_id = abc_mgr.Next_id();
tbl_fil.Insert(fil_id, dir_id, fil, xtn_tid, ext_id, bin_len, modified, hash, bin_db_id);
img_needs_create.Val_(true);
}
else { // existing item
if ( fil_itm.Db_bin_id() == Fsdb_bin_tbl.Null_db_bin_id // prv row was previously inserted by thumb
&& xtn_tid != Fsdb_xtn_tid_.Tid_thm // cur row is not thumb
) {
tbl_fil.Update(fil_id, dir_id, fil, xtn_tid, ext_id, bin_len, modified, hash, bin_db_id); // update props; note that thumb inserts null props, whereas file will insert real props (EX: bin_db_id)
if (xtn_tid == Fsdb_xtn_tid_.Tid_img)
img_needs_create.Val_(true);
}
}
return fil_id;
}
}

View File

@@ -0,0 +1,76 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*; import gplx.cache.*;
public class Fsdb_db_atr_mgr implements RlsAble {
private Fsdb_db_atr_fil[] itms; private Fsdb_db_atr_fil itms_0;
public int Len() {return itms.length;}
public Fsdb_db_atr_fil Get_at(int i) {return i == Id_0 ? itms_0 : itms[i];}
public Fsdb_fil_itm Fil_select(byte[] dir, byte[] fil) {return itms_0.Fil_select(dir, fil);}
public boolean Thm_select(int owner_id, Fsdb_xtn_thm_itm thm) {return itms_0.Thm_select(owner_id, thm);}
public int Fil_insert(Fsdb_fil_itm rv , byte[] dir, byte[] fil, int ext_id, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
return itms_0.Fil_insert(rv, String_.new_utf8_(dir), String_.new_utf8_(fil), ext_id, modified, hash, bin_db_id, bin_len, bin_rdr);
}
public int Img_insert(Fsdb_xtn_img_itm rv, String dir, String fil, int ext_id, int img_w, int img_h, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
return itms_0.Img_insert(rv, dir, fil, ext_id, img_w, img_h, modified, hash, bin_db_id, bin_len, bin_rdr);
}
public int Thm_insert(Fsdb_xtn_thm_itm rv, byte[] dir, byte[] fil, int ext_id, int width, int height, double thumbtime, int page, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
return itms_0.Thm_insert(rv, String_.new_utf8_(dir), String_.new_utf8_(fil), ext_id, width, height, thumbtime, page, modified, hash, bin_db_id, bin_len, bin_rdr);
}
public void Txn_open() {
int len = itms.length;
for (int i = 0; i < len; i++) {
Fsdb_db_atr_fil itm = itms[i];
itm.Txn_open();
}
}
public void Txn_save(Db_provider provider) {
Fsdb_db_atr_tbl.Commit_all(provider, itms);
int len = itms.length;
for (int i = 0; i < len; i++) {
Fsdb_db_atr_fil itm = itms[i];
itm.Txn_save();
}
}
public void Rls() {
int len = itms.length;
for (int i = 0; i < len; i++) {
Fsdb_db_atr_fil itm = itms[i];
itm.Rls();
}
}
public static Fsdb_db_atr_mgr load_(Fsdb_db_abc_mgr abc_mgr, Db_provider p, Io_url dir) {
Fsdb_db_atr_mgr rv = new Fsdb_db_atr_mgr();
rv.itms = Fsdb_db_atr_tbl.Select_all(abc_mgr, p, dir);
rv.itms_0 = rv.itms[0];
return rv;
}
public static Fsdb_db_atr_mgr make_(Fsdb_db_abc_mgr abc_mgr, Db_provider p, Io_url dir) {
Fsdb_db_atr_tbl.Create_table(p);
Fsdb_db_atr_mgr rv = new Fsdb_db_atr_mgr();
Fsdb_db_atr_fil itm = Fsdb_db_atr_fil.make_(abc_mgr, Id_0, url_(dir, Id_0), Path_bgn_0);
rv.itms_0 = itm;
rv.itms = new Fsdb_db_atr_fil[] {itm};
return rv;
}
private static Io_url url_(Io_url dir, int id) {
return dir.GenSubFil_ary("fsdb.atr.", Int_.XtoStr_PadBgn(id, 2), ".sqlite3");
}
public static final int Id_0 = 0;
public static final String Path_bgn_0 = "";
}

View File

@@ -0,0 +1,64 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*;
public class Fsdb_db_atr_tbl {
public static void Create_table(Db_provider p) {Sqlite_engine_.Tbl_create(p, Tbl_name, Tbl_sql);}
public static Fsdb_db_atr_fil[] Select_all(Fsdb_db_abc_mgr abc_mgr, Db_provider p, Io_url dir) {
ListAdp rv = ListAdp_.new_();
Db_qry qry = Db_qry_select.new_().From_(Tbl_name).Cols_all_().OrderBy_asc_(Fld_uid);
DataRdr rdr = DataRdr_.Null;
try {
rdr = p.Exec_qry_as_rdr(qry);
while (rdr.MoveNextPeer()) {
Fsdb_db_atr_fil itm = Fsdb_db_atr_fil.load_(abc_mgr, rdr, dir);
rv.Add(itm);
}
} finally {rdr.Rls();}
return (Fsdb_db_atr_fil[])rv.XtoAry(Fsdb_db_atr_fil.class);
}
public static void Commit_all(Db_provider provider, Fsdb_db_atr_fil[] ary) {
stmt_bldr.Init(provider);
try {
int len = ary.length;
for (int i = 0; i < len; i++)
Commit_itm(ary[i]);
stmt_bldr.Commit();
} finally {stmt_bldr.Rls();}
}
private static void Commit_itm(Fsdb_db_atr_fil itm) {
Db_stmt stmt = stmt_bldr.Get(itm.Cmd_mode());
switch (itm.Cmd_mode()) {
case Db_cmd_mode.Create: stmt.Clear().Val_int_(itm.Id()) .Val_str_(itm.Url().NameAndExt()).Val_str_(itm.Path_bgn()).Exec_insert(); break;
case Db_cmd_mode.Update: stmt.Clear() .Val_str_(itm.Url().NameAndExt()).Val_str_(itm.Path_bgn()).Val_int_(itm.Id()).Exec_update(); break;
case Db_cmd_mode.Delete: stmt.Clear().Val_int_(itm.Id()).Exec_delete(); break;
case Db_cmd_mode.Ignore: break;
default: throw Err_.unhandled(itm.Cmd_mode());
}
itm.Cmd_mode_(Db_cmd_mode.Ignore);
}
public static final String Tbl_name = "fsdb_db_atr", Fld_uid = "uid", Fld_url = "url", Fld_path_bgn = "path_bgn";
private static final String Tbl_sql = String_.Concat_lines_nl
( "CREATE TABLE IF NOT EXISTS fsdb_db_atr"
, "( uid integer NOT NULL PRIMARY KEY"
, ", url varchar(255) NOT NULL"
, ", path_bgn varchar(255) NOT NULL"
, ");"
);
private static Db_stmt_bldr stmt_bldr = new Db_stmt_bldr(Tbl_name, String_.Ary(Fld_uid), Fld_url, Fld_path_bgn);
}

View File

@@ -0,0 +1,85 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*; import gplx.ios.*;
public class Fsdb_db_bin_fil implements RlsAble {
public int Id() {return id;} private int id;
public Io_url Url() {return url;} private Io_url url;
public long Bin_max() {return bin_max;} private long bin_max;
public void Bin_max_(long v) {
bin_max = v;
if (cmd_mode == Db_cmd_mode.Ignore) cmd_mode = Db_cmd_mode.Update;
}
public long Bin_len() {return bin_len;} private long bin_len;
public void Bin_len_(long v) {
bin_len = v;
if (cmd_mode == Db_cmd_mode.Ignore) cmd_mode = Db_cmd_mode.Update;
}
public byte Cmd_mode() {return cmd_mode;} public Fsdb_db_bin_fil Cmd_mode_(byte v) {cmd_mode = v; return this;} private byte cmd_mode;
public Db_provider Provider() {
if (provider == null) {
if (cmd_mode == Db_cmd_mode.Create) {
provider = Db_provider_.new_(Db_connect_sqlite.make_(url));
Sqlite_engine_.Pragma_page_size_4096(provider);
Fsdb_bin_tbl.Create_table(provider);
}
else
provider = Db_provider_.new_(Db_connect_sqlite.load_(url));
}
return provider;
} private Db_provider provider;
public void Rls() {if (provider != null) provider.Rls();}
public long Insert(int bin_id, byte owner_tid, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
Db_stmt stmt = Db_stmt_.Null;
try {
stmt = Fsdb_bin_tbl.Insert_stmt(this.Provider());
return Fsdb_bin_tbl.Insert_rdr(stmt, bin_id, owner_tid, bin_len, bin_rdr);
}
finally {stmt.Rls();}
}
public boolean Get_to_url(int id, Io_url url, byte[] bin_bfr, int bin_flush_when) {
return Fsdb_bin_tbl.Select_to_url(this.Provider(), id, url, bin_bfr, bin_flush_when);
}
public Io_stream_rdr Get_as_rdr(int id) {
return Fsdb_bin_tbl.Select_as_rdr(this.Provider(), id);
}
public static Fsdb_db_bin_fil load_(DataRdr rdr, Io_url dir) {
return new_
( rdr.ReadInt(Fsdb_db_bin_tbl.Fld_uid)
, dir.GenSubFil(rdr.ReadStr(Fsdb_db_bin_tbl.Fld_url))
, rdr.ReadLong(Fsdb_db_bin_tbl.Fld_bin_len)
, rdr.ReadLong(Fsdb_db_bin_tbl.Fld_bin_max)
, Db_cmd_mode.Ignore
);
}
public static Fsdb_db_bin_fil make_(int id, Io_url url, long bin_len, long bin_max) {
Fsdb_db_bin_fil rv = new_(id, url, bin_len, bin_max, Db_cmd_mode.Create);
rv.Provider(); // force table create
return rv;
}
private static Fsdb_db_bin_fil new_(int id, Io_url url, long bin_len, long bin_max, byte cmd_mode) {
Fsdb_db_bin_fil rv = new Fsdb_db_bin_fil();
rv.id = id;
rv.url = url;
rv.bin_len = bin_len;
rv.bin_max = bin_max;
rv.cmd_mode = cmd_mode;
return rv;
}
public static final Fsdb_db_bin_fil[] Ary_empty = new Fsdb_db_bin_fil[0];
}

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.fsdb; import gplx.*;
import gplx.dbs.*;
public class Fsdb_db_bin_mgr implements RlsAble {
private Io_url dir;
private Fsdb_db_bin_fil[] itms = Fsdb_db_bin_fil.Ary_empty; private int itms_len = 0;
private Fsdb_db_bin_fil itms_n;
private Db_provider provider;
private Fsdb_db_bin_mgr(Io_url dir) {this.dir = dir;}
public int Len() {return itms.length;}
public long Db_bin_max() {return db_bin_max;}
public int Insert_to_bin() {return insert_to_bin;} public Fsdb_db_bin_mgr Insert_to_bin_(int v) {insert_to_bin = v; return this;} private int insert_to_bin = Fsdb_mnt_mgr.Insert_to_bin_null;
public Fsdb_db_bin_mgr Db_bin_max_(long v) {
db_bin_max = v;
for (int i = 0; i < itms_len; i++)
itms[i].Bin_max_(v);
return this;
} private long db_bin_max = Io_mgr.Len_mb * Long_.X_by_int(188);
public Fsdb_db_bin_fil Get_at(int i) {return itms[i];}
private Fsdb_db_bin_fil Get_cur() {return itms_len == 0 ? null : itms[itms_len - 1];}
public void Txn_open() {
Get_cur().Provider().Txn_mgr().Txn_bgn_if_none();
}
public void Txn_save() {
Fsdb_db_bin_tbl.Commit_all(provider, itms);
Get_cur().Provider().Txn_mgr().Txn_end_all();
}
public void Rls() {
int len = itms.length;
for (int i = 0; i < len; i++) {
Fsdb_db_bin_fil itm = itms[i];
itm.Rls();
}
}
public int Get_id_for_insert(long bin_len) {
if (insert_to_bin != Fsdb_mnt_mgr.Insert_to_bin_null) return insert_to_bin; // insert_to_bin specified; return it
if (itms_n.Bin_len() > itms_n.Bin_max())
Itms_add(0);
return itms_n.Id();
}
public void Increment(long bin_len) {
long new_bin_len = itms_n.Bin_len() + bin_len;
itms_n.Bin_len_(new_bin_len);
}
public long Insert(int db_id, int bin_id, byte owner_tid, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
Fsdb_db_bin_fil bin_fil = itms[db_id];
return bin_fil.Insert(bin_id, owner_tid, bin_len, bin_rdr);
}
public static Fsdb_db_bin_mgr load_(Db_provider p, Io_url dir) {
Fsdb_db_bin_mgr rv = new Fsdb_db_bin_mgr(dir);
rv.provider = p;
rv.itms = Fsdb_db_bin_tbl.Select_all(p, dir);
rv.itms_len = rv.itms.length;
rv.itms_n = rv.itms[rv.itms_len - 1];
return rv;
}
public static Fsdb_db_bin_mgr make_(Db_provider p, Io_url dir) {
Fsdb_db_bin_tbl.Create_table(p);
Fsdb_db_bin_mgr rv = new Fsdb_db_bin_mgr(dir);
rv.provider = p;
rv.Itms_add(0);
return rv;
}
private void Itms_add(long bin_len) {
Fsdb_db_bin_fil cur = Get_cur();
if (cur != null) {
cur.Provider().Txn_mgr().Txn_end_all();
cur.Provider().Rls();
}
int new_itms_len = itms_len + 1;
Fsdb_db_bin_fil[] new_itms = new Fsdb_db_bin_fil[new_itms_len];
for (int i = 0; i < itms_len; i++)
new_itms[i] = itms[i];
itms_n = Fsdb_db_bin_fil.make_(itms_len, url_(dir, itms_len), bin_len, db_bin_max);
itms = new_itms;
itms_len = new_itms_len;
itms[itms_len - 1] = itms_n;
this.Txn_open();
}
private static Io_url url_(Io_url dir, int id) {
return dir.GenSubFil_ary("fsdb.bin.", Int_.XtoStr_PadBgn(id, 4), ".sqlite3");
}
}

View File

@@ -0,0 +1,65 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.fsdb; import gplx.*;
import gplx.dbs.*;
public class Fsdb_db_bin_tbl {
public static void Create_table(Db_provider p) {Sqlite_engine_.Tbl_create(p, Tbl_name, Tbl_sql);}
public static void Commit_all(Db_provider provider, Fsdb_db_bin_fil[] ary) {
stmt_bldr.Init(provider);
try {
int len = ary.length;
for (int i = 0; i < len; i++)
Commit_itm(ary[i]);
stmt_bldr.Commit();
} finally {stmt_bldr.Rls();}
}
private static void Commit_itm(Fsdb_db_bin_fil itm) {
Db_stmt stmt = stmt_bldr.Get(itm.Cmd_mode());
switch (itm.Cmd_mode()) {
case Db_cmd_mode.Create: stmt.Clear().Val_int_(itm.Id()) .Val_str_(itm.Url().NameAndExt()).Val_long_(itm.Bin_len()).Val_long_(itm.Bin_max()).Exec_insert(); break;
case Db_cmd_mode.Update: stmt.Clear() .Val_str_(itm.Url().NameAndExt()).Val_long_(itm.Bin_len()).Val_long_(itm.Bin_max()).Val_int_(itm.Id()).Exec_update(); break;
case Db_cmd_mode.Delete: stmt.Clear().Val_int_(itm.Id()).Exec_delete(); break;
case Db_cmd_mode.Ignore: break;
default: throw Err_.unhandled(itm.Cmd_mode());
}
itm.Cmd_mode_(Db_cmd_mode.Ignore);
}
public static Fsdb_db_bin_fil[] Select_all(Db_provider p, Io_url dir) {
ListAdp rv = ListAdp_.new_();
Db_qry qry = Db_qry_select.new_().From_(Tbl_name).Cols_all_().OrderBy_asc_(Fld_uid);
DataRdr rdr = DataRdr_.Null;
try {
rdr = p.Exec_qry_as_rdr(qry);
while (rdr.MoveNextPeer()) {
Fsdb_db_bin_fil itm = Fsdb_db_bin_fil.load_(rdr, dir);
rv.Add(itm);
}
} finally {rdr.Rls();}
return (Fsdb_db_bin_fil[])rv.XtoAry(Fsdb_db_bin_fil.class);
}
public static final String Tbl_name = "fsdb_db_bin", Fld_uid = "uid", Fld_url = "url", Fld_bin_len = "bin_len", Fld_bin_max = "bin_max";
private static final String Tbl_sql = String_.Concat_lines_nl
( "CREATE TABLE IF NOT EXISTS fsdb_db_bin"
, "( uid integer NOT NULL PRIMARY KEY"
, ", url varchar(255) NOT NULL"
, ", bin_len bigint NOT NULL"
, ", bin_max bigint NOT NULL"
, ");"
);
private static Db_stmt_bldr stmt_bldr = new Db_stmt_bldr(Tbl_name, String_.Ary(Fld_uid), Fld_url, Fld_bin_len, Fld_bin_max);
}

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.fsdb; import gplx.*;
public class Fsdb_dir_itm {
public Fsdb_dir_itm(int id, int owner, String name) {this.id = id; this.owner = owner; this.name = name;}
public int Id() {return id;} public Fsdb_dir_itm Id_(int v) {id = v; return this;} private int id;
public int Owner() {return owner;} public Fsdb_dir_itm Owner_(int v) {owner = v; return this;} private int owner;
public String Name() {return name;} public Fsdb_dir_itm Name_(String v) {name = v; return this;} private String name;
public static final Fsdb_dir_itm Null = new Fsdb_dir_itm(0, 0, "");
}

View File

@@ -0,0 +1,87 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*;
public class Fsdb_dir_tbl {
private Db_provider provider;
private Db_stmt stmt_insert, stmt_update, stmt_select_by_name;
public Fsdb_dir_tbl(Db_provider provider, boolean created) {
this.provider = provider;
if (created) Create_table();
}
public void Rls() {
if (stmt_insert != null) {stmt_insert.Rls(); stmt_insert = null;}
if (stmt_update != null) {stmt_update.Rls(); stmt_update = null;}
if (stmt_select_by_name != null) {stmt_select_by_name.Rls(); stmt_select_by_name = null;}
}
public void Create_table() {
Sqlite_engine_.Tbl_create(provider, Tbl_name, Tbl_sql);
Sqlite_engine_.Idx_create(provider, Idx_name);
}
private Db_stmt Insert_stmt() {return Db_stmt_.new_insert_(provider, Tbl_name, Fld_dir_id, Fld_dir_owner_id, Fld_dir_name);}
public void Insert(int id, String name, int owner_id) {
if (stmt_insert == null) stmt_insert = Insert_stmt();
try {
stmt_insert.Clear()
.Val_int_(id)
.Val_int_(owner_id)
.Val_str_(name)
.Exec_insert();
} catch (Exception exc) {stmt_insert = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
}
private Db_stmt Update_stmt() {return Db_stmt_.new_update_(provider, Tbl_name, String_.Ary(Fld_dir_id), Fld_dir_owner_id, Fld_dir_name);}
public void Update(int id, String name, int owner_id) {
if (stmt_update == null) stmt_update = Update_stmt();
try {
stmt_update.Clear()
.Val_int_(id)
.Val_str_(name)
.Val_int_(owner_id)
.Exec_update();
} catch (Exception exc) {stmt_update = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
}
private Db_stmt Select_itm_stmt() {
Db_qry qry = Db_qry_.select_().From_(Tbl_name).Cols_(Fld_dir_id, Fld_dir_owner_id).Where_(Db_crt_.eq_(Fld_dir_name, Bry_.Empty));
return provider.Prepare(qry);
}
public Fsdb_dir_itm Select_itm(String dir_name) {
if (stmt_select_by_name == null) stmt_select_by_name = Select_itm_stmt();
DataRdr rdr = DataRdr_.Null;
try {
rdr = stmt_select_by_name.Clear()
.Val_str_(dir_name)
.Exec_select();
while (rdr.MoveNextPeer()) {
return new Fsdb_dir_itm(rdr.ReadInt(Fld_dir_id), rdr.ReadInt(Fld_dir_owner_id), dir_name);
}
return Fsdb_dir_itm.Null;
}
finally {rdr.Rls();}
}
public static final String Tbl_name = "fsdb_dir", Fld_dir_id = "dir_id", Fld_dir_owner_id = "dir_owner_id", Fld_dir_name = "dir_name";
private static final String Tbl_sql = String_.Concat_lines_nl
( "CREATE TABLE IF NOT EXISTS fsdb_dir"
, "( dir_id integer NOT NULL PRIMARY KEY"
, ", dir_owner_id integer NOT NULL"
, ", dir_name varchar(255) NOT NULL"
, ");"
);
public static final Db_idx_itm
Idx_name = Db_idx_itm.sql_("CREATE INDEX IF NOT EXISTS fsdb_dir__name ON fsdb_dir (dir_name, dir_owner_id, dir_id);")
;
}

View File

@@ -0,0 +1,29 @@
/*
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.fsdb; import gplx.*;
public class Fsdb_fil_itm {
public int Id() {return id;} public Fsdb_fil_itm Id_(int v) {id = v; return this;} private int id;
public int Owner() {return owner;} public Fsdb_fil_itm Owner_(int v) {owner = v; return this;} private int owner;
public int Ext_id() {return ext_id;} public Fsdb_fil_itm Ext_id_(int v) {ext_id = v; return this;} private int ext_id;
public String Name() {return name;} public Fsdb_fil_itm Name_(String v) {name = v; return this;} private String name;
public int Db_bin_id() {return bin_db_id;} public Fsdb_fil_itm Db_bin_id_(int v) {bin_db_id = v; return this;} private int bin_db_id;
public int Mnt_id() {return mnt_id;} public Fsdb_fil_itm Mnt_id_(int v) {mnt_id = v; return this;} private int mnt_id;
public Fsdb_fil_itm Init(int id, int owner, int ext_id, String name, int bin_db_id) {this.id = id; this.owner = owner; this.ext_id = ext_id; this.name = name; this.bin_db_id = bin_db_id; return this;}
public static final int Null_id = 0;
public static final Fsdb_fil_itm Null = new Fsdb_fil_itm().Init(Null_id, 0, 0, "", Fsdb_bin_tbl.Null_db_bin_id);
}

View File

@@ -0,0 +1,134 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.fsdb; import gplx.*;
import gplx.dbs.*;
public class Fsdb_fil_tbl {
private Db_provider provider;
private Db_stmt stmt_insert, stmt_update, stmt_select_by_name, stmt_select_by_id;
public Fsdb_fil_tbl(Db_provider provider, boolean created) {
this.provider = provider;
if (created) Create_table();
}
private void Create_table() {
Sqlite_engine_.Tbl_create(provider, Tbl_name, Tbl_sql);
Sqlite_engine_.Idx_create(provider, Idx_owner);
}
public void Rls() {
if (stmt_insert != null) {stmt_insert.Rls(); stmt_insert = null;}
if (stmt_update != null) {stmt_update.Rls(); stmt_update = null;}
if (stmt_select_by_name != null) {stmt_select_by_name.Rls(); stmt_select_by_name = null;}
if (stmt_select_by_id != null) {stmt_select_by_id.Rls(); stmt_select_by_id = null;}
}
private Db_stmt Insert_stmt() {return Db_stmt_.new_insert_(provider, Tbl_name, Fld_fil_id, Fld_fil_owner_id, Fld_fil_name, Fld_fil_xtn_id, Fld_fil_ext_id, Fld_fil_bin_db_id, Fld_fil_size, Fld_fil_modified, Fld_fil_hash);}
public void Insert(int id, int owner_id, String name, int xtn_id, int ext_id, long size, DateAdp modified, String hash, int bin_db_id) {
if (stmt_insert == null) stmt_insert = Insert_stmt();
try {
stmt_insert.Clear()
.Val_int_(id)
.Val_int_(owner_id)
.Val_str_(name)
.Val_int_(xtn_id)
.Val_int_(ext_id)
.Val_int_(bin_db_id)
.Val_long_(size)
.Val_str_(Sqlite_engine_.X_date_to_str(modified))
.Val_str_(hash)
.Exec_insert();
} catch (Exception exc) {stmt_insert = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
}
private Db_stmt Update_stmt() {return Db_stmt_.new_update_(provider, Tbl_name, String_.Ary(Fld_fil_id), Fld_fil_owner_id, Fld_fil_name, Fld_fil_xtn_id, Fld_fil_ext_id, Fld_fil_bin_db_id, Fld_fil_size, Fld_fil_modified, Fld_fil_hash);}
public void Update(int id, int owner_id, String name, int xtn_id, int ext_id, long size, DateAdp modified, String hash, int bin_db_id) {
if (stmt_update == null) stmt_update = Update_stmt();
try {
stmt_update.Clear()
.Val_int_(owner_id)
.Val_str_(name)
.Val_int_(xtn_id)
.Val_int_(ext_id)
.Val_int_(bin_db_id)
.Val_long_(size)
.Val_str_(Sqlite_engine_.X_date_to_str(modified))
.Val_str_(hash)
.Val_int_(id)
.Exec_update();
} catch (Exception exc) {stmt_update = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
}
private Db_stmt Select_by_name_stmt() {
Db_qry qry = Sqlite_engine_.Supports_indexed_by
? (Db_qry)Db_qry_sql.rdr_("SELECT * FROM fsdb_fil INDEXED BY fsdb_fil__owner WHERE fil_owner_id = ? AND fil_name = ?;")
: Db_qry_.select_().From_(Tbl_name).Cols_all_().Where_(gplx.criterias.Criteria_.And_many(Db_crt_.eq_(Fld_fil_owner_id, Int_.MinValue), Db_crt_.eq_(Fld_fil_name, "")))
;
return provider.Prepare(qry);
}
public Fsdb_fil_itm Select_itm_by_name(int dir_id, String fil_name) {
if (stmt_select_by_name == null) stmt_select_by_name = Select_by_name_stmt();
DataRdr rdr = DataRdr_.Null;
try {
rdr = stmt_select_by_name.Clear()
.Val_int_(dir_id)
.Val_str_(fil_name)
.Exec_select();
if (rdr.MoveNextPeer())
return load_(rdr);
else
return Fsdb_fil_itm.Null;
}
finally {rdr.Rls();}
}
private Db_stmt Select_by_id_stmt() {
Db_qry qry = Db_qry_.select_().From_(Tbl_name).Cols_all_().Where_(Db_crt_.eq_(Fld_fil_id, 0));
return provider.Prepare(qry);
}
public Fsdb_fil_itm Select_itm_by_id(int fil_id) {
if (stmt_select_by_id == null) stmt_select_by_id = Select_by_id_stmt();
DataRdr rdr = DataRdr_.Null;
try {
rdr = stmt_select_by_name.Clear()
.Val_int_(fil_id)
.Exec_select();
if (rdr.MoveNextPeer())
return load_(rdr);
else
return Fsdb_fil_itm.Null;
}
finally {rdr.Rls();}
}
private Fsdb_fil_itm load_(DataRdr rdr) {
return new Fsdb_fil_itm().Init(rdr.ReadInt(Fld_fil_id), rdr.ReadInt(Fld_fil_owner_id), rdr.ReadInt(Fld_fil_ext_id), rdr.ReadStr(Fld_fil_name), rdr.ReadInt(Fld_fil_bin_db_id));
}
public static final String Tbl_name = "fsdb_fil", Fld_fil_id = "fil_id", Fld_fil_owner_id = "fil_owner_id", Fld_fil_name = "fil_name", Fld_fil_xtn_id = "fil_xtn_id", Fld_fil_ext_id = "fil_ext_id"
, Fld_fil_size = "fil_size", Fld_fil_modified = "fil_modified", Fld_fil_hash = "fil_hash", Fld_fil_bin_db_id = "fil_bin_db_id"
;
private static final String Tbl_sql = String_.Concat_lines_nl
( "CREATE TABLE IF NOT EXISTS fsdb_fil"
, "( fil_id integer NOT NULL PRIMARY KEY"
, ", fil_owner_id integer NOT NULL"
, ", fil_xtn_id integer NOT NULL"
, ", fil_ext_id integer NOT NULL"
, ", fil_bin_db_id integer NOT NULL" // group ints at beginning of table
, ", fil_name varchar(255) NOT NULL"
, ", fil_size bigint NOT NULL"
, ", fil_modified varchar(14) NOT NULL" // stored as yyyyMMddHHmmss
, ", fil_hash varchar(40) NOT NULL"
, ");"
);
public static final Db_idx_itm
// Idx_name = Db_idx_itm.sql_ ("CREATE INDEX IF NOT EXISTS fsdb_fil__name ON fsdb_fil (fil_name, fil_owner_id, fil_id, fil_ext_id);")
Idx_owner = Db_idx_itm.sql_ ("CREATE INDEX IF NOT EXISTS fsdb_fil__owner ON fsdb_fil (fil_owner_id, fil_name, fil_id);")
;
}

View File

@@ -0,0 +1,26 @@
/*
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.fsdb; import gplx.*;
public class Fsdb_mnt_itm {
public Fsdb_mnt_itm(int id, String name, String url) {this.id = id; this.name = name; this.url = url;}
public int Id() {return id;} public Fsdb_mnt_itm Id_(int v) {id = v; return this;} private int id;
public String Name() {return name;} public Fsdb_mnt_itm Name_(String v) {name = v; return this;} private String name;
public String Url() {return url;} public Fsdb_mnt_itm Url_(String v) {url = v; return this;} private String url;
public static final Fsdb_mnt_itm Null = new Fsdb_mnt_itm(0, "", "");
public static final Fsdb_mnt_itm[] Ary_empty = new Fsdb_mnt_itm[0];
}

View File

@@ -0,0 +1,119 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.fsdb; import gplx.*;
import gplx.dbs.*; import gplx.xowa.files.fsdb.*;
public class Fsdb_mnt_mgr implements GfoInvkAble {
private Db_provider provider;
private Fsdb_cfg_tbl tbl_cfg;
private Fsdb_db_abc_mgr[] ary; int ary_len = 0;
public Gfo_usr_dlg Usr_dlg() {return usr_dlg;} public Fsdb_mnt_mgr Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v; return this;} private Gfo_usr_dlg usr_dlg = Gfo_usr_dlg_.Null;
public void Init(Io_url cur_dir) {
Fsdb_mnt_itm[] mnts = Db_load_or_make(cur_dir);
ary_len = mnts.length;
ary = new Fsdb_db_abc_mgr[ary_len];
for (int i = 0; i < ary_len; i++) {
Fsdb_mnt_itm itm = mnts[i];
Io_url abc_url = cur_dir.GenSubFil_nest(itm.Url(), "fsdb.abc.sqlite3");
ary[i] = new Fsdb_db_abc_mgr(this).Init(abc_url.OwnerDir());
}
insert_to_mnt = tbl_cfg.Select_as_int_or_fail("core", "mnt.insert_idx");
}
public int Insert_to_mnt() {return insert_to_mnt;} public Fsdb_mnt_mgr Insert_to_mnt_(int v) {insert_to_mnt = v; return this;} private int insert_to_mnt = Mnt_idx_user;
public int Abc_mgr_len() {return ary == null ? 0 : ary.length;}
public Fsdb_db_abc_mgr Abc_mgr_at(int i) {return ary[i];}
private Fsdb_mnt_itm[] Db_load_or_make(Io_url cur_dir) {
Bool_obj_ref created = Bool_obj_ref.n_();
provider = Sqlite_engine_.Provider_load_or_make_(cur_dir.GenSubFil("wiki.mnt.sqlite3"), created);
tbl_cfg = new Fsdb_cfg_tbl_sql().Ctor(provider, created.Val());
if (created.Val()) {
Fsdb_mnt_tbl.Create_table(provider);
Fsdb_mnt_tbl.Insert(provider, Mnt_idx_main, "fsdb.main", "fsdb.main");
Fsdb_mnt_tbl.Insert(provider, Mnt_idx_user, "fsdb.user", "fsdb.user");
tbl_cfg.Insert("core", "mnt.insert_idx", Int_.XtoStr(Mnt_idx_user));
}
return Fsdb_mnt_tbl.Select_all(provider);
}
public Fsdb_db_bin_fil Bin_db_get(int mnt_id, int bin_db_id) {
return ary[mnt_id].Bin_mgr().Get_at(bin_db_id);
}
public Fsdb_fil_itm Fil_select_bin(byte[] dir, byte[] fil, boolean is_thumb, int width, double thumbtime) {
for (int i = 0; i < ary_len; i++) {
Fsdb_fil_itm rv = ary[i].Fil_select_bin(dir, fil, is_thumb, width, thumbtime);
if (rv != Fsdb_fil_itm.Null && rv.Db_bin_id() != Fsdb_bin_tbl.Null_db_bin_id) { // NOTE: mnt_0 can have thumb, but mnt_1 can have itm; check for itm with Db_bin_id; DATE:2013-11-16
rv.Mnt_id_(i);
return rv;
}
}
return Fsdb_fil_itm.Null;
}
public boolean Thm_select_bin(byte[] dir, byte[] fil, Fsdb_xtn_thm_itm thm) {
for (int i = 0; i < ary_len; i++) {
boolean rv = ary[i].Thm_select_bin(dir, fil, thm);
if (rv) {
thm.Mnt_id_(i);
return rv;
}
}
return false;
}
public void Fil_insert(Fsdb_fil_itm rv , byte[] dir, byte[] fil, int ext_id, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
ary[insert_to_mnt].Fil_insert(rv, dir, fil, ext_id, modified, hash, bin_len, bin_rdr);
}
public void Thm_insert(Fsdb_xtn_thm_itm rv, byte[] dir, byte[] fil, int ext_id, int w, int h, double thumbtime, int page, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
ary[insert_to_mnt].Thm_insert(rv, dir, fil, ext_id, w, h, thumbtime, page, modified, hash, bin_len, bin_rdr);
}
public void Img_insert(Fsdb_xtn_img_itm rv, byte[] dir, byte[] fil, int ext_id, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr, int img_w, int img_h) {
ary[insert_to_mnt].Img_insert(rv, dir, fil, ext_id, modified, hash, bin_len, bin_rdr, img_w, img_h);
}
public void Bin_db_max_(long v) {
for (int i = 0; i < ary_len; i++)
ary[i].Bin_mgr().Db_bin_max_(v);
}
public void Insert_to_bin_(int v) {
for (int i = 0; i < ary_len; i++)
ary[i].Bin_mgr().Insert_to_bin_(v);
}
public void Txn_open() {
for (int i = 0; i < ary_len; i++)
ary[i].Txn_open();
}
public void Txn_save() {
for (int i = 0; i < ary_len; i++)
ary[i].Txn_save();
}
public void Rls() {
for (int i = 0; i < ary_len; i++)
ary[i].Rls();
tbl_cfg.Rls();
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_bin_db_max_in_mb_)) this.Bin_db_max_(m.ReadLong("v") * Io_mgr.Len_mb);
else if (ctx.Match(k, Invk_insert_to_mnt_)) insert_to_mnt = m.ReadInt("v");
else if (ctx.Match(k, Invk_insert_to_bin_)) this.Insert_to_bin_(m.ReadInt("v"));
else return GfoInvkAble_.Rv_unhandled;
return this;
} private static final String Invk_bin_db_max_in_mb_ = "bin_db_max_in_mb_", Invk_insert_to_mnt_ = "insert_to_mnt_", Invk_insert_to_bin_ = "insert_to_bin_";
public static final int Mnt_idx_main = 0, Mnt_idx_user = 1, Insert_to_bin_null = -1;
public static void Patch(Fsdb_mnt_mgr mnt_mgr) {
mnt_mgr.Abc_mgr_at(Fsdb_mnt_mgr.Mnt_idx_main).Cfg_mgr()
.Update(Xof_fsdb_mgr_cfg.Grp_xowa, Xof_fsdb_mgr_cfg.Key_gallery_fix_defaults, "y")
.Update(Xof_fsdb_mgr_cfg.Grp_xowa, Xof_fsdb_mgr_cfg.Key_gallery_packed, "y")
.Update(Xof_fsdb_mgr_cfg.Grp_xowa, Xof_fsdb_mgr_cfg.Key_upright_patch, "y")
;
}
}

View File

@@ -0,0 +1,67 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*;
public class Fsdb_mnt_tbl {
public static void Create_table(Db_provider p) {
Sqlite_engine_.Tbl_create(p, Tbl_name, Tbl_sql);
}
public static void Insert(Db_provider p, int id, String name, String url) {
Db_stmt stmt = Insert_stmt(p);
try {Insert(stmt, id, name, url);}
finally {stmt.Rls();}
}
private static Db_stmt Insert_stmt(Db_provider p) {return Db_stmt_.new_insert_(p, Tbl_name, Fld_mnt_id, Fld_mnt_name, Fld_mnt_url);}
private static void Insert(Db_stmt stmt, int id, String name, String url) {
stmt.Clear()
.Val_int_(id)
.Val_str_(name)
.Val_str_(url)
.Exec_insert();
}
public static Db_stmt Update_stmt(Db_provider p) {return Db_stmt_.new_update_(p, Tbl_name, String_.Ary(Fld_mnt_id), Fld_mnt_name, Fld_mnt_url);}
public static void Update(Db_stmt stmt, int id, String name, String url) {
stmt.Clear()
.Val_str_(name)
.Val_str_(url)
.Val_int_(id)
.Exec_update();
}
public static Fsdb_mnt_itm[] Select_all(Db_provider p) {
Db_qry qry = Db_qry_.select_().From_(Tbl_name);
DataRdr rdr = DataRdr_.Null;
ListAdp list = ListAdp_.new_();
try {
rdr = p.Exec_qry_as_rdr(qry);
while (rdr.MoveNextPeer()) {
Fsdb_mnt_itm itm = new Fsdb_mnt_itm(rdr.ReadInt(Fld_mnt_id), rdr.ReadStr(Fld_mnt_name), rdr.ReadStr(Fld_mnt_url));
list.Add(itm);
}
}
finally {rdr.Rls();}
return (Fsdb_mnt_itm[])list.XtoAryAndClear(Fsdb_mnt_itm.class);
}
public static final String Tbl_name = "fsdb_mnt", Fld_mnt_id = "mnt_id", Fld_mnt_name = "mnt_name", Fld_mnt_url = "mnt_url";
private static final String Tbl_sql = String_.Concat_lines_nl
( "CREATE TABLE IF NOT EXISTS fsdb_mnt"
, "( mnt_id integer NOT NULL PRIMARY KEY"
, ", mnt_name varchar(255) NOT NULL"
, ", mnt_url varchar(255) NOT NULL"
, ");"
);
}

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.fsdb; import gplx.*;
public class Fsdb_xtn_img_itm {
public int Id() {return id;} public void Id_(int v) {this.id = v;} private int id;
public int W() {return w;} public void W_(int v) {this.w = v;} private int w;
public int H() {return h;} public void H_(int v) {this.h = v;} private int h;
public int Db_bin_id() {return bin_db_id;} public Fsdb_xtn_img_itm Db_bin_id_(int v) {bin_db_id = v; return this;} private int bin_db_id;
public Fsdb_xtn_img_itm Init_by_load(int id, int w, int h) {this.id = id; this.w = w; this.h = h; return this;}
public static final Fsdb_xtn_img_itm Null = new Fsdb_xtn_img_itm();
public static final int Bits_default = 8;
}

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.fsdb; import gplx.*;
import gplx.dbs.*;
public class Fsdb_xtn_img_tbl {
private Db_provider provider;
private Db_stmt stmt_insert, stmt_select_by_id;
public Fsdb_xtn_img_tbl(Db_provider provider, boolean created) {
this.provider = provider;
if (created) Create_table();
}
public void Rls() {
if (stmt_insert != null) {stmt_insert.Rls(); stmt_insert = null;}
if (stmt_select_by_id != null) {stmt_select_by_id.Rls(); stmt_select_by_id = null;}
}
public void Create_table() {
Sqlite_engine_.Tbl_create(provider, Tbl_name, Tbl_sql);
}
public Db_stmt Insert_stmt() {return Db_stmt_.new_insert_(provider, Tbl_name, Fld_img_id, Fld_img_w, Fld_img_h);}
public void Insert(int id, int w, int h) {
if (stmt_insert == null) stmt_insert = Insert_stmt();
try {
stmt_insert.Clear()
.Val_int_(id)
.Val_int_(w)
.Val_int_(h)
.Exec_insert();
} catch (Exception exc) {stmt_insert = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
}
public Db_stmt Select_itm_by_id_stmt() {return Db_stmt_.new_select_(provider, Tbl_name, String_.Ary(Fld_img_id), Fld_img_w, Fld_img_h); }
public Fsdb_xtn_img_itm Select_itm_by_id(int id) {
if (stmt_select_by_id == null) stmt_select_by_id = this.Select_itm_by_id_stmt();
DataRdr rdr = DataRdr_.Null;
try {
rdr = stmt_select_by_id.Clear()
.Val_int_(id)
.Exec_select();
if (rdr.MoveNextPeer())
return new Fsdb_xtn_img_itm().Init_by_load(id, rdr.ReadInt(Fld_img_w), rdr.ReadInt(Fld_img_h));
else
return Fsdb_xtn_img_itm.Null;
}
finally {rdr.Rls();}
}
public static final String Tbl_name = "fsdb_xtn_img", Fld_img_id = "img_id", Fld_img_w = "img_w", Fld_img_h = "img_h";
private static final String Tbl_sql = String_.Concat_lines_nl
( "CREATE TABLE IF NOT EXISTS fsdb_xtn_img"
, "( img_id integer NOT NULL PRIMARY KEY"
, ", img_w integer NOT NULL"
, ", img_h integer NOT NULL"
, ");"
);
}

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.fsdb; import gplx.*;
public class Fsdb_xtn_thm_itm {
protected Fsdb_xtn_thm_itm() {}
public int Id() {return id;} public Fsdb_xtn_thm_itm Id_(int v) {id = v; return this;} private int id;
public Fsdb_fil_itm Owner() {return owner;} public Fsdb_xtn_thm_itm Owner_(Fsdb_fil_itm v) {owner = v; return this;} private Fsdb_fil_itm owner = Fsdb_fil_itm.Null;
public int Owner_id() {return owner_id;} public Fsdb_xtn_thm_itm Owner_id_(int v) {owner_id = v; return this;} private int owner_id;
public int Width() {return width;} public Fsdb_xtn_thm_itm Width_(int v) {width = v; return this;} private int width;
public double Thumbtime() {return thumbtime;} public Fsdb_xtn_thm_itm Thumbtime_(double v) {thumbtime = v; return this;} private double thumbtime;
public int Page() {return page;} public Fsdb_xtn_thm_itm Page_(int v) {page = v; return this;} private int page;
public int Height() {return height;} public Fsdb_xtn_thm_itm Height_(int v) {height = v; return this;} private int height;
public long Size() {return size;} public Fsdb_xtn_thm_itm Size_(long v) {size = v; return this;} private long size;
public String Modified() {return modified;} public Fsdb_xtn_thm_itm Modified_(String v) {modified = v; return this;} private String modified;
public String Hash() {return hash;} public Fsdb_xtn_thm_itm Hash_(String v) {hash = v; return this;} private String hash;
public int Dir_id() {return dir_id;} public Fsdb_xtn_thm_itm Dir_id_(int v) {dir_id = v; return this;} private int dir_id;
public int Db_bin_id() {return bin_db_id;} public Fsdb_xtn_thm_itm Db_bin_id_(int v) {bin_db_id = v; return this;} private int bin_db_id;
public int Mnt_id() {return mnt_id;} public Fsdb_xtn_thm_itm Mnt_id_(int v) {mnt_id = v; return this;} private int mnt_id;
public void Init_by_load(DataRdr rdr, boolean schema_thm_page) {
this.id = rdr.ReadInt(Fsdb_xtn_thm_tbl.Fld_thm_id);
this.owner_id = rdr.ReadInt(Fsdb_xtn_thm_tbl.Fld_thm_owner_id);
this.width = rdr.ReadInt(Fsdb_xtn_thm_tbl.Fld_thm_w);
this.height = rdr.ReadInt(Fsdb_xtn_thm_tbl.Fld_thm_h);
this.size = rdr.ReadLong(Fsdb_xtn_thm_tbl.Fld_thm_size);
this.modified = rdr.ReadStr(Fsdb_xtn_thm_tbl.Fld_thm_modified);
this.hash = rdr.ReadStr(Fsdb_xtn_thm_tbl.Fld_thm_hash);
this.bin_db_id = rdr.ReadInt(Fsdb_xtn_thm_tbl.Fld_thm_bin_db_id);
if (schema_thm_page) {
this.thumbtime = gplx.xowa.files.Xof_doc_thumb.Db_load_double(rdr, Fsdb_xtn_thm_tbl.Fld_thm_time);
this.page = gplx.xowa.files.Xof_doc_page.Db_load_int(rdr, Fsdb_xtn_thm_tbl.Fld_thm_page);
}
else {
this.thumbtime = gplx.xowa.files.Xof_doc_thumb.Db_load_int(rdr, Fsdb_xtn_thm_tbl.Fld_thm_thumbtime);
this.page = gplx.xowa.files.Xof_doc_page.Null;
}
}
public static Fsdb_xtn_thm_itm new_() {return new Fsdb_xtn_thm_itm();} // NOTE: Owner is null by default
public static Fsdb_xtn_thm_itm load_() {return new Fsdb_xtn_thm_itm().Owner_(new Fsdb_fil_itm());} // NOTE: Owner is new'd b/c load will use owner.Ext_id
public static final Fsdb_xtn_thm_itm Null = new Fsdb_xtn_thm_itm();
public static final Fsdb_xtn_thm_itm[] Ary_empty = new Fsdb_xtn_thm_itm[0];
}

View File

@@ -0,0 +1,128 @@
/*
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.fsdb; import gplx.*;
import gplx.dbs.*;
public class Fsdb_xtn_thm_tbl {
private Fsdb_db_atr_fil atr_fil; private Db_provider provider;
private Db_stmt stmt_insert, stmt_select_by_fil_w;
public Fsdb_xtn_thm_tbl(Fsdb_db_atr_fil atr_fil, Db_provider provider, boolean created) {
this.atr_fil = atr_fil; this.provider = provider;
if (created) Create_table();
}
private void Create_table() {
Sqlite_engine_.Tbl_create(provider, Tbl_name, Tbl_sql);
Sqlite_engine_.Idx_create(provider, Idx_name);
}
public void Rls() {
if (stmt_insert != null) {stmt_insert.Rls(); stmt_insert = null;}
if (stmt_select_by_fil_w != null) {stmt_select_by_fil_w.Rls(); stmt_select_by_fil_w = null;}
}
private boolean Schema_thm_page() {
if (schema_thm_page_init) {
schema_thm_page = atr_fil.Abc_mgr().Cfg_mgr().Schema_thm_page();
schema_thm_page_init = false;
}
return schema_thm_page;
} private boolean schema_thm_page, schema_thm_page_init = true;
private Db_stmt Make_stmt_insert() {
return this.Schema_thm_page()
? Db_stmt_.new_insert_(provider, Tbl_name, Fld_thm_id, Fld_thm_owner_id, Fld_thm_w, Fld_thm_h, Fld_thm_bin_db_id, Fld_thm_size, Fld_thm_modified, Fld_thm_hash, Fld_thm_time, Fld_thm_page)
: Db_stmt_.new_insert_(provider, Tbl_name, Fld_thm_id, Fld_thm_owner_id, Fld_thm_w, Fld_thm_h, Fld_thm_bin_db_id, Fld_thm_size, Fld_thm_modified, Fld_thm_hash, Fld_thm_thumbtime)
;
}
public void Insert(int id, int thm_owner_id, int width, int height, double thumbtime, int page, int bin_db_id, long size, DateAdp modified, String hash) {
if (stmt_insert == null) stmt_insert = Make_stmt_insert();
try {
stmt_insert.Clear()
.Val_int_(id)
.Val_int_(thm_owner_id)
.Val_int_(width)
.Val_int_(height)
.Val_int_(bin_db_id)
.Val_long_(size)
.Val_str_(Sqlite_engine_.X_date_to_str(modified))
.Val_str_(hash);
if (this.Schema_thm_page()) {
stmt_insert.Val_double_ (gplx.xowa.files.Xof_doc_thumb.Db_save_double(thumbtime));
stmt_insert.Val_int_ (gplx.xowa.files.Xof_doc_page.Db_save_int(page));
}
else
stmt_insert.Val_int_(gplx.xowa.files.Xof_doc_thumb.Db_save_int(thumbtime));
stmt_insert.Exec_insert();
} catch (Exception exc) {stmt_insert = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
}
private Db_stmt Select_by_fil_w_stmt() {
Db_qry_select qry = Db_qry_.select_().From_(Tbl_name).Cols_all_();
gplx.criterias.Criteria crt
= this.Schema_thm_page()
? gplx.criterias.Criteria_.And_many(Db_crt_.eq_(Fld_thm_owner_id, Int_.MinValue), Db_crt_.eq_(Fld_thm_w, Int_.MinValue), Db_crt_.eq_(Fld_thm_time, Int_.MinValue), Db_crt_.eq_(Fld_thm_page, Int_.MinValue))
: gplx.criterias.Criteria_.And_many(Db_crt_.eq_(Fld_thm_owner_id, Int_.MinValue), Db_crt_.eq_(Fld_thm_w, Int_.MinValue), Db_crt_.eq_(Fld_thm_thumbtime, Int_.MinValue))
;
qry.Where_(crt);
return provider.Prepare(qry);
}
public boolean Select_itm_by_fil_width(int owner_id, Fsdb_xtn_thm_itm thm) {
if (stmt_select_by_fil_w == null) stmt_select_by_fil_w = Select_by_fil_w_stmt();
DataRdr rdr = DataRdr_.Null;
try {
stmt_select_by_fil_w.Clear()
.Val_int_(owner_id)
.Val_int_(thm.Width())
;
if (this.Schema_thm_page()) {
stmt_select_by_fil_w.Val_double_(gplx.xowa.files.Xof_doc_thumb.Db_save_double(thm.Thumbtime()));
stmt_select_by_fil_w.Val_int_(gplx.xowa.files.Xof_doc_page.Db_save_int(thm.Page()));
}
else {
stmt_select_by_fil_w.Val_int_(gplx.xowa.files.Xof_doc_thumb.Db_save_int(thm.Thumbtime()));
}
rdr = stmt_select_by_fil_w.Exec_select();
if (rdr.MoveNextPeer()) {
thm.Init_by_load(rdr, this.Schema_thm_page());
return true;
}
else
return false;
}
finally {rdr.Rls();}
}
public static final String Tbl_name = "fsdb_xtn_thm"
, Fld_thm_id = "thm_id", Fld_thm_owner_id = "thm_owner_id", Fld_thm_w = "thm_w", Fld_thm_h = "thm_h"
, Fld_thm_thumbtime = "thm_thumbtime", Fld_thm_time = "thm_time", Fld_thm_page = "thm_page"
, Fld_thm_bin_db_id = "thm_bin_db_id", Fld_thm_size = "thm_size", Fld_thm_modified = "thm_modified", Fld_thm_hash = "thm_hash";
private static final String Tbl_sql = String_.Concat_lines_nl
( "CREATE TABLE IF NOT EXISTS fsdb_xtn_thm"
, "( thm_id integer NOT NULL PRIMARY KEY"
, ", thm_owner_id integer NOT NULL"
, ", thm_w integer NOT NULL"
, ", thm_h integer NOT NULL"
//, ", thm_thumbtime integer NOT NULL" // removed; DATE:2014-01-23
, ", thm_time double NOT NULL" // replacement for thm_time
, ", thm_page integer NOT NULL"
, ", thm_bin_db_id integer NOT NULL"
, ", thm_size bigint NOT NULL"
, ", thm_modified varchar(14) NOT NULL" // stored as yyyyMMddHHmmss
, ", thm_hash varchar(40) NOT NULL"
, ");"
);
public static final Db_idx_itm
Idx_name = Db_idx_itm.sql_("CREATE INDEX IF NOT EXISTS fsdb_xtn_thm__owner ON fsdb_xtn_thm (thm_owner_id, thm_id, thm_w, thm_time, thm_page);")
;
public static final DateAdp Modified_null = null;
public static final String Hash_null = "";
}

View File

@@ -0,0 +1,21 @@
/*
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.fsdb; import gplx.*;
public class Fsdb_xtn_tid_ {
public static final int Tid_none = 0, Tid_thm = 1, Tid_img = 2;
}

View File

@@ -0,0 +1,214 @@
/*
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.gfs; import gplx.*;
interface Gfs_lxr {
byte Lxr_tid();
int Process(Gfs_parser_ctx ctx, int bgn, int end);
}
class Gfs_lxr_whitespace implements Gfs_lxr {
public byte Lxr_tid() {return Gfs_lxr_.Tid_whitespace;}
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
byte[] src = ctx.Src(); int src_len = ctx.Src_len();
int rv = Gfs_lxr_.Rv_eos, cur_pos;
for (cur_pos = end; cur_pos < src_len; cur_pos++) {
byte b = src[cur_pos];
Object o = ctx.Trie().Match(b, src, cur_pos, src_len);
if (o == null) {
rv = Gfs_lxr_.Rv_null;
ctx.Process_null(cur_pos);
break;
}
else {
Gfs_lxr lxr = (Gfs_lxr)o;
if (lxr.Lxr_tid() == Gfs_lxr_.Tid_whitespace) {}
else {
rv = Gfs_lxr_.Rv_lxr;
ctx.Process_lxr(cur_pos, lxr);
break;
}
}
}
return rv;
}
public static final Gfs_lxr_whitespace _ = new Gfs_lxr_whitespace(); Gfs_lxr_whitespace() {}
}
class Gfs_lxr_comment_flat implements Gfs_lxr {
public Gfs_lxr_comment_flat(byte[] bgn_bry, byte[] end_bry) {
this.bgn_bry = bgn_bry; this.bgn_bry_len = bgn_bry.length;
this.end_bry = end_bry; this.end_bry_len = end_bry.length;
} byte[] bgn_bry, end_bry; int bgn_bry_len, end_bry_len;
public byte Lxr_tid() {return Gfs_lxr_.Tid_comment;}
public int Process(Gfs_parser_ctx ctx, int lxr_bgn, int lxr_end) {
byte[] src = ctx.Src(); int src_len = ctx.Src_len();
int end_pos = Bry_finder.Find_fwd(src, end_bry, lxr_end, src_len);
// if (end_pos == Bry_.NotFound) throw Err_.new_fmt_("comment is not closed: {0}", String_.new_utf8_(end_bry));
return (end_pos == Bry_.NotFound)
? src_len // allow eos to terminate flat comment; needed for "tidy-always-adds-nl-in-textarea" fix; NOTE: DATE:2014-06-21
: end_pos + end_bry_len; // position after end_bry
}
}
class Gfs_lxr_identifier implements Gfs_lxr {
public byte Lxr_tid() {return Gfs_lxr_.Tid_identifier;}
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
byte[] src = ctx.Src(); int src_len = ctx.Src_len();
int pos, rv = Gfs_lxr_.Rv_eos;
for (pos = end; pos < src_len; pos++) {
byte b = src[pos];
Object o = ctx.Trie().Match(b, src, pos, src_len);
if (o == null) { // invalid char; stop;
rv = Gfs_lxr_.Rv_null;
ctx.Process_null(pos);
break;
}
else {
Gfs_lxr lxr = (Gfs_lxr)o;
if (lxr.Lxr_tid() == Gfs_lxr_.Tid_identifier) {} // still an identifier; continue
else { // new lxr (EX: "." in "abc."); (a) hold word of "abc"; mark "." as new lxr;
ctx.Hold_word(bgn, pos);
rv = Gfs_lxr_.Rv_lxr;
ctx.Process_lxr(pos, lxr);
break;
}
}
}
if (rv == Gfs_lxr_.Rv_eos) ctx.Process_eos(); // eos
return rv;
}
public static final Gfs_lxr_identifier _ = new Gfs_lxr_identifier(); Gfs_lxr_identifier() {}
}
class Gfs_lxr_semic implements Gfs_lxr {
public byte Lxr_tid() {return Gfs_lxr_.Tid_semic;}
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
switch (ctx.Prv_lxr()) {
case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); ctx.Cur_nde_from_stack(); break; // a;
case Gfs_lxr_.Tid_quote:
case Gfs_lxr_.Tid_paren_end: ctx.Cur_nde_from_stack(); break; // a();
case Gfs_lxr_.Tid_semic: break; // a;; ignore;
default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Semic); break;
}
return end;
}
public static final Gfs_lxr_semic _ = new Gfs_lxr_semic(); Gfs_lxr_semic() {}
}
class Gfs_lxr_dot implements Gfs_lxr {
public byte Lxr_tid() {return Gfs_lxr_.Tid_dot;}
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
switch (ctx.Prv_lxr()) {
case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); break; // a.
case Gfs_lxr_.Tid_paren_end: break; // a().
default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Dot); break;
}
return end;
}
public static final Gfs_lxr_dot _ = new Gfs_lxr_dot(); Gfs_lxr_dot() {}
}
class Gfs_lxr_paren_bgn implements Gfs_lxr {
public byte Lxr_tid() {return Gfs_lxr_.Tid_paren_bgn;}
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
switch (ctx.Prv_lxr()) {
case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); break; // a(;
default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Paren_bgn); break;
}
return end;
}
public static final Gfs_lxr_paren_bgn _ = new Gfs_lxr_paren_bgn(); Gfs_lxr_paren_bgn() {}
}
class Gfs_lxr_paren_end implements Gfs_lxr {
public byte Lxr_tid() {return Gfs_lxr_.Tid_paren_end;}
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
switch (ctx.Prv_lxr()) {
case Gfs_lxr_.Tid_paren_bgn:
case Gfs_lxr_.Tid_quote: break; // "))", "abc)", "'abc')"
case Gfs_lxr_.Tid_identifier: ctx.Make_atr_by_idf(); break; // 123)
default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Paren_end); break;
}
return end;
}
public static final Gfs_lxr_paren_end _ = new Gfs_lxr_paren_end(); Gfs_lxr_paren_end() {}
}
class Gfs_lxr_quote implements Gfs_lxr {
public Gfs_lxr_quote(byte[] bgn_bry, byte[] end_bry) {
this.bgn_bry_len = bgn_bry.length;
this.end_bry = end_bry; this.end_bry_len = end_bry.length;
} private byte[] end_bry; private int bgn_bry_len, end_bry_len;
public byte Lxr_tid() {return Gfs_lxr_.Tid_quote;}
public int Process(Gfs_parser_ctx ctx, int lxr_bgn, int lxr_end) {
byte[] src = ctx.Src(); int src_len = ctx.Src_len();
int end_pos = Bry_finder.Find_fwd(src, end_bry, lxr_end, src_len);
if (end_pos == Bry_.NotFound) throw Err_.new_fmt_("quote is not closed: {0}", String_.new_utf8_(end_bry));
Bry_bfr bfr = ctx.Tmp_bfr().Clear();
int prv_pos = lxr_end;
int nxt_pos = end_pos + end_bry_len;
if (Bry_.Match(src, nxt_pos, nxt_pos + end_bry_len, end_bry)) { // end_bry is doubled; EX: end_bry = ' and raw = a''
while (true) {
bfr.Add_mid(src, prv_pos, end_pos); // add everything up to end_bry
bfr.Add(end_bry); // add end_bry
prv_pos = nxt_pos + end_bry_len; // set prv_pos to after doubled end_bry
end_pos = Bry_finder.Find_fwd(src, end_bry, prv_pos, src_len);
if (end_pos == Bry_.NotFound) throw Err_.new_fmt_("quote is not closed: {0}", String_.new_utf8_(end_bry));
nxt_pos = end_pos + end_bry_len;
if (!Bry_.Match(src, nxt_pos, nxt_pos + end_bry_len, end_bry)) {
bfr.Add_mid(src, prv_pos, end_pos);
break;
}
}
ctx.Make_atr_by_bry(lxr_bgn + bgn_bry_len, end_pos, bfr.XtoAryAndClear());
}
else
ctx.Make_atr(lxr_bgn + bgn_bry_len, end_pos);
return end_pos + end_bry_len; // position after quote
}
}
class Gfs_lxr_curly_bgn implements Gfs_lxr {
public byte Lxr_tid() {return Gfs_lxr_.Tid_curly_bgn;}
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
switch (ctx.Prv_lxr()) {
case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); ctx.Stack_add(); break; // a{;
case Gfs_lxr_.Tid_paren_end: ctx.Stack_add(); break; // a(){; NOTE: node exists but needs to be pushed onto stack
default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Curly_bgn); break;
}
return end;
}
public static final Gfs_lxr_curly_bgn _ = new Gfs_lxr_curly_bgn(); Gfs_lxr_curly_bgn() {}
}
class Gfs_lxr_curly_end implements Gfs_lxr {
public byte Lxr_tid() {return Gfs_lxr_.Tid_curly_end;}
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
ctx.Stack_pop(bgn);
return end;
}
public static final Gfs_lxr_curly_end _ = new Gfs_lxr_curly_end(); Gfs_lxr_curly_end() {}
}
class Gfs_lxr_equal implements Gfs_lxr {
public byte Lxr_tid() {return Gfs_lxr_.Tid_eq;}
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
ctx.Make_nde(bgn, end).Op_tid_(Gfs_nde.Op_tid_assign);
return end;
}
public static final Gfs_lxr_equal _ = new Gfs_lxr_equal(); Gfs_lxr_equal() {}
}
class Gfs_lxr_comma implements Gfs_lxr {
public byte Lxr_tid() {return Gfs_lxr_.Tid_comma;}
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
switch (ctx.Prv_lxr()) {
case Gfs_lxr_.Tid_identifier: ctx.Make_atr_by_idf(); break; // 123,
}
return end;
}
public static final Gfs_lxr_comma _ = new Gfs_lxr_comma(); Gfs_lxr_comma() {}
}

View File

@@ -0,0 +1,39 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.gfs; import gplx.*;
class Gfs_lxr_ {
public static final int Rv_init = -1, Rv_null = -2, Rv_eos = -3, Rv_lxr = -4;
public static final byte Tid_identifier = 1, Tid_dot = 2, Tid_semic = 3, Tid_paren_bgn = 4, Tid_paren_end = 5, Tid_curly_bgn = 6, Tid_curly_end = 7, Tid_quote = 8, Tid_comma = 9, Tid_whitespace = 10, Tid_comment = 11, Tid_eq = 12;
public static String Tid__name(byte tid) {
switch (tid) {
case Tid_identifier: return "identifier";
case Tid_dot: return "dot";
case Tid_semic: return "semic";
case Tid_paren_bgn: return "paren_bgn";
case Tid_paren_end: return "paren_end";
case Tid_curly_bgn: return "curly_bgn";
case Tid_curly_end: return "curly_end";
case Tid_quote: return "quote";
case Tid_comma: return "comma";
case Tid_whitespace: return "whitespace";
case Tid_comment: return "comment";
case Tid_eq: return "eq";
default: throw Err_.unhandled(tid);
}
}
}

View File

@@ -0,0 +1,49 @@
/*
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.gfs; import gplx.*;
public class Gfs_msg_bldr implements GfoMsgParser {
Gfs_parser parser = new Gfs_parser();
public GfoMsg ParseToMsg(String s) {return Bld(s);}
public GfoMsg Bld(String src) {return Bld(Bry_.new_utf8_(src));}
public GfoMsg Bld(byte[] src) {
Gfs_nde nde = parser.Parse(src);
return Bld_msg(src, nde);
}
GfoMsg Bld_msg(byte[] src, Gfs_nde nde) {
boolean op_is_assign = (nde.Op_tid() == Gfs_nde.Op_tid_assign);
String name = String_.new_utf8_(nde.Name_bry(src));
if (op_is_assign) name += Tkn_mutator;
GfoMsg rv = GfoMsg_.new_parse_(name);
int len = nde.Atrs_len();
for (int i = 0; i < len; i++) {
Gfs_nde atr = nde.Atrs_get_at(i);
rv.Add("", String_.new_utf8_(atr.Name_bry(src)));
}
len = nde.Subs_len();
for (int i = 0; i < len; i++) {
Gfs_nde sub = nde.Subs_get_at(i);
if (op_is_assign) // NOTE: for now (a) assignss cannot be nested; EX: "a.b = c;" is okay but "a.b = c.d;" is not
rv.Add("", Bld_msg(src, sub).Key());
else
rv.Subs_add(Bld_msg(src, sub));
}
return rv;
}
public static final Gfs_msg_bldr _ = new Gfs_msg_bldr(); Gfs_msg_bldr() {}
public static final String Tkn_mutator = "_";
}

View File

@@ -0,0 +1,76 @@
/*
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.gfs; import gplx.*;
import org.junit.*;
public class Gfs_msg_bldr_tst {
@Before public void init() {fxt.Clear();} Gfs_msg_bldr_fxt fxt = new Gfs_msg_bldr_fxt();
@Test public void Basic() {
fxt.Test_build("a;", fxt.msg_("a"));
}
@Test public void Dot() {
fxt.Test_build("a.b.c;"
, fxt.msg_("a").Subs_
( fxt.msg_("b").Subs_
( fxt.msg_("c")
)));
}
@Test public void Args() {
fxt.Test_build("a('b', 'c');", fxt.msg_("a", fxt.kv_("", "b"), fxt.kv_("", "c")));
}
@Test public void Args_num() {
fxt.Test_build("a(1);", fxt.msg_("a", fxt.kv_("", "1")));
}
@Test public void Assign() {
fxt.Test_build("a = 'b';", fxt.msg_("a_", fxt.kv_("", "b")));
}
@Test public void Assign_num() {
fxt.Test_build("a = 1;", fxt.msg_("a_", fxt.kv_("", "1")));
}
}
class Gfs_msg_bldr_fxt {
public void Clear() {} String_bldr sb = String_bldr_.new_(); Gfs_msg_bldr msg_bldr = Gfs_msg_bldr._;
public KeyVal kv_(String key, String val) {return KeyVal_.new_(key, val);}
public GfoMsg msg_(String key, KeyVal... args) {
GfoMsg rv = GfoMsg_.new_parse_(key);
int len = args.length;
for (int i = 0; i < len; i++) {
KeyVal kv = args[i];
rv.Add(kv.Key(), kv.Val());
}
return rv;
}
public void Test_build(String raw, GfoMsg... expd) {
GfoMsg root = msg_bldr.Bld(raw);
Tfds.Eq_str_lines(Xto_str(expd), Xto_str(Xto_ary(root)));
}
GfoMsg[] Xto_ary(GfoMsg msg) {
int len = msg.Subs_count();
GfoMsg[] rv = new GfoMsg[len];
for (int i = 0; i < len; i++)
rv[i] = msg.Subs_getAt(i);
return rv;
}
String Xto_str(GfoMsg[] ary) {
int len = ary.length;
for (int i = 0; i < len; i++) {
if (i != 0) sb.Add_char_crlf();
sb.Add(ary[i].XtoStr());
}
return sb.XtoStrAndClear();
}
}

View File

@@ -0,0 +1,85 @@
/*
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.gfs; import gplx.*;
public class Gfs_nde {
public byte[] Name_bry(byte[] src) {return name == null ? Bry_.Mid(src, name_bgn, name_end) : name;}
public byte[] Name() {return name;} public Gfs_nde Name_(byte[] v) {name = v; return this;} private byte[] name;
public int Name_bgn() {return name_bgn;} private int name_bgn = -1;
public int Name_end() {return name_end;} private int name_end = -1;
public Gfs_nde Name_rng_(int name_bgn, int name_end) {this.name_bgn = name_bgn; this.name_end = name_end; return this;}
public byte Op_tid() {return op_tid;} public Gfs_nde Op_tid_(byte v) {op_tid = v; return this;} private byte op_tid;
public void Subs_clear() {
for (int i = 0; i < subs_len; i++)
subs[i] = null;
subs_len = 0;
}
public int Subs_len() {return subs_len;} private int subs_len;
public Gfs_nde Subs_add_many(Gfs_nde... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
Subs_add(ary[i]);
return this;
}
public Gfs_nde Subs_add(Gfs_nde nde) {
int new_len = subs_len + 1;
if (new_len > subs_max) { // ary too small >>> expand
subs_max = new_len * 2;
Gfs_nde[] new_subs = new Gfs_nde[subs_max];
Array_.CopyTo(subs, 0, new_subs, 0, subs_len);
subs = new_subs;
}
subs[subs_len] = nde;
subs_len = new_len;
return this;
} Gfs_nde[] subs = Gfs_nde.Ary_empty; int subs_max; int[] subs_pos_ary = Int_.Ary_empty;
public Gfs_nde Subs_get_at(int i) {return subs[i];}
public Gfs_nde[] Subs_to_ary() {
Gfs_nde[] rv = new Gfs_nde[subs_len];
for (int i = 0; i < subs_len; i++)
rv[i] = subs[i];
return rv;
}
public int Atrs_len() {return args_len;} private int args_len;
public Gfs_nde Atrs_get_at(int i) {return args[i];}
public Gfs_nde Atrs_add_many(Gfs_nde... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
Atrs_add(ary[i]);
return this;
}
public Gfs_nde Atrs_add(Gfs_nde nde) {
int new_len = args_len + 1;
if (new_len > args_max) { // ary too small >>> expand
args_max = new_len * 2;
Gfs_nde[] new_args = new Gfs_nde[args_max];
Array_.CopyTo(args, 0, new_args, 0, args_len);
args = new_args;
}
args[args_len] = nde;
args_len = new_len;
return this;
} Gfs_nde[] args = Gfs_nde.Ary_empty; int args_max; int[] args_pos_ary = Int_.Ary_empty;
public Gfs_nde[] Atrs_to_ary() {
Gfs_nde[] rv = new Gfs_nde[args_len];
for (int i = 0; i < args_len; i++)
rv[i] = args[i];
return rv;
}
public static final Gfs_nde[] Ary_empty = new Gfs_nde[0];
public static final byte Op_tid_null = 0, Op_tid_assign = 1;
}

View File

@@ -0,0 +1,103 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.gfs; import gplx.*;
public class Gfs_parser {
ByteTrieMgr_fast trie = Gfs_parser_.trie_();
Gfs_parser_ctx ctx = new Gfs_parser_ctx();
public Gfs_nde Parse(byte[] src) {
ctx.Root().Subs_clear();
int src_len = src.length; if (src_len == 0) return ctx.Root();
ctx.Init(trie, src, src_len);
int pos = 0;
while (pos < src_len) {
byte b = src[pos];
Object o = trie.Match(b, src, pos, src_len);
if (o == null)
ctx.Err_mgr().Fail_unknown_char(ctx, pos, b);
else {
Gfs_lxr lxr = (Gfs_lxr)o;
while (lxr != null) {
int rslt = lxr.Process(ctx, pos, trie.Match_pos());
switch (lxr.Lxr_tid()) {
case Gfs_lxr_.Tid_whitespace: break;
case Gfs_lxr_.Tid_comment: break;
default: ctx.Prv_lxr_(lxr.Lxr_tid()); break;
}
switch (rslt) {
case Gfs_lxr_.Rv_lxr:
pos = ctx.Nxt_pos();
lxr = ctx.Nxt_lxr();
break;
case Gfs_lxr_.Rv_eos:
pos = src_len;
lxr = null;
break;
default:
pos = rslt;
lxr = null;
break;
}
}
}
}
switch (ctx.Prv_lxr()) {
case Gfs_lxr_.Tid_curly_end:
case Gfs_lxr_.Tid_semic: break;
default: ctx.Err_mgr().Fail_eos(ctx); break;
}
return ctx.Root();
}
}
class Gfs_parser_ {
public static ByteTrieMgr_fast trie_() {
ByteTrieMgr_fast rv = ByteTrieMgr_fast.ci_ascii_(); // NOTE:ci.ascii:gfs;letters/symbols only;
Gfs_lxr_identifier word_lxr = Gfs_lxr_identifier._;
trie_add_rng(rv, word_lxr, Byte_ascii.Ltr_a, Byte_ascii.Ltr_z);
trie_add_rng(rv, word_lxr, Byte_ascii.Ltr_A, Byte_ascii.Ltr_Z);
trie_add_rng(rv, word_lxr, Byte_ascii.Num_0, Byte_ascii.Num_9);
rv.Add(Byte_ascii.Underline, word_lxr);
trie_add_many(rv, Gfs_lxr_whitespace._, Byte_ascii.Space, Byte_ascii.NewLine, Byte_ascii.CarriageReturn, Byte_ascii.Tab);
trie_add_quote(rv, new byte[] {Byte_ascii.Apos});
trie_add_quote(rv, new byte[] {Byte_ascii.Quote});
trie_add_quote(rv, Bry_.new_ascii_("<:[\"\n"), Bry_.new_ascii_("\n\"]:>"));
trie_add_quote(rv, Bry_.new_ascii_("<:['\n"), Bry_.new_ascii_("\n']:>"));
trie_add_comment(rv, new byte[] {Byte_ascii.Slash, Byte_ascii.Slash}, new byte[] {Byte_ascii.NewLine});
trie_add_comment(rv, new byte[] {Byte_ascii.Slash, Byte_ascii.Asterisk}, new byte[] {Byte_ascii.Asterisk, Byte_ascii.Slash});
rv.Add(Byte_ascii.Semic, Gfs_lxr_semic._);
rv.Add(Byte_ascii.Paren_bgn, Gfs_lxr_paren_bgn._);
rv.Add(Byte_ascii.Paren_end, Gfs_lxr_paren_end._);
rv.Add(Byte_ascii.Curly_bgn, Gfs_lxr_curly_bgn._);
rv.Add(Byte_ascii.Curly_end, Gfs_lxr_curly_end._);
rv.Add(Byte_ascii.Dot, Gfs_lxr_dot._);
rv.Add(Byte_ascii.Comma, Gfs_lxr_comma._);
rv.Add(Byte_ascii.Eq, Gfs_lxr_equal._);
return rv;
}
private static void trie_add_rng(ByteTrieMgr_fast trie, Gfs_lxr lxr, byte bgn, byte end) {
for (byte b = bgn; b <= end; b++)
trie.Add(b, lxr);
}
private static void trie_add_many(ByteTrieMgr_fast trie, Gfs_lxr lxr, byte... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
trie.Add(ary[i], lxr);
}
private static void trie_add_quote(ByteTrieMgr_fast trie, byte[] bgn) {trie_add_quote(trie, bgn, bgn);}
private static void trie_add_quote(ByteTrieMgr_fast trie, byte[] bgn, byte[] end) {trie.Add(bgn, new Gfs_lxr_quote(bgn, end));}
private static void trie_add_comment(ByteTrieMgr_fast trie, byte[] bgn, byte[] end) {trie.Add(bgn, new Gfs_lxr_comment_flat(bgn, end));}
}

View File

@@ -0,0 +1,125 @@
/*
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.gfs; import gplx.*;
class Gfs_parser_ctx {
public ByteTrieMgr_fast Trie() {return trie;} ByteTrieMgr_fast trie;
public Gfs_nde Root() {return root;} Gfs_nde root = new Gfs_nde();
public byte[] Src() {return src;} private byte[] src;
public int Src_len() {return src_len;} private int src_len;
public byte Prv_lxr() {return prv_lxr;} public Gfs_parser_ctx Prv_lxr_(byte v) {prv_lxr = v; return this;} private byte prv_lxr;
public Gfs_nde Cur_nde() {return cur_nde;} Gfs_nde cur_nde;
public int Nxt_pos() {return nxt_pos;} private int nxt_pos;
public Gfs_lxr Nxt_lxr() {return nxt_lxr;} Gfs_lxr nxt_lxr;
public Bry_bfr Tmp_bfr() {return tmp_bfr;} private Bry_bfr tmp_bfr = Bry_bfr.new_();
public void Process_eos() {}
public void Process_lxr(int nxt_pos, Gfs_lxr nxt_lxr) {this.nxt_pos = nxt_pos; this.nxt_lxr = nxt_lxr;}
public void Process_null(int cur_pos) {this.nxt_pos = cur_pos; this.nxt_lxr = null;}
public void Init(ByteTrieMgr_fast trie, byte[] src, int src_len) {
this.trie = trie; this.src = src; this.src_len = src_len;
cur_nde = root;
Stack_add();
}
public void Hold_word(int bgn, int end) {
cur_idf_bgn = bgn;
cur_idf_end = end;
} int cur_idf_bgn = -1, cur_idf_end = -1;
private void Held_word_clear() {cur_idf_bgn = -1; cur_idf_end = -1;}
public Gfs_nde Make_nde(int tkn_bgn, int tkn_end) { // "abc."; "abc("; "abc;"; "abc{"
Gfs_nde nde = new Gfs_nde().Name_rng_(cur_idf_bgn, cur_idf_end);
this.Held_word_clear();
cur_nde.Subs_add(nde);
cur_nde = nde;
return nde;
}
public void Make_atr_by_idf() {Make_atr(cur_idf_bgn, cur_idf_end); Held_word_clear();}
public void Make_atr_by_bry(int bgn, int end, byte[] bry) {Make_atr(bgn, end).Name_(bry);}
public Gfs_nde Make_atr(int bgn, int end) {
Gfs_nde nde = new Gfs_nde().Name_rng_(bgn, end);
cur_nde.Atrs_add(nde);
return nde;
}
public void Cur_nde_from_stack() {cur_nde = (Gfs_nde)nodes.FetchAtLast();}
public void Stack_add() {nodes.Add(cur_nde);} ListAdp nodes = ListAdp_.new_();
public void Stack_pop(int pos) {
if (nodes.Count() < 2) err_mgr.Fail_nde_stack_empty(this, pos); // NOTE: need at least 2 items; 1 to pop and 1 to set as current
ListAdp_.DelAt_last(nodes);
Cur_nde_from_stack();
}
public Gfs_err_mgr Err_mgr() {return err_mgr;} Gfs_err_mgr err_mgr = new Gfs_err_mgr();
}
class Gfs_err_mgr {
public void Fail_eos(Gfs_parser_ctx ctx) {Fail(ctx, Fail_msg_eos, ctx.Src_len());}
public void Fail_unknown_char(Gfs_parser_ctx ctx, int pos, byte c) {Fail(ctx, Fail_msg_unknown_char, pos, KeyVal_.new_("char", Char_.XtoStr((char)c)));}
public void Fail_nde_stack_empty(Gfs_parser_ctx ctx, int pos) {Fail(ctx, Fail_msg_nde_stack_empty, pos);}
public void Fail_invalid_lxr(Gfs_parser_ctx ctx, int pos, byte cur_lxr, byte c) {
Fail(ctx, Fail_msg_invalid_lxr, pos, KeyVal_.new_("char", Char_.XtoStr((char)c)), KeyVal_.new_("cur_lxr", Gfs_lxr_.Tid__name(cur_lxr)), KeyVal_.new_("prv_lxr", Gfs_lxr_.Tid__name(ctx.Prv_lxr())));
}
private void Fail(Gfs_parser_ctx ctx, String msg, int pos, KeyVal... args) {
byte[] src = ctx.Src(); int src_len = ctx.Src_len();
Fail_args_standard(src, src_len, pos);
int len = args.length;
for (int i = 0; i < len; i++) {
KeyVal arg = args[i];
tmp_fail_args.Add(arg.Key(), arg.Val_to_str_or_empty());
}
throw Err_.new_(Fail_msg(msg, tmp_fail_args));
}
private void Fail_args_standard(byte[] src, int src_len, int pos) {
tmp_fail_args.Add("excerpt_bgn", Fail_excerpt_bgn(src, src_len, pos));
tmp_fail_args.Add("excerpt_end", Fail_excerpt_end(src, src_len, pos));
tmp_fail_args.Add("pos" , pos);
}
public static final String Fail_msg_invalid_lxr = "invalid character", Fail_msg_unknown_char = "unknown char", Fail_msg_eos = "end of stream", Fail_msg_nde_stack_empty = "node stack empty";
String Fail_msg(String type, KeyValList fail_args) {
tmp_fail_bfr.Add_str(type).Add_byte(Byte_ascii.Colon);
int len = fail_args.Count();
for (int i = 0; i < len; i++) {
tmp_fail_bfr.Add_byte(Byte_ascii.Space);
KeyVal kv = fail_args.GetAt(i);
tmp_fail_bfr.Add_str(kv.Key());
tmp_fail_bfr.Add_byte(Byte_ascii.Eq).Add_byte(Byte_ascii.Apos);
tmp_fail_bfr.Add_str(kv.Val_to_str_or_empty()).Add_byte(Byte_ascii.Apos);
}
return tmp_fail_bfr.XtoStrAndClear();
}
Bry_bfr tmp_fail_bfr = Bry_bfr.reset_(255);
KeyValList tmp_fail_args = new KeyValList();
private static int excerpt_len = 50;
String Fail_excerpt_bgn(byte[] src, int src_len, int pos) {
int bgn = pos - excerpt_len; if (bgn < 0) bgn = 0;
Fail_excerpt_rng(tmp_fail_bfr, src, bgn, pos);
return tmp_fail_bfr.XtoStrAndClear();
}
String Fail_excerpt_end(byte[] src, int src_len, int pos) {
int end = pos + excerpt_len; if (end > src_len) end = src_len;
Fail_excerpt_rng(tmp_fail_bfr, src, pos, end);
return tmp_fail_bfr.XtoStrAndClear();
}
private static void Fail_excerpt_rng(Bry_bfr bfr, byte[] src, int bgn, int end) {
for (int i = bgn; i < end; i++) {
byte b = src[i];
switch (b) {
case Byte_ascii.Tab: bfr.Add(Esc_tab); break;
case Byte_ascii.NewLine: bfr.Add(Esc_nl); break;
case Byte_ascii.CarriageReturn: bfr.Add(Esc_cr); break;
default: bfr.Add_byte(b); break;
}
}
} static final byte[] Esc_nl = Bry_.new_ascii_("\\n"), Esc_cr = Bry_.new_ascii_("\\r"), Esc_tab = Bry_.new_ascii_("\\t");
}

View File

@@ -0,0 +1,196 @@
/*
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.gfs; import gplx.*;
import org.junit.*;
public class Gfs_parser_tst {
@Before public void init() {fxt.Clear();} Gfs_parser_fxt fxt = new Gfs_parser_fxt();
@Test public void Semicolon() {
fxt .Test_parse("a;", fxt.nde_("a"));
fxt .Test_parse("a;b;c;", fxt.nde_("a"), fxt.nde_("b"), fxt.nde_("c"));
fxt .Test_parse("a_0;", fxt.nde_("a_0"));
}
@Test public void Dot() {
fxt .Test_parse("a.b;", fxt.nde_("a").Subs_add(fxt.nde_("b")));
fxt .Test_parse("a.b;c.d;", fxt.nde_("a").Subs_add(fxt.nde_("b")), fxt.nde_("c").Subs_add(fxt.nde_("d")));
}
@Test public void Parens() {
fxt .Test_parse("a();b();", fxt.nde_("a"), fxt.nde_("b"));
fxt .Test_parse("a().b();c().d();", fxt.nde_("a").Subs_add(fxt.nde_("b")), fxt.nde_("c").Subs_add(fxt.nde_("d")));
}
@Test public void Num() {
fxt .Test_parse("a(1,2);", fxt.nde_("a").Atrs_add_many(fxt.val_("1"), fxt.val_("2")));
}
@Test public void Quote() {
fxt .Test_parse("a('b');", fxt.nde_("a").Atrs_add(fxt.val_("b")));
}
@Test public void Quote_escaped() {
fxt .Test_parse("a('b''c''d');", fxt.nde_("a").Atrs_add(fxt.val_("b'c'd")));
}
@Test public void Quote_escaped_2() {
fxt .Test_parse("a('a''''b');", fxt.nde_("a").Atrs_add(fxt.val_("a''b")));
}
@Test public void Quote_mixed() {
fxt .Test_parse("a('b\"c');", fxt.nde_("a").Atrs_add(fxt.val_("b\"c")));
}
@Test public void Comma() {
fxt .Test_parse("a('b','c','d');", fxt.nde_("a").Atrs_add_many(fxt.val_("b"), fxt.val_("c"), fxt.val_("d")));
}
@Test public void Ws() {
fxt .Test_parse(" a ( 'b' , 'c' ) ; ", fxt.nde_("a").Atrs_add_many(fxt.val_("b"), fxt.val_("c")));
}
@Test public void Comment_slash_slash() {
fxt .Test_parse("//z\na;//y\n", fxt.nde_("a"));
}
@Test public void Comment_slash_star() {
fxt .Test_parse("/*z*/a;/*y*/", fxt.nde_("a"));
}
@Test public void Curly() {
fxt .Test_parse("a{b;}", fxt.nde_("a").Subs_add(fxt.nde_("b")));
}
@Test public void Curly_nest() {
fxt .Test_parse("a{b{c{d;}}}"
, fxt.nde_("a").Subs_add
( fxt.nde_("b").Subs_add
( fxt.nde_("c").Subs_add
( fxt.nde_("d")
))));
}
@Test public void Curly_nest_peers() {
fxt .Test_parse(String_.Concat_lines_nl
( "a{"
, " a0{"
, " a00{"
, " a000;"
, " }"
, " a01;"
, " }"
, " a1;"
, "}"
)
, fxt.nde_("a").Subs_add_many
( fxt.nde_("a0").Subs_add_many
( fxt.nde_("a00").Subs_add
( fxt.nde_("a000")
)
, fxt.nde_("a01")
)
, fxt.nde_("a1")
));
}
@Test public void Curly_dot() {
fxt .Test_parse("a{a0.a00;a1.a10;}"
, fxt.nde_("a").Subs_add_many
( fxt.nde_("a0").Subs_add_many(fxt.nde_("a00"))
, fxt.nde_("a1").Subs_add_many(fxt.nde_("a10"))
));
}
@Test public void Eq() {
fxt .Test_parse("a='b';", fxt.nde_("a").Atrs_add(fxt.val_("b")));
fxt .Test_parse("a.b.c='d';"
, fxt.nde_("a").Subs_add
( fxt.nde_("b").Subs_add_many
( fxt.nde_("c").Atrs_add(fxt.val_("d"))
)));
fxt .Test_parse("a.b{c='d'; e='f'}"
, fxt.nde_("a").Subs_add
( fxt.nde_("b").Subs_add_many
( fxt.nde_("c").Atrs_add(fxt.val_("d"))
, fxt.nde_("e").Atrs_add(fxt.val_("f"))
)));
}
@Test public void Curly_nest_peers2() {
fxt .Test_parse(String_.Concat_lines_nl
( "a() {"
, " k1 = 'v1';"
, "}"
)
, fxt.nde_("a").Subs_add_many
( fxt.nde_("k1").Atrs_add(fxt.val_("v1"))
)
);
}
@Test public void Fail() {
fxt .Test_parse_fail("a(.);", Gfs_err_mgr.Fail_msg_invalid_lxr); // (.)
fxt .Test_parse_fail("a..b;", Gfs_err_mgr.Fail_msg_invalid_lxr); // ..
fxt .Test_parse_fail("a.;", Gfs_err_mgr.Fail_msg_invalid_lxr); // .;
fxt .Test_parse_fail("a", Gfs_err_mgr.Fail_msg_eos); // eos
fxt .Test_parse_fail("a;~;", Gfs_err_mgr.Fail_msg_unknown_char); // ~
}
}
class Gfs_parser_fxt {
public void Clear() {}
public Gfs_nde nde_(String v) {return new Gfs_nde().Name_(Bry_.new_ascii_(v));}
public Gfs_nde val_(String v) {return new Gfs_nde().Name_(Bry_.new_ascii_(v));}
public void Test_parse(String src_str, Gfs_nde... expd) {
byte[] src_bry = Bry_.new_utf8_(src_str);
Gfs_nde root = parser.Parse(src_bry);
Tfds.Eq_str_lines(To_str(null, expd), To_str(src_bry, root.Subs_to_ary()));
} private Bry_bfr tmp_bfr = Bry_bfr.new_(), path_bfr = Bry_bfr.new_(); Gfs_parser parser = new Gfs_parser();
public void Test_parse_fail(String src_str, String expd_err) {
byte[] src_bry = Bry_.new_utf8_(src_str);
try {parser.Parse(src_bry);}
catch (Exception e) {
String actl_err = Err_.Message_gplx_brief(e);
actl_err = String_.GetStrBefore(actl_err, ":");
boolean match = String_.HasAtBgn(actl_err, expd_err);
if (!match) Tfds.Fail("expecting '" + expd_err + "' got '" + actl_err + "'");
return;
}
Tfds.Fail("expected to fail with " + expd_err);
}
public String To_str(byte[] src, Gfs_nde[] expd) {
int subs_len = expd.length;
for (int i = 0; i < subs_len; i++) {
path_bfr.Clear().Add_int_variable(i);
To_str(tmp_bfr, path_bfr, src, expd[i]);
}
return tmp_bfr.XtoStrAndClear();
}
public void To_str(Bry_bfr bfr, Bry_bfr path, byte[] src, Gfs_nde nde) {
To_str_atr(bfr, path, src, Atr_name, nde.Name(), nde.Name_bgn(), nde.Name_end());
int atrs_len = nde.Atrs_len();
for (int i = 0; i < atrs_len; i++) {
Gfs_nde atr = nde.Atrs_get_at(i);
int path_len_old = path.Len();
path.Add_byte(Byte_ascii.Dot).Add_byte((byte)(Byte_ascii.Ltr_a + i));
int path_len_new = path.Len();
To_str(bfr, path, src, atr);
path.Del_by(path_len_new - path_len_old);
}
int subs_len = nde.Subs_len();
for (int i = 0; i < subs_len; i++) {
Gfs_nde sub = nde.Subs_get_at(i);
int path_len_old = path.Len();
path.Add_byte(Byte_ascii.Dot).Add_int_variable(i);
int path_len_new = path.Len();
To_str(bfr, path, src, sub);
path.Del_by(path_len_new - path_len_old);
}
}
private void To_str_atr(Bry_bfr bfr, Bry_bfr path_bfr, byte[] src, byte[] name, byte[] val, int val_bgn, int val_end) {
if (val == null && val_bgn == -1 && val_end == -1) return;
bfr.Add_bfr(path_bfr).Add_byte(Byte_ascii.Colon);
bfr.Add(name);
if (val == null)
bfr.Add_mid(src, val_bgn, val_end);
else
bfr.Add(val);
bfr.Add_byte_nl();
}
private static final byte[] Atr_name = Bry_.new_ascii_("name=");
}

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.gfs; import gplx.*;
public class Gfs_wtr {
public byte Quote_char() {return quote_char;} public Gfs_wtr Quote_char_(byte v) {quote_char = v; return this;} private byte quote_char = Byte_ascii.Apos;
public Bry_bfr Bfr() {return bfr;} private Bry_bfr bfr = Bry_bfr.reset_(255);
public void Add_grp_bgn(byte[] key) {
bfr.Add(key); // key
bfr.Add_byte(Byte_ascii.Curly_bgn); // {
}
public void Add_grp_end(byte[] key) {
bfr.Add_byte(Byte_ascii.Curly_end); // }
}
public void Add_set_eq(byte[] key, byte[] val) {
bfr.Add(key); // key
bfr.Add_byte_eq(); // =
bfr.Add_byte(quote_char); // '
Write_val(val);
bfr.Add_byte(quote_char); // '
bfr.Add_byte(Byte_ascii.Semic); // ;
}
private void Write_val(byte[] bry) {
int bry_len = bry.length;
for (int i = 0; i < bry_len; i++) {
byte b = bry[i];
if (b == quote_char) // byte is quote
bfr.Add_byte(b); // double up
bfr.Add_byte(b);
}
}
}

View File

@@ -0,0 +1,286 @@
/*
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.gfui; import gplx.*;
public class Gfui_bnd_parser {
private Bry_bfr tmp_bfr = Bry_bfr.reset_(32);
private Hash_adp_bry
gfui_regy = Hash_adp_bry.ci_ascii_()
, norm_regy = Hash_adp_bry.ci_ascii_()
;
private static final Gfui_bnd_tkn
Itm_sym_plus = new_sym_(Gfui_bnd_tkn.Tid_sym_plus , new byte[] {Byte_ascii.Plus})
, Itm_sym_pipe = new_sym_(Gfui_bnd_tkn.Tid_sym_pipe , new byte[] {Byte_ascii.Pipe})
, Itm_sym_comma = new_sym_(Gfui_bnd_tkn.Tid_sym_comma , new byte[] {Byte_ascii.Comma})
// , Itm_sym_ws = new_sym_(Gfui_bnd_tkn.Tid_sym_ws , Bry_.Empty)
, Itm_sym_eos = new_sym_(Gfui_bnd_tkn.Tid_sym_eos , Bry_.Empty)
;
private static final Gfui_bnd_tkn[] Mod_ary = new Gfui_bnd_tkn[]
{ null
, new_mod_(Gfui_bnd_tkn.Tid_mod_c , "mod.c" , "Ctrl")
, new_mod_(Gfui_bnd_tkn.Tid_mod_a , "mod.a" , "Alt")
, new_mod_(Gfui_bnd_tkn.Tid_mod_ca , "mod.ca" , "Ctrl + Alt")
, new_mod_(Gfui_bnd_tkn.Tid_mod_s , "mod.s" , "Shift")
, new_mod_(Gfui_bnd_tkn.Tid_mod_cs , "mod.cs" , "Ctrl + Shift")
, new_mod_(Gfui_bnd_tkn.Tid_mod_as , "mod.as" , "Alt + Shift")
, new_mod_(Gfui_bnd_tkn.Tid_mod_cas , "mod.cas" , "Ctrl + Alt + Shift")
};
private byte[] src; private int src_len;
private ListAdp tkns = ListAdp_.new_(); private int mod_val = Mod_val_null;
public String X_to_norm(String src_str) {return Convert(Bool_.Y, src_str);}
public String X_to_gfui(String src_str) {return Convert(Bool_.N, src_str);}
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
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) {
case Byte_ascii.Plus: // simultaneous; EX: Ctrl + S
sym_tkn = Itm_sym_plus;
break;
case Byte_ascii.Pipe: // alternate; EX: Ctrl + S | Ctrl + Alt + s
sym_tkn = Itm_sym_pipe;
break;
case Byte_ascii.Comma: // chorded; EX: Ctrl + S, Ctrl + T
sym_tkn = Itm_sym_comma;
break;
case Byte_ascii.NewLine: // eos: process anything in bfr
sym_tkn = Itm_sym_eos;
break;
case Byte_ascii.Space:
if (itm_bgn != -1) // if word started, " " ends word; EX: "Ctrl + A"; " +" ends "Ctrl"
itm_end = pos;
++pos;
continue;
default: // letter / number; continue
if (itm_bgn == -1) // no word started; start it
itm_bgn = pos;
++pos;
continue;
}
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);
if (sym_tkn.Tid() == Gfui_bnd_tkn.Tid_sym_eos)
break;
else
++pos;
itm_bgn = itm_end = -1;
}
int tkns_len = tkns.Count();
for (int i = 0; i < tkns_len; i++) {
Gfui_bnd_tkn tkn = (Gfui_bnd_tkn)tkns.FetchAt(i);
tkn.Write(tmp_bfr, !src_is_gfui);
}
return tmp_bfr.XtoStrAndClear();
}
private void Process_sym(boolean src_is_gfui, 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);
if (tkn == null) throw Err_.new_fmt_("unknown key: key={0}", String_.new_utf8_(src, itm_bgn, itm_end));
int mod_adj = Mod_val_null;
switch (tkn.Tid()) {
case Gfui_bnd_tkn.Tid_mod_c: mod_adj = Gfui_bnd_tkn.Tid_mod_c; break;
case Gfui_bnd_tkn.Tid_mod_a: mod_adj = Gfui_bnd_tkn.Tid_mod_a; break;
case Gfui_bnd_tkn.Tid_mod_s: mod_adj = Gfui_bnd_tkn.Tid_mod_s; break;
case Gfui_bnd_tkn.Tid_mod_cs: mod_adj = Gfui_bnd_tkn.Tid_mod_cs; break;
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;
default: throw Err_.unhandled(tkn.Tid());
}
switch (sym_tkn.Tid()) {
case Gfui_bnd_tkn.Tid_sym_plus: // EX: Ctrl + A
if (mod_adj != Mod_val_null) { // if mod, just update mod_val and exit
mod_val = Enm_.FlipInt(true, mod_val, mod_adj);
return;
}
break;
}
if (mod_val != Mod_val_null) { // modifier exists; add tkn
tkns.Add(Mod_ary[mod_val]);
tkns.Add(Itm_sym_plus);
mod_val = Mod_val_null;
}
tkns.Add(tkn); // add word
if (sym_tkn.Tid() != Gfui_bnd_tkn.Tid_sym_eos)
tkns.Add(sym_tkn);
}
private Gfui_bnd_parser Init_en() {
Init_itm_mod(Gfui_bnd_tkn.Tid_mod_c);
Init_itm_mod(Gfui_bnd_tkn.Tid_mod_a);
Init_itm_mod(Gfui_bnd_tkn.Tid_mod_s);
Init_itm_mod(Gfui_bnd_tkn.Tid_mod_ca);
Init_itm_mod(Gfui_bnd_tkn.Tid_mod_cs);
Init_itm_mod(Gfui_bnd_tkn.Tid_mod_as);
Init_itm_mod(Gfui_bnd_tkn.Tid_mod_cas);
Init_itm(Gfui_bnd_tkn.Tid_mod_c, "key.ctrl", "Ctrl");
Init_itm(Gfui_bnd_tkn.Tid_mod_a, "key.alt", "Atl");
Init_itm(Gfui_bnd_tkn.Tid_mod_s, "key.shift", "Shift");
Init_itm("key.a", "A");
Init_itm("key.b", "B");
Init_itm("key.c", "C");
Init_itm("key.d", "D");
Init_itm("key.e", "E");
Init_itm("key.f", "F");
Init_itm("key.g", "G");
Init_itm("key.h", "H");
Init_itm("key.i", "I");
Init_itm("key.j", "J");
Init_itm("key.k", "K");
Init_itm("key.l", "L");
Init_itm("key.m", "M");
Init_itm("key.n", "N");
Init_itm("key.o", "O");
Init_itm("key.p", "P");
Init_itm("key.q", "Q");
Init_itm("key.r", "R");
Init_itm("key.s", "S");
Init_itm("key.t", "T");
Init_itm("key.u", "U");
Init_itm("key.v", "V");
Init_itm("key.w", "W");
Init_itm("key.x", "X");
Init_itm("key.y", "Y");
Init_itm("key.z", "Z");
Init_itm("key.d0", "0");
Init_itm("key.d1", "1");
Init_itm("key.d2", "2");
Init_itm("key.d3", "3");
Init_itm("key.d4", "4");
Init_itm("key.d5", "5");
Init_itm("key.d6", "6");
Init_itm("key.d7", "7");
Init_itm("key.d8", "8");
Init_itm("key.d9", "9");
Init_itm("key.f1", "F1");
Init_itm("key.f2", "F2");
Init_itm("key.f3", "F3");
Init_itm("key.f4", "F4");
Init_itm("key.f5", "F5");
Init_itm("key.f6", "F6");
Init_itm("key.f7", "F7");
Init_itm("key.f8", "F8");
Init_itm("key.f9", "F9");
Init_itm("key.f10", "F10");
Init_itm("key.f11", "F11");
Init_itm("key.f12", "F12");
Init_itm("key.none", "None");
Init_itm("key.back", "Backspace");
Init_itm("key.tab", "Tab");
Init_itm("key.clear", "Clear");
Init_itm("key.enter", "Enter");
Init_itm("key.shiftKey", "ShiftKey");
Init_itm("key.ctrlKey", "CtrlKey");
Init_itm("key.altKey", "AltKey");
Init_itm("key.pause", "Pause");
Init_itm("key.capsLock", "CapsLock");
Init_itm("key.escape", "Escape");
Init_itm("key.space", "Space");
Init_itm("key.pageUp", "PageUp");
Init_itm("key.pageDown", "PageDown");
Init_itm("key.end", "End");
Init_itm("key.home", "Home");
Init_itm("key.left", "Left");
Init_itm("key.up", "Up");
Init_itm("key.right", "Right");
Init_itm("key.down", "Down");
Init_itm("key.printScreen", "PrintScreen");
Init_itm("key.insert", "Insert");
Init_itm("key.delete", "Delete");
Init_itm("key.numLock", "NumLock");
Init_itm("key.scrollLock", "ScrollLock");
Init_itm("key.semicolon", "Semicolon");
Init_itm("key.equal", "Equal");
Init_itm("key.comma", "Comma");
Init_itm("key.minus", "Minus");
Init_itm("key.period", "Period");
Init_itm("key.slash", "Slash");
Init_itm("key.tick", "Tick");
Init_itm("key.openBracket", "OpenBracket");
Init_itm("key.backslash", "Backslash");
Init_itm("key.closeBracket", "CloseBracket");
Init_itm("key.quote", "Quote");
Init_itm("mouse.middle", "Middle Click");
Init_itm("mouse.left", "Left Click");
Init_itm("mouse.right", "Right Click");
return this;
}
private void Init_itm(String gfui, String norm) {Init_itm(Gfui_bnd_tkn.Tid_key, gfui, norm);}
private void Init_itm_mod(int tid) {
Gfui_bnd_tkn itm = Mod_ary[tid];
gfui_regy.Add(itm.Bry_gfui(), itm);
norm_regy.Add(itm.Bry_norm(), itm);
}
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_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));}
}
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 void Write(Bry_bfr bfr, boolean src_is_gfui) {
byte[] bry = src_is_gfui ? bry_gfui : bry_norm;
switch (tid) {
case Tid_mod_c: case Tid_mod_a: case Tid_mod_s:
case Tid_mod_ca: case Tid_mod_cs: case Tid_mod_as: case Tid_mod_cas:
bfr.Add(bry);
break;
case Tid_sym_plus:
if (!src_is_gfui)
bfr.Add_byte_space();
bfr.Add(bry);
if (!src_is_gfui)
bfr.Add_byte_space();
break;
case Tid_sym_pipe:
if (!src_is_gfui)
bfr.Add_byte_space();
bfr.Add(bry);
if (!src_is_gfui)
bfr.Add_byte_space();
break;
case Tid_sym_comma:
bfr.Add(bry);
if (!src_is_gfui)
bfr.Add_byte_space();
break;
case Tid_key:
bfr.Add(bry);
break;
}
}
public static final byte
Tid_mod_c = 1 , Tid_mod_a = 2 , Tid_mod_s = 4
, Tid_mod_ca = 3 , Tid_mod_cs = 5 , Tid_mod_as = 6, Tid_mod_cas = 7
, Tid_sym_plus = 8 , Tid_sym_pipe = 9 , Tid_sym_comma = 10, Tid_sym_eos = 11
, Tid_key = 12
;
}

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.gfui; import gplx.*;
import org.junit.*;
public class Gfui_bnd_parser_tst {
@Before public void init() {fxt.Clear();} private Gfui_bnd_parser_fxt fxt = new Gfui_bnd_parser_fxt();
@Test public void Norm_one() {
fxt.Test_x_to_norm("mod.c" , "Ctrl");
fxt.Test_x_to_norm("key.ctrl" , "Ctrl");
fxt.Test_x_to_norm("key.a" , "A");
fxt.Test_x_to_norm("key.left" , "Left");
}
@Test public void Norm_add() {
fxt.Test_x_to_norm("mod.c+key.a" , "Ctrl + A");
fxt.Test_x_to_norm("mod.ca+key.a" , "Ctrl + Alt + A");
fxt.Test_x_to_norm("mod.cas+key.a" , "Ctrl + Alt + Shift + A");
}
@Test public void Norm_chord() {
fxt.Test_x_to_norm("key.a,key.b" , "A, B");
}
@Test public void Norm_add_and_chord() {
fxt.Test_x_to_norm("mod.c+key.a,mod.a+key.b" , "Ctrl + A, Alt + B");
}
@Test public void Gfui_add() {
fxt.Test_x_to_gfui("Ctrl + A" , "mod.c+key.a");
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");
}
}
class Gfui_bnd_parser_fxt {
private Gfui_bnd_parser parser;
public void Clear() {
parser = Gfui_bnd_parser.new_en_();
}
public void Test_x_to_norm(String key, String expd) {
Tfds.Eq(expd, parser.X_to_norm(key));
}
public void Test_x_to_gfui(String key, String expd) {
Tfds.Eq(expd, parser.X_to_gfui(key));
}
}

View File

@@ -0,0 +1,28 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.html; import gplx.*;
public class Html_atrs {
public static final String
Src_str = "src"
;
public static final byte[]
Id_bry = Bry_.new_ascii_("id")
, Cls_bry = Bry_.new_ascii_("class")
, Style_bry = Bry_.new_ascii_("style")
;
}

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.html; import gplx.*;
public class Html_consts {
public static final String Nl_str = "&#10;";
public static final String
Comm_bgn_str = "<!--"
, Comm_end_str = "-->"
, Img_str = "img"
;
public static final byte[]
Lt = Bry_.new_ascii_("&lt;"), Gt = Bry_.new_ascii_("&gt;")
, Amp = Bry_.new_ascii_("&amp;"), Quote = Bry_.new_ascii_("&quot;"), Apos = Bry_.new_ascii_("&#39;")
, Eq = Bry_.new_ascii_("&#61;")
, Nl_bry = Bry_.new_ascii_(Nl_str), Space_bry = Bry_.new_ascii_("&#32;")
, Comm_bgn = Bry_.new_ascii_(Comm_bgn_str), Comm_end = Bry_.new_ascii_(Comm_end_str)
, Hr_bry = Bry_.new_ascii_("<hr/>")
, Br_bry = Bry_.new_ascii_("<br/>")
, Td_bgn_bry = Bry_.new_ascii_("<td>")
, Td_end_bry = Bry_.new_ascii_("</td>")
, Ul_tag_bry = Bry_.new_ascii_("ul")
;
public static final int
Comm_bgn_len = Comm_bgn.length
, Comm_end_len = Comm_end.length
;
}

View File

@@ -0,0 +1,94 @@
/*
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.html; import gplx.*;
public class Html_nde {
public Html_nde(byte[] src, boolean tag_tid_is_inline, int tag_lhs_bgn, int tag_lhs_end, int tag_rhs_bgn, int tag_rhs_end, int name_bgn, int name_end, int[] cur_atrs, int atrs_idx) {
this.src = src;
this.tag_tid_is_inline = tag_tid_is_inline;
this.tag_lhs_bgn = tag_lhs_bgn; this.tag_lhs_end = tag_lhs_end; this.tag_rhs_bgn = tag_rhs_bgn; this.tag_rhs_end = tag_rhs_end; this.name_bgn = name_bgn; this.name_end = name_end;
if (atrs_idx > 0) {
atrs = new int[atrs_idx];
for (int i = 0; i < atrs_idx; i++)
atrs[i] = cur_atrs[i];
atrs_len = atrs_idx / 5;
}
}
public byte[] Src() {return src;} private byte[] src;
public int[] Atrs() {return atrs;} private int[] atrs = Int_.Ary_empty;
public int Atrs_len() {return atrs_len;} private int atrs_len;
public boolean Tag_tid_is_inline() {return tag_tid_is_inline;} private boolean tag_tid_is_inline;
public int Tag_lhs_bgn() {return tag_lhs_bgn;} public Html_nde Tag_lhs_bgn_(int v) {tag_lhs_bgn = v; return this;} private int tag_lhs_bgn;
public int Tag_lhs_end() {return tag_lhs_end;} public Html_nde Tag_lhs_end_(int v) {tag_lhs_end = v; return this;} private int tag_lhs_end;
public int Tag_rhs_bgn() {return tag_rhs_bgn;} public Html_nde Tag_rhs_bgn_(int v) {tag_rhs_bgn = v; return this;} private int tag_rhs_bgn;
public int Tag_rhs_end() {return tag_rhs_end;} public Html_nde Tag_rhs_end_(int v) {tag_rhs_end = v; return this;} private int tag_rhs_end;
public int Name_bgn() {return name_bgn;} public Html_nde Name_bgn_(int v) {name_bgn = v; return this;} private int name_bgn;
public int Name_end() {return name_end;} public Html_nde Name_end_(int v) {name_end = v; return this;} private int name_end;
public void Clear() {tag_lhs_bgn = tag_rhs_bgn = -1;}
public String Atrs_val_by_key_str(String find_key_str) {return String_.new_utf8_(Atrs_val_by_key_bry(Bry_.new_utf8_(find_key_str)));}
public byte[] Atrs_val_by_key_bry(byte[] find_key_bry) {
for (int i = 0; i < atrs_len; i ++) {
int atrs_idx = i * 5;
int atr_key_bgn = atrs[atrs_idx + 1];
int atr_key_end = atrs[atrs_idx + 2];
if (Bry_.Match(src, atr_key_bgn, atr_key_end, find_key_bry))
return Atrs_vals_by_pos(src, atrs[atrs_idx + 0], atrs[atrs_idx + 3], atrs[atrs_idx + 4]);
}
return null;
}
byte[] Atrs_vals_by_pos(byte[] src, int quote_byte, int bgn, int end) {
Bry_bfr tmp_bfr = Bry_bfr.new_();
boolean dirty = false;
for (int i = bgn; i < end; i++) {
byte b = src[i];
switch (b) {
case Byte_ascii.Backslash:
if (!dirty) {dirty = true; tmp_bfr.Add_mid(src, bgn, i);}
++i;
tmp_bfr.Add_byte(src[i]);
break;
default:
if (b == quote_byte) {
byte next_byte = src[i + 1];
if (next_byte == b) {
if (!dirty) {dirty = true; tmp_bfr.Add_mid(src, bgn, i);}
++i;
tmp_bfr.Add_byte(src[i]);
}
}
else {
if (dirty)
tmp_bfr.Add_byte(b);
}
break;
}
}
return dirty ? tmp_bfr.XtoAryAndClear() : Bry_.Mid(src, bgn, end);
}
public byte[] Data(byte[] src) {
return Bry_.Mid(src, tag_lhs_end, tag_rhs_bgn);
}
}
// class Xoh_atr {
// public byte[] Key_bry() {return key_bry;} private byte[] key_bry;
// public byte[] Val_bry() {return val_bry;} private byte[] val_bry;
// public int Key_bgn() {return key_bgn;} private int key_bgn;
// public int Key_end() {return key_end;} private int key_end;
// public int Val_bgn() {return val_bgn;} private int val_bgn;
// public int Val_end() {return val_end;} private int val_end;
// public byte Val_quote_tid() {return val_quote_tid;} private byte val_quote_tid;
// }

View File

@@ -0,0 +1,165 @@
/*
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.html; import gplx.*;
import gplx.core.bytes.*;
public class Html_parser {
public Html_parser() {
Bry_bldr bry_bldr = new Bry_bldr();
bry_xnde_name = bry_bldr.New_256().Set_rng_xml_identifier(Scan_valid).Set_rng_ws(Scan_stop).Val();
bry_atr_key = bry_bldr.New_256().Set_rng_xml_identifier(Scan_valid).Set_rng_ws(Scan_stop).Set_many(Scan_stop, Byte_ascii.Eq).Val();
}
byte[] src; int pos, end; byte[] bry_xnde_name, bry_atr_key;
int cur_atrs_idx = 0; int[] cur_atrs = new int[250];// define max of 50 atrs;
public Html_nde[] Parse_as_ary(byte[] src) {return Parse_as_ary(src, 0, src.length, Wildcard, Wildcard);}
public Html_nde[] Parse_as_ary(byte[] src, int bgn, int end) {return Parse_as_ary(src, bgn, end, Wildcard, Wildcard);}
public Html_nde[] Parse_as_ary(byte[] src, int bgn, int end, byte[] find_key, byte[] find_val) { // flattens html into a list of hndes; only used for Options
this.src = src; pos = bgn; this.end = end;
ListAdp rv = ListAdp_.new_();
while (pos < end) {
byte b = src[pos++];
switch (b) {
case Byte_ascii.Lt:
if (xnde_init) {
if (Parse_xnde_lhs()) {
if (tag_tid_is_inline)
rv.Add(new Html_nde(src, tag_tid_is_inline, cur_lhs_bgn, cur_lhs_end, cur_rhs_bgn, pos, cur_name_bgn, cur_name_end, cur_atrs, cur_atrs_idx));
else
xnde_init = false;
}
}
else {
if (Parse_xnde_rhs()) {
rv.Add(new Html_nde(src, tag_tid_is_inline, cur_lhs_bgn, cur_lhs_end, cur_rhs_bgn, pos, cur_name_bgn, cur_name_end, cur_atrs, cur_atrs_idx));
}
xnde_init = true;
}
break;
default:
break;
}
}
return (Html_nde[])rv.XtoAry(Html_nde.class);
}
int cur_lhs_bgn, cur_lhs_end, cur_name_bgn, cur_name_end, cur_rhs_bgn; boolean xnde_init = true, tag_tid_is_inline = false;
private boolean Parse_xnde_rhs() {
cur_rhs_bgn = pos - 1; // -1 b/c "<" is already read
byte b = src[pos];
if (b != Byte_ascii.Slash) return false;
++pos;
int name_len = cur_name_end - cur_name_bgn;
if (pos + name_len >= end) return false;
if (!Bry_.Match(src, pos, pos + name_len, src, cur_name_bgn, cur_name_end)) return false;
pos += name_len;
if (src[pos] != Byte_ascii.Gt) return false;
++pos;
return true;
}
private boolean Parse_xnde_lhs() {
cur_atrs_idx = 0;
cur_lhs_bgn = pos - 1;
cur_name_bgn = pos;
tag_tid_is_inline = false;
byte rslt = Skip_while_valid(this.bry_atr_key);
if (rslt == Scan_invalid) return false;
cur_name_end = pos;
int key_bgn, key_end, val_bgn, quote_type;
while (true) {
if (pos >= end) return false;
key_bgn = key_end = val_bgn = quote_type = -1;
Skip_ws();
byte b = src[pos];
if (b == Byte_ascii.Slash) {
++pos;
if (pos == end) return false;
byte next = src[pos];
if (next == Byte_ascii.Gt) {
tag_tid_is_inline = true;
++pos;
break;
}
else return false; // NOTE: don't consume byte b/c false
}
else if (b == Byte_ascii.Gt) {
++pos;
break;
}
key_bgn = pos;
rslt = Skip_while_valid(this.bry_atr_key);
if (rslt == Scan_invalid) return false;
key_end = pos;
Skip_ws();
if (src[pos++] != Byte_ascii.Eq) return false;
Skip_ws();
byte quote_byte = src[pos];
switch (quote_byte) {
case Byte_ascii.Quote: quote_type = quote_byte; break;
case Byte_ascii.Apos: quote_type = quote_byte; break;
default: return false;
}
val_bgn = ++pos; // ++pos: start val after quote
if (!Skip_to_quote_end(quote_byte)) return false;
cur_atrs[cur_atrs_idx + 0] = quote_type;
cur_atrs[cur_atrs_idx + 1] = key_bgn;
cur_atrs[cur_atrs_idx + 2] = key_end;
cur_atrs[cur_atrs_idx + 3] = val_bgn;
cur_atrs[cur_atrs_idx + 4] = pos - 1; // NOTE: Skip_to_quote_end positions after quote
cur_atrs_idx += 5;
}
cur_lhs_end = pos;
return true;
}
private void Skip_ws() {
while (pos < end) {
switch (src[pos]) {
case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.NewLine: case Byte_ascii.CarriageReturn:
++pos;
break;
default:
return;
}
}
}
boolean Skip_to_quote_end(byte v) {
while (pos < end) {
byte b = src[pos++];
if (b == v) {
if (pos == end) return false;
byte next = src[pos];
if (next != v) return true;
else ++pos;
}
else if (b == Byte_ascii.Backslash) {
++pos;
}
}
return false;
}
byte Skip_while_valid(byte[] comp) {
while (pos < end) {
byte rv = comp[src[pos]];
if (rv == Scan_valid)
++pos;
else
return rv;
}
return Scan_invalid;
}
private static final byte Scan_invalid = 0, Scan_valid = 1, Scan_stop = 2;
public static final byte[] Wildcard = null;
public static final String Wildcard_str = null;
}

View File

@@ -0,0 +1,53 @@
/*
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.html; import gplx.*;
import org.junit.*;
public class Html_parser_tst {
@Before public void init() {fxt.Clear();} private Xoh_parser_fxt fxt = new Xoh_parser_fxt();
@Test public void One() {fxt.Test_parse_find_all("<a id='id0'></a>", "id0");}
@Test public void Many() {fxt.Test_parse_find_all("<a id='id0'></a><a id='id1'></a><a id='id2'></a>", "id0", "id1", "id2");}
@Test public void Inline() {fxt.Test_parse_find_all("<a id='id0'/>", "id0");}
@Test public void Mix() {fxt.Test_parse_find_all("012<a id='id0'></a>id=id2<a id='id1'/>345<a id='id2'></a>abc", "id0", "id1", "id2");}
@Test public void Quote_double() {fxt.Test_parse_find_all("<a id='id''0'/>", "id'0");}
@Test public void Quote_escape() {fxt.Test_parse_find_all("<a id='id\\'0'/>", "id'0");}
}
class Xoh_parser_fxt {
public void Clear() {
if (parser == null) {
parser = new Html_parser();
}
} private Html_parser parser;
public Xoh_parser_fxt Test_parse_find_all(String raw_str, String... expd) {return Test_parse_find(raw_str, Html_parser.Wildcard_str, Html_parser.Wildcard_str, expd);}
public Xoh_parser_fxt Test_parse_find(String raw_str, String find_key, String find_val, String... expd) {
byte[] raw = Bry_.new_ascii_(raw_str);
Html_nde[] actl_ndes = parser.Parse_as_ary(raw, 0, raw.length, Bry_.new_ascii_(find_key), Bry_.new_ascii_(find_val));
String[] actl = Xto_ids(raw, actl_ndes);
Tfds.Eq_ary_str(expd, actl);
return this;
}
private String[] Xto_ids(byte[] src, Html_nde[] ary) {
int len = ary.length;
String[] rv = new String[len];
for (int i = 0; i < len; i++) {
Html_nde itm = ary[i];
String atr_val = itm.Atrs_val_by_key_str("id");
rv[i] = atr_val;
}
return rv;
}
}

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.html; import gplx.*;
public class Html_selecter {
public static Html_nde[] Select(byte[] src, Html_nde[] ary, Hash_adp_bry hash) {
ListAdp list = ListAdp_.new_();
int xndes_len = ary.length;
for (int i = 0; i < xndes_len; i++) {
Html_nde hnde = ary[i];
int[] atrs = hnde.Atrs();
int atrs_len = atrs.length;
for (int j = 0; j < atrs_len; j += 5) {
int atr_key_bgn = atrs[j + 1];
int atr_key_end = atrs[j + 2];
if (hash.Get_by_mid(src, atr_key_bgn, atr_key_end) != null) {
list.Add(hnde);
break;
}
}
}
Html_nde[] rv = (Html_nde[])list.XtoAry(Html_nde.class);
list.Clear();
return rv;
}
}

View File

@@ -0,0 +1,36 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.html; import gplx.*;
public class Html_tags {
public static final String
A_str = "a"
, Img_str = "img"
;
public static final byte[]
Body_lhs = Bry_.new_ascii_("<body>")
, Body_rhs = Bry_.new_ascii_("</body>")
, Html_rhs = Bry_.new_ascii_("</html>")
, Head_lhs_bgn = Bry_.new_ascii_("<head")
, Head_rhs = Bry_.new_ascii_("</head>")
, Style_lhs_w_type = Bry_.new_ascii_("<style type=\"text/css\">")
, Style_rhs = Bry_.new_ascii_("</style>")
, Script_lhs = Bry_.new_ascii_("<script>")
, Script_lhs_w_type = Bry_.new_ascii_("<script type='text/javascript'>")
, Script_rhs = Bry_.new_ascii_("</script>")
;
}

View File

@@ -0,0 +1,167 @@
/*
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.html; import gplx.*;
public class Html_utl {
public static byte[] Escape_for_atr_val_as_bry(String s, byte quote_byte) {
Bry_bfr tmp_bfr = null;
if (s == null) return null;
byte[] bry = Bry_.new_utf8_(s);
boolean dirty = false;
int len = bry.length;
for (int i = 0; i < len; i++) {
byte b = bry[i];
if (b == quote_byte) {
if (!dirty) {
tmp_bfr = Bry_bfr.reset_(256);
tmp_bfr.Add_mid(bry, 0, i);
dirty = true;
}
switch (quote_byte) {
case Byte_ascii.Apos: tmp_bfr.Add(Html_consts.Apos); break;
case Byte_ascii.Quote: tmp_bfr.Add(Html_consts.Quote); break;
default: throw Err_.unhandled(quote_byte);
}
}
else {
if (dirty)
tmp_bfr.Add_byte(b);
}
}
return dirty ? tmp_bfr.XtoAryAndClear() : bry;
}
public static String Escape_html_as_str(String v) {return String_.new_utf8_(Escape_html_as_bry(Bry_.new_utf8_(v)));}
public static byte[] Escape_html_as_bry(Bry_bfr tmp, byte[] bry) {return Escape_html(false, tmp, bry, 0, bry.length, true, true, true, true, true);}
public static byte[] Escape_html_as_bry(byte[] bry) {return Escape_html(false, Bry_bfr.new_(), bry, 0, bry.length, true, true, true, true, true);}
public static byte[] Escape_html_as_bry(byte[] bry, boolean lt, boolean gt, boolean amp, boolean quote, boolean apos)
{return Escape_html(false, Bry_bfr.new_(), bry, 0, bry.length, lt, gt, amp, quote, apos);}
public static void Escape_html_to_bfr(Bry_bfr bfr, byte[] bry, int bgn, int end, boolean escape_lt, boolean escape_gt, boolean escape_amp, boolean escape_quote, boolean escape_apos) {
Escape_html(true, bfr, bry, bgn, end, escape_lt, escape_gt, escape_amp, escape_quote, escape_apos);
}
private static byte[] Escape_html(boolean write_to_bfr, Bry_bfr bfr, byte[] bry, int bgn, int end, boolean escape_lt, boolean escape_gt, boolean escape_amp, boolean escape_quote, boolean escape_apos) {
if (bry == null) return null;
boolean dirty = write_to_bfr ? true : false; // if write_to_bfr, then mark true, else bfr.Add_mid(bry, 0, i); will write whole bry again
byte[] escaped = null;
for (int i = bgn; i < end; i++) {
byte b = bry[i];
switch (b) {
case Byte_ascii.Lt: if (escape_lt) escaped = Html_consts.Lt; break;
case Byte_ascii.Gt: if (escape_gt) escaped = Html_consts.Gt; break;
case Byte_ascii.Amp: if (escape_amp) escaped = Html_consts.Amp; break;
case Byte_ascii.Quote: if (escape_quote) escaped = Html_consts.Quote; break;
case Byte_ascii.Apos: if (escape_apos) escaped = Html_consts.Apos; break;
default:
if (dirty || write_to_bfr)
bfr.Add_byte(b);
continue;
}
// handle lt, gt, amp, quote; everything else handled by default: continue above
if (escaped == null) { // handle do-not-escape calls; EX: Escape(y, y, n, y);
if (dirty || write_to_bfr)
bfr.Add_byte(b);
}
else {
if (!dirty) {
bfr.Add_mid(bry, bgn, i);
dirty = true;
}
bfr.Add(escaped);
escaped = null;
}
}
if (write_to_bfr)
return null;
else
return dirty ? bfr.XtoAryAndClear() : bry;
}
private static final ByteTrieMgr_slim unescape_trie = ByteTrieMgr_slim.ci_ascii_()
.Add_bry_bval(Html_consts.Lt , Byte_ascii.Lt)
.Add_bry_bval(Html_consts.Gt , Byte_ascii.Gt)
.Add_bry_bval(Html_consts.Amp , Byte_ascii.Amp)
.Add_bry_bval(Html_consts.Quote , Byte_ascii.Quote)
.Add_bry_bval(Html_consts.Apos , Byte_ascii.Apos)
;
public static String Unescape_as_str(String src) {
Bry_bfr bfr = Bry_bfr.reset_(255);
byte[] bry = Bry_.new_utf8_(src);
Unescape(Bool_.Y, bfr, bry, 0, bry.length, Bool_.Y, Bool_.Y, Bool_.Y, Bool_.Y, Bool_.Y);
return bfr.XtoStrAndClear();
}
public static byte[] Unescape(boolean write_to_bfr, Bry_bfr bfr, byte[] bry, int bgn, int end, boolean escape_lt, boolean escape_gt, boolean escape_amp, boolean escape_quote, boolean escape_apos) {
if (bry == null) return null;
boolean dirty = write_to_bfr ? true : false; // if write_to_bfr, then mark true, else bfr.Add_mid(bry, 0, i); will write whole bry again
int pos = bgn;
while (pos < end) {
byte b = bry[pos];
Object o = unescape_trie.Match(b, bry, pos, end);
if (o == null) {
if (dirty || write_to_bfr)
bfr.Add_byte(b);
++pos;
}
else {
Byte_obj_val unescaped_bval = (Byte_obj_val)o;
byte unescaped_byte = unescaped_bval.Val();
boolean unescape = false;
switch (unescaped_byte) {
case Byte_ascii.Lt: if (escape_lt) unescape = true; break;
case Byte_ascii.Gt: if (escape_gt) unescape = true; break;
case Byte_ascii.Amp: if (escape_amp) unescape = true; break;
case Byte_ascii.Quote: if (escape_quote) unescape = true; break;
case Byte_ascii.Apos: if (escape_apos) unescape = true; break;
}
if (unescape) {
if (!dirty) {
bfr.Add_mid(bry, bgn, pos);
dirty = true;
}
bfr.Add_byte(unescaped_byte);
}
else {
if (dirty || write_to_bfr)
bfr.Add_byte(b);
}
pos = unescape_trie.Match_pos();
}
}
if (write_to_bfr)
return null;
else
return dirty ? bfr.XtoAryAndClear() : bry;
}
public static byte[] Del_comments(Bry_bfr bfr, byte[] src) {return Del_comments(bfr, src, 0, src.length);}
public static byte[] Del_comments(Bry_bfr bfr, byte[] src, int pos, int end) {
while (true) {
if (pos >= end) break;
int comm_bgn = Bry_finder.Find_fwd(src, Html_consts.Comm_bgn, pos); // look for <!--
if (comm_bgn == Bry_finder.Not_found) { // not found; consume rest
bfr.Add_mid(src, pos, end);
break;
}
int comm_end = Bry_finder.Find_fwd(src, Html_consts.Comm_end, comm_bgn + Html_consts.Comm_bgn_len); // look for -->
if (comm_end == Bry_finder.Not_found) { // not found; consume rest
bfr.Add_mid(src, pos, end);
break;
}
bfr.Add_mid(src, pos, comm_bgn); // add everything between pos and comm_bgn
pos = comm_end + Html_consts.Comm_end_len; // reposition pos after comm_end
}
return bfr.XtoAryAndClear();
}
}

View File

@@ -0,0 +1,62 @@
/*
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.html; import gplx.*;
import org.junit.*;
public class Html_utl_tst {
@Before public void init() {fxt.Clear();} private Html_utl_fxt fxt = new Html_utl_fxt();
@Test public void Basic() {fxt.Test_del_comments("a<!-- b -->c" , "ac");}
@Test public void Bgn_missing() {fxt.Test_del_comments("a b c" , "a b c");}
@Test public void End_missing() {fxt.Test_del_comments("a<!-- b c" , "a<!-- b c");}
@Test public void Multiple() {fxt.Test_del_comments("a<!--b-->c<!--d-->e" , "ace");}
@Test public void Escape() {
fxt.Test_escape_html(Bool_.Y, Bool_.Y, Bool_.Y, Bool_.Y, Bool_.Y, "a<b" , "a&lt;b"); // basic
fxt.Test_escape_html(Bool_.Y, Bool_.Y, Bool_.N, Bool_.Y, Bool_.Y, "a<&b" , "a&lt;&b"); // fix: & not escaped when <> present
fxt.Test_escape_html(Bool_.Y, Bool_.Y, Bool_.Y, Bool_.Y, Bool_.Y, "a<>'&\"b" , "a&lt;&gt;&#39;&amp;&quot;b");
}
@Test public void Escape_for_atr_val() {
fxt.Test_escape_for_atr("abc" , Bool_.N, "abc"); // basic
fxt.Test_escape_for_atr("a'\"b" , Bool_.Y, "a&#39;\"b"); // quote is '
fxt.Test_escape_for_atr("a'\"b" , Bool_.N, "a'&quot;b"); // quote is "
}
@Test public void Unescape() {
fxt.Test_unescape_html(Bool_.Y, Bool_.Y, Bool_.Y, Bool_.Y, Bool_.Y, "a&lt;&gt;&#39;&amp;&quot;b" , "a<>'&\"b"); // basic
}
}
class Html_utl_fxt {
private Bry_bfr tmp_bfr = Bry_bfr.reset_(255);
public void Clear() {
tmp_bfr.Clear();
}
public void Test_del_comments(String src, String expd) {
byte[] actl = Html_utl.Del_comments(tmp_bfr, Bry_.new_utf8_(src));
Tfds.Eq(expd, String_.new_ascii_(actl));
}
public void Test_escape_html(boolean lt, boolean gt, boolean amp, boolean quote, boolean apos, String src, String expd) {
byte[] actl = Html_utl.Escape_html_as_bry(Bry_.new_ascii_(src), lt, gt, amp, quote, apos);
Tfds.Eq(expd, String_.new_ascii_(actl));
}
public void Test_escape_for_atr(String src, boolean quote_is_apos, String expd) {
byte[] actl = Html_utl.Escape_for_atr_val_as_bry(src, quote_is_apos ? Byte_ascii.Apos : Byte_ascii.Quote);
Tfds.Eq(expd, String_.new_utf8_(actl));
}
public void Test_unescape_html(boolean lt, boolean gt, boolean amp, boolean quote, boolean apos, String src, String expd) {
byte[] bry = Bry_.new_utf8_(src);
byte[] actl = Html_utl.Unescape(false, tmp_bfr, bry, 0, bry.length, lt, gt, amp, quote, apos);
Tfds.Eq(expd, String_.new_ascii_(actl));
}
}

View File

@@ -0,0 +1,98 @@
/*
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.html; import gplx.*;
public class Html_wtr {
private Bry_bfr bfr = Bry_bfr.reset_(255);
private ListAdp nde_stack = ListAdp_.new_();
public byte Atr_quote() {return atr_quote;} public Html_wtr Atr_quote_(byte v) {atr_quote = v; return this;} private byte atr_quote = Byte_ascii.Quote;
public Html_wtr Nde_full_atrs(byte[] tag, byte[] text, boolean text_escape, byte[]... atrs) {
Nde_bgn(tag);
int atrs_len = atrs.length;
for (int i = 0; i < atrs_len; i += 2) {
byte[] key = atrs[i];
byte[] val = atrs[i + 1];
Atr(key, val);
}
Nde_end_hdr();
if (text_escape)
Txt(text);
else
bfr.Add(text);
Nde_end();
return this;
}
public Html_wtr Nde_full(byte[] tag, byte[] text) {
Nde_bgn_hdr(tag);
Txt(text);
Nde_end();
return this;
}
public Html_wtr Txt_mid(byte[] src, int bgn, int end) {bfr.Add_mid(src, bgn, end); return this;}
public Html_wtr Txt_byte(byte v) {bfr.Add_byte(v); return this;}
public Html_wtr Txt_raw(byte[] v) {bfr.Add(v); return this;}
public Html_wtr Txt(byte[] v) {
if (v != null) {
bfr.Add(Html_utl.Escape_html_as_bry(v));
}
return this;
}
public Html_wtr Nde_bgn_hdr(byte[] name) {
this.Nde_bgn(name);
this.Nde_end_hdr();
return this;
}
public Html_wtr Nde_bgn(byte[] name) {
bfr.Add_byte(Byte_ascii.Lt);
bfr.Add(name);
nde_stack.Add(name);
return this;
}
public Html_wtr Atr(byte[] key, byte[] val) {
Write_atr(bfr, atr_quote, key, val);
return this;
}
public Html_wtr Nde_end_inline() {
bfr.Add_byte(Byte_ascii.Slash).Add_byte(Byte_ascii.Gt);
nde_stack.PopLast();
return this;
}
public Html_wtr Nde_end_hdr() {
bfr.Add_byte(Byte_ascii.Gt);
return this;
}
public Html_wtr Nde_end() {
byte[] name = (byte[])nde_stack.PopLast();
bfr.Add_byte(Byte_ascii.Lt).Add_byte(Byte_ascii.Slash);
bfr.Add(name);
bfr.Add_byte(Byte_ascii.Gt);
return this;
}
public byte[] X_to_bry_and_clear() {return bfr.XtoAryAndClear();}
public byte[] X_to_bry() {return bfr.XtoAry();}
public String X_to_str() {return bfr.XtoStr();}
public static void Write_atr(Bry_bfr bfr, byte[] key, byte[] val) {Write_atr(bfr, Byte_ascii.Quote, key, val);}
public static void Write_atr(Bry_bfr bfr, byte atr_quote, byte[] key, byte[] val) {
if (Bry_.Len_eq_0(val)) return; // don't write empty
bfr.Add_byte_space();
bfr.Add(key);
bfr.Add_byte(Byte_ascii.Eq);
bfr.Add_byte(atr_quote);
Html_utl.Escape_html_to_bfr(bfr, val, 0, val.length, false, false, false, true, true);
bfr.Add_byte(atr_quote);
}
}

View File

@@ -0,0 +1,66 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.ios; import gplx.*;
import java.io.InputStream;
public class Io_stream_rdr_process implements Io_stream_rdr {
private Process process;
private InputStream stream_read;
private String[] process_args;
Io_stream_rdr_process(Io_url process_exe, Io_url stream_url, String[] process_args) {this.process_exe = process_exe; this.url = stream_url; this.process_args = process_args;}
public byte Tid() {return Io_stream_.Tid_bzip2;} // for now, classify as bzip2; not sure if separate tid is necessary
public Io_url Url() {return url;} public Io_stream_rdr Url_(Io_url v) {url = v; return this;} private Io_url url;
public long Len() {return len;} public Io_stream_rdr Len_(long v) {len = v; return this;} private long len;
public Io_url Process_exe() {return process_exe;} private Io_url process_exe;
public Io_stream_rdr Open() {
ProcessBuilder pb = new ProcessBuilder(process_args);
pb.redirectErrorStream(false);
try {process = pb.start();}
catch (Exception e) {throw Err_.err_(e, "process init failed: {0} {1}", String_.AryXtoStr(process_args), Err_.Message_gplx_brief(e));}
stream_read = process.getInputStream();
return this;
}
public void Open_mem(byte[] v) {throw Err_.not_implemented_();}
public Object Under() {throw Err_.not_implemented_();}
public int Read(byte[] bry, int bgn, int len) {
try {
int rv = 0;
int cur_pos = bgn;
int cur_len = len;
while (true) {
int read = stream_read.read(bry, cur_pos, cur_len);
if (read <= 0) break;
rv += read;
cur_pos += read;
cur_len -= read;
if (rv >= len) break;
}
return rv;
} catch (Exception e) {throw Err_.err_(e, "process read failed: bgn={0} len={1} err={2}", bgn, len, Err_.Message_gplx_brief(e));}
}
public long Skip(long len) {
try {return stream_read.skip(len);}
catch (Exception e) {throw Err_.err_(e, "process skip failed: len={0} err={1}", len, Err_.Message_gplx_brief(e));}
}
public void Rls() {
try {stream_read.close();}
catch (Exception e) {throw Err_.err_(e, "process rls failed: err={0}", Err_.Message_gplx_brief(e));}
process.destroy();
}
public static Io_stream_rdr_process new_(Io_url process_exe, Io_url stream_url, String... process_args) {return new Io_stream_rdr_process(process_exe, stream_url, process_args);}
}

View File

@@ -0,0 +1,54 @@
/*
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.ios; import gplx.*;
public class Io_stream_zip_mgr {
private Bry_bfr bfr = Bry_bfr.reset_(256);
private Io_stream_wtr wtr_gzip, wtr_zip, wtr_bzip2;
private Io_stream_rdr rdr_gzip, rdr_zip, rdr_bzip2;
public byte[] Zip(byte type, byte[] val) {
if (type == Io_stream_.Tid_file) return val;
Io_stream_wtr wtr = Wtr(type);
wtr.Write(val, 0, val.length);
wtr.Flush();
return wtr.Xto_ary_and_clear();
}
public byte[] Unzip(byte type, byte[] val) {
if (type == Io_stream_.Tid_file) return val;
Io_stream_rdr rdr = Rdr(type);
rdr.Open_mem(val);
return Io_stream_rdr_.Load_all_as_bry(bfr, rdr);
}
private Io_stream_wtr Wtr(byte type) {
switch (type) {
case Io_stream_.Tid_gzip : if (wtr_gzip == null) wtr_gzip = Io_stream_wtr_.new_by_mem(bfr, Io_stream_.Tid_gzip) ; return wtr_gzip.Open();
case Io_stream_.Tid_zip : if (wtr_zip == null) wtr_zip = Io_stream_wtr_.new_by_mem(bfr, Io_stream_.Tid_zip) ; return wtr_zip.Open();
case Io_stream_.Tid_bzip2 : if (wtr_bzip2 == null) wtr_bzip2 = Io_stream_wtr_.new_by_mem(bfr, Io_stream_.Tid_bzip2) ; return wtr_bzip2.Open();
case Io_stream_.Tid_file :
default : throw Err_.unhandled(type);
}
}
private Io_stream_rdr Rdr(byte type) {
switch (type) {
case Io_stream_.Tid_gzip : if (rdr_gzip == null) rdr_gzip = Io_stream_rdr_.new_by_tid_(Io_stream_.Tid_gzip) ; return rdr_gzip;
case Io_stream_.Tid_zip : if (rdr_zip == null) rdr_zip = Io_stream_rdr_.new_by_tid_(Io_stream_.Tid_zip) ; return rdr_zip;
case Io_stream_.Tid_bzip2 : if (rdr_bzip2 == null) rdr_bzip2 = Io_stream_rdr_.new_by_tid_(Io_stream_.Tid_bzip2) ; return rdr_bzip2;
case Io_stream_.Tid_file :
default : throw Err_.unhandled(type);
}
}
}

View File

@@ -0,0 +1,65 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.json; import gplx.*;
public class Json_doc {
public void Ctor(byte[] src, Json_itm_nde root) {this.src = src; this.root = root;}
public Bry_bfr Bfr() {return bfr;} Bry_bfr bfr = Bry_bfr.new_();
public NumberParser Utl_num_parser() {return utl_num_parser;} NumberParser utl_num_parser = new NumberParser();
public byte[] Str_utf8_bry() {return str_utf8_bry;} private byte[] str_utf8_bry = new byte[6];
public byte[] Src() {return src;} private byte[] src;
public Json_itm_nde Root() {return root;} Json_itm_nde root;
public byte[] Get_val_as_bry_or(byte[] qry_bry, byte[] or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_bry_or(tmp_qry_bry, or);}
public byte[] Get_val_as_bry_or(byte[][] qry_bry, byte[] or) {
Json_itm nde = Find_nde(root, qry_bry, qry_bry.length - 1, 0);
return nde == null || nde.Tid() != Json_itm_.Tid_string ? or : nde.Data_bry();
}
public String Get_val_as_str_or(byte[] qry_bry, String or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_str_or(tmp_qry_bry, or);}
public String Get_val_as_str_or(byte[][] qry_bry, String or) {
Json_itm nde = Find_nde(root, qry_bry, qry_bry.length - 1, 0);
return nde == null || nde.Tid() != Json_itm_.Tid_string ? or : (String)nde.Data();
}
public Json_grp Get_grp(byte[] qry_bry) {
tmp_qry_bry[0] = qry_bry;
Json_itm rv = Find_nde(root, tmp_qry_bry, 0, 0); if (rv == null) return null;
return (Json_grp)rv;
} byte[][] tmp_qry_bry = new byte[1][];
public Json_grp Get_grp(byte[][] qry_bry) {
Json_itm rv = Find_nde(root, qry_bry, qry_bry.length - 1, 0); if (rv == null) return null;
return (Json_grp)rv;
}
public Json_itm Find_nde(byte[] key) {
tmp_qry_bry[0] = key;
return Find_nde(root, tmp_qry_bry, 0, 0);
}
private Json_itm Find_nde(Json_itm_nde owner, byte[][] paths, int paths_last, int paths_idx) {
byte[] path = paths[paths_idx];
int subs_len = owner.Subs_len();
for (int i = 0; i < subs_len; i++) {
Json_itm_kv itm = Json_itm_kv.cast_(owner.Subs_get_at(i)); if (itm == null) continue; // ignore simple props, arrays, ndes
if (!itm.Key_eq(path)) continue;
if (paths_idx == paths_last) return itm.Val();
Json_itm_nde sub_nde = Json_itm_nde.cast_(itm.Val()); if (sub_nde == null) return null; // match, but has not a nde; exit
return Find_nde(sub_nde, paths, paths_last, paths_idx + 1);
}
return null;
}
public static Json_doc new_apos_concat_nl(String... ary) {return new_apos_(String_.Concat_lines_nl(ary));}
public static Json_doc new_apos_(String v) {return new_(Bry_.Replace(Bry_.new_utf8_(v), Byte_ascii.Apos, Byte_ascii.Quote));}
public static Json_doc new_(String v) {return new_(Bry_.new_utf8_(v));}
public static Json_doc new_(byte[] v) {return parser.Parse(v);} static Json_parser parser = new Json_parser();
}

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.json; import gplx.*;
public class Json_doc_bldr {
public Json_itm_nde Nde() {return factory.Nde(-1);}
public Json_itm_nde Nde(Json_grp owner) {
Json_itm_nde rv = factory.Nde(-1);
owner.Subs_add(rv);
return rv;
}
public Json_itm Str(byte[] v) {return Str(String_.new_utf8_(v));}
public Json_itm Str(String v) {return Json_itm_tmp.new_str_(v);}
public Json_itm Int(int v) {return Json_itm_tmp.new_int_(v);}
public Json_itm_kv Kv_int(Json_grp owner, String key, int val) {Json_itm_kv rv = factory.Kv(Json_itm_tmp.new_str_(key), Json_itm_tmp.new_int_(val)); owner.Subs_add(rv); return rv;}
public Json_itm_kv Kv_str(Json_grp owner, String key, String val) {Json_itm_kv rv = factory.Kv(Json_itm_tmp.new_str_(key), Json_itm_tmp.new_str_(val)); owner.Subs_add(rv); return rv;}
public Json_itm_ary Kv_ary(Json_grp owner, String key, Json_itm... subs) {
Json_itm key_itm = Json_itm_tmp.new_str_(key);
Json_itm_ary val_ary = factory.Ary(-1, -1);
Json_itm_kv kv = factory.Kv(key_itm, val_ary);
owner.Subs_add(kv);
int len = subs.length;
for (int i = 0; i < len; i++)
val_ary.Subs_add(subs[i]);
return val_ary;
}
Json_doc doc = new Json_doc(); Json_factory factory = new Json_factory();
}

View File

@@ -0,0 +1,89 @@
/*
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.json; import gplx.*;
public class Json_doc_srl {
private int indent = -1;
private Bry_bfr bfr = Bry_bfr.reset_(255);
public boolean Ws_enabled() {return ws_enabled;} public void Ws_enabled_(boolean v) {ws_enabled = v;} private boolean ws_enabled = false;
public byte[] Bld() {return bfr.XtoAryAndClear();}
public String Bld_as_str() {return bfr.XtoStrAndClear();}
public Json_doc_srl Write_root(byte[] key, Object val) {
Write_nde_bgn();
Write_obj(false, key, val);
Write_nde_end();
return this;
}
public void Write_obj(boolean comma, byte[] key, Object val) {
Class<?> t = ClassAdp_.ClassOf_obj(val);
if (ClassAdp_.Is_array(t))
Write_kv_ary(comma, key, (Object[])val);
else
Write_kv_str(comma, key, Object_.XtoStr_OrEmpty(val));
}
private void Write_kv_ary(boolean comma, byte[] key, Object[] val) {
Write_key(comma, key); Write_new_line(); // '"key":\n'
Write_ary_bgn(); // '[\n'
Indent_add(); // -->
int len = val.length;
for (int i = 0; i < len; i++) {
Write_itm_hdr(i != 0); // ', '
Write_str(Bry_.new_utf8_(Object_.XtoStr_OrNull(val[i])));
Write_new_line();
}
Indent_del();
Write_ary_end();
}
private void Write_kv_str(boolean comma, byte[] key, String val) {
Write_key(comma, key); // "key":
Write_str(Bry_.new_utf8_(val)); // "val"
Write_new_line(); // \n
}
private void Write_key(boolean comma, byte[] key) { // "key":
Write_indent();
Write_str(key);
bfr.Add_byte(Byte_ascii.Colon);
}
private void Write_indent() {if (ws_enabled && indent > 0) bfr.Add_byte_repeat(Byte_ascii.Space, indent);}
private void Write_str(byte[] v) {
if (v == null)
bfr.Add(Bry_null);
else
bfr.Add_byte(Byte_ascii.Quote).Add(v).Add_byte(Byte_ascii.Quote);
} private static final byte[] Bry_null = Bry_.new_ascii_("null");
private void Write_comma(boolean comma) {
if (comma)
bfr.Add_byte(Byte_ascii.Comma);
else {
if (ws_enabled)
bfr.Add_byte(Byte_ascii.Space);
}
if (ws_enabled)
bfr.Add_byte(Byte_ascii.Space);
}
private void Write_ary_bgn() {Indent_add(); Write_indent(); bfr.Add_byte(Byte_ascii.Brack_bgn); Write_new_line();}
private void Write_ary_end() { Write_indent(); bfr.Add_byte(Byte_ascii.Brack_end); Write_new_line(); Indent_del();}
private void Write_nde_bgn() {Indent_add(); Write_indent(); bfr.Add_byte(Byte_ascii.Curly_bgn); Write_new_line();}
private void Write_nde_end() { Write_indent(); bfr.Add_byte(Byte_ascii.Curly_end); Write_new_line(); Indent_del();}
private void Write_itm_hdr(boolean comma) {
Write_indent();
Write_comma(comma);
}
private void Indent_add() {indent += 2;}
private void Indent_del() {indent -= 2;}
private void Write_new_line() {if (ws_enabled) bfr.Add_byte_nl();}
}

View File

@@ -0,0 +1,45 @@
/*
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.json; import gplx.*;
import org.junit.*;
public class Json_doc_tst {
Json_qry_mgr_fxt fxt = new Json_qry_mgr_fxt();
@Before public void init() {}
@Test public void Select() {
Json_doc doc = Json_doc.new_apos_(String_.Concat_lines_nl
( "{'0':"
, " {'0_0':"
, " {'0_0_0':'000'"
, " },"
, " '0_1':"
, " {'0_1_0':'010'"
, " }"
, " }"
, "}"
));
fxt.Test_get_val_as_str(doc, "0/0_0/0_0_0", "000");
fxt.Test_get_val_as_str(doc, "0/0_1/0_1_0", "010");
fxt.Test_get_val_as_str(doc, "x", null);
}
}
class Json_qry_mgr_fxt {
public void Test_get_val_as_str(Json_doc doc, String qry, String expd){
byte[][] qry_bry = Bry_.Split(Bry_.new_utf8_(qry), Byte_ascii.Slash);
Tfds.Eq(expd, doc.Get_val_as_str_or(qry_bry, null));
}
}

View File

@@ -0,0 +1,98 @@
/*
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.json; import gplx.*;
public class Json_doc_wtr {
private int indent = -2;
private Bry_bfr bfr = Bry_bfr.reset_(255);
public Json_doc_wtr Indent() {return Indent(indent);}
private Json_doc_wtr Indent(int v) {if (v > 0) bfr.Add_byte_repeat(Byte_ascii.Space, v); return this;}
public Json_doc_wtr Indent_add() {indent += 2; return this;}
public Json_doc_wtr Indent_del() {indent -= 2; return this;}
public Json_doc_wtr Nde_bgn() {Indent_add(); Indent(); bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte_nl(); return this;}
public Json_doc_wtr Nde_end() { Indent(); bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl(); Indent_del(); return this;}
public Json_doc_wtr Ary_bgn() {Indent_add(); Indent(); bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte_nl(); return this;}
public Json_doc_wtr Ary_end() { Indent(); bfr.Add_byte(Byte_ascii.Brack_end).Add_byte_nl(); Indent_del(); return this;}
public Json_doc_wtr New_line() {bfr.Add_byte_nl(); return this;}
public Json_doc_wtr Str(byte[] v) {
if (v == null)
bfr.Add(Bry_null);
else
bfr.Add_byte(Byte_ascii.Quote).Add(v).Add_byte(Byte_ascii.Quote);
return this;
} private static final byte[] Bry_null = Bry_.new_ascii_("null");
public Json_doc_wtr Int(int v) {bfr.Add_int_variable(v); return this;}
public Json_doc_wtr Double(double v) {bfr.Add_double(v); return this;}
public Json_doc_wtr Comma() {Indent(); bfr.Add_byte(Byte_ascii.Comma).Add_byte_nl(); return this;}
public Json_doc_wtr Kv_ary_empty(boolean comma, byte[] key) {
Key_internal(comma, key);
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Brack_end);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Kv(boolean comma, byte[] key, byte[] val) {
Key_internal(comma, key);
Str(val);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Kv_double(boolean comma, byte[] key, double v) {
Key_internal(comma, key);
Double(v);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Kv(boolean comma, byte[] key, int v) {
Key_internal(comma, key);
Int(v);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Key(boolean comma, byte[] key) {
Key_internal(comma, key);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Val(boolean comma, int v) {
Val_internal(comma);
Int(v);
New_line();
return this;
}
public Json_doc_wtr Val(boolean comma, byte[] v) {
Val_internal(comma);
Str(v);
New_line();
return this;
}
Json_doc_wtr Val_internal(boolean comma) {
Indent();
bfr.Add_byte(comma ? Byte_ascii.Comma : Byte_ascii.Space);
bfr.Add_byte(Byte_ascii.Space);
return this;
}
Json_doc_wtr Key_internal(boolean comma, byte[] key) {
Indent();
bfr.Add_byte(comma ? Byte_ascii.Comma : Byte_ascii.Space);
bfr.Add_byte(Byte_ascii.Space);
Str(key);
bfr.Add_byte(Byte_ascii.Colon);
return this;
}
public byte[] Bld() {return bfr.XtoAryAndClear();}
public String Bld_as_str() {return bfr.XtoStrAndClear();}
}

View File

@@ -0,0 +1,29 @@
/*
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.json; import gplx.*;
public class Json_factory {
public Json_itm Null() {return Json_itm_null.Null;}
public Json_itm Bool_n() {return Json_itm_bool.Bool_n;}
public Json_itm Bool_y() {return Json_itm_bool.Bool_y;}
public Json_itm_int Int(Json_doc doc, int bgn, int end) {return new Json_itm_int(doc, bgn, end);}
public Json_itm Decimal(Json_doc doc, int bgn, int end) {return new Json_itm_decimal(doc, bgn, end);}
public Json_itm Str(Json_doc doc, int bgn, int end, boolean exact) {return new Json_itm_str(doc, bgn, end, exact);}
public Json_itm_kv Kv(Json_itm key, Json_itm val) {return new Json_itm_kv(key, val);}
public Json_itm_ary Ary(int bgn, int end) {return new Json_itm_ary(bgn, end);}
public Json_itm_nde Nde(int bgn) {return new Json_itm_nde(bgn);}
}

View File

@@ -0,0 +1,34 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.json; import gplx.*;
public interface Json_grp extends Json_itm {
void Src_end_(int v);
int Subs_len();
Json_itm Subs_get_at(int i);
void Subs_add(Json_itm itm);
}
class Json_grp_ {
public static final Json_grp[] Ary_empty = new Json_grp[0];
public static void Print_nl(Bry_bfr bfr) { // \n\n can be caused by nested groups (EX: "[[]]"); only print 1
if (bfr.Bfr()[bfr.Len() - 1] != Byte_ascii.NewLine)
bfr.Add_byte_nl();
}
public static void Print_indent(Bry_bfr bfr, int depth) {
if (depth > 0) bfr.Add_byte_repeat(Byte_ascii.Space, depth * 2); // indent
}
}

View File

@@ -0,0 +1,116 @@
/*
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.json; import gplx.*;
public interface Json_itm {
byte Tid();
int Src_bgn();
int Src_end();
Object Data();
byte[] Data_bry();
void Print_as_json(Bry_bfr bfr, int depth);
boolean Data_eq(byte[] comp);
}
class Json_itm_null extends Json_itm_base {
Json_itm_null() {this.Ctor(-1, -1);}
@Override public byte Tid() {return Json_itm_.Tid_null;}
@Override public Object Data() {return null;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add(Bry_null);}
@Override public byte[] Data_bry() {return Bry_null;}
private static final byte[] Bry_null = Bry_.new_ascii_("null");
public static Json_itm_null Null = new Json_itm_null();
}
class Json_itm_bool extends Json_itm_base {
public Json_itm_bool(boolean data) {this.data = data; this.Ctor(-1, -1);} private boolean data;
@Override public byte Tid() {return Json_itm_.Tid_bool;}
@Override public Object Data() {return data;}
@Override public byte[] Data_bry() {return data ? Json_itm_.Const_true : Json_itm_.Const_false;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add(data ? Json_itm_.Const_true: Json_itm_.Const_false);}
public static Json_itm_bool Bool_n = new Json_itm_bool(false), Bool_y = new Json_itm_bool(true);
}
class Json_itm_decimal extends Json_itm_base {
public Json_itm_decimal(Json_doc doc, int src_bgn, int src_end) {this.Ctor(src_bgn, src_end); this.doc = doc;} Json_doc doc;
@Override public byte Tid() {return Json_itm_.Tid_decimal;}
@Override public Object Data() {
if (data == null)
data = DecimalAdp_.parse_(String_.new_ascii_(this.Data_bry()));
return data;
} DecimalAdp data;
@Override public byte[] Data_bry() {
if (data_bry == null) data_bry = Bry_.Mid(doc.Src(), this.Src_bgn(), this.Src_end());
return data_bry;
} byte[] data_bry;
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_mid(doc.Src(), this.Src_bgn(), this.Src_end());}
}
class Json_itm_str extends Json_itm_base {
public Json_itm_str(Json_doc doc, int src_bgn, int src_end, boolean exact) {this.Ctor(src_bgn + 1, src_end - 1); this.doc = doc; this.exact = exact;} private boolean exact; Json_doc doc;
@Override public byte Tid() {return Json_itm_.Tid_string;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
bfr.Add_byte(Byte_ascii.Quote);
gplx.html.Html_utl.Escape_html_to_bfr(bfr, doc.Src(), this.Src_bgn(), this.Src_end(), true, true, true, true, false); // false to apos for backwards compatibility
bfr.Add_byte(Byte_ascii.Quote);
}
@Override public Object Data() {
if (data_str == null) {
if (data_bry == null)
data_bry = Data_make_bry();
data_str = String_.new_utf8_(data_bry);
}
return data_str;
} private String data_str;
@Override public byte[] Data_bry() {if (data_bry == null) data_bry = Data_make_bry(); return data_bry;}
@Override public boolean Data_eq(byte[] comp) {
if (exact) return Bry_.Eq(comp, doc.Src(), this.Src_bgn(), this.Src_end());
if (data_bry == null) data_bry = Data_make_bry();
return Bry_.Match(data_bry, comp);
} byte[] data_bry = null;
private byte[] Data_make_bry() {
byte[] src = doc.Src(); int bgn = this.Src_bgn(), end = this.Src_end();
if (exact) return Bry_.Mid(src, bgn, end);
Bry_bfr bfr = doc.Bfr();
byte[] utf8_bry = doc.Str_utf8_bry();
for (int i = bgn; i < end; i++) {
byte b = src[i];
switch (b) {
case Byte_ascii.Backslash:
b = src[++i];
switch (b) { // NOTE: must properly unescape chars; EX:wd.q:2; DATE:2014-04-23
case Byte_ascii.Ltr_t: bfr.Add_byte(Byte_ascii.Tab); break;
case Byte_ascii.Ltr_n: bfr.Add_byte(Byte_ascii.NewLine); break;
case Byte_ascii.Ltr_r: bfr.Add_byte(Byte_ascii.CarriageReturn); break;
case Byte_ascii.Ltr_b: bfr.Add_byte(Byte_ascii.Backfeed); break;
case Byte_ascii.Ltr_f: bfr.Add_byte(Byte_ascii.Formfeed); break;
case Byte_ascii.Ltr_u:
int utf8_val = gplx.texts.HexDecUtl.parse_or_(src, i + 1, i + 5, -1);
int len = gplx.intl.Utf16_.Encode_int(utf8_val, utf8_bry, 0);
bfr.Add_mid(utf8_bry, 0, len);
i += 4;
break; // \uFFFF 4 hex-dec
case Byte_ascii.Backslash:
case Byte_ascii.Slash:
default:
bfr.Add_byte(b); break; // \? " \ / b f n r t
}
break;
default:
bfr.Add_byte(b);
break;
}
}
return bfr.XtoAryAndClear();
}
}

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.json; import gplx.*;
public class Json_itm_ {
public static final Json_itm[] Ary_empty = new Json_itm[0];
public static final byte Tid_unknown = 0, Tid_null = 1, Tid_bool = 2, Tid_int = 3, Tid_decimal = 4, Tid_string = 5, Tid_kv = 6, Tid_array = 7, Tid_nde = 8;
public static final byte[][] Names = Bry_.Ary("unknown", "null", "boolean", "int", "decimal", "string", "keyval", "array", "nde");
public static final byte[] Const_true = Bry_.new_ascii_("true"), Const_false = Bry_.new_ascii_("false"), Const_null = Bry_.new_ascii_("null");
}

View File

@@ -0,0 +1,64 @@
/*
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.json; import gplx.*;
public class Json_itm_ary extends Json_itm_base implements Json_grp {
public Json_itm_ary(int src_bgn, int src_end) {this.Ctor(src_bgn, src_end);}
@Override public byte Tid() {return Json_itm_.Tid_array;}
public void Src_end_(int v) {this.src_end = v;}
@Override public Object Data() {return null;}
@Override public byte[] Data_bry() {return null;}
public int Subs_len() {return subs_len;} private int subs_len = 0, subs_max = 0;
public Json_itm Subs_get_at(int i) {return subs[i];}
public Json_itm_ary Subs_add_many(Json_itm... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
Subs_add(ary[i]);
return this;
}
public void Subs_add(Json_itm itm) {
int new_len = subs_len + 1;
if (new_len > subs_max) { // ary too small >>> expand
subs_max = new_len * 2;
Json_itm[] new_subs = new Json_itm[subs_max];
Array_.CopyTo(subs, 0, new_subs, 0, subs_len);
subs = new_subs;
}
subs[subs_len] = itm;
subs_len = new_len;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
if (subs_len == 0) { // empty grp; print on one line (rather than printing across 3)
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Brack_end);
return;
}
bfr.Add_byte_nl();
Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Space);
for (int i = 0; i < subs_len; i++) {
if (i != 0) {
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
}
subs[i].Print_as_json(bfr, depth + 1);
}
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Brack_end).Add_byte_nl();
}
Json_itm[] subs = Json_itm_.Ary_empty;
public static Json_itm_ary cast_(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid_array ? null : (Json_itm_ary)v;}
}

View File

@@ -0,0 +1,29 @@
/*
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.json; import gplx.*;
public abstract class Json_itm_base implements Json_itm {
public abstract byte Tid();
public void Ctor(int src_bgn, int src_end) {this.src_bgn = src_bgn; this.src_end = src_end;}
public int Src_bgn() {return src_bgn;} private int src_bgn;
public int Src_end() {return src_end;} protected int src_end;
public abstract Object Data();
public abstract byte[] Data_bry();
public String Print_as_json() {Bry_bfr bfr = Bry_bfr.new_(); Print_as_json(bfr, 0); return bfr.XtoStrAndClear();}
public abstract void Print_as_json(Bry_bfr bfr, int depth);
@gplx.Virtual public boolean Data_eq(byte[] comp) {return false;}
}

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.json; import gplx.*;
public class Json_itm_int extends Json_itm_base {
public Json_itm_int(Json_doc doc, int src_bgn, int src_end) {this.Ctor(src_bgn, src_end); this.doc = doc;} Json_doc doc;
@Override public byte Tid() {return Json_itm_.Tid_int;}
public int Data_as_int() {
if (data_is_null) {
data = doc.Utl_num_parser().Parse(doc.Src(), Src_bgn(), Src_end()).AsInt();
data_is_null = false;
}
return data;
}
@Override public Object Data() {return Data_as_int();} int data; boolean data_is_null = true;
@Override public byte[] Data_bry() {if (data_bry == null) data_bry = Bry_.Mid(doc.Src(), this.Src_bgn(), this.Src_end()); return data_bry;} private byte[] data_bry;
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_mid(doc.Src(), this.Src_bgn(), this.Src_end());}
public static Json_itm_int cast_(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid_int ? null : (Json_itm_int)v;}
}

View File

@@ -0,0 +1,35 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.json; import gplx.*;
public class Json_itm_kv extends Json_itm_base {
public Json_itm_kv(Json_itm key, Json_itm val) {this.key = key; this.val = val;}
@Override public byte Tid() {return Json_itm_.Tid_kv;}
public Json_itm Key() {return key;} Json_itm key;
public Json_itm Val() {return val;} Json_itm val;
public String Key_as_str() {return (String)key.Data();}
public boolean Key_eq(byte[] comp) {return ((Json_itm_str)key).Data_eq(comp);}
@Override public Object Data() {return null;}
@Override public byte[] Data_bry() {return null;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
key.Print_as_json(bfr, depth);
bfr.Add_byte(Byte_ascii.Colon);
val.Print_as_json(bfr, depth);
}
public static final Json_itm_kv[] Ary_empty = new Json_itm_kv[0];
public static Json_itm_kv cast_(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid_kv ? null : (Json_itm_kv)v;}
}

View File

@@ -0,0 +1,72 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.json; import gplx.*;
public class Json_itm_nde extends Json_itm_base implements Json_grp {
public Json_itm_nde(int src_bgn) {this.Ctor(src_bgn, -1);}
@Override public byte Tid() {return Json_itm_.Tid_nde;}
public void Src_end_(int v) {this.src_end = v;}
@Override public Object Data() {return null;}
@Override public byte[] Data_bry() {return null;}
public int Subs_len() {return subs_len;} private int subs_len = 0, subs_max = 0;
public Json_itm Subs_get_at(int i) {return subs[i];}
public Json_itm Subs_get_by_key(byte[] key) {
for (int i = 0; i < subs_len; i++) {
Json_itm itm = subs[i];
if (itm.Tid() == Json_itm_.Tid_kv) {
Json_itm_kv itm_as_kv = (Json_itm_kv)itm;
if (Bry_.Eq(key, itm_as_kv.Key().Data_bry()))
return itm;
}
}
return null;
}
public Json_itm_nde Subs_add_many(Json_itm... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
Subs_add(ary[i]);
return this;
}
public void Subs_add(Json_itm itm) {
int new_len = subs_len + 1;
if (new_len > subs_max) { // ary too small >>> expand
subs_max = new_len * 2;
Json_itm[] new_subs = new Json_itm[subs_max];
Array_.CopyTo(subs, 0, new_subs, 0, subs_len);
subs = new_subs;
}
subs[subs_len] = (Json_itm)itm;
subs_len = new_len;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
if (bfr.Len() != 0)
bfr.Add_byte_nl();
Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte(Byte_ascii.Space);
for (int i = 0; i < subs_len; i++) {
if (i != 0) {
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
}
subs[i].Print_as_json(bfr, depth + 1);
}
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl();
}
Json_itm[] subs = Json_itm_.Ary_empty;
public static Json_itm_nde cast_(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid_nde ? null : (Json_itm_nde)v;}
}

View File

@@ -0,0 +1,31 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.json; import gplx.*;
public class Json_itm_tmp implements Json_itm {
public Json_itm_tmp(byte tid, String data) {this.tid = tid; this.data = data;}
public byte Tid() {return tid;} private byte tid;
public byte[] Data_bry() {return Bry_.new_utf8_(Object_.XtoStr_OrEmpty(data));}
public int Src_bgn() {return -1;}
public int Src_end() {return -1;}
public Object Data() {return data;} private String data;
public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_str(data);}
public boolean Data_eq(byte[] comp) {return false;}
public void Clear() {}
public static Json_itm new_str_(String v) {return new Json_itm_tmp(Json_itm_.Tid_string, "\"" + v + "\"");}
public static Json_itm new_int_(int v) {return new Json_itm_tmp(Json_itm_.Tid_int, Int_.XtoStr(v));}
}

View File

@@ -0,0 +1,61 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.json; import gplx.*;
public class Json_kv_ary_srl {
public static KeyVal Kv_by_itm(Json_itm itm) {
switch (itm.Tid()) {
case Json_itm_.Tid_kv:
Json_itm_kv kv = (Json_itm_kv)itm;
return KeyVal_.new_(kv.Key_as_str(), Val_by_itm(kv.Val()));
default:
throw Err_.unhandled(itm.Tid());
}
}
private static Object Val_by_itm(Json_itm itm) {
switch (itm.Tid()) {
case Json_itm_.Tid_bool: return Bool_.XtoStr_lower(Bool_.cast_(itm.Data()));
case Json_itm_.Tid_int:
case Json_itm_.Tid_null:
case Json_itm_.Tid_string:
case Json_itm_.Tid_decimal: return itm.Data();
case Json_itm_.Tid_array: return Val_by_itm_ary((Json_itm_ary)itm);
case Json_itm_.Tid_nde: return Val_by_itm_nde((Json_itm_nde)itm);
case Json_itm_.Tid_kv: // kv should never be val; EX: "a":"b":c; not possible
default: throw Err_.unhandled(itm.Tid());
}
}
private static KeyVal[] Val_by_itm_ary(Json_itm_ary itm) {
int subs_len = itm.Subs_len();
KeyVal[] rv = new KeyVal[subs_len];
for (int i = 0; i < subs_len; i++) {
Json_itm sub = itm.Subs_get_at(i);
KeyVal kv = KeyVal_.new_(Int_.XtoStr(i + Int_.Base1), Val_by_itm(sub));
rv[i] = kv;
}
return rv;
}
public static KeyVal[] Val_by_itm_nde(Json_itm_nde itm) {
int subs_len = itm.Subs_len();
KeyVal[] rv = new KeyVal[subs_len];
for (int i = 0; i < subs_len; i++) {
Json_itm sub = itm.Subs_get_at(i);
rv[i] = Kv_by_itm(sub);
}
return rv;
}
}

View File

@@ -0,0 +1,50 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.json; import gplx.*;
import org.junit.*;
public class Json_kv_ary_srl_tst {
@Before public void init() {fxt.Clear();} private Json_kv_ary_srl_fxt fxt = new Json_kv_ary_srl_fxt();
@Test public void Null() {fxt.Test_parse("{'k0':null}" , fxt.ary_(fxt.kv_str_("k0", null)));}
@Test public void Bool_n() {fxt.Test_parse("{'k0':false}" , fxt.ary_(fxt.kv_bool_("k0", false)));}
@Test public void Num() {fxt.Test_parse("{'k0':123}" , fxt.ary_(fxt.kv_int_("k0", 123)));}
@Test public void Str() {fxt.Test_parse("{'k0':'v0'}" , fxt.ary_(fxt.kv_str_("k0", "v0")));}
@Test public void Num_dec() {fxt.Test_parse("{'k0':1.23}" , fxt.ary_(fxt.kv_dec_("k0", DecimalAdp_.parse_("1.23"))));}
@Test public void Ary_int() {fxt.Test_parse("{'k0':[1,2,3]}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_(fxt.kv_int_("1", 1), fxt.kv_int_("2", 2), fxt.kv_int_("3", 3)))));}
@Test public void Ary_empty() {fxt.Test_parse("{'k0':[]}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_())));}
@Test public void Subs_int() {fxt.Test_parse("{'k0':{'k00':1,'k01':2}}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_(fxt.kv_int_("k00", 1), fxt.kv_int_("k01", 2)))));}
@Test public void Subs_empty() {fxt.Test_parse("{'k0':{}}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_())));}
}
class Json_kv_ary_srl_fxt {
public void Clear() {
if (parser == null) {
parser = new Json_parser();
}
} private Json_parser parser;
public void Test_parse(String raw_str, KeyVal[] expd) {
byte[] raw_bry = Json_parser_tst.Replace_apos(Bry_.new_utf8_(raw_str));
Json_doc doc = parser.Parse(raw_bry);
KeyVal[] actl = Json_kv_ary_srl.Val_by_itm_nde(doc.Root());
Tfds.Eq_str_lines(KeyVal_.Ary_x_to_str(expd), KeyVal_.Ary_x_to_str(actl));
}
public KeyVal[] ary_(KeyVal... ary) {return ary;}
public KeyVal kv_obj_(String key, Object val) {return KeyVal_.new_(key, val);}
public KeyVal kv_str_(String key, String val) {return KeyVal_.new_(key, val);}
public KeyVal kv_int_(String key, int val) {return KeyVal_.new_(key, val);}
public KeyVal kv_bool_(String key, boolean val) {return KeyVal_.new_(key, Bool_.XtoStr_lower(val));}
public KeyVal kv_dec_(String key, DecimalAdp val) {return KeyVal_.new_(key, val.XtoStr());}
}

View File

@@ -0,0 +1,167 @@
/*
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.json; import gplx.*;
public class Json_parser {
public Json_factory Factory() {return factory;} Json_factory factory = new Json_factory();
private byte[] src; private int src_len, pos; private NumberParser num_parser = new NumberParser();
private static final byte[] Bry_bool_rue = Bry_.new_ascii_("rue"), Bry_bool_alse = Bry_.new_ascii_("alse"), Bry_null_ull = Bry_.new_ascii_("ull");
public Json_doc Parse(byte[] src) {
Json_doc doc = new Json_doc();
this.src = src; this.src_len = src.length; pos = 0;
Skip_ws();
if (src.length == 0) return null;
if (src[pos] != Byte_ascii.Curly_bgn) return null;
Skip_ws();
// if (src[pos + 1] != Byte_ascii.Quote) return null;
// throw Err_.new_("doc must start with {");
Json_itm_nde root = Make_nde(doc);
doc.Ctor(src, root);
return doc;
}
Json_itm_nde Make_nde(Json_doc doc) {
++pos; // brack_bgn
Json_itm_nde nde = new Json_itm_nde(pos);
while (pos < src_len) {
Skip_ws();
if (src[pos] == Byte_ascii.Curly_end) {++pos; return nde;}
else nde.Subs_add(Make_kv(doc));
Skip_ws();
switch (src[pos++]) {
case Byte_ascii.Comma: break;
case Byte_ascii.Curly_end: return nde;
default: throw Err_.unhandled(src[pos - 1]);
}
}
throw Err_.new_("eos inside nde");
}
Json_itm Make_kv(Json_doc doc) {
Json_itm key = Make_string(doc);
Skip_ws();
Chk(Byte_ascii.Colon);
Skip_ws();
Json_itm val = Make_val(doc);
return new Json_itm_kv(key, val);
}
Json_itm Make_val(Json_doc doc) {
while (pos < src_len) {
byte b = src[pos];
switch (b) {
case Byte_ascii.Ltr_n: return Make_literal(Bry_null_ull , 3, factory.Null());
case Byte_ascii.Ltr_f: return Make_literal(Bry_bool_alse , 4, factory.Bool_n());
case Byte_ascii.Ltr_t: return Make_literal(Bry_bool_rue , 3, factory.Bool_y());
case Byte_ascii.Quote: return Make_string(doc);
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
case Byte_ascii.Dash: return Make_num(doc);
case Byte_ascii.Brack_bgn: return Make_ary(doc);
case Byte_ascii.Curly_bgn: return Make_nde(doc);
}
throw Err_.unhandled(Char_.XtoStr(b));
}
throw Err_.new_("eos reached in val");
}
Json_itm Make_literal(byte[] remainder, int remainder_len, Json_itm singleton) {
++pos; // 1st char
int literal_end = pos + remainder_len;
if (Bry_.Eq(remainder, src, pos, literal_end)) {
pos = literal_end;
return singleton;
}
throw Err_.new_("invalid literal");
}
Json_itm Make_string(Json_doc doc) {
int bgn = pos++; // ++: quote_bgn
boolean exact = true;
while (pos < src_len) {
switch (src[pos]) {
case Byte_ascii.Backslash:
++pos; // backslash
switch (src[pos]) {
case Byte_ascii.Ltr_u: pos += 4; break; // \uFFFF 4 hex-dec
default: ++pos; break; // \? " \ / b f n r t
}
exact = false;
break;
case Byte_ascii.Quote:
return factory.Str(doc, bgn, ++pos, exact); // ++: quote_end
default:
++pos;
break;
}
}
throw Err_.new_("eos reached inside quote");
}
Json_itm Make_num(Json_doc doc) {
int num_bgn = pos;
boolean loop = true;
while (loop) {
if (pos == src_len) throw Err_.new_("eos reached inside num");
switch (src[pos]) {
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
++pos;
break;
case Byte_ascii.Dot:
case Byte_ascii.Dash: case Byte_ascii.Plus:
case Byte_ascii.Ltr_E: case Byte_ascii.Ltr_e: // e e+ e- E E+ E-
++pos;
break;
default:
loop = false;
break;
}
}
num_parser.Parse(src, num_bgn, pos);
return num_parser.HasFrac()
? factory.Decimal(doc, num_bgn, pos)
: factory.Int(doc, num_bgn, pos);
}
Json_itm_ary Make_ary(Json_doc doc) {
Json_itm_ary rv = factory.Ary(pos++, pos); // brack_bgn
while (pos < src_len) {
Skip_ws();
if (src[pos] == Byte_ascii.Brack_end) {++pos; return rv;}
else rv.Subs_add(Make_val(doc));
Skip_ws();
switch (src[pos]) {
case Byte_ascii.Comma: ++pos; break;
case Byte_ascii.Brack_end: ++pos; return rv;
}
}
throw Err_.new_("eos inside ary");
}
private void Skip_ws() {
while (pos < src_len) {
switch (src[pos]) {
case Byte_ascii.Space: case Byte_ascii.NewLine: case Byte_ascii.Tab: case Byte_ascii.CarriageReturn: ++pos; break;
default: return;
}
}
}
private void Chk(byte expd) {
if (src[pos] == expd)
++pos;
else
throw err_(src, pos, "expected '{0}' but got '{1}'", Char_.XtoStr(expd), Char_.XtoStr(src[pos]));
}
Err err_(byte[] src, int bgn, String fmt, Object... args) {return err_(src, bgn, src.length, fmt, args);}
Err err_(byte[] src, int bgn, int src_len, String fmt, Object... args) {
String msg = String_.Format(fmt, args) + " " + Int_.XtoStr(bgn) + " " + String_.new_utf8_len_safe_(src, bgn, 20);
return Err_.new_(msg);
}
}

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.json; import gplx.*;
import org.junit.*;
public class Json_parser_tst {
Json_parser_fxt fxt = new Json_parser_fxt();
@Before public void init() {fxt.Clear();}
@Test public void Null() {fxt.Test_parse_val0("{'k0':null}" , null);}
@Test public void Bool_n() {fxt.Test_parse_val0("{'k0':false}" , false);}
@Test public void Bool_y() {fxt.Test_parse_val0("{'k0':true}" , true);}
@Test public void Num() {fxt.Test_parse_val0("{'k0':123}" , 123);}
@Test public void Num_neg() {fxt.Test_parse_val0("{'k0':-123}" , -123);}
@Test public void Str() {fxt.Test_parse_val0("{'k0':'v0'}" , "v0");}
@Test public void Str_esc_quote() {fxt.Test_parse_val0("{'k0':'a\\\"b'}" , "a\"b");}
@Test public void Str_esc_hex4() {fxt.Test_parse_val0("{'k0':'a\\u0021b'}" , "a!b");}
@Test public void Num_dec() {fxt.Test_parse("{'k0':1.23}" , fxt.itm_nde_().Subs_add_many(fxt.itm_kv_dec_("k0", "1.23")));}
@Test public void Num_exp() {fxt.Test_parse("{'k0':1e+2}" , fxt.itm_nde_().Subs_add_many(fxt.itm_kv_dec_("k0", "1e+2")));}
@Test public void Num_mix() {fxt.Test_parse("{'k0':-1.23e-1}" , fxt.itm_nde_().Subs_add_many(fxt.itm_kv_dec_("k0", "-1.23e-1")));}
@Test public void Str_many() {fxt.Test_parse("{'k0':'v0','k1':'v1','k2':'v2'}", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_("k0", "v0"), fxt.itm_kv_("k1", "v1"), fxt.itm_kv_("k2", "v2")));}
@Test public void Ary_empty() {fxt.Test_parse("{'k0':[]}", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_ary_int_("k0")));}
@Test public void Ary_int() {fxt.Test_parse("{'k0':[1,2,3]}", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_ary_int_("k0", 1, 2, 3)));}
@Test public void Ary_str() {fxt.Test_parse("{'k0':['a','b','c']}", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_ary_str_("k0", "a", "b", "c")));}
@Test public void Ary_ws() {fxt.Test_parse("{'k0': [ 1 , 2 , 3 ] }", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_ary_int_("k0", 1, 2, 3)));}
@Test public void Subs_int() {fxt.Test_parse("{'k0':{'k00':1}}", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_("k0", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_("k00", 1)))));}
@Test public void Subs_empty() {fxt.Test_parse("{'k0':{}}", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_("k0", fxt.itm_nde_())));}
@Test public void Subs_ws() {fxt.Test_parse("{'k0': { 'k00' : 1 } }", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_("k0", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_("k00", 1)))));}
@Test public void Ws() {fxt.Test_parse(" { 'k0' : 'v0' } ", fxt.itm_nde_().Subs_add_many(fxt.itm_kv_("k0", "v0")));}
public static String Replace_apos_as_str(String v) {return String_.new_utf8_(Replace_apos(Bry_.new_utf8_(v)));}
public static byte[] Replace_apos(byte[] v) {return Bry_.Replace(v, Byte_ascii.Apos, Byte_ascii.Quote);}
}
class Json_parser_fxt {
public void Clear() {
if (parser == null) {
parser = new Json_parser();
factory = parser.Factory();
}
} Json_parser parser; Json_factory factory; Bry_bfr tmp_bfr = Bry_bfr.reset_(255);
Json_itm itm_int_(int v) {return Json_itm_tmp.new_int_(v);}
Json_itm itm_str_(String v) {return Json_itm_tmp.new_str_(v);}
public Json_itm_ary itm_ary_() {return factory.Ary(-1, -1);}
public Json_itm_nde itm_nde_() {return factory.Nde(-1);}
public Json_itm_kv itm_kv_null_(String k) {return factory.Kv(itm_str_(k), factory.Null());}
public Json_itm_kv itm_kv_(String k, String v) {return factory.Kv(itm_str_(k), itm_str_(v));}
public Json_itm_kv itm_kv_(String k, int v) {return factory.Kv(itm_str_(k), itm_int_(v));}
public Json_itm_kv itm_kv_(String k, boolean v) {return factory.Kv(itm_str_(k), v ? factory.Bool_y() : factory.Bool_n());}
public Json_itm_kv itm_kv_dec_(String k, String v) {return factory.Kv(itm_str_(k), new Json_itm_tmp(Json_itm_.Tid_decimal, v));}
public Json_itm_kv itm_kv_(String k, Json_itm_nde v) {return factory.Kv(itm_str_(k), v);}
public Json_itm_kv itm_kv_ary_int_(String k, int... v) {
Json_itm_ary ary = factory.Ary(-1, -1);
int len = v.length;
for (int i = 0; i < len; i++)
ary.Subs_add(itm_int_(v[i]));
return factory.Kv(itm_str_(k), ary);
}
public Json_itm_kv itm_kv_ary_str_(String k, String... v) {
Json_itm_ary ary = factory.Ary(-1, -1);
int len = v.length;
for (int i = 0; i < len; i++)
ary.Subs_add(itm_str_(v[i]));
return factory.Kv(itm_str_(k), ary);
}
public void Test_parse(String raw_str, Json_itm... expd_ary) {
byte[] raw = Json_parser_tst.Replace_apos(Bry_.new_utf8_(raw_str));
Json_doc doc = parser.Parse(raw);
doc.Root().Print_as_json(tmp_bfr, 0);
String actl = tmp_bfr.XtoStrAndClear();
String expd = Xto_str(raw, doc, expd_ary, 0, expd_ary.length);
Tfds.Eq_str_lines(expd, actl, actl);
}
public void Test_parse_val0(String raw_str, Object expd) {
byte[] raw = Json_parser_tst.Replace_apos(Bry_.new_utf8_(raw_str));
Json_doc doc = parser.Parse(raw);
Json_itm_kv kv = Json_itm_kv.cast_(doc.Root().Subs_get_at(0)); // assume root has kv as first sub; EX: {"a":"b"}
Object actl = kv.Val().Data(); // NOTE: Data_bry is escaped val; EX: a\"b has DataBry of a"b
Tfds.Eq(expd, actl);
}
String Xto_str(byte[] raw, Json_doc doc, Json_itm[] ary, int bgn, int end) {
for (int i = bgn; i < end; i++) {
Json_itm itm = ary[i];
itm.Print_as_json(tmp_bfr, 0);
}
return tmp_bfr.XtoStrAndClear();
}
}

View File

@@ -0,0 +1,21 @@
/*
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.php; import gplx.*;
public class Php_ctx {
public byte[] Src() {return src;} public Php_ctx Src_(byte[] v) {this.src = v; return this;} private byte[] src;
}

View File

@@ -0,0 +1,263 @@
/*
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.php; import gplx.*;
/*
NOTE: naive implementation of PHP evaluator. intended only for parsing Messages**.php files in MediaWiki. Specifically, it assumes the following:
- all lines are assignment lines: EX: $a = b;
- only the assignment operator is allowed (=); EX: $a = 5 + 7; fails b/c of + operator;
- no functions are supported: EX: strlen('a') fails
*/
public class Php_evaluator implements Php_tkn_wkr {
byte mode = Mode_key_bgn, next_tid = 0, next_mode = 0;
Php_line_assign cur_line; Php_itm_ary cur_ary; Php_key cur_kv_key;
ListAdp frame_stack = ListAdp_.new_();
public Php_evaluator(Gfo_msg_log msg_log) {this.msg_log = msg_log;} Gfo_msg_log msg_log;
public void Init(Php_ctx ctx) {src = ctx.Src(); frame_stack.Clear();} private byte[] src;
public ListAdp List() {return lines;} ListAdp lines = ListAdp_.new_();
public Gfo_msg_log Msg_log() {return msg_log;}
public void Clear() {
lines.Clear(); msg_log.Clear();
cur_line = null;
cur_ary = null;
cur_kv_key = null;
mode = Mode_key_bgn;
next_tid = next_mode = 0;
}
public void Process(Php_tkn tkn) {
byte tkn_tid = tkn.Tkn_tid();
switch (tkn_tid) {
case Php_tkn_.Tid_declaration: case Php_tkn_.Tid_comment: case Php_tkn_.Tid_ws: // always discard, regardless of mode
return;
}
switch (mode) {
case Mode_expect: // handles sequences like "array("
if (tkn_tid == next_tid)
mode = next_mode;
else {
Msg_many(src, tkn.Src_bgn(), tkn.Src_end(), Expecting_itm_failed, Php_tkn_.Xto_str(next_tid), Php_tkn_.Xto_str(tkn_tid));
Fail();
}
break;
case Mode_suspend:
if (tkn_tid == Php_tkn_.Tid_semic) mode = Mode_key_bgn;
break;
case Mode_key_bgn:
if (tkn_tid == Php_tkn_.Tid_var) {
cur_ary = null;
cur_line = new Php_line_assign();
lines.Add(cur_line);
Php_tkn_var var_tkn = (Php_tkn_var)tkn;
cur_line.Key_(new Php_itm_var(var_tkn.Var_name(src)));
mode = Mode_key_end;
}
else {
Msg_many(src, tkn.Src_bgn(), tkn.Src_end(), Expecting_itm_failed, Php_tkn_.Xto_str(Php_tkn_.Tid_var), Php_tkn_.Xto_str(tkn_tid));
Fail();
}
break;
case Mode_key_end:
switch (tkn_tid) {
case Php_tkn_.Tid_eq: mode = Mode_val; break;
case Php_tkn_.Tid_brack_bgn: mode = Mode_brack_itm; break;
case Php_tkn_.Tid_brack_end: Expect(Php_tkn_.Tid_eq, Mode_val); break;
default: {
Msg_many(src, tkn.Src_bgn(), tkn.Src_end(), Expecting_itm_failed, Php_tkn_.Xto_str(Php_tkn_.Tid_var), Php_tkn_.Xto_str(tkn_tid));
Fail();
break;
}
}
break;
case Mode_brack_itm:
switch (tkn_tid) {
case Php_tkn_.Tid_quote:
Php_tkn_quote tkn_quote = (Php_tkn_quote)tkn;
Php_itm_quote key_sub = new Php_itm_quote(tkn_quote.Quote_text(src));
cur_line.Key_subs_(new Php_key[] {key_sub});
mode = Mode_key_end;
break;
default: {
Msg_many(src, tkn.Src_bgn(), tkn.Src_end(), Expecting_itm_failed, Php_tkn_.Xto_str(Php_tkn_.Tid_var), Php_tkn_.Xto_str(tkn_tid));
Fail();
break;
}
}
break;
case Mode_val:
Php_itm line_val = null;
switch (tkn_tid) {
case Php_tkn_.Tid_null: Expect(Php_tkn_.Tid_semic, Mode_key_bgn); line_val = Php_itm_null._; break;
case Php_tkn_.Tid_false: Expect(Php_tkn_.Tid_semic, Mode_key_bgn); line_val = Php_itm_bool_false._; break;
case Php_tkn_.Tid_true: Expect(Php_tkn_.Tid_semic, Mode_key_bgn); line_val = Php_itm_bool_true._; break;
case Php_tkn_.Tid_quote:
Expect(Php_tkn_.Tid_semic, Mode_key_bgn);
Php_tkn_quote tkn_quote = (Php_tkn_quote)tkn;
line_val = new Php_itm_quote(tkn_quote.Quote_text(src));
break;
case Php_tkn_.Tid_ary:
Expect(Php_tkn_.Tid_paren_bgn, Mode_ary_subs);
Php_itm_ary ary = new Php_itm_ary();
if (cur_ary == null)
line_val = ary;
else {
cur_ary.Subs_add(ary);
frame_stack.Add(new Php_scanner_frame(cur_ary));
cur_kv_key = null;
}
this.cur_ary = ary;
break;
case Php_tkn_.Tid_txt:
case Php_tkn_.Tid_var:
break;
case Php_tkn_.Tid_eq:
case Php_tkn_.Tid_eq_kv:
case Php_tkn_.Tid_semic:
case Php_tkn_.Tid_comma:
case Php_tkn_.Tid_paren_bgn:
case Php_tkn_.Tid_paren_end:
case Php_tkn_.Tid_num:
break;
}
cur_line.Val_(line_val);
break;
case Mode_ary_subs:
switch (tkn_tid) {
case Php_tkn_.Tid_null: Ary_add_itm(Php_itm_null._); break;
case Php_tkn_.Tid_false: Ary_add_itm(Php_itm_bool_false._); break;
case Php_tkn_.Tid_true: Ary_add_itm(Php_itm_bool_true._); break;
case Php_tkn_.Tid_quote:
Php_tkn_quote tkn_quote = (Php_tkn_quote)tkn;
Ary_add_itm(new Php_itm_quote(tkn_quote.Quote_text(src)));
break;
case Php_tkn_.Tid_num:
Php_tkn_num tkn_num = (Php_tkn_num)tkn;
Ary_add_itm(new Php_itm_int(tkn_num.Num_val_int(src)));
break;
case Php_tkn_.Tid_var:
Php_tkn_var tkn_var = (Php_tkn_var)tkn;
Ary_add_itm(new Php_itm_var(Bry_.Mid(src, tkn_var.Src_bgn(), tkn_var.Src_end())));
break;
case Php_tkn_.Tid_txt:
Php_tkn_txt tkn_txt = (Php_tkn_txt)tkn;
Ary_add_itm(new Php_itm_var(Bry_.Mid(src, tkn_txt.Src_bgn(), tkn_txt.Src_end())));
break;
case Php_tkn_.Tid_ary:
Expect(Php_tkn_.Tid_paren_bgn, Mode_ary_subs);
Php_itm_ary ary = new Php_itm_ary();
if (cur_ary == null)
line_val = ary;
else {
frame_stack.Add(new Php_scanner_frame(cur_ary));
if (cur_kv_key == null)
cur_ary.Subs_add(ary);
else {
Php_itm_kv ary_itm = new Php_itm_kv().Key_(cur_kv_key).Val_(ary);
cur_ary.Subs_add(ary_itm);
cur_kv_key = null;
}
}
this.cur_ary = ary;
break;
case Php_tkn_.Tid_paren_end:
mode = Mode_ary_term;
if (frame_stack.Count() == 0)
cur_ary = null;
else {
Php_scanner_frame frame = (Php_scanner_frame)ListAdp_.Pop(frame_stack);
cur_ary = frame.Ary();
frame.Rls();
}
break;
case Php_tkn_.Tid_semic: // NOTE: will occur in following construct array(array());
mode = Mode_key_bgn;
break;
case Php_tkn_.Tid_eq:
case Php_tkn_.Tid_eq_kv:
case Php_tkn_.Tid_comma:
case Php_tkn_.Tid_paren_bgn:
break;
}
break;
case Mode_ary_dlm:
switch (tkn_tid) {
case Php_tkn_.Tid_comma:
mode = Mode_ary_subs;
break;
case Php_tkn_.Tid_paren_end:
mode = Mode_ary_term;
if (frame_stack.Count() == 0)
cur_ary = null;
else {
Php_scanner_frame frame = (Php_scanner_frame)ListAdp_.Pop(frame_stack);
cur_ary = frame.Ary();
frame.Rls();
}
break;
case Php_tkn_.Tid_eq_kv:
Php_itm_sub tmp_key = cur_ary.Subs_pop();
cur_kv_key = (Php_key)tmp_key;
mode = Mode_ary_subs;
break;
}
break;
case Mode_ary_term:
switch (tkn_tid) {
case Php_tkn_.Tid_comma:
case Php_tkn_.Tid_paren_end: // NOTE: paren_end occurs in multiple nests; EX: array(array())
mode = Mode_ary_subs;
break;
case Php_tkn_.Tid_semic:
mode = Mode_key_bgn;
break;
}
break;
}
}
private void Fail() {mode = Mode_suspend;}
private void Ary_add_itm(Php_itm val) {
mode = Mode_ary_dlm;
if (cur_kv_key == null)
cur_ary.Subs_add((Php_itm_sub)val);
else {
Php_itm_kv ary_itm = new Php_itm_kv().Key_(cur_kv_key).Val_(val);
cur_ary.Subs_add(ary_itm);
cur_kv_key = null;
}
}
private void Expect(byte next_tid, byte next_mode) {
mode = Mode_expect;
this.next_tid = next_tid;
this.next_mode = next_mode;
}
public void Msg_many(byte[] src, int bgn, int end, Gfo_msg_itm itm, Object... args) {
msg_log.Add_itm_many(itm, src, bgn, end, args);
}
public static final Gfo_msg_itm Expecting_itm_failed = Gfo_msg_itm_.new_warn_(Php_parser.Log_nde, "expecting_itm_failed", "expecting_itm ~{0} but got ~{1} instead");
static final byte Mode_key_bgn = 1, Mode_key_end = 2, Mode_expect = 3, Mode_suspend = 4, Mode_val = 5, Mode_ary_subs = 6, Mode_ary_dlm = 7, Mode_ary_term = 8, Mode_brack_itm = 9;
}
class Php_scanner_frame {
public Php_scanner_frame(Php_itm_ary ary) {this.ary = ary;}
public Php_itm_ary Ary() {return ary;} Php_itm_ary ary;
public void Rls() {ary = null;}
}
class Php_parser_interrupt {
public static final Php_parser_interrupt Char = new Php_parser_interrupt();
}

View File

@@ -0,0 +1,44 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.php; import gplx.*;
public interface Php_itm {
byte Itm_tid();
byte[] Val_obj_bry();
}
class Php_itm_null implements Php_itm, Php_itm_sub {
public byte Itm_tid() {return Php_itm_.Tid_null;}
public byte[] Val_obj_bry() {return null;}
public static final Php_itm_null _ = new Php_itm_null(); Php_itm_null() {}
}
class Php_itm_bool_true implements Php_itm, Php_itm_sub {
public byte Itm_tid() {return Php_itm_.Tid_bool_true;}
public byte[] Val_obj_bry() {return Bry_true;}
public static final Php_itm_bool_true _ = new Php_itm_bool_true(); Php_itm_bool_true() {}
private static final byte[] Bry_true = Bry_.new_ascii_("true");
}
class Php_itm_bool_false implements Php_itm, Php_itm_sub {
public byte Itm_tid() {return Php_itm_.Tid_bool_false;}
public byte[] Val_obj_bry() {return Bry_true;}
public static final Php_itm_bool_false _ = new Php_itm_bool_false(); Php_itm_bool_false() {}
private static final byte[] Bry_true = Bry_.new_ascii_("false");
}
class Php_itm_var implements Php_itm, Php_itm_sub, Php_key {
public Php_itm_var(byte[] v) {this.val_obj_bry = v;}
public byte Itm_tid() {return Php_itm_.Tid_var;}
public byte[] Val_obj_bry() {return val_obj_bry;} private byte[] val_obj_bry;
}

View File

@@ -0,0 +1,44 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.php; import gplx.*;
public class Php_itm_ {
public static final byte Tid_null = 0, Tid_bool_false = 1, Tid_bool_true = 2, Tid_int = 3, Tid_quote = 4, Tid_ary = 5, Tid_kv = 6, Tid_var = 7;
public static int Parse_int_or(Php_itm itm, int or) {
int rv = -1;
switch (itm.Itm_tid()) {
case Php_itm_.Tid_int:
rv = ((Php_itm_int)itm).Val_obj_int();
return rv;
case Php_itm_.Tid_quote:
byte[] bry = ((Php_itm_quote)itm).Val_obj_bry();
rv = Bry_.X_to_int_or(bry, -1);
return (rv == -1) ? or : rv;
default:
return or;
}
}
public static byte[] Parse_bry(Php_itm itm) {
switch (itm.Itm_tid()) {
case Php_itm_.Tid_kv:
case Php_itm_.Tid_ary:
throw Err_mgr._.unhandled_(itm.Itm_tid());
default:
return itm.Val_obj_bry();
}
}
}

View File

@@ -0,0 +1,37 @@
/*
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.php; import gplx.*;
public class Php_itm_ary implements Php_itm, Php_itm_sub {
public Php_itm_ary() {}
public byte Itm_tid() {return Php_itm_.Tid_ary;}
public byte[] Val_obj_bry() {return null;}
public int Subs_len() {return subs_len;} private int subs_len;
public Php_itm_sub Subs_get(int i) {return ary[i];}
public Php_itm_sub Subs_pop() {return ary[--subs_len];}
public void Subs_add(Php_itm_sub v) {
int new_len = subs_len + 1;
if (new_len > subs_max) { // ary too small >>> expand
subs_max = new_len * 2;
Php_itm_sub[] new_ary = new Php_itm_sub[subs_max];
Array_.CopyTo(ary, 0, new_ary, 0, subs_len);
ary = new_ary;
}
ary[subs_len] = v;
subs_len = new_len;
} Php_itm_sub[] ary = Php_itm_sub_.Ary_empty; int subs_max;
}

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.php; import gplx.*;
public class Php_itm_int implements Php_itm, Php_itm_sub, Php_key {
public Php_itm_int(int v) {this.val_obj_int = v;}
public byte Itm_tid() {return Php_itm_.Tid_int;}
public byte[] Val_obj_bry() {return Bry_.XbyInt(val_obj_int);}
public int Val_obj_int() {return val_obj_int;} private int val_obj_int;
}

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.php; import gplx.*;
public class Php_itm_kv implements Php_itm, Php_itm_sub {
public byte Itm_tid() {return Php_itm_.Tid_kv;}
public byte[] Val_obj_bry() {return null;}
public Php_key Key() {return key;} public Php_itm_kv Key_(Php_key v) {this.key = v; return this;} Php_key key;
public Php_itm Val() {return val;} public Php_itm_kv Val_(Php_itm v) {this.val = v; return this;} Php_itm val;
}

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.php; import gplx.*;
public class Php_itm_quote implements Php_itm, Php_itm_sub, Php_key {
public Php_itm_quote(byte[] v) {this.val_obj_bry = v;} // NOTE: use Php_text_itm_parser to parse \" and related
public byte Itm_tid() {return Php_itm_.Tid_quote;}
public byte[] Val_obj_bry() {return val_obj_bry;} private byte[] val_obj_bry;
}

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.php; import gplx.*;
public interface Php_itm_sub extends Php_itm {
}
class Php_itm_sub_ {
public static final Php_itm_sub[] Ary_empty = new Php_itm_sub[0];
}

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.php; import gplx.*;
public interface Php_key extends Php_itm {
}
class Php_key_ {
public static final Php_key[] Ary_empty = new Php_key[0];
}

View File

@@ -0,0 +1,19 @@
/*
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.php; import gplx.*;
public interface Php_line {}

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.php; import gplx.*;
public class Php_line_assign implements Php_line {
public Php_key Key() {return key;} public Php_line_assign Key_(Php_key v) {this.key = v; return this;} Php_key key;
public Php_key[] Key_subs() {return key_subs;} public Php_line_assign Key_subs_(Php_key[] v) {this.key_subs = v; return this;} Php_key[] key_subs = Php_key_.Ary_empty;
public Php_itm Val() {return val;} public Php_line_assign Val_(Php_itm v) {this.val = v; return this;} Php_itm val;
}

View File

@@ -0,0 +1,282 @@
/*
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.php; import gplx.*;
interface Php_lxr {
byte Lxr_tid();
void Lxr_ini(ByteTrieMgr_slim trie, Php_parser_interrupt[] parser_interrupts);
void Lxr_bgn(byte[] src, int src_len, Php_tkn_wkr tkn_wkr, Php_tkn_factory tkn_factory);
int Lxr_make(Php_ctx ctx, int bgn, int cur);
}
class Php_lxr_ {
public static final byte Tid_declaration = 1, Tid_ws = 2, Tid_comment = 3, Tid_var = 4, Tid_sym = 5, Tid_keyword = 6, Tid_num = 7, Tid_quote = 8;
}
abstract class Php_lxr_base implements Php_lxr {
protected byte[] src; protected int src_len; protected Php_tkn_wkr tkn_wkr; protected Php_tkn_factory tkn_factory;
public abstract byte Lxr_tid();
public abstract void Lxr_ini(ByteTrieMgr_slim trie, Php_parser_interrupt[] parser_interrupts);
public void Lxr_bgn(byte[] src, int src_len, Php_tkn_wkr tkn_wkr, Php_tkn_factory tkn_factory) {this.src = src; this.src_len = src_len; this.tkn_wkr = tkn_wkr; this.tkn_factory = tkn_factory;}
public abstract int Lxr_make(Php_ctx ctx, int bgn, int cur);
}
class Php_lxr_declaration extends Php_lxr_base {
@Override public byte Lxr_tid() {return Php_lxr_.Tid_declaration;}
@Override public void Lxr_ini(ByteTrieMgr_slim trie, Php_parser_interrupt[] parser_interrupts) {
trie.Add(Bry_declaration, this);
parser_interrupts[Byte_ascii.Lt] = Php_parser_interrupt.Char;
}
@Override public int Lxr_make(Php_ctx ctx, int bgn, int cur) {
boolean loop = true;
boolean ws_found = false;
while (loop) {
if (cur == src_len) break;
byte b = src[cur];
switch (b) {
case Byte_ascii.NewLine: case Byte_ascii.CarriageReturn:
ws_found = true;
++cur;
break;
default:
if (ws_found) loop = false;
else return Php_parser.NotFound;
break;
}
}
tkn_wkr.Process(tkn_factory.Declaration(bgn, cur));
return cur;
}
private static final byte[] Bry_declaration = Bry_.new_ascii_("<?php");
}
class Php_lxr_ws extends Php_lxr_base {
public Php_lxr_ws(byte ws_tid) {
this.ws_tid = ws_tid;
switch (ws_tid) {
case Php_tkn_ws.Tid_space: ws_bry = Bry_ws_space; break;
case Php_tkn_ws.Tid_nl: ws_bry = Bry_ws_nl; break;
case Php_tkn_ws.Tid_tab: ws_bry = Bry_ws_tab; break;
case Php_tkn_ws.Tid_cr: ws_bry = Bry_ws_cr; break;
}
}
public byte Ws_tid() {return ws_tid;} private byte ws_tid;
public byte[] Ws_bry() {return ws_bry;} private byte[] ws_bry;
@Override public byte Lxr_tid() {return Php_lxr_.Tid_ws;}
@Override public void Lxr_ini(ByteTrieMgr_slim trie, Php_parser_interrupt[] parser_interrupts) {
trie.Add(ws_bry, this);
parser_interrupts[ws_bry[0]] = Php_parser_interrupt.Char;
}
@Override public int Lxr_make(Php_ctx ctx, int bgn, int cur) {
boolean loop = true;
while (loop) {
if (cur == src_len) break;
byte b = src[cur];
switch (b) {
case Byte_ascii.Space: case Byte_ascii.NewLine: case Byte_ascii.Tab: case Byte_ascii.CarriageReturn:
++cur;
break;
default:
loop = false;
break;
}
}
tkn_wkr.Process(tkn_factory.Ws(bgn, cur, ws_tid));
return cur;
}
public static final byte[] Bry_ws_space = Bry_.new_ascii_(" "), Bry_ws_nl = Bry_.new_ascii_("\n"), Bry_ws_tab = Bry_.new_ascii_("\t"), Bry_ws_cr = Bry_.new_ascii_("\r");
}
class Php_lxr_comment extends Php_lxr_base {
public Php_lxr_comment(byte comment_tid) {
this.comment_tid = comment_tid;
switch (comment_tid) {
case Php_tkn_comment.Tid_mult: comment_bgn = Bry_bgn_mult; comment_end = Bry_end_mult; break;
case Php_tkn_comment.Tid_slash: comment_bgn = Bry_bgn_slash; comment_end = Bry_end_nl; break;
case Php_tkn_comment.Tid_hash: comment_bgn = Bry_bgn_hash; comment_end = Bry_end_nl; break;
}
}
@Override public byte Lxr_tid() {return Php_lxr_.Tid_comment;}
@Override public void Lxr_ini(ByteTrieMgr_slim trie, Php_parser_interrupt[] parser_interrupts) {
trie.Add(comment_bgn, this);
parser_interrupts[Byte_ascii.Slash] = Php_parser_interrupt.Char;
parser_interrupts[Byte_ascii.Hash] = Php_parser_interrupt.Char;
}
public byte Comment_tid() {return comment_tid;} private byte comment_tid;
public byte[] Comment_bgn() {return comment_bgn;} private byte[] comment_bgn;
public byte[] Comment_end() {return comment_end;} private byte[] comment_end;
@Override public int Lxr_make(Php_ctx ctx, int bgn, int cur) {
int end = Bry_finder.Find_fwd(src, comment_end, bgn);
if (end == Bry_.NotFound) {
tkn_wkr.Msg_many(src, bgn, cur, Php_lxr_comment.Dangling_comment, comment_tid, comment_end);
cur = src_len; // NOTE: terminating sequence not found; assume rest of src is comment
}
else
cur = end + comment_end.length;
tkn_wkr.Process(tkn_factory.Comment(bgn, cur, comment_tid));
return cur;
}
public static final Gfo_msg_itm Dangling_comment = Gfo_msg_itm_.new_warn_(Php_parser.Log_nde, "dangling_comment", "dangling_comment");
public static final byte[] Bry_bgn_mult = Bry_.new_ascii_("/*"), Bry_bgn_slash = Bry_.new_ascii_("//"), Bry_bgn_hash = Bry_.new_ascii_("#")
, Bry_end_mult = Bry_.new_ascii_("*/"), Bry_end_nl = Bry_.new_ascii_("\n");
}
class Php_lxr_var extends Php_lxr_base {
@Override public byte Lxr_tid() {return Php_lxr_.Tid_var;}
@Override public void Lxr_ini(ByteTrieMgr_slim trie, Php_parser_interrupt[] parser_interrupts) {
trie.Add(Bry_var, this);
parser_interrupts[Byte_ascii.Dollar] = Php_parser_interrupt.Char;
}
@Override public int Lxr_make(Php_ctx ctx, int bgn, int cur) {
boolean loop = true;
while (loop) {
if (cur == src_len) break;
byte b = src[cur];
switch (b) {
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
case Byte_ascii.Ltr_A: case Byte_ascii.Ltr_B: case Byte_ascii.Ltr_C: case Byte_ascii.Ltr_D: case Byte_ascii.Ltr_E:
case Byte_ascii.Ltr_F: case Byte_ascii.Ltr_G: case Byte_ascii.Ltr_H: case Byte_ascii.Ltr_I: case Byte_ascii.Ltr_J:
case Byte_ascii.Ltr_K: case Byte_ascii.Ltr_L: case Byte_ascii.Ltr_M: case Byte_ascii.Ltr_N: case Byte_ascii.Ltr_O:
case Byte_ascii.Ltr_P: case Byte_ascii.Ltr_Q: case Byte_ascii.Ltr_R: case Byte_ascii.Ltr_S: case Byte_ascii.Ltr_T:
case Byte_ascii.Ltr_U: case Byte_ascii.Ltr_V: case Byte_ascii.Ltr_W: case Byte_ascii.Ltr_X: case Byte_ascii.Ltr_Y: case Byte_ascii.Ltr_Z:
case Byte_ascii.Ltr_a: case Byte_ascii.Ltr_b: case Byte_ascii.Ltr_c: case Byte_ascii.Ltr_d: case Byte_ascii.Ltr_e:
case Byte_ascii.Ltr_f: case Byte_ascii.Ltr_g: case Byte_ascii.Ltr_h: case Byte_ascii.Ltr_i: case Byte_ascii.Ltr_j:
case Byte_ascii.Ltr_k: case Byte_ascii.Ltr_l: case Byte_ascii.Ltr_m: case Byte_ascii.Ltr_n: case Byte_ascii.Ltr_o:
case Byte_ascii.Ltr_p: case Byte_ascii.Ltr_q: case Byte_ascii.Ltr_r: case Byte_ascii.Ltr_s: case Byte_ascii.Ltr_t:
case Byte_ascii.Ltr_u: case Byte_ascii.Ltr_v: case Byte_ascii.Ltr_w: case Byte_ascii.Ltr_x: case Byte_ascii.Ltr_y: case Byte_ascii.Ltr_z:
case Byte_ascii.Underline:
++cur;
break;
default:
loop = false;
break;
}
}
tkn_wkr.Process(tkn_factory.Var(bgn, cur));
return cur;
}
private static final byte[] Bry_var = Bry_.new_ascii_("$");
}
class Php_lxr_sym extends Php_lxr_base {
public Php_lxr_sym(String hook_str, byte tkn_tid) {this.hook = Bry_.new_ascii_(hook_str); this.tkn_tid = tkn_tid;} private byte[] hook; byte tkn_tid;
@Override public byte Lxr_tid() {return Php_lxr_.Tid_sym;}
@Override public void Lxr_ini(ByteTrieMgr_slim trie, Php_parser_interrupt[] parser_interrupts) {
trie.Add(hook, this);
parser_interrupts[hook[0]] = Php_parser_interrupt.Char;
}
@Override public int Lxr_make(Php_ctx ctx, int bgn, int cur) {
tkn_wkr.Process(tkn_factory.Generic(bgn, cur, tkn_tid));
return cur;
}
}
class Php_lxr_quote extends Php_lxr_base {
public Php_lxr_quote(byte quote_tid) {
this.quote_tid = quote_tid;
switch (quote_tid) {
case Byte_ascii.Apos: quote_bry = Quote_bry_single; break;
case Byte_ascii.Quote: quote_bry = Quote_bry_double; break;
}
}
@Override public byte Lxr_tid() {return Php_lxr_.Tid_quote;}
@Override public void Lxr_ini(ByteTrieMgr_slim trie, Php_parser_interrupt[] parser_interrupts) {
trie.Add(quote_bry, this);
parser_interrupts[quote_tid] = Php_parser_interrupt.Char;
}
public byte Quote_tid() {return quote_tid;} private byte quote_tid;
public byte[] Quote_bry() {return quote_bry;} private byte[] quote_bry;
@Override public int Lxr_make(Php_ctx ctx, int bgn, int cur) {
int end = -1;
while (true) {
end = Bry_finder.Find_fwd(src, quote_bry, cur);
if (end == Bry_.NotFound) {
tkn_wkr.Msg_many(src, bgn, cur, Php_lxr_quote.Dangling_quote, quote_tid, quote_bry);
cur = src_len; // NOTE: terminating sequence not found; assume rest of src is comment
break;
}
else {
boolean end_quote = true;
if (src[end - 1] == Byte_ascii.Backslash) { // \' encountered;
int backslash_count = 1;
for (int i = end - 2; i > -1; i--) { // count preceding backslashes
if (src[i] == Byte_ascii.Backslash)
++backslash_count;
else
break;
}
if (backslash_count % 2 == 1) { // odd backslashes; this means that ' is escaped; EX: \' and \\\'; note that even backslashes means not escaped; EX: \\'
end_quote = false;
cur = end + 1;
}
}
if (end_quote) {
cur = end + quote_bry.length;
break;
}
}
}
tkn_wkr.Process(tkn_factory.Quote(bgn, cur, quote_tid));
return cur;
}
public static final Gfo_msg_itm Dangling_quote = Gfo_msg_itm_.new_warn_(Php_parser.Log_nde, "dangling_quote", "dangling_quote");
public static final byte[] Quote_bry_single = Bry_.new_ascii_("'"), Quote_bry_double = Bry_.new_ascii_("\"");
}
class Php_lxr_keyword extends Php_lxr_base {
public Php_lxr_keyword(String hook_str, byte tkn_tid) {this.hook = Bry_.new_ascii_(hook_str); this.tkn_tid = tkn_tid;} private byte[] hook; byte tkn_tid;
@Override public byte Lxr_tid() {return Php_lxr_.Tid_keyword;}
@Override public void Lxr_ini(ByteTrieMgr_slim trie, Php_parser_interrupt[] parser_interrupts) {trie.Add(hook, this);}
@Override public int Lxr_make(Php_ctx ctx, int bgn, int cur) {
if (cur < src_len) {
byte next_byte = src[cur];
switch (next_byte) { // valid characters for end of word; EX: 'null '; 'null='; etc..
case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.NewLine: case Byte_ascii.CarriageReturn:
case Byte_ascii.Hash: case Byte_ascii.Slash:
case Byte_ascii.Quote: case Byte_ascii.Apos:
case Byte_ascii.Bang: 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.Plus:
case Byte_ascii.Comma: case Byte_ascii.Dash: case Byte_ascii.Dot: case Byte_ascii.Semic:
case Byte_ascii.Lt: case Byte_ascii.Eq: case Byte_ascii.Gt: case Byte_ascii.Question: case Byte_ascii.At:
case Byte_ascii.Brack_bgn: case Byte_ascii.Backslash: 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:
break;
default: // num,ltr or extended utf8 character sequence; treat keyword as false match; EX: 'nulla'; 'null0'
return Php_parser.NotFound;
}
}
tkn_wkr.Process(tkn_factory.Generic(bgn, cur, tkn_tid));
return cur;
}
}
class Php_lxr_num extends Php_lxr_base {
@Override public byte Lxr_tid() {return Php_lxr_.Tid_keyword;}
@Override public void Lxr_ini(ByteTrieMgr_slim trie, Php_parser_interrupt[] parser_interrupts) {
for (int i = 0; i < 10; i++)
trie.Add(new byte[] {(byte)(i + Byte_ascii.Num_0)}, this);
}
@Override public int Lxr_make(Php_ctx ctx, int bgn, int cur) {
boolean loop = true;
while (loop) {
if (cur == src_len) break;
byte b = src[cur];
switch (b) {
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
++cur;
break;
default:
loop = false;
break;
}
}
tkn_wkr.Process(tkn_factory.Num(bgn, cur));
return cur;
}
}

View File

@@ -0,0 +1,120 @@
/*
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.php; import gplx.*;
public class Php_parser {
Php_lxr[] lxrs; int lxrs_len;
int txt_bgn; Php_tkn_txt txt_tkn;
private ByteTrieMgr_slim trie = ByteTrieMgr_slim.ci_ascii_(); // NOTE:ci:PHP tkns are ASCII
byte[] src; int src_len; Php_tkn_wkr tkn_wkr; Php_tkn_factory tkn_factory = new Php_tkn_factory(); Php_ctx ctx = new Php_ctx();
Php_parser_interrupt[] parser_interrupts = new Php_parser_interrupt[256];
public Php_parser() {
ListAdp list = ListAdp_.new_();
Init_lxr(list, new Php_lxr_declaration());
Init_lxr(list, new Php_lxr_ws(Php_tkn_ws.Tid_space));
Init_lxr(list, new Php_lxr_ws(Php_tkn_ws.Tid_nl));
Init_lxr(list, new Php_lxr_ws(Php_tkn_ws.Tid_tab));
Init_lxr(list, new Php_lxr_ws(Php_tkn_ws.Tid_cr));
Init_lxr(list, new Php_lxr_comment(Php_tkn_comment.Tid_mult));
Init_lxr(list, new Php_lxr_comment(Php_tkn_comment.Tid_slash));
Init_lxr(list, new Php_lxr_comment(Php_tkn_comment.Tid_hash));
Init_lxr(list, new Php_lxr_var());
Init_lxr(list, new Php_lxr_sym(";", Php_tkn_.Tid_semic));
Init_lxr(list, new Php_lxr_sym("=", Php_tkn_.Tid_eq));
Init_lxr(list, new Php_lxr_sym("=>", Php_tkn_.Tid_eq_kv));
Init_lxr(list, new Php_lxr_sym(",", Php_tkn_.Tid_comma));
Init_lxr(list, new Php_lxr_sym("(", Php_tkn_.Tid_paren_bgn));
Init_lxr(list, new Php_lxr_sym(")", Php_tkn_.Tid_paren_end));
Init_lxr(list, new Php_lxr_sym("[", Php_tkn_.Tid_brack_bgn));
Init_lxr(list, new Php_lxr_sym("]", Php_tkn_.Tid_brack_end));
Init_lxr(list, new Php_lxr_keyword("null", Php_tkn_.Tid_null));
Init_lxr(list, new Php_lxr_keyword("false", Php_tkn_.Tid_false));
Init_lxr(list, new Php_lxr_keyword("true", Php_tkn_.Tid_true));
Init_lxr(list, new Php_lxr_keyword("array", Php_tkn_.Tid_ary));
Init_lxr(list, new Php_lxr_num());
Init_lxr(list, new Php_lxr_quote(Byte_ascii.Apos));
Init_lxr(list, new Php_lxr_quote(Byte_ascii.Quote));
lxrs = (Php_lxr[])list.XtoAry(Php_lxr.class);
lxrs_len = list.Count();
}
private void Init_lxr(ListAdp list, Php_lxr lxr) {
lxr.Lxr_ini(trie, parser_interrupts);
list.Add(lxr);
}
public void Parse_tkns(String src, Php_tkn_wkr tkn_wkr) {Parse_tkns(Bry_.new_utf8_(src), tkn_wkr);}
public void Parse_tkns(byte[] src, Php_tkn_wkr tkn_wkr) {
this.src = src; this.src_len = src.length; this.tkn_wkr = tkn_wkr;
ctx.Src_(src);
tkn_wkr.Init(ctx);
if (src_len == 0) return;
for (int i = 0; i < lxrs_len; i++)
lxrs[i].Lxr_bgn(src, src_len, tkn_wkr, tkn_factory);
int pos = 0;
byte b = src[pos];
txt_tkn = null; txt_bgn = 0;
boolean loop_raw = true, loop_txt = true;
while (loop_raw) {
Object o = trie.Match(b, src, pos, src_len);
if (o == null) { // char does not hook into a lxr
loop_txt = true;
while (loop_txt) { // keep looping until end of String or parser_interrupt
++pos;
if (pos == src_len) {loop_raw = false; break;}
b = src[pos];
if (parser_interrupts[b & 0xFF] == Php_parser_interrupt.Char) {
Make_txt(txt_bgn, pos);
break;
}
}
if (!loop_raw) break;
continue; // continue b/c b is set to interrupt char, and should be matched against trie
}
else { // char hooks into lxr
if (txt_bgn != pos) // txt_bgn is set; make text tkn
Make_txt(txt_bgn, pos);
Php_lxr lxr = (Php_lxr)o;
int match_pos = trie.Match_pos();
int make_pos = lxr.Lxr_make(ctx, pos, match_pos);
if (make_pos == Php_parser.NotFound) {
Make_txt(txt_bgn, pos);
++pos;
}
else {
txt_tkn = null;
txt_bgn = pos = make_pos;
}
}
if (pos == src_len) break;
b = src[pos];
}
if (txt_bgn != pos)
Make_txt(txt_bgn, pos);
}
int Make_txt(int bgn, int end) {
if (txt_tkn == null) {
txt_tkn = tkn_factory.Txt(bgn, end);
tkn_wkr.Process(txt_tkn);
}
else
txt_tkn.Src_end_(end);
return end;
}
public static final int NotFound = -1;
public static final Gfo_msg_grp Log_nde = Gfo_msg_grp_.new_(Gfo_msg_grp_.Root_gplx, "php_parser");
}

View File

@@ -0,0 +1,399 @@
/*
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.php; import gplx.*;
import org.junit.*;
public class Php_parser_tst {
Php_parser_fxt fxt = new Php_parser_fxt();
@Before public void init() {fxt.Clear();}
@Test public void Text() {
fxt.tst_tkns("text", fxt.tkn_txt(0, 4));
}
@Test public void Declaration_pass() {
fxt.tst_tkns("<?php", fxt.tkn_declaration());
}
@Test public void Declaration_fail() {
fxt.tst_tkns("<?phpx", fxt.tkn_txt(0, 6));
}
@Test public void Ws_basic() {
fxt.tst_tkns(" ", fxt.tkn_ws(0, 1));
}
@Test public void Ws_mix() {
fxt.tst_tkns(" a\n", fxt.tkn_ws(0, 1), fxt.tkn_txt(1, 2), fxt.tkn_ws(2, 3));
}
@Test public void Comment_mult() {
fxt.tst_tkns("/*a*/", fxt.tkn_comment_mult(0, 5));
}
@Test public void Comment_slash() {
fxt.tst_tkns("//a\n", fxt.tkn_comment_slash(0, 4));
}
@Test public void Comment_hash() {
fxt.tst_tkns("#a\n", fxt.tkn_comment_hash(0, 3));
}
@Test public void Comment_mult_fail() {
fxt.Msg(Php_lxr_comment.Dangling_comment, 0, 2).tst_tkns("/*a", fxt.tkn_comment_mult(0, 3));
}
@Test public void Var() {
fxt.tst_tkns("$abc", fxt.tkn_var(0, 4, "abc"));
}
@Test public void Sym() {
fxt.tst_tkns(";==>,()", fxt.tkn_generic(0, 1, Php_tkn_.Tid_semic), fxt.tkn_generic(1, 2, Php_tkn_.Tid_eq), fxt.tkn_generic(2, 4, Php_tkn_.Tid_eq_kv), fxt.tkn_generic(4, 5, Php_tkn_.Tid_comma), fxt.tkn_generic(5, 6, Php_tkn_.Tid_paren_bgn), fxt.tkn_generic(6, 7, Php_tkn_.Tid_paren_end));
}
@Test public void Keyword() {
fxt.tst_tkns("null=nulla", fxt.tkn_generic(0, 4, Php_tkn_.Tid_null), fxt.tkn_generic(4, 5, Php_tkn_.Tid_eq), fxt.tkn_txt(5, 10));
}
@Test public void Num() {
fxt.tst_tkns("0=123", fxt.tkn_num(0, 1, 0), fxt.tkn_generic(1, 2, Php_tkn_.Tid_eq), fxt.tkn_num(2, 5, 123));
}
@Test public void Quote_apos() {
fxt.tst_tkns("'a\"b'", fxt.tkn_quote_apos(0, 5));
}
@Test public void Quote_quote() {
fxt.tst_tkns("\"a'b\"", fxt.tkn_quote_quote(0, 5));
}
@Test public void Quote_escape() {
fxt.tst_tkns("'a\\'b'", fxt.tkn_quote_apos(0, 6));
}
@Test public void Brack() {
fxt.tst_tkns("['a']", fxt.tkn_generic(0, 1, Php_tkn_.Tid_brack_bgn), fxt.tkn_quote_apos(1, 4), fxt.tkn_generic(4, 5, Php_tkn_.Tid_brack_end));
}
@Test public void Line_assign_false() {
fxt.tst_lines("$a = false;", fxt.line_assign("a", fxt.itm_bool_false()));
}
@Test public void Line_assign_quote_charcode() {
fxt.tst_lines("$a = 'bc';", fxt.line_assign("a", fxt.itm_quote("bc")));
}
@Test public void Line_assign_mult() {
fxt.tst_lines("$a = 'b';\n$c='d';", fxt.line_assign("a", fxt.itm_quote("b")), fxt.line_assign("c", fxt.itm_quote("d")));
}
@Test public void Line_ary_flat() {
fxt.tst_lines("$a = array('b', 'c', 'd');", fxt.line_assign("a", fxt.itm_ary().Subs_(fxt.itm_quote("b"), fxt.itm_quote("c"), fxt.itm_quote("d"))));
}
@Test public void Line_ary_flat_escape() { // PURPOSE.fix: \\' was being interpreted incorrectly; \\ should escape \, but somehow \' was being escaped
fxt.tst_lines("$a = array('b\\\\', 'c');", fxt.line_assign("a", fxt.itm_ary().Subs_(fxt.itm_quote("b\\\\"), fxt.itm_quote("c"))));
}
@Test public void Line_ary_flat_escape2() { // PURPOSE.fix: \\' was being interpreted incorrectly; \\ should escape \, but somehow \' was being escaped
fxt.tst_lines("$a = array('b\\\\\\'c', 'd');", fxt.line_assign("a", fxt.itm_ary().Subs_(fxt.itm_quote("b\\\\\\'c"), fxt.itm_quote("d"))));
}
@Test public void Line_ary_kv() {
fxt.tst_lines("$a = array(k0 => 'v0', k1 => 'v1', k2 => 'v2');", fxt.line_assign("a", fxt.itm_ary().Subs_(fxt.itm_kv_quote("k0", "v0"), fxt.itm_kv_quote("k1", "v1"), fxt.itm_kv_quote("k2", "v2"))));
}
@Test public void Line_ary_kv_num() {
fxt.tst_lines("$a = array(k0 => 0, k1 => 1);", fxt.line_assign("a", fxt.itm_ary().Subs_(fxt.itm_kv_int("k0", 0), fxt.itm_kv_int("k1", 1))));
}
@Test public void Line_ary_nest() {
fxt.tst_lines("$a = array('b', array('c', 'd'), 'e');", fxt.line_assign("a", fxt.itm_ary().Subs_(fxt.itm_quote("b"), fxt.itm_ary().Subs_(fxt.itm_quote("c"), fxt.itm_quote("d")), fxt.itm_quote("e"))));
}
@Test public void Line_ary_nest_kv() {
fxt.tst_lines("$a = array('i00' => array('01', '02'), 'i10' => array('11', '12'), 'i20' => array('21', '22'));"
, fxt.line_assign
( "a"
, fxt.itm_ary().Subs_
( fxt.itm_kv_itm("i00", fxt.itm_ary().Subs_(fxt.itm_quote("01"), fxt.itm_quote("02")))
, fxt.itm_kv_itm("i10", fxt.itm_ary().Subs_(fxt.itm_quote("11"), fxt.itm_quote("12")))
, fxt.itm_kv_itm("i20", fxt.itm_ary().Subs_(fxt.itm_quote("21"), fxt.itm_quote("22")))
)));
}
@Test public void Line_ws() {
fxt.tst_lines("\r\n$a = false;", fxt.line_assign("a", fxt.itm_bool_false()));
}
@Test public void Empty_usr_array() {
fxt.tst_lines("$a = array();\n$b = array();"
, fxt.line_assign("a", fxt.itm_ary())
, fxt.line_assign("b", fxt.itm_ary())
);
}
@Test public void Line_ary_kv_txt() {
fxt.tst_lines("$a = array('k0' => a, 'k1' => b);", fxt.line_assign("a", fxt.itm_ary().Subs_(fxt.itm_kv_txt("k0", "a"), fxt.itm_kv_txt("k1", "b"))));
}
@Test public void Line_brack() {
fxt.tst_lines("$a['b'] = 'c';", fxt.line_assign_subs("a", String_.Ary("b"), fxt.itm_quote("c")));
}
}
class Php_parser_fxt {
Php_tkn_factory tkn_factory = new Php_tkn_factory();
Php_parser parser = new Php_parser();
Php_tkn_wkr_tkn tkn_wkr = new Php_tkn_wkr_tkn();
Php_evaluator line_wkr = new Php_evaluator(new Gfo_msg_log("test"));
Tst_mgr tst_mgr = new Tst_mgr();
Gfo_msg_log_chkr log_mgr_chkr = new Gfo_msg_log_chkr();
public void Clear() {log_mgr_chkr.Clear(); tkn_wkr.Clear(); line_wkr.Clear();}
public Php_tkn_chkr_base tkn_declaration() {return Php_tkn_declaration_chkr._;}
public Php_tkn_chkr_base tkn_txt(int bgn, int end) {return new Php_tkn_txt_chkr(bgn, end);}
public Php_tkn_chkr_base tkn_ws(int bgn, int end) {return new Php_tkn_ws_chkr(bgn, end);}
public Php_tkn_chkr_base tkn_generic(int bgn, int end, byte tid) {return new Php_tkn_generic_chkr(bgn, end, tid);}
public Php_tkn_comment_chkr tkn_comment_mult(int bgn, int end) {return new Php_tkn_comment_chkr(bgn, end).Comment_tid_(Php_tkn_comment.Tid_mult);}
public Php_tkn_comment_chkr tkn_comment_slash(int bgn, int end) {return new Php_tkn_comment_chkr(bgn, end).Comment_tid_(Php_tkn_comment.Tid_slash);}
public Php_tkn_comment_chkr tkn_comment_hash(int bgn, int end) {return new Php_tkn_comment_chkr(bgn, end).Comment_tid_(Php_tkn_comment.Tid_hash);}
public Php_tkn_quote_chkr tkn_quote_apos(int bgn, int end) {return new Php_tkn_quote_chkr(bgn, end).Quote_tid_(Byte_ascii.Apos);}
public Php_tkn_quote_chkr tkn_quote_quote(int bgn, int end) {return new Php_tkn_quote_chkr(bgn, end).Quote_tid_(Byte_ascii.Quote);}
public Php_parser_fxt Msg(Gfo_msg_itm itm, int bgn, int end) {
log_mgr_chkr.Add_itm(itm, bgn, end);
return this;
}
public Php_tkn_var_chkr tkn_var(int bgn, int end, String v) {return new Php_tkn_var_chkr(bgn, end).Var_name_(v);}
public Php_tkn_num_chkr tkn_num(int bgn, int end, int v) {return new Php_tkn_num_chkr(bgn, end).Num_val_int_(v);}
public Php_line_assign_chkr line_assign(String key, Php_itm_chkr_base val) {return new Php_line_assign_chkr().Key_(key).Val_(val);}
public Php_line_assign_chkr line_assign_subs(String key, String[] subs, Php_itm_chkr_base val) {return new Php_line_assign_chkr().Key_(key).Subs_(subs).Val_(val);}
public Php_itm_chkr_base itm_bool_true() {return new Php_itm_generic_chkr(Php_itm_.Tid_bool_true);}
public Php_itm_chkr_base itm_bool_false() {return new Php_itm_generic_chkr(Php_itm_.Tid_bool_false);}
public Php_itm_chkr_base itm_null() {return new Php_itm_generic_chkr(Php_itm_.Tid_null);}
public Php_itm_chkr_base itm_quote(String v) {return new Php_itm_quote_chkr().Val_obj_str_(v);}
public Php_itm_chkr_base itm_int(int v) {return new Php_itm_int_chkr().Val_obj_int_(v);}
public Php_itm_chkr_base itm_txt(String v) {return new Php_itm_txt_chkr().Val_obj_str_(v);}
public Php_itm_ary_chkr itm_ary() {return new Php_itm_ary_chkr();}
public Php_itm_kv_chkr itm_kv_quote(String k, String v) {return new Php_itm_kv_chkr().Key_(k).Val_(itm_quote(v));}
public Php_itm_kv_chkr itm_kv_txt(String k, String v) {return new Php_itm_kv_chkr().Key_(k).Val_(itm_txt(v));}
public Php_itm_kv_chkr itm_kv_int(String k, int v) {return new Php_itm_kv_chkr().Key_(k).Val_(itm_int(v));}
public Php_itm_kv_chkr itm_kv_itm(String k, Php_itm_chkr_base v) {return new Php_itm_kv_chkr().Key_(k).Val_(v);}
public void tst_tkns(String raw, Php_tkn_chkr_base... expd) {
byte[] raw_bry = Bry_.new_utf8_(raw);
parser.Parse_tkns(raw_bry, tkn_wkr);
Php_tkn[] actl = (Php_tkn[])tkn_wkr.List().XtoAry(Php_tkn.class);
tst_mgr.Vars().Clear().Add("raw_bry", raw_bry);
tst_mgr.Tst_ary("", expd, actl);
log_mgr_chkr.tst(tst_mgr, tkn_wkr.Msg_log());
}
public void tst_lines(String raw, Php_line_assign_chkr... expd) {
byte[] raw_bry = Bry_.new_utf8_(raw);
parser.Parse_tkns(raw_bry, line_wkr);
Php_line[] actl = (Php_line[])line_wkr.List().XtoAry(Php_line.class);
tst_mgr.Vars().Clear().Add("raw_bry", raw_bry);
tst_mgr.Tst_ary("", expd, actl);
log_mgr_chkr.tst(tst_mgr, line_wkr.Msg_log());
}
}
abstract class Php_tkn_chkr_base implements Tst_chkr {
public abstract byte Tkn_tid();
public abstract Class<?> TypeOf();
public int Src_bgn() {return src_bgn;} private int src_bgn = -1;
public int Src_end() {return src_end;} private int src_end = -1;
public void Src_rng_(int src_bgn, int src_end) {this.src_bgn = src_bgn; this.src_end = src_end;}
public int Chk(Tst_mgr mgr, String path, Object actl_obj) {
Php_tkn actl = (Php_tkn)actl_obj;
int rv = 0;
rv += mgr.Tst_val(false, path, "tkn_tid", this.Tkn_tid(), actl.Tkn_tid());
rv += mgr.Tst_val(src_bgn == -1, path, "src_bgn", src_bgn, actl.Src_bgn());
rv += mgr.Tst_val(src_end == -1, path, "src_end", src_end, actl.Src_end());
rv += Chk_tkn(mgr, path, actl);
return rv;
}
@gplx.Virtual public int Chk_tkn(Tst_mgr mgr, String path, Php_tkn actl_obj) {return 0;}
}
class Php_tkn_declaration_chkr extends Php_tkn_chkr_base {
@Override public Class<?> TypeOf() {return Php_tkn_declaration.class;}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_declaration;}
public static final Php_tkn_declaration_chkr _ = new Php_tkn_declaration_chkr();
}
class Php_tkn_txt_chkr extends Php_tkn_chkr_base {
public Php_tkn_txt_chkr(int src_bgn, int src_end) {this.Src_rng_(src_bgn, src_end);}
@Override public Class<?> TypeOf() {return Php_tkn_txt.class;}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_txt;}
}
class Php_tkn_ws_chkr extends Php_tkn_chkr_base {
public Php_tkn_ws_chkr(int src_bgn, int src_end) {this.Src_rng_(src_bgn, src_end);}
@Override public Class<?> TypeOf() {return Php_tkn_ws.class;}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_ws;}
}
class Php_tkn_comment_chkr extends Php_tkn_chkr_base {
public Php_tkn_comment_chkr(int src_bgn, int src_end) {this.Src_rng_(src_bgn, src_end);}
@Override public Class<?> TypeOf() {return Php_tkn_comment.class;}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_comment;}
public Php_tkn_comment_chkr Comment_tid_(byte v) {this.comment_tid = v; return this;} private byte comment_tid = Php_tkn_comment.Tid_null;
@Override public int Chk_tkn(Tst_mgr mgr, String path, Php_tkn actl_obj) {
Php_tkn_comment actl = (Php_tkn_comment)actl_obj;
int rv = 0;
rv += mgr.Tst_val(comment_tid == Php_tkn_comment.Tid_null, path, "comment_tid", comment_tid, actl.Comment_tid());
return rv;
}
}
class Php_tkn_quote_chkr extends Php_tkn_chkr_base {
public Php_tkn_quote_chkr(int src_bgn, int src_end) {this.Src_rng_(src_bgn, src_end);}
@Override public Class<?> TypeOf() {return Php_tkn_quote.class;}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_quote;}
public Php_tkn_quote_chkr Quote_tid_(byte v) {this.quote_tid = v; return this;} private byte quote_tid = Byte_ascii.Nil;
@Override public int Chk_tkn(Tst_mgr mgr, String path, Php_tkn actl_obj) {
Php_tkn_quote actl = (Php_tkn_quote)actl_obj;
int rv = 0;
rv += mgr.Tst_val(quote_tid == Byte_ascii.Nil, path, "quote_tid", quote_tid, actl.Quote_tid());
return rv;
}
}
class Php_tkn_var_chkr extends Php_tkn_chkr_base {
public Php_tkn_var_chkr(int src_bgn, int src_end) {this.Src_rng_(src_bgn, src_end);}
@Override public Class<?> TypeOf() {return Php_tkn_var.class;}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_var;}
public Php_tkn_var_chkr Var_name_(String v) {this.var_name = v; return this;} private String var_name;
@Override public int Chk_tkn(Tst_mgr mgr, String path, Php_tkn actl_obj) {
Php_tkn_var actl = (Php_tkn_var)actl_obj;
int rv = 0;
byte[] raw_bry = (byte[])mgr.Vars_get_by_key("raw_bry");
rv += mgr.Tst_val(var_name == null, path, "var_name", var_name, String_.new_utf8_(actl.Var_name(raw_bry)));
return rv;
}
}
class Php_tkn_num_chkr extends Php_tkn_chkr_base {
public Php_tkn_num_chkr(int src_bgn, int src_end) {this.Src_rng_(src_bgn, src_end);}
@Override public Class<?> TypeOf() {return Php_tkn_num.class;}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_num;}
public Php_tkn_num_chkr Num_val_int_(int v) {this.num_val_int = v; return this;} private int num_val_int = Int_.MinValue;
@Override public int Chk_tkn(Tst_mgr mgr, String path, Php_tkn actl_obj) {
Php_tkn_num actl = (Php_tkn_num)actl_obj;
int rv = 0;
byte[] raw_bry = (byte[])mgr.Vars_get_by_key("raw_bry");
rv += mgr.Tst_val(num_val_int == Int_.MinValue, path, "num_val_int", num_val_int, actl.Num_val_int(raw_bry));
return rv;
}
}
class Php_tkn_generic_chkr extends Php_tkn_chkr_base {
public Php_tkn_generic_chkr(int src_bgn, int src_end, byte tkn_tid) {this.Src_rng_(src_bgn, src_end); this.tkn_tid = tkn_tid;}
@Override public Class<?> TypeOf() {return Php_tkn.class;}
@Override public byte Tkn_tid() {return tkn_tid;} private byte tkn_tid;
}
class Php_line_assign_chkr implements Tst_chkr {
public Class<?> TypeOf() {return Php_line_assign.class;}
public Php_line_assign_chkr Key_(String v) {key = v; return this;} private String key;
public Php_line_assign_chkr Subs_(String[] v) {
int subs_len = v.length;
subs = new Php_itm_quote_chkr[subs_len];
for (int i = 0; i < subs_len; i++)
subs[i] = new Php_itm_quote_chkr().Val_obj_str_(v[i]);
return this;
} Php_itm_chkr_base[] subs;
public Php_line_assign_chkr Val_(Php_itm_chkr_base v) {val = v; return this;} Php_itm_chkr_base val;
public int Chk(Tst_mgr mgr, String path, Object actl_obj) {
Php_line_assign actl = (Php_line_assign)actl_obj;
int rv = 0;
rv += mgr.Tst_val(key == null, path, "key", key, String_.new_utf8_(actl.Key().Val_obj_bry()));
if (subs != null) rv += mgr.Tst_sub_ary(subs, actl.Key_subs(), "subs", rv);
rv += mgr.Tst_sub_obj(val, actl.Val(), "val", rv);
return rv;
}
}
abstract class Php_itm_chkr_base implements Tst_chkr {
public abstract byte Itm_tid();
public abstract Class<?> TypeOf();
public int Chk(Tst_mgr mgr, String path, Object actl_obj) {
Php_itm actl = (Php_itm)actl_obj;
int rv = 0;
rv += mgr.Tst_val(false, path, "tkn_tid", this.Itm_tid(), actl.Itm_tid());
rv += Chk_itm(mgr, path, actl);
return rv;
}
@gplx.Virtual public int Chk_itm(Tst_mgr mgr, String path, Php_itm actl_obj) {return 0;}
public static final Php_itm_chkr_base[] Ary_empty = new Php_itm_chkr_base[0];
}
class Php_itm_generic_chkr extends Php_itm_chkr_base {
public Php_itm_generic_chkr(byte itm_tid) {this.itm_tid = itm_tid;} private byte itm_tid;
@Override public byte Itm_tid() {return itm_tid;}
@Override public Class<?> TypeOf() {return Php_itm.class;}
}
class Php_itm_int_chkr extends Php_itm_chkr_base {
@Override public byte Itm_tid() {return Php_itm_.Tid_int;}
@Override public Class<?> TypeOf() {return Php_itm.class;}
public Php_itm_int_chkr Val_obj_int_(int v) {this.val_obj_int = v; return this;} private int val_obj_int;
@Override public int Chk_itm(Tst_mgr mgr, String path, Php_itm actl_obj) {
Php_itm_int actl = (Php_itm_int)actl_obj;
int rv = 0;
rv += mgr.Tst_val(false, path, "val_obj_str", val_obj_int, actl.Val_obj_int());
return rv;
}
}
class Php_itm_txt_chkr extends Php_itm_chkr_base {
@Override public byte Itm_tid() {return Php_itm_.Tid_var;}
@Override public Class<?> TypeOf() {return Php_itm.class;}
public Php_itm_txt_chkr Val_obj_str_(String v) {this.val_obj_str = v; return this;} private String val_obj_str;
@Override public int Chk_itm(Tst_mgr mgr, String path, Php_itm actl_obj) {
Php_itm_var actl = (Php_itm_var)actl_obj;
int rv = 0;
rv += mgr.Tst_val(false, path, "val_obj_str", val_obj_str, String_.new_utf8_(actl.Val_obj_bry()));
return rv;
}
}
class Php_itm_quote_chkr extends Php_itm_chkr_base {
@Override public byte Itm_tid() {return Php_itm_.Tid_quote;}
@Override public Class<?> TypeOf() {return Php_itm.class;}
public Php_itm_quote_chkr Val_obj_str_(String v) {this.val_obj_str = v; return this;} private String val_obj_str;
@Override public int Chk_itm(Tst_mgr mgr, String path, Php_itm actl_obj) {
Php_itm_quote actl = (Php_itm_quote)actl_obj;
int rv = 0;
rv += mgr.Tst_val(false, path, "val_obj_str", val_obj_str, String_.new_utf8_(actl.Val_obj_bry()));
return rv;
}
}
class Php_itm_ary_chkr extends Php_itm_chkr_base {
@Override public byte Itm_tid() {return Php_itm_.Tid_ary;}
@Override public Class<?> TypeOf() {return Php_itm.class;}
public Php_itm_ary_chkr Subs_(Php_itm_chkr_base... v) {this.itms = v; return this;} Php_itm_chkr_base[] itms = Php_itm_chkr_base.Ary_empty;
@Override public int Chk_itm(Tst_mgr mgr, String path, Php_itm actl_obj) {
Php_itm_ary actl = (Php_itm_ary)actl_obj;
int rv = 0;
int actl_subs_len = actl.Subs_len();
Php_itm[] actl_ary = new Php_itm[actl_subs_len];
for (int i = 0; i < actl_subs_len; i++) {
actl_ary[i] = (Php_itm)actl.Subs_get(i);
}
rv += mgr.Tst_sub_ary(itms, actl_ary, "subs", rv);
return rv;
}
}
class Php_itm_kv_chkr extends Php_itm_chkr_base {
@Override public byte Itm_tid() {return Php_itm_.Tid_kv;}
@Override public Class<?> TypeOf() {return Php_itm.class;}
public Php_itm_kv_chkr Key_(String v) {key = v; return this;} private String key;
public Php_itm_kv_chkr Val_(Php_itm_chkr_base v) {val = v; return this;} Php_itm_chkr_base val;
@Override public int Chk_itm(Tst_mgr mgr, String path, Php_itm actl_obj) {
Php_itm_kv actl = (Php_itm_kv)actl_obj;
int rv = 0;
rv += mgr.Tst_val(false, path, "key", key, String_.new_utf8_(actl.Key().Val_obj_bry()));
rv += mgr.Tst_sub_obj(val, actl.Val(), path, rv);
return rv;
}
}
class Gfo_msg_log_chkr implements Tst_chkr {
ListAdp itms = ListAdp_.new_();
public Class<?> TypeOf() {return Gfo_msg_log.class;}
public void Clear() {itms.Clear();}
public void Add_itm(Gfo_msg_itm itm, int bgn, int end) {
Gfo_msg_data_chkr chkr = new Gfo_msg_data_chkr();
chkr.Itm_(itm).Excerpt_bgn_(bgn).Excerpt_end_(end);
itms.Add(chkr);
}
public int Chk(Tst_mgr mgr, String path, Object actl_obj) {return 0;}
public void tst(Tst_mgr mgr, Object actl_obj) {
Gfo_msg_log actl = (Gfo_msg_log)actl_obj;
int actl_itms_len = actl.Ary_len();
Gfo_msg_data[] actl_itms = new Gfo_msg_data[actl_itms_len];
for (int i = 0; i < actl_itms_len; i++)
actl_itms[i] = actl.Ary_get(i);
mgr.Tst_ary("itms", (Gfo_msg_data_chkr[])itms.XtoAry(Gfo_msg_data_chkr.class), actl_itms);
}
}
class Gfo_msg_data_chkr implements Tst_chkr {
public Class<?> TypeOf() {return Gfo_msg_data.class;}
public Gfo_msg_data_chkr Itm_(Gfo_msg_itm v) {itm = v; return this;} Gfo_msg_itm itm;
public Gfo_msg_data_chkr Excerpt_bgn_(int v) {excerpt_bgn = v; return this;} private int excerpt_bgn = -1;
public Gfo_msg_data_chkr Excerpt_end_(int v) {excerpt_end = v; return this;} private int excerpt_end = -1;
public int Chk(Tst_mgr mgr, String path, Object actl_obj) {
Gfo_msg_data actl = (Gfo_msg_data)actl_obj;
int rv = 0;
rv += mgr.Tst_val(itm == null, path, "itm", itm.Path_str(), actl.Item().Path_str());
rv += mgr.Tst_val(excerpt_bgn == -1, path, "excerpt_bgn", excerpt_bgn, actl.Src_bgn());
rv += mgr.Tst_val(excerpt_end == -1, path, "excerpt_end", excerpt_end, actl.Src_end());
return rv;
}
}

View File

@@ -0,0 +1,138 @@
/*
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.php; import gplx.*;
interface Php_srl_itm {
byte Tid();
int Src_bgn();
int Src_end();
Object Val();
void Xto_bfr(Bry_bfr bfr, int depth);
void Clear();
}
class Php_srl_itm_ {
public static final Php_srl_itm[] Ary_empty = new Php_srl_itm[0];
public static final byte Tid_unknown = 0, Tid_nil = 1, Tid_bool = 2, Tid_int = 3, Tid_double = 4, Tid_string = 5, Tid_array = 6, Tid_function = 7;
public static final byte[][] Names = Bry_.Ary("unknown", "nil", "boolean", "int", "double", "string", "array", "function");
public static final Object Val_nil = null, Val_table = null;
}
abstract class Php_srl_itm_base implements Php_srl_itm {
public abstract byte Tid();
public void Ctor(int src_bgn, int src_end, Object val) {this.src_bgn = src_bgn; this.src_end = src_end; this.val = val;}
public int Src_bgn() {return src_bgn;} private int src_bgn;
public int Src_end() {return src_end;} private int src_end;
public Object Val() {return val;} Object val;
@gplx.Virtual public void Xto_bfr(Bry_bfr bfr, int depth) {
Php_srl_wtr.Indent(bfr, depth);
bfr.Add(Php_srl_itm_.Names[this.Tid()]).Add_byte(Byte_ascii.Colon);
bfr.Add_str(Object_.XtoStr_OrNullStr(this.Val())).Add_byte(Byte_ascii.Semic).Add_byte_nl();
}
public void Clear() {}
}
class Php_srl_itm_nil extends Php_srl_itm_base {
public Php_srl_itm_nil() {this.Ctor(-1, -1, null);}
@Override public byte Tid() {return Php_srl_itm_.Tid_nil;}
public byte[] Bry_extract(byte[] raw) {return null;}
public static Php_srl_itm_nil Nil = new Php_srl_itm_nil();
}
class Php_srl_itm_bool extends Php_srl_itm_base {
public Php_srl_itm_bool(boolean val, byte[] bry) {this.val = val; this.bry = bry; this.Ctor(-1, -1, val);}
@Override public byte Tid() {return Php_srl_itm_.Tid_bool;}
public byte[] Bry_extract(byte[] raw) {return bry;} private byte[] bry;
public boolean Val_as_bool() {return val;} private boolean val;
public static Php_srl_itm_bool Bool_n = new Php_srl_itm_bool(false, new byte[] {Byte_ascii.Num_0}), Bool_y = new Php_srl_itm_bool(true, new byte[] {Byte_ascii.Num_1});
}
class Php_srl_itm_int extends Php_srl_itm_base {
public Php_srl_itm_int(int src_bgn, int src_end, int val) {this.val = val; this.Ctor(src_bgn, src_end, val);}
@Override public byte Tid() {return Php_srl_itm_.Tid_int;}
public int Val_as_int() {return val;} private int val;
}
class Php_srl_itm_double extends Php_srl_itm_base {
public Php_srl_itm_double(int src_bgn, int src_end, double val) {this.val = val; this.Ctor(src_bgn, src_end, val);}
@Override public byte Tid() {return Php_srl_itm_.Tid_double;}
public double Val_as_double() {return val;} double val;
}
class Php_srl_itm_str extends Php_srl_itm_base {
public Php_srl_itm_str(int src_bgn, int src_end, String val) {this.val = val; this.Ctor(src_bgn, src_end, val);}
@Override public byte Tid() {return Php_srl_itm_.Tid_string;}
public String Val_as_str() {return val;} private String val;
}
class Php_srl_itm_func extends Php_srl_itm_base {
public Php_srl_itm_func(int src_bgn, int src_end, int val) {this.val = val; this.Ctor(src_bgn, src_end, val);}
@Override public byte Tid() {return Php_srl_itm_.Tid_function;}
public int Val_as_int() {return val;} private int val;
}
class Php_srl_itm_ary extends Php_srl_itm_base {
public Php_srl_itm_ary(int src_bgn, int src_end) {this.Ctor(src_bgn, src_end, null);}
@Override public byte Tid() {return Php_srl_itm_.Tid_array;}
public Php_srl_itm_kv[] Subs_ary() {return subs;}
public int Subs_len() {return subs_len;} private int subs_len = 0, subs_max = 0;
public Php_srl_itm_kv Subs_get_at(int i) {return subs[i];}
public void Subs_clear() {
for (int i = 0; i < subs_len; i++) {
subs[i].Clear();
}
subs = Php_srl_itm_kv.Ary_empty;
subs_len = subs_max = 0;
}
public Php_srl_itm_ary Subs_add_many(Php_srl_itm_kv... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
Subs_add(ary[i]);
return this;
}
public Php_srl_itm_ary Subs_add(Php_srl_itm_kv itm) {
int new_len = subs_len + 1;
if (new_len > subs_max) { // ary too small >>> expand
subs_max = new_len * 2;
Php_srl_itm_kv[] new_subs = new Php_srl_itm_kv[subs_max];
Array_.CopyTo(subs, 0, new_subs, 0, subs_len);
subs = new_subs;
}
subs[subs_len] = itm;
subs_len = new_len;
return this;
}
@Override public void Xto_bfr(Bry_bfr bfr, int depth) {
Php_srl_wtr.Indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Ltr_a).Add_byte(Byte_ascii.Brack_bgn).Add_int_variable(subs_len).Add(CONST_ary_bgn);
for (int i = 0; i < subs_len; i++)
subs[i].Xto_bfr(bfr, depth + 1);
Php_srl_wtr.Indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl();
} static final byte[] CONST_ary_bgn = Bry_.new_ascii_("]{\n");
Php_srl_itm_kv[] subs = Php_srl_itm_kv.Ary_empty;
}
class Php_srl_itm_kv {
public int Idx_int() {return idx_int;} public Php_srl_itm_kv Idx_int_(int v) {idx_int = v; return this;} private int idx_int = -1;
public Php_srl_itm Key() {return key;} public Php_srl_itm_kv Key_(Php_srl_itm v) {key = v; return this;} Php_srl_itm key;
public Php_srl_itm Val() {return val;} public Php_srl_itm_kv Val_(Php_srl_itm v) {val = v; return this;} Php_srl_itm val;
public void Clear() {
key.Clear();
val.Clear();
}
public void Xto_bfr(Bry_bfr bfr, int depth) {
key.Xto_bfr(bfr, depth);
val.Xto_bfr(bfr, depth);
}
public static final Php_srl_itm_kv[] Ary_empty = new Php_srl_itm_kv[0];
}
class Php_srl_wtr {
public static void Indent(Bry_bfr bfr, int depth) {
if (depth > 0) bfr.Add_byte_repeat(Byte_ascii.Space, depth * 2); // indent
}
}

View File

@@ -0,0 +1,208 @@
/*
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.php; import gplx.*;
import gplx.texts.*;
public class Php_srl_parser {
@gplx.Internal protected Php_srl_factory Factory() {return factory;} Php_srl_factory factory = new Php_srl_factory();
byte[] raw; int raw_len, pos;
public KeyVal[] Parse_as_kvs(byte[] raw) {
Php_srl_itm_ary root = Parse(raw);
return Xto_kv_ary(root);
}
KeyVal[] Xto_kv_ary(Php_srl_itm_ary ary) {
int len = ary.Subs_len();
KeyVal[] rv = new KeyVal[len];
for (int i = 0; i < len; i++)
rv[i] = Xto_kv(ary.Subs_get_at(i));
return rv;
}
KeyVal Xto_kv(Php_srl_itm_kv itm) {
Php_srl_itm itm_key = itm.Key();
Object key = itm_key == null ? null : itm_key.Val();
Php_srl_itm itm_val = itm.Val();
Object val = null;
switch (itm_val.Tid()) {
case Php_srl_itm_.Tid_array:
Php_srl_itm_ary ary = (Php_srl_itm_ary)itm_val;
val = Xto_kv_ary(ary);
break;
case Php_srl_itm_.Tid_function:
val = new gplx.xowa.xtns.scribunto.Scrib_lua_proc(Object_.XtoStr_OrNullStr(key), Int_.cast_(itm_val.Val())); // NOTE: in most cases, key is a STRING (name of ScribFunction); however, for gsub it is an INT (arg_idx) b/c it is passed as a parameter
break;
default:
val = itm_val.Val();
break;
}
return KeyVal_.obj_(key, val);
}
@gplx.Internal protected Php_srl_itm_ary Parse(byte[] raw) {
this.raw = raw; this.raw_len = raw.length; pos = 0;
Php_srl_itm_ary rv = new Php_srl_itm_ary(0, raw_len);
Php_srl_itm_kv cur_kv = factory.Kv();
rv.Subs_add(cur_kv);
boolean mode_is_key = false;
while (true) {
if (pos >= raw_len) break;
if (mode_is_key) {
cur_kv.Key_(Parse_itm(pos));
mode_is_key = false;
}
else {
cur_kv.Val_(Parse_itm(pos));
mode_is_key = true;
}
}
return rv;
}
Php_srl_itm_ary Parse_array(int bgn, int subs_len) { // enters after '{'; EX: 'a:1{' -> Parse_array
Php_srl_itm_ary rv = factory.Ary(bgn, bgn);
for (int i = 0; i < subs_len; i++) {
Php_srl_itm_kv kv = factory.Kv();
Php_srl_itm key_itm = Parse_itm(pos);
kv.Key_(key_itm);
Php_srl_itm val_itm = Parse_itm(pos);
kv.Val_(val_itm);
rv.Subs_add(kv);
}
return rv;
}
Php_srl_itm Parse_itm(int bgn) {
pos = bgn;
Php_srl_itm rv = null;
byte b = raw[pos];
switch (b) {
case Byte_ascii.Ltr_N: // EX: 'N;'
rv = factory.Nil();
pos = Chk(raw, pos + 1, Byte_ascii.Semic);
break;
case Byte_ascii.Ltr_b: // EX: 'b:0;' or 'b:1;'
pos = Chk(raw, pos + 1, Byte_ascii.Colon);
b = raw[pos];
switch (b) {
case Byte_ascii.Num_1: rv = factory.Bool_y(); break;
case Byte_ascii.Num_0: rv = factory.Bool_n(); break;
default: throw err_(raw, pos, raw_len, "unknown boolean type {0}", Char_.XtoStr(b));
}
pos = Chk(raw, pos + 1, Byte_ascii.Semic);
break;
case Byte_ascii.Ltr_i: // EX: 'i:123;'
rv = Parse_int(pos);
pos = Chk(raw, pos, Byte_ascii.Semic);
break;
case Byte_ascii.Ltr_d: // EX: 'd:1.23;'
pos = Chk(raw, pos + 1, Byte_ascii.Colon);
int double_end = Bry_finder.Find_fwd(raw, Byte_ascii.Semic, pos, raw_len);
String double_str = String_.new_ascii_(raw, pos, double_end);
double double_val = 0;
if (String_.Eq(double_str, "INF")) double_val = Double_.Inf_pos;
else if (String_.Eq(double_str, "NAN")) double_val = Double_.NaN;
else double_val = Double_.parse_(double_str);
rv = factory.Double(pos, double_end, double_val);
pos = Chk(raw, double_end, Byte_ascii.Semic);
break;
case Byte_ascii.Ltr_s: // EX: 's:3:"abc";'
int len_val = Parse_int(pos).Val_as_int();
pos = Chk(raw, pos, Byte_ascii.Colon);
pos = Chk(raw, pos, Byte_ascii.Quote);
int str_end = pos + len_val;
String str_val = String_.new_utf8_(raw, pos, str_end);
rv = factory.Str(pos, str_end, str_val);
pos = Chk(raw, str_end, Byte_ascii.Quote);
pos = Chk(raw, pos, Byte_ascii.Semic);
break;
case Byte_ascii.Ltr_a: // EX: 'a:0:{}'
int subs_len = Parse_int(pos).Val_as_int();
pos = Chk(raw, pos, Byte_ascii.Colon);
pos = Chk(raw, pos, Byte_ascii.Curly_bgn);
rv = Parse_array(pos, subs_len);
pos = Chk(raw, pos, Byte_ascii.Curly_end);
break;
case Byte_ascii.Ltr_O: // EX: 'O:42:"Scribunto_LuaStandaloneInterpreterFunction":1:{s:2:"id";i:123;}'
int func_bgn = pos;
pos += 62; // 64= len of constant String after ":42:"Scribunto...."
int func_id = Parse_int_val(pos);
rv = factory.Func(func_bgn, pos, func_id);
pos += 2;
break;
default: throw err_(raw, pos, "unexpected type: {0}", Char_.XtoStr(b));
}
return rv;
} static final byte[] CONST_funct_bgn = Bry_.new_ascii_("O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:"), CONST_funct_end = Bry_.new_ascii_(";}");
int Parse_int_val(int bgn) {
pos = bgn;
pos = Chk(raw, pos + 1, Byte_ascii.Colon);
int int_end = Skip_while_num(raw, raw_len, pos, true);
int int_val = Bry_.X_to_int_or(raw, pos, int_end, Int_.MinValue);
pos = int_end;
return int_val;
}
Php_srl_itm_int Parse_int(int bgn) {
pos = bgn;
pos = Chk(raw, pos + 1, Byte_ascii.Colon);
int int_end = Skip_while_num(raw, raw_len, pos, true);
int int_val = Bry_.X_to_int_or(raw, pos, int_end, Int_.MinValue);
Php_srl_itm_int rv = factory.Int(pos, int_end, int_val);
pos = int_end;
return rv;
}
int Chk(byte[] raw, int i, byte expd) {
byte actl = raw[i];
if (actl == expd)
return i + 1;
else
throw err_(raw, i, "expected '{0}' but got '{1}'", Char_.XtoStr(expd), Char_.XtoStr(actl));
}
int Skip_while_num(byte[] raw, int raw_len, int bgn, boolean num_is_int) {
int num_len = 1;
for (int i = bgn; i < raw_len; i++) {
byte b = raw[i];
switch (b) {
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
break;
case Byte_ascii.Dot:
case Byte_ascii.Dash:
break;
default:
if (num_is_int && num_len < 11) {
return i;
}
else
return i;
}
}
throw err_(raw, raw_len, raw_len, "skip_ws found eos");
}
Err err_(byte[] raw, int bgn, String fmt, Object... args) {return err_(raw, bgn, raw.length, fmt, args);}
Err err_(byte[] raw, int bgn, int raw_len, String fmt, Object... args) {
String msg = String_.Format(fmt, args) + " " + Int_.XtoStr(bgn) + " " + String_.new_utf8_len_safe_(raw, bgn, 20);
return Err_.new_(msg);
}
}
class Php_srl_factory {
public Php_srl_itm Nil() {return Php_srl_itm_nil.Nil;}
public Php_srl_itm Bool_n() {return Php_srl_itm_bool.Bool_n;}
public Php_srl_itm Bool_y() {return Php_srl_itm_bool.Bool_y;}
public Php_srl_itm_int Int(int bgn, int end, int v) {return new Php_srl_itm_int(bgn, end, v);}
public Php_srl_itm Double(int bgn, int end, double v) {return new Php_srl_itm_double(bgn, end, v);}
public Php_srl_itm Str(int bgn, int end) {return new Php_srl_itm_str(bgn, end, null);}
public Php_srl_itm Str(int bgn, int end, String v) {return new Php_srl_itm_str(bgn, end, v);}
public Php_srl_itm_func Func(int bgn, int end, int v) {return new Php_srl_itm_func(bgn, end, v);}
public Php_srl_itm_ary Ary(int bgn, int end) {return new Php_srl_itm_ary(bgn, end);}
public Php_srl_itm_kv Kv() {return new Php_srl_itm_kv();}
}

View File

@@ -0,0 +1,112 @@
/*
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.php; import gplx.*;
import org.junit.*;
public class Php_srl_parser_tst {
Php_srl_parser_fxt fxt = new Php_srl_parser_fxt();
@Before public void init() {fxt.Clear();}
@Test public void Nil() {fxt.Test_parse("N;", fxt.itm_nil_());}
@Test public void Bool_y() {fxt.Test_parse("b:1;", fxt.itm_bool_y_());}
@Test public void Bool_n() {fxt.Test_parse("b:0;", fxt.itm_bool_n_());}
@Test public void Num_int() {fxt.Test_parse("i:123;", fxt.itm_int_(123));}
@Test public void Num_int_neg() {fxt.Test_parse("i:-123;", fxt.itm_int_(-123));}
@Test public void Num_double() {fxt.Test_parse("d:1.23;", fxt.itm_double_(1.23d));}
@Test public void Num_double_inf_pos(){fxt.Test_parse("d:INF;", fxt.itm_double_(Double_.Inf_pos));}
@Test public void Num_double_exp() {fxt.Test_parse("d:1.2e+2;", fxt.itm_double_(120));}
@Test public void Num_double_nan() {fxt.Test_parse("d:NAN;", fxt.itm_double_(Double_.NaN));}
@Test public void Str_len_3() {fxt.Test_parse("s:3:\"abc\";", fxt.itm_str_("abc"));}
@Test public void Str_len_4() {fxt.Test_parse("s:4:\"abcd\";", fxt.itm_str_("abcd"));}
@Test public void Str_len_0() {fxt.Test_parse("s:0:\"\";", fxt.itm_str_(""));}
@Test public void Ary_empty() {fxt.Test_parse("a:0:{}", fxt.itm_ary_());}
@Test public void Ary_flat_one() {fxt.Test_parse("a:1:{i:1;i:9;}", fxt.itm_ary_().Subs_add(fxt.itm_kvi_(1, fxt.itm_int_(9))));}
@Test public void Ary_flat_many() {
fxt.Test_parse(String_.Concat
( "a:3:{"
, "i:1;i:9;"
, "i:2;i:8;"
, "i:3;i:7;"
, "}"), fxt.itm_ary_().Subs_add_many
( fxt.itm_kvi_(1, fxt.itm_int_(9))
, fxt.itm_kvi_(2, fxt.itm_int_(8))
, fxt.itm_kvi_(3, fxt.itm_int_(7))
));
}
@Test public void Ary_nest_one() {
fxt.Test_parse(String_.Concat
( "a:1:{"
, "i:1;"
, "a:2:{"
, "i:1;i:9;"
, "i:2;i:8;"
, "}"
, "}"
)
, fxt.itm_ary_().Subs_add_many
( fxt.itm_kvi_(1, fxt.itm_ary_().Subs_add_many
( fxt.itm_kvi_(1, fxt.itm_int_(9))
, fxt.itm_kvi_(2, fxt.itm_int_(8))
))));
}
@Test public void Ary_key_str() {
fxt.Test_parse(String_.Concat
( "a:1:{"
, "s:3:\"abc\";"
, "i:987;"
, "}"), fxt.itm_ary_().Subs_add_many
( fxt.itm_kvs_("abc", fxt.itm_int_(987))
));
}
@Test public void Func() {
fxt.Test_parse("O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:123;}", fxt.itm_func_(123));
}
@Test public void Smoke() {
// fxt.Test_parse("a:2:{s:6:\"values\";a:1:{i:1;a:9:{s:21:\"makeProt"+"ectedEnvFuncs\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:2;}s:3:\"log\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:3;}s:14:\"clearLogBuffer\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:4;}s:5:\"setup\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:5;}s:5:\"clone\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:6;}s:15:\"getCurrentFrame\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:7;}s:13:\"executeModule\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:8;}s:15:\"executeFunction\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:9;}s:12:\"getLogBuffer\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:10;}}}s:2:\"op\";s:6:\"return\";}");
}
}
class Php_srl_parser_fxt {
public void Clear() {
parser = new Php_srl_parser();
factory = parser.Factory();
} Php_srl_parser parser; Php_srl_factory factory; Bry_bfr tmp_bfr = Bry_bfr.reset_(255);
public Php_srl_itm itm_nil_() {return factory.Nil();}
public Php_srl_itm itm_bool_n_() {return factory.Bool_n();}
public Php_srl_itm itm_bool_y_() {return factory.Bool_y();}
public Php_srl_itm itm_int_(int v) {return factory.Int(-1, -1, v);}
public Php_srl_itm itm_double_(double v) {return factory.Double(-1, -1, v);}
public Php_srl_itm itm_str_(String v) {return factory.Str(-1, -1, v);}
public Php_srl_itm itm_func_(int v) {return factory.Func(-1, -1, v);}
public Php_srl_itm_ary itm_ary_() {return factory.Ary(-1, -1);}
public Php_srl_itm_kv itm_kvi_(int k, Php_srl_itm v){return factory.Kv().Key_(itm_int_(k)).Val_(v);}
public Php_srl_itm_kv itm_kvs_(String k, Php_srl_itm v){return factory.Kv().Key_(itm_str_(k)).Val_(v);}
public void Test_parse(String raw_str, Php_srl_itm... expd_ary) {
byte[] raw = Bry_.new_utf8_(raw_str);
Php_srl_itm_ary root = parser.Parse(raw);
Php_srl_itm root_sub = root.Subs_get_at(0).Val();
root_sub.Xto_bfr(tmp_bfr, 0);
String actl = tmp_bfr.XtoStrAndClear();
String expd = Xto_str(expd_ary, 0, expd_ary.length);
Tfds.Eq_str_lines(expd, actl, actl);
}
String Xto_str(Php_srl_itm[] ary, int bgn, int end) {
for (int i = bgn; i < end; i++) {
Php_srl_itm itm = ary[i];
itm.Xto_bfr(tmp_bfr, 0);
}
return tmp_bfr.XtoStrAndClear();
}
}

View File

@@ -0,0 +1,62 @@
/*
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.php; import gplx.*;
interface Php_text_itm {
byte Tid();
int Src_bgn();
int Src_end();
void Bld(Bry_bfr bfr, byte[] src);
}
class Php_text_itm_ {
public static final byte Tid_text = 0, Tid_escaped = 1, Tid_arg = 2, Tid_utf16 = 3;
}
class Php_text_itm_text implements Php_text_itm {
public Php_text_itm_text(int src_bgn, int src_end) {this.src_bgn = src_bgn; this.src_end = src_end;}
public byte Tid() {return Php_text_itm_.Tid_text;}
public int Src_bgn() {return src_bgn;} private int src_bgn;
public int Src_end() {return src_end;} private int src_end;
public void Bld(Bry_bfr bfr, byte[] src) {bfr.Add_mid(src, src_bgn, src_end);}
}
class Php_text_itm_escaped implements Php_text_itm {
public Php_text_itm_escaped(int src_bgn, int src_end, byte literal) {this.src_bgn = src_bgn; this.src_end = src_end; this.literal = literal;}
public byte Tid() {return Php_text_itm_.Tid_escaped;}
public int Src_bgn() {return src_bgn;} private int src_bgn;
public int Src_end() {return src_end;} private int src_end;
public byte Literal() {return literal;} private byte literal;
public void Bld(Bry_bfr bfr, byte[] src) {bfr.Add_byte(literal);}
}
class Php_text_itm_utf16 implements Php_text_itm {
public Php_text_itm_utf16(int src_bgn, int src_end, byte[] literal) {this.src_bgn = src_bgn; this.src_end = src_end; this.literal = literal;}
public byte Tid() {return Php_text_itm_.Tid_utf16;}
public int Src_bgn() {return src_bgn;} private int src_bgn;
public int Src_end() {return src_end;} private int src_end;
public byte[] Literal() {return literal;} private byte[] literal;
public void Bld(Bry_bfr bfr, byte[] src) {bfr.Add(literal);}
}
class Php_text_itm_arg implements Php_text_itm {
public Php_text_itm_arg(int src_bgn, int src_end, int idx) {this.src_bgn = src_bgn; this.src_end = src_end; this.idx = idx;}
public byte Tid() {return Php_text_itm_.Tid_escaped;}
public int Src_bgn() {return src_bgn;} private int src_bgn;
public int Src_end() {return src_end;} private int src_end;
public int Idx() {return idx;} private int idx;
public void Bld(Bry_bfr bfr, byte[] src) {
bfr.Add_byte(Byte_ascii.Tilde).Add_byte(Byte_ascii.Curly_bgn)
.Add_int_variable(idx - ListAdp_.Base1) // php is super 1
.Add_byte(Byte_ascii.Curly_end);
}
}

View File

@@ -0,0 +1,126 @@
/*
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.php; import gplx.*;
public class Php_text_itm_parser {
public static final byte Rslt_orig = 0, Rslt_dirty = 1, Rslt_fmt = 2;
public byte[] Parse_as_bry(ListAdp tmp_list, byte[] raw, Byte_obj_ref rslt_ref, Bry_bfr tmp_bfr) {
Parse(tmp_list, raw, rslt_ref);
byte[] rv = raw;
switch (rslt_ref.Val()) {
case Rslt_orig: break;
case Rslt_dirty:
case Rslt_fmt:
tmp_bfr.Clear();
int tmp_list_len = tmp_list.Count();
for (int i = 0; i < tmp_list_len; i++) {
Php_text_itm itm = (Php_text_itm)tmp_list.FetchAt(i);
itm.Bld(tmp_bfr, raw);
}
rv = tmp_bfr.XtoAryAndClear();
break;
}
return rv;
}
public void Parse(ListAdp tmp_list, byte[] raw) {
Parse(tmp_list, raw, Byte_obj_ref.zero_());
}
public void Parse(ListAdp tmp_list, byte[] raw, Byte_obj_ref rslt) {
tmp_list.Clear();
int raw_len = raw.length; int raw_last = raw_len - 1;
int txt_bgn = -1;
byte rslt_val = Rslt_orig;
for (int i = 0; i < raw_len; i++) {
byte b = raw[i];
switch (b) {
case Byte_ascii.Backslash:
if (txt_bgn != -1) {tmp_list.Add(new Php_text_itm_text(txt_bgn, i)); txt_bgn = -1; rslt_val = Rslt_dirty;}
if (i == raw_last) throw Err_mgr._.fmt_auto_(GRP_KEY, "backslash_is_last_char", String_.new_utf8_(raw));
int next_pos = i + 1;
byte next_char = raw[next_pos];
switch (next_char) {
case Byte_ascii.Ltr_N:
case Byte_ascii.Ltr_n: next_char = Byte_ascii.NewLine; break;
case Byte_ascii.Ltr_T:
case Byte_ascii.Ltr_t: next_char = Byte_ascii.Tab; break;
case Byte_ascii.Ltr_R:
case Byte_ascii.Ltr_r: next_char = Byte_ascii.CarriageReturn; break;
case Byte_ascii.Ltr_U:
case Byte_ascii.Ltr_u: { // EX: "\u007C"
rslt_val = Rslt_dirty;
Parse_utf16(tmp_list, raw, next_pos + 1, raw_len); // +1 to skip u
i = next_pos + 4; // +4 to skip utf16 seq; EX: \u007C; +4 for 007C
continue;
}
case Byte_ascii.Ltr_X:
case Byte_ascii.Ltr_x: { // EX: "\xc2"
rslt_val = Rslt_dirty;
byte[] literal = Bry_.Add(CONST_utf_prefix, Bry_.Mid(raw, next_pos + 1, next_pos + 3));
tmp_list.Add(new Php_text_itm_utf16(i, i + 4, literal));
i = next_pos + 2; // +2 to skip rest; EX: \xc2; +2 for c2
continue;
}
}
tmp_list.Add(new Php_text_itm_escaped(i, next_pos, next_char)); rslt_val = Rslt_dirty;
i = next_pos;
break;
case Byte_ascii.Dollar:
if (txt_bgn != -1) {tmp_list.Add(new Php_text_itm_text(txt_bgn, i)); txt_bgn = -1;}
if (i == raw_last) {
//throw Err_mgr._.fmt_auto_(GRP_KEY, "dollar_is_last_char", String_.new_utf8_(raw));
}
int int_end = Find_fwd_non_int(raw, i + 1, raw_len); // +1 to search after $
int int_val = Bry_.X_to_int_or(raw, i + 1, int_end, -1); // +1 to search after $
if (int_val == -1) {
tmp_list.Add(new Php_text_itm_text(i, i + 1));
continue;
}
//throw Err_mgr._.fmt_auto_(GRP_KEY, "invalid_arg", String_.new_utf8_(raw));
tmp_list.Add(new Php_text_itm_arg(i, int_end, int_val));
rslt_val = Rslt_fmt;
i = int_end - 1; // -1 b/c i++ in for loop
break;
default:
if (txt_bgn == -1) txt_bgn = i;
break;
}
}
if (txt_bgn != -1) {tmp_list.Add(new Php_text_itm_text(txt_bgn, raw_len)); txt_bgn = -1; rslt_val = Rslt_dirty;}
rslt.Val_(rslt_val);
} private static final byte[] CONST_utf_prefix = Bry_.new_ascii_("\\u00");
private void Parse_utf16(ListAdp rv, byte[] src, int bgn, int src_len) {
int end = bgn + 4;
if (end >= src_len) throw Err_mgr._.fmt_auto_(GRP_KEY, "utf16_parse", String_.new_utf8_(src));
int v = Int_.Xto_int_hex(src, bgn, end); // +2; skip "\" + "u"
byte[] literal = gplx.intl.Utf16_.Encode_int_to_bry(v);
rv.Add(new Php_text_itm_utf16(bgn, end, literal));
}
private static final String GRP_KEY = "xowa.php.quote_text_parser";
public static int Find_fwd_non_int(byte[] src, int bgn, int end) {
for (int i = bgn; i < end; i++) {
byte b = src[i];
switch (b) {
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
break;
default:
return i;
}
}
return end;
}
}

View File

@@ -0,0 +1,39 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.php; import gplx.*;
import org.junit.*;
public class Php_text_itm_tst {
@Test public void Basic() {Tst_("abcde", "abcde");}
@Test public void Escaped() {Tst_("a\\$b\\\"c\\td\\ne", "a$b\"c\td\ne");}
@Test public void Fmt() {Tst_("a$1b$2c", "a~{0}b~{1}c");}
@Test public void Utf16() {Tst_("a\\u007Cd", "a|d");}
@Test public void Utf8_nbsp() {Tst_("a\\xc2\\xa0d", "a\\u00c2\\u00a0d");}
private void Tst_(String raw_str, String expd) {
Php_text_itm_parser parser = new Php_text_itm_parser();
ListAdp list = ListAdp_.new_();
byte[] raw = Bry_.new_utf8_(raw_str);
parser.Parse(list, raw);
Bry_bfr bfr = Bry_bfr.reset_(255);
int list_len = list.Count();
for (int i = 0; i < list_len; i++) {
Php_text_itm itm = (Php_text_itm)list.FetchAt(i);
itm.Bld(bfr, raw);
}
Tfds.Eq(expd, bfr.XtoStrAndClear());
}
}

View File

@@ -0,0 +1,74 @@
/*
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.php; import gplx.*;
public interface Php_tkn {
byte Tkn_tid();
int Src_bgn();
int Src_end();
}
class Php_tkn_ {
public static final byte Tid_txt = 1, Tid_declaration = 2, Tid_ws = 3, Tid_comment = 4, Tid_var = 5, Tid_eq = 6, Tid_eq_kv = 7, Tid_semic = 8, Tid_comma = 9, Tid_paren_bgn = 10, Tid_paren_end = 11, Tid_null = 12, Tid_false = 13, Tid_true = 14, Tid_ary = 15, Tid_num = 16, Tid_quote = 17, Tid_brack_bgn = 18, Tid_brack_end = 19;
public static String Xto_str(byte tid) {return Byte_.XtoStr(tid);}
}
abstract class Php_tkn_base implements Php_tkn {
public abstract byte Tkn_tid();
public int Src_bgn() {return src_bgn;} private int src_bgn;
public int Src_end() {return src_end;} public void Src_end_(int v) {this.src_end = v;} private int src_end;
public void Src_rng_(int src_bgn, int src_end) {this.src_bgn = src_bgn; this.src_end = src_end;}
}
class Php_tkn_generic extends Php_tkn_base {
public Php_tkn_generic(int src_bgn, int src_end, byte tid) {this.Src_rng_(src_bgn, src_end); this.tid = tid;}
@Override public byte Tkn_tid() {return tid;} private byte tid;
}
class Php_tkn_txt extends Php_tkn_base {
public Php_tkn_txt(int src_bgn, int src_end) {this.Src_rng_(src_bgn, src_end);}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_txt;}
}
class Php_tkn_ws extends Php_tkn_base {
public Php_tkn_ws(int src_bgn, int src_end, byte ws_tid) {this.Src_rng_(src_bgn, src_end); this.ws_tid = ws_tid;}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_ws;}
public byte Ws_tid() {return ws_tid;} private byte ws_tid;
public static final byte Tid_space = 0, Tid_nl = 1, Tid_tab = 2, Tid_cr = 3;
}
class Php_tkn_comment extends Php_tkn_base {
public Php_tkn_comment(int src_bgn, int src_end, byte comment_tid) {this.Src_rng_(src_bgn, src_end); this.comment_tid = comment_tid;}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_comment;}
public byte Comment_tid() {return comment_tid;} private byte comment_tid;
public static final byte Tid_null = 0, Tid_mult = 1, Tid_slash = 2, Tid_hash = 3;
}
class Php_tkn_var extends Php_tkn_base {
public Php_tkn_var(int src_bgn, int src_end) {this.Src_rng_(src_bgn, src_end);}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_var;}
public byte[] Var_name(byte[] src) {return Bry_.Mid(src, this.Src_bgn() + 1, this.Src_end());} // NOTE: assume vars are of form $abc; +1 to skip first $
}
class Php_tkn_num extends Php_tkn_base {
public Php_tkn_num(int src_bgn, int src_end) {this.Src_rng_(src_bgn, src_end);}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_num;}
public int Num_val_int(byte[] src) {return Bry_.X_to_int_or(src, this.Src_bgn(), this.Src_end(), Int_.MinValue);}
}
class Php_tkn_quote extends Php_tkn_base {
public Php_tkn_quote(int src_bgn, int src_end, byte quote_tid) {this.Src_rng_(src_bgn, src_end); this.quote_tid = quote_tid;}
@Override public byte Tkn_tid() {return Php_tkn_.Tid_quote;}
public byte Quote_tid() {return quote_tid;} private byte quote_tid;
public byte[] Quote_text(byte[] src) {return Bry_.Mid(src, this.Src_bgn() + 1, this.Src_end() - 1);} // NOTE: assume quote are of form 'abc'; +1, -1 to skip flanking chars
public static final byte Tid_null = 0, Tid_mult = 1, Tid_slash = 2, Tid_hash = 3;
}
class Php_tkn_declaration extends Php_tkn_base {
@Override public byte Tkn_tid() {return Php_tkn_.Tid_declaration;}
public static final Php_tkn_declaration _ = new Php_tkn_declaration();
}

View File

@@ -0,0 +1,28 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.php; import gplx.*;
class Php_tkn_factory {
public Php_tkn_generic Generic(int bgn, int end, byte tid) {return new Php_tkn_generic(bgn, end, tid);}
public Php_tkn_txt Txt(int bgn, int end) {return new Php_tkn_txt(bgn, end);}
public Php_tkn Declaration(int bgn, int end) {return Php_tkn_declaration._;}
public Php_tkn_ws Ws(int bgn, int end, byte ws_tid) {return new Php_tkn_ws(bgn, end, ws_tid);}
public Php_tkn_var Var(int bgn, int end) {return new Php_tkn_var(bgn, end);}
public Php_tkn_num Num(int bgn, int end) {return new Php_tkn_num(bgn, end);}
public Php_tkn_comment Comment(int bgn, int end, byte comment_tid) {return new Php_tkn_comment(bgn, end, comment_tid);}
public Php_tkn_quote Quote(int bgn, int end, byte quote_tid) {return new Php_tkn_quote(bgn, end, quote_tid);}
}

View File

@@ -0,0 +1,35 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.php; import gplx.*;
public interface Php_tkn_wkr {
void Init(Php_ctx ctx);
void Process(Php_tkn tkn);
void Msg_many(byte[] src, int bgn, int end, Gfo_msg_itm itm, Object... args);
}
class Php_tkn_wkr_tkn implements Php_tkn_wkr {
public void Init(Php_ctx ctx) {}
public ListAdp List() {return lines;} ListAdp lines = ListAdp_.new_();
public Gfo_msg_log Msg_log() {return msg_log;} Gfo_msg_log msg_log = new Gfo_msg_log("gplx.php");
public void Clear() {lines.Clear(); msg_log.Clear();}
public void Process(Php_tkn tkn) {
lines.Add(tkn);
}
public void Msg_many(byte[] src, int bgn, int end, Gfo_msg_itm itm, Object... args) {
msg_log.Add_itm_many(itm, src, bgn, end, args);
}
}

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.srls.dsvs; import gplx.*; import gplx.srls.*;
public interface Dsv_fld_parser {
void Init(byte fld_dlm, byte row_dlm);
int Parse(Dsv_tbl_parser tbl_parser, Dsv_wkr_base mgr, byte[] src, int pos, int src_len, int fld_idx, int fld_bgn);
}

View File

@@ -0,0 +1,85 @@
/*
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.srls.dsvs; import gplx.*; import gplx.srls.*;
public class Dsv_fld_parser_ {
public static final Dsv_fld_parser Bry_parser = Dsv_fld_parser_bry._;
public static final Dsv_fld_parser Int_parser = Dsv_fld_parser_int._;
public static Err err_fld_unhandled(Dsv_fld_parser parser, Dsv_wkr_base wkr, int fld_idx, byte[] src, int bgn, int end) {
throw Err_.new_fmt_("fld unhandled; parser={0} wkr={1} fld_idx={2} val={3}", ClassAdp_.NameOf_obj(parser), ClassAdp_.NameOf_obj(wkr), fld_idx, String_.new_utf8_(src, bgn, end));
}
}
class Dsv_fld_parser_bry implements Dsv_fld_parser {
private byte fld_dlm = Byte_ascii.Pipe, row_dlm = Byte_ascii.NewLine;
public void Init(byte fld_dlm, byte row_dlm) {
this.fld_dlm = fld_dlm; this.row_dlm = row_dlm;
}
public int Parse(Dsv_tbl_parser parser, Dsv_wkr_base wkr, byte[] src, int pos, int src_len, int fld_idx, int fld_bgn) {
while (true) {
boolean pos_is_last = pos == src_len;
byte b = pos_is_last ? row_dlm : src[pos];
if (b == fld_dlm) {
boolean pass = wkr.Write_bry(parser, fld_idx, src, fld_bgn, pos);
if (!pass) throw Dsv_fld_parser_.err_fld_unhandled(this, wkr, fld_idx, src, fld_bgn, pos);
int rv = pos + 1; // fld_dlm is always 1 byte
parser.Update_by_fld(rv);
return rv;
}
else if (b == row_dlm) {
boolean pass = wkr.Write_bry(parser, fld_idx, src, fld_bgn, pos);
if (!pass) throw Dsv_fld_parser_.err_fld_unhandled(this, wkr, fld_idx, src, fld_bgn, pos);
wkr.Commit_itm(parser, pos);
int rv = pos + 1; // row_dlm is always 1 byte
parser.Update_by_row(rv);
return rv;
}
else
++pos;
}
}
public static final Dsv_fld_parser_bry _ = new Dsv_fld_parser_bry(); Dsv_fld_parser_bry() {}
}
class Dsv_fld_parser_int implements Dsv_fld_parser {
private byte fld_dlm = Byte_ascii.Pipe, row_dlm = Byte_ascii.NewLine;
public void Init(byte fld_dlm, byte row_dlm) {
this.fld_dlm = fld_dlm; this.row_dlm = row_dlm;
}
public int Parse(Dsv_tbl_parser parser, Dsv_wkr_base wkr, byte[] src, int pos, int src_len, int fld_idx, int fld_bgn) {
while (true) {
boolean pos_is_last = pos == src_len;
byte b = pos_is_last ? row_dlm : src[pos];
if (b == fld_dlm) {
boolean pass = wkr.Write_int(parser, fld_idx, pos, Bry_.X_to_int_or(src, fld_bgn, pos, -1));
if (!pass) throw Dsv_fld_parser_.err_fld_unhandled(this, wkr, fld_idx, src, fld_bgn, pos);
int rv = pos + 1; // fld_dlm is always 1 byte
parser.Update_by_fld(rv);
return rv;
}
else if (b == row_dlm) {
boolean pass = wkr.Write_int(parser, fld_idx, pos, Bry_.X_to_int_or(src, fld_bgn, pos, -1));
if (!pass) throw Dsv_fld_parser_.err_fld_unhandled(this, wkr, fld_idx, src, fld_bgn, pos);
wkr.Commit_itm(parser, pos);
int rv = pos + 1; // row_dlm is always 1 byte
parser.Update_by_row(rv);
return rv;
}
else
++pos;
}
}
public static final Dsv_fld_parser_int _ = new Dsv_fld_parser_int(); Dsv_fld_parser_int() {}
}

View File

@@ -0,0 +1,79 @@
/*
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.srls.dsvs; import gplx.*; import gplx.srls.*;
public class Dsv_tbl_parser implements GfoInvkAble, RlsAble {
private Dsv_wkr_base mgr;
private Dsv_fld_parser[] fld_parsers = new Dsv_fld_parser[2];
public byte[] Src() {return src;} private byte[] src;
public int Fld_bgn() {return fld_bgn;} private int fld_bgn = 0;
public int Fld_idx() {return fld_idx;} private int fld_idx = 0;
public int Row_bgn() {return row_bgn;} private int row_bgn = 0;
public int Row_idx() {return row_idx;} private int row_idx = 0;
public boolean Skip_blank_lines() {return skip_blank_lines;} public Dsv_tbl_parser Skip_blank_lines_(boolean v) {skip_blank_lines = v; return this;} private boolean skip_blank_lines = true;
public byte Fld_dlm() {return fld_dlm;} public Dsv_tbl_parser Fld_dlm_(byte v) {fld_dlm = v; return this;} private byte fld_dlm = Byte_ascii.Pipe;
public byte Row_dlm() {return row_dlm;} public Dsv_tbl_parser Row_dlm_(byte v) {row_dlm = v; return this;} private byte row_dlm = Byte_ascii.NewLine;
public void Init(Dsv_wkr_base mgr, Dsv_fld_parser... fld_parsers) {
this.mgr = mgr;
this.fld_parsers = fld_parsers;
int fld_parsers_len = fld_parsers.length;
for (int i = 0; i < fld_parsers_len; i++)
fld_parsers[i].Init(fld_dlm, row_dlm);
}
public void Clear() {
fld_bgn = fld_idx = row_bgn = row_idx = 0;
}
public Err Err_row_bgn(String fmt, int pos) {
return Err_.new_fmt_(fmt + "; line={0}", String_.new_utf8_(src, row_bgn, pos));
}
public void Update_by_fld(int pos) {
fld_bgn = pos;
++fld_idx;
}
public void Update_by_row(int pos) {
row_bgn = fld_bgn = pos;
++row_idx;
fld_idx = 0;
}
public void Parse(byte[] src) {
this.src = src;
int src_len = src.length;
int pos = 0;
while (pos < src_len) {
if (fld_idx == 0 && skip_blank_lines) { // row committed; skip blank lines
while (pos < src_len) {
if (src[pos] == row_dlm) {
++pos;
row_bgn = fld_bgn = pos;
}
else
break;
}
}
Dsv_fld_parser fld_parser = fld_parsers[fld_idx];
pos = fld_parser.Parse(this, mgr, src, pos, src_len, fld_idx, fld_bgn);
}
}
public void Rls() {
src = null; fld_parsers = null; mgr = null;
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_load_by_str)) Parse(m.ReadBry("v"));
else return GfoInvkAble_.Rv_unhandled;
return this;
} private static final String Invk_load_by_str = "load_by_str";
}

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