16f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/*
26f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org **********************************************************************
36f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   Copyright (C) 1999-2012, International Business Machines
46f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   Corporation and others.  All Rights Reserved.
56f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org **********************************************************************
66f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   Date        Name        Description
76f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   11/17/99    aliu        Creation.
86f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org **********************************************************************
96f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "utypeinfo.h"  // for 'typeid' to work
126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/utypes.h"
146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_TRANSLITERATION
166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/putil.h"
186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/translit.h"
196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/locid.h"
206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/msgfmt.h"
216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/rep.h"
226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/resbund.h"
236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/unifilt.h"
246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/uniset.h"
256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/uscript.h"
266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/strenum.h"
276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/utf16.h"
286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cpdtrans.h"
296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "nultrans.h"
306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "rbt_data.h"
316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "rbt_pars.h"
326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "rbt.h"
336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "transreg.h"
346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "name2uni.h"
356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "nortrans.h"
366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "remtrans.h"
376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "titletrn.h"
386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "tolowtrn.h"
396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "toupptrn.h"
406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uni2name.h"
416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "brktrans.h"
426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "esctrn.h"
436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unesctrn.h"
446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "tridpars.h"
456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "anytrans.h"
466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "util.h"
476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "hash.h"
486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "mutex.h"
496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "ucln_in.h"
506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uassert.h"
516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cmemory.h"
526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cstring.h"
536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uinvchar.h"
546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar TARGET_SEP  = 0x002D; /*-*/
566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_DELIM    = 0x003B; /*;*/
576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar VARIANT_SEP = 0x002F; // '/'
586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Prefix for resource bundle key for the display name for a
616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * transliterator.  The ID is appended to this to form the key.
626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * The resource bundle value should be a String.
636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const char RB_DISPLAY_NAME_PREFIX[] = "%Translit%%";
656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Prefix for resource bundle key for the display name for a
686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * transliterator SCRIPT.  The ID is appended to this to form the key.
696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * The resource bundle value should be a String.
706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const char RB_SCRIPT_DISPLAY_NAME_PREFIX[] = "%Translit%";
726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Resource bundle key for display name pattern.
756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * The resource bundle value should be a String forming a
766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * MessageFormat pattern, e.g.:
776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * "{0,choice,0#|1#{1} Transliterator|2#{1} to {2} Transliterator}".
786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const char RB_DISPLAY_NAME_PATTERN[] = "TransliteratorNamePattern";
806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Resource bundle key for the list of RuleBasedTransliterator IDs.
836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * The resource bundle value should be a String[] with each element
846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * being a valid ID.  The ID will be appended to RB_RULE_BASED_PREFIX
856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * to obtain the class name in which the RB_RULE key will be sought.
866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const char RB_RULE_BASED_IDS[] = "RuleBasedTransliteratorIDs";
886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * The mutex controlling access to registry object.
916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic UMutex registryMutex = U_MUTEX_INITIALIZER;
936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * System transliterator registry; non-null when initialized.
966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic icu::TransliteratorRegistry* registry = 0;
986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Macro to check/initialize the registry. ONLY USE WITHIN
1006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// MUTEX. Avoids function call when registry is initialized.
1016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define HAVE_REGISTRY(status) (registry!=0 || initializeRegistry(status))
1026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_BEGIN
1046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(Transliterator)
1066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
1086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Return TRUE if the given UTransPosition is valid for text of
1096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * the given length.
1106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
1116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic inline UBool positionIsValid(UTransPosition& index, int32_t len) {
1126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return !(index.contextStart < 0 ||
1136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org             index.start < index.contextStart ||
1146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org             index.limit < index.start ||
1156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org             index.contextLimit < index.limit ||
1166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org             len < index.contextLimit);
1176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
1206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Default constructor.
1216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param theID the string identifier for this transliterator
1226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param theFilter the filter.  Any character for which
1236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <tt>filter.contains()</tt> returns <tt>FALSE</tt> will not be
1246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * altered by this transliterator.  If <tt>filter</tt> is
1256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <tt>null</tt> then no filtering is applied.
1266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
1276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator::Transliterator(const UnicodeString& theID,
1286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                               UnicodeFilter* adoptedFilter) :
1296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UObject(), ID(theID), filter(adoptedFilter),
1306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    maximumContextLength(0)
1316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // NUL-terminate the ID string, which is a non-aliased copy.
1336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID.append((UChar)0);
1346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID.truncate(ID.length()-1);
1356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
1386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Destructor.
1396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
1406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator::~Transliterator() {
1416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (filter) {
1426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete filter;
1436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
1476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Copy constructor.
1486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
1496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator::Transliterator(const Transliterator& other) :
1506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UObject(other), ID(other.ID), filter(0),
1516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    maximumContextLength(other.maximumContextLength)
1526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // NUL-terminate the ID string, which is a non-aliased copy.
1546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID.append((UChar)0);
1556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID.truncate(ID.length()-1);
1566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (other.filter != 0) {
1586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // We own the filter, so we must have our own copy
1596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        filter = (UnicodeFilter*) other.filter->clone();
1606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator* Transliterator::clone() const {
1646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
1656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
1686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Assignment operator.
1696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
1706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator& Transliterator::operator=(const Transliterator& other) {
1716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID = other.ID;
1726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // NUL-terminate the ID string
1736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID.getTerminatedBuffer();
1746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    maximumContextLength = other.maximumContextLength;
1766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    adoptFilter((other.filter == 0) ? 0 : (UnicodeFilter*) other.filter->clone());
1776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return *this;
1786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
1816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Transliterates a segment of a string.  <code>Transliterator</code> API.
1826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param text the string to be transliterated
1836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param start the beginning index, inclusive; <code>0 <= start
1846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <= limit</code>.
1856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param limit the ending index, exclusive; <code>start <= limit
1866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <= text.length()</code>.
1876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @return the new limit index, or -1
1886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
1896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t Transliterator::transliterate(Replaceable& text,
1906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                      int32_t start, int32_t limit) const {
1916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (start < 0 ||
1926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        limit < start ||
1936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        text.length() < limit) {
1946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return -1;
1956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UTransPosition offsets;
1986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    offsets.contextStart= start;
1996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    offsets.contextLimit = limit;
2006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    offsets.start = start;
2016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    offsets.limit = limit;
2026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    filteredTransliterate(text, offsets, FALSE, TRUE);
2036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return offsets.limit;
2046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
2076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Transliterates an entire string in place. Convenience method.
2086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param text the string to be transliterated
2096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
2106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::transliterate(Replaceable& text) const {
2116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    transliterate(text, 0, text.length());
2126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
2156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Transliterates the portion of the text buffer that can be
2166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * transliterated unambiguosly after new text has been inserted,
2176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * typically as a result of a keyboard event.  The new text in
2186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>insertion</code> will be inserted into <code>text</code>
2196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * at <code>index.contextLimit</code>, advancing
2206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>index.contextLimit</code> by <code>insertion.length()</code>.
2216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Then the transliterator will try to transliterate characters of
2226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>text</code> between <code>index.start</code> and
2236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>index.contextLimit</code>.  Characters before
2246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>index.start</code> will not be changed.
2256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
2266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <p>Upon return, values in <code>index</code> will be updated.
2276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>index.contextStart</code> will be advanced to the first
2286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * character that future calls to this method will read.
2296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>index.start</code> and <code>index.contextLimit</code> will
2306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * be adjusted to delimit the range of text that future calls to
2316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * this method may change.
2326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
2336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <p>Typical usage of this method begins with an initial call
2346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * with <code>index.contextStart</code> and <code>index.contextLimit</code>
2356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * set to indicate the portion of <code>text</code> to be
2366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * transliterated, and <code>index.start == index.contextStart</code>.
2376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Thereafter, <code>index</code> can be used without
2386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * modification in future calls, provided that all changes to
2396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>text</code> are made via this method.
2406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
2416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <p>This method assumes that future calls may be made that will
2426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * insert new text into the buffer.  As a result, it only performs
2436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * unambiguous transliterations.  After the last call to this
2446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * method, there may be untransliterated text that is waiting for
2456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * more input to resolve an ambiguity.  In order to perform these
2466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * pending transliterations, clients should call {@link
2476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * #finishKeyboardTransliteration} after the last call to this
2486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * method has been made.
2496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
2506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param text the buffer holding transliterated and untransliterated text
2516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param index an array of three integers.
2526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
2536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <ul><li><code>index.contextStart</code>: the beginning index,
2546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * inclusive; <code>0 <= index.contextStart <= index.contextLimit</code>.
2556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
2566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <li><code>index.contextLimit</code>: the ending index, exclusive;
2576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>index.contextStart <= index.contextLimit <= text.length()</code>.
2586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>insertion</code> is inserted at
2596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>index.contextLimit</code>.
2606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
2616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <li><code>index.start</code>: the next character to be
2626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * considered for transliteration; <code>index.contextStart <=
2636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * index.start <= index.contextLimit</code>.  Characters before
2646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>index.start</code> will not be changed by future calls
2656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * to this method.</ul>
2666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
2676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param insertion text to be inserted and possibly
2686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * transliterated into the translation buffer at
2696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>index.contextLimit</code>.  If <code>null</code> then no text
2706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * is inserted.
2716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #START
2726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #LIMIT
2736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #CURSOR
2746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #handleTransliterate
2756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @exception IllegalArgumentException if <code>index</code>
2766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * is invalid
2776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
2786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::transliterate(Replaceable& text,
2796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   UTransPosition& index,
2806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   const UnicodeString& insertion,
2816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   UErrorCode &status) const {
2826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    _transliterate(text, index, &insertion, status);
2836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
2866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Transliterates the portion of the text buffer that can be
2876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * transliterated unambiguosly after a new character has been
2886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * inserted, typically as a result of a keyboard event.  This is a
2896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * convenience method; see {@link
2906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * #transliterate(Replaceable, int[], String)} for details.
2916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param text the buffer holding transliterated and
2926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * untransliterated text
2936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param index an array of three integers.  See {@link
2946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * #transliterate(Replaceable, int[], String)}.
2956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param insertion text to be inserted and possibly
2966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * transliterated into the translation buffer at
2976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>index.contextLimit</code>.
2986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #transliterate(Replaceable, int[], String)
2996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
3006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::transliterate(Replaceable& text,
3016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   UTransPosition& index,
3026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   UChar32 insertion,
3036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   UErrorCode& status) const {
3046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString str(insertion);
3056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    _transliterate(text, index, &str, status);
3066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
3096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Transliterates the portion of the text buffer that can be
3106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * transliterated unambiguosly.  This is a convenience method; see
3116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * {@link #transliterate(Replaceable, int[], String)} for
3126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * details.
3136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param text the buffer holding transliterated and
3146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * untransliterated text
3156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param index an array of three integers.  See {@link
3166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * #transliterate(Replaceable, int[], String)}.
3176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #transliterate(Replaceable, int[], String)
3186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
3196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::transliterate(Replaceable& text,
3206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   UTransPosition& index,
3216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   UErrorCode& status) const {
3226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    _transliterate(text, index, 0, status);
3236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
3266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Finishes any pending transliterations that were waiting for
3276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * more characters.  Clients should call this method as the last
3286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * call after a sequence of one or more calls to
3296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>transliterate()</code>.
3306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param text the buffer holding transliterated and
3316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * untransliterated text.
3326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param index the array of indices previously passed to {@link
3336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * #transliterate}
3346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
3356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::finishTransliteration(Replaceable& text,
3366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                           UTransPosition& index) const {
3376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!positionIsValid(index, text.length())) {
3386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
3396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    filteredTransliterate(text, index, FALSE, TRUE);
3426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
3456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * This internal method does keyboard transliteration.  If the
3466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * 'insertion' is non-null then we append it to 'text' before
3476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * proceeding.  This method calls through to the pure virtual
3486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * framework method handleTransliterate() to do the actual
3496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * work.
3506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
3516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::_transliterate(Replaceable& text,
3526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                    UTransPosition& index,
3536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                    const UnicodeString* insertion,
3546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                    UErrorCode &status) const {
3556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
3566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
3576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!positionIsValid(index, text.length())) {
3606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_ILLEGAL_ARGUMENT_ERROR;
3616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
3626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//    int32_t originalStart = index.contextStart;
3656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (insertion != 0) {
3666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        text.handleReplaceBetween(index.limit, index.limit, *insertion);
3676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        index.limit += insertion->length();
3686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        index.contextLimit += insertion->length();
3696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (index.limit > 0 &&
3726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        U16_IS_LEAD(text.charAt(index.limit - 1))) {
3736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Oops, there is a dangling lead surrogate in the buffer.
3746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // This will break most transliterators, since they will
3756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // assume it is part of a pair.  Don't transliterate until
3766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // more text comes in.
3776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
3786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    filteredTransliterate(text, index, TRUE, TRUE);
3816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if 0
3836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // TODO
3846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // I CAN'T DO what I'm attempting below now that the Kleene star
3856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // operator is supported.  For example, in the rule
3866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //   ([:Lu:]+) { x } > $1;
3886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // what is the maximum context length?  getMaximumContextLength()
3906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // will return 1, but this is just the length of the ante context
3916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // part of the pattern string -- 1 character, which is a standin
3926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // for a Quantifier, which contains a StringMatcher, which
3936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // contains a UnicodeSet.
3946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // There is a complicated way to make this work again, and that's
3966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // to add a "maximum left context" protocol into the
3976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // UnicodeMatcher hierarchy.  At present I'm not convinced this is
3986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // worth it.
3996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // ---
4016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // The purpose of the code below is to keep the context small
4036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // while doing incremental transliteration.  When part of the left
4046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // context (between contextStart and start) is no longer needed,
4056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // we try to advance contextStart past that portion.  We use the
4066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // maximum context length to do so.
4076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t newCS = index.start;
4086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t n = getMaximumContextLength();
4096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    while (newCS > originalStart && n-- > 0) {
4106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        --newCS;
4116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        newCS -= U16_LENGTH(text.char32At(newCS)) - 1;
4126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    index.contextStart = uprv_max(newCS, originalStart);
4146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
4156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
4186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * This method breaks up the input text into runs of unfiltered
4196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * characters.  It passes each such run to
4206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <subclass>.handleTransliterate().  Subclasses that can handle the
4216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * filter logic more efficiently themselves may override this method.
4226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
4236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * All transliteration calls in this class go through this method.
4246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
4256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::filteredTransliterate(Replaceable& text,
4266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                           UTransPosition& index,
4276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                           UBool incremental,
4286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                           UBool rollback) const {
4296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Short circuit path for transliterators with no filter in
4306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // non-incremental mode.
4316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (filter == 0 && !rollback) {
4326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        handleTransliterate(text, index, incremental);
4336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
4346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //----------------------------------------------------------------------
4376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // This method processes text in two groupings:
4386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //
4396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // RUNS -- A run is a contiguous group of characters which are contained
4406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // in the filter for this transliterator (filter.contains(ch) == TRUE).
4416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Text outside of runs may appear as context but it is not modified.
4426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // The start and limit Position values are narrowed to each run.
4436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //
4446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // PASSES (incremental only) -- To make incremental mode work correctly,
4456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // each run is broken up into n passes, where n is the length (in code
4466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // points) of the run.  Each pass contains the first n characters.  If a
4476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // pass is completely transliterated, it is committed, and further passes
4486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // include characters after the committed text.  If a pass is blocked,
4496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // and does not transliterate completely, then this method rolls back
4506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // the changes made during the pass, extends the pass by one code point,
4516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // and tries again.
4526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //----------------------------------------------------------------------
4536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // globalLimit is the limit value for the entire operation.  We
4556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // set index.limit to the end of each unfiltered run before
4566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // calling handleTransliterate(), so we need to maintain the real
4576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // value of index.limit here.  After each transliteration, we
4586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // update globalLimit for insertions or deletions that have
4596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // happened.
4606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t globalLimit = index.limit;
4616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // If there is a non-null filter, then break the input text up.  Say the
4636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // input text has the form:
4646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //   xxxabcxxdefxx
4656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // where 'x' represents a filtered character (filter.contains('x') ==
4666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // false).  Then we break this up into:
4676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //   xxxabc xxdef xx
4686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Each pass through the loop consumes a run of filtered
4696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // characters (which are ignored) and a subsequent run of
4706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // unfiltered characters (which are transliterated).
4716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (;;) {
4736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (filter != NULL) {
4756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Narrow the range to be transliterated to the first segment
4766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // of unfiltered characters at or after index.start.
4776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Advance past filtered chars
4796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UChar32 c;
4806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            while (index.start < globalLimit &&
4816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                   !filter->contains(c=text.char32At(index.start))) {
4826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                index.start += U16_LENGTH(c);
4836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
4846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Find the end of this run of unfiltered chars
4866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            index.limit = index.start;
4876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            while (index.limit < globalLimit &&
4886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                   filter->contains(c=text.char32At(index.limit))) {
4896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                index.limit += U16_LENGTH(c);
4906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
4916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
4926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Check to see if the unfiltered run is empty.  This only
4946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // happens at the end of the string when all the remaining
4956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // characters are filtered.
4966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (index.limit == index.start) {
4976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // assert(index.start == globalLimit);
4986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
4996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
5006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Is this run incremental?  If there is additional
5026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // filtered text (if limit < globalLimit) then we pass in
5036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // an incremental value of FALSE to force the subclass to
5046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // complete the transliteration for this run.
5056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UBool isIncrementalRun =
5066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            (index.limit < globalLimit ? FALSE : incremental);
5076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t delta;
5096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Implement rollback.  To understand the need for rollback,
5116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // consider the following transliterator:
5126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        //
5136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        //  "t" is "a > A;"
5146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        //  "u" is "A > b;"
5156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        //  "v" is a compound of "t; NFD; u" with a filter [:Ll:]
5166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        //
5176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Now apply "c" to the input text "a".  The result is "b".  But if
5186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // the transliteration is done incrementally, then the NFD holds
5196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // things up after "t" has already transformed "a" to "A".  When
5206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // finishTransliterate() is called, "A" is _not_ processed because
5216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // it gets excluded by the [:Ll:] filter, and the end result is "A"
5226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // -- incorrect.  The problem is that the filter is applied to a
5236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // partially-transliterated result, when we only want it to apply to
5246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // input text.  Although this example hinges on a compound
5256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // transliterator containing NFD and a specific filter, it can
5266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // actually happen with any transliterator which may do a partial
5276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // transformation in incremental mode into characters outside its
5286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // filter.
5296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        //
5306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // To handle this, when in incremental mode we supply characters to
5316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // handleTransliterate() in several passes.  Each pass adds one more
5326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // input character to the input text.  That is, for input "ABCD", we
5336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // first try "A", then "AB", then "ABC", and finally "ABCD".  If at
5346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // any point we block (upon return, start < limit) then we roll
5356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // back.  If at any point we complete the run (upon return start ==
5366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // limit) then we commit that run.
5376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (rollback && isIncrementalRun) {
5396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t runStart = index.start;
5416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t runLimit = index.limit;
5426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t runLength =  runLimit - runStart;
5436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Make a rollback copy at the end of the string
5456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t rollbackOrigin = text.length();
5466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            text.copy(runStart, runLimit, rollbackOrigin);
5476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Variables reflecting the commitment of completely
5496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // transliterated text.  passStart is the runStart, advanced
5506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // past committed text.  rollbackStart is the rollbackOrigin,
5516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // advanced past rollback text that corresponds to committed
5526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // text.
5536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t passStart = runStart;
5546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t rollbackStart = rollbackOrigin;
5556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // The limit for each pass; we advance by one code point with
5576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // each iteration.
5586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t passLimit = index.start;
5596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Total length, in 16-bit code units, of uncommitted text.
5616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // This is the length to be rolled back.
5626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t uncommittedLength = 0;
5636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Total delta (change in length) for all passes
5656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t totalDelta = 0;
5666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // PASS MAIN LOOP -- Start with a single character, and extend
5686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // the text by one character at a time.  Roll back partial
5696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // transliterations and commit complete transliterations.
5706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            for (;;) {
5716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // Length of additional code point, either one or two
5726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                int32_t charLength = U16_LENGTH(text.char32At(passLimit));
5736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                passLimit += charLength;
5746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (passLimit > runLimit) {
5756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    break;
5766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
5776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                uncommittedLength += charLength;
5786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                index.limit = passLimit;
5806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // Delegate to subclass for actual transliteration.  Upon
5826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // return, start will be updated to point after the
5836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // transliterated text, and limit and contextLimit will be
5846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // adjusted for length changes.
5856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                handleTransliterate(text, index, TRUE);
5866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                delta = index.limit - passLimit; // change in length
5886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // We failed to completely transliterate this pass.
5906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // Roll back the text.  Indices remain unchanged; reset
5916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // them where necessary.
5926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (index.start != index.limit) {
5936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // Find the rollbackStart, adjusted for length changes
5946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // and the deletion of partially transliterated text.
5956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    int32_t rs = rollbackStart + delta - (index.limit - passStart);
5966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // Delete the partially transliterated text
5986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    text.handleReplaceBetween(passStart, index.limit, UnicodeString());
5996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // Copy the rollback text back
6016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    text.copy(rs, rs + uncommittedLength, passStart);
6026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // Restore indices to their original values
6046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    index.start = passStart;
6056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    index.limit = passLimit;
6066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    index.contextLimit -= delta;
6076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
6086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // We did completely transliterate this pass.  Update the
6106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // commit indices to record how far we got.  Adjust indices
6116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // for length change.
6126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                else {
6136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // Move the pass indices past the committed text.
6146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    passStart = passLimit = index.start;
6156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // Adjust the rollbackStart for length changes and move
6176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // it past the committed text.  All characters we've
6186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // processed to this point are committed now, so zero
6196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // out the uncommittedLength.
6206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    rollbackStart += delta + uncommittedLength;
6216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    uncommittedLength = 0;
6226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // Adjust indices for length changes.
6246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    runLimit += delta;
6256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    totalDelta += delta;
6266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
6276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
6286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Adjust overall limit and rollbackOrigin for insertions and
6306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // deletions.  Don't need to worry about contextLimit because
6316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // handleTransliterate() maintains that.
6326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            rollbackOrigin += totalDelta;
6336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            globalLimit += totalDelta;
6346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Delete the rollback copy
6366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            text.handleReplaceBetween(rollbackOrigin, rollbackOrigin + runLength, UnicodeString());
6376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Move start past committed text
6396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            index.start = passStart;
6406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
6416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        else {
6436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Delegate to subclass for actual transliteration.
6446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t limit = index.limit;
6456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            handleTransliterate(text, index, isIncrementalRun);
6466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            delta = index.limit - limit; // change in length
6476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // In a properly written transliterator, start == limit after
6496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // handleTransliterate() returns when incremental is false.
6506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Catch cases where the subclass doesn't do this, and throw
6516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // an exception.  (Just pinning start to limit is a bad idea,
6526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // because what's probably happening is that the subclass
6536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // isn't transliterating all the way to the end, and it should
6546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // in non-incremental mode.)
6556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (!incremental && index.start != index.limit) {
6566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // We can't throw an exception, so just fudge things
6576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                index.start = index.limit;
6586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
6596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Adjust overall limit for insertions/deletions.  Don't need
6616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // to worry about contextLimit because handleTransliterate()
6626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // maintains that.
6636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            globalLimit += delta;
6646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
6656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (filter == NULL || isIncrementalRun) {
6676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
6686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
6696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // If we did completely transliterate this
6716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // run, then repeat with the next unfiltered run.
6726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Start is valid where it is.  Limit needs to be put back where
6756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // it was, modulo adjustments for deletions/insertions.
6766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    index.limit = globalLimit;
6776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::filteredTransliterate(Replaceable& text,
6806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                           UTransPosition& index,
6816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                           UBool incremental) const {
6826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    filteredTransliterate(text, index, incremental, FALSE);
6836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
6866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Method for subclasses to use to set the maximum context length.
6876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #getMaximumContextLength
6886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
6896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::setMaximumContextLength(int32_t maxContextLength) {
6906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    maximumContextLength = maxContextLength;
6916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
6946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Returns a programmatic identifier for this transliterator.
6956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * If this identifier is passed to <code>getInstance()</code>, it
6966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * will return this object, if it has been registered.
6976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #registerInstance
6986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #getAvailableIDs
6996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
7006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst UnicodeString& Transliterator::getID(void) const {
7016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return ID;
7026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
7036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
7056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Returns a name for this transliterator that is appropriate for
7066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * display to the user in the default locale.  See {@link
7076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * #getDisplayName(Locale)} for details.
7086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
7096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& U_EXPORT2 Transliterator::getDisplayName(const UnicodeString& ID,
7106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                              UnicodeString& result) {
7116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return getDisplayName(ID, Locale::getDefault(), result);
7126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
7136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
7156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Returns a name for this transliterator that is appropriate for
7166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * display to the user in the given locale.  This name is taken
7176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * from the locale resource data in the standard manner of the
7186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>java.text</code> package.
7196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
7206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <p>If no localized names exist in the system resource bundles,
7216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * a name is synthesized using a localized
7226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>MessageFormat</code> pattern from the resource data.  The
7236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * arguments to this pattern are an integer followed by one or two
7246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * strings.  The integer is the number of strings, either 1 or 2.
7256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * The strings are formed by splitting the ID for this
7266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * transliterator at the first TARGET_SEP.  If there is no TARGET_SEP, then the
7276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * entire ID forms the only string.
7286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param inLocale the Locale in which the display name should be
7296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * localized.
7306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see java.text.MessageFormat
7316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
7326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& U_EXPORT2 Transliterator::getDisplayName(const UnicodeString& id,
7336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                              const Locale& inLocale,
7346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                              UnicodeString& result) {
7356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode status = U_ZERO_ERROR;
7366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ResourceBundle bundle(U_ICUDATA_TRANSLIT, inLocale, status);
7386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Suspend checking status until later...
7406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    result.truncate(0);
7426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Normalize the ID
7446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString source, target, variant;
7456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UBool sawSource;
7466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    TransliteratorIDParser::IDtoSTV(id, source, target, variant, sawSource);
7476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (target.length() < 1) {
7486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // No target; malformed id
7496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return result;
7506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (variant.length() > 0) { // Change "Foo" to "/Foo"
7526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        variant.insert(0, VARIANT_SEP);
7536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString ID(source);
7556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID.append(TARGET_SEP).append(target).append(variant);
7566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // build the char* key
7586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (uprv_isInvariantUString(ID.getBuffer(), ID.length())) {
7596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        char key[200];
7606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uprv_strcpy(key, RB_DISPLAY_NAME_PREFIX);
7616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t length=(int32_t)uprv_strlen(RB_DISPLAY_NAME_PREFIX);
7626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ID.extract(0, (int32_t)(sizeof(key)-length), key+length, (int32_t)(sizeof(key)-length), US_INV);
7636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Try to retrieve a UnicodeString from the bundle.
7656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UnicodeString resString = bundle.getStringEx(key, status);
7666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (U_SUCCESS(status) && resString.length() != 0) {
7686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return result = resString; // [sic] assign & return
7696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
7706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_FORMATTING
7726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // We have failed to get a name from the locale data.  This is
7736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // typical, since most transliterators will not have localized
7746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // name data.  The next step is to retrieve the MessageFormat
7756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // pattern from the locale data and to use it to synthesize the
7766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // name from the ID.
7776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_ZERO_ERROR;
7796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        resString = bundle.getStringEx(RB_DISPLAY_NAME_PATTERN, status);
7806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (U_SUCCESS(status) && resString.length() != 0) {
7826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            MessageFormat msg(resString, inLocale, status);
7836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Suspend checking status until later...
7846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // We pass either 2 or 3 Formattable objects to msg.
7866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            Formattable args[3];
7876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t nargs;
7886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            args[0].setLong(2); // # of args to follow
7896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            args[1].setString(source);
7906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            args[2].setString(target);
7916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            nargs = 3;
7926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Use display names for the scripts, if they exist
7946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UnicodeString s;
7956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            length=(int32_t)uprv_strlen(RB_SCRIPT_DISPLAY_NAME_PREFIX);
7966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            for (int j=1; j<=2; ++j) {
7976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                status = U_ZERO_ERROR;
7986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                uprv_strcpy(key, RB_SCRIPT_DISPLAY_NAME_PREFIX);
7996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                args[j].getString(s);
8006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (uprv_isInvariantUString(s.getBuffer(), s.length())) {
8016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    s.extract(0, sizeof(key)-length-1, key+length, (int32_t)sizeof(key)-length-1, US_INV);
8026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    resString = bundle.getStringEx(key, status);
8046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    if (U_SUCCESS(status)) {
8066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        args[j] = resString;
8076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    }
8086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
8096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
8106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            status = U_ZERO_ERROR;
8126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            FieldPosition pos; // ignored by msg
8136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            msg.format(args, nargs, result, pos, status);
8146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (U_SUCCESS(status)) {
8156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                result.append(variant);
8166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return result;
8176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
8186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
8196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
8206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
8216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // We should not reach this point unless there is something
8236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // wrong with the build or the RB_DISPLAY_NAME_PATTERN has
8246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // been deleted from the root RB_LOCALE_ELEMENTS resource.
8256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    result = ID;
8266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
8276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
8306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Returns the filter used by this transliterator, or <tt>null</tt>
8316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * if this transliterator uses no filter.  Caller musn't delete
8326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * the result!
8336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
8346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst UnicodeFilter* Transliterator::getFilter(void) const {
8356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return filter;
8366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
8396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Returns the filter used by this transliterator, or
8406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <tt>NULL</tt> if this transliterator uses no filter.  The
8416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * caller must eventually delete the result.  After this call,
8426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * this transliterator's filter is set to <tt>NULL</tt>.
8436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
8446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeFilter* Transliterator::orphanFilter(void) {
8456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeFilter *result = filter;
8466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    filter = NULL;
8476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
8486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
8516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Changes the filter used by this transliterator.  If the filter
8526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * is set to <tt>null</tt> then no filtering will occur.
8536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
8546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <p>Callers must take care if a transliterator is in use by
8556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * multiple threads.  The filter should not be changed by one
8566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * thread while another thread may be transliterating.
8576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
8586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::adoptFilter(UnicodeFilter* filterToAdopt) {
8596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    delete filter;
8606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    filter = filterToAdopt;
8616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
8646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Returns this transliterator's inverse.  See the class
8656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * documentation for details.  This implementation simply inverts
8666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * the two entities in the ID and attempts to retrieve the
8676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * resulting transliterator.  That is, if <code>getID()</code>
8686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * returns "A-B", then this method will return the result of
8696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>getInstance("B-A")</code>, or <code>null</code> if that
8706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * call fails.
8716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
8726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <p>This method does not take filtering into account.  The
8736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * returned transliterator will have no filter.
8746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
8756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <p>Subclasses with knowledge of their inverse may wish to
8766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * override this method.
8776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
8786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @return a transliterator that is an inverse, not necessarily
8796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * exact, of this transliterator, or <code>null</code> if no such
8806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * transliterator is registered.
8816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #registerInstance
8826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
8836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator* Transliterator::createInverse(UErrorCode& status) const {
8846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UParseError parseError;
8856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return Transliterator::createInstance(ID, UTRANS_REVERSE,parseError,status);
8866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator* U_EXPORT2
8896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator::createInstance(const UnicodeString& ID,
8906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                UTransDirection dir,
8916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                UErrorCode& status)
8926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
8936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UParseError parseError;
8946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return createInstance(ID, dir, parseError, status);
8956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
8986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Returns a <code>Transliterator</code> object given its ID.
8996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * The ID must be either a system transliterator ID or a ID registered
9006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * using <code>registerInstance()</code>.
9016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
9026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param ID a valid ID, as enumerated by <code>getAvailableIDs()</code>
9036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @return A <code>Transliterator</code> object with the given ID
9046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #registerInstance
9056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #getAvailableIDs
9066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #getID
9076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
9086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator* U_EXPORT2
9096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator::createInstance(const UnicodeString& ID,
9106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                UTransDirection dir,
9116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                UParseError& parseError,
9126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                UErrorCode& status)
9136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
9146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
9156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return 0;
9166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString canonID;
9196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UVector list(status);
9206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
9216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
9226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeSet* globalFilter;
9256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // TODO add code for parseError...currently unused, but
9266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // later may be used by parsing code...
9276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!TransliteratorIDParser::parseCompoundID(ID, dir, canonID, list, globalFilter)) {
9286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_INVALID_ID;
9296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
9306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    TransliteratorIDParser::instantiateList(list, status);
9336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
9346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
9356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    U_ASSERT(list.size() > 0);
9386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Transliterator* t = NULL;
9396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (list.size() > 1 || canonID.indexOf(ID_DELIM) >= 0) {
9416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // [NOTE: If it's a compoundID, we instantiate a CompoundTransliterator even if it only
9426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // has one child transliterator.  This is so that toRules() will return the right thing
9436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // (without any inactive ID), but our main ID still comes out correct.  That is, if we
9446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // instantiate "(Lower);Latin-Greek;", we want the rules to come out as "::Latin-Greek;"
9456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // even though the ID is "(Lower);Latin-Greek;".
9466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t = new CompoundTransliterator(list, parseError, status);
9476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    else {
9496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t = (Transliterator*)list.elementAt(0);
9506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Check null pointer
9526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (t != NULL) {
9536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t->setID(canonID);
9546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (globalFilter != NULL) {
9556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t->adoptFilter(globalFilter);
9566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
9576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    else if (U_SUCCESS(status)) {
9596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_MEMORY_ALLOCATION_ERROR;
9606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return t;
9626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
9636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
9656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Create a transliterator from a basic ID.  This is an ID
9666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * containing only the forward direction source, target, and
9676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * variant.
9686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param id a basic ID of the form S-T or S-T/V.
9696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @return a newly created Transliterator or null if the ID is
9706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * invalid.
9716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
9726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator* Transliterator::createBasicInstance(const UnicodeString& id,
9736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                    const UnicodeString* canon) {
9746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UParseError pe;
9756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
9766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    TransliteratorAlias* alias = 0;
9776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Transliterator* t = 0;
9786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    umtx_lock(&registryMutex);
9806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
9816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t = registry->get(id, alias, ec);
9826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    umtx_unlock(&registryMutex);
9846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(ec)) {
9866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete t;
9876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete alias;
9886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return 0;
9896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // We may have not gotten a transliterator:  Because we can't
9926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // instantiate a transliterator from inside TransliteratorRegistry::
9936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // get() (that would deadlock), we sometimes pass back an alias.  This
9946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // contains the data we need to finish the instantiation outside the
9956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // registry mutex.  The alias may, in turn, generate another alias, so
9966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // we handle aliases in a loop.  The max times through the loop is two.
9976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // [alan]
9986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    while (alias != 0) {
9996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        U_ASSERT(t==0);
10006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Rule-based aliases are handled with TransliteratorAlias::
10016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // parse(), followed by TransliteratorRegistry::reget().
10026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Other aliases are handled with TransliteratorAlias::create().
10036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (alias->isRuleBased()) {
10046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Step 1. parse
10056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            TransliteratorParser parser(ec);
10066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            alias->parse(parser, pe, ec);
10076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            delete alias;
10086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            alias = 0;
10096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Step 2. reget
10116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            umtx_lock(&registryMutex);
10126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (HAVE_REGISTRY(ec)) {
10136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                t = registry->reget(id, parser, alias, ec);
10146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
10156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            umtx_unlock(&registryMutex);
10166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Step 3. Loop back around!
10186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
10196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t = alias->create(pe, ec);
10206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            delete alias;
10216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            alias = 0;
10226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
10236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
10246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (U_FAILURE(ec)) {
10256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            delete t;
10266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            delete alias;
10276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t = NULL;
10286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
10296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
10306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
10316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (t != NULL && canon != NULL) {
10336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t->setID(*canon);
10346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
10356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return t;
10376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
10386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
10406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Returns a <code>Transliterator</code> object constructed from
10416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * the given rule string.  This will be a RuleBasedTransliterator,
10426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * if the rule string contains only rules, or a
10436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * CompoundTransliterator, if it contains ID blocks, or a
10446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * NullTransliterator, if it contains ID blocks which parse as
10456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * empty for the given direction.
10466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
10476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator* U_EXPORT2
10486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgTransliterator::createFromRules(const UnicodeString& ID,
10496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                const UnicodeString& rules,
10506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                UTransDirection dir,
10516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                UParseError& parseError,
10526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                UErrorCode& status)
10536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
10546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Transliterator* t = NULL;
10556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    TransliteratorParser parser(status);
10576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    parser.parse(rules, dir, parseError, status);
10586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
10606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return 0;
10616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
10626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // NOTE: The logic here matches that in TransliteratorRegistry.
10646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (parser.idBlockVector.size() == 0 && parser.dataVector.size() == 0) {
10656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t = new NullTransliterator();
10666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
10676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    else if (parser.idBlockVector.size() == 0 && parser.dataVector.size() == 1) {
10686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t = new RuleBasedTransliterator(ID, (TransliterationRuleData*)parser.dataVector.orphanElementAt(0), TRUE);
10696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
10706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    else if (parser.idBlockVector.size() == 1 && parser.dataVector.size() == 0) {
10716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // idBlock, no data -- this is an alias.  The ID has
10726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // been munged from reverse into forward mode, if
10736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // necessary, so instantiate the ID in the forward
10746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // direction.
10756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (parser.compoundFilter != NULL) {
10766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UnicodeString filterPattern;
10776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            parser.compoundFilter->toPattern(filterPattern, FALSE);
10786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t = createInstance(filterPattern + UnicodeString(ID_DELIM)
10796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    + *((UnicodeString*)parser.idBlockVector.elementAt(0)), UTRANS_FORWARD, parseError, status);
10806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
10816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        else
10826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t = createInstance(*((UnicodeString*)parser.idBlockVector.elementAt(0)), UTRANS_FORWARD, parseError, status);
10836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (t != NULL) {
10866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t->setID(ID);
10876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
10886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
10896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    else {
10906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UVector transliterators(status);
10916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t passNumber = 1;
10926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t limit = parser.idBlockVector.size();
10946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (parser.dataVector.size() > limit)
10956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            limit = parser.dataVector.size();
10966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        for (int32_t i = 0; i < limit; i++) {
10986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (i < parser.idBlockVector.size()) {
10996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                UnicodeString* idBlock = (UnicodeString*)parser.idBlockVector.elementAt(i);
11006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (!idBlock->isEmpty()) {
11016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    Transliterator* temp = createInstance(*idBlock, UTRANS_FORWARD, parseError, status);
11026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    if (temp != NULL && typeid(*temp) != typeid(NullTransliterator))
11036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        transliterators.addElement(temp, status);
11046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    else
11056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        delete temp;
11066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
11076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
11086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (!parser.dataVector.isEmpty()) {
11096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                TransliterationRuleData* data = (TransliterationRuleData*)parser.dataVector.orphanElementAt(0);
11106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // TODO: Should passNumber be turned into a decimal-string representation (1 -> "1")?
11116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                RuleBasedTransliterator* temprbt = new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + UnicodeString(passNumber++),
11126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        data, TRUE);
11136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // Check if NULL before adding it to transliterators to avoid future usage of NULL pointer.
11146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (temprbt == NULL) {
11156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                	status = U_MEMORY_ALLOCATION_ERROR;
11166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                	return t;
11176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
11186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                transliterators.addElement(temprbt, status);
11196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
11206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
11216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
11226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t = new CompoundTransliterator(transliterators, passNumber - 1, parseError, status);
11236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Null pointer check
11246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (t != NULL) {
11256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t->setID(ID);
11266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t->adoptFilter(parser.orphanCompoundFilter());
11276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
11286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
11296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_SUCCESS(status) && t == NULL) {
11306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_MEMORY_ALLOCATION_ERROR;
11316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
11326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return t;
11336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
11346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
11356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& Transliterator::toRules(UnicodeString& rulesSource,
11366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                       UBool escapeUnprintable) const {
11376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // The base class implementation of toRules munges the ID into
11386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // the correct format.  That is: foo => ::foo
11396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (escapeUnprintable) {
11406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        rulesSource.truncate(0);
11416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UnicodeString id = getID();
11426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        for (int32_t i=0; i<id.length();) {
11436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UChar32 c = id.char32At(i);
11446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (!ICU_Utility::escapeUnprintable(rulesSource, c)) {
11456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                rulesSource.append(c);
11466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
11476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            i += U16_LENGTH(c);
11486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
11496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
11506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        rulesSource = getID();
11516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
11526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // KEEP in sync with rbt_pars
11536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    rulesSource.insert(0, UNICODE_STRING_SIMPLE("::"));
11546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    rulesSource.append(ID_DELIM);
11556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return rulesSource;
11566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
11576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
11586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t Transliterator::countElements() const {
11596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const CompoundTransliterator* ct = dynamic_cast<const CompoundTransliterator*>(this);
11606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return ct != NULL ? ct->getCount() : 0;
11616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
11626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
11636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst Transliterator& Transliterator::getElement(int32_t index, UErrorCode& ec) const {
11646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(ec)) {
11656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return *this;
11666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
11676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const CompoundTransliterator* cpd = dynamic_cast<const CompoundTransliterator*>(this);
11686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t n = (cpd == NULL) ? 1 : cpd->getCount();
11696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (index < 0 || index >= n) {
11706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ec = U_INDEX_OUTOFBOUNDS_ERROR;
11716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return *this;
11726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
11736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return (n == 1) ? *this : cpd->getTransliterator(index);
11746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
11756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
11766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
11776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeSet& Transliterator::getSourceSet(UnicodeSet& result) const {
11786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    handleGetSourceSet(result);
11796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (filter != NULL) {
11806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UnicodeSet* filterSet = dynamic_cast<UnicodeSet*>(filter);
11816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UBool deleteFilterSet = FALSE;
11826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Most, but not all filters will be UnicodeSets.  Optimize for
11836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // the high-runner case.
11846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (filterSet == NULL) {
11856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            filterSet = new UnicodeSet();
11866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Check null pointer
11876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (filterSet == NULL) {
11886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return result;
11896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
11906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            deleteFilterSet = TRUE;
11916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            filter->addMatchSetTo(*filterSet);
11926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
11936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result.retainAll(*filterSet);
11946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (deleteFilterSet) {
11956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            delete filterSet;
11966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
11976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
11986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
11996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::handleGetSourceSet(UnicodeSet& result) const {
12026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    result.clear();
12036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeSet& Transliterator::getTargetSet(UnicodeSet& result) const {
12066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result.clear();
12076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// For public consumption
12106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid U_EXPORT2 Transliterator::registerFactory(const UnicodeString& id,
12116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                     Transliterator::Factory factory,
12126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                     Transliterator::Token context) {
12136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
12146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
12156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
12166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        _registerFactory(id, factory, context);
12176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
12186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// To be called only by Transliterator subclasses that are called
12216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// to register themselves by initializeRegistry().
12226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::_registerFactory(const UnicodeString& id,
12236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                      Transliterator::Factory factory,
12246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                      Transliterator::Token context) {
12256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
12266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry->put(id, factory, context, TRUE, ec);
12276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// To be called only by Transliterator subclasses that are called
12306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// to register themselves by initializeRegistry().
12316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::_registerSpecialInverse(const UnicodeString& target,
12326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                             const UnicodeString& inverseTarget,
12336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                             UBool bidirectional) {
12346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode status = U_ZERO_ERROR;
12356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    TransliteratorIDParser::registerSpecialInverse(target, inverseTarget, bidirectional, status);
12366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
12396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Registers a instance <tt>obj</tt> of a subclass of
12406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>Transliterator</code> with the system.  This object must
12416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * implement the <tt>clone()</tt> method.  When
12426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <tt>getInstance()</tt> is called with an ID string that is
12436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * equal to <tt>obj.getID()</tt>, then <tt>obj.clone()</tt> is
12446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * returned.
12456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
12466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param obj an instance of subclass of
12476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * <code>Transliterator</code> that defines <tt>clone()</tt>
12486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #getInstance
12496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #unregister
12506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
12516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid U_EXPORT2 Transliterator::registerInstance(Transliterator* adoptedPrototype) {
12526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
12536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
12546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
12556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        _registerInstance(adoptedPrototype);
12566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
12576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::_registerInstance(Transliterator* adoptedPrototype) {
12606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
12616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry->put(adoptedPrototype, TRUE, ec);
12626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid U_EXPORT2 Transliterator::registerAlias(const UnicodeString& aliasID,
12656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                             const UnicodeString& realID) {
12666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
12676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
12686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
12696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        _registerAlias(aliasID, realID);
12706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
12716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid Transliterator::_registerAlias(const UnicodeString& aliasID,
12746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                    const UnicodeString& realID) {
12756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
12766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry->put(aliasID, realID, FALSE, TRUE, ec);
12776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
12806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Unregisters a transliterator or class.  This may be either
12816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * a system transliterator or a user transliterator or class.
12826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
12836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param ID the ID of the transliterator or class
12846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @see #registerInstance
12856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
12876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid U_EXPORT2 Transliterator::unregister(const UnicodeString& ID) {
12886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
12896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
12906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
12916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        registry->remove(ID);
12926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
12936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
12966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * == OBSOLETE - remove in ICU 3.4 ==
12976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Return the number of IDs currently registered with the system.
12986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * To retrieve the actual IDs, call getAvailableID(i) with
12996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * i from 0 to countAvailableIDs() - 1.
13006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
13016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t U_EXPORT2 Transliterator::countAvailableIDs(void) {
13026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t retVal = 0;
13036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
13046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
13056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
13066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        retVal = registry->countAvailableIDs();
13076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return retVal;
13096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
13126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * == OBSOLETE - remove in ICU 3.4 ==
13136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Return the index-th available ID.  index must be between 0
13146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * and countAvailableIDs() - 1, inclusive.  If index is out of
13156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * range, the result of getAvailableID(0) is returned.
13166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
13176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst UnicodeString& U_EXPORT2 Transliterator::getAvailableID(int32_t index) {
13186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const UnicodeString* result = NULL;
13196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    umtx_lock(&registryMutex);
13206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
13216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
13226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result = &registry->getAvailableID(index);
13236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    umtx_unlock(&registryMutex);
13256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    U_ASSERT(result != NULL); // fail if no registry
13266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return *result;
13276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgStringEnumeration* U_EXPORT2 Transliterator::getAvailableIDs(UErrorCode& ec) {
13306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(ec)) return NULL;
13316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    StringEnumeration* result = NULL;
13326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    umtx_lock(&registryMutex);
13336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
13346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result = registry->getAvailableIDs();
13356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    umtx_unlock(&registryMutex);
13376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (result == NULL) {
13386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ec = U_INTERNAL_TRANSLITERATOR_ERROR;
13396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
13416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t U_EXPORT2 Transliterator::countAvailableSources(void) {
13446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
13456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
13466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return HAVE_REGISTRY(ec) ? _countAvailableSources() : 0;
13476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& U_EXPORT2 Transliterator::getAvailableSource(int32_t index,
13506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                  UnicodeString& result) {
13516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
13526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
13536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
13546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        _getAvailableSource(index, result);
13556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
13576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t U_EXPORT2 Transliterator::countAvailableTargets(const UnicodeString& source) {
13606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
13616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
13626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return HAVE_REGISTRY(ec) ? _countAvailableTargets(source) : 0;
13636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& U_EXPORT2 Transliterator::getAvailableTarget(int32_t index,
13666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                  const UnicodeString& source,
13676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                  UnicodeString& result) {
13686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
13696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
13706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
13716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        _getAvailableTarget(index, source, result);
13726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
13746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t U_EXPORT2 Transliterator::countAvailableVariants(const UnicodeString& source,
13776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                               const UnicodeString& target) {
13786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
13796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
13806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return HAVE_REGISTRY(ec) ? _countAvailableVariants(source, target) : 0;
13816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& U_EXPORT2 Transliterator::getAvailableVariant(int32_t index,
13846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                   const UnicodeString& source,
13856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                   const UnicodeString& target,
13866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                   UnicodeString& result) {
13876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Mutex lock(&registryMutex);
13886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
13896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (HAVE_REGISTRY(ec)) {
13906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        _getAvailableVariant(index, source, target, result);
13916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
13936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t Transliterator::_countAvailableSources(void) {
13966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return registry->countAvailableSources();
13976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& Transliterator::_getAvailableSource(int32_t index,
14006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                  UnicodeString& result) {
14016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return registry->getAvailableSource(index, result);
14026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
14036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t Transliterator::_countAvailableTargets(const UnicodeString& source) {
14056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return registry->countAvailableTargets(source);
14066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
14076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& Transliterator::_getAvailableTarget(int32_t index,
14096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                  const UnicodeString& source,
14106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                  UnicodeString& result) {
14116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return registry->getAvailableTarget(index, source, result);
14126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
14136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t Transliterator::_countAvailableVariants(const UnicodeString& source,
14156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                               const UnicodeString& target) {
14166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return registry->countAvailableVariants(source, target);
14176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
14186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& Transliterator::_getAvailableVariant(int32_t index,
14206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                   const UnicodeString& source,
14216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                   const UnicodeString& target,
14226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                   UnicodeString& result) {
14236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return registry->getAvailableVariant(index, source, target, result);
14246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
14256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#ifdef U_USE_DEPRECATED_TRANSLITERATOR_API
14276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
14296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Method for subclasses to use to obtain a character in the given
14306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * string, with filtering.
14316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @deprecated the new architecture provides filtering at the top
14326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * level.  This method will be removed Dec 31 2001.
14336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
14346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUChar Transliterator::filteredCharAt(const Replaceable& text, int32_t i) const {
14356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UChar c;
14366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const UnicodeFilter* localFilter = getFilter();
14376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return (localFilter == 0) ? text.charAt(i) :
14386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        (localFilter->contains(c = text.charAt(i)) ? c : (UChar)0xFFFE);
14396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
14406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
14426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
14446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * If the registry is initialized, return TRUE.  If not, initialize it
14456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * and return TRUE.  If the registry cannot be initialized, return
14466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * FALSE (rare).
14476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
14486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * IMPORTANT: Upon entry, registryMutex must be LOCKED.  The entire
14496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * initialization is done with the lock held.  There is NO REASON to
14506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * unlock, since no other thread that is waiting on the registryMutex
14516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * cannot itself proceed until the registry is initialized.
14526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
14536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool Transliterator::initializeRegistry(UErrorCode &status) {
14546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (registry != 0) {
14556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return TRUE;
14566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
14576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry = new TransliteratorRegistry(status);
14596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (registry == 0 || U_FAILURE(status)) {
14606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete registry;
14616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        registry = 0;
14626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return FALSE; // can't create registry, no recovery
14636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
14646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /* The following code parses the index table located in
14666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * icu/data/translit/root.txt.  The index is an n x 4 table
14676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * that follows this format:
14686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *  <id>{
14696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *      file{
14706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *          resource{"<resource>"}
14716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *          direction{"<direction>"}
14726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *      }
14736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *  }
14746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *  <id>{
14756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *      internal{
14766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *          resource{"<resource>"}
14776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *          direction{"<direction"}
14786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *       }
14796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *  }
14806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *  <id>{
14816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *      alias{"<getInstanceArg"}
14826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *  }
14836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * <id> is the ID of the system transliterator being defined.  These
14846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * are public IDs enumerated by Transliterator.getAvailableIDs(),
14856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * unless the second field is "internal".
14866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *
14876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * <resource> is a ResourceReader resource name.  Currently these refer
14886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * to file names under com/ibm/text/resources.  This string is passed
14896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * directly to ResourceReader, together with <encoding>.
14906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *
14916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * <direction> is either "FORWARD" or "REVERSE".
14926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *
14936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * <getInstanceArg> is a string to be passed directly to
14946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * Transliterator.getInstance().  The returned Transliterator object
14956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * then has its ID changed to <id> and is returned.
14966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     *
14976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * The extra blank field on "alias" lines is to make the array square.
14986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     */
14996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //static const char translit_index[] = "translit_index";
15006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UResourceBundle *bundle, *transIDs, *colBund;
15026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    bundle = ures_open(U_ICUDATA_TRANSLIT, NULL/*open default locale*/, &status);
15036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    transIDs = ures_getByKey(bundle, RB_RULE_BASED_IDS, 0, &status);
15046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t row, maxRows;
15066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_SUCCESS(status)) {
15076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        maxRows = ures_getSize(transIDs);
15086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        for (row = 0; row < maxRows; row++) {
15096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            colBund = ures_getByIndex(transIDs, row, 0, &status);
15106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (U_SUCCESS(status)) {
15116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                UnicodeString id(ures_getKey(colBund), -1, US_INV);
15126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                UResourceBundle* res = ures_getNextResource(colBund, NULL, &status);
15136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                const char* typeStr = ures_getKey(res);
15146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                UChar type;
15156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                u_charsToUChars(typeStr, &type, 1);
15166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (U_SUCCESS(status)) {
15186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    int32_t len = 0;
15196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    const UChar *resString;
15206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    switch (type) {
15216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    case 0x66: // 'f'
15226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    case 0x69: // 'i'
15236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        // 'file' or 'internal';
15246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        // row[2]=resource, row[3]=direction
15256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        {
15266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            resString = ures_getStringByKey(res, "resource", &len, &status);
15286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UBool visible = (type == 0x0066 /*f*/);
15296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UTransDirection dir =
15306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                (ures_getUnicodeStringByKey(res, "direction", &status).charAt(0) ==
15316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                 0x0046 /*F*/) ?
15326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                UTRANS_FORWARD : UTRANS_REVERSE;
15336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            registry->put(id, UnicodeString(TRUE, resString, len), dir, TRUE, visible, status);
15346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        }
15356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        break;
15366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    case 0x61: // 'a'
15376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        // 'alias'; row[2]=createInstance argument
15386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        resString = ures_getString(res, &len, &status);
15396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        registry->put(id, UnicodeString(TRUE, resString, len), TRUE, TRUE, status);
15406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        break;
15416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    }
15426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
15436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                ures_close(res);
15446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
15456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            ures_close(colBund);
15466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
15476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
15486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ures_close(transIDs);
15506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ures_close(bundle);
15516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Manually add prototypes that the system knows about to the
15536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // cache.  This is how new non-rule-based transliterators are
15546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // added to the system.
15556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // This is to allow for null pointer check
15576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    NullTransliterator* tempNullTranslit = new NullTransliterator();
15586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    LowercaseTransliterator* tempLowercaseTranslit = new LowercaseTransliterator();
15596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UppercaseTransliterator* tempUppercaseTranslit = new UppercaseTransliterator();
15606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    TitlecaseTransliterator* tempTitlecaseTranslit = new TitlecaseTransliterator();
15616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeNameTransliterator* tempUnicodeTranslit = new UnicodeNameTransliterator();
15626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    NameUnicodeTransliterator* tempNameUnicodeTranslit = new NameUnicodeTransliterator();
15636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_BREAK_ITERATION
15646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     // TODO: could or should these transliterators be referenced polymorphically once constructed?
15656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     BreakTransliterator* tempBreakTranslit         = new BreakTransliterator();
15666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
15676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Check for null pointers
15686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (tempNullTranslit == NULL || tempLowercaseTranslit == NULL || tempUppercaseTranslit == NULL ||
15696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        tempTitlecaseTranslit == NULL || tempUnicodeTranslit == NULL ||
15706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_BREAK_ITERATION
15716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        tempBreakTranslit == NULL ||
15726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
15736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        tempNameUnicodeTranslit == NULL )
15746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    {
15756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete tempNullTranslit;
15766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete tempLowercaseTranslit;
15776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete tempUppercaseTranslit;
15786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete tempTitlecaseTranslit;
15796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete tempUnicodeTranslit;
15806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete tempNameUnicodeTranslit;
15816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_BREAK_ITERATION
15826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete tempBreakTranslit;
15836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
15846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Since there was an error, remove registry
15856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete registry;
15866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        registry = NULL;
15876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_MEMORY_ALLOCATION_ERROR;
15896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return 0;
15906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
15916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry->put(tempNullTranslit, TRUE, status);
15936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry->put(tempLowercaseTranslit, TRUE, status);
15946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry->put(tempUppercaseTranslit, TRUE, status);
15956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry->put(tempTitlecaseTranslit, TRUE, status);
15966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry->put(tempUnicodeTranslit, TRUE, status);
15976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry->put(tempNameUnicodeTranslit, TRUE, status);
15986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_BREAK_ITERATION
15996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    registry->put(tempBreakTranslit, FALSE, status);   // FALSE means invisible.
16006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
16016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    RemoveTransliterator::registerIDs(); // Must be within mutex
16036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    EscapeTransliterator::registerIDs();
16046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnescapeTransliterator::registerIDs();
16056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    NormalizationTransliterator::registerIDs();
16066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    AnyTransliterator::registerIDs();
16076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    _registerSpecialInverse(UNICODE_STRING_SIMPLE("Null"),
16096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UNICODE_STRING_SIMPLE("Null"), FALSE);
16106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    _registerSpecialInverse(UNICODE_STRING_SIMPLE("Upper"),
16116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UNICODE_STRING_SIMPLE("Lower"), TRUE);
16126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    _registerSpecialInverse(UNICODE_STRING_SIMPLE("Title"),
16136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UNICODE_STRING_SIMPLE("Lower"), FALSE);
16146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ucln_i18n_registerCleanup(UCLN_I18N_TRANSLITERATOR, utrans_transliterator_cleanup);
16166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return TRUE;
16186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
16196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_END
16216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Defined in ucln_in.h:
16236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
16256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Release all static memory held by transliterator.  This will
16266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * necessarily invalidate any rule-based transliterators held by the
16276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * user, because RBTs hold pointers to common data objects.
16286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
16296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CFUNC UBool utrans_transliterator_cleanup(void) {
16306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    U_NAMESPACE_USE
16316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    TransliteratorIDParser::cleanup();
16326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (registry) {
16336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete registry;
16346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        registry = NULL;
16356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
16366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return TRUE;
16376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
16386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif /* #if !UCONFIG_NO_TRANSLITERATION */
16406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//eof
1642