Overview

Packages

  • application
    • commands
    • components
      • actions
      • filters
      • leftWidget
      • permissions
      • sortableWidget
      • util
      • webupdater
      • x2flow
        • actions
        • triggers
      • X2GridView
      • X2Settings
    • controllers
    • models
      • embedded
    • modules
      • accounts
        • controllers
        • models
      • actions
        • controllers
        • models
      • calendar
        • controllers
        • models
      • charts
        • models
      • contacts
        • controllers
        • models
      • docs
        • components
        • controllers
        • models
      • groups
        • controllers
        • models
      • marketing
        • components
        • controllers
        • models
      • media
        • controllers
        • models
      • mobile
        • components
      • opportunities
        • controllers
        • models
      • products
        • controllers
        • models
      • quotes
        • controllers
        • models
      • services
        • controllers
        • models
      • template
        • models
      • users
        • controllers
        • models
      • workflow
        • controllers
        • models
      • x2Leads
        • controllers
        • models
  • Net
  • None
  • PHP
  • system
    • base
    • caching
      • dependencies
    • collections
    • console
    • db
      • ar
      • schema
        • cubrid
        • mssql
        • mysql
        • oci
        • pgsql
        • sqlite
    • i18n
      • gettext
    • logging
    • test
    • utils
    • validators
    • web
      • actions
      • auth
      • filters
      • form
      • helpers
      • renderers
      • services
      • widgets
        • captcha
        • pagers
  • Text
    • Highlighter
  • zii
    • behaviors
    • widgets
      • grid
      • jui

Classes

  • Net_IDNA2
  • Overview
  • Package
  • Class
  • Tree
   1: <?php
   2: 
   3: // {{{ license
   4: 
   5: /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
   6: //
   7: // +----------------------------------------------------------------------+
   8: // | This library is free software; you can redistribute it and/or modify |
   9: // | it under the terms of the GNU Lesser General Public License as       |
  10: // | published by the Free Software Foundation; either version 2.1 of the |
  11: // | License, or (at your option) any later version.                      |
  12: // |                                                                      |
  13: // | This library is distributed in the hope that it will be useful, but  |
  14: // | WITHOUT ANY WARRANTY; without even the implied warranty of           |
  15: // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
  16: // | Lesser General Public License for more details.                      |
  17: // |                                                                      |
  18: // | You should have received a copy of the GNU Lesser General Public     |
  19: // | License along with this library; if not, write to the Free Software  |
  20: // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 |
  21: // | USA.                                                                 |
  22: // +----------------------------------------------------------------------+
  23: //
  24: 
  25: // }}}
  26: require_once dirname(__FILE__).'/IDNA2/Exception.php';
  27: require_once dirname(__FILE__).'/IDNA2/Exception/Nameprep.php';
  28: 
  29: /**
  30:  * Encode/decode Internationalized Domain Names.
  31:  *
  32:  * The class allows to convert internationalized domain names
  33:  * (see RFC 3490 for details) as they can be used with various registries worldwide
  34:  * to be translated between their original (localized) form and their encoded form
  35:  * as it will be used in the DNS (Domain Name System).
  36:  *
  37:  * The class provides two public methods, encode() and decode(), which do exactly
  38:  * what you would expect them to do. You are allowed to use complete domain names,
  39:  * simple strings and complete email addresses as well. That means, that you might
  40:  * use any of the following notations:
  41:  *
  42:  * - www.n�rgler.com
  43:  * - xn--nrgler-wxa
  44:  * - xn--brse-5qa.xn--knrz-1ra.info
  45:  *
  46:  * Unicode input might be given as either UTF-8 string, UCS-4 string or UCS-4
  47:  * array. Unicode output is available in the same formats.
  48:  * You can select your preferred format via {@link set_paramter()}.
  49:  *
  50:  * ACE input and output is always expected to be ASCII.
  51:  *
  52:  * @package Net
  53:  * @author  Markus Nix <mnix@docuverse.de>
  54:  * @author  Matthias Sommerfeld <mso@phlylabs.de>
  55:  * @author  Stefan Neufeind <pear.neufeind@speedpartner.de>
  56:  * @version $Id: IDNA2.php 305344 2010-11-14 23:52:42Z neufeind $
  57:  */
  58: class Net_IDNA2
  59: {
  60:     // {{{ npdata
  61:     /**
  62:      * These Unicode codepoints are
  63:      * mapped to nothing, See RFC3454 for details
  64:      *
  65:      * @static
  66:      * @var array
  67:      * @access private
  68:      */
  69:     private static $_np_map_nothing = array(
  70:         0xAD,
  71:         0x34F,
  72:         0x1806,
  73:         0x180B,
  74:         0x180C,
  75:         0x180D,
  76:         0x200B,
  77:         0x200C,
  78:         0x200D,
  79:         0x2060,
  80:         0xFE00,
  81:         0xFE01,
  82:         0xFE02,
  83:         0xFE03,
  84:         0xFE04,
  85:         0xFE05,
  86:         0xFE06,
  87:         0xFE07,
  88:         0xFE08,
  89:         0xFE09,
  90:         0xFE0A,
  91:         0xFE0B,
  92:         0xFE0C,
  93:         0xFE0D,
  94:         0xFE0E,
  95:         0xFE0F,
  96:         0xFEFF
  97:     );
  98: 
  99:     /**
 100:      * Prohibited codepints
 101:      *
 102:      * @static
 103:      * @var array
 104:      * @access private
 105:      */
 106:     private static $_general_prohibited = array(
 107:         0,
 108:         1,
 109:         2,
 110:         3,
 111:         4,
 112:         5,
 113:         6,
 114:         7,
 115:         8,
 116:         9,
 117:         0xA,
 118:         0xB,
 119:         0xC,
 120:         0xD,
 121:         0xE,
 122:         0xF,
 123:         0x10,
 124:         0x11,
 125:         0x12,
 126:         0x13,
 127:         0x14,
 128:         0x15,
 129:         0x16,
 130:         0x17,
 131:         0x18,
 132:         0x19,
 133:         0x1A,
 134:         0x1B,
 135:         0x1C,
 136:         0x1D,
 137:         0x1E,
 138:         0x1F,
 139:         0x20,
 140:         0x21,
 141:         0x22,
 142:         0x23,
 143:         0x24,
 144:         0x25,
 145:         0x26,
 146:         0x27,
 147:         0x28,
 148:         0x29,
 149:         0x2A,
 150:         0x2B,
 151:         0x2C,
 152:         0x2F,
 153:         0x3B,
 154:         0x3C,
 155:         0x3D,
 156:         0x3E,
 157:         0x3F,
 158:         0x40,
 159:         0x5B,
 160:         0x5C,
 161:         0x5D,
 162:         0x5E,
 163:         0x5F,
 164:         0x60,
 165:         0x7B,
 166:         0x7C,
 167:         0x7D,
 168:         0x7E,
 169:         0x7F,
 170:         0x3002
 171:     );
 172: 
 173:     /**
 174:      * Codepints prohibited by Nameprep
 175:      * @static
 176:      * @var array
 177:      * @access private
 178:      */
 179:     private static $_np_prohibit = array(
 180:         0xA0,
 181:         0x1680,
 182:         0x2000,
 183:         0x2001,
 184:         0x2002,
 185:         0x2003,
 186:         0x2004,
 187:         0x2005,
 188:         0x2006,
 189:         0x2007,
 190:         0x2008,
 191:         0x2009,
 192:         0x200A,
 193:         0x200B,
 194:         0x202F,
 195:         0x205F,
 196:         0x3000,
 197:         0x6DD,
 198:         0x70F,
 199:         0x180E,
 200:         0x200C,
 201:         0x200D,
 202:         0x2028,
 203:         0x2029,
 204:         0xFEFF,
 205:         0xFFF9,
 206:         0xFFFA,
 207:         0xFFFB,
 208:         0xFFFC,
 209:         0xFFFE,
 210:         0xFFFF,
 211:         0x1FFFE,
 212:         0x1FFFF,
 213:         0x2FFFE,
 214:         0x2FFFF,
 215:         0x3FFFE,
 216:         0x3FFFF,
 217:         0x4FFFE,
 218:         0x4FFFF,
 219:         0x5FFFE,
 220:         0x5FFFF,
 221:         0x6FFFE,
 222:         0x6FFFF,
 223:         0x7FFFE,
 224:         0x7FFFF,
 225:         0x8FFFE,
 226:         0x8FFFF,
 227:         0x9FFFE,
 228:         0x9FFFF,
 229:         0xAFFFE,
 230:         0xAFFFF,
 231:         0xBFFFE,
 232:         0xBFFFF,
 233:         0xCFFFE,
 234:         0xCFFFF,
 235:         0xDFFFE,
 236:         0xDFFFF,
 237:         0xEFFFE,
 238:         0xEFFFF,
 239:         0xFFFFE,
 240:         0xFFFFF,
 241:         0x10FFFE,
 242:         0x10FFFF,
 243:         0xFFF9,
 244:         0xFFFA,
 245:         0xFFFB,
 246:         0xFFFC,
 247:         0xFFFD,
 248:         0x340,
 249:         0x341,
 250:         0x200E,
 251:         0x200F,
 252:         0x202A,
 253:         0x202B,
 254:         0x202C,
 255:         0x202D,
 256:         0x202E,
 257:         0x206A,
 258:         0x206B,
 259:         0x206C,
 260:         0x206D,
 261:         0x206E,
 262:         0x206F,
 263:         0xE0001
 264:     );
 265: 
 266:     /**
 267:      * Codepoint ranges prohibited by nameprep
 268:      *
 269:      * @static
 270:      * @var array
 271:      * @access private
 272:      */
 273:     private static $_np_prohibit_ranges = array(
 274:         array(0x80,     0x9F    ),
 275:         array(0x2060,   0x206F  ),
 276:         array(0x1D173,  0x1D17A ),
 277:         array(0xE000,   0xF8FF  ),
 278:         array(0xF0000,  0xFFFFD ),
 279:         array(0x100000, 0x10FFFD),
 280:         array(0xFDD0,   0xFDEF  ),
 281:         array(0xD800,   0xDFFF  ),
 282:         array(0x2FF0,   0x2FFB  ),
 283:         array(0xE0020,  0xE007F )
 284:     );
 285: 
 286:     /**
 287:      * Replacement mappings (casemapping, replacement sequences, ...)
 288:      *
 289:      * @static
 290:      * @var array
 291:      * @access private
 292:      */
 293:     private static $_np_replacemaps = array(
 294:         0x41    => array(0x61),
 295:         0x42    => array(0x62),
 296:         0x43    => array(0x63),
 297:         0x44    => array(0x64),
 298:         0x45    => array(0x65),
 299:         0x46    => array(0x66),
 300:         0x47    => array(0x67),
 301:         0x48    => array(0x68),
 302:         0x49    => array(0x69),
 303:         0x4A    => array(0x6A),
 304:         0x4B    => array(0x6B),
 305:         0x4C    => array(0x6C),
 306:         0x4D    => array(0x6D),
 307:         0x4E    => array(0x6E),
 308:         0x4F    => array(0x6F),
 309:         0x50    => array(0x70),
 310:         0x51    => array(0x71),
 311:         0x52    => array(0x72),
 312:         0x53    => array(0x73),
 313:         0x54    => array(0x74),
 314:         0x55    => array(0x75),
 315:         0x56    => array(0x76),
 316:         0x57    => array(0x77),
 317:         0x58    => array(0x78),
 318:         0x59    => array(0x79),
 319:         0x5A    => array(0x7A),
 320:         0xB5    => array(0x3BC),
 321:         0xC0    => array(0xE0),
 322:         0xC1    => array(0xE1),
 323:         0xC2    => array(0xE2),
 324:         0xC3    => array(0xE3),
 325:         0xC4    => array(0xE4),
 326:         0xC5    => array(0xE5),
 327:         0xC6    => array(0xE6),
 328:         0xC7    => array(0xE7),
 329:         0xC8    => array(0xE8),
 330:         0xC9    => array(0xE9),
 331:         0xCA    => array(0xEA),
 332:         0xCB    => array(0xEB),
 333:         0xCC    => array(0xEC),
 334:         0xCD    => array(0xED),
 335:         0xCE    => array(0xEE),
 336:         0xCF    => array(0xEF),
 337:         0xD0    => array(0xF0),
 338:         0xD1    => array(0xF1),
 339:         0xD2    => array(0xF2),
 340:         0xD3    => array(0xF3),
 341:         0xD4    => array(0xF4),
 342:         0xD5    => array(0xF5),
 343:         0xD6    => array(0xF6),
 344:         0xD8    => array(0xF8),
 345:         0xD9    => array(0xF9),
 346:         0xDA    => array(0xFA),
 347:         0xDB    => array(0xFB),
 348:         0xDC    => array(0xFC),
 349:         0xDD    => array(0xFD),
 350:         0xDE    => array(0xFE),
 351:         0xDF    => array(0x73, 0x73),
 352:         0x100   => array(0x101),
 353:         0x102   => array(0x103),
 354:         0x104   => array(0x105),
 355:         0x106   => array(0x107),
 356:         0x108   => array(0x109),
 357:         0x10A   => array(0x10B),
 358:         0x10C   => array(0x10D),
 359:         0x10E   => array(0x10F),
 360:         0x110   => array(0x111),
 361:         0x112   => array(0x113),
 362:         0x114   => array(0x115),
 363:         0x116   => array(0x117),
 364:         0x118   => array(0x119),
 365:         0x11A   => array(0x11B),
 366:         0x11C   => array(0x11D),
 367:         0x11E   => array(0x11F),
 368:         0x120   => array(0x121),
 369:         0x122   => array(0x123),
 370:         0x124   => array(0x125),
 371:         0x126   => array(0x127),
 372:         0x128   => array(0x129),
 373:         0x12A   => array(0x12B),
 374:         0x12C   => array(0x12D),
 375:         0x12E   => array(0x12F),
 376:         0x130   => array(0x69, 0x307),
 377:         0x132   => array(0x133),
 378:         0x134   => array(0x135),
 379:         0x136   => array(0x137),
 380:         0x139   => array(0x13A),
 381:         0x13B   => array(0x13C),
 382:         0x13D   => array(0x13E),
 383:         0x13F   => array(0x140),
 384:         0x141   => array(0x142),
 385:         0x143   => array(0x144),
 386:         0x145   => array(0x146),
 387:         0x147   => array(0x148),
 388:         0x149   => array(0x2BC, 0x6E),
 389:         0x14A   => array(0x14B),
 390:         0x14C   => array(0x14D),
 391:         0x14E   => array(0x14F),
 392:         0x150   => array(0x151),
 393:         0x152   => array(0x153),
 394:         0x154   => array(0x155),
 395:         0x156   => array(0x157),
 396:         0x158   => array(0x159),
 397:         0x15A   => array(0x15B),
 398:         0x15C   => array(0x15D),
 399:         0x15E   => array(0x15F),
 400:         0x160   => array(0x161),
 401:         0x162   => array(0x163),
 402:         0x164   => array(0x165),
 403:         0x166   => array(0x167),
 404:         0x168   => array(0x169),
 405:         0x16A   => array(0x16B),
 406:         0x16C   => array(0x16D),
 407:         0x16E   => array(0x16F),
 408:         0x170   => array(0x171),
 409:         0x172   => array(0x173),
 410:         0x174   => array(0x175),
 411:         0x176   => array(0x177),
 412:         0x178   => array(0xFF),
 413:         0x179   => array(0x17A),
 414:         0x17B   => array(0x17C),
 415:         0x17D   => array(0x17E),
 416:         0x17F   => array(0x73),
 417:         0x181   => array(0x253),
 418:         0x182   => array(0x183),
 419:         0x184   => array(0x185),
 420:         0x186   => array(0x254),
 421:         0x187   => array(0x188),
 422:         0x189   => array(0x256),
 423:         0x18A   => array(0x257),
 424:         0x18B   => array(0x18C),
 425:         0x18E   => array(0x1DD),
 426:         0x18F   => array(0x259),
 427:         0x190   => array(0x25B),
 428:         0x191   => array(0x192),
 429:         0x193   => array(0x260),
 430:         0x194   => array(0x263),
 431:         0x196   => array(0x269),
 432:         0x197   => array(0x268),
 433:         0x198   => array(0x199),
 434:         0x19C   => array(0x26F),
 435:         0x19D   => array(0x272),
 436:         0x19F   => array(0x275),
 437:         0x1A0   => array(0x1A1),
 438:         0x1A2   => array(0x1A3),
 439:         0x1A4   => array(0x1A5),
 440:         0x1A6   => array(0x280),
 441:         0x1A7   => array(0x1A8),
 442:         0x1A9   => array(0x283),
 443:         0x1AC   => array(0x1AD),
 444:         0x1AE   => array(0x288),
 445:         0x1AF   => array(0x1B0),
 446:         0x1B1   => array(0x28A),
 447:         0x1B2   => array(0x28B),
 448:         0x1B3   => array(0x1B4),
 449:         0x1B5   => array(0x1B6),
 450:         0x1B7   => array(0x292),
 451:         0x1B8   => array(0x1B9),
 452:         0x1BC   => array(0x1BD),
 453:         0x1C4   => array(0x1C6),
 454:         0x1C5   => array(0x1C6),
 455:         0x1C7   => array(0x1C9),
 456:         0x1C8   => array(0x1C9),
 457:         0x1CA   => array(0x1CC),
 458:         0x1CB   => array(0x1CC),
 459:         0x1CD   => array(0x1CE),
 460:         0x1CF   => array(0x1D0),
 461:         0x1D1   => array(0x1D2),
 462:         0x1D3   => array(0x1D4),
 463:         0x1D5   => array(0x1D6),
 464:         0x1D7   => array(0x1D8),
 465:         0x1D9   => array(0x1DA),
 466:         0x1DB   => array(0x1DC),
 467:         0x1DE   => array(0x1DF),
 468:         0x1E0   => array(0x1E1),
 469:         0x1E2   => array(0x1E3),
 470:         0x1E4   => array(0x1E5),
 471:         0x1E6   => array(0x1E7),
 472:         0x1E8   => array(0x1E9),
 473:         0x1EA   => array(0x1EB),
 474:         0x1EC   => array(0x1ED),
 475:         0x1EE   => array(0x1EF),
 476:         0x1F0   => array(0x6A, 0x30C),
 477:         0x1F1   => array(0x1F3),
 478:         0x1F2   => array(0x1F3),
 479:         0x1F4   => array(0x1F5),
 480:         0x1F6   => array(0x195),
 481:         0x1F7   => array(0x1BF),
 482:         0x1F8   => array(0x1F9),
 483:         0x1FA   => array(0x1FB),
 484:         0x1FC   => array(0x1FD),
 485:         0x1FE   => array(0x1FF),
 486:         0x200   => array(0x201),
 487:         0x202   => array(0x203),
 488:         0x204   => array(0x205),
 489:         0x206   => array(0x207),
 490:         0x208   => array(0x209),
 491:         0x20A   => array(0x20B),
 492:         0x20C   => array(0x20D),
 493:         0x20E   => array(0x20F),
 494:         0x210   => array(0x211),
 495:         0x212   => array(0x213),
 496:         0x214   => array(0x215),
 497:         0x216   => array(0x217),
 498:         0x218   => array(0x219),
 499:         0x21A   => array(0x21B),
 500:         0x21C   => array(0x21D),
 501:         0x21E   => array(0x21F),
 502:         0x220   => array(0x19E),
 503:         0x222   => array(0x223),
 504:         0x224   => array(0x225),
 505:         0x226   => array(0x227),
 506:         0x228   => array(0x229),
 507:         0x22A   => array(0x22B),
 508:         0x22C   => array(0x22D),
 509:         0x22E   => array(0x22F),
 510:         0x230   => array(0x231),
 511:         0x232   => array(0x233),
 512:         0x345   => array(0x3B9),
 513:         0x37A   => array(0x20, 0x3B9),
 514:         0x386   => array(0x3AC),
 515:         0x388   => array(0x3AD),
 516:         0x389   => array(0x3AE),
 517:         0x38A   => array(0x3AF),
 518:         0x38C   => array(0x3CC),
 519:         0x38E   => array(0x3CD),
 520:         0x38F   => array(0x3CE),
 521:         0x390   => array(0x3B9, 0x308, 0x301),
 522:         0x391   => array(0x3B1),
 523:         0x392   => array(0x3B2),
 524:         0x393   => array(0x3B3),
 525:         0x394   => array(0x3B4),
 526:         0x395   => array(0x3B5),
 527:         0x396   => array(0x3B6),
 528:         0x397   => array(0x3B7),
 529:         0x398   => array(0x3B8),
 530:         0x399   => array(0x3B9),
 531:         0x39A   => array(0x3BA),
 532:         0x39B   => array(0x3BB),
 533:         0x39C   => array(0x3BC),
 534:         0x39D   => array(0x3BD),
 535:         0x39E   => array(0x3BE),
 536:         0x39F   => array(0x3BF),
 537:         0x3A0   => array(0x3C0),
 538:         0x3A1   => array(0x3C1),
 539:         0x3A3   => array(0x3C3),
 540:         0x3A4   => array(0x3C4),
 541:         0x3A5   => array(0x3C5),
 542:         0x3A6   => array(0x3C6),
 543:         0x3A7   => array(0x3C7),
 544:         0x3A8   => array(0x3C8),
 545:         0x3A9   => array(0x3C9),
 546:         0x3AA   => array(0x3CA),
 547:         0x3AB   => array(0x3CB),
 548:         0x3B0   => array(0x3C5, 0x308, 0x301),
 549:         0x3C2   => array(0x3C3),
 550:         0x3D0   => array(0x3B2),
 551:         0x3D1   => array(0x3B8),
 552:         0x3D2   => array(0x3C5),
 553:         0x3D3   => array(0x3CD),
 554:         0x3D4   => array(0x3CB),
 555:         0x3D5   => array(0x3C6),
 556:         0x3D6   => array(0x3C0),
 557:         0x3D8   => array(0x3D9),
 558:         0x3DA   => array(0x3DB),
 559:         0x3DC   => array(0x3DD),
 560:         0x3DE   => array(0x3DF),
 561:         0x3E0   => array(0x3E1),
 562:         0x3E2   => array(0x3E3),
 563:         0x3E4   => array(0x3E5),
 564:         0x3E6   => array(0x3E7),
 565:         0x3E8   => array(0x3E9),
 566:         0x3EA   => array(0x3EB),
 567:         0x3EC   => array(0x3ED),
 568:         0x3EE   => array(0x3EF),
 569:         0x3F0   => array(0x3BA),
 570:         0x3F1   => array(0x3C1),
 571:         0x3F2   => array(0x3C3),
 572:         0x3F4   => array(0x3B8),
 573:         0x3F5   => array(0x3B5),
 574:         0x400   => array(0x450),
 575:         0x401   => array(0x451),
 576:         0x402   => array(0x452),
 577:         0x403   => array(0x453),
 578:         0x404   => array(0x454),
 579:         0x405   => array(0x455),
 580:         0x406   => array(0x456),
 581:         0x407   => array(0x457),
 582:         0x408   => array(0x458),
 583:         0x409   => array(0x459),
 584:         0x40A   => array(0x45A),
 585:         0x40B   => array(0x45B),
 586:         0x40C   => array(0x45C),
 587:         0x40D   => array(0x45D),
 588:         0x40E   => array(0x45E),
 589:         0x40F   => array(0x45F),
 590:         0x410   => array(0x430),
 591:         0x411   => array(0x431),
 592:         0x412   => array(0x432),
 593:         0x413   => array(0x433),
 594:         0x414   => array(0x434),
 595:         0x415   => array(0x435),
 596:         0x416   => array(0x436),
 597:         0x417   => array(0x437),
 598:         0x418   => array(0x438),
 599:         0x419   => array(0x439),
 600:         0x41A   => array(0x43A),
 601:         0x41B   => array(0x43B),
 602:         0x41C   => array(0x43C),
 603:         0x41D   => array(0x43D),
 604:         0x41E   => array(0x43E),
 605:         0x41F   => array(0x43F),
 606:         0x420   => array(0x440),
 607:         0x421   => array(0x441),
 608:         0x422   => array(0x442),
 609:         0x423   => array(0x443),
 610:         0x424   => array(0x444),
 611:         0x425   => array(0x445),
 612:         0x426   => array(0x446),
 613:         0x427   => array(0x447),
 614:         0x428   => array(0x448),
 615:         0x429   => array(0x449),
 616:         0x42A   => array(0x44A),
 617:         0x42B   => array(0x44B),
 618:         0x42C   => array(0x44C),
 619:         0x42D   => array(0x44D),
 620:         0x42E   => array(0x44E),
 621:         0x42F   => array(0x44F),
 622:         0x460   => array(0x461),
 623:         0x462   => array(0x463),
 624:         0x464   => array(0x465),
 625:         0x466   => array(0x467),
 626:         0x468   => array(0x469),
 627:         0x46A   => array(0x46B),
 628:         0x46C   => array(0x46D),
 629:         0x46E   => array(0x46F),
 630:         0x470   => array(0x471),
 631:         0x472   => array(0x473),
 632:         0x474   => array(0x475),
 633:         0x476   => array(0x477),
 634:         0x478   => array(0x479),
 635:         0x47A   => array(0x47B),
 636:         0x47C   => array(0x47D),
 637:         0x47E   => array(0x47F),
 638:         0x480   => array(0x481),
 639:         0x48A   => array(0x48B),
 640:         0x48C   => array(0x48D),
 641:         0x48E   => array(0x48F),
 642:         0x490   => array(0x491),
 643:         0x492   => array(0x493),
 644:         0x494   => array(0x495),
 645:         0x496   => array(0x497),
 646:         0x498   => array(0x499),
 647:         0x49A   => array(0x49B),
 648:         0x49C   => array(0x49D),
 649:         0x49E   => array(0x49F),
 650:         0x4A0   => array(0x4A1),
 651:         0x4A2   => array(0x4A3),
 652:         0x4A4   => array(0x4A5),
 653:         0x4A6   => array(0x4A7),
 654:         0x4A8   => array(0x4A9),
 655:         0x4AA   => array(0x4AB),
 656:         0x4AC   => array(0x4AD),
 657:         0x4AE   => array(0x4AF),
 658:         0x4B0   => array(0x4B1),
 659:         0x4B2   => array(0x4B3),
 660:         0x4B4   => array(0x4B5),
 661:         0x4B6   => array(0x4B7),
 662:         0x4B8   => array(0x4B9),
 663:         0x4BA   => array(0x4BB),
 664:         0x4BC   => array(0x4BD),
 665:         0x4BE   => array(0x4BF),
 666:         0x4C1   => array(0x4C2),
 667:         0x4C3   => array(0x4C4),
 668:         0x4C5   => array(0x4C6),
 669:         0x4C7   => array(0x4C8),
 670:         0x4C9   => array(0x4CA),
 671:         0x4CB   => array(0x4CC),
 672:         0x4CD   => array(0x4CE),
 673:         0x4D0   => array(0x4D1),
 674:         0x4D2   => array(0x4D3),
 675:         0x4D4   => array(0x4D5),
 676:         0x4D6   => array(0x4D7),
 677:         0x4D8   => array(0x4D9),
 678:         0x4DA   => array(0x4DB),
 679:         0x4DC   => array(0x4DD),
 680:         0x4DE   => array(0x4DF),
 681:         0x4E0   => array(0x4E1),
 682:         0x4E2   => array(0x4E3),
 683:         0x4E4   => array(0x4E5),
 684:         0x4E6   => array(0x4E7),
 685:         0x4E8   => array(0x4E9),
 686:         0x4EA   => array(0x4EB),
 687:         0x4EC   => array(0x4ED),
 688:         0x4EE   => array(0x4EF),
 689:         0x4F0   => array(0x4F1),
 690:         0x4F2   => array(0x4F3),
 691:         0x4F4   => array(0x4F5),
 692:         0x4F8   => array(0x4F9),
 693:         0x500   => array(0x501),
 694:         0x502   => array(0x503),
 695:         0x504   => array(0x505),
 696:         0x506   => array(0x507),
 697:         0x508   => array(0x509),
 698:         0x50A   => array(0x50B),
 699:         0x50C   => array(0x50D),
 700:         0x50E   => array(0x50F),
 701:         0x531   => array(0x561),
 702:         0x532   => array(0x562),
 703:         0x533   => array(0x563),
 704:         0x534   => array(0x564),
 705:         0x535   => array(0x565),
 706:         0x536   => array(0x566),
 707:         0x537   => array(0x567),
 708:         0x538   => array(0x568),
 709:         0x539   => array(0x569),
 710:         0x53A   => array(0x56A),
 711:         0x53B   => array(0x56B),
 712:         0x53C   => array(0x56C),
 713:         0x53D   => array(0x56D),
 714:         0x53E   => array(0x56E),
 715:         0x53F   => array(0x56F),
 716:         0x540   => array(0x570),
 717:         0x541   => array(0x571),
 718:         0x542   => array(0x572),
 719:         0x543   => array(0x573),
 720:         0x544   => array(0x574),
 721:         0x545   => array(0x575),
 722:         0x546   => array(0x576),
 723:         0x547   => array(0x577),
 724:         0x548   => array(0x578),
 725:         0x549   => array(0x579),
 726:         0x54A   => array(0x57A),
 727:         0x54B   => array(0x57B),
 728:         0x54C   => array(0x57C),
 729:         0x54D   => array(0x57D),
 730:         0x54E   => array(0x57E),
 731:         0x54F   => array(0x57F),
 732:         0x550   => array(0x580),
 733:         0x551   => array(0x581),
 734:         0x552   => array(0x582),
 735:         0x553   => array(0x583),
 736:         0x554   => array(0x584),
 737:         0x555   => array(0x585),
 738:         0x556   => array(0x586),
 739:         0x587   => array(0x565, 0x582),
 740:         0x1E00  => array(0x1E01),
 741:         0x1E02  => array(0x1E03),
 742:         0x1E04  => array(0x1E05),
 743:         0x1E06  => array(0x1E07),
 744:         0x1E08  => array(0x1E09),
 745:         0x1E0A  => array(0x1E0B),
 746:         0x1E0C  => array(0x1E0D),
 747:         0x1E0E  => array(0x1E0F),
 748:         0x1E10  => array(0x1E11),
 749:         0x1E12  => array(0x1E13),
 750:         0x1E14  => array(0x1E15),
 751:         0x1E16  => array(0x1E17),
 752:         0x1E18  => array(0x1E19),
 753:         0x1E1A  => array(0x1E1B),
 754:         0x1E1C  => array(0x1E1D),
 755:         0x1E1E  => array(0x1E1F),
 756:         0x1E20  => array(0x1E21),
 757:         0x1E22  => array(0x1E23),
 758:         0x1E24  => array(0x1E25),
 759:         0x1E26  => array(0x1E27),
 760:         0x1E28  => array(0x1E29),
 761:         0x1E2A  => array(0x1E2B),
 762:         0x1E2C  => array(0x1E2D),
 763:         0x1E2E  => array(0x1E2F),
 764:         0x1E30  => array(0x1E31),
 765:         0x1E32  => array(0x1E33),
 766:         0x1E34  => array(0x1E35),
 767:         0x1E36  => array(0x1E37),
 768:         0x1E38  => array(0x1E39),
 769:         0x1E3A  => array(0x1E3B),
 770:         0x1E3C  => array(0x1E3D),
 771:         0x1E3E  => array(0x1E3F),
 772:         0x1E40  => array(0x1E41),
 773:         0x1E42  => array(0x1E43),
 774:         0x1E44  => array(0x1E45),
 775:         0x1E46  => array(0x1E47),
 776:         0x1E48  => array(0x1E49),
 777:         0x1E4A  => array(0x1E4B),
 778:         0x1E4C  => array(0x1E4D),
 779:         0x1E4E  => array(0x1E4F),
 780:         0x1E50  => array(0x1E51),
 781:         0x1E52  => array(0x1E53),
 782:         0x1E54  => array(0x1E55),
 783:         0x1E56  => array(0x1E57),
 784:         0x1E58  => array(0x1E59),
 785:         0x1E5A  => array(0x1E5B),
 786:         0x1E5C  => array(0x1E5D),
 787:         0x1E5E  => array(0x1E5F),
 788:         0x1E60  => array(0x1E61),
 789:         0x1E62  => array(0x1E63),
 790:         0x1E64  => array(0x1E65),
 791:         0x1E66  => array(0x1E67),
 792:         0x1E68  => array(0x1E69),
 793:         0x1E6A  => array(0x1E6B),
 794:         0x1E6C  => array(0x1E6D),
 795:         0x1E6E  => array(0x1E6F),
 796:         0x1E70  => array(0x1E71),
 797:         0x1E72  => array(0x1E73),
 798:         0x1E74  => array(0x1E75),
 799:         0x1E76  => array(0x1E77),
 800:         0x1E78  => array(0x1E79),
 801:         0x1E7A  => array(0x1E7B),
 802:         0x1E7C  => array(0x1E7D),
 803:         0x1E7E  => array(0x1E7F),
 804:         0x1E80  => array(0x1E81),
 805:         0x1E82  => array(0x1E83),
 806:         0x1E84  => array(0x1E85),
 807:         0x1E86  => array(0x1E87),
 808:         0x1E88  => array(0x1E89),
 809:         0x1E8A  => array(0x1E8B),
 810:         0x1E8C  => array(0x1E8D),
 811:         0x1E8E  => array(0x1E8F),
 812:         0x1E90  => array(0x1E91),
 813:         0x1E92  => array(0x1E93),
 814:         0x1E94  => array(0x1E95),
 815:         0x1E96  => array(0x68, 0x331),
 816:         0x1E97  => array(0x74, 0x308),
 817:         0x1E98  => array(0x77, 0x30A),
 818:         0x1E99  => array(0x79, 0x30A),
 819:         0x1E9A  => array(0x61, 0x2BE),
 820:         0x1E9B  => array(0x1E61),
 821:         0x1EA0  => array(0x1EA1),
 822:         0x1EA2  => array(0x1EA3),
 823:         0x1EA4  => array(0x1EA5),
 824:         0x1EA6  => array(0x1EA7),
 825:         0x1EA8  => array(0x1EA9),
 826:         0x1EAA  => array(0x1EAB),
 827:         0x1EAC  => array(0x1EAD),
 828:         0x1EAE  => array(0x1EAF),
 829:         0x1EB0  => array(0x1EB1),
 830:         0x1EB2  => array(0x1EB3),
 831:         0x1EB4  => array(0x1EB5),
 832:         0x1EB6  => array(0x1EB7),
 833:         0x1EB8  => array(0x1EB9),
 834:         0x1EBA  => array(0x1EBB),
 835:         0x1EBC  => array(0x1EBD),
 836:         0x1EBE  => array(0x1EBF),
 837:         0x1EC0  => array(0x1EC1),
 838:         0x1EC2  => array(0x1EC3),
 839:         0x1EC4  => array(0x1EC5),
 840:         0x1EC6  => array(0x1EC7),
 841:         0x1EC8  => array(0x1EC9),
 842:         0x1ECA  => array(0x1ECB),
 843:         0x1ECC  => array(0x1ECD),
 844:         0x1ECE  => array(0x1ECF),
 845:         0x1ED0  => array(0x1ED1),
 846:         0x1ED2  => array(0x1ED3),
 847:         0x1ED4  => array(0x1ED5),
 848:         0x1ED6  => array(0x1ED7),
 849:         0x1ED8  => array(0x1ED9),
 850:         0x1EDA  => array(0x1EDB),
 851:         0x1EDC  => array(0x1EDD),
 852:         0x1EDE  => array(0x1EDF),
 853:         0x1EE0  => array(0x1EE1),
 854:         0x1EE2  => array(0x1EE3),
 855:         0x1EE4  => array(0x1EE5),
 856:         0x1EE6  => array(0x1EE7),
 857:         0x1EE8  => array(0x1EE9),
 858:         0x1EEA  => array(0x1EEB),
 859:         0x1EEC  => array(0x1EED),
 860:         0x1EEE  => array(0x1EEF),
 861:         0x1EF0  => array(0x1EF1),
 862:         0x1EF2  => array(0x1EF3),
 863:         0x1EF4  => array(0x1EF5),
 864:         0x1EF6  => array(0x1EF7),
 865:         0x1EF8  => array(0x1EF9),
 866:         0x1F08  => array(0x1F00),
 867:         0x1F09  => array(0x1F01),
 868:         0x1F0A  => array(0x1F02),
 869:         0x1F0B  => array(0x1F03),
 870:         0x1F0C  => array(0x1F04),
 871:         0x1F0D  => array(0x1F05),
 872:         0x1F0E  => array(0x1F06),
 873:         0x1F0F  => array(0x1F07),
 874:         0x1F18  => array(0x1F10),
 875:         0x1F19  => array(0x1F11),
 876:         0x1F1A  => array(0x1F12),
 877:         0x1F1B  => array(0x1F13),
 878:         0x1F1C  => array(0x1F14),
 879:         0x1F1D  => array(0x1F15),
 880:         0x1F28  => array(0x1F20),
 881:         0x1F29  => array(0x1F21),
 882:         0x1F2A  => array(0x1F22),
 883:         0x1F2B  => array(0x1F23),
 884:         0x1F2C  => array(0x1F24),
 885:         0x1F2D  => array(0x1F25),
 886:         0x1F2E  => array(0x1F26),
 887:         0x1F2F  => array(0x1F27),
 888:         0x1F38  => array(0x1F30),
 889:         0x1F39  => array(0x1F31),
 890:         0x1F3A  => array(0x1F32),
 891:         0x1F3B  => array(0x1F33),
 892:         0x1F3C  => array(0x1F34),
 893:         0x1F3D  => array(0x1F35),
 894:         0x1F3E  => array(0x1F36),
 895:         0x1F3F  => array(0x1F37),
 896:         0x1F48  => array(0x1F40),
 897:         0x1F49  => array(0x1F41),
 898:         0x1F4A  => array(0x1F42),
 899:         0x1F4B  => array(0x1F43),
 900:         0x1F4C  => array(0x1F44),
 901:         0x1F4D  => array(0x1F45),
 902:         0x1F50  => array(0x3C5, 0x313),
 903:         0x1F52  => array(0x3C5, 0x313, 0x300),
 904:         0x1F54  => array(0x3C5, 0x313, 0x301),
 905:         0x1F56  => array(0x3C5, 0x313, 0x342),
 906:         0x1F59  => array(0x1F51),
 907:         0x1F5B  => array(0x1F53),
 908:         0x1F5D  => array(0x1F55),
 909:         0x1F5F  => array(0x1F57),
 910:         0x1F68  => array(0x1F60),
 911:         0x1F69  => array(0x1F61),
 912:         0x1F6A  => array(0x1F62),
 913:         0x1F6B  => array(0x1F63),
 914:         0x1F6C  => array(0x1F64),
 915:         0x1F6D  => array(0x1F65),
 916:         0x1F6E  => array(0x1F66),
 917:         0x1F6F  => array(0x1F67),
 918:         0x1F80  => array(0x1F00, 0x3B9),
 919:         0x1F81  => array(0x1F01, 0x3B9),
 920:         0x1F82  => array(0x1F02, 0x3B9),
 921:         0x1F83  => array(0x1F03, 0x3B9),
 922:         0x1F84  => array(0x1F04, 0x3B9),
 923:         0x1F85  => array(0x1F05, 0x3B9),
 924:         0x1F86  => array(0x1F06, 0x3B9),
 925:         0x1F87  => array(0x1F07, 0x3B9),
 926:         0x1F88  => array(0x1F00, 0x3B9),
 927:         0x1F89  => array(0x1F01, 0x3B9),
 928:         0x1F8A  => array(0x1F02, 0x3B9),
 929:         0x1F8B  => array(0x1F03, 0x3B9),
 930:         0x1F8C  => array(0x1F04, 0x3B9),
 931:         0x1F8D  => array(0x1F05, 0x3B9),
 932:         0x1F8E  => array(0x1F06, 0x3B9),
 933:         0x1F8F  => array(0x1F07, 0x3B9),
 934:         0x1F90  => array(0x1F20, 0x3B9),
 935:         0x1F91  => array(0x1F21, 0x3B9),
 936:         0x1F92  => array(0x1F22, 0x3B9),
 937:         0x1F93  => array(0x1F23, 0x3B9),
 938:         0x1F94  => array(0x1F24, 0x3B9),
 939:         0x1F95  => array(0x1F25, 0x3B9),
 940:         0x1F96  => array(0x1F26, 0x3B9),
 941:         0x1F97  => array(0x1F27, 0x3B9),
 942:         0x1F98  => array(0x1F20, 0x3B9),
 943:         0x1F99  => array(0x1F21, 0x3B9),
 944:         0x1F9A  => array(0x1F22, 0x3B9),
 945:         0x1F9B  => array(0x1F23, 0x3B9),
 946:         0x1F9C  => array(0x1F24, 0x3B9),
 947:         0x1F9D  => array(0x1F25, 0x3B9),
 948:         0x1F9E  => array(0x1F26, 0x3B9),
 949:         0x1F9F  => array(0x1F27, 0x3B9),
 950:         0x1FA0  => array(0x1F60, 0x3B9),
 951:         0x1FA1  => array(0x1F61, 0x3B9),
 952:         0x1FA2  => array(0x1F62, 0x3B9),
 953:         0x1FA3  => array(0x1F63, 0x3B9),
 954:         0x1FA4  => array(0x1F64, 0x3B9),
 955:         0x1FA5  => array(0x1F65, 0x3B9),
 956:         0x1FA6  => array(0x1F66, 0x3B9),
 957:         0x1FA7  => array(0x1F67, 0x3B9),
 958:         0x1FA8  => array(0x1F60, 0x3B9),
 959:         0x1FA9  => array(0x1F61, 0x3B9),
 960:         0x1FAA  => array(0x1F62, 0x3B9),
 961:         0x1FAB  => array(0x1F63, 0x3B9),
 962:         0x1FAC  => array(0x1F64, 0x3B9),
 963:         0x1FAD  => array(0x1F65, 0x3B9),
 964:         0x1FAE  => array(0x1F66, 0x3B9),
 965:         0x1FAF  => array(0x1F67, 0x3B9),
 966:         0x1FB2  => array(0x1F70, 0x3B9),
 967:         0x1FB3  => array(0x3B1, 0x3B9),
 968:         0x1FB4  => array(0x3AC, 0x3B9),
 969:         0x1FB6  => array(0x3B1, 0x342),
 970:         0x1FB7  => array(0x3B1, 0x342, 0x3B9),
 971:         0x1FB8  => array(0x1FB0),
 972:         0x1FB9  => array(0x1FB1),
 973:         0x1FBA  => array(0x1F70),
 974:         0x1FBB  => array(0x1F71),
 975:         0x1FBC  => array(0x3B1, 0x3B9),
 976:         0x1FBE  => array(0x3B9),
 977:         0x1FC2  => array(0x1F74, 0x3B9),
 978:         0x1FC3  => array(0x3B7, 0x3B9),
 979:         0x1FC4  => array(0x3AE, 0x3B9),
 980:         0x1FC6  => array(0x3B7, 0x342),
 981:         0x1FC7  => array(0x3B7, 0x342, 0x3B9),
 982:         0x1FC8  => array(0x1F72),
 983:         0x1FC9  => array(0x1F73),
 984:         0x1FCA  => array(0x1F74),
 985:         0x1FCB  => array(0x1F75),
 986:         0x1FCC  => array(0x3B7, 0x3B9),
 987:         0x1FD2  => array(0x3B9, 0x308, 0x300),
 988:         0x1FD3  => array(0x3B9, 0x308, 0x301),
 989:         0x1FD6  => array(0x3B9, 0x342),
 990:         0x1FD7  => array(0x3B9, 0x308, 0x342),
 991:         0x1FD8  => array(0x1FD0),
 992:         0x1FD9  => array(0x1FD1),
 993:         0x1FDA  => array(0x1F76),
 994:         0x1FDB  => array(0x1F77),
 995:         0x1FE2  => array(0x3C5, 0x308, 0x300),
 996:         0x1FE3  => array(0x3C5, 0x308, 0x301),
 997:         0x1FE4  => array(0x3C1, 0x313),
 998:         0x1FE6  => array(0x3C5, 0x342),
 999:         0x1FE7  => array(0x3C5, 0x308, 0x342),
1000:         0x1FE8  => array(0x1FE0),
1001:         0x1FE9  => array(0x1FE1),
1002:         0x1FEA  => array(0x1F7A),
1003:         0x1FEB  => array(0x1F7B),
1004:         0x1FEC  => array(0x1FE5),
1005:         0x1FF2  => array(0x1F7C, 0x3B9),
1006:         0x1FF3  => array(0x3C9, 0x3B9),
1007:         0x1FF4  => array(0x3CE, 0x3B9),
1008:         0x1FF6  => array(0x3C9, 0x342),
1009:         0x1FF7  => array(0x3C9, 0x342, 0x3B9),
1010:         0x1FF8  => array(0x1F78),
1011:         0x1FF9  => array(0x1F79),
1012:         0x1FFA  => array(0x1F7C),
1013:         0x1FFB  => array(0x1F7D),
1014:         0x1FFC  => array(0x3C9, 0x3B9),
1015:         0x20A8  => array(0x72, 0x73),
1016:         0x2102  => array(0x63),
1017:         0x2103  => array(0xB0, 0x63),
1018:         0x2107  => array(0x25B),
1019:         0x2109  => array(0xB0, 0x66),
1020:         0x210B  => array(0x68),
1021:         0x210C  => array(0x68),
1022:         0x210D  => array(0x68),
1023:         0x2110  => array(0x69),
1024:         0x2111  => array(0x69),
1025:         0x2112  => array(0x6C),
1026:         0x2115  => array(0x6E),
1027:         0x2116  => array(0x6E, 0x6F),
1028:         0x2119  => array(0x70),
1029:         0x211A  => array(0x71),
1030:         0x211B  => array(0x72),
1031:         0x211C  => array(0x72),
1032:         0x211D  => array(0x72),
1033:         0x2120  => array(0x73, 0x6D),
1034:         0x2121  => array(0x74, 0x65, 0x6C),
1035:         0x2122  => array(0x74, 0x6D),
1036:         0x2124  => array(0x7A),
1037:         0x2126  => array(0x3C9),
1038:         0x2128  => array(0x7A),
1039:         0x212A  => array(0x6B),
1040:         0x212B  => array(0xE5),
1041:         0x212C  => array(0x62),
1042:         0x212D  => array(0x63),
1043:         0x2130  => array(0x65),
1044:         0x2131  => array(0x66),
1045:         0x2133  => array(0x6D),
1046:         0x213E  => array(0x3B3),
1047:         0x213F  => array(0x3C0),
1048:         0x2145  => array(0x64),
1049:         0x2160  => array(0x2170),
1050:         0x2161  => array(0x2171),
1051:         0x2162  => array(0x2172),
1052:         0x2163  => array(0x2173),
1053:         0x2164  => array(0x2174),
1054:         0x2165  => array(0x2175),
1055:         0x2166  => array(0x2176),
1056:         0x2167  => array(0x2177),
1057:         0x2168  => array(0x2178),
1058:         0x2169  => array(0x2179),
1059:         0x216A  => array(0x217A),
1060:         0x216B  => array(0x217B),
1061:         0x216C  => array(0x217C),
1062:         0x216D  => array(0x217D),
1063:         0x216E  => array(0x217E),
1064:         0x216F  => array(0x217F),
1065:         0x24B6  => array(0x24D0),
1066:         0x24B7  => array(0x24D1),
1067:         0x24B8  => array(0x24D2),
1068:         0x24B9  => array(0x24D3),
1069:         0x24BA  => array(0x24D4),
1070:         0x24BB  => array(0x24D5),
1071:         0x24BC  => array(0x24D6),
1072:         0x24BD  => array(0x24D7),
1073:         0x24BE  => array(0x24D8),
1074:         0x24BF  => array(0x24D9),
1075:         0x24C0  => array(0x24DA),
1076:         0x24C1  => array(0x24DB),
1077:         0x24C2  => array(0x24DC),
1078:         0x24C3  => array(0x24DD),
1079:         0x24C4  => array(0x24DE),
1080:         0x24C5  => array(0x24DF),
1081:         0x24C6  => array(0x24E0),
1082:         0x24C7  => array(0x24E1),
1083:         0x24C8  => array(0x24E2),
1084:         0x24C9  => array(0x24E3),
1085:         0x24CA  => array(0x24E4),
1086:         0x24CB  => array(0x24E5),
1087:         0x24CC  => array(0x24E6),
1088:         0x24CD  => array(0x24E7),
1089:         0x24CE  => array(0x24E8),
1090:         0x24CF  => array(0x24E9),
1091:         0x3371  => array(0x68, 0x70, 0x61),
1092:         0x3373  => array(0x61, 0x75),
1093:         0x3375  => array(0x6F, 0x76),
1094:         0x3380  => array(0x70, 0x61),
1095:         0x3381  => array(0x6E, 0x61),
1096:         0x3382  => array(0x3BC, 0x61),
1097:         0x3383  => array(0x6D, 0x61),
1098:         0x3384  => array(0x6B, 0x61),
1099:         0x3385  => array(0x6B, 0x62),
1100:         0x3386  => array(0x6D, 0x62),
1101:         0x3387  => array(0x67, 0x62),
1102:         0x338A  => array(0x70, 0x66),
1103:         0x338B  => array(0x6E, 0x66),
1104:         0x338C  => array(0x3BC, 0x66),
1105:         0x3390  => array(0x68, 0x7A),
1106:         0x3391  => array(0x6B, 0x68, 0x7A),
1107:         0x3392  => array(0x6D, 0x68, 0x7A),
1108:         0x3393  => array(0x67, 0x68, 0x7A),
1109:         0x3394  => array(0x74, 0x68, 0x7A),
1110:         0x33A9  => array(0x70, 0x61),
1111:         0x33AA  => array(0x6B, 0x70, 0x61),
1112:         0x33AB  => array(0x6D, 0x70, 0x61),
1113:         0x33AC  => array(0x67, 0x70, 0x61),
1114:         0x33B4  => array(0x70, 0x76),
1115:         0x33B5  => array(0x6E, 0x76),
1116:         0x33B6  => array(0x3BC, 0x76),
1117:         0x33B7  => array(0x6D, 0x76),
1118:         0x33B8  => array(0x6B, 0x76),
1119:         0x33B9  => array(0x6D, 0x76),
1120:         0x33BA  => array(0x70, 0x77),
1121:         0x33BB  => array(0x6E, 0x77),
1122:         0x33BC  => array(0x3BC, 0x77),
1123:         0x33BD  => array(0x6D, 0x77),
1124:         0x33BE  => array(0x6B, 0x77),
1125:         0x33BF  => array(0x6D, 0x77),
1126:         0x33C0  => array(0x6B, 0x3C9),
1127:         0x33C1  => array(0x6D, 0x3C9),
1128:         /* 0x33C2  => array(0x61, 0x2E, 0x6D, 0x2E), */
1129:         0x33C3  => array(0x62, 0x71),
1130:         0x33C6  => array(0x63, 0x2215, 0x6B, 0x67),
1131:         0x33C7  => array(0x63, 0x6F, 0x2E),
1132:         0x33C8  => array(0x64, 0x62),
1133:         0x33C9  => array(0x67, 0x79),
1134:         0x33CB  => array(0x68, 0x70),
1135:         0x33CD  => array(0x6B, 0x6B),
1136:         0x33CE  => array(0x6B, 0x6D),
1137:         0x33D7  => array(0x70, 0x68),
1138:         0x33D9  => array(0x70, 0x70, 0x6D),
1139:         0x33DA  => array(0x70, 0x72),
1140:         0x33DC  => array(0x73, 0x76),
1141:         0x33DD  => array(0x77, 0x62),
1142:         0xFB00  => array(0x66, 0x66),
1143:         0xFB01  => array(0x66, 0x69),
1144:         0xFB02  => array(0x66, 0x6C),
1145:         0xFB03  => array(0x66, 0x66, 0x69),
1146:         0xFB04  => array(0x66, 0x66, 0x6C),
1147:         0xFB05  => array(0x73, 0x74),
1148:         0xFB06  => array(0x73, 0x74),
1149:         0xFB13  => array(0x574, 0x576),
1150:         0xFB14  => array(0x574, 0x565),
1151:         0xFB15  => array(0x574, 0x56B),
1152:         0xFB16  => array(0x57E, 0x576),
1153:         0xFB17  => array(0x574, 0x56D),
1154:         0xFF21  => array(0xFF41),
1155:         0xFF22  => array(0xFF42),
1156:         0xFF23  => array(0xFF43),
1157:         0xFF24  => array(0xFF44),
1158:         0xFF25  => array(0xFF45),
1159:         0xFF26  => array(0xFF46),
1160:         0xFF27  => array(0xFF47),
1161:         0xFF28  => array(0xFF48),
1162:         0xFF29  => array(0xFF49),
1163:         0xFF2A  => array(0xFF4A),
1164:         0xFF2B  => array(0xFF4B),
1165:         0xFF2C  => array(0xFF4C),
1166:         0xFF2D  => array(0xFF4D),
1167:         0xFF2E  => array(0xFF4E),
1168:         0xFF2F  => array(0xFF4F),
1169:         0xFF30  => array(0xFF50),
1170:         0xFF31  => array(0xFF51),
1171:         0xFF32  => array(0xFF52),
1172:         0xFF33  => array(0xFF53),
1173:         0xFF34  => array(0xFF54),
1174:         0xFF35  => array(0xFF55),
1175:         0xFF36  => array(0xFF56),
1176:         0xFF37  => array(0xFF57),
1177:         0xFF38  => array(0xFF58),
1178:         0xFF39  => array(0xFF59),
1179:         0xFF3A  => array(0xFF5A),
1180:         0x10400 => array(0x10428),
1181:         0x10401 => array(0x10429),
1182:         0x10402 => array(0x1042A),
1183:         0x10403 => array(0x1042B),
1184:         0x10404 => array(0x1042C),
1185:         0x10405 => array(0x1042D),
1186:         0x10406 => array(0x1042E),
1187:         0x10407 => array(0x1042F),
1188:         0x10408 => array(0x10430),
1189:         0x10409 => array(0x10431),
1190:         0x1040A => array(0x10432),
1191:         0x1040B => array(0x10433),
1192:         0x1040C => array(0x10434),
1193:         0x1040D => array(0x10435),
1194:         0x1040E => array(0x10436),
1195:         0x1040F => array(0x10437),
1196:         0x10410 => array(0x10438),
1197:         0x10411 => array(0x10439),
1198:         0x10412 => array(0x1043A),
1199:         0x10413 => array(0x1043B),
1200:         0x10414 => array(0x1043C),
1201:         0x10415 => array(0x1043D),
1202:         0x10416 => array(0x1043E),
1203:         0x10417 => array(0x1043F),
1204:         0x10418 => array(0x10440),
1205:         0x10419 => array(0x10441),
1206:         0x1041A => array(0x10442),
1207:         0x1041B => array(0x10443),
1208:         0x1041C => array(0x10444),
1209:         0x1041D => array(0x10445),
1210:         0x1041E => array(0x10446),
1211:         0x1041F => array(0x10447),
1212:         0x10420 => array(0x10448),
1213:         0x10421 => array(0x10449),
1214:         0x10422 => array(0x1044A),
1215:         0x10423 => array(0x1044B),
1216:         0x10424 => array(0x1044C),
1217:         0x10425 => array(0x1044D),
1218:         0x1D400 => array(0x61),
1219:         0x1D401 => array(0x62),
1220:         0x1D402 => array(0x63),
1221:         0x1D403 => array(0x64),
1222:         0x1D404 => array(0x65),
1223:         0x1D405 => array(0x66),
1224:         0x1D406 => array(0x67),
1225:         0x1D407 => array(0x68),
1226:         0x1D408 => array(0x69),
1227:         0x1D409 => array(0x6A),
1228:         0x1D40A => array(0x6B),
1229:         0x1D40B => array(0x6C),
1230:         0x1D40C => array(0x6D),
1231:         0x1D40D => array(0x6E),
1232:         0x1D40E => array(0x6F),
1233:         0x1D40F => array(0x70),
1234:         0x1D410 => array(0x71),
1235:         0x1D411 => array(0x72),
1236:         0x1D412 => array(0x73),
1237:         0x1D413 => array(0x74),
1238:         0x1D414 => array(0x75),
1239:         0x1D415 => array(0x76),
1240:         0x1D416 => array(0x77),
1241:         0x1D417 => array(0x78),
1242:         0x1D418 => array(0x79),
1243:         0x1D419 => array(0x7A),
1244:         0x1D434 => array(0x61),
1245:         0x1D435 => array(0x62),
1246:         0x1D436 => array(0x63),
1247:         0x1D437 => array(0x64),
1248:         0x1D438 => array(0x65),
1249:         0x1D439 => array(0x66),
1250:         0x1D43A => array(0x67),
1251:         0x1D43B => array(0x68),
1252:         0x1D43C => array(0x69),
1253:         0x1D43D => array(0x6A),
1254:         0x1D43E => array(0x6B),
1255:         0x1D43F => array(0x6C),
1256:         0x1D440 => array(0x6D),
1257:         0x1D441 => array(0x6E),
1258:         0x1D442 => array(0x6F),
1259:         0x1D443 => array(0x70),
1260:         0x1D444 => array(0x71),
1261:         0x1D445 => array(0x72),
1262:         0x1D446 => array(0x73),
1263:         0x1D447 => array(0x74),
1264:         0x1D448 => array(0x75),
1265:         0x1D449 => array(0x76),
1266:         0x1D44A => array(0x77),
1267:         0x1D44B => array(0x78),
1268:         0x1D44C => array(0x79),
1269:         0x1D44D => array(0x7A),
1270:         0x1D468 => array(0x61),
1271:         0x1D469 => array(0x62),
1272:         0x1D46A => array(0x63),
1273:         0x1D46B => array(0x64),
1274:         0x1D46C => array(0x65),
1275:         0x1D46D => array(0x66),
1276:         0x1D46E => array(0x67),
1277:         0x1D46F => array(0x68),
1278:         0x1D470 => array(0x69),
1279:         0x1D471 => array(0x6A),
1280:         0x1D472 => array(0x6B),
1281:         0x1D473 => array(0x6C),
1282:         0x1D474 => array(0x6D),
1283:         0x1D475 => array(0x6E),
1284:         0x1D476 => array(0x6F),
1285:         0x1D477 => array(0x70),
1286:         0x1D478 => array(0x71),
1287:         0x1D479 => array(0x72),
1288:         0x1D47A => array(0x73),
1289:         0x1D47B => array(0x74),
1290:         0x1D47C => array(0x75),
1291:         0x1D47D => array(0x76),
1292:         0x1D47E => array(0x77),
1293:         0x1D47F => array(0x78),
1294:         0x1D480 => array(0x79),
1295:         0x1D481 => array(0x7A),
1296:         0x1D49C => array(0x61),
1297:         0x1D49E => array(0x63),
1298:         0x1D49F => array(0x64),
1299:         0x1D4A2 => array(0x67),
1300:         0x1D4A5 => array(0x6A),
1301:         0x1D4A6 => array(0x6B),
1302:         0x1D4A9 => array(0x6E),
1303:         0x1D4AA => array(0x6F),
1304:         0x1D4AB => array(0x70),
1305:         0x1D4AC => array(0x71),
1306:         0x1D4AE => array(0x73),
1307:         0x1D4AF => array(0x74),
1308:         0x1D4B0 => array(0x75),
1309:         0x1D4B1 => array(0x76),
1310:         0x1D4B2 => array(0x77),
1311:         0x1D4B3 => array(0x78),
1312:         0x1D4B4 => array(0x79),
1313:         0x1D4B5 => array(0x7A),
1314:         0x1D4D0 => array(0x61),
1315:         0x1D4D1 => array(0x62),
1316:         0x1D4D2 => array(0x63),
1317:         0x1D4D3 => array(0x64),
1318:         0x1D4D4 => array(0x65),
1319:         0x1D4D5 => array(0x66),
1320:         0x1D4D6 => array(0x67),
1321:         0x1D4D7 => array(0x68),
1322:         0x1D4D8 => array(0x69),
1323:         0x1D4D9 => array(0x6A),
1324:         0x1D4DA => array(0x6B),
1325:         0x1D4DB => array(0x6C),
1326:         0x1D4DC => array(0x6D),
1327:         0x1D4DD => array(0x6E),
1328:         0x1D4DE => array(0x6F),
1329:         0x1D4DF => array(0x70),
1330:         0x1D4E0 => array(0x71),
1331:         0x1D4E1 => array(0x72),
1332:         0x1D4E2 => array(0x73),
1333:         0x1D4E3 => array(0x74),
1334:         0x1D4E4 => array(0x75),
1335:         0x1D4E5 => array(0x76),
1336:         0x1D4E6 => array(0x77),
1337:         0x1D4E7 => array(0x78),
1338:         0x1D4E8 => array(0x79),
1339:         0x1D4E9 => array(0x7A),
1340:         0x1D504 => array(0x61),
1341:         0x1D505 => array(0x62),
1342:         0x1D507 => array(0x64),
1343:         0x1D508 => array(0x65),
1344:         0x1D509 => array(0x66),
1345:         0x1D50A => array(0x67),
1346:         0x1D50D => array(0x6A),
1347:         0x1D50E => array(0x6B),
1348:         0x1D50F => array(0x6C),
1349:         0x1D510 => array(0x6D),
1350:         0x1D511 => array(0x6E),
1351:         0x1D512 => array(0x6F),
1352:         0x1D513 => array(0x70),
1353:         0x1D514 => array(0x71),
1354:         0x1D516 => array(0x73),
1355:         0x1D517 => array(0x74),
1356:         0x1D518 => array(0x75),
1357:         0x1D519 => array(0x76),
1358:         0x1D51A => array(0x77),
1359:         0x1D51B => array(0x78),
1360:         0x1D51C => array(0x79),
1361:         0x1D538 => array(0x61),
1362:         0x1D539 => array(0x62),
1363:         0x1D53B => array(0x64),
1364:         0x1D53C => array(0x65),
1365:         0x1D53D => array(0x66),
1366:         0x1D53E => array(0x67),
1367:         0x1D540 => array(0x69),
1368:         0x1D541 => array(0x6A),
1369:         0x1D542 => array(0x6B),
1370:         0x1D543 => array(0x6C),
1371:         0x1D544 => array(0x6D),
1372:         0x1D546 => array(0x6F),
1373:         0x1D54A => array(0x73),
1374:         0x1D54B => array(0x74),
1375:         0x1D54C => array(0x75),
1376:         0x1D54D => array(0x76),
1377:         0x1D54E => array(0x77),
1378:         0x1D54F => array(0x78),
1379:         0x1D550 => array(0x79),
1380:         0x1D56C => array(0x61),
1381:         0x1D56D => array(0x62),
1382:         0x1D56E => array(0x63),
1383:         0x1D56F => array(0x64),
1384:         0x1D570 => array(0x65),
1385:         0x1D571 => array(0x66),
1386:         0x1D572 => array(0x67),
1387:         0x1D573 => array(0x68),
1388:         0x1D574 => array(0x69),
1389:         0x1D575 => array(0x6A),
1390:         0x1D576 => array(0x6B),
1391:         0x1D577 => array(0x6C),
1392:         0x1D578 => array(0x6D),
1393:         0x1D579 => array(0x6E),
1394:         0x1D57A => array(0x6F),
1395:         0x1D57B => array(0x70),
1396:         0x1D57C => array(0x71),
1397:         0x1D57D => array(0x72),
1398:         0x1D57E => array(0x73),
1399:         0x1D57F => array(0x74),
1400:         0x1D580 => array(0x75),
1401:         0x1D581 => array(0x76),
1402:         0x1D582 => array(0x77),
1403:         0x1D583 => array(0x78),
1404:         0x1D584 => array(0x79),
1405:         0x1D585 => array(0x7A),
1406:         0x1D5A0 => array(0x61),
1407:         0x1D5A1 => array(0x62),
1408:         0x1D5A2 => array(0x63),
1409:         0x1D5A3 => array(0x64),
1410:         0x1D5A4 => array(0x65),
1411:         0x1D5A5 => array(0x66),
1412:         0x1D5A6 => array(0x67),
1413:         0x1D5A7 => array(0x68),
1414:         0x1D5A8 => array(0x69),
1415:         0x1D5A9 => array(0x6A),
1416:         0x1D5AA => array(0x6B),
1417:         0x1D5AB => array(0x6C),
1418:         0x1D5AC => array(0x6D),
1419:         0x1D5AD => array(0x6E),
1420:         0x1D5AE => array(0x6F),
1421:         0x1D5AF => array(0x70),
1422:         0x1D5B0 => array(0x71),
1423:         0x1D5B1 => array(0x72),
1424:         0x1D5B2 => array(0x73),
1425:         0x1D5B3 => array(0x74),
1426:         0x1D5B4 => array(0x75),
1427:         0x1D5B5 => array(0x76),
1428:         0x1D5B6 => array(0x77),
1429:         0x1D5B7 => array(0x78),
1430:         0x1D5B8 => array(0x79),
1431:         0x1D5B9 => array(0x7A),
1432:         0x1D5D4 => array(0x61),
1433:         0x1D5D5 => array(0x62),
1434:         0x1D5D6 => array(0x63),
1435:         0x1D5D7 => array(0x64),
1436:         0x1D5D8 => array(0x65),
1437:         0x1D5D9 => array(0x66),
1438:         0x1D5DA => array(0x67),
1439:         0x1D5DB => array(0x68),
1440:         0x1D5DC => array(0x69),
1441:         0x1D5DD => array(0x6A),
1442:         0x1D5DE => array(0x6B),
1443:         0x1D5DF => array(0x6C),
1444:         0x1D5E0 => array(0x6D),
1445:         0x1D5E1 => array(0x6E),
1446:         0x1D5E2 => array(0x6F),
1447:         0x1D5E3 => array(0x70),
1448:         0x1D5E4 => array(0x71),
1449:         0x1D5E5 => array(0x72),
1450:         0x1D5E6 => array(0x73),
1451:         0x1D5E7 => array(0x74),
1452:         0x1D5E8 => array(0x75),
1453:         0x1D5E9 => array(0x76),
1454:         0x1D5EA => array(0x77),
1455:         0x1D5EB => array(0x78),
1456:         0x1D5EC => array(0x79),
1457:         0x1D5ED => array(0x7A),
1458:         0x1D608 => array(0x61),
1459:         0x1D609 => array(0x62),
1460:         0x1D60A => array(0x63),
1461:         0x1D60B => array(0x64),
1462:         0x1D60C => array(0x65),
1463:         0x1D60D => array(0x66),
1464:         0x1D60E => array(0x67),
1465:         0x1D60F => array(0x68),
1466:         0x1D610 => array(0x69),
1467:         0x1D611 => array(0x6A),
1468:         0x1D612 => array(0x6B),
1469:         0x1D613 => array(0x6C),
1470:         0x1D614 => array(0x6D),
1471:         0x1D615 => array(0x6E),
1472:         0x1D616 => array(0x6F),
1473:         0x1D617 => array(0x70),
1474:         0x1D618 => array(0x71),
1475:         0x1D619 => array(0x72),
1476:         0x1D61A => array(0x73),
1477:         0x1D61B => array(0x74),
1478:         0x1D61C => array(0x75),
1479:         0x1D61D => array(0x76),
1480:         0x1D61E => array(0x77),
1481:         0x1D61F => array(0x78),
1482:         0x1D620 => array(0x79),
1483:         0x1D621 => array(0x7A),
1484:         0x1D63C => array(0x61),
1485:         0x1D63D => array(0x62),
1486:         0x1D63E => array(0x63),
1487:         0x1D63F => array(0x64),
1488:         0x1D640 => array(0x65),
1489:         0x1D641 => array(0x66),
1490:         0x1D642 => array(0x67),
1491:         0x1D643 => array(0x68),
1492:         0x1D644 => array(0x69),
1493:         0x1D645 => array(0x6A),
1494:         0x1D646 => array(0x6B),
1495:         0x1D647 => array(0x6C),
1496:         0x1D648 => array(0x6D),
1497:         0x1D649 => array(0x6E),
1498:         0x1D64A => array(0x6F),
1499:         0x1D64B => array(0x70),
1500:         0x1D64C => array(0x71),
1501:         0x1D64D => array(0x72),
1502:         0x1D64E => array(0x73),
1503:         0x1D64F => array(0x74),
1504:         0x1D650 => array(0x75),
1505:         0x1D651 => array(0x76),
1506:         0x1D652 => array(0x77),
1507:         0x1D653 => array(0x78),
1508:         0x1D654 => array(0x79),
1509:         0x1D655 => array(0x7A),
1510:         0x1D670 => array(0x61),
1511:         0x1D671 => array(0x62),
1512:         0x1D672 => array(0x63),
1513:         0x1D673 => array(0x64),
1514:         0x1D674 => array(0x65),
1515:         0x1D675 => array(0x66),
1516:         0x1D676 => array(0x67),
1517:         0x1D677 => array(0x68),
1518:         0x1D678 => array(0x69),
1519:         0x1D679 => array(0x6A),
1520:         0x1D67A => array(0x6B),
1521:         0x1D67B => array(0x6C),
1522:         0x1D67C => array(0x6D),
1523:         0x1D67D => array(0x6E),
1524:         0x1D67E => array(0x6F),
1525:         0x1D67F => array(0x70),
1526:         0x1D680 => array(0x71),
1527:         0x1D681 => array(0x72),
1528:         0x1D682 => array(0x73),
1529:         0x1D683 => array(0x74),
1530:         0x1D684 => array(0x75),
1531:         0x1D685 => array(0x76),
1532:         0x1D686 => array(0x77),
1533:         0x1D687 => array(0x78),
1534:         0x1D688 => array(0x79),
1535:         0x1D689 => array(0x7A),
1536:         0x1D6A8 => array(0x3B1),
1537:         0x1D6A9 => array(0x3B2),
1538:         0x1D6AA => array(0x3B3),
1539:         0x1D6AB => array(0x3B4),
1540:         0x1D6AC => array(0x3B5),
1541:         0x1D6AD => array(0x3B6),
1542:         0x1D6AE => array(0x3B7),
1543:         0x1D6AF => array(0x3B8),
1544:         0x1D6B0 => array(0x3B9),
1545:         0x1D6B1 => array(0x3BA),
1546:         0x1D6B2 => array(0x3BB),
1547:         0x1D6B3 => array(0x3BC),
1548:         0x1D6B4 => array(0x3BD),
1549:         0x1D6B5 => array(0x3BE),
1550:         0x1D6B6 => array(0x3BF),
1551:         0x1D6B7 => array(0x3C0),
1552:         0x1D6B8 => array(0x3C1),
1553:         0x1D6B9 => array(0x3B8),
1554:         0x1D6BA => array(0x3C3),
1555:         0x1D6BB => array(0x3C4),
1556:         0x1D6BC => array(0x3C5),
1557:         0x1D6BD => array(0x3C6),
1558:         0x1D6BE => array(0x3C7),
1559:         0x1D6BF => array(0x3C8),
1560:         0x1D6C0 => array(0x3C9),
1561:         0x1D6D3 => array(0x3C3),
1562:         0x1D6E2 => array(0x3B1),
1563:         0x1D6E3 => array(0x3B2),
1564:         0x1D6E4 => array(0x3B3),
1565:         0x1D6E5 => array(0x3B4),
1566:         0x1D6E6 => array(0x3B5),
1567:         0x1D6E7 => array(0x3B6),
1568:         0x1D6E8 => array(0x3B7),
1569:         0x1D6E9 => array(0x3B8),
1570:         0x1D6EA => array(0x3B9),
1571:         0x1D6EB => array(0x3BA),
1572:         0x1D6EC => array(0x3BB),
1573:         0x1D6ED => array(0x3BC),
1574:         0x1D6EE => array(0x3BD),
1575:         0x1D6EF => array(0x3BE),
1576:         0x1D6F0 => array(0x3BF),
1577:         0x1D6F1 => array(0x3C0),
1578:         0x1D6F2 => array(0x3C1),
1579:         0x1D6F3 => array(0x3B8),
1580:         0x1D6F4 => array(0x3C3),
1581:         0x1D6F5 => array(0x3C4),
1582:         0x1D6F6 => array(0x3C5),
1583:         0x1D6F7 => array(0x3C6),
1584:         0x1D6F8 => array(0x3C7),
1585:         0x1D6F9 => array(0x3C8),
1586:         0x1D6FA => array(0x3C9),
1587:         0x1D70D => array(0x3C3),
1588:         0x1D71C => array(0x3B1),
1589:         0x1D71D => array(0x3B2),
1590:         0x1D71E => array(0x3B3),
1591:         0x1D71F => array(0x3B4),
1592:         0x1D720 => array(0x3B5),
1593:         0x1D721 => array(0x3B6),
1594:         0x1D722 => array(0x3B7),
1595:         0x1D723 => array(0x3B8),
1596:         0x1D724 => array(0x3B9),
1597:         0x1D725 => array(0x3BA),
1598:         0x1D726 => array(0x3BB),
1599:         0x1D727 => array(0x3BC),
1600:         0x1D728 => array(0x3BD),
1601:         0x1D729 => array(0x3BE),
1602:         0x1D72A => array(0x3BF),
1603:         0x1D72B => array(0x3C0),
1604:         0x1D72C => array(0x3C1),
1605:         0x1D72D => array(0x3B8),
1606:         0x1D72E => array(0x3C3),
1607:         0x1D72F => array(0x3C4),
1608:         0x1D730 => array(0x3C5),
1609:         0x1D731 => array(0x3C6),
1610:         0x1D732 => array(0x3C7),
1611:         0x1D733 => array(0x3C8),
1612:         0x1D734 => array(0x3C9),
1613:         0x1D747 => array(0x3C3),
1614:         0x1D756 => array(0x3B1),
1615:         0x1D757 => array(0x3B2),
1616:         0x1D758 => array(0x3B3),
1617:         0x1D759 => array(0x3B4),
1618:         0x1D75A => array(0x3B5),
1619:         0x1D75B => array(0x3B6),
1620:         0x1D75C => array(0x3B7),
1621:         0x1D75D => array(0x3B8),
1622:         0x1D75E => array(0x3B9),
1623:         0x1D75F => array(0x3BA),
1624:         0x1D760 => array(0x3BB),
1625:         0x1D761 => array(0x3BC),
1626:         0x1D762 => array(0x3BD),
1627:         0x1D763 => array(0x3BE),
1628:         0x1D764 => array(0x3BF),
1629:         0x1D765 => array(0x3C0),
1630:         0x1D766 => array(0x3C1),
1631:         0x1D767 => array(0x3B8),
1632:         0x1D768 => array(0x3C3),
1633:         0x1D769 => array(0x3C4),
1634:         0x1D76A => array(0x3C5),
1635:         0x1D76B => array(0x3C6),
1636:         0x1D76C => array(0x3C7),
1637:         0x1D76D => array(0x3C8),
1638:         0x1D76E => array(0x3C9),
1639:         0x1D781 => array(0x3C3),
1640:         0x1D790 => array(0x3B1),
1641:         0x1D791 => array(0x3B2),
1642:         0x1D792 => array(0x3B3),
1643:         0x1D793 => array(0x3B4),
1644:         0x1D794 => array(0x3B5),
1645:         0x1D795 => array(0x3B6),
1646:         0x1D796 => array(0x3B7),
1647:         0x1D797 => array(0x3B8),
1648:         0x1D798 => array(0x3B9),
1649:         0x1D799 => array(0x3BA),
1650:         0x1D79A => array(0x3BB),
1651:         0x1D79B => array(0x3BC),
1652:         0x1D79C => array(0x3BD),
1653:         0x1D79D => array(0x3BE),
1654:         0x1D79E => array(0x3BF),
1655:         0x1D79F => array(0x3C0),
1656:         0x1D7A0 => array(0x3C1),
1657:         0x1D7A1 => array(0x3B8),
1658:         0x1D7A2 => array(0x3C3),
1659:         0x1D7A3 => array(0x3C4),
1660:         0x1D7A4 => array(0x3C5),
1661:         0x1D7A5 => array(0x3C6),
1662:         0x1D7A6 => array(0x3C7),
1663:         0x1D7A7 => array(0x3C8),
1664:         0x1D7A8 => array(0x3C9),
1665:         0x1D7BB => array(0x3C3),
1666:         0x3F9   => array(0x3C3),
1667:         0x1D2C  => array(0x61),
1668:         0x1D2D  => array(0xE6),
1669:         0x1D2E  => array(0x62),
1670:         0x1D30  => array(0x64),
1671:         0x1D31  => array(0x65),
1672:         0x1D32  => array(0x1DD),
1673:         0x1D33  => array(0x67),
1674:         0x1D34  => array(0x68),
1675:         0x1D35  => array(0x69),
1676:         0x1D36  => array(0x6A),
1677:         0x1D37  => array(0x6B),
1678:         0x1D38  => array(0x6C),
1679:         0x1D39  => array(0x6D),
1680:         0x1D3A  => array(0x6E),
1681:         0x1D3C  => array(0x6F),
1682:         0x1D3D  => array(0x223),
1683:         0x1D3E  => array(0x70),
1684:         0x1D3F  => array(0x72),
1685:         0x1D40  => array(0x74),
1686:         0x1D41  => array(0x75),
1687:         0x1D42  => array(0x77),
1688:         0x213B  => array(0x66, 0x61, 0x78),
1689:         0x3250  => array(0x70, 0x74, 0x65),
1690:         0x32CC  => array(0x68, 0x67),
1691:         0x32CE  => array(0x65, 0x76),
1692:         0x32CF  => array(0x6C, 0x74, 0x64),
1693:         0x337A  => array(0x69, 0x75),
1694:         0x33DE  => array(0x76, 0x2215, 0x6D),
1695:         0x33DF  => array(0x61, 0x2215, 0x6D)
1696:     );
1697: 
1698:     /**
1699:      * Normalization Combining Classes; Code Points not listed
1700:      * got Combining Class 0.
1701:      *
1702:      * @static
1703:      * @var array
1704:      * @access private
1705:      */
1706:     private static $_np_norm_combcls = array(
1707:         0x334   => 1,
1708:         0x335   => 1,
1709:         0x336   => 1,
1710:         0x337   => 1,
1711:         0x338   => 1,
1712:         0x93C   => 7,
1713:         0x9BC   => 7,
1714:         0xA3C   => 7,
1715:         0xABC   => 7,
1716:         0xB3C   => 7,
1717:         0xCBC   => 7,
1718:         0x1037  => 7,
1719:         0x3099  => 8,
1720:         0x309A  => 8,
1721:         0x94D   => 9,
1722:         0x9CD   => 9,
1723:         0xA4D   => 9,
1724:         0xACD   => 9,
1725:         0xB4D   => 9,
1726:         0xBCD   => 9,
1727:         0xC4D   => 9,
1728:         0xCCD   => 9,
1729:         0xD4D   => 9,
1730:         0xDCA   => 9,
1731:         0xE3A   => 9,
1732:         0xF84   => 9,
1733:         0x1039  => 9,
1734:         0x1714  => 9,
1735:         0x1734  => 9,
1736:         0x17D2  => 9,
1737:         0x5B0   => 10,
1738:         0x5B1   => 11,
1739:         0x5B2   => 12,
1740:         0x5B3   => 13,
1741:         0x5B4   => 14,
1742:         0x5B5   => 15,
1743:         0x5B6   => 16,
1744:         0x5B7   => 17,
1745:         0x5B8   => 18,
1746:         0x5B9   => 19,
1747:         0x5BB   => 20,
1748:         0x5Bc   => 21,
1749:         0x5BD   => 22,
1750:         0x5BF   => 23,
1751:         0x5C1   => 24,
1752:         0x5C2   => 25,
1753:         0xFB1E  => 26,
1754:         0x64B   => 27,
1755:         0x64C   => 28,
1756:         0x64D   => 29,
1757:         0x64E   => 30,
1758:         0x64F   => 31,
1759:         0x650   => 32,
1760:         0x651   => 33,
1761:         0x652   => 34,
1762:         0x670   => 35,
1763:         0x711   => 36,
1764:         0xC55   => 84,
1765:         0xC56   => 91,
1766:         0xE38   => 103,
1767:         0xE39   => 103,
1768:         0xE48   => 107,
1769:         0xE49   => 107,
1770:         0xE4A   => 107,
1771:         0xE4B   => 107,
1772:         0xEB8   => 118,
1773:         0xEB9   => 118,
1774:         0xEC8   => 122,
1775:         0xEC9   => 122,
1776:         0xECA   => 122,
1777:         0xECB   => 122,
1778:         0xF71   => 129,
1779:         0xF72   => 130,
1780:         0xF7A   => 130,
1781:         0xF7B   => 130,
1782:         0xF7C   => 130,
1783:         0xF7D   => 130,
1784:         0xF80   => 130,
1785:         0xF74   => 132,
1786:         0x321   => 202,
1787:         0x322   => 202,
1788:         0x327   => 202,
1789:         0x328   => 202,
1790:         0x31B   => 216,
1791:         0xF39   => 216,
1792:         0x1D165 => 216,
1793:         0x1D166 => 216,
1794:         0x1D16E => 216,
1795:         0x1D16F => 216,
1796:         0x1D170 => 216,
1797:         0x1D171 => 216,
1798:         0x1D172 => 216,
1799:         0x302A  => 218,
1800:         0x316   => 220,
1801:         0x317   => 220,
1802:         0x318   => 220,
1803:         0x319   => 220,
1804:         0x31C   => 220,
1805:         0x31D   => 220,
1806:         0x31E   => 220,
1807:         0x31F   => 220,
1808:         0x320   => 220,
1809:         0x323   => 220,
1810:         0x324   => 220,
1811:         0x325   => 220,
1812:         0x326   => 220,
1813:         0x329   => 220,
1814:         0x32A   => 220,
1815:         0x32B   => 220,
1816:         0x32C   => 220,
1817:         0x32D   => 220,
1818:         0x32E   => 220,
1819:         0x32F   => 220,
1820:         0x330   => 220,
1821:         0x331   => 220,
1822:         0x332   => 220,
1823:         0x333   => 220,
1824:         0x339   => 220,
1825:         0x33A   => 220,
1826:         0x33B   => 220,
1827:         0x33C   => 220,
1828:         0x347   => 220,
1829:         0x348   => 220,
1830:         0x349   => 220,
1831:         0x34D   => 220,
1832:         0x34E   => 220,
1833:         0x353   => 220,
1834:         0x354   => 220,
1835:         0x355   => 220,
1836:         0x356   => 220,
1837:         0x591   => 220,
1838:         0x596   => 220,
1839:         0x59B   => 220,
1840:         0x5A3   => 220,
1841:         0x5A4   => 220,
1842:         0x5A5   => 220,
1843:         0x5A6   => 220,
1844:         0x5A7   => 220,
1845:         0x5AA   => 220,
1846:         0x655   => 220,
1847:         0x656   => 220,
1848:         0x6E3   => 220,
1849:         0x6EA   => 220,
1850:         0x6ED   => 220,
1851:         0x731   => 220,
1852:         0x734   => 220,
1853:         0x737   => 220,
1854:         0x738   => 220,
1855:         0x739   => 220,
1856:         0x73B   => 220,
1857:         0x73C   => 220,
1858:         0x73E   => 220,
1859:         0x742   => 220,
1860:         0x744   => 220,
1861:         0x746   => 220,
1862:         0x748   => 220,
1863:         0x952   => 220,
1864:         0xF18   => 220,
1865:         0xF19   => 220,
1866:         0xF35   => 220,
1867:         0xF37   => 220,
1868:         0xFC6   => 220,
1869:         0x193B  => 220,
1870:         0x20E8  => 220,
1871:         0x1D17B => 220,
1872:         0x1D17C => 220,
1873:         0x1D17D => 220,
1874:         0x1D17E => 220,
1875:         0x1D17F => 220,
1876:         0x1D180 => 220,
1877:         0x1D181 => 220,
1878:         0x1D182 => 220,
1879:         0x1D18A => 220,
1880:         0x1D18B => 220,
1881:         0x59A   => 222,
1882:         0x5AD   => 222,
1883:         0x1929  => 222,
1884:         0x302D  => 222,
1885:         0x302E  => 224,
1886:         0x302F  => 224,
1887:         0x1D16D => 226,
1888:         0x5AE   => 228,
1889:         0x18A9  => 228,
1890:         0x302B  => 228,
1891:         0x300   => 230,
1892:         0x301   => 230,
1893:         0x302   => 230,
1894:         0x303   => 230,
1895:         0x304   => 230,
1896:         0x305   => 230,
1897:         0x306   => 230,
1898:         0x307   => 230,
1899:         0x308   => 230,
1900:         0x309   => 230,
1901:         0x30A   => 230,
1902:         0x30B   => 230,
1903:         0x30C   => 230,
1904:         0x30D   => 230,
1905:         0x30E   => 230,
1906:         0x30F   => 230,
1907:         0x310   => 230,
1908:         0x311   => 230,
1909:         0x312   => 230,
1910:         0x313   => 230,
1911:         0x314   => 230,
1912:         0x33D   => 230,
1913:         0x33E   => 230,
1914:         0x33F   => 230,
1915:         0x340   => 230,
1916:         0x341   => 230,
1917:         0x342   => 230,
1918:         0x343   => 230,
1919:         0x344   => 230,
1920:         0x346   => 230,
1921:         0x34A   => 230,
1922:         0x34B   => 230,
1923:         0x34C   => 230,
1924:         0x350   => 230,
1925:         0x351   => 230,
1926:         0x352   => 230,
1927:         0x357   => 230,
1928:         0x363   => 230,
1929:         0x364   => 230,
1930:         0x365   => 230,
1931:         0x366   => 230,
1932:         0x367   => 230,
1933:         0x368   => 230,
1934:         0x369   => 230,
1935:         0x36A   => 230,
1936:         0x36B   => 230,
1937:         0x36C   => 230,
1938:         0x36D   => 230,
1939:         0x36E   => 230,
1940:         0x36F   => 230,
1941:         0x483   => 230,
1942:         0x484   => 230,
1943:         0x485   => 230,
1944:         0x486   => 230,
1945:         0x592   => 230,
1946:         0x593   => 230,
1947:         0x594   => 230,
1948:         0x595   => 230,
1949:         0x597   => 230,
1950:         0x598   => 230,
1951:         0x599   => 230,
1952:         0x59C   => 230,
1953:         0x59D   => 230,
1954:         0x59E   => 230,
1955:         0x59F   => 230,
1956:         0x5A0   => 230,
1957:         0x5A1   => 230,
1958:         0x5A8   => 230,
1959:         0x5A9   => 230,
1960:         0x5AB   => 230,
1961:         0x5AC   => 230,
1962:         0x5AF   => 230,
1963:         0x5C4   => 230,
1964:         0x610   => 230,
1965:         0x611   => 230,
1966:         0x612   => 230,
1967:         0x613   => 230,
1968:         0x614   => 230,
1969:         0x615   => 230,
1970:         0x653   => 230,
1971:         0x654   => 230,
1972:         0x657   => 230,
1973:         0x658   => 230,
1974:         0x6D6   => 230,
1975:         0x6D7   => 230,
1976:         0x6D8   => 230,
1977:         0x6D9   => 230,
1978:         0x6DA   => 230,
1979:         0x6DB   => 230,
1980:         0x6DC   => 230,
1981:         0x6DF   => 230,
1982:         0x6E0   => 230,
1983:         0x6E1   => 230,
1984:         0x6E2   => 230,
1985:         0x6E4   => 230,
1986:         0x6E7   => 230,
1987:         0x6E8   => 230,
1988:         0x6EB   => 230,
1989:         0x6EC   => 230,
1990:         0x730   => 230,
1991:         0x732   => 230,
1992:         0x733   => 230,
1993:         0x735   => 230,
1994:         0x736   => 230,
1995:         0x73A   => 230,
1996:         0x73D   => 230,
1997:         0x73F   => 230,
1998:         0x740   => 230,
1999:         0x741   => 230,
2000:         0x743   => 230,
2001:         0x745   => 230,
2002:         0x747   => 230,
2003:         0x749   => 230,
2004:         0x74A   => 230,
2005:         0x951   => 230,
2006:         0x953   => 230,
2007:         0x954   => 230,
2008:         0xF82   => 230,
2009:         0xF83   => 230,
2010:         0xF86   => 230,
2011:         0xF87   => 230,
2012:         0x170D  => 230,
2013:         0x193A  => 230,
2014:         0x20D0  => 230,
2015:         0x20D1  => 230,
2016:         0x20D4  => 230,
2017:         0x20D5  => 230,
2018:         0x20D6  => 230,
2019:         0x20D7  => 230,
2020:         0x20DB  => 230,
2021:         0x20DC  => 230,
2022:         0x20E1  => 230,
2023:         0x20E7  => 230,
2024:         0x20E9  => 230,
2025:         0xFE20  => 230,
2026:         0xFE21  => 230,
2027:         0xFE22  => 230,
2028:         0xFE23  => 230,
2029:         0x1D185 => 230,
2030:         0x1D186 => 230,
2031:         0x1D187 => 230,
2032:         0x1D189 => 230,
2033:         0x1D188 => 230,
2034:         0x1D1AA => 230,
2035:         0x1D1AB => 230,
2036:         0x1D1AC => 230,
2037:         0x1D1AD => 230,
2038:         0x315   => 232,
2039:         0x31A   => 232,
2040:         0x302C  => 232,
2041:         0x35F   => 233,
2042:         0x362   => 233,
2043:         0x35D   => 234,
2044:         0x35E   => 234,
2045:         0x360   => 234,
2046:         0x361   => 234,
2047:         0x345   => 240
2048:     );
2049:     // }}}
2050: 
2051:     // {{{ properties
2052:     /**
2053:      * @var string
2054:      * @access private
2055:      */
2056:     private $_punycode_prefix = 'xn--';
2057: 
2058:     /**
2059:      * @access private
2060:      */
2061:     private $_invalid_ucs = 0x80000000;
2062: 
2063:     /**
2064:      * @access private
2065:      */
2066:     private $_max_ucs = 0x10FFFF;
2067: 
2068:     /**
2069:      * @var int
2070:      * @access private
2071:      */
2072:     private $_base = 36;
2073: 
2074:     /**
2075:      * @var int
2076:      * @access private
2077:      */
2078:     private $_tmin = 1;
2079: 
2080:     /**
2081:      * @var int
2082:      * @access private
2083:      */
2084:     private $_tmax = 26;
2085: 
2086:     /**
2087:      * @var int
2088:      * @access private
2089:      */
2090:     private $_skew = 38;
2091: 
2092:     /**
2093:      * @var int
2094:      * @access private
2095:      */
2096:     private $_damp = 700;
2097: 
2098:     /**
2099:      * @var int
2100:      * @access private
2101:      */
2102:     private $_initial_bias = 72;
2103: 
2104:     /**
2105:      * @var int
2106:      * @access private
2107:      */
2108:     private $_initial_n = 0x80;
2109: 
2110:     /**
2111:      * @var int
2112:      * @access private
2113:      */
2114:     private $_slast;
2115: 
2116:     /**
2117:      * @access private
2118:      */
2119:     private $_sbase = 0xAC00;
2120: 
2121:     /**
2122:      * @access private
2123:      */
2124:     private $_lbase = 0x1100;
2125: 
2126:     /**
2127:      * @access private
2128:      */
2129:     private $_vbase = 0x1161;
2130: 
2131:     /**
2132:      * @access private
2133:      */
2134:     private $_tbase = 0x11a7;
2135: 
2136:     /**
2137:      * @var int
2138:      * @access private
2139:      */
2140:     private $_lcount = 19;
2141: 
2142:     /**
2143:      * @var int
2144:      * @access private
2145:      */
2146:     private $_vcount = 21;
2147: 
2148:     /**
2149:      * @var int
2150:      * @access private
2151:      */
2152:     private $_tcount = 28;
2153: 
2154:     /**
2155:      * vcount * tcount
2156:      *
2157:      * @var int
2158:      * @access private
2159:      */
2160:     private $_ncount = 588;
2161: 
2162:     /**
2163:      * lcount * tcount * vcount
2164:      *
2165:      * @var int
2166:      * @access private
2167:      */
2168:     private $_scount = 11172;
2169: 
2170:     /**
2171:      * Default encoding for encode()'s input and decode()'s output is UTF-8;
2172:      * Other possible encodings are ucs4_string and ucs4_array
2173:      * See {@link setParams()} for how to select these
2174:      *
2175:      * @var bool
2176:      * @access private
2177:      */
2178:     private $_api_encoding = 'utf8';
2179: 
2180:     /**
2181:      * Overlong UTF-8 encodings are forbidden
2182:      *
2183:      * @var bool
2184:      * @access private
2185:      */
2186:     private $_allow_overlong = false;
2187: 
2188:     /**
2189:      * Behave strict or not
2190:      *
2191:      * @var bool
2192:      * @access private
2193:      */
2194:     private $_strict_mode = false;
2195: 
2196:     /**
2197:      * IDNA-version to use
2198:      *
2199:      * Values are "2003" and "2008".
2200:      * Defaults to "2003", since that was the original version and for
2201:      * compatibility with previous versions of this library.
2202:      * If you need to encode "new" characters like the German "Eszett",
2203:      * please switch to 2008 first before encoding.
2204:      *
2205:      * @var bool
2206:      * @access private
2207:      */
2208:     private $_version = '2003';
2209: 
2210:     /**
2211:      * Cached value indicating whether or not mbstring function overloading is
2212:      * on for strlen
2213:      *
2214:      * This is cached for optimal performance.
2215:      *
2216:      * @var boolean
2217:      * @see Net_IDNA2::_byteLength()
2218:      */
2219:     private static $_mb_string_overload = null;
2220:     // }}}
2221: 
2222: 
2223:     // {{{ constructor
2224:     /**
2225:      * Constructor
2226:      *
2227:      * @param array $options Options to initialise the object with
2228:      *
2229:      * @access public
2230:      * @see    setParams()
2231:      */
2232:     public function __construct($options = null)
2233:     {
2234:         $this->_slast = $this->_sbase + $this->_lcount * $this->_vcount * $this->_tcount;
2235: 
2236:         if (is_array($options)) {
2237:             $this->setParams($options);
2238:         }
2239: 
2240:         // populate mbstring overloading cache if not set
2241:         if (self::$_mb_string_overload === null) {
2242:             self::$_mb_string_overload = (extension_loaded('mbstring')
2243:                 && (ini_get('mbstring.func_overload') & 0x02) === 0x02);
2244:         }
2245:     }
2246:     // }}}
2247: 
2248: 
2249:     /**
2250:      * Sets a new option value. Available options and values:
2251:      *
2252:      * [utf8 -     Use either UTF-8 or ISO-8859-1 as input (true for UTF-8, false
2253:      *             otherwise); The output is always UTF-8]
2254:      * [overlong - Unicode does not allow unnecessarily long encodings of chars,
2255:      *             to allow this, set this parameter to true, else to false;
2256:      *             default is false.]
2257:      * [strict -   true: strict mode, good for registration purposes - Causes errors
2258:      *             on failures; false: loose mode, ideal for "wildlife" applications
2259:      *             by silently ignoring errors and returning the original input instead]
2260:      *
2261:      * @param mixed  $option Parameter to set (string: single parameter; array of Parameter => Value pairs)
2262:      * @param string $value  Value to use (if parameter 1 is a string)
2263:      *
2264:      * @return boolean       true on success, false otherwise
2265:      * @access public
2266:      */
2267:     public function setParams($option, $value = false)
2268:     {
2269:         if (!is_array($option)) {
2270:             $option = array($option => $value);
2271:         }
2272: 
2273:         foreach ($option as $k => $v) {
2274:             switch ($k) {
2275:             case 'encoding':
2276:                 switch ($v) {
2277:                 case 'utf8':
2278:                 case 'ucs4_string':
2279:                 case 'ucs4_array':
2280:                     $this->_api_encoding = $v;
2281:                     break;
2282: 
2283:                 default:
2284:                     throw new InvalidArgumentException('Set Parameter: Unknown parameter '.$v.' for option '.$k);
2285:                 }
2286: 
2287:                 break;
2288: 
2289:             case 'overlong':
2290:                 $this->_allow_overlong = ($v) ? true : false;
2291:                 break;
2292: 
2293:             case 'strict':
2294:                 $this->_strict_mode = ($v) ? true : false;
2295:                 break;
2296: 
2297:             case 'version':
2298:                 if (in_array($v, array('2003', '2008'))) {
2299:                     $this->_version = $v;
2300:                 } else {
2301:                     throw new InvalidArgumentException('Set Parameter: Invalid parameter '.$v.' for option '.$k);
2302:                 }
2303:                 break;
2304: 
2305:             default:
2306:                 return false;
2307:             }
2308:         }
2309: 
2310:         return true;
2311:     }
2312: 
2313:     /**
2314:      * Encode a given UTF-8 domain name.
2315:      *
2316:      * @param string $decoded           Domain name (UTF-8 or UCS-4)
2317:      * @param string $one_time_encoding Desired input encoding, see {@link set_parameter}
2318:      *                                  If not given will use default-encoding
2319:      *
2320:      * @return string Encoded Domain name (ACE string)
2321:      * @return mixed  processed string
2322:      * @throws Exception
2323:      * @access public
2324:      */
2325:     public function encode($decoded, $one_time_encoding = false)
2326:     {
2327:         // Forcing conversion of input to UCS4 array
2328:         // If one time encoding is given, use this, else the objects property
2329:         switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) {
2330:         case 'utf8':
2331:             $decoded = $this->_utf8_to_ucs4($decoded);
2332:             break;
2333:         case 'ucs4_string':
2334:             $decoded = $this->_ucs4_string_to_ucs4($decoded);
2335:         case 'ucs4_array': // No break; before this line. Catch case, but do nothing
2336:             break;
2337:         default:
2338:             throw new InvalidArgumentException('Unsupported input format');
2339:         }
2340: 
2341:         // No input, no output, what else did you expect?
2342:         if (empty($decoded)) return '';
2343: 
2344:         // Anchors for iteration
2345:         $last_begin = 0;
2346:         // Output string
2347:         $output = '';
2348: 
2349:         foreach ($decoded as $k => $v) {
2350:             // Make sure to use just the plain dot
2351:             switch($v) {
2352:             case 0x3002:
2353:             case 0xFF0E:
2354:             case 0xFF61:
2355:                 $decoded[$k] = 0x2E;
2356:                 // It's right, no break here
2357:                 // The codepoints above have to be converted to dots anyway
2358: 
2359:             // Stumbling across an anchoring character
2360:             case 0x2E:
2361:             case 0x2F:
2362:             case 0x3A:
2363:             case 0x3F:
2364:             case 0x40:
2365:                 // Neither email addresses nor URLs allowed in strict mode
2366:                 if ($this->_strict_mode) {
2367:                     throw new InvalidArgumentException('Neither email addresses nor URLs are allowed in strict mode.');
2368:                 }
2369:                 // Skip first char
2370:                 if ($k) {
2371:                     $encoded = '';
2372:                     $encoded = $this->_encode(array_slice($decoded, $last_begin, (($k)-$last_begin)));
2373:                     if ($encoded) {
2374:                         $output .= $encoded;
2375:                     } else {
2376:                         $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($k)-$last_begin)));
2377:                     }
2378:                     $output .= chr($decoded[$k]);
2379:                 }
2380:                 $last_begin = $k + 1;
2381:             }
2382:         }
2383:         // Catch the rest of the string
2384:         if ($last_begin) {
2385:             $inp_len = sizeof($decoded);
2386:             $encoded = '';
2387:             $encoded = $this->_encode(array_slice($decoded, $last_begin, (($inp_len)-$last_begin)));
2388:             if ($encoded) {
2389:                 $output .= $encoded;
2390:             } else {
2391:                 $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($inp_len)-$last_begin)));
2392:             }
2393:             return $output;
2394:         }
2395: 
2396:         if ($output = $this->_encode($decoded)) {
2397:             return $output;
2398:         }
2399: 
2400:         return $this->_ucs4_to_utf8($decoded);
2401:     }
2402: 
2403:     /**
2404:      * Decode a given ACE domain name.
2405:      *
2406:      * @param string $input             Domain name (ACE string)
2407:      * @param string $one_time_encoding Desired output encoding, see {@link set_parameter}
2408:      *
2409:      * @return string                   Decoded Domain name (UTF-8 or UCS-4)
2410:      * @throws Exception
2411:      * @access public
2412:      */
2413:     public function decode($input, $one_time_encoding = false)
2414:     {
2415:         // Optionally set
2416:         if ($one_time_encoding) {
2417:             switch ($one_time_encoding) {
2418:             case 'utf8':
2419:             case 'ucs4_string':
2420:             case 'ucs4_array':
2421:                 break;
2422:             default:
2423:                 throw new InvalidArgumentException('Unknown encoding '.$one_time_encoding);
2424:             }
2425:         }
2426:         // Make sure to drop any newline characters around
2427:         $input = trim($input);
2428: 
2429:         // Negotiate input and try to determine, wether it is a plain string,
2430:         // an email address or something like a complete URL
2431:         if (strpos($input, '@')) { // Maybe it is an email address
2432:             // No no in strict mode
2433:             if ($this->_strict_mode) {
2434:                 throw new InvalidArgumentException('Only simple domain name parts can be handled in strict mode');
2435:             }
2436:             list($email_pref, $input) = explode('@', $input, 2);
2437:             $arr = explode('.', $input);
2438:             foreach ($arr as $k => $v) {
2439:                 $conv = $this->_decode($v);
2440:                 if ($conv) $arr[$k] = $conv;
2441:             }
2442:             $return = $email_pref . '@' . join('.', $arr);
2443:         } elseif (preg_match('![:\./]!', $input)) { // Or a complete domain name (with or without paths / parameters)
2444:             // No no in strict mode
2445:             if ($this->_strict_mode) {
2446:                 throw new InvalidArgumentException('Only simple domain name parts can be handled in strict mode');
2447:             }
2448: 
2449:             $parsed = parse_url($input);
2450:             if (isset($parsed['host'])) {
2451:                 $arr = explode('.', $parsed['host']);
2452:                 foreach ($arr as $k => $v) {
2453:                     $conv = $this->_decode($v);
2454:                     if ($conv) $arr[$k] = $conv;
2455:                 }
2456:                 $parsed['host'] = join('.', $arr);
2457:                 if (isset($parsed['scheme'])) {
2458:                     $parsed['scheme'] .= (strtolower($parsed['scheme']) == 'mailto') ? ':' : '://';
2459:                 }
2460:                 $return = $this->_unparse_url($parsed);
2461:             } else { // parse_url seems to have failed, try without it
2462:                 $arr = explode('.', $input);
2463:                 foreach ($arr as $k => $v) {
2464:                     $conv = $this->_decode($v);
2465:                     if ($conv) $arr[$k] = $conv;
2466:                 }
2467:                 $return = join('.', $arr);
2468:             }
2469:         } else { // Otherwise we consider it being a pure domain name string
2470:             $return = $this->_decode($input);
2471:         }
2472:         // The output is UTF-8 by default, other output formats need conversion here
2473:         // If one time encoding is given, use this, else the objects property
2474:         switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) {
2475:         case 'utf8':
2476:             return $return;
2477:             break;
2478:         case 'ucs4_string':
2479:             return $this->_ucs4_to_ucs4_string($this->_utf8_to_ucs4($return));
2480:             break;
2481:         case 'ucs4_array':
2482:             return $this->_utf8_to_ucs4($return);
2483:             break;
2484:         default:
2485:             throw new InvalidArgumentException('Unsupported output format');
2486:         }
2487:     }
2488: 
2489: 
2490:     // {{{ private
2491:     /**
2492:      * Opposite function to parse_url()
2493:      *
2494:      * Inspired by code from comments of php.net-documentation for parse_url()
2495:      *
2496:      * @param array $parts_arr parts (strings) as returned by parse_url()
2497:      *
2498:      * @return string
2499:      * @access private
2500:      */
2501:     private function _unparse_url($parts_arr)
2502:     {
2503:         if (!empty($parts_arr['scheme'])) {
2504:             $ret_url = $parts_arr['scheme'];
2505:         }
2506:         if (!empty($parts_arr['user'])) {
2507:             $ret_url .= $parts_arr['user'];
2508:             if (!empty($parts_arr['pass'])) {
2509:                 $ret_url .= ':' . $parts_arr['pass'];
2510:             }
2511:             $ret_url .= '@';
2512:         }
2513:         $ret_url .= $parts_arr['host'];
2514:         if (!empty($parts_arr['port'])) {
2515:             $ret_url .= ':' . $parts_arr['port'];
2516:         }
2517:         $ret_url .= $parts_arr['path'];
2518:         if (!empty($parts_arr['query'])) {
2519:             $ret_url .= '?' . $parts_arr['query'];
2520:         }
2521:         if (!empty($parts_arr['fragment'])) {
2522:             $ret_url .= '#' . $parts_arr['fragment'];
2523:         }
2524:         return $ret_url;
2525:     }
2526: 
2527:     /**
2528:      * The actual encoding algorithm.
2529:      *
2530:      * @param string $decoded Decoded string which should be encoded
2531:      *
2532:      * @return string         Encoded string
2533:      * @throws Exception
2534:      * @access private
2535:      */
2536:     private function _encode($decoded)
2537:     {
2538:         // We cannot encode a domain name containing the Punycode prefix
2539:         $extract = self::_byteLength($this->_punycode_prefix);
2540:         $check_pref = $this->_utf8_to_ucs4($this->_punycode_prefix);
2541:         $check_deco = array_slice($decoded, 0, $extract);
2542: 
2543:         if ($check_pref == $check_deco) {
2544:             throw new InvalidArgumentException('This is already a punycode string');
2545:         }
2546: 
2547:         // We will not try to encode strings consisting of basic code points only
2548:         $encodable = false;
2549:         foreach ($decoded as $k => $v) {
2550:             if ($v > 0x7a) {
2551:                 $encodable = true;
2552:                 break;
2553:             }
2554:         }
2555:         if (!$encodable) {
2556:             if ($this->_strict_mode) {
2557:                 throw new InvalidArgumentException('The given string does not contain encodable chars');
2558:             }
2559: 
2560:             return false;
2561:         }
2562: 
2563:         // Do NAMEPREP
2564:         $decoded = $this->_nameprep($decoded);
2565: 
2566:         $deco_len = count($decoded);
2567: 
2568:         // Empty array
2569:         if (!$deco_len) {
2570:             return false;
2571:         }
2572: 
2573:         // How many chars have been consumed
2574:         $codecount = 0;
2575: 
2576:         // Start with the prefix; copy it to output
2577:         $encoded = $this->_punycode_prefix;
2578: 
2579:         $encoded = '';
2580:         // Copy all basic code points to output
2581:         for ($i = 0; $i < $deco_len; ++$i) {
2582:             $test = $decoded[$i];
2583:             // Will match [0-9a-zA-Z-]
2584:             if ((0x2F < $test && $test < 0x40)
2585:                 || (0x40 < $test && $test < 0x5B)
2586:                 || (0x60 < $test && $test <= 0x7B)
2587:                 || (0x2D == $test)
2588:             ) {
2589:                 $encoded .= chr($decoded[$i]);
2590:                 $codecount++;
2591:             }
2592:         }
2593: 
2594:         // All codepoints were basic ones
2595:         if ($codecount == $deco_len) {
2596:             return $encoded;
2597:         }
2598: 
2599:         // Start with the prefix; copy it to output
2600:         $encoded = $this->_punycode_prefix . $encoded;
2601: 
2602:         // If we have basic code points in output, add an hyphen to the end
2603:         if ($codecount) {
2604:             $encoded .= '-';
2605:         }
2606: 
2607:         // Now find and encode all non-basic code points
2608:         $is_first  = true;
2609:         $cur_code  = $this->_initial_n;
2610:         $bias      = $this->_initial_bias;
2611:         $delta     = 0;
2612: 
2613:         while ($codecount < $deco_len) {
2614:             // Find the smallest code point >= the current code point and
2615:             // remember the last ouccrence of it in the input
2616:             for ($i = 0, $next_code = $this->_max_ucs; $i < $deco_len; $i++) {
2617:                 if ($decoded[$i] >= $cur_code && $decoded[$i] <= $next_code) {
2618:                     $next_code = $decoded[$i];
2619:                 }
2620:             }
2621: 
2622:             $delta += ($next_code - $cur_code) * ($codecount + 1);
2623:             $cur_code = $next_code;
2624: 
2625:             // Scan input again and encode all characters whose code point is $cur_code
2626:             for ($i = 0; $i < $deco_len; $i++) {
2627:                 if ($decoded[$i] < $cur_code) {
2628:                     $delta++;
2629:                 } else if ($decoded[$i] == $cur_code) {
2630:                     for ($q = $delta, $k = $this->_base; 1; $k += $this->_base) {
2631:                         $t = ($k <= $bias)?
2632:                             $this->_tmin :
2633:                             (($k >= $bias + $this->_tmax)? $this->_tmax : $k - $bias);
2634: 
2635:                         if ($q < $t) {
2636:                             break;
2637:                         }
2638: 
2639:                         $encoded .= $this->_encodeDigit(ceil($t + (($q - $t) % ($this->_base - $t))));
2640:                         $q = ($q - $t) / ($this->_base - $t);
2641:                     }
2642: 
2643:                     $encoded .= $this->_encodeDigit($q);
2644:                     $bias = $this->_adapt($delta, $codecount + 1, $is_first);
2645:                     $codecount++;
2646:                     $delta = 0;
2647:                     $is_first = false;
2648:                 }
2649:             }
2650: 
2651:             $delta++;
2652:             $cur_code++;
2653:         }
2654: 
2655:         return $encoded;
2656:     }
2657: 
2658:     /**
2659:      * The actual decoding algorithm.
2660:      *
2661:      * @param string $encoded Encoded string which should be decoded
2662:      *
2663:      * @return string         Decoded string
2664:      * @throws Exception
2665:      * @access private
2666:      */
2667:     private function _decode($encoded)
2668:     {
2669:         // We do need to find the Punycode prefix
2670:         if (!preg_match('!^' . preg_quote($this->_punycode_prefix, '!') . '!', $encoded)) {
2671:             return false;
2672:         }
2673: 
2674:         $encode_test = preg_replace('!^' . preg_quote($this->_punycode_prefix, '!') . '!', '', $encoded);
2675: 
2676:         // If nothing left after removing the prefix, it is hopeless
2677:         if (!$encode_test) {
2678:             return false;
2679:         }
2680: 
2681:         // Find last occurence of the delimiter
2682:         $delim_pos = strrpos($encoded, '-');
2683: 
2684:         if ($delim_pos > self::_byteLength($this->_punycode_prefix)) {
2685:             for ($k = self::_byteLength($this->_punycode_prefix); $k < $delim_pos; ++$k) {
2686:                 $decoded[] = ord($encoded{$k});
2687:             }
2688:         } else {
2689:             $decoded = array();
2690:         }
2691: 
2692:         $deco_len = count($decoded);
2693:         $enco_len = self::_byteLength($encoded);
2694: 
2695:         // Wandering through the strings; init
2696:         $is_first = true;
2697:         $bias     = $this->_initial_bias;
2698:         $idx      = 0;
2699:         $char     = $this->_initial_n;
2700: 
2701:         for ($enco_idx = ($delim_pos)? ($delim_pos + 1) : 0; $enco_idx < $enco_len; ++$deco_len) {
2702:             for ($old_idx = $idx, $w = 1, $k = $this->_base; 1 ; $k += $this->_base) {
2703:                 $digit = $this->_decodeDigit($encoded{$enco_idx++});
2704:                 $idx += $digit * $w;
2705: 
2706:                 $t = ($k <= $bias) ?
2707:                     $this->_tmin :
2708:                     (($k >= $bias + $this->_tmax)? $this->_tmax : ($k - $bias));
2709: 
2710:                 if ($digit < $t) {
2711:                     break;
2712:                 }
2713: 
2714:                 $w = (int)($w * ($this->_base - $t));
2715:             }
2716: 
2717:             $bias      = $this->_adapt($idx - $old_idx, $deco_len + 1, $is_first);
2718:             $is_first  = false;
2719:             $char     += (int) ($idx / ($deco_len + 1));
2720:             $idx      %= ($deco_len + 1);
2721: 
2722:             if ($deco_len > 0) {
2723:                 // Make room for the decoded char
2724:                 for ($i = $deco_len; $i > $idx; $i--) {
2725:                     $decoded[$i] = $decoded[($i - 1)];
2726:                 }
2727:             }
2728: 
2729:             $decoded[$idx++] = $char;
2730:         }
2731: 
2732:         return $this->_ucs4_to_utf8($decoded);
2733:     }
2734: 
2735:     /**
2736:      * Adapt the bias according to the current code point and position.
2737:      *
2738:      * @param int     $delta    ...
2739:      * @param int     $npoints  ...
2740:      * @param boolean $is_first ...
2741:      *
2742:      * @return int
2743:      * @access private
2744:      */
2745:     private function _adapt($delta, $npoints, $is_first)
2746:     {
2747:         $delta = (int) ($is_first ? ($delta / $this->_damp) : ($delta / 2));
2748:         $delta += (int) ($delta / $npoints);
2749: 
2750:         for ($k = 0; $delta > (($this->_base - $this->_tmin) * $this->_tmax) / 2; $k += $this->_base) {
2751:             $delta = (int) ($delta / ($this->_base - $this->_tmin));
2752:         }
2753: 
2754:         return (int) ($k + ($this->_base - $this->_tmin + 1) * $delta / ($delta + $this->_skew));
2755:     }
2756: 
2757:     /**
2758:      * Encoding a certain digit.
2759:      *
2760:      * @param int $d One digit to encode
2761:      *
2762:      * @return char  Encoded digit
2763:      * @access private
2764:      */
2765:     private function _encodeDigit($d)
2766:     {
2767:         return chr($d + 22 + 75 * ($d < 26));
2768:     }
2769: 
2770:     /**
2771:      * Decode a certain digit.
2772:      *
2773:      * @param char $cp One digit (character) to decode
2774:      *
2775:      * @return int     Decoded digit
2776:      * @access private
2777:      */
2778:     private function _decodeDigit($cp)
2779:     {
2780:         $cp = ord($cp);
2781:         return ($cp - 48 < 10)? $cp - 22 : (($cp - 65 < 26)? $cp - 65 : (($cp - 97 < 26)? $cp - 97 : $this->_base));
2782:     }
2783: 
2784:     /**
2785:      * Do Nameprep according to RFC3491 and RFC3454.
2786:      *
2787:      * @param array $input Unicode Characters
2788:      *
2789:      * @return string      Unicode Characters, Nameprep'd
2790:      * @throws Exception
2791:      * @access private
2792:      */
2793:     private function _nameprep($input)
2794:     {
2795:         $output = array();
2796: 
2797:         // Walking through the input array, performing the required steps on each of
2798:         // the input chars and putting the result into the output array
2799:         // While mapping required chars we apply the cannonical ordering
2800: 
2801:         foreach ($input as $v) {
2802:             // Map to nothing == skip that code point
2803:             if (in_array($v, self::$_np_map_nothing)) {
2804:                 continue;
2805:             }
2806: 
2807:             // Try to find prohibited input
2808:             if (in_array($v, self::$_np_prohibit) || in_array($v, self::$_general_prohibited)) {
2809:                 throw new Net_IDNA2_Exception_Nameprep('Prohibited input U+' . sprintf('%08X', $v));
2810:             }
2811: 
2812:             foreach (self::$_np_prohibit_ranges as $range) {
2813:                 if ($range[0] <= $v && $v <= $range[1]) {
2814:                     throw new Net_IDNA2_Exception_Nameprep('Prohibited input U+' . sprintf('%08X', $v));
2815:                 }
2816:             }
2817: 
2818:             // Hangul syllable decomposition
2819:             if (0xAC00 <= $v && $v <= 0xD7AF) {
2820:                 foreach ($this->_hangulDecompose($v) as $out) {
2821:                     $output[] = $out;
2822:                 }
2823:             } else if (($this->_version == '2003') && isset(self::$_np_replacemaps[$v])) {
2824:                 // There's a decomposition mapping for that code point
2825:                 // Decompositions only in version 2003 (original) of IDNA
2826:                 foreach ($this->_applyCannonicalOrdering(self::$_np_replacemaps[$v]) as $out) {
2827:                     $output[] = $out;
2828:                 }
2829:             } else {
2830:                 $output[] = $v;
2831:             }
2832:         }
2833: 
2834:         // Combine code points
2835: 
2836:         $last_class   = 0;
2837:         $last_starter = 0;
2838:         $out_len      = count($output);
2839: 
2840:         for ($i = 0; $i < $out_len; ++$i) {
2841:             $class = $this->_getCombiningClass($output[$i]);
2842: 
2843:             if ((!$last_class || $last_class != $class) && $class) {
2844:                 // Try to match
2845:                 $seq_len = $i - $last_starter;
2846:                 $out = $this->_combine(array_slice($output, $last_starter, $seq_len));
2847: 
2848:                 // On match: Replace the last starter with the composed character and remove
2849:                 // the now redundant non-starter(s)
2850:                 if ($out) {
2851:                     $output[$last_starter] = $out;
2852: 
2853:                     if (count($out) != $seq_len) {
2854:                         for ($j = $i + 1; $j < $out_len; ++$j) {
2855:                             $output[$j - 1] = $output[$j];
2856:                         }
2857: 
2858:                         unset($output[$out_len]);
2859:                     }
2860: 
2861:                     // Rewind the for loop by one, since there can be more possible compositions
2862:                     $i--;
2863:                     $out_len--;
2864:                     $last_class = ($i == $last_starter)? 0 : $this->_getCombiningClass($output[$i - 1]);
2865: 
2866:                     continue;
2867:                 }
2868:             }
2869: 
2870:             // The current class is 0
2871:             if (!$class) {
2872:                 $last_starter = $i;
2873:             }
2874: 
2875:             $last_class = $class;
2876:         }
2877: 
2878:         return $output;
2879:     }
2880: 
2881:     /**
2882:      * Decomposes a Hangul syllable
2883:      * (see http://www.unicode.org/unicode/reports/tr15/#Hangul).
2884:      *
2885:      * @param integer $char 32bit UCS4 code point
2886:      *
2887:      * @return array        Either Hangul Syllable decomposed or original 32bit
2888:      *                      value as one value array
2889:      * @access private
2890:      */
2891:     private function _hangulDecompose($char)
2892:     {
2893:         $sindex = $char - $this->_sbase;
2894: 
2895:         if ($sindex < 0 || $sindex >= $this->_scount) {
2896:             return array($char);
2897:         }
2898: 
2899:         $result   = array();
2900:         $T        = $this->_tbase + $sindex % $this->_tcount;
2901:         $result[] = (int)($this->_lbase +  $sindex / $this->_ncount);
2902:         $result[] = (int)($this->_vbase + ($sindex % $this->_ncount) / $this->_tcount);
2903: 
2904:         if ($T != $this->_tbase) {
2905:             $result[] = $T;
2906:         }
2907: 
2908:         return $result;
2909:     }
2910: 
2911:     /**
2912:      * Ccomposes a Hangul syllable
2913:      * (see http://www.unicode.org/unicode/reports/tr15/#Hangul).
2914:      *
2915:      * @param array $input Decomposed UCS4 sequence
2916:      *
2917:      * @return array       UCS4 sequence with syllables composed
2918:      * @access private
2919:      */
2920:     private function _hangulCompose($input)
2921:     {
2922:         $inp_len = count($input);
2923: 
2924:         if (!$inp_len) {
2925:             return array();
2926:         }
2927: 
2928:         $result   = array();
2929:         $last     = $input[0];
2930:         $result[] = $last; // copy first char from input to output
2931: 
2932:         for ($i = 1; $i < $inp_len; ++$i) {
2933:             $char = $input[$i];
2934: 
2935:             // Find out, wether two current characters from L and V
2936:             $lindex = $last - $this->_lbase;
2937: 
2938:             if (0 <= $lindex && $lindex < $this->_lcount) {
2939:                 $vindex = $char - $this->_vbase;
2940: 
2941:                 if (0 <= $vindex && $vindex < $this->_vcount) {
2942:                     // create syllable of form LV
2943:                     $last    = ($this->_sbase + ($lindex * $this->_vcount + $vindex) * $this->_tcount);
2944:                     $out_off = count($result) - 1;
2945:                     $result[$out_off] = $last; // reset last
2946: 
2947:                     // discard char
2948:                     continue;
2949:                 }
2950:             }
2951: 
2952:             // Find out, wether two current characters are LV and T
2953:             $sindex = $last - $this->_sbase;
2954: 
2955:             if (0 <= $sindex && $sindex < $this->_scount && ($sindex % $this->_tcount) == 0) {
2956:                 $tindex = $char - $this->_tbase;
2957: 
2958:                 if (0 <= $tindex && $tindex <= $this->_tcount) {
2959:                     // create syllable of form LVT
2960:                     $last += $tindex;
2961:                     $out_off = count($result) - 1;
2962:                     $result[$out_off] = $last; // reset last
2963: 
2964:                     // discard char
2965:                     continue;
2966:                 }
2967:             }
2968: 
2969:             // if neither case was true, just add the character
2970:             $last = $char;
2971:             $result[] = $char;
2972:         }
2973: 
2974:         return $result;
2975:     }
2976: 
2977:     /**
2978:      * Returns the combining class of a certain wide char.
2979:      *
2980:      * @param integer $char Wide char to check (32bit integer)
2981:      *
2982:      * @return integer      Combining class if found, else 0
2983:      * @access private
2984:      */
2985:     private function _getCombiningClass($char)
2986:     {
2987:         return isset(self::$_np_norm_combcls[$char])? self::$_np_norm_combcls[$char] : 0;
2988:     }
2989: 
2990:     /**
2991:      * Apllies the cannonical ordering of a decomposed UCS4 sequence.
2992:      *
2993:      * @param array $input Decomposed UCS4 sequence
2994:      *
2995:      * @return array       Ordered USC4 sequence
2996:      * @access private
2997:      */
2998:     private function _applyCannonicalOrdering($input)
2999:     {
3000:         $swap = true;
3001:         $size = count($input);
3002: 
3003:         while ($swap) {
3004:             $swap = false;
3005:             $last = $this->_getCombiningClass($input[0]);
3006: 
3007:             for ($i = 0; $i < $size - 1; ++$i) {
3008:                 $next = $this->_getCombiningClass($input[$i + 1]);
3009: 
3010:                 if ($next != 0 && $last > $next) {
3011:                     // Move item leftward until it fits
3012:                     for ($j = $i + 1; $j > 0; --$j) {
3013:                         if ($this->_getCombiningClass($input[$j - 1]) <= $next) {
3014:                             break;
3015:                         }
3016: 
3017:                         $t = $input[$j];
3018:                         $input[$j] = $input[$j - 1];
3019:                         $input[$j - 1] = $t;
3020:                         $swap = 1;
3021:                     }
3022: 
3023:                     // Reentering the loop looking at the old character again
3024:                     $next = $last;
3025:                 }
3026: 
3027:                 $last = $next;
3028:             }
3029:         }
3030: 
3031:         return $input;
3032:     }
3033: 
3034:     /**
3035:      * Do composition of a sequence of starter and non-starter.
3036:      *
3037:      * @param array $input UCS4 Decomposed sequence
3038:      *
3039:      * @return array       Ordered USC4 sequence
3040:      * @access private
3041:      */
3042:     private function _combine($input)
3043:     {
3044:         $inp_len = count($input);
3045: 
3046:         // Is it a Hangul syllable?
3047:         if (1 != $inp_len) {
3048:             $hangul = $this->_hangulCompose($input);
3049: 
3050:             // This place is probably wrong
3051:             if (count($hangul) != $inp_len) {
3052:                 return $hangul;
3053:             }
3054:         }
3055: 
3056:         foreach (self::$_np_replacemaps as $np_src => $np_target) {
3057:             if ($np_target[0] != $input[0]) {
3058:                 continue;
3059:             }
3060: 
3061:             if (count($np_target) != $inp_len) {
3062:                 continue;
3063:             }
3064: 
3065:             $hit = false;
3066: 
3067:             foreach ($input as $k2 => $v2) {
3068:                 if ($v2 == $np_target[$k2]) {
3069:                     $hit = true;
3070:                 } else {
3071:                     $hit = false;
3072:                     break;
3073:                 }
3074:             }
3075: 
3076:             if ($hit) {
3077:                 return $np_src;
3078:             }
3079:         }
3080: 
3081:         return false;
3082:     }
3083: 
3084:     /**
3085:      * This converts an UTF-8 encoded string to its UCS-4 (array) representation
3086:      * By talking about UCS-4 we mean arrays of 32bit integers representing
3087:      * each of the "chars". This is due to PHP not being able to handle strings with
3088:      * bit depth different from 8. This applies to the reverse method _ucs4_to_utf8(), too.
3089:      * The following UTF-8 encodings are supported:
3090:      *
3091:      * bytes bits  representation
3092:      * 1        7  0xxxxxxx
3093:      * 2       11  110xxxxx 10xxxxxx
3094:      * 3       16  1110xxxx 10xxxxxx 10xxxxxx
3095:      * 4       21  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
3096:      * 5       26  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
3097:      * 6       31  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
3098:      *
3099:      * Each x represents a bit that can be used to store character data.
3100:      *
3101:      * @param string $input utf8-encoded string
3102:      *
3103:      * @return array        ucs4-encoded array
3104:      * @throws Exception
3105:      * @access private
3106:      */
3107:     private function _utf8_to_ucs4($input)
3108:     {
3109:         $output = array();
3110:         $out_len = 0;
3111:         $inp_len = self::_byteLength($input, '8bit');
3112:         $mode = 'next';
3113:         $test = 'none';
3114:         for ($k = 0; $k < $inp_len; ++$k) {
3115:             $v = ord($input{$k}); // Extract byte from input string
3116: 
3117:             if ($v < 128) { // We found an ASCII char - put into stirng as is
3118:                 $output[$out_len] = $v;
3119:                 ++$out_len;
3120:                 if ('add' == $mode) {
3121:                     throw new UnexpectedValueException('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k);
3122:                 }
3123:                 continue;
3124:             }
3125:             if ('next' == $mode) { // Try to find the next start byte; determine the width of the Unicode char
3126:                 $start_byte = $v;
3127:                 $mode = 'add';
3128:                 $test = 'range';
3129:                 if ($v >> 5 == 6) { // &110xxxxx 10xxxxx
3130:                     $next_byte = 0; // Tells, how many times subsequent bitmasks must rotate 6bits to the left
3131:                     $v = ($v - 192) << 6;
3132:                 } elseif ($v >> 4 == 14) { // &1110xxxx 10xxxxxx 10xxxxxx
3133:                     $next_byte = 1;
3134:                     $v = ($v - 224) << 12;
3135:                 } elseif ($v >> 3 == 30) { // &11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
3136:                     $next_byte = 2;
3137:                     $v = ($v - 240) << 18;
3138:                 } elseif ($v >> 2 == 62) { // &111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
3139:                     $next_byte = 3;
3140:                     $v = ($v - 248) << 24;
3141:                 } elseif ($v >> 1 == 126) { // &1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
3142:                     $next_byte = 4;
3143:                     $v = ($v - 252) << 30;
3144:                 } else {
3145:                     throw new UnexpectedValueException('This might be UTF-8, but I don\'t understand it at byte '.$k);
3146:                 }
3147:                 if ('add' == $mode) {
3148:                     $output[$out_len] = (int) $v;
3149:                     ++$out_len;
3150:                     continue;
3151:                 }
3152:             }
3153:             if ('add' == $mode) {
3154:                 if (!$this->_allow_overlong && $test == 'range') {
3155:                     $test = 'none';
3156:                     if (($v < 0xA0 && $start_byte == 0xE0) || ($v < 0x90 && $start_byte == 0xF0) || ($v > 0x8F && $start_byte == 0xF4)) {
3157:                         throw new OutOfRangeException('Bogus UTF-8 character detected (out of legal range) at byte '.$k);
3158:                     }
3159:                 }
3160:                 if ($v >> 6 == 2) { // Bit mask must be 10xxxxxx
3161:                     $v = ($v - 128) << ($next_byte * 6);
3162:                     $output[($out_len - 1)] += $v;
3163:                     --$next_byte;
3164:                 } else {
3165:                     throw new UnexpectedValueException('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k);
3166:                 }
3167:                 if ($next_byte < 0) {
3168:                     $mode = 'next';
3169:                 }
3170:             }
3171:         } // for
3172:         return $output;
3173:     }
3174: 
3175:     /**
3176:      * Convert UCS-4 array into UTF-8 string
3177:      *
3178:      * @param array $input ucs4-encoded array
3179:      *
3180:      * @return string      utf8-encoded string
3181:      * @throws Exception
3182:      * @access private
3183:      */
3184:     private function _ucs4_to_utf8($input)
3185:     {
3186:         $output = '';
3187: 
3188:         foreach ($input as $v) {
3189:             // $v = ord($v);
3190: 
3191:             if ($v < 128) {
3192:                 // 7bit are transferred literally
3193:                 $output .= chr($v);
3194:             } else if ($v < 1 << 11) {
3195:                 // 2 bytes
3196:                 $output .= chr(192 + ($v >> 6))
3197:                     . chr(128 + ($v & 63));
3198:             } else if ($v < 1 << 16) {
3199:                 // 3 bytes
3200:                 $output .= chr(224 + ($v >> 12))
3201:                     . chr(128 + (($v >> 6) & 63))
3202:                     . chr(128 + ($v & 63));
3203:             } else if ($v < 1 << 21) {
3204:                 // 4 bytes
3205:                 $output .= chr(240 + ($v >> 18))
3206:                     . chr(128 + (($v >> 12) & 63))
3207:                     . chr(128 + (($v >>  6) & 63))
3208:                     . chr(128 + ($v & 63));
3209:             } else if ($v < 1 << 26) {
3210:                 // 5 bytes
3211:                 $output .= chr(248 + ($v >> 24))
3212:                     . chr(128 + (($v >> 18) & 63))
3213:                     . chr(128 + (($v >> 12) & 63))
3214:                     . chr(128 + (($v >>  6) & 63))
3215:                     . chr(128 + ($v & 63));
3216:             } else if ($v < 1 << 31) {
3217:                 // 6 bytes
3218:                 $output .= chr(252 + ($v >> 30))
3219:                     . chr(128 + (($v >> 24) & 63))
3220:                     . chr(128 + (($v >> 18) & 63))
3221:                     . chr(128 + (($v >> 12) & 63))
3222:                     . chr(128 + (($v >>  6) & 63))
3223:                     . chr(128 + ($v & 63));
3224:             } else {
3225:                 throw new UnexpectedValueException('Conversion from UCS-4 to UTF-8 failed: malformed input');
3226:             }
3227:         }
3228: 
3229:         return $output;
3230:     }
3231: 
3232:     /**
3233:      * Convert UCS-4 array into UCS-4 string
3234:      *
3235:      * @param array $input ucs4-encoded array
3236:      *
3237:      * @return string      ucs4-encoded string
3238:      * @throws Exception
3239:      * @access private
3240:      */
3241:     private function _ucs4_to_ucs4_string($input)
3242:     {
3243:         $output = '';
3244:         // Take array values and split output to 4 bytes per value
3245:         // The bit mask is 255, which reads &11111111
3246:         foreach ($input as $v) {
3247:             $output .= ($v & (255 << 24) >> 24) . ($v & (255 << 16) >> 16) . ($v & (255 << 8) >> 8) . ($v & 255);
3248:         }
3249:         return $output;
3250:     }
3251: 
3252:     /**
3253:      * Convert UCS-4 string into UCS-4 array
3254:      *
3255:      * @param string $input ucs4-encoded string
3256:      *
3257:      * @return array        ucs4-encoded array
3258:      * @throws InvalidArgumentException
3259:      * @access private
3260:      */
3261:     private function _ucs4_string_to_ucs4($input)
3262:     {
3263:         $output = array();
3264: 
3265:         $inp_len = self::_byteLength($input);
3266:         // Input length must be dividable by 4
3267:         if ($inp_len % 4) {
3268:             throw new InvalidArgumentException('Input UCS4 string is broken');
3269:         }
3270: 
3271:         // Empty input - return empty output
3272:         if (!$inp_len) {
3273:             return $output;
3274:         }
3275: 
3276:         for ($i = 0, $out_len = -1; $i < $inp_len; ++$i) {
3277:             // Increment output position every 4 input bytes
3278:             if (!$i % 4) {
3279:                 $out_len++;
3280:                 $output[$out_len] = 0;
3281:             }
3282:             $output[$out_len] += ord($input{$i}) << (8 * (3 - ($i % 4) ) );
3283:         }
3284:         return $output;
3285:     }
3286: 
3287:     /**
3288:      * Echo hex representation of UCS4 sequence.
3289:      *
3290:      * @param array   $input       UCS4 sequence
3291:      * @param boolean $include_bit Include bitmask in output
3292:      *
3293:      * @return void
3294:      * @static
3295:      * @access private
3296:      */
3297:     private static function _showHex($input, $include_bit = false)
3298:     {
3299:         foreach ($input as $k => $v) {
3300:             echo '[', $k, '] => ', sprintf('%X', $v);
3301: 
3302:             if ($include_bit) {
3303:                 echo ' (', Net_IDNA2::_showBitmask($v), ')';
3304:             }
3305: 
3306:             echo "\n";
3307:         }
3308:     }
3309: 
3310:     /**
3311:      * Gives you a bit representation of given Byte (8 bits), Word (16 bits) or DWord (32 bits)
3312:      * Output width is automagically determined
3313:      *
3314:      * @param int $octet ...
3315:      *
3316:      * @return string    Bitmask-representation
3317:      * @static
3318:      * @access private
3319:      */
3320:     private static function _showBitmask($octet)
3321:     {
3322:         if ($octet >= (1 << 16)) {
3323:             $w = 31;
3324:         } else if ($octet >= (1 << 8)) {
3325:             $w = 15;
3326:         } else {
3327:             $w = 7;
3328:         }
3329: 
3330:         $return = '';
3331: 
3332:         for ($i = $w; $i > -1; $i--) {
3333:             $return .= ($octet & (1 << $i))? '1' : '0';
3334:         }
3335: 
3336:         return $return;
3337:     }
3338: 
3339:     /**
3340:      * Gets the length of a string in bytes even if mbstring function
3341:      * overloading is turned on
3342:      *
3343:      * @param string $string the string for which to get the length.
3344:      *
3345:      * @return integer the length of the string in bytes.
3346:      *
3347:      * @see Net_IDNA2::$_mb_string_overload
3348:      */
3349:     private static function _byteLength($string)
3350:     {
3351:         if (self::$_mb_string_overload) {
3352:             return mb_strlen($string, '8bit');
3353:         }
3354:         return strlen((binary)$string);
3355:     }
3356: 
3357:     // }}}}
3358: 
3359:     // {{{ factory
3360:     /**
3361:      * Attempts to return a concrete IDNA instance for either php4 or php5.
3362:      *
3363:      * @param array $params Set of paramaters
3364:      *
3365:      * @return Net_IDNA2
3366:      * @access public
3367:      */
3368:     function getInstance($params = array())
3369:     {
3370:         return new Net_IDNA2($params);
3371:     }
3372:     // }}}
3373: 
3374:     // {{{ singleton
3375:     /**
3376:      * Attempts to return a concrete IDNA instance for either php4 or php5,
3377:      * only creating a new instance if no IDNA instance with the same
3378:      * parameters currently exists.
3379:      *
3380:      * @param array $params Set of paramaters
3381:      *
3382:      * @return object Net_IDNA2
3383:      * @access public
3384:      */
3385:     function singleton($params = array())
3386:     {
3387:         static $instances;
3388:         if (!isset($instances)) {
3389:             $instances = array();
3390:         }
3391: 
3392:         $signature = serialize($params);
3393:         if (!isset($instances[$signature])) {
3394:             $instances[$signature] = Net_IDNA2::getInstance($params);
3395:         }
3396: 
3397:         return $instances[$signature];
3398:     }
3399:     // }}}
3400: }
3401: 
3402: ?>
3403: 
API documentation generated by ApiGen 2.8.0