// © 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html /* ******************************************************************************* * * Copyright (C) 2004-2014, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* * file name: ucase.cpp * encoding: UTF-8 * tab size: 8 (not used) * indentation:4 * * created on: 2004aug30 * created by: Markus W. Scherer * * Low-level Unicode character/string case mapping code. * Much code moved here (and modified) from uchar.c. */ #include "unicode/utypes.h" #include "unicode/unistr.h" #include "unicode/uset.h" #include "unicode/utf16.h" #include "cmemory.h" #include "uassert.h" #include "ucase.h" #include "umutex.h" #include "utrie2.h" /* ucase_props_data.h is machine-generated by genprops/casepropsbuilder.cpp */ #define INCLUDED_FROM_UCASE_CPP #include "ucase_props_data.h" /* set of property starts for UnicodeSet ------------------------------------ */ static UBool U_CALLCONV _enumPropertyStartsRange(const void *context, UChar32 start, UChar32 /*end*/, uint32_t /*value*/) { … } U_CFUNC void U_EXPORT2 ucase_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) { … } /* data access primitives --------------------------------------------------- */ U_CAPI const struct UCaseProps * U_EXPORT2 ucase_getSingleton(int32_t *pExceptionsLength, int32_t *pUnfoldLength) { … } U_CFUNC const UTrie2 * U_EXPORT2 ucase_getTrie() { … } #define GET_EXCEPTIONS(csp, props) … /* number of bits in an 8-bit integer value */ static const uint8_t flagsOffset[256]= …; #define HAS_SLOT(flags, idx) … #define SLOT_OFFSET(flags, idx) … /* * Get the value of an optional-value slot where HAS_SLOT(excWord, idx). * * @param excWord (in) initial exceptions word * @param idx (in) desired slot index * @param pExc16 (in/out) const uint16_t * after excWord=*pExc16++; * moved to the last uint16_t of the value, use +1 for beginning of next slot * @param value (out) int32_t or uint32_t output if hasSlot, otherwise not modified */ #define GET_SLOT_VALUE(excWord, idx, pExc16, value) … /* simple case mappings ----------------------------------------------------- */ U_CAPI UChar32 U_EXPORT2 ucase_tolower(UChar32 c) { … } U_CAPI UChar32 U_EXPORT2 ucase_toupper(UChar32 c) { … } U_CAPI UChar32 U_EXPORT2 ucase_totitle(UChar32 c) { … } static const char16_t iDot[2] = …; static const char16_t jDot[2] = …; static const char16_t iOgonekDot[3] = …; static const char16_t iDotGrave[3] = …; static const char16_t iDotAcute[3] = …; static const char16_t iDotTilde[3] = …; U_CFUNC void U_EXPORT2 ucase_addCaseClosure(UChar32 c, const USetAdder *sa) { … } U_CFUNC void U_EXPORT2 ucase_addSimpleCaseClosure(UChar32 c, const USetAdder *sa) { … } /* * compare s, which has a length, with t, which has a maximum length or is NUL-terminated * must be length>0 and max>0 and length<=max */ static inline int32_t strcmpMax(const char16_t *s, int32_t length, const char16_t *t, int32_t max) { … } U_CFUNC UBool U_EXPORT2 ucase_addStringCaseClosure(const char16_t *s, int32_t length, const USetAdder *sa) { … } U_NAMESPACE_BEGIN FullCaseFoldingIterator::FullCaseFoldingIterator() : … { … } UChar32 FullCaseFoldingIterator::next(UnicodeString &full) { … } namespace LatinCase { const int8_t TO_LOWER_NORMAL[LIMIT] = …; const int8_t TO_LOWER_TR_LT[LIMIT] = …; const int8_t TO_UPPER_NORMAL[LIMIT] = …; const int8_t TO_UPPER_TR[LIMIT] = …; } // namespace LatinCase U_NAMESPACE_END /** @return UCASE_NONE, UCASE_LOWER, UCASE_UPPER, UCASE_TITLE */ U_CAPI int32_t U_EXPORT2 ucase_getType(UChar32 c) { … } /** @return same as ucase_getType() and set bit 2 if c is case-ignorable */ U_CAPI int32_t U_EXPORT2 ucase_getTypeOrIgnorable(UChar32 c) { … } /** @return UCASE_NO_DOT, UCASE_SOFT_DOTTED, UCASE_ABOVE, UCASE_OTHER_ACCENT */ static inline int32_t getDotType(UChar32 c) { … } U_CAPI UBool U_EXPORT2 ucase_isSoftDotted(UChar32 c) { … } U_CAPI UBool U_EXPORT2 ucase_isCaseSensitive(UChar32 c) { … } /* string casing ------------------------------------------------------------ */ /* * These internal functions form the core of string case mappings. * They map single code points to result code points or strings and take * all necessary conditions (context, locale ID, options) into account. * * They do not iterate over the source or write to the destination * so that the same functions are useful for non-standard string storage, * such as in a Replaceable (for Transliterator) or UTF-8/32 strings etc. * For the same reason, the "surrounding text" context is passed in as a * UCaseContextIterator which does not make any assumptions about * the underlying storage. * * This section contains helper functions that check for conditions * in the input text surrounding the current code point * according to SpecialCasing.txt. * * Each helper function gets the index * - after the current code point if it looks at following text * - before the current code point if it looks at preceding text * * Unicode 3.2 UAX 21 "Case Mappings" defines the conditions as follows: * * Final_Sigma * C is preceded by a sequence consisting of * a cased letter and a case-ignorable sequence, * and C is not followed by a sequence consisting of * an ignorable sequence and then a cased letter. * * More_Above * C is followed by one or more characters of combining class 230 (ABOVE) * in the combining character sequence. * * After_Soft_Dotted * The last preceding character with combining class of zero before C * was Soft_Dotted, * and there is no intervening combining character class 230 (ABOVE). * * Before_Dot * C is followed by combining dot above (U+0307). * Any sequence of characters with a combining class that is neither 0 nor 230 * may intervene between the current character and the combining dot above. * * The erratum from 2002-10-31 adds the condition * * After_I * The last preceding base character was an uppercase I, and there is no * intervening combining character class 230 (ABOVE). * * (See Jitterbug 2344 and the comments on After_I below.) * * Helper definitions in Unicode 3.2 UAX 21: * * D1. A character C is defined to be cased * if it meets any of the following criteria: * * - The general category of C is Titlecase Letter (Lt) * - In [CoreProps], C has one of the properties Uppercase, or Lowercase * - Given D = NFD(C), then it is not the case that: * D = UCD_lower(D) = UCD_upper(D) = UCD_title(D) * (This third criterion does not add any characters to the list * for Unicode 3.2. Ignored.) * * D2. A character C is defined to be case-ignorable * if it meets either of the following criteria: * * - The general category of C is * Nonspacing Mark (Mn), or Enclosing Mark (Me), or Format Control (Cf), or * Letter Modifier (Lm), or Symbol Modifier (Sk) * - C is one of the following characters * U+0027 APOSTROPHE * U+00AD SOFT HYPHEN (SHY) * U+2019 RIGHT SINGLE QUOTATION MARK * (the preferred character for apostrophe) * * D3. A case-ignorable sequence is a sequence of * zero or more case-ignorable characters. */ #define is_d(c) … #define is_e(c) … #define is_i(c) … #define is_l(c) … #define is_r(c) … #define is_t(c) … #define is_u(c) … #define is_y(c) … #define is_z(c) … /* separator? */ #define is_sep(c) … /** * Requires non-nullptr locale ID but otherwise does the equivalent of * checking for language codes as if uloc_getLanguage() were called: * Accepts both 2- and 3-letter codes and accepts case variants. */ U_CFUNC int32_t ucase_getCaseLocale(const char *locale) { … } /* * Is followed by * {case-ignorable}* cased * ? * (dir determines looking forward/backward) * If a character is case-ignorable, it is skipped regardless of whether * it is also cased or not. */ static UBool isFollowedByCasedLetter(UCaseContextIterator *iter, void *context, int8_t dir) { … } /* Is preceded by Soft_Dotted character with no intervening cc=230 ? */ static UBool isPrecededBySoftDotted(UCaseContextIterator *iter, void *context) { … } /* * See Jitterbug 2344: * The condition After_I for Turkic-lowercasing of U+0307 combining dot above * is checked in ICU 2.0, 2.1, 2.6 but was not in 2.2 & 2.4 because * we made those releases compatible with Unicode 3.2 which had not fixed * a related bug in SpecialCasing.txt. * * From the Jitterbug 2344 text: * ... this bug is listed as a Unicode erratum * from 2002-10-31 at http://www.unicode.org/uni2errata/UnicodeErrata.html * <quote> * There are two errors in SpecialCasing.txt. * 1. Missing semicolons on two lines. ... [irrelevant for ICU] * 2. An incorrect context definition. Correct as follows: * < 0307; ; 0307; 0307; tr After_Soft_Dotted; # COMBINING DOT ABOVE * < 0307; ; 0307; 0307; az After_Soft_Dotted; # COMBINING DOT ABOVE * --- * > 0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE * > 0307; ; 0307; 0307; az After_I; # COMBINING DOT ABOVE * where the context After_I is defined as: * The last preceding base character was an uppercase I, and there is no * intervening combining character class 230 (ABOVE). * </quote> * * Note that SpecialCasing.txt even in Unicode 3.2 described the condition as: * * # When lowercasing, remove dot_above in the sequence I + dot_above, which will turn into i. * # This matches the behavior of the canonically equivalent I-dot_above * * See also the description in this place in older versions of uchar.c (revision 1.100). * * Markus W. Scherer 2003-feb-15 */ /* Is preceded by base character 'I' with no intervening cc=230 ? */ static UBool isPrecededBy_I(UCaseContextIterator *iter, void *context) { … } /* Is followed by one or more cc==230 ? */ static UBool isFollowedByMoreAbove(UCaseContextIterator *iter, void *context) { … } /* Is followed by a dot above (without cc==230 in between) ? */ static UBool isFollowedByDotAbove(UCaseContextIterator *iter, void *context) { … } U_CAPI int32_t U_EXPORT2 ucase_toFullLower(UChar32 c, UCaseContextIterator *iter, void *context, const char16_t **pString, int32_t loc) { … } /* internal */ static int32_t toUpperOrTitle(UChar32 c, UCaseContextIterator *iter, void *context, const char16_t **pString, int32_t loc, UBool upperNotTitle) { … } U_CAPI int32_t U_EXPORT2 ucase_toFullUpper(UChar32 c, UCaseContextIterator *iter, void *context, const char16_t **pString, int32_t caseLocale) { … } U_CAPI int32_t U_EXPORT2 ucase_toFullTitle(UChar32 c, UCaseContextIterator *iter, void *context, const char16_t **pString, int32_t caseLocale) { … } /* case folding ------------------------------------------------------------- */ /* * Case folding is similar to lowercasing. * The result may be a simple mapping, i.e., a single code point, or * a full mapping, i.e., a string. * If the case folding for a code point is the same as its simple (1:1) lowercase mapping, * then only the lowercase mapping is stored. * * Some special cases are hardcoded because their conditions cannot be * parsed and processed from CaseFolding.txt. * * Unicode 3.2 CaseFolding.txt specifies for its status field: # C: common case folding, common mappings shared by both simple and full mappings. # F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces. # S: simple case folding, mappings to single characters where different from F. # T: special case for uppercase I and dotted uppercase I # - For non-Turkic languages, this mapping is normally not used. # - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters. # # Usage: # A. To do a simple case folding, use the mappings with status C + S. # B. To do a full case folding, use the mappings with status C + F. # # The mappings with status T can be used or omitted depending on the desired case-folding # behavior. (The default option is to exclude them.) * Unicode 3.2 has 'T' mappings as follows: 0049; T; 0131; # LATIN CAPITAL LETTER I 0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE * while the default mappings for these code points are: 0049; C; 0069; # LATIN CAPITAL LETTER I 0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE * U+0130 has no simple case folding (simple-case-folds to itself). */ /* return the simple case folding mapping for c */ U_CAPI UChar32 U_EXPORT2 ucase_fold(UChar32 c, uint32_t options) { … } /* * Issue for canonical caseless match (UAX #21): * Turkic casefolding (using "T" mappings in CaseFolding.txt) does not preserve * canonical equivalence, unlike default-option casefolding. * For example, I-grave and I + grave fold to strings that are not canonically * equivalent. * For more details, see the comment in unorm_compare() in unorm.cpp * and the intermediate prototype changes for Jitterbug 2021. * (For example, revision 1.104 of uchar.c and 1.4 of CaseFolding.txt.) * * This did not get fixed because it appears that it is not possible to fix * it for uppercase and lowercase characters (I-grave vs. i-grave) * together in a way that they still fold to common result strings. */ U_CAPI int32_t U_EXPORT2 ucase_toFullFolding(UChar32 c, const char16_t **pString, uint32_t options) { … } /* case mapping properties API ---------------------------------------------- */ /* public API (see uchar.h) */ U_CAPI UBool U_EXPORT2 u_isULowercase(UChar32 c) { … } U_CAPI UBool U_EXPORT2 u_isUUppercase(UChar32 c) { … } /* Transforms the Unicode character to its lower case equivalent.*/ U_CAPI UChar32 U_EXPORT2 u_tolower(UChar32 c) { … } /* Transforms the Unicode character to its upper case equivalent.*/ U_CAPI UChar32 U_EXPORT2 u_toupper(UChar32 c) { … } /* Transforms the Unicode character to its title case equivalent.*/ U_CAPI UChar32 U_EXPORT2 u_totitle(UChar32 c) { … } /* return the simple case folding mapping for c */ U_CAPI UChar32 U_EXPORT2 u_foldCase(UChar32 c, uint32_t options) { … } U_CFUNC int32_t U_EXPORT2 ucase_hasBinaryProperty(UChar32 c, UProperty which) { … }