summaryrefslogtreecommitdiff
path: root/thirdparty/harfbuzz
diff options
context:
space:
mode:
authorbruvzg <7645683+bruvzg@users.noreply.github.com>2022-05-23 13:18:11 +0300
committerbruvzg <7645683+bruvzg@users.noreply.github.com>2022-05-23 13:18:11 +0300
commit797ccd3ef83d5f20096f14d25334ae8207d8ad20 (patch)
tree6bc49b72a4f00214de081fad6509a73ff35cf6ef /thirdparty/harfbuzz
parent3568b3deeaf3fbbf9e728ff25c7d0349075f9f1a (diff)
HarfBuzz: Update to version 4.3.0
Diffstat (limited to 'thirdparty/harfbuzz')
-rw-r--r--thirdparty/harfbuzz/src/hb-algs.hh28
-rw-r--r--thirdparty/harfbuzz/src/hb-array.hh26
-rw-r--r--thirdparty/harfbuzz/src/hb-bimap.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-page.hh9
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-set-invertible.hh9
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-set.hh64
-rw-r--r--thirdparty/harfbuzz/src/hb-cff-interp-common.hh118
-rw-r--r--thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh17
-rw-r--r--thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh89
-rw-r--r--thirdparty/harfbuzz/src/hb-font.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ft.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-map.cc20
-rw-r--r--thirdparty/harfbuzz/src/hb-map.h4
-rw-r--r--thirdparty/harfbuzz/src/hb-map.hh41
-rw-r--r--thirdparty/harfbuzz/src/hb-meta.hh13
-rw-r--r--thirdparty/harfbuzz/src/hb-open-type.hh11
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff-common.hh182
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff1-table.cc45
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff1-table.hh165
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff2-table.cc38
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff2-table.hh30
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cmap-table.hh147
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh60
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-glyf-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-common.hh266
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag-table.hh3559
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag.cc107
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh16
-rw-r--r--thirdparty/harfbuzz/src/hb-priority-queue.hh32
-rw-r--r--thirdparty/harfbuzz/src/hb-repacker.hh82
-rw-r--r--thirdparty/harfbuzz/src/hb-serialize.hh17
-rw-r--r--thirdparty/harfbuzz/src/hb-set.hh26
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff-common.hh100
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff1.cc22
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff2.cc28
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.cc114
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-subset.cc87
-rw-r--r--thirdparty/harfbuzz/src/hb-vector.hh97
-rw-r--r--thirdparty/harfbuzz/src/hb-version.h6
44 files changed, 3051 insertions, 2658 deletions
diff --git a/thirdparty/harfbuzz/src/hb-algs.hh b/thirdparty/harfbuzz/src/hb-algs.hh
index c40a55cd1f..05b4df52f1 100644
--- a/thirdparty/harfbuzz/src/hb-algs.hh
+++ b/thirdparty/harfbuzz/src/hb-algs.hh
@@ -150,10 +150,26 @@ struct BEInt<Type, 4>
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 <typename T>
static inline
-T hb_coerce (const T v) { return v; }
+constexpr T hb_coerce (const T v) { return v; }
template <typename T, typename V,
hb_enable_if (!hb_is_same (hb_decay<T>, hb_decay<V>) && std::is_pointer<V>::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 1d1476d7cd..1963698cf7 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 <typename T>
+ template <typename T, typename ...Ts>
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 <typename T>
- bool bsearch_impl (const T &x, unsigned *pos) const
+ template <typename T, typename ...Ts>
+ 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<T, Type>);
+ _hb_cmp_method<T, Type, Ts...>,
+ ds...);
}
};
template <typename T> inline hb_sorted_array_t<T>
@@ -403,7 +404,7 @@ hb_sorted_array (T (&array_)[length_])
{ return hb_sorted_array_t<T> (array_); }
template <typename T>
-bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
+inline bool hb_array_t<T>::operator == (const hb_array_t<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<T>::operator == (const hb_array_t<T> &o) const
}
return true;
}
-
-/* TODO Specialize operator== for hb_bytes_t and hb_ubytes_t. */
+template <>
+inline bool hb_array_t<const char>::operator == (const hb_array_t<const char> &o) const
+{
+ if (o.length != this->length) return false;
+ return 0 == hb_memcmp (arrayZ, o.arrayZ, length);
+}
+template <>
+inline bool hb_array_t<const unsigned char>::operator == (const hb_array_t<const unsigned char> &o) const
+{
+ if (o.length != this->length) return false;
+ return 0 == hb_memcmp (arrayZ, o.arrayZ, length);
+}
template <>
inline uint32_t hb_array_t<const char>::hash () const {
@@ -421,7 +432,6 @@ inline uint32_t hb_array_t<const char>::hash () const {
current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
return current;
}
-
template <>
inline uint32_t hb_array_t<const unsigned char>::hash () const {
uint32_t current = 0;
diff --git a/thirdparty/harfbuzz/src/hb-bimap.hh b/thirdparty/harfbuzz/src/hb-bimap.hh
index a9e1278de7..5b313bf59c 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 9759836654..cbe918ee40 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 4a4ce34053..caea47d8d3 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 fcaff9f3be..11a4359dc9 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 641de0eff2..5c2cb060a4 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 <HBUINT8>
{
+ 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 <typename T, typename V>
static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value)
@@ -274,33 +277,10 @@ struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
/* 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_t> byte_str_array_t;
+using byte_str_array_t = hb_vector_t<hb_ubytes_t>;
/* stack */
template <typename ELEM, int LIMIT>
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<const ELEM> sub_array (unsigned start, unsigned length) const
+ { return hb_array_t<const ELEM> (elements).sub_array (start, length); }
- protected:
- bool error;
- unsigned int count;
- hb_vector_t<ELEM> 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<ARG, 513>
return true;
}
- hb_array_t<const ARG> get_subarray (unsigned int start) const
- { return S::elements.sub_array (start); }
-
private:
typedef cff_stack_t<ARG, 513> S;
};
@@ -518,8 +491,8 @@ struct arg_stack_t : cff_stack_t<ARG, 513>
/* 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 <typename ARG=number_t>
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<ARG>
argStack;
protected:
- bool error;
+ bool error = false;
};
-typedef interp_env_t<> num_interp_env_t;
+using num_interp_env_t = interp_env_t<>;
template <typename ARG=number_t>
struct opset_t
@@ -668,11 +643,8 @@ struct opset_t
template <typename ENV>
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 ef299369b5..2983ae54a1 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 <typename ARG, typename SUBRS>
struct cs_interp_env_t : interp_env_t<ARG>
{
- 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<ARG> (str)
{
- interp_env_t<ARG>::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<ARG>
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<ARG>::fini ();
-
- callStack.fini ();
globalSubrs.fini ();
localSubrs.fini ();
}
@@ -880,6 +875,8 @@ struct path_procs_t
template <typename ENV, typename OPSET, typename PARAM>
struct cs_interpreter_t : interpreter_t<ENV>
{
+ cs_interpreter_t (ENV& env_) : interpreter_t<ENV> (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 a520ca3bce..79fe9b42c5 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 <typename OPSET, typename PARAM, typename ENV=num_interp_env_t>
struct dict_interpreter_t : interpreter_t<ENV>
{
+ dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (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 1c8762c172..b306c2ecc9 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<CFF1Subrs> cff1_biased_subrs_t;
struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
{
template <typename ACC>
- 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<number_t, OPSET, cff1_cs_interp_env_t, PARAM
};
template <typename OPSET, typename PARAM>
-struct cff1_cs_interpreter_t : cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM> {};
+using cff1_cs_interpreter_t = cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM>;
} /* namespace CFF */
diff --git a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh
index 766183760e..d0b9e7b086 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<blend_arg_t> BlendInterpEnv;
typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t;
-struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
+template <typename ELEM>
+struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
{
template <typename ACC>
- 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<blend_arg_t, CFF2Subrs>
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<blend_arg_t, CFF2Subrs>
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<blend_arg_t, CFF2Subrs>
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<blend_arg_t, CFF2Subrs>
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<const ELEM> 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<blend_arg_t, CFF2Subrs>
bool seen_vsindex_;
bool seen_blend;
- typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
+ typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
};
-template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>>
-struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
+template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>>
+struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, 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<ELEM> &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<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA
break;
case OpCode_vsindexcs:
+#if 0
if (unlikely (env.argStack.peek ().blending ()))
{
env.set_error ();
break;
}
+#endif
OPSET::process_vsindex (env, param);
break;
@@ -217,7 +213,26 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA
}
}
- static void process_blend (cff2_cs_interp_env_t &env, PARAM& param)
+ template <typename T = ELEM,
+ hb_enable_if (hb_is_same (T, blend_arg_t))>
+ static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
+ ELEM &arg,
+ const hb_array_t<const ELEM> blends,
+ unsigned n, unsigned i)
+ {
+ arg.set_blends (n, i, blends.length, blends);
+ }
+ template <typename T = ELEM,
+ hb_enable_if (!hb_is_same (T, blend_arg_t))>
+ static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
+ ELEM &arg,
+ const hb_array_t<const ELEM> blends,
+ unsigned n, unsigned i)
+ {
+ arg.set_real (arg.to_real () + env.blend_deltas (blends));
+ }
+
+ static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
{
unsigned int n, k;
@@ -234,26 +249,26 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA
}
for (unsigned int i = 0; i < n; i++)
{
- const hb_array_t<const blend_arg_t> blends = env.argStack.get_subarray (start + n + (i * k));
- env.argStack[start + i].set_blends (n, i, k, blends);
+ const hb_array_t<const ELEM> 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<ELEM> &env, PARAM& param)
{
env.process_vsindex ();
env.clear_args ();
}
private:
- typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> SUPER;
+ typedef cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH> SUPER;
};
-template <typename OPSET, typename PARAM>
-struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {};
+template <typename OPSET, typename PARAM, typename ELEM>
+using cff2_cs_interpreter_t = cs_interpreter_t<cff2_cs_interp_env_t<ELEM>, OPSET, PARAM>;
} /* namespace CFF */
diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc
index db05f017a5..5700e06271 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 0cfbb22e31..d3c5d3db93 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 9f1ac42846..6c83c670c9 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 6a45a7bdd5..3f67c50b92 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 9341637eac..aec7d87f42 100644
--- a/thirdparty/harfbuzz/src/hb-map.hh
+++ b/thirdparty/harfbuzz/src/hb-map.hh
@@ -42,11 +42,12 @@ template <typename K, typename V,
struct hb_hashmap_t
{
hb_hashmap_t () { init (); }
+ hb_hashmap_t (std::nullptr_t) : hb_hashmap_t () {}
~hb_hashmap_t () { fini (); }
- hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { hb_copy (o, *this); }
+ hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (population); hb_copy (o, *this); }
hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); }
- hb_hashmap_t& operator= (const hb_hashmap_t& o) { hb_copy (o, *this); return *this; }
+ hb_hashmap_t& operator= (const hb_hashmap_t& o) { resize (population); hb_copy (o, *this); return *this; }
hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; }
hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> 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_codepoint_t,
HB_MAP_VALUE_INVALID,
HB_MAP_VALUE_INVALID>;
- 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<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> lst) : hashmap (lst) {}
diff --git a/thirdparty/harfbuzz/src/hb-meta.hh b/thirdparty/harfbuzz/src/hb-meta.hh
index 3fea5d995e..90757d38ac 100644
--- a/thirdparty/harfbuzz/src/hb-meta.hh
+++ b/thirdparty/harfbuzz/src/hb-meta.hh
@@ -188,6 +188,19 @@ template <> struct hb_int_max<signed long long> : hb_integral_constant<signed l
template <> struct hb_int_max<unsigned long long> : hb_integral_constant<unsigned long long, ULLONG_MAX> {};
#define hb_int_max(T) hb_int_max<T>::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<T>::value
+#define hb_is_trivially_copy_assignable(T) std::is_trivially_copy_assignable<T>::value
+#define hb_is_trivially_constructible(T) std::is_trivially_constructible<T>::value
+#define hb_is_trivially_copy_constructible(T) std::is_trivially_copy_constructible<T>::value
+#define hb_is_trivially_destructible(T) std::is_trivially_destructible<T>::value
+#endif
/* Class traits. */
diff --git a/thirdparty/harfbuzz/src/hb-open-type.hh b/thirdparty/harfbuzz/src/hb-open-type.hh
index 7e524177f6..aee7064be3 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<Type>::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<Ts> (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<Type>::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<Ts> (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<Type>::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<Ts> (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<Type>::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<Ts> (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<Type>::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<Ts> (ds)...)))
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
index c102c15173..ae3b83a256 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
@@ -46,49 +46,21 @@ template<typename Type>
static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
{ return offset ? StructAtOffset<Type> (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<unsigned char> str_buff_t;
-struct str_buff_vec_t : hb_vector_t<str_buff_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<str_buff_t> SUPER;
-};
+using str_buff_t = hb_vector_t<unsigned char>;
+using str_buff_vec_t = hb_vector_t<str_buff_t>;
/* CFF INDEX */
template <typename COUNT>
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<CFFIndex> (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<COUNT> ();
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<HBUINT8> (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 ();
- }
+ /* serialize CFFIndex header */
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+ this->count = byteArray.length;
+ this->offSize = offSize_;
+ if (unlikely (!c->allocate_size<HBUINT8> (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<unsigned char> (bs.length);
- if (unlikely (!dest)) return_trace (false);
- memcpy (dest, &bs[0], bs.length);
- }
+ /* serialize data */
+ for (unsigned int i = 0; i < byteArray.length; i++)
+ {
+ const hb_ubytes_t &bs = byteArray[i];
+ unsigned char *dest = c->allocate_size<unsigned char> (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<COUNT> ();
- 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<HBUINT8> (off_size * (it.len () + 1))))
+ if (unlikely (!c->allocate_size<HBUINT8> (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 (); }
-
- unsigned int data_size () const { return HBINT8::static_size; }
+ { return (const unsigned char *) this + min_size + offSize.static_size + offset_array_size (); }
+ public:
- 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 <typename COUNT, typename TYPE>
struct CFFIndexOf : CFFIndex<COUNT>
{
- const byte_str_t operator [] (unsigned int index) const
- {
- if (likely (index < CFFIndex<COUNT>::count))
- return byte_str_t (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index));
- return Null (byte_str_t);
- }
-
template <typename DATA, typename PARAM1, typename PARAM2>
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 df4554ac00..bd9fe5d6d4 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<cff1_cs_opset_extents_t, cff1_extents_param_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<cff1_cs_opset_extents_t, cff1_extents_param_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<cff1_cs_opset_path_t, cff1_path_param_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<cff1_cs_opset_path_t, cff1_path_param_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<cff1_cs_opset_seac_t, get_seac_param_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<cff1_cs_opset_seac_t, get_seac_param_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<cff1_cs_opset_seac_t, get_seac_param_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 542e3f4de3..b5047002ac 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<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
+ const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
- dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp;
- priv_interp.env.init (privDictStr);
+ num_interp_env_t env2 (privDictStr);
+ dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> 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<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
+ const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
- dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp;
- priv_interp.env.init (privDictStr);
+ num_interp_env_t env (privDictStr);
+ dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> 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<gname_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<gname_t> *names = glyph_names.get ();
+ if (unlikely (!names))
+ {
+ names = (hb_sorted_vector_t<gname_t> *) calloc (sizeof (hb_sorted_vector_t<gname_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<gname_t> glyph_names;
+ mutable hb_atomic_ptr_t<hb_sorted_vector_t<gname_t>> glyph_names;
typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER;
};
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
index 817fe064ce..50c76daf93 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<cff2_path_procs_extents_t, cff2_cs_interp_env_t, cff2_extents_param_t>
+struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t<number_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<number_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<number_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<cff2_path_procs_extents_t, cff2_
param.update_bounds (env.get_pt ());
}
- static void curve (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
+ static void curve (cff2_cs_interp_env_t<number_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<cff2_path_procs_extents_t, cff2_
}
};
-struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t> {};
+struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t, cff2_path_procs_extents_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<cff2_cs_opset_extents_t, cff2_extents_param_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<number_t> env (str, *this, fd, font->coords, font->num_coords);
+ cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_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<cff2_path_procs_path_t, cff2_cs_interp_env_t, cff2_path_param_t>
+struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t<number_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<number_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<number_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<number_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<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {};
+struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t, cff2_path_procs_path_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<cff2_cs_opset_path_t, cff2_path_param_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<number_t> env (str, *this, fd, font->coords, font->num_coords);
+ cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t, number_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 b77e7f53fa..746160dc8e 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<num_dict_val_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<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
- dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp;
- priv_interp.env.init(privDictStr);
+ cff2_priv_dict_interp_env_t env2 (privDictStr);
+ dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_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 a8747ee5a1..7e96d9c8b3 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;
-
- delta = (*it).second - (*it).first;
+ {
+ 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 = 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<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
+ 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<hb_codepoint_t, hb_codepoint_t> cp_to_gid;
- + it | hb_sink (cp_to_gid);
+ hb_map_t cp_to_gid { it };
HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (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<HBUINT16> () - 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<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> cp_to_gid {
+ format4_iter
+ };
+
//serialize endCode[], startCode[], idDelta[]
HBUINT16* endCode = c->start_embed<HBUINT16> ();
- 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<hb_codepoint_t, CustomRange, unsigned>,
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<HBUINT16> {};
-struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {};
template <typename T>
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<CmapSubtableFormat12>
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<CmapSubtableFormat12>
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<CmapSubtableLongGroup> &groups_data)
@@ -1448,6 +1472,37 @@ struct EncodingRecord
DEFINE_SIZE_STATIC (8);
};
+struct SubtableUnicodesCache {
+
+ private:
+ const void* base;
+ hb_hashmap_t<intptr_t, hb_set_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<hb_codepoint_t, hb_codepoint_t> (_, new_gid);
- })
+ + c->plan->unicode_to_new_gid_list.iter ()
| hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_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 a9deeba9a7..24476eda17 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<const BGRAColor> &color_records,
const hb_array_t<const HBUINT16> &color_record_indices,
- const hb_map_t &color_record_index_map,
- const hb_set_t &retained_color_record_indices) const
+ const hb_array_t<const BGRAColor> &color_records,
+ const hb_vector_t<unsigned>& 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<HBUINT16> (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<BGRAColor> (color_records[_]))
+ for (hb_codepoint_t color_index : retained_color_indices)
{
- c->pop_discard ();
- return_trace (false);
+ if (!c->copy<BGRAColor> (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<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
- hb_map_t color_record_index_map;
- hb_set_t retained_color_record_indices;
+ hb_vector_t<unsigned> first_color_index_for_layer;
+ hb_map_t first_color_to_layer_index;
- unsigned record_count = 0;
+ const hb_array_t<const HBUINT16> 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<const BGRAColor> 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 b4ac688344..866bb7e04c 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<typename T>
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 f2a58028e3..b644df708d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
@@ -91,12 +91,12 @@ template<typename Iterator>
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<HBGlyphID16> &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<hb_pair_t<hb_codepoint_t, hb_codepoint_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<hb_codepoint_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<Coverage> ()->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<HBGlyphID16> &glyphs,
const hb_set_t &klasses,
bool use_class_zero,
- hb_map_t *klass_map /*INOUT*/)
+ hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_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<hb_codepoint_t, unsigned>
- {
- 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<HBGlyphID16> glyphs;
+ hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_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<HBGlyphID16> glyphs;
+ hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_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 56e8c5b006..c9750ff63b 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 ea627cd27e..c8e5151694 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 5261783277..b242fba2d8 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"))
- {
- /* 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"))
+ if (limit - lang_str >= 7)
{
- /* 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 f50be97ad3..a4a9515362 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_languages2[i].cmp (&ot_languages2[i - 1]);
+ if (c > 0)
+ {
+ 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_languages[i].cmp (&ot_languages[i - 1]);
+ int c = ot_languages3[i].cmp (&ot_languages3[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_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 618cec08fb..3b2a38b9a6 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 7d799ae906..ffb86e30ae 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<int64_t, unsigned> item_t;
hb_vector_t<item_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 ());
+
+ item_t result = heap.arrayZ[0];
- heap[0] = heap[heap.length - 1];
+ 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 2a9e75c45b..ce9ff90bb4 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.
@@ -247,59 +260,6 @@ struct graph_t
}
/*
- * 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<unsigned> queue;
- hb_vector_t<vertex_t> sorted_graph;
- if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
- hb_vector_t<unsigned> id_map;
- if (unlikely (!check_success (id_map.resize (vertices_.length)))) return;
-
- hb_vector_t<unsigned> 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<vertex_t> sorted_graph;
+ hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_;
if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
hb_vector_t<unsigned> 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<vertex_t> vertices_;
+ hb_vector_t<vertex_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 40895a4548..5663b290c3 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 1f05407869..6025626363 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<hb_codepoint_t> lst) : hb_sparseset_t ()
@@ -53,7 +53,7 @@ struct hb_sparseset_t
add (item);
}
template <typename Iterable,
- hb_requires (hb_is_iterable (Iterable))>
+ 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_bit_set_invertible_t>
{
- hb_set_t () = default;
+ using sparseset = hb_sparseset_t<hb_bit_set_invertible_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<hb_codepoint_t> lst) : hb_sparseset_t<hb_bit_set_invertible_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<hb_codepoint_t> lst) : sparseset (lst) {}
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
- hb_set_t (const Iterable &o) : hb_sparseset_t<hb_bit_set_invertible_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 18657705fa..ae155b4e3c 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<ENV, OPSET, flatten_param_t> interp;
- interp.env.init (str, acc, fd);
+ ENV env (str, acc, fd);
+ cs_interpreter_t<ENV, OPSET, flatten_param_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<parsed_cs_op_t>
@@ -398,19 +396,19 @@ struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_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<ENV, OPSET, subr_subset_param_t> interp;
- interp.env.init (str, acc, fd);
+ ENV env (str, acc, fd);
+ cs_interpreter_t<ENV, OPSET, subr_subset_param_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 35fecd67bc..52bb13d320 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<cff1_top_dic
supp_op.op = op;
if ( unlikely (!(opstr.str.length >= 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<code_pair_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 92dd6b1d2c..08e820efcf 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<cff2_cs_opset_flatten_t, flatten_param_t>
+struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_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<blend_arg_t> &env, flatten_param_t& param)
{
switch (op)
{
@@ -97,7 +97,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
}
}
- static void flush_args (cff2_cs_interp_env_t &env, flatten_param_t& param)
+ static void flush_args (cff2_cs_interp_env_t<blend_arg_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<cff2_cs_opset_flatten_t, flatte
SUPER::flush_args (env, param);
}
- static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t &env, flatten_param_t& param)
+ static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t<blend_arg_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<cff2_cs_opset_flatten_t, flatte
encoder.encode_op (OpCode_blendcs);
}
- static void flush_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param)
+ static void flush_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
{
switch (op)
{
@@ -163,13 +163,13 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
}
private:
- typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> SUPER;
- typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t, flatten_param_t> CSOPSET;
+ typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t> SUPER;
+ typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t<blend_arg_t>, flatten_param_t> CSOPSET;
};
-struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t>
+struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_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<blend_arg_t> &env, subr_subset_param_t& param)
{
switch (op) {
@@ -201,7 +201,7 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t
protected:
static void process_call_subr (op_code_t op, cs_type_t type,
- cff2_cs_interp_env_t &env, subr_subset_param_t& param,
+ cff2_cs_interp_env_t<blend_arg_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<cff2_cs_opset_subr_subset_t
}
private:
- typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
+ typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_t> SUPER;
};
-struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t>
+struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_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<blend_arg_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<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t>
+ subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_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 74b7e3977c..a62ae8e024 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<hb_codepoint_t, hb_codepoint_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 ());
@@ -413,6 +421,20 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
}
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<hb_codepoint_t, hb_codepoint_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,
const hb_set_t *all_gids_to_retain,
@@ -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<hb_codepoint_t, hb_codepoint_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 ab2c4c302c..cb567b769e 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<hb_pair_t<hb_codepoint_t, hb_codepoint_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 4588268b76..31ddb4f894 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<char>* buf,
- unsigned buf_size,
hb_subset_context_t* c /* OUT */)
{
c->serializer->start_serialize<TableType> ();
@@ -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<typename TableType>
static bool
-_subset (hb_subset_plan_t *plan)
+_subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf)
{
hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
const TableType *table = source_blob->as<TableType> ();
@@ -167,10 +169,13 @@ _subset (hb_subset_plan_t *plan)
return false;
}
- hb_vector_t<char> 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<char> &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<const OT::glyf> (plan);
- case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan);
- case HB_OT_TAG_name: return _subset<const OT::name> (plan);
+ case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan, buf);
+ case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan, buf);
+ case HB_OT_TAG_name: return _subset<const OT::name> (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<const OT::head> (plan);
+ return _subset<const OT::head> (plan, buf);
case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */
- case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan);
+ case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan, buf);
case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */
- case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan);
- case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan);
- case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan);
+ case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan, buf);
+ case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan, buf);
+ case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan, buf);
case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */
- case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan);
- case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan);
- case HB_OT_TAG_post: return _subset<const OT::post> (plan);
- case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan);
- case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan);
- case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan);
+ case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan, buf);
+ case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan, buf);
+ case HB_OT_TAG_post: return _subset<const OT::post> (plan, buf);
+ case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan, buf);
+ case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan, buf);
+ case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan, buf);
case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */
- case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan);
+ case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf);
#ifndef HB_NO_SUBSET_CFF
- case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan);
- case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan);
- case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan);
+ case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan, buf);
+ case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan, buf);
+ case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan, buf);
#endif
#ifndef HB_NO_SUBSET_LAYOUT
- case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan);
- case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan);
- case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan);
- case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan);
- case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan);
- case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan);
+ case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan, buf);
+ case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan, buf);
+ case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan, buf);
+ case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan, buf);
+ case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
+ case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (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<char> 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 6c7d32e49d..7b08e3b4d2 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<sorted, hb_vector_t<Type, false>, hb_empty
using c_array_t = typename std::conditional<sorted, hb_sorted_array_t<const Type>, hb_array_t<const Type>>::type;
hb_vector_t () = default;
+ hb_vector_t (std::nullptr_t) : hb_vector_t () {}
hb_vector_t (std::initializer_list<Type> lst) : hb_vector_t ()
{
alloc (lst.size ());
@@ -59,7 +61,8 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, 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<sorted, hb_vector_t<Type, false>, 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<sorted, hb_vector_t<Type, false>, 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<sorted, hb_vector_t<Type, false>, hb_empty
{
if (unlikely (!resize (length + 1)))
return &Crap (Type);
- return &arrayZ[length - 1];
+ return std::addressof (arrayZ[length - 1]);
}
- template <typename T>
+ template <typename T,
+ typename T2 = Type,
+ hb_enable_if (!std::is_copy_constructible<T2>::value &&
+ std::is_copy_assignable<T>::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<sorted, hb_vector_t<Type, false>, hb_empty
*p = std::forward<T> (v);
return p;
}
+ template <typename T,
+ typename T2 = Type,
+ hb_enable_if (std::is_copy_constructible<T2>::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<T> (v));
+ }
bool in_error () const { return allocated < 0; }
template <typename T = Type,
- hb_enable_if (std::is_trivially_copy_assignable<T>::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 <typename T = Type,
- hb_enable_if (!std::is_trivially_copy_assignable<T>::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<sorted, hb_vector_t<Type, false>, hb_empty
}
template <typename T = Type,
- hb_enable_if (std::is_trivially_constructible<T>::value ||
- !std::is_default_constructible<T>::value)>
+ hb_enable_if (hb_is_trivially_constructible(T))>
void
grow_vector (unsigned size)
{
@@ -239,8 +261,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
length = size;
}
template <typename T = Type,
- hb_enable_if (!std::is_trivially_constructible<T>::value &&
- std::is_default_constructible<T>::value)>
+ hb_enable_if (!hb_is_trivially_constructible(T))>
void
grow_vector (unsigned size)
{
@@ -252,14 +273,52 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
}
template <typename T = Type,
- hb_enable_if (std::is_trivially_destructible<T>::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 <typename T = Type,
+ hb_enable_if (!hb_is_trivially_copyable (T) &&
+ std::is_copy_constructible<T>::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 <typename T = Type,
+ hb_enable_if (!hb_is_trivially_copyable (T) &&
+ !std::is_copy_constructible<T>::value &&
+ std::is_default_constructible<T>::value &&
+ std::is_copy_assignable<T>::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 <typename T = Type,
+ hb_enable_if (hb_is_trivially_destructible(T))>
void
shrink_vector (unsigned size)
{
length = size;
}
template <typename T = Type,
- hb_enable_if (!std::is_trivially_destructible<T>::value)>
+ hb_enable_if (!hb_is_trivially_destructible(T))>
void
shrink_vector (unsigned size)
{
@@ -271,7 +330,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
}
template <typename T = Type,
- hb_enable_if (std::is_trivially_copy_assignable<T>::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<sorted, hb_vector_t<Type, false>, hb_empty
(length - i) * sizeof (Type));
}
template <typename T = Type,
- hb_enable_if (!std::is_trivially_copy_assignable<T>::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<sorted, hb_vector_t<Type, false>, 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<sorted, hb_vector_t<Type, false>, 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 94c73e15bf..ae707cde6c 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: