From: Weng Xuetian <wengxt@gmail.com>
Date: Wed, 29 Aug 2018 22:47:10 -0700
Subject: [xkb] use iso-codes json file to parse the iso codes data.
Applied-Upsream: commit:00a6bb364c3c24e6361faab8a6b31025e55067fa
Bug-Debian: https://bugs.debian.org/907523

---
 CMakeLists.txt                    |   7 +-
 cmake/FindIsoCodes.cmake          |  12 ++--
 config.h.in                       |   6 +-
 src/im/keyboard/CMakeLists.txt    |   6 +-
 src/im/keyboard/isocodes.c        | 141 +++++++++++++++++++++-----------------
 src/im/keyboard/keyboard.c        |  10 +--
 src/module/CMakeLists.txt         |   2 +-
 src/module/xkbdbus/CMakeLists.txt |   2 +-
 src/module/xkbdbus/xkbdbus.c      |   2 +-
 9 files changed, 104 insertions(+), 84 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5552ba0..dd5197c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@ option(ENABLE_GLIB2 "Enable GLib2 as depenedency" ON)
 option(ENABLE_CAIRO "Enable Cairo" ON)
 option(ENABLE_DBUS "Enable DBus Support" ON)
 option(ENABLE_PANGO "Enable Pango Support" ON)
-option(ENABLE_LIBXML2 "Enable libxml2" ON)
+option(ENABLE_XKB "Enable xkb support" ON)
 option(ENABLE_DEBUG "Enable Debug" OFF)
 option(ENABLE_PINYIN "Enable Pinyin" ON)
 option(ENABLE_TABLE "Enable Table IM" ON)
@@ -95,11 +95,12 @@ if(ENABLE_ENCHANT)
     set(ENABLE_ENCHANT Off)
   endif()
 endif()
-if (ENABLE_LIBXML2)
+if (ENABLE_XKB)
     find_package(LibXml2 REQUIRED)
     find_package(IsoCodes REQUIRED)
     find_package(XkbFile REQUIRED)
-endif (ENABLE_LIBXML2)
+    pkg_check_modules(JsonC "json-c" IMPORTED_TARGET REQUIRED)
+endif (ENABLE_XKB)
 if(ENABLE_PRESAGE)
   find_package(Presage)
   if(NOT (PRESAGE_FOUND OR FORCE_PRESAGE))
diff --git a/cmake/FindIsoCodes.cmake b/cmake/FindIsoCodes.cmake
index 384c82b..d2d1318 100644
--- a/cmake/FindIsoCodes.cmake
+++ b/cmake/FindIsoCodes.cmake
@@ -18,15 +18,15 @@ endif(ISOCODES_INCLUDE_DIR AND ISOCODES_LIBRARIES)
 find_package(PkgConfig)
 pkg_check_modules(PC_ISOCODES iso-codes)
 
-find_file(ISOCODES_ISO639_XML iso_639.xml
-          HINTS "${PC_ISOCODES_PREFIX}/share/xml/iso-codes/"
+find_file(ISOCODES_ISO639_JSON iso_639-3.json
+          HINTS "${PC_ISOCODES_PREFIX}/share/iso-codes/json/"
           )
 
-find_file(ISOCODES_ISO3166_XML iso_3166.xml
-          HINTS "${PC_ISOCODES_PREFIX}/share/xml/iso-codes/"
+find_file(ISOCODES_ISO3166_JSON iso_3166-1.json
+          HINTS "${PC_ISOCODES_PREFIX}/share/iso-codes/json/"
           )
 
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(IsoCodes  DEFAULT_MSG  ISOCODES_ISO639_XML ISOCODES_ISO3166_XML)
+find_package_handle_standard_args(IsoCodes  DEFAULT_MSG  ISOCODES_ISO639_JSON ISOCODES_ISO3166_JSON)
 
-mark_as_advanced(ISOCODES_ISO639_XML ISOCODES_ISO3166_XML)
+mark_as_advanced(ISOCODES_ISO639_JSON ISOCODES_ISO3166_JSON)
diff --git a/config.h.in b/config.h.in
index 9c13100..a584d62 100644
--- a/config.h.in
+++ b/config.h.in
@@ -16,12 +16,12 @@
 #cmakedefine LIBICONV_SECOND_ARGUMENT_IS_CONST
 #cmakedefine ENABLE_SNOOPER
 #cmakedefine ENABLE_X11
-#cmakedefine ENABLE_LIBXML2
+#cmakedefine ENABLE_XKB
 #cmakedefine ENABLE_BACKTRACE
 #define NO_SNOOPER_APPS "@NO_SNOOPER_APPS@"
 #define NO_PREEDIT_APPS "@NO_PREEDIT_APPS@"
-#define ISOCODES_ISO639_XML "@ISOCODES_ISO639_XML@"
-#define ISOCODES_ISO3166_XML "@ISOCODES_ISO3166_XML@"
+#define ISOCODES_ISO639_JSON "@ISOCODES_ISO639_JSON@"
+#define ISOCODES_ISO3166_JSON "@ISOCODES_ISO3166_JSON@"
 #define XKEYBOARDCONFIG_XKBBASE "@XKEYBOARDCONFIG_XKBBASE@"
 #cmakedefine XKB_RULES_XML_FILE "${XKB_RULES_XML_FILE}"
 #cmakedefine LIBICONV_SECOND_ARGUMENT_IS_CONST
diff --git a/src/im/keyboard/CMakeLists.txt b/src/im/keyboard/CMakeLists.txt
index f4dd43c..d317889 100644
--- a/src/im/keyboard/CMakeLists.txt
+++ b/src/im/keyboard/CMakeLists.txt
@@ -3,7 +3,7 @@ include_directories (
   ${LIBICONV_INCLUDE_DIR}
   )
 set(FCITX_KEYBOARD_LINK_LIBS ${LIBICONV_LIBRARIES})
-if(ENABLE_LIBXML2)
+if(ENABLE_XKB)
   include_directories(${LIBXML2_INCLUDE_DIR})
   set(FCITX_KEYBOARD_LINK_LIBS ${FCITX_KEYBOARD_LINK_LIBS} ${LIBXML2_LIBRARIES})
 endif()
@@ -13,11 +13,11 @@ set(FCITX_KEYBOARD_SOURCES
   keyboardconfig.c
   )
 
-if(ENABLE_LIBXML2)
+if(ENABLE_XKB)
   set(FCITX_KEYBOARD_SOURCES ${FCITX_KEYBOARD_SOURCES} isocodes.c)
 endif()
 
 fcitx_add_addon_full(keyboard DESC
   SOURCES ${FCITX_KEYBOARD_SOURCES}
-  LINK_LIBS ${FCITX_KEYBOARD_LINK_LIBS} XKBCommon::XKBCommon
+  LINK_LIBS ${FCITX_KEYBOARD_LINK_LIBS} XKBCommon::XKBCommon PkgConfig::JsonC
   EXTRA_PO isocodes.c isocodes.h keyboard.h)
diff --git a/src/im/keyboard/isocodes.c b/src/im/keyboard/isocodes.c
index a62e7fe..0f67776 100644
--- a/src/im/keyboard/isocodes.c
+++ b/src/im/keyboard/isocodes.c
@@ -20,69 +20,94 @@
 
 #include "config.h"
 
-#include <libxml/parser.h>
+#include <json-c/json.h>
 
 #include <string.h>
 
 #include <fcitx-utils/utils.h>
 #include "isocodes.h"
 
-#define XMLCHAR_CAST (const char*)
 
-static void IsoCodes639HandlerStartElement(void *ctx,
-                                           const xmlChar *name,
-                                           const xmlChar **atts);
-static void IsoCodes3166HandlerStartElement(void *ctx,
-                                            const xmlChar *name,
-                                            const xmlChar **atts);
+static void IsoCodes639Handler(FcitxIsoCodes *isocodes, json_object *entry);
+static void IsoCodes3166Handler(FcitxIsoCodes *isocodes, json_object *entry);
 static void FcitxIsoCodes639EntryFree(FcitxIsoCodes639Entry* entry);
 static void FcitxIsoCodes3166EntryFree(FcitxIsoCodes3166Entry* entry);
 
 FcitxIsoCodes* FcitxXkbReadIsoCodes(const char* iso639, const char* iso3166)
 {
-    xmlSAXHandler handle;
-    memset(&handle, 0, sizeof(xmlSAXHandler));
+    FcitxIsoCodes* isocodes = fcitx_utils_new(FcitxIsoCodes);
 
-    xmlInitParser();
-
-    FcitxIsoCodes* isocodes = (FcitxIsoCodes*) fcitx_utils_malloc0(sizeof(FcitxIsoCodes));
+    json_object *obj;
+    do {
+        obj = json_object_from_file(iso639);
+        if (!obj) {
+            break;
+        }
+        json_object *obj639 = json_object_object_get(obj, "639-2");
+        if (!obj639 || json_object_get_type(obj639) != json_type_array) {
+            break;
+        }
 
-    handle.startElement = IsoCodes639HandlerStartElement;
-    xmlSAXUserParseFile(&handle, isocodes, iso639);
-    handle.startElement = IsoCodes3166HandlerStartElement;
-    xmlSAXUserParseFile(&handle, isocodes, iso3166);
+        for (size_t i = 0, e = json_object_array_length(obj639); i < e; i++) {
+            json_object *entry = json_object_array_get_idx(obj639, i);
+            IsoCodes639Handler(isocodes, entry);
+        }
+    } while(0);
+    json_object_put(obj);
 
-    /* DO NOT Call xmlCleanupParser() */
+    do {
+        obj = json_object_from_file(iso3166);
+        if (!obj) {
+            break;
+        }
+        json_object *obj3166 = json_object_object_get(obj, "3166-1");
+        if (!obj3166 || json_object_get_type(obj3166) != json_type_array) {
+            break;
+        }
 
+        for (size_t i = 0, e = json_object_array_length(obj3166); i < e; i++) {
+            json_object *entry = json_object_array_get_idx(obj3166, i);
+            IsoCodes3166Handler(isocodes, entry);
+        }
+    } while(0);
     return isocodes;
 }
 
-static void IsoCodes639HandlerStartElement(void *ctx,
-                                           const xmlChar *name,
-                                           const xmlChar **atts)
+static void IsoCodes639Handler(FcitxIsoCodes *isocodes, json_object *entry)
 {
-    FcitxIsoCodes* isocodes = ctx;
-    if (strcmp(XMLCHAR_CAST name, "iso_639_entry") == 0) {
-        FcitxIsoCodes639Entry* entry = fcitx_utils_malloc0(sizeof(FcitxIsoCodes639Entry));
-        int i = 0;
-        while(atts && atts[i*2] != 0) {
-            if (strcmp(XMLCHAR_CAST atts[i * 2], "iso_639_2B_code") == 0)
-                entry->iso_639_2B_code = strdup(XMLCHAR_CAST atts[i * 2 + 1]);
-            else if (strcmp(XMLCHAR_CAST atts[i * 2], "iso_639_2T_code") == 0)
-                entry->iso_639_2T_code = strdup(XMLCHAR_CAST atts[i * 2 + 1]);
-            else if (strcmp(XMLCHAR_CAST atts[i * 2], "iso_639_1_code") == 0)
-                entry->iso_639_1_code = strdup(XMLCHAR_CAST atts[i * 2 + 1]);
-            else if (strcmp(XMLCHAR_CAST atts[i * 2], "name") == 0)
-                entry->name = strdup(XMLCHAR_CAST atts[i * 2 + 1]);
-            i++;
-        }
-        if (!entry->iso_639_2B_code || !entry->iso_639_2T_code || !entry->name)
-            FcitxIsoCodes639EntryFree(entry);
-        else {
-            HASH_ADD_KEYPTR(hh1, isocodes->iso6392B, entry->iso_639_2B_code, strlen(entry->iso_639_2B_code), entry);
-            HASH_ADD_KEYPTR(hh2, isocodes->iso6392T, entry->iso_639_2T_code, strlen(entry->iso_639_2T_code), entry);
-        }
+    json_object *alpha2 = json_object_object_get(entry, "alpha_2");
+    json_object *alpha3 = json_object_object_get(entry, "alpha_3");
+    json_object *bibliographic = json_object_object_get(entry, "bibliographic");
+    json_object *name= json_object_object_get(entry, "name");
+    if (!name || json_object_get_type(name) != json_type_string) {
+        return;
+    }
+    // there must be alpha3
+    if (!alpha3 || json_object_get_type(alpha3) != json_type_string) {
+        return;
     }
+
+    // alpha2 is optional
+    if (alpha2 && json_object_get_type(alpha2) != json_type_string) {
+        return;
+    }
+
+    // bibliographic is optional
+    if (bibliographic && json_object_get_type(bibliographic) != json_type_string) {
+        return;
+    }
+    if (!bibliographic) {
+        bibliographic = alpha3;
+    }
+    FcitxIsoCodes639Entry* e = fcitx_utils_new(FcitxIsoCodes639Entry);
+    e->name = strndup(json_object_get_string(name), json_object_get_string_len(name));
+    if (alpha2) {
+        e->iso_639_1_code = strndup(json_object_get_string(alpha2), json_object_get_string_len(alpha2));
+    }
+    e->iso_639_2B_code = strndup(json_object_get_string(bibliographic), json_object_get_string_len(bibliographic));
+    e->iso_639_2T_code = strndup(json_object_get_string(alpha3), json_object_get_string_len(alpha3));
+    HASH_ADD_KEYPTR(hh1, isocodes->iso6392B, e->iso_639_2B_code, strlen(e->iso_639_2B_code), e);
+    HASH_ADD_KEYPTR(hh2, isocodes->iso6392T, e->iso_639_2T_code, strlen(e->iso_639_2T_code), e);
 }
 
 void FcitxIsoCodes639EntryFree(FcitxIsoCodes639Entry* entry)
@@ -101,27 +126,21 @@ void FcitxIsoCodes3166EntryFree(FcitxIsoCodes3166Entry* entry)
     free(entry);
 }
 
-
-static void IsoCodes3166HandlerStartElement(void *ctx,
-                                           const xmlChar *name,
-                                           const xmlChar **atts)
+static void IsoCodes3166Handler(FcitxIsoCodes *isocodes, json_object *entry)
 {
-    FcitxIsoCodes* isocodes = ctx;
-    if (strcmp(XMLCHAR_CAST name, "iso_3166_entry") == 0) {
-        FcitxIsoCodes3166Entry* entry = fcitx_utils_malloc0(sizeof(FcitxIsoCodes3166Entry));
-        int i = 0;
-        while(atts && atts[i*2] != 0) {
-            if (strcmp(XMLCHAR_CAST atts[i * 2], "alpha_2_code") == 0)
-                entry->alpha_2_code = strdup(XMLCHAR_CAST atts[i * 2 + 1]);
-            else if (strcmp(XMLCHAR_CAST atts[i * 2], "name") == 0)
-                entry->name = strdup(XMLCHAR_CAST atts[i * 2 + 1]);
-            i++;
-        }
-        if (!entry->name || !entry->alpha_2_code)
-            FcitxIsoCodes3166EntryFree(entry);
-        else
-            HASH_ADD_KEYPTR(hh, isocodes->iso3166, entry->alpha_2_code, strlen(entry->alpha_2_code), entry);
+    json_object *alpha2 = json_object_object_get(entry, "alpha_2");
+    json_object *name= json_object_object_get(entry, "name");
+    if (!name || json_object_get_type(name) != json_type_string) {
+        return;
+    }
+    // there must be alpha3
+    if (!alpha2 || json_object_get_type(alpha2) != json_type_string) {
+        return;
     }
+    FcitxIsoCodes3166Entry* e = fcitx_utils_new(FcitxIsoCodes3166Entry);
+    e->name = strndup(json_object_get_string(name), json_object_get_string_len(name));
+    e->alpha_2_code = strndup(json_object_get_string(alpha2), json_object_get_string_len(alpha2));
+    HASH_ADD_KEYPTR(hh, isocodes->iso3166, e->alpha_2_code, strlen(e->alpha_2_code), e);
 }
 
 FcitxIsoCodes639Entry* FcitxIsoCodesGetEntry(FcitxIsoCodes* isocodes, const char* lang)
diff --git a/src/im/keyboard/keyboard.c b/src/im/keyboard/keyboard.c
index 342ee83..9486799 100644
--- a/src/im/keyboard/keyboard.c
+++ b/src/im/keyboard/keyboard.c
@@ -41,7 +41,7 @@
 #include "module/freedesktop-notify/fcitx-freedesktop-notify.h"
 
 #include "keyboard.h"
-#if defined(ENABLE_LIBXML2)
+#if defined(ENABLE_XKB)
 #include "isocodes.h"
 #endif
 
@@ -224,7 +224,7 @@ void* SimpleCopy(void* arg, void* dest, void* src)
     return src;
 }
 
-#if defined(ENABLE_LIBXML2)
+#if defined(ENABLE_XKB)
 static const char* FindBestLanguage(FcitxIsoCodes* isocodes, const char* hint, UT_array* languages)
 {
     const char* bestLang = NULL;
@@ -337,7 +337,7 @@ void* FcitxKeyboardCreate(FcitxInstance* instance)
     if (!keyboard->initialLayout)
         keyboard->initialLayout = strdup("us");
 
-#if defined(ENABLE_LIBXML2)
+#if defined(ENABLE_XKB)
     if (rules && utarray_len(rules->layoutInfos)) {
         char* tempfile = NULL;
         FcitxXDGGetFileUserWithPrefix("", "", "w", NULL);
@@ -351,7 +351,7 @@ void* FcitxKeyboardCreate(FcitxInstance* instance)
             free(tempfile);
         }
 
-        FcitxIsoCodes* isocodes = FcitxXkbReadIsoCodes(ISOCODES_ISO639_XML, ISOCODES_ISO3166_XML);
+        FcitxIsoCodes* isocodes = FcitxXkbReadIsoCodes(ISOCODES_ISO639_JSON, ISOCODES_ISO3166_JSON);
         utarray_foreach(layoutInfo, rules->layoutInfos, FcitxXkbLayoutInfo) {
             {
                 const char* lang = FindBestLanguage(isocodes, layoutInfo->description, layoutInfo->languages);
@@ -407,7 +407,7 @@ void* FcitxKeyboardCreate(FcitxInstance* instance)
 #endif
     {
         /* though this is unrelated to libxml2, but can only generated with libxml2 enabled */
-#if defined(ENABLE_LIBXML2)
+#if defined(ENABLE_XKB)
         FILE* fp = FcitxXDGGetFileUserWithPrefix("", "cached_layout", "r", NULL);
         if (fp) {
             char *buf = NULL, *buf1 = NULL;
diff --git a/src/module/CMakeLists.txt b/src/module/CMakeLists.txt
index 904caa9..a7153bd 100644
--- a/src/module/CMakeLists.txt
+++ b/src/module/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_subdirectory(x11)
 
-if(ENABLE_X11 AND ENABLE_LIBXML2)
+if(ENABLE_X11 AND ENABLE_XKB)
   set(_ENABLE_XKB On)
 else()
   set(_ENABLE_XKB Off)
diff --git a/src/module/xkbdbus/CMakeLists.txt b/src/module/xkbdbus/CMakeLists.txt
index c8570ad..149b68c 100644
--- a/src/module/xkbdbus/CMakeLists.txt
+++ b/src/module/xkbdbus/CMakeLists.txt
@@ -16,4 +16,4 @@ set(FCITX_XKBDBUS_SOURCES
   ../../im/keyboard/isocodes.c)
 fcitx_add_addon_full(xkbdbus SCAN SCAN_PRIV ${xkbdbus_noinstall}
   SOURCES ${FCITX_XKBDBUS_SOURCES}
-  LINK_LIBS ${FCITX_XKBDBUS_LINK_LIBS})
+  LINK_LIBS ${FCITX_XKBDBUS_LINK_LIBS} PkgConfig::JsonC)
diff --git a/src/module/xkbdbus/xkbdbus.c b/src/module/xkbdbus/xkbdbus.c
index a496d46..7d98370 100644
--- a/src/module/xkbdbus/xkbdbus.c
+++ b/src/module/xkbdbus/xkbdbus.c
@@ -156,7 +156,7 @@ void* FcitxXkbDBusCreate(FcitxInstance* instance)
         dbus_message_unref(message);
 
         xkbdbus->rules = rules;
-        xkbdbus->isocodes = FcitxXkbReadIsoCodes(ISOCODES_ISO639_XML, ISOCODES_ISO3166_XML);
+        xkbdbus->isocodes = FcitxXkbReadIsoCodes(ISOCODES_ISO639_JSON, ISOCODES_ISO3166_JSON);
         FcitxXkbDBusAddFunctions(instance);
         return xkbdbus;
     } while(0);
