| 1 | // SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later |
| 2 | // Copyright 2010, SIL International, All rights reserved. |
| 3 | |
| 4 | #pragma once |
| 5 | #include <cstring> |
| 6 | #include <cassert> |
| 7 | |
| 8 | #include "inc/Main.h" |
| 9 | |
| 10 | |
| 11 | namespace graphite2 { |
| 12 | |
| 13 | struct IsoLangEntry |
| 14 | { |
| 15 | unsigned short mnLang; |
| 16 | char maLangStr[4]; |
| 17 | char maCountry[3]; |
| 18 | }; |
| 19 | |
| 20 | // Windows Language ID, Locale ISO-639 language, country code as used in |
| 21 | // naming table of OpenType fonts |
| 22 | const IsoLangEntry LANG_ENTRIES[] = { |
| 23 | { 0x0401, "ar" ,"SA" }, // Arabic Saudi Arabia |
| 24 | { 0x0402, "bg" ,"BG" }, // Bulgarian Bulgaria |
| 25 | { 0x0403, "ca" ,"ES" }, // Catalan Catalan |
| 26 | { 0x0404, "zh" ,"TW" }, // Chinese Taiwan |
| 27 | { 0x0405, "cs" ,"CZ" }, // Czech Czech Republic |
| 28 | { 0x0406, "da" ,"DK" }, // Danish Denmark |
| 29 | { 0x0407, "de" ,"DE" }, // German Germany |
| 30 | { 0x0408, "el" ,"GR" }, // Greek Greece |
| 31 | { 0x0409, "en" ,"US" }, // English United States |
| 32 | { 0x040A, "es" ,"ES" }, // Spanish (Traditional Sort) Spain |
| 33 | { 0x040B, "fi" ,"FI" }, // Finnish Finland |
| 34 | { 0x040C, "fr" ,"FR" }, // French France |
| 35 | { 0x040D, "he" ,"IL" }, // Hebrew Israel |
| 36 | { 0x040E, "hu" ,"HU" }, // Hungarian Hungary |
| 37 | { 0x040F, "is" ,"IS" }, // Icelandic Iceland |
| 38 | { 0x0410, "it" ,"IT" }, // Italian Italy |
| 39 | { 0x0411, "jp" ,"JP" }, // Japanese Japan |
| 40 | { 0x0412, "ko" ,"KR" }, // Korean Korea |
| 41 | { 0x0413, "nl" ,"NL" }, // Dutch Netherlands |
| 42 | { 0x0414, "no" ,"NO" }, // Norwegian (Bokmal) Norway |
| 43 | { 0x0415, "pl" ,"PL" }, // Polish Poland |
| 44 | { 0x0416, "pt" ,"BR" }, // Portuguese Brazil |
| 45 | { 0x0417, "rm" ,"CH" }, // Romansh Switzerland |
| 46 | { 0x0418, "ro" ,"RO" }, // Romanian Romania |
| 47 | { 0x0419, "ru" ,"RU" }, // Russian Russia |
| 48 | { 0x041A, "hr" ,"HR" }, // Croatian Croatia |
| 49 | { 0x041B, "sk" ,"SK" }, // Slovak Slovakia |
| 50 | { 0x041C, "sq" ,"AL" }, // Albanian Albania |
| 51 | { 0x041D, "sv" ,"SE" }, // Swedish Sweden |
| 52 | { 0x041E, "th" ,"TH" }, // Thai Thailand |
| 53 | { 0x041F, "tr" ,"TR" }, // Turkish Turkey |
| 54 | { 0x0420, "ur" ,"PK" }, // Urdu Islamic Republic of Pakistan |
| 55 | { 0x0421, "id" ,"ID" }, // Indonesian Indonesia |
| 56 | { 0x0422, "uk" ,"UA" }, // Ukrainian Ukraine |
| 57 | { 0x0423, "be" ,"BY" }, // Belarusian Belarus |
| 58 | { 0x0424, "sl" ,"SI" }, // Slovenian Slovenia |
| 59 | { 0x0425, "et" ,"EE" }, // Estonian Estonia |
| 60 | { 0x0426, "lv" ,"LV" }, // Latvian Latvia |
| 61 | { 0x0427, "lt" ,"LT" }, // Lithuanian Lithuania |
| 62 | { 0x0428, "tg" ,"TJ" }, // Tajik (Cyrillic) Tajikistan |
| 63 | { 0x042A, "vi" ,"VN" }, // Vietnamese Vietnam |
| 64 | { 0x042B, "hy" ,"AM" }, // Armenian Armenia |
| 65 | { 0x042C, "az" ,"AZ" }, // Azeri (Latin) Azerbaijan |
| 66 | { 0x042D, "eu" ,"" }, // Basque Basque |
| 67 | { 0x042E, "hsb" ,"DE" }, // Upper Sorbian Germany |
| 68 | { 0x042F, "mk" ,"MK" }, // Macedonian (FYROM) Former Yugoslav Republic of Macedonia |
| 69 | { 0x0432, "tn" ,"ZA" }, // Setswana South Africa |
| 70 | { 0x0434, "xh" ,"ZA" }, // isiXhosa South Africa |
| 71 | { 0x0435, "zu" ,"ZA" }, // isiZulu South Africa |
| 72 | { 0x0436, "af" ,"ZA" }, // Afrikaans South Africa |
| 73 | { 0x0437, "ka" ,"GE" }, // Georgian Georgia |
| 74 | { 0x0438, "fo" ,"FO" }, // Faroese Faroe Islands |
| 75 | { 0x0439, "hi" ,"IN" }, // Hindi India |
| 76 | { 0x043A, "mt" ,"MT" }, // Maltese Malta |
| 77 | { 0x043B, "se" ,"NO" }, // Sami (Northern) Norway |
| 78 | { 0x043E, "ms" ,"MY" }, // Malay Malaysia |
| 79 | { 0x043F, "kk" ,"KZ" }, // Kazakh Kazakhstan |
| 80 | { 0x0440, "ky" ,"KG" }, // Kyrgyz Kyrgyzstan |
| 81 | { 0x0441, "sw" ,"KE" }, // Kiswahili Kenya |
| 82 | { 0x0442, "tk" ,"TM" }, // Turkmen Turkmenistan |
| 83 | { 0x0443, "uz" ,"UZ" }, // Uzbek (Latin) Uzbekistan |
| 84 | { 0x0444, "tt" ,"RU" }, // Tatar Russia |
| 85 | { 0x0445, "bn" ,"IN" }, // Bengali India |
| 86 | { 0x0446, "pa" ,"IN" }, // Punjabi India |
| 87 | { 0x0447, "gu" ,"IN" }, // Gujarati India |
| 88 | { 0x0448, "or" ,"IN" }, // Oriya India |
| 89 | { 0x0448, "wo" ,"SN" }, // Wolof Senegal |
| 90 | { 0x0449, "ta" ,"IN" }, // Tamil India |
| 91 | { 0x044A, "te" ,"IN" }, // Telugu India |
| 92 | { 0x044B, "kn" ,"IN" }, // Kannada India |
| 93 | { 0x044C, "ml" ,"IN" }, // Malayalam India |
| 94 | { 0x044D, "as" ,"IN" }, // Assamese India |
| 95 | { 0x044E, "mr" ,"IN" }, // Marathi India |
| 96 | { 0x044F, "sa" ,"IN" }, // Sanskrit India |
| 97 | { 0x0450, "mn" ,"MN" }, // Mongolian (Cyrillic) Mongolia |
| 98 | { 0x0451, "bo" ,"CN" }, // Tibetan PRC |
| 99 | { 0x0452, "cy" ,"GB" }, // Welsh United Kingdom |
| 100 | { 0x0453, "km" ,"KH" }, // Khmer Cambodia |
| 101 | { 0x0454, "lo" ,"LA" }, // Lao Lao P.D.R. |
| 102 | { 0x0455, "my" ,"MM" }, // Burmese Myanmar - not listed in Microsoft docs anymore |
| 103 | { 0x0456, "gl" ,"ES" }, // Galician Galician |
| 104 | { 0x0457, "kok" ,"IN" }, // Konkani India |
| 105 | { 0x045A, "syr" ,"TR" }, // Syriac Syria |
| 106 | { 0x045B, "si" ,"LK" }, // Sinhala Sri Lanka |
| 107 | { 0x045D, "iu" ,"CA" }, // Inuktitut Canada |
| 108 | { 0x045E, "am" ,"ET" }, // Amharic Ethiopia |
| 109 | { 0x0461, "ne" ,"NP" }, // Nepali Nepal |
| 110 | { 0x0462, "fy" ,"NL" }, // Frisian Netherlands |
| 111 | { 0x0463, "ps" ,"AF" }, // Pashto Afghanistan |
| 112 | { 0x0464, "fil" ,"PH" }, // Filipino Philippines |
| 113 | { 0x0465, "dv" ,"MV" }, // Divehi Maldives |
| 114 | { 0x0468, "ha" ,"NG" }, // Hausa (Latin) Nigeria |
| 115 | { 0x046A, "yo" ,"NG" }, // Yoruba Nigeria |
| 116 | { 0x046B, "qu" ,"BO" }, // Quechua Bolivia |
| 117 | { 0x046C, "st" ,"ZA" }, // Sesotho sa Leboa South Africa |
| 118 | { 0x046D, "ba" ,"RU" }, // Bashkir Russia |
| 119 | { 0x046E, "lb" ,"LU" }, // Luxembourgish Luxembourg |
| 120 | { 0x046F, "kl" ,"GL" }, // Greenlandic Greenland |
| 121 | { 0x0470, "ig" ,"NG" }, // Igbo Nigeria |
| 122 | { 0x0478, "ii" ,"CN" }, // Yi PRC |
| 123 | { 0x047A, "arn" ,"CL" }, // Mapudungun Chile |
| 124 | { 0x047C, "moh" ,"CA" }, // Mohawk Mohawk |
| 125 | { 0x047E, "br" ,"FR" }, // Breton France |
| 126 | { 0x0480, "ug" ,"CN" }, // Uighur PRC |
| 127 | { 0x0481, "mi" ,"NZ" }, // Maori New Zealand |
| 128 | { 0x0482, "oc" ,"FR" }, // Occitan France |
| 129 | { 0x0483, "co" ,"FR" }, // Corsican France |
| 130 | { 0x0484, "gsw" ,"FR" }, // Alsatian France |
| 131 | { 0x0485, "sah" ,"RU" }, // Yakut Russia |
| 132 | { 0x0486, "qut" ,"GT" }, // K'iche Guatemala |
| 133 | { 0x0487, "rw" ,"RW" }, // Kinyarwanda Rwanda |
| 134 | { 0x048C, "gbz" ,"AF" }, // Dari Afghanistan |
| 135 | { 0x0801, "ar" ,"IQ" }, // Arabic Iraq |
| 136 | { 0x0804, "zn" ,"CH" }, // Chinese People's Republic of China |
| 137 | { 0x0807, "de" ,"CH" }, // German Switzerland |
| 138 | { 0x0809, "en" ,"GB" }, // English United Kingdom |
| 139 | { 0x080A, "es" ,"MX" }, // Spanish Mexico |
| 140 | { 0x080C, "fr" ,"BE" }, // French Belgium |
| 141 | { 0x0810, "it" ,"CH" }, // Italian Switzerland |
| 142 | { 0x0813, "nl" ,"BE" }, // Dutch Belgium |
| 143 | { 0x0814, "nn" ,"NO" }, // Norwegian (Nynorsk) Norway |
| 144 | { 0x0816, "pt" ,"PT" }, // Portuguese Portugal |
| 145 | { 0x081A, "sh" ,"RS" }, // Serbian (Latin) Serbia |
| 146 | { 0x081D, "sv" ,"FI" }, // Sweden Finland |
| 147 | { 0x082C, "az" ,"AZ" }, // Azeri (Cyrillic) Azerbaijan |
| 148 | { 0x082E, "dsb" ,"DE" }, // Lower Sorbian Germany |
| 149 | { 0x083B, "se" ,"SE" }, // Sami (Northern) Sweden |
| 150 | { 0x083C, "ga" ,"IE" }, // Irish Ireland |
| 151 | { 0x083E, "ms" ,"BN" }, // Malay Brunei Darussalam |
| 152 | { 0x0843, "uz" ,"UZ" }, // Uzbek (Cyrillic) Uzbekistan |
| 153 | { 0x0845, "bn" ,"BD" }, // Bengali Bangladesh |
| 154 | { 0x0850, "mn" ,"MN" }, // Mongolian (Traditional) People's Republic of China |
| 155 | { 0x085D, "iu" ,"CA" }, // Inuktitut (Latin) Canada |
| 156 | { 0x085F, "ber" ,"DZ" }, // Tamazight (Latin) Algeria |
| 157 | { 0x086B, "es" ,"EC" }, // Quechua Ecuador |
| 158 | { 0x0C01, "ar" ,"EG" }, // Arabic Egypt |
| 159 | { 0x0C04, "zh" ,"HK" }, // Chinese Hong Kong S.A.R. |
| 160 | { 0x0C07, "de" ,"AT" }, // German Austria |
| 161 | { 0x0C09, "en" ,"AU" }, // English Australia |
| 162 | { 0x0C0A, "es" ,"ES" }, // Spanish (Modern Sort) Spain |
| 163 | { 0x0C0C, "fr" ,"CA" }, // French Canada |
| 164 | { 0x0C1A, "sr" ,"CS" }, // Serbian (Cyrillic) Serbia |
| 165 | { 0x0C3B, "se" ,"FI" }, // Sami (Northern) Finland |
| 166 | { 0x0C6B, "qu" ,"PE" }, // Quechua Peru |
| 167 | { 0x1001, "ar" ,"LY" }, // Arabic Libya |
| 168 | { 0x1004, "zh" ,"SG" }, // Chinese Singapore |
| 169 | { 0x1007, "de" ,"LU" }, // German Luxembourg |
| 170 | { 0x1009, "en" ,"CA" }, // English Canada |
| 171 | { 0x100A, "es" ,"GT" }, // Spanish Guatemala |
| 172 | { 0x100C, "fr" ,"CH" }, // French Switzerland |
| 173 | { 0x101A, "hr" ,"BA" }, // Croatian (Latin) Bosnia and Herzegovina |
| 174 | { 0x103B, "smj" ,"NO" }, // Sami (Lule) Norway |
| 175 | { 0x1401, "ar" ,"DZ" }, // Arabic Algeria |
| 176 | { 0x1404, "zh" ,"MO" }, // Chinese Macao S.A.R. |
| 177 | { 0x1407, "de" ,"LI" }, // German Liechtenstein |
| 178 | { 0x1409, "en" ,"NZ" }, // English New Zealand |
| 179 | { 0x140A, "es" ,"CR" }, // Spanish Costa Rica |
| 180 | { 0x140C, "fr" ,"LU" }, // French Luxembourg |
| 181 | { 0x141A, "bs" ,"BA" }, // Bosnian (Latin) Bosnia and Herzegovina |
| 182 | { 0x143B, "smj" ,"SE" }, // Sami (Lule) Sweden |
| 183 | { 0x1801, "ar" ,"MA" }, // Arabic Morocco |
| 184 | { 0x1809, "en" ,"IE" }, // English Ireland |
| 185 | { 0x180A, "es" ,"PA" }, // Spanish Panama |
| 186 | { 0x180C, "fr" ,"MC" }, // French Principality of Monoco |
| 187 | { 0x181A, "sh" ,"BA" }, // Serbian (Latin) Bosnia and Herzegovina |
| 188 | { 0x183B, "sma" ,"NO" }, // Sami (Southern) Norway |
| 189 | { 0x1C01, "ar" ,"TN" }, // Arabic Tunisia |
| 190 | { 0x1C09, "en" ,"ZA" }, // English South Africa |
| 191 | { 0x1C0A, "es" ,"DO" }, // Spanish Dominican Republic |
| 192 | { 0x1C1A, "sr" ,"BA" }, // Serbian (Cyrillic) Bosnia and Herzegovina |
| 193 | { 0x1C3B, "sma" ,"SE" }, // Sami (Southern) Sweden |
| 194 | { 0x2001, "ar" ,"OM" }, // Arabic Oman |
| 195 | { 0x2009, "en" ,"JM" }, // English Jamaica |
| 196 | { 0x200A, "es" ,"VE" }, // Spanish Venezuela |
| 197 | { 0x201A, "bs" ,"BA" }, // Bosnian (Cyrillic) Bosnia and Herzegovina |
| 198 | { 0x203B, "sms" ,"FI" }, // Sami (Skolt) Finland |
| 199 | { 0x2401, "ar" ,"YE" }, // Arabic Yemen |
| 200 | { 0x2409, "en" ,"BS" }, // English Caribbean |
| 201 | { 0x240A, "es" ,"CO" }, // Spanish Colombia |
| 202 | { 0x243B, "smn" ,"FI" }, // Sami (Inari) Finland |
| 203 | { 0x2801, "ar" ,"SY" }, // Arabic Syria |
| 204 | { 0x2809, "en" ,"BZ" }, // English Belize |
| 205 | { 0x280A, "es" ,"PE" }, // Spanish Peru |
| 206 | { 0x2C01, "ar" ,"JO" }, // Arabic Jordan |
| 207 | { 0x2C09, "en" ,"TT" }, // English Trinidad and Tobago |
| 208 | { 0x2C0A, "es" ,"AR" }, // Spanish Argentina |
| 209 | { 0x3001, "ar" ,"LB" }, // Arabic Lebanon |
| 210 | { 0x3009, "en" ,"ZW" }, // English Zimbabwe |
| 211 | { 0x300A, "es" ,"EC" }, // Spanish Ecuador |
| 212 | { 0x3401, "ar" ,"KW" }, // Arabic Kuwait |
| 213 | { 0x3409, "en" ,"PH" }, // English Republic of the Philippines |
| 214 | { 0x340A, "es" ,"CL" }, // Spanish Chile |
| 215 | { 0x3801, "ar" ,"AE" }, // Arabic U.A.E. |
| 216 | { 0x380A, "es" ,"UY" }, // Spanish Uruguay |
| 217 | { 0x3C01, "ar" ,"BH" }, // Arabic Bahrain |
| 218 | { 0x3C0A, "es" ,"PY" }, // Spanish Paraguay |
| 219 | { 0x4001, "ar" ,"QA" }, // Arabic Qatar |
| 220 | { 0x4009, "en" ,"IN" }, // English India |
| 221 | { 0x400A, "es" ,"BO" }, // Spanish Bolivia |
| 222 | { 0x4409, "en" ,"MY" }, // English Malaysia |
| 223 | { 0x440A, "es" ,"SV" }, // Spanish El Salvador |
| 224 | { 0x4809, "en" ,"SG" }, // English Singapore |
| 225 | { 0x480A, "es" ,"HN" }, // Spanish Honduras |
| 226 | { 0x4C0A, "es" ,"NI" }, // Spanish Nicaragua |
| 227 | { 0x500A, "es" ,"PR" }, // Spanish Puerto Rico |
| 228 | { 0x540A, "es" ,"US" } // Spanish United States |
| 229 | }; |
| 230 | |
| 231 | class Locale2Lang |
| 232 | { |
| 233 | Locale2Lang(const Locale2Lang &); |
| 234 | Locale2Lang & operator = (const Locale2Lang &); |
| 235 | |
| 236 | public: |
| 237 | Locale2Lang() : mSeedPosition(128) |
| 238 | { |
| 239 | memset((void*)mLangLookup, 0, sizeof(mLangLookup)); |
| 240 | // create a tri lookup on first 2 letters of language code |
| 241 | static const int maxIndex = sizeof(LANG_ENTRIES)/sizeof(IsoLangEntry); |
| 242 | for (int i = 0; i < maxIndex; i++) |
| 243 | { |
| 244 | size_t a = LANG_ENTRIES[i].maLangStr[0] - 'a'; |
| 245 | size_t b = LANG_ENTRIES[i].maLangStr[1] - 'a'; |
| 246 | if (mLangLookup[a][b]) |
| 247 | { |
| 248 | const IsoLangEntry ** old = mLangLookup[a][b]; |
| 249 | int len = 1; |
| 250 | while (old[len]) len++; |
| 251 | len += 2; |
| 252 | mLangLookup[a][b] = gralloc<const IsoLangEntry *>(len); |
| 253 | if (!mLangLookup[a][b]) |
| 254 | { |
| 255 | mLangLookup[a][b] = old; |
| 256 | continue; |
| 257 | } |
| 258 | mLangLookup[a][b][--len] = NULL; |
| 259 | mLangLookup[a][b][--len] = &LANG_ENTRIES[i]; |
| 260 | while (--len >= 0) |
| 261 | { |
| 262 | assert(len >= 0); |
| 263 | mLangLookup[a][b][len] = old[len]; |
| 264 | } |
| 265 | free(old); |
| 266 | } |
| 267 | else |
| 268 | { |
| 269 | mLangLookup[a][b] = gralloc<const IsoLangEntry *>(2); |
| 270 | if (!mLangLookup[a][b]) continue; |
| 271 | mLangLookup[a][b][1] = NULL; |
| 272 | mLangLookup[a][b][0] = &LANG_ENTRIES[i]; |
| 273 | } |
| 274 | } |
| 275 | while (2 * mSeedPosition < maxIndex) |
| 276 | mSeedPosition *= 2; |
| 277 | }; |
| 278 | ~Locale2Lang() |
| 279 | { |
| 280 | for (int i = 0; i != 26; ++i) |
| 281 | for (int j = 0; j != 26; ++j) |
| 282 | free(mLangLookup[i][j]); |
| 283 | } |
| 284 | unsigned short getMsId(const char * locale) const |
| 285 | { |
| 286 | size_t length = strlen(locale); |
| 287 | size_t langLength = length; |
| 288 | const char * language = locale; |
| 289 | const char * script = NULL; |
| 290 | const char * region = NULL; |
| 291 | size_t regionLength = 0; |
| 292 | const char * dash = strchr(locale, '-'); |
| 293 | if (dash && (dash != locale)) |
| 294 | { |
| 295 | langLength = (dash - locale); |
| 296 | size_t nextPartLength = length - langLength - 1; |
| 297 | if (nextPartLength >= 2) |
| 298 | { |
| 299 | script = ++dash; |
| 300 | dash = strchr(dash, '-'); |
| 301 | if (dash) |
| 302 | { |
| 303 | nextPartLength = (dash - script); |
| 304 | region = ++dash; |
| 305 | } |
| 306 | if (nextPartLength == 2 && |
| 307 | (locale[langLength+1] > 0x40) && (locale[langLength+1] < 0x5B) && |
| 308 | (locale[langLength+2] > 0x40) && (locale[langLength+2] < 0x5B)) |
| 309 | { |
| 310 | region = script; |
| 311 | regionLength = nextPartLength; |
| 312 | script = NULL; |
| 313 | } |
| 314 | else if (nextPartLength == 4) |
| 315 | { |
| 316 | if (dash) |
| 317 | { |
| 318 | dash = strchr(dash, '-'); |
| 319 | if (dash) |
| 320 | { |
| 321 | nextPartLength = (dash - region); |
| 322 | } |
| 323 | else |
| 324 | { |
| 325 | nextPartLength = langLength - (region - locale); |
| 326 | } |
| 327 | regionLength = nextPartLength; |
| 328 | } |
| 329 | } |
| 330 | } |
| 331 | } |
| 332 | size_t a = 'e' - 'a'; |
| 333 | size_t b = 'n' - 'a'; |
| 334 | unsigned short langId = 0; |
| 335 | int i = 0; |
| 336 | switch (langLength) |
| 337 | { |
| 338 | case 2: |
| 339 | { |
| 340 | a = language[0] - 'a'; |
| 341 | b = language[1] - 'a'; |
| 342 | if ((a < 26) && (b < 26) && mLangLookup[a][b]) |
| 343 | { |
| 344 | while (mLangLookup[a][b][i]) |
| 345 | { |
| 346 | if (mLangLookup[a][b][i]->maLangStr[2] != '\0') |
| 347 | { |
| 348 | ++i; |
| 349 | continue; |
| 350 | } |
| 351 | if (region && (strncmp(mLangLookup[a][b][i]->maCountry, region, regionLength) == 0)) |
| 352 | { |
| 353 | langId = mLangLookup[a][b][i]->mnLang; |
| 354 | break; |
| 355 | } |
| 356 | else if (langId == 0) |
| 357 | { |
| 358 | // possible fallback code |
| 359 | langId = mLangLookup[a][b][i]->mnLang; |
| 360 | } |
| 361 | ++i; |
| 362 | } |
| 363 | } |
| 364 | } |
| 365 | break; |
| 366 | case 3: |
| 367 | { |
| 368 | a = language[0] - 'a'; |
| 369 | b = language[1] - 'a'; |
| 370 | if (mLangLookup[a][b]) |
| 371 | { |
| 372 | while (mLangLookup[a][b][i]) |
| 373 | { |
| 374 | if (mLangLookup[a][b][i]->maLangStr[2] != language[2]) |
| 375 | { |
| 376 | ++i; |
| 377 | continue; |
| 378 | } |
| 379 | if (region && (strncmp(mLangLookup[a][b][i]->maCountry, region, regionLength) == 0)) |
| 380 | { |
| 381 | langId = mLangLookup[a][b][i]->mnLang; |
| 382 | break; |
| 383 | } |
| 384 | else if (langId == 0) |
| 385 | { |
| 386 | // possible fallback code |
| 387 | langId = mLangLookup[a][b][i]->mnLang; |
| 388 | } |
| 389 | ++i; |
| 390 | } |
| 391 | } |
| 392 | } |
| 393 | break; |
| 394 | default: |
| 395 | break; |
| 396 | } |
| 397 | if (langId == 0) langId = 0x409; |
| 398 | return langId; |
| 399 | } |
| 400 | const IsoLangEntry * findEntryById(unsigned short langId) const |
| 401 | { |
| 402 | static const int maxIndex = sizeof(LANG_ENTRIES)/sizeof(IsoLangEntry); |
| 403 | int window = mSeedPosition; |
| 404 | int guess = mSeedPosition - 1; |
| 405 | while (LANG_ENTRIES[guess].mnLang != langId) |
| 406 | { |
| 407 | window /= 2; |
| 408 | if (window == 0) return NULL; |
| 409 | guess += (LANG_ENTRIES[guess].mnLang > langId)? -window : window; |
| 410 | while (guess >= maxIndex) |
| 411 | { |
| 412 | window /= 2; |
| 413 | guess -= window; |
| 414 | assert(window); |
| 415 | } |
| 416 | } |
| 417 | return &LANG_ENTRIES[guess]; |
| 418 | } |
| 419 | |
| 420 | CLASS_NEW_DELETE; |
| 421 | |
| 422 | private: |
| 423 | const IsoLangEntry ** mLangLookup[26][26]; |
| 424 | int mSeedPosition; |
| 425 | }; |
| 426 | |
| 427 | } // namespace graphite2 |
| 428 | |