/* XOWA: the XOWA Offline Wiki Application Copyright (C) 2012-2017 gnosygnu@gmail.com XOWA is licensed under the terms of the General Public License (GPL) Version 3, or alternatively under the terms of the Apache License Version 2.0. You may use XOWA according to either of these licenses as is most appropriate for your project on a case-by-case basis. The terms of each license can be found in the source code repository: GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt */ package gplx.xowa.parsers.vnts; import gplx.*; import gplx.xowa.*; import gplx.xowa.parsers.*; import gplx.core.btries.*; import gplx.core.primitives.*; import gplx.xowa.langs.vnts.*; class Vnt_convert_rule { // REF.MW: /languages/LanguageConverter.php|ConverterRule private final Vnt_flag_parser flag_parser = new Vnt_flag_parser(); private final Vnt_flag_code_mgr flag_codes = new Vnt_flag_code_mgr(); private final Vnt_flag_lang_mgr flag_langs = new Vnt_flag_lang_mgr(); private final Vnt_rule_parser rule_parser = new Vnt_rule_parser(); private final Vnt_rule_undi_mgr rule_undis = new Vnt_rule_undi_mgr(); private final Vnt_rule_bidi_mgr rule_bidis = new Vnt_rule_bidi_mgr(); private final Bry_bfr tmp_bfr = Bry_bfr_.New(); private final Ordered_hash cnv_marked_hash = Ordered_hash_.New_bry(); private Vnt_convert_lang converter; private Xol_vnt_regy vnt_regy; private byte[] vnt_key; private Vnt_log_mgr log_mgr; private byte[] rule_raw; private boolean rule_parser_init = true; public byte[] Display() {return display;} private byte[] display; public byte[] Title() {return title;} private byte[] title; public byte Action() {return action;} private byte action; public Vnt_rule_undi_mgr Cnv_tbl() {return cnv_tbl;} private final Vnt_rule_undi_mgr cnv_tbl = new Vnt_rule_undi_mgr(); public Vnt_convert_rule(Vnt_convert_lang converter, Xol_vnt_regy vnt_regy, Vnt_log_mgr log_mgr) { this.converter = converter; this.log_mgr = log_mgr; this.vnt_regy = vnt_regy; flag_parser.Init(log_mgr); rule_parser.Init(log_mgr, vnt_regy); } public void Parse(Xol_vnt_itm vnt_itm, byte[] src, int src_bgn, int src_end) { if (rule_parser_init) { // WORKAROUND: initialized vnt_regy on first parse; initializing during constructor doesn't work b/c vnt_regy == 0 due to load order of gfs script; DATE:2016-11-09 rule_parser_init = false; rule_parser.Init(log_mgr, vnt_regy); } this.vnt_key = vnt_itm.Key(); this.display = this.title = null; this.action = Byte_ascii.Null; int pipe_pos = Bry_find_.Find_fwd(src, Byte_ascii.Pipe, src_bgn, src_end); flag_parser.Parse(flag_codes, flag_langs, vnt_regy, src, src_bgn, pipe_pos); int rule_bgn = pipe_pos == -1 ? src_bgn : pipe_pos + 1; this.rule_raw = Bry_.Mid(src, rule_bgn, src_end); int flag_langs_count = flag_langs.Count(); if (flag_langs_count > 0) { // vnts exist in flag; EX: -{zh-hans;zh-hant|text}- if (flag_langs.Has(vnt_key)) rule_raw = converter.Auto_convert(vnt_itm, rule_raw); // convert rule text to current language; EX:-{|convert}- else { byte[][] fallbacks = vnt_itm.Fallback_ary(); int fallbacks_len = fallbacks.length; for (int i = 0; i < fallbacks_len; ++i) { byte[] fallback = fallbacks[i]; if (flag_langs.Has(fallback)) { Xol_vnt_itm fallback_itm = (Xol_vnt_itm)vnt_regy.Get_by(fallback); rule_raw = converter.Auto_convert(fallback_itm, rule_raw); break; } } } flag_codes.Limit(Vnt_flag_code_.Tid_raw); } rule_parser.Clear(rule_undis, rule_bidis, rule_raw); if (!flag_codes.Get(Vnt_flag_code_.Tid_raw) && !flag_codes.Get(Vnt_flag_code_.Tid_name)) rule_parser.Parse(src, rule_bgn, src_end); if (log_mgr != null) log_mgr.Log_rule(src_bgn, src_end, Bry_.Mid(src, src_bgn, src_end), flag_codes, flag_langs, rule_undis, rule_bidis); if (rule_undis.Has_none() && rule_bidis.Has_none()) { if ( flag_codes.Get(Vnt_flag_code_.Tid_add) || flag_codes.Get(Vnt_flag_code_.Tid_del) ) { // fill all variants if text in -{A/H/-|text} without rules for (int i = 0; i < flag_langs_count; ++i) { Xol_vnt_itm itm = flag_langs.Get_at(i); rule_bidis.Set(itm.Key(), rule_raw); } } else if ( !flag_codes.Get(Vnt_flag_code_.Tid_name) && !flag_codes.Get(Vnt_flag_code_.Tid_title) ) { flag_codes.Limit(Vnt_flag_code_.Tid_raw); } } int flag_count = Vnt_flag_code_.Tid__max; for (int flag = 0; flag < flag_count; ++flag) { if (!flag_codes.Get(flag)) continue; switch (flag) { case Vnt_flag_code_.Tid_raw: display = rule_parser.Raw(); break; // if we don't do content convert, still strip the -{}- tags case Vnt_flag_code_.Tid_name: // process N flag: output current variant name byte[] vnt_key_trim = Bry_.Trim(rule_parser.Raw()); Xol_vnt_itm vnt_itm_trim = vnt_regy.Get_by(vnt_key_trim); display = vnt_itm_trim == null ? display = Bry_.Empty : vnt_itm_trim.Name(); break; case Vnt_flag_code_.Tid_descrip: display = Make_descrip(); break; // process D flag: output rules description case Vnt_flag_code_.Tid_hide: display = Bry_.Empty; break; // process H,- flag or T only: output nothing case Vnt_flag_code_.Tid_del: display = Bry_.Empty; action = Byte_ascii.Dash; break; case Vnt_flag_code_.Tid_add: display = Bry_.Empty; action = Byte_ascii.Plus; break; case Vnt_flag_code_.Tid_show: display = Make_converted(vnt_itm); break; case Vnt_flag_code_.Tid_title: display = Bry_.Empty; title = Make_title(vnt_itm); break; default: break; // ignore unknown flags (but see error case below) } } if (display == null) display = Bry_.Add(Bry__error_bgn, Bry__error_end); // wfMessage( 'converter-manual-rule-error' )->inContentLanguage()->escaped() Make_conv_tbl(); } private void Make_conv_tbl() { if (rule_undis.Has_none() && rule_bidis.Has_none()) return; // Special case optimisation cnv_tbl.Clear(); cnv_marked_hash.Clear(); int vnt_regy_len = vnt_regy.Len(); for (int i = 0; i < vnt_regy_len; ++i) { Xol_vnt_itm vnt = vnt_regy.Get_at(i); byte[] vnt_key = vnt.Key(); // bidi: fill in missing variants with fallbacks byte[] bidi_bry = rule_bidis.Get_text_by_key_or_null(vnt_key); if (bidi_bry == null) { bidi_bry = rule_bidis.Get_text_by_ary_or_null(vnt.Fallback_ary()); if (bidi_bry != null) rule_bidis.Set(vnt_key, bidi_bry); } if (bidi_bry != null) { int marked_len = cnv_marked_hash.Count(); for (int j = 0; j < marked_len; ++j) { Xol_vnt_itm marked_itm = (Xol_vnt_itm)cnv_marked_hash.Get_at(j); byte[] marked_key = marked_itm.Key(); byte[] marked_bry = rule_bidis.Get_text_by_key_or_null(marked_key); byte[] cur_bidi_bry = rule_bidis.Get_text_by_key_or_null(vnt_key); if (vnt.Dir() == Xol_vnt_dir_.Tid__bi) cnv_tbl.Set(vnt_key, marked_bry, cur_bidi_bry); if (marked_itm.Dir() == Xol_vnt_dir_.Tid__bi) cnv_tbl.Set(marked_key, cur_bidi_bry, marked_bry); } cnv_marked_hash.Add(vnt_key, vnt); } // undi: fill to convert tables byte[] undi_bry = rule_undis.Get_text_by_key_or_null(vnt_key); if (vnt.Dir() != Xol_vnt_dir_.Tid__none && undi_bry != null) { Vnt_rule_undi_grp undi_grp = rule_undis.Get_by(vnt_key); int undi_grp_len = undi_grp.Len(); for (int j = 0; j < undi_grp_len; ++j) { Vnt_rule_undi_itm undi_itm = undi_grp.Get_at(j); cnv_tbl.Set(vnt_key, undi_itm.Src(), undi_itm.Trg()); } } } } private byte[] Make_descrip() { int len = rule_bidis.Len(); for (int i = 0; i < len; ++i) { Vnt_rule_bidi_itm bidi_itm = rule_bidis.Get_at(i); Xol_vnt_itm vnt_itm = vnt_regy.Get_by(bidi_itm.Vnt()); tmp_bfr.Add(vnt_itm.Name()).Add_byte_colon().Add(bidi_itm.Text()).Add_byte_semic(); } len = rule_undis.Len(); for (int i = 0; i < len; ++i) { Vnt_rule_undi_grp undi_grp = rule_undis.Get_at(i); int sub_len = undi_grp.Len(); for (int j = 0; j < sub_len; ++j) { Vnt_rule_undi_itm undi_itm = (Vnt_rule_undi_itm)undi_grp.Get_at(j); Xol_vnt_itm undi_vnt = vnt_regy.Get_by(undi_grp.Vnt()); tmp_bfr.Add(undi_itm.Src()).Add(Bry__undi_spr).Add(undi_vnt.Name()).Add_byte_colon().Add(undi_itm.Trg()).Add_byte_semic(); } } return tmp_bfr.To_bry_and_clear(); } private byte[] Make_title(Xol_vnt_itm vnt) { if (vnt.Idx() == 0) { // for mainLanguageCode; EX: "zh" byte[] rv = rule_bidis.Get_text_by_key_or_null(vnt.Key()); return rv == null ? rule_undis.Get_text_by_key_or_null(vnt.Key()) : rv; } else return Make_converted(vnt); } private byte[] Make_converted(Xol_vnt_itm vnt) { if (rule_bidis.Len() == 0 && rule_undis.Len() == 0) return rule_raw; byte[] rv = rule_bidis.Get_text_by_key_or_null(vnt.Key()); // display current variant in bidirectional array if (rv == null) rv = rule_bidis.Get_text_by_ary_or_null(vnt.Fallback_ary()); // or display current variant in fallbacks if (rv == null) rv = rule_undis.Get_text_by_key_or_null(vnt.Key()); // or display current variant in unidirectional array if (rv == null && vnt.Dir() == Xol_vnt_dir_.Tid__none) { // or display first text under disable manual convert rv = (rule_bidis.Len() > 0) ? rule_bidis.Get_text_at(0) : rule_undis.Get_text_at(0); } return rv; } private final static byte[] Bry__error_bgn = Bry_.new_a7("<span class=\"error\">vnt error") , Bry__error_end = Bry_.new_a7("</span>") , Bry__undi_spr = Bry_.new_u8("⇒") ; }