LCOV - code coverage report
Current view: top level - gfx/harfbuzz/src - hb-ot-tag.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 43 133 32.3 %
Date: 2017-07-14 16:53:18 Functions: 7 10 70.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright © 2009  Red Hat, Inc.
       3             :  * Copyright © 2011  Google, Inc.
       4             :  *
       5             :  *  This is part of HarfBuzz, a text shaping library.
       6             :  *
       7             :  * Permission is hereby granted, without written agreement and without
       8             :  * license or royalty fees, to use, copy, modify, and distribute this
       9             :  * software and its documentation for any purpose, provided that the
      10             :  * above copyright notice and the following two paragraphs appear in
      11             :  * all copies of this software.
      12             :  *
      13             :  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
      14             :  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
      15             :  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
      16             :  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
      17             :  * DAMAGE.
      18             :  *
      19             :  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
      20             :  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
      21             :  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
      22             :  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
      23             :  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
      24             :  *
      25             :  * Red Hat Author(s): Behdad Esfahbod
      26             :  * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
      27             :  */
      28             : 
      29             : #include "hb-private.hh"
      30             : 
      31             : 
      32             : /* hb_script_t */
      33             : 
      34             : static hb_tag_t
      35         348 : hb_ot_old_tag_from_script (hb_script_t script)
      36             : {
      37             :   /* This seems to be accurate as of end of 2012. */
      38             : 
      39         348 :   switch ((hb_tag_t) script) {
      40           0 :     case HB_SCRIPT_INVALID:             return HB_OT_TAG_DEFAULT_SCRIPT;
      41             : 
      42             :     /* KATAKANA and HIRAGANA both map to 'kana' */
      43           2 :     case HB_SCRIPT_HIRAGANA:            return HB_TAG('k','a','n','a');
      44             : 
      45             :     /* Spaces at the end are preserved, unlike ISO 15924 */
      46           2 :     case HB_SCRIPT_LAO:                 return HB_TAG('l','a','o',' ');
      47           2 :     case HB_SCRIPT_YI:                  return HB_TAG('y','i',' ',' ');
      48             :     /* Unicode-5.0 additions */
      49           2 :     case HB_SCRIPT_NKO:                 return HB_TAG('n','k','o',' ');
      50             :     /* Unicode-5.1 additions */
      51           2 :     case HB_SCRIPT_VAI:                 return HB_TAG('v','a','i',' ');
      52             :     /* Unicode-5.2 additions */
      53             :     /* Unicode-6.0 additions */
      54             :   }
      55             : 
      56             :   /* Else, just change first char to lowercase and return */
      57         338 :   return ((hb_tag_t) script) | 0x20000000u;
      58             : }
      59             : 
      60             : static hb_script_t
      61           3 : hb_ot_old_tag_to_script (hb_tag_t tag)
      62             : {
      63           3 :   if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT))
      64           0 :     return HB_SCRIPT_INVALID;
      65             : 
      66             :   /* This side of the conversion is fully algorithmic. */
      67             : 
      68             :   /* Any spaces at the end of the tag are replaced by repeating the last
      69             :    * letter.  Eg 'nko ' -> 'Nkoo' */
      70           3 :   if (unlikely ((tag & 0x0000FF00u) == 0x00002000u))
      71           0 :     tag |= (tag >> 8) & 0x0000FF00u; /* Copy second letter to third */
      72           3 :   if (unlikely ((tag & 0x000000FFu) == 0x00000020u))
      73           0 :     tag |= (tag >> 8) & 0x000000FFu; /* Copy third letter to fourth */
      74             : 
      75             :   /* Change first char to uppercase and return */
      76           3 :   return (hb_script_t) (tag & ~0x20000000u);
      77             : }
      78             : 
      79             : static hb_tag_t
      80         348 : hb_ot_new_tag_from_script (hb_script_t script)
      81             : {
      82         348 :   switch ((hb_tag_t) script) {
      83           2 :     case HB_SCRIPT_BENGALI:             return HB_TAG('b','n','g','2');
      84           2 :     case HB_SCRIPT_DEVANAGARI:          return HB_TAG('d','e','v','2');
      85           2 :     case HB_SCRIPT_GUJARATI:            return HB_TAG('g','j','r','2');
      86           2 :     case HB_SCRIPT_GURMUKHI:            return HB_TAG('g','u','r','2');
      87           2 :     case HB_SCRIPT_KANNADA:             return HB_TAG('k','n','d','2');
      88           2 :     case HB_SCRIPT_MALAYALAM:           return HB_TAG('m','l','m','2');
      89           2 :     case HB_SCRIPT_ORIYA:               return HB_TAG('o','r','y','2');
      90           2 :     case HB_SCRIPT_TAMIL:               return HB_TAG('t','m','l','2');
      91           2 :     case HB_SCRIPT_TELUGU:              return HB_TAG('t','e','l','2');
      92           2 :     case HB_SCRIPT_MYANMAR:             return HB_TAG('m','y','m','2');
      93             :   }
      94             : 
      95         328 :   return HB_OT_TAG_DEFAULT_SCRIPT;
      96             : }
      97             : 
      98             : static hb_script_t
      99           0 : hb_ot_new_tag_to_script (hb_tag_t tag)
     100             : {
     101           0 :   switch (tag) {
     102           0 :     case HB_TAG('b','n','g','2'):       return HB_SCRIPT_BENGALI;
     103           0 :     case HB_TAG('d','e','v','2'):       return HB_SCRIPT_DEVANAGARI;
     104           0 :     case HB_TAG('g','j','r','2'):       return HB_SCRIPT_GUJARATI;
     105           0 :     case HB_TAG('g','u','r','2'):       return HB_SCRIPT_GURMUKHI;
     106           0 :     case HB_TAG('k','n','d','2'):       return HB_SCRIPT_KANNADA;
     107           0 :     case HB_TAG('m','l','m','2'):       return HB_SCRIPT_MALAYALAM;
     108           0 :     case HB_TAG('o','r','y','2'):       return HB_SCRIPT_ORIYA;
     109           0 :     case HB_TAG('t','m','l','2'):       return HB_SCRIPT_TAMIL;
     110           0 :     case HB_TAG('t','e','l','2'):       return HB_SCRIPT_TELUGU;
     111           0 :     case HB_TAG('m','y','m','2'):       return HB_SCRIPT_MYANMAR;
     112             :   }
     113             : 
     114           0 :   return HB_SCRIPT_UNKNOWN;
     115             : }
     116             : 
     117             : /*
     118             :  * Complete list at:
     119             :  * https://www.microsoft.com/typography/otspec/scripttags.htm
     120             :  * https://www.microsoft.com/typography/otspec160/scripttagsProposed.htm
     121             :  *
     122             :  * Most of the script tags are the same as the ISO 15924 tag but lowercased.
     123             :  * So we just do that, and handle the exceptional cases in a switch.
     124             :  */
     125             : 
     126             : void
     127         348 : hb_ot_tags_from_script (hb_script_t  script,
     128             :                         hb_tag_t    *script_tag_1,
     129             :                         hb_tag_t    *script_tag_2)
     130             : {
     131             :   hb_tag_t new_tag;
     132             : 
     133         348 :   *script_tag_2 = HB_OT_TAG_DEFAULT_SCRIPT;
     134         348 :   *script_tag_1 = hb_ot_old_tag_from_script (script);
     135             : 
     136         348 :   new_tag = hb_ot_new_tag_from_script (script);
     137         348 :   if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) {
     138          20 :     *script_tag_2 = *script_tag_1;
     139          20 :     *script_tag_1 = new_tag;
     140             :   }
     141         348 : }
     142             : 
     143             : hb_script_t
     144           3 : hb_ot_tag_to_script (hb_tag_t tag)
     145             : {
     146           3 :   if (unlikely ((tag & 0x000000FFu) == '2'))
     147           0 :     return hb_ot_new_tag_to_script (tag);
     148             : 
     149           3 :   return hb_ot_old_tag_to_script (tag);
     150             : }
     151             : 
     152             : 
     153             : /* hb_language_t */
     154             : 
     155             : typedef struct {
     156             :   char language[4];
     157             :   hb_tag_t tag;
     158             : } LangTag;
     159             : 
     160             : /*
     161             :  * Complete list at:
     162             :  * http://www.microsoft.com/typography/otspec/languagetags.htm
     163             :  *
     164             :  * Generated by intersecting the OpenType language tag list from
     165             :  * Draft OpenType 1.5 spec, with with the ISO 639-3 codes from
     166             :  * 2008-08-04, matching on name, and finally adjusted manually.
     167             :  *
     168             :  * Updated on 2012-12-07 with more research into remaining codes.
     169             :  *
     170             :  * Updated on 2013-11-23 based on usage in SIL and Microsoft fonts,
     171             :  * the new proposal from Microsoft, and latest ISO 639-3 names.
     172             :  *
     173             :  * Some items still missing.  Those are commented out at the end.
     174             :  * Keep sorted for bsearch.
     175             :  *
     176             :  * Updated as of 2015-05-06: OT1.7 on MS website has some newer
     177             :  * items that we don't have here, eg. Zazaki.  This is the new
     178             :  * items in OpenType 1.7 (red items), most of which we have:
     179             :  * http://www.microsoft.com/typography/otspec170/languagetags.htm
     180             :  */
     181             : 
     182             : static const LangTag ot_languages[] = {
     183             :   {"aa",      HB_TAG('A','F','R',' ')},       /* Afar */
     184             :   {"ab",      HB_TAG('A','B','K',' ')},       /* Abkhazian */
     185             :   {"abq",     HB_TAG('A','B','A',' ')},       /* Abaza */
     186             :   {"acf",     HB_TAG('F','A','N',' ')},       /* French Antillean */
     187             :   {"ach",     HB_TAG('A','C','H',' ')},       /* Acoli */
     188             :   {"acr",     HB_TAG('A','C','R',' ')},       /* Achi */
     189             :   {"ada",     HB_TAG('D','N','G',' ')},       /* Dangme */
     190             :   {"ady",     HB_TAG('A','D','Y',' ')},       /* Adyghe */
     191             :   {"af",      HB_TAG('A','F','K',' ')},       /* Afrikaans */
     192             :   {"ahg",     HB_TAG('A','G','W',' ')},       /* Agaw */
     193             :   {"aii",     HB_TAG('S','W','A',' ')},       /* Swadaya Aramaic */
     194             :   {"aio",     HB_TAG('A','I','O',' ')},       /* Aiton */
     195             :   {"aiw",     HB_TAG('A','R','I',' ')},       /* Aari */
     196             :   {"ak",      HB_TAG('T','W','I',' ')},       /* Akan [macrolanguage] */
     197             :   {"aka",     HB_TAG('A','K','A',' ')},       /* Akan */
     198             :   {"alt",     HB_TAG('A','L','T',' ')},       /* [Southern] Altai */
     199             :   {"am",      HB_TAG('A','M','H',' ')},       /* Amharic */
     200             :   {"amf",     HB_TAG('H','B','N',' ')},       /* Hammer-Banna */
     201             :   {"amw",     HB_TAG('S','Y','R',' ')},       /* Western Neo-Aramaic */
     202             :   {"an",      HB_TAG('A','R','G',' ')},       /* Aragonese */
     203             :   {"ang",     HB_TAG('A','N','G',' ')},       /* Old English (ca. 450-1100) */
     204             :   {"ar",      HB_TAG('A','R','A',' ')},       /* Arabic [macrolanguage] */
     205             :   {"arb",     HB_TAG('A','R','A',' ')},       /* Standard Arabic */
     206             :   {"arn",     HB_TAG('M','A','P',' ')},       /* Mapudungun */
     207             :   {"ary",     HB_TAG('M','O','R',' ')},       /* Moroccan Arabic */
     208             :   {"as",      HB_TAG('A','S','M',' ')},       /* Assamese */
     209             :   {"ast",     HB_TAG('A','S','T',' ')},       /* Asturian/Asturleonese/Bable/Leonese */
     210             :   {"ath",     HB_TAG('A','T','H',' ')},       /* Athapaskan [family] */
     211             :   {"atj",     HB_TAG('R','C','R',' ')},       /* R-Cree */
     212             :   {"atv",     HB_TAG('A','L','T',' ')},       /* [Northern] Altai */
     213             :   {"av",      HB_TAG('A','V','R',' ')},       /* Avaric */
     214             :   {"awa",     HB_TAG('A','W','A',' ')},       /* Awadhi */
     215             :   {"ay",      HB_TAG('A','Y','M',' ')},       /* Aymara [macrolanguage] */
     216             :   {"az",      HB_TAG('A','Z','E',' ')},       /* Azerbaijani [macrolanguage] */
     217             :   {"azb",     HB_TAG('A','Z','B',' ')},       /* South Azerbaijani */
     218             :   {"azj",     HB_TAG('A','Z','E',' ')},       /* North Azerbaijani */
     219             :   {"ba",      HB_TAG('B','S','H',' ')},       /* Bashkir */
     220             :   {"bad",     HB_TAG('B','A','D','0')},       /* Banda */
     221             :   {"bai",     HB_TAG('B','M','L',' ')},       /* Bamileke [family] */
     222             :   {"bal",     HB_TAG('B','L','I',' ')},       /* Baluchi [macrolangauge] */
     223             :   {"ban",     HB_TAG('B','A','N',' ')},       /* Balinese */
     224             :   {"bar",     HB_TAG('B','A','R',' ')},       /* Bavarian */
     225             :   {"bbc",     HB_TAG('B','B','C',' ')},       /* Batak Toba */
     226             :   {"bci",     HB_TAG('B','A','U',' ')},       /* Baoulé */
     227             :   {"bcl",     HB_TAG('B','I','K',' ')},       /* Central Bikol */
     228             :   {"bcq",     HB_TAG('B','C','H',' ')},       /* Bench */
     229             :   {"bdy",     HB_TAG('B','D','Y',' ')},       /* Bandjalang */
     230             :   {"be",      HB_TAG('B','E','L',' ')},       /* Belarusian */
     231             :   {"bem",     HB_TAG('B','E','M',' ')},       /* Bemba (Zambia) */
     232             :   {"ber",     HB_TAG('B','E','R',' ')},       /* Berber [family] */
     233             :   {"bfq",     HB_TAG('B','A','D',' ')},       /* Badaga */
     234             :   {"bft",     HB_TAG('B','L','T',' ')},       /* Balti */
     235             :   {"bfu",     HB_TAG('L','A','H',' ')},       /* Lahuli */
     236             :   {"bfy",     HB_TAG('B','A','G',' ')},       /* Baghelkhandi */
     237             :   {"bg",      HB_TAG('B','G','R',' ')},       /* Bulgarian */
     238             :   {"bgc",     HB_TAG('B','G','C',' ')},       /* Haryanvi */
     239             :   {"bgq",     HB_TAG('B','G','Q',' ')},       /* Bagri */
     240             :   {"bgr",     HB_TAG('Q','I','N',' ')},       /* Bawm Chin */
     241             :   {"bhb",     HB_TAG('B','H','I',' ')},       /* Bhili */
     242             :   {"bhk",     HB_TAG('B','I','K',' ')},       /* Albay Bicolano (retired code) */
     243             :   {"bho",     HB_TAG('B','H','O',' ')},       /* Bhojpuri */
     244             :   {"bi",      HB_TAG('B','I','S',' ')},       /* Bislama */
     245             :   {"bik",     HB_TAG('B','I','K',' ')},       /* Bikol [macrolanguage] */
     246             :   {"bin",     HB_TAG('E','D','O',' ')},       /* Bini */
     247             :   {"bjj",     HB_TAG('B','J','J',' ')},       /* Kanauji */
     248             :   {"bjt",     HB_TAG('B','L','N',' ')},       /* Balanta-Ganja */
     249             :   {"bla",     HB_TAG('B','K','F',' ')},       /* Blackfoot */
     250             :   {"ble",     HB_TAG('B','L','N',' ')},       /* Balanta-Kentohe */
     251             :   {"blk",     HB_TAG('B','L','K',' ')},       /* Pa'O/Pa'o Karen */
     252             :   {"bln",     HB_TAG('B','I','K',' ')},       /* Southern Catanduanes Bikol */
     253             :   {"bm",      HB_TAG('B','M','B',' ')},       /* Bambara */
     254             :   {"bn",      HB_TAG('B','E','N',' ')},       /* Bengali */
     255             :   {"bo",      HB_TAG('T','I','B',' ')},       /* Tibetan */
     256             :   {"bpy",     HB_TAG('B','P','Y',' ')},       /* Bishnupriya */
     257             :   {"bqi",     HB_TAG('L','R','C',' ')},       /* Bakhtiari */
     258             :   {"br",      HB_TAG('B','R','E',' ')},       /* Breton */
     259             :   {"bra",     HB_TAG('B','R','I',' ')},       /* Braj Bhasha */
     260             :   {"brh",     HB_TAG('B','R','H',' ')},       /* Brahui */
     261             :   {"brx",     HB_TAG('B','R','X',' ')},       /* Bodo (India) */
     262             :   {"bs",      HB_TAG('B','O','S',' ')},       /* Bosnian */
     263             :   {"btb",     HB_TAG('B','T','I',' ')},       /* Beti (Cameroon) */
     264             :   {"bto",     HB_TAG('B','I','K',' ')},       /* Rinconada Bikol */
     265             :   {"bts",     HB_TAG('B','T','S',' ')},       /* Batak Simalungun */
     266             :   {"bug",     HB_TAG('B','U','G',' ')},       /* Buginese */
     267             :   {"bxr",     HB_TAG('R','B','U',' ')},       /* Russian Buriat */
     268             :   {"byn",     HB_TAG('B','I','L',' ')},       /* Bilen */
     269             :   {"ca",      HB_TAG('C','A','T',' ')},       /* Catalan */
     270             :   {"cak",     HB_TAG('C','A','K',' ')},       /* Kaqchikel */
     271             :   {"cbk",     HB_TAG('C','B','K',' ')},       /* Chavacano */
     272             :   {"cbl",     HB_TAG('Q','I','N',' ')},       /* Bualkhaw Chin */
     273             :   {"ce",      HB_TAG('C','H','E',' ')},       /* Chechen */
     274             :   {"ceb",     HB_TAG('C','E','B',' ')},       /* Cebuano */
     275             :   {"cfm",     HB_TAG('H','A','L',' ')},       /* Halam/Falam Chin */
     276             :   {"cgg",     HB_TAG('C','G','G',' ')},       /* Chiga */
     277             :   {"ch",      HB_TAG('C','H','A',' ')},       /* Chamorro */
     278             :   {"chk",     HB_TAG('C','H','K','0')},       /* Chuukese */
     279             :   {"cho",     HB_TAG('C','H','O',' ')},       /* Choctaw */
     280             :   {"chp",     HB_TAG('C','H','P',' ')},       /* Chipewyan */
     281             :   {"chr",     HB_TAG('C','H','R',' ')},       /* Cherokee */
     282             :   {"chy",     HB_TAG('C','H','Y',' ')},       /* Cheyenne */
     283             :   {"cja",     HB_TAG('C','J','A',' ')},       /* Western Cham */
     284             :   {"cjm",     HB_TAG('C','J','M',' ')},       /* Eastern Cham */
     285             :   {"cka",     HB_TAG('Q','I','N',' ')},       /* Khumi Awa Chin */
     286             :   {"ckb",     HB_TAG('K','U','R',' ')},       /* Central Kurdish (Sorani) */
     287             :   {"ckt",     HB_TAG('C','H','K',' ')},       /* Chukchi */
     288             :   {"cld",     HB_TAG('S','Y','R',' ')},       /* Chaldean Neo-Aramaic */
     289             :   {"cmr",     HB_TAG('Q','I','N',' ')},       /* Mro-Khimi Chin */
     290             :   {"cnb",     HB_TAG('Q','I','N',' ')},       /* Chinbon Chin */
     291             :   {"cnh",     HB_TAG('Q','I','N',' ')},       /* Hakha Chin */
     292             :   {"cnk",     HB_TAG('Q','I','N',' ')},       /* Khumi Chin */
     293             :   {"cnw",     HB_TAG('Q','I','N',' ')},       /* Ngawn Chin */
     294             :   {"cop",     HB_TAG('C','O','P',' ')},       /* Coptic */
     295             :   {"cpp",     HB_TAG('C','P','P',' ')},       /* Creoles */
     296             :   {"cr",      HB_TAG('C','R','E',' ')},       /* Cree */
     297             :   {"cre",     HB_TAG('Y','C','R',' ')},       /* Y-Cree */
     298             :   {"crh",     HB_TAG('C','R','T',' ')},       /* Crimean Tatar */
     299             :   {"crj",     HB_TAG('E','C','R',' ')},       /* [Southern] East Cree */
     300             :   {"crk",     HB_TAG('W','C','R',' ')},       /* West-Cree */
     301             :   {"crl",     HB_TAG('E','C','R',' ')},       /* [Northern] East Cree */
     302             :   {"crm",     HB_TAG('M','C','R',' ')},       /* Moose Cree */
     303             :   {"crx",     HB_TAG('C','R','R',' ')},       /* Carrier */
     304             :   {"cs",      HB_TAG('C','S','Y',' ')},       /* Czech */
     305             :   {"csb",     HB_TAG('C','S','B',' ')},       /* Kashubian */
     306             :   {"csh",     HB_TAG('Q','I','N',' ')},       /* Asho Chin */
     307             :   {"csy",     HB_TAG('Q','I','N',' ')},       /* Siyin Chin */
     308             :   {"ctd",     HB_TAG('Q','I','N',' ')},       /* Tedim Chin */
     309             :   {"ctg",     HB_TAG('C','T','G',' ')},       /* Chittagonian */
     310             :   {"cts",     HB_TAG('B','I','K',' ')},       /* Northern Catanduanes Bikol */
     311             :   {"cu",      HB_TAG('C','S','L',' ')},       /* Church Slavic */
     312             :   {"cuk",     HB_TAG('C','U','K',' ')},       /* San Blas Kuna */
     313             :   {"cv",      HB_TAG('C','H','U',' ')},       /* Chuvash */
     314             :   {"cwd",     HB_TAG('D','C','R',' ')},       /* Woods Cree */
     315             :   {"cy",      HB_TAG('W','E','L',' ')},       /* Welsh */
     316             :   {"czt",     HB_TAG('Q','I','N',' ')},       /* Zotung Chin */
     317             :   {"da",      HB_TAG('D','A','N',' ')},       /* Danish */
     318             :   {"dao",     HB_TAG('Q','I','N',' ')},       /* Daai Chin */
     319             :   {"dap",     HB_TAG('N','I','S',' ')},       /* Nisi (India) */
     320             :   {"dar",     HB_TAG('D','A','R',' ')},       /* Dargwa */
     321             :   {"dax",     HB_TAG('D','A','X',' ')},       /* Dayi */
     322             :   {"de",      HB_TAG('D','E','U',' ')},       /* German */
     323             :   {"dgo",     HB_TAG('D','G','O',' ')},       /* Dogri */
     324             :   {"dhd",     HB_TAG('M','A','W',' ')},       /* Dhundari */
     325             :   {"dhg",     HB_TAG('D','H','G',' ')},       /* Dhangu */
     326             :   {"din",     HB_TAG('D','N','K',' ')},       /* Dinka [macrolanguage] */
     327             :   {"diq",     HB_TAG('D','I','Q',' ')},       /* Dimli */
     328             :   {"dje",     HB_TAG('D','J','R',' ')},       /* Zarma */
     329             :   {"djr",     HB_TAG('D','J','R','0')},       /* Djambarrpuyngu */
     330             :   {"dng",     HB_TAG('D','U','N',' ')},       /* Dungan */
     331             :   {"dnj",     HB_TAG('D','N','J',' ')},       /* Dan */
     332             :   {"doi",     HB_TAG('D','G','R',' ')},       /* Dogri [macrolanguage] */
     333             :   {"dsb",     HB_TAG('L','S','B',' ')},       /* Lower Sorbian */
     334             :   {"duj",     HB_TAG('D','U','J',' ')},       /* Dhuwal */
     335             :   {"dv",      HB_TAG('D','I','V',' ')},       /* Dhivehi/Divehi/Maldivian */
     336             :   {"dyu",     HB_TAG('J','U','L',' ')},       /* Jula */
     337             :   {"dz",      HB_TAG('D','Z','N',' ')},       /* Dzongkha */
     338             :   {"ee",      HB_TAG('E','W','E',' ')},       /* Ewe */
     339             :   {"efi",     HB_TAG('E','F','I',' ')},       /* Efik */
     340             :   {"ekk",     HB_TAG('E','T','I',' ')},       /* Standard Estonian */
     341             :   {"el",      HB_TAG('E','L','L',' ')},       /* Modern Greek (1453-) */
     342             :   {"emk",     HB_TAG('M','N','K',' ')},       /* Eastern Maninkakan */
     343             :   {"en",      HB_TAG('E','N','G',' ')},       /* English */
     344             :   {"enf",     HB_TAG('F','N','E',' ')},       /* Forest Nenets */
     345             :   {"enh",     HB_TAG('T','N','E',' ')},       /* Tundra Nenets */
     346             :   {"eo",      HB_TAG('N','T','O',' ')},       /* Esperanto */
     347             :   {"eot",     HB_TAG('B','T','I',' ')},       /* Beti (Côte d'Ivoire) */
     348             :   {"es",      HB_TAG('E','S','P',' ')},       /* Spanish */
     349             :   {"esu",     HB_TAG('E','S','U',' ')},       /* Central Yupik */
     350             :   {"et",      HB_TAG('E','T','I',' ')},       /* Estonian [macrolanguage] */
     351             :   {"eu",      HB_TAG('E','U','Q',' ')},       /* Basque */
     352             :   {"eve",     HB_TAG('E','V','N',' ')},       /* Even */
     353             :   {"evn",     HB_TAG('E','V','K',' ')},       /* Evenki */
     354             :   {"fa",      HB_TAG('F','A','R',' ')},       /* Persian [macrolanguage] */
     355             :   {"fan",     HB_TAG('F','A','N','0')},       /* Fang */
     356             :   {"fat",     HB_TAG('F','A','T',' ')},       /* Fanti */
     357             :   {"ff",      HB_TAG('F','U','L',' ')},       /* Fulah [macrolanguage] */
     358             :   {"fi",      HB_TAG('F','I','N',' ')},       /* Finnish */
     359             :   {"fil",     HB_TAG('P','I','L',' ')},       /* Filipino */
     360             :   {"fj",      HB_TAG('F','J','I',' ')},       /* Fijian */
     361             :   {"flm",     HB_TAG('H','A','L',' ')},       /* Halam/Falam Chin [retired ISO639 code] */
     362             :   {"fo",      HB_TAG('F','O','S',' ')},       /* Faroese */
     363             :   {"fon",     HB_TAG('F','O','N',' ')},       /* Fon */
     364             :   {"fr",      HB_TAG('F','R','A',' ')},       /* French */
     365             :   {"frc",     HB_TAG('F','R','C',' ')},       /* Cajun French */
     366             :   {"frp",     HB_TAG('F','R','P',' ')},       /* Arpitan/Francoprovençal */
     367             :   {"fuf",     HB_TAG('F','T','A',' ')},       /* Futa */
     368             :   {"fur",     HB_TAG('F','R','L',' ')},       /* Friulian */
     369             :   {"fuv",     HB_TAG('F','U','V',' ')},       /* Nigerian Fulfulde */
     370             :   {"fy",      HB_TAG('F','R','I',' ')},       /* Western Frisian */
     371             :   {"ga",      HB_TAG('I','R','I',' ')},       /* Irish */
     372             :   {"gaa",     HB_TAG('G','A','D',' ')},       /* Ga */
     373             :   {"gag",     HB_TAG('G','A','G',' ')},       /* Gagauz */
     374             :   {"gbm",     HB_TAG('G','A','W',' ')},       /* Garhwali */
     375             :   {"gd",      HB_TAG('G','A','E',' ')},       /* Scottish Gaelic */
     376             :   {"gez",     HB_TAG('G','E','Z',' ')},       /* Ge'ez */
     377             :   {"ggo",     HB_TAG('G','O','N',' ')},       /* Southern Gondi */
     378             :   {"gih",     HB_TAG('G','I','H',' ')},       /* Githabul */
     379             :   {"gil",     HB_TAG('G','I','L','0')},       /* Kiribati (Gilbertese) */
     380             :   {"gkp",     HB_TAG('G','K','P',' ')},       /* Kpelle (Guinea) */
     381             :   {"gl",      HB_TAG('G','A','L',' ')},       /* Galician */
     382             :   {"gld",     HB_TAG('N','A','N',' ')},       /* Nanai */
     383             :   {"gle",     HB_TAG('I','R','T',' ')},       /* Irish Traditional */
     384             :   {"glk",     HB_TAG('G','L','K',' ')},       /* Gilaki */
     385             :   {"gn",      HB_TAG('G','U','A',' ')},       /* Guarani [macrolanguage] */
     386             :   {"gnn",     HB_TAG('G','N','N',' ')},       /* Gumatj */
     387             :   {"gno",     HB_TAG('G','O','N',' ')},       /* Northern Gondi */
     388             :   {"gog",     HB_TAG('G','O','G',' ')},       /* Gogo */
     389             :   {"gon",     HB_TAG('G','O','N',' ')},       /* Gondi [macrolanguage] */
     390             :   {"grt",     HB_TAG('G','R','O',' ')},       /* Garo */
     391             :   {"gru",     HB_TAG('S','O','G',' ')},       /* Sodo Gurage */
     392             :   {"gsw",     HB_TAG('A','L','S',' ')},       /* Alsatian */
     393             :   {"gu",      HB_TAG('G','U','J',' ')},       /* Gujarati */
     394             :   {"guc",     HB_TAG('G','U','C',' ')},       /* Wayuu */
     395             :   {"guf",     HB_TAG('G','U','F',' ')},       /* Gupapuyngu */
     396             :   {"guk",     HB_TAG('G','M','Z',' ')},       /* Gumuz */
     397             : /*{"guk",     HB_TAG('G','U','K',' ')},*/     /* Gumuz (in SIL fonts) */
     398             :   {"guz",     HB_TAG('G','U','Z',' ')},       /* Ekegusii/Gusii */
     399             :   {"gv",      HB_TAG('M','N','X',' ')},       /* Manx */
     400             :   {"ha",      HB_TAG('H','A','U',' ')},       /* Hausa */
     401             :   {"har",     HB_TAG('H','R','I',' ')},       /* Harari */
     402             :   {"haw",     HB_TAG('H','A','W',' ')},       /* Hawaiian */
     403             :   {"hay",     HB_TAG('H','A','Y',' ')},       /* Haya */
     404             :   {"haz",     HB_TAG('H','A','Z',' ')},       /* Hazaragi */
     405             :   {"he",      HB_TAG('I','W','R',' ')},       /* Hebrew */
     406             :   {"hi",      HB_TAG('H','I','N',' ')},       /* Hindi */
     407             :   {"hil",     HB_TAG('H','I','L',' ')},       /* Hiligaynon */
     408             :   {"hlt",     HB_TAG('Q','I','N',' ')},       /* Matu Chin */
     409             :   {"hmn",     HB_TAG('H','M','N',' ')},       /* Hmong */
     410             :   {"hnd",     HB_TAG('H','N','D',' ')},       /* [Southern] Hindko */
     411             :   {"hne",     HB_TAG('C','H','H',' ')},       /* Chattisgarhi */
     412             :   {"hno",     HB_TAG('H','N','D',' ')},       /* [Northern] Hindko */
     413             :   {"ho",      HB_TAG('H','M','O',' ')},       /* Hiri Motu */
     414             :   {"hoc",     HB_TAG('H','O',' ',' ')},       /* Ho */
     415             :   {"hoj",     HB_TAG('H','A','R',' ')},       /* Harauti */
     416             :   {"hr",      HB_TAG('H','R','V',' ')},       /* Croatian */
     417             :   {"hsb",     HB_TAG('U','S','B',' ')},       /* Upper Sorbian */
     418             :   {"ht",      HB_TAG('H','A','I',' ')},       /* Haitian/Haitian Creole */
     419             :   {"hu",      HB_TAG('H','U','N',' ')},       /* Hungarian */
     420             :   {"hy",      HB_TAG('H','Y','E',' ')},       /* Armenian */
     421             :   {"hz",      HB_TAG('H','E','R',' ')},       /* Herero */
     422             :   {"ia",      HB_TAG('I','N','A',' ')},       /* Interlingua (International Auxiliary Language Association) */
     423             :   {"iba",     HB_TAG('I','B','A',' ')},       /* Iban */
     424             :   {"ibb",     HB_TAG('I','B','B',' ')},       /* Ibibio */
     425             :   {"id",      HB_TAG('I','N','D',' ')},       /* Indonesian */
     426             :   {"ie",      HB_TAG('I','L','E',' ')},       /* Interlingue/Occidental */
     427             :   {"ig",      HB_TAG('I','B','O',' ')},       /* Igbo */
     428             :   {"igb",     HB_TAG('E','B','I',' ')},       /* Ebira */
     429             :   {"ii",      HB_TAG('Y','I','M',' ')},       /* Yi Modern */
     430             :   {"ijc",     HB_TAG('I','J','O',' ')},       /* Izon */
     431             :   {"ijo",     HB_TAG('I','J','O',' ')},       /* Ijo [family] */
     432             :   {"ik",      HB_TAG('I','P','K',' ')},       /* Inupiaq [macrolanguage] */
     433             :   {"ilo",     HB_TAG('I','L','O',' ')},       /* Ilokano */
     434             :   {"inh",     HB_TAG('I','N','G',' ')},       /* Ingush */
     435             :   {"io",      HB_TAG('I','D','O',' ')},       /* Ido */
     436             :   {"is",      HB_TAG('I','S','L',' ')},       /* Icelandic */
     437             :   {"it",      HB_TAG('I','T','A',' ')},       /* Italian */
     438             :   {"iu",      HB_TAG('I','N','U',' ')},       /* Inuktitut [macrolanguage] */
     439             :   {"ja",      HB_TAG('J','A','N',' ')},       /* Japanese */
     440             :   {"jam",     HB_TAG('J','A','M',' ')},       /* Jamaican Creole English */
     441             :   {"jbo",     HB_TAG('J','B','O',' ')},       /* Lojban */
     442             :   {"jv",      HB_TAG('J','A','V',' ')},       /* Javanese */
     443             :   {"ka",      HB_TAG('K','A','T',' ')},       /* Georgian */
     444             :   {"kaa",     HB_TAG('K','R','K',' ')},       /* Karakalpak */
     445             :   {"kab",     HB_TAG('K','A','B','0')},       /* Kabyle */
     446             :   {"kam",     HB_TAG('K','M','B',' ')},       /* Kamba (Kenya) */
     447             :   {"kar",     HB_TAG('K','R','N',' ')},       /* Karen [family] */
     448             :   {"kat",     HB_TAG('K','G','E',' ')},       /* Khutsuri Georgian */
     449             :   {"kbd",     HB_TAG('K','A','B',' ')},       /* Kabardian */
     450             :   {"kde",     HB_TAG('K','D','E',' ')},       /* Makonde */
     451             :   {"kdr",     HB_TAG('K','R','M',' ')},       /* Karaim */
     452             :   {"kdt",     HB_TAG('K','U','Y',' ')},       /* Kuy */
     453             :   {"kea",     HB_TAG('K','E','A',' ')},       /* Kabuverdianu (Crioulo) */
     454             :   {"kek",     HB_TAG('K','E','K',' ')},       /* Kekchi */
     455             :   {"kex",     HB_TAG('K','K','N',' ')},       /* Kokni */
     456             :   {"kfa",     HB_TAG('K','O','D',' ')},       /* Kodagu */
     457             :   {"kfr",     HB_TAG('K','A','C',' ')},       /* Kachchi */
     458             :   {"kfx",     HB_TAG('K','U','L',' ')},       /* Kulvi */
     459             :   {"kfy",     HB_TAG('K','M','N',' ')},       /* Kumaoni */
     460             :   {"kg",      HB_TAG('K','O','N',' ')},       /* Kongo [macrolanguage] */
     461             :   {"kha",     HB_TAG('K','S','I',' ')},       /* Khasi */
     462             :   {"khb",     HB_TAG('X','B','D',' ')},       /* Lü */
     463             :   {"kht",     HB_TAG('K','H','N',' ')},       /* Khamti (Microsoft fonts) */
     464             : /*{"kht",     HB_TAG('K','H','T',' ')},*/     /* Khamti (OpenType spec and SIL fonts) */
     465             :   {"khw",     HB_TAG('K','H','W',' ')},       /* Khowar */
     466             :   {"ki",      HB_TAG('K','I','K',' ')},       /* Gikuyu/Kikuyu */
     467             :   {"kiu",     HB_TAG('K','I','U',' ')},       /* Kirmanjki */
     468             :   {"kj",      HB_TAG('K','U','A',' ')},       /* Kuanyama/Kwanyama */
     469             :   {"kjd",     HB_TAG('K','J','D',' ')},       /* Southern Kiwai */
     470             :   {"kjh",     HB_TAG('K','H','A',' ')},       /* Khakass */
     471             :   {"kjp",     HB_TAG('K','J','P',' ')},       /* Pwo Eastern Karen */
     472             :   {"kk",      HB_TAG('K','A','Z',' ')},       /* Kazakh */
     473             :   {"kl",      HB_TAG('G','R','N',' ')},       /* Kalaallisut */
     474             :   {"kln",     HB_TAG('K','A','L',' ')},       /* Kalenjin */
     475             :   {"km",      HB_TAG('K','H','M',' ')},       /* Central Khmer */
     476             :   {"kmb",     HB_TAG('M','B','N',' ')},       /* Kimbundu */
     477             :   {"kmw",     HB_TAG('K','M','O',' ')},       /* Komo (Democratic Republic of Congo) */
     478             :   {"kn",      HB_TAG('K','A','N',' ')},       /* Kannada */
     479             :   {"knn",     HB_TAG('K','O','K',' ')},       /* Konkani */
     480             :   {"ko",      HB_TAG('K','O','R',' ')},       /* Korean */
     481             :   {"koi",     HB_TAG('K','O','P',' ')},       /* Komi-Permyak */
     482             :   {"kok",     HB_TAG('K','O','K',' ')},       /* Konkani [macrolanguage] */
     483             :   {"kon",     HB_TAG('K','O','N','0')},       /* Kongo */
     484             :   {"kos",     HB_TAG('K','O','S',' ')},       /* Kosraean */
     485             :   {"kpe",     HB_TAG('K','P','L',' ')},       /* Kpelle [macrolanguage] */
     486             :   {"kpv",     HB_TAG('K','O','Z',' ')},       /* Komi-Zyrian */
     487             :   {"kpy",     HB_TAG('K','Y','K',' ')},       /* Koryak */
     488             :   {"kqy",     HB_TAG('K','R','T',' ')},       /* Koorete */
     489             :   {"kr",      HB_TAG('K','N','R',' ')},       /* Kanuri [macrolanguage] */
     490             :   {"kri",     HB_TAG('K','R','I',' ')},       /* Krio */
     491             :   {"krl",     HB_TAG('K','R','L',' ')},       /* Karelian */
     492             :   {"kru",     HB_TAG('K','U','U',' ')},       /* Kurukh */
     493             :   {"ks",      HB_TAG('K','S','H',' ')},       /* Kashmiri */
     494             :   {"ksh",     HB_TAG('K','S','H','0')},       /* Ripuarian, Kölsch */
     495             : /*{"ksw",     HB_TAG('K','R','N',' ')},*/     /* S'gaw Karen (Microsoft fonts?) */
     496             :   {"ksw",     HB_TAG('K','S','W',' ')},       /* S'gaw Karen (OpenType spec and SIL fonts) */
     497             :   {"ktb",     HB_TAG('K','E','B',' ')},       /* Kebena */
     498             :   {"ktu",     HB_TAG('K','O','N',' ')},       /* Kikongo */
     499             :   {"ku",      HB_TAG('K','U','R',' ')},       /* Kurdish [macrolanguage] */
     500             :   {"kum",     HB_TAG('K','U','M',' ')},       /* Kumyk */
     501             :   {"kv",      HB_TAG('K','O','M',' ')},       /* Komi [macrolanguage] */
     502             :   {"kvd",     HB_TAG('K','U','I',' ')},       /* Kui (Indonesia) */
     503             :   {"kw",      HB_TAG('C','O','R',' ')},       /* Cornish */
     504             :   {"kxc",     HB_TAG('K','M','S',' ')},       /* Komso */
     505             :   {"kxu",     HB_TAG('K','U','I',' ')},       /* Kui (India) */
     506             :   {"ky",      HB_TAG('K','I','R',' ')},       /* Kirghiz/Kyrgyz */
     507             :   {"kyu",     HB_TAG('K','Y','U',' ')},       /* Western Kayah */
     508             :   {"la",      HB_TAG('L','A','T',' ')},       /* Latin */
     509             :   {"lad",     HB_TAG('J','U','D',' ')},       /* Ladino */
     510             :   {"lb",      HB_TAG('L','T','Z',' ')},       /* Luxembourgish */
     511             :   {"lbe",     HB_TAG('L','A','K',' ')},       /* Lak */
     512             :   {"lbj",     HB_TAG('L','D','K',' ')},       /* Ladakhi */
     513             :   {"lez",     HB_TAG('L','E','Z',' ')},       /* Lezgi */
     514             :   {"lg",      HB_TAG('L','U','G',' ')},       /* Ganda */
     515             :   {"li",      HB_TAG('L','I','M',' ')},       /* Limburgan/Limburger/Limburgish */
     516             :   {"lif",     HB_TAG('L','M','B',' ')},       /* Limbu */
     517             :   {"lij",     HB_TAG('L','I','J',' ')},       /* Ligurian */
     518             :   {"lis",     HB_TAG('L','I','S',' ')},       /* Lisu */
     519             :   {"ljp",     HB_TAG('L','J','P',' ')},       /* Lampung Api */
     520             :   {"lki",     HB_TAG('L','K','I',' ')},       /* Laki */
     521             :   {"lld",     HB_TAG('L','A','D',' ')},       /* Ladin */
     522             :   {"lmn",     HB_TAG('L','A','M',' ')},       /* Lambani */
     523             :   {"lmo",     HB_TAG('L','M','O',' ')},       /* Lombard */
     524             :   {"ln",      HB_TAG('L','I','N',' ')},       /* Lingala */
     525             :   {"lo",      HB_TAG('L','A','O',' ')},       /* Lao */
     526             :   {"lom",     HB_TAG('L','O','M',' ')},       /* Loma */
     527             :   {"lrc",     HB_TAG('L','R','C',' ')},       /* Northern Luri */
     528             :   {"lt",      HB_TAG('L','T','H',' ')},       /* Lithuanian */
     529             :   {"lu",      HB_TAG('L','U','B',' ')},       /* Luba-Katanga */
     530             :   {"lua",     HB_TAG('L','U','B',' ')},       /* Luba-Kasai */
     531             :   {"luo",     HB_TAG('L','U','O',' ')},       /* Luo (Kenya and Tanzania) */
     532             :   {"lus",     HB_TAG('M','I','Z',' ')},       /* Mizo */
     533             :   {"luy",     HB_TAG('L','U','H',' ')},       /* Luyia/Oluluyia [macrolanguage] */
     534             :   {"luz",     HB_TAG('L','R','C',' ')},       /* Southern Luri */
     535             :   {"lv",      HB_TAG('L','V','I',' ')},       /* Latvian */
     536             :   {"lzz",     HB_TAG('L','A','Z',' ')},       /* Laz */
     537             :   {"mad",     HB_TAG('M','A','D',' ')},       /* Madurese */
     538             :   {"mag",     HB_TAG('M','A','G',' ')},       /* Magahi */
     539             :   {"mai",     HB_TAG('M','T','H',' ')},       /* Maithili */
     540             :   {"mak",     HB_TAG('M','K','R',' ')},       /* Makasar */
     541             :   {"mal",     HB_TAG('M','A','L',' ')},       /* Malayalam */
     542             :   {"mam",     HB_TAG('M','A','M',' ')},       /* Mam */
     543             :   {"man",     HB_TAG('M','N','K',' ')},       /* Manding/Mandingo [macrolanguage] */
     544             :   {"mdc",     HB_TAG('M','L','E',' ')},       /* Male (Papua New Guinea) */
     545             :   {"mdf",     HB_TAG('M','O','K',' ')},       /* Moksha */
     546             :   {"mdr",     HB_TAG('M','D','R',' ')},       /* Mandar */
     547             :   {"mdy",     HB_TAG('M','L','E',' ')},       /* Male (Ethiopia) */
     548             :   {"men",     HB_TAG('M','D','E',' ')},       /* Mende (Sierra Leone) */
     549             :   {"mer",     HB_TAG('M','E','R',' ')},       /* Meru */
     550             :   {"mfe",     HB_TAG('M','F','E',' ')},       /* Morisyen */
     551             :   {"mg",      HB_TAG('M','L','G',' ')},       /* Malagasy [macrolanguage] */
     552             :   {"mh",      HB_TAG('M','A','H',' ')},       /* Marshallese */
     553             :   {"mhr",     HB_TAG('L','M','A',' ')},       /* Low Mari */
     554             :   {"mi",      HB_TAG('M','R','I',' ')},       /* Maori */
     555             :   {"min",     HB_TAG('M','I','N',' ')},       /* Minangkabau */
     556             :   {"mk",      HB_TAG('M','K','D',' ')},       /* Macedonian */
     557             :   {"mku",     HB_TAG('M','N','K',' ')},       /* Konyanka Maninka */
     558             :   {"mkw",     HB_TAG('M','K','W',' ')},       /* Kituba (Congo) */
     559             :   {"ml",      HB_TAG('M','L','R',' ')},       /* Malayalam */
     560             :   {"mlq",     HB_TAG('M','N','K',' ')},       /* Western Maninkakan */
     561             :   {"mn",      HB_TAG('M','N','G',' ')},       /* Mongolian [macrolanguage] */
     562             :   {"mnc",     HB_TAG('M','C','H',' ')},       /* Manchu */
     563             :   {"mni",     HB_TAG('M','N','I',' ')},       /* Manipuri */
     564             :   {"mnk",     HB_TAG('M','N','D',' ')},       /* Mandinka */
     565             :   {"mns",     HB_TAG('M','A','N',' ')},       /* Mansi */
     566             :   {"mnw",     HB_TAG('M','O','N',' ')},       /* Mon */
     567             :   {"mo",      HB_TAG('M','O','L',' ')},       /* Moldavian */
     568             :   {"moh",     HB_TAG('M','O','H',' ')},       /* Mohawk */
     569             :   {"mos",     HB_TAG('M','O','S',' ')},       /* Mossi */
     570             :   {"mpe",     HB_TAG('M','A','J',' ')},       /* Majang */
     571             :   {"mr",      HB_TAG('M','A','R',' ')},       /* Marathi */
     572             :   {"mrh",     HB_TAG('Q','I','N',' ')},       /* Mara Chin */
     573             :   {"mrj",     HB_TAG('H','M','A',' ')},       /* High Mari */
     574             :   {"ms",      HB_TAG('M','L','Y',' ')},       /* Malay [macrolanguage] */
     575             :   {"msc",     HB_TAG('M','N','K',' ')},       /* Sankaran Maninka */
     576             :   {"mt",      HB_TAG('M','T','S',' ')},       /* Maltese */
     577             :   {"mtr",     HB_TAG('M','A','W',' ')},       /* Mewari */
     578             :   {"mus",     HB_TAG('M','U','S',' ')},       /* Creek */
     579             :   {"mve",     HB_TAG('M','A','W',' ')},       /* Marwari (Pakistan) */
     580             :   {"mwk",     HB_TAG('M','N','K',' ')},       /* Kita Maninkakan */
     581             :   {"mwl",     HB_TAG('M','W','L',' ')},       /* Mirandese */
     582             :   {"mwr",     HB_TAG('M','A','W',' ')},       /* Marwari [macrolanguage] */
     583             :   {"mww",     HB_TAG('M','W','W',' ')},       /* Hmong Daw */
     584             :   {"my",      HB_TAG('B','R','M',' ')},       /* Burmese */
     585             :   {"mym",     HB_TAG('M','E','N',' ')},       /* Me'en */
     586             :   {"myn",     HB_TAG('M','Y','N',' ')},       /* Mayan */
     587             :   {"myq",     HB_TAG('M','N','K',' ')},       /* Forest Maninka (retired code) */
     588             :   {"myv",     HB_TAG('E','R','Z',' ')},       /* Erzya */
     589             :   {"mzn",     HB_TAG('M','Z','N',' ')},       /* Mazanderani */
     590             :   {"na",      HB_TAG('N','A','U',' ')},       /* Nauru */
     591             :   {"nag",     HB_TAG('N','A','G',' ')},       /* Naga-Assamese */
     592             :   {"nah",     HB_TAG('N','A','H',' ')},       /* Nahuatl [family] */
     593             :   {"nap",     HB_TAG('N','A','P',' ')},       /* Neapolitan */
     594             :   {"nb",      HB_TAG('N','O','R',' ')},       /* Norwegian Bokmål */
     595             :   {"nco",     HB_TAG('S','I','B',' ')},       /* Sibe */
     596             :   {"nd",      HB_TAG('N','D','B',' ')},       /* [North] Ndebele */
     597             :   {"ndc",     HB_TAG('N','D','C',' ')},       /* Ndau */
     598             :   {"nds",     HB_TAG('N','D','S',' ')},       /* Low German/Low Saxon */
     599             :   {"ne",      HB_TAG('N','E','P',' ')},       /* Nepali */
     600             :   {"new",     HB_TAG('N','E','W',' ')},       /* Newari */
     601             :   {"ng",      HB_TAG('N','D','G',' ')},       /* Ndonga */
     602             :   {"nga",     HB_TAG('N','G','A',' ')},       /* Ngabaka */
     603             :   {"ngl",     HB_TAG('L','M','W',' ')},       /* Lomwe */
     604             :   {"ngo",     HB_TAG('S','X','T',' ')},       /* Sutu */
     605             :   {"niu",     HB_TAG('N','I','U',' ')},       /* Niuean */
     606             :   {"niv",     HB_TAG('G','I','L',' ')},       /* Gilyak */
     607             :   {"nl",      HB_TAG('N','L','D',' ')},       /* Dutch */
     608             :   {"nn",      HB_TAG('N','Y','N',' ')},       /* Norwegian Nynorsk */
     609             :   {"no",      HB_TAG('N','O','R',' ')},       /* Norwegian [macrolanguage] */
     610             :   {"nod",     HB_TAG('N','T','A',' ')},       /* Northern Thai */
     611             :   {"noe",     HB_TAG('N','O','E',' ')},       /* Nimadi */
     612             :   {"nog",     HB_TAG('N','O','G',' ')},       /* Nogai */
     613             :   {"nov",     HB_TAG('N','O','V',' ')},       /* Novial */
     614             :   {"nqo",     HB_TAG('N','K','O',' ')},       /* N'Ko */
     615             :   {"nr",      HB_TAG('N','D','B',' ')},       /* [South] Ndebele */
     616             :   {"nsk",     HB_TAG('N','A','S',' ')},       /* Naskapi */
     617             :   {"nso",     HB_TAG('S','O','T',' ')},       /* [Northern] Sotho */
     618             :   {"nv",      HB_TAG('N','A','V',' ')},       /* Navajo */
     619             :   {"ny",      HB_TAG('C','H','I',' ')},       /* Chewa/Chichwa/Nyanja */
     620             :   {"nym",     HB_TAG('N','Y','M',' ')},       /* Nyamwezi */
     621             :   {"nyn",     HB_TAG('N','K','L',' ')},       /* Nyankole */
     622             :   {"oc",      HB_TAG('O','C','I',' ')},       /* Occitan (post 1500) */
     623             :   {"oj",      HB_TAG('O','J','B',' ')},       /* Ojibwa [macrolanguage] */
     624             :   {"ojs",     HB_TAG('O','C','R',' ')},       /* Oji-Cree */
     625             :   {"okm",     HB_TAG('K','O','H',' ')},       /* Korean Old Hangul */
     626             :   {"om",      HB_TAG('O','R','O',' ')},       /* Oromo [macrolanguage] */
     627             :   {"or",      HB_TAG('O','R','I',' ')},       /* Oriya */
     628             :   {"os",      HB_TAG('O','S','S',' ')},       /* Ossetian */
     629             :   {"pa",      HB_TAG('P','A','N',' ')},       /* Panjabi */
     630             :   {"pag",     HB_TAG('P','A','G',' ')},       /* Pangasinan */
     631             :   {"pam",     HB_TAG('P','A','M',' ')},       /* Kapampangan/Pampanga */
     632             :   {"pap",     HB_TAG('P','A','P','0')},       /* Papiamento */
     633             :   {"pau",     HB_TAG('P','A','U',' ')},       /* Palauan */
     634             :   {"pcc",     HB_TAG('P','C','C',' ')},       /* Bouyei */
     635             :   {"pcd",     HB_TAG('P','C','D',' ')},       /* Picard */
     636             :   {"pce",     HB_TAG('P','L','G',' ')},       /* [Ruching] Palaung */
     637             :   {"pck",     HB_TAG('Q','I','N',' ')},       /* Paite Chin */
     638             :   {"pdc",     HB_TAG('P','D','C',' ')},       /* Pennsylvania German */
     639             :   {"pes",     HB_TAG('F','A','R',' ')},       /* Iranian Persian */
     640             :   {"phk",     HB_TAG('P','H','K',' ')},       /* Phake */
     641             :   {"pi",      HB_TAG('P','A','L',' ')},       /* Pali */
     642             :   {"pih",     HB_TAG('P','I','H',' ')},       /* Pitcairn-Norfolk */
     643             :   {"pl",      HB_TAG('P','L','K',' ')},       /* Polish */
     644             :   {"pll",     HB_TAG('P','L','G',' ')},       /* [Shwe] Palaung */
     645             :   {"plp",     HB_TAG('P','A','P',' ')},       /* Palpa */
     646             :   {"pms",     HB_TAG('P','M','S',' ')},       /* Piemontese */
     647             :   {"pnb",     HB_TAG('P','N','B',' ')},       /* Western Panjabi */
     648             :   {"poh",     HB_TAG('P','O','H',' ')},       /* Pocomchi */
     649             :   {"pon",     HB_TAG('P','O','N',' ')},       /* Pohnpeian */
     650             :   {"prs",     HB_TAG('D','R','I',' ')},       /* Afghan Persian/Dari */
     651             :   {"ps",      HB_TAG('P','A','S',' ')},       /* Pashto/Pushto [macrolanguage] */
     652             :   {"pt",      HB_TAG('P','T','G',' ')},       /* Portuguese */
     653             :   {"pwo",     HB_TAG('P','W','O',' ')},       /* Pwo Western Karen */
     654             :   {"qu",      HB_TAG('Q','U','Z',' ')},       /* Quechua [macrolanguage] */
     655             :   {"quc",     HB_TAG('Q','U','C',' ')},       /* K'iche'/Quiché */
     656             :   {"quh",     HB_TAG('Q','U','H',' ')},       /* Quechua (Bolivia) */
     657             :   {"quz",     HB_TAG('Q','U','Z',' ')},       /* Cusco Quechua */
     658             :   {"qvi",     HB_TAG('Q','V','I',' ')},       /* Quechua (Ecuador) */
     659             :   {"qwh",     HB_TAG('Q','W','H',' ')},       /* Quechua (Peru) */
     660             :   {"raj",     HB_TAG('R','A','J',' ')},       /* Rajasthani [macrolanguage] */
     661             :   {"rar",     HB_TAG('R','A','R',' ')},       /* Rarotongan */
     662             :   {"rbb",     HB_TAG('P','L','G',' ')},       /* Rumai Palaung */
     663             :   {"rej",     HB_TAG('R','E','J',' ')},       /* Rejang */
     664             :   {"ria",     HB_TAG('R','I','A',' ')},       /* Riang (India) */
     665             :   {"rif",     HB_TAG('R','I','F',' ')},       /* Tarifit */
     666             :   {"ril",     HB_TAG('R','I','A',' ')},       /* Riang (Myanmar) */
     667             :   {"rit",     HB_TAG('R','I','T',' ')},       /* Ritarungo */
     668             :   {"rki",     HB_TAG('A','R','K',' ')},       /* Rakhine */
     669             :   {"rkw",     HB_TAG('R','K','W',' ')},       /* Arakwal */
     670             :   {"rm",      HB_TAG('R','M','S',' ')},       /* Romansh */
     671             :   {"rmy",     HB_TAG('R','M','Y',' ')},       /* Vlax Romani */
     672             :   {"rn",      HB_TAG('R','U','N',' ')},       /* Rundi */
     673             :   {"ro",      HB_TAG('R','O','M',' ')},       /* Romanian */
     674             :   {"rom",     HB_TAG('R','O','Y',' ')},       /* Romany [macrolanguage] */
     675             :   {"rtm",     HB_TAG('R','T','M',' ')},       /* Rotuman */
     676             :   {"ru",      HB_TAG('R','U','S',' ')},       /* Russian */
     677             :   {"rue",     HB_TAG('R','S','Y',' ')},       /* Rusyn */
     678             :   {"rup",     HB_TAG('R','U','P',' ')},       /* Aromanian/Arumanian/Macedo-Romanian */
     679             :   {"rw",      HB_TAG('R','U','A',' ')},       /* Kinyarwanda */
     680             :   {"rwr",     HB_TAG('M','A','W',' ')},       /* Marwari (India) */
     681             :   {"sa",      HB_TAG('S','A','N',' ')},       /* Sanskrit */
     682             :   {"sah",     HB_TAG('Y','A','K',' ')},       /* Yakut */
     683             :   {"sam",     HB_TAG('P','A','A',' ')},       /* Palestinian Aramaic */
     684             :   {"sas",     HB_TAG('S','A','S',' ')},       /* Sasak */
     685             :   {"sat",     HB_TAG('S','A','T',' ')},       /* Santali */
     686             :   {"sc",      HB_TAG('S','R','D',' ')},       /* Sardinian [macrolanguage] */
     687             :   {"sck",     HB_TAG('S','A','D',' ')},       /* Sadri */
     688             :   {"scn",     HB_TAG('S','C','N',' ')},       /* Sicilian */
     689             :   {"sco",     HB_TAG('S','C','O',' ')},       /* Scots */
     690             :   {"scs",     HB_TAG('S','L','A',' ')},       /* [North] Slavey */
     691             :   {"sd",      HB_TAG('S','N','D',' ')},       /* Sindhi */
     692             :   {"se",      HB_TAG('N','S','M',' ')},       /* Northern Sami */
     693             :   {"seh",     HB_TAG('S','N','A',' ')},       /* Sena */
     694             :   {"sel",     HB_TAG('S','E','L',' ')},       /* Selkup */
     695             :   {"sez",     HB_TAG('Q','I','N',' ')},       /* Senthang Chin */
     696             :   {"sg",      HB_TAG('S','G','O',' ')},       /* Sango */
     697             :   {"sga",     HB_TAG('S','G','A',' ')},       /* Old Irish (to 900) */
     698             :   {"sgs",     HB_TAG('S','G','S',' ')},       /* Samogitian */
     699             :   {"sgw",     HB_TAG('C','H','G',' ')},       /* Sebat Bet Gurage */
     700             : /*{"sgw",     HB_TAG('S','G','W',' ')},*/     /* Sebat Bet Gurage (in SIL fonts) */
     701             :   {"shi",     HB_TAG('S','H','I',' ')},       /* Tachelhit */
     702             :   {"shn",     HB_TAG('S','H','N',' ')},       /* Shan */
     703             :   {"si",      HB_TAG('S','N','H',' ')},       /* Sinhala */
     704             :   {"sid",     HB_TAG('S','I','D',' ')},       /* Sidamo */
     705             :   {"sjd",     HB_TAG('K','S','M',' ')},       /* Kildin Sami */
     706             :   {"sk",      HB_TAG('S','K','Y',' ')},       /* Slovak */
     707             :   {"skr",     HB_TAG('S','R','K',' ')},       /* Seraiki */
     708             :   {"sl",      HB_TAG('S','L','V',' ')},       /* Slovenian */
     709             :   {"sm",      HB_TAG('S','M','O',' ')},       /* Samoan */
     710             :   {"sma",     HB_TAG('S','S','M',' ')},       /* Southern Sami */
     711             :   {"smj",     HB_TAG('L','S','M',' ')},       /* Lule Sami */
     712             :   {"smn",     HB_TAG('I','S','M',' ')},       /* Inari Sami */
     713             :   {"sms",     HB_TAG('S','K','S',' ')},       /* Skolt Sami */
     714             :   {"sn",      HB_TAG('S','N','A','0')},       /* Shona */
     715             :   {"snk",     HB_TAG('S','N','K',' ')},       /* Soninke */
     716             :   {"so",      HB_TAG('S','M','L',' ')},       /* Somali */
     717             :   {"sop",     HB_TAG('S','O','P',' ')},       /* Songe */
     718             :   {"sq",      HB_TAG('S','Q','I',' ')},       /* Albanian [macrolanguage] */
     719             :   {"sr",      HB_TAG('S','R','B',' ')},       /* Serbian */
     720             :   {"srr",     HB_TAG('S','R','R',' ')},       /* Serer */
     721             :   {"ss",      HB_TAG('S','W','Z',' ')},       /* Swati */
     722             :   {"st",      HB_TAG('S','O','T',' ')},       /* [Southern] Sotho */
     723             :   {"stq",     HB_TAG('S','T','Q',' ')},       /* Saterfriesisch */
     724             :   {"stv",     HB_TAG('S','I','G',' ')},       /* Silt'e */
     725             :   {"su",      HB_TAG('S','U','N',' ')},       /* Sundanese */
     726             :   {"suk",     HB_TAG('S','U','K',' ')},       /* Sukama */
     727             :   {"suq",     HB_TAG('S','U','R',' ')},       /* Suri */
     728             :   {"sv",      HB_TAG('S','V','E',' ')},       /* Swedish */
     729             :   {"sva",     HB_TAG('S','V','A',' ')},       /* Svan */
     730             :   {"sw",      HB_TAG('S','W','K',' ')},       /* Swahili [macrolanguage] */
     731             :   {"swb",     HB_TAG('C','M','R',' ')},       /* Comorian */
     732             :   {"swh",     HB_TAG('S','W','K',' ')},       /* Kiswahili/Swahili */
     733             :   {"swv",     HB_TAG('M','A','W',' ')},       /* Shekhawati */
     734             :   {"sxu",     HB_TAG('S','X','U',' ')},       /* Upper Saxon */
     735             :   {"syc",     HB_TAG('S','Y','R',' ')},       /* Classical Syriac */
     736             :   {"syl",     HB_TAG('S','Y','L',' ')},       /* Sylheti */
     737             :   {"syr",     HB_TAG('S','Y','R',' ')},       /* Syriac [macrolanguage] */
     738             :   {"szl",     HB_TAG('S','Z','L',' ')},       /* Silesian */
     739             :   {"ta",      HB_TAG('T','A','M',' ')},       /* Tamil */
     740             :   {"tab",     HB_TAG('T','A','B',' ')},       /* Tabasaran */
     741             :   {"tcp",     HB_TAG('Q','I','N',' ')},       /* Tawr Chin */
     742             :   {"tcy",     HB_TAG('T','U','L',' ')},       /* Tulu */
     743             :   {"tcz",     HB_TAG('Q','I','N',' ')},       /* Thado Chin */
     744             :   {"tdd",     HB_TAG('T','D','D',' ')},       /* Tai Nüa */
     745             :   {"te",      HB_TAG('T','E','L',' ')},       /* Telugu */
     746             :   {"tem",     HB_TAG('T','M','N',' ')},       /* Temne */
     747             :   {"tet",     HB_TAG('T','E','T',' ')},       /* Tetum */
     748             :   {"tg",      HB_TAG('T','A','J',' ')},       /* Tajik */
     749             :   {"th",      HB_TAG('T','H','A',' ')},       /* Thai */
     750             :   {"ti",      HB_TAG('T','G','Y',' ')},       /* Tigrinya */
     751             :   {"tig",     HB_TAG('T','G','R',' ')},       /* Tigre */
     752             :   {"tiv",     HB_TAG('T','I','V',' ')},       /* Tiv */
     753             :   {"tk",      HB_TAG('T','K','M',' ')},       /* Turkmen */
     754             :   {"tl",      HB_TAG('T','G','L',' ')},       /* Tagalog */
     755             :   {"tmh",     HB_TAG('T','M','H',' ')},       /* Tamashek */
     756             :   {"tn",      HB_TAG('T','N','A',' ')},       /* Tswana */
     757             :   {"to",      HB_TAG('T','G','N',' ')},       /* Tonga (Tonga Islands) */
     758             :   {"tod",     HB_TAG('T','O','D','0')},       /* Toma */
     759             :   {"toi",     HB_TAG('T','N','G',' ')},       /* Tonga */
     760             :   {"tpi",     HB_TAG('T','P','I',' ')},       /* Tok Pisin */
     761             :   {"tr",      HB_TAG('T','R','K',' ')},       /* Turkish */
     762             :   {"tru",     HB_TAG('T','U','A',' ')},       /* Turoyo Aramaic */
     763             :   {"ts",      HB_TAG('T','S','G',' ')},       /* Tsonga */
     764             :   {"tt",      HB_TAG('T','A','T',' ')},       /* Tatar */
     765             :   {"tum",     HB_TAG('T','U','M',' ')},       /* Tumbuka */
     766             :   {"tvl",     HB_TAG('T','V','L',' ')},       /* Tuvalu */
     767             :   {"tw",      HB_TAG('T','W','I',' ')},       /* Twi */
     768             :   {"ty",      HB_TAG('T','H','T',' ')},       /* Tahitian */
     769             :   {"tyv",     HB_TAG('T','U','V',' ')},       /* Tuvin */
     770             :   {"tyz",     HB_TAG('T','Y','Z',' ')},       /* Tày */
     771             :   {"tzm",     HB_TAG('T','Z','M',' ')},       /* Central Atlas Tamazight */
     772             :   {"tzo",     HB_TAG('T','Z','O',' ')},       /* Tzotzil */
     773             :   {"udm",     HB_TAG('U','D','M',' ')},       /* Udmurt */
     774             :   {"ug",      HB_TAG('U','Y','G',' ')},       /* Uighur */
     775             :   {"uk",      HB_TAG('U','K','R',' ')},       /* Ukrainian */
     776             :   {"umb",     HB_TAG('U','M','B',' ')},       /* Umbundu */
     777             :   {"unr",     HB_TAG('M','U','N',' ')},       /* Mundari */
     778             :   {"ur",      HB_TAG('U','R','D',' ')},       /* Urdu */
     779             :   {"uz",      HB_TAG('U','Z','B',' ')},       /* Uzbek [macrolanguage] */
     780             :   {"uzn",     HB_TAG('U','Z','B',' ')},       /* Northern Uzbek */
     781             :   {"uzs",     HB_TAG('U','Z','B',' ')},       /* Southern Uzbek */
     782             :   {"ve",      HB_TAG('V','E','N',' ')},       /* Venda */
     783             :   {"vec",     HB_TAG('V','E','C',' ')},       /* Venetian */
     784             :   {"vi",      HB_TAG('V','I','T',' ')},       /* Vietnamese */
     785             :   {"vls",     HB_TAG('F','L','E',' ')},       /* Vlaams */
     786             :   {"vmw",     HB_TAG('M','A','K',' ')},       /* Makhuwa */
     787             :   {"vo",      HB_TAG('V','O','L',' ')},       /* Volapük */
     788             :   {"vro",     HB_TAG('V','R','O',' ')},       /* Võro */
     789             :   {"wa",      HB_TAG('W','L','N',' ')},       /* Walloon */
     790             :   {"war",     HB_TAG('W','A','R',' ')},       /* Waray (Philippines) */
     791             :   {"wbm",     HB_TAG('W','A',' ',' ')},       /* Wa */
     792             :   {"wbr",     HB_TAG('W','A','G',' ')},       /* Wagdi */
     793             :   {"wle",     HB_TAG('S','I','G',' ')},       /* Wolane */
     794             :   {"wo",      HB_TAG('W','L','F',' ')},       /* Wolof */
     795             :   {"wry",     HB_TAG('M','A','W',' ')},       /* Merwari */
     796             :   {"wtm",     HB_TAG('W','T','M',' ')},       /* Mewati */
     797             :   {"xal",     HB_TAG('K','L','M',' ')},       /* Kalmyk */
     798             :   {"xan",     HB_TAG('S','E','K',' ')},       /* Sekota */
     799             :   {"xh",      HB_TAG('X','H','S',' ')},       /* Xhosa */
     800             :   {"xjb",     HB_TAG('X','J','B',' ')},       /* Minjangbal */
     801             :   {"xog",     HB_TAG('X','O','G',' ')},       /* Soga */
     802             :   {"xom",     HB_TAG('K','M','O',' ')},       /* Komo (Sudan) */
     803             :   {"xpe",     HB_TAG('X','P','E',' ')},       /* Kpelle (Liberia) */
     804             :   {"xsl",     HB_TAG('S','S','L',' ')},       /* South Slavey */
     805             :   {"xst",     HB_TAG('S','I','G',' ')},       /* Silt'e (retired code) */
     806             :   {"xwo",     HB_TAG('T','O','D',' ')},       /* Written Oirat (Todo) */
     807             :   {"yao",     HB_TAG('Y','A','O',' ')},       /* Yao */
     808             :   {"yap",     HB_TAG('Y','A','P',' ')},       /* Yapese */
     809             :   {"yi",      HB_TAG('J','I','I',' ')},       /* Yiddish [macrolanguage] */
     810             :   {"yo",      HB_TAG('Y','B','A',' ')},       /* Yoruba */
     811             :   {"yos",     HB_TAG('Q','I','N',' ')},       /* Yos, deprecated by IANA in favor of Zou [zom] */
     812             :   {"yso",     HB_TAG('N','I','S',' ')},       /* Nisi (China) */
     813             :   {"za",      HB_TAG('Z','H','A',' ')},       /* Chuang/Zhuang [macrolanguage] */
     814             :   {"zea",     HB_TAG('Z','E','A',' ')},       /* Zeeuws */
     815             :   {"zgh",     HB_TAG('Z','G','H',' ')},       /* Standard Morrocan Tamazigh */
     816             :   {"zne",     HB_TAG('Z','N','D',' ')},       /* Zande */
     817             :   {"zom",     HB_TAG('Q','I','N',' ')},       /* Zou */
     818             :   {"zu",      HB_TAG('Z','U','L',' ')},       /* Zulu */
     819             :   {"zum",     HB_TAG('L','R','C',' ')},       /* Kumzari */
     820             :   {"zza",     HB_TAG('Z','Z','A',' ')},       /* Zazaki */
     821             : 
     822             :   /* The corresponding languages IDs for the following IDs are unclear,
     823             :    * overlap, or are architecturally weird. Needs more research. */
     824             : 
     825             : /*{"chp",     HB_TAG('S','A','Y',' ')},*/     /* Sayisi */
     826             : /*{"cwd",     HB_TAG('T','C','R',' ')},*/     /* TH-Cree */
     827             : /*{"emk",     HB_TAG('E','M','K',' ')},*/     /* Eastern Maninkakan */
     828             : /*{"krc",     HB_TAG('B','A','L',' ')},*/     /* Balkar */
     829             : /*{"??",      HB_TAG('B','C','R',' ')},*/     /* Bible Cree */
     830             : /*{"zh?",     HB_TAG('C','H','N',' ')},*/     /* Chinese (seen in Microsoft fonts) */
     831             : /*{"ar-Syrc?",        HB_TAG('G','A','R',' ')},*/     /* Garshuni */
     832             : /*{"hy?",     HB_TAG('H','Y','E','0')},*/     /* Armenian East (ISO 639-3 hye according to Microsoft, but that’s equivalent to ISO 639-1 hy) */
     833             : /*{"ga-Latg?/"        HB_TAG('I','R','T',' ')},*/     /* Irish Traditional */
     834             : /*{"krc",     HB_TAG('K','A','R',' ')},*/     /* Karachay */
     835             : /*{"ka-Geok?",        HB_TAG('K','G','E',' ')},*/     /* Khutsuri Georgian */
     836             : /*{"kca",     HB_TAG('K','H','K',' ')},*/     /* Khanty-Kazim */
     837             : /*{"kca",     HB_TAG('K','H','S',' ')},*/     /* Khanty-Shurishkar */
     838             : /*{"kca",     HB_TAG('K','H','V',' ')},*/     /* Khanty-Vakhi */
     839             : /*{"kqs, kss",        HB_TAG('K','I','S',' ')},*/     /* Kisii */
     840             : /*{"lua",     HB_TAG('L','U','A',' ')},*/     /* Luba-Lulua */
     841             : /*{"mlq",     HB_TAG('M','L','N',' ')},*/     /* Malinke */
     842             : /*{"nso",     HB_TAG('N','S','O',' ')},*/     /* Sotho, Northern */
     843             : /*{"??",      HB_TAG('M','A','L',' ')},*/     /* Malayalam Traditional */
     844             : /*{"csw",     HB_TAG('N','C','R',' ')},*/     /* N-Cree */
     845             : /*{"csw",     HB_TAG('N','H','C',' ')},*/     /* Norway House Cree */
     846             : /*{"el-polyton",      HB_TAG('P','G','R',' ')},*/     /* Polytonic Greek */
     847             : /*{"bgr, cnh, cnw, czt, sez, tcp, csy, ctd, flm, pck, tcz, zom, cmr, dao, hlt, cka, cnk, mrh, mwg, cbl, cnb, csh",    HB_TAG('Q','I','N',' ')},*/     /* Chin */
     848             : /*{"??",      HB_TAG('Y','I','C',' ')},*/     /* Yi Classic */
     849             : /*{"zh-Latn-pinyin",  HB_TAG('Z','H','P',' ')},*/     /* Chinese Phonetic */
     850             : };
     851             : 
     852             : typedef struct {
     853             :   char language[11];
     854             :   hb_tag_t tag;
     855             : } LangTagLong;
     856             : static const LangTagLong ot_languages_zh[] = {
     857             :   /* Store longest-first, if one is a prefix of another. */
     858             :   {"zh-cn",   HB_TAG('Z','H','S',' ')},       /* Chinese (China) */
     859             :   {"zh-hk",   HB_TAG('Z','H','H',' ')},       /* Chinese (Hong Kong) */
     860             :   {"zh-mo",   HB_TAG('Z','H','H',' ')},       /* Chinese (Macao) */
     861             :   {"zh-sg",   HB_TAG('Z','H','S',' ')},       /* Chinese (Singapore) */
     862             :   {"zh-tw",   HB_TAG('Z','H','T',' ')},       /* Chinese (Taiwan) */
     863             :   {"zh-hans", HB_TAG('Z','H','S',' ')},       /* Chinese (Simplified) */
     864             :   {"zh-hant-hk",HB_TAG('Z','H','H',' ')},     /* Chinese (Hong Kong) */
     865             :   {"zh-hant-mo",HB_TAG('Z','H','H',' ')},     /* Chinese (Macao) */
     866             :   {"zh-hant", HB_TAG('Z','H','T',' ')},       /* Chinese (Traditional) */
     867             : };
     868             : 
     869             : static int
     870           0 : lang_compare_first_component (const char *a,
     871             :                               const char *b)
     872             : {
     873             :   unsigned int da, db;
     874             :   const char *p;
     875             : 
     876           0 :   p = strchr (a, '-');
     877           0 :   da = p ? (unsigned int) (p - a) : strlen (a);
     878             : 
     879           0 :   p = strchr (b, '-');
     880           0 :   db = p ? (unsigned int) (p - b) : strlen (b);
     881             : 
     882           0 :   return strncmp (a, b, MAX (da, db));
     883             : }
     884             : 
     885             : static hb_bool_t
     886           0 : lang_matches (const char *lang_str, const char *spec)
     887             : {
     888           0 :   unsigned int len = strlen (spec);
     889             : 
     890           0 :   return strncmp (lang_str, spec, len) == 0 &&
     891           0 :          (lang_str[len] == '\0' || lang_str[len] == '-');
     892             : }
     893             : 
     894             : hb_tag_t
     895           2 : hb_ot_tag_from_language (hb_language_t language)
     896             : {
     897             :   const char *lang_str, *s;
     898             : 
     899           2 :   if (language == HB_LANGUAGE_INVALID)
     900           2 :     return HB_OT_TAG_DEFAULT_LANGUAGE;
     901             : 
     902           0 :   lang_str = hb_language_to_string (language);
     903             : 
     904           0 :   s = strstr (lang_str, "x-hbot");
     905           0 :   if (s) {
     906             :     char tag[4];
     907             :     int i;
     908           0 :     s += 6;
     909           0 :     for (i = 0; i < 4 && ISALPHA (s[i]); i++)
     910           0 :       tag[i] = TOUPPER (s[i]);
     911           0 :     if (i) {
     912           0 :       for (; i < 4; i++)
     913           0 :         tag[i] = ' ';
     914           0 :       return HB_TAG_CHAR4 (tag);
     915             :     }
     916             :   }
     917             : 
     918             :   /*
     919             :    * "fonipa" is a variant tag in BCP-47, meaning the International Phonetic Alphabet.
     920             :    * It can be applied to any language.
     921             :    */
     922           0 :   if (strstr (lang_str, "-fonipa")) {
     923           0 :     return HB_TAG('I','P','P','H');  /* Phonetic transcription—IPA conventions */
     924             :   }
     925             : 
     926             :   /*
     927             :    * "fonnapa" is a variant tag in BCP-47, meaning the North American Phonetic Alphabet
     928             :    * also known as Americanist Phonetic Notation.  It can be applied to any language.
     929             :    */
     930           0 :   if (strstr (lang_str, "-fonnapa")) {
     931           0 :     return HB_TAG('A','P','P','H');  /* Phonetic transcription—Americanist conventions */
     932             :   }
     933             : 
     934             :   /*
     935             :    * "Syre" is a BCP-47 script tag, meaning the Estrangela variant of the Syriac script.
     936             :    * It can be applied to any language.
     937             :    */
     938           0 :   if (strstr (lang_str, "-syre")) {
     939           0 :     return HB_TAG('S','Y','R','E');  /* Estrangela Syriac */
     940             :   }
     941             : 
     942             :   /*
     943             :    * "Syrj" is a BCP-47 script tag, meaning the Western variant of the Syriac script.
     944             :    * It can be applied to any language.
     945             :    */
     946           0 :   if (strstr (lang_str, "-syrj")) {
     947           0 :     return HB_TAG('S','Y','R','J');  /* Western Syriac */
     948             :   }
     949             : 
     950             :   /*
     951             :    * "Syrn" is a BCP-47 script tag, meaning the Eastern variant of the Syriac script.
     952             :    * It can be applied to any language.
     953             :    */
     954           0 :   if (strstr (lang_str, "-syrn")) {
     955           0 :     return HB_TAG('S','Y','R','N');  /* Eastern Syriac */
     956             :   }
     957             : 
     958             :   /* Find a language matching in the first component */
     959             :   {
     960             :     const LangTag *lang_tag;
     961           0 :     lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
     962           0 :                                     ARRAY_LENGTH (ot_languages), sizeof (LangTag),
     963           0 :                                     (hb_compare_func_t) lang_compare_first_component);
     964           0 :     if (lang_tag)
     965           0 :       return lang_tag->tag;
     966             :   }
     967             : 
     968             :   /* Otherwise, check the Chinese ones */
     969           0 :   if (0 == lang_compare_first_component (lang_str, "zh"))
     970             :   {
     971             :     unsigned int i;
     972             : 
     973           0 :     for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++)
     974             :     {
     975             :       const LangTagLong *lang_tag;
     976           0 :       lang_tag = &ot_languages_zh[i];
     977           0 :       if (lang_matches (lang_str, lang_tag->language))
     978           0 :         return lang_tag->tag;
     979             :     }
     980             : 
     981             :     /* Otherwise just return 'ZHS ' */
     982           0 :     return HB_TAG('Z','H','S',' ');
     983             :   }
     984             : 
     985           0 :   s = strchr (lang_str, '-');
     986           0 :   if (!s)
     987           0 :     s = lang_str + strlen (lang_str);
     988           0 :   if (s - lang_str == 3) {
     989             :     /* Assume it's ISO-639-3 and upper-case and use it. */
     990           0 :     return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u;
     991             :   }
     992             : 
     993           0 :   return HB_OT_TAG_DEFAULT_LANGUAGE;
     994             : }
     995             : 
     996             : /**
     997             :  * hb_ot_tag_to_language:
     998             :  *
     999             :  * 
    1000             :  *
    1001             :  * Return value: (transfer none):
    1002             :  *
    1003             :  * Since: 0.9.2
    1004             :  **/
    1005             : hb_language_t
    1006          34 : hb_ot_tag_to_language (hb_tag_t tag)
    1007             : {
    1008             :   unsigned int i;
    1009             : 
    1010          34 :   if (tag == HB_OT_TAG_DEFAULT_LANGUAGE)
    1011          34 :     return NULL;
    1012             : 
    1013             :   /* struct LangTag has only room for 3-letter language tags. */
    1014           0 :   switch (tag) {
    1015             :   case HB_TAG('A','P','P','H'):  /* Phonetic transcription—Americanist conventions */
    1016           0 :     return hb_language_from_string ("und-fonnapa", -1);
    1017             :   case HB_TAG('I','P','P','H'):  /* Phonetic transcription—IPA conventions */
    1018           0 :     return hb_language_from_string ("und-fonipa", -1);
    1019             :   case HB_TAG('S','Y','R',' '):  /* Syriac [macrolanguage] */
    1020           0 :     return hb_language_from_string ("syr", -1);
    1021             :   case HB_TAG('S','Y','R','E'):  /* Estrangela Syriac */
    1022           0 :     return hb_language_from_string ("und-Syre", -1);
    1023             :   case HB_TAG('S','Y','R','J'):  /* Western Syriac */
    1024           0 :     return hb_language_from_string ("und-Syrj", -1);
    1025             :   case HB_TAG('S','Y','R','N'):  /* Eastern Syriac */
    1026           0 :     return hb_language_from_string ("und-Syrn", -1);
    1027             :   }
    1028             : 
    1029           0 :   for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
    1030           0 :     if (ot_languages[i].tag == tag)
    1031           0 :       return hb_language_from_string (ot_languages[i].language, -1);
    1032             : 
    1033             :   /* If tag starts with ZH, it's Chinese */
    1034           0 :   if ((tag & 0xFFFF0000u)  == 0x5A480000u) {
    1035           0 :     switch (tag) {
    1036           0 :       case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */
    1037           0 :       case HB_TAG('Z','H','S',' '): return hb_language_from_string ("zh-Hans", -1); /* Simplified */
    1038           0 :       case HB_TAG('Z','H','T',' '): return hb_language_from_string ("zh-Hant", -1); /* Traditional */
    1039           0 :       default: break; /* Fall through */
    1040             :     }
    1041             :   }
    1042             : 
    1043             :   /* Else return a custom language in the form of "x-hbotABCD" */
    1044             :   {
    1045           0 :     unsigned char buf[11] = "x-hbot";
    1046           0 :     buf[6] = tag >> 24;
    1047           0 :     buf[7] = (tag >> 16) & 0xFF;
    1048           0 :     buf[8] = (tag >> 8) & 0xFF;
    1049           0 :     buf[9] = tag & 0xFF;
    1050           0 :     if (buf[9] == 0x20)
    1051           0 :       buf[9] = '\0';
    1052           0 :     buf[10] = '\0';
    1053           0 :     return hb_language_from_string ((char *) buf, -1);
    1054             :   }
    1055             : }
    1056             : 
    1057             : #ifdef MAIN
    1058             : static inline void
    1059             : test_langs_sorted (void)
    1060             : {
    1061             :   for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++)
    1062             :   {
    1063             :     int c = lang_compare_first_component (ot_languages[i-1].language, ot_languages[i].language);
    1064             :     if (c >= 0)
    1065             :     {
    1066             :       fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n",
    1067             :                i, ot_languages[i-1].language, c, ot_languages[i].language);
    1068             :       abort();
    1069             :     }
    1070             :   }
    1071             : }
    1072             : 
    1073             : int
    1074             : main (void)
    1075             : {
    1076             :   test_langs_sorted ();
    1077             :   return 0;
    1078             : }
    1079             : 
    1080             : #endif

Generated by: LCOV version 1.13