diff --git a/thirdparty/README.md b/thirdparty/README.md index 0047f1c66c3..31b19451b3f 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -208,7 +208,7 @@ Files extracted from upstream source: ## harfbuzz - Upstream: https://github.com/harfbuzz/harfbuzz -- Version: 4.2.1 (f7aee78e90bc53b3a95eb56d7550c9effe569ea2, 2022) +- Version: 4.3.0 (aee123fc83388b8f5acfb301d87bd92eccc5b843, 2022) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/harfbuzz/src/hb-algs.hh b/thirdparty/harfbuzz/src/hb-algs.hh index c40a55cd1fa..05b4df52f15 100644 --- a/thirdparty/harfbuzz/src/hb-algs.hh +++ b/thirdparty/harfbuzz/src/hb-algs.hh @@ -150,10 +150,26 @@ struct BEInt uint8_t ((V >> 16) & 0xFF), uint8_t ((V >> 8) & 0xFF), uint8_t ((V ) & 0xFF)} {} - constexpr operator Type () const { return (v[0] << 24) - + (v[1] << 16) - + (v[2] << 8) - + (v[3] ); } + + struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + constexpr operator Type () const { +#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ + defined(__BYTE_ORDER) && \ + (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) + /* Spoon-feed the compiler a big-endian integer with alignment 1. + * https://github.com/harfbuzz/harfbuzz/pull/1398 */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + return __builtin_bswap32 (((packed_uint32_t *) this)->v); +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + return ((packed_uint32_t *) this)->v; +#endif +#else + return (v[0] << 24) + + (v[1] << 16) + + (v[2] << 8) + + (v[3] ); +#endif + } private: uint8_t v[4]; }; @@ -213,11 +229,11 @@ HB_FUNCOBJ (hb_bool); template static inline -T hb_coerce (const T v) { return v; } +constexpr T hb_coerce (const T v) { return v; } template , hb_decay) && std::is_pointer::value)> static inline -T hb_coerce (const V v) { return *v; } +constexpr T hb_coerce (const V v) { return *v; } struct { diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh index 1d1476d7cda..1963698cf7f 100644 --- a/thirdparty/harfbuzz/src/hb-array.hh +++ b/thirdparty/harfbuzz/src/hb-array.hh @@ -346,7 +346,7 @@ struct hb_sorted_array_t : unsigned int i; return bfind (x, &i) ? &this->arrayZ[i] : not_found; } - template + template const Type *bsearch (const T &x, const Type *not_found = nullptr) const { unsigned int i; @@ -384,15 +384,16 @@ struct hb_sorted_array_t : } return false; } - template - bool bsearch_impl (const T &x, unsigned *pos) const + template + bool bsearch_impl (const T &x, unsigned *pos, Ts... ds) const { return hb_bsearch_impl (pos, x, this->arrayZ, this->length, sizeof (Type), - _hb_cmp_method); + _hb_cmp_method, + ds...); } }; template inline hb_sorted_array_t @@ -403,7 +404,7 @@ hb_sorted_array (T (&array_)[length_]) { return hb_sorted_array_t (array_); } template -bool hb_array_t::operator == (const hb_array_t &o) const +inline bool hb_array_t::operator == (const hb_array_t &o) const { if (o.length != this->length) return false; for (unsigned int i = 0; i < this->length; i++) { @@ -411,8 +412,18 @@ bool hb_array_t::operator == (const hb_array_t &o) const } return true; } - -/* TODO Specialize operator== for hb_bytes_t and hb_ubytes_t. */ +template <> +inline bool hb_array_t::operator == (const hb_array_t &o) const +{ + if (o.length != this->length) return false; + return 0 == hb_memcmp (arrayZ, o.arrayZ, length); +} +template <> +inline bool hb_array_t::operator == (const hb_array_t &o) const +{ + if (o.length != this->length) return false; + return 0 == hb_memcmp (arrayZ, o.arrayZ, length); +} template <> inline uint32_t hb_array_t::hash () const { @@ -421,7 +432,6 @@ inline uint32_t hb_array_t::hash () const { current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); return current; } - template <> inline uint32_t hb_array_t::hash () const { uint32_t current = 0; diff --git a/thirdparty/harfbuzz/src/hb-bimap.hh b/thirdparty/harfbuzz/src/hb-bimap.hh index a9e1278de70..5b313bf59c7 100644 --- a/thirdparty/harfbuzz/src/hb-bimap.hh +++ b/thirdparty/harfbuzz/src/hb-bimap.hh @@ -39,6 +39,12 @@ struct hb_bimap_t back_map.reset (); } + void resize (unsigned pop) + { + forw_map.resize (pop); + back_map.resize (pop); + } + bool in_error () const { return forw_map.in_error () || back_map.in_error (); } void set (hb_codepoint_t lhs, hb_codepoint_t rhs) diff --git a/thirdparty/harfbuzz/src/hb-bit-page.hh b/thirdparty/harfbuzz/src/hb-bit-page.hh index 97598366544..cbe918ee401 100644 --- a/thirdparty/harfbuzz/src/hb-bit-page.hh +++ b/thirdparty/harfbuzz/src/hb-bit-page.hh @@ -40,11 +40,18 @@ struct hb_bit_page_t bool is_empty () const { - for (unsigned int i = 0; i < len (); i++) + for (unsigned i = 0; i < len (); i++) if (v[i]) return false; return true; } + uint32_t hash () const + { + uint32_t h = 0; + for (unsigned i = 0; i < len (); i++) + h = h * 31 + hb_hash (v[i]); + return h; + } void add (hb_codepoint_t g) { elt (g) |= mask (g); } void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } diff --git a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh index 4a4ce340537..caea47d8d3f 100644 --- a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh +++ b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh @@ -38,10 +38,10 @@ struct hb_bit_set_invertible_t bool inverted = false; hb_bit_set_invertible_t () = default; - hb_bit_set_invertible_t (hb_bit_set_invertible_t& o) = default; - hb_bit_set_invertible_t (hb_bit_set_invertible_t&& o) = default; + hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default; + hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) : hb_bit_set_invertible_t () { hb_swap (*this, other); } hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default; - hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& o) = default; + hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) { hb_swap (*this, other); return *this; } friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) { if (likely (!a.s.successful || !b.s.successful)) @@ -56,6 +56,7 @@ struct hb_bit_set_invertible_t bool in_error () const { return s.in_error (); } explicit operator bool () const { return !is_empty (); } + void alloc (unsigned sz) { s.alloc (sz); } void reset () { s.reset (); @@ -79,6 +80,8 @@ struct hb_bit_set_invertible_t next (&v); return v == INVALID; } + uint32_t hash () const { return s.hash () ^ inverted; } + hb_codepoint_t get_min () const { hb_codepoint_t v = INVALID; diff --git a/thirdparty/harfbuzz/src/hb-bit-set.hh b/thirdparty/harfbuzz/src/hb-bit-set.hh index fcaff9f3be3..11a4359dc90 100644 --- a/thirdparty/harfbuzz/src/hb-bit-set.hh +++ b/thirdparty/harfbuzz/src/hb-bit-set.hh @@ -97,6 +97,13 @@ struct hb_bit_set_t return true; } + void alloc (unsigned sz) + { + sz >>= (page_t::PAGE_BITS_LOG_2 - 1); + pages.alloc (sz); + page_map.alloc (sz); + } + void reset () { successful = true; @@ -119,6 +126,14 @@ struct hb_bit_set_t } explicit operator bool () const { return !is_empty (); } + uint32_t hash () const + { + uint32_t h = 0; + for (auto &map : page_map) + h = h * 31 + hb_hash (map.major) + hb_hash (pages[map.index]); + return h; + } + private: void dirty () { population = UINT_MAX; } public: @@ -341,15 +356,14 @@ struct hb_bit_set_t return; population = other.population; - /* TODO switch to vector operator =. */ - hb_memcpy ((void *) pages, (const void *) other.pages, count * pages.item_size); - hb_memcpy ((void *) page_map, (const void *) other.page_map, count * page_map.item_size); + page_map = other.page_map; + pages = other.pages; } bool is_equal (const hb_bit_set_t &other) const { if (has_population () && other.has_population () && - get_population () != other.get_population ()) + population != other.population) return false; unsigned int na = pages.length; @@ -377,7 +391,7 @@ struct hb_bit_set_t bool is_subset (const hb_bit_set_t &larger_set) const { if (has_population () && larger_set.has_population () && - get_population () != larger_set.get_population ()) + population != larger_set.population) return false; uint32_t spi = 0; @@ -874,7 +888,19 @@ struct hb_bit_set_t page_t *page_for (hb_codepoint_t g, bool insert = false) { - page_map_t map = {get_major (g), pages.length}; + unsigned major = get_major (g); + + /* The extra page_map length is necessary; can't just rely on vector here, + * since the next check would be tricked because a null page also has + * major==0, which we can't distinguish from an actualy major==0 page... */ + if (likely (last_page_lookup < page_map.length)) + { + auto &cached_page = page_map.arrayZ[last_page_lookup]; + if (cached_page.major == major) + return &pages[cached_page.index]; + } + + page_map_t map = {major, pages.length}; unsigned int i; if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST)) { @@ -890,15 +916,31 @@ struct hb_bit_set_t (page_map.length - 1 - i) * page_map.item_size); page_map[i] = map; } + + last_page_lookup = i; return &pages[page_map[i].index]; } const page_t *page_for (hb_codepoint_t g) const { - page_map_t key = {get_major (g)}; - const page_map_t *found = page_map.bsearch (key); - if (found) - return &pages[found->index]; - return nullptr; + unsigned major = get_major (g); + + /* The extra page_map length is necessary; can't just rely on vector here, + * since the next check would be tricked because a null page also has + * major==0, which we can't distinguish from an actualy major==0 page... */ + if (likely (last_page_lookup < page_map.length)) + { + auto &cached_page = page_map.arrayZ[last_page_lookup]; + if (cached_page.major == major) + return &pages[cached_page.index]; + } + + page_map_t key = {major}; + unsigned int i; + if (!page_map.bfind (key, &i)) + return nullptr; + + last_page_lookup = i; + return &pages[page_map[i].index]; } page_t &page_at (unsigned int i) { return pages[page_map[i].index]; } const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; } diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh index 641de0eff2b..5c2cb060a41 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh @@ -248,6 +248,9 @@ struct number_t /* byte string */ struct UnsizedByteStr : UnsizedArrayOf { + hb_ubytes_t as_ubytes (unsigned l) const + { return hb_ubytes_t ((const unsigned char *) this, l); } + // encode 2-byte int (Dict/CharString) or 4-byte int (Dict) template static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value) @@ -274,33 +277,10 @@ struct UnsizedByteStr : UnsizedArrayOf /* Defining null_size allows a Null object may be created. Should be safe because: * A descendent struct Dict uses a Null pointer to indicate a missing table, * checked before access. - * byte_str_t, a wrapper struct pairing a byte pointer along with its length, always - * checks the length before access. A Null pointer is used as the initial pointer - * along with zero length by the default ctor. */ DEFINE_SIZE_MIN(0); }; -/* Holder of a section of byte string within a CFFIndex entry */ -struct byte_str_t : hb_ubytes_t -{ - byte_str_t () - : hb_ubytes_t () {} - byte_str_t (const UnsizedByteStr& s, unsigned int l) - : hb_ubytes_t ((const unsigned char*)&s, l) {} - byte_str_t (const unsigned char *s, unsigned int l) - : hb_ubytes_t (s, l) {} - byte_str_t (const hb_ubytes_t &ub) /* conversion from hb_ubytes_t */ - : hb_ubytes_t (ub) {} - - /* sub-string */ - byte_str_t sub_str (unsigned int offset, unsigned int len_) const - { return byte_str_t (hb_ubytes_t::sub_array (offset, len_)); } - - bool check_limit (unsigned int offset, unsigned int count) const - { return (offset + count <= length); } -}; - /* A byte string associated with the current offset and an error condition */ struct byte_str_ref_t { @@ -308,17 +288,17 @@ struct byte_str_ref_t void init () { - str = byte_str_t (); + str = hb_ubytes_t (); offset = 0; error = false; } void fini () {} - byte_str_ref_t (const byte_str_t &str_, unsigned int offset_ = 0) + byte_str_ref_t (const hb_ubytes_t &str_, unsigned int offset_ = 0) : str (str_), offset (offset_), error (false) {} - void reset (const byte_str_t &str_, unsigned int offset_ = 0) + void reset (const hb_ubytes_t &str_, unsigned int offset_ = 0) { str = str_; offset = offset_; @@ -334,14 +314,14 @@ struct byte_str_ref_t return str[offset + i]; } - /* Conversion to byte_str_t */ - operator byte_str_t () const { return str.sub_str (offset, str.length - offset); } + /* Conversion to hb_ubytes_t */ + operator hb_ubytes_t () const { return str.sub_array (offset, str.length - offset); } - byte_str_t sub_str (unsigned int offset_, unsigned int len_) const - { return str.sub_str (offset_, len_); } + hb_ubytes_t sub_array (unsigned int offset_, unsigned int len_) const + { return str.sub_array (offset_, len_); } bool avail (unsigned int count=1) const - { return (!in_error () && str.check_limit (offset, count)); } + { return (!in_error () && offset + count <= str.length); } void inc (unsigned int count=1) { if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length))) @@ -358,44 +338,39 @@ struct byte_str_ref_t void set_error () { error = true; } bool in_error () const { return error; } - byte_str_t str; + hb_ubytes_t str; unsigned int offset; /* beginning of the sub-string within str */ protected: bool error; }; -typedef hb_vector_t byte_str_array_t; +using byte_str_array_t = hb_vector_t; /* stack */ template struct cff_stack_t { - void init () - { - error = false; - count = 0; - elements.init (); - elements.resize (kSizeLimit); - } - void fini () { elements.fini (); } - ELEM& operator [] (unsigned int i) { - if (unlikely (i >= count)) set_error (); + if (unlikely (i >= count)) + { + set_error (); + return Crap (ELEM); + } return elements[i]; } void push (const ELEM &v) { - if (likely (count < elements.length)) + if (likely (count < LIMIT)) elements[count++] = v; else set_error (); } ELEM &push () { - if (likely (count < elements.length)) + if (likely (count < LIMIT)) return elements[count++]; else { @@ -424,7 +399,7 @@ struct cff_stack_t const ELEM& peek () { - if (unlikely (count < 0)) + if (unlikely (count == 0)) { set_error (); return Null (ELEM); @@ -434,7 +409,7 @@ struct cff_stack_t void unpop () { - if (likely (count < elements.length)) + if (likely (count < LIMIT)) count++; else set_error (); @@ -442,18 +417,19 @@ struct cff_stack_t void clear () { count = 0; } - bool in_error () const { return (error || elements.in_error ()); } + bool in_error () const { return (error); } void set_error () { error = true; } unsigned int get_count () const { return count; } bool is_empty () const { return !count; } - static constexpr unsigned kSizeLimit = LIMIT; + hb_array_t sub_array (unsigned start, unsigned length) const + { return hb_array_t (elements).sub_array (start, length); } - protected: - bool error; - unsigned int count; - hb_vector_t elements; + private: + bool error = false; + unsigned int count = 0; + ELEM elements[LIMIT]; }; /* argument stack */ @@ -508,9 +484,6 @@ struct arg_stack_t : cff_stack_t return true; } - hb_array_t get_subarray (unsigned int start) const - { return S::elements.sub_array (start); } - private: typedef cff_stack_t S; }; @@ -518,8 +491,8 @@ struct arg_stack_t : cff_stack_t /* an operator prefixed by its operands in a byte string */ struct op_str_t { + hb_ubytes_t str; op_code_t op; - byte_str_t str; }; /* base of OP_SERIALIZER */ @@ -547,11 +520,16 @@ struct parsed_values_t } void fini () { values.fini (); } + void alloc (unsigned n) + { + values.alloc (n); + } + void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ()) { VAL *val = values.push (); val->op = op; - val->str = str_ref.str.sub_str (opStart, str_ref.offset - opStart); + val->str = str_ref.str.sub_array (opStart, str_ref.offset - opStart); opStart = str_ref.offset; } @@ -559,14 +537,14 @@ struct parsed_values_t { VAL *val = values.push (v); val->op = op; - val->str = str_ref.sub_str ( opStart, str_ref.offset - opStart); + val->str = str_ref.sub_array ( opStart, str_ref.offset - opStart); opStart = str_ref.offset; } bool has_op (op_code_t op) const { - for (unsigned int i = 0; i < get_count (); i++) - if (get_value (i).op == op) return true; + for (const auto& v : values) + if (v.op == op) return true; return false; } @@ -581,14 +559,11 @@ struct parsed_values_t template struct interp_env_t { - void init (const byte_str_t &str_) + interp_env_t () {} + interp_env_t (const hb_ubytes_t &str_) { str_ref.reset (str_); - argStack.init (); - error = false; } - void fini () { argStack.fini (); } - bool in_error () const { return error || str_ref.in_error () || argStack.in_error (); } @@ -622,10 +597,10 @@ struct interp_env_t arg_stack_t argStack; protected: - bool error; + bool error = false; }; -typedef interp_env_t<> num_interp_env_t; +using num_interp_env_t = interp_env_t<>; template struct opset_t @@ -668,11 +643,8 @@ struct opset_t template struct interpreter_t { - ~interpreter_t() { fini (); } - - void fini () { env.fini (); } - - ENV env; + interpreter_t (ENV& env_) : env (env_) {} + ENV& env; }; } /* namespace CFF */ diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh index ef299369b5e..2983ae54a1e 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh @@ -79,10 +79,10 @@ struct biased_subrs_t unsigned int get_count () const { return subrs ? subrs->count : 0; } unsigned int get_bias () const { return bias; } - byte_str_t operator [] (unsigned int index) const + hb_ubytes_t operator [] (unsigned int index) const { if (unlikely (!subrs || index >= subrs->count)) - return Null (byte_str_t); + return hb_ubytes_t (); else return (*subrs)[index]; } @@ -112,10 +112,9 @@ struct point_t template struct cs_interp_env_t : interp_env_t { - void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) + cs_interp_env_t (const hb_ubytes_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) : + interp_env_t (str) { - interp_env_t::init (str); - context.init (str, CSType_CharString); seen_moveto = true; seen_hintmask = false; @@ -123,15 +122,11 @@ struct cs_interp_env_t : interp_env_t vstem_count = 0; hintmask_size = 0; pt.set_int (0, 0); - callStack.init (); globalSubrs.init (globalSubrs_); localSubrs.init (localSubrs_); } - void fini () + ~cs_interp_env_t () { - interp_env_t::fini (); - - callStack.fini (); globalSubrs.fini (); localSubrs.fini (); } @@ -880,6 +875,8 @@ struct path_procs_t template struct cs_interpreter_t : interpreter_t { + cs_interpreter_t (ENV& env_) : interpreter_t (env_) {} + bool interpret (PARAM& param) { SUPER::env.set_endchar (false); diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh index a520ca3bce5..79fe9b42c5f 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh @@ -179,6 +179,8 @@ struct top_dict_opset_t : dict_opset_t template struct dict_interpreter_t : interpreter_t { + dict_interpreter_t (ENV& env_) : interpreter_t (env_) {} + bool interpret (PARAM& param) { param.init (); diff --git a/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh b/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh index 1c8762c172b..b306c2ecc9a 100644 --- a/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh +++ b/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh @@ -38,17 +38,15 @@ typedef biased_subrs_t cff1_biased_subrs_t; struct cff1_cs_interp_env_t : cs_interp_env_t { template - void init (const byte_str_t &str, ACC &acc, unsigned int fd) + cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd) + : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs) { - SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs); processed_width = false; has_width = false; arg_start = 0; in_seac = false; } - void fini () { SUPER::fini (); } - void set_width (bool has_width_) { if (likely (!processed_width && (SUPER::argStack.get_count () > 0))) @@ -154,7 +152,7 @@ struct cff1_cs_opset_t : cs_opset_t -struct cff1_cs_interpreter_t : cs_interpreter_t {}; +using cff1_cs_interpreter_t = cs_interpreter_t; } /* namespace CFF */ diff --git a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh index 766183760e0..d0b9e7b0863 100644 --- a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh +++ b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh @@ -64,14 +64,14 @@ struct blend_arg_t : number_t typedef interp_env_t BlendInterpEnv; typedef biased_subrs_t cff2_biased_subrs_t; -struct cff2_cs_interp_env_t : cs_interp_env_t +template +struct cff2_cs_interp_env_t : cs_interp_env_t { template - void init (const byte_str_t &str, ACC &acc, unsigned int fd, - const int *coords_=nullptr, unsigned int num_coords_=0) + cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd, + const int *coords_=nullptr, unsigned int num_coords_=0) + : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs) { - SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs); - coords = coords_; num_coords = num_coords_; varStore = acc.varStore; @@ -100,18 +100,14 @@ struct cff2_cs_interp_env_t : cs_interp_env_t return OpCode_return; } - const blend_arg_t& eval_arg (unsigned int i) + const ELEM& eval_arg (unsigned int i) { - blend_arg_t &arg = argStack[i]; - blend_arg (arg); - return arg; + return SUPER::argStack[i]; } - const blend_arg_t& pop_arg () + const ELEM& pop_arg () { - blend_arg_t &arg = argStack.pop (); - blend_arg (arg); - return arg; + return SUPER::argStack.pop (); } void process_blend () @@ -122,7 +118,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t if (do_blend) { if (unlikely (!scalars.resize (region_count))) - set_error (); + SUPER::set_error (); else varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords, &scalars[0], region_count); @@ -133,10 +129,10 @@ struct cff2_cs_interp_env_t : cs_interp_env_t void process_vsindex () { - unsigned int index = argStack.pop_uint (); + unsigned int index = SUPER::argStack.pop_uint (); if (unlikely (seen_vsindex () || seen_blend)) { - set_error (); + SUPER::set_error (); } else { @@ -151,22 +147,18 @@ struct cff2_cs_interp_env_t : cs_interp_env_t void set_ivs (unsigned int ivs_) { ivs = ivs_; } bool seen_vsindex () const { return seen_vsindex_; } - protected: - void blend_arg (blend_arg_t &arg) + double blend_deltas (hb_array_t deltas) const { - if (do_blend && arg.blending ()) + double v = 0; + if (do_blend) { - if (likely (scalars.length == arg.deltas.length)) + if (likely (scalars.length == deltas.length)) { - double v = arg.to_real (); for (unsigned int i = 0; i < scalars.length; i++) - { - v += (double)scalars[i] * arg.deltas[i].to_real (); - } - arg.set_real (v); - arg.deltas.resize (0); + v += (double) scalars[i] * deltas[i].to_real (); } } + return v; } protected: @@ -180,22 +172,24 @@ struct cff2_cs_interp_env_t : cs_interp_env_t bool seen_vsindex_; bool seen_blend; - typedef cs_interp_env_t SUPER; + typedef cs_interp_env_t SUPER; }; -template > -struct cff2_cs_opset_t : cs_opset_t +template , PARAM>> +struct cff2_cs_opset_t : cs_opset_t, PARAM, PATH> { - static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param) + static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param) { switch (op) { case OpCode_callsubr: case OpCode_callgsubr: /* a subroutine number shouldn't be a blended value */ +#if 0 if (unlikely (env.argStack.peek ().blending ())) { env.set_error (); break; } +#endif SUPER::process_op (op, env, param); break; @@ -204,11 +198,13 @@ struct cff2_cs_opset_t : cs_opset_t + static void process_arg_blend (cff2_cs_interp_env_t &env, + ELEM &arg, + const hb_array_t blends, + unsigned n, unsigned i) + { + arg.set_blends (n, i, blends.length, blends); + } + template + static void process_arg_blend (cff2_cs_interp_env_t &env, + ELEM &arg, + const hb_array_t blends, + unsigned n, unsigned i) + { + arg.set_real (arg.to_real () + env.blend_deltas (blends)); + } + + static void process_blend (cff2_cs_interp_env_t &env, PARAM& param) { unsigned int n, k; @@ -234,26 +249,26 @@ struct cff2_cs_opset_t : cs_opset_t blends = env.argStack.get_subarray (start + n + (i * k)); - env.argStack[start + i].set_blends (n, i, k, blends); + const hb_array_t blends = env.argStack.sub_array (start + n + (i * k), k); + process_arg_blend (env, env.argStack[start + i], blends, n, i); } /* pop off blend values leaving default values now adorned with blend values */ env.argStack.pop (k * n); } - static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param) + static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param) { env.process_vsindex (); env.clear_args (); } private: - typedef cs_opset_t SUPER; + typedef cs_opset_t, PARAM, PATH> SUPER; }; -template -struct cff2_cs_interpreter_t : cs_interpreter_t {}; +template +using cff2_cs_interpreter_t = cs_interpreter_t, OPSET, PARAM>; } /* namespace CFF */ diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc index db05f017a5e..5700e06271c 100644 --- a/thirdparty/harfbuzz/src/hb-font.cc +++ b/thirdparty/harfbuzz/src/hb-font.cc @@ -2596,12 +2596,14 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, return; } + /* Since we pass it to two destroying functions. */ + trampoline_reference (&trampoline->closure); + hb_font_funcs_set_nominal_glyph_func (ffuncs, hb_font_get_nominal_glyph_trampoline, trampoline, trampoline_destroy); - trampoline_reference (&trampoline->closure); hb_font_funcs_set_variation_glyph_func (ffuncs, hb_font_get_variation_glyph_trampoline, trampoline, diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc index 0cfbb22e31d..d3c5d3db93a 100644 --- a/thirdparty/harfbuzz/src/hb-ft.cc +++ b/thirdparty/harfbuzz/src/hb-ft.cc @@ -80,12 +80,12 @@ struct hb_ft_font_t { - mutable hb_mutex_t lock; - FT_Face ft_face; int load_flags; bool symbol; /* Whether selected cmap is symbol cmap. */ bool unref; /* Whether to destroy ft_face when done. */ + mutable hb_mutex_t lock; + FT_Face ft_face; mutable int cached_x_scale; mutable hb_advance_cache_t advance_cache; }; diff --git a/thirdparty/harfbuzz/src/hb-map.cc b/thirdparty/harfbuzz/src/hb-map.cc index 9f1ac42846d..6c83c670c93 100644 --- a/thirdparty/harfbuzz/src/hb-map.cc +++ b/thirdparty/harfbuzz/src/hb-map.cc @@ -289,3 +289,23 @@ hb_map_get_population (const hb_map_t *map) { return map->get_population (); } + +/** + * hb_map_is_equal: + * @map: A map + * @other: Another map + * + * Tests whether @map and @other are equal (contain the same + * elements). + * + * Return value: %true if the two maps are equal, %false otherwise. + * + * Since: 4.3.0 + **/ +hb_bool_t +hb_map_is_equal (const hb_map_t *map, + const hb_map_t *other) +{ + return map->is_equal (*other); +} + diff --git a/thirdparty/harfbuzz/src/hb-map.h b/thirdparty/harfbuzz/src/hb-map.h index 6a45a7bdd52..3f67c50b92e 100644 --- a/thirdparty/harfbuzz/src/hb-map.h +++ b/thirdparty/harfbuzz/src/hb-map.h @@ -91,6 +91,10 @@ hb_map_is_empty (const hb_map_t *map); HB_EXTERN unsigned int hb_map_get_population (const hb_map_t *map); +HB_EXTERN hb_bool_t +hb_map_is_equal (const hb_map_t *map, + const hb_map_t *other); + HB_EXTERN void hb_map_set (hb_map_t *map, hb_codepoint_t key, diff --git a/thirdparty/harfbuzz/src/hb-map.hh b/thirdparty/harfbuzz/src/hb-map.hh index 9341637eac0..aec7d87f426 100644 --- a/thirdparty/harfbuzz/src/hb-map.hh +++ b/thirdparty/harfbuzz/src/hb-map.hh @@ -42,11 +42,12 @@ template > lst) : hb_hashmap_t () @@ -58,7 +59,10 @@ struct hb_hashmap_t hb_requires (hb_is_iterable (Iterable))> hb_hashmap_t (const Iterable &o) : hb_hashmap_t () { - hb_copy (o, *this); + auto iter = hb_iter (o); + if (iter.is_random_access_iterator) + resize (hb_len (iter)); + hb_copy (iter, *this); } struct item_t @@ -154,11 +158,11 @@ struct hb_hashmap_t bool in_error () const { return !successful; } - bool resize () + bool resize (unsigned new_population = 0) { if (unlikely (!successful)) return false; - unsigned int power = hb_bit_storage (population * 2 + 8); + unsigned int power = hb_bit_storage (hb_max (population, new_population) * 2 + 8); unsigned int new_size = 1u << power; item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t)); if (unlikely (!new_items)) @@ -235,6 +239,27 @@ struct hb_hashmap_t bool is_empty () const { return population == 0; } explicit operator bool () const { return !is_empty (); } + uint32_t hash () const + { + uint32_t h = 0; + for (auto pair : iter ()) + h ^= (hb_hash (pair.first) * 31) + hb_hash (pair.second); + return h; + } + + bool is_equal (const hb_hashmap_t &other) const + { + if (population != other.population) return false; + + for (auto pair : iter ()) + if (get (pair.first) != pair.second) + return false; + + return true; + } + bool operator == (const hb_hashmap_t &other) const { return is_equal (other); } + bool operator != (const hb_hashmap_t &other) const { return !is_equal (other); } + unsigned int get_population () const { return population; } /* @@ -389,9 +414,11 @@ struct hb_map_t : hb_hashmap_t; - hb_map_t () = default; ~hb_map_t () = default; - hb_map_t (hb_map_t&) = default; + hb_map_t () : hashmap () {} + hb_map_t (std::nullptr_t) : hb_map_t () {} + hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {} + hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {} hb_map_t& operator= (const hb_map_t&) = default; hb_map_t& operator= (hb_map_t&&) = default; hb_map_t (std::initializer_list> lst) : hashmap (lst) {} diff --git a/thirdparty/harfbuzz/src/hb-meta.hh b/thirdparty/harfbuzz/src/hb-meta.hh index 3fea5d995e9..90757d38acd 100644 --- a/thirdparty/harfbuzz/src/hb-meta.hh +++ b/thirdparty/harfbuzz/src/hb-meta.hh @@ -188,6 +188,19 @@ template <> struct hb_int_max : hb_integral_constant struct hb_int_max : hb_integral_constant {}; #define hb_int_max(T) hb_int_max::value +#if __GNUG__ && __GNUC__ < 5 +#define hb_is_trivially_copyable(T) __has_trivial_copy(T) +#define hb_is_trivially_copy_assignable(T) __has_trivial_assign(T) +#define hb_is_trivially_constructible(T) __has_trivial_constructor(T) +#define hb_is_trivially_copy_constructible(T) __has_trivial_copy_constructor(T) +#define hb_is_trivially_destructible(T) __has_trivial_destructor(T) +#else +#define hb_is_trivially_copyable(T) std::is_trivially_copyable::value +#define hb_is_trivially_copy_assignable(T) std::is_trivially_copy_assignable::value +#define hb_is_trivially_constructible(T) std::is_trivially_constructible::value +#define hb_is_trivially_copy_constructible(T) std::is_trivially_copy_constructible::value +#define hb_is_trivially_destructible(T) std::is_trivially_destructible::value +#endif /* Class traits. */ diff --git a/thirdparty/harfbuzz/src/hb-open-type.hh b/thirdparty/harfbuzz/src/hb-open-type.hh index 7e524177f67..aee7064be3e 100644 --- a/thirdparty/harfbuzz/src/hb-open-type.hh +++ b/thirdparty/harfbuzz/src/hb-open-type.hh @@ -33,6 +33,7 @@ #include "hb-blob.hh" #include "hb-face.hh" #include "hb-machinery.hh" +#include "hb-meta.hh" #include "hb-subset.hh" @@ -518,7 +519,7 @@ struct UnsizedArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c, count))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward (ds)...))) return_trace (false); @@ -707,7 +708,7 @@ struct ArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward (ds)...))) @@ -835,7 +836,7 @@ struct HeadlessArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward (ds)...))) @@ -884,7 +885,7 @@ struct ArrayOfM1 { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = lenM1 + 1; for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward (ds)...))) @@ -1070,7 +1071,7 @@ struct VarSizedBinSearchArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) if (unlikely (!(*this)[i].sanitize (c, std::forward (ds)...))) diff --git a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh index c102c151733..ae3b83a2563 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh @@ -46,49 +46,21 @@ template static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset) { return offset ? StructAtOffset (P, offset) : Null (Type); } -inline unsigned int calcOffSize (unsigned int dataSize) -{ - unsigned int size = 1; - unsigned int offset = dataSize + 1; - while (offset & ~0xFF) - { - size++; - offset >>= 8; - } - /* format does not support size > 4; caller should handle it as an error */ - return size; -} - struct code_pair_t { hb_codepoint_t code; hb_codepoint_t glyph; }; -typedef hb_vector_t str_buff_t; -struct str_buff_vec_t : hb_vector_t -{ - unsigned int total_size () const - { - unsigned int size = 0; - for (unsigned int i = 0; i < length; i++) - size += (*this)[i].length; - return size; - } - - private: - typedef hb_vector_t SUPER; -}; +using str_buff_t = hb_vector_t; +using str_buff_vec_t = hb_vector_t; /* CFF INDEX */ template struct CFFIndex { - static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count) - { return offSize * (count + 1); } - unsigned int offset_array_size () const - { return calculate_offset_array_size (offSize, count); } + { return offSize * (count + 1); } CFFIndex *copy (hb_serialize_context_t *c) const { @@ -100,55 +72,46 @@ struct CFFIndex return_trace (out); } - bool serialize (hb_serialize_context_t *c, const CFFIndex &src) - { - TRACE_SERIALIZE (this); - unsigned int size = src.get_size (); - CFFIndex *dest = c->allocate_size (size); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); - return_trace (true); - } - bool serialize (hb_serialize_context_t *c, unsigned int offSize_, const byte_str_array_t &byteArray) { TRACE_SERIALIZE (this); + if (byteArray.length == 0) { COUNT *dest = c->allocate_min (); if (unlikely (!dest)) return_trace (false); *dest = 0; + return_trace (true); } - else + + /* serialize CFFIndex header */ + if (unlikely (!c->extend_min (this))) return_trace (false); + this->count = byteArray.length; + this->offSize = offSize_; + if (unlikely (!c->allocate_size (offSize_ * (byteArray.length + 1)))) + return_trace (false); + + /* serialize indices */ + unsigned int offset = 1; + unsigned int i = 0; + for (; i < byteArray.length; i++) { - /* serialize CFFIndex header */ - if (unlikely (!c->extend_min (this))) return_trace (false); - this->count = byteArray.length; - this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (byteArray.length + 1)))) - return_trace (false); - - /* serialize indices */ - unsigned int offset = 1; - unsigned int i = 0; - for (; i < byteArray.length; i++) - { - set_offset_at (i, offset); - offset += byteArray[i].get_size (); - } set_offset_at (i, offset); - - /* serialize data */ - for (unsigned int i = 0; i < byteArray.length; i++) - { - const byte_str_t &bs = byteArray[i]; - unsigned char *dest = c->allocate_size (bs.length); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &bs[0], bs.length); - } + offset += byteArray[i].get_size (); } + set_offset_at (i, offset); + + /* serialize data */ + for (unsigned int i = 0; i < byteArray.length; i++) + { + const hb_ubytes_t &bs = byteArray[i]; + unsigned char *dest = c->allocate_size (bs.length); + if (unlikely (!dest)) return_trace (false); + memcpy (dest, &bs[0], bs.length); + } + return_trace (true); } @@ -160,7 +123,7 @@ struct CFFIndex byteArray.init (); byteArray.resize (buffArray.length); for (unsigned int i = 0; i < byteArray.length; i++) - byteArray[i] = byte_str_t (buffArray[i].arrayZ, buffArray[i].length); + byteArray[i] = hb_ubytes_t (buffArray[i].arrayZ, buffArray[i].length); bool result = this->serialize (c, offSize_, byteArray); byteArray.fini (); return result; @@ -172,18 +135,9 @@ struct CFFIndex Iterator it) { TRACE_SERIALIZE (this); - if (it.len () == 0) - { - COUNT *dest = c->allocate_min (); - if (unlikely (!dest)) return_trace (false); - *dest = 0; - } - else - { - serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; })); - for (const auto &_ : +it) - _.copy (c); - } + serialize_header(c, + it | hb_map ([] (const hb_ubytes_t &_) { return _.length; })); + for (const auto &_ : +it) + _.copy (c); return_trace (true); } @@ -196,7 +150,7 @@ struct CFFIndex { auto it = + hb_iter (buffArray) - | hb_map ([] (const str_buff_t &_) { return byte_str_t (_.arrayZ, _.length); }) + | hb_map ([] (const str_buff_t &_) { return hb_ubytes_t (_.arrayZ, _.length); }) ; return serialize (c, it); } @@ -209,13 +163,15 @@ struct CFFIndex TRACE_SERIALIZE (this); unsigned total = + it | hb_reduce (hb_add, 0); - unsigned off_size = calcOffSize (total); + unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; /* serialize CFFIndex header */ if (unlikely (!c->extend_min (this))) return_trace (false); this->count = it.len (); + if (!this->count) return_trace (true); + if (unlikely (!c->extend (this->offSize))) return_trace (false); this->offSize = off_size; - if (unlikely (!c->allocate_size (off_size * (it.len () + 1)))) + if (unlikely (!c->allocate_size (off_size * (this->count + 1)))) return_trace (false); /* serialize indices */ @@ -233,6 +189,7 @@ struct CFFIndex void set_offset_at (unsigned int index, unsigned int offset) { + assert (index <= count); HBUINT8 *p = offsets + offSize * index + offSize; unsigned int size = offSize; for (; size; size--) @@ -243,11 +200,13 @@ struct CFFIndex } } + private: unsigned int offset_at (unsigned int index) const { assert (index <= count); - const HBUINT8 *p = offsets + offSize * index; + unsigned int size = offSize; + const HBUINT8 *p = offsets + size * index; unsigned int offset = 0; for (; size; size--) offset = (offset << 8) + *p++; @@ -256,72 +215,57 @@ struct CFFIndex unsigned int length_at (unsigned int index) const { - if (unlikely ((offset_at (index + 1) < offset_at (index)) || - (offset_at (index + 1) > offset_at (count)))) + unsigned offset0 = offset_at (index); + unsigned offset1 = offset_at (index + 1); + if (unlikely (offset1 < offset0 || offset1 > offset_at (count))) return 0; - return offset_at (index + 1) - offset_at (index); + return offset1 - offset0; } const unsigned char *data_base () const - { return (const unsigned char *) this + min_size + offset_array_size (); } + { return (const unsigned char *) this + min_size + offSize.static_size + offset_array_size (); } + public: - unsigned int data_size () const { return HBINT8::static_size; } - - byte_str_t operator [] (unsigned int index) const + hb_ubytes_t operator [] (unsigned int index) const { - if (unlikely (index >= count)) return Null (byte_str_t); - return byte_str_t (data_base () + offset_at (index) - 1, length_at (index)); + if (unlikely (index >= count)) return hb_ubytes_t (); + unsigned length = length_at (index); + if (unlikely (!length)) return hb_ubytes_t (); + return hb_ubytes_t (data_base () + offset_at (index) - 1, length); } unsigned int get_size () const { - if (this == &Null (CFFIndex)) return 0; - if (count > 0) - return min_size + offset_array_size () + (offset_at (count) - 1); - return count.static_size; /* empty CFFIndex contains count only */ + if (count) + return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); + return min_size; /* empty CFFIndex contains count only */ } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely ((c->check_struct (this) && count == 0) || /* empty INDEX */ - (c->check_struct (this) && offSize >= 1 && offSize <= 4 && - c->check_array (offsets, offSize, count + 1) && - c->check_array ((const HBUINT8*) data_base (), 1, max_offset () - 1)))); - } - - protected: - unsigned int max_offset () const - { - unsigned int max = 0; - for (unsigned int i = 0; i < count + 1u; i++) - { - unsigned int off = offset_at (i); - if (off > max) max = off; - } - return max; + return_trace (likely (c->check_struct (this) && + (count == 0 || /* empty INDEX */ + (count < count + 1u && + c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 && + c->check_array (offsets, offSize, count + 1u) && + c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count) - 1))))); } public: COUNT count; /* Number of object data. Note there are (count+1) offsets */ + private: HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ HBUINT8 offsets[HB_VAR_ARRAY]; /* The array of (count + 1) offsets into objects array (1-base). */ /* HBUINT8 data[HB_VAR_ARRAY]; Object data */ public: - DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets); + DEFINE_SIZE_MIN (COUNT::static_size); }; template struct CFFIndexOf : CFFIndex { - const byte_str_t operator [] (unsigned int index) const - { - if (likely (index < CFFIndex::count)) - return byte_str_t (CFFIndex::data_base () + CFFIndex::offset_at (index) - 1, CFFIndex::length_at (index)); - return Null (byte_str_t); - } - template bool serialize (hb_serialize_context_t *c, unsigned int offSize_, diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc index df4554ac001..bd9fe5d6d40 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc +++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc @@ -311,10 +311,8 @@ struct bounds_t struct cff1_extents_param_t { - void init (const OT::cff1::accelerator_t *_cff) + cff1_extents_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) { - path_open = false; - cff = _cff; bounds.init (); } @@ -322,7 +320,7 @@ struct cff1_extents_param_t void end_path () { path_open = false; } bool is_path_open () const { return path_open; } - bool path_open; + bool path_open = false; bounds_t bounds; const OT::cff1::accelerator_t *cff; @@ -395,12 +393,11 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; unsigned int fd = cff->fdSelect->get_fd (glyph); - cff1_cs_interpreter_t interp; - const byte_str_t str = (*cff->charStrings)[glyph]; - interp.env.init (str, *cff, fd); - interp.env.set_in_seac (in_seac); - cff1_extents_param_t param; - param.init (cff); + const hb_ubytes_t str = (*cff->charStrings)[glyph]; + cff1_cs_interp_env_t env (str, *cff, fd); + env.set_in_seac (in_seac); + cff1_cs_interpreter_t interp (env); + cff1_extents_param_t param (cff); if (unlikely (!interp.interpret (param))) return false; bounds = param.bounds; return true; @@ -541,10 +538,10 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; unsigned int fd = cff->fdSelect->get_fd (glyph); - cff1_cs_interpreter_t interp; - const byte_str_t str = (*cff->charStrings)[glyph]; - interp.env.init (str, *cff, fd); - interp.env.set_in_seac (in_seac); + const hb_ubytes_t str = (*cff->charStrings)[glyph]; + cff1_cs_interp_env_t env (str, *cff, fd); + env.set_in_seac (in_seac); + cff1_cs_interpreter_t interp (env); cff1_path_param_t param (cff, font, draw_session, delta); if (unlikely (!interp.interpret (param))) return false; @@ -566,18 +563,13 @@ bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h struct get_seac_param_t { - void init (const OT::cff1::accelerator_t *_cff) - { - cff = _cff; - base = 0; - accent = 0; - } + get_seac_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) {} bool has_seac () const { return base && accent; } const OT::cff1::accelerator_t *cff; - hb_codepoint_t base; - hb_codepoint_t accent; + hb_codepoint_t base = 0; + hb_codepoint_t accent = 0; }; struct cff1_cs_opset_seac_t : cff1_cs_opset_t @@ -598,11 +590,10 @@ bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_code if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int fd = fdSelect->get_fd (glyph); - cff1_cs_interpreter_t interp; - const byte_str_t str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd); - get_seac_param_t param; - param.init (this); + const hb_ubytes_t str = (*charStrings)[glyph]; + cff1_cs_interp_env_t env (str, *this, fd); + cff1_cs_interpreter_t interp (env); + get_seac_param_t param (this); if (unlikely (!interp.interpret (param))) return false; if (param.has_seac ()) diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh index 542e3f4de35..b5047002ac4 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh @@ -318,14 +318,21 @@ struct Charset0 { return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c)); } - hb_codepoint_t get_sid (hb_codepoint_t glyph) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const { + if (unlikely (glyph >= num_glyphs)) return 0; if (glyph == 0) return 0; else return sids[glyph - 1]; } + void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + { + for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++) + mapping->set (gid, sids[gid - 1]); + } + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const { if (sid == 0) @@ -381,20 +388,36 @@ struct Charset1_2 { return_trace (true); } - hb_codepoint_t get_sid (hb_codepoint_t glyph) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const { + if (unlikely (glyph >= num_glyphs)) return 0; if (glyph == 0) return 0; glyph--; for (unsigned int i = 0;; i++) { if (glyph <= ranges[i].nLeft) - return (hb_codepoint_t)ranges[i].first + glyph; + return (hb_codepoint_t) ranges[i].first + glyph; glyph -= (ranges[i].nLeft + 1); } return 0; } + void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + { + hb_codepoint_t gid = 1; + for (unsigned i = 0;; i++) + { + hb_codepoint_t sid = ranges[i].first; + unsigned count = ranges[i].nLeft + 1; + for (unsigned j = 0; j < count; j++) + mapping->set (gid++, sid++); + + if (gid >= num_glyphs) + break; + } + } + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const { if (sid == 0) return 0; @@ -521,16 +544,26 @@ struct Charset hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const { - if (unlikely (glyph >= num_glyphs)) return 0; switch (format) { - case 0: return u.format0.get_sid (glyph); - case 1: return u.format1.get_sid (glyph); - case 2: return u.format2.get_sid (glyph); + case 0: return u.format0.get_sid (glyph, num_glyphs); + case 1: return u.format1.get_sid (glyph, num_glyphs); + case 2: return u.format2.get_sid (glyph, num_glyphs); default:return 0; } } + void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + { + switch (format) + { + case 0: u.format0.collect_glyph_to_sid_map (mapping, num_glyphs); return; + case 1: u.format1.collect_glyph_to_sid_map (mapping, num_glyphs); return; + case 2: u.format2.collect_glyph_to_sid_map (mapping, num_glyphs); return; + default:return; + } + } + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const { switch (format) @@ -602,6 +635,8 @@ struct cff1_top_dict_interp_env_t : num_interp_env_t { cff1_top_dict_interp_env_t () : num_interp_env_t(), prev_offset(0), last_offset(0) {} + cff1_top_dict_interp_env_t (const hb_ubytes_t &bytes) + : num_interp_env_t(bytes), prev_offset(0), last_offset(0) {} unsigned int prev_offset; unsigned int last_offset; @@ -1024,11 +1059,10 @@ struct cff1 { fini (); return; } { /* parse top dict */ - const byte_str_t topDictStr = (*topDictIndex)[0]; + const hb_ubytes_t topDictStr = (*topDictIndex)[0]; if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } - cff1_top_dict_interpreter_t top_interp; - top_interp.env.init (topDictStr); - topDict.init (); + cff1_top_dict_interp_env_t env (topDictStr); + cff1_top_dict_interpreter_t top_interp (env); if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } } @@ -1098,20 +1132,20 @@ struct cff1 { for (unsigned int i = 0; i < fdCount; i++) { - byte_str_t fontDictStr = (*fdArray)[i]; + hb_ubytes_t fontDictStr = (*fdArray)[i]; if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } cff1_font_dict_values_t *font; - cff1_font_dict_interpreter_t font_interp; - font_interp.env.init (fontDictStr); + cff1_top_dict_interp_env_t env (fontDictStr); + cff1_font_dict_interpreter_t font_interp (env); font = fontDicts.push (); if (unlikely (font == &Crap (cff1_font_dict_values_t))) { fini (); return; } font->init (); if (unlikely (!font_interp.interpret (*font))) { fini (); return; } PRIVDICTVAL *priv = &privateDicts[i]; - const byte_str_t privDictStr (StructAtOffset (cff, font->privateDictInfo.offset), font->privateDictInfo.size); + const hb_ubytes_t privDictStr = StructAtOffset (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } - dict_interpreter_t priv_interp; - priv_interp.env.init (privDictStr); + num_interp_env_t env2 (privDictStr); + dict_interpreter_t priv_interp (env2); priv->init (); if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } @@ -1126,10 +1160,10 @@ struct cff1 cff1_top_dict_values_t *font = &topDict; PRIVDICTVAL *priv = &privateDicts[0]; - const byte_str_t privDictStr (StructAtOffset (cff, font->privateDictInfo.offset), font->privateDictInfo.size); + const hb_ubytes_t privDictStr = StructAtOffset (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } - dict_interpreter_t priv_interp; - priv_interp.env.init (privDictStr); + num_interp_env_t env (privDictStr); + dict_interpreter_t priv_interp (env); priv->init (); if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } @@ -1194,6 +1228,19 @@ struct cff1 } } + hb_map_t *create_glyph_to_sid_map () const + { + if (charset != &Null (Charset)) + { + hb_map_t *mapping = hb_map_create (); + mapping->set (0, 0); + charset->collect_glyph_to_sid_map (mapping, num_glyphs); + return mapping; + } + else + return nullptr; + } + hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const { if (charset != &Null (Charset)) @@ -1274,30 +1321,20 @@ struct cff1 { SUPER::init (face); + glyph_names.set_relaxed (nullptr); + if (!is_valid ()) return; if (is_CID ()) return; - /* fill glyph_names */ - for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) - { - hb_codepoint_t sid = glyph_to_sid (gid); - gname_t gname; - gname.sid = sid; - if (sid < cff1_std_strings_length) - gname.name = cff1_std_strings (sid); - else - { - byte_str_t ustr = (*stringIndex)[sid - cff1_std_strings_length]; - gname.name = hb_bytes_t ((const char*)ustr.arrayZ, ustr.length); - } - if (unlikely (!gname.name.arrayZ)) { fini (); return; } - glyph_names.push (gname); - } - glyph_names.qsort (); } ~accelerator_t () { - glyph_names.fini (); + hb_sorted_vector_t *names = glyph_names.get_relaxed (); + if (names) + { + names->fini (); + free (names); + } SUPER::fini (); } @@ -1305,9 +1342,9 @@ struct cff1 bool get_glyph_name (hb_codepoint_t glyph, char *buf, unsigned int buf_len) const { - if (!buf) return true; if (unlikely (!is_valid ())) return false; if (is_CID()) return false; + if (unlikely (!buf_len)) return true; hb_codepoint_t sid = glyph_to_sid (glyph); const char *str; size_t str_len; @@ -1319,7 +1356,7 @@ struct cff1 } else { - byte_str_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length]; + hb_ubytes_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length]; str = (const char *)ubyte_str.arrayZ; str_len = ubyte_str.length; } @@ -1333,11 +1370,53 @@ struct cff1 bool get_glyph_from_name (const char *name, int len, hb_codepoint_t *glyph) const { + if (unlikely (!is_valid ())) return false; + if (is_CID()) return false; if (len < 0) len = strlen (name); if (unlikely (!len)) return false; + retry: + hb_sorted_vector_t *names = glyph_names.get (); + if (unlikely (!names)) + { + names = (hb_sorted_vector_t *) calloc (sizeof (hb_sorted_vector_t), 1); + if (likely (names)) + { + names->init (); + /* TODO */ + + /* fill glyph names */ + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + hb_codepoint_t sid = glyph_to_sid (gid); + gname_t gname; + gname.sid = sid; + if (sid < cff1_std_strings_length) + gname.name = cff1_std_strings (sid); + else + { + hb_ubytes_t ustr = (*stringIndex)[sid - cff1_std_strings_length]; + gname.name = hb_bytes_t ((const char*) ustr.arrayZ, ustr.length); + } + if (unlikely (!gname.name.arrayZ)) + gname.name = hb_bytes_t ("", 0); /* To avoid nullptr. */ + names->push (gname); + } + names->qsort (); + } + if (unlikely (!glyph_names.cmpexch (nullptr, names))) + { + if (names) + { + names->fini (); + free (names); + } + goto retry; + } + } + gname_t key = { hb_bytes_t (name, len), 0 }; - const gname_t *gname = glyph_names.bsearch (key); + const gname_t *gname = glyph_names->bsearch (key); if (!gname) return false; hb_codepoint_t gid = sid_to_glyph (gname->sid); if (!gid && gname->sid) return false; @@ -1359,7 +1438,7 @@ struct cff1 { const gname_t *a = (const gname_t *)a_; const gname_t *b = (const gname_t *)b_; - int minlen = hb_min (a->name.length, b->name.length); + unsigned minlen = hb_min (a->name.length, b->name.length); int ret = strncmp (a->name.arrayZ, b->name.arrayZ, minlen); if (ret) return ret; return a->name.length - b->name.length; @@ -1368,7 +1447,7 @@ struct cff1 int cmp (const gname_t &a) const { return cmp (&a, this); } }; - hb_sorted_vector_t glyph_names; + mutable hb_atomic_ptr_t> glyph_names; typedef accelerator_templ_t SUPER; }; diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc index 817fe064ce4..50c76daf93e 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc +++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc @@ -36,9 +36,8 @@ using namespace CFF; struct cff2_extents_param_t { - void init () + cff2_extents_param_t () { - path_open = false; min_x.set_int (INT_MAX); min_y.set_int (INT_MAX); max_x.set_int (INT_MIN); @@ -57,22 +56,22 @@ struct cff2_extents_param_t if (pt.y > max_y) max_y = pt.y; } - bool path_open; + bool path_open = false; number_t min_x; number_t min_y; number_t max_x; number_t max_y; }; -struct cff2_path_procs_extents_t : path_procs_t +struct cff2_path_procs_extents_t : path_procs_t, cff2_extents_param_t> { - static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt) + static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt) { param.end_path (); env.moveto (pt); } - static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1) + static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1) { if (!param.is_path_open ()) { @@ -83,7 +82,7 @@ struct cff2_path_procs_extents_t : path_procs_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) { if (!param.is_path_open ()) { @@ -98,7 +97,7 @@ struct cff2_path_procs_extents_t : path_procs_t {}; +struct cff2_cs_opset_extents_t : cff2_cs_opset_t {}; bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, @@ -112,11 +111,10 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int fd = fdSelect->get_fd (glyph); - cff2_cs_interpreter_t interp; - const byte_str_t str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd, font->coords, font->num_coords); + const hb_ubytes_t str = (*charStrings)[glyph]; + cff2_cs_interp_env_t env (str, *this, fd, font->coords, font->num_coords); + cff2_cs_interpreter_t interp (env); cff2_extents_param_t param; - param.init (); if (unlikely (!interp.interpret (param))) return false; if (param.min_x >= param.max_x) @@ -169,28 +167,28 @@ struct cff2_path_param_t hb_font_t *font; }; -struct cff2_path_procs_path_t : path_procs_t +struct cff2_path_procs_path_t : path_procs_t, cff2_path_param_t> { - static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt) + static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt) { param.move_to (pt); env.moveto (pt); } - static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1) + static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1) { param.line_to (pt1); env.moveto (pt1); } - static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) + static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) { param.cubic_to (pt1, pt2, pt3); env.moveto (pt3); } }; -struct cff2_cs_opset_path_t : cff2_cs_opset_t {}; +struct cff2_cs_opset_path_t : cff2_cs_opset_t {}; bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const { @@ -202,9 +200,9 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int fd = fdSelect->get_fd (glyph); - cff2_cs_interpreter_t interp; - const byte_str_t str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd, font->coords, font->num_coords); + const hb_ubytes_t str = (*charStrings)[glyph]; + cff2_cs_interp_env_t env (str, *this, fd, font->coords, font->num_coords); + cff2_cs_interpreter_t interp (env); cff2_path_param_t param (font, draw_session); if (unlikely (!interp.interpret (param))) return false; return true; diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh index b77e7f53fad..746160dc8e4 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh @@ -247,12 +247,8 @@ typedef cff2_private_dict_values_base_t cff2_private_dict_values struct cff2_priv_dict_interp_env_t : num_interp_env_t { - void init (const byte_str_t &str) - { - num_interp_env_t::init (str); - ivs = 0; - seen_vsindex = false; - } + cff2_priv_dict_interp_env_t (const hb_ubytes_t &str) : + num_interp_env_t (str) {} void process_vsindex () { @@ -267,8 +263,8 @@ struct cff2_priv_dict_interp_env_t : num_interp_env_t void set_ivs (unsigned int ivs_) { ivs = ivs_; } protected: - unsigned int ivs; - bool seen_vsindex; + unsigned int ivs = 0; + bool seen_vsindex = false; }; struct cff2_private_dict_opset_t : dict_opset_t @@ -415,10 +411,10 @@ struct cff2 goto fail; { /* parse top dict */ - byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize); + hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize); if (unlikely (!topDictStr.sanitize (&sc))) goto fail; - cff2_top_dict_interpreter_t top_interp; - top_interp.env.init (topDictStr); + num_interp_env_t env (topDictStr); + cff2_top_dict_interpreter_t top_interp (env); topDict.init (); if (unlikely (!top_interp.interpret (topDict))) goto fail; } @@ -447,20 +443,20 @@ struct cff2 /* parse font dicts and gather private dicts */ for (unsigned int i = 0; i < fdCount; i++) { - const byte_str_t fontDictStr = (*fdArray)[i]; + const hb_ubytes_t fontDictStr = (*fdArray)[i]; if (unlikely (!fontDictStr.sanitize (&sc))) goto fail; cff2_font_dict_values_t *font; - cff2_font_dict_interpreter_t font_interp; - font_interp.env.init (fontDictStr); + num_interp_env_t env (fontDictStr); + cff2_font_dict_interpreter_t font_interp (env); font = fontDicts.push (); if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail; font->init (); if (unlikely (!font_interp.interpret (*font))) goto fail; - const byte_str_t privDictStr (StructAtOffsetOrNull (cff2, font->privateDictInfo.offset), font->privateDictInfo.size); + const hb_ubytes_t privDictStr = StructAtOffsetOrNull (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) goto fail; - dict_interpreter_t priv_interp; - priv_interp.env.init(privDictStr); + cff2_priv_dict_interp_env_t env2 (privDictStr); + dict_interpreter_t priv_interp (env2); privateDicts[i].init (); if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail; diff --git a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh index a8747ee5a18..7e96d9c8b32 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh @@ -44,7 +44,7 @@ struct CmapSubtableFormat0 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0; - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -109,22 +109,26 @@ struct CmapSubtableFormat4 while (it) { // Start a new range - start_cp = (*it).first; - prev_run_start_cp = (*it).first; - run_start_cp = (*it).first; - end_cp = (*it).first; - last_gid = (*it).second; - run_length = 1; - prev_delta = 0; + { + const auto& pair = *it; + start_cp = pair.first; + prev_run_start_cp = start_cp; + run_start_cp = start_cp; + end_cp = start_cp; + last_gid = pair.second; + run_length = 1; + prev_delta = 0; + } - delta = (*it).second - (*it).first; + delta = last_gid - start_cp; mode = FIRST_SUB_RANGE; it++; while (it) { // Process range - hb_codepoint_t next_cp = (*it).first; - hb_codepoint_t next_gid = (*it).second; + const auto& pair = *it; + hb_codepoint_t next_cp = pair.first; + hb_codepoint_t next_gid = pair.second; if (next_cp != end_cp + 1) { // Current range is over, stop processing. break; @@ -282,23 +286,22 @@ struct CmapSubtableFormat4 } template + hb_requires (hb_is_iterator (Iterator))> HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c, - Iterator it, + Iterator it, HBUINT16 *endCode, HBUINT16 *startCode, HBINT16 *idDelta, unsigned segcount) { - hb_hashmap_t cp_to_gid; - + it | hb_sink (cp_to_gid); + hb_map_t cp_to_gid { it }; HBUINT16 *idRangeOffset = c->allocate_size (HBUINT16::static_size * segcount); if (unlikely (!c->check_success (idRangeOffset))) return nullptr; if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr; for (unsigned i : + hb_range (segcount) - | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })) + | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })) { idRangeOffset[i] = 2 * (c->start_embed () - idRangeOffset - i); for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++) @@ -323,22 +326,31 @@ struct CmapSubtableFormat4 { return _.first <= 0xFFFF; }) ; - if (format4_iter.len () == 0) return; + if (!format4_iter) return; unsigned table_initpos = c->length (); if (unlikely (!c->extend_min (this))) return; this->format = 4; + hb_vector_t> cp_to_gid { + format4_iter + }; + //serialize endCode[], startCode[], idDelta[] HBUINT16* endCode = c->start_embed (); - unsigned segcount = serialize_find_segcount (format4_iter); - if (unlikely (!serialize_start_end_delta_arrays (c, format4_iter, segcount))) + unsigned segcount = serialize_find_segcount (cp_to_gid.iter()); + if (unlikely (!serialize_start_end_delta_arrays (c, cp_to_gid.iter(), segcount))) return; HBUINT16 *startCode = endCode + segcount + 1; HBINT16 *idDelta = ((HBINT16*)startCode) + segcount; - HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount); + HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, + cp_to_gid.iter (), + endCode, + startCode, + idDelta, + segcount); if (unlikely (!c->check_success (idRangeOffset))) return; this->length = c->length () - table_initpos; @@ -401,7 +413,7 @@ struct CmapSubtableFormat4 2, _hb_cmp_method, this->segCount + 1); - if (!found) + if (unlikely (!found)) return false; unsigned int i = found - endCount; @@ -421,7 +433,7 @@ struct CmapSubtableFormat4 gid += this->idDelta[i]; } gid &= 0xFFFFu; - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -440,14 +452,14 @@ struct CmapSubtableFormat4 hb_codepoint_t start = this->startCount[i]; hb_codepoint_t end = this->endCount[i]; unsigned int rangeOffset = this->idRangeOffset[i]; + out->add_range(start, end); if (rangeOffset == 0) { for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) { hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu; if (unlikely (!gid)) - continue; - out->add (codepoint); + out->del(codepoint); } } else @@ -456,11 +468,13 @@ struct CmapSubtableFormat4 { unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; if (unlikely (index >= this->glyphIdArrayLength)) + { + out->del_range (codepoint, end); break; + } hb_codepoint_t gid = this->glyphIdArray[index]; if (unlikely (!gid)) - continue; - out->add (codepoint); + out->del(codepoint); } } } @@ -469,6 +483,8 @@ struct CmapSubtableFormat4 void collect_mapping (hb_set_t *unicodes, /* OUT */ hb_map_t *mapping /* OUT */) const { + // TODO(grieger): optimize similar to collect_unicodes + // (ie. use add_range()) unsigned count = this->segCount; if (count && this->startCount[count - 1] == 0xFFFFu) count--; /* Skip sentinel segment. */ @@ -620,7 +636,7 @@ struct CmapSubtableTrimmed { /* Rely on our implicit array bound-checking. */ hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -674,7 +690,7 @@ struct CmapSubtableTrimmed }; struct CmapSubtableFormat6 : CmapSubtableTrimmed {}; -struct CmapSubtableFormat10 : CmapSubtableTrimmed {}; +struct CmapSubtableFormat10 : CmapSubtableTrimmed {}; template struct CmapSubtableLongSegmented @@ -684,7 +700,7 @@ struct CmapSubtableLongSegmented bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint); - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -722,11 +738,19 @@ struct CmapSubtableLongSegmented hb_map_t *mapping, /* OUT */ unsigned num_glyphs) const { + hb_codepoint_t last_end = 0; for (unsigned i = 0; i < this->groups.len; i++) { hb_codepoint_t start = this->groups[i].startCharCode; hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode, (hb_codepoint_t) HB_UNICODE_MAX); + if (unlikely (start > end || start < last_end)) { + // Range is not in order and is invalid, skip it. + continue; + } + last_end = end; + + hb_codepoint_t gid = this->groups[i].glyphID; if (!gid) { @@ -778,16 +802,16 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented void serialize (hb_serialize_context_t *c, Iterator it) { - if (it.len () == 0) return; + if (!it) return; unsigned table_initpos = c->length (); if (unlikely (!c->extend_min (this))) return; - hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF; + hb_codepoint_t startCharCode = (hb_codepoint_t) -1, endCharCode = (hb_codepoint_t) -1; hb_codepoint_t glyphID = 0; for (const auto& _ : +it) { - if (startCharCode == 0xFFFF) + if (startCharCode == (hb_codepoint_t) -1) { startCharCode = _.first; endCharCode = _.first; @@ -818,7 +842,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented this->format = 12; this->reserved = 0; this->length = c->length () - table_initpos; - this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size; + this->groups.len = (this->length - min_size) / CmapSubtableLongGroup::static_size; } static size_t get_sub_table_size (const hb_sorted_vector_t &groups_data) @@ -1448,6 +1472,37 @@ struct EncodingRecord DEFINE_SIZE_STATIC (8); }; +struct SubtableUnicodesCache { + + private: + const void* base; + hb_hashmap_t cached_unicodes; + + public: + SubtableUnicodesCache(const void* cmap_base) + : base(cmap_base), cached_unicodes() {} + ~SubtableUnicodesCache() + { + for (hb_set_t* s : cached_unicodes.values()) { + hb_set_destroy (s); + } + } + + hb_set_t* set_for(const EncodingRecord* record) + { + if (!cached_unicodes.has ((intptr_t) record)) { + hb_set_t* new_set = hb_set_create (); + if (!cached_unicodes.set ((intptr_t) record, new_set)) { + hb_set_destroy (new_set); + return hb_set_get_empty (); + } + (base+record->subtable).collect_unicodes (cached_unicodes.get ((intptr_t) record)); + } + return cached_unicodes.get ((intptr_t) record); + } + +}; + struct cmap { static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; @@ -1467,6 +1522,7 @@ struct cmap unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; auto snap = c->snapshot (); + SubtableUnicodesCache unicodes_cache (base); for (const EncodingRecord& _ : encodingrec_iter) { if (c->in_error ()) @@ -1475,12 +1531,11 @@ struct cmap unsigned format = (base+_.subtable).u.format; if (format != 4 && format != 12 && format != 14) continue; - hb_set_t unicodes_set; - (base+_.subtable).collect_unicodes (&unicodes_set); + hb_set_t* unicodes_set = unicodes_cache.set_for (&_); if (!drop_format_4 && format == 4) { - c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx); + c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 4u, base, plan, &format4objidx); if (c->in_error () && c->only_overflow ()) { // cmap4 overflowed, reset and retry serialization without format 4 subtables. @@ -1495,8 +1550,8 @@ struct cmap else if (format == 12) { - if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue; - c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx); + if (_can_drop (_, *unicodes_set, base, unicodes_cache, + it | hb_map (hb_first), encodingrec_iter)) continue; + c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx); } else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx); } @@ -1514,6 +1569,7 @@ struct cmap bool _can_drop (const EncodingRecord& cmap12, const hb_set_t& cmap12_unicodes, const void* base, + SubtableUnicodesCache& unicodes_cache, Iterator subset_unicodes, EncodingRecordIterator encoding_records) { @@ -1544,11 +1600,10 @@ struct cmap || (base+_.subtable).get_language() != target_language) continue; - hb_set_t sibling_unicodes; - (base+_.subtable).collect_unicodes (&sibling_unicodes); + hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_); auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes); - auto sibling = + subset_unicodes | hb_filter (sibling_unicodes); + auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes); for (; cmap12 && sibling; cmap12++, sibling++) { unsigned a = *cmap12; @@ -1616,13 +1671,7 @@ struct cmap if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false); auto it = - + hb_iter (c->plan->unicodes) - | hb_map ([&] (hb_codepoint_t _) - { - hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID; - c->plan->new_gid_for_codepoint (_, &new_gid); - return hb_pair_t (_, new_gid); - }) + + c->plan->unicode_to_new_gid_list.iter () | hb_filter ([&] (const hb_pair_t _) { return (_.second != HB_MAP_VALUE_INVALID); }) ; diff --git a/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh index a9deeba9a7a..24476eda178 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh @@ -197,30 +197,38 @@ struct CPAL public: bool serialize (hb_serialize_context_t *c, - const hb_array_t &color_records, const hb_array_t &color_record_indices, - const hb_map_t &color_record_index_map, - const hb_set_t &retained_color_record_indices) const + const hb_array_t &color_records, + const hb_vector_t& first_color_index_for_layer, + const hb_map_t& first_color_to_layer_index, + const hb_set_t &retained_color_indices) const { TRACE_SERIALIZE (this); + // TODO(grieger): limit total final size. + for (const auto idx : color_record_indices) { + hb_codepoint_t layer_index = first_color_to_layer_index[idx]; + HBUINT16 new_idx; - if (idx == 0) new_idx = 0; - else new_idx = color_record_index_map.get (idx); + new_idx = layer_index * retained_color_indices.get_population (); if (!c->copy (new_idx)) return_trace (false); } c->push (); - for (const auto _ : retained_color_record_indices.iter ()) + for (unsigned first_color_index : first_color_index_for_layer) { - if (!c->copy (color_records[_])) + for (hb_codepoint_t color_index : retained_color_indices) { - c->pop_discard (); - return_trace (false); + if (!c->copy (color_records[first_color_index + color_index])) + { + c->pop_discard (); + return_trace (false); + } } } + c->add_link (colorRecordsZ, c->pop_pack ()); return_trace (true); } @@ -228,6 +236,8 @@ struct CPAL bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); + if (!numPalettes) return_trace (false); + const hb_map_t *color_index_map = c->plan->colr_palettes; if (color_index_map->is_empty ()) return_trace (false); @@ -242,30 +252,34 @@ struct CPAL auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->version = version; out->numColors = retained_color_indices.get_population (); out->numPalettes = numPalettes; - const hb_array_t colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes); - hb_map_t color_record_index_map; - hb_set_t retained_color_record_indices; + hb_vector_t first_color_index_for_layer; + hb_map_t first_color_to_layer_index; - unsigned record_count = 0; + const hb_array_t colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes); for (const auto first_color_record_idx : colorRecordIndices) { - for (unsigned retained_color_idx : retained_color_indices.iter ()) - { - unsigned color_record_idx = first_color_record_idx + retained_color_idx; - if (color_record_index_map.has (color_record_idx)) continue; - color_record_index_map.set (color_record_idx, record_count); - retained_color_record_indices.add (color_record_idx); - record_count++; - } + if (first_color_to_layer_index.has (first_color_record_idx)) continue; + + first_color_index_for_layer.push (first_color_record_idx); + first_color_to_layer_index.set (first_color_record_idx, + first_color_index_for_layer.length - 1); } - out->numColorRecords = record_count; + out->numColorRecords = first_color_index_for_layer.length + * retained_color_indices.get_population (); + const hb_array_t color_records = (this+colorRecordsZ).as_array (numColorRecords); - if (!out->serialize (c->serializer, color_records, colorRecordIndices, color_record_index_map, retained_color_record_indices)) + if (!out->serialize (c->serializer, + colorRecordIndices, + color_records, + first_color_index_for_layer, + first_color_to_layer_index, + retained_color_indices)) return_trace (false); if (version == 1) diff --git a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh index b4ac6883443..866bb7e04c1 100644 --- a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh @@ -953,6 +953,8 @@ struct glyf glyf_table.destroy (); } + bool has_data () const { return num_glyphs; } + protected: template bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh index f2a58028e32..b644df708d4 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh @@ -91,12 +91,12 @@ template static inline void ClassDef_serialize (hb_serialize_context_t *c, Iterator it); -static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, - const hb_map_t &gid_klass_map, - hb_sorted_vector_t &glyphs, - const hb_set_t &klasses, - bool use_class_zero, - hb_map_t *klass_map /*INOUT*/); +static void ClassDef_remap_and_serialize ( + hb_serialize_context_t *c, + const hb_set_t &klasses, + bool use_class_zero, + hb_sorted_vector_t> &glyph_and_klass, /* IN/OUT */ + hb_map_t *klass_map /*IN/OUT*/); struct hb_prune_langsys_context_t @@ -1470,7 +1470,8 @@ struct CoverageFormat1 void next () { i++; } hb_codepoint_t get_glyph () const { return c->glyphArray[i]; } bool operator != (const iter_t& o) const - { return i != o.i || c != o.c; } + { return i != o.i; } + iter_t __end__ () const { iter_t it; it.init (*c); it.i = c->glyphArray.len; return it; } private: const struct CoverageFormat1 *c; @@ -1506,12 +1507,6 @@ struct CoverageFormat2 TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!glyphs)) - { - rangeRecord.len = 0; - return_trace (true); - } - /* TODO(iter) Write more efficiently? */ unsigned num_ranges = 0; @@ -1524,6 +1519,7 @@ struct CoverageFormat2 } if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false); + if (!num_ranges) return_trace (true); unsigned count = 0; unsigned range = (unsigned) -1; @@ -1552,25 +1548,26 @@ struct CoverageFormat2 bool intersects (const hb_set_t *glyphs) const { - /* TODO Speed up, using hb_set_next() and bsearch()? */ - /* TODO(iter) Rewrite as dagger. */ - for (const auto& range : rangeRecord.as_array ()) - if (range.intersects (glyphs)) - return true; - return false; + return hb_any (+ hb_iter (rangeRecord.as_array ()) + | hb_map ([glyphs] (const RangeRecord &range) { return range.intersects (glyphs); })); } bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - /* TODO(iter) Rewrite as dagger. */ - for (const auto& range : rangeRecord.as_array ()) + auto cmp = [] (const void *pk, const void *pr) -> int { - if (range.value <= index && - index < (unsigned int) range.value + (range.last - range.first) && - range.intersects (glyphs)) - return true; - else if (index < range.value) - return false; - } + unsigned index = * (const unsigned *) pk; + const RangeRecord &range = * (const RangeRecord *) pr; + if (index < range.value) return -1; + if (index > (unsigned int) range.value + (range.last - range.first)) return +1; + return 0; + }; + + auto arr = rangeRecord.as_array (); + unsigned idx; + if (hb_bsearch_impl (&idx, index, + arr.arrayZ, arr.length, sizeof (arr[0]), + (int (*)(const void *_key, const void *_item)) cmp)) + return arr.arrayZ[idx].intersects (glyphs); return false; } @@ -1579,8 +1576,10 @@ struct CoverageFormat2 for (const auto& range : rangeRecord.as_array ()) { if (!range.intersects (glyphs)) continue; - for (hb_codepoint_t g = range.first; g <= range.last; g++) - if (glyphs->has (g)) intersect_glyphs->add (g); + unsigned last = range.last; + for (hb_codepoint_t g = range.first - 1; + glyphs->next (&g) && g <= last;) + intersect_glyphs->add (g); } } @@ -1632,6 +1631,8 @@ struct CoverageFormat2 return; } } + else + j = 0; return; } coverage++; @@ -1639,7 +1640,15 @@ struct CoverageFormat2 } hb_codepoint_t get_glyph () const { return j; } bool operator != (const iter_t& o) const - { return i != o.i || j != o.j || c != o.c; } + { return i != o.i || j != o.j; } + iter_t __end__ () const + { + iter_t it; + it.init (*c); + it.i = c->rangeRecord.len; + it.j = 0; + return it; + } private: const struct CoverageFormat2 *c; @@ -1708,18 +1717,17 @@ struct Coverage bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - auto it = + iter () - | hb_filter (glyphset) - | hb_map_retains_sorting (glyph_map) + | hb_filter (c->plan->glyph_map_gsub) + | hb_map_retains_sorting (c->plan->glyph_map_gsub) ; - bool ret = bool (it); - Coverage_serialize (c->serializer, it); - return_trace (ret); + // Cache the iterator result as it will be iterated multiple times + // by the serialize code below. + hb_sorted_vector_t glyphs (it); + Coverage_serialize (c->serializer, glyphs.iter ()); + return_trace (bool (glyphs)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1822,7 +1830,7 @@ struct Coverage } bool operator != (const iter_t& o) const { - if (format != o.format) return true; + if (unlikely (format != o.format)) return true; switch (format) { case 1: return u.format1 != o.u.format1; @@ -1830,6 +1838,18 @@ struct Coverage default:return false; } } + iter_t __end__ () const + { + iter_t it = {}; + it.format = format; + switch (format) + { + case 1: it.u.format1 = u.format1.__end__ (); break; + case 2: it.u.format2 = u.format2.__end__ (); break; + default: break; + } + return it; + } private: unsigned int format; @@ -1857,16 +1877,14 @@ Coverage_serialize (hb_serialize_context_t *c, { c->start_embed ()->serialize (c, it); } static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, - const hb_map_t &gid_klass_map, - hb_sorted_vector_t &glyphs, const hb_set_t &klasses, bool use_class_zero, - hb_map_t *klass_map /*INOUT*/) + hb_sorted_vector_t> &glyph_and_klass, /* IN/OUT */ + hb_map_t *klass_map /*IN/OUT*/) { if (!klass_map) { - ClassDef_serialize (c, hb_zip (glyphs.iter (), + glyphs.iter () - | hb_map (gid_klass_map))); + ClassDef_serialize (c, glyph_and_klass.iter ()); return; } @@ -1883,17 +1901,15 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, idx++; } - auto it = - + glyphs.iter () - | hb_map_retains_sorting ([&] (const HBGlyphID16& gid) -> hb_pair_t - { - unsigned new_klass = klass_map->get (gid_klass_map[gid]); - return hb_pair ((hb_codepoint_t)gid, new_klass); - }) - ; - c->propagate_error (glyphs, klasses); - ClassDef_serialize (c, it); + for (unsigned i = 0; i < glyph_and_klass.length; i++) + { + hb_codepoint_t klass = glyph_and_klass[i].second; + glyph_and_klass[i].second = klass_map->get (klass); + } + + c->propagate_error (glyph_and_klass, klasses); + ClassDef_serialize (c, glyph_and_klass.iter ()); } /* @@ -1949,36 +1965,37 @@ struct ClassDefFormat1 const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; + const hb_map_t &glyph_map = *c->plan->glyph_map_gsub; - hb_sorted_vector_t glyphs; + hb_sorted_vector_t> glyph_and_klass; hb_set_t orig_klasses; - hb_map_t gid_org_klass_map; hb_codepoint_t start = startGlyph; hb_codepoint_t end = start + classValue.len; - for (const hb_codepoint_t gid : + hb_range (start, end) - | hb_filter (glyphset)) + for (const hb_codepoint_t gid : + hb_range (start, end)) { + hb_codepoint_t new_gid = glyph_map[gid]; + if (new_gid == HB_MAP_VALUE_INVALID) continue; if (glyph_filter && !glyph_filter->has(gid)) continue; unsigned klass = classValue[gid - start]; if (!klass) continue; - glyphs.push (glyph_map[gid]); - gid_org_klass_map.set (glyph_map[gid], klass); + glyph_and_klass.push (hb_pair (new_gid, klass)); orig_klasses.add (klass); } unsigned glyph_count = glyph_filter - ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) - : glyphset.get_population (); - use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population (); - ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map, - glyphs, orig_klasses, use_class_zero, klass_map); - return_trace (keep_empty_table || (bool) glyphs); + ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter)) + : glyph_map.get_population (); + use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length; + ClassDef_remap_and_serialize (c->serializer, + orig_klasses, + use_class_zero, + glyph_and_klass, + klass_map); + return_trace (keep_empty_table || (bool) glyph_and_klass); } bool sanitize (hb_sanitize_context_t *c) const @@ -2044,10 +2061,9 @@ struct ClassDefFormat1 } /* TODO Speed up, using set overlap first? */ /* TODO(iter) Rewrite as dagger. */ - HBUINT16 k {klass}; const HBUINT16 *arr = classValue.arrayZ; for (unsigned int i = 0; i < count; i++) - if (arr[i] == k && glyphs->has (startGlyph + i)) + if (arr[i] == klass && glyphs->has (startGlyph + i)) return true; return false; } @@ -2057,17 +2073,32 @@ struct ClassDefFormat1 unsigned count = classValue.len; if (klass == 0) { - hb_codepoint_t endGlyph = startGlyph + count -1; - for (hb_codepoint_t g : glyphs->iter ()) - if (g < startGlyph || g > endGlyph) - intersect_glyphs->add (g); + unsigned start_glyph = startGlyph; + for (unsigned g = HB_SET_VALUE_INVALID; + hb_set_next (glyphs, &g) && g < start_glyph;) + intersect_glyphs->add (g); + + for (unsigned g = startGlyph + count - 1; + hb_set_next (glyphs, &g);) + intersect_glyphs->add (g); return; } for (unsigned i = 0; i < count; i++) if (classValue[i] == klass && glyphs->has (startGlyph + i)) - intersect_glyphs->add (startGlyph + i); + intersect_glyphs->add (startGlyph + i); + +#if 0 + /* The following implementation is faster asymptotically, but slower + * in practice. */ + unsigned start_glyph = startGlyph; + unsigned end_glyph = start_glyph + count; + for (unsigned g = startGlyph - 1; + hb_set_next (glyphs, &g) && g < end_glyph;) + if (classValue.arrayZ[g - start_glyph] == klass) + intersect_glyphs->add (g); +#endif } void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const @@ -2167,12 +2198,10 @@ struct ClassDefFormat2 const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; + const hb_map_t &glyph_map = *c->plan->glyph_map_gsub; - hb_sorted_vector_t glyphs; + hb_sorted_vector_t> glyph_and_klass; hb_set_t orig_klasses; - hb_map_t gid_org_klass_map; unsigned count = rangeRecord.len; for (unsigned i = 0; i < count; i++) @@ -2183,21 +2212,26 @@ struct ClassDefFormat2 hb_codepoint_t end = rangeRecord[i].last + 1; for (hb_codepoint_t g = start; g < end; g++) { - if (!glyphset.has (g)) continue; + hb_codepoint_t new_gid = glyph_map[g]; + if (new_gid == HB_MAP_VALUE_INVALID) continue; if (glyph_filter && !glyph_filter->has (g)) continue; - glyphs.push (glyph_map[g]); - gid_org_klass_map.set (glyph_map[g], klass); + + glyph_and_klass.push (hb_pair (new_gid, klass)); orig_klasses.add (klass); } } + const hb_set_t& glyphset = *c->plan->glyphset_gsub (); unsigned glyph_count = glyph_filter ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) - : glyphset.get_population (); - use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population (); - ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map, - glyphs, orig_klasses, use_class_zero, klass_map); - return_trace (keep_empty_table || (bool) glyphs); + : glyph_map.get_population (); + use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length; + ClassDef_remap_and_serialize (c->serializer, + orig_klasses, + use_class_zero, + glyph_and_klass, + klass_map); + return_trace (keep_empty_table || (bool) glyph_and_klass); } bool sanitize (hb_sanitize_context_t *c) const @@ -2263,10 +2297,9 @@ struct ClassDefFormat2 } /* TODO Speed up, using set overlap first? */ /* TODO(iter) Rewrite as dagger. */ - HBUINT16 k {klass}; const RangeRecord *arr = rangeRecord.arrayZ; for (unsigned int i = 0; i < count; i++) - if (arr[i].value == k && arr[i].intersects (glyphs)) + if (arr[i].value == klass && arr[i].intersects (glyphs)) return true; return false; } @@ -2279,43 +2312,44 @@ struct ClassDefFormat2 hb_codepoint_t g = HB_SET_VALUE_INVALID; for (unsigned int i = 0; i < count; i++) { - if (!hb_set_next (glyphs, &g)) - break; - while (g != HB_SET_VALUE_INVALID && g < rangeRecord[i].first) - { - intersect_glyphs->add (g); - hb_set_next (glyphs, &g); + if (!hb_set_next (glyphs, &g)) + goto done; + while (g < rangeRecord[i].first) + { + intersect_glyphs->add (g); + if (!hb_set_next (glyphs, &g)) + goto done; } g = rangeRecord[i].last; } - while (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g)) - intersect_glyphs->add (g); + while (hb_set_next (glyphs, &g)) + intersect_glyphs->add (g); + done: return; } - hb_codepoint_t g = HB_SET_VALUE_INVALID; +#if 0 + /* The following implementation is faster asymptotically, but slower + * in practice. */ + if ((count >> 3) > glyphs->get_population ()) + { + for (hb_codepoint_t g = HB_SET_VALUE_INVALID; + hb_set_next (glyphs, &g);) + if (rangeRecord.as_array ().bfind (g)) + intersect_glyphs->add (g); + return; + } +#endif + for (unsigned int i = 0; i < count; i++) { if (rangeRecord[i].value != klass) continue; - if (g != HB_SET_VALUE_INVALID) - { - if (g >= rangeRecord[i].first && - g <= rangeRecord[i].last) - intersect_glyphs->add (g); - if (g > rangeRecord[i].last) - continue; - } - - g = rangeRecord[i].first - 1; - while (hb_set_next (glyphs, &g)) - { - if (g >= rangeRecord[i].first && g <= rangeRecord[i].last) - intersect_glyphs->add (g); - else if (g > rangeRecord[i].last) - break; - } + unsigned end = rangeRecord[i].last + 1; + for (hb_codepoint_t g = rangeRecord[i].first - 1; + hb_set_next (glyphs, &g) && g < end;) + intersect_glyphs->add (g); } } diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh index 56e8c5b0063..c9750ff63b5 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh @@ -1328,7 +1328,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, bool has_pos_glyphs = false; hb_set_t pos_glyphs; - if (hb_set_is_empty (covered_seq_indicies) || !hb_set_has (covered_seq_indicies, seqIndex)) + if (!hb_set_has (covered_seq_indicies, seqIndex)) { has_pos_glyphs = true; if (seqIndex == 0) @@ -1361,7 +1361,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, covered_seq_indicies->add (seqIndex); if (has_pos_glyphs) { - c->push_cur_active_glyphs () = pos_glyphs; + c->push_cur_active_glyphs () = std::move (pos_glyphs); } else { c->push_cur_active_glyphs ().set (*c->glyphs); } diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh index ea627cd27ef..c8e51516949 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh @@ -606,7 +606,7 @@ static const uint8_t use_table[] = { /* 10A00 */ B, VBlw, VBlw, VBlw, WJ, VAbv, VBlw, WJ, WJ, WJ, WJ, WJ, VPst, VMBlw, VMBlw, VMAbv, /* 10A10 */ B, B, B, B, WJ, B, B, B, WJ, B, B, B, B, B, B, B, /* 10A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 10A30 */ B, B, B, B, B, B, WJ, WJ, CMAbv, CMBlw, CMBlw, WJ, WJ, WJ, WJ, IS, + /* 10A30 */ B, B, B, B, B, B, WJ, WJ, CMBlw, CMBlw, CMBlw, WJ, WJ, WJ, WJ, IS, /* 10A40 */ B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, #define use_offset_0x10ac0u 4304 diff --git a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh index 52617832774..b242fba2d87 100644 --- a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh @@ -13,1610 +13,1613 @@ #ifndef HB_OT_TAG_TABLE_HH #define HB_OT_TAG_TABLE_HH -static const LangTag ot_languages[] = { - {"aa", HB_TAG('A','F','R',' ')}, /* Afar */ - {"aae", HB_TAG('S','Q','I',' ')}, /* Arbëreshë Albanian -> Albanian */ - {"aao", HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */ - {"aat", HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */ - {"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */ - {"aba", HB_TAG_NONE }, /* Abé != Abaza */ - {"abh", HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */ - {"abq", HB_TAG('A','B','A',' ')}, /* Abaza */ - {"abs", HB_TAG('C','P','P',' ')}, /* Ambonese Malay -> Creoles */ - {"abv", HB_TAG('A','R','A',' ')}, /* Baharna Arabic -> Arabic */ - {"acf", HB_TAG('F','A','N',' ')}, /* Saint Lucian Creole French -> French Antillean */ - {"acf", HB_TAG('C','P','P',' ')}, /* Saint Lucian Creole French -> Creoles */ -/*{"ach", HB_TAG('A','C','H',' ')},*/ /* Acoli -> Acholi */ - {"acm", HB_TAG('A','R','A',' ')}, /* Mesopotamian Arabic -> Arabic */ - {"acq", HB_TAG('A','R','A',' ')}, /* Ta'izzi-Adeni Arabic -> Arabic */ - {"acr", HB_TAG('A','C','R',' ')}, /* Achi */ - {"acr", HB_TAG('M','Y','N',' ')}, /* Achi -> Mayan */ - {"acw", HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */ - {"acx", HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */ - {"acy", HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */ - {"ada", HB_TAG('D','N','G',' ')}, /* Adangme -> Dangme */ - {"adf", HB_TAG('A','R','A',' ')}, /* Dhofari Arabic -> Arabic */ - {"adp", HB_TAG('D','Z','N',' ')}, /* Adap (retired code) -> Dzongkha */ -/*{"ady", HB_TAG('A','D','Y',' ')},*/ /* Adyghe */ - {"aeb", HB_TAG('A','R','A',' ')}, /* Tunisian Arabic -> Arabic */ - {"aec", HB_TAG('A','R','A',' ')}, /* Saidi Arabic -> Arabic */ - {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */ - {"afb", HB_TAG('A','R','A',' ')}, /* Gulf Arabic -> Arabic */ - {"afk", HB_TAG_NONE }, /* Nanubae != Afrikaans */ - {"afs", HB_TAG('C','P','P',' ')}, /* Afro-Seminole Creole -> Creoles */ - {"agu", HB_TAG('M','Y','N',' ')}, /* Aguacateco -> Mayan */ - {"agw", HB_TAG_NONE }, /* Kahua != Agaw */ - {"ahg", HB_TAG('A','G','W',' ')}, /* Qimant -> Agaw */ - {"aht", HB_TAG('A','T','H',' ')}, /* Ahtena -> Athapaskan */ - {"aig", HB_TAG('C','P','P',' ')}, /* Antigua and Barbuda Creole English -> Creoles */ - {"aii", HB_TAG('S','W','A',' ')}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ - {"aii", HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */ -/*{"aio", HB_TAG('A','I','O',' ')},*/ /* Aiton */ - {"aiw", HB_TAG('A','R','I',' ')}, /* Aari */ - {"ajp", HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */ - {"ajt", HB_TAG('A','R','A',' ')}, /* Judeo-Tunisian Arabic (retired code) -> Arabic */ - {"ak", HB_TAG('A','K','A',' ')}, /* Akan [macrolanguage] */ - {"akb", HB_TAG('A','K','B',' ')}, /* Batak Angkola */ - {"akb", HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */ - {"aln", HB_TAG('S','Q','I',' ')}, /* Gheg Albanian -> Albanian */ - {"als", HB_TAG('S','Q','I',' ')}, /* Tosk Albanian -> Albanian */ -/*{"alt", HB_TAG('A','L','T',' ')},*/ /* Southern Altai -> Altai */ - {"am", HB_TAG('A','M','H',' ')}, /* Amharic */ - {"amf", HB_TAG('H','B','N',' ')}, /* Hamer-Banna -> Hammer-Banna */ - {"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic -> Syriac */ - {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */ -/*{"ang", HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */ - {"aoa", HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */ - {"apa", HB_TAG('A','T','H',' ')}, /* Apache [collection] -> Athapaskan */ - {"apc", HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */ - {"apd", HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */ - {"apj", HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */ - {"apk", HB_TAG('A','T','H',' ')}, /* Kiowa Apache -> Athapaskan */ - {"apl", HB_TAG('A','T','H',' ')}, /* Lipan Apache -> Athapaskan */ - {"apm", HB_TAG('A','T','H',' ')}, /* Mescalero-Chiricahua Apache -> Athapaskan */ - {"apw", HB_TAG('A','T','H',' ')}, /* Western Apache -> Athapaskan */ - {"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */ - {"arb", HB_TAG('A','R','A',' ')}, /* Standard Arabic -> Arabic */ - {"ari", HB_TAG_NONE }, /* Arikara != Aari */ - {"ark", HB_TAG_NONE }, /* Arikapú != Rakhine */ - {"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */ - {"arq", HB_TAG('A','R','A',' ')}, /* Algerian Arabic -> Arabic */ - {"ars", HB_TAG('A','R','A',' ')}, /* Najdi Arabic -> Arabic */ - {"ary", HB_TAG('M','O','R',' ')}, /* Moroccan Arabic -> Moroccan */ - {"ary", HB_TAG('A','R','A',' ')}, /* Moroccan Arabic -> Arabic */ - {"arz", HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */ - {"as", HB_TAG('A','S','M',' ')}, /* Assamese */ -/*{"ast", HB_TAG('A','S','T',' ')},*/ /* Asturian */ -/*{"ath", HB_TAG('A','T','H',' ')},*/ /* Athapascan [collection] -> Athapaskan */ - {"atj", HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */ - {"atv", HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */ - {"auj", HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */ - {"auz", HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */ - {"av", HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */ - {"avl", HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ -/*{"avn", HB_TAG('A','V','N',' ')},*/ /* Avatime */ -/*{"awa", HB_TAG('A','W','A',' ')},*/ /* Awadhi */ - {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */ - {"ayc", HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */ - {"ayh", HB_TAG('A','R','A',' ')}, /* Hadrami Arabic -> Arabic */ - {"ayl", HB_TAG('A','R','A',' ')}, /* Libyan Arabic -> Arabic */ - {"ayn", HB_TAG('A','R','A',' ')}, /* Sanaani Arabic -> Arabic */ - {"ayp", HB_TAG('A','R','A',' ')}, /* North Mesopotamian Arabic -> Arabic */ - {"ayr", HB_TAG('A','Y','M',' ')}, /* Central Aymara -> Aymara */ - {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */ - {"azb", HB_TAG('A','Z','B',' ')}, /* South Azerbaijani -> Torki */ - {"azb", HB_TAG('A','Z','E',' ')}, /* South Azerbaijani -> Azerbaijani */ - {"azd", HB_TAG('N','A','H',' ')}, /* Eastern Durango Nahuatl -> Nahuatl */ - {"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani -> Azerbaijani */ - {"azn", HB_TAG('N','A','H',' ')}, /* Western Durango Nahuatl -> Nahuatl */ - {"azz", HB_TAG('N','A','H',' ')}, /* Highland Puebla Nahuatl -> Nahuatl */ - {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */ - {"bad", HB_TAG('B','A','D','0')}, /* Banda [collection] */ - {"bag", HB_TAG_NONE }, /* Tuki != Baghelkhandi */ - {"bah", HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */ - {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [collection] */ - {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */ -/*{"ban", HB_TAG('B','A','N',' ')},*/ /* Balinese */ -/*{"bar", HB_TAG('B','A','R',' ')},*/ /* Bavarian */ - {"bau", HB_TAG_NONE }, /* Bada (Nigeria) != Baulé */ - {"bbc", HB_TAG('B','B','C',' ')}, /* Batak Toba */ - {"bbc", HB_TAG('B','T','K',' ')}, /* Batak Toba -> Batak */ - {"bbj", HB_TAG('B','M','L',' ')}, /* Ghomálá' -> Bamileke */ - {"bbp", HB_TAG('B','A','D','0')}, /* West Central Banda -> Banda */ - {"bbr", HB_TAG_NONE }, /* Girawa != Berber */ - {"bbz", HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic (retired code) -> Arabic */ - {"bcc", HB_TAG('B','L','I',' ')}, /* Southern Balochi -> Baluchi */ - {"bch", HB_TAG_NONE }, /* Bariai != Bench */ - {"bci", HB_TAG('B','A','U',' ')}, /* Baoulé -> Baulé */ - {"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */ - {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */ - {"bcr", HB_TAG('A','T','H',' ')}, /* Babine -> Athapaskan */ -/*{"bdy", HB_TAG('B','D','Y',' ')},*/ /* Bandjalang */ - {"be", HB_TAG('B','E','L',' ')}, /* Belarusian -> Belarussian */ - {"bea", HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */ - {"beb", HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */ -/*{"bem", HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */ - {"ber", HB_TAG('B','B','R',' ')}, /* Berber [collection] */ - {"bew", HB_TAG('C','P','P',' ')}, /* Betawi -> Creoles */ - {"bfl", HB_TAG('B','A','D','0')}, /* Banda-Ndélé -> Banda */ - {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */ - {"bft", HB_TAG('B','L','T',' ')}, /* Balti */ - {"bfu", HB_TAG('L','A','H',' ')}, /* Gahri -> Lahuli */ - {"bfy", HB_TAG('B','A','G',' ')}, /* Bagheli -> Baghelkhandi */ - {"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */ -/*{"bgc", HB_TAG('B','G','C',' ')},*/ /* Haryanvi */ - {"bgn", HB_TAG('B','L','I',' ')}, /* Western Balochi -> Baluchi */ - {"bgp", HB_TAG('B','L','I',' ')}, /* Eastern Balochi -> Baluchi */ - {"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */ - {"bgq", HB_TAG('R','A','J',' ')}, /* Bagri -> Rajasthani */ - {"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin -> Chin */ - {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */ -/*{"bhi", HB_TAG('B','H','I',' ')},*/ /* Bhilali -> Bhili */ - {"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) -> Bikol */ -/*{"bho", HB_TAG('B','H','O',' ')},*/ /* Bhojpuri */ - {"bhr", HB_TAG('M','L','G',' ')}, /* Bara Malagasy -> Malagasy */ - {"bi", HB_TAG('B','I','S',' ')}, /* Bislama */ - {"bi", HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */ -/*{"bik", HB_TAG('B','I','K',' ')},*/ /* Bikol [macrolanguage] */ - {"bil", HB_TAG_NONE }, /* Bile != Bilen */ - {"bin", HB_TAG('E','D','O',' ')}, /* Edo */ - {"biu", HB_TAG('Q','I','N',' ')}, /* Biete -> Chin */ -/*{"bjj", HB_TAG('B','J','J',' ')},*/ /* Kanauji */ - {"bjn", HB_TAG('M','L','Y',' ')}, /* Banjar -> Malay */ - {"bjo", HB_TAG('B','A','D','0')}, /* Mid-Southern Banda -> Banda */ - {"bjq", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ - {"bjs", HB_TAG('C','P','P',' ')}, /* Bajan -> Creoles */ - {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja -> Balante */ - {"bkf", HB_TAG_NONE }, /* Beeke != Blackfoot */ - {"bko", HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */ - {"bla", HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */ - {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */ - {"blg", HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */ - {"bli", HB_TAG_NONE }, /* Bolia != Baluchi */ - {"blk", HB_TAG('B','L','K',' ')}, /* Pa’o Karen */ - {"blk", HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */ - {"bln", HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol -> Bikol */ - {"blt", HB_TAG_NONE }, /* Tai Dam != Balti */ - {"bm", HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */ - {"bmb", HB_TAG_NONE }, /* Bembe != Bambara (Bamanankan) */ - {"bml", HB_TAG_NONE }, /* Bomboli != Bamileke */ - {"bmm", HB_TAG('M','L','G',' ')}, /* Northern Betsimisaraka Malagasy -> Malagasy */ - {"bn", HB_TAG('B','E','N',' ')}, /* Bengali */ - {"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */ - {"bpd", HB_TAG('B','A','D','0')}, /* Banda-Banda -> Banda */ - {"bpl", HB_TAG('C','P','P',' ')}, /* Broome Pearling Lugger Pidgin -> Creoles */ - {"bpq", HB_TAG('C','P','P',' ')}, /* Banda Malay -> Creoles */ -/*{"bpy", HB_TAG('B','P','Y',' ')},*/ /* Bishnupriya -> Bishnupriya Manipuri */ - {"bqi", HB_TAG('L','R','C',' ')}, /* Bakhtiari -> Luri */ - {"bqk", HB_TAG('B','A','D','0')}, /* Banda-Mbrès -> Banda */ - {"br", HB_TAG('B','R','E',' ')}, /* Breton */ - {"bra", HB_TAG('B','R','I',' ')}, /* Braj -> Braj Bhasha */ - {"brc", HB_TAG('C','P','P',' ')}, /* Berbice Creole Dutch -> Creoles */ -/*{"brh", HB_TAG('B','R','H',' ')},*/ /* Brahui */ - {"bri", HB_TAG_NONE }, /* Mokpwe != Braj Bhasha */ - {"brm", HB_TAG_NONE }, /* Barambu != Burmese */ -/*{"brx", HB_TAG('B','R','X',' ')},*/ /* Bodo (India) */ - {"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */ - {"bsh", HB_TAG_NONE }, /* Kati != Bashkir */ -/*{"bsk", HB_TAG('B','S','K',' ')},*/ /* Burushaski */ - {"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) (retired code) */ - {"btd", HB_TAG('B','T','D',' ')}, /* Batak Dairi (Pakpak) */ - {"btd", HB_TAG('B','T','K',' ')}, /* Batak Dairi -> Batak */ - {"bti", HB_TAG_NONE }, /* Burate != Beti */ - {"btj", HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */ -/*{"btk", HB_TAG('B','T','K',' ')},*/ /* Batak [collection] */ - {"btm", HB_TAG('B','T','M',' ')}, /* Batak Mandailing */ - {"btm", HB_TAG('B','T','K',' ')}, /* Batak Mandailing -> Batak */ - {"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */ - {"bts", HB_TAG('B','T','S',' ')}, /* Batak Simalungun */ - {"bts", HB_TAG('B','T','K',' ')}, /* Batak Simalungun -> Batak */ - {"btx", HB_TAG('B','T','X',' ')}, /* Batak Karo */ - {"btx", HB_TAG('B','T','K',' ')}, /* Batak Karo -> Batak */ - {"btz", HB_TAG('B','T','Z',' ')}, /* Batak Alas-Kluet */ - {"btz", HB_TAG('B','T','K',' ')}, /* Batak Alas-Kluet -> Batak */ -/*{"bug", HB_TAG('B','U','G',' ')},*/ /* Buginese -> Bugis */ - {"bum", HB_TAG('B','T','I',' ')}, /* Bulu (Cameroon) -> Beti */ - {"bve", HB_TAG('M','L','Y',' ')}, /* Berau Malay -> Malay */ - {"bvu", HB_TAG('M','L','Y',' ')}, /* Bukit Malay -> Malay */ - {"bwe", HB_TAG('K','R','N',' ')}, /* Bwe Karen -> Karen */ - {"bxk", HB_TAG('L','U','H',' ')}, /* Bukusu -> Luyia */ - {"bxo", HB_TAG('C','P','P',' ')}, /* Barikanchi -> Creoles */ - {"bxp", HB_TAG('B','T','I',' ')}, /* Bebil -> Beti */ - {"bxr", HB_TAG('R','B','U',' ')}, /* Russia Buriat -> Russian Buriat */ - {"byn", HB_TAG('B','I','L',' ')}, /* Bilin -> Bilen */ - {"byv", HB_TAG('B','Y','V',' ')}, /* Medumba */ - {"byv", HB_TAG('B','M','L',' ')}, /* Medumba -> Bamileke */ - {"bzc", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy -> Malagasy */ - {"bzj", HB_TAG('C','P','P',' ')}, /* Belize Kriol English -> Creoles */ - {"bzk", HB_TAG('C','P','P',' ')}, /* Nicaragua Creole English -> Creoles */ - {"ca", HB_TAG('C','A','T',' ')}, /* Catalan */ - {"caa", HB_TAG('M','Y','N',' ')}, /* Chortí -> Mayan */ - {"cac", HB_TAG('M','Y','N',' ')}, /* Chuj -> Mayan */ - {"caf", HB_TAG('C','R','R',' ')}, /* Southern Carrier -> Carrier */ - {"caf", HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */ - {"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */ - {"cak", HB_TAG('M','Y','N',' ')}, /* Kaqchikel -> Mayan */ - {"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano -> Zamboanga Chavacano */ - {"cbk", HB_TAG('C','P','P',' ')}, /* Chavacano -> Creoles */ - {"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */ - {"ccl", HB_TAG('C','P','P',' ')}, /* Cutchi-Swahili -> Creoles */ - {"ccm", HB_TAG('C','P','P',' ')}, /* Malaccan Creole Malay -> Creoles */ - {"cco", HB_TAG('C','C','H','N')}, /* Comaltepec Chinantec -> Chinantec */ - {"ccq", HB_TAG('A','R','K',' ')}, /* Chaungtha (retired code) -> Rakhine */ - {"cdo", HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese, Simplified */ - {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */ -/*{"ceb", HB_TAG('C','E','B',' ')},*/ /* Cebuano */ - {"cek", HB_TAG('Q','I','N',' ')}, /* Eastern Khumi Chin -> Chin */ - {"cey", HB_TAG('Q','I','N',' ')}, /* Ekai Chin -> Chin */ - {"cfm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) */ - {"cfm", HB_TAG('Q','I','N',' ')}, /* Falam Chin -> Chin */ -/*{"cgg", HB_TAG('C','G','G',' ')},*/ /* Chiga */ - {"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */ - {"chf", HB_TAG('M','Y','N',' ')}, /* Tabasco Chontal -> Mayan */ - {"chg", HB_TAG_NONE }, /* Chagatai != Chaha Gurage */ - {"chh", HB_TAG_NONE }, /* Chinook != Chattisgarhi */ - {"chj", HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */ - {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */ - {"chm", HB_TAG('H','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> High Mari */ - {"chm", HB_TAG('L','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> Low Mari */ - {"chn", HB_TAG('C','P','P',' ')}, /* Chinook jargon -> Creoles */ -/*{"cho", HB_TAG('C','H','O',' ')},*/ /* Choctaw */ - {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */ - {"chp", HB_TAG('S','A','Y',' ')}, /* Chipewyan -> Sayisi */ - {"chp", HB_TAG('A','T','H',' ')}, /* Chipewyan -> Athapaskan */ - {"chq", HB_TAG('C','C','H','N')}, /* Quiotepec Chinantec -> Chinantec */ -/*{"chr", HB_TAG('C','H','R',' ')},*/ /* Cherokee */ -/*{"chy", HB_TAG('C','H','Y',' ')},*/ /* Cheyenne */ - {"chz", HB_TAG('C','C','H','N')}, /* Ozumacín Chinantec -> Chinantec */ - {"ciw", HB_TAG('O','J','B',' ')}, /* Chippewa -> Ojibway */ -/*{"cja", HB_TAG('C','J','A',' ')},*/ /* Western Cham */ -/*{"cjm", HB_TAG('C','J','M',' ')},*/ /* Eastern Cham */ - {"cjy", HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese, Simplified */ - {"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin (retired code) -> Chin */ - {"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish -> Kurdish */ - {"ckn", HB_TAG('Q','I','N',' ')}, /* Kaang Chin -> Chin */ - {"cks", HB_TAG('C','P','P',' ')}, /* Tayo -> Creoles */ - {"ckt", HB_TAG('C','H','K',' ')}, /* Chukot -> Chukchi */ - {"ckz", HB_TAG('M','Y','N',' ')}, /* Cakchiquel-Quiché Mixed Language -> Mayan */ - {"clc", HB_TAG('A','T','H',' ')}, /* Chilcotin -> Athapaskan */ - {"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */ - {"cle", HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */ - {"clj", HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */ - {"clt", HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */ - {"cmn", HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */ - {"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */ - {"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */ - {"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin -> Chin */ - {"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin -> Chin */ - {"cnl", HB_TAG('C','C','H','N')}, /* Lalana Chinantec -> Chinantec */ - {"cnp", HB_TAG('Z','H','S',' ')}, /* Northern Ping Chinese -> Chinese, Simplified */ - {"cnr", HB_TAG('S','R','B',' ')}, /* Montenegrin -> Serbian */ - {"cnt", HB_TAG('C','C','H','N')}, /* Tepetotutla Chinantec -> Chinantec */ - {"cnu", HB_TAG('B','B','R',' ')}, /* Chenoua -> Berber */ - {"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */ - {"co", HB_TAG('C','O','S',' ')}, /* Corsican */ - {"coa", HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */ - {"cob", HB_TAG('M','Y','N',' ')}, /* Chicomuceltec -> Mayan */ -/*{"cop", HB_TAG('C','O','P',' ')},*/ /* Coptic */ - {"coq", HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */ - {"cpa", HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */ - {"cpe", HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [collection] -> Creoles */ - {"cpf", HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [collection] -> Creoles */ - {"cpi", HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */ -/*{"cpp", HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [collection] -> Creoles */ - {"cpx", HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese, Simplified */ - {"cqd", HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */ - {"cqu", HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ - {"cqu", HB_TAG('Q','U','Z',' ')}, /* Chilean Quechua (retired code) -> Quechua */ - {"cr", HB_TAG('C','R','E',' ')}, /* Cree [macrolanguage] */ - {"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ - {"cri", HB_TAG('C','P','P',' ')}, /* Sãotomense -> Creoles */ - {"crj", HB_TAG('E','C','R',' ')}, /* Southern East Cree -> Eastern Cree */ - {"crj", HB_TAG('Y','C','R',' ')}, /* Southern East Cree -> Y-Cree */ - {"crj", HB_TAG('C','R','E',' ')}, /* Southern East Cree -> Cree */ - {"crk", HB_TAG('W','C','R',' ')}, /* Plains Cree -> West-Cree */ - {"crk", HB_TAG('Y','C','R',' ')}, /* Plains Cree -> Y-Cree */ - {"crk", HB_TAG('C','R','E',' ')}, /* Plains Cree -> Cree */ - {"crl", HB_TAG('E','C','R',' ')}, /* Northern East Cree -> Eastern Cree */ - {"crl", HB_TAG('Y','C','R',' ')}, /* Northern East Cree -> Y-Cree */ - {"crl", HB_TAG('C','R','E',' ')}, /* Northern East Cree -> Cree */ - {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */ - {"crm", HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */ - {"crm", HB_TAG('C','R','E',' ')}, /* Moose Cree -> Cree */ - {"crp", HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [collection] -> Creoles */ - {"crr", HB_TAG_NONE }, /* Carolina Algonquian != Carrier */ - {"crs", HB_TAG('C','P','P',' ')}, /* Seselwa Creole French -> Creoles */ - {"crt", HB_TAG_NONE }, /* Iyojwa'ja Chorote != Crimean Tatar */ - {"crx", HB_TAG('C','R','R',' ')}, /* Carrier */ - {"crx", HB_TAG('A','T','H',' ')}, /* Carrier -> Athapaskan */ - {"cs", HB_TAG('C','S','Y',' ')}, /* Czech */ - {"csa", HB_TAG('C','C','H','N')}, /* Chiltepec Chinantec -> Chinantec */ -/*{"csb", HB_TAG('C','S','B',' ')},*/ /* Kashubian */ - {"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin -> Chin */ - {"csj", HB_TAG('Q','I','N',' ')}, /* Songlai Chin -> Chin */ - {"csl", HB_TAG_NONE }, /* Chinese Sign Language != Church Slavonic */ - {"cso", HB_TAG('C','C','H','N')}, /* Sochiapam Chinantec -> Chinantec */ - {"csp", HB_TAG('Z','H','S',' ')}, /* Southern Ping Chinese -> Chinese, Simplified */ - {"csv", HB_TAG('Q','I','N',' ')}, /* Sumtu Chin -> Chin */ - {"csw", HB_TAG('N','C','R',' ')}, /* Swampy Cree -> N-Cree */ - {"csw", HB_TAG('N','H','C',' ')}, /* Swampy Cree -> Norway House Cree */ - {"csw", HB_TAG('C','R','E',' ')}, /* Swampy Cree -> Cree */ - {"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin -> Chin */ - {"ctc", HB_TAG('A','T','H',' ')}, /* Chetco -> Athapaskan */ - {"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin -> Chin */ - {"cte", HB_TAG('C','C','H','N')}, /* Tepinapa Chinantec -> Chinantec */ -/*{"ctg", HB_TAG('C','T','G',' ')},*/ /* Chittagonian */ - {"cth", HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */ - {"ctl", HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */ - {"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */ -/*{"ctt", HB_TAG('C','T','T',' ')},*/ /* Wayanad Chetti */ - {"ctu", HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */ - {"cu", HB_TAG('C','S','L',' ')}, /* Church Slavonic */ - {"cuc", HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */ -/*{"cuk", HB_TAG('C','U','K',' ')},*/ /* San Blas Kuna */ - {"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */ - {"cvn", HB_TAG('C','C','H','N')}, /* Valle Nacional Chinantec -> Chinantec */ - {"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */ - {"cwd", HB_TAG('T','C','R',' ')}, /* Woods Cree -> TH-Cree */ - {"cwd", HB_TAG('C','R','E',' ')}, /* Woods Cree -> Cree */ - {"cy", HB_TAG('W','E','L',' ')}, /* Welsh */ - {"czh", HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese, Simplified */ - {"czo", HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */ - {"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */ - {"da", HB_TAG('D','A','N',' ')}, /* Danish */ -/*{"dag", HB_TAG('D','A','G',' ')},*/ /* Dagbani */ - {"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */ - {"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */ -/*{"dar", HB_TAG('D','A','R',' ')},*/ /* Dargwa */ -/*{"dax", HB_TAG('D','A','X',' ')},*/ /* Dayi */ - {"dcr", HB_TAG('C','P','P',' ')}, /* Negerhollands -> Creoles */ - {"de", HB_TAG('D','E','U',' ')}, /* German */ - {"den", HB_TAG('S','L','A',' ')}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ - {"den", HB_TAG('A','T','H',' ')}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ - {"dep", HB_TAG('C','P','P',' ')}, /* Pidgin Delaware -> Creoles */ - {"dgo", HB_TAG('D','G','O',' ')}, /* Dogri (individual language) */ - {"dgo", HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) */ - {"dgr", HB_TAG('A','T','H',' ')}, /* Dogrib -> Athapaskan */ - {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */ -/*{"dhg", HB_TAG('D','H','G',' ')},*/ /* Dhangu */ - {"dhv", HB_TAG_NONE }, /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */ - {"dib", HB_TAG('D','N','K',' ')}, /* South Central Dinka -> Dinka */ - {"dik", HB_TAG('D','N','K',' ')}, /* Southwestern Dinka -> Dinka */ - {"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ - {"dip", HB_TAG('D','N','K',' ')}, /* Northeastern Dinka -> Dinka */ - {"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */ - {"diq", HB_TAG('Z','Z','A',' ')}, /* Dimli -> Zazaki */ - {"diw", HB_TAG('D','N','K',' ')}, /* Northwestern Dinka -> Dinka */ - {"dje", HB_TAG('D','J','R',' ')}, /* Zarma */ - {"djk", HB_TAG('C','P','P',' ')}, /* Eastern Maroon Creole -> Creoles */ - {"djr", HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ - {"dks", HB_TAG('D','N','K',' ')}, /* Southeastern Dinka -> Dinka */ - {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */ -/*{"dnj", HB_TAG('D','N','J',' ')},*/ /* Dan */ - {"dnk", HB_TAG_NONE }, /* Dengka != Dinka */ - {"doi", HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) [macrolanguage] */ - {"drh", HB_TAG('M','N','G',' ')}, /* Darkhat (retired code) -> Mongolian */ - {"dri", HB_TAG_NONE }, /* C'Lela != Dari */ - {"drw", HB_TAG('D','R','I',' ')}, /* Darwazi (retired code) -> Dari */ - {"drw", HB_TAG('F','A','R',' ')}, /* Darwazi (retired code) -> Persian */ - {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ - {"dty", HB_TAG('N','E','P',' ')}, /* Dotyali -> Nepali */ -/*{"duj", HB_TAG('D','U','J',' ')},*/ /* Dhuwal (retired code) */ - {"dun", HB_TAG_NONE }, /* Dusun Deyah != Dungan */ - {"dup", HB_TAG('M','L','Y',' ')}, /* Duano -> Malay */ - {"dv", HB_TAG('D','I','V',' ')}, /* Divehi (Dhivehi, Maldivian) */ - {"dv", HB_TAG('D','H','V',' ')}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ - {"dwk", HB_TAG('K','U','I',' ')}, /* Dawik Kui -> Kui */ - {"dwu", HB_TAG('D','U','J',' ')}, /* Dhuwal */ - {"dwy", HB_TAG('D','U','J',' ')}, /* Dhuwaya -> Dhuwal */ - {"dyu", HB_TAG('J','U','L',' ')}, /* Dyula -> Jula */ - {"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */ - {"dzn", HB_TAG_NONE }, /* Dzando != Dzongkha */ - {"ecr", HB_TAG_NONE }, /* Eteocretan != Eastern Cree */ - {"ee", HB_TAG('E','W','E',' ')}, /* Ewe */ -/*{"efi", HB_TAG('E','F','I',' ')},*/ /* Efik */ - {"ekk", HB_TAG('E','T','I',' ')}, /* Standard Estonian -> Estonian */ - {"eky", HB_TAG('K','R','N',' ')}, /* Eastern Kayah -> Karen */ - {"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) -> Greek */ - {"emk", HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */ - {"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */ - {"emy", HB_TAG('M','Y','N',' ')}, /* Epigraphic Mayan -> Mayan */ - {"en", HB_TAG('E','N','G',' ')}, /* English */ - {"enb", HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */ - {"enf", HB_TAG('F','N','E',' ')}, /* Forest Enets */ - {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Enets */ - {"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */ - {"es", HB_TAG('E','S','P',' ')}, /* Spanish */ - {"esg", HB_TAG('G','O','N',' ')}, /* Aheri Gondi -> Gondi */ - {"esi", HB_TAG('I','P','K',' ')}, /* North Alaskan Inupiatun -> Inupiat */ - {"esk", HB_TAG('I','P','K',' ')}, /* Northwest Alaska Inupiatun -> Inupiat */ -/*{"esu", HB_TAG('E','S','U',' ')},*/ /* Central Yupik */ - {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ - {"eto", HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */ - {"eu", HB_TAG('E','U','Q',' ')}, /* Basque */ - {"euq", HB_TAG_NONE }, /* Basque [collection] != Basque */ - {"eve", HB_TAG('E','V','N',' ')}, /* Even */ - {"evn", HB_TAG('E','V','K',' ')}, /* Evenki */ - {"ewo", HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */ - {"eyo", HB_TAG('K','A','L',' ')}, /* Keiyo -> Kalenjin */ - {"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */ - {"fab", HB_TAG('C','P','P',' ')}, /* Fa d'Ambu -> Creoles */ - {"fan", HB_TAG('F','A','N','0')}, /* Fang (Equatorial Guinea) */ - {"fan", HB_TAG('B','T','I',' ')}, /* Fang (Equatorial Guinea) -> Beti */ - {"far", HB_TAG_NONE }, /* Fataleka != Persian */ - {"fat", HB_TAG('F','A','T',' ')}, /* Fanti */ - {"fat", HB_TAG('A','K','A',' ')}, /* Fanti -> Akan */ - {"fbl", HB_TAG('B','I','K',' ')}, /* West Albay Bikol -> Bikol */ - {"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */ - {"ffm", HB_TAG('F','U','L',' ')}, /* Maasina Fulfulde -> Fulah */ - {"fi", HB_TAG('F','I','N',' ')}, /* Finnish */ - {"fil", HB_TAG('P','I','L',' ')}, /* Filipino */ - {"fj", HB_TAG('F','J','I',' ')}, /* Fijian */ - {"flm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) (retired code) */ - {"flm", HB_TAG('Q','I','N',' ')}, /* Falam Chin (retired code) -> Chin */ - {"fmp", HB_TAG('F','M','P',' ')}, /* Fe’fe’ */ - {"fmp", HB_TAG('B','M','L',' ')}, /* Fe'fe' -> Bamileke */ - {"fng", HB_TAG('C','P','P',' ')}, /* Fanagalo -> Creoles */ - {"fo", HB_TAG('F','O','S',' ')}, /* Faroese */ -/*{"fon", HB_TAG('F','O','N',' ')},*/ /* Fon */ - {"fos", HB_TAG_NONE }, /* Siraya != Faroese */ - {"fpe", HB_TAG('C','P','P',' ')}, /* Fernando Po Creole English -> Creoles */ - {"fr", HB_TAG('F','R','A',' ')}, /* French */ -/*{"frc", HB_TAG('F','R','C',' ')},*/ /* Cajun French */ -/*{"frp", HB_TAG('F','R','P',' ')},*/ /* Arpitan */ - {"fub", HB_TAG('F','U','L',' ')}, /* Adamawa Fulfulde -> Fulah */ - {"fuc", HB_TAG('F','U','L',' ')}, /* Pulaar -> Fulah */ - {"fue", HB_TAG('F','U','L',' ')}, /* Borgu Fulfulde -> Fulah */ - {"fuf", HB_TAG('F','T','A',' ')}, /* Pular -> Futa */ - {"fuf", HB_TAG('F','U','L',' ')}, /* Pular -> Fulah */ - {"fuh", HB_TAG('F','U','L',' ')}, /* Western Niger Fulfulde -> Fulah */ - {"fui", HB_TAG('F','U','L',' ')}, /* Bagirmi Fulfulde -> Fulah */ - {"fuq", HB_TAG('F','U','L',' ')}, /* Central-Eastern Niger Fulfulde -> Fulah */ - {"fur", HB_TAG('F','R','L',' ')}, /* Friulian */ - {"fuv", HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */ - {"fuv", HB_TAG('F','U','L',' ')}, /* Nigerian Fulfulde -> Fulah */ - {"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */ - {"ga", HB_TAG('I','R','I',' ')}, /* Irish */ - {"gaa", HB_TAG('G','A','D',' ')}, /* Ga */ - {"gac", HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */ - {"gad", HB_TAG_NONE }, /* Gaddang != Ga */ - {"gae", HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */ -/*{"gag", HB_TAG('G','A','G',' ')},*/ /* Gagauz */ - {"gal", HB_TAG_NONE }, /* Galolen != Galician */ - {"gan", HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */ - {"gar", HB_TAG_NONE }, /* Galeya != Garshuni */ - {"gaw", HB_TAG_NONE }, /* Nobonob != Garhwali */ - {"gax", HB_TAG('O','R','O',' ')}, /* Borana-Arsi-Guji Oromo -> Oromo */ - {"gaz", HB_TAG('O','R','O',' ')}, /* West Central Oromo -> Oromo */ - {"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */ - {"gce", HB_TAG('A','T','H',' ')}, /* Galice -> Athapaskan */ - {"gcf", HB_TAG('C','P','P',' ')}, /* Guadeloupean Creole French -> Creoles */ - {"gcl", HB_TAG('C','P','P',' ')}, /* Grenadian Creole English -> Creoles */ - {"gcr", HB_TAG('C','P','P',' ')}, /* Guianese Creole French -> Creoles */ - {"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */ - {"gda", HB_TAG('R','A','J',' ')}, /* Gade Lohar -> Rajasthani */ -/*{"gez", HB_TAG('G','E','Z',' ')},*/ /* Geez */ - {"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */ - {"gha", HB_TAG('B','B','R',' ')}, /* Ghadamès -> Berber */ - {"ghk", HB_TAG('K','R','N',' ')}, /* Geko Karen -> Karen */ - {"gho", HB_TAG('B','B','R',' ')}, /* Ghomara -> Berber */ - {"gib", HB_TAG('C','P','P',' ')}, /* Gibanawa -> Creoles */ -/*{"gih", HB_TAG('G','I','H',' ')},*/ /* Githabul */ - {"gil", HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ - {"gju", HB_TAG('R','A','J',' ')}, /* Gujari -> Rajasthani */ - {"gkp", HB_TAG('G','K','P',' ')}, /* Guinea Kpelle -> Kpelle (Guinea) */ - {"gkp", HB_TAG('K','P','L',' ')}, /* Guinea Kpelle -> Kpelle */ - {"gl", HB_TAG('G','A','L',' ')}, /* Galician */ - {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */ -/*{"glk", HB_TAG('G','L','K',' ')},*/ /* Gilaki */ - {"gmz", HB_TAG_NONE }, /* Mgbolizhia != Gumuz */ - {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */ - {"gnb", HB_TAG('Q','I','N',' ')}, /* Gangte -> Chin */ -/*{"gnn", HB_TAG('G','N','N',' ')},*/ /* Gumatj */ - {"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi -> Gondi */ - {"gnw", HB_TAG('G','U','A',' ')}, /* Western Bolivian Guaraní -> Guarani */ -/*{"gog", HB_TAG('G','O','G',' ')},*/ /* Gogo */ - {"gom", HB_TAG('K','O','K',' ')}, /* Goan Konkani -> Konkani */ -/*{"gon", HB_TAG('G','O','N',' ')},*/ /* Gondi [macrolanguage] */ - {"goq", HB_TAG('C','P','P',' ')}, /* Gorap -> Creoles */ - {"gox", HB_TAG('B','A','D','0')}, /* Gobu -> Banda */ - {"gpe", HB_TAG('C','P','P',' ')}, /* Ghanaian Pidgin English -> Creoles */ - {"gro", HB_TAG_NONE }, /* Groma != Garo */ - {"grr", HB_TAG('B','B','R',' ')}, /* Taznatit -> Berber */ - {"grt", HB_TAG('G','R','O',' ')}, /* Garo */ - {"gru", HB_TAG('S','O','G',' ')}, /* Kistane -> Sodo Gurage */ - {"gsw", HB_TAG('A','L','S',' ')}, /* Alsatian */ - {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */ - {"gua", HB_TAG_NONE }, /* Shiki != Guarani */ -/*{"guc", HB_TAG('G','U','C',' ')},*/ /* Wayuu */ -/*{"guf", HB_TAG('G','U','F',' ')},*/ /* Gupapuyngu */ - {"gug", HB_TAG('G','U','A',' ')}, /* Paraguayan Guaraní -> Guarani */ - {"gui", HB_TAG('G','U','A',' ')}, /* Eastern Bolivian Guaraní -> Guarani */ - {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */ - {"gul", HB_TAG('C','P','P',' ')}, /* Sea Island Creole English -> Creoles */ - {"gun", HB_TAG('G','U','A',' ')}, /* Mbyá Guaraní -> Guarani */ -/*{"guz", HB_TAG('G','U','Z',' ')},*/ /* Gusii */ - {"gv", HB_TAG('M','N','X',' ')}, /* Manx */ - {"gwi", HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */ - {"gyn", HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */ - {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */ - {"haa", HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */ - {"hae", HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */ - {"hai", HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */ - {"hak", HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */ - {"hal", HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */ - {"har", HB_TAG('H','R','I',' ')}, /* Harari */ -/*{"haw", HB_TAG('H','A','W',' ')},*/ /* Hawaiian */ - {"hax", HB_TAG('H','A','I','0')}, /* Southern Haida -> Haida */ -/*{"hay", HB_TAG('H','A','Y',' ')},*/ /* Haya */ -/*{"haz", HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */ - {"hbn", HB_TAG_NONE }, /* Heiban != Hammer-Banna */ - {"hca", HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */ - {"hdn", HB_TAG('H','A','I','0')}, /* Northern Haida -> Haida */ - {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */ - {"hea", HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */ -/*{"hei", HB_TAG('H','E','I',' ')},*/ /* Heiltsuk */ - {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */ -/*{"hil", HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */ - {"hji", HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */ - {"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */ - {"hma", HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */ - {"hmc", HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */ - {"hmd", HB_TAG('H','M','D',' ')}, /* Large Flowery Miao -> A-Hmao */ - {"hmd", HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */ - {"hme", HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */ - {"hmg", HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */ - {"hmh", HB_TAG('H','M','N',' ')}, /* Southwestern Huishui Hmong -> Hmong */ - {"hmi", HB_TAG('H','M','N',' ')}, /* Northern Huishui Hmong -> Hmong */ - {"hmj", HB_TAG('H','M','N',' ')}, /* Ge -> Hmong */ - {"hml", HB_TAG('H','M','N',' ')}, /* Luopohe Hmong -> Hmong */ - {"hmm", HB_TAG('H','M','N',' ')}, /* Central Mashan Hmong -> Hmong */ -/*{"hmn", HB_TAG('H','M','N',' ')},*/ /* Hmong [macrolanguage] */ - {"hmp", HB_TAG('H','M','N',' ')}, /* Northern Mashan Hmong -> Hmong */ - {"hmq", HB_TAG('H','M','N',' ')}, /* Eastern Qiandong Miao -> Hmong */ - {"hmr", HB_TAG('Q','I','N',' ')}, /* Hmar -> Chin */ - {"hms", HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */ - {"hmw", HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */ - {"hmy", HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */ - {"hmz", HB_TAG('H','M','Z',' ')}, /* Hmong Shua -> Hmong Shuat */ - {"hmz", HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */ -/*{"hnd", HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */ - {"hne", HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */ - {"hnj", HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */ - {"hno", HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */ - {"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */ - {"ho", HB_TAG('C','P','P',' ')}, /* Hiri Motu -> Creoles */ - {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */ - {"hoi", HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */ - {"hoj", HB_TAG('H','A','R',' ')}, /* Hadothi -> Harauti */ - {"hoj", HB_TAG('R','A','J',' ')}, /* Hadothi -> Rajasthani */ - {"hr", HB_TAG('H','R','V',' ')}, /* Croatian */ - {"hra", HB_TAG('Q','I','N',' ')}, /* Hrangkhol -> Chin */ - {"hrm", HB_TAG('H','M','N',' ')}, /* Horned Miao -> Hmong */ - {"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ - {"hsn", HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese, Simplified */ - {"ht", HB_TAG('H','A','I',' ')}, /* Haitian (Haitian Creole) */ - {"ht", HB_TAG('C','P','P',' ')}, /* Haitian -> Creoles */ - {"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */ - {"huj", HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */ - {"hup", HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */ - {"hus", HB_TAG('M','Y','N',' ')}, /* Huastec -> Mayan */ - {"hwc", HB_TAG('C','P','P',' ')}, /* Hawai'i Creole English -> Creoles */ - {"hy", HB_TAG('H','Y','E','0')}, /* Armenian -> Armenian East */ - {"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */ - {"hyw", HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */ - {"hz", HB_TAG('H','E','R',' ')}, /* Herero */ - {"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */ -/*{"iba", HB_TAG('I','B','A',' ')},*/ /* Iban */ -/*{"ibb", HB_TAG('I','B','B',' ')},*/ /* Ibibio */ - {"iby", HB_TAG('I','J','O',' ')}, /* Ibani -> Ijo */ - {"icr", HB_TAG('C','P','P',' ')}, /* Islander Creole English -> Creoles */ - {"id", HB_TAG('I','N','D',' ')}, /* Indonesian */ - {"id", HB_TAG('M','L','Y',' ')}, /* Indonesian -> Malay */ - {"ida", HB_TAG('L','U','H',' ')}, /* Idakho-Isukha-Tiriki -> Luyia */ - {"idb", HB_TAG('C','P','P',' ')}, /* Indo-Portuguese -> Creoles */ - {"ie", HB_TAG('I','L','E',' ')}, /* Interlingue */ - {"ig", HB_TAG('I','B','O',' ')}, /* Igbo */ - {"igb", HB_TAG('E','B','I',' ')}, /* Ebira */ - {"ihb", HB_TAG('C','P','P',' ')}, /* Iha Based Pidgin -> Creoles */ - {"ii", HB_TAG('Y','I','M',' ')}, /* Sichuan Yi -> Yi Modern */ - {"ijc", HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */ - {"ije", HB_TAG('I','J','O',' ')}, /* Biseni -> Ijo */ - {"ijn", HB_TAG('I','J','O',' ')}, /* Kalabari -> Ijo */ -/*{"ijo", HB_TAG('I','J','O',' ')},*/ /* Ijo [collection] */ - {"ijs", HB_TAG('I','J','O',' ')}, /* Southeast Ijo -> Ijo */ - {"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */ - {"ike", HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */ - {"ike", HB_TAG('I','N','U','K')}, /* Eastern Canadian Inuktitut -> Nunavik Inuktitut */ - {"ikt", HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */ -/*{"ilo", HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */ - {"in", HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */ - {"in", HB_TAG('M','L','Y',' ')}, /* Indonesian (retired code) -> Malay */ - {"ing", HB_TAG('A','T','H',' ')}, /* Degexit'an -> Athapaskan */ - {"inh", HB_TAG('I','N','G',' ')}, /* Ingush */ - {"io", HB_TAG('I','D','O',' ')}, /* Ido */ - {"iri", HB_TAG_NONE }, /* Rigwe != Irish */ -/*{"iru", HB_TAG('I','R','U',' ')},*/ /* Irula */ - {"is", HB_TAG('I','S','L',' ')}, /* Icelandic */ - {"ism", HB_TAG_NONE }, /* Masimasi != Inari Sami */ - {"it", HB_TAG('I','T','A',' ')}, /* Italian */ - {"itz", HB_TAG('M','Y','N',' ')}, /* Itzá -> Mayan */ - {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ - {"iu", HB_TAG('I','N','U','K')}, /* Inuktitut [macrolanguage] -> Nunavik Inuktitut */ - {"iw", HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */ - {"ixl", HB_TAG('M','Y','N',' ')}, /* Ixil -> Mayan */ - {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */ - {"jac", HB_TAG('M','Y','N',' ')}, /* Popti' -> Mayan */ - {"jak", HB_TAG('M','L','Y',' ')}, /* Jakun -> Malay */ - {"jam", HB_TAG('J','A','M',' ')}, /* Jamaican Creole English -> Jamaican Creole */ - {"jam", HB_TAG('C','P','P',' ')}, /* Jamaican Creole English -> Creoles */ - {"jan", HB_TAG_NONE }, /* Jandai != Japanese */ - {"jax", HB_TAG('M','L','Y',' ')}, /* Jambi Malay -> Malay */ - {"jbe", HB_TAG('B','B','R',' ')}, /* Judeo-Berber -> Berber */ - {"jbn", HB_TAG('B','B','R',' ')}, /* Nafusi -> Berber */ -/*{"jbo", HB_TAG('J','B','O',' ')},*/ /* Lojban */ -/*{"jct", HB_TAG('J','C','T',' ')},*/ /* Krymchak */ - {"jgo", HB_TAG('B','M','L',' ')}, /* Ngomba -> Bamileke */ - {"ji", HB_TAG('J','I','I',' ')}, /* Yiddish (retired code) */ - {"jii", HB_TAG_NONE }, /* Jiiddu != Yiddish */ - {"jkm", HB_TAG('K','R','N',' ')}, /* Mobwa Karen -> Karen */ - {"jkp", HB_TAG('K','R','N',' ')}, /* Paku Karen -> Karen */ - {"jud", HB_TAG_NONE }, /* Worodougou != Ladino */ - {"jul", HB_TAG_NONE }, /* Jirel != Jula */ - {"jv", HB_TAG('J','A','V',' ')}, /* Javanese */ - {"jvd", HB_TAG('C','P','P',' ')}, /* Javindo -> Creoles */ - {"jw", HB_TAG('J','A','V',' ')}, /* Javanese (retired code) */ - {"ka", HB_TAG('K','A','T',' ')}, /* Georgian */ - {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */ - {"kab", HB_TAG('K','A','B','0')}, /* Kabyle */ - {"kab", HB_TAG('B','B','R',' ')}, /* Kabyle -> Berber */ - {"kac", HB_TAG_NONE }, /* Kachin != Kachchi */ - {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ - {"kar", HB_TAG('K','R','N',' ')}, /* Karen [collection] */ -/*{"kaw", HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */ - {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */ - {"kby", HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */ - {"kca", HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */ - {"kca", HB_TAG('K','H','S',' ')}, /* Khanty -> Khanty-Shurishkar */ - {"kca", HB_TAG('K','H','V',' ')}, /* Khanty -> Khanty-Vakhi */ - {"kcn", HB_TAG('C','P','P',' ')}, /* Nubi -> Creoles */ -/*{"kde", HB_TAG('K','D','E',' ')},*/ /* Makonde */ - {"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */ - {"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */ - {"kea", HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */ - {"kea", HB_TAG('C','P','P',' ')}, /* Kabuverdianu -> Creoles */ - {"keb", HB_TAG_NONE }, /* Kélé != Kebena */ - {"kek", HB_TAG('K','E','K',' ')}, /* Kekchi */ - {"kek", HB_TAG('M','Y','N',' ')}, /* Kekchí -> Mayan */ - {"kex", HB_TAG('K','K','N',' ')}, /* Kukna -> Kokni */ - {"kfa", HB_TAG('K','O','D',' ')}, /* Kodava -> Kodagu */ - {"kfr", HB_TAG('K','A','C',' ')}, /* Kachhi -> Kachchi */ - {"kfx", HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */ - {"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */ - {"kg", HB_TAG('K','O','N','0')}, /* Kongo [macrolanguage] */ - {"kge", HB_TAG_NONE }, /* Komering != Khutsuri Georgian */ - {"kha", HB_TAG('K','S','I',' ')}, /* Khasi */ - {"khb", HB_TAG('X','B','D',' ')}, /* Lü */ - {"khk", HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */ - {"khn", HB_TAG_NONE }, /* Khandesi != Khamti Shan (Microsoft fonts) */ - {"khs", HB_TAG_NONE }, /* Kasua != Khanty-Shurishkar */ - {"kht", HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan */ - {"kht", HB_TAG('K','H','N',' ')}, /* Khamti -> Khamti Shan (Microsoft fonts) */ - {"khv", HB_TAG_NONE }, /* Khvarshi != Khanty-Vakhi */ -/*{"khw", HB_TAG('K','H','W',' ')},*/ /* Khowar */ - {"ki", HB_TAG('K','I','K',' ')}, /* Kikuyu (Gikuyu) */ - {"kis", HB_TAG_NONE }, /* Kis != Kisii */ - {"kiu", HB_TAG('K','I','U',' ')}, /* Kirmanjki */ - {"kiu", HB_TAG('Z','Z','A',' ')}, /* Kirmanjki -> Zazaki */ - {"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama */ - {"kjb", HB_TAG('M','Y','N',' ')}, /* Q'anjob'al -> Mayan */ -/*{"kjd", HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */ - {"kjh", HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */ - {"kjp", HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ - {"kjp", HB_TAG('K','R','N',' ')}, /* Pwo Eastern Karen -> Karen */ - {"kjt", HB_TAG('K','R','N',' ')}, /* Phrae Pwo Karen -> Karen */ -/*{"kjz", HB_TAG('K','J','Z',' ')},*/ /* Bumthangkha */ - {"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */ - {"kkn", HB_TAG_NONE }, /* Kon Keu != Kokni */ - {"kkz", HB_TAG('A','T','H',' ')}, /* Kaska -> Athapaskan */ - {"kl", HB_TAG('G','R','N',' ')}, /* Greenlandic */ - {"klm", HB_TAG_NONE }, /* Migum != Kalmyk */ - {"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */ - {"km", HB_TAG('K','H','M',' ')}, /* Khmer */ - {"kmb", HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */ - {"kmn", HB_TAG_NONE }, /* Awtuw != Kumaoni */ - {"kmo", HB_TAG_NONE }, /* Kwoma != Komo */ - {"kmr", HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */ - {"kms", HB_TAG_NONE }, /* Kamasau != Komso */ - {"kmv", HB_TAG('C','P','P',' ')}, /* Karipúna Creole French -> Creoles */ - {"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ -/*{"kmz", HB_TAG('K','M','Z',' ')},*/ /* Khorasani Turkish -> Khorasani Turkic */ - {"kn", HB_TAG('K','A','N',' ')}, /* Kannada */ - {"knc", HB_TAG('K','N','R',' ')}, /* Central Kanuri -> Kanuri */ - {"kng", HB_TAG('K','O','N','0')}, /* Koongo -> Kongo */ - {"knj", HB_TAG('M','Y','N',' ')}, /* Western Kanjobal -> Mayan */ - {"knn", HB_TAG('K','O','K',' ')}, /* Konkani */ - {"knr", HB_TAG_NONE }, /* Kaningra != Kanuri */ - {"ko", HB_TAG('K','O','R',' ')}, /* Korean */ - {"ko", HB_TAG('K','O','H',' ')}, /* Korean -> Korean Old Hangul */ - {"kod", HB_TAG_NONE }, /* Kodi != Kodagu */ - {"koh", HB_TAG_NONE }, /* Koyo != Korean Old Hangul */ - {"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ - {"koi", HB_TAG('K','O','M',' ')}, /* Komi-Permyak -> Komi */ -/*{"kok", HB_TAG('K','O','K',' ')},*/ /* Konkani [macrolanguage] */ - {"kop", HB_TAG_NONE }, /* Waube != Komi-Permyak */ -/*{"kos", HB_TAG('K','O','S',' ')},*/ /* Kosraean */ - {"koy", HB_TAG('A','T','H',' ')}, /* Koyukon -> Athapaskan */ - {"koz", HB_TAG_NONE }, /* Korak != Komi-Zyrian */ - {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ - {"kpl", HB_TAG_NONE }, /* Kpala != Kpelle */ - {"kpp", HB_TAG('K','R','N',' ')}, /* Paku Karen (retired code) -> Karen */ - {"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ - {"kpv", HB_TAG('K','O','M',' ')}, /* Komi-Zyrian -> Komi */ - {"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */ - {"kqs", HB_TAG('K','I','S',' ')}, /* Northern Kissi -> Kisii */ - {"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */ - {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */ - {"krc", HB_TAG('K','A','R',' ')}, /* Karachay-Balkar -> Karachay */ - {"krc", HB_TAG('B','A','L',' ')}, /* Karachay-Balkar -> Balkar */ - {"kri", HB_TAG('K','R','I',' ')}, /* Krio */ - {"kri", HB_TAG('C','P','P',' ')}, /* Krio -> Creoles */ - {"krk", HB_TAG_NONE }, /* Kerek != Karakalpak */ -/*{"krl", HB_TAG('K','R','L',' ')},*/ /* Karelian */ - {"krm", HB_TAG_NONE }, /* Krim (retired code) != Karaim */ - {"krn", HB_TAG_NONE }, /* Sapo != Karen */ - {"krt", HB_TAG('K','N','R',' ')}, /* Tumari Kanuri -> Kanuri */ - {"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */ - {"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */ - {"ksh", HB_TAG('K','S','H','0')}, /* Kölsch -> Ripuarian */ - {"ksi", HB_TAG_NONE }, /* Krisa != Khasi */ - {"ksm", HB_TAG_NONE }, /* Kumba != Kildin Sami */ - {"kss", HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */ - {"ksw", HB_TAG('K','S','W',' ')}, /* S’gaw Karen */ - {"ksw", HB_TAG('K','R','N',' ')}, /* S'gaw Karen -> Karen */ - {"ktb", HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */ - {"ktu", HB_TAG('K','O','N',' ')}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ - {"ktw", HB_TAG('A','T','H',' ')}, /* Kato -> Athapaskan */ - {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */ - {"kui", HB_TAG_NONE }, /* Kuikúro-Kalapálo != Kui */ - {"kul", HB_TAG_NONE }, /* Kulere != Kulvi */ -/*{"kum", HB_TAG('K','U','M',' ')},*/ /* Kumyk */ - {"kuu", HB_TAG('A','T','H',' ')}, /* Upper Kuskokwim -> Athapaskan */ - {"kuw", HB_TAG('B','A','D','0')}, /* Kpagua -> Banda */ - {"kuy", HB_TAG_NONE }, /* Kuuku-Ya'u != Kuy */ - {"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */ - {"kvb", HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */ - {"kvl", HB_TAG('K','R','N',' ')}, /* Kayaw -> Karen */ - {"kvq", HB_TAG('K','R','N',' ')}, /* Geba Karen -> Karen */ - {"kvr", HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */ - {"kvt", HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */ - {"kvu", HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */ - {"kvy", HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */ - {"kw", HB_TAG('C','O','R',' ')}, /* Cornish */ -/*{"kwk", HB_TAG('K','W','K',' ')},*/ /* Kwakiutl -> Kwakʼwala */ - {"kww", HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */ - {"kwy", HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */ - {"kxc", HB_TAG('K','M','S',' ')}, /* Konso -> Komso */ - {"kxd", HB_TAG('M','L','Y',' ')}, /* Brunei -> Malay */ - {"kxf", HB_TAG('K','R','N',' ')}, /* Manumanaw Karen -> Karen */ - {"kxk", HB_TAG('K','R','N',' ')}, /* Zayein Karen -> Karen */ - {"kxl", HB_TAG('K','U','U',' ')}, /* Nepali Kurux (retired code) -> Kurukh */ - {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) (retired code) */ - {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz (Kyrgyz) */ - {"kyk", HB_TAG_NONE }, /* Kamayo != Koryak */ - {"kyu", HB_TAG('K','Y','U',' ')}, /* Western Kayah */ - {"kyu", HB_TAG('K','R','N',' ')}, /* Western Kayah -> Karen */ - {"la", HB_TAG('L','A','T',' ')}, /* Latin */ - {"lac", HB_TAG('M','Y','N',' ')}, /* Lacandon -> Mayan */ - {"lad", HB_TAG('J','U','D',' ')}, /* Ladino */ - {"lah", HB_TAG_NONE }, /* Lahnda [macrolanguage] != Lahuli */ - {"lak", HB_TAG_NONE }, /* Laka (Nigeria) (retired code) != Lak */ - {"lam", HB_TAG_NONE }, /* Lamba != Lambani */ - {"laz", HB_TAG_NONE }, /* Aribwatsa != Laz */ - {"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ - {"lbe", HB_TAG('L','A','K',' ')}, /* Lak */ - {"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */ - {"lbl", HB_TAG('B','I','K',' ')}, /* Libon Bikol -> Bikol */ - {"lce", HB_TAG('M','L','Y',' ')}, /* Loncong -> Malay */ - {"lcf", HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */ - {"ldi", HB_TAG('K','O','N','0')}, /* Laari -> Kongo */ - {"ldk", HB_TAG_NONE }, /* Leelau != Ladakhi */ -/*{"lef", HB_TAG('L','E','F',' ')},*/ /* Lelemi */ -/*{"lez", HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */ - {"lg", HB_TAG('L','U','G',' ')}, /* Ganda */ - {"li", HB_TAG('L','I','M',' ')}, /* Limburgish */ - {"lif", HB_TAG('L','M','B',' ')}, /* Limbu */ -/*{"lij", HB_TAG('L','I','J',' ')},*/ /* Ligurian */ - {"lir", HB_TAG('C','P','P',' ')}, /* Liberian English -> Creoles */ -/*{"lis", HB_TAG('L','I','S',' ')},*/ /* Lisu */ - {"liw", HB_TAG('M','L','Y',' ')}, /* Col -> Malay */ - {"liy", HB_TAG('B','A','D','0')}, /* Banda-Bambari -> Banda */ -/*{"ljp", HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */ - {"lkb", HB_TAG('L','U','H',' ')}, /* Kabras -> Luyia */ -/*{"lki", HB_TAG('L','K','I',' ')},*/ /* Laki */ - {"lko", HB_TAG('L','U','H',' ')}, /* Khayo -> Luyia */ - {"lks", HB_TAG('L','U','H',' ')}, /* Kisa -> Luyia */ - {"lld", HB_TAG('L','A','D',' ')}, /* Ladin */ - {"lma", HB_TAG_NONE }, /* East Limba != Low Mari */ - {"lmb", HB_TAG_NONE }, /* Merei != Limbu */ - {"lmn", HB_TAG('L','A','M',' ')}, /* Lambadi -> Lambani */ -/*{"lmo", HB_TAG('L','M','O',' ')},*/ /* Lombard */ - {"lmw", HB_TAG_NONE }, /* Lake Miwok != Lomwe */ - {"ln", HB_TAG('L','I','N',' ')}, /* Lingala */ - {"lna", HB_TAG('B','A','D','0')}, /* Langbashe -> Banda */ - {"lnl", HB_TAG('B','A','D','0')}, /* South Central Banda -> Banda */ - {"lo", HB_TAG('L','A','O',' ')}, /* Lao */ -/*{"lom", HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */ - {"lou", HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */ -/*{"lpo", HB_TAG('L','P','O',' ')},*/ /* Lipo */ -/*{"lrc", HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */ - {"lri", HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */ - {"lrm", HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */ - {"lrt", HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */ - {"lsb", HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */ - {"lsm", HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */ - {"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */ - {"ltg", HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */ - {"lth", HB_TAG_NONE }, /* Thur != Lithuanian */ - {"lto", HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */ - {"lts", HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */ - {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ -/*{"lua", HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ -/*{"luo", HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */ - {"lus", HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */ - {"lus", HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */ - {"luy", HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */ - {"luz", HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */ - {"lv", HB_TAG('L','V','I',' ')}, /* Latvian [macrolanguage] */ - {"lvi", HB_TAG_NONE }, /* Lavi != Latvian */ - {"lvs", HB_TAG('L','V','I',' ')}, /* Standard Latvian -> Latvian */ - {"lwg", HB_TAG('L','U','H',' ')}, /* Wanga -> Luyia */ - {"lzh", HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese, Traditional */ - {"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */ -/*{"mad", HB_TAG('M','A','D',' ')},*/ /* Madurese -> Madura */ -/*{"mag", HB_TAG('M','A','G',' ')},*/ /* Magahi */ - {"mai", HB_TAG('M','T','H',' ')}, /* Maithili */ - {"maj", HB_TAG_NONE }, /* Jalapa De Díaz Mazatec != Majang */ - {"mak", HB_TAG('M','K','R',' ')}, /* Makasar */ - {"mam", HB_TAG('M','A','M',' ')}, /* Mam */ - {"mam", HB_TAG('M','Y','N',' ')}, /* Mam -> Mayan */ - {"man", HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */ - {"map", HB_TAG_NONE }, /* Austronesian [collection] != Mapudungun */ - {"maw", HB_TAG_NONE }, /* Mampruli != Marwari */ - {"max", HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */ - {"max", HB_TAG('C','P','P',' ')}, /* North Moluccan Malay -> Creoles */ - {"mbf", HB_TAG('C','P','P',' ')}, /* Baba Malay -> Creoles */ - {"mbn", HB_TAG_NONE }, /* Macaguán != Mbundu */ -/*{"mbo", HB_TAG('M','B','O',' ')},*/ /* Mbo (Cameroon) */ - {"mch", HB_TAG_NONE }, /* Maquiritari != Manchu */ - {"mcm", HB_TAG('C','P','P',' ')}, /* Malaccan Creole Portuguese -> Creoles */ - {"mcr", HB_TAG_NONE }, /* Menya != Moose Cree */ - {"mct", HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */ - {"mde", HB_TAG_NONE }, /* Maba (Chad) != Mende */ - {"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */ -/*{"mdr", HB_TAG('M','D','R',' ')},*/ /* Mandar */ - {"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ - {"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ - {"meo", HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */ -/*{"mer", HB_TAG('M','E','R',' ')},*/ /* Meru */ - {"mfa", HB_TAG('M','F','A',' ')}, /* Pattani Malay */ - {"mfa", HB_TAG('M','L','Y',' ')}, /* Pattani Malay -> Malay */ - {"mfb", HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */ - {"mfe", HB_TAG('M','F','E',' ')}, /* Morisyen */ - {"mfe", HB_TAG('C','P','P',' ')}, /* Morisyen -> Creoles */ - {"mfp", HB_TAG('C','P','P',' ')}, /* Makassar Malay -> Creoles */ - {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */ - {"mh", HB_TAG('M','A','H',' ')}, /* Marshallese */ - {"mhc", HB_TAG('M','Y','N',' ')}, /* Mocho -> Mayan */ - {"mhr", HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */ - {"mhv", HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */ - {"mi", HB_TAG('M','R','I',' ')}, /* Maori */ - {"min", HB_TAG('M','I','N',' ')}, /* Minangkabau */ - {"min", HB_TAG('M','L','Y',' ')}, /* Minangkabau -> Malay */ - {"miz", HB_TAG_NONE }, /* Coatzospan Mixtec != Mizo */ - {"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */ - {"mkn", HB_TAG('C','P','P',' ')}, /* Kupang Malay -> Creoles */ - {"mkr", HB_TAG_NONE }, /* Malas != Makasar */ - {"mku", HB_TAG('M','N','K',' ')}, /* Konyanka Maninka -> Maninka */ -/*{"mkw", HB_TAG('M','K','W',' ')},*/ /* Kituba (Congo) */ - {"ml", HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */ - {"ml", HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */ - {"mle", HB_TAG_NONE }, /* Manambu != Male */ - {"mln", HB_TAG_NONE }, /* Malango != Malinke */ - {"mlq", HB_TAG('M','L','N',' ')}, /* Western Maninkakan -> Malinke */ - {"mlq", HB_TAG('M','N','K',' ')}, /* Western Maninkakan -> Maninka */ - {"mlr", HB_TAG_NONE }, /* Vame != Malayalam Reformed */ - {"mmr", HB_TAG('H','M','N',' ')}, /* Western Xiangxi Miao -> Hmong */ - {"mn", HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */ - {"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */ - {"mnd", HB_TAG_NONE }, /* Mondé != Mandinka */ - {"mng", HB_TAG_NONE }, /* Eastern Mnong != Mongolian */ - {"mnh", HB_TAG('B','A','D','0')}, /* Mono (Democratic Republic of Congo) -> Banda */ -/*{"mni", HB_TAG('M','N','I',' ')},*/ /* Manipuri */ - {"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */ - {"mnk", HB_TAG('M','N','K',' ')}, /* Mandinka -> Maninka */ - {"mnp", HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese, Simplified */ - {"mns", HB_TAG('M','A','N',' ')}, /* Mansi */ - {"mnw", HB_TAG('M','O','N',' ')}, /* Mon */ - {"mnw", HB_TAG('M','O','N','T')}, /* Mon -> Thailand Mon */ - {"mnx", HB_TAG_NONE }, /* Manikion != Manx */ - {"mo", HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */ - {"mo", HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */ - {"mod", HB_TAG('C','P','P',' ')}, /* Mobilian -> Creoles */ -/*{"moh", HB_TAG('M','O','H',' ')},*/ /* Mohawk */ - {"mok", HB_TAG_NONE }, /* Morori != Moksha */ - {"mop", HB_TAG('M','Y','N',' ')}, /* Mopán Maya -> Mayan */ - {"mor", HB_TAG_NONE }, /* Moro != Moroccan */ -/*{"mos", HB_TAG('M','O','S',' ')},*/ /* Mossi */ - {"mpe", HB_TAG('M','A','J',' ')}, /* Majang */ - {"mqg", HB_TAG('M','L','Y',' ')}, /* Kota Bangun Kutai Malay -> Malay */ - {"mr", HB_TAG('M','A','R',' ')}, /* Marathi */ - {"mrh", HB_TAG('Q','I','N',' ')}, /* Mara Chin -> Chin */ - {"mrj", HB_TAG('H','M','A',' ')}, /* Western Mari -> High Mari */ - {"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */ - {"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka -> Maninka */ - {"msh", HB_TAG('M','L','G',' ')}, /* Masikoro Malagasy -> Malagasy */ - {"msi", HB_TAG('M','L','Y',' ')}, /* Sabah Malay -> Malay */ - {"msi", HB_TAG('C','P','P',' ')}, /* Sabah Malay -> Creoles */ - {"mt", HB_TAG('M','T','S',' ')}, /* Maltese */ - {"mth", HB_TAG_NONE }, /* Munggui != Maithili */ - {"mtr", HB_TAG('M','A','W',' ')}, /* Mewari -> Marwari */ - {"mts", HB_TAG_NONE }, /* Yora != Maltese */ - {"mud", HB_TAG('C','P','P',' ')}, /* Mednyj Aleut -> Creoles */ - {"mui", HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */ - {"mun", HB_TAG_NONE }, /* Munda [collection] != Mundari */ - {"mup", HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */ - {"muq", HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */ -/*{"mus", HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */ - {"mvb", HB_TAG('A','T','H',' ')}, /* Mattole -> Athapaskan */ - {"mve", HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */ - {"mvf", HB_TAG('M','N','G',' ')}, /* Peripheral Mongolian -> Mongolian */ - {"mwk", HB_TAG('M','N','K',' ')}, /* Kita Maninkakan -> Maninka */ -/*{"mwl", HB_TAG('M','W','L',' ')},*/ /* Mirandese */ - {"mwq", HB_TAG('Q','I','N',' ')}, /* Mün Chin -> Chin */ - {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ - {"mww", HB_TAG('M','W','W',' ')}, /* Hmong Daw */ - {"mww", HB_TAG('H','M','N',' ')}, /* Hmong Daw -> Hmong */ - {"my", HB_TAG('B','R','M',' ')}, /* Burmese */ - {"mym", HB_TAG('M','E','N',' ')}, /* Me’en */ -/*{"myn", HB_TAG('M','Y','N',' ')},*/ /* Mayan [collection] */ - {"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */ - {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */ - {"mzb", HB_TAG('B','B','R',' ')}, /* Tumzabt -> Berber */ -/*{"mzn", HB_TAG('M','Z','N',' ')},*/ /* Mazanderani */ - {"mzs", HB_TAG('C','P','P',' ')}, /* Macanese -> Creoles */ - {"na", HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */ - {"nag", HB_TAG('N','A','G',' ')}, /* Naga Pidgin -> Naga-Assamese */ - {"nag", HB_TAG('C','P','P',' ')}, /* Naga Pidgin -> Creoles */ -/*{"nah", HB_TAG('N','A','H',' ')},*/ /* Nahuatl [collection] */ - {"nan", HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese, Simplified */ -/*{"nap", HB_TAG('N','A','P',' ')},*/ /* Neapolitan */ - {"nas", HB_TAG_NONE }, /* Naasioi != Naskapi */ - {"naz", HB_TAG('N','A','H',' ')}, /* Coatepec Nahuatl -> Nahuatl */ - {"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål -> Norwegian */ - {"nch", HB_TAG('N','A','H',' ')}, /* Central Huasteca Nahuatl -> Nahuatl */ - {"nci", HB_TAG('N','A','H',' ')}, /* Classical Nahuatl -> Nahuatl */ - {"ncj", HB_TAG('N','A','H',' ')}, /* Northern Puebla Nahuatl -> Nahuatl */ - {"ncl", HB_TAG('N','A','H',' ')}, /* Michoacán Nahuatl -> Nahuatl */ - {"ncr", HB_TAG_NONE }, /* Ncane != N-Cree */ - {"ncx", HB_TAG('N','A','H',' ')}, /* Central Puebla Nahuatl -> Nahuatl */ - {"nd", HB_TAG('N','D','B',' ')}, /* North Ndebele -> Ndebele */ - {"ndb", HB_TAG_NONE }, /* Kenswei Nsei != Ndebele */ -/*{"ndc", HB_TAG('N','D','C',' ')},*/ /* Ndau */ - {"ndg", HB_TAG_NONE }, /* Ndengereko != Ndonga */ -/*{"nds", HB_TAG('N','D','S',' ')},*/ /* Low Saxon */ - {"ne", HB_TAG('N','E','P',' ')}, /* Nepali [macrolanguage] */ - {"nef", HB_TAG('C','P','P',' ')}, /* Nefamese -> Creoles */ -/*{"new", HB_TAG('N','E','W',' ')},*/ /* Newari */ - {"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */ -/*{"nga", HB_TAG('N','G','A',' ')},*/ /* Ngbaka */ - {"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */ - {"ngm", HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */ - {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */ - {"ngr", HB_TAG_NONE }, /* Engdewu != Nagari */ - {"ngu", HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */ - {"nhc", HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */ - {"nhd", HB_TAG('G','U','A',' ')}, /* Chiripá -> Guarani */ - {"nhe", HB_TAG('N','A','H',' ')}, /* Eastern Huasteca Nahuatl -> Nahuatl */ - {"nhg", HB_TAG('N','A','H',' ')}, /* Tetelcingo Nahuatl -> Nahuatl */ - {"nhi", HB_TAG('N','A','H',' ')}, /* Zacatlán-Ahuacatlán-Tepetzintla Nahuatl -> Nahuatl */ - {"nhk", HB_TAG('N','A','H',' ')}, /* Isthmus-Cosoleacaque Nahuatl -> Nahuatl */ - {"nhm", HB_TAG('N','A','H',' ')}, /* Morelos Nahuatl -> Nahuatl */ - {"nhn", HB_TAG('N','A','H',' ')}, /* Central Nahuatl -> Nahuatl */ - {"nhp", HB_TAG('N','A','H',' ')}, /* Isthmus-Pajapan Nahuatl -> Nahuatl */ - {"nhq", HB_TAG('N','A','H',' ')}, /* Huaxcaleca Nahuatl -> Nahuatl */ - {"nht", HB_TAG('N','A','H',' ')}, /* Ometepec Nahuatl -> Nahuatl */ - {"nhv", HB_TAG('N','A','H',' ')}, /* Temascaltepec Nahuatl -> Nahuatl */ - {"nhw", HB_TAG('N','A','H',' ')}, /* Western Huasteca Nahuatl -> Nahuatl */ - {"nhx", HB_TAG('N','A','H',' ')}, /* Isthmus-Mecayapan Nahuatl -> Nahuatl */ - {"nhy", HB_TAG('N','A','H',' ')}, /* Northern Oaxaca Nahuatl -> Nahuatl */ - {"nhz", HB_TAG('N','A','H',' ')}, /* Santa María La Alta Nahuatl -> Nahuatl */ - {"niq", HB_TAG('K','A','L',' ')}, /* Nandi -> Kalenjin */ - {"nis", HB_TAG_NONE }, /* Nimi != Nisi */ -/*{"niu", HB_TAG('N','I','U',' ')},*/ /* Niuean */ - {"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */ - {"njt", HB_TAG('C','P','P',' ')}, /* Ndyuka-Trio Pidgin -> Creoles */ - {"njz", HB_TAG('N','I','S',' ')}, /* Nyishi -> Nisi */ - {"nko", HB_TAG_NONE }, /* Nkonya != N’Ko */ - {"nkx", HB_TAG('I','J','O',' ')}, /* Nkoroo -> Ijo */ - {"nl", HB_TAG('N','L','D',' ')}, /* Dutch */ - {"nla", HB_TAG('B','M','L',' ')}, /* Ngombale -> Bamileke */ - {"nle", HB_TAG('L','U','H',' ')}, /* East Nyala -> Luyia */ - {"nln", HB_TAG('N','A','H',' ')}, /* Durango Nahuatl (retired code) -> Nahuatl */ - {"nlv", HB_TAG('N','A','H',' ')}, /* Orizaba Nahuatl -> Nahuatl */ - {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ - {"nnh", HB_TAG('B','M','L',' ')}, /* Ngiemboon -> Bamileke */ - {"nnz", HB_TAG('B','M','L',' ')}, /* Nda'nda' -> Bamileke */ - {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ - {"nod", HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */ -/*{"noe", HB_TAG('N','O','E',' ')},*/ /* Nimadi */ -/*{"nog", HB_TAG('N','O','G',' ')},*/ /* Nogai */ -/*{"nov", HB_TAG('N','O','V',' ')},*/ /* Novial */ - {"npi", HB_TAG('N','E','P',' ')}, /* Nepali */ - {"npl", HB_TAG('N','A','H',' ')}, /* Southeastern Puebla Nahuatl -> Nahuatl */ - {"nqo", HB_TAG('N','K','O',' ')}, /* N’Ko */ - {"nr", HB_TAG('N','D','B',' ')}, /* South Ndebele -> Ndebele */ - {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */ - {"nsm", HB_TAG_NONE }, /* Sumi Naga != Northern Sami */ -/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Northern Sotho */ - {"nsu", HB_TAG('N','A','H',' ')}, /* Sierra Negra Nahuatl -> Nahuatl */ - {"nto", HB_TAG_NONE }, /* Ntomba != Esperanto */ - {"nue", HB_TAG('B','A','D','0')}, /* Ngundu -> Banda */ - {"nuu", HB_TAG('B','A','D','0')}, /* Ngbundu -> Banda */ - {"nuz", HB_TAG('N','A','H',' ')}, /* Tlamacazapa Nahuatl -> Nahuatl */ - {"nv", HB_TAG('N','A','V',' ')}, /* Navajo */ - {"nv", HB_TAG('A','T','H',' ')}, /* Navajo -> Athapaskan */ - {"nwe", HB_TAG('B','M','L',' ')}, /* Ngwe -> Bamileke */ - {"ny", HB_TAG('C','H','I',' ')}, /* Chichewa (Chewa, Nyanja) */ - {"nyd", HB_TAG('L','U','H',' ')}, /* Nyore -> Luyia */ -/*{"nym", HB_TAG('N','Y','M',' ')},*/ /* Nyamwezi */ - {"nyn", HB_TAG('N','K','L',' ')}, /* Nyankole */ -/*{"nza", HB_TAG('N','Z','A',' ')},*/ /* Tigon Mbembe -> Mbembe Tigon */ - {"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ - {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */ -/*{"ojb", HB_TAG('O','J','B',' ')},*/ /* Northwestern Ojibwa -> Ojibway */ - {"ojc", HB_TAG('O','J','B',' ')}, /* Central Ojibwa -> Ojibway */ - {"ojg", HB_TAG('O','J','B',' ')}, /* Eastern Ojibwa -> Ojibway */ - {"ojs", HB_TAG('O','C','R',' ')}, /* Severn Ojibwa -> Oji-Cree */ - {"ojs", HB_TAG('O','J','B',' ')}, /* Severn Ojibwa -> Ojibway */ - {"ojw", HB_TAG('O','J','B',' ')}, /* Western Ojibwa -> Ojibway */ - {"okd", HB_TAG('I','J','O',' ')}, /* Okodia -> Ijo */ - {"oki", HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */ - {"okm", HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ - {"okr", HB_TAG('I','J','O',' ')}, /* Kirike -> Ijo */ - {"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */ - {"onx", HB_TAG('C','P','P',' ')}, /* Onin Based Pidgin -> Creoles */ - {"oor", HB_TAG('C','P','P',' ')}, /* Oorlams -> Creoles */ - {"or", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */ - {"orc", HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */ - {"orn", HB_TAG('M','L','Y',' ')}, /* Orang Kanaq -> Malay */ - {"oro", HB_TAG_NONE }, /* Orokolo != Oromo */ - {"orr", HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */ - {"ors", HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */ - {"ory", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */ - {"os", HB_TAG('O','S','S',' ')}, /* Ossetian */ - {"otw", HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */ - {"oua", HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */ - {"pa", HB_TAG('P','A','N',' ')}, /* Punjabi */ - {"paa", HB_TAG_NONE }, /* Papuan [collection] != Palestinian Aramaic */ -/*{"pag", HB_TAG('P','A','G',' ')},*/ /* Pangasinan */ - {"pal", HB_TAG_NONE }, /* Pahlavi != Pali */ -/*{"pam", HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */ - {"pap", HB_TAG('P','A','P','0')}, /* Papiamento -> Papiamentu */ - {"pap", HB_TAG('C','P','P',' ')}, /* Papiamento -> Creoles */ - {"pas", HB_TAG_NONE }, /* Papasena != Pashto */ -/*{"pau", HB_TAG('P','A','U',' ')},*/ /* Palauan */ - {"pbt", HB_TAG('P','A','S',' ')}, /* Southern Pashto -> Pashto */ - {"pbu", HB_TAG('P','A','S',' ')}, /* Northern Pashto -> Pashto */ -/*{"pcc", HB_TAG('P','C','C',' ')},*/ /* Bouyei */ -/*{"pcd", HB_TAG('P','C','D',' ')},*/ /* Picard */ - {"pce", HB_TAG('P','L','G',' ')}, /* Ruching Palaung -> Palaung */ - {"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin -> Chin */ - {"pcm", HB_TAG('C','P','P',' ')}, /* Nigerian Pidgin -> Creoles */ -/*{"pdc", HB_TAG('P','D','C',' ')},*/ /* Pennsylvania German */ - {"pdu", HB_TAG('K','R','N',' ')}, /* Kayan -> Karen */ - {"pea", HB_TAG('C','P','P',' ')}, /* Peranakan Indonesian -> Creoles */ - {"pel", HB_TAG('M','L','Y',' ')}, /* Pekal -> Malay */ - {"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian -> Persian */ - {"pey", HB_TAG('C','P','P',' ')}, /* Petjo -> Creoles */ - {"pga", HB_TAG('A','R','A',' ')}, /* Sudanese Creole Arabic -> Arabic */ - {"pga", HB_TAG('C','P','P',' ')}, /* Sudanese Creole Arabic -> Creoles */ -/*{"phk", HB_TAG('P','H','K',' ')},*/ /* Phake */ - {"pi", HB_TAG('P','A','L',' ')}, /* Pali */ - {"pih", HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk -> Norfolk */ - {"pih", HB_TAG('C','P','P',' ')}, /* Pitcairn-Norfolk -> Creoles */ - {"pil", HB_TAG_NONE }, /* Yom != Filipino */ - {"pis", HB_TAG('C','P','P',' ')}, /* Pijin -> Creoles */ - {"pkh", HB_TAG('Q','I','N',' ')}, /* Pankhu -> Chin */ - {"pko", HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */ - {"pl", HB_TAG('P','L','K',' ')}, /* Polish */ - {"plg", HB_TAG_NONE }, /* Pilagá != Palaung */ - {"plk", HB_TAG_NONE }, /* Kohistani Shina != Polish */ - {"pll", HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */ - {"pln", HB_TAG('C','P','P',' ')}, /* Palenquero -> Creoles */ - {"plp", HB_TAG('P','A','P',' ')}, /* Palpa (retired code) */ - {"plt", HB_TAG('M','L','G',' ')}, /* Plateau Malagasy -> Malagasy */ - {"pml", HB_TAG('C','P','P',' ')}, /* Lingua Franca -> Creoles */ -/*{"pms", HB_TAG('P','M','S',' ')},*/ /* Piemontese */ - {"pmy", HB_TAG('C','P','P',' ')}, /* Papuan Malay -> Creoles */ -/*{"pnb", HB_TAG('P','N','B',' ')},*/ /* Western Panjabi */ - {"poc", HB_TAG('M','Y','N',' ')}, /* Poqomam -> Mayan */ - {"poh", HB_TAG('P','O','H',' ')}, /* Poqomchi' -> Pocomchi */ - {"poh", HB_TAG('M','Y','N',' ')}, /* Poqomchi' -> Mayan */ -/*{"pon", HB_TAG('P','O','N',' ')},*/ /* Pohnpeian */ - {"pov", HB_TAG('C','P','P',' ')}, /* Upper Guinea Crioulo -> Creoles */ - {"ppa", HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */ - {"pre", HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */ -/*{"pro", HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */ - {"prs", HB_TAG('D','R','I',' ')}, /* Dari */ - {"prs", HB_TAG('F','A','R',' ')}, /* Dari -> Persian */ - {"ps", HB_TAG('P','A','S',' ')}, /* Pashto [macrolanguage] */ - {"pse", HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */ - {"pst", HB_TAG('P','A','S',' ')}, /* Central Pashto -> Pashto */ - {"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */ - {"pub", HB_TAG('Q','I','N',' ')}, /* Purum -> Chin */ - {"puz", HB_TAG('Q','I','N',' ')}, /* Purum Naga (retired code) -> Chin */ - {"pwo", HB_TAG('P','W','O',' ')}, /* Pwo Western Karen -> Western Pwo Karen */ - {"pwo", HB_TAG('K','R','N',' ')}, /* Pwo Western Karen -> Karen */ - {"pww", HB_TAG('K','R','N',' ')}, /* Pwo Northern Karen -> Karen */ - {"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */ - {"qub", HB_TAG('Q','W','H',' ')}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ - {"qub", HB_TAG('Q','U','Z',' ')}, /* Huallaga Huánuco Quechua -> Quechua */ - {"quc", HB_TAG('Q','U','C',' ')}, /* K’iche’ */ - {"quc", HB_TAG('M','Y','N',' ')}, /* K'iche' -> Mayan */ - {"qud", HB_TAG('Q','V','I',' ')}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ - {"qud", HB_TAG('Q','U','Z',' ')}, /* Calderón Highland Quichua -> Quechua */ - {"quf", HB_TAG('Q','U','Z',' ')}, /* Lambayeque Quechua -> Quechua */ - {"qug", HB_TAG('Q','V','I',' ')}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ - {"qug", HB_TAG('Q','U','Z',' ')}, /* Chimborazo Highland Quichua -> Quechua */ - {"quh", HB_TAG('Q','U','H',' ')}, /* South Bolivian Quechua -> Quechua (Bolivia) */ - {"quh", HB_TAG('Q','U','Z',' ')}, /* South Bolivian Quechua -> Quechua */ - {"quk", HB_TAG('Q','U','Z',' ')}, /* Chachapoyas Quechua -> Quechua */ - {"qul", HB_TAG('Q','U','H',' ')}, /* North Bolivian Quechua -> Quechua (Bolivia) */ - {"qul", HB_TAG('Q','U','Z',' ')}, /* North Bolivian Quechua -> Quechua */ - {"qum", HB_TAG('M','Y','N',' ')}, /* Sipacapense -> Mayan */ - {"qup", HB_TAG('Q','V','I',' ')}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ - {"qup", HB_TAG('Q','U','Z',' ')}, /* Southern Pastaza Quechua -> Quechua */ - {"qur", HB_TAG('Q','W','H',' ')}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ - {"qur", HB_TAG('Q','U','Z',' ')}, /* Yanahuanca Pasco Quechua -> Quechua */ - {"qus", HB_TAG('Q','U','H',' ')}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ - {"qus", HB_TAG('Q','U','Z',' ')}, /* Santiago del Estero Quichua -> Quechua */ - {"quv", HB_TAG('M','Y','N',' ')}, /* Sacapulteco -> Mayan */ - {"quw", HB_TAG('Q','V','I',' ')}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ - {"quw", HB_TAG('Q','U','Z',' ')}, /* Tena Lowland Quichua -> Quechua */ - {"qux", HB_TAG('Q','W','H',' ')}, /* Yauyos Quechua -> Quechua (Peru) */ - {"qux", HB_TAG('Q','U','Z',' ')}, /* Yauyos Quechua -> Quechua */ - {"quy", HB_TAG('Q','U','Z',' ')}, /* Ayacucho Quechua -> Quechua */ -/*{"quz", HB_TAG('Q','U','Z',' ')},*/ /* Cusco Quechua -> Quechua */ - {"qva", HB_TAG('Q','W','H',' ')}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ - {"qva", HB_TAG('Q','U','Z',' ')}, /* Ambo-Pasco Quechua -> Quechua */ - {"qvc", HB_TAG('Q','U','Z',' ')}, /* Cajamarca Quechua -> Quechua */ - {"qve", HB_TAG('Q','U','Z',' ')}, /* Eastern Apurímac Quechua -> Quechua */ - {"qvh", HB_TAG('Q','W','H',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ - {"qvh", HB_TAG('Q','U','Z',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua */ - {"qvi", HB_TAG('Q','V','I',' ')}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ - {"qvi", HB_TAG('Q','U','Z',' ')}, /* Imbabura Highland Quichua -> Quechua */ - {"qvj", HB_TAG('Q','V','I',' ')}, /* Loja Highland Quichua -> Quechua (Ecuador) */ - {"qvj", HB_TAG('Q','U','Z',' ')}, /* Loja Highland Quichua -> Quechua */ - {"qvl", HB_TAG('Q','W','H',' ')}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ - {"qvl", HB_TAG('Q','U','Z',' ')}, /* Cajatambo North Lima Quechua -> Quechua */ - {"qvm", HB_TAG('Q','W','H',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ - {"qvm", HB_TAG('Q','U','Z',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */ - {"qvn", HB_TAG('Q','W','H',' ')}, /* North Junín Quechua -> Quechua (Peru) */ - {"qvn", HB_TAG('Q','U','Z',' ')}, /* North Junín Quechua -> Quechua */ - {"qvo", HB_TAG('Q','V','I',' ')}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ - {"qvo", HB_TAG('Q','U','Z',' ')}, /* Napo Lowland Quechua -> Quechua */ - {"qvp", HB_TAG('Q','W','H',' ')}, /* Pacaraos Quechua -> Quechua (Peru) */ - {"qvp", HB_TAG('Q','U','Z',' ')}, /* Pacaraos Quechua -> Quechua */ - {"qvs", HB_TAG('Q','U','Z',' ')}, /* San Martín Quechua -> Quechua */ - {"qvw", HB_TAG('Q','W','H',' ')}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ - {"qvw", HB_TAG('Q','U','Z',' ')}, /* Huaylla Wanca Quechua -> Quechua */ - {"qvz", HB_TAG('Q','V','I',' ')}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ - {"qvz", HB_TAG('Q','U','Z',' ')}, /* Northern Pastaza Quichua -> Quechua */ - {"qwa", HB_TAG('Q','W','H',' ')}, /* Corongo Ancash Quechua -> Quechua (Peru) */ - {"qwa", HB_TAG('Q','U','Z',' ')}, /* Corongo Ancash Quechua -> Quechua */ - {"qwc", HB_TAG('Q','U','Z',' ')}, /* Classical Quechua -> Quechua */ - {"qwh", HB_TAG('Q','W','H',' ')}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ - {"qwh", HB_TAG('Q','U','Z',' ')}, /* Huaylas Ancash Quechua -> Quechua */ - {"qws", HB_TAG('Q','W','H',' ')}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ - {"qws", HB_TAG('Q','U','Z',' ')}, /* Sihuas Ancash Quechua -> Quechua */ - {"qwt", HB_TAG('A','T','H',' ')}, /* Kwalhioqua-Tlatskanai -> Athapaskan */ - {"qxa", HB_TAG('Q','W','H',' ')}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ - {"qxa", HB_TAG('Q','U','Z',' ')}, /* Chiquián Ancash Quechua -> Quechua */ - {"qxc", HB_TAG('Q','W','H',' ')}, /* Chincha Quechua -> Quechua (Peru) */ - {"qxc", HB_TAG('Q','U','Z',' ')}, /* Chincha Quechua -> Quechua */ - {"qxh", HB_TAG('Q','W','H',' ')}, /* Panao Huánuco Quechua -> Quechua (Peru) */ - {"qxh", HB_TAG('Q','U','Z',' ')}, /* Panao Huánuco Quechua -> Quechua */ - {"qxl", HB_TAG('Q','V','I',' ')}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ - {"qxl", HB_TAG('Q','U','Z',' ')}, /* Salasaca Highland Quichua -> Quechua */ - {"qxn", HB_TAG('Q','W','H',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ - {"qxn", HB_TAG('Q','U','Z',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua */ - {"qxo", HB_TAG('Q','W','H',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ - {"qxo", HB_TAG('Q','U','Z',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua */ - {"qxp", HB_TAG('Q','U','Z',' ')}, /* Puno Quechua -> Quechua */ - {"qxr", HB_TAG('Q','V','I',' ')}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ - {"qxr", HB_TAG('Q','U','Z',' ')}, /* Cañar Highland Quichua -> Quechua */ - {"qxt", HB_TAG('Q','W','H',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ - {"qxt", HB_TAG('Q','U','Z',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua */ - {"qxu", HB_TAG('Q','U','Z',' ')}, /* Arequipa-La Unión Quechua -> Quechua */ - {"qxw", HB_TAG('Q','W','H',' ')}, /* Jauja Wanca Quechua -> Quechua (Peru) */ - {"qxw", HB_TAG('Q','U','Z',' ')}, /* Jauja Wanca Quechua -> Quechua */ - {"rag", HB_TAG('L','U','H',' ')}, /* Logooli -> Luyia */ -/*{"raj", HB_TAG('R','A','J',' ')},*/ /* Rajasthani [macrolanguage] */ - {"ral", HB_TAG('Q','I','N',' ')}, /* Ralte -> Chin */ -/*{"rar", HB_TAG('R','A','R',' ')},*/ /* Rarotongan */ - {"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung -> Palaung */ - {"rbl", HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */ - {"rcf", HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */ -/*{"rej", HB_TAG('R','E','J',' ')},*/ /* Rejang */ -/*{"rhg", HB_TAG('R','H','G',' ')},*/ /* Rohingya */ -/*{"ria", HB_TAG('R','I','A',' ')},*/ /* Riang (India) */ - {"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */ - {"rif", HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */ -/*{"rit", HB_TAG('R','I','T',' ')},*/ /* Ritharrngu -> Ritarungo */ - {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */ -/*{"rkw", HB_TAG('R','K','W',' ')},*/ /* Arakwal */ - {"rm", HB_TAG('R','M','S',' ')}, /* Romansh */ - {"rmc", HB_TAG('R','O','Y',' ')}, /* Carpathian Romani -> Romany */ - {"rmf", HB_TAG('R','O','Y',' ')}, /* Kalo Finnish Romani -> Romany */ - {"rml", HB_TAG('R','O','Y',' ')}, /* Baltic Romani -> Romany */ - {"rmn", HB_TAG('R','O','Y',' ')}, /* Balkan Romani -> Romany */ - {"rmo", HB_TAG('R','O','Y',' ')}, /* Sinte Romani -> Romany */ - {"rms", HB_TAG_NONE }, /* Romanian Sign Language != Romansh */ - {"rmw", HB_TAG('R','O','Y',' ')}, /* Welsh Romani -> Romany */ - {"rmy", HB_TAG('R','M','Y',' ')}, /* Vlax Romani */ - {"rmy", HB_TAG('R','O','Y',' ')}, /* Vlax Romani -> Romany */ - {"rmz", HB_TAG('A','R','K',' ')}, /* Marma -> Rakhine */ - {"rn", HB_TAG('R','U','N',' ')}, /* Rundi */ - {"ro", HB_TAG('R','O','M',' ')}, /* Romanian */ - {"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ - {"rop", HB_TAG('C','P','P',' ')}, /* Kriol -> Creoles */ - {"rtc", HB_TAG('Q','I','N',' ')}, /* Rungtu Chin -> Chin */ -/*{"rtm", HB_TAG('R','T','M',' ')},*/ /* Rotuman */ - {"ru", HB_TAG('R','U','S',' ')}, /* Russian */ - {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */ -/*{"rup", HB_TAG('R','U','P',' ')},*/ /* Aromanian */ - {"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */ - {"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */ - {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */ - {"sad", HB_TAG_NONE }, /* Sandawe != Sadri */ - {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut -> Sakha */ - {"sam", HB_TAG('P','A','A',' ')}, /* Samaritan Aramaic -> Palestinian Aramaic */ -/*{"sas", HB_TAG('S','A','S',' ')},*/ /* Sasak */ -/*{"sat", HB_TAG('S','A','T',' ')},*/ /* Santali */ - {"say", HB_TAG_NONE }, /* Saya != Sayisi */ - {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */ - {"scf", HB_TAG('C','P','P',' ')}, /* San Miguel Creole French -> Creoles */ - {"sch", HB_TAG('Q','I','N',' ')}, /* Sakachep -> Chin */ - {"sci", HB_TAG('C','P','P',' ')}, /* Sri Lankan Creole Malay -> Creoles */ - {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */ -/*{"scn", HB_TAG('S','C','N',' ')},*/ /* Sicilian */ -/*{"sco", HB_TAG('S','C','O',' ')},*/ /* Scots */ - {"scs", HB_TAG('S','C','S',' ')}, /* North Slavey */ - {"scs", HB_TAG('S','L','A',' ')}, /* North Slavey -> Slavey */ - {"scs", HB_TAG('A','T','H',' ')}, /* North Slavey -> Athapaskan */ - {"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */ - {"sdc", HB_TAG('S','R','D',' ')}, /* Sassarese Sardinian -> Sardinian */ - {"sdh", HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */ - {"sdn", HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */ - {"sds", HB_TAG('B','B','R',' ')}, /* Sened -> Berber */ - {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */ - {"seh", HB_TAG('S','N','A',' ')}, /* Sena */ - {"sek", HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */ -/*{"sel", HB_TAG('S','E','L',' ')},*/ /* Selkup */ - {"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */ - {"sfm", HB_TAG('S','F','M',' ')}, /* Small Flowery Miao */ - {"sfm", HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */ - {"sg", HB_TAG('S','G','O',' ')}, /* Sango */ -/*{"sga", HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */ - {"sgc", HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */ - {"sgo", HB_TAG_NONE }, /* Songa (retired code) != Sango */ -/*{"sgs", HB_TAG('S','G','S',' ')},*/ /* Samogitian */ - {"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ - {"sh", HB_TAG('B','O','S',' ')}, /* Serbo-Croatian [macrolanguage] -> Bosnian */ - {"sh", HB_TAG('H','R','V',' ')}, /* Serbo-Croatian [macrolanguage] -> Croatian */ - {"sh", HB_TAG('S','R','B',' ')}, /* Serbo-Croatian [macrolanguage] -> Serbian */ - {"shi", HB_TAG('S','H','I',' ')}, /* Tachelhit */ - {"shi", HB_TAG('B','B','R',' ')}, /* Tachelhit -> Berber */ - {"shl", HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */ -/*{"shn", HB_TAG('S','H','N',' ')},*/ /* Shan */ - {"shu", HB_TAG('A','R','A',' ')}, /* Chadian Arabic -> Arabic */ - {"shy", HB_TAG('B','B','R',' ')}, /* Tachawit -> Berber */ - {"si", HB_TAG('S','N','H',' ')}, /* Sinhala (Sinhalese) */ - {"sib", HB_TAG_NONE }, /* Sebop != Sibe */ -/*{"sid", HB_TAG('S','I','D',' ')},*/ /* Sidamo */ - {"sig", HB_TAG_NONE }, /* Paasaal != Silte Gurage */ - {"siz", HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */ - {"sjd", HB_TAG('K','S','M',' ')}, /* Kildin Sami */ - {"sjo", HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */ - {"sjs", HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */ - {"sk", HB_TAG('S','K','Y',' ')}, /* Slovak */ - {"skg", HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */ - {"skr", HB_TAG('S','R','K',' ')}, /* Saraiki */ - {"sks", HB_TAG_NONE }, /* Maia != Skolt Sami */ - {"skw", HB_TAG('C','P','P',' ')}, /* Skepi Creole Dutch -> Creoles */ - {"sky", HB_TAG_NONE }, /* Sikaiana != Slovak */ - {"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */ - {"sla", HB_TAG_NONE }, /* Slavic [collection] != Slavey */ - {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */ - {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */ - {"smd", HB_TAG('M','B','N',' ')}, /* Sama (retired code) -> Mbundu */ - {"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */ - {"sml", HB_TAG_NONE }, /* Central Sama != Somali */ - {"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */ - {"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */ - {"smt", HB_TAG('Q','I','N',' ')}, /* Simte -> Chin */ - {"sn", HB_TAG('S','N','A','0')}, /* Shona */ - {"snb", HB_TAG('I','B','A',' ')}, /* Sebuyau (retired code) -> Iban */ - {"snh", HB_TAG_NONE }, /* Shinabo (retired code) != Sinhala (Sinhalese) */ -/*{"snk", HB_TAG('S','N','K',' ')},*/ /* Soninke */ - {"so", HB_TAG('S','M','L',' ')}, /* Somali */ - {"sog", HB_TAG_NONE }, /* Sogdian != Sodo Gurage */ -/*{"sop", HB_TAG('S','O','P',' ')},*/ /* Songe */ - {"spv", HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */ - {"spy", HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */ - {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */ - {"sr", HB_TAG('S','R','B',' ')}, /* Serbian */ - {"srb", HB_TAG_NONE }, /* Sora != Serbian */ - {"src", HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */ - {"srk", HB_TAG_NONE }, /* Serudung Murut != Saraiki */ - {"srm", HB_TAG('C','P','P',' ')}, /* Saramaccan -> Creoles */ - {"srn", HB_TAG('C','P','P',' ')}, /* Sranan Tongo -> Creoles */ - {"sro", HB_TAG('S','R','D',' ')}, /* Campidanese Sardinian -> Sardinian */ -/*{"srr", HB_TAG('S','R','R',' ')},*/ /* Serer */ - {"srs", HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */ - {"ss", HB_TAG('S','W','Z',' ')}, /* Swati */ - {"ssh", HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */ - {"ssl", HB_TAG_NONE }, /* Western Sisaala != South Slavey */ - {"ssm", HB_TAG_NONE }, /* Semnam != Southern Sami */ - {"st", HB_TAG('S','O','T',' ')}, /* Southern Sotho */ - {"sta", HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */ -/*{"stq", HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */ - {"stv", HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */ - {"su", HB_TAG('S','U','N',' ')}, /* Sundanese */ -/*{"suk", HB_TAG('S','U','K',' ')},*/ /* Sukuma */ - {"suq", HB_TAG('S','U','R',' ')}, /* Suri */ - {"sur", HB_TAG_NONE }, /* Mwaghavul != Suri */ - {"sv", HB_TAG('S','V','E',' ')}, /* Swedish */ -/*{"sva", HB_TAG('S','V','A',' ')},*/ /* Svan */ - {"svc", HB_TAG('C','P','P',' ')}, /* Vincentian Creole English -> Creoles */ - {"sve", HB_TAG_NONE }, /* Serili != Swedish */ - {"sw", HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */ - {"swb", HB_TAG('C','M','R',' ')}, /* Maore Comorian -> Comorian */ - {"swc", HB_TAG('S','W','K',' ')}, /* Congo Swahili -> Swahili */ - {"swh", HB_TAG('S','W','K',' ')}, /* Swahili */ - {"swk", HB_TAG_NONE }, /* Malawi Sena != Swahili */ - {"swn", HB_TAG('B','B','R',' ')}, /* Sawknah -> Berber */ - {"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati -> Marwari */ -/*{"sxu", HB_TAG('S','X','U',' ')},*/ /* Upper Saxon */ - {"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac -> Syriac */ -/*{"syl", HB_TAG('S','Y','L',' ')},*/ /* Sylheti */ -/*{"syr", HB_TAG('S','Y','R',' ')},*/ /* Syriac [macrolanguage] */ -/*{"szl", HB_TAG('S','Z','L',' ')},*/ /* Silesian */ - {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */ - {"taa", HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */ -/*{"tab", HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */ - {"taj", HB_TAG_NONE }, /* Eastern Tamang != Tajiki */ - {"taq", HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */ - {"taq", HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */ - {"tas", HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */ - {"tau", HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */ - {"tcb", HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */ - {"tce", HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */ - {"tch", HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */ - {"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */ - {"tcs", HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */ - {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */ - {"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */ -/*{"tdd", HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */ - {"tdx", HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ - {"te", HB_TAG('T','E','L',' ')}, /* Telugu */ - {"tec", HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */ - {"tem", HB_TAG('T','M','N',' ')}, /* Timne -> Temne */ -/*{"tet", HB_TAG('T','E','T',' ')},*/ /* Tetum */ - {"tez", HB_TAG('B','B','R',' ')}, /* Tetserret -> Berber */ - {"tfn", HB_TAG('A','T','H',' ')}, /* Tanaina -> Athapaskan */ - {"tg", HB_TAG('T','A','J',' ')}, /* Tajik -> Tajiki */ - {"tgh", HB_TAG('C','P','P',' ')}, /* Tobagonian Creole English -> Creoles */ - {"tgj", HB_TAG('N','I','S',' ')}, /* Tagin -> Nisi */ - {"tgn", HB_TAG_NONE }, /* Tandaganon != Tongan */ - {"tgr", HB_TAG_NONE }, /* Tareng != Tigre */ - {"tgx", HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */ - {"tgy", HB_TAG_NONE }, /* Togoyo != Tigrinya */ - {"th", HB_TAG('T','H','A',' ')}, /* Thai */ - {"tht", HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */ - {"thv", HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */ - {"thv", HB_TAG('B','B','R',' ')}, /* Tahaggart Tamahaq -> Berber */ - {"thz", HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */ - {"thz", HB_TAG('B','B','R',' ')}, /* Tayart Tamajeq -> Berber */ - {"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */ - {"tia", HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */ - {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */ -/*{"tiv", HB_TAG('T','I','V',' ')},*/ /* Tiv */ -/*{"tjl", HB_TAG('T','J','L',' ')},*/ /* Tai Laing */ - {"tjo", HB_TAG('B','B','R',' ')}, /* Temacine Tamazight -> Berber */ - {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */ - {"tkg", HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */ - {"tkm", HB_TAG_NONE }, /* Takelma != Turkmen */ - {"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */ -/*{"tli", HB_TAG('T','L','I',' ')},*/ /* Tlingit */ - {"tmg", HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */ - {"tmh", HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */ - {"tmh", HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */ - {"tmn", HB_TAG_NONE }, /* Taman (Indonesia) != Temne */ - {"tmw", HB_TAG('M','L','Y',' ')}, /* Temuan -> Malay */ - {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */ - {"tna", HB_TAG_NONE }, /* Tacana != Tswana */ - {"tne", HB_TAG_NONE }, /* Tinoc Kallahan (retired code) != Tundra Enets */ - {"tnf", HB_TAG('D','R','I',' ')}, /* Tangshewi (retired code) -> Dari */ - {"tnf", HB_TAG('F','A','R',' ')}, /* Tangshewi (retired code) -> Persian */ - {"tng", HB_TAG_NONE }, /* Tobanga != Tonga */ - {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) -> Tongan */ - {"tod", HB_TAG('T','O','D','0')}, /* Toma */ - {"toi", HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */ - {"toj", HB_TAG('M','Y','N',' ')}, /* Tojolabal -> Mayan */ - {"tol", HB_TAG('A','T','H',' ')}, /* Tolowa -> Athapaskan */ - {"tor", HB_TAG('B','A','D','0')}, /* Togbo-Vara Banda -> Banda */ - {"tpi", HB_TAG('T','P','I',' ')}, /* Tok Pisin */ - {"tpi", HB_TAG('C','P','P',' ')}, /* Tok Pisin -> Creoles */ - {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */ - {"trf", HB_TAG('C','P','P',' ')}, /* Trinidadian Creole English -> Creoles */ - {"trk", HB_TAG_NONE }, /* Turkic [collection] != Turkish */ - {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */ - {"tru", HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */ - {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */ - {"tsg", HB_TAG_NONE }, /* Tausug != Tsonga */ -/*{"tsj", HB_TAG('T','S','J',' ')},*/ /* Tshangla */ - {"tt", HB_TAG('T','A','T',' ')}, /* Tatar */ - {"ttc", HB_TAG('M','Y','N',' ')}, /* Tektiteko -> Mayan */ - {"ttm", HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */ - {"ttq", HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */ - {"ttq", HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */ - {"tua", HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */ - {"tul", HB_TAG_NONE }, /* Tula != Tumbuka */ -/*{"tum", HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */ - {"tuu", HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */ - {"tuv", HB_TAG_NONE }, /* Turkana != Tuvin */ - {"tuy", HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */ -/*{"tvl", HB_TAG('T','V','L',' ')},*/ /* Tuvalu */ - {"tvy", HB_TAG('C','P','P',' ')}, /* Timor Pidgin -> Creoles */ - {"tw", HB_TAG('T','W','I',' ')}, /* Twi */ - {"tw", HB_TAG('A','K','A',' ')}, /* Twi -> Akan */ - {"txc", HB_TAG('A','T','H',' ')}, /* Tsetsaut -> Athapaskan */ - {"txy", HB_TAG('M','L','G',' ')}, /* Tanosy Malagasy -> Malagasy */ - {"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */ - {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvinian -> Tuvin */ -/*{"tyz", HB_TAG('T','Y','Z',' ')},*/ /* Tày */ - {"tzh", HB_TAG('M','Y','N',' ')}, /* Tzeltal -> Mayan */ - {"tzj", HB_TAG('M','Y','N',' ')}, /* Tz'utujil -> Mayan */ - {"tzm", HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight -> Tamazight */ - {"tzm", HB_TAG('B','B','R',' ')}, /* Central Atlas Tamazight -> Berber */ - {"tzo", HB_TAG('T','Z','O',' ')}, /* Tzotzil */ - {"tzo", HB_TAG('M','Y','N',' ')}, /* Tzotzil -> Mayan */ - {"ubl", HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */ -/*{"udm", HB_TAG('U','D','M',' ')},*/ /* Udmurt */ - {"ug", HB_TAG('U','Y','G',' ')}, /* Uyghur */ - {"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */ - {"uki", HB_TAG('K','U','I',' ')}, /* Kui (India) */ - {"uln", HB_TAG('C','P','P',' ')}, /* Unserdeutsch -> Creoles */ -/*{"umb", HB_TAG('U','M','B',' ')},*/ /* Umbundu */ - {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */ - {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */ - {"urk", HB_TAG('M','L','Y',' ')}, /* Urak Lawoi' -> Malay */ - {"usp", HB_TAG('M','Y','N',' ')}, /* Uspanteco -> Mayan */ - {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */ - {"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek -> Uzbek */ - {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek -> Uzbek */ - {"vap", HB_TAG('Q','I','N',' ')}, /* Vaiphei -> Chin */ - {"ve", HB_TAG('V','E','N',' ')}, /* Venda */ -/*{"vec", HB_TAG('V','E','C',' ')},*/ /* Venetian */ - {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */ - {"vic", HB_TAG('C','P','P',' ')}, /* Virgin Islands Creole English -> Creoles */ - {"vit", HB_TAG_NONE }, /* Viti != Vietnamese */ - {"vkk", HB_TAG('M','L','Y',' ')}, /* Kaur -> Malay */ - {"vkp", HB_TAG('C','P','P',' ')}, /* Korlai Creole Portuguese -> Creoles */ - {"vkt", HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */ - {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */ - {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */ - {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */ -/*{"vro", HB_TAG('V','R','O',' ')},*/ /* Võro */ - {"wa", HB_TAG('W','L','N',' ')}, /* Walloon */ - {"wag", HB_TAG_NONE }, /* Wa'ema != Wagdi */ -/*{"war", HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */ - {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */ - {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */ - {"wbr", HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */ -/*{"wci", HB_TAG('W','C','I',' ')},*/ /* Waci Gbe */ - {"wea", HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */ - {"wes", HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */ - {"weu", HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */ - {"wlc", HB_TAG('C','M','R',' ')}, /* Mwali Comorian -> Comorian */ - {"wle", HB_TAG('S','I','G',' ')}, /* Wolane -> Silte Gurage */ - {"wlk", HB_TAG('A','T','H',' ')}, /* Wailaki -> Athapaskan */ - {"wni", HB_TAG('C','M','R',' ')}, /* Ndzwani Comorian -> Comorian */ - {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */ - {"wry", HB_TAG('M','A','W',' ')}, /* Merwari -> Marwari */ - {"wsg", HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */ -/*{"wtm", HB_TAG('W','T','M',' ')},*/ /* Mewati */ - {"wuu", HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese, Simplified */ - {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */ - {"xal", HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */ - {"xan", HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */ - {"xbd", HB_TAG_NONE }, /* Bindal != Lü */ - {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */ -/*{"xjb", HB_TAG('X','J','B',' ')},*/ /* Minjungbal -> Minjangbal */ -/*{"xkf", HB_TAG('X','K','F',' ')},*/ /* Khengkha */ - {"xmg", HB_TAG('B','M','L',' ')}, /* Mengaka -> Bamileke */ - {"xmm", HB_TAG('M','L','Y',' ')}, /* Manado Malay -> Malay */ - {"xmm", HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */ - {"xmv", HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */ - {"xmw", HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */ - {"xnj", HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */ - {"xnq", HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */ - {"xnr", HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */ -/*{"xog", HB_TAG('X','O','G',' ')},*/ /* Soga */ - {"xpe", HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */ - {"xpe", HB_TAG('K','P','L',' ')}, /* Liberia Kpelle -> Kpelle */ - {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */ - {"xsl", HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */ - {"xsl", HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */ - {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */ -/*{"xub", HB_TAG('X','U','B',' ')},*/ /* Betta Kurumba -> Bette Kuruma */ -/*{"xuj", HB_TAG('X','U','J',' ')},*/ /* Jennu Kurumba -> Jennu Kuruma */ - {"xup", HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */ - {"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */ - {"yaj", HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */ - {"yak", HB_TAG_NONE }, /* Yakama != Sakha */ -/*{"yao", HB_TAG('Y','A','O',' ')},*/ /* Yao */ -/*{"yap", HB_TAG('Y','A','P',' ')},*/ /* Yapese */ - {"yba", HB_TAG_NONE }, /* Yala != Yoruba */ - {"ybb", HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */ - {"ybd", HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */ - {"ydd", HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */ -/*{"ygp", HB_TAG('Y','G','P',' ')},*/ /* Gepo */ - {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */ - {"yih", HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */ - {"yim", HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */ -/*{"yna", HB_TAG('Y','N','A',' ')},*/ /* Aluo */ - {"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */ - {"yos", HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */ - {"yua", HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */ - {"yue", HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */ -/*{"ywq", HB_TAG('Y','W','Q',' ')},*/ /* Wuding-Luquan Yi */ - {"za", HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */ - {"zch", HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */ - {"zdj", HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */ -/*{"zea", HB_TAG('Z','E','A',' ')},*/ /* Zeeuws -> Zealandic */ - {"zeh", HB_TAG('Z','H','A',' ')}, /* Eastern Hongshuihe Zhuang -> Zhuang */ - {"zen", HB_TAG('B','B','R',' ')}, /* Zenaga -> Berber */ - {"zgb", HB_TAG('Z','H','A',' ')}, /* Guibei Zhuang -> Zhuang */ - {"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Moroccan Tamazight */ - {"zgh", HB_TAG('B','B','R',' ')}, /* Standard Moroccan Tamazight -> Berber */ - {"zgm", HB_TAG('Z','H','A',' ')}, /* Minz Zhuang -> Zhuang */ - {"zgn", HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */ - {"zh", HB_TAG('Z','H','S',' ')}, /* Chinese, Simplified [macrolanguage] */ - {"zhd", HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */ - {"zhn", HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */ - {"zlj", HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */ - {"zlm", HB_TAG('M','L','Y',' ')}, /* Malay */ - {"zln", HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */ - {"zlq", HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */ - {"zmi", HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */ - {"zmz", HB_TAG('B','A','D','0')}, /* Mbandja -> Banda */ - {"znd", HB_TAG_NONE }, /* Zande [collection] != Zande */ - {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */ - {"zom", HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */ - {"zqe", HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */ - {"zsm", HB_TAG('M','L','Y',' ')}, /* Standard Malay -> Malay */ - {"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */ - {"zum", HB_TAG('L','R','C',' ')}, /* Kumzari -> Luri */ - {"zyb", HB_TAG('Z','H','A',' ')}, /* Yongbei Zhuang -> Zhuang */ - {"zyg", HB_TAG('Z','H','A',' ')}, /* Yang Zhuang -> Zhuang */ - {"zyj", HB_TAG('Z','H','A',' ')}, /* Youjiang Zhuang -> Zhuang */ - {"zyn", HB_TAG('Z','H','A',' ')}, /* Yongnan Zhuang -> Zhuang */ - {"zyp", HB_TAG('Q','I','N',' ')}, /* Zyphe Chin -> Chin */ -/*{"zza", HB_TAG('Z','Z','A',' ')},*/ /* Zazaki [macrolanguage] */ - {"zzj", HB_TAG('Z','H','A',' ')}, /* Zuojiang Zhuang -> Zhuang */ +static const LangTag ot_languages2[] = { + {HB_TAG('a','a',' ',' '), HB_TAG('A','F','R',' ')}, /* Afar */ + {HB_TAG('a','b',' ',' '), HB_TAG('A','B','K',' ')}, /* Abkhazian */ + {HB_TAG('a','f',' ',' '), HB_TAG('A','F','K',' ')}, /* Afrikaans */ + {HB_TAG('a','k',' ',' '), HB_TAG('A','K','A',' ')}, /* Akan [macrolanguage] */ + {HB_TAG('a','m',' ',' '), HB_TAG('A','M','H',' ')}, /* Amharic */ + {HB_TAG('a','n',' ',' '), HB_TAG('A','R','G',' ')}, /* Aragonese */ + {HB_TAG('a','r',' ',' '), HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */ + {HB_TAG('a','s',' ',' '), HB_TAG('A','S','M',' ')}, /* Assamese */ + {HB_TAG('a','v',' ',' '), HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */ + {HB_TAG('a','y',' ',' '), HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */ + {HB_TAG('a','z',' ',' '), HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */ + {HB_TAG('b','a',' ',' '), HB_TAG('B','S','H',' ')}, /* Bashkir */ + {HB_TAG('b','e',' ',' '), HB_TAG('B','E','L',' ')}, /* Belarusian -> Belarussian */ + {HB_TAG('b','g',' ',' '), HB_TAG('B','G','R',' ')}, /* Bulgarian */ + {HB_TAG('b','i',' ',' '), HB_TAG('B','I','S',' ')}, /* Bislama */ + {HB_TAG('b','i',' ',' '), HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */ + {HB_TAG('b','m',' ',' '), HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */ + {HB_TAG('b','n',' ',' '), HB_TAG('B','E','N',' ')}, /* Bengali */ + {HB_TAG('b','o',' ',' '), HB_TAG('T','I','B',' ')}, /* Tibetan */ + {HB_TAG('b','r',' ',' '), HB_TAG('B','R','E',' ')}, /* Breton */ + {HB_TAG('b','s',' ',' '), HB_TAG('B','O','S',' ')}, /* Bosnian */ + {HB_TAG('c','a',' ',' '), HB_TAG('C','A','T',' ')}, /* Catalan */ + {HB_TAG('c','e',' ',' '), HB_TAG('C','H','E',' ')}, /* Chechen */ + {HB_TAG('c','h',' ',' '), HB_TAG('C','H','A',' ')}, /* Chamorro */ + {HB_TAG('c','o',' ',' '), HB_TAG('C','O','S',' ')}, /* Corsican */ + {HB_TAG('c','r',' ',' '), HB_TAG('C','R','E',' ')}, /* Cree [macrolanguage] */ + {HB_TAG('c','s',' ',' '), HB_TAG('C','S','Y',' ')}, /* Czech */ + {HB_TAG('c','u',' ',' '), HB_TAG('C','S','L',' ')}, /* Church Slavonic */ + {HB_TAG('c','v',' ',' '), HB_TAG('C','H','U',' ')}, /* Chuvash */ + {HB_TAG('c','y',' ',' '), HB_TAG('W','E','L',' ')}, /* Welsh */ + {HB_TAG('d','a',' ',' '), HB_TAG('D','A','N',' ')}, /* Danish */ + {HB_TAG('d','e',' ',' '), HB_TAG('D','E','U',' ')}, /* German */ + {HB_TAG('d','v',' ',' '), HB_TAG('D','I','V',' ')}, /* Divehi (Dhivehi, Maldivian) */ + {HB_TAG('d','v',' ',' '), HB_TAG('D','H','V',' ')}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ + {HB_TAG('d','z',' ',' '), HB_TAG('D','Z','N',' ')}, /* Dzongkha */ + {HB_TAG('e','e',' ',' '), HB_TAG('E','W','E',' ')}, /* Ewe */ + {HB_TAG('e','l',' ',' '), HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) -> Greek */ + {HB_TAG('e','n',' ',' '), HB_TAG('E','N','G',' ')}, /* English */ + {HB_TAG('e','o',' ',' '), HB_TAG('N','T','O',' ')}, /* Esperanto */ + {HB_TAG('e','s',' ',' '), HB_TAG('E','S','P',' ')}, /* Spanish */ + {HB_TAG('e','t',' ',' '), HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ + {HB_TAG('e','u',' ',' '), HB_TAG('E','U','Q',' ')}, /* Basque */ + {HB_TAG('f','a',' ',' '), HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */ + {HB_TAG('f','f',' ',' '), HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */ + {HB_TAG('f','i',' ',' '), HB_TAG('F','I','N',' ')}, /* Finnish */ + {HB_TAG('f','j',' ',' '), HB_TAG('F','J','I',' ')}, /* Fijian */ + {HB_TAG('f','o',' ',' '), HB_TAG('F','O','S',' ')}, /* Faroese */ + {HB_TAG('f','r',' ',' '), HB_TAG('F','R','A',' ')}, /* French */ + {HB_TAG('f','y',' ',' '), HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */ + {HB_TAG('g','a',' ',' '), HB_TAG('I','R','I',' ')}, /* Irish */ + {HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */ + {HB_TAG('g','l',' ',' '), HB_TAG('G','A','L',' ')}, /* Galician */ + {HB_TAG('g','n',' ',' '), HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */ + {HB_TAG('g','u',' ',' '), HB_TAG('G','U','J',' ')}, /* Gujarati */ + {HB_TAG('g','v',' ',' '), HB_TAG('M','N','X',' ')}, /* Manx */ + {HB_TAG('h','a',' ',' '), HB_TAG('H','A','U',' ')}, /* Hausa */ + {HB_TAG('h','e',' ',' '), HB_TAG('I','W','R',' ')}, /* Hebrew */ + {HB_TAG('h','i',' ',' '), HB_TAG('H','I','N',' ')}, /* Hindi */ + {HB_TAG('h','o',' ',' '), HB_TAG('H','M','O',' ')}, /* Hiri Motu */ + {HB_TAG('h','o',' ',' '), HB_TAG('C','P','P',' ')}, /* Hiri Motu -> Creoles */ + {HB_TAG('h','r',' ',' '), HB_TAG('H','R','V',' ')}, /* Croatian */ + {HB_TAG('h','t',' ',' '), HB_TAG('H','A','I',' ')}, /* Haitian (Haitian Creole) */ + {HB_TAG('h','t',' ',' '), HB_TAG('C','P','P',' ')}, /* Haitian -> Creoles */ + {HB_TAG('h','u',' ',' '), HB_TAG('H','U','N',' ')}, /* Hungarian */ + {HB_TAG('h','y',' ',' '), HB_TAG('H','Y','E','0')}, /* Armenian -> Armenian East */ + {HB_TAG('h','y',' ',' '), HB_TAG('H','Y','E',' ')}, /* Armenian */ + {HB_TAG('h','z',' ',' '), HB_TAG('H','E','R',' ')}, /* Herero */ + {HB_TAG('i','a',' ',' '), HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */ + {HB_TAG('i','d',' ',' '), HB_TAG('I','N','D',' ')}, /* Indonesian */ + {HB_TAG('i','d',' ',' '), HB_TAG('M','L','Y',' ')}, /* Indonesian -> Malay */ + {HB_TAG('i','e',' ',' '), HB_TAG('I','L','E',' ')}, /* Interlingue */ + {HB_TAG('i','g',' ',' '), HB_TAG('I','B','O',' ')}, /* Igbo */ + {HB_TAG('i','i',' ',' '), HB_TAG('Y','I','M',' ')}, /* Sichuan Yi -> Yi Modern */ + {HB_TAG('i','k',' ',' '), HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */ + {HB_TAG('i','n',' ',' '), HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */ + {HB_TAG('i','n',' ',' '), HB_TAG('M','L','Y',' ')}, /* Indonesian (retired code) -> Malay */ + {HB_TAG('i','o',' ',' '), HB_TAG('I','D','O',' ')}, /* Ido */ + {HB_TAG('i','s',' ',' '), HB_TAG('I','S','L',' ')}, /* Icelandic */ + {HB_TAG('i','t',' ',' '), HB_TAG('I','T','A',' ')}, /* Italian */ + {HB_TAG('i','u',' ',' '), HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ + {HB_TAG('i','u',' ',' '), HB_TAG('I','N','U','K')}, /* Inuktitut [macrolanguage] -> Nunavik Inuktitut */ + {HB_TAG('i','w',' ',' '), HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */ + {HB_TAG('j','a',' ',' '), HB_TAG('J','A','N',' ')}, /* Japanese */ + {HB_TAG('j','i',' ',' '), HB_TAG('J','I','I',' ')}, /* Yiddish (retired code) */ + {HB_TAG('j','v',' ',' '), HB_TAG('J','A','V',' ')}, /* Javanese */ + {HB_TAG('j','w',' ',' '), HB_TAG('J','A','V',' ')}, /* Javanese (retired code) */ + {HB_TAG('k','a',' ',' '), HB_TAG('K','A','T',' ')}, /* Georgian */ + {HB_TAG('k','g',' ',' '), HB_TAG('K','O','N','0')}, /* Kongo [macrolanguage] */ + {HB_TAG('k','i',' ',' '), HB_TAG('K','I','K',' ')}, /* Kikuyu (Gikuyu) */ + {HB_TAG('k','j',' ',' '), HB_TAG('K','U','A',' ')}, /* Kuanyama */ + {HB_TAG('k','k',' ',' '), HB_TAG('K','A','Z',' ')}, /* Kazakh */ + {HB_TAG('k','l',' ',' '), HB_TAG('G','R','N',' ')}, /* Greenlandic */ + {HB_TAG('k','m',' ',' '), HB_TAG('K','H','M',' ')}, /* Khmer */ + {HB_TAG('k','n',' ',' '), HB_TAG('K','A','N',' ')}, /* Kannada */ + {HB_TAG('k','o',' ',' '), HB_TAG('K','O','R',' ')}, /* Korean */ + {HB_TAG('k','o',' ',' '), HB_TAG('K','O','H',' ')}, /* Korean -> Korean Old Hangul */ + {HB_TAG('k','r',' ',' '), HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */ + {HB_TAG('k','s',' ',' '), HB_TAG('K','S','H',' ')}, /* Kashmiri */ + {HB_TAG('k','u',' ',' '), HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */ + {HB_TAG('k','v',' ',' '), HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */ + {HB_TAG('k','w',' ',' '), HB_TAG('C','O','R',' ')}, /* Cornish */ + {HB_TAG('k','y',' ',' '), HB_TAG('K','I','R',' ')}, /* Kirghiz (Kyrgyz) */ + {HB_TAG('l','a',' ',' '), HB_TAG('L','A','T',' ')}, /* Latin */ + {HB_TAG('l','b',' ',' '), HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ + {HB_TAG('l','g',' ',' '), HB_TAG('L','U','G',' ')}, /* Ganda */ + {HB_TAG('l','i',' ',' '), HB_TAG('L','I','M',' ')}, /* Limburgish */ + {HB_TAG('l','n',' ',' '), HB_TAG('L','I','N',' ')}, /* Lingala */ + {HB_TAG('l','o',' ',' '), HB_TAG('L','A','O',' ')}, /* Lao */ + {HB_TAG('l','t',' ',' '), HB_TAG('L','T','H',' ')}, /* Lithuanian */ + {HB_TAG('l','u',' ',' '), HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ + {HB_TAG('l','v',' ',' '), HB_TAG('L','V','I',' ')}, /* Latvian [macrolanguage] */ + {HB_TAG('m','g',' ',' '), HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */ + {HB_TAG('m','h',' ',' '), HB_TAG('M','A','H',' ')}, /* Marshallese */ + {HB_TAG('m','i',' ',' '), HB_TAG('M','R','I',' ')}, /* Maori */ + {HB_TAG('m','k',' ',' '), HB_TAG('M','K','D',' ')}, /* Macedonian */ + {HB_TAG('m','l',' ',' '), HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */ + {HB_TAG('m','l',' ',' '), HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */ + {HB_TAG('m','n',' ',' '), HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */ + {HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */ + {HB_TAG('m','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */ + {HB_TAG('m','r',' ',' '), HB_TAG('M','A','R',' ')}, /* Marathi */ + {HB_TAG('m','s',' ',' '), HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */ + {HB_TAG('m','t',' ',' '), HB_TAG('M','T','S',' ')}, /* Maltese */ + {HB_TAG('m','y',' ',' '), HB_TAG('B','R','M',' ')}, /* Burmese */ + {HB_TAG('n','a',' ',' '), HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */ + {HB_TAG('n','b',' ',' '), HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål -> Norwegian */ + {HB_TAG('n','d',' ',' '), HB_TAG('N','D','B',' ')}, /* North Ndebele -> Ndebele */ + {HB_TAG('n','e',' ',' '), HB_TAG('N','E','P',' ')}, /* Nepali [macrolanguage] */ + {HB_TAG('n','g',' ',' '), HB_TAG('N','D','G',' ')}, /* Ndonga */ + {HB_TAG('n','l',' ',' '), HB_TAG('N','L','D',' ')}, /* Dutch */ + {HB_TAG('n','n',' ',' '), HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + {HB_TAG('n','o',' ',' '), HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ + {HB_TAG('n','r',' ',' '), HB_TAG('N','D','B',' ')}, /* South Ndebele -> Ndebele */ + {HB_TAG('n','v',' ',' '), HB_TAG('N','A','V',' ')}, /* Navajo */ + {HB_TAG('n','v',' ',' '), HB_TAG('A','T','H',' ')}, /* Navajo -> Athapaskan */ + {HB_TAG('n','y',' ',' '), HB_TAG('C','H','I',' ')}, /* Chichewa (Chewa, Nyanja) */ + {HB_TAG('o','c',' ',' '), HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ + {HB_TAG('o','j',' ',' '), HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */ + {HB_TAG('o','m',' ',' '), HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */ + {HB_TAG('o','r',' ',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */ + {HB_TAG('o','s',' ',' '), HB_TAG('O','S','S',' ')}, /* Ossetian */ + {HB_TAG('p','a',' ',' '), HB_TAG('P','A','N',' ')}, /* Punjabi */ + {HB_TAG('p','i',' ',' '), HB_TAG('P','A','L',' ')}, /* Pali */ + {HB_TAG('p','l',' ',' '), HB_TAG('P','L','K',' ')}, /* Polish */ + {HB_TAG('p','s',' ',' '), HB_TAG('P','A','S',' ')}, /* Pashto [macrolanguage] */ + {HB_TAG('p','t',' ',' '), HB_TAG('P','T','G',' ')}, /* Portuguese */ + {HB_TAG('q','u',' ',' '), HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */ + {HB_TAG('r','m',' ',' '), HB_TAG('R','M','S',' ')}, /* Romansh */ + {HB_TAG('r','n',' ',' '), HB_TAG('R','U','N',' ')}, /* Rundi */ + {HB_TAG('r','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Romanian */ + {HB_TAG('r','u',' ',' '), HB_TAG('R','U','S',' ')}, /* Russian */ + {HB_TAG('r','w',' ',' '), HB_TAG('R','U','A',' ')}, /* Kinyarwanda */ + {HB_TAG('s','a',' ',' '), HB_TAG('S','A','N',' ')}, /* Sanskrit */ + {HB_TAG('s','c',' ',' '), HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */ + {HB_TAG('s','d',' ',' '), HB_TAG('S','N','D',' ')}, /* Sindhi */ + {HB_TAG('s','e',' ',' '), HB_TAG('N','S','M',' ')}, /* Northern Sami */ + {HB_TAG('s','g',' ',' '), HB_TAG('S','G','O',' ')}, /* Sango */ + {HB_TAG('s','h',' ',' '), HB_TAG('B','O','S',' ')}, /* Serbo-Croatian [macrolanguage] -> Bosnian */ + {HB_TAG('s','h',' ',' '), HB_TAG('H','R','V',' ')}, /* Serbo-Croatian [macrolanguage] -> Croatian */ + {HB_TAG('s','h',' ',' '), HB_TAG('S','R','B',' ')}, /* Serbo-Croatian [macrolanguage] -> Serbian */ + {HB_TAG('s','i',' ',' '), HB_TAG('S','N','H',' ')}, /* Sinhala (Sinhalese) */ + {HB_TAG('s','k',' ',' '), HB_TAG('S','K','Y',' ')}, /* Slovak */ + {HB_TAG('s','l',' ',' '), HB_TAG('S','L','V',' ')}, /* Slovenian */ + {HB_TAG('s','m',' ',' '), HB_TAG('S','M','O',' ')}, /* Samoan */ + {HB_TAG('s','n',' ',' '), HB_TAG('S','N','A','0')}, /* Shona */ + {HB_TAG('s','o',' ',' '), HB_TAG('S','M','L',' ')}, /* Somali */ + {HB_TAG('s','q',' ',' '), HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */ + {HB_TAG('s','r',' ',' '), HB_TAG('S','R','B',' ')}, /* Serbian */ + {HB_TAG('s','s',' ',' '), HB_TAG('S','W','Z',' ')}, /* Swati */ + {HB_TAG('s','t',' ',' '), HB_TAG('S','O','T',' ')}, /* Southern Sotho */ + {HB_TAG('s','u',' ',' '), HB_TAG('S','U','N',' ')}, /* Sundanese */ + {HB_TAG('s','v',' ',' '), HB_TAG('S','V','E',' ')}, /* Swedish */ + {HB_TAG('s','w',' ',' '), HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */ + {HB_TAG('t','a',' ',' '), HB_TAG('T','A','M',' ')}, /* Tamil */ + {HB_TAG('t','e',' ',' '), HB_TAG('T','E','L',' ')}, /* Telugu */ + {HB_TAG('t','g',' ',' '), HB_TAG('T','A','J',' ')}, /* Tajik -> Tajiki */ + {HB_TAG('t','h',' ',' '), HB_TAG('T','H','A',' ')}, /* Thai */ + {HB_TAG('t','i',' ',' '), HB_TAG('T','G','Y',' ')}, /* Tigrinya */ + {HB_TAG('t','k',' ',' '), HB_TAG('T','K','M',' ')}, /* Turkmen */ + {HB_TAG('t','l',' ',' '), HB_TAG('T','G','L',' ')}, /* Tagalog */ + {HB_TAG('t','n',' ',' '), HB_TAG('T','N','A',' ')}, /* Tswana */ + {HB_TAG('t','o',' ',' '), HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) -> Tongan */ + {HB_TAG('t','r',' ',' '), HB_TAG('T','R','K',' ')}, /* Turkish */ + {HB_TAG('t','s',' ',' '), HB_TAG('T','S','G',' ')}, /* Tsonga */ + {HB_TAG('t','t',' ',' '), HB_TAG('T','A','T',' ')}, /* Tatar */ + {HB_TAG('t','w',' ',' '), HB_TAG('T','W','I',' ')}, /* Twi */ + {HB_TAG('t','w',' ',' '), HB_TAG('A','K','A',' ')}, /* Twi -> Akan */ + {HB_TAG('t','y',' ',' '), HB_TAG('T','H','T',' ')}, /* Tahitian */ + {HB_TAG('u','g',' ',' '), HB_TAG('U','Y','G',' ')}, /* Uyghur */ + {HB_TAG('u','k',' ',' '), HB_TAG('U','K','R',' ')}, /* Ukrainian */ + {HB_TAG('u','r',' ',' '), HB_TAG('U','R','D',' ')}, /* Urdu */ + {HB_TAG('u','z',' ',' '), HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */ + {HB_TAG('v','e',' ',' '), HB_TAG('V','E','N',' ')}, /* Venda */ + {HB_TAG('v','i',' ',' '), HB_TAG('V','I','T',' ')}, /* Vietnamese */ + {HB_TAG('v','o',' ',' '), HB_TAG('V','O','L',' ')}, /* Volapük */ + {HB_TAG('w','a',' ',' '), HB_TAG('W','L','N',' ')}, /* Walloon */ + {HB_TAG('w','o',' ',' '), HB_TAG('W','L','F',' ')}, /* Wolof */ + {HB_TAG('x','h',' ',' '), HB_TAG('X','H','S',' ')}, /* Xhosa */ + {HB_TAG('y','i',' ',' '), HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */ + {HB_TAG('y','o',' ',' '), HB_TAG('Y','B','A',' ')}, /* Yoruba */ + {HB_TAG('z','a',' ',' '), HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */ + {HB_TAG('z','h',' ',' '), HB_TAG('Z','H','S',' ')}, /* Chinese, Simplified [macrolanguage] */ + {HB_TAG('z','u',' ',' '), HB_TAG('Z','U','L',' ')}, /* Zulu */ +}; + +static const LangTag ot_languages3[] = { + {HB_TAG('a','a','e',' '), HB_TAG('S','Q','I',' ')}, /* Arbëreshë Albanian -> Albanian */ + {HB_TAG('a','a','o',' '), HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */ + {HB_TAG('a','a','t',' '), HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */ + {HB_TAG('a','b','a',' '), HB_TAG_NONE }, /* Abé != Abaza */ + {HB_TAG('a','b','h',' '), HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */ + {HB_TAG('a','b','q',' '), HB_TAG('A','B','A',' ')}, /* Abaza */ + {HB_TAG('a','b','s',' '), HB_TAG('C','P','P',' ')}, /* Ambonese Malay -> Creoles */ + {HB_TAG('a','b','v',' '), HB_TAG('A','R','A',' ')}, /* Baharna Arabic -> Arabic */ + {HB_TAG('a','c','f',' '), HB_TAG('F','A','N',' ')}, /* Saint Lucian Creole French -> French Antillean */ + {HB_TAG('a','c','f',' '), HB_TAG('C','P','P',' ')}, /* Saint Lucian Creole French -> Creoles */ +/*{HB_TAG('a','c','h',' '), HB_TAG('A','C','H',' ')},*/ /* Acoli -> Acholi */ + {HB_TAG('a','c','m',' '), HB_TAG('A','R','A',' ')}, /* Mesopotamian Arabic -> Arabic */ + {HB_TAG('a','c','q',' '), HB_TAG('A','R','A',' ')}, /* Ta'izzi-Adeni Arabic -> Arabic */ + {HB_TAG('a','c','r',' '), HB_TAG('A','C','R',' ')}, /* Achi */ + {HB_TAG('a','c','r',' '), HB_TAG('M','Y','N',' ')}, /* Achi -> Mayan */ + {HB_TAG('a','c','w',' '), HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */ + {HB_TAG('a','c','x',' '), HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */ + {HB_TAG('a','c','y',' '), HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */ + {HB_TAG('a','d','a',' '), HB_TAG('D','N','G',' ')}, /* Adangme -> Dangme */ + {HB_TAG('a','d','f',' '), HB_TAG('A','R','A',' ')}, /* Dhofari Arabic -> Arabic */ + {HB_TAG('a','d','p',' '), HB_TAG('D','Z','N',' ')}, /* Adap (retired code) -> Dzongkha */ +/*{HB_TAG('a','d','y',' '), HB_TAG('A','D','Y',' ')},*/ /* Adyghe */ + {HB_TAG('a','e','b',' '), HB_TAG('A','R','A',' ')}, /* Tunisian Arabic -> Arabic */ + {HB_TAG('a','e','c',' '), HB_TAG('A','R','A',' ')}, /* Saidi Arabic -> Arabic */ + {HB_TAG('a','f','b',' '), HB_TAG('A','R','A',' ')}, /* Gulf Arabic -> Arabic */ + {HB_TAG('a','f','k',' '), HB_TAG_NONE }, /* Nanubae != Afrikaans */ + {HB_TAG('a','f','s',' '), HB_TAG('C','P','P',' ')}, /* Afro-Seminole Creole -> Creoles */ + {HB_TAG('a','g','u',' '), HB_TAG('M','Y','N',' ')}, /* Aguacateco -> Mayan */ + {HB_TAG('a','g','w',' '), HB_TAG_NONE }, /* Kahua != Agaw */ + {HB_TAG('a','h','g',' '), HB_TAG('A','G','W',' ')}, /* Qimant -> Agaw */ + {HB_TAG('a','h','t',' '), HB_TAG('A','T','H',' ')}, /* Ahtena -> Athapaskan */ + {HB_TAG('a','i','g',' '), HB_TAG('C','P','P',' ')}, /* Antigua and Barbuda Creole English -> Creoles */ + {HB_TAG('a','i','i',' '), HB_TAG('S','W','A',' ')}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ + {HB_TAG('a','i','i',' '), HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */ +/*{HB_TAG('a','i','o',' '), HB_TAG('A','I','O',' ')},*/ /* Aiton */ + {HB_TAG('a','i','w',' '), HB_TAG('A','R','I',' ')}, /* Aari */ + {HB_TAG('a','j','p',' '), HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */ + {HB_TAG('a','j','t',' '), HB_TAG('A','R','A',' ')}, /* Judeo-Tunisian Arabic (retired code) -> Arabic */ + {HB_TAG('a','k','b',' '), HB_TAG('A','K','B',' ')}, /* Batak Angkola */ + {HB_TAG('a','k','b',' '), HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */ + {HB_TAG('a','l','n',' '), HB_TAG('S','Q','I',' ')}, /* Gheg Albanian -> Albanian */ + {HB_TAG('a','l','s',' '), HB_TAG('S','Q','I',' ')}, /* Tosk Albanian -> Albanian */ +/*{HB_TAG('a','l','t',' '), HB_TAG('A','L','T',' ')},*/ /* Southern Altai -> Altai */ + {HB_TAG('a','m','f',' '), HB_TAG('H','B','N',' ')}, /* Hamer-Banna -> Hammer-Banna */ + {HB_TAG('a','m','w',' '), HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic -> Syriac */ +/*{HB_TAG('a','n','g',' '), HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */ + {HB_TAG('a','o','a',' '), HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */ + {HB_TAG('a','p','a',' '), HB_TAG('A','T','H',' ')}, /* Apache [collection] -> Athapaskan */ + {HB_TAG('a','p','c',' '), HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */ + {HB_TAG('a','p','d',' '), HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */ + {HB_TAG('a','p','j',' '), HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */ + {HB_TAG('a','p','k',' '), HB_TAG('A','T','H',' ')}, /* Kiowa Apache -> Athapaskan */ + {HB_TAG('a','p','l',' '), HB_TAG('A','T','H',' ')}, /* Lipan Apache -> Athapaskan */ + {HB_TAG('a','p','m',' '), HB_TAG('A','T','H',' ')}, /* Mescalero-Chiricahua Apache -> Athapaskan */ + {HB_TAG('a','p','w',' '), HB_TAG('A','T','H',' ')}, /* Western Apache -> Athapaskan */ + {HB_TAG('a','r','b',' '), HB_TAG('A','R','A',' ')}, /* Standard Arabic -> Arabic */ + {HB_TAG('a','r','i',' '), HB_TAG_NONE }, /* Arikara != Aari */ + {HB_TAG('a','r','k',' '), HB_TAG_NONE }, /* Arikapú != Rakhine */ + {HB_TAG('a','r','n',' '), HB_TAG('M','A','P',' ')}, /* Mapudungun */ + {HB_TAG('a','r','q',' '), HB_TAG('A','R','A',' ')}, /* Algerian Arabic -> Arabic */ + {HB_TAG('a','r','s',' '), HB_TAG('A','R','A',' ')}, /* Najdi Arabic -> Arabic */ + {HB_TAG('a','r','y',' '), HB_TAG('M','O','R',' ')}, /* Moroccan Arabic -> Moroccan */ + {HB_TAG('a','r','y',' '), HB_TAG('A','R','A',' ')}, /* Moroccan Arabic -> Arabic */ + {HB_TAG('a','r','z',' '), HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */ +/*{HB_TAG('a','s','t',' '), HB_TAG('A','S','T',' ')},*/ /* Asturian */ +/*{HB_TAG('a','t','h',' '), HB_TAG('A','T','H',' ')},*/ /* Athapascan [collection] -> Athapaskan */ + {HB_TAG('a','t','j',' '), HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */ + {HB_TAG('a','t','v',' '), HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */ + {HB_TAG('a','u','j',' '), HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */ + {HB_TAG('a','u','z',' '), HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */ + {HB_TAG('a','v','l',' '), HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ +/*{HB_TAG('a','v','n',' '), HB_TAG('A','V','N',' ')},*/ /* Avatime */ +/*{HB_TAG('a','w','a',' '), HB_TAG('A','W','A',' ')},*/ /* Awadhi */ + {HB_TAG('a','y','c',' '), HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */ + {HB_TAG('a','y','h',' '), HB_TAG('A','R','A',' ')}, /* Hadrami Arabic -> Arabic */ + {HB_TAG('a','y','l',' '), HB_TAG('A','R','A',' ')}, /* Libyan Arabic -> Arabic */ + {HB_TAG('a','y','n',' '), HB_TAG('A','R','A',' ')}, /* Sanaani Arabic -> Arabic */ + {HB_TAG('a','y','p',' '), HB_TAG('A','R','A',' ')}, /* North Mesopotamian Arabic -> Arabic */ + {HB_TAG('a','y','r',' '), HB_TAG('A','Y','M',' ')}, /* Central Aymara -> Aymara */ + {HB_TAG('a','z','b',' '), HB_TAG('A','Z','B',' ')}, /* South Azerbaijani -> Torki */ + {HB_TAG('a','z','b',' '), HB_TAG('A','Z','E',' ')}, /* South Azerbaijani -> Azerbaijani */ + {HB_TAG('a','z','d',' '), HB_TAG('N','A','H',' ')}, /* Eastern Durango Nahuatl -> Nahuatl */ + {HB_TAG('a','z','j',' '), HB_TAG('A','Z','E',' ')}, /* North Azerbaijani -> Azerbaijani */ + {HB_TAG('a','z','n',' '), HB_TAG('N','A','H',' ')}, /* Western Durango Nahuatl -> Nahuatl */ + {HB_TAG('a','z','z',' '), HB_TAG('N','A','H',' ')}, /* Highland Puebla Nahuatl -> Nahuatl */ + {HB_TAG('b','a','d',' '), HB_TAG('B','A','D','0')}, /* Banda [collection] */ + {HB_TAG('b','a','g',' '), HB_TAG_NONE }, /* Tuki != Baghelkhandi */ + {HB_TAG('b','a','h',' '), HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */ + {HB_TAG('b','a','i',' '), HB_TAG('B','M','L',' ')}, /* Bamileke [collection] */ + {HB_TAG('b','a','l',' '), HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */ +/*{HB_TAG('b','a','n',' '), HB_TAG('B','A','N',' ')},*/ /* Balinese */ +/*{HB_TAG('b','a','r',' '), HB_TAG('B','A','R',' ')},*/ /* Bavarian */ + {HB_TAG('b','a','u',' '), HB_TAG_NONE }, /* Bada (Nigeria) != Baulé */ + {HB_TAG('b','b','c',' '), HB_TAG('B','B','C',' ')}, /* Batak Toba */ + {HB_TAG('b','b','c',' '), HB_TAG('B','T','K',' ')}, /* Batak Toba -> Batak */ + {HB_TAG('b','b','j',' '), HB_TAG('B','M','L',' ')}, /* Ghomálá' -> Bamileke */ + {HB_TAG('b','b','p',' '), HB_TAG('B','A','D','0')}, /* West Central Banda -> Banda */ + {HB_TAG('b','b','r',' '), HB_TAG_NONE }, /* Girawa != Berber */ + {HB_TAG('b','b','z',' '), HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic (retired code) -> Arabic */ + {HB_TAG('b','c','c',' '), HB_TAG('B','L','I',' ')}, /* Southern Balochi -> Baluchi */ + {HB_TAG('b','c','h',' '), HB_TAG_NONE }, /* Bariai != Bench */ + {HB_TAG('b','c','i',' '), HB_TAG('B','A','U',' ')}, /* Baoulé -> Baulé */ + {HB_TAG('b','c','l',' '), HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */ + {HB_TAG('b','c','q',' '), HB_TAG('B','C','H',' ')}, /* Bench */ + {HB_TAG('b','c','r',' '), HB_TAG('A','T','H',' ')}, /* Babine -> Athapaskan */ +/*{HB_TAG('b','d','y',' '), HB_TAG('B','D','Y',' ')},*/ /* Bandjalang */ + {HB_TAG('b','e','a',' '), HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */ + {HB_TAG('b','e','b',' '), HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */ +/*{HB_TAG('b','e','m',' '), HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */ + {HB_TAG('b','e','r',' '), HB_TAG('B','B','R',' ')}, /* Berber [collection] */ + {HB_TAG('b','e','w',' '), HB_TAG('C','P','P',' ')}, /* Betawi -> Creoles */ + {HB_TAG('b','f','l',' '), HB_TAG('B','A','D','0')}, /* Banda-Ndélé -> Banda */ + {HB_TAG('b','f','q',' '), HB_TAG('B','A','D',' ')}, /* Badaga */ + {HB_TAG('b','f','t',' '), HB_TAG('B','L','T',' ')}, /* Balti */ + {HB_TAG('b','f','u',' '), HB_TAG('L','A','H',' ')}, /* Gahri -> Lahuli */ + {HB_TAG('b','f','y',' '), HB_TAG('B','A','G',' ')}, /* Bagheli -> Baghelkhandi */ +/*{HB_TAG('b','g','c',' '), HB_TAG('B','G','C',' ')},*/ /* Haryanvi */ + {HB_TAG('b','g','n',' '), HB_TAG('B','L','I',' ')}, /* Western Balochi -> Baluchi */ + {HB_TAG('b','g','p',' '), HB_TAG('B','L','I',' ')}, /* Eastern Balochi -> Baluchi */ + {HB_TAG('b','g','q',' '), HB_TAG('B','G','Q',' ')}, /* Bagri */ + {HB_TAG('b','g','q',' '), HB_TAG('R','A','J',' ')}, /* Bagri -> Rajasthani */ + {HB_TAG('b','g','r',' '), HB_TAG('Q','I','N',' ')}, /* Bawm Chin -> Chin */ + {HB_TAG('b','h','b',' '), HB_TAG('B','H','I',' ')}, /* Bhili */ +/*{HB_TAG('b','h','i',' '), HB_TAG('B','H','I',' ')},*/ /* Bhilali -> Bhili */ + {HB_TAG('b','h','k',' '), HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) -> Bikol */ +/*{HB_TAG('b','h','o',' '), HB_TAG('B','H','O',' ')},*/ /* Bhojpuri */ + {HB_TAG('b','h','r',' '), HB_TAG('M','L','G',' ')}, /* Bara Malagasy -> Malagasy */ +/*{HB_TAG('b','i','k',' '), HB_TAG('B','I','K',' ')},*/ /* Bikol [macrolanguage] */ + {HB_TAG('b','i','l',' '), HB_TAG_NONE }, /* Bile != Bilen */ + {HB_TAG('b','i','n',' '), HB_TAG('E','D','O',' ')}, /* Edo */ + {HB_TAG('b','i','u',' '), HB_TAG('Q','I','N',' ')}, /* Biete -> Chin */ +/*{HB_TAG('b','j','j',' '), HB_TAG('B','J','J',' ')},*/ /* Kanauji */ + {HB_TAG('b','j','n',' '), HB_TAG('M','L','Y',' ')}, /* Banjar -> Malay */ + {HB_TAG('b','j','o',' '), HB_TAG('B','A','D','0')}, /* Mid-Southern Banda -> Banda */ + {HB_TAG('b','j','q',' '), HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ + {HB_TAG('b','j','s',' '), HB_TAG('C','P','P',' ')}, /* Bajan -> Creoles */ + {HB_TAG('b','j','t',' '), HB_TAG('B','L','N',' ')}, /* Balanta-Ganja -> Balante */ + {HB_TAG('b','k','f',' '), HB_TAG_NONE }, /* Beeke != Blackfoot */ + {HB_TAG('b','k','o',' '), HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */ + {HB_TAG('b','l','a',' '), HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */ + {HB_TAG('b','l','e',' '), HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */ + {HB_TAG('b','l','g',' '), HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */ + {HB_TAG('b','l','i',' '), HB_TAG_NONE }, /* Bolia != Baluchi */ + {HB_TAG('b','l','k',' '), HB_TAG('B','L','K',' ')}, /* Pa’o Karen */ + {HB_TAG('b','l','k',' '), HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */ + {HB_TAG('b','l','n',' '), HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol -> Bikol */ + {HB_TAG('b','l','t',' '), HB_TAG_NONE }, /* Tai Dam != Balti */ + {HB_TAG('b','m','b',' '), HB_TAG_NONE }, /* Bembe != Bambara (Bamanankan) */ + {HB_TAG('b','m','l',' '), HB_TAG_NONE }, /* Bomboli != Bamileke */ + {HB_TAG('b','m','m',' '), HB_TAG('M','L','G',' ')}, /* Northern Betsimisaraka Malagasy -> Malagasy */ + {HB_TAG('b','p','d',' '), HB_TAG('B','A','D','0')}, /* Banda-Banda -> Banda */ + {HB_TAG('b','p','l',' '), HB_TAG('C','P','P',' ')}, /* Broome Pearling Lugger Pidgin -> Creoles */ + {HB_TAG('b','p','q',' '), HB_TAG('C','P','P',' ')}, /* Banda Malay -> Creoles */ +/*{HB_TAG('b','p','y',' '), HB_TAG('B','P','Y',' ')},*/ /* Bishnupriya -> Bishnupriya Manipuri */ + {HB_TAG('b','q','i',' '), HB_TAG('L','R','C',' ')}, /* Bakhtiari -> Luri */ + {HB_TAG('b','q','k',' '), HB_TAG('B','A','D','0')}, /* Banda-Mbrès -> Banda */ + {HB_TAG('b','r','a',' '), HB_TAG('B','R','I',' ')}, /* Braj -> Braj Bhasha */ + {HB_TAG('b','r','c',' '), HB_TAG('C','P','P',' ')}, /* Berbice Creole Dutch -> Creoles */ +/*{HB_TAG('b','r','h',' '), HB_TAG('B','R','H',' ')},*/ /* Brahui */ + {HB_TAG('b','r','i',' '), HB_TAG_NONE }, /* Mokpwe != Braj Bhasha */ + {HB_TAG('b','r','m',' '), HB_TAG_NONE }, /* Barambu != Burmese */ +/*{HB_TAG('b','r','x',' '), HB_TAG('B','R','X',' ')},*/ /* Bodo (India) */ + {HB_TAG('b','s','h',' '), HB_TAG_NONE }, /* Kati != Bashkir */ +/*{HB_TAG('b','s','k',' '), HB_TAG('B','S','K',' ')},*/ /* Burushaski */ + {HB_TAG('b','t','b',' '), HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) (retired code) */ + {HB_TAG('b','t','d',' '), HB_TAG('B','T','D',' ')}, /* Batak Dairi (Pakpak) */ + {HB_TAG('b','t','d',' '), HB_TAG('B','T','K',' ')}, /* Batak Dairi -> Batak */ + {HB_TAG('b','t','i',' '), HB_TAG_NONE }, /* Burate != Beti */ + {HB_TAG('b','t','j',' '), HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */ +/*{HB_TAG('b','t','k',' '), HB_TAG('B','T','K',' ')},*/ /* Batak [collection] */ + {HB_TAG('b','t','m',' '), HB_TAG('B','T','M',' ')}, /* Batak Mandailing */ + {HB_TAG('b','t','m',' '), HB_TAG('B','T','K',' ')}, /* Batak Mandailing -> Batak */ + {HB_TAG('b','t','o',' '), HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */ + {HB_TAG('b','t','s',' '), HB_TAG('B','T','S',' ')}, /* Batak Simalungun */ + {HB_TAG('b','t','s',' '), HB_TAG('B','T','K',' ')}, /* Batak Simalungun -> Batak */ + {HB_TAG('b','t','x',' '), HB_TAG('B','T','X',' ')}, /* Batak Karo */ + {HB_TAG('b','t','x',' '), HB_TAG('B','T','K',' ')}, /* Batak Karo -> Batak */ + {HB_TAG('b','t','z',' '), HB_TAG('B','T','Z',' ')}, /* Batak Alas-Kluet */ + {HB_TAG('b','t','z',' '), HB_TAG('B','T','K',' ')}, /* Batak Alas-Kluet -> Batak */ +/*{HB_TAG('b','u','g',' '), HB_TAG('B','U','G',' ')},*/ /* Buginese -> Bugis */ + {HB_TAG('b','u','m',' '), HB_TAG('B','T','I',' ')}, /* Bulu (Cameroon) -> Beti */ + {HB_TAG('b','v','e',' '), HB_TAG('M','L','Y',' ')}, /* Berau Malay -> Malay */ + {HB_TAG('b','v','u',' '), HB_TAG('M','L','Y',' ')}, /* Bukit Malay -> Malay */ + {HB_TAG('b','w','e',' '), HB_TAG('K','R','N',' ')}, /* Bwe Karen -> Karen */ + {HB_TAG('b','x','k',' '), HB_TAG('L','U','H',' ')}, /* Bukusu -> Luyia */ + {HB_TAG('b','x','o',' '), HB_TAG('C','P','P',' ')}, /* Barikanchi -> Creoles */ + {HB_TAG('b','x','p',' '), HB_TAG('B','T','I',' ')}, /* Bebil -> Beti */ + {HB_TAG('b','x','r',' '), HB_TAG('R','B','U',' ')}, /* Russia Buriat -> Russian Buriat */ + {HB_TAG('b','y','n',' '), HB_TAG('B','I','L',' ')}, /* Bilin -> Bilen */ + {HB_TAG('b','y','v',' '), HB_TAG('B','Y','V',' ')}, /* Medumba */ + {HB_TAG('b','y','v',' '), HB_TAG('B','M','L',' ')}, /* Medumba -> Bamileke */ + {HB_TAG('b','z','c',' '), HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy -> Malagasy */ + {HB_TAG('b','z','j',' '), HB_TAG('C','P','P',' ')}, /* Belize Kriol English -> Creoles */ + {HB_TAG('b','z','k',' '), HB_TAG('C','P','P',' ')}, /* Nicaragua Creole English -> Creoles */ + {HB_TAG('c','a','a',' '), HB_TAG('M','Y','N',' ')}, /* Chortí -> Mayan */ + {HB_TAG('c','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Chuj -> Mayan */ + {HB_TAG('c','a','f',' '), HB_TAG('C','R','R',' ')}, /* Southern Carrier -> Carrier */ + {HB_TAG('c','a','f',' '), HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */ + {HB_TAG('c','a','k',' '), HB_TAG('C','A','K',' ')}, /* Kaqchikel */ + {HB_TAG('c','a','k',' '), HB_TAG('M','Y','N',' ')}, /* Kaqchikel -> Mayan */ + {HB_TAG('c','b','k',' '), HB_TAG('C','B','K',' ')}, /* Chavacano -> Zamboanga Chavacano */ + {HB_TAG('c','b','k',' '), HB_TAG('C','P','P',' ')}, /* Chavacano -> Creoles */ + {HB_TAG('c','b','l',' '), HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */ + {HB_TAG('c','c','l',' '), HB_TAG('C','P','P',' ')}, /* Cutchi-Swahili -> Creoles */ + {HB_TAG('c','c','m',' '), HB_TAG('C','P','P',' ')}, /* Malaccan Creole Malay -> Creoles */ + {HB_TAG('c','c','o',' '), HB_TAG('C','C','H','N')}, /* Comaltepec Chinantec -> Chinantec */ + {HB_TAG('c','c','q',' '), HB_TAG('A','R','K',' ')}, /* Chaungtha (retired code) -> Rakhine */ + {HB_TAG('c','d','o',' '), HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese, Simplified */ +/*{HB_TAG('c','e','b',' '), HB_TAG('C','E','B',' ')},*/ /* Cebuano */ + {HB_TAG('c','e','k',' '), HB_TAG('Q','I','N',' ')}, /* Eastern Khumi Chin -> Chin */ + {HB_TAG('c','e','y',' '), HB_TAG('Q','I','N',' ')}, /* Ekai Chin -> Chin */ + {HB_TAG('c','f','m',' '), HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) */ + {HB_TAG('c','f','m',' '), HB_TAG('Q','I','N',' ')}, /* Falam Chin -> Chin */ +/*{HB_TAG('c','g','g',' '), HB_TAG('C','G','G',' ')},*/ /* Chiga */ + {HB_TAG('c','h','f',' '), HB_TAG('M','Y','N',' ')}, /* Tabasco Chontal -> Mayan */ + {HB_TAG('c','h','g',' '), HB_TAG_NONE }, /* Chagatai != Chaha Gurage */ + {HB_TAG('c','h','h',' '), HB_TAG_NONE }, /* Chinook != Chattisgarhi */ + {HB_TAG('c','h','j',' '), HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */ + {HB_TAG('c','h','k',' '), HB_TAG('C','H','K','0')}, /* Chuukese */ + {HB_TAG('c','h','m',' '), HB_TAG('H','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> High Mari */ + {HB_TAG('c','h','m',' '), HB_TAG('L','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> Low Mari */ + {HB_TAG('c','h','n',' '), HB_TAG('C','P','P',' ')}, /* Chinook jargon -> Creoles */ +/*{HB_TAG('c','h','o',' '), HB_TAG('C','H','O',' ')},*/ /* Choctaw */ + {HB_TAG('c','h','p',' '), HB_TAG('C','H','P',' ')}, /* Chipewyan */ + {HB_TAG('c','h','p',' '), HB_TAG('S','A','Y',' ')}, /* Chipewyan -> Sayisi */ + {HB_TAG('c','h','p',' '), HB_TAG('A','T','H',' ')}, /* Chipewyan -> Athapaskan */ + {HB_TAG('c','h','q',' '), HB_TAG('C','C','H','N')}, /* Quiotepec Chinantec -> Chinantec */ +/*{HB_TAG('c','h','r',' '), HB_TAG('C','H','R',' ')},*/ /* Cherokee */ +/*{HB_TAG('c','h','y',' '), HB_TAG('C','H','Y',' ')},*/ /* Cheyenne */ + {HB_TAG('c','h','z',' '), HB_TAG('C','C','H','N')}, /* Ozumacín Chinantec -> Chinantec */ + {HB_TAG('c','i','w',' '), HB_TAG('O','J','B',' ')}, /* Chippewa -> Ojibway */ +/*{HB_TAG('c','j','a',' '), HB_TAG('C','J','A',' ')},*/ /* Western Cham */ +/*{HB_TAG('c','j','m',' '), HB_TAG('C','J','M',' ')},*/ /* Eastern Cham */ + {HB_TAG('c','j','y',' '), HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese, Simplified */ + {HB_TAG('c','k','a',' '), HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin (retired code) -> Chin */ + {HB_TAG('c','k','b',' '), HB_TAG('K','U','R',' ')}, /* Central Kurdish -> Kurdish */ + {HB_TAG('c','k','n',' '), HB_TAG('Q','I','N',' ')}, /* Kaang Chin -> Chin */ + {HB_TAG('c','k','s',' '), HB_TAG('C','P','P',' ')}, /* Tayo -> Creoles */ + {HB_TAG('c','k','t',' '), HB_TAG('C','H','K',' ')}, /* Chukot -> Chukchi */ + {HB_TAG('c','k','z',' '), HB_TAG('M','Y','N',' ')}, /* Cakchiquel-Quiché Mixed Language -> Mayan */ + {HB_TAG('c','l','c',' '), HB_TAG('A','T','H',' ')}, /* Chilcotin -> Athapaskan */ + {HB_TAG('c','l','d',' '), HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */ + {HB_TAG('c','l','e',' '), HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */ + {HB_TAG('c','l','j',' '), HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */ + {HB_TAG('c','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */ + {HB_TAG('c','m','n',' '), HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */ + {HB_TAG('c','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */ + {HB_TAG('c','n','b',' '), HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */ + {HB_TAG('c','n','h',' '), HB_TAG('Q','I','N',' ')}, /* Hakha Chin -> Chin */ + {HB_TAG('c','n','k',' '), HB_TAG('Q','I','N',' ')}, /* Khumi Chin -> Chin */ + {HB_TAG('c','n','l',' '), HB_TAG('C','C','H','N')}, /* Lalana Chinantec -> Chinantec */ + {HB_TAG('c','n','p',' '), HB_TAG('Z','H','S',' ')}, /* Northern Ping Chinese -> Chinese, Simplified */ + {HB_TAG('c','n','r',' '), HB_TAG('S','R','B',' ')}, /* Montenegrin -> Serbian */ + {HB_TAG('c','n','t',' '), HB_TAG('C','C','H','N')}, /* Tepetotutla Chinantec -> Chinantec */ + {HB_TAG('c','n','u',' '), HB_TAG('B','B','R',' ')}, /* Chenoua -> Berber */ + {HB_TAG('c','n','w',' '), HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */ + {HB_TAG('c','o','a',' '), HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */ + {HB_TAG('c','o','b',' '), HB_TAG('M','Y','N',' ')}, /* Chicomuceltec -> Mayan */ +/*{HB_TAG('c','o','p',' '), HB_TAG('C','O','P',' ')},*/ /* Coptic */ + {HB_TAG('c','o','q',' '), HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */ + {HB_TAG('c','p','a',' '), HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */ + {HB_TAG('c','p','e',' '), HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','p','f',' '), HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','p','i',' '), HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */ +/*{HB_TAG('c','p','p',' '), HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','p','x',' '), HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese, Simplified */ + {HB_TAG('c','q','d',' '), HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */ + {HB_TAG('c','q','u',' '), HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ + {HB_TAG('c','q','u',' '), HB_TAG('Q','U','Z',' ')}, /* Chilean Quechua (retired code) -> Quechua */ + {HB_TAG('c','r','h',' '), HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ + {HB_TAG('c','r','i',' '), HB_TAG('C','P','P',' ')}, /* Sãotomense -> Creoles */ + {HB_TAG('c','r','j',' '), HB_TAG('E','C','R',' ')}, /* Southern East Cree -> Eastern Cree */ + {HB_TAG('c','r','j',' '), HB_TAG('Y','C','R',' ')}, /* Southern East Cree -> Y-Cree */ + {HB_TAG('c','r','j',' '), HB_TAG('C','R','E',' ')}, /* Southern East Cree -> Cree */ + {HB_TAG('c','r','k',' '), HB_TAG('W','C','R',' ')}, /* Plains Cree -> West-Cree */ + {HB_TAG('c','r','k',' '), HB_TAG('Y','C','R',' ')}, /* Plains Cree -> Y-Cree */ + {HB_TAG('c','r','k',' '), HB_TAG('C','R','E',' ')}, /* Plains Cree -> Cree */ + {HB_TAG('c','r','l',' '), HB_TAG('E','C','R',' ')}, /* Northern East Cree -> Eastern Cree */ + {HB_TAG('c','r','l',' '), HB_TAG('Y','C','R',' ')}, /* Northern East Cree -> Y-Cree */ + {HB_TAG('c','r','l',' '), HB_TAG('C','R','E',' ')}, /* Northern East Cree -> Cree */ + {HB_TAG('c','r','m',' '), HB_TAG('M','C','R',' ')}, /* Moose Cree */ + {HB_TAG('c','r','m',' '), HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */ + {HB_TAG('c','r','m',' '), HB_TAG('C','R','E',' ')}, /* Moose Cree -> Cree */ + {HB_TAG('c','r','p',' '), HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','r','r',' '), HB_TAG_NONE }, /* Carolina Algonquian != Carrier */ + {HB_TAG('c','r','s',' '), HB_TAG('C','P','P',' ')}, /* Seselwa Creole French -> Creoles */ + {HB_TAG('c','r','t',' '), HB_TAG_NONE }, /* Iyojwa'ja Chorote != Crimean Tatar */ + {HB_TAG('c','r','x',' '), HB_TAG('C','R','R',' ')}, /* Carrier */ + {HB_TAG('c','r','x',' '), HB_TAG('A','T','H',' ')}, /* Carrier -> Athapaskan */ + {HB_TAG('c','s','a',' '), HB_TAG('C','C','H','N')}, /* Chiltepec Chinantec -> Chinantec */ +/*{HB_TAG('c','s','b',' '), HB_TAG('C','S','B',' ')},*/ /* Kashubian */ + {HB_TAG('c','s','h',' '), HB_TAG('Q','I','N',' ')}, /* Asho Chin -> Chin */ + {HB_TAG('c','s','j',' '), HB_TAG('Q','I','N',' ')}, /* Songlai Chin -> Chin */ + {HB_TAG('c','s','l',' '), HB_TAG_NONE }, /* Chinese Sign Language != Church Slavonic */ + {HB_TAG('c','s','o',' '), HB_TAG('C','C','H','N')}, /* Sochiapam Chinantec -> Chinantec */ + {HB_TAG('c','s','p',' '), HB_TAG('Z','H','S',' ')}, /* Southern Ping Chinese -> Chinese, Simplified */ + {HB_TAG('c','s','v',' '), HB_TAG('Q','I','N',' ')}, /* Sumtu Chin -> Chin */ + {HB_TAG('c','s','w',' '), HB_TAG('N','C','R',' ')}, /* Swampy Cree -> N-Cree */ + {HB_TAG('c','s','w',' '), HB_TAG('N','H','C',' ')}, /* Swampy Cree -> Norway House Cree */ + {HB_TAG('c','s','w',' '), HB_TAG('C','R','E',' ')}, /* Swampy Cree -> Cree */ + {HB_TAG('c','s','y',' '), HB_TAG('Q','I','N',' ')}, /* Siyin Chin -> Chin */ + {HB_TAG('c','t','c',' '), HB_TAG('A','T','H',' ')}, /* Chetco -> Athapaskan */ + {HB_TAG('c','t','d',' '), HB_TAG('Q','I','N',' ')}, /* Tedim Chin -> Chin */ + {HB_TAG('c','t','e',' '), HB_TAG('C','C','H','N')}, /* Tepinapa Chinantec -> Chinantec */ +/*{HB_TAG('c','t','g',' '), HB_TAG('C','T','G',' ')},*/ /* Chittagonian */ + {HB_TAG('c','t','h',' '), HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */ + {HB_TAG('c','t','l',' '), HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */ + {HB_TAG('c','t','s',' '), HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */ +/*{HB_TAG('c','t','t',' '), HB_TAG('C','T','T',' ')},*/ /* Wayanad Chetti */ + {HB_TAG('c','t','u',' '), HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */ + {HB_TAG('c','u','c',' '), HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */ +/*{HB_TAG('c','u','k',' '), HB_TAG('C','U','K',' ')},*/ /* San Blas Kuna */ + {HB_TAG('c','v','n',' '), HB_TAG('C','C','H','N')}, /* Valle Nacional Chinantec -> Chinantec */ + {HB_TAG('c','w','d',' '), HB_TAG('D','C','R',' ')}, /* Woods Cree */ + {HB_TAG('c','w','d',' '), HB_TAG('T','C','R',' ')}, /* Woods Cree -> TH-Cree */ + {HB_TAG('c','w','d',' '), HB_TAG('C','R','E',' ')}, /* Woods Cree -> Cree */ + {HB_TAG('c','z','h',' '), HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese, Simplified */ + {HB_TAG('c','z','o',' '), HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */ + {HB_TAG('c','z','t',' '), HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */ +/*{HB_TAG('d','a','g',' '), HB_TAG('D','A','G',' ')},*/ /* Dagbani */ + {HB_TAG('d','a','o',' '), HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */ + {HB_TAG('d','a','p',' '), HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */ +/*{HB_TAG('d','a','r',' '), HB_TAG('D','A','R',' ')},*/ /* Dargwa */ +/*{HB_TAG('d','a','x',' '), HB_TAG('D','A','X',' ')},*/ /* Dayi */ + {HB_TAG('d','c','r',' '), HB_TAG('C','P','P',' ')}, /* Negerhollands -> Creoles */ + {HB_TAG('d','e','n',' '), HB_TAG('S','L','A',' ')}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ + {HB_TAG('d','e','n',' '), HB_TAG('A','T','H',' ')}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ + {HB_TAG('d','e','p',' '), HB_TAG('C','P','P',' ')}, /* Pidgin Delaware -> Creoles */ + {HB_TAG('d','g','o',' '), HB_TAG('D','G','O',' ')}, /* Dogri (individual language) */ + {HB_TAG('d','g','o',' '), HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) */ + {HB_TAG('d','g','r',' '), HB_TAG('A','T','H',' ')}, /* Dogrib -> Athapaskan */ + {HB_TAG('d','h','d',' '), HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */ +/*{HB_TAG('d','h','g',' '), HB_TAG('D','H','G',' ')},*/ /* Dhangu */ + {HB_TAG('d','h','v',' '), HB_TAG_NONE }, /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */ + {HB_TAG('d','i','b',' '), HB_TAG('D','N','K',' ')}, /* South Central Dinka -> Dinka */ + {HB_TAG('d','i','k',' '), HB_TAG('D','N','K',' ')}, /* Southwestern Dinka -> Dinka */ + {HB_TAG('d','i','n',' '), HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ + {HB_TAG('d','i','p',' '), HB_TAG('D','N','K',' ')}, /* Northeastern Dinka -> Dinka */ + {HB_TAG('d','i','q',' '), HB_TAG('D','I','Q',' ')}, /* Dimli */ + {HB_TAG('d','i','q',' '), HB_TAG('Z','Z','A',' ')}, /* Dimli -> Zazaki */ + {HB_TAG('d','i','w',' '), HB_TAG('D','N','K',' ')}, /* Northwestern Dinka -> Dinka */ + {HB_TAG('d','j','e',' '), HB_TAG('D','J','R',' ')}, /* Zarma */ + {HB_TAG('d','j','k',' '), HB_TAG('C','P','P',' ')}, /* Eastern Maroon Creole -> Creoles */ + {HB_TAG('d','j','r',' '), HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ + {HB_TAG('d','k','s',' '), HB_TAG('D','N','K',' ')}, /* Southeastern Dinka -> Dinka */ + {HB_TAG('d','n','g',' '), HB_TAG('D','U','N',' ')}, /* Dungan */ +/*{HB_TAG('d','n','j',' '), HB_TAG('D','N','J',' ')},*/ /* Dan */ + {HB_TAG('d','n','k',' '), HB_TAG_NONE }, /* Dengka != Dinka */ + {HB_TAG('d','o','i',' '), HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) [macrolanguage] */ + {HB_TAG('d','r','h',' '), HB_TAG('M','N','G',' ')}, /* Darkhat (retired code) -> Mongolian */ + {HB_TAG('d','r','i',' '), HB_TAG_NONE }, /* C'Lela != Dari */ + {HB_TAG('d','r','w',' '), HB_TAG('D','R','I',' ')}, /* Darwazi (retired code) -> Dari */ + {HB_TAG('d','r','w',' '), HB_TAG('F','A','R',' ')}, /* Darwazi (retired code) -> Persian */ + {HB_TAG('d','s','b',' '), HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ + {HB_TAG('d','t','y',' '), HB_TAG('N','E','P',' ')}, /* Dotyali -> Nepali */ +/*{HB_TAG('d','u','j',' '), HB_TAG('D','U','J',' ')},*/ /* Dhuwal (retired code) */ + {HB_TAG('d','u','n',' '), HB_TAG_NONE }, /* Dusun Deyah != Dungan */ + {HB_TAG('d','u','p',' '), HB_TAG('M','L','Y',' ')}, /* Duano -> Malay */ + {HB_TAG('d','w','k',' '), HB_TAG('K','U','I',' ')}, /* Dawik Kui -> Kui */ + {HB_TAG('d','w','u',' '), HB_TAG('D','U','J',' ')}, /* Dhuwal */ + {HB_TAG('d','w','y',' '), HB_TAG('D','U','J',' ')}, /* Dhuwaya -> Dhuwal */ + {HB_TAG('d','y','u',' '), HB_TAG('J','U','L',' ')}, /* Dyula -> Jula */ + {HB_TAG('d','z','n',' '), HB_TAG_NONE }, /* Dzando != Dzongkha */ + {HB_TAG('e','c','r',' '), HB_TAG_NONE }, /* Eteocretan != Eastern Cree */ +/*{HB_TAG('e','f','i',' '), HB_TAG('E','F','I',' ')},*/ /* Efik */ + {HB_TAG('e','k','k',' '), HB_TAG('E','T','I',' ')}, /* Standard Estonian -> Estonian */ + {HB_TAG('e','k','y',' '), HB_TAG('K','R','N',' ')}, /* Eastern Kayah -> Karen */ + {HB_TAG('e','m','k',' '), HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */ + {HB_TAG('e','m','k',' '), HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */ + {HB_TAG('e','m','y',' '), HB_TAG('M','Y','N',' ')}, /* Epigraphic Mayan -> Mayan */ + {HB_TAG('e','n','b',' '), HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */ + {HB_TAG('e','n','f',' '), HB_TAG('F','N','E',' ')}, /* Forest Enets */ + {HB_TAG('e','n','h',' '), HB_TAG('T','N','E',' ')}, /* Tundra Enets */ + {HB_TAG('e','s','g',' '), HB_TAG('G','O','N',' ')}, /* Aheri Gondi -> Gondi */ + {HB_TAG('e','s','i',' '), HB_TAG('I','P','K',' ')}, /* North Alaskan Inupiatun -> Inupiat */ + {HB_TAG('e','s','k',' '), HB_TAG('I','P','K',' ')}, /* Northwest Alaska Inupiatun -> Inupiat */ +/*{HB_TAG('e','s','u',' '), HB_TAG('E','S','U',' ')},*/ /* Central Yupik */ + {HB_TAG('e','t','o',' '), HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */ + {HB_TAG('e','u','q',' '), HB_TAG_NONE }, /* Basque [collection] != Basque */ + {HB_TAG('e','v','e',' '), HB_TAG('E','V','N',' ')}, /* Even */ + {HB_TAG('e','v','n',' '), HB_TAG('E','V','K',' ')}, /* Evenki */ + {HB_TAG('e','w','o',' '), HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */ + {HB_TAG('e','y','o',' '), HB_TAG('K','A','L',' ')}, /* Keiyo -> Kalenjin */ + {HB_TAG('f','a','b',' '), HB_TAG('C','P','P',' ')}, /* Fa d'Ambu -> Creoles */ + {HB_TAG('f','a','n',' '), HB_TAG('F','A','N','0')}, /* Fang (Equatorial Guinea) */ + {HB_TAG('f','a','n',' '), HB_TAG('B','T','I',' ')}, /* Fang (Equatorial Guinea) -> Beti */ + {HB_TAG('f','a','r',' '), HB_TAG_NONE }, /* Fataleka != Persian */ + {HB_TAG('f','a','t',' '), HB_TAG('F','A','T',' ')}, /* Fanti */ + {HB_TAG('f','a','t',' '), HB_TAG('A','K','A',' ')}, /* Fanti -> Akan */ + {HB_TAG('f','b','l',' '), HB_TAG('B','I','K',' ')}, /* West Albay Bikol -> Bikol */ + {HB_TAG('f','f','m',' '), HB_TAG('F','U','L',' ')}, /* Maasina Fulfulde -> Fulah */ + {HB_TAG('f','i','l',' '), HB_TAG('P','I','L',' ')}, /* Filipino */ + {HB_TAG('f','l','m',' '), HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) (retired code) */ + {HB_TAG('f','l','m',' '), HB_TAG('Q','I','N',' ')}, /* Falam Chin (retired code) -> Chin */ + {HB_TAG('f','m','p',' '), HB_TAG('F','M','P',' ')}, /* Fe’fe’ */ + {HB_TAG('f','m','p',' '), HB_TAG('B','M','L',' ')}, /* Fe'fe' -> Bamileke */ + {HB_TAG('f','n','g',' '), HB_TAG('C','P','P',' ')}, /* Fanagalo -> Creoles */ +/*{HB_TAG('f','o','n',' '), HB_TAG('F','O','N',' ')},*/ /* Fon */ + {HB_TAG('f','o','s',' '), HB_TAG_NONE }, /* Siraya != Faroese */ + {HB_TAG('f','p','e',' '), HB_TAG('C','P','P',' ')}, /* Fernando Po Creole English -> Creoles */ +/*{HB_TAG('f','r','c',' '), HB_TAG('F','R','C',' ')},*/ /* Cajun French */ +/*{HB_TAG('f','r','p',' '), HB_TAG('F','R','P',' ')},*/ /* Arpitan */ + {HB_TAG('f','u','b',' '), HB_TAG('F','U','L',' ')}, /* Adamawa Fulfulde -> Fulah */ + {HB_TAG('f','u','c',' '), HB_TAG('F','U','L',' ')}, /* Pulaar -> Fulah */ + {HB_TAG('f','u','e',' '), HB_TAG('F','U','L',' ')}, /* Borgu Fulfulde -> Fulah */ + {HB_TAG('f','u','f',' '), HB_TAG('F','T','A',' ')}, /* Pular -> Futa */ + {HB_TAG('f','u','f',' '), HB_TAG('F','U','L',' ')}, /* Pular -> Fulah */ + {HB_TAG('f','u','h',' '), HB_TAG('F','U','L',' ')}, /* Western Niger Fulfulde -> Fulah */ + {HB_TAG('f','u','i',' '), HB_TAG('F','U','L',' ')}, /* Bagirmi Fulfulde -> Fulah */ + {HB_TAG('f','u','q',' '), HB_TAG('F','U','L',' ')}, /* Central-Eastern Niger Fulfulde -> Fulah */ + {HB_TAG('f','u','r',' '), HB_TAG('F','R','L',' ')}, /* Friulian */ + {HB_TAG('f','u','v',' '), HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */ + {HB_TAG('f','u','v',' '), HB_TAG('F','U','L',' ')}, /* Nigerian Fulfulde -> Fulah */ + {HB_TAG('g','a','a',' '), HB_TAG('G','A','D',' ')}, /* Ga */ + {HB_TAG('g','a','c',' '), HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */ + {HB_TAG('g','a','d',' '), HB_TAG_NONE }, /* Gaddang != Ga */ + {HB_TAG('g','a','e',' '), HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */ +/*{HB_TAG('g','a','g',' '), HB_TAG('G','A','G',' ')},*/ /* Gagauz */ + {HB_TAG('g','a','l',' '), HB_TAG_NONE }, /* Galolen != Galician */ + {HB_TAG('g','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */ + {HB_TAG('g','a','r',' '), HB_TAG_NONE }, /* Galeya != Garshuni */ + {HB_TAG('g','a','w',' '), HB_TAG_NONE }, /* Nobonob != Garhwali */ + {HB_TAG('g','a','x',' '), HB_TAG('O','R','O',' ')}, /* Borana-Arsi-Guji Oromo -> Oromo */ + {HB_TAG('g','a','z',' '), HB_TAG('O','R','O',' ')}, /* West Central Oromo -> Oromo */ + {HB_TAG('g','b','m',' '), HB_TAG('G','A','W',' ')}, /* Garhwali */ + {HB_TAG('g','c','e',' '), HB_TAG('A','T','H',' ')}, /* Galice -> Athapaskan */ + {HB_TAG('g','c','f',' '), HB_TAG('C','P','P',' ')}, /* Guadeloupean Creole French -> Creoles */ + {HB_TAG('g','c','l',' '), HB_TAG('C','P','P',' ')}, /* Grenadian Creole English -> Creoles */ + {HB_TAG('g','c','r',' '), HB_TAG('C','P','P',' ')}, /* Guianese Creole French -> Creoles */ + {HB_TAG('g','d','a',' '), HB_TAG('R','A','J',' ')}, /* Gade Lohar -> Rajasthani */ +/*{HB_TAG('g','e','z',' '), HB_TAG('G','E','Z',' ')},*/ /* Geez */ + {HB_TAG('g','g','o',' '), HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */ + {HB_TAG('g','h','a',' '), HB_TAG('B','B','R',' ')}, /* Ghadamès -> Berber */ + {HB_TAG('g','h','k',' '), HB_TAG('K','R','N',' ')}, /* Geko Karen -> Karen */ + {HB_TAG('g','h','o',' '), HB_TAG('B','B','R',' ')}, /* Ghomara -> Berber */ + {HB_TAG('g','i','b',' '), HB_TAG('C','P','P',' ')}, /* Gibanawa -> Creoles */ +/*{HB_TAG('g','i','h',' '), HB_TAG('G','I','H',' ')},*/ /* Githabul */ + {HB_TAG('g','i','l',' '), HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ + {HB_TAG('g','j','u',' '), HB_TAG('R','A','J',' ')}, /* Gujari -> Rajasthani */ + {HB_TAG('g','k','p',' '), HB_TAG('G','K','P',' ')}, /* Guinea Kpelle -> Kpelle (Guinea) */ + {HB_TAG('g','k','p',' '), HB_TAG('K','P','L',' ')}, /* Guinea Kpelle -> Kpelle */ + {HB_TAG('g','l','d',' '), HB_TAG('N','A','N',' ')}, /* Nanai */ +/*{HB_TAG('g','l','k',' '), HB_TAG('G','L','K',' ')},*/ /* Gilaki */ + {HB_TAG('g','m','z',' '), HB_TAG_NONE }, /* Mgbolizhia != Gumuz */ + {HB_TAG('g','n','b',' '), HB_TAG('Q','I','N',' ')}, /* Gangte -> Chin */ +/*{HB_TAG('g','n','n',' '), HB_TAG('G','N','N',' ')},*/ /* Gumatj */ + {HB_TAG('g','n','o',' '), HB_TAG('G','O','N',' ')}, /* Northern Gondi -> Gondi */ + {HB_TAG('g','n','w',' '), HB_TAG('G','U','A',' ')}, /* Western Bolivian Guaraní -> Guarani */ +/*{HB_TAG('g','o','g',' '), HB_TAG('G','O','G',' ')},*/ /* Gogo */ + {HB_TAG('g','o','m',' '), HB_TAG('K','O','K',' ')}, /* Goan Konkani -> Konkani */ +/*{HB_TAG('g','o','n',' '), HB_TAG('G','O','N',' ')},*/ /* Gondi [macrolanguage] */ + {HB_TAG('g','o','q',' '), HB_TAG('C','P','P',' ')}, /* Gorap -> Creoles */ + {HB_TAG('g','o','x',' '), HB_TAG('B','A','D','0')}, /* Gobu -> Banda */ + {HB_TAG('g','p','e',' '), HB_TAG('C','P','P',' ')}, /* Ghanaian Pidgin English -> Creoles */ + {HB_TAG('g','r','o',' '), HB_TAG_NONE }, /* Groma != Garo */ + {HB_TAG('g','r','r',' '), HB_TAG('B','B','R',' ')}, /* Taznatit -> Berber */ + {HB_TAG('g','r','t',' '), HB_TAG('G','R','O',' ')}, /* Garo */ + {HB_TAG('g','r','u',' '), HB_TAG('S','O','G',' ')}, /* Kistane -> Sodo Gurage */ + {HB_TAG('g','s','w',' '), HB_TAG('A','L','S',' ')}, /* Alsatian */ + {HB_TAG('g','u','a',' '), HB_TAG_NONE }, /* Shiki != Guarani */ +/*{HB_TAG('g','u','c',' '), HB_TAG('G','U','C',' ')},*/ /* Wayuu */ +/*{HB_TAG('g','u','f',' '), HB_TAG('G','U','F',' ')},*/ /* Gupapuyngu */ + {HB_TAG('g','u','g',' '), HB_TAG('G','U','A',' ')}, /* Paraguayan Guaraní -> Guarani */ + {HB_TAG('g','u','i',' '), HB_TAG('G','U','A',' ')}, /* Eastern Bolivian Guaraní -> Guarani */ + {HB_TAG('g','u','k',' '), HB_TAG('G','M','Z',' ')}, /* Gumuz */ + {HB_TAG('g','u','l',' '), HB_TAG('C','P','P',' ')}, /* Sea Island Creole English -> Creoles */ + {HB_TAG('g','u','n',' '), HB_TAG('G','U','A',' ')}, /* Mbyá Guaraní -> Guarani */ +/*{HB_TAG('g','u','z',' '), HB_TAG('G','U','Z',' ')},*/ /* Gusii */ + {HB_TAG('g','w','i',' '), HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */ + {HB_TAG('g','y','n',' '), HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */ + {HB_TAG('h','a','a',' '), HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */ + {HB_TAG('h','a','e',' '), HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */ + {HB_TAG('h','a','i',' '), HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */ + {HB_TAG('h','a','k',' '), HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */ + {HB_TAG('h','a','l',' '), HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */ + {HB_TAG('h','a','r',' '), HB_TAG('H','R','I',' ')}, /* Harari */ +/*{HB_TAG('h','a','w',' '), HB_TAG('H','A','W',' ')},*/ /* Hawaiian */ + {HB_TAG('h','a','x',' '), HB_TAG('H','A','I','0')}, /* Southern Haida -> Haida */ +/*{HB_TAG('h','a','y',' '), HB_TAG('H','A','Y',' ')},*/ /* Haya */ +/*{HB_TAG('h','a','z',' '), HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */ + {HB_TAG('h','b','n',' '), HB_TAG_NONE }, /* Heiban != Hammer-Banna */ + {HB_TAG('h','c','a',' '), HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */ + {HB_TAG('h','d','n',' '), HB_TAG('H','A','I','0')}, /* Northern Haida -> Haida */ + {HB_TAG('h','e','a',' '), HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */ +/*{HB_TAG('h','e','i',' '), HB_TAG('H','E','I',' ')},*/ /* Heiltsuk */ +/*{HB_TAG('h','i','l',' '), HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */ + {HB_TAG('h','j','i',' '), HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */ + {HB_TAG('h','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */ + {HB_TAG('h','m','a',' '), HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */ + {HB_TAG('h','m','c',' '), HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */ + {HB_TAG('h','m','d',' '), HB_TAG('H','M','D',' ')}, /* Large Flowery Miao -> A-Hmao */ + {HB_TAG('h','m','d',' '), HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */ + {HB_TAG('h','m','e',' '), HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */ + {HB_TAG('h','m','g',' '), HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */ + {HB_TAG('h','m','h',' '), HB_TAG('H','M','N',' ')}, /* Southwestern Huishui Hmong -> Hmong */ + {HB_TAG('h','m','i',' '), HB_TAG('H','M','N',' ')}, /* Northern Huishui Hmong -> Hmong */ + {HB_TAG('h','m','j',' '), HB_TAG('H','M','N',' ')}, /* Ge -> Hmong */ + {HB_TAG('h','m','l',' '), HB_TAG('H','M','N',' ')}, /* Luopohe Hmong -> Hmong */ + {HB_TAG('h','m','m',' '), HB_TAG('H','M','N',' ')}, /* Central Mashan Hmong -> Hmong */ +/*{HB_TAG('h','m','n',' '), HB_TAG('H','M','N',' ')},*/ /* Hmong [macrolanguage] */ + {HB_TAG('h','m','p',' '), HB_TAG('H','M','N',' ')}, /* Northern Mashan Hmong -> Hmong */ + {HB_TAG('h','m','q',' '), HB_TAG('H','M','N',' ')}, /* Eastern Qiandong Miao -> Hmong */ + {HB_TAG('h','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Hmar -> Chin */ + {HB_TAG('h','m','s',' '), HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */ + {HB_TAG('h','m','w',' '), HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */ + {HB_TAG('h','m','y',' '), HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */ + {HB_TAG('h','m','z',' '), HB_TAG('H','M','Z',' ')}, /* Hmong Shua -> Hmong Shuat */ + {HB_TAG('h','m','z',' '), HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */ +/*{HB_TAG('h','n','d',' '), HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */ + {HB_TAG('h','n','e',' '), HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */ + {HB_TAG('h','n','j',' '), HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */ + {HB_TAG('h','n','o',' '), HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */ + {HB_TAG('h','o','c',' '), HB_TAG('H','O',' ',' ')}, /* Ho */ + {HB_TAG('h','o','i',' '), HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */ + {HB_TAG('h','o','j',' '), HB_TAG('H','A','R',' ')}, /* Hadothi -> Harauti */ + {HB_TAG('h','o','j',' '), HB_TAG('R','A','J',' ')}, /* Hadothi -> Rajasthani */ + {HB_TAG('h','r','a',' '), HB_TAG('Q','I','N',' ')}, /* Hrangkhol -> Chin */ + {HB_TAG('h','r','m',' '), HB_TAG('H','M','N',' ')}, /* Horned Miao -> Hmong */ + {HB_TAG('h','s','b',' '), HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ + {HB_TAG('h','s','n',' '), HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese, Simplified */ + {HB_TAG('h','u','j',' '), HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */ + {HB_TAG('h','u','p',' '), HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */ + {HB_TAG('h','u','s',' '), HB_TAG('M','Y','N',' ')}, /* Huastec -> Mayan */ + {HB_TAG('h','w','c',' '), HB_TAG('C','P','P',' ')}, /* Hawai'i Creole English -> Creoles */ + {HB_TAG('h','y','w',' '), HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */ +/*{HB_TAG('i','b','a',' '), HB_TAG('I','B','A',' ')},*/ /* Iban */ +/*{HB_TAG('i','b','b',' '), HB_TAG('I','B','B',' ')},*/ /* Ibibio */ + {HB_TAG('i','b','y',' '), HB_TAG('I','J','O',' ')}, /* Ibani -> Ijo */ + {HB_TAG('i','c','r',' '), HB_TAG('C','P','P',' ')}, /* Islander Creole English -> Creoles */ + {HB_TAG('i','d','a',' '), HB_TAG('L','U','H',' ')}, /* Idakho-Isukha-Tiriki -> Luyia */ + {HB_TAG('i','d','b',' '), HB_TAG('C','P','P',' ')}, /* Indo-Portuguese -> Creoles */ + {HB_TAG('i','g','b',' '), HB_TAG('E','B','I',' ')}, /* Ebira */ + {HB_TAG('i','h','b',' '), HB_TAG('C','P','P',' ')}, /* Iha Based Pidgin -> Creoles */ + {HB_TAG('i','j','c',' '), HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */ + {HB_TAG('i','j','e',' '), HB_TAG('I','J','O',' ')}, /* Biseni -> Ijo */ + {HB_TAG('i','j','n',' '), HB_TAG('I','J','O',' ')}, /* Kalabari -> Ijo */ +/*{HB_TAG('i','j','o',' '), HB_TAG('I','J','O',' ')},*/ /* Ijo [collection] */ + {HB_TAG('i','j','s',' '), HB_TAG('I','J','O',' ')}, /* Southeast Ijo -> Ijo */ + {HB_TAG('i','k','e',' '), HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */ + {HB_TAG('i','k','e',' '), HB_TAG('I','N','U','K')}, /* Eastern Canadian Inuktitut -> Nunavik Inuktitut */ + {HB_TAG('i','k','t',' '), HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */ +/*{HB_TAG('i','l','o',' '), HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */ + {HB_TAG('i','n','g',' '), HB_TAG('A','T','H',' ')}, /* Degexit'an -> Athapaskan */ + {HB_TAG('i','n','h',' '), HB_TAG('I','N','G',' ')}, /* Ingush */ + {HB_TAG('i','r','i',' '), HB_TAG_NONE }, /* Rigwe != Irish */ +/*{HB_TAG('i','r','u',' '), HB_TAG('I','R','U',' ')},*/ /* Irula */ + {HB_TAG('i','s','m',' '), HB_TAG_NONE }, /* Masimasi != Inari Sami */ + {HB_TAG('i','t','z',' '), HB_TAG('M','Y','N',' ')}, /* Itzá -> Mayan */ + {HB_TAG('i','x','l',' '), HB_TAG('M','Y','N',' ')}, /* Ixil -> Mayan */ + {HB_TAG('j','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Popti' -> Mayan */ + {HB_TAG('j','a','k',' '), HB_TAG('M','L','Y',' ')}, /* Jakun -> Malay */ + {HB_TAG('j','a','m',' '), HB_TAG('J','A','M',' ')}, /* Jamaican Creole English -> Jamaican Creole */ + {HB_TAG('j','a','m',' '), HB_TAG('C','P','P',' ')}, /* Jamaican Creole English -> Creoles */ + {HB_TAG('j','a','n',' '), HB_TAG_NONE }, /* Jandai != Japanese */ + {HB_TAG('j','a','x',' '), HB_TAG('M','L','Y',' ')}, /* Jambi Malay -> Malay */ + {HB_TAG('j','b','e',' '), HB_TAG('B','B','R',' ')}, /* Judeo-Berber -> Berber */ + {HB_TAG('j','b','n',' '), HB_TAG('B','B','R',' ')}, /* Nafusi -> Berber */ +/*{HB_TAG('j','b','o',' '), HB_TAG('J','B','O',' ')},*/ /* Lojban */ +/*{HB_TAG('j','c','t',' '), HB_TAG('J','C','T',' ')},*/ /* Krymchak */ + {HB_TAG('j','g','o',' '), HB_TAG('B','M','L',' ')}, /* Ngomba -> Bamileke */ + {HB_TAG('j','i','i',' '), HB_TAG_NONE }, /* Jiiddu != Yiddish */ + {HB_TAG('j','k','m',' '), HB_TAG('K','R','N',' ')}, /* Mobwa Karen -> Karen */ + {HB_TAG('j','k','p',' '), HB_TAG('K','R','N',' ')}, /* Paku Karen -> Karen */ + {HB_TAG('j','u','d',' '), HB_TAG_NONE }, /* Worodougou != Ladino */ + {HB_TAG('j','u','l',' '), HB_TAG_NONE }, /* Jirel != Jula */ + {HB_TAG('j','v','d',' '), HB_TAG('C','P','P',' ')}, /* Javindo -> Creoles */ + {HB_TAG('k','a','a',' '), HB_TAG('K','R','K',' ')}, /* Karakalpak */ + {HB_TAG('k','a','b',' '), HB_TAG('K','A','B','0')}, /* Kabyle */ + {HB_TAG('k','a','b',' '), HB_TAG('B','B','R',' ')}, /* Kabyle -> Berber */ + {HB_TAG('k','a','c',' '), HB_TAG_NONE }, /* Kachin != Kachchi */ + {HB_TAG('k','a','m',' '), HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ + {HB_TAG('k','a','r',' '), HB_TAG('K','R','N',' ')}, /* Karen [collection] */ +/*{HB_TAG('k','a','w',' '), HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */ + {HB_TAG('k','b','d',' '), HB_TAG('K','A','B',' ')}, /* Kabardian */ + {HB_TAG('k','b','y',' '), HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */ + {HB_TAG('k','c','a',' '), HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */ + {HB_TAG('k','c','a',' '), HB_TAG('K','H','S',' ')}, /* Khanty -> Khanty-Shurishkar */ + {HB_TAG('k','c','a',' '), HB_TAG('K','H','V',' ')}, /* Khanty -> Khanty-Vakhi */ + {HB_TAG('k','c','n',' '), HB_TAG('C','P','P',' ')}, /* Nubi -> Creoles */ +/*{HB_TAG('k','d','e',' '), HB_TAG('K','D','E',' ')},*/ /* Makonde */ + {HB_TAG('k','d','r',' '), HB_TAG('K','R','M',' ')}, /* Karaim */ + {HB_TAG('k','d','t',' '), HB_TAG('K','U','Y',' ')}, /* Kuy */ + {HB_TAG('k','e','a',' '), HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */ + {HB_TAG('k','e','a',' '), HB_TAG('C','P','P',' ')}, /* Kabuverdianu -> Creoles */ + {HB_TAG('k','e','b',' '), HB_TAG_NONE }, /* Kélé != Kebena */ + {HB_TAG('k','e','k',' '), HB_TAG('K','E','K',' ')}, /* Kekchi */ + {HB_TAG('k','e','k',' '), HB_TAG('M','Y','N',' ')}, /* Kekchí -> Mayan */ + {HB_TAG('k','e','x',' '), HB_TAG('K','K','N',' ')}, /* Kukna -> Kokni */ + {HB_TAG('k','f','a',' '), HB_TAG('K','O','D',' ')}, /* Kodava -> Kodagu */ + {HB_TAG('k','f','r',' '), HB_TAG('K','A','C',' ')}, /* Kachhi -> Kachchi */ + {HB_TAG('k','f','x',' '), HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */ + {HB_TAG('k','f','y',' '), HB_TAG('K','M','N',' ')}, /* Kumaoni */ + {HB_TAG('k','g','e',' '), HB_TAG_NONE }, /* Komering != Khutsuri Georgian */ + {HB_TAG('k','h','a',' '), HB_TAG('K','S','I',' ')}, /* Khasi */ + {HB_TAG('k','h','b',' '), HB_TAG('X','B','D',' ')}, /* Lü */ + {HB_TAG('k','h','k',' '), HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */ + {HB_TAG('k','h','n',' '), HB_TAG_NONE }, /* Khandesi != Khamti Shan (Microsoft fonts) */ + {HB_TAG('k','h','s',' '), HB_TAG_NONE }, /* Kasua != Khanty-Shurishkar */ + {HB_TAG('k','h','t',' '), HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan */ + {HB_TAG('k','h','t',' '), HB_TAG('K','H','N',' ')}, /* Khamti -> Khamti Shan (Microsoft fonts) */ + {HB_TAG('k','h','v',' '), HB_TAG_NONE }, /* Khvarshi != Khanty-Vakhi */ +/*{HB_TAG('k','h','w',' '), HB_TAG('K','H','W',' ')},*/ /* Khowar */ + {HB_TAG('k','i','s',' '), HB_TAG_NONE }, /* Kis != Kisii */ + {HB_TAG('k','i','u',' '), HB_TAG('K','I','U',' ')}, /* Kirmanjki */ + {HB_TAG('k','i','u',' '), HB_TAG('Z','Z','A',' ')}, /* Kirmanjki -> Zazaki */ + {HB_TAG('k','j','b',' '), HB_TAG('M','Y','N',' ')}, /* Q'anjob'al -> Mayan */ +/*{HB_TAG('k','j','d',' '), HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */ + {HB_TAG('k','j','h',' '), HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */ + {HB_TAG('k','j','p',' '), HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ + {HB_TAG('k','j','p',' '), HB_TAG('K','R','N',' ')}, /* Pwo Eastern Karen -> Karen */ + {HB_TAG('k','j','t',' '), HB_TAG('K','R','N',' ')}, /* Phrae Pwo Karen -> Karen */ +/*{HB_TAG('k','j','z',' '), HB_TAG('K','J','Z',' ')},*/ /* Bumthangkha */ + {HB_TAG('k','k','n',' '), HB_TAG_NONE }, /* Kon Keu != Kokni */ + {HB_TAG('k','k','z',' '), HB_TAG('A','T','H',' ')}, /* Kaska -> Athapaskan */ + {HB_TAG('k','l','m',' '), HB_TAG_NONE }, /* Migum != Kalmyk */ + {HB_TAG('k','l','n',' '), HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */ + {HB_TAG('k','m','b',' '), HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */ + {HB_TAG('k','m','n',' '), HB_TAG_NONE }, /* Awtuw != Kumaoni */ + {HB_TAG('k','m','o',' '), HB_TAG_NONE }, /* Kwoma != Komo */ + {HB_TAG('k','m','r',' '), HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */ + {HB_TAG('k','m','s',' '), HB_TAG_NONE }, /* Kamasau != Komso */ + {HB_TAG('k','m','v',' '), HB_TAG('C','P','P',' ')}, /* Karipúna Creole French -> Creoles */ + {HB_TAG('k','m','w',' '), HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ +/*{HB_TAG('k','m','z',' '), HB_TAG('K','M','Z',' ')},*/ /* Khorasani Turkish -> Khorasani Turkic */ + {HB_TAG('k','n','c',' '), HB_TAG('K','N','R',' ')}, /* Central Kanuri -> Kanuri */ + {HB_TAG('k','n','g',' '), HB_TAG('K','O','N','0')}, /* Koongo -> Kongo */ + {HB_TAG('k','n','j',' '), HB_TAG('M','Y','N',' ')}, /* Western Kanjobal -> Mayan */ + {HB_TAG('k','n','n',' '), HB_TAG('K','O','K',' ')}, /* Konkani */ + {HB_TAG('k','n','r',' '), HB_TAG_NONE }, /* Kaningra != Kanuri */ + {HB_TAG('k','o','d',' '), HB_TAG_NONE }, /* Kodi != Kodagu */ + {HB_TAG('k','o','h',' '), HB_TAG_NONE }, /* Koyo != Korean Old Hangul */ + {HB_TAG('k','o','i',' '), HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ + {HB_TAG('k','o','i',' '), HB_TAG('K','O','M',' ')}, /* Komi-Permyak -> Komi */ +/*{HB_TAG('k','o','k',' '), HB_TAG('K','O','K',' ')},*/ /* Konkani [macrolanguage] */ + {HB_TAG('k','o','p',' '), HB_TAG_NONE }, /* Waube != Komi-Permyak */ +/*{HB_TAG('k','o','s',' '), HB_TAG('K','O','S',' ')},*/ /* Kosraean */ + {HB_TAG('k','o','y',' '), HB_TAG('A','T','H',' ')}, /* Koyukon -> Athapaskan */ + {HB_TAG('k','o','z',' '), HB_TAG_NONE }, /* Korak != Komi-Zyrian */ + {HB_TAG('k','p','e',' '), HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ + {HB_TAG('k','p','l',' '), HB_TAG_NONE }, /* Kpala != Kpelle */ + {HB_TAG('k','p','p',' '), HB_TAG('K','R','N',' ')}, /* Paku Karen (retired code) -> Karen */ + {HB_TAG('k','p','v',' '), HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ + {HB_TAG('k','p','v',' '), HB_TAG('K','O','M',' ')}, /* Komi-Zyrian -> Komi */ + {HB_TAG('k','p','y',' '), HB_TAG('K','Y','K',' ')}, /* Koryak */ + {HB_TAG('k','q','s',' '), HB_TAG('K','I','S',' ')}, /* Northern Kissi -> Kisii */ + {HB_TAG('k','q','y',' '), HB_TAG('K','R','T',' ')}, /* Koorete */ + {HB_TAG('k','r','c',' '), HB_TAG('K','A','R',' ')}, /* Karachay-Balkar -> Karachay */ + {HB_TAG('k','r','c',' '), HB_TAG('B','A','L',' ')}, /* Karachay-Balkar -> Balkar */ + {HB_TAG('k','r','i',' '), HB_TAG('K','R','I',' ')}, /* Krio */ + {HB_TAG('k','r','i',' '), HB_TAG('C','P','P',' ')}, /* Krio -> Creoles */ + {HB_TAG('k','r','k',' '), HB_TAG_NONE }, /* Kerek != Karakalpak */ +/*{HB_TAG('k','r','l',' '), HB_TAG('K','R','L',' ')},*/ /* Karelian */ + {HB_TAG('k','r','m',' '), HB_TAG_NONE }, /* Krim (retired code) != Karaim */ + {HB_TAG('k','r','n',' '), HB_TAG_NONE }, /* Sapo != Karen */ + {HB_TAG('k','r','t',' '), HB_TAG('K','N','R',' ')}, /* Tumari Kanuri -> Kanuri */ + {HB_TAG('k','r','u',' '), HB_TAG('K','U','U',' ')}, /* Kurukh */ + {HB_TAG('k','s','h',' '), HB_TAG('K','S','H','0')}, /* Kölsch -> Ripuarian */ + {HB_TAG('k','s','i',' '), HB_TAG_NONE }, /* Krisa != Khasi */ + {HB_TAG('k','s','m',' '), HB_TAG_NONE }, /* Kumba != Kildin Sami */ + {HB_TAG('k','s','s',' '), HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */ + {HB_TAG('k','s','w',' '), HB_TAG('K','S','W',' ')}, /* S’gaw Karen */ + {HB_TAG('k','s','w',' '), HB_TAG('K','R','N',' ')}, /* S'gaw Karen -> Karen */ + {HB_TAG('k','t','b',' '), HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */ + {HB_TAG('k','t','u',' '), HB_TAG('K','O','N',' ')}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ + {HB_TAG('k','t','w',' '), HB_TAG('A','T','H',' ')}, /* Kato -> Athapaskan */ + {HB_TAG('k','u','i',' '), HB_TAG_NONE }, /* Kuikúro-Kalapálo != Kui */ + {HB_TAG('k','u','l',' '), HB_TAG_NONE }, /* Kulere != Kulvi */ +/*{HB_TAG('k','u','m',' '), HB_TAG('K','U','M',' ')},*/ /* Kumyk */ + {HB_TAG('k','u','u',' '), HB_TAG('A','T','H',' ')}, /* Upper Kuskokwim -> Athapaskan */ + {HB_TAG('k','u','w',' '), HB_TAG('B','A','D','0')}, /* Kpagua -> Banda */ + {HB_TAG('k','u','y',' '), HB_TAG_NONE }, /* Kuuku-Ya'u != Kuy */ + {HB_TAG('k','v','b',' '), HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */ + {HB_TAG('k','v','l',' '), HB_TAG('K','R','N',' ')}, /* Kayaw -> Karen */ + {HB_TAG('k','v','q',' '), HB_TAG('K','R','N',' ')}, /* Geba Karen -> Karen */ + {HB_TAG('k','v','r',' '), HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */ + {HB_TAG('k','v','t',' '), HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */ + {HB_TAG('k','v','u',' '), HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */ + {HB_TAG('k','v','y',' '), HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */ +/*{HB_TAG('k','w','k',' '), HB_TAG('K','W','K',' ')},*/ /* Kwakiutl -> Kwakʼwala */ + {HB_TAG('k','w','w',' '), HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */ + {HB_TAG('k','w','y',' '), HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */ + {HB_TAG('k','x','c',' '), HB_TAG('K','M','S',' ')}, /* Konso -> Komso */ + {HB_TAG('k','x','d',' '), HB_TAG('M','L','Y',' ')}, /* Brunei -> Malay */ + {HB_TAG('k','x','f',' '), HB_TAG('K','R','N',' ')}, /* Manumanaw Karen -> Karen */ + {HB_TAG('k','x','k',' '), HB_TAG('K','R','N',' ')}, /* Zayein Karen -> Karen */ + {HB_TAG('k','x','l',' '), HB_TAG('K','U','U',' ')}, /* Nepali Kurux (retired code) -> Kurukh */ + {HB_TAG('k','x','u',' '), HB_TAG('K','U','I',' ')}, /* Kui (India) (retired code) */ + {HB_TAG('k','y','k',' '), HB_TAG_NONE }, /* Kamayo != Koryak */ + {HB_TAG('k','y','u',' '), HB_TAG('K','Y','U',' ')}, /* Western Kayah */ + {HB_TAG('k','y','u',' '), HB_TAG('K','R','N',' ')}, /* Western Kayah -> Karen */ + {HB_TAG('l','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Lacandon -> Mayan */ + {HB_TAG('l','a','d',' '), HB_TAG('J','U','D',' ')}, /* Ladino */ + {HB_TAG('l','a','h',' '), HB_TAG_NONE }, /* Lahnda [macrolanguage] != Lahuli */ + {HB_TAG('l','a','k',' '), HB_TAG_NONE }, /* Laka (Nigeria) (retired code) != Lak */ + {HB_TAG('l','a','m',' '), HB_TAG_NONE }, /* Lamba != Lambani */ + {HB_TAG('l','a','z',' '), HB_TAG_NONE }, /* Aribwatsa != Laz */ + {HB_TAG('l','b','e',' '), HB_TAG('L','A','K',' ')}, /* Lak */ + {HB_TAG('l','b','j',' '), HB_TAG('L','D','K',' ')}, /* Ladakhi */ + {HB_TAG('l','b','l',' '), HB_TAG('B','I','K',' ')}, /* Libon Bikol -> Bikol */ + {HB_TAG('l','c','e',' '), HB_TAG('M','L','Y',' ')}, /* Loncong -> Malay */ + {HB_TAG('l','c','f',' '), HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */ + {HB_TAG('l','d','i',' '), HB_TAG('K','O','N','0')}, /* Laari -> Kongo */ + {HB_TAG('l','d','k',' '), HB_TAG_NONE }, /* Leelau != Ladakhi */ +/*{HB_TAG('l','e','f',' '), HB_TAG('L','E','F',' ')},*/ /* Lelemi */ +/*{HB_TAG('l','e','z',' '), HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */ + {HB_TAG('l','i','f',' '), HB_TAG('L','M','B',' ')}, /* Limbu */ +/*{HB_TAG('l','i','j',' '), HB_TAG('L','I','J',' ')},*/ /* Ligurian */ + {HB_TAG('l','i','r',' '), HB_TAG('C','P','P',' ')}, /* Liberian English -> Creoles */ +/*{HB_TAG('l','i','s',' '), HB_TAG('L','I','S',' ')},*/ /* Lisu */ + {HB_TAG('l','i','w',' '), HB_TAG('M','L','Y',' ')}, /* Col -> Malay */ + {HB_TAG('l','i','y',' '), HB_TAG('B','A','D','0')}, /* Banda-Bambari -> Banda */ +/*{HB_TAG('l','j','p',' '), HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */ + {HB_TAG('l','k','b',' '), HB_TAG('L','U','H',' ')}, /* Kabras -> Luyia */ +/*{HB_TAG('l','k','i',' '), HB_TAG('L','K','I',' ')},*/ /* Laki */ + {HB_TAG('l','k','o',' '), HB_TAG('L','U','H',' ')}, /* Khayo -> Luyia */ + {HB_TAG('l','k','s',' '), HB_TAG('L','U','H',' ')}, /* Kisa -> Luyia */ + {HB_TAG('l','l','d',' '), HB_TAG('L','A','D',' ')}, /* Ladin */ + {HB_TAG('l','m','a',' '), HB_TAG_NONE }, /* East Limba != Low Mari */ + {HB_TAG('l','m','b',' '), HB_TAG_NONE }, /* Merei != Limbu */ + {HB_TAG('l','m','n',' '), HB_TAG('L','A','M',' ')}, /* Lambadi -> Lambani */ +/*{HB_TAG('l','m','o',' '), HB_TAG('L','M','O',' ')},*/ /* Lombard */ + {HB_TAG('l','m','w',' '), HB_TAG_NONE }, /* Lake Miwok != Lomwe */ + {HB_TAG('l','n','a',' '), HB_TAG('B','A','D','0')}, /* Langbashe -> Banda */ + {HB_TAG('l','n','l',' '), HB_TAG('B','A','D','0')}, /* South Central Banda -> Banda */ +/*{HB_TAG('l','o','m',' '), HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */ + {HB_TAG('l','o','u',' '), HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */ +/*{HB_TAG('l','p','o',' '), HB_TAG('L','P','O',' ')},*/ /* Lipo */ +/*{HB_TAG('l','r','c',' '), HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */ + {HB_TAG('l','r','i',' '), HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */ + {HB_TAG('l','r','m',' '), HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */ + {HB_TAG('l','r','t',' '), HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */ + {HB_TAG('l','s','b',' '), HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */ + {HB_TAG('l','s','m',' '), HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */ + {HB_TAG('l','t','g',' '), HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */ + {HB_TAG('l','t','h',' '), HB_TAG_NONE }, /* Thur != Lithuanian */ + {HB_TAG('l','t','o',' '), HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */ + {HB_TAG('l','t','s',' '), HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */ +/*{HB_TAG('l','u','a',' '), HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ +/*{HB_TAG('l','u','o',' '), HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */ + {HB_TAG('l','u','s',' '), HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */ + {HB_TAG('l','u','s',' '), HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */ + {HB_TAG('l','u','y',' '), HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */ + {HB_TAG('l','u','z',' '), HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */ + {HB_TAG('l','v','i',' '), HB_TAG_NONE }, /* Lavi != Latvian */ + {HB_TAG('l','v','s',' '), HB_TAG('L','V','I',' ')}, /* Standard Latvian -> Latvian */ + {HB_TAG('l','w','g',' '), HB_TAG('L','U','H',' ')}, /* Wanga -> Luyia */ + {HB_TAG('l','z','h',' '), HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese, Traditional */ + {HB_TAG('l','z','z',' '), HB_TAG('L','A','Z',' ')}, /* Laz */ +/*{HB_TAG('m','a','d',' '), HB_TAG('M','A','D',' ')},*/ /* Madurese -> Madura */ +/*{HB_TAG('m','a','g',' '), HB_TAG('M','A','G',' ')},*/ /* Magahi */ + {HB_TAG('m','a','i',' '), HB_TAG('M','T','H',' ')}, /* Maithili */ + {HB_TAG('m','a','j',' '), HB_TAG_NONE }, /* Jalapa De Díaz Mazatec != Majang */ + {HB_TAG('m','a','k',' '), HB_TAG('M','K','R',' ')}, /* Makasar */ + {HB_TAG('m','a','m',' '), HB_TAG('M','A','M',' ')}, /* Mam */ + {HB_TAG('m','a','m',' '), HB_TAG('M','Y','N',' ')}, /* Mam -> Mayan */ + {HB_TAG('m','a','n',' '), HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */ + {HB_TAG('m','a','p',' '), HB_TAG_NONE }, /* Austronesian [collection] != Mapudungun */ + {HB_TAG('m','a','w',' '), HB_TAG_NONE }, /* Mampruli != Marwari */ + {HB_TAG('m','a','x',' '), HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */ + {HB_TAG('m','a','x',' '), HB_TAG('C','P','P',' ')}, /* North Moluccan Malay -> Creoles */ + {HB_TAG('m','b','f',' '), HB_TAG('C','P','P',' ')}, /* Baba Malay -> Creoles */ + {HB_TAG('m','b','n',' '), HB_TAG_NONE }, /* Macaguán != Mbundu */ +/*{HB_TAG('m','b','o',' '), HB_TAG('M','B','O',' ')},*/ /* Mbo (Cameroon) */ + {HB_TAG('m','c','h',' '), HB_TAG_NONE }, /* Maquiritari != Manchu */ + {HB_TAG('m','c','m',' '), HB_TAG('C','P','P',' ')}, /* Malaccan Creole Portuguese -> Creoles */ + {HB_TAG('m','c','r',' '), HB_TAG_NONE }, /* Menya != Moose Cree */ + {HB_TAG('m','c','t',' '), HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */ + {HB_TAG('m','d','e',' '), HB_TAG_NONE }, /* Maba (Chad) != Mende */ + {HB_TAG('m','d','f',' '), HB_TAG('M','O','K',' ')}, /* Moksha */ +/*{HB_TAG('m','d','r',' '), HB_TAG('M','D','R',' ')},*/ /* Mandar */ + {HB_TAG('m','d','y',' '), HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ + {HB_TAG('m','e','n',' '), HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ + {HB_TAG('m','e','o',' '), HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */ +/*{HB_TAG('m','e','r',' '), HB_TAG('M','E','R',' ')},*/ /* Meru */ + {HB_TAG('m','f','a',' '), HB_TAG('M','F','A',' ')}, /* Pattani Malay */ + {HB_TAG('m','f','a',' '), HB_TAG('M','L','Y',' ')}, /* Pattani Malay -> Malay */ + {HB_TAG('m','f','b',' '), HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */ + {HB_TAG('m','f','e',' '), HB_TAG('M','F','E',' ')}, /* Morisyen */ + {HB_TAG('m','f','e',' '), HB_TAG('C','P','P',' ')}, /* Morisyen -> Creoles */ + {HB_TAG('m','f','p',' '), HB_TAG('C','P','P',' ')}, /* Makassar Malay -> Creoles */ + {HB_TAG('m','h','c',' '), HB_TAG('M','Y','N',' ')}, /* Mocho -> Mayan */ + {HB_TAG('m','h','r',' '), HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */ + {HB_TAG('m','h','v',' '), HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */ + {HB_TAG('m','i','n',' '), HB_TAG('M','I','N',' ')}, /* Minangkabau */ + {HB_TAG('m','i','n',' '), HB_TAG('M','L','Y',' ')}, /* Minangkabau -> Malay */ + {HB_TAG('m','i','z',' '), HB_TAG_NONE }, /* Coatzospan Mixtec != Mizo */ + {HB_TAG('m','k','n',' '), HB_TAG('C','P','P',' ')}, /* Kupang Malay -> Creoles */ + {HB_TAG('m','k','r',' '), HB_TAG_NONE }, /* Malas != Makasar */ + {HB_TAG('m','k','u',' '), HB_TAG('M','N','K',' ')}, /* Konyanka Maninka -> Maninka */ +/*{HB_TAG('m','k','w',' '), HB_TAG('M','K','W',' ')},*/ /* Kituba (Congo) */ + {HB_TAG('m','l','e',' '), HB_TAG_NONE }, /* Manambu != Male */ + {HB_TAG('m','l','n',' '), HB_TAG_NONE }, /* Malango != Malinke */ + {HB_TAG('m','l','q',' '), HB_TAG('M','L','N',' ')}, /* Western Maninkakan -> Malinke */ + {HB_TAG('m','l','q',' '), HB_TAG('M','N','K',' ')}, /* Western Maninkakan -> Maninka */ + {HB_TAG('m','l','r',' '), HB_TAG_NONE }, /* Vame != Malayalam Reformed */ + {HB_TAG('m','m','r',' '), HB_TAG('H','M','N',' ')}, /* Western Xiangxi Miao -> Hmong */ + {HB_TAG('m','n','c',' '), HB_TAG('M','C','H',' ')}, /* Manchu */ + {HB_TAG('m','n','d',' '), HB_TAG_NONE }, /* Mondé != Mandinka */ + {HB_TAG('m','n','g',' '), HB_TAG_NONE }, /* Eastern Mnong != Mongolian */ + {HB_TAG('m','n','h',' '), HB_TAG('B','A','D','0')}, /* Mono (Democratic Republic of Congo) -> Banda */ +/*{HB_TAG('m','n','i',' '), HB_TAG('M','N','I',' ')},*/ /* Manipuri */ + {HB_TAG('m','n','k',' '), HB_TAG('M','N','D',' ')}, /* Mandinka */ + {HB_TAG('m','n','k',' '), HB_TAG('M','N','K',' ')}, /* Mandinka -> Maninka */ + {HB_TAG('m','n','p',' '), HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese, Simplified */ + {HB_TAG('m','n','s',' '), HB_TAG('M','A','N',' ')}, /* Mansi */ + {HB_TAG('m','n','w',' '), HB_TAG('M','O','N',' ')}, /* Mon */ + {HB_TAG('m','n','w',' '), HB_TAG('M','O','N','T')}, /* Mon -> Thailand Mon */ + {HB_TAG('m','n','x',' '), HB_TAG_NONE }, /* Manikion != Manx */ + {HB_TAG('m','o','d',' '), HB_TAG('C','P','P',' ')}, /* Mobilian -> Creoles */ +/*{HB_TAG('m','o','h',' '), HB_TAG('M','O','H',' ')},*/ /* Mohawk */ + {HB_TAG('m','o','k',' '), HB_TAG_NONE }, /* Morori != Moksha */ + {HB_TAG('m','o','p',' '), HB_TAG('M','Y','N',' ')}, /* Mopán Maya -> Mayan */ + {HB_TAG('m','o','r',' '), HB_TAG_NONE }, /* Moro != Moroccan */ +/*{HB_TAG('m','o','s',' '), HB_TAG('M','O','S',' ')},*/ /* Mossi */ + {HB_TAG('m','p','e',' '), HB_TAG('M','A','J',' ')}, /* Majang */ + {HB_TAG('m','q','g',' '), HB_TAG('M','L','Y',' ')}, /* Kota Bangun Kutai Malay -> Malay */ + {HB_TAG('m','r','h',' '), HB_TAG('Q','I','N',' ')}, /* Mara Chin -> Chin */ + {HB_TAG('m','r','j',' '), HB_TAG('H','M','A',' ')}, /* Western Mari -> High Mari */ + {HB_TAG('m','s','c',' '), HB_TAG('M','N','K',' ')}, /* Sankaran Maninka -> Maninka */ + {HB_TAG('m','s','h',' '), HB_TAG('M','L','G',' ')}, /* Masikoro Malagasy -> Malagasy */ + {HB_TAG('m','s','i',' '), HB_TAG('M','L','Y',' ')}, /* Sabah Malay -> Malay */ + {HB_TAG('m','s','i',' '), HB_TAG('C','P','P',' ')}, /* Sabah Malay -> Creoles */ + {HB_TAG('m','t','h',' '), HB_TAG_NONE }, /* Munggui != Maithili */ + {HB_TAG('m','t','r',' '), HB_TAG('M','A','W',' ')}, /* Mewari -> Marwari */ + {HB_TAG('m','t','s',' '), HB_TAG_NONE }, /* Yora != Maltese */ + {HB_TAG('m','u','d',' '), HB_TAG('C','P','P',' ')}, /* Mednyj Aleut -> Creoles */ + {HB_TAG('m','u','i',' '), HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */ + {HB_TAG('m','u','n',' '), HB_TAG_NONE }, /* Munda [collection] != Mundari */ + {HB_TAG('m','u','p',' '), HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */ + {HB_TAG('m','u','q',' '), HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */ +/*{HB_TAG('m','u','s',' '), HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */ + {HB_TAG('m','v','b',' '), HB_TAG('A','T','H',' ')}, /* Mattole -> Athapaskan */ + {HB_TAG('m','v','e',' '), HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */ + {HB_TAG('m','v','f',' '), HB_TAG('M','N','G',' ')}, /* Peripheral Mongolian -> Mongolian */ + {HB_TAG('m','w','k',' '), HB_TAG('M','N','K',' ')}, /* Kita Maninkakan -> Maninka */ +/*{HB_TAG('m','w','l',' '), HB_TAG('M','W','L',' ')},*/ /* Mirandese */ + {HB_TAG('m','w','q',' '), HB_TAG('Q','I','N',' ')}, /* Mün Chin -> Chin */ + {HB_TAG('m','w','r',' '), HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ + {HB_TAG('m','w','w',' '), HB_TAG('M','W','W',' ')}, /* Hmong Daw */ + {HB_TAG('m','w','w',' '), HB_TAG('H','M','N',' ')}, /* Hmong Daw -> Hmong */ + {HB_TAG('m','y','m',' '), HB_TAG('M','E','N',' ')}, /* Me’en */ +/*{HB_TAG('m','y','n',' '), HB_TAG('M','Y','N',' ')},*/ /* Mayan [collection] */ + {HB_TAG('m','y','q',' '), HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */ + {HB_TAG('m','y','v',' '), HB_TAG('E','R','Z',' ')}, /* Erzya */ + {HB_TAG('m','z','b',' '), HB_TAG('B','B','R',' ')}, /* Tumzabt -> Berber */ +/*{HB_TAG('m','z','n',' '), HB_TAG('M','Z','N',' ')},*/ /* Mazanderani */ + {HB_TAG('m','z','s',' '), HB_TAG('C','P','P',' ')}, /* Macanese -> Creoles */ + {HB_TAG('n','a','g',' '), HB_TAG('N','A','G',' ')}, /* Naga Pidgin -> Naga-Assamese */ + {HB_TAG('n','a','g',' '), HB_TAG('C','P','P',' ')}, /* Naga Pidgin -> Creoles */ +/*{HB_TAG('n','a','h',' '), HB_TAG('N','A','H',' ')},*/ /* Nahuatl [collection] */ + {HB_TAG('n','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese, Simplified */ +/*{HB_TAG('n','a','p',' '), HB_TAG('N','A','P',' ')},*/ /* Neapolitan */ + {HB_TAG('n','a','s',' '), HB_TAG_NONE }, /* Naasioi != Naskapi */ + {HB_TAG('n','a','z',' '), HB_TAG('N','A','H',' ')}, /* Coatepec Nahuatl -> Nahuatl */ + {HB_TAG('n','c','h',' '), HB_TAG('N','A','H',' ')}, /* Central Huasteca Nahuatl -> Nahuatl */ + {HB_TAG('n','c','i',' '), HB_TAG('N','A','H',' ')}, /* Classical Nahuatl -> Nahuatl */ + {HB_TAG('n','c','j',' '), HB_TAG('N','A','H',' ')}, /* Northern Puebla Nahuatl -> Nahuatl */ + {HB_TAG('n','c','l',' '), HB_TAG('N','A','H',' ')}, /* Michoacán Nahuatl -> Nahuatl */ + {HB_TAG('n','c','r',' '), HB_TAG_NONE }, /* Ncane != N-Cree */ + {HB_TAG('n','c','x',' '), HB_TAG('N','A','H',' ')}, /* Central Puebla Nahuatl -> Nahuatl */ + {HB_TAG('n','d','b',' '), HB_TAG_NONE }, /* Kenswei Nsei != Ndebele */ +/*{HB_TAG('n','d','c',' '), HB_TAG('N','D','C',' ')},*/ /* Ndau */ + {HB_TAG('n','d','g',' '), HB_TAG_NONE }, /* Ndengereko != Ndonga */ +/*{HB_TAG('n','d','s',' '), HB_TAG('N','D','S',' ')},*/ /* Low Saxon */ + {HB_TAG('n','e','f',' '), HB_TAG('C','P','P',' ')}, /* Nefamese -> Creoles */ +/*{HB_TAG('n','e','w',' '), HB_TAG('N','E','W',' ')},*/ /* Newari */ +/*{HB_TAG('n','g','a',' '), HB_TAG('N','G','A',' ')},*/ /* Ngbaka */ + {HB_TAG('n','g','l',' '), HB_TAG('L','M','W',' ')}, /* Lomwe */ + {HB_TAG('n','g','m',' '), HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */ + {HB_TAG('n','g','o',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */ + {HB_TAG('n','g','r',' '), HB_TAG_NONE }, /* Engdewu != Nagari */ + {HB_TAG('n','g','u',' '), HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */ + {HB_TAG('n','h','c',' '), HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */ + {HB_TAG('n','h','d',' '), HB_TAG('G','U','A',' ')}, /* Chiripá -> Guarani */ + {HB_TAG('n','h','e',' '), HB_TAG('N','A','H',' ')}, /* Eastern Huasteca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','g',' '), HB_TAG('N','A','H',' ')}, /* Tetelcingo Nahuatl -> Nahuatl */ + {HB_TAG('n','h','i',' '), HB_TAG('N','A','H',' ')}, /* Zacatlán-Ahuacatlán-Tepetzintla Nahuatl -> Nahuatl */ + {HB_TAG('n','h','k',' '), HB_TAG('N','A','H',' ')}, /* Isthmus-Cosoleacaque Nahuatl -> Nahuatl */ + {HB_TAG('n','h','m',' '), HB_TAG('N','A','H',' ')}, /* Morelos Nahuatl -> Nahuatl */ + {HB_TAG('n','h','n',' '), HB_TAG('N','A','H',' ')}, /* Central Nahuatl -> Nahuatl */ + {HB_TAG('n','h','p',' '), HB_TAG('N','A','H',' ')}, /* Isthmus-Pajapan Nahuatl -> Nahuatl */ + {HB_TAG('n','h','q',' '), HB_TAG('N','A','H',' ')}, /* Huaxcaleca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','t',' '), HB_TAG('N','A','H',' ')}, /* Ometepec Nahuatl -> Nahuatl */ + {HB_TAG('n','h','v',' '), HB_TAG('N','A','H',' ')}, /* Temascaltepec Nahuatl -> Nahuatl */ + {HB_TAG('n','h','w',' '), HB_TAG('N','A','H',' ')}, /* Western Huasteca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','x',' '), HB_TAG('N','A','H',' ')}, /* Isthmus-Mecayapan Nahuatl -> Nahuatl */ + {HB_TAG('n','h','y',' '), HB_TAG('N','A','H',' ')}, /* Northern Oaxaca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','z',' '), HB_TAG('N','A','H',' ')}, /* Santa María La Alta Nahuatl -> Nahuatl */ + {HB_TAG('n','i','q',' '), HB_TAG('K','A','L',' ')}, /* Nandi -> Kalenjin */ + {HB_TAG('n','i','s',' '), HB_TAG_NONE }, /* Nimi != Nisi */ +/*{HB_TAG('n','i','u',' '), HB_TAG('N','I','U',' ')},*/ /* Niuean */ + {HB_TAG('n','i','v',' '), HB_TAG('G','I','L',' ')}, /* Gilyak */ + {HB_TAG('n','j','t',' '), HB_TAG('C','P','P',' ')}, /* Ndyuka-Trio Pidgin -> Creoles */ + {HB_TAG('n','j','z',' '), HB_TAG('N','I','S',' ')}, /* Nyishi -> Nisi */ + {HB_TAG('n','k','o',' '), HB_TAG_NONE }, /* Nkonya != N’Ko */ + {HB_TAG('n','k','x',' '), HB_TAG('I','J','O',' ')}, /* Nkoroo -> Ijo */ + {HB_TAG('n','l','a',' '), HB_TAG('B','M','L',' ')}, /* Ngombale -> Bamileke */ + {HB_TAG('n','l','e',' '), HB_TAG('L','U','H',' ')}, /* East Nyala -> Luyia */ + {HB_TAG('n','l','n',' '), HB_TAG('N','A','H',' ')}, /* Durango Nahuatl (retired code) -> Nahuatl */ + {HB_TAG('n','l','v',' '), HB_TAG('N','A','H',' ')}, /* Orizaba Nahuatl -> Nahuatl */ + {HB_TAG('n','n','h',' '), HB_TAG('B','M','L',' ')}, /* Ngiemboon -> Bamileke */ + {HB_TAG('n','n','z',' '), HB_TAG('B','M','L',' ')}, /* Nda'nda' -> Bamileke */ + {HB_TAG('n','o','d',' '), HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */ +/*{HB_TAG('n','o','e',' '), HB_TAG('N','O','E',' ')},*/ /* Nimadi */ +/*{HB_TAG('n','o','g',' '), HB_TAG('N','O','G',' ')},*/ /* Nogai */ +/*{HB_TAG('n','o','v',' '), HB_TAG('N','O','V',' ')},*/ /* Novial */ + {HB_TAG('n','p','i',' '), HB_TAG('N','E','P',' ')}, /* Nepali */ + {HB_TAG('n','p','l',' '), HB_TAG('N','A','H',' ')}, /* Southeastern Puebla Nahuatl -> Nahuatl */ + {HB_TAG('n','q','o',' '), HB_TAG('N','K','O',' ')}, /* N’Ko */ + {HB_TAG('n','s','k',' '), HB_TAG('N','A','S',' ')}, /* Naskapi */ + {HB_TAG('n','s','m',' '), HB_TAG_NONE }, /* Sumi Naga != Northern Sami */ +/*{HB_TAG('n','s','o',' '), HB_TAG('N','S','O',' ')},*/ /* Northern Sotho */ + {HB_TAG('n','s','u',' '), HB_TAG('N','A','H',' ')}, /* Sierra Negra Nahuatl -> Nahuatl */ + {HB_TAG('n','t','o',' '), HB_TAG_NONE }, /* Ntomba != Esperanto */ + {HB_TAG('n','u','e',' '), HB_TAG('B','A','D','0')}, /* Ngundu -> Banda */ + {HB_TAG('n','u','u',' '), HB_TAG('B','A','D','0')}, /* Ngbundu -> Banda */ + {HB_TAG('n','u','z',' '), HB_TAG('N','A','H',' ')}, /* Tlamacazapa Nahuatl -> Nahuatl */ + {HB_TAG('n','w','e',' '), HB_TAG('B','M','L',' ')}, /* Ngwe -> Bamileke */ + {HB_TAG('n','y','d',' '), HB_TAG('L','U','H',' ')}, /* Nyore -> Luyia */ +/*{HB_TAG('n','y','m',' '), HB_TAG('N','Y','M',' ')},*/ /* Nyamwezi */ + {HB_TAG('n','y','n',' '), HB_TAG('N','K','L',' ')}, /* Nyankole */ +/*{HB_TAG('n','z','a',' '), HB_TAG('N','Z','A',' ')},*/ /* Tigon Mbembe -> Mbembe Tigon */ +/*{HB_TAG('o','j','b',' '), HB_TAG('O','J','B',' ')},*/ /* Northwestern Ojibwa -> Ojibway */ + {HB_TAG('o','j','c',' '), HB_TAG('O','J','B',' ')}, /* Central Ojibwa -> Ojibway */ + {HB_TAG('o','j','g',' '), HB_TAG('O','J','B',' ')}, /* Eastern Ojibwa -> Ojibway */ + {HB_TAG('o','j','s',' '), HB_TAG('O','C','R',' ')}, /* Severn Ojibwa -> Oji-Cree */ + {HB_TAG('o','j','s',' '), HB_TAG('O','J','B',' ')}, /* Severn Ojibwa -> Ojibway */ + {HB_TAG('o','j','w',' '), HB_TAG('O','J','B',' ')}, /* Western Ojibwa -> Ojibway */ + {HB_TAG('o','k','d',' '), HB_TAG('I','J','O',' ')}, /* Okodia -> Ijo */ + {HB_TAG('o','k','i',' '), HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */ + {HB_TAG('o','k','m',' '), HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ + {HB_TAG('o','k','r',' '), HB_TAG('I','J','O',' ')}, /* Kirike -> Ijo */ + {HB_TAG('o','n','x',' '), HB_TAG('C','P','P',' ')}, /* Onin Based Pidgin -> Creoles */ + {HB_TAG('o','o','r',' '), HB_TAG('C','P','P',' ')}, /* Oorlams -> Creoles */ + {HB_TAG('o','r','c',' '), HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */ + {HB_TAG('o','r','n',' '), HB_TAG('M','L','Y',' ')}, /* Orang Kanaq -> Malay */ + {HB_TAG('o','r','o',' '), HB_TAG_NONE }, /* Orokolo != Oromo */ + {HB_TAG('o','r','r',' '), HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */ + {HB_TAG('o','r','s',' '), HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */ + {HB_TAG('o','r','y',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */ + {HB_TAG('o','t','w',' '), HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */ + {HB_TAG('o','u','a',' '), HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */ + {HB_TAG('p','a','a',' '), HB_TAG_NONE }, /* Papuan [collection] != Palestinian Aramaic */ +/*{HB_TAG('p','a','g',' '), HB_TAG('P','A','G',' ')},*/ /* Pangasinan */ + {HB_TAG('p','a','l',' '), HB_TAG_NONE }, /* Pahlavi != Pali */ +/*{HB_TAG('p','a','m',' '), HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */ + {HB_TAG('p','a','p',' '), HB_TAG('P','A','P','0')}, /* Papiamento -> Papiamentu */ + {HB_TAG('p','a','p',' '), HB_TAG('C','P','P',' ')}, /* Papiamento -> Creoles */ + {HB_TAG('p','a','s',' '), HB_TAG_NONE }, /* Papasena != Pashto */ +/*{HB_TAG('p','a','u',' '), HB_TAG('P','A','U',' ')},*/ /* Palauan */ + {HB_TAG('p','b','t',' '), HB_TAG('P','A','S',' ')}, /* Southern Pashto -> Pashto */ + {HB_TAG('p','b','u',' '), HB_TAG('P','A','S',' ')}, /* Northern Pashto -> Pashto */ +/*{HB_TAG('p','c','c',' '), HB_TAG('P','C','C',' ')},*/ /* Bouyei */ +/*{HB_TAG('p','c','d',' '), HB_TAG('P','C','D',' ')},*/ /* Picard */ + {HB_TAG('p','c','e',' '), HB_TAG('P','L','G',' ')}, /* Ruching Palaung -> Palaung */ + {HB_TAG('p','c','k',' '), HB_TAG('Q','I','N',' ')}, /* Paite Chin -> Chin */ + {HB_TAG('p','c','m',' '), HB_TAG('C','P','P',' ')}, /* Nigerian Pidgin -> Creoles */ +/*{HB_TAG('p','d','c',' '), HB_TAG('P','D','C',' ')},*/ /* Pennsylvania German */ + {HB_TAG('p','d','u',' '), HB_TAG('K','R','N',' ')}, /* Kayan -> Karen */ + {HB_TAG('p','e','a',' '), HB_TAG('C','P','P',' ')}, /* Peranakan Indonesian -> Creoles */ + {HB_TAG('p','e','l',' '), HB_TAG('M','L','Y',' ')}, /* Pekal -> Malay */ + {HB_TAG('p','e','s',' '), HB_TAG('F','A','R',' ')}, /* Iranian Persian -> Persian */ + {HB_TAG('p','e','y',' '), HB_TAG('C','P','P',' ')}, /* Petjo -> Creoles */ + {HB_TAG('p','g','a',' '), HB_TAG('A','R','A',' ')}, /* Sudanese Creole Arabic -> Arabic */ + {HB_TAG('p','g','a',' '), HB_TAG('C','P','P',' ')}, /* Sudanese Creole Arabic -> Creoles */ +/*{HB_TAG('p','h','k',' '), HB_TAG('P','H','K',' ')},*/ /* Phake */ + {HB_TAG('p','i','h',' '), HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk -> Norfolk */ + {HB_TAG('p','i','h',' '), HB_TAG('C','P','P',' ')}, /* Pitcairn-Norfolk -> Creoles */ + {HB_TAG('p','i','l',' '), HB_TAG_NONE }, /* Yom != Filipino */ + {HB_TAG('p','i','s',' '), HB_TAG('C','P','P',' ')}, /* Pijin -> Creoles */ + {HB_TAG('p','k','h',' '), HB_TAG('Q','I','N',' ')}, /* Pankhu -> Chin */ + {HB_TAG('p','k','o',' '), HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */ + {HB_TAG('p','l','g',' '), HB_TAG_NONE }, /* Pilagá != Palaung */ + {HB_TAG('p','l','k',' '), HB_TAG_NONE }, /* Kohistani Shina != Polish */ + {HB_TAG('p','l','l',' '), HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */ + {HB_TAG('p','l','n',' '), HB_TAG('C','P','P',' ')}, /* Palenquero -> Creoles */ + {HB_TAG('p','l','p',' '), HB_TAG('P','A','P',' ')}, /* Palpa (retired code) */ + {HB_TAG('p','l','t',' '), HB_TAG('M','L','G',' ')}, /* Plateau Malagasy -> Malagasy */ + {HB_TAG('p','m','l',' '), HB_TAG('C','P','P',' ')}, /* Lingua Franca -> Creoles */ +/*{HB_TAG('p','m','s',' '), HB_TAG('P','M','S',' ')},*/ /* Piemontese */ + {HB_TAG('p','m','y',' '), HB_TAG('C','P','P',' ')}, /* Papuan Malay -> Creoles */ +/*{HB_TAG('p','n','b',' '), HB_TAG('P','N','B',' ')},*/ /* Western Panjabi */ + {HB_TAG('p','o','c',' '), HB_TAG('M','Y','N',' ')}, /* Poqomam -> Mayan */ + {HB_TAG('p','o','h',' '), HB_TAG('P','O','H',' ')}, /* Poqomchi' -> Pocomchi */ + {HB_TAG('p','o','h',' '), HB_TAG('M','Y','N',' ')}, /* Poqomchi' -> Mayan */ +/*{HB_TAG('p','o','n',' '), HB_TAG('P','O','N',' ')},*/ /* Pohnpeian */ + {HB_TAG('p','o','v',' '), HB_TAG('C','P','P',' ')}, /* Upper Guinea Crioulo -> Creoles */ + {HB_TAG('p','p','a',' '), HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */ + {HB_TAG('p','r','e',' '), HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */ +/*{HB_TAG('p','r','o',' '), HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */ + {HB_TAG('p','r','s',' '), HB_TAG('D','R','I',' ')}, /* Dari */ + {HB_TAG('p','r','s',' '), HB_TAG('F','A','R',' ')}, /* Dari -> Persian */ + {HB_TAG('p','s','e',' '), HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */ + {HB_TAG('p','s','t',' '), HB_TAG('P','A','S',' ')}, /* Central Pashto -> Pashto */ + {HB_TAG('p','u','b',' '), HB_TAG('Q','I','N',' ')}, /* Purum -> Chin */ + {HB_TAG('p','u','z',' '), HB_TAG('Q','I','N',' ')}, /* Purum Naga (retired code) -> Chin */ + {HB_TAG('p','w','o',' '), HB_TAG('P','W','O',' ')}, /* Pwo Western Karen -> Western Pwo Karen */ + {HB_TAG('p','w','o',' '), HB_TAG('K','R','N',' ')}, /* Pwo Western Karen -> Karen */ + {HB_TAG('p','w','w',' '), HB_TAG('K','R','N',' ')}, /* Pwo Northern Karen -> Karen */ + {HB_TAG('q','u','b',' '), HB_TAG('Q','W','H',' ')}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','b',' '), HB_TAG('Q','U','Z',' ')}, /* Huallaga Huánuco Quechua -> Quechua */ + {HB_TAG('q','u','c',' '), HB_TAG('Q','U','C',' ')}, /* K’iche’ */ + {HB_TAG('q','u','c',' '), HB_TAG('M','Y','N',' ')}, /* K'iche' -> Mayan */ + {HB_TAG('q','u','d',' '), HB_TAG('Q','V','I',' ')}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','d',' '), HB_TAG('Q','U','Z',' ')}, /* Calderón Highland Quichua -> Quechua */ + {HB_TAG('q','u','f',' '), HB_TAG('Q','U','Z',' ')}, /* Lambayeque Quechua -> Quechua */ + {HB_TAG('q','u','g',' '), HB_TAG('Q','V','I',' ')}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','g',' '), HB_TAG('Q','U','Z',' ')}, /* Chimborazo Highland Quichua -> Quechua */ + {HB_TAG('q','u','h',' '), HB_TAG('Q','U','H',' ')}, /* South Bolivian Quechua -> Quechua (Bolivia) */ + {HB_TAG('q','u','h',' '), HB_TAG('Q','U','Z',' ')}, /* South Bolivian Quechua -> Quechua */ + {HB_TAG('q','u','k',' '), HB_TAG('Q','U','Z',' ')}, /* Chachapoyas Quechua -> Quechua */ + {HB_TAG('q','u','l',' '), HB_TAG('Q','U','H',' ')}, /* North Bolivian Quechua -> Quechua (Bolivia) */ + {HB_TAG('q','u','l',' '), HB_TAG('Q','U','Z',' ')}, /* North Bolivian Quechua -> Quechua */ + {HB_TAG('q','u','m',' '), HB_TAG('M','Y','N',' ')}, /* Sipacapense -> Mayan */ + {HB_TAG('q','u','p',' '), HB_TAG('Q','V','I',' ')}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ + {HB_TAG('q','u','p',' '), HB_TAG('Q','U','Z',' ')}, /* Southern Pastaza Quechua -> Quechua */ + {HB_TAG('q','u','r',' '), HB_TAG('Q','W','H',' ')}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','r',' '), HB_TAG('Q','U','Z',' ')}, /* Yanahuanca Pasco Quechua -> Quechua */ + {HB_TAG('q','u','s',' '), HB_TAG('Q','U','H',' ')}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ + {HB_TAG('q','u','s',' '), HB_TAG('Q','U','Z',' ')}, /* Santiago del Estero Quichua -> Quechua */ + {HB_TAG('q','u','v',' '), HB_TAG('M','Y','N',' ')}, /* Sacapulteco -> Mayan */ + {HB_TAG('q','u','w',' '), HB_TAG('Q','V','I',' ')}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','w',' '), HB_TAG('Q','U','Z',' ')}, /* Tena Lowland Quichua -> Quechua */ + {HB_TAG('q','u','x',' '), HB_TAG('Q','W','H',' ')}, /* Yauyos Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','x',' '), HB_TAG('Q','U','Z',' ')}, /* Yauyos Quechua -> Quechua */ + {HB_TAG('q','u','y',' '), HB_TAG('Q','U','Z',' ')}, /* Ayacucho Quechua -> Quechua */ +/*{HB_TAG('q','u','z',' '), HB_TAG('Q','U','Z',' ')},*/ /* Cusco Quechua -> Quechua */ + {HB_TAG('q','v','a',' '), HB_TAG('Q','W','H',' ')}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','a',' '), HB_TAG('Q','U','Z',' ')}, /* Ambo-Pasco Quechua -> Quechua */ + {HB_TAG('q','v','c',' '), HB_TAG('Q','U','Z',' ')}, /* Cajamarca Quechua -> Quechua */ + {HB_TAG('q','v','e',' '), HB_TAG('Q','U','Z',' ')}, /* Eastern Apurímac Quechua -> Quechua */ + {HB_TAG('q','v','h',' '), HB_TAG('Q','W','H',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','h',' '), HB_TAG('Q','U','Z',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua */ + {HB_TAG('q','v','i',' '), HB_TAG('Q','V','I',' ')}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','i',' '), HB_TAG('Q','U','Z',' ')}, /* Imbabura Highland Quichua -> Quechua */ + {HB_TAG('q','v','j',' '), HB_TAG('Q','V','I',' ')}, /* Loja Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','j',' '), HB_TAG('Q','U','Z',' ')}, /* Loja Highland Quichua -> Quechua */ + {HB_TAG('q','v','l',' '), HB_TAG('Q','W','H',' ')}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','l',' '), HB_TAG('Q','U','Z',' ')}, /* Cajatambo North Lima Quechua -> Quechua */ + {HB_TAG('q','v','m',' '), HB_TAG('Q','W','H',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','m',' '), HB_TAG('Q','U','Z',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */ + {HB_TAG('q','v','n',' '), HB_TAG('Q','W','H',' ')}, /* North Junín Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','n',' '), HB_TAG('Q','U','Z',' ')}, /* North Junín Quechua -> Quechua */ + {HB_TAG('q','v','o',' '), HB_TAG('Q','V','I',' ')}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ + {HB_TAG('q','v','o',' '), HB_TAG('Q','U','Z',' ')}, /* Napo Lowland Quechua -> Quechua */ + {HB_TAG('q','v','p',' '), HB_TAG('Q','W','H',' ')}, /* Pacaraos Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','p',' '), HB_TAG('Q','U','Z',' ')}, /* Pacaraos Quechua -> Quechua */ + {HB_TAG('q','v','s',' '), HB_TAG('Q','U','Z',' ')}, /* San Martín Quechua -> Quechua */ + {HB_TAG('q','v','w',' '), HB_TAG('Q','W','H',' ')}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','w',' '), HB_TAG('Q','U','Z',' ')}, /* Huaylla Wanca Quechua -> Quechua */ + {HB_TAG('q','v','z',' '), HB_TAG('Q','V','I',' ')}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','z',' '), HB_TAG('Q','U','Z',' ')}, /* Northern Pastaza Quichua -> Quechua */ + {HB_TAG('q','w','a',' '), HB_TAG('Q','W','H',' ')}, /* Corongo Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','a',' '), HB_TAG('Q','U','Z',' ')}, /* Corongo Ancash Quechua -> Quechua */ + {HB_TAG('q','w','c',' '), HB_TAG('Q','U','Z',' ')}, /* Classical Quechua -> Quechua */ + {HB_TAG('q','w','h',' '), HB_TAG('Q','W','H',' ')}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','h',' '), HB_TAG('Q','U','Z',' ')}, /* Huaylas Ancash Quechua -> Quechua */ + {HB_TAG('q','w','s',' '), HB_TAG('Q','W','H',' ')}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','s',' '), HB_TAG('Q','U','Z',' ')}, /* Sihuas Ancash Quechua -> Quechua */ + {HB_TAG('q','w','t',' '), HB_TAG('A','T','H',' ')}, /* Kwalhioqua-Tlatskanai -> Athapaskan */ + {HB_TAG('q','x','a',' '), HB_TAG('Q','W','H',' ')}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','a',' '), HB_TAG('Q','U','Z',' ')}, /* Chiquián Ancash Quechua -> Quechua */ + {HB_TAG('q','x','c',' '), HB_TAG('Q','W','H',' ')}, /* Chincha Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','c',' '), HB_TAG('Q','U','Z',' ')}, /* Chincha Quechua -> Quechua */ + {HB_TAG('q','x','h',' '), HB_TAG('Q','W','H',' ')}, /* Panao Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','h',' '), HB_TAG('Q','U','Z',' ')}, /* Panao Huánuco Quechua -> Quechua */ + {HB_TAG('q','x','l',' '), HB_TAG('Q','V','I',' ')}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','x','l',' '), HB_TAG('Q','U','Z',' ')}, /* Salasaca Highland Quichua -> Quechua */ + {HB_TAG('q','x','n',' '), HB_TAG('Q','W','H',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','n',' '), HB_TAG('Q','U','Z',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua */ + {HB_TAG('q','x','o',' '), HB_TAG('Q','W','H',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','o',' '), HB_TAG('Q','U','Z',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua */ + {HB_TAG('q','x','p',' '), HB_TAG('Q','U','Z',' ')}, /* Puno Quechua -> Quechua */ + {HB_TAG('q','x','r',' '), HB_TAG('Q','V','I',' ')}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','x','r',' '), HB_TAG('Q','U','Z',' ')}, /* Cañar Highland Quichua -> Quechua */ + {HB_TAG('q','x','t',' '), HB_TAG('Q','W','H',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','t',' '), HB_TAG('Q','U','Z',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua */ + {HB_TAG('q','x','u',' '), HB_TAG('Q','U','Z',' ')}, /* Arequipa-La Unión Quechua -> Quechua */ + {HB_TAG('q','x','w',' '), HB_TAG('Q','W','H',' ')}, /* Jauja Wanca Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','w',' '), HB_TAG('Q','U','Z',' ')}, /* Jauja Wanca Quechua -> Quechua */ + {HB_TAG('r','a','g',' '), HB_TAG('L','U','H',' ')}, /* Logooli -> Luyia */ +/*{HB_TAG('r','a','j',' '), HB_TAG('R','A','J',' ')},*/ /* Rajasthani [macrolanguage] */ + {HB_TAG('r','a','l',' '), HB_TAG('Q','I','N',' ')}, /* Ralte -> Chin */ +/*{HB_TAG('r','a','r',' '), HB_TAG('R','A','R',' ')},*/ /* Rarotongan */ + {HB_TAG('r','b','b',' '), HB_TAG('P','L','G',' ')}, /* Rumai Palaung -> Palaung */ + {HB_TAG('r','b','l',' '), HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */ + {HB_TAG('r','c','f',' '), HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */ +/*{HB_TAG('r','e','j',' '), HB_TAG('R','E','J',' ')},*/ /* Rejang */ +/*{HB_TAG('r','h','g',' '), HB_TAG('R','H','G',' ')},*/ /* Rohingya */ +/*{HB_TAG('r','i','a',' '), HB_TAG('R','I','A',' ')},*/ /* Riang (India) */ + {HB_TAG('r','i','f',' '), HB_TAG('R','I','F',' ')}, /* Tarifit */ + {HB_TAG('r','i','f',' '), HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */ +/*{HB_TAG('r','i','t',' '), HB_TAG('R','I','T',' ')},*/ /* Ritharrngu -> Ritarungo */ + {HB_TAG('r','k','i',' '), HB_TAG('A','R','K',' ')}, /* Rakhine */ +/*{HB_TAG('r','k','w',' '), HB_TAG('R','K','W',' ')},*/ /* Arakwal */ + {HB_TAG('r','m','c',' '), HB_TAG('R','O','Y',' ')}, /* Carpathian Romani -> Romany */ + {HB_TAG('r','m','f',' '), HB_TAG('R','O','Y',' ')}, /* Kalo Finnish Romani -> Romany */ + {HB_TAG('r','m','l',' '), HB_TAG('R','O','Y',' ')}, /* Baltic Romani -> Romany */ + {HB_TAG('r','m','n',' '), HB_TAG('R','O','Y',' ')}, /* Balkan Romani -> Romany */ + {HB_TAG('r','m','o',' '), HB_TAG('R','O','Y',' ')}, /* Sinte Romani -> Romany */ + {HB_TAG('r','m','s',' '), HB_TAG_NONE }, /* Romanian Sign Language != Romansh */ + {HB_TAG('r','m','w',' '), HB_TAG('R','O','Y',' ')}, /* Welsh Romani -> Romany */ + {HB_TAG('r','m','y',' '), HB_TAG('R','M','Y',' ')}, /* Vlax Romani */ + {HB_TAG('r','m','y',' '), HB_TAG('R','O','Y',' ')}, /* Vlax Romani -> Romany */ + {HB_TAG('r','m','z',' '), HB_TAG('A','R','K',' ')}, /* Marma -> Rakhine */ + {HB_TAG('r','o','m',' '), HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ + {HB_TAG('r','o','p',' '), HB_TAG('C','P','P',' ')}, /* Kriol -> Creoles */ + {HB_TAG('r','t','c',' '), HB_TAG('Q','I','N',' ')}, /* Rungtu Chin -> Chin */ +/*{HB_TAG('r','t','m',' '), HB_TAG('R','T','M',' ')},*/ /* Rotuman */ + {HB_TAG('r','u','e',' '), HB_TAG('R','S','Y',' ')}, /* Rusyn */ +/*{HB_TAG('r','u','p',' '), HB_TAG('R','U','P',' ')},*/ /* Aromanian */ + {HB_TAG('r','w','r',' '), HB_TAG('M','A','W',' ')}, /* Marwari (India) */ + {HB_TAG('s','a','d',' '), HB_TAG_NONE }, /* Sandawe != Sadri */ + {HB_TAG('s','a','h',' '), HB_TAG('Y','A','K',' ')}, /* Yakut -> Sakha */ + {HB_TAG('s','a','m',' '), HB_TAG('P','A','A',' ')}, /* Samaritan Aramaic -> Palestinian Aramaic */ +/*{HB_TAG('s','a','s',' '), HB_TAG('S','A','S',' ')},*/ /* Sasak */ +/*{HB_TAG('s','a','t',' '), HB_TAG('S','A','T',' ')},*/ /* Santali */ + {HB_TAG('s','a','y',' '), HB_TAG_NONE }, /* Saya != Sayisi */ + {HB_TAG('s','c','f',' '), HB_TAG('C','P','P',' ')}, /* San Miguel Creole French -> Creoles */ + {HB_TAG('s','c','h',' '), HB_TAG('Q','I','N',' ')}, /* Sakachep -> Chin */ + {HB_TAG('s','c','i',' '), HB_TAG('C','P','P',' ')}, /* Sri Lankan Creole Malay -> Creoles */ + {HB_TAG('s','c','k',' '), HB_TAG('S','A','D',' ')}, /* Sadri */ +/*{HB_TAG('s','c','n',' '), HB_TAG('S','C','N',' ')},*/ /* Sicilian */ +/*{HB_TAG('s','c','o',' '), HB_TAG('S','C','O',' ')},*/ /* Scots */ + {HB_TAG('s','c','s',' '), HB_TAG('S','C','S',' ')}, /* North Slavey */ + {HB_TAG('s','c','s',' '), HB_TAG('S','L','A',' ')}, /* North Slavey -> Slavey */ + {HB_TAG('s','c','s',' '), HB_TAG('A','T','H',' ')}, /* North Slavey -> Athapaskan */ + {HB_TAG('s','d','c',' '), HB_TAG('S','R','D',' ')}, /* Sassarese Sardinian -> Sardinian */ + {HB_TAG('s','d','h',' '), HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */ + {HB_TAG('s','d','n',' '), HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */ + {HB_TAG('s','d','s',' '), HB_TAG('B','B','R',' ')}, /* Sened -> Berber */ + {HB_TAG('s','e','h',' '), HB_TAG('S','N','A',' ')}, /* Sena */ + {HB_TAG('s','e','k',' '), HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */ +/*{HB_TAG('s','e','l',' '), HB_TAG('S','E','L',' ')},*/ /* Selkup */ + {HB_TAG('s','e','z',' '), HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */ + {HB_TAG('s','f','m',' '), HB_TAG('S','F','M',' ')}, /* Small Flowery Miao */ + {HB_TAG('s','f','m',' '), HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */ +/*{HB_TAG('s','g','a',' '), HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */ + {HB_TAG('s','g','c',' '), HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */ + {HB_TAG('s','g','o',' '), HB_TAG_NONE }, /* Songa (retired code) != Sango */ +/*{HB_TAG('s','g','s',' '), HB_TAG('S','G','S',' ')},*/ /* Samogitian */ + {HB_TAG('s','g','w',' '), HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ + {HB_TAG('s','h','i',' '), HB_TAG('S','H','I',' ')}, /* Tachelhit */ + {HB_TAG('s','h','i',' '), HB_TAG('B','B','R',' ')}, /* Tachelhit -> Berber */ + {HB_TAG('s','h','l',' '), HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */ +/*{HB_TAG('s','h','n',' '), HB_TAG('S','H','N',' ')},*/ /* Shan */ + {HB_TAG('s','h','u',' '), HB_TAG('A','R','A',' ')}, /* Chadian Arabic -> Arabic */ + {HB_TAG('s','h','y',' '), HB_TAG('B','B','R',' ')}, /* Tachawit -> Berber */ + {HB_TAG('s','i','b',' '), HB_TAG_NONE }, /* Sebop != Sibe */ +/*{HB_TAG('s','i','d',' '), HB_TAG('S','I','D',' ')},*/ /* Sidamo */ + {HB_TAG('s','i','g',' '), HB_TAG_NONE }, /* Paasaal != Silte Gurage */ + {HB_TAG('s','i','z',' '), HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */ + {HB_TAG('s','j','d',' '), HB_TAG('K','S','M',' ')}, /* Kildin Sami */ + {HB_TAG('s','j','o',' '), HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */ + {HB_TAG('s','j','s',' '), HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */ + {HB_TAG('s','k','g',' '), HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */ + {HB_TAG('s','k','r',' '), HB_TAG('S','R','K',' ')}, /* Saraiki */ + {HB_TAG('s','k','s',' '), HB_TAG_NONE }, /* Maia != Skolt Sami */ + {HB_TAG('s','k','w',' '), HB_TAG('C','P','P',' ')}, /* Skepi Creole Dutch -> Creoles */ + {HB_TAG('s','k','y',' '), HB_TAG_NONE }, /* Sikaiana != Slovak */ + {HB_TAG('s','l','a',' '), HB_TAG_NONE }, /* Slavic [collection] != Slavey */ + {HB_TAG('s','m','a',' '), HB_TAG('S','S','M',' ')}, /* Southern Sami */ + {HB_TAG('s','m','d',' '), HB_TAG('M','B','N',' ')}, /* Sama (retired code) -> Mbundu */ + {HB_TAG('s','m','j',' '), HB_TAG('L','S','M',' ')}, /* Lule Sami */ + {HB_TAG('s','m','l',' '), HB_TAG_NONE }, /* Central Sama != Somali */ + {HB_TAG('s','m','n',' '), HB_TAG('I','S','M',' ')}, /* Inari Sami */ + {HB_TAG('s','m','s',' '), HB_TAG('S','K','S',' ')}, /* Skolt Sami */ + {HB_TAG('s','m','t',' '), HB_TAG('Q','I','N',' ')}, /* Simte -> Chin */ + {HB_TAG('s','n','b',' '), HB_TAG('I','B','A',' ')}, /* Sebuyau (retired code) -> Iban */ + {HB_TAG('s','n','h',' '), HB_TAG_NONE }, /* Shinabo (retired code) != Sinhala (Sinhalese) */ +/*{HB_TAG('s','n','k',' '), HB_TAG('S','N','K',' ')},*/ /* Soninke */ + {HB_TAG('s','o','g',' '), HB_TAG_NONE }, /* Sogdian != Sodo Gurage */ +/*{HB_TAG('s','o','p',' '), HB_TAG('S','O','P',' ')},*/ /* Songe */ + {HB_TAG('s','p','v',' '), HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */ + {HB_TAG('s','p','y',' '), HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */ + {HB_TAG('s','r','b',' '), HB_TAG_NONE }, /* Sora != Serbian */ + {HB_TAG('s','r','c',' '), HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */ + {HB_TAG('s','r','k',' '), HB_TAG_NONE }, /* Serudung Murut != Saraiki */ + {HB_TAG('s','r','m',' '), HB_TAG('C','P','P',' ')}, /* Saramaccan -> Creoles */ + {HB_TAG('s','r','n',' '), HB_TAG('C','P','P',' ')}, /* Sranan Tongo -> Creoles */ + {HB_TAG('s','r','o',' '), HB_TAG('S','R','D',' ')}, /* Campidanese Sardinian -> Sardinian */ +/*{HB_TAG('s','r','r',' '), HB_TAG('S','R','R',' ')},*/ /* Serer */ + {HB_TAG('s','r','s',' '), HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */ + {HB_TAG('s','s','h',' '), HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */ + {HB_TAG('s','s','l',' '), HB_TAG_NONE }, /* Western Sisaala != South Slavey */ + {HB_TAG('s','s','m',' '), HB_TAG_NONE }, /* Semnam != Southern Sami */ + {HB_TAG('s','t','a',' '), HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */ +/*{HB_TAG('s','t','q',' '), HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */ + {HB_TAG('s','t','v',' '), HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */ +/*{HB_TAG('s','u','k',' '), HB_TAG('S','U','K',' ')},*/ /* Sukuma */ + {HB_TAG('s','u','q',' '), HB_TAG('S','U','R',' ')}, /* Suri */ + {HB_TAG('s','u','r',' '), HB_TAG_NONE }, /* Mwaghavul != Suri */ +/*{HB_TAG('s','v','a',' '), HB_TAG('S','V','A',' ')},*/ /* Svan */ + {HB_TAG('s','v','c',' '), HB_TAG('C','P','P',' ')}, /* Vincentian Creole English -> Creoles */ + {HB_TAG('s','v','e',' '), HB_TAG_NONE }, /* Serili != Swedish */ + {HB_TAG('s','w','b',' '), HB_TAG('C','M','R',' ')}, /* Maore Comorian -> Comorian */ + {HB_TAG('s','w','c',' '), HB_TAG('S','W','K',' ')}, /* Congo Swahili -> Swahili */ + {HB_TAG('s','w','h',' '), HB_TAG('S','W','K',' ')}, /* Swahili */ + {HB_TAG('s','w','k',' '), HB_TAG_NONE }, /* Malawi Sena != Swahili */ + {HB_TAG('s','w','n',' '), HB_TAG('B','B','R',' ')}, /* Sawknah -> Berber */ + {HB_TAG('s','w','v',' '), HB_TAG('M','A','W',' ')}, /* Shekhawati -> Marwari */ +/*{HB_TAG('s','x','u',' '), HB_TAG('S','X','U',' ')},*/ /* Upper Saxon */ + {HB_TAG('s','y','c',' '), HB_TAG('S','Y','R',' ')}, /* Classical Syriac -> Syriac */ +/*{HB_TAG('s','y','l',' '), HB_TAG('S','Y','L',' ')},*/ /* Sylheti */ +/*{HB_TAG('s','y','r',' '), HB_TAG('S','Y','R',' ')},*/ /* Syriac [macrolanguage] */ +/*{HB_TAG('s','z','l',' '), HB_TAG('S','Z','L',' ')},*/ /* Silesian */ + {HB_TAG('t','a','a',' '), HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */ +/*{HB_TAG('t','a','b',' '), HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */ + {HB_TAG('t','a','j',' '), HB_TAG_NONE }, /* Eastern Tamang != Tajiki */ + {HB_TAG('t','a','q',' '), HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */ + {HB_TAG('t','a','q',' '), HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */ + {HB_TAG('t','a','s',' '), HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */ + {HB_TAG('t','a','u',' '), HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */ + {HB_TAG('t','c','b',' '), HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */ + {HB_TAG('t','c','e',' '), HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */ + {HB_TAG('t','c','h',' '), HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */ + {HB_TAG('t','c','p',' '), HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */ + {HB_TAG('t','c','s',' '), HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */ + {HB_TAG('t','c','y',' '), HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */ + {HB_TAG('t','c','z',' '), HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */ +/*{HB_TAG('t','d','d',' '), HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */ + {HB_TAG('t','d','x',' '), HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ + {HB_TAG('t','e','c',' '), HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */ + {HB_TAG('t','e','m',' '), HB_TAG('T','M','N',' ')}, /* Timne -> Temne */ +/*{HB_TAG('t','e','t',' '), HB_TAG('T','E','T',' ')},*/ /* Tetum */ + {HB_TAG('t','e','z',' '), HB_TAG('B','B','R',' ')}, /* Tetserret -> Berber */ + {HB_TAG('t','f','n',' '), HB_TAG('A','T','H',' ')}, /* Tanaina -> Athapaskan */ + {HB_TAG('t','g','h',' '), HB_TAG('C','P','P',' ')}, /* Tobagonian Creole English -> Creoles */ + {HB_TAG('t','g','j',' '), HB_TAG('N','I','S',' ')}, /* Tagin -> Nisi */ + {HB_TAG('t','g','n',' '), HB_TAG_NONE }, /* Tandaganon != Tongan */ + {HB_TAG('t','g','r',' '), HB_TAG_NONE }, /* Tareng != Tigre */ + {HB_TAG('t','g','x',' '), HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */ + {HB_TAG('t','g','y',' '), HB_TAG_NONE }, /* Togoyo != Tigrinya */ + {HB_TAG('t','h','t',' '), HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */ + {HB_TAG('t','h','v',' '), HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */ + {HB_TAG('t','h','v',' '), HB_TAG('B','B','R',' ')}, /* Tahaggart Tamahaq -> Berber */ + {HB_TAG('t','h','z',' '), HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */ + {HB_TAG('t','h','z',' '), HB_TAG('B','B','R',' ')}, /* Tayart Tamajeq -> Berber */ + {HB_TAG('t','i','a',' '), HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */ + {HB_TAG('t','i','g',' '), HB_TAG('T','G','R',' ')}, /* Tigre */ +/*{HB_TAG('t','i','v',' '), HB_TAG('T','I','V',' ')},*/ /* Tiv */ +/*{HB_TAG('t','j','l',' '), HB_TAG('T','J','L',' ')},*/ /* Tai Laing */ + {HB_TAG('t','j','o',' '), HB_TAG('B','B','R',' ')}, /* Temacine Tamazight -> Berber */ + {HB_TAG('t','k','g',' '), HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */ + {HB_TAG('t','k','m',' '), HB_TAG_NONE }, /* Takelma != Turkmen */ +/*{HB_TAG('t','l','i',' '), HB_TAG('T','L','I',' ')},*/ /* Tlingit */ + {HB_TAG('t','m','g',' '), HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */ + {HB_TAG('t','m','h',' '), HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */ + {HB_TAG('t','m','h',' '), HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */ + {HB_TAG('t','m','n',' '), HB_TAG_NONE }, /* Taman (Indonesia) != Temne */ + {HB_TAG('t','m','w',' '), HB_TAG('M','L','Y',' ')}, /* Temuan -> Malay */ + {HB_TAG('t','n','a',' '), HB_TAG_NONE }, /* Tacana != Tswana */ + {HB_TAG('t','n','e',' '), HB_TAG_NONE }, /* Tinoc Kallahan (retired code) != Tundra Enets */ + {HB_TAG('t','n','f',' '), HB_TAG('D','R','I',' ')}, /* Tangshewi (retired code) -> Dari */ + {HB_TAG('t','n','f',' '), HB_TAG('F','A','R',' ')}, /* Tangshewi (retired code) -> Persian */ + {HB_TAG('t','n','g',' '), HB_TAG_NONE }, /* Tobanga != Tonga */ + {HB_TAG('t','o','d',' '), HB_TAG('T','O','D','0')}, /* Toma */ + {HB_TAG('t','o','i',' '), HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */ + {HB_TAG('t','o','j',' '), HB_TAG('M','Y','N',' ')}, /* Tojolabal -> Mayan */ + {HB_TAG('t','o','l',' '), HB_TAG('A','T','H',' ')}, /* Tolowa -> Athapaskan */ + {HB_TAG('t','o','r',' '), HB_TAG('B','A','D','0')}, /* Togbo-Vara Banda -> Banda */ + {HB_TAG('t','p','i',' '), HB_TAG('T','P','I',' ')}, /* Tok Pisin */ + {HB_TAG('t','p','i',' '), HB_TAG('C','P','P',' ')}, /* Tok Pisin -> Creoles */ + {HB_TAG('t','r','f',' '), HB_TAG('C','P','P',' ')}, /* Trinidadian Creole English -> Creoles */ + {HB_TAG('t','r','k',' '), HB_TAG_NONE }, /* Turkic [collection] != Turkish */ + {HB_TAG('t','r','u',' '), HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */ + {HB_TAG('t','r','u',' '), HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */ + {HB_TAG('t','s','g',' '), HB_TAG_NONE }, /* Tausug != Tsonga */ +/*{HB_TAG('t','s','j',' '), HB_TAG('T','S','J',' ')},*/ /* Tshangla */ + {HB_TAG('t','t','c',' '), HB_TAG('M','Y','N',' ')}, /* Tektiteko -> Mayan */ + {HB_TAG('t','t','m',' '), HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */ + {HB_TAG('t','t','q',' '), HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */ + {HB_TAG('t','t','q',' '), HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */ + {HB_TAG('t','u','a',' '), HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */ + {HB_TAG('t','u','l',' '), HB_TAG_NONE }, /* Tula != Tumbuka */ +/*{HB_TAG('t','u','m',' '), HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */ + {HB_TAG('t','u','u',' '), HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */ + {HB_TAG('t','u','v',' '), HB_TAG_NONE }, /* Turkana != Tuvin */ + {HB_TAG('t','u','y',' '), HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */ +/*{HB_TAG('t','v','l',' '), HB_TAG('T','V','L',' ')},*/ /* Tuvalu */ + {HB_TAG('t','v','y',' '), HB_TAG('C','P','P',' ')}, /* Timor Pidgin -> Creoles */ + {HB_TAG('t','x','c',' '), HB_TAG('A','T','H',' ')}, /* Tsetsaut -> Athapaskan */ + {HB_TAG('t','x','y',' '), HB_TAG('M','L','G',' ')}, /* Tanosy Malagasy -> Malagasy */ + {HB_TAG('t','y','v',' '), HB_TAG('T','U','V',' ')}, /* Tuvinian -> Tuvin */ +/*{HB_TAG('t','y','z',' '), HB_TAG('T','Y','Z',' ')},*/ /* Tày */ + {HB_TAG('t','z','h',' '), HB_TAG('M','Y','N',' ')}, /* Tzeltal -> Mayan */ + {HB_TAG('t','z','j',' '), HB_TAG('M','Y','N',' ')}, /* Tz'utujil -> Mayan */ + {HB_TAG('t','z','m',' '), HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight -> Tamazight */ + {HB_TAG('t','z','m',' '), HB_TAG('B','B','R',' ')}, /* Central Atlas Tamazight -> Berber */ + {HB_TAG('t','z','o',' '), HB_TAG('T','Z','O',' ')}, /* Tzotzil */ + {HB_TAG('t','z','o',' '), HB_TAG('M','Y','N',' ')}, /* Tzotzil -> Mayan */ + {HB_TAG('u','b','l',' '), HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */ +/*{HB_TAG('u','d','m',' '), HB_TAG('U','D','M',' ')},*/ /* Udmurt */ + {HB_TAG('u','k','i',' '), HB_TAG('K','U','I',' ')}, /* Kui (India) */ + {HB_TAG('u','l','n',' '), HB_TAG('C','P','P',' ')}, /* Unserdeutsch -> Creoles */ +/*{HB_TAG('u','m','b',' '), HB_TAG('U','M','B',' ')},*/ /* Umbundu */ + {HB_TAG('u','n','r',' '), HB_TAG('M','U','N',' ')}, /* Mundari */ + {HB_TAG('u','r','k',' '), HB_TAG('M','L','Y',' ')}, /* Urak Lawoi' -> Malay */ + {HB_TAG('u','s','p',' '), HB_TAG('M','Y','N',' ')}, /* Uspanteco -> Mayan */ + {HB_TAG('u','z','n',' '), HB_TAG('U','Z','B',' ')}, /* Northern Uzbek -> Uzbek */ + {HB_TAG('u','z','s',' '), HB_TAG('U','Z','B',' ')}, /* Southern Uzbek -> Uzbek */ + {HB_TAG('v','a','p',' '), HB_TAG('Q','I','N',' ')}, /* Vaiphei -> Chin */ +/*{HB_TAG('v','e','c',' '), HB_TAG('V','E','C',' ')},*/ /* Venetian */ + {HB_TAG('v','i','c',' '), HB_TAG('C','P','P',' ')}, /* Virgin Islands Creole English -> Creoles */ + {HB_TAG('v','i','t',' '), HB_TAG_NONE }, /* Viti != Vietnamese */ + {HB_TAG('v','k','k',' '), HB_TAG('M','L','Y',' ')}, /* Kaur -> Malay */ + {HB_TAG('v','k','p',' '), HB_TAG('C','P','P',' ')}, /* Korlai Creole Portuguese -> Creoles */ + {HB_TAG('v','k','t',' '), HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */ + {HB_TAG('v','l','s',' '), HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */ + {HB_TAG('v','m','w',' '), HB_TAG('M','A','K',' ')}, /* Makhuwa */ +/*{HB_TAG('v','r','o',' '), HB_TAG('V','R','O',' ')},*/ /* Võro */ + {HB_TAG('w','a','g',' '), HB_TAG_NONE }, /* Wa'ema != Wagdi */ +/*{HB_TAG('w','a','r',' '), HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */ + {HB_TAG('w','b','m',' '), HB_TAG('W','A',' ',' ')}, /* Wa */ + {HB_TAG('w','b','r',' '), HB_TAG('W','A','G',' ')}, /* Wagdi */ + {HB_TAG('w','b','r',' '), HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */ +/*{HB_TAG('w','c','i',' '), HB_TAG('W','C','I',' ')},*/ /* Waci Gbe */ + {HB_TAG('w','e','a',' '), HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */ + {HB_TAG('w','e','s',' '), HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */ + {HB_TAG('w','e','u',' '), HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */ + {HB_TAG('w','l','c',' '), HB_TAG('C','M','R',' ')}, /* Mwali Comorian -> Comorian */ + {HB_TAG('w','l','e',' '), HB_TAG('S','I','G',' ')}, /* Wolane -> Silte Gurage */ + {HB_TAG('w','l','k',' '), HB_TAG('A','T','H',' ')}, /* Wailaki -> Athapaskan */ + {HB_TAG('w','n','i',' '), HB_TAG('C','M','R',' ')}, /* Ndzwani Comorian -> Comorian */ + {HB_TAG('w','r','y',' '), HB_TAG('M','A','W',' ')}, /* Merwari -> Marwari */ + {HB_TAG('w','s','g',' '), HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */ +/*{HB_TAG('w','t','m',' '), HB_TAG('W','T','M',' ')},*/ /* Mewati */ + {HB_TAG('w','u','u',' '), HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese, Simplified */ + {HB_TAG('x','a','l',' '), HB_TAG('K','L','M',' ')}, /* Kalmyk */ + {HB_TAG('x','a','l',' '), HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */ + {HB_TAG('x','a','n',' '), HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */ + {HB_TAG('x','b','d',' '), HB_TAG_NONE }, /* Bindal != Lü */ +/*{HB_TAG('x','j','b',' '), HB_TAG('X','J','B',' ')},*/ /* Minjungbal -> Minjangbal */ +/*{HB_TAG('x','k','f',' '), HB_TAG('X','K','F',' ')},*/ /* Khengkha */ + {HB_TAG('x','m','g',' '), HB_TAG('B','M','L',' ')}, /* Mengaka -> Bamileke */ + {HB_TAG('x','m','m',' '), HB_TAG('M','L','Y',' ')}, /* Manado Malay -> Malay */ + {HB_TAG('x','m','m',' '), HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */ + {HB_TAG('x','m','v',' '), HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */ + {HB_TAG('x','m','w',' '), HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */ + {HB_TAG('x','n','j',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */ + {HB_TAG('x','n','q',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */ + {HB_TAG('x','n','r',' '), HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */ +/*{HB_TAG('x','o','g',' '), HB_TAG('X','O','G',' ')},*/ /* Soga */ + {HB_TAG('x','p','e',' '), HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */ + {HB_TAG('x','p','e',' '), HB_TAG('K','P','L',' ')}, /* Liberia Kpelle -> Kpelle */ + {HB_TAG('x','s','l',' '), HB_TAG('S','S','L',' ')}, /* South Slavey */ + {HB_TAG('x','s','l',' '), HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */ + {HB_TAG('x','s','l',' '), HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */ + {HB_TAG('x','s','t',' '), HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */ +/*{HB_TAG('x','u','b',' '), HB_TAG('X','U','B',' ')},*/ /* Betta Kurumba -> Bette Kuruma */ +/*{HB_TAG('x','u','j',' '), HB_TAG('X','U','J',' ')},*/ /* Jennu Kurumba -> Jennu Kuruma */ + {HB_TAG('x','u','p',' '), HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */ + {HB_TAG('x','w','o',' '), HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */ + {HB_TAG('y','a','j',' '), HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */ + {HB_TAG('y','a','k',' '), HB_TAG_NONE }, /* Yakama != Sakha */ +/*{HB_TAG('y','a','o',' '), HB_TAG('Y','A','O',' ')},*/ /* Yao */ +/*{HB_TAG('y','a','p',' '), HB_TAG('Y','A','P',' ')},*/ /* Yapese */ + {HB_TAG('y','b','a',' '), HB_TAG_NONE }, /* Yala != Yoruba */ + {HB_TAG('y','b','b',' '), HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */ + {HB_TAG('y','b','d',' '), HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */ + {HB_TAG('y','d','d',' '), HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */ +/*{HB_TAG('y','g','p',' '), HB_TAG('Y','G','P',' ')},*/ /* Gepo */ + {HB_TAG('y','i','h',' '), HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */ + {HB_TAG('y','i','m',' '), HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */ +/*{HB_TAG('y','n','a',' '), HB_TAG('Y','N','A',' ')},*/ /* Aluo */ + {HB_TAG('y','o','s',' '), HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */ + {HB_TAG('y','u','a',' '), HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */ + {HB_TAG('y','u','e',' '), HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */ +/*{HB_TAG('y','w','q',' '), HB_TAG('Y','W','Q',' ')},*/ /* Wuding-Luquan Yi */ + {HB_TAG('z','c','h',' '), HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */ + {HB_TAG('z','d','j',' '), HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */ +/*{HB_TAG('z','e','a',' '), HB_TAG('Z','E','A',' ')},*/ /* Zeeuws -> Zealandic */ + {HB_TAG('z','e','h',' '), HB_TAG('Z','H','A',' ')}, /* Eastern Hongshuihe Zhuang -> Zhuang */ + {HB_TAG('z','e','n',' '), HB_TAG('B','B','R',' ')}, /* Zenaga -> Berber */ + {HB_TAG('z','g','b',' '), HB_TAG('Z','H','A',' ')}, /* Guibei Zhuang -> Zhuang */ + {HB_TAG('z','g','h',' '), HB_TAG('Z','G','H',' ')}, /* Standard Moroccan Tamazight */ + {HB_TAG('z','g','h',' '), HB_TAG('B','B','R',' ')}, /* Standard Moroccan Tamazight -> Berber */ + {HB_TAG('z','g','m',' '), HB_TAG('Z','H','A',' ')}, /* Minz Zhuang -> Zhuang */ + {HB_TAG('z','g','n',' '), HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */ + {HB_TAG('z','h','d',' '), HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */ + {HB_TAG('z','h','n',' '), HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */ + {HB_TAG('z','l','j',' '), HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */ + {HB_TAG('z','l','m',' '), HB_TAG('M','L','Y',' ')}, /* Malay */ + {HB_TAG('z','l','n',' '), HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */ + {HB_TAG('z','l','q',' '), HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */ + {HB_TAG('z','m','i',' '), HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */ + {HB_TAG('z','m','z',' '), HB_TAG('B','A','D','0')}, /* Mbandja -> Banda */ + {HB_TAG('z','n','d',' '), HB_TAG_NONE }, /* Zande [collection] != Zande */ + {HB_TAG('z','n','e',' '), HB_TAG('Z','N','D',' ')}, /* Zande */ + {HB_TAG('z','o','m',' '), HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */ + {HB_TAG('z','q','e',' '), HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */ + {HB_TAG('z','s','m',' '), HB_TAG('M','L','Y',' ')}, /* Standard Malay -> Malay */ + {HB_TAG('z','u','m',' '), HB_TAG('L','R','C',' ')}, /* Kumzari -> Luri */ + {HB_TAG('z','y','b',' '), HB_TAG('Z','H','A',' ')}, /* Yongbei Zhuang -> Zhuang */ + {HB_TAG('z','y','g',' '), HB_TAG('Z','H','A',' ')}, /* Yang Zhuang -> Zhuang */ + {HB_TAG('z','y','j',' '), HB_TAG('Z','H','A',' ')}, /* Youjiang Zhuang -> Zhuang */ + {HB_TAG('z','y','n',' '), HB_TAG('Z','H','A',' ')}, /* Yongnan Zhuang -> Zhuang */ + {HB_TAG('z','y','p',' '), HB_TAG('Q','I','N',' ')}, /* Zyphe Chin -> Chin */ +/*{HB_TAG('z','z','a',' '), HB_TAG('Z','Z','A',' ')},*/ /* Zazaki [macrolanguage] */ + {HB_TAG('z','z','j',' '), HB_TAG('Z','H','A',' ')}, /* Zuojiang Zhuang -> Zhuang */ }; /** @@ -1639,69 +1642,75 @@ hb_ot_tags_from_complex_language (const char *lang_str, unsigned int *count /* IN/OUT */, hb_tag_t *tags /* OUT */) { - if (subtag_matches (lang_str, limit, "-fonnapa")) + if (limit - lang_str >= 7) { - /* Undetermined; North American Phonetic Alphabet */ - tags[0] = HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-polyton")) - { - /* Modern Greek (1453-); Polytonic Greek */ - tags[0] = HB_TAG('P','G','R',' '); /* Polytonic Greek */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-arevmda")) - { - /* Armenian; Western Armenian (retired code) */ - tags[0] = HB_TAG('H','Y','E',' '); /* Armenian */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-provenc")) - { - /* Occitan (post 1500); Provençal */ - tags[0] = HB_TAG('P','R','O',' '); /* Provençal / Old Provençal */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-fonipa")) - { - /* Undetermined; International Phonetic Alphabet */ - tags[0] = HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-geok")) - { - /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ - tags[0] = HB_TAG('K','G','E',' '); /* Khutsuri Georgian */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-syre")) - { - /* Undetermined; Syriac (Estrangelo variant) */ - tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-syrj")) - { - /* Undetermined; Syriac (Western variant) */ - tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-syrn")) - { - /* Undetermined; Syriac (Eastern variant) */ - tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ - *count = 1; - return true; + const char *p = strchr (lang_str, '-'); + if (!p || p >= limit || limit - p < 5) goto out; + if (subtag_matches (p, limit, "-fonnapa", 8)) + { + /* Undetermined; North American Phonetic Alphabet */ + tags[0] = HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-polyton", 8)) + { + /* Modern Greek (1453-); Polytonic Greek */ + tags[0] = HB_TAG('P','G','R',' '); /* Polytonic Greek */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-arevmda", 8)) + { + /* Armenian; Western Armenian (retired code) */ + tags[0] = HB_TAG('H','Y','E',' '); /* Armenian */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-provenc", 8)) + { + /* Occitan (post 1500); Provençal */ + tags[0] = HB_TAG('P','R','O',' '); /* Provençal / Old Provençal */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-fonipa", 7)) + { + /* Undetermined; International Phonetic Alphabet */ + tags[0] = HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-geok", 5)) + { + /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ + tags[0] = HB_TAG('K','G','E',' '); /* Khutsuri Georgian */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-syre", 5)) + { + /* Undetermined; Syriac (Estrangelo variant) */ + tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-syrj", 5)) + { + /* Undetermined; Syriac (Western variant) */ + tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-syrn", 5)) + { + /* Undetermined; Syriac (Eastern variant) */ + tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ + *count = 1; + return true; + } } +out: switch (lang_str[0]) { case 'a': @@ -1714,14 +1723,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'c': - if (lang_matches (&lang_str[1], "do-hant-hk")) + if (lang_matches (&lang_str[1], limit, "do-hant-hk", 10)) { /* Min Dong Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "do-hant-mo")) + if (lang_matches (&lang_str[1], limit, "do-hant-mo", 10)) { /* Min Dong Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1734,14 +1743,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "jy-hant-hk")) + if (lang_matches (&lang_str[1], limit, "jy-hant-hk", 10)) { /* Jinyu Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "jy-hant-mo")) + if (lang_matches (&lang_str[1], limit, "jy-hant-mo", 10)) { /* Jinyu Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1754,14 +1763,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "mn-hant-hk")) + if (lang_matches (&lang_str[1], limit, "mn-hant-hk", 10)) { /* Mandarin Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "mn-hant-mo")) + if (lang_matches (&lang_str[1], limit, "mn-hant-mo", 10)) { /* Mandarin Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1774,14 +1783,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "np-hant-hk")) + if (lang_matches (&lang_str[1], limit, "np-hant-hk", 10)) { /* Northern Ping Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant-mo")) + if (lang_matches (&lang_str[1], limit, "np-hant-mo", 10)) { /* Northern Ping Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1794,14 +1803,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "px-hant-hk")) + if (lang_matches (&lang_str[1], limit, "px-hant-hk", 10)) { /* Pu-Xian Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "px-hant-mo")) + if (lang_matches (&lang_str[1], limit, "px-hant-mo", 10)) { /* Pu-Xian Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1814,14 +1823,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "sp-hant-hk")) + if (lang_matches (&lang_str[1], limit, "sp-hant-hk", 10)) { /* Southern Ping Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sp-hant-mo")) + if (lang_matches (&lang_str[1], limit, "sp-hant-mo", 10)) { /* Southern Ping Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1834,14 +1843,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "zh-hant-hk")) + if (lang_matches (&lang_str[1], limit, "zh-hant-hk", 10)) { /* Huizhou Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zh-hant-mo")) + if (lang_matches (&lang_str[1], limit, "zh-hant-mo", 10)) { /* Huizhou Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1854,14 +1863,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "zo-hant-hk")) + if (lang_matches (&lang_str[1], limit, "zo-hant-hk", 10)) { /* Min Zhong Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zo-hant-mo")) + if (lang_matches (&lang_str[1], limit, "zo-hant-mo", 10)) { /* Min Zhong Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1874,112 +1883,112 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "do-hans")) + if (lang_matches (&lang_str[1], limit, "do-hans", 7)) { /* Min Dong Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "do-hant")) + if (lang_matches (&lang_str[1], limit, "do-hant", 7)) { /* Min Dong Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "jy-hans")) + if (lang_matches (&lang_str[1], limit, "jy-hans", 7)) { /* Jinyu Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "jy-hant")) + if (lang_matches (&lang_str[1], limit, "jy-hant", 7)) { /* Jinyu Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "mn-hans")) + if (lang_matches (&lang_str[1], limit, "mn-hans", 7)) { /* Mandarin Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "mn-hant")) + if (lang_matches (&lang_str[1], limit, "mn-hant", 7)) { /* Mandarin Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hans")) + if (lang_matches (&lang_str[1], limit, "np-hans", 7)) { /* Northern Ping Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant")) + if (lang_matches (&lang_str[1], limit, "np-hant", 7)) { /* Northern Ping Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "px-hans")) + if (lang_matches (&lang_str[1], limit, "px-hans", 7)) { /* Pu-Xian Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "px-hant")) + if (lang_matches (&lang_str[1], limit, "px-hant", 7)) { /* Pu-Xian Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sp-hans")) + if (lang_matches (&lang_str[1], limit, "sp-hans", 7)) { /* Southern Ping Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sp-hant")) + if (lang_matches (&lang_str[1], limit, "sp-hant", 7)) { /* Southern Ping Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zh-hans")) + if (lang_matches (&lang_str[1], limit, "zh-hans", 7)) { /* Huizhou Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zh-hant")) + if (lang_matches (&lang_str[1], limit, "zh-hant", 7)) { /* Huizhou Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zo-hans")) + if (lang_matches (&lang_str[1], limit, "zo-hans", 7)) { /* Min Zhong Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zo-hant")) + if (lang_matches (&lang_str[1], limit, "zo-hant", 7)) { /* Min Zhong Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -1987,7 +1996,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "do-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Dong Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -1995,7 +2004,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "do-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Dong Chinese; Macao */ unsigned int i; @@ -2009,7 +2018,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "do-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Dong Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2017,7 +2026,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "jy-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Jinyu Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2025,7 +2034,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "jy-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Jinyu Chinese; Macao */ unsigned int i; @@ -2039,7 +2048,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "jy-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Jinyu Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2047,7 +2056,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "mn-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Mandarin Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2055,7 +2064,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "mn-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Mandarin Chinese; Macao */ unsigned int i; @@ -2069,7 +2078,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "mn-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Mandarin Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2077,7 +2086,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Northern Ping Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2085,7 +2094,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Northern Ping Chinese; Macao */ unsigned int i; @@ -2099,7 +2108,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Northern Ping Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2107,7 +2116,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "px-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Pu-Xian Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2115,7 +2124,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "px-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Pu-Xian Chinese; Macao */ unsigned int i; @@ -2129,7 +2138,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "px-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Pu-Xian Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2137,7 +2146,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sp-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Southern Ping Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2145,7 +2154,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sp-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Southern Ping Chinese; Macao */ unsigned int i; @@ -2159,7 +2168,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sp-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Southern Ping Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2167,7 +2176,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zh-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Huizhou Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2175,7 +2184,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zh-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Huizhou Chinese; Macao */ unsigned int i; @@ -2189,7 +2198,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zh-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Huizhou Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2197,7 +2206,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zo-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Zhong Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2205,7 +2214,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zo-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Zhong Chinese; Macao */ unsigned int i; @@ -2219,7 +2228,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zo-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Zhong Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2228,14 +2237,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'g': - if (lang_matches (&lang_str[1], "an-hant-hk")) + if (lang_matches (&lang_str[1], limit, "an-hant-hk", 10)) { /* Gan Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant-mo")) + if (lang_matches (&lang_str[1], limit, "an-hant-mo", 10)) { /* Gan Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2248,21 +2257,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "an-hans")) + if (lang_matches (&lang_str[1], limit, "an-hans", 7)) { /* Gan Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant")) + if (lang_matches (&lang_str[1], limit, "an-hant", 7)) { /* Gan Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "a-latg")) + if (lang_matches (&lang_str[1], limit, "a-latg", 6)) { /* Irish; Latin (Gaelic variant) */ tags[0] = HB_TAG('I','R','T',' '); /* Irish Traditional */ @@ -2270,7 +2279,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Gan Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2278,7 +2287,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Gan Chinese; Macao */ unsigned int i; @@ -2292,7 +2301,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Gan Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2301,14 +2310,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'h': - if (lang_matches (&lang_str[1], "ak-hant-hk")) + if (lang_matches (&lang_str[1], limit, "ak-hant-hk", 10)) { /* Hakka Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "ak-hant-mo")) + if (lang_matches (&lang_str[1], limit, "ak-hant-mo", 10)) { /* Hakka Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2321,14 +2330,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "sn-hant-hk")) + if (lang_matches (&lang_str[1], limit, "sn-hant-hk", 10)) { /* Xiang Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sn-hant-mo")) + if (lang_matches (&lang_str[1], limit, "sn-hant-mo", 10)) { /* Xiang Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2341,28 +2350,28 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "ak-hans")) + if (lang_matches (&lang_str[1], limit, "ak-hans", 7)) { /* Hakka Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "ak-hant")) + if (lang_matches (&lang_str[1], limit, "ak-hant", 7)) { /* Hakka Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sn-hans")) + if (lang_matches (&lang_str[1], limit, "sn-hans", 7)) { /* Xiang Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sn-hant")) + if (lang_matches (&lang_str[1], limit, "sn-hant", 7)) { /* Xiang Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2370,7 +2379,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "ak-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Hakka Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2378,7 +2387,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "ak-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Hakka Chinese; Macao */ unsigned int i; @@ -2392,7 +2401,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "ak-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Hakka Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2400,7 +2409,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sn-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Xiang Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2408,7 +2417,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sn-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Xiang Chinese; Macao */ unsigned int i; @@ -2422,7 +2431,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sn-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Xiang Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2460,7 +2469,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'l': - if (lang_matches (&lang_str[1], "zh-hans")) + if (lang_matches (&lang_str[1], limit, "zh-hans", 7)) { /* Literary Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ @@ -2469,14 +2478,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'm': - if (lang_matches (&lang_str[1], "np-hant-hk")) + if (lang_matches (&lang_str[1], limit, "np-hant-hk", 10)) { /* Min Bei Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant-mo")) + if (lang_matches (&lang_str[1], limit, "np-hant-mo", 10)) { /* Min Bei Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2489,14 +2498,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "np-hans")) + if (lang_matches (&lang_str[1], limit, "np-hans", 7)) { /* Min Bei Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant")) + if (lang_matches (&lang_str[1], limit, "np-hant", 7)) { /* Min Bei Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2504,7 +2513,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Bei Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2512,7 +2521,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Bei Chinese; Macao */ unsigned int i; @@ -2526,7 +2535,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Bei Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2534,7 +2543,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "nw-", 3) - && subtag_matches (lang_str, limit, "-th")) + && subtag_matches (lang_str, limit, "-th", 3)) { /* Mon; Thailand */ tags[0] = HB_TAG('M','O','N','T'); /* Thailand Mon */ @@ -2543,14 +2552,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'n': - if (lang_matches (&lang_str[1], "an-hant-hk")) + if (lang_matches (&lang_str[1], limit, "an-hant-hk", 10)) { /* Min Nan Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant-mo")) + if (lang_matches (&lang_str[1], limit, "an-hant-mo", 10)) { /* Min Nan Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2563,14 +2572,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "an-hans")) + if (lang_matches (&lang_str[1], limit, "an-hans", 7)) { /* Min Nan Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant")) + if (lang_matches (&lang_str[1], limit, "an-hant", 7)) { /* Min Nan Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2578,7 +2587,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Nan Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2586,7 +2595,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Nan Chinese; Macao */ unsigned int i; @@ -2600,7 +2609,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Nan Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2624,7 +2633,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, break; case 'r': if (0 == strncmp (&lang_str[1], "o-", 2) - && subtag_matches (lang_str, limit, "-md")) + && subtag_matches (lang_str, limit, "-md", 3)) { /* Romanian; Moldova */ unsigned int i; @@ -2639,14 +2648,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'w': - if (lang_matches (&lang_str[1], "uu-hant-hk")) + if (lang_matches (&lang_str[1], limit, "uu-hant-hk", 10)) { /* Wu Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "uu-hant-mo")) + if (lang_matches (&lang_str[1], limit, "uu-hant-mo", 10)) { /* Wu Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2659,14 +2668,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "uu-hans")) + if (lang_matches (&lang_str[1], limit, "uu-hans", 7)) { /* Wu Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "uu-hant")) + if (lang_matches (&lang_str[1], limit, "uu-hant", 7)) { /* Wu Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2674,7 +2683,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "uu-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Wu Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2682,7 +2691,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "uu-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Wu Chinese; Macao */ unsigned int i; @@ -2696,7 +2705,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "uu-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Wu Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2705,7 +2714,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'y': - if (lang_matches (&lang_str[1], "ue-hans")) + if (lang_matches (&lang_str[1], limit, "ue-hans", 7)) { /* Yue Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ @@ -2714,14 +2723,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'z': - if (lang_matches (&lang_str[1], "h-hant-hk")) + if (lang_matches (&lang_str[1], limit, "h-hant-hk", 9)) { /* Chinese [macrolanguage]; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "h-hant-mo")) + if (lang_matches (&lang_str[1], limit, "h-hant-mo", 9)) { /* Chinese [macrolanguage]; Han (Traditional variant); Macao */ unsigned int i; @@ -2741,14 +2750,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } - if (lang_matches (&lang_str[1], "h-hans")) + if (lang_matches (&lang_str[1], limit, "h-hans", 6)) { /* Chinese [macrolanguage]; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "h-hant")) + if (lang_matches (&lang_str[1], limit, "h-hant", 6)) { /* Chinese [macrolanguage]; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2763,7 +2772,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "h-", 2) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Chinese [macrolanguage]; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2771,7 +2780,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "h-", 2) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Chinese [macrolanguage]; Macao */ unsigned int i; @@ -2785,7 +2794,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "h-", 2) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Chinese [macrolanguage]; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc index f50be97ad3a..a4a9515362a 100644 --- a/thirdparty/harfbuzz/src/hb-ot-tag.cc +++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc @@ -189,48 +189,46 @@ hb_ot_tag_to_script (hb_tag_t tag) /* hb_language_t */ -static bool +static inline bool subtag_matches (const char *lang_str, const char *limit, - const char *subtag) + const char *subtag, + unsigned subtag_len) { + if (likely ((unsigned) (limit - lang_str) < subtag_len)) + return false; + do { const char *s = strstr (lang_str, subtag); if (!s || s >= limit) return false; - if (!ISALNUM (s[strlen (subtag)])) + if (!ISALNUM (s[subtag_len])) return true; - lang_str = s + strlen (subtag); + lang_str = s + subtag_len; } while (true); } -static hb_bool_t -lang_matches (const char *lang_str, const char *spec) +static bool +lang_matches (const char *lang_str, + const char *limit, + const char *spec, + unsigned spec_len) { - unsigned int len = strlen (spec); + if (likely ((unsigned) (limit - lang_str) < spec_len)) + return false; - return strncmp (lang_str, spec, len) == 0 && - (lang_str[len] == '\0' || lang_str[len] == '-'); + return strncmp (lang_str, spec, spec_len) == 0 && + (lang_str[spec_len] == '\0' || lang_str[spec_len] == '-'); } struct LangTag { - char language[4]; + hb_tag_t language; hb_tag_t tag; - int cmp (const char *a) const + int cmp (hb_tag_t a) const { - const char *b = this->language; - unsigned int da, db; - const char *p; - - p = strchr (a, '-'); - da = p ? (unsigned int) (p - a) : strlen (a); - - p = strchr (b, '-'); - db = p ? (unsigned int) (p - b) : strlen (b); - - return strncmp (a, b, hb_max (da, db)); + return a < this->language ? -1 : a > this->language ? +1 : 0; } int cmp (const LangTag *that) const { return cmp (that->language); } @@ -266,7 +264,6 @@ hb_ot_tags_from_language (const char *lang_str, hb_tag_t *tags) { const char *s; - unsigned int tag_idx; /* Check for matches of multiple subtags. */ if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags)) @@ -283,17 +280,39 @@ hb_ot_tags_from_language (const char *lang_str, ISALPHA (s[1])) lang_str = s + 1; } - if (hb_sorted_array (ot_languages).bfind (lang_str, &tag_idx)) + const LangTag *ot_languages = nullptr; + unsigned ot_languages_len = 0; + const char *dash = strchr (lang_str, '-'); + unsigned first_len = dash ? dash - lang_str : limit - lang_str; + if (first_len == 2) { + ot_languages = ot_languages2; + ot_languages_len = ARRAY_LENGTH (ot_languages2); + } + else if (first_len == 3) + { + ot_languages = ot_languages3; + ot_languages_len = ARRAY_LENGTH (ot_languages3); + } + + hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len); + + static unsigned last_tag_idx; /* Poor man's cache. */ + unsigned tag_idx = last_tag_idx; + + if (likely (tag_idx < ot_languages_len && ot_languages[tag_idx].language == lang_tag) || + hb_sorted_array (ot_languages, ot_languages_len).bfind (lang_tag, &tag_idx)) + { + last_tag_idx = tag_idx; unsigned int i; while (tag_idx != 0 && - 0 == strcmp (ot_languages[tag_idx].language, ot_languages[tag_idx - 1].language)) + ot_languages[tag_idx].language == ot_languages[tag_idx - 1].language) tag_idx--; for (i = 0; i < *count && - tag_idx + i < ARRAY_LENGTH (ot_languages) && + tag_idx + i < ot_languages_len && ot_languages[tag_idx + i].tag != HB_TAG_NONE && - 0 == strcmp (ot_languages[tag_idx + i].language, ot_languages[tag_idx].language); + ot_languages[tag_idx + i].language == ot_languages[tag_idx].language; i++) tags[i] = ot_languages[tag_idx + i].tag; *count = i; @@ -459,9 +478,19 @@ hb_ot_tag_to_language (hb_tag_t tag) return disambiguated_tag; } - for (i = 0; i < ARRAY_LENGTH (ot_languages); i++) - if (ot_languages[i].tag == tag) - return hb_language_from_string (ot_languages[i].language, -1); + char buf[4]; + for (i = 0; i < ARRAY_LENGTH (ot_languages2); i++) + if (ot_languages2[i].tag == tag) + { + hb_tag_to_string (ot_languages2[i].language, buf); + return hb_language_from_string (buf, 2); + } + for (i = 0; i < ARRAY_LENGTH (ot_languages3); i++) + if (ot_languages3[i].tag == tag) + { + hb_tag_to_string (ot_languages3[i].language, buf); + return hb_language_from_string (buf, 3); + } /* Return a custom language in the form of "x-hbot-AABBCCDD". * If it's three letters long, also guess it's ISO 639-3 and lower-case and @@ -557,13 +586,23 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag, static inline void test_langs_sorted () { - for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++) + for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages2); i++) { - int c = ot_languages[i].cmp (&ot_languages[i - 1]); + int c = ot_languages2[i].cmp (&ot_languages2[i - 1]); if (c > 0) { - fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n", - i, ot_languages[i-1].language, c, ot_languages[i].language); + fprintf (stderr, "ot_languages2 not sorted at index %d: %08x %d %08x\n", + i, ot_languages2[i-1].language, c, ot_languages2[i].language); + abort(); + } + } + for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages3); i++) + { + int c = ot_languages3[i].cmp (&ot_languages3[i - 1]); + if (c > 0) + { + fprintf (stderr, "ot_languages3 not sorted at index %d: %08x %d %08x\n", + i, ot_languages3[i-1].language, c, ot_languages3[i].language); abort(); } } diff --git a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh index 618cec08fbf..3b2a38b9a61 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh @@ -390,13 +390,10 @@ struct gvar { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && (version.major == 1) && - (glyphCount == c->get_num_glyphs ()) && sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) && (is_long_offset () ? c->check_array (get_long_offset_array (), glyphCount+1) : - c->check_array (get_short_offset_array (), glyphCount+1)) && - c->check_array (((const HBUINT8*)&(this+dataZ)) + get_offset (0), - get_offset (glyphCount) - get_offset (0))); + c->check_array (get_short_offset_array (), glyphCount+1))); } /* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */ @@ -482,7 +479,9 @@ struct gvar const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const { unsigned start_offset = get_offset (glyph); - unsigned length = get_offset (glyph+1) - start_offset; + unsigned end_offset = get_offset (glyph+1); + if (unlikely (end_offset < start_offset)) return hb_bytes_t (); + unsigned length = end_offset - start_offset; hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length); return likely (var_data.length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t (); } @@ -490,7 +489,10 @@ struct gvar bool is_long_offset () const { return flags & 1; } unsigned get_offset (unsigned i) const - { return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; } + { + if (unlikely (i > glyphCount)) return 0; + return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; + } const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; } const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; } @@ -696,7 +698,7 @@ no_more_gaps: offsetZ; /* Offsets from the start of the GlyphVariationData array * to each GlyphVariationData table. */ public: - DEFINE_SIZE_MIN (20); + DEFINE_SIZE_ARRAY (20, offsetZ); }; struct gvar_accelerator_t : gvar::accelerator_t { diff --git a/thirdparty/harfbuzz/src/hb-priority-queue.hh b/thirdparty/harfbuzz/src/hb-priority-queue.hh index 7d799ae9062..ffb86e30ae2 100644 --- a/thirdparty/harfbuzz/src/hb-priority-queue.hh +++ b/thirdparty/harfbuzz/src/hb-priority-queue.hh @@ -38,18 +38,11 @@ */ struct hb_priority_queue_t { - HB_DELETE_COPY_ASSIGN (hb_priority_queue_t); - hb_priority_queue_t () { init (); } - ~hb_priority_queue_t () { fini (); } - private: typedef hb_pair_t item_t; hb_vector_t heap; public: - void init () { heap.init (); } - - void fini () { heap.fini (); } void reset () { heap.resize (0); } @@ -58,14 +51,17 @@ struct hb_priority_queue_t void insert (int64_t priority, unsigned value) { heap.push (item_t (priority, value)); + if (unlikely (heap.in_error ())) return; bubble_up (heap.length - 1); } item_t pop_minimum () { - item_t result = heap[0]; + assert (!is_empty ()); - heap[0] = heap[heap.length - 1]; + item_t result = heap.arrayZ[0]; + + heap.arrayZ[0] = heap.arrayZ[heap.length - 1]; heap.shrink (heap.length - 1); bubble_down (0); @@ -104,6 +100,8 @@ struct hb_priority_queue_t void bubble_down (unsigned index) { + assert (index <= heap.length); + unsigned left = left_child (index); unsigned right = right_child (index); @@ -113,11 +111,11 @@ struct hb_priority_queue_t return; bool has_right = right < heap.length; - if (heap[index].first <= heap[left].first - && (!has_right || heap[index].first <= heap[right].first)) + if (heap.arrayZ[index].first <= heap.arrayZ[left].first + && (!has_right || heap[index].first <= heap.arrayZ[right].first)) return; - if (!has_right || heap[left].first < heap[right].first) + if (!has_right || heap.arrayZ[left].first < heap.arrayZ[right].first) { swap (index, left); bubble_down (left); @@ -130,10 +128,12 @@ struct hb_priority_queue_t void bubble_up (unsigned index) { + assert (index <= heap.length); + if (index == 0) return; unsigned parent_index = parent (index); - if (heap[parent_index].first <= heap[index].first) + if (heap.arrayZ[parent_index].first <= heap.arrayZ[index].first) return; swap (index, parent_index); @@ -142,9 +142,9 @@ struct hb_priority_queue_t void swap (unsigned a, unsigned b) { - item_t temp = heap[a]; - heap[a] = heap[b]; - heap[b] = temp; + assert (a <= heap.length); + assert (b <= heap.length); + hb_swap (heap.arrayZ[a], heap.arrayZ[b]); } }; diff --git a/thirdparty/harfbuzz/src/hb-repacker.hh b/thirdparty/harfbuzz/src/hb-repacker.hh index 2a9e75c45b1..ce9ff90bb4f 100644 --- a/thirdparty/harfbuzz/src/hb-repacker.hh +++ b/thirdparty/harfbuzz/src/hb-repacker.hh @@ -49,6 +49,17 @@ struct graph_t unsigned end = 0; unsigned priority = 0; + friend void swap (vertex_t& a, vertex_t& b) + { + hb_swap (a.obj, b.obj); + hb_swap (a.distance, b.distance); + hb_swap (a.space, b.space); + hb_swap (a.parents, b.parents); + hb_swap (a.start, b.start); + hb_swap (a.end, b.end); + hb_swap (a.priority, b.priority); + } + bool is_shared () const { return parents.length > 1; @@ -148,6 +159,8 @@ struct graph_t { num_roots_for_space_.push (1); bool removed_nil = false; + vertices_.alloc (objects.length); + vertices_scratch_.alloc (objects.length); for (unsigned i = 0; i < objects.length; i++) { // TODO(grieger): check all links point to valid objects. @@ -246,59 +259,6 @@ struct graph_t return c.copy_blob (); } - /* - * Generates a new topological sorting of graph using Kahn's - * algorithm: https://en.wikipedia.org/wiki/Topological_sorting#Algorithms - */ - void sort_kahn () - { - positions_invalid = true; - - if (vertices_.length <= 1) { - // Graph of 1 or less doesn't need sorting. - return; - } - - hb_vector_t queue; - hb_vector_t sorted_graph; - if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return; - hb_vector_t id_map; - if (unlikely (!check_success (id_map.resize (vertices_.length)))) return; - - hb_vector_t removed_edges; - if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; - update_parents (); - - queue.push (root_idx ()); - int new_id = vertices_.length - 1; - - while (!queue.in_error () && queue.length) - { - unsigned next_id = queue[0]; - queue.remove (0); - - vertex_t& next = vertices_[next_id]; - sorted_graph[new_id] = next; - id_map[next_id] = new_id--; - - for (const auto& link : next.obj.all_links ()) { - removed_edges[link.objidx]++; - if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx])) - queue.push (link.objidx); - } - } - - check_success (!queue.in_error ()); - check_success (!sorted_graph.in_error ()); - if (!check_success (new_id == -1)) - print_orphaned_nodes (); - - remap_all_obj_indices (id_map, &sorted_graph); - - hb_swap (vertices_, sorted_graph); - sorted_graph.fini (); - } - /* * Generates a new topological sorting of graph ordered by the shortest * distance to each node. @@ -315,7 +275,7 @@ struct graph_t update_distances (); hb_priority_queue_t queue; - hb_vector_t sorted_graph; + hb_vector_t &sorted_graph = vertices_scratch_; if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return; hb_vector_t id_map; if (unlikely (!check_success (id_map.resize (vertices_.length)))) return; @@ -331,8 +291,9 @@ struct graph_t { unsigned next_id = queue.pop_minimum().second; - vertex_t& next = vertices_[next_id]; - sorted_graph[new_id] = next; + hb_swap (sorted_graph[new_id], vertices_[next_id]); + const vertex_t& next = sorted_graph[new_id]; + id_map[next_id] = new_id--; for (const auto& link : next.obj.all_links ()) { @@ -356,7 +317,6 @@ struct graph_t remap_all_obj_indices (id_map, &sorted_graph); hb_swap (vertices_, sorted_graph); - sorted_graph.fini (); } /* @@ -568,12 +528,10 @@ struct graph_t // The last object is the root of the graph, so swap back the root to the end. // The root's obj idx does change, however since it's root nothing else refers to it. // all other obj idx's will be unaffected. - vertex_t root = vertices_[vertices_.length - 2]; - vertices_[clone_idx] = *clone; - vertices_[vertices_.length - 1] = root; + hb_swap (vertices_[vertices_.length - 2], *clone); // Since the root moved, update the parents arrays of all children on the root. - for (const auto& l : root.obj.all_links ()) + for (const auto& l : root ().obj.all_links ()) vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ()); return clone_idx; @@ -1090,6 +1048,7 @@ struct graph_t public: // TODO(garretrieger): make private, will need to move most of offset overflow code into graph. hb_vector_t vertices_; + hb_vector_t vertices_scratch_; private: bool parents_invalid; bool distance_invalid; @@ -1217,7 +1176,6 @@ hb_resolve_overflows (const T& packed, // Kahn sort is ~twice as fast as shortest distance sort and works for many fonts // so try it first to save time. graph_t sorted_graph (packed); - sorted_graph.sort_kahn (); if (!sorted_graph.will_overflow ()) { return sorted_graph.serialize (); diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh index 40895a45482..5663b290c3b 100644 --- a/thirdparty/harfbuzz/src/hb-serialize.hh +++ b/thirdparty/harfbuzz/src/hb-serialize.hh @@ -74,7 +74,7 @@ struct hb_serialize_context_t } object_t () = default; - + #ifdef HB_EXPERIMENTAL_API object_t (const hb_object_t &o) { @@ -91,6 +91,15 @@ struct hb_serialize_context_t } #endif + friend void swap (object_t& a, object_t& b) + { + hb_swap (a.head, b.head); + hb_swap (a.tail, b.tail); + hb_swap (a.next, b.next); + hb_swap (a.real_links, b.real_links); + hb_swap (a.virtual_links, b.virtual_links); + } + bool operator == (const object_t &o) const { // Virtual links aren't considered for equality since they don't affect the functionality @@ -111,10 +120,10 @@ struct hb_serialize_context_t struct link_t { unsigned width: 3; - bool is_signed: 1; + unsigned is_signed: 1; unsigned whence: 2; - unsigned position: 28; - unsigned bias; + unsigned bias : 26; + unsigned position; objidx_t objidx; link_t () = default; diff --git a/thirdparty/harfbuzz/src/hb-set.hh b/thirdparty/harfbuzz/src/hb-set.hh index 1f054078692..60256263637 100644 --- a/thirdparty/harfbuzz/src/hb-set.hh +++ b/thirdparty/harfbuzz/src/hb-set.hh @@ -43,8 +43,8 @@ struct hb_sparseset_t hb_sparseset_t (const hb_sparseset_t& other) : hb_sparseset_t () { set (other); } hb_sparseset_t (hb_sparseset_t&& other) : hb_sparseset_t () { s = std::move (other.s); } - hb_sparseset_t& operator= (const hb_sparseset_t& other) { set (other); return *this; } - hb_sparseset_t& operator= (hb_sparseset_t&& other) { hb_swap (*this, other); return *this; } + hb_sparseset_t& operator = (const hb_sparseset_t& other) { set (other); return *this; } + hb_sparseset_t& operator = (hb_sparseset_t&& other) { s = std::move (other.s); return *this; } friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) { hb_swap (a.s, b.s); } hb_sparseset_t (std::initializer_list lst) : hb_sparseset_t () @@ -53,7 +53,7 @@ struct hb_sparseset_t add (item); } template + hb_requires (hb_is_iterable (Iterable))> hb_sparseset_t (const Iterable &o) : hb_sparseset_t () { hb_copy (o, *this); @@ -77,10 +77,12 @@ struct hb_sparseset_t void err () { s.err (); } bool in_error () const { return s.in_error (); } + void alloc (unsigned sz) { s.alloc (sz); } void reset () { s.reset (); } void clear () { s.clear (); } void invert () { s.invert (); } bool is_empty () const { return s.is_empty (); } + uint32_t hash () const { return s.hash (); } void add (hb_codepoint_t g) { s.add (g); } bool add_range (hb_codepoint_t a, hb_codepoint_t b) { return s.add_range (a, b); } @@ -125,6 +127,8 @@ struct hb_sparseset_t void set (const hb_sparseset_t &other) { s.set (other.s); } bool is_equal (const hb_sparseset_t &other) const { return s.is_equal (other.s); } + bool operator == (const hb_set_t &other) const { return is_equal (other); } + bool operator != (const hb_set_t &other) const { return !is_equal (other); } bool is_subset (const hb_sparseset_t &larger_set) const { return s.is_subset (larger_set.s); } @@ -158,15 +162,19 @@ struct hb_sparseset_t struct hb_set_t : hb_sparseset_t { - hb_set_t () = default; + using sparseset = hb_sparseset_t; + ~hb_set_t () = default; - hb_set_t (hb_set_t&) = default; - hb_set_t& operator= (const hb_set_t&) = default; - hb_set_t& operator= (hb_set_t&&) = default; - hb_set_t (std::initializer_list lst) : hb_sparseset_t (lst) {} + hb_set_t () : sparseset () {}; + hb_set_t (std::nullptr_t) : hb_set_t () {}; + hb_set_t (const hb_set_t &o) : sparseset ((sparseset &) o) {}; + hb_set_t (hb_set_t&& o) : sparseset (std::move ((sparseset &) o)) {} + hb_set_t& operator = (const hb_set_t&) = default; + hb_set_t& operator = (hb_set_t&&) = default; + hb_set_t (std::initializer_list lst) : sparseset (lst) {} template - hb_set_t (const Iterable &o) : hb_sparseset_t (o) {} + hb_set_t (const Iterable &o) : sparseset (o) {} }; static_assert (hb_set_t::INVALID == HB_SET_VALUE_INVALID, ""); diff --git a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh index 18657705fac..ae155b4e3c8 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh +++ b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh @@ -40,7 +40,7 @@ struct str_encoder_t str_encoder_t (str_buff_t &buff_) : buff (buff_), error (false) {} - void reset () { buff.resize (0); } + void reset () { buff.reset (); } void encode_byte (unsigned char b) { @@ -107,20 +107,18 @@ struct str_encoder_t encode_byte (op); } - void copy_str (const byte_str_t &str) + void copy_str (const hb_ubytes_t &str) { unsigned int offset = buff.length; - if (unlikely (!buff.resize (offset + str.length))) + /* Manually resize buffer since faster. */ + if ((signed) (buff.length + str.length) <= buff.allocated) + buff.length += str.length; + else if (unlikely (!buff.resize (offset + str.length))) { set_error (); return; } - if (unlikely (buff.length < offset + str.length)) - { - set_error (); - return; - } - memcpy (&buff[offset], &str[0], str.length); + memcpy (buff.arrayZ + offset, &str[0], str.length); } bool is_error () const { return error; } @@ -253,12 +251,12 @@ struct subr_flattener_t if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op); continue; } - const byte_str_t str = (*acc.charStrings)[glyph]; + const hb_ubytes_t str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - cs_interpreter_t interp; - interp.env.init (str, acc, fd); + ENV env (str, acc, fd); + cs_interpreter_t interp (env); flatten_param_t param = { flat_charstrings[i], (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) @@ -317,9 +315,9 @@ struct parsed_cs_op_t : op_str_t unsigned int subr_num; protected: - bool drop_flag : 1; - bool keep_flag : 1; - bool skip_flag : 1; + bool drop_flag; + bool keep_flag; + bool skip_flag; }; struct parsed_cs_str_t : parsed_values_t @@ -398,19 +396,19 @@ struct parsed_cs_str_vec_t : hb_vector_t struct subr_subset_param_t { - void init (parsed_cs_str_t *parsed_charstring_, - parsed_cs_str_vec_t *parsed_global_subrs_, parsed_cs_str_vec_t *parsed_local_subrs_, - hb_set_t *global_closure_, hb_set_t *local_closure_, - bool drop_hints_) - { - parsed_charstring = parsed_charstring_; - current_parsed_str = parsed_charstring; - parsed_global_subrs = parsed_global_subrs_; - parsed_local_subrs = parsed_local_subrs_; - global_closure = global_closure_; - local_closure = local_closure_; - drop_hints = drop_hints_; - } + subr_subset_param_t (parsed_cs_str_t *parsed_charstring_, + parsed_cs_str_vec_t *parsed_global_subrs_, + parsed_cs_str_vec_t *parsed_local_subrs_, + hb_set_t *global_closure_, + hb_set_t *local_closure_, + bool drop_hints_) : + current_parsed_str (parsed_charstring_), + parsed_charstring (parsed_charstring_), + parsed_global_subrs (parsed_global_subrs_), + parsed_local_subrs (parsed_local_subrs_), + global_closure (global_closure_), + local_closure (local_closure_), + drop_hints (drop_hints_) {} parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context) { @@ -468,6 +466,7 @@ struct subr_remap_t : hb_inc_bimap_t * no optimization based on usage counts. fonttools doesn't appear doing that either. */ + resize (closure->get_population ()); hb_codepoint_t old_num = HB_SET_VALUE_INVALID; while (hb_set_next (closure, &old_num)) add (old_num); @@ -561,19 +560,21 @@ struct subr_subsetter_t hb_codepoint_t glyph; if (!plan->old_gid_for_new_gid (i, &glyph)) continue; - const byte_str_t str = (*acc.charStrings)[glyph]; + const hb_ubytes_t str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - cs_interpreter_t interp; - interp.env.init (str, acc, fd); + ENV env (str, acc, fd); + cs_interpreter_t interp (env); - subr_subset_param_t param; - param.init (&parsed_charstrings[i], - &parsed_global_subrs, &parsed_local_subrs[fd], - &closures.global_closure, &closures.local_closures[fd], - plan->flags & HB_SUBSET_FLAGS_NO_HINTING); + parsed_charstrings[i].alloc (str.length); + subr_subset_param_t param (&parsed_charstrings[i], + &parsed_global_subrs, + &parsed_local_subrs[fd], + &closures.global_closure, + &closures.local_closures[fd], + plan->flags & HB_SUBSET_FLAGS_NO_HINTING); if (unlikely (!interp.interpret (param))) return false; @@ -593,11 +594,12 @@ struct subr_subsetter_t unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - subr_subset_param_t param; - param.init (&parsed_charstrings[i], - &parsed_global_subrs, &parsed_local_subrs[fd], - &closures.global_closure, &closures.local_closures[fd], - plan->flags & HB_SUBSET_FLAGS_NO_HINTING); + subr_subset_param_t param (&parsed_charstrings[i], + &parsed_global_subrs, + &parsed_local_subrs[fd], + &closures.global_closure, + &closures.local_closures[fd], + plan->flags & HB_SUBSET_FLAGS_NO_HINTING); drop_hints_param_t drop; if (drop_hints_in_str (parsed_charstrings[i], param, drop)) @@ -618,11 +620,12 @@ struct subr_subsetter_t unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - subr_subset_param_t param; - param.init (&parsed_charstrings[i], - &parsed_global_subrs, &parsed_local_subrs[fd], - &closures.global_closure, &closures.local_closures[fd], - plan->flags & HB_SUBSET_FLAGS_NO_HINTING); + subr_subset_param_t param (&parsed_charstrings[i], + &parsed_global_subrs, + &parsed_local_subrs[fd], + &closures.global_closure, + &closures.local_closures[fd], + plan->flags & HB_SUBSET_FLAGS_NO_HINTING); collect_subr_refs_in_str (parsed_charstrings[i], param); } } @@ -849,9 +852,10 @@ struct subr_subsetter_t bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const { - buff.init (); + unsigned count = str.get_count (); str_encoder_t encoder (buff); encoder.reset (); + buff.alloc (count * 3); /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints, * re-insert it at the beginning of charstreing */ if (str.has_prefix () && str.is_hint_dropped ()) @@ -860,7 +864,7 @@ struct subr_subsetter_t if (str.prefix_op () != OpCode_Invalid) encoder.encode_op (str.prefix_op ()); } - for (unsigned int i = 0; i < str.get_count(); i++) + for (unsigned int i = 0; i < count; i++) { const parsed_cs_op_t &opstr = str.values[i]; if (!opstr.for_drop () && !opstr.for_skip ()) diff --git a/thirdparty/harfbuzz/src/hb-subset-cff1.cc b/thirdparty/harfbuzz/src/hb-subset-cff1.cc index 35fecd67bc5..52bb13d320b 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff1.cc +++ b/thirdparty/harfbuzz/src/hb-subset-cff1.cc @@ -169,7 +169,7 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t= opstr.last_arg_offset + 3))) return_trace (false); - supp_op.str = byte_str_t (&opstr.str + opstr.last_arg_offset, opstr.str.length - opstr.last_arg_offset); + supp_op.str = hb_ubytes_t (&opstr.str + opstr.last_arg_offset, opstr.str.length - opstr.last_arg_offset); return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::registry]) && UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) && copy_opstr (c, supp_op)); @@ -270,13 +270,13 @@ struct range_list_t : hb_vector_t /* replace the first glyph ID in the "glyph" field each range with a nLeft value */ bool complete (unsigned int last_glyph) { - bool two_byte = false; - for (unsigned int i = (*this).length; i > 0; i--) + bool two_byte = false; + unsigned count = this->length; + for (unsigned int i = count; i; i--) { - code_pair_t &pair = (*this)[i - 1]; - unsigned int nLeft = last_glyph - pair.glyph - 1; - if (nLeft >= 0x100) - two_byte = true; + code_pair_t &pair = arrayZ[i - 1]; + unsigned int nLeft = last_glyph - pair.glyph - 1; + two_byte |= nLeft >= 0x100; last_glyph = pair.glyph; pair.glyph = nLeft; } @@ -442,6 +442,9 @@ struct cff_subset_plan { return; } + bool use_glyph_to_sid_map = plan->num_output_glyphs () > plan->source->get_num_glyphs () / 8.; + hb_map_t *glyph_to_sid_map = use_glyph_to_sid_map ? acc.create_glyph_to_sid_map () : nullptr; + unsigned int glyph; for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++) { @@ -451,7 +454,7 @@ struct cff_subset_plan { /* Retain the SID for the old missing glyph ID */ old_glyph = glyph; } - sid = acc.glyph_to_sid (old_glyph); + sid = glyph_to_sid_map ? glyph_to_sid_map->get (old_glyph) : acc.glyph_to_sid (old_glyph); if (!acc.is_CID ()) sid = sidmap.add (sid); @@ -464,6 +467,9 @@ struct cff_subset_plan { last_sid = sid; } + if (glyph_to_sid_map) + hb_map_destroy (glyph_to_sid_map); + bool two_byte = subset_charset_ranges.complete (glyph); size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1); diff --git a/thirdparty/harfbuzz/src/hb-subset-cff2.cc b/thirdparty/harfbuzz/src/hb-subset-cff2.cc index 92dd6b1d2ca..08e820efcfb 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff2.cc +++ b/thirdparty/harfbuzz/src/hb-subset-cff2.cc @@ -67,9 +67,9 @@ struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<> } }; -struct cff2_cs_opset_flatten_t : cff2_cs_opset_t +struct cff2_cs_opset_flatten_t : cff2_cs_opset_t { - static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) + static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) { switch (op) { @@ -97,7 +97,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t &env, flatten_param_t& param) { for (unsigned int i = 0; i < env.argStack.get_count ();) { @@ -122,7 +122,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t &env, flatten_param_t& param) { /* flatten the default values */ str_encoder_t encoder (param.flatStr); @@ -149,7 +149,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t &env, flatten_param_t& param) { switch (op) { @@ -163,13 +163,13 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t SUPER; - typedef cs_opset_t CSOPSET; + typedef cff2_cs_opset_t SUPER; + typedef cs_opset_t, flatten_param_t> CSOPSET; }; -struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t +struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t { - static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param) + static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param) { switch (op) { @@ -201,7 +201,7 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t &env, subr_subset_param_t& param, cff2_biased_subrs_t& subrs, hb_set_t *closure) { byte_str_ref_t str_ref = env.str_ref; @@ -212,15 +212,15 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t SUPER; + typedef cff2_cs_opset_t SUPER; }; -struct cff2_subr_subsetter_t : subr_subsetter_t +struct cff2_subr_subsetter_t : subr_subsetter_t, cff2_cs_opset_subr_subset_t> { cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_) : subr_subsetter_t (acc_, plan_) {} - static void complete_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) + static void complete_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) { /* vsindex is inserted at the beginning of the charstring as necessary */ if (env.seen_vsindex ()) @@ -245,7 +245,7 @@ struct cff2_subset_plan { if (desubroutinize) { /* Flatten global & local subrs */ - subr_flattener_t + subr_flattener_t, cff2_cs_opset_flatten_t> flattener(acc, plan); if (!flattener.flatten (subset_charstrings)) return false; diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc index 74b7e3977c0..a62ae8e0245 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.cc +++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc @@ -279,12 +279,7 @@ static inline void _remove_invalid_gids (hb_set_t *glyphs, unsigned int num_glyphs) { - hb_codepoint_t gid = HB_SET_VALUE_INVALID; - while (glyphs->next (&gid)) - { - if (gid >= num_glyphs) - glyphs->del (gid); - } + glyphs->del_range (num_glyphs, HB_SET_VALUE_INVALID); } static void @@ -294,12 +289,13 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, { OT::cmap::accelerator_t cmap (plan->source); - constexpr static const int size_threshold = 4096; - + unsigned size_threshold = plan->source->get_num_glyphs (); if (glyphs->is_empty () && unicodes->get_population () < size_threshold) { - /* This is the fast path if it's anticipated that size of unicodes - * is << than the number of codepoints in the font. */ + // This is approach to collection is faster, but can only be used if glyphs + // are not being explicitly added to the subset and the input unicodes set is + // not excessively large (eg. an inverted set). + plan->unicode_to_new_gid_list.alloc (unicodes->get_population ()); for (hb_codepoint_t cp : *unicodes) { hb_codepoint_t gid; @@ -310,27 +306,32 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, } plan->codepoint_to_glyph->set (cp, gid); + plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); } } else { + // This approach is slower, but can handle adding in glyphs to the subset and will match + // them with cmap entries. hb_map_t unicode_glyphid_map; - cmap.collect_mapping (hb_set_get_empty (), &unicode_glyphid_map); + hb_set_t cmap_unicodes; + cmap.collect_mapping (&cmap_unicodes, &unicode_glyphid_map); + plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population () + + glyphs->get_population (), + cmap_unicodes.get_population ())); - for (hb_pair_t cp_gid : - + unicode_glyphid_map.iter ()) + for (hb_codepoint_t cp : cmap_unicodes) { - if (!unicodes->has (cp_gid.first) && !glyphs->has (cp_gid.second)) - continue; + hb_codepoint_t gid = unicode_glyphid_map[cp]; + if (!unicodes->has (cp) && !glyphs->has (gid)) + continue; - plan->codepoint_to_glyph->set (cp_gid.first, cp_gid.second); + plan->codepoint_to_glyph->set (cp, gid); + plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); } /* Add gids which where requested, but not mapped in cmap */ - // TODO(garretrieger): - // Once https://github.com/harfbuzz/harfbuzz/issues/3169 - // is implemented, this can be done with union and del_range - for (hb_codepoint_t gid : glyphs->iter ()) + for (hb_codepoint_t gid : *glyphs) { if (gid >= plan->source->get_num_glyphs ()) break; @@ -338,8 +339,12 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, } } - + plan->codepoint_to_glyph->keys () | hb_sink (plan->unicodes); - + plan->codepoint_to_glyph->values () | hb_sink (plan->_glyphset_gsub); + auto &arr = plan->unicode_to_new_gid_list; + if (arr.length) + { + plan->unicodes->add_sorted_array (&arr.arrayZ->first, arr.length, sizeof (*arr.arrayZ)); + plan->_glyphset_gsub->add_array (&arr.arrayZ->second, arr.length, sizeof (*arr.arrayZ)); + } } static void @@ -388,16 +393,19 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ()); hb_set_set (plan->_glyphset_colred, &cur_glyphset); - // Populate a full set of glyphs to retain by adding all referenced - // composite glyphs. - for (hb_codepoint_t gid : cur_glyphset.iter ()) - { - glyf.add_gid_and_children (gid, plan->_glyphset); + + /* Populate a full set of glyphs to retain by adding all referenced + * composite glyphs. */ + if (glyf.has_data ()) + for (hb_codepoint_t gid : cur_glyphset) + glyf.add_gid_and_children (gid, plan->_glyphset); + else + plan->_glyphset->union_ (cur_glyphset); #ifndef HB_NO_SUBSET_CFF - if (cff.is_valid ()) + if (cff.is_valid ()) + for (hb_codepoint_t gid : cur_glyphset) _add_cff_seac_components (cff, gid, plan->_glyphset); #endif - } _remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ()); @@ -412,6 +420,20 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, #endif } +static void +_create_glyph_map_gsub (const hb_set_t* glyph_set_gsub, + const hb_map_t* glyph_map, + hb_map_t* out) +{ + + hb_iter (glyph_set_gsub) + | hb_map ([&] (hb_codepoint_t gid) { + return hb_pair_t (gid, + glyph_map->get (gid)); + }) + | hb_sink (out) + ; +} + static void _create_old_gid_to_new_gid_map (const hb_face_t *face, bool retain_gids, @@ -420,13 +442,19 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, hb_map_t *reverse_glyph_map, /* OUT */ unsigned int *num_glyphs /* OUT */) { + unsigned pop = all_gids_to_retain->get_population (); + reverse_glyph_map->resize (pop); + glyph_map->resize (pop); + if (!retain_gids) { + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0) | hb_sink (reverse_glyph_map) ; *num_glyphs = reverse_glyph_map->get_population (); - } else { + } + else + { + hb_iter (all_gids_to_retain) | hb_map ([] (hb_codepoint_t _) { return hb_pair_t (_, _); @@ -434,10 +462,9 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, | hb_sink (reverse_glyph_map) ; - unsigned max_glyph = - + hb_iter (all_gids_to_retain) - | hb_reduce (hb_max, 0u) - ; + hb_codepoint_t max_glyph = HB_SET_VALUE_INVALID; + hb_set_previous (all_gids_to_retain, &max_glyph); + *num_glyphs = max_glyph + 1; } @@ -485,6 +512,9 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->successful = true; plan->flags = input->flags; plan->unicodes = hb_set_create (); + + plan->unicode_to_new_gid_list.init (); + plan->name_ids = hb_set_copy (input->sets.name_ids); _nameid_closure (face, plan->name_ids); plan->name_languages = hb_set_copy (input->sets.name_languages); @@ -502,6 +532,7 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->codepoint_to_glyph = hb_map_create (); plan->glyph_map = hb_map_create (); plan->reverse_glyph_map = hb_map_create (); + plan->glyph_map_gsub = hb_map_create (); plan->gsub_lookups = hb_map_create (); plan->gpos_lookups = hb_map_create (); @@ -536,6 +567,19 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->reverse_glyph_map, &plan->_num_output_glyphs); + _create_glyph_map_gsub ( + plan->_glyphset_gsub, + plan->glyph_map, + plan->glyph_map_gsub); + + // Now that we have old to new gid map update the unicode to new gid list. + for (unsigned i = 0; i < plan->unicode_to_new_gid_list.length; i++) + { + // Use raw array access for performance. + plan->unicode_to_new_gid_list.arrayZ[i].second = + plan->glyph_map->get(plan->unicode_to_new_gid_list.arrayZ[i].second); + } + if (unlikely (plan->in_error ())) { hb_subset_plan_destroy (plan); return nullptr; @@ -558,6 +602,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) if (!hb_object_destroy (plan)) return; hb_set_destroy (plan->unicodes); + plan->unicode_to_new_gid_list.fini (); hb_set_destroy (plan->name_ids); hb_set_destroy (plan->name_languages); hb_set_destroy (plan->layout_features); @@ -569,6 +614,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_map_destroy (plan->codepoint_to_glyph); hb_map_destroy (plan->glyph_map); hb_map_destroy (plan->reverse_glyph_map); + hb_map_destroy (plan->glyph_map_gsub); hb_set_destroy (plan->_glyphset); hb_set_destroy (plan->_glyphset_gsub); hb_set_destroy (plan->_glyphset_mathed); diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh index ab2c4c302c5..cb567b769ea 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.hh +++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh @@ -44,6 +44,7 @@ struct hb_subset_plan_t // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; + hb_vector_t> unicode_to_new_gid_list; // name_ids we would like to retain hb_set_t *name_ids; @@ -69,6 +70,7 @@ struct hb_subset_plan_t // Old -> New glyph id mapping hb_map_t *glyph_map; hb_map_t *reverse_glyph_map; + hb_map_t *glyph_map_gsub; // Plan is only good for a specific source/dest so keep them with it hb_face_t *source; diff --git a/thirdparty/harfbuzz/src/hb-subset.cc b/thirdparty/harfbuzz/src/hb-subset.cc index 4588268b762..31ddb4f8940 100644 --- a/thirdparty/harfbuzz/src/hb-subset.cc +++ b/thirdparty/harfbuzz/src/hb-subset.cc @@ -79,12 +79,14 @@ using OT::Layout::GSUB::GSUB; */ static unsigned -_plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len) +_plan_estimate_subset_table_size (hb_subset_plan_t *plan, + unsigned table_len, + bool same_size) { unsigned src_glyphs = plan->source->get_num_glyphs (); unsigned dst_glyphs = plan->glyphset ()->get_population (); - if (unlikely (!src_glyphs)) + if (unlikely (!src_glyphs) || same_size) return 512 + table_len; return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); @@ -123,7 +125,6 @@ static bool _try_subset (const TableType *table, hb_vector_t* buf, - unsigned buf_size, hb_subset_context_t* c /* OUT */) { c->serializer->start_serialize (); @@ -136,7 +137,8 @@ _try_subset (const TableType *table, return needed; } - buf_size += (buf_size >> 1) + 32; + unsigned buf_size = buf->allocated; + buf_size = buf_size * 2 + 16; DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (c->table_tag), buf_size); @@ -147,13 +149,13 @@ _try_subset (const TableType *table, return needed; } - c->serializer->reset (buf->arrayZ, buf_size); - return _try_subset (table, buf, buf_size, c); + c->serializer->reset (buf->arrayZ, buf->allocated); + return _try_subset (table, buf, c); } template static bool -_subset (hb_subset_plan_t *plan) +_subset (hb_subset_plan_t *plan, hb_vector_t &buf) { hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table (plan->source); const TableType *table = source_blob->as (); @@ -167,10 +169,13 @@ _subset (hb_subset_plan_t *plan) return false; } - hb_vector_t buf; - /* TODO Not all tables are glyph-related. 'name' table size for example should not be - * affected by number of glyphs. Accommodate that. */ - unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); + /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's + * because those are expensive to subset, so giving them more room is fine. */ + bool same_size_table = TableType::tableTag == HB_OT_TAG_GSUB || + TableType::tableTag == HB_OT_TAG_GPOS || + TableType::tableTag == HB_OT_TAG_name; + + unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length, same_size_table); DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); if (unlikely (!buf.alloc (buf_size))) @@ -181,10 +186,10 @@ _subset (hb_subset_plan_t *plan) } bool needed = false; - hb_serialize_context_t serializer (buf.arrayZ, buf_size); + hb_serialize_context_t serializer (buf.arrayZ, buf.allocated); { hb_subset_context_t c (source_blob, plan, &serializer, tag); - needed = _try_subset (table, &buf, buf_size, &c); + needed = _try_subset (table, &buf, &c); } hb_blob_destroy (source_blob); @@ -274,7 +279,9 @@ _passthrough (hb_subset_plan_t *plan, hb_tag_t tag) } static bool -_subset_table (hb_subset_plan_t *plan, hb_tag_t tag) +_subset_table (hb_subset_plan_t *plan, + hb_vector_t &buf, + hb_tag_t tag) { if (plan->no_subset_tables->has (tag)) { return _passthrough (plan, tag); @@ -283,42 +290,42 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag) DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag)); switch (tag) { - case HB_OT_TAG_glyf: return _subset (plan); - case HB_OT_TAG_hdmx: return _subset (plan); - case HB_OT_TAG_name: return _subset (plan); + case HB_OT_TAG_glyf: return _subset (plan, buf); + case HB_OT_TAG_hdmx: return _subset (plan, buf); + case HB_OT_TAG_name: return _subset (plan, buf); case HB_OT_TAG_head: if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf)) return true; /* skip head, handled by glyf */ - return _subset (plan); + return _subset (plan, buf); case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */ - case HB_OT_TAG_hmtx: return _subset (plan); + case HB_OT_TAG_hmtx: return _subset (plan, buf); case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */ - case HB_OT_TAG_vmtx: return _subset (plan); - case HB_OT_TAG_maxp: return _subset (plan); - case HB_OT_TAG_sbix: return _subset (plan); + case HB_OT_TAG_vmtx: return _subset (plan, buf); + case HB_OT_TAG_maxp: return _subset (plan, buf); + case HB_OT_TAG_sbix: return _subset (plan, buf); case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */ - case HB_OT_TAG_cmap: return _subset (plan); - case HB_OT_TAG_OS2 : return _subset (plan); - case HB_OT_TAG_post: return _subset (plan); - case HB_OT_TAG_COLR: return _subset (plan); - case HB_OT_TAG_CPAL: return _subset (plan); - case HB_OT_TAG_CBLC: return _subset (plan); + case HB_OT_TAG_cmap: return _subset (plan, buf); + case HB_OT_TAG_OS2 : return _subset (plan, buf); + case HB_OT_TAG_post: return _subset (plan, buf); + case HB_OT_TAG_COLR: return _subset (plan, buf); + case HB_OT_TAG_CPAL: return _subset (plan, buf); + case HB_OT_TAG_CBLC: return _subset (plan, buf); case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */ - case HB_OT_TAG_MATH: return _subset (plan); + case HB_OT_TAG_MATH: return _subset (plan, buf); #ifndef HB_NO_SUBSET_CFF - case HB_OT_TAG_cff1: return _subset (plan); - case HB_OT_TAG_cff2: return _subset (plan); - case HB_OT_TAG_VORG: return _subset (plan); + case HB_OT_TAG_cff1: return _subset (plan, buf); + case HB_OT_TAG_cff2: return _subset (plan, buf); + case HB_OT_TAG_VORG: return _subset (plan, buf); #endif #ifndef HB_NO_SUBSET_LAYOUT - case HB_OT_TAG_GDEF: return _subset (plan); - case HB_OT_TAG_GSUB: return _subset (plan); - case HB_OT_TAG_GPOS: return _subset (plan); - case HB_OT_TAG_gvar: return _subset (plan); - case HB_OT_TAG_HVAR: return _subset (plan); - case HB_OT_TAG_VVAR: return _subset (plan); + case HB_OT_TAG_GDEF: return _subset (plan, buf); + case HB_OT_TAG_GSUB: return _subset (plan, buf); + case HB_OT_TAG_GPOS: return _subset (plan, buf); + case HB_OT_TAG_gvar: return _subset (plan, buf); + case HB_OT_TAG_HVAR: return _subset (plan, buf); + case HB_OT_TAG_VVAR: return _subset (plan, buf); #endif default: @@ -379,6 +386,8 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) bool success = true; hb_tag_t table_tags[32]; unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); + hb_vector_t buf; + buf.alloc (4096 - 16); while ((hb_face_get_table_tags (plan->source, offset, &num_tables, table_tags), num_tables)) { for (unsigned i = 0; i < num_tables; ++i) @@ -386,7 +395,7 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) hb_tag_t tag = table_tags[i]; if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue; tags_set.add (tag); - success = _subset_table (plan, tag); + success = _subset_table (plan, buf, tag); if (unlikely (!success)) goto end; } offset += num_tables; diff --git a/thirdparty/harfbuzz/src/hb-vector.hh b/thirdparty/harfbuzz/src/hb-vector.hh index 6c7d32e49d8..7b08e3b4d27 100644 --- a/thirdparty/harfbuzz/src/hb-vector.hh +++ b/thirdparty/harfbuzz/src/hb-vector.hh @@ -29,6 +29,7 @@ #include "hb.hh" #include "hb-array.hh" +#include "hb-meta.hh" #include "hb-null.hh" @@ -42,6 +43,7 @@ struct hb_vector_t : std::conditional, hb_empty using c_array_t = typename std::conditional, hb_array_t>::type; hb_vector_t () = default; + hb_vector_t (std::nullptr_t) : hb_vector_t () {} hb_vector_t (std::initializer_list lst) : hb_vector_t () { alloc (lst.size ()); @@ -59,7 +61,8 @@ struct hb_vector_t : std::conditional, hb_empty hb_vector_t (const hb_vector_t &o) : hb_vector_t () { alloc (o.length); - hb_copy (o, *this); + if (unlikely (in_error ())) return; + copy_vector (o); } hb_vector_t (hb_vector_t &&o) { @@ -70,9 +73,8 @@ struct hb_vector_t : std::conditional, hb_empty } ~hb_vector_t () { fini (); } - private: - int allocated = 0; /* == -1 means allocation failed. */ public: + int allocated = 0; /* == -1 means allocation failed. */ unsigned int length = 0; public: Type *arrayZ = nullptr; @@ -108,7 +110,10 @@ struct hb_vector_t : std::conditional, hb_empty { reset (); alloc (o.length); - hb_copy (o, *this); + if (unlikely (in_error ())) return *this; + + copy_vector (o); + return *this; } hb_vector_t& operator = (hb_vector_t &&o) @@ -184,12 +189,14 @@ struct hb_vector_t : std::conditional, hb_empty { if (unlikely (!resize (length + 1))) return &Crap (Type); - return &arrayZ[length - 1]; + return std::addressof (arrayZ[length - 1]); } - template + template ::value && + std::is_copy_assignable::value)> Type *push (T&& v) { - /* TODO Emplace? */ Type *p = push (); if (p == &Crap (Type)) // If push failed to allocate then don't copy v, since this may cause @@ -199,18 +206,34 @@ struct hb_vector_t : std::conditional, hb_empty *p = std::forward (v); return p; } + template ::value)> + Type *push (T&& v) + { + if (unlikely (!alloc (length + 1))) + // If push failed to allocate then don't copy v, since this may cause + // the created copy to leak memory since we won't have stored a + // reference to it. + return &Crap (Type); + + /* Emplace. */ + length++; + Type *p = std::addressof (arrayZ[length - 1]); + return new (p) Type (std::forward (v)); + } bool in_error () const { return allocated < 0; } template ::value)> + hb_enable_if (hb_is_trivially_copy_assignable(T))> Type * realloc_vector (unsigned new_allocated) { return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); } template ::value)> + hb_enable_if (!hb_is_trivially_copy_assignable(T))> Type * realloc_vector (unsigned new_allocated) { @@ -230,8 +253,7 @@ struct hb_vector_t : std::conditional, hb_empty } template ::value || - !std::is_default_constructible::value)> + hb_enable_if (hb_is_trivially_constructible(T))> void grow_vector (unsigned size) { @@ -239,8 +261,7 @@ struct hb_vector_t : std::conditional, hb_empty length = size; } template ::value && - std::is_default_constructible::value)> + hb_enable_if (!hb_is_trivially_constructible(T))> void grow_vector (unsigned size) { @@ -252,14 +273,52 @@ struct hb_vector_t : std::conditional, hb_empty } template ::value)> + hb_enable_if (hb_is_trivially_copyable (T))> + void + copy_vector (const hb_vector_t &other) + { + length = other.length; + hb_memcpy ((void *) arrayZ, (const void *) other.arrayZ, length * item_size); + } + template ::value)> + void + copy_vector (const hb_vector_t &other) + { + length = 0; + while (length < other.length) + { + length++; + new (std::addressof (arrayZ[length - 1])) Type (other.arrayZ[length - 1]); + } + } + template ::value && + std::is_default_constructible::value && + std::is_copy_assignable::value)> + void + copy_vector (const hb_vector_t &other) + { + length = 0; + while (length < other.length) + { + length++; + new (std::addressof (arrayZ[length - 1])) Type (); + arrayZ[length - 1] = other.arrayZ[length - 1]; + } + } + + template void shrink_vector (unsigned size) { length = size; } template ::value)> + hb_enable_if (!hb_is_trivially_destructible(T))> void shrink_vector (unsigned size) { @@ -271,7 +330,7 @@ struct hb_vector_t : std::conditional, hb_empty } template ::value)> + hb_enable_if (hb_is_trivially_copy_assignable(T))> void shift_down_vector (unsigned i) { @@ -280,7 +339,7 @@ struct hb_vector_t : std::conditional, hb_empty (length - i) * sizeof (Type)); } template ::value)> + hb_enable_if (!hb_is_trivially_copy_assignable(T))> void shift_down_vector (unsigned i) { @@ -341,7 +400,7 @@ struct hb_vector_t : std::conditional, hb_empty Type pop () { if (!length) return Null (Type); - Type v = std::move (arrayZ[length - 1]); + Type v = arrayZ[length - 1]; arrayZ[length - 1].~Type (); length--; return v; @@ -351,8 +410,8 @@ struct hb_vector_t : std::conditional, hb_empty { if (unlikely (i >= length)) return; - arrayZ[i].~Type (); shift_down_vector (i + 1); + arrayZ[length - 1].~Type (); length--; } diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h index 94c73e15bf8..ae707cde6cc 100644 --- a/thirdparty/harfbuzz/src/hb-version.h +++ b/thirdparty/harfbuzz/src/hb-version.h @@ -47,20 +47,20 @@ HB_BEGIN_DECLS * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 2 +#define HB_VERSION_MINOR 3 /** * HB_VERSION_MICRO: * * The micro component of the library version available at compile-time. */ -#define HB_VERSION_MICRO 1 +#define HB_VERSION_MICRO 0 /** * HB_VERSION_STRING: * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "4.2.1" +#define HB_VERSION_STRING "4.3.0" /** * HB_VERSION_ATLEAST: