public virtual Transliterator GetInstance() { List <Transliterator> transliterators = new List <Transliterator>(); int passNumber = 1; int limit = Math.Max(idBlockVector.Count, dataVector.Count); for (int i = 0; i < limit; i++) { if (i < idBlockVector.Count) { string idBlock = idBlockVector[i]; if (idBlock.Length > 0) { transliterators.Add(Transliterator.GetInstance(idBlock)); } } if (i < dataVector.Count) { #pragma warning disable 612, 618 Data data = dataVector[i]; transliterators.Add(new RuleBasedTransliterator("%Pass" + passNumber++, data, null)); #pragma warning restore 612, 618 } } Transliterator t = new CompoundTransliterator(transliterators, passNumber - 1); t.ID = id; if (compoundFilter != null) { t.Filter = compoundFilter; } return(t); }
/// <summary> /// Given an Entry object, instantiate it. Caller owns result. Return /// 0 on failure. /// <para/> /// Return a non-empty <paramref name="aliasReturn"/> value if the <paramref name="ID"/> points to an alias. /// We cannot instantiate it ourselves because the alias may contain /// filters or compounds, which we do not understand. Caller should /// make <paramref name="aliasReturn"/> empty before calling. /// <para/> /// The entry object is assumed to reside in the dynamic store. It may be /// modified. /// </summary> private Transliterator InstantiateEntry(string ID, object[] entryWrapper, StringBuffer aliasReturn) { // We actually modify the entry object in some cases. If it // is a string, we may partially parse it and turn it into a // more processed precursor. This makes the next // instantiation faster and allows sharing of immutable // components like the RuleBasedTransliterator.Data objects. // For this reason, the entry object is an Object[] of length // 1. for (; ;) { object entry = entryWrapper[0]; #pragma warning disable 612, 618 if (entry is RuleBasedTransliterator.Data) { RuleBasedTransliterator.Data data = (RuleBasedTransliterator.Data)entry; return(new RuleBasedTransliterator(ID, data, null)); #pragma warning restore 612, 618 } else if (entry is Type) { try { //return (Transliterator)((Type)entry).newInstance(); return((Transliterator)Activator.CreateInstance((Type)entry)); } catch (TargetInvocationException) { } catch (MethodAccessException) { } return(null); } else if (entry is AliasEntry) { aliasReturn.Append(((AliasEntry)entry).Alias); return(null); } else if (entry is ITransliteratorFactory) { return(((ITransliteratorFactory)entry).GetInstance(ID)); } else if (entry is CompoundRBTEntry) { return(((CompoundRBTEntry)entry).GetInstance()); } else if (entry is AnyTransliterator) { AnyTransliterator temp = (AnyTransliterator)entry; return(temp.SafeClone()); } #pragma warning disable 612, 618 else if (entry is RuleBasedTransliterator) { RuleBasedTransliterator temp = (RuleBasedTransliterator)entry; return(temp.SafeClone()); } #pragma warning restore 612, 618 else if (entry is CompoundTransliterator) { CompoundTransliterator temp = (CompoundTransliterator)entry; return(temp.SafeClone()); } else if (entry is Transliterator) { return((Transliterator)entry); } // At this point entry type must be either RULES_FORWARD or // RULES_REVERSE. We process the rule data into a // TransliteratorRuleData object, and possibly also into an // .id header and/or footer. Then we modify the registry with // the parsed data and retry. TransliteratorParser parser = new TransliteratorParser(); try { ResourceEntry re = (ResourceEntry)entry; parser.Parse(re.Resource, re.Direction); } catch (InvalidCastException) { // If we pull a rule from a locale resource bundle it will // be a LocaleEntry. LocaleEntry le = (LocaleEntry)entry; parser.Parse(le.Rule, le.Direction); } // Reset entry to something that we process at the // top of the loop, then loop back to the top. As long as we // do this, we only loop through twice at most. // NOTE: The logic here matches that in // Transliterator.createFromRules(). if (parser.IdBlockVector.Count == 0 && parser.DataVector.Count == 0) { // No idBlock, no data -- this is just an // alias for Null entryWrapper[0] = new AliasEntry(NullTransliterator._ID); } else if (parser.IdBlockVector.Count == 0 && parser.DataVector.Count == 1) { // No idBlock, data != 0 -- this is an // ordinary RBT_DATA entryWrapper[0] = parser.DataVector[0]; } else if (parser.IdBlockVector.Count == 1 && parser.DataVector.Count == 0) { // idBlock, no data -- this is an alias. The ID has // been munged from reverse into forward mode, if // necessary, so instantiate the ID in the forward // direction. if (parser.CompoundFilter != null) { entryWrapper[0] = new AliasEntry(parser.CompoundFilter.ToPattern(false) + ";" + parser.IdBlockVector[0]); } else { entryWrapper[0] = new AliasEntry(parser.IdBlockVector[0]); } } else { entryWrapper[0] = new CompoundRBTEntry(ID, parser.IdBlockVector, parser.DataVector, parser.CompoundFilter); } } }
/// <summary> /// Returns a transliterator from the given source to our target or /// target/variant. Returns NULL if the source is the same as our /// target script, or if the source is <see cref="UScript.InvalidCode"/>. /// Caches the result and returns the same transliterator the next /// time. The caller does NOT own the result and must not delete /// it. /// </summary> private Transliterator GetTransliterator(int source) { if (source == targetScript || source == UScript.InvalidCode) { if (IsWide(targetScript)) { return(null); } else { return(widthFix); } } int key = (int)source; Transliterator t = cache.Get(key); if (!cache.TryGetValue(key, out t) || t == null) { string sourceName = UScript.GetName(source); string id = sourceName + TARGET_SEP + target; try { t = Transliterator.GetInstance(id, FORWARD); } catch (Exception e) { } if (t == null) { // Try to pivot around Latin, our most common script id = sourceName + LATIN_PIVOT + target; try { t = Transliterator.GetInstance(id, FORWARD); } catch (Exception e) { } } if (t != null) { if (!IsWide(targetScript)) { IList <Transliterator> v = new List <Transliterator>(); v.Add(widthFix); v.Add(t); t = new CompoundTransliterator(v); } //Transliterator prevCachedT = cache.putIfAbsent(key, t); Transliterator prevCachedT; // ICU4N: This is to simulate putIfAbsent // ICU4N TODO: If this works, make it into a PutIfAbsent extension method so we can go back to using ConcurrentDictionary elsewhere if (!cache.TryGetValue(key, out prevCachedT)) { // If another thread beat us here, set the prevCachedT // value to NullTransliterator to indicate it already exists if (!cache.TryAdd(key, t)) { prevCachedT = new NullTransliterator(); } } if (prevCachedT != null) { t = prevCachedT; } } else if (!IsWide(targetScript)) { return(widthFix); } } return(t); }