IDNA2.php 102 KB

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