[TASK] CharsetConverter: Remove Case Folding 90/57090/2
authorBenni Mack <benni@typo3.org>
Wed, 30 May 2018 12:44:05 +0000 (14:44 +0200)
committerWouter Wolters <typo3@wouterwolters.nl>
Wed, 30 May 2018 17:37:42 +0000 (19:37 +0200)
Special Case Folding within CharsetConverter is not used anymore, and can be removed.

The public property $caseFolding used as runtime cache is removed, as it was never possible
to fill it either to have it accessed from the outside.

The SpecialCasing.txt file has no meaning anymore and can be removed.

Resolves: #85118
Releases: master
Change-Id: Ib770fe99a97ac06c4f9c485e960c681ab21c9113
Reviewed-on: https://review.typo3.org/57090
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Tymoteusz Motylewski <t.motylewski@gmail.com>
Tested-by: Tymoteusz Motylewski <t.motylewski@gmail.com>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
typo3/sysext/core/Classes/Charset/CharsetConverter.php
typo3/sysext/core/Resources/Private/Charsets/unidata/SpecialCasing.txt [deleted file]

index 043006e..a09e8e9 100644 (file)
@@ -66,13 +66,6 @@ class CharsetConverter implements SingletonInterface
     public $parsedCharsets = [];
 
     /**
-     * An array where case folding data will be stored (cached)
-     *
-     * @var array
-     */
-    public $caseFolding = [];
-
-    /**
      * An array where charset-to-ASCII mappings are stored (cached)
      *
      * @var array
@@ -695,36 +688,20 @@ class CharsetConverter implements SingletonInterface
      *
      * PLEASE SEE: http://www.unicode.org/Public/UNIDATA/
      *
-     * @param string $mode Mode ("case", "ascii", ...)
      * @return int Returns FALSE on error, a TRUE value on success: 1 table already loaded, 2, cached version, 3 table parsed (and cached).
      */
-    protected function initUnicodeData($mode = null)
+    protected function initUnicodeData()
     {
-        // Cache files
-        $cacheFileCase = Environment::getVarPath() . '/charset/cscase_utf-8.tbl';
+        // Cache file
         $cacheFileASCII = Environment::getVarPath() . '/charset/csascii_utf-8.tbl';
         // Only process if the tables are not yet loaded
-        switch ($mode) {
-            case 'case':
-                if (is_array($this->caseFolding['utf-8'])) {
-                    return 1;
-                }
-                // Use cached version if possible
-                if ($cacheFileCase && @is_file($cacheFileCase)) {
-                    $this->caseFolding['utf-8'] = unserialize(file_get_contents($cacheFileCase));
-                    return 2;
-                }
-                break;
-            case 'ascii':
-                if (isset($this->toASCII['utf-8']) && is_array($this->toASCII['utf-8'])) {
-                    return 1;
-                }
-                // Use cached version if possible
-                if ($cacheFileASCII && @is_file($cacheFileASCII)) {
-                    $this->toASCII['utf-8'] = unserialize(file_get_contents($cacheFileASCII));
-                    return 2;
-                }
-                break;
+        if (isset($this->toASCII['utf-8']) && is_array($this->toASCII['utf-8'])) {
+            return 1;
+        }
+        // Use cached version if possible
+        if ($cacheFileASCII && @is_file($cacheFileASCII)) {
+            $this->toASCII['utf-8'] = unserialize(file_get_contents($cacheFileASCII));
+            return 2;
         }
         // Process main Unicode data file
         $unicodeDataFile = ExtensionManagementUtility::extPath('core') . 'Resources/Private/Charsets/unidata/UnicodeData.txt';
@@ -735,14 +712,6 @@ class CharsetConverter implements SingletonInterface
         if (!$fh) {
             return false;
         }
-        // key = utf8 char (single codepoint), value = utf8 string (codepoint sequence)
-        // Note: we use the UTF-8 characters here and not the Unicode numbers to avoid conversion roundtrip in utf8_strtolower/-upper)
-        $this->caseFolding['utf-8'] = [];
-        $utf8CaseFolding = &$this->caseFolding['utf-8'];
-        // a shorthand
-        $utf8CaseFolding['toUpper'] = [];
-        $utf8CaseFolding['toLower'] = [];
-        $utf8CaseFolding['toTitle'] = [];
         // Array of temp. decompositions
         $decomposition = [];
         // Array of chars that are marks (eg. composing accents)
@@ -754,23 +723,12 @@ class CharsetConverter implements SingletonInterface
         while (!feof($fh)) {
             $line = fgets($fh, 4096);
             // Has a lot of info
-            list($char, $name, $cat, , , $decomp, , , $num, , , , $upper, $lower, $title, ) = explode(';', rtrim($line));
+            list($char, $name, $cat, , , $decomp, , , $num) = explode(';', rtrim($line));
             $ord = hexdec($char);
             if ($ord > 65535) {
                 // Only process the BMP
                 break;
             }
-            $utf8_char = $this->UnumberToChar($ord);
-            if ($upper) {
-                $utf8CaseFolding['toUpper'][$utf8_char] = $this->UnumberToChar(hexdec($upper));
-            }
-            if ($lower) {
-                $utf8CaseFolding['toLower'][$utf8_char] = $this->UnumberToChar(hexdec($lower));
-            }
-            // Store "title" only when different from "upper" (only a few)
-            if ($title && $title !== $upper) {
-                $utf8CaseFolding['toTitle'][$utf8_char] = $this->UnumberToChar(hexdec($title));
-            }
             switch ($cat[0]) {
                 case 'M':
                     // mark (accent, umlaut, ...)
@@ -820,44 +778,6 @@ class CharsetConverter implements SingletonInterface
             }
         }
         fclose($fh);
-        // Process additional Unicode data for casing (allow folded characters to expand into a sequence)
-        $specialCasingFile = ExtensionManagementUtility::extPath('core') . 'Resources/Private/Charsets/unidata/SpecialCasing.txt';
-        if (GeneralUtility::validPathStr($specialCasingFile) && @is_file($specialCasingFile)) {
-            $fh = fopen($specialCasingFile, 'rb');
-            if ($fh) {
-                while (!feof($fh)) {
-                    $line = fgets($fh, 4096);
-                    if ($line[0] !== '#' && trim($line) !== '') {
-                        list($char, $lower, $title, $upper, $cond) = GeneralUtility::trimExplode(';', $line);
-                        if ($cond === '' || $cond[0] === '#') {
-                            $utf8_char = $this->UnumberToChar(hexdec($char));
-                            if ($char !== $lower) {
-                                $arr = explode(' ', $lower);
-                                for ($i = 0; isset($arr[$i]); $i++) {
-                                    $arr[$i] = $this->UnumberToChar(hexdec($arr[$i]));
-                                }
-                                $utf8CaseFolding['toLower'][$utf8_char] = implode('', $arr);
-                            }
-                            if ($char !== $title && $title !== $upper) {
-                                $arr = explode(' ', $title);
-                                for ($i = 0; isset($arr[$i]); $i++) {
-                                    $arr[$i] = $this->UnumberToChar(hexdec($arr[$i]));
-                                }
-                                $utf8CaseFolding['toTitle'][$utf8_char] = implode('', $arr);
-                            }
-                            if ($char !== $upper) {
-                                $arr = explode(' ', $upper);
-                                for ($i = 0; isset($arr[$i]); $i++) {
-                                    $arr[$i] = $this->UnumberToChar(hexdec($arr[$i]));
-                                }
-                                $utf8CaseFolding['toUpper'][$utf8_char] = implode('', $arr);
-                            }
-                        }
-                    }
-                }
-                fclose($fh);
-            }
-        }
         // Process custom decompositions
         $customTranslitFile = ExtensionManagementUtility::extPath('core') . 'Resources/Private/Charsets/unidata/Translit.txt';
         if (GeneralUtility::validPathStr($customTranslitFile) && @is_file($customTranslitFile)) {
@@ -898,7 +818,6 @@ class CharsetConverter implements SingletonInterface
         }
         // Create ascii only mapping
         $this->toASCII['utf-8'] = [];
-        $ascii = &$this->toASCII['utf-8'];
         foreach ($decomposition as $from => $to) {
             $code_decomp = [];
             while ($code_value = array_shift($to)) {
@@ -909,81 +828,17 @@ class CharsetConverter implements SingletonInterface
                 // Skip decompositions containing non-ASCII chars
                 $code_decomp[] = chr($ord);
             }
-            $ascii[$this->UnumberToChar(hexdec($from))] = implode('', $code_decomp);
+            $this->toASCII['utf-8'][$this->UnumberToChar(hexdec($from))] = implode('', $code_decomp);
         }
         // Add numeric decompositions
         foreach ($number as $from => $to) {
             $utf8_char = $this->UnumberToChar(hexdec($from));
-            if (!isset($ascii[$utf8_char])) {
-                $ascii[$utf8_char] = $to;
+            if (!isset($this->toASCII['utf-8'][$utf8_char])) {
+                $this->toASCII['utf-8'][$utf8_char] = $to;
             }
         }
-        if ($cacheFileCase) {
-            GeneralUtility::writeFileToTypo3tempDir($cacheFileCase, serialize($utf8CaseFolding));
-        }
         if ($cacheFileASCII) {
-            GeneralUtility::writeFileToTypo3tempDir($cacheFileASCII, serialize($ascii));
-        }
-        return 3;
-    }
-
-    /**
-     * This function initializes the folding table for a charset other than UTF-8.
-     * This function is automatically called by the case folding functions.
-     *
-     * @param string $charset Charset for which to initialize case folding.
-     * @return int Returns FALSE on error, a TRUE value on success: 1 table already loaded, 2, cached version, 3 table parsed (and cached).
-     */
-    protected function initCaseFolding($charset)
-    {
-        // Only process if the case table is not yet loaded:
-        if (is_array($this->caseFolding[$charset])) {
-            return 1;
-        }
-        // Use cached version if possible
-        $cacheFile = Environment::getVarPath() . '/charset/cscase_' . $charset . '.tbl';
-        if ($cacheFile && @is_file($cacheFile)) {
-            $this->caseFolding[$charset] = unserialize(file_get_contents($cacheFile));
-            return 2;
-        }
-        // init UTF-8 conversion for this charset
-        if (!$this->initCharset($charset)) {
-            return false;
-        }
-        // UTF-8 case folding is used as the base conversion table
-        if (!$this->initUnicodeData('case')) {
-            return false;
-        }
-        $nochar = chr($this->noCharByteVal);
-        foreach ($this->parsedCharsets[$charset]['local'] as $ci => $utf8) {
-            // Reconvert to charset (don't use chr() of numeric value, might be muli-byte)
-            $c = $this->utf8_decode($utf8, $charset);
-            $cc = $this->utf8_decode($this->caseFolding['utf-8']['toUpper'][$utf8], $charset);
-            if ($cc !== '' && $cc !== $nochar) {
-                $this->caseFolding[$charset]['toUpper'][$c] = $cc;
-            }
-            $cc = $this->utf8_decode($this->caseFolding['utf-8']['toLower'][$utf8], $charset);
-            if ($cc !== '' && $cc !== $nochar) {
-                $this->caseFolding[$charset]['toLower'][$c] = $cc;
-            }
-            $cc = $this->utf8_decode($this->caseFolding['utf-8']['toTitle'][$utf8], $charset);
-            if ($cc !== '' && $cc !== $nochar) {
-                $this->caseFolding[$charset]['toTitle'][$c] = $cc;
-            }
-        }
-        // Add the ASCII case table
-        $start = ord('a');
-        $end = ord('z');
-        for ($i = $start; $i <= $end; $i++) {
-            $this->caseFolding[$charset]['toUpper'][chr($i)] = chr($i - 32);
-        }
-        $start = ord('A');
-        $end = ord('Z');
-        for ($i = $start; $i <= $end; $i++) {
-            $this->caseFolding[$charset]['toLower'][chr($i)] = chr($i + 32);
-        }
-        if ($cacheFile) {
-            GeneralUtility::writeFileToTypo3tempDir($cacheFile, serialize($this->caseFolding[$charset]));
+            GeneralUtility::writeFileToTypo3tempDir($cacheFileASCII, serialize($this->toASCII['utf-8']));
         }
         return 3;
     }
@@ -1012,7 +867,7 @@ class CharsetConverter implements SingletonInterface
             return false;
         }
         // UTF-8/ASCII transliteration is used as the base conversion table
-        if (!$this->initUnicodeData('ascii')) {
+        if (!$this->initUnicodeData()) {
             return false;
         }
         foreach ($this->parsedCharsets[$charset]['local'] as $ci => $utf8) {
@@ -1188,7 +1043,7 @@ class CharsetConverter implements SingletonInterface
      */
     public function utf8_char_mapping($str)
     {
-        if (!$this->initUnicodeData('ascii')) {
+        if (!$this->initUnicodeData()) {
             // Do nothing
             return $str;
         }
diff --git a/typo3/sysext/core/Resources/Private/Charsets/unidata/SpecialCasing.txt b/typo3/sysext/core/Resources/Private/Charsets/unidata/SpecialCasing.txt
deleted file mode 100644 (file)
index c8401d6..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-# SpecialCasing-4.0.1.txt
-# Date: 2003-10-06, 17:30:00 PST [KW]
-#
-# Special Casing Properties
-#
-# This file is a supplement to the UnicodeData file.
-# It contains additional information about the casing of Unicode characters.
-# (For compatibility, the UnicodeData.txt file only contains case mappings for
-# characters where they are 1-1, and does not have locale-specific mappings.)
-# For more information, see the discussion of Case Mappings in the Unicode Standard.
-#
-# All code points not listed in this file that do not have a simple case mappings
-# in UnicodeData.txt map to themselves.
-# ================================================================================
-# Format
-# ================================================================================
-# The entries in this file are in the following machine-readable format:
-#
-# <code>; <lower> ; <title> ; <upper> ; (<condition_list> ;)? # <comment>
-#
-# <code>, <lower>, <title>, and <upper> provide character values in hex. If there is more than
-# one character, they are separated by spaces. Other than as used to separate elements,
-# spaces are to be ignored.
-#
-# The <condition_list> is optional. Where present, it consists of one or more locales or contexts,
-# separated by spaces. In these conditions:
-# - A condition list overrides the normal behavior if all of the listed conditions are true.
-# - The context is always the context of the characters in the original string,
-#   NOT in the resulting string.
-# - Case distinctions in the condition list are not significant.
-# - Conditions preceded by "Not_" represent the negation of the condition.
-#
-# A locale is defined as:
-# <locale> := <ISO_639_code> ( "_" <ISO_3166_code> ( "_" <variant> )? )?
-# <ISO_3166_code> := 2-letter ISO country code,
-# <ISO_639_code> :=  2-letter ISO language code
-#
-# A context is one of the following, as defined in the Unicode Standard:
-#   Final_Sigma, After_Soft_Dotted, More_Above, Before_Dot, Not_Before_Dot, After_I
-#
-# Parsers of this file must be prepared to deal with future additions to this format:
-#  * Additional contexts
-#  * Additional fields
-# ================================================================================
-
-# ================================================================================
-# Unconditional mappings
-# ================================================================================
-
-# The German es-zed is special--the normal mapping is to SS.
-# Note: the titlecase should never occur in practice. It is equal to titlecase(uppercase(<es-zed>))
-
-00DF; 00DF; 0053 0073; 0053 0053; # LATIN SMALL LETTER SHARP S
-
-# Preserve canonical equivalence for I with dot. Turkic is handled below.
-
-0130; 0069 0307; 0130; 0130; # LATIN CAPITAL LETTER I WITH DOT ABOVE
-
-# Ligatures
-
-FB00; FB00; 0046 0066; 0046 0046; # LATIN SMALL LIGATURE FF
-FB01; FB01; 0046 0069; 0046 0049; # LATIN SMALL LIGATURE FI
-FB02; FB02; 0046 006C; 0046 004C; # LATIN SMALL LIGATURE FL
-FB03; FB03; 0046 0066 0069; 0046 0046 0049; # LATIN SMALL LIGATURE FFI
-FB04; FB04; 0046 0066 006C; 0046 0046 004C; # LATIN SMALL LIGATURE FFL
-FB05; FB05; 0053 0074; 0053 0054; # LATIN SMALL LIGATURE LONG S T
-FB06; FB06; 0053 0074; 0053 0054; # LATIN SMALL LIGATURE ST
-
-0587; 0587; 0535 0582; 0535 0552; # ARMENIAN SMALL LIGATURE ECH YIWN
-FB13; FB13; 0544 0576; 0544 0546; # ARMENIAN SMALL LIGATURE MEN NOW
-FB14; FB14; 0544 0565; 0544 0535; # ARMENIAN SMALL LIGATURE MEN ECH
-FB15; FB15; 0544 056B; 0544 053B; # ARMENIAN SMALL LIGATURE MEN INI
-FB16; FB16; 054E 0576; 054E 0546; # ARMENIAN SMALL LIGATURE VEW NOW
-FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH
-
-# No corresponding uppercase precomposed character
-
-0149; 0149; 02BC 004E; 02BC 004E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
-0390; 0390; 0399 0308 0301; 0399 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
-03B0; 03B0; 03A5 0308 0301; 03A5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
-01F0; 01F0; 004A 030C; 004A 030C; # LATIN SMALL LETTER J WITH CARON
-1E96; 1E96; 0048 0331; 0048 0331; # LATIN SMALL LETTER H WITH LINE BELOW
-1E97; 1E97; 0054 0308; 0054 0308; # LATIN SMALL LETTER T WITH DIAERESIS
-1E98; 1E98; 0057 030A; 0057 030A; # LATIN SMALL LETTER W WITH RING ABOVE
-1E99; 1E99; 0059 030A; 0059 030A; # LATIN SMALL LETTER Y WITH RING ABOVE
-1E9A; 1E9A; 0041 02BE; 0041 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING
-1F50; 1F50; 03A5 0313; 03A5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI
-1F52; 1F52; 03A5 0313 0300; 03A5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
-1F54; 1F54; 03A5 0313 0301; 03A5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
-1F56; 1F56; 03A5 0313 0342; 03A5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
-1FB6; 1FB6; 0391 0342; 0391 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI
-1FC6; 1FC6; 0397 0342; 0397 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI
-1FD2; 1FD2; 0399 0308 0300; 0399 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
-1FD3; 1FD3; 0399 0308 0301; 0399 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
-1FD6; 1FD6; 0399 0342; 0399 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI
-1FD7; 1FD7; 0399 0308 0342; 0399 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
-1FE2; 1FE2; 03A5 0308 0300; 03A5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
-1FE3; 1FE3; 03A5 0308 0301; 03A5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
-1FE4; 1FE4; 03A1 0313; 03A1 0313; # GREEK SMALL LETTER RHO WITH PSILI
-1FE6; 1FE6; 03A5 0342; 03A5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI
-1FE7; 1FE7; 03A5 0308 0342; 03A5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
-1FF6; 1FF6; 03A9 0342; 03A9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI
-
-# IMPORTANT-when capitalizing iota-subscript (0345)
-#  It MUST be in normalized form--moved to the end of any sequence of combining marks.
-#  This is because logically it represents a following base character!
-#  E.g. <iota_subscript> (<Mn> | <Mc> | <Me>)+ => (<Mn> | <Mc> | <Me>)+ <iota_subscript>
-# It should never be the first character in a word, so in titlecasing it can be left as is.
-
-# The following cases are already in the UnicodeData file, so are only commented here.
-
-# 0345; 0345; 0345; 0399; # COMBINING GREEK YPOGEGRAMMENI
-
-# All letters with YPOGEGRAMMENI (iota-subscript) or PROSGEGRAMMENI (iota adscript)
-# have special uppercases.
-# Note: characters with PROSGEGRAMMENI are actually titlecase, not uppercase!
-
-1F80; 1F80; 1F88; 1F08 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI
-1F81; 1F81; 1F89; 1F09 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI
-1F82; 1F82; 1F8A; 1F0A 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-1F83; 1F83; 1F8B; 1F0B 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-1F84; 1F84; 1F8C; 1F0C 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-1F85; 1F85; 1F8D; 1F0D 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-1F86; 1F86; 1F8E; 1F0E 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-1F87; 1F87; 1F8F; 1F0F 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-1F88; 1F80; 1F88; 1F08 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
-1F89; 1F81; 1F89; 1F09 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
-1F8A; 1F82; 1F8A; 1F0A 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-1F8B; 1F83; 1F8B; 1F0B 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-1F8C; 1F84; 1F8C; 1F0C 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-1F8D; 1F85; 1F8D; 1F0D 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-1F8E; 1F86; 1F8E; 1F0E 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-1F8F; 1F87; 1F8F; 1F0F 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-1F90; 1F90; 1F98; 1F28 0399; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI
-1F91; 1F91; 1F99; 1F29 0399; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI
-1F92; 1F92; 1F9A; 1F2A 0399; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-1F93; 1F93; 1F9B; 1F2B 0399; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-1F94; 1F94; 1F9C; 1F2C 0399; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-1F95; 1F95; 1F9D; 1F2D 0399; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-1F96; 1F96; 1F9E; 1F2E 0399; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-1F97; 1F97; 1F9F; 1F2F 0399; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-1F98; 1F90; 1F98; 1F28 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
-1F99; 1F91; 1F99; 1F29 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
-1F9A; 1F92; 1F9A; 1F2A 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-1F9B; 1F93; 1F9B; 1F2B 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-1F9C; 1F94; 1F9C; 1F2C 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-1F9D; 1F95; 1F9D; 1F2D 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-1F9E; 1F96; 1F9E; 1F2E 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-1F9F; 1F97; 1F9F; 1F2F 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-1FA0; 1FA0; 1FA8; 1F68 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI
-1FA1; 1FA1; 1FA9; 1F69 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI
-1FA2; 1FA2; 1FAA; 1F6A 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-1FA3; 1FA3; 1FAB; 1F6B 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-1FA4; 1FA4; 1FAC; 1F6C 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-1FA5; 1FA5; 1FAD; 1F6D 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-1FA6; 1FA6; 1FAE; 1F6E 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-1FA7; 1FA7; 1FAF; 1F6F 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-1FA8; 1FA0; 1FA8; 1F68 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
-1FA9; 1FA1; 1FA9; 1F69 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
-1FAA; 1FA2; 1FAA; 1F6A 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-1FAB; 1FA3; 1FAB; 1F6B 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-1FAC; 1FA4; 1FAC; 1F6C 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-1FAD; 1FA5; 1FAD; 1F6D 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-1FAE; 1FA6; 1FAE; 1F6E 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-1FAF; 1FA7; 1FAF; 1F6F 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-1FB3; 1FB3; 1FBC; 0391 0399; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI
-1FBC; 1FB3; 1FBC; 0391 0399; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
-1FC3; 1FC3; 1FCC; 0397 0399; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI
-1FCC; 1FC3; 1FCC; 0397 0399; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
-1FF3; 1FF3; 1FFC; 03A9 0399; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI
-1FFC; 1FF3; 1FFC; 03A9 0399; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
-
-# Some characters with YPOGEGRAMMENI also have no corresponding titlecases
-
-1FB2; 1FB2; 1FBA 0345; 1FBA 0399; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
-1FB4; 1FB4; 0386 0345; 0386 0399; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
-1FC2; 1FC2; 1FCA 0345; 1FCA 0399; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
-1FC4; 1FC4; 0389 0345; 0389 0399; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
-1FF2; 1FF2; 1FFA 0345; 1FFA 0399; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
-1FF4; 1FF4; 038F 0345; 038F 0399; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
-
-1FB7; 1FB7; 0391 0342 0345; 0391 0342 0399; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
-1FC7; 1FC7; 0397 0342 0345; 0397 0342 0399; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
-1FF7; 1FF7; 03A9 0342 0345; 03A9 0342 0399; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
-
-# ================================================================================
-# Conditional mappings
-# ================================================================================
-
-# Special case for final form of sigma
-
-03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA
-
-# Note: the following cases for non-final are already in the UnicodeData file.
-
-# 03A3; 03C3; 03A3; 03A3; # GREEK CAPITAL LETTER SIGMA
-# 03C3; 03C3; 03A3; 03A3; # GREEK SMALL LETTER SIGMA
-# 03C2; 03C2; 03A3; 03A3; # GREEK SMALL LETTER FINAL SIGMA
-
-# Note: the following cases are not included, since they would case-fold in lowercasing
-
-# 03C3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK SMALL LETTER SIGMA
-# 03C2; 03C3; 03A3; 03A3; Not_Final_Sigma; # GREEK SMALL LETTER FINAL SIGMA
-
-# ================================================================================
-# Locale-sensitive mappings
-# ================================================================================
-
-# Lithuanian
-
-# Lithuanian retains the dot in a lowercase i when followed by accents.
-
-# Remove DOT ABOVE after "i" with upper or titlecase
-
-0307; 0307; ; ; lt After_Soft_Dotted; # COMBINING DOT ABOVE
-
-# Introduce an explicit dot above when lowercasing capital I's and J's
-# whenever there are more accents above.
-# (of the accents used in Lithuanian: grave, acute, tilde above, and ogonek)
-
-0049; 0069 0307; 0049; 0049; lt More_Above; # LATIN CAPITAL LETTER I
-004A; 006A 0307; 004A; 004A; lt More_Above; # LATIN CAPITAL LETTER J
-012E; 012F 0307; 012E; 012E; lt More_Above; # LATIN CAPITAL LETTER I WITH OGONEK
-00CC; 0069 0307 0300; 00CC; 00CC; lt; # LATIN CAPITAL LETTER I WITH GRAVE
-00CD; 0069 0307 0301; 00CD; 00CD; lt; # LATIN CAPITAL LETTER I WITH ACUTE
-0128; 0069 0307 0303; 0128; 0128; lt; # LATIN CAPITAL LETTER I WITH TILDE
-
-# ================================================================================
-
-# Turkish and Azeri
-
-# I and i-dotless; I-dot and i are case pairs in Turkish and Azeri
-# The following rules handle those cases.
-
-0130; 0069; 0130; 0130; tr; # LATIN CAPITAL LETTER I WITH DOT ABOVE
-0130; 0069; 0130; 0130; az; # LATIN CAPITAL LETTER I WITH DOT ABOVE
-
-# 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
-
-0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE
-0307; ; 0307; 0307; az After_I; # COMBINING DOT ABOVE
-
-# When lowercasing, unless an I is before a dot_above, it turns into a dotless i.
-
-0049; 0131; 0049; 0049; tr Not_Before_Dot; # LATIN CAPITAL LETTER I
-0049; 0131; 0049; 0049; az Not_Before_Dot; # LATIN CAPITAL LETTER I
-
-# When uppercasing, i turns into a dotted capital I
-
-0069; 0069; 0130; 0130; tr; # LATIN SMALL LETTER I
-0069; 0069; 0130; 0130; az; # LATIN SMALL LETTER I
-
-# Note: the following case is already in the UnicodeData file.
-
-# 0131; 0131; 0049; 0049; tr; # LATIN SMALL LETTER DOTLESS I