]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/uloc.cpp
ICU-57132.0.1.tar.gz
[apple/icu.git] / icuSources / common / uloc.cpp
index 25caee1b56459c935b566491446cf0329e075e73..bf1a5ff6886749bcf0dc59df01f221ab29121251 100644 (file)
@@ -1,6 +1,6 @@
 /*
 **********************************************************************
-*   Copyright (C) 1997-2012, International Business Machines
+*   Copyright (C) 1997-2016, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 **********************************************************************
 *
@@ -38,7 +38,6 @@
 #include "umutex.h"
 #include "cstring.h"
 #include "cmemory.h"
-#include "ucln_cmn.h"
 #include "locmap.h"
 #include "uarrsort.h"
 #include "uenumimp.h"
@@ -92,70 +91,98 @@ locale_getKeywords(const char *localeID,
  *
  * The range qaa-qtz is reserved for local use
  */
+/* Generated using org.unicode.cldr.icu.GenerateISO639LanguageTables */
+/* ISO639 table version is 20150505 */
 static const char * const LANGUAGES[] = {
-    "aa",  "ab",  "ace", "ach", "ada", "ady", "ae",  "af",  "afa",
-    "afh", "agq", "ain", "ak",  "akk", "ale", "alg", "alt", "am",  "an",  
-    "ang", "anp", "apa",
-    "ar",  "arc", "arn", "arp", "art", "arw", "as", "asa", "ast",
-    "ath", "aus", "av",  "awa", "ay",  "az",  "ba",  "bad",
-    "bai", "bal", "ban", "bas", "bat", "be",  "bej",
-    "bem", "ber", "bez", "bg",  "bh",  "bho", "bi",  "bik", "bin",
-    "bla", "bm",  "bn",  "bnt", "bo",  "br",  "bra", "brx", "bs",
-    "btk", "bua", "bug", "byn", "ca",  "cad", "cai", "car", "cau",
-    "cch", "ce",  "ceb", "cel", "cgg", "ch",  "chb", "chg", "chk", "chm",
-    "chn", "cho", "chp", "chr", "chy", "cmc", "co",  "cop",
-    "cpe", "cpf", "cpp", "cr",  "crh", "crp", "cs",  "csb", "cu",  "cus",
-    "cv",  "cy",  "da",  "dak", "dar", "dav", "day", "de",  "del", "den",
-    "dgr", "din", "dje", "doi", "dra", "dsb", "dua", "dum", "dv",  "dyo", "dyu",
-    "dz",  "ebu", "ee",  "efi", "egy", "eka", "el",  "elx", "en",
-    "enm", "eo",  "es",  "et",  "eu",  "ewo", "fa",
-    "fan", "fat", "ff",  "fi",  "fil", "fiu", "fj",  "fo",  "fon",
-    "fr",  "frm", "fro", "frr", "frs", "fur", "fy",  
-    "ga",  "gaa", "gan", "gay", "gba", "gd",  "gem", "gez", "gil", 
-    "gl",  "gmh", "gn",  "goh", "gon", "gor", "got", "grb", 
-    "grc", "gsw", "gu",  "guz", "gv",  "gwi",
-    "ha",  "hai", "hak", "haw", "he",  "hi",  "hil", "him",
-    "hit", "hmn", "ho",  "hr",  "hsb", "hsn", "ht",  "hu",  "hup", "hy",  "hz",
-    "ia",  "iba", "id",  "ie",  "ig",  "ii",  "ijo", "ik",
-    "ilo", "inc", "ine", "inh", "io",  "ira", "iro", "is",  "it",
-    "iu",  "ja",  "jbo", "jmc", "jpr", "jrb", "jv",  "ka",  "kaa", "kab",
-    "kac", "kaj", "kam", "kar", "kaw", "kbd", "kcg", "kde", "kea", "kfo", "kg",  "kha", "khi",
-    "kho", "khq", "ki",  "kj",  "kk",  "kl",  "kln", "km",  "kmb", "kn",
-    "ko",  "kok", "kos", "kpe", "kr",  "krc", "krl", "kro", "kru", "ks", "ksb", "ksf",
-    "ku",  "kum", "kut", "kv",  "kw",  "ky",  "la",  "lad", "lag",
-    "lah", "lam", "lb",  "lez", "lg",  "li",  "ln",  "lo",  "lol",
-    "loz", "lt",  "lu",  "lua", "lui", "lun", "luo", "lus", "luy",
-    "lv",  "mad", "mag", "mai", "mak", "man", "map", "mas",
-    "mdf", "mdr", "men", "mer", "mfe", "mg",  "mga", "mgh", "mh",  "mi",  "mic", "min",
-    "mis", "mk",  "mkh", "ml",  "mn",  "mnc", "mni", "mno",
-    "mo",  "moh", "mos", "mr",  "ms",  "mt",  "mua", "mul", "mun",
-    "mus", "mwl", "mwr", "my",  "myn", "myv", "na",  "nah", "nai", "nan", "nap", "naq",
-    "nb",  "nd",  "nds", "ne",  "new", "ng",  "nia", "nic",
-    "niu", "nl",  "nmg", "nn",  "no",  "nog", "non", "nqo", "nr",  "nso", "nub", "nus",
-    "nv",  "nwc", "ny",  "nym", "nyn", "nyo", "nzi", "oc",  "oj",
-    "om",  "or",  "os",  "osa", "ota", "oto", "pa",  "paa",
-    "pag", "pal", "pam", "pap", "pau", "peo", "phi", "phn",
-    "pi",  "pl",  "pon", "pra", "pro", "ps",  "pt",  "qu",
-    "raj", "rap", "rar", "rm",  "rn",  "ro",  "roa", "rof", "rom",
-    "ru",  "rup", "rw",  "rwk", "sa",  "sad", "sah", "sai", "sal", "sam", "saq",
-    "sas", "sat", "sbp", "sc",  "scn", "sco", "sd",  "se",  "seh", "sel", "sem", "ses",
-    "sg",  "sga", "sgn", "shi", "shn", "si",  "sid", "sio", "sit",
-    "sk",  "sl",  "sla", "sm",  "sma", "smi", "smj", "smn",
-    "sms", "sn",  "snk", "so",  "sog", "son", "sq",  "sr",
-    "srn", "srr", "ss",  "ssa", "st",  "su",  "suk", "sus", "sux",
-    "sv",  "sw",  "swc", "syc", "syr", "ta",  "tai", "te",  "tem", "teo", "ter",
-    "tet", "tg",  "th",  "ti",  "tig", "tiv", "tk",  "tkl",
-    "tl",  "tlh", "tli", "tmh", "tn",  "to",  "tog", "tpi", "tr", "trv",
-    "ts",  "tsi", "tt",  "tum", "tup", "tut", "tvl", "tw", "twq",
-    "ty",  "tyv", "tzm", "udm", "ug",  "uga", "uk",  "umb", "und", "ur",
-    "uz",  "vai", "ve",  "vi",  "vo",  "vot", "vun", "wa",  "wak",
-    "wal", "war", "was", "wen", "wo",  "wuu", "xal", "xh",  "xog", "yao", "yap", "yav",
-    "yi",  "yo",  "ypk", "yue", "za",  "zap", "zbl", "zen", "zh",  "znd",
-    "zu",  "zun", "zxx", "zza",
+    "aa",  "ab",  "ace", "ach", "ada", "ady", "ae",  "aeb", 
+    "af",  "afh", "agq", "ain", "ak",  "akk", "akz", "ale", 
+    "aln", "alt", "am",  "an",  "ang", "anp", "ar",  "arc", 
+    "arn", "aro", "arp", "arq", "ars", "arw", "ary", "arz", "as",  
+    "asa", "ase", "ast", "av",  "avk", "awa", "ay",  "az",  
+    "ba",  "bal", "ban", "bar", "bas", "bax", "bbc", "bbj", 
+    "be",  "bej", "bem", "bew", "bez", "bfd", "bfq", "bg",  
+    "bgn", "bho", "bi",  "bik", "bin", "bjn", "bkm", "bla", 
+    "bm",  "bn",  "bo",  "bpy", "bqi", "br",  "bra", "brh", 
+    "brx", "bs",  "bss", "bua", "bug", "bum", "byn", "byv", 
+    "ca",  "cad", "car", "cay", "cch", "ce",  "ceb", "cgg", 
+    "ch",  "chb", "chg", "chk", "chm", "chn", "cho", "chp", 
+    "chr", "chy", "ckb", "co",  "cop", "cps", "cr",  "crh", 
+    "cs",  "csb", "cu",  "cv",  "cy",  
+    "da",  "dak", "dar", "dav", "de",  "del", "den", "dgr", 
+    "din", "dje", "doi", "dsb", "dtp", "dua", "dum", "dv",  
+    "dyo", "dyu", "dz",  "dzg", 
+    "ebu", "ee",  "efi", "egl", "egy", "eka", "el",  "elx", 
+    "en",  "enm", "eo",  "es",  "esu", "et",  "eu",  "ewo", 
+    "ext", 
+    "fa",  "fan", "fat", "ff",  "fi",  "fil", "fit", "fj",  
+    "fo",  "fon", "fr",  "frc", "frm", "fro", "frp", "frr", 
+    "frs", "fur", "fy",  
+    "ga",  "gaa", "gag", "gan", "gay", "gba", "gbz", "gd",  
+    "gez", "gil", "gl",  "glk", "gmh", "gn",  "goh", "gom", 
+    "gon", "gor", "got", "grb", "grc", "gsw", "gu",  "guc", 
+    "gur", "guz", "gv",  "gwi", 
+    "ha",  "hai", "hak", "haw", "he",  "hi",  "hif", "hil", 
+    "hit", "hmn", "ho",  "hr",  "hsb", "hsn", "ht",  "hu",  
+    "hup", "hy",  "hz",  
+    "ia",  "iba", "ibb", "id",  "ie",  "ig",  "ii",  "ik",  
+    "ilo", "inh", "io",  "is",  "it",  "iu",  "izh", 
+    "ja",  "jam", "jbo", "jgo", "jmc", "jpr", "jrb", "jut", 
+    "jv",  
+    "ka",  "kaa", "kab", "kac", "kaj", "kam", "kaw", "kbd", 
+    "kbl", "kcg", "kde", "kea", "ken", "kfo", "kg",  "kgp", 
+    "kha", "kho", "khq", "khw", "ki",  "kiu", "kj",  "kk",  
+    "kkj", "kl",  "kln", "km",  "kmb", "kn",  "ko",  "koi", 
+    "kok", "kos", "kpe", "kr",  "krc", "kri", "krj", "krl", 
+    "kru", "ks",  "ksb", "ksf", "ksh", "ku",  "kum", "kut", 
+    "kv",  "kw",  "ky",  
+    "la",  "lad", "lag", "lah", "lam", "lb",  "lez", "lfn", 
+    "lg",  "li",  "lij", "liv", "lkt", "lmo", "ln",  "lo",  
+    "lol", "loz", "lrc", "lt",  "ltg", "lu",  "lua", "lui", 
+    "lun", "luo", "lus", "luy", "lv",  "lzh", "lzz", 
+    "mad", "maf", "mag", "mai", "mak", "man", "mas", "mde", 
+    "mdf", "mdh", "mdr", "men", "mer", "mfe", "mg",  "mga", 
+    "mgh", "mgo", "mh",  "mi",  "mic", "min", "mis", "mk",  
+    "ml",  "mn",  "mnc", "mni", "moh", "mos", "mr",  "mrj", 
+    "ms",  "mt",  "mua", "mul", "mus", "mwl", "mwr", "mwv", 
+    "my",  "mye", "myv", "mzn", 
+    "na",  "nan", "nap", "naq", "nb",  "nd",  "nds", "ne",  
+    "new", "ng",  "nia", "niu", "njo", "nl",  "nmg", "nn",  
+    "nnh", "no",  "nog", "non", "nov", "nqo", "nr",  "nso", 
+    "nus", "nv",  "nwc", "ny",  "nym", "nyn", "nyo", "nzi", 
+    "oc",  "oj",  "om",  "or",  "os",  "osa", "ota", 
+    "pa",  "pag", "pal", "pam", "pap", "pau", "pcd", "pdc", 
+    "pdt", "peo", "pfl", "phn", "pi",  "pl",  "pms", "pnt", 
+    "pon", "prg", "pro", "ps",  "pt",  
+    "qu",  "quc", "qug", 
+    "raj", "rap", "rar", "rgn", "rif", "rm",  "rn",  "ro",  
+    "rof", "rom", "rtm", "ru",  "rue", "rug", "rup", 
+    "rw",  "rwk", 
+    "sa",  "sad", "sah", "sam", "saq", "sas", "sat", "saz", 
+    "sba", "sbp", "sc",  "scn", "sco", "sd",  "sdc", "sdh", 
+    "se",  "see", "seh", "sei", "sel", "ses", "sg",  "sga", 
+    "sgs", "shi", "shn", "shu", "si",  "sid", "sk",  
+    "sl",  "sli", "sly", "sm",  "sma", "smj", "smn", "sms", 
+    "sn",  "snk", "so",  "sog", "sq",  "sr",  "srn", "srr", 
+    "ss",  "ssy", "st",  "stq", "su",  "suk", "sus", "sux", 
+    "sv",  "sw",  "swb", "swc", "syc", "syr", "szl", 
+    "ta",  "tcy", "te",  "tem", "teo", "ter", "tet", "tg",  
+    "th",  "ti",  "tig", "tiv", "tk",  "tkl", "tkr", "tl",  
+    "tlh", "tli", "tly", "tmh", "tn",  "to",  "tog", "tpi", 
+    "tr",  "tru", "trv", "ts",  "tsd", "tsi", "tt",  "ttt", 
+    "tum", "tvl", "tw",  "twq", "ty",  "tyv", "tzm", 
+    "udm", "ug",  "uga", "uk",  "umb", "und", "ur",  "uz",  
+    "vai", "ve",  "vec", "vep", "vi",  "vls", "vmf", "vo",  
+    "vot", "vro", "vun", 
+    "wa",  "wae", "wal", "war", "was", "wbp", "wo",  "wuu", 
+    "xal", "xh",  "xmf", "xog", 
+    "yao", "yap", "yav", "ybb", "yi",  "yo",  "yrl", "yue", 
+    "za",  "zap", "zbl", "zea", "zen", "zgh", "zh",  "zu",  
+    "zun", "zxx", "zza", 
 NULL,
     "in",  "iw",  "ji",  "jw",  "sh",    /* obsolete language codes */
 NULL
 };
+
 static const char* const DEPRECATED_LANGUAGES[]={
     "in", "iw", "ji", "jw", NULL, NULL
 };
@@ -179,121 +206,93 @@ static const char* const REPLACEMENT_LANGUAGES[]={
  * second list, and another NULL entry.  The two lists correspond to
  * the two lists in LANGUAGES.
  */
+/* Generated using org.unicode.cldr.icu.GenerateISO639LanguageTables */
+/* ISO639 table version is 20150505 */
 static const char * const LANGUAGES_3[] = {
-/*  "aa",  "ab",  "ace", "ach", "ada", "ady", "ae",  "af",  "afa",    */
-    "aar", "abk", "ace", "ach", "ada", "ady", "ave", "afr", "afa",
-/*  "afh", "agq", "ain", "ak",  "akk", "ale", "alg", "alt", "am",  "an",  "ang", "anp", "apa",    */
-    "afh", "agq", "ain", "aka", "akk", "ale", "alg", "alt", "amh", "arg", "ang", "anp", "apa",
-/*  "ar",  "arc", "arn", "arp", "art", "arw", "as",  "asa", "ast",    */
-    "ara", "arc", "arn", "arp", "art", "arw", "asm", "asa", "ast",
-/*  "ath", "aus", "av",  "awa", "ay",  "az",  "ba",  "bad",    */
-    "ath", "aus", "ava", "awa", "aym", "aze", "bak", "bad",
-/*  "bai", "bal", "ban", "bas", "bat", "be",  "bej",    */
-    "bai", "bal", "ban", "bas", "bat", "bel", "bej",
-/*  "bem", "ber", "bez", "bg",  "bh",  "bho", "bi",  "bik", "bin",    */
-    "bem", "ber", "bez", "bul", "bih", "bho", "bis", "bik", "bin",
-/*  "bla", "bm",  "bn",  "bnt", "bo",  "br",  "bra", "brx", "bs",     */
-    "bla", "bam", "ben", "bnt", "bod", "bre", "bra", "brx", "bos",
-/*  "btk", "bua", "bug", "byn", "ca",  "cad", "cai", "car", "cau",    */
-    "btk", "bua", "bug", "byn", "cat", "cad", "cai", "car", "cau",
-/*  "cch", "ce",  "ceb", "cel", "cgg", "ch",  "chb", "chg", "chk", "chm",    */
-    "cch", "che", "ceb", "cel", "cgg", "cha", "chb", "chg", "chk", "chm",
-/*  "chn", "cho", "chp", "chr", "chy", "cmc", "co",  "cop",    */
-    "chn", "cho", "chp", "chr", "chy", "cmc", "cos", "cop",
-/*  "cpe", "cpf", "cpp", "cr",  "crh", "crp", "cs",  "csb", "cu",  "cus",    */
-    "cpe", "cpf", "cpp", "cre", "crh", "crp", "ces", "csb", "chu", "cus",
-/*  "cv",  "cy",  "da",  "dak", "dar", "dav", "day", "de",  "del", "den",    */
-    "chv", "cym", "dan", "dak", "dar", "dav", "day", "deu", "del", "den",
-/*  "dgr", "din", "dje", "doi", "dra", "dsb", "dua", "dum", "dv",  "dyo", "dyu",    */
-    "dgr", "din", "dje", "doi", "dra", "dsb", "dua", "dum", "div", "dyo", "dyu",
-/*  "dz",  "ebu", "ee",  "efi", "egy", "eka", "el",  "elx", "en",     */
-    "dzo", "ebu", "ewe", "efi", "egy", "eka", "ell", "elx", "eng",
-/*  "enm", "eo",  "es",  "et",  "eu",  "ewo", "fa",     */
-    "enm", "epo", "spa", "est", "eus", "ewo", "fas",
-/*  "fan", "fat", "ff",  "fi",  "fil", "fiu", "fj",  "fo",  "fon",    */
-    "fan", "fat", "ful", "fin", "fil", "fiu", "fij", "fao", "fon",
-/*  "fr",  "frm", "fro", "frr", "frs", "fur", "fy",  "ga",  "gaa", "gan", "gay",    */
-    "fra", "frm", "fro", "frr", "frs", "fur", "fry", "gle", "gaa", "gan", "gay",
-/*  "gba", "gd",  "gem", "gez", "gil", "gl",  "gmh", "gn",     */
-    "gba", "gla", "gem", "gez", "gil", "glg", "gmh", "grn",
-/*  "goh", "gon", "gor", "got", "grb", "grc", "gsw", "gu",  "guz", "gv",     */
-    "goh", "gon", "gor", "got", "grb", "grc", "gsw", "guj", "guz", "glv",
-/*  "gwi", "ha",  "hai", "hak", "haw", "he",  "hi",  "hil", "him",    */
-    "gwi", "hau", "hai", "hak", "haw", "heb", "hin", "hil", "him",
-/*  "hit", "hmn", "ho",  "hr",  "hsb", "hsn", "ht",  "hu",  "hup", "hy",  "hz",     */
-    "hit", "hmn", "hmo", "hrv", "hsb", "hsn", "hat", "hun", "hup", "hye", "her",
-/*  "ia",  "iba", "id",  "ie",  "ig",  "ii",  "ijo", "ik",     */
-    "ina", "iba", "ind", "ile", "ibo", "iii", "ijo", "ipk",
-/*  "ilo", "inc", "ine", "inh", "io",  "ira", "iro", "is",  "it",      */
-    "ilo", "inc", "ine", "inh", "ido", "ira", "iro", "isl", "ita",
-/*  "iu",  "ja",  "jbo", "jmc", "jpr", "jrb", "jv",  "ka",  "kaa", "kab",   */
-    "iku", "jpn", "jbo", "jmc", "jpr", "jrb", "jav", "kat", "kaa", "kab",
-/*  "kac", "kaj", "kam", "kar", "kaw", "kbd", "kcg", "kde", "kea", "kfo", "kg",  "kha", "khi",*/
-    "kac", "kaj", "kam", "kar", "kaw", "kbd", "kcg", "kde", "kea", "kfo", "kg",  "kha", "khi",
-/*  "kho", "khq", "ki",  "kj",  "kk",  "kl",  "kln", "km",  "kmb", "kn",     */
-    "kho", "khq", "kik", "kua", "kaz", "kal", "kln", "khm", "kmb", "kan",
-/*  "ko",  "kok", "kos", "kpe", "kr",  "krc", "krl", "kro", "kru", "ks",  "ksb", "ksf", */
-    "kor", "kok", "kos", "kpe", "kau", "krc", "krl", "kro", "kru", "kas", "ksb", "ksf",
-/*  "ku",  "kum", "kut", "kv",  "kw",  "ky",  "la",  "lad", "lag",    */
-    "kur", "kum", "kut", "kom", "cor", "kir", "lat", "lad", "lag",
-/*  "lah", "lam", "lb",  "lez", "lg",  "li",  "ln",  "lo",  "lol",    */
-    "lah", "lam", "ltz", "lez", "lug", "lim", "lin", "lao", "lol",
-/*  "loz", "lt",  "lu",  "lua", "lui", "lun", "luo", "lus", "luy",   */
-    "loz", "lit", "lub", "lua", "lui", "lun", "luo", "lus", "luy",
-/*  "lv",  "mad", "mag", "mai", "mak", "man", "map", "mas",    */
-    "lav", "mad", "mag", "mai", "mak", "man", "map", "mas",
-/*  "mdf", "mdr", "men", "mer", "mfe", "mg",  "mga", "mgh", "mh",  "mi",  "mic", "min",    */
-    "mdf", "mdr", "men", "mer", "mfe", "mlg", "mga", "mgh", "mah", "mri", "mic", "min",
-/*  "mis", "mk",  "mkh", "ml",  "mn",  "mnc", "mni", "mno",    */
-    "mis", "mkd", "mkh", "mal", "mon", "mnc", "mni", "mno",
-/*  "mo",  "moh", "mos", "mr",  "ms",  "mt",  "mua", "mul", "mun",    */
-    "mol", "moh", "mos", "mar", "msa", "mlt", "mua", "mul", "mun",
-/*  "mus", "mwl", "mwr", "my",  "myn", "myv", "na",  "nah", "nai", "nan", "nap", "naq",   */
-    "mus", "mwl", "mwr", "mya", "myn", "myv", "nau", "nah", "nai", "nan", "nap", "naq",
-/*  "nb",  "nd",  "nds", "ne",  "new", "ng",  "nia", "nic",    */
-    "nob", "nde", "nds", "nep", "new", "ndo", "nia", "nic",
-/*  "niu", "nl",  "nmg", "nn",  "no",  "nog", "non", "nqo", "nr",  "nso", "nub", "nus",   */
-    "niu", "nld", "nmg", "nno", "nor", "nog", "non", "nqo", "nbl", "nso", "nub", "nus",
-/*  "nv",  "nwc", "ny",  "nym", "nyn", "nyo", "nzi", "oc",  "oj",     */
-    "nav", "nwc", "nya", "nym", "nyn", "nyo", "nzi", "oci", "oji",
-/*  "om",  "or",  "os",  "osa", "ota", "oto", "pa",  "paa",    */
-    "orm", "ori", "oss", "osa", "ota", "oto", "pan", "paa",
-/*  "pag", "pal", "pam", "pap", "pau", "peo", "phi", "phn",    */
-    "pag", "pal", "pam", "pap", "pau", "peo", "phi", "phn",
-/*  "pi",  "pl",  "pon", "pra", "pro", "ps",  "pt",  "qu",     */
-    "pli", "pol", "pon", "pra", "pro", "pus", "por", "que",
-/*  "raj", "rap", "rar", "rm",  "rn",  "ro",  "roa", "rof", "rom",    */
-    "raj", "rap", "rar", "roh", "run", "ron", "roa", "rof", "rom",
-/*  "ru",  "rup", "rw",  "rwk", "sa",  "sad", "sah", "sai", "sal", "sam", "saq",    */
-    "rus", "rup", "kin", "rwk", "san", "sad", "sah", "sai", "sal", "sam", "saq",
-/*  "sas", "sat", "sbp", "sc",  "scn", "sco", "sd",  "se",  "seh", "sel", "sem", "ses",    */
-    "sas", "sat", "sbp", "srd", "scn", "sco", "snd", "sme", "seh", "sel", "sem", "ses",
-/*  "sg",  "sga", "sgn", "shi", "shn", "si",  "sid", "sio", "sit",    */
-    "sag", "sga", "sgn", "shi", "shn", "sin", "sid", "sio", "sit",
-/*  "sk",  "sl",  "sla", "sm",  "sma", "smi", "smj", "smn",    */
-    "slk", "slv", "sla", "smo", "sma", "smi", "smj", "smn",
-/*  "sms", "sn",  "snk", "so",  "sog", "son", "sq",  "sr",     */
-    "sms", "sna", "snk", "som", "sog", "son", "sqi", "srp",
-/*  "srn", "srr", "ss",  "ssa", "st",  "su",  "suk", "sus", "sux",    */
-    "srn", "srr", "ssw", "ssa", "sot", "sun", "suk", "sus", "sux",
-/*  "sv",  "sw",  "swc", "syc", "syr", "ta",  "tai", "te",  "tem", "teo", "ter",    */
-    "swe", "swa", "swc", "syc", "syr", "tam", "tai", "tel", "tem", "teo", "ter",
-/*  "tet", "tg",  "th",  "ti",  "tig", "tiv", "tk",  "tkl",    */
-    "tet", "tgk", "tha", "tir", "tig", "tiv", "tuk", "tkl",
-/*  "tl",  "tlh", "tli", "tmh", "tn",  "to",  "tog", "tpi", "tr", "trv",    */
-    "tgl", "tlh", "tli", "tmh", "tsn", "ton", "tog", "tpi", "tur", "trv",
-/*  "ts",  "tsi", "tt",  "tum", "tup", "tut", "tvl", "tw",  "twq"   */
-    "tso", "tsi", "tat", "tum", "tup", "tut", "tvl", "twi", "twq",
-/*  "ty",  "tyv", "tzm", "udm", "ug",  "uga", "uk",  "umb", "und", "ur",     */
-    "tah", "tyv", "tzm", "udm", "uig", "uga", "ukr", "umb", "und", "urd",
-/*  "uz",  "vai", "ve",  "vi",  "vo",  "vot", "vun", "wa",  "wak",    */
-    "uzb", "vai", "ven", "vie", "vol", "vot", "vun", "wln", "wak",
-/*  "wal", "war", "was", "wen", "wo",  "wuu", "xal", "xh",  "xog", "yao", "yap", "yav",   */
-    "wal", "war", "was", "wen", "wol", "wuu", "xal", "xho", "xog", "yao", "yap", "yav",
-/*  "yi",  "yo",  "ypk", "yue", "za",  "zap", "zbl", "zen", "zh",  "znd",    */
-    "yid", "yor", "ypk", "yue", "zha", "zap", "zbl", "zen", "zho", "znd",
-/*  "zu",  "zun", "zxx", "zza",                                         */
-    "zul", "zun", "zxx", "zza",
+    "aar", "abk", "ace", "ach", "ada", "ady", "ave", "aeb", 
+    "afr", "afh", "agq", "ain", "aka", "akk", "akz", "ale", 
+    "aln", "alt", "amh", "arg", "ang", "anp", "ara", "arc", 
+    "arn", "aro", "arp", "arq", "ars", "arw", "ary", "arz", "asm", 
+    "asa", "ase", "ast", "ava", "avk", "awa", "aym", "aze", 
+    "bak", "bal", "ban", "bar", "bas", "bax", "bbc", "bbj", 
+    "bel", "bej", "bem", "bew", "bez", "bfd", "bfq", "bul", 
+    "bgn", "bho", "bis", "bik", "bin", "bjn", "bkm", "bla", 
+    "bam", "ben", "bod", "bpy", "bqi", "bre", "bra", "brh", 
+    "brx", "bos", "bss", "bua", "bug", "bum", "byn", "byv", 
+    "cat", "cad", "car", "cay", "cch", "che", "ceb", "cgg", 
+    "cha", "chb", "chg", "chk", "chm", "chn", "cho", "chp", 
+    "chr", "chy", "ckb", "cos", "cop", "cps", "cre", "crh", 
+    "ces", "csb", "chu", "chv", "cym", 
+    "dan", "dak", "dar", "dav", "deu", "del", "den", "dgr", 
+    "din", "dje", "doi", "dsb", "dtp", "dua", "dum", "div", 
+    "dyo", "dyu", "dzo", "dzg", 
+    "ebu", "ewe", "efi", "egl", "egy", "eka", "ell", "elx", 
+    "eng", "enm", "epo", "spa", "esu", "est", "eus", "ewo", 
+    "ext", 
+    "fas", "fan", "fat", "ful", "fin", "fil", "fit", "fij", 
+    "fao", "fon", "fra", "frc", "frm", "fro", "frp", "frr", 
+    "frs", "fur", "fry", 
+    "gle", "gaa", "gag", "gan", "gay", "gba", "gbz", "gla", 
+    "gez", "gil", "glg", "glk", "gmh", "grn", "goh", "gom", 
+    "gon", "gor", "got", "grb", "grc", "gsw", "guj", "guc", 
+    "gur", "guz", "glv", "gwi", 
+    "hau", "hai", "hak", "haw", "heb", "hin", "hif", "hil", 
+    "hit", "hmn", "hmo", "hrv", "hsb", "hsn", "hat", "hun", 
+    "hup", "hye", "her", 
+    "ina", "iba", "ibb", "ind", "ile", "ibo", "iii", "ipk", 
+    "ilo", "inh", "ido", "isl", "ita", "iku", "izh", 
+    "jpn", "jam", "jbo", "jgo", "jmc", "jpr", "jrb", "jut", 
+    "jav", 
+    "kat", "kaa", "kab", "kac", "kaj", "kam", "kaw", "kbd", 
+    "kbl", "kcg", "kde", "kea", "ken", "kfo", "kon", "kgp", 
+    "kha", "kho", "khq", "khw", "kik", "kiu", "kua", "kaz", 
+    "kkj", "kal", "kln", "khm", "kmb", "kan", "kor", "koi", 
+    "kok", "kos", "kpe", "kau", "krc", "kri", "krj", "krl", 
+    "kru", "kas", "ksb", "ksf", "ksh", "kur", "kum", "kut", 
+    "kom", "cor", "kir", 
+    "lat", "lad", "lag", "lah", "lam", "ltz", "lez", "lfn", 
+    "lug", "lim", "lij", "liv", "lkt", "lmo", "lin", "lao", 
+    "lol", "loz", "lrc", "lit", "ltg", "lub", "lua", "lui", 
+    "lun", "luo", "lus", "luy", "lav", "lzh", "lzz", 
+    "mad", "maf", "mag", "mai", "mak", "man", "mas", "mde", 
+    "mdf", "mdh", "mdr", "men", "mer", "mfe", "mlg", "mga", 
+    "mgh", "mgo", "mah", "mri", "mic", "min", "mis", "mkd", 
+    "mal", "mon", "mnc", "mni", "moh", "mos", "mar", "mrj", 
+    "msa", "mlt", "mua", "mul", "mus", "mwl", "mwr", "mwv", 
+    "mya", "mye", "myv", "mzn", 
+    "nau", "nan", "nap", "naq", "nob", "nde", "nds", "nep", 
+    "new", "ndo", "nia", "niu", "njo", "nld", "nmg", "nno", 
+    "nnh", "nor", "nog", "non", "nov", "nqo", "nbl", "nso", 
+    "nus", "nav", "nwc", "nya", "nym", "nyn", "nyo", "nzi", 
+    "oci", "oji", "orm", "ori", "oss", "osa", "ota", 
+    "pan", "pag", "pal", "pam", "pap", "pau", "pcd", "pdc", 
+    "pdt", "peo", "pfl", "phn", "pli", "pol", "pms", "pnt", 
+    "pon", "prg", "pro", "pus", "por", 
+    "que", "quc", "qug", 
+    "raj", "rap", "rar", "rgn", "rif", "roh", "run", "ron", 
+    "rof", "rom", "rtm", "rus", "rue", "rug", "rup", 
+    "kin", "rwk", 
+    "san", "sad", "sah", "sam", "saq", "sas", "sat", "saz", 
+    "sba", "sbp", "srd", "scn", "sco", "snd", "sdc", "sdh", 
+    "sme", "see", "seh", "sei", "sel", "ses", "sag", "sga", 
+    "sgs", "shi", "shn", "shu", "sin", "sid", "slk", 
+    "slv", "sli", "sly", "smo", "sma", "smj", "smn", "sms", 
+    "sna", "snk", "som", "sog", "sqi", "srp", "srn", "srr", 
+    "ssw", "ssy", "sot", "stq", "sun", "suk", "sus", "sux", 
+    "swe", "swa", "swb", "swc", "syc", "syr", "szl", 
+    "tam", "tcy", "tel", "tem", "teo", "ter", "tet", "tgk", 
+    "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr", "tgl", 
+    "tlh", "tli", "tly", "tmh", "tsn", "ton", "tog", "tpi", 
+    "tur", "tru", "trv", "tso", "tsd", "tsi", "tat", "ttt", 
+    "tum", "tvl", "twi", "twq", "tah", "tyv", "tzm", 
+    "udm", "uig", "uga", "ukr", "umb", "und", "urd", "uzb", 
+    "vai", "ven", "vec", "vep", "vie", "vls", "vmf", "vol", 
+    "vot", "vro", "vun", 
+    "wln", "wae", "wal", "war", "was", "wbp", "wol", "wuu", 
+    "xal", "xho", "xmf", "xog", 
+    "yao", "yap", "yav", "ybb", "yid", "yor", "yrl", "yue", 
+    "zha", "zap", "zbl", "zea", "zen", "zgh", "zho", "zul", 
+    "zun", "zxx", "zza", 
 NULL,
 /*  "in",  "iw",  "ji",  "jw",  "sh",                          */
     "ind", "heb", "yid", "jaw", "srp",
@@ -325,19 +324,19 @@ NULL
  * http://www.iso.org/iso/en/prods-services/iso3166ma/03updates-on-iso-3166/nlv3e-rou.html
  */
 static const char * const COUNTRIES[] = {
-    "AD",  "AE",  "AF",  "AG",  "AI",  "AL",  "AM",  "AN",
+    "AC",  "AD",  "AE",  "AF",  "AG",  "AI",  "AL",  "AM",
     "AO",  "AQ",  "AR",  "AS",  "AT",  "AU",  "AW",  "AX",  "AZ",
     "BA",  "BB",  "BD",  "BE",  "BF",  "BG",  "BH",  "BI",
-    "BJ",  "BL",  "BM",  "BN",  "BO",  "BR",  "BS",  "BT",  "BV",
+    "BJ",  "BL",  "BM",  "BN",  "BO",  "BQ",  "BR",  "BS",  "BT",  "BV",
     "BW",  "BY",  "BZ",  "CA",  "CC",  "CD",  "CF",  "CG",
-    "CH",  "CI",  "CK",  "CL",  "CM",  "CN",  "CO",  "CR",
-    "CU",  "CV",  "CX",  "CY",  "CZ",  "DE",  "DJ",  "DK",
-    "DM",  "DO",  "DZ",  "EC",  "EE",  "EG",  "EH",  "ER",
+    "CH",  "CI",  "CK",  "CL",  "CM",  "CN",  "CO",  "CP",  "CR",
+    "CU",  "CV",  "CW",  "CX",  "CY",  "CZ",  "DE",  "DG",  "DJ",  "DK",
+    "DM",  "DO",  "DZ",  "EA",  "EC",  "EE",  "EG",  "EH",  "ER",
     "ES",  "ET",  "FI",  "FJ",  "FK",  "FM",  "FO",  "FR",
     "GA",  "GB",  "GD",  "GE",  "GF",  "GG",  "GH",  "GI",  "GL",
     "GM",  "GN",  "GP",  "GQ",  "GR",  "GS",  "GT",  "GU",
     "GW",  "GY",  "HK",  "HM",  "HN",  "HR",  "HT",  "HU",
-    "ID",  "IE",  "IL",  "IM",  "IN",  "IO",  "IQ",  "IR",  "IS",
+    "IC",  "ID",  "IE",  "IL",  "IM",  "IN",  "IO",  "IQ",  "IR",  "IS",
     "IT",  "JE",  "JM",  "JO",  "JP",  "KE",  "KG",  "KH",  "KI",
     "KM",  "KN",  "KP",  "KR",  "KW",  "KY",  "KZ",  "LA",
     "LB",  "LC",  "LI",  "LK",  "LR",  "LS",  "LT",  "LU",
@@ -349,23 +348,23 @@ static const char * const COUNTRIES[] = {
     "PH",  "PK",  "PL",  "PM",  "PN",  "PR",  "PS",  "PT",
     "PW",  "PY",  "QA",  "RE",  "RO",  "RS",  "RU",  "RW",  "SA",
     "SB",  "SC",  "SD",  "SE",  "SG",  "SH",  "SI",  "SJ",
-    "SK",  "SL",  "SM",  "SN",  "SO",  "SR",  "ST",  "SV",
-    "SY",  "SZ",  "TC",  "TD",  "TF",  "TG",  "TH",  "TJ",
+    "SK",  "SL",  "SM",  "SN",  "SO",  "SR",  "SS",  "ST",  "SV",
+    "SX",  "SY",  "SZ",  "TA",  "TC",  "TD",  "TF",  "TG",  "TH",  "TJ",
     "TK",  "TL",  "TM",  "TN",  "TO",  "TR",  "TT",  "TV",
     "TW",  "TZ",  "UA",  "UG",  "UM",  "US",  "UY",  "UZ",
     "VA",  "VC",  "VE",  "VG",  "VI",  "VN",  "VU",  "WF",
-    "WS",  "YE",  "YT",  "ZA",  "ZM",  "ZW",
+    "WS",  "XK",  "YE",  "YT",  "ZA",  "ZM",  "ZW",
 NULL,
-    "FX",  "CS",  "RO",  "TP",  "YU",  "ZR",   /* obsolete country codes */
+    "AN",  "BU", "CS", "FX", "RO", "SU", "TP", "YD", "YU", "ZR",   /* obsolete country codes */
 NULL
 };
 
-static const char* const DEPRECATED_COUNTRIES[] ={
-    "BU", "CS", "DY", "FX", "HV", "NH", "RH", "TP", "YU", "ZR", NULL, NULL /* deprecated country list */
+static const char* const DEPRECATED_COUNTRIES[] = {
+    "AN", "BU", "CS", "DD", "DY", "FX", "HV", "NH", "RH", "SU", "TP", "UK", "VD", "YD", "YU", "ZR", NULL, NULL /* deprecated country list */
 };
 static const char* const REPLACEMENT_COUNTRIES[] = {
-/*  "BU", "CS", "DY", "FX", "HV", "NH", "RH", "TP", "YU", "ZR" */
-    "MM", "RS", "BJ", "FR", "BF", "VU", "ZW", "TL", "RS", "CD", NULL, NULL  /* replacement country codes */      
+/*  "AN", "BU", "CS", "DD", "DY", "FX", "HV", "NH", "RH", "SU", "TP", "UK", "VD", "YD", "YU", "ZR" */
+    "CW", "MM", "RS", "DE", "BJ", "FR", "BF", "VU", "ZW", "RU", "TL", "GB", "VN", "YE", "RS", "CD", NULL, NULL  /* replacement country codes */      
 };
     
 /**
@@ -382,22 +381,22 @@ static const char* const REPLACEMENT_COUNTRIES[] = {
  * the two lists in COUNTRIES.
  */
 static const char * const COUNTRIES_3[] = {
-/*  "AD",  "AE",  "AF",  "AG",  "AI",  "AL",  "AM",  "AN",     */
-    "AND", "ARE", "AFG", "ATG", "AIA", "ALB", "ARM", "ANT",
+/*  "AC",  "AD",  "AE",  "AF",  "AG",  "AI",  "AL",  "AM",      */
+    "ASC", "AND", "ARE", "AFG", "ATG", "AIA", "ALB", "ARM",
 /*  "AO",  "AQ",  "AR",  "AS",  "AT",  "AU",  "AW",  "AX",  "AZ",     */
     "AGO", "ATA", "ARG", "ASM", "AUT", "AUS", "ABW", "ALA", "AZE",
 /*  "BA",  "BB",  "BD",  "BE",  "BF",  "BG",  "BH",  "BI",     */
     "BIH", "BRB", "BGD", "BEL", "BFA", "BGR", "BHR", "BDI",
-/*  "BJ",  "BL",  "BM",  "BN",  "BO",  "BR",  "BS",  "BT",  "BV",     */
-    "BEN", "BLM", "BMU", "BRN", "BOL", "BRA", "BHS", "BTN", "BVT",
+/*  "BJ",  "BL",  "BM",  "BN",  "BO",  "BQ",  "BR",  "BS",  "BT",  "BV",     */
+    "BEN", "BLM", "BMU", "BRN", "BOL", "BES", "BRA", "BHS", "BTN", "BVT",
 /*  "BW",  "BY",  "BZ",  "CA",  "CC",  "CD",  "CF",  "CG",     */
     "BWA", "BLR", "BLZ", "CAN", "CCK", "COD", "CAF", "COG",
-/*  "CH",  "CI",  "CK",  "CL",  "CM",  "CN",  "CO",  "CR",     */
-    "CHE", "CIV", "COK", "CHL", "CMR", "CHN", "COL", "CRI",
-/*  "CU",  "CV",  "CX",  "CY",  "CZ",  "DE",  "DJ",  "DK",     */
-    "CUB", "CPV", "CXR", "CYP", "CZE", "DEU", "DJI", "DNK",
-/*  "DM",  "DO",  "DZ",  "EC",  "EE",  "EG",  "EH",  "ER",     */
-    "DMA", "DOM", "DZA", "ECU", "EST", "EGY", "ESH", "ERI",
+/*  "CH",  "CI",  "CK",  "CL",  "CM",  "CN",  "CO",  "CP",  "CR",     */
+    "CHE", "CIV", "COK", "CHL", "CMR", "CHN", "COL", "CPT", "CRI",
+/*  "CU",  "CV",  "CW",  "CX",  "CY",  "CZ",  "DE",  "DG",  "DJ",  "DK",     */
+    "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DGA", "DJI", "DNK",
+/*  "DM",  "DO",  "DZ",  "EA",  "EC",  "EE",  "EG",  "EH",  "ER",     */
+    "DMA", "DOM", "DZA", "EA ", "ECU", "EST", "EGY", "ESH", "ERI", /* no valid 3-letter code for EA */
 /*  "ES",  "ET",  "FI",  "FJ",  "FK",  "FM",  "FO",  "FR",     */
     "ESP", "ETH", "FIN", "FJI", "FLK", "FSM", "FRO", "FRA",
 /*  "GA",  "GB",  "GD",  "GE",  "GF",  "GG",  "GH",  "GI",  "GL",     */
@@ -406,8 +405,8 @@ static const char * const COUNTRIES_3[] = {
     "GMB", "GIN", "GLP", "GNQ", "GRC", "SGS", "GTM", "GUM",
 /*  "GW",  "GY",  "HK",  "HM",  "HN",  "HR",  "HT",  "HU",     */
     "GNB", "GUY", "HKG", "HMD", "HND", "HRV", "HTI", "HUN",
-/*  "ID",  "IE",  "IL",  "IM",  "IN",  "IO",  "IQ",  "IR",  "IS" */
-    "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL",
+/*  "IC",  "ID",  "IE",  "IL",  "IM",  "IN",  "IO",  "IQ",  "IR",  "IS" */
+    "IC ", "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL", /* no valid 3-letter code for IC */
 /*  "IT",  "JE",  "JM",  "JO",  "JP",  "KE",  "KG",  "KH",  "KI",     */
     "ITA", "JEY", "JAM", "JOR", "JPN", "KEN", "KGZ", "KHM", "KIR",
 /*  "KM",  "KN",  "KP",  "KR",  "KW",  "KY",  "KZ",  "LA",     */
@@ -430,21 +429,21 @@ static const char * const COUNTRIES_3[] = {
     "PLW", "PRY", "QAT", "REU", "ROU", "SRB", "RUS", "RWA", "SAU",
 /*  "SB",  "SC",  "SD",  "SE",  "SG",  "SH",  "SI",  "SJ",     */
     "SLB", "SYC", "SDN", "SWE", "SGP", "SHN", "SVN", "SJM",
-/*  "SK",  "SL",  "SM",  "SN",  "SO",  "SR",  "ST",  "SV",     */
-    "SVK", "SLE", "SMR", "SEN", "SOM", "SUR", "STP", "SLV",
-/*  "SY",  "SZ",  "TC",  "TD",  "TF",  "TG",  "TH",  "TJ",     */
-    "SYR", "SWZ", "TCA", "TCD", "ATF", "TGO", "THA", "TJK",
+/*  "SK",  "SL",  "SM",  "SN",  "SO",  "SR",  "SS",  "ST",  "SV",     */
+    "SVK", "SLE", "SMR", "SEN", "SOM", "SUR", "SSD", "STP", "SLV",
+/*  "SX",  "SY",  "SZ",  "TA",  "TC",  "TD",  "TF",  "TG",  "TH",  "TJ",     */
+    "SXM", "SYR", "SWZ", "TAA", "TCA", "TCD", "ATF", "TGO", "THA", "TJK",
 /*  "TK",  "TL",  "TM",  "TN",  "TO",  "TR",  "TT",  "TV",     */
     "TKL", "TLS", "TKM", "TUN", "TON", "TUR", "TTO", "TUV",
 /*  "TW",  "TZ",  "UA",  "UG",  "UM",  "US",  "UY",  "UZ",     */
     "TWN", "TZA", "UKR", "UGA", "UMI", "USA", "URY", "UZB",
 /*  "VA",  "VC",  "VE",  "VG",  "VI",  "VN",  "VU",  "WF",     */
     "VAT", "VCT", "VEN", "VGB", "VIR", "VNM", "VUT", "WLF",
-/*  "WS",  "YE",  "YT",  "ZA",  "ZM",  "ZW",          */
-    "WSM", "YEM", "MYT", "ZAF", "ZMB", "ZWE",
+/*  "WS",  "XK",  "YE",  "YT",  "ZA",  "ZM",  "ZW",          */
+    "WSM", "XKK", "YEM", "MYT", "ZAF", "ZMB", "ZWE",
 NULL,
-/*  "FX",  "CS",  "RO",  "TP",  "YU",  "ZR",   */
-    "FXX", "SCG", "ROM", "TMP", "YUG", "ZAR",
+/*  "AN",  "BU",  "CS",  "FX",  "RO", "SU",  "TP",  "YD",  "YU",  "ZR" */
+    "ANT", "BUR", "SCG", "FXX", "ROM", "SUN", "TMP", "YMD", "YUG", "ZAR",
 NULL
 };
 
@@ -686,6 +685,13 @@ _getKeywords(const char *localeID,
                     keywordList[numKeywords].keyword[n++] = uprv_tolower(pos[i]);
                 }
             }
+
+            /* zero-length keyword is an error. */
+            if (n == 0) {
+                *status = U_INVALID_FORMAT_ERROR;
+                return 0;
+            }
+
             keywordList[numKeywords].keyword[n] = 0;
             keywordList[numKeywords].keywordLen = n;
             /* now grab the value part. First we skip the '=' */
@@ -694,8 +700,15 @@ _getKeywords(const char *localeID,
             while(*equalSign == ' ') {
                 equalSign++;
             }
+
+            /* Premature end or zero-length value */
+            if (!*equalSign || equalSign == semicolon) {
+                *status = U_INVALID_FORMAT_ERROR;
+                return 0;
+            }
+
             keywordList[numKeywords].valueStart = equalSign;
-            
+
             pos = semicolon;
             i = 0;
             if(pos) {
@@ -1009,7 +1022,7 @@ uloc_setKeywordValue(const char* keywordName,
         while(keywordStart[i-1] == ' ') {
             i--;
         }
-        U_ASSERT(i>=0);
+        U_ASSERT(i>=0 && i<ULOC_KEYWORD_BUFFER_LEN);
         localeKeywordNameBuffer[i] = 0;
 
         nextSeparator = uprv_strchr(nextEqualsign, ';');
@@ -1525,7 +1538,7 @@ uloc_openKeywordList(const char *keywordList, int32_t keywordListSize, UErrorCod
         return NULL;
     }
     uprv_memcpy(result, &gKeywordsEnum, sizeof(UEnumeration));
-    myContext = reinterpret_cast<UKeywordsContext *>(uprv_malloc(sizeof(UKeywordsContext)));
+    myContext = static_cast<UKeywordsContext *>(uprv_malloc(sizeof(UKeywordsContext)));
     if (myContext == NULL) {
         *status = U_MEMORY_ALLOCATION_ERROR;
         uprv_free(result);
@@ -1601,7 +1614,7 @@ uloc_openKeywords(const char* localeID,
 #define OPTION_SET(options, mask) ((options & mask) != 0)
 
 static const char i_default[] = {'i', '-', 'd', 'e', 'f', 'a', 'u', 'l', 't'};
-#define I_DEFAULT_LENGTH (sizeof i_default / sizeof i_default[0])
+#define I_DEFAULT_LENGTH UPRV_LENGTHOF(i_default)
 
 /**
  * Canonicalize the given localeID, to level 1 or to level 2,
@@ -1700,8 +1713,8 @@ _canonicalize(const char* localeID,
                 len+=cntrySize;
             }
             if(_isIDSeparator(*tmpLocaleID)) {
-                /* If there is something else, then we add the _  if we found country before.*/
-                if (cntrySize > 0) {
+                /* If there is something else, then we add the _  if we found country before. */
+                if (cntrySize >= 0 && ! _isIDSeparator(*(tmpLocaleID+1)) ) {
                     ++fieldCount;
                     if(len<nameCapacity) {
                         name[len]='_';
@@ -1791,7 +1804,7 @@ _canonicalize(const char* localeID,
 
         /* Handle generic variants first */
         if (variant) {
-            for (j=0; j<(int32_t)(sizeof(VARIANT_MAP)/sizeof(VARIANT_MAP[0])); j++) {
+            for (j=0; j<UPRV_LENGTHOF(VARIANT_MAP); j++) {
                 const char* variantToCompare = VARIANT_MAP[j].variant;
                 int32_t n = (int32_t)uprv_strlen(variantToCompare);
                 int32_t variantLen = _deleteVariant(variant, uprv_min(variantSize, (nameCapacity-len)), variantToCompare, n);
@@ -1811,7 +1824,7 @@ _canonicalize(const char* localeID,
         }
 
         /* Look up the ID in the canonicalization map */
-        for (j=0; j<(int32_t)(sizeof(CANONICALIZE_MAP)/sizeof(CANONICALIZE_MAP[0])); j++) {
+        for (j=0; j<UPRV_LENGTHOF(CANONICALIZE_MAP); j++) {
             const char* id = CANONICALIZE_MAP[j].id;
             int32_t n = (int32_t)uprv_strlen(id);
             if (len == n && uprv_strncmp(name, id, n) == 0) {
@@ -1839,7 +1852,7 @@ _canonicalize(const char* localeID,
             len += _getKeywords(tmpLocaleID+1, '@', (len<nameCapacity ? name+len : NULL), nameCapacity-len,
                                 NULL, 0, NULL, TRUE, addKeyword, addValue, err);
         } else if (addKeyword != NULL) {
-            U_ASSERT(addValue != NULL);
+            U_ASSERT(addValue != NULL && len < nameCapacity);
             /* inelegant but works -- later make _getKeywords do this? */
             len += _copyCount(name+len, nameCapacity-len, "@");
             len += _copyCount(name+len, nameCapacity-len, addKeyword);
@@ -2103,6 +2116,39 @@ uloc_getLCID(const char* localeID)
         return 0;
     }
 
+    if (uprv_strchr(localeID, '@')) {
+        // uprv_convertToLCID does not support keywords other than collation.
+        // Remove all keywords except collation.
+        int32_t len;
+        char collVal[ULOC_KEYWORDS_CAPACITY];
+        char tmpLocaleID[ULOC_FULLNAME_CAPACITY];
+
+        len = uloc_getKeywordValue(localeID, "collation", collVal,
+            UPRV_LENGTHOF(collVal) - 1, &status);
+
+        if (U_SUCCESS(status) && len > 0) {
+            collVal[len] = 0;
+
+            len = uloc_getBaseName(localeID, tmpLocaleID,
+                UPRV_LENGTHOF(tmpLocaleID) - 1, &status);
+
+            if (U_SUCCESS(status) && len > 0) {
+                tmpLocaleID[len] = 0;
+
+                len = uloc_setKeywordValue("collation", collVal, tmpLocaleID,
+                    UPRV_LENGTHOF(tmpLocaleID) - len - 1, &status);
+
+                if (U_SUCCESS(status) && len > 0) {
+                    tmpLocaleID[len] = 0;
+                    return uprv_convertToLCID(langID, tmpLocaleID, &status);
+                }
+            }
+        }
+
+        // fall through - all keywords are simply ignored
+        status = U_ZERO_ERROR;
+    }
+
     return uprv_convertToLCID(langID, localeID, &status);
 }
 
@@ -2110,19 +2156,7 @@ U_CAPI int32_t U_EXPORT2
 uloc_getLocaleForLCID(uint32_t hostid, char *locale, int32_t localeCapacity,
                 UErrorCode *status)
 {
-    int32_t length;
-    const char *posix = uprv_convertToPosix(hostid, status);
-    if (U_FAILURE(*status) || posix == NULL) {
-        return 0;
-    }
-    length = (int32_t)uprv_strlen(posix);
-    if (length+1 > localeCapacity) {
-        *status = U_BUFFER_OVERFLOW_ERROR;
-    }
-    else {
-        uprv_strcpy(locale, posix);
-    }
-    return length;
+    return uprv_convertToPosix(hostid, locale, localeCapacity, status);
 }
 
 /* ### Default locale **************************************************/
@@ -2146,7 +2180,7 @@ uloc_setDefault(const char*   newDefaultLocale,
 }
 
 /**
- * Returns a list of all language codes defined in ISO 639.  This is a pointer
+ * Returns a list of all 2-letter language codes defined in ISO 639.  This is a pointer
  * to an array of pointers to arrays of char.  All of these pointers are owned
  * by ICU-- do not delete them, and do not write through them.  The array is
  * terminated with a null pointer.
@@ -2270,7 +2304,7 @@ uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult
     char *tempstr; /* Use for null pointer check */
 
     j = smallBuffer;
-    jSize = sizeof(smallBuffer)/sizeof(smallBuffer[0]);
+    jSize = UPRV_LENGTHOF(smallBuffer);
     if(U_FAILURE(*status)) {
         return -1;
     }
@@ -2315,7 +2349,7 @@ uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult
             return -1;
         }
         j[n].locale = tempstr;
-        uloc_canonicalize(j[n].locale,tmp,sizeof(tmp)/sizeof(tmp[0]),status);
+        uloc_canonicalize(j[n].locale,tmp,UPRV_LENGTHOF(tmp),status);
         if(strcmp(j[n].locale,tmp)) {
             uprv_free(j[n].locale);
             j[n].locale=uprv_strdup(tmp);
@@ -2330,7 +2364,7 @@ uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult
         }
         if(n>=jSize) {
             if(j==smallBuffer) {  /* overflowed the small buffer. */
-                j = reinterpret_cast<_acceptLangItem *>(uprv_malloc(sizeof(j[0])*(jSize*2)));
+                j = static_cast<_acceptLangItem *>(uprv_malloc(sizeof(j[0])*(jSize*2)));
                 if(j!=NULL) {
                     uprv_memcpy(j,smallBuffer,sizeof(j[0])*jSize);
                 }
@@ -2338,7 +2372,7 @@ uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult
                 fprintf(stderr,"malloced at size %d\n", jSize);
 #endif
             } else {
-                j = reinterpret_cast<_acceptLangItem *>(uprv_realloc(j, sizeof(j[0])*jSize*2));
+                j = static_cast<_acceptLangItem *>(uprv_realloc(j, sizeof(j[0])*jSize*2));
 #if defined(ULOC_DEBUG)
                 fprintf(stderr,"re-alloced at size %d\n", jSize);
 #endif
@@ -2360,7 +2394,7 @@ uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult
         }
         return -1;
     }
-    strs = reinterpret_cast<char **>(uprv_malloc((size_t)(sizeof(strs[0])*n)));
+    strs = static_cast<char **>(uprv_malloc((size_t)(sizeof(strs[0])*n)));
     /* Check for null pointer */
     if (strs == NULL) {
         uprv_free(j); /* Free to avoid memory leak */
@@ -2405,7 +2439,7 @@ uloc_acceptLanguage(char *result, int32_t resultAvailable,
     if(U_FAILURE(*status)) {
         return -1;
     }
-    fallbackList = reinterpret_cast<char **>(uprv_malloc((size_t)(sizeof(fallbackList[0])*acceptListCount)));
+    fallbackList = static_cast<char **>(uprv_malloc((size_t)(sizeof(fallbackList[0])*acceptListCount)));
     if(fallbackList==NULL) {
         *status = U_MEMORY_ALLOCATION_ERROR;
         return -1;
@@ -2441,7 +2475,7 @@ uloc_acceptLanguage(char *result, int32_t resultAvailable,
         }
         uenum_reset(availableLocales, status);    
         /* save off parent info */
-        if(uloc_getParent(acceptList[i], tmp, sizeof(tmp)/sizeof(tmp[0]), status)!=0) {
+        if(uloc_getParent(acceptList[i], tmp, UPRV_LENGTHOF(tmp), status)!=0) {
             fallbackList[i] = uprv_strdup(tmp);
         } else {
             fallbackList[i]=0;
@@ -2478,7 +2512,7 @@ uloc_acceptLanguage(char *result, int32_t resultAvailable,
                 }
                 uenum_reset(availableLocales, status);    
 
-                if(uloc_getParent(fallbackList[i], tmp, sizeof(tmp)/sizeof(tmp[0]), status)!=0) {
+                if(uloc_getParent(fallbackList[i], tmp, UPRV_LENGTHOF(tmp), status)!=0) {
                     uprv_free(fallbackList[i]);
                     fallbackList[i] = uprv_strdup(tmp);
                 } else {
@@ -2498,4 +2532,104 @@ uloc_acceptLanguage(char *result, int32_t resultAvailable,
     return -1;
 }
 
+U_CAPI const char* U_EXPORT2
+uloc_toUnicodeLocaleKey(const char* keyword)
+{
+    const char* bcpKey = ulocimp_toBcpKey(keyword);
+    if (bcpKey == NULL && ultag_isUnicodeLocaleKey(keyword, -1)) {
+        // unknown keyword, but syntax is fine..
+        return keyword;
+    }
+    return bcpKey;
+}
+
+U_CAPI const char* U_EXPORT2
+uloc_toUnicodeLocaleType(const char* keyword, const char* value)
+{
+    const char* bcpType = ulocimp_toBcpType(keyword, value, NULL, NULL);
+    if (bcpType == NULL && ultag_isUnicodeLocaleType(value, -1)) {
+        // unknown keyword, but syntax is fine..
+        return value;
+    }
+    return bcpType;
+}
+
+#define UPRV_ISDIGIT(c) (((c) >= '0') && ((c) <= '9'))
+#define UPRV_ISALPHANUM(c) (uprv_isASCIILetter(c) || UPRV_ISDIGIT(c) )
+
+static UBool
+isWellFormedLegacyKey(const char* legacyKey)
+{
+    const char* p = legacyKey;
+    while (*p) {
+        if (!UPRV_ISALPHANUM(*p)) {
+            return FALSE;
+        }
+        p++;
+    }
+    return TRUE;
+}
+
+static UBool
+isWellFormedLegacyType(const char* legacyType)
+{
+    const char* p = legacyType;
+    int32_t alphaNumLen = 0;
+    while (*p) {
+        if (*p == '_' || *p == '/' || *p == '-') {
+            if (alphaNumLen == 0) {
+                return FALSE;
+            }
+            alphaNumLen = 0;
+        } else if (UPRV_ISALPHANUM(*p)) {
+            alphaNumLen++;
+        } else {
+            return FALSE;
+        }
+        p++;
+    }
+    return (alphaNumLen != 0);
+}
+
+U_CAPI const char* U_EXPORT2
+uloc_toLegacyKey(const char* keyword)
+{
+    const char* legacyKey = ulocimp_toLegacyKey(keyword);
+    if (legacyKey == NULL) {
+        // Checks if the specified locale key is well-formed with the legacy locale syntax.
+        //
+        // Note:
+        //  Neither ICU nor LDML/CLDR provides the definition of keyword syntax.
+        //  However, a key should not contain '=' obviously. For now, all existing
+        //  keys are using ASCII alphabetic letters only. We won't add any new key
+        //  that is not compatible with the BCP 47 syntax. Therefore, we assume
+        //  a valid key consist from [0-9a-zA-Z], no symbols.
+        if (isWellFormedLegacyKey(keyword)) {
+            return keyword;
+        }
+    }
+    return legacyKey;
+}
+
+U_CAPI const char* U_EXPORT2
+uloc_toLegacyType(const char* keyword, const char* value)
+{
+    const char* legacyType = ulocimp_toLegacyType(keyword, value, NULL, NULL);
+    if (legacyType == NULL) {
+        // Checks if the specified locale type is well-formed with the legacy locale syntax.
+        //
+        // Note:
+        //  Neither ICU nor LDML/CLDR provides the definition of keyword syntax.
+        //  However, a type should not contain '=' obviously. For now, all existing
+        //  types are using ASCII alphabetic letters with a few symbol letters. We won't
+        //  add any new type that is not compatible with the BCP 47 syntax except timezone
+        //  IDs. For now, we assume a valid type start with [0-9a-zA-Z], but may contain
+        //  '-' '_' '/' in the middle.
+        if (isWellFormedLegacyType(value)) {
+            return value;
+        }
+    }
+    return legacyType;
+}
+
 /*eof*/