mirror of https://github.com/gnosygnu/xowa
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
94 lines
4.1 KiB
94 lines
4.1 KiB
/*
|
|
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.brys.fmts; import gplx.*; import gplx.core.*; import gplx.core.brys.*;
|
|
public class Bry_fmt_parser_ {
|
|
public static Bry_fmt_itm[] Parse(byte escape, byte grp_bgn, byte grp_end, Bfr_fmt_arg[] args, byte[][] keys, byte[] src) {
|
|
int src_len = src.length;
|
|
int pos = 0;
|
|
int txt_bgn = -1;
|
|
int key_idx = -1;
|
|
Hash_adp_bry keys_hash = Hash_adp_bry.cs();
|
|
List_adp list = List_adp_.new_();
|
|
while (true) {
|
|
boolean is_last = pos == src_len;
|
|
byte b = is_last ? escape : src[pos];
|
|
if (b == escape) {
|
|
if (txt_bgn != -1) list.Add(new Bry_fmt_itm(Bry_fmt_itm.Tid__txt, txt_bgn, pos));
|
|
if (is_last) break;
|
|
++pos;
|
|
if (pos == src_len) throw Err_.new_("bry_fmtr", "fmt cannot end with escape", "escape", Byte_ascii.To_str(escape), "raw", src);
|
|
b = src[pos];
|
|
if (b == escape) {
|
|
list.Add(new Bry_fmt_itm(Bry_fmt_itm.Tid__txt, pos, pos + 1));
|
|
++pos;
|
|
}
|
|
else if (b == grp_bgn) {
|
|
++pos;
|
|
int grp_end_pos = Bry_find_.Find_fwd(src, grp_end, pos); if (grp_end_pos == Bry_find_.Not_found) throw Err_.new_("bry_fmtr", "grp_end missing", "grp_bgn", Byte_ascii.To_str(grp_bgn), "grp_end", Byte_ascii.To_str(grp_end), "raw", src);
|
|
byte[] key_bry = Bry_.Mid(src, pos, grp_end_pos);
|
|
Bry_fmt_itm key_itm = (Bry_fmt_itm)keys_hash.Get_by_bry(key_bry);
|
|
if (key_itm == null) {
|
|
key_itm = new Bry_fmt_itm(Bry_fmt_itm.Tid__key, pos - 2, grp_end_pos + 1); // -2 to get "~{"; +1 to get "}"
|
|
key_itm.Key_idx = ++key_idx;
|
|
keys_hash.Add(key_bry, key_itm);
|
|
}
|
|
list.Add(key_itm);
|
|
pos = grp_end_pos + 1;
|
|
}
|
|
else throw Err_.new_("bry_fmtr", "escape must be followed by escape or group_bgn", "escape", Byte_ascii.To_str(escape), "group_bgn", Byte_ascii.To_str(escape), "raw", src);
|
|
txt_bgn = -1;
|
|
}
|
|
else {
|
|
if (txt_bgn == -1) txt_bgn = pos;
|
|
++pos;
|
|
}
|
|
}
|
|
Bry_fmt_itm[] rv = (Bry_fmt_itm[])list.To_ary_and_clear(Bry_fmt_itm.class);
|
|
int len = args.length;
|
|
for (int i = 0; i < len; ++i) {
|
|
Bfr_fmt_arg arg = args[i];
|
|
Bry_fmt_itm key_itm = (Bry_fmt_itm)keys_hash.Get_by(arg.Key); if (key_itm == null) continue;
|
|
key_itm.Tid = Bry_fmt_itm.Tid__arg;
|
|
key_itm.Arg = arg.Arg;
|
|
}
|
|
len = keys.length;
|
|
for (int i = 0; i < len; ++i) {
|
|
byte[] key = keys[i];
|
|
Bry_fmt_itm key_itm = (Bry_fmt_itm)keys_hash.Get_by(key); if (key_itm == null) continue; // NOTE: ignore missing keys; EX: fmt=a~{b}c keys=b,d; do not fail b/c ~{d} is not in fmt; allows redefining from tests
|
|
key_itm.Key_idx = i;
|
|
}
|
|
return rv;
|
|
}
|
|
public static byte[][] Parse_keys(byte[] src) {
|
|
Ordered_hash list = Ordered_hash_.New_bry();
|
|
int src_len = src.length;
|
|
int pos = -1;
|
|
while (pos < src_len) {
|
|
int lhs_pos = Bry_find_.Move_fwd(src, Bry_arg_lhs, pos + 1, src_len);
|
|
if (lhs_pos == Bry_find_.Not_found) break; // no more "~{"
|
|
int rhs_pos = Bry_find_.Find_fwd(src, Byte_ascii.Curly_end, lhs_pos, src_len);
|
|
if (rhs_pos == Bry_find_.Not_found) throw Err_.new_("bry_fmt", "unable to find closing }", "src", src);
|
|
if (rhs_pos - lhs_pos == 0) throw Err_.new_("bry_fmt", "{} will result in empty key", "src", src);
|
|
byte[] key = Bry_.Mid(src, lhs_pos, rhs_pos);
|
|
if (!list.Has(key)) list.Add(key, key);
|
|
pos = rhs_pos + 1;
|
|
}
|
|
return (byte[][])list.To_ary(byte[].class);
|
|
} private static final byte[] Bry_arg_lhs = Bry_.new_a7("~{");
|
|
}
|