// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
* Copyright (c) 2001-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Date Name Description
* 08/10/2001 aliu Creation.
**********************************************************************
*/
#ifndef _TRANSREG_H
#define _TRANSREG_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_TRANSLITERATION
#include "unicode/uobject.h"
#include "unicode/translit.h"
#include "hash.h"
#include "uvector.h"
U_NAMESPACE_BEGIN
class TransliteratorEntry;
class TransliteratorSpec;
class UnicodeString;
//------------------------------------------------------------------
// TransliteratorAlias
//------------------------------------------------------------------
/**
* A TransliteratorAlias object is returned by get() if the given ID
* actually translates into something else. The caller then invokes
* the create() method on the alias to create the actual
* transliterator, and deletes the alias.
*
* Why all the shenanigans? To prevent circular calls between
* the registry code and the transliterator code that deadlocks.
*/
class TransliteratorAlias : public UMemory {
public:
/**
* Construct a simple alias (type == SIMPLE)
* @param aliasID the given id.
*/
TransliteratorAlias(const UnicodeString& aliasID, const UnicodeSet* compoundFilter);
/**
* Construct a compound RBT alias (type == COMPOUND)
*/
TransliteratorAlias(const UnicodeString& ID, const UnicodeString& idBlocks,
UVector* adoptedTransliterators,
const UnicodeSet* compoundFilter);
/**
* Construct a rules alias (type = RULES)
*/
TransliteratorAlias(const UnicodeString& theID,
const UnicodeString& rules,
UTransDirection dir);
~TransliteratorAlias();
/**
* The whole point of create() is that the caller must invoke
* it when the registry mutex is NOT held, to prevent deadlock.
* It may only be called once.
*
* Note: Only call create() if isRuleBased() returns FALSE.
*
* This method must be called *outside* of the TransliteratorRegistry
* mutex.
*/
Transliterator* create(UParseError&, UErrorCode&);
/**
* Return TRUE if this alias is rule-based. If so, the caller
* must call parse() on it, then call TransliteratorRegistry::reget().
*/
UBool isRuleBased() const;
/**
* If isRuleBased() returns TRUE, then the caller must call this
* method, followed by TransliteratorRegistry::reget(). The latter
* method must be called inside the TransliteratorRegistry mutex.
*
* Note: Only call parse() if isRuleBased() returns TRUE.
*
* This method must be called *outside* of the TransliteratorRegistry
* mutex, because it can instantiate Transliterators embedded in
* the rules via the "&Latin-Arabic()" syntax.
*/
void parse(TransliteratorParser& parser,
UParseError& pe, UErrorCode& ec) const;
private:
// We actually come in three flavors:
// 1. Simple alias
// Here aliasID is the alias string. Everything else is
// null, zero, empty.
// 2. CompoundRBT
// Here ID is the ID, aliasID is the idBlock, trans is the
// contained RBT, and idSplitPoint is the offet in aliasID
// where the contained RBT goes. compoundFilter is the
// compound filter, and it is _not_ owned.
// 3. Rules
// Here ID is the ID, aliasID is the rules string.
// idSplitPoint is the UTransDirection.
UnicodeString ID;
UnicodeString aliasesOrRules;
UVector* transes; // owned
const UnicodeSet* compoundFilter; // alias
UTransDirection direction;
enum { SIMPLE, COMPOUND, RULES } type;
TransliteratorAlias(const TransliteratorAlias &other); // forbid copying of this class
TransliteratorAlias &operator=(const TransliteratorAlias &other); // forbid copying of this class
};
/**
* A registry of system transliterators. This is the data structure
* that implements the mapping between transliterator IDs and the data
* or function pointers used to create the corresponding
* transliterators. There is one instance of the registry that is
* created statically.
*
* The registry consists of a dynamic component -- a hashtable -- and
* a static component -- locale resource bundles. The dynamic store
* is semantically overlaid on the static store, so the static mapping
* can be dynamically overridden.
*
* This is an internal class that is only used by Transliterator.
* Transliterator maintains one static instance of this class and
* delegates all registry-related operations to it.
*
* @author Alan Liu
*/
class TransliteratorRegistry : public UMemory {
public:
/**
* Contructor
* @param status Output param set to success/failure code.
*/
TransliteratorRegistry(UErrorCode& status);
/**
* Nonvirtual destructor -- this class is not subclassable.
*/
~TransliteratorRegistry();
//------------------------------------------------------------------
// Basic public API
//------------------------------------------------------------------
/**
* Given a simple ID (forward direction, no inline filter, not
* compound) attempt to instantiate it from the registry. Return
* 0 on failure.
*
* Return a non-NULL aliasReturn value if the ID points to an alias.
* We cannot instantiate it ourselves because the alias may contain
* filters or compounds, which we do not understand. Caller should
* make aliasReturn NULL before calling.
* @param ID the given ID
* @param aliasReturn output param to receive TransliteratorAlias;
* should be NULL on entry
* @param parseError Struct to recieve information on position
* of error if an error is encountered
* @param status Output param set to success/failure code.
*/
Transliterator* get(const UnicodeString& ID,
TransliteratorAlias*& aliasReturn,
UErrorCode& status);
/**
* The caller must call this after calling get(), if [a] calling get()
* returns an alias, and [b] the alias is rule based. In that
* situation the caller must call alias->parse() to do the parsing
* OUTSIDE THE REGISTRY MUTEX, then call this method to retry
* instantiating the transliterator.
*
* Note: Another alias might be returned by this method.
*
* This method (like all public methods of this class) must be called
* from within the TransliteratorRegistry mutex.
*
* @param aliasReturn output param to receive TransliteratorAlias;
* should be NULL on entry
*/
Transliterator* reget(const UnicodeString& ID,
TransliteratorParser& parser,
TransliteratorAlias*& aliasReturn,
UErrorCode& status);
/**
* Register a prototype (adopted). This adds an entry to the
* dynamic store, or replaces an existing entry. Any entry in the
* underlying static locale resource store is masked.
*/
void put(Transliterator* adoptedProto,
UBool visible,
UErrorCode& ec);
/**
* Register an ID and a factory function pointer. This adds an
* entry to the dynamic store, or replaces an existing entry. Any
* entry in the underlying static locale resource store is masked.
*/
void put(const UnicodeString& ID,
Transliterator::Factory factory,
Transliterator::Token context,
UBool visible,
UErrorCode& ec);
/**
* Register an ID and a resource name. This adds an entry to the
* dynamic store, or replaces an existing entry. Any entry in the
* underlying static locale resource store is masked.
*/
void put(const UnicodeString& ID,
const UnicodeString& resourceName,
UTransDirection dir,
UBool readonlyResourceAlias,
UBool visible,
UErrorCode& ec);
/**
* Register an ID and an alias ID. This adds an entry to the
* dynamic store, or replaces an existing entry. Any entry in the
* underlying static locale resource store is masked.
*/
void put(const UnicodeString& ID,
const UnicodeString& alias,
UBool readonlyAliasAlias,
UBool visible,
UErrorCode& ec);
/**
* Unregister an ID. This removes an entry from the dynamic store
* if there is one. The static locale resource store is
* unaffected.
* @param ID the given ID.
*/
void remove(const UnicodeString& ID);
//------------------------------------------------------------------
// Public ID and spec management
//------------------------------------------------------------------
/**
* Return a StringEnumeration over the IDs currently registered
* with the system.
* @internal
*/
StringEnumeration* getAvailableIDs() const;
/**
* == OBSOLETE - remove in ICU 3.4 ==
* Return the number of IDs currently registered with the system.
* To retrieve the actual IDs, call getAvailableID(i) with
* i from 0 to countAvailableIDs() - 1.
* @return the number of IDs currently registered with the system.
* @internal
*/
int32_t countAvailableIDs(void) const;
/**
* == OBSOLETE - remove in ICU 3.4 ==
* Return the index-th available ID. index must be between 0
* and countAvailableIDs() - 1, inclusive. If index is out of
* range, the result of getAvailableID(0) is returned.
* @param index the given index.
* @return the index-th available ID. index must be between 0
* and countAvailableIDs() - 1, inclusive. If index is out of
* range, the result of getAvailableID(0) is returned.
* @internal
*/
const UnicodeString& getAvailableID(int32_t index) const;
/**
* Return the number of registered source specifiers.
* @return the number of registered source specifiers.
*/
int32_t countAvailableSources(void) const;
/**
* Return a registered source specifier.
* @param index which specifier to return, from 0 to n-1, where
* n = countAvailableSources()
* @param result fill-in paramter to receive the source specifier.
* If index is out of range, result will be empty.
* @return reference to result
*/
UnicodeString& getAvailableSource(int32_t index,
UnicodeString& result) const;
/**
* Return the number of registered target specifiers for a given
* source specifier.
* @param source the given source specifier.
* @return the number of registered target specifiers for a given
* source specifier.
*/
int32_t countAvailableTargets(const UnicodeString& source) const;
/**
* Return a registered target specifier for a given source.
* @param index which specifier to return, from 0 to n-1, where
* n = countAvailableTargets(source)
* @param source the source specifier
* @param result fill-in paramter to receive the target specifier.
* If source is invalid or if index is out of range, result will
* be empty.
* @return reference to result
*/
UnicodeString& getAvailableTarget(int32_t index,
const UnicodeString& source,
UnicodeString& result) const;
/**
* Return the number of registered variant specifiers for a given
* source-target pair. There is always at least one variant: If
* just source-target is registered, then the single variant
* NO_VARIANT is returned. If source-target/variant is registered
* then that variant is returned.
* @param source the source specifiers
* @param target the target specifiers
* @return the number of registered variant specifiers for a given
* source-target pair.
*/
int32_t countAvailableVariants(const UnicodeString& source,
const UnicodeString& target) const;
/**
* Return a registered variant specifier for a given source-target
* pair. If NO_VARIANT is one of the variants, then it will be
* at index 0.
* @param index which specifier to return, from 0 to n-1, where
* n = countAvailableVariants(source, target)
* @param source the source specifier
* @param target the target specifier
* @param result fill-in paramter to receive the variant
* specifier. If source is invalid or if target is invalid or if
* index is out of range, result will be empty.
* @return reference to result
*/
UnicodeString& getAvailableVariant(int32_t index,
const UnicodeString& source,
const UnicodeString& target,
UnicodeString& result) const;
private:
//----------------------------------------------------------------
// Private implementation
//----------------------------------------------------------------
TransliteratorEntry* find(const UnicodeString& ID);
TransliteratorEntry* find(UnicodeString& source,
UnicodeString& target,
UnicodeString& variant);
TransliteratorEntry* findInDynamicStore(const TransliteratorSpec& src,
const TransliteratorSpec& trg,
const UnicodeString& variant) const;
TransliteratorEntry* findInStaticStore(const TransliteratorSpec& src,
const TransliteratorSpec& trg,
const UnicodeString& variant);
static TransliteratorEntry* findInBundle(const TransliteratorSpec& specToOpen,
const TransliteratorSpec& specToFind,
const UnicodeString& variant,
UTransDirection direction);
void registerEntry(const UnicodeString& source,
const UnicodeString& target,
const UnicodeString& variant,
TransliteratorEntry* adopted,
UBool visible);
void registerEntry(const UnicodeString& ID,
TransliteratorEntry* adopted,
UBool visible);
void registerEntry(const UnicodeString& ID,
const UnicodeString& source,
const UnicodeString& target,
const UnicodeString& variant,
TransliteratorEntry* adopted,
UBool visible);
void registerSTV(const UnicodeString& source,
const UnicodeString& target,
const UnicodeString& variant);
void removeSTV(const UnicodeString& source,
const UnicodeString& target,
const UnicodeString& variant);
Transliterator* instantiateEntry(const UnicodeString& ID,
TransliteratorEntry *entry,
TransliteratorAlias*& aliasReturn,
UErrorCode& status);
/**
* A StringEnumeration over the registered IDs in this object.
*/
class Enumeration : public StringEnumeration {
public:
Enumeration(const TransliteratorRegistry& reg);
virtual ~Enumeration();
virtual int32_t count(UErrorCode& status) const;
virtual const UnicodeString* snext(UErrorCode& status);
virtual void reset(UErrorCode& status);
static UClassID U_EXPORT2 getStaticClassID();
virtual UClassID getDynamicClassID() const;
private:
int32_t index;
const TransliteratorRegistry& reg;
};
friend class Enumeration;
private:
/**
* Dynamic registry mapping full IDs to Entry objects. This
* contains both public and internal entities. The visibility is
* controlled by whether an entry is listed in availableIDs and
* specDAG or not.
*/
Hashtable registry;
/**
* DAG of visible IDs by spec. Hashtable: source => (Hashtable:
* target => variant bitmask)
*/
Hashtable specDAG;
/**
* Vector of all variant names
*/
UVector variantList;
/**
* Vector of public full IDs.
*/
UVector availableIDs;
TransliteratorRegistry(const TransliteratorRegistry &other); // forbid copying of this class
TransliteratorRegistry &operator=(const TransliteratorRegistry &other); // forbid copying of this class
};
U_NAMESPACE_END
U_CFUNC UBool utrans_transliterator_cleanup(void);
#endif /* #if !UCONFIG_NO_TRANSLITERATION */
#endif
//eof