"Fossies" - the Fresh Open Source Software Archive

Member "grav/vendor/symfony/polyfill-iconv/Iconv.php" (1 Sep 2020, 22669 Bytes) of package /linux/www/grav-v1.6.27.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Iconv.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 
    3 /*
    4  * This file is part of the Symfony package.
    5  *
    6  * (c) Fabien Potencier <fabien@symfony.com>
    7  *
    8  * For the full copyright and license information, please view the LICENSE
    9  * file that was distributed with this source code.
   10  */
   11 
   12 namespace Symfony\Polyfill\Iconv;
   13 
   14 /**
   15  * iconv implementation in pure PHP, UTF-8 centric.
   16  *
   17  * Implemented:
   18  * - iconv              - Convert string to requested character encoding
   19  * - iconv_mime_decode  - Decodes a MIME header field
   20  * - iconv_mime_decode_headers - Decodes multiple MIME header fields at once
   21  * - iconv_get_encoding - Retrieve internal configuration variables of iconv extension
   22  * - iconv_set_encoding - Set current setting for character encoding conversion
   23  * - iconv_mime_encode  - Composes a MIME header field
   24  * - iconv_strlen       - Returns the character count of string
   25  * - iconv_strpos       - Finds position of first occurrence of a needle within a haystack
   26  * - iconv_strrpos      - Finds the last occurrence of a needle within a haystack
   27  * - iconv_substr       - Cut out part of a string
   28  *
   29  * Charsets available for conversion are defined by files
   30  * in the charset/ directory and by Iconv::$alias below.
   31  * You're welcome to send back any addition you make.
   32  *
   33  * @author Nicolas Grekas <p@tchwork.com>
   34  *
   35  * @internal
   36  */
   37 final class Iconv
   38 {
   39     const ERROR_ILLEGAL_CHARACTER = 'iconv(): Detected an illegal character in input string';
   40     const ERROR_WRONG_CHARSET = 'iconv(): Wrong charset, conversion from `%s\' to `%s\' is not allowed';
   41 
   42     public static $inputEncoding = 'utf-8';
   43     public static $outputEncoding = 'utf-8';
   44     public static $internalEncoding = 'utf-8';
   45 
   46     private static $alias = array(
   47         'utf8' => 'utf-8',
   48         'ascii' => 'us-ascii',
   49         'tis-620' => 'iso-8859-11',
   50         'cp1250' => 'windows-1250',
   51         'cp1251' => 'windows-1251',
   52         'cp1252' => 'windows-1252',
   53         'cp1253' => 'windows-1253',
   54         'cp1254' => 'windows-1254',
   55         'cp1255' => 'windows-1255',
   56         'cp1256' => 'windows-1256',
   57         'cp1257' => 'windows-1257',
   58         'cp1258' => 'windows-1258',
   59         'shift-jis' => 'cp932',
   60         'shift_jis' => 'cp932',
   61         'latin1' => 'iso-8859-1',
   62         'latin2' => 'iso-8859-2',
   63         'latin3' => 'iso-8859-3',
   64         'latin4' => 'iso-8859-4',
   65         'latin5' => 'iso-8859-9',
   66         'latin6' => 'iso-8859-10',
   67         'latin7' => 'iso-8859-13',
   68         'latin8' => 'iso-8859-14',
   69         'latin9' => 'iso-8859-15',
   70         'latin10' => 'iso-8859-16',
   71         'iso8859-1' => 'iso-8859-1',
   72         'iso8859-2' => 'iso-8859-2',
   73         'iso8859-3' => 'iso-8859-3',
   74         'iso8859-4' => 'iso-8859-4',
   75         'iso8859-5' => 'iso-8859-5',
   76         'iso8859-6' => 'iso-8859-6',
   77         'iso8859-7' => 'iso-8859-7',
   78         'iso8859-8' => 'iso-8859-8',
   79         'iso8859-9' => 'iso-8859-9',
   80         'iso8859-10' => 'iso-8859-10',
   81         'iso8859-11' => 'iso-8859-11',
   82         'iso8859-12' => 'iso-8859-12',
   83         'iso8859-13' => 'iso-8859-13',
   84         'iso8859-14' => 'iso-8859-14',
   85         'iso8859-15' => 'iso-8859-15',
   86         'iso8859-16' => 'iso-8859-16',
   87         'iso_8859-1' => 'iso-8859-1',
   88         'iso_8859-2' => 'iso-8859-2',
   89         'iso_8859-3' => 'iso-8859-3',
   90         'iso_8859-4' => 'iso-8859-4',
   91         'iso_8859-5' => 'iso-8859-5',
   92         'iso_8859-6' => 'iso-8859-6',
   93         'iso_8859-7' => 'iso-8859-7',
   94         'iso_8859-8' => 'iso-8859-8',
   95         'iso_8859-9' => 'iso-8859-9',
   96         'iso_8859-10' => 'iso-8859-10',
   97         'iso_8859-11' => 'iso-8859-11',
   98         'iso_8859-12' => 'iso-8859-12',
   99         'iso_8859-13' => 'iso-8859-13',
  100         'iso_8859-14' => 'iso-8859-14',
  101         'iso_8859-15' => 'iso-8859-15',
  102         'iso_8859-16' => 'iso-8859-16',
  103         'iso88591' => 'iso-8859-1',
  104         'iso88592' => 'iso-8859-2',
  105         'iso88593' => 'iso-8859-3',
  106         'iso88594' => 'iso-8859-4',
  107         'iso88595' => 'iso-8859-5',
  108         'iso88596' => 'iso-8859-6',
  109         'iso88597' => 'iso-8859-7',
  110         'iso88598' => 'iso-8859-8',
  111         'iso88599' => 'iso-8859-9',
  112         'iso885910' => 'iso-8859-10',
  113         'iso885911' => 'iso-8859-11',
  114         'iso885912' => 'iso-8859-12',
  115         'iso885913' => 'iso-8859-13',
  116         'iso885914' => 'iso-8859-14',
  117         'iso885915' => 'iso-8859-15',
  118         'iso885916' => 'iso-8859-16',
  119     );
  120     private static $translitMap = array();
  121     private static $convertMap = array();
  122     private static $errorHandler;
  123     private static $lastError;
  124 
  125     private static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
  126     private static $isValidUtf8;
  127 
  128     public static function iconv($inCharset, $outCharset, $str)
  129     {
  130         $str = (string) $str;
  131         if ('' === $str) {
  132             return '';
  133         }
  134 
  135         // Prepare for //IGNORE and //TRANSLIT
  136 
  137         $translit = $ignore = '';
  138 
  139         $outCharset = strtolower($outCharset);
  140         $inCharset = strtolower($inCharset);
  141 
  142         if ('' === $outCharset) {
  143             $outCharset = 'iso-8859-1';
  144         }
  145         if ('' === $inCharset) {
  146             $inCharset = 'iso-8859-1';
  147         }
  148 
  149         do {
  150             $loop = false;
  151 
  152             if ('//translit' === substr($outCharset, -10)) {
  153                 $loop = $translit = true;
  154                 $outCharset = substr($outCharset, 0, -10);
  155             }
  156 
  157             if ('//ignore' === substr($outCharset, -8)) {
  158                 $loop = $ignore = true;
  159                 $outCharset = substr($outCharset, 0, -8);
  160             }
  161         } while ($loop);
  162 
  163         do {
  164             $loop = false;
  165 
  166             if ('//translit' === substr($inCharset, -10)) {
  167                 $loop = true;
  168                 $inCharset = substr($inCharset, 0, -10);
  169             }
  170 
  171             if ('//ignore' === substr($inCharset, -8)) {
  172                 $loop = true;
  173                 $inCharset = substr($inCharset, 0, -8);
  174             }
  175         } while ($loop);
  176 
  177         if (isset(self::$alias[$inCharset])) {
  178             $inCharset = self::$alias[$inCharset];
  179         }
  180         if (isset(self::$alias[$outCharset])) {
  181             $outCharset = self::$alias[$outCharset];
  182         }
  183 
  184         // Load charset maps
  185 
  186         if (('utf-8' !== $inCharset && !self::loadMap('from.', $inCharset, $inMap))
  187           || ('utf-8' !== $outCharset && !self::loadMap('to.', $outCharset, $outMap))) {
  188             trigger_error(sprintf(self::ERROR_WRONG_CHARSET, $inCharset, $outCharset));
  189 
  190             return false;
  191         }
  192 
  193         if ('utf-8' !== $inCharset) {
  194             // Convert input to UTF-8
  195             $result = '';
  196             if (self::mapToUtf8($result, $inMap, $str, $ignore)) {
  197                 $str = $result;
  198             } else {
  199                 $str = false;
  200             }
  201             self::$isValidUtf8 = true;
  202         } else {
  203             self::$isValidUtf8 = preg_match('//u', $str);
  204 
  205             if (!self::$isValidUtf8 && !$ignore) {
  206                 trigger_error(self::ERROR_ILLEGAL_CHARACTER);
  207 
  208                 return false;
  209             }
  210 
  211             if ('utf-8' === $outCharset) {
  212                 // UTF-8 validation
  213                 $str = self::utf8ToUtf8($str, $ignore);
  214             }
  215         }
  216 
  217         if ('utf-8' !== $outCharset && false !== $str) {
  218             // Convert output to UTF-8
  219             $result = '';
  220             if (self::mapFromUtf8($result, $outMap, $str, $ignore, $translit)) {
  221                 return $result;
  222             }
  223 
  224             return false;
  225         }
  226 
  227         return $str;
  228     }
  229 
  230     public static function iconv_mime_decode_headers($str, $mode = 0, $charset = null)
  231     {
  232         if (null === $charset) {
  233             $charset = self::$internalEncoding;
  234         }
  235 
  236         if (false !== strpos($str, "\r")) {
  237             $str = strtr(str_replace("\r\n", "\n", $str), "\r", "\n");
  238         }
  239         $str = explode("\n\n", $str, 2);
  240 
  241         $headers = array();
  242 
  243         $str = preg_split('/\n(?![ \t])/', $str[0]);
  244         foreach ($str as $str) {
  245             $str = self::iconv_mime_decode($str, $mode, $charset);
  246             if (false === $str) {
  247                 return false;
  248             }
  249             $str = explode(':', $str, 2);
  250 
  251             if (2 === \count($str)) {
  252                 if (isset($headers[$str[0]])) {
  253                     if (!\is_array($headers[$str[0]])) {
  254                         $headers[$str[0]] = array($headers[$str[0]]);
  255                     }
  256                     $headers[$str[0]][] = ltrim($str[1]);
  257                 } else {
  258                     $headers[$str[0]] = ltrim($str[1]);
  259                 }
  260             }
  261         }
  262 
  263         return $headers;
  264     }
  265 
  266     public static function iconv_mime_decode($str, $mode = 0, $charset = null)
  267     {
  268         if (null === $charset) {
  269             $charset = self::$internalEncoding;
  270         }
  271         if (ICONV_MIME_DECODE_CONTINUE_ON_ERROR & $mode) {
  272             $charset .= '//IGNORE';
  273         }
  274 
  275         if (false !== strpos($str, "\r")) {
  276             $str = strtr(str_replace("\r\n", "\n", $str), "\r", "\n");
  277         }
  278         $str = preg_split('/\n(?![ \t])/', rtrim($str), 2);
  279         $str = preg_replace('/[ \t]*\n[ \t]+/', ' ', rtrim($str[0]));
  280         $str = preg_split('/=\?([^?]+)\?([bqBQ])\?(.*?)\?=/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
  281 
  282         $result = self::iconv('utf-8', $charset, $str[0]);
  283         if (false === $result) {
  284             return false;
  285         }
  286 
  287         $i = 1;
  288         $len = \count($str);
  289 
  290         while ($i < $len) {
  291             $c = strtolower($str[$i]);
  292             if ((ICONV_MIME_DECODE_CONTINUE_ON_ERROR & $mode)
  293               && 'utf-8' !== $c
  294               && !isset(self::$alias[$c])
  295               && !self::loadMap('from.', $c, $d)) {
  296                 $d = false;
  297             } elseif ('B' === strtoupper($str[$i + 1])) {
  298                 $d = base64_decode($str[$i + 2]);
  299             } else {
  300                 $d = rawurldecode(strtr(str_replace('%', '%25', $str[$i + 2]), '=_', '% '));
  301             }
  302 
  303             if (false !== $d) {
  304                 if ('' !== $d) {
  305                     if ('' === $d = self::iconv($c, $charset, $d)) {
  306                         $str[$i + 3] = substr($str[$i + 3], 1);
  307                     } else {
  308                         $result .= $d;
  309                     }
  310                 }
  311                 $d = self::iconv('utf-8', $charset, $str[$i + 3]);
  312                 if ('' !== trim($d)) {
  313                     $result .= $d;
  314                 }
  315             } elseif (ICONV_MIME_DECODE_CONTINUE_ON_ERROR & $mode) {
  316                 $result .= "=?{$str[$i]}?{$str[$i + 1]}?{$str[$i + 2]}?={$str[$i + 3]}";
  317             } else {
  318                 $result = false;
  319                 break;
  320             }
  321 
  322             $i += 4;
  323         }
  324 
  325         return $result;
  326     }
  327 
  328     public static function iconv_get_encoding($type = 'all')
  329     {
  330         switch ($type) {
  331             case 'input_encoding': return self::$inputEncoding;
  332             case 'output_encoding': return self::$outputEncoding;
  333             case 'internal_encoding': return self::$internalEncoding;
  334         }
  335 
  336         return array(
  337             'input_encoding' => self::$inputEncoding,
  338             'output_encoding' => self::$outputEncoding,
  339             'internal_encoding' => self::$internalEncoding,
  340         );
  341     }
  342 
  343     public static function iconv_set_encoding($type, $charset)
  344     {
  345         switch ($type) {
  346             case 'input_encoding': self::$inputEncoding = $charset; break;
  347             case 'output_encoding': self::$outputEncoding = $charset; break;
  348             case 'internal_encoding': self::$internalEncoding = $charset; break;
  349 
  350             default: return false;
  351         }
  352 
  353         return true;
  354     }
  355 
  356     public static function iconv_mime_encode($fieldName, $fieldValue, $pref = null)
  357     {
  358         if (!\is_array($pref)) {
  359             $pref = array();
  360         }
  361 
  362         $pref += array(
  363             'scheme' => 'B',
  364             'input-charset' => self::$internalEncoding,
  365             'output-charset' => self::$internalEncoding,
  366             'line-length' => 76,
  367             'line-break-chars' => "\r\n",
  368         );
  369 
  370         if (preg_match('/[\x80-\xFF]/', $fieldName)) {
  371             $fieldName = '';
  372         }
  373 
  374         $scheme = strtoupper(substr($pref['scheme'], 0, 1));
  375         $in = strtolower($pref['input-charset']);
  376         $out = strtolower($pref['output-charset']);
  377 
  378         if ('utf-8' !== $in && false === $fieldValue = self::iconv($in, 'utf-8', $fieldValue)) {
  379             return false;
  380         }
  381 
  382         preg_match_all('/./us', $fieldValue, $chars);
  383 
  384         $chars = isset($chars[0]) ? $chars[0] : array();
  385 
  386         $lineBreak = (int) $pref['line-length'];
  387         $lineStart = "=?{$pref['output-charset']}?{$scheme}?";
  388         $lineLength = \strlen($fieldName) + 2 + \strlen($lineStart) + 2;
  389         $lineOffset = \strlen($lineStart) + 3;
  390         $lineData = '';
  391 
  392         $fieldValue = array();
  393 
  394         $Q = 'Q' === $scheme;
  395 
  396         foreach ($chars as $c) {
  397             if ('utf-8' !== $out && false === $c = self::iconv('utf-8', $out, $c)) {
  398                 return false;
  399             }
  400 
  401             $o = $Q
  402                 ? $c = preg_replace_callback(
  403                     '/[=_\?\x00-\x1F\x80-\xFF]/',
  404                     array(__CLASS__, 'qpByteCallback'),
  405                     $c
  406                 )
  407                 : base64_encode($lineData.$c);
  408 
  409             if (isset($o[$lineBreak - $lineLength])) {
  410                 if (!$Q) {
  411                     $lineData = base64_encode($lineData);
  412                 }
  413                 $fieldValue[] = $lineStart.$lineData.'?=';
  414                 $lineLength = $lineOffset;
  415                 $lineData = '';
  416             }
  417 
  418             $lineData .= $c;
  419             $Q && $lineLength += \strlen($c);
  420         }
  421 
  422         if ('' !== $lineData) {
  423             if (!$Q) {
  424                 $lineData = base64_encode($lineData);
  425             }
  426             $fieldValue[] = $lineStart.$lineData.'?=';
  427         }
  428 
  429         return $fieldName.': '.implode($pref['line-break-chars'].' ', $fieldValue);
  430     }
  431 
  432     public static function iconv_strlen($s, $encoding = null)
  433     {
  434         static $hasXml = null;
  435         if (null === $hasXml) {
  436             $hasXml = \extension_loaded('xml');
  437         }
  438 
  439         if ($hasXml) {
  440             return self::strlen1($s, $encoding);
  441         }
  442 
  443         return self::strlen2($s, $encoding);
  444     }
  445 
  446     public static function strlen1($s, $encoding = null)
  447     {
  448         if (null === $encoding) {
  449             $encoding = self::$internalEncoding;
  450         }
  451         if (0 !== stripos($encoding, 'utf-8') && false === $s = self::iconv($encoding, 'utf-8', $s)) {
  452             return false;
  453         }
  454 
  455         return \strlen(utf8_decode($s));
  456     }
  457 
  458     public static function strlen2($s, $encoding = null)
  459     {
  460         if (null === $encoding) {
  461             $encoding = self::$internalEncoding;
  462         }
  463         if (0 !== stripos($encoding, 'utf-8') && false === $s = self::iconv($encoding, 'utf-8', $s)) {
  464             return false;
  465         }
  466 
  467         $ulenMask = self::$ulenMask;
  468 
  469         $i = 0;
  470         $j = 0;
  471         $len = \strlen($s);
  472 
  473         while ($i < $len) {
  474             $u = $s[$i] & "\xF0";
  475             $i += isset($ulenMask[$u]) ? $ulenMask[$u] : 1;
  476             ++$j;
  477         }
  478 
  479         return $j;
  480     }
  481 
  482     public static function iconv_strpos($haystack, $needle, $offset = 0, $encoding = null)
  483     {
  484         if (null === $encoding) {
  485             $encoding = self::$internalEncoding;
  486         }
  487 
  488         if (0 !== stripos($encoding, 'utf-8')) {
  489             if (false === $haystack = self::iconv($encoding, 'utf-8', $haystack)) {
  490                 return false;
  491             }
  492             if (false === $needle = self::iconv($encoding, 'utf-8', $needle)) {
  493                 return false;
  494             }
  495         }
  496 
  497         if ($offset = (int) $offset) {
  498             $haystack = self::iconv_substr($haystack, $offset, 2147483647, 'utf-8');
  499         }
  500         $pos = strpos($haystack, $needle);
  501 
  502         return false === $pos ? false : ($offset + ($pos ? self::iconv_strlen(substr($haystack, 0, $pos), 'utf-8') : 0));
  503     }
  504 
  505     public static function iconv_strrpos($haystack, $needle, $encoding = null)
  506     {
  507         if (null === $encoding) {
  508             $encoding = self::$internalEncoding;
  509         }
  510 
  511         if (0 !== stripos($encoding, 'utf-8')) {
  512             if (false === $haystack = self::iconv($encoding, 'utf-8', $haystack)) {
  513                 return false;
  514             }
  515             if (false === $needle = self::iconv($encoding, 'utf-8', $needle)) {
  516                 return false;
  517             }
  518         }
  519 
  520         $pos = isset($needle[0]) ? strrpos($haystack, $needle) : false;
  521 
  522         return false === $pos ? false : self::iconv_strlen($pos ? substr($haystack, 0, $pos) : $haystack, 'utf-8');
  523     }
  524 
  525     public static function iconv_substr($s, $start, $length = 2147483647, $encoding = null)
  526     {
  527         if (null === $encoding) {
  528             $encoding = self::$internalEncoding;
  529         }
  530         if (0 !== stripos($encoding, 'utf-8')) {
  531             $encoding = null;
  532         } elseif (false === $s = self::iconv($encoding, 'utf-8', $s)) {
  533             return false;
  534         }
  535 
  536         $s = (string) $s;
  537         $slen = self::iconv_strlen($s, 'utf-8');
  538         $start = (int) $start;
  539 
  540         if (0 > $start) {
  541             $start += $slen;
  542         }
  543         if (0 > $start) {
  544             return false;
  545         }
  546         if ($start >= $slen) {
  547             return false;
  548         }
  549 
  550         $rx = $slen - $start;
  551 
  552         if (0 > $length) {
  553             $length += $rx;
  554         }
  555         if (0 === $length) {
  556             return '';
  557         }
  558         if (0 > $length) {
  559             return false;
  560         }
  561 
  562         if ($length > $rx) {
  563             $length = $rx;
  564         }
  565 
  566         $rx = '/^'.($start ? self::pregOffset($start) : '').'('.self::pregOffset($length).')/u';
  567 
  568         $s = preg_match($rx, $s, $s) ? $s[1] : '';
  569 
  570         if (null === $encoding) {
  571             return $s;
  572         }
  573 
  574         return self::iconv('utf-8', $encoding, $s);
  575     }
  576 
  577     private static function loadMap($type, $charset, &$map)
  578     {
  579         if (!isset(self::$convertMap[$type.$charset])) {
  580             if (false === $map = self::getData($type.$charset)) {
  581                 if ('to.' === $type && self::loadMap('from.', $charset, $map)) {
  582                     $map = array_flip($map);
  583                 } else {
  584                     return false;
  585                 }
  586             }
  587 
  588             self::$convertMap[$type.$charset] = $map;
  589         } else {
  590             $map = self::$convertMap[$type.$charset];
  591         }
  592 
  593         return true;
  594     }
  595 
  596     private static function utf8ToUtf8($str, $ignore)
  597     {
  598         $ulenMask = self::$ulenMask;
  599         $valid = self::$isValidUtf8;
  600 
  601         $u = $str;
  602         $i = $j = 0;
  603         $len = \strlen($str);
  604 
  605         while ($i < $len) {
  606             if ($str[$i] < "\x80") {
  607                 $u[$j++] = $str[$i++];
  608             } else {
  609                 $ulen = $str[$i] & "\xF0";
  610                 $ulen = isset($ulenMask[$ulen]) ? $ulenMask[$ulen] : 1;
  611                 $uchr = substr($str, $i, $ulen);
  612 
  613                 if (1 === $ulen || !($valid || preg_match('/^.$/us', $uchr))) {
  614                     if ($ignore) {
  615                         ++$i;
  616                         continue;
  617                     }
  618 
  619                     trigger_error(self::ERROR_ILLEGAL_CHARACTER);
  620 
  621                     return false;
  622                 } else {
  623                     $i += $ulen;
  624                 }
  625 
  626                 $u[$j++] = $uchr[0];
  627 
  628                 isset($uchr[1]) && 0 !== ($u[$j++] = $uchr[1])
  629                     && isset($uchr[2]) && 0 !== ($u[$j++] = $uchr[2])
  630                     && isset($uchr[3]) && 0 !== ($u[$j++] = $uchr[3]);
  631             }
  632         }
  633 
  634         return substr($u, 0, $j);
  635     }
  636 
  637     private static function mapToUtf8(&$result, array $map, $str, $ignore)
  638     {
  639         $len = \strlen($str);
  640         for ($i = 0; $i < $len; ++$i) {
  641             if (isset($str[$i + 1], $map[$str[$i].$str[$i + 1]])) {
  642                 $result .= $map[$str[$i].$str[++$i]];
  643             } elseif (isset($map[$str[$i]])) {
  644                 $result .= $map[$str[$i]];
  645             } elseif (!$ignore) {
  646                 trigger_error(self::ERROR_ILLEGAL_CHARACTER);
  647 
  648                 return false;
  649             }
  650         }
  651 
  652         return true;
  653     }
  654 
  655     private static function mapFromUtf8(&$result, array $map, $str, $ignore, $translit)
  656     {
  657         $ulenMask = self::$ulenMask;
  658         $valid = self::$isValidUtf8;
  659 
  660         if ($translit && !self::$translitMap) {
  661             self::$translitMap = self::getData('translit');
  662         }
  663 
  664         $i = 0;
  665         $len = \strlen($str);
  666 
  667         while ($i < $len) {
  668             if ($str[$i] < "\x80") {
  669                 $uchr = $str[$i++];
  670             } else {
  671                 $ulen = $str[$i] & "\xF0";
  672                 $ulen = isset($ulenMask[$ulen]) ? $ulenMask[$ulen] : 1;
  673                 $uchr = substr($str, $i, $ulen);
  674 
  675                 if ($ignore && (1 === $ulen || !($valid || preg_match('/^.$/us', $uchr)))) {
  676                     ++$i;
  677                     continue;
  678                 } else {
  679                     $i += $ulen;
  680                 }
  681             }
  682 
  683             if (isset($map[$uchr])) {
  684                 $result .= $map[$uchr];
  685             } elseif ($translit) {
  686                 if (isset(self::$translitMap[$uchr])) {
  687                     $uchr = self::$translitMap[$uchr];
  688                 } elseif ($uchr >= "\xC3\x80") {
  689                     $uchr = \Normalizer::normalize($uchr, \Normalizer::NFD);
  690 
  691                     if ($uchr[0] < "\x80") {
  692                         $uchr = $uchr[0];
  693                     } elseif ($ignore) {
  694                         continue;
  695                     } else {
  696                         return false;
  697                     }
  698                 } elseif ($ignore) {
  699                     continue;
  700                 } else {
  701                     return false;
  702                 }
  703 
  704                 $str = $uchr.substr($str, $i);
  705                 $len = \strlen($str);
  706                 $i = 0;
  707             } elseif (!$ignore) {
  708                 return false;
  709             }
  710         }
  711 
  712         return true;
  713     }
  714 
  715     private static function qpByteCallback(array $m)
  716     {
  717         return '='.strtoupper(dechex(\ord($m[0])));
  718     }
  719 
  720     private static function pregOffset($offset)
  721     {
  722         $rx = array();
  723         $offset = (int) $offset;
  724 
  725         while ($offset > 65535) {
  726             $rx[] = '.{65535}';
  727             $offset -= 65535;
  728         }
  729 
  730         return implode('', $rx).'.{'.$offset.'}';
  731     }
  732 
  733     private static function getData($file)
  734     {
  735         if (file_exists($file = __DIR__.'/Resources/charset/'.$file.'.php')) {
  736             return require $file;
  737         }
  738 
  739         return false;
  740     }
  741 }