From a36040288a3d8b98c03e317a8fdefe8f9782234e Mon Sep 17 00:00:00 2001
From: Ludovico de Nittis <ludovico.denittis@collabora.com>
Date: Mon, 9 Nov 2020 13:49:59 +0100
Subject: [PATCH] Start using the new JSON-GLib functions "*_with_default"

JSON-Glib 1.6.0 introduced new functions to get members from a JSON
object with a default fallback value.
This allows us to avoid manually checking the existence of a member.

The functions that we currently need, have been backported to allow the
execution on systems with a JSON-GLIB version older than the 1.6.0

Signed-off-by: Ludovico de Nittis <ludovico.denittis@collabora.com>
---
 helpers/check-xdg-portal.c                    |   2 +-
 steam-runtime-tools/architecture.c            |   8 +-
 steam-runtime-tools/desktop-entry.c           |  25 ++--
 steam-runtime-tools/graphics.c                | 107 +++++++-------
 .../json-glib-backports-internal.h            |  55 ++++++++
 steam-runtime-tools/json-glib-backports.c     | 131 ++++++++++++++++++
 steam-runtime-tools/json-glib-compat.h        |  41 ------
 steam-runtime-tools/library.c                 |   7 +-
 steam-runtime-tools/locale.c                  |  33 ++---
 steam-runtime-tools/meson.build               |   2 +
 steam-runtime-tools/os.c                      |  45 +++---
 steam-runtime-tools/steam.c                   |  24 ++--
 steam-runtime-tools/system-info.c             |  22 +--
 steam-runtime-tools/xdg-portal.c              |  19 ++-
 tests/system-info-cli.c                       |   2 +-
 15 files changed, 322 insertions(+), 201 deletions(-)
 create mode 100644 steam-runtime-tools/json-glib-backports-internal.h
 create mode 100644 steam-runtime-tools/json-glib-backports.c
 delete mode 100644 steam-runtime-tools/json-glib-compat.h

diff --git a/helpers/check-xdg-portal.c b/helpers/check-xdg-portal.c
index f0869c7f2..4f24c1efb 100644
--- a/helpers/check-xdg-portal.c
+++ b/helpers/check-xdg-portal.c
@@ -33,7 +33,7 @@
 #include <json-glib/json-glib.h>
 
 #include <steam-runtime-tools/glib-backports-internal.h>
-#include <steam-runtime-tools/json-glib-compat.h>
+#include <steam-runtime-tools/json-glib-backports-internal.h>
 #include <steam-runtime-tools/utils-internal.h>
 
 #if !GLIB_CHECK_VERSION(2, 43, 4)
diff --git a/steam-runtime-tools/architecture.c b/steam-runtime-tools/architecture.c
index eb740f167..5f278b147 100644
--- a/steam-runtime-tools/architecture.c
+++ b/steam-runtime-tools/architecture.c
@@ -27,6 +27,7 @@
 #include "steam-runtime-tools/architecture-internal.h"
 
 #include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/json-glib-backports-internal.h"
 #include "steam-runtime-tools/utils.h"
 #include "steam-runtime-tools/utils-internal.h"
 
@@ -174,12 +175,7 @@ srt_architecture_can_run_x86_64 (void)
 gboolean
 _srt_architecture_can_run_from_report (JsonObject *json_obj)
 {
-  gboolean can_run = FALSE;
-
   g_return_val_if_fail (json_obj != NULL, FALSE);
 
-  if (json_object_has_member (json_obj, "can-run"))
-    can_run = json_object_get_boolean_member (json_obj, "can-run");
-
-  return can_run;
+  return json_object_get_boolean_member_with_default (json_obj, "can-run", FALSE);
 }
diff --git a/steam-runtime-tools/desktop-entry.c b/steam-runtime-tools/desktop-entry.c
index e98c75fcc..213853db0 100644
--- a/steam-runtime-tools/desktop-entry.c
+++ b/steam-runtime-tools/desktop-entry.c
@@ -37,6 +37,7 @@
 #include "steam-runtime-tools/desktop-entry-internal.h"
 #include "steam-runtime-tools/enums.h"
 #include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/json-glib-backports-internal.h"
 #include "steam-runtime-tools/utils.h"
 
 /**
@@ -427,20 +428,16 @@ _srt_get_steam_desktop_entries_from_json_report (JsonObject *json_obj)
           gboolean is_default = FALSE;
           gboolean is_steam_handler = FALSE;
           json_sub_obj = json_array_get_object_element (array, i);
-          if (json_object_has_member (json_sub_obj, "id"))
-            id = json_object_get_string_member (json_sub_obj, "id");
-
-          if (json_object_has_member (json_sub_obj, "commandline"))
-            commandline = json_object_get_string_member (json_sub_obj, "commandline");
-
-          if (json_object_has_member (json_sub_obj, "filename"))
-            filename = json_object_get_string_member (json_sub_obj, "filename");
-
-          if (json_object_has_member (json_sub_obj, "default_steam_uri_handler"))
-            is_default = json_object_get_boolean_member (json_sub_obj, "default_steam_uri_handler");
-
-          if (json_object_has_member (json_sub_obj, "steam_uri_handler"))
-            is_steam_handler = json_object_get_boolean_member (json_sub_obj, "steam_uri_handler");
+          id = json_object_get_string_member_with_default (json_sub_obj, "id", NULL);
+          commandline = json_object_get_string_member_with_default (json_sub_obj, "commandline",
+                                                                    NULL);
+          filename = json_object_get_string_member_with_default (json_sub_obj, "filename", NULL);
+          is_default = json_object_get_boolean_member_with_default (json_sub_obj,
+                                                                    "default_steam_uri_handler",
+                                                                    FALSE);
+          is_steam_handler = json_object_get_boolean_member_with_default (json_sub_obj,
+                                                                          "steam_uri_handler",
+                                                                          FALSE);
 
           desktop_entries = g_list_prepend (desktop_entries, _srt_desktop_entry_new (id,
                                                                                      commandline,
diff --git a/steam-runtime-tools/graphics.c b/steam-runtime-tools/graphics.c
index f49c05dc4..e209abd49 100644
--- a/steam-runtime-tools/graphics.c
+++ b/steam-runtime-tools/graphics.c
@@ -29,6 +29,7 @@
 #include "steam-runtime-tools/enums.h"
 #include "steam-runtime-tools/glib-backports-internal.h"
 #include "steam-runtime-tools/graphics-internal.h"
+#include "steam-runtime-tools/json-glib-backports-internal.h"
 #include "steam-runtime-tools/library-internal.h"
 #include "steam-runtime-tools/utils.h"
 #include "steam-runtime-tools/utils-internal.h"
@@ -1486,9 +1487,8 @@ _srt_graphics_get_from_report (JsonObject *json_obj,
           const gchar *messages = NULL;
           const gchar *renderer = NULL;
           const gchar *version = NULL;
-          /* A missing exit_status means that its value is the default zero */
-          int exit_status = 0;
-          int terminating_signal = 0;
+          int exit_status;
+          int terminating_signal;
           SrtGraphics *graphics;
           SrtGraphicsLibraryVendor library_vendor = SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN;
           SrtGraphicsIssues graphics_issues = SRT_GRAPHICS_ISSUES_NONE;
@@ -1531,14 +1531,12 @@ _srt_graphics_get_from_report (JsonObject *json_obj,
               continue;
             }
 
-          if (json_object_has_member (json_stack_obj, "messages"))
-            messages = json_object_get_string_member (json_stack_obj, "messages");
-
-          if (json_object_has_member (json_stack_obj, "renderer"))
-            renderer = json_object_get_string_member (json_stack_obj, "renderer");
-
-          if (json_object_has_member (json_stack_obj, "version"))
-            version = json_object_get_string_member (json_stack_obj, "version");
+          messages = json_object_get_string_member_with_default (json_stack_obj, "messages",
+                                                                 NULL);
+          renderer = json_object_get_string_member_with_default (json_stack_obj, "renderer",
+                                                                 NULL);
+          version = json_object_get_string_member_with_default (json_stack_obj, "version",
+                                                                NULL);
 
           /* In graphics, a missing "issues" array means that no issues were found */
           if (json_object_has_member (json_stack_obj, "issues"))
@@ -1565,11 +1563,11 @@ _srt_graphics_get_from_report (JsonObject *json_obj,
                 }
             }
 
-          if (json_object_has_member (json_stack_obj, "exit-status"))
-            exit_status = json_object_get_int_member (json_stack_obj, "exit-status");
-
-          if (json_object_has_member (json_stack_obj, "terminating-signal"))
-            terminating_signal = json_object_get_int_member (json_stack_obj, "terminating-signal");
+          /* A missing exit_status means that its value is the default zero */
+          exit_status = json_object_get_int_member_with_default (json_stack_obj, "exit-status", 0);
+          terminating_signal = json_object_get_int_member_with_default (json_stack_obj,
+                                                                        "terminating-signal",
+                                                                        0);
 
           if (json_object_has_member (json_stack_obj, "library-vendor"))
             {
@@ -2848,11 +2846,10 @@ _srt_dri_driver_get_from_report (JsonObject *json_obj)
           const gchar *dri_path = NULL;
           gboolean is_extra = FALSE;
           JsonObject *json_dri_obj = json_array_get_object_element (array, j);
-          if (json_object_has_member (json_dri_obj, "library_path"))
-            dri_path = json_object_get_string_member (json_dri_obj, "library_path");
-
-          if (json_object_has_member (json_dri_obj, "is_extra"))
-            is_extra = json_object_get_boolean_member (json_dri_obj, "is_extra");
+          dri_path = json_object_get_string_member_with_default (json_dri_obj, "library_path",
+                                                                 NULL);
+          is_extra = json_object_get_boolean_member_with_default (json_dri_obj, "is_extra",
+                                                                  FALSE);
 
           dri_drivers = g_list_prepend (dri_drivers, srt_dri_driver_new (dri_path, is_extra));
         }
@@ -4035,11 +4032,12 @@ _srt_va_api_driver_get_from_report (JsonObject *json_obj)
           const gchar *va_api_path = NULL;
           gboolean is_extra = FALSE;
           JsonObject *json_va_api_obj = json_array_get_object_element (array, j);
-          if (json_object_has_member (json_va_api_obj, "library_path"))
-            va_api_path = json_object_get_string_member (json_va_api_obj, "library_path");
-
-          if (json_object_has_member (json_va_api_obj, "is_extra"))
-            is_extra = json_object_get_boolean_member (json_va_api_obj, "is_extra");
+          va_api_path = json_object_get_string_member_with_default (json_va_api_obj,
+                                                                    "library_path",
+                                                                    NULL);
+          is_extra = json_object_get_boolean_member_with_default (json_va_api_obj,
+                                                                  "is_extra",
+                                                                  FALSE);
 
           va_api_drivers = g_list_prepend (va_api_drivers, srt_va_api_driver_new (va_api_path, is_extra));
         }
@@ -4325,14 +4323,12 @@ _srt_vdpau_driver_get_from_report (JsonObject *json_obj)
           const gchar *vdpau_link = NULL;
           gboolean is_extra = FALSE;
           JsonObject *json_vdpau_obj = json_array_get_object_element (array, j);
-          if (json_object_has_member (json_vdpau_obj, "library_path"))
-            vdpau_path = json_object_get_string_member (json_vdpau_obj, "library_path");
-
-          if (json_object_has_member (json_vdpau_obj, "library_link"))
-            vdpau_link = json_object_get_string_member (json_vdpau_obj, "library_link");
-
-          if (json_object_has_member (json_vdpau_obj, "is_extra"))
-            is_extra = json_object_get_boolean_member (json_vdpau_obj, "is_extra");
+          vdpau_path = json_object_get_string_member_with_default (json_vdpau_obj, "library_path",
+                                                                   NULL);
+          vdpau_link = json_object_get_string_member_with_default (json_vdpau_obj, "library_link",
+                                                                   NULL);
+          is_extra = json_object_get_boolean_member_with_default (json_vdpau_obj, "is_extra",
+                                                                  FALSE);
 
           vdpau_drivers = g_list_prepend (vdpau_drivers, srt_vdpau_driver_new (vdpau_path, vdpau_link, is_extra));
         }
@@ -5039,9 +5035,9 @@ get_driver_icds_from_json_report (JsonObject *json_obj,
               const gchar *json_path = NULL;
               const gchar *library_path = NULL;
               const gchar *api_version = NULL;
-              GQuark error_domain = 0;
-              gint error_code = -1;
-              const gchar *error_message = "(missing error message)";
+              GQuark error_domain;
+              gint error_code;
+              const gchar *error_message;
               GError *icd_error = NULL;
               JsonObject *json_icd_obj = json_array_get_object_element (array, i);
               if (json_object_has_member (json_icd_obj, "json_path"))
@@ -5052,21 +5048,19 @@ get_driver_icds_from_json_report (JsonObject *json_obj,
                   continue;
                 }
 
-              if (json_object_has_member (json_icd_obj, "library_path"))
-                library_path = json_object_get_string_member (json_icd_obj, "library_path");
-
-              if (json_object_has_member (json_icd_obj, "api_version"))
-                api_version = json_object_get_string_member (json_icd_obj, "api_version");
-
-              if (json_object_has_member (json_icd_obj, "error-domain"))
-                error_domain = g_quark_from_string (json_object_get_string_member (json_icd_obj,
-                                                                                   "error-domain"));
-
-              if (json_object_has_member (json_icd_obj, "error-code"))
-                error_code = json_object_get_int_member (json_icd_obj, "error-code");
-
-              if (json_object_has_member (json_icd_obj, "error"))
-                error_message = json_object_get_string_member (json_icd_obj, "error");
+              library_path = json_object_get_string_member_with_default (json_icd_obj,
+                                                                         "library_path",
+                                                                         NULL);
+              api_version = json_object_get_string_member_with_default (json_icd_obj,
+                                                                        "api_version",
+                                                                        NULL);
+              error_domain = g_quark_from_string (json_object_get_string_member_with_default (json_icd_obj,
+                                                                                              "error-domain",
+                                                                                              NULL));
+              error_code = json_object_get_int_member_with_default (json_icd_obj, "error-code", -1);
+              error_message = json_object_get_string_member_with_default (json_icd_obj,
+                                                                          "error",
+                                                                          "(missing error message)");
 
               if (library_path != NULL)
                 {
@@ -5315,11 +5309,10 @@ _srt_glx_icd_get_from_report (JsonObject *json_obj)
           const gchar *glx_path = NULL;
           const gchar *glx_soname = NULL;
           JsonObject *json_glx_obj = json_array_get_object_element (array, j);
-          if (json_object_has_member (json_glx_obj, "library_path"))
-            glx_path = json_object_get_string_member (json_glx_obj, "library_path");
-
-          if (json_object_has_member (json_glx_obj, "library_soname"))
-            glx_soname = json_object_get_string_member (json_glx_obj, "library_soname");
+          glx_path = json_object_get_string_member_with_default (json_glx_obj, "library_path",
+                                                                 NULL);
+          glx_soname = json_object_get_string_member_with_default (json_glx_obj, "library_soname",
+                                                                   NULL);
 
           glx_drivers = g_list_prepend (glx_drivers, srt_glx_icd_new (glx_soname, glx_path));
         }
diff --git a/steam-runtime-tools/json-glib-backports-internal.h b/steam-runtime-tools/json-glib-backports-internal.h
new file mode 100644
index 000000000..4d4382a12
--- /dev/null
+++ b/steam-runtime-tools/json-glib-backports-internal.h
@@ -0,0 +1,55 @@
+/*<private_header>*/
+/*
+ * Backports from JSON-GLib
+ *
+ * Copyright (C) 2007  OpenedHand Ltd.
+ * Copyright (C) 2009  Intel Corp.
+ * Copyright © 2019-2020 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <libglnx.h>
+
+#include <json-glib/json-glib.h>
+
+#if !JSON_CHECK_VERSION(1, 1, 2)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonBuilder, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonGenerator, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonParser, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonPath, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonReader, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonArray, json_array_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonNode, json_node_free)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonObject, json_object_unref)
+#endif
+
+#if !JSON_CHECK_VERSION(1, 6, 0)
+#define json_object_get_string_member_with_default my_json_object_get_string_member_with_default
+const char * my_json_object_get_string_member_with_default (JsonObject *object,
+                                                            const char *member_name,
+                                                            const char *default_value);
+
+#define json_object_get_boolean_member_with_default my_json_object_get_boolean_member_with_default
+gboolean my_json_object_get_boolean_member_with_default (JsonObject *object,
+                                                         const char *member_name,
+                                                         gboolean default_value);
+
+#define json_object_get_int_member_with_default my_json_object_get_int_member_with_default
+gint64 my_json_object_get_int_member_with_default (JsonObject *object,
+                                                   const char *member_name,
+                                                   gint64 default_value);
+#endif
diff --git a/steam-runtime-tools/json-glib-backports.c b/steam-runtime-tools/json-glib-backports.c
new file mode 100644
index 000000000..0e787dce8
--- /dev/null
+++ b/steam-runtime-tools/json-glib-backports.c
@@ -0,0 +1,131 @@
+/*
+ * Backports from JSON-GLib
+ *
+ * Copyright (C) 2007  OpenedHand Ltd.
+ * Copyright (C) 2009  Intel Corp.
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "steam-runtime-tools/json-glib-backports-internal.h"
+
+#include <glib-object.h>
+
+#if !JSON_CHECK_VERSION(1, 6, 0)
+/*
+ * json_object_get_string_member_with_default:
+ * @object: a #JsonObject
+ * @member_name: the name of the object member
+ * @default_value: the value to return if member_name is not valid
+ *
+ * Convenience function that retrieves the string value stored in
+ * @member_name of object.
+ *
+ * If @member_name does not exist, does not contain a scalar value, or
+ * contains %NULL, then @default_value is returned instead.
+ *
+ * Returns: the string value of the object's member, or the given default
+ */
+const char *
+my_json_object_get_string_member_with_default (JsonObject *object,
+                                               const char *member_name,
+                                               const char *default_value)
+{
+  g_return_val_if_fail (object != NULL, default_value);
+  g_return_val_if_fail (member_name != NULL, default_value);
+
+  JsonNode *node = json_object_get_member (object, member_name);
+
+  if (node == NULL)
+    return default_value;
+
+  if (JSON_NODE_HOLDS_NULL (node))
+    return default_value;
+
+  g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, default_value);
+
+  return json_node_get_string (node);
+}
+
+/*
+ * json_object_get_boolean_member_with_default:
+ * @object: a #JsonObject
+ * @member_name: the name of the object member
+ * @default_value: the value to return if member_name is not valid
+ *
+ * Convenience function that retrieves the boolean value stored in
+ * @member_name of object.
+ *
+ * If @member_name does not exist, does not contain a scalar value, or
+ * contains %NULL, then @default_value is returned instead.
+ *
+ * Returns: the boolean value of the object's member, or the given default
+ */
+gboolean
+my_json_object_get_boolean_member_with_default (JsonObject *object,
+                                                const char *member_name,
+                                                gboolean default_value)
+{
+  g_return_val_if_fail (object != NULL, default_value);
+  g_return_val_if_fail (member_name != NULL, default_value);
+
+  JsonNode *node = json_object_get_member (object, member_name);
+
+  if (node == NULL)
+    return default_value;
+
+  if (JSON_NODE_HOLDS_NULL (node))
+    return default_value;
+
+  g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, default_value);
+
+  return json_node_get_boolean (node);
+}
+
+/*
+ * json_object_get_int_member_with_default:
+ * @object: a #JsonObject
+ * @member_name: the name of the object member
+ * @default_value: the value to return if member_name is not valid
+ *
+ * Convenience function that retrieves the integer value stored in
+ * @member_name of object.
+ *
+ * If @member_name does not exist, does not contain a scalar value, or
+ * contains %NULL, then @default_value is returned instead.
+ *
+ * Returns: the integer value of the object's member, or the given default
+ */
+gint64
+my_json_object_get_int_member_with_default (JsonObject *object,
+                                            const char *member_name,
+                                            gint64 default_value)
+{
+  g_return_val_if_fail (object != NULL, default_value);
+  g_return_val_if_fail (member_name != NULL, default_value);
+
+  JsonNode *node = json_object_get_member (object, member_name);
+
+  if (node == NULL)
+    return default_value;
+
+  if (JSON_NODE_HOLDS_NULL (node))
+    return default_value;
+
+  g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, default_value);
+
+  return json_node_get_int (node);
+}
+#endif
diff --git a/steam-runtime-tools/json-glib-compat.h b/steam-runtime-tools/json-glib-compat.h
deleted file mode 100644
index b01b6e68c..000000000
--- a/steam-runtime-tools/json-glib-compat.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*<private_header>*/
-/*
- * Copyright © 2019 Collabora Ltd.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#pragma once
-
-#include <libglnx.h>
-
-#include <json-glib/json-glib.h>
-
-#if !JSON_CHECK_VERSION(1, 1, 2)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonBuilder, g_object_unref)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonGenerator, g_object_unref)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonParser, g_object_unref)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonPath, g_object_unref)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonReader, g_object_unref)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonArray, json_array_unref)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonNode, json_node_free)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (JsonObject, json_object_unref)
-#endif
diff --git a/steam-runtime-tools/library.c b/steam-runtime-tools/library.c
index a8c0d8265..a09c18149 100644
--- a/steam-runtime-tools/library.c
+++ b/steam-runtime-tools/library.c
@@ -28,6 +28,7 @@
 #include "steam-runtime-tools/architecture.h"
 #include "steam-runtime-tools/enums.h"
 #include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/json-glib-backports-internal.h"
 #include "steam-runtime-tools/library-internal.h"
 #include "steam-runtime-tools/utils.h"
 #include "steam-runtime-tools/utils-internal.h"
@@ -777,10 +778,8 @@ _srt_check_library_presence (const char *helpers_path,
     }
   json = json_object_get_object_member (json, requested_name);
 
-  absolute_path = g_strdup (json_object_get_string_member (json, "path"));
-
-  if (json_object_has_member (json, "SONAME"))
-    real_soname = g_strdup (json_object_get_string_member (json, "SONAME"));
+  absolute_path = g_strdup (json_object_get_string_member_with_default (json, "path", NULL));
+  real_soname = g_strdup (json_object_get_string_member_with_default (json, "SONAME", NULL));
 
   if (json_object_has_member (json, "missing_symbols"))
     missing_array = json_object_get_array_member (json, "missing_symbols");
diff --git a/steam-runtime-tools/locale.c b/steam-runtime-tools/locale.c
index d8d8b2eb8..8e46d9eb6 100644
--- a/steam-runtime-tools/locale.c
+++ b/steam-runtime-tools/locale.c
@@ -28,6 +28,7 @@
 #include "steam-runtime-tools/architecture.h"
 #include "steam-runtime-tools/enums.h"
 #include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/json-glib-backports-internal.h"
 #include "steam-runtime-tools/locale-internal.h"
 #include "steam-runtime-tools/utils-internal.h"
 
@@ -378,31 +379,23 @@ _srt_locale_get_locale_from_report (JsonObject *json_obj,
   const gchar *resulting_name = NULL;
   const gchar *charset = NULL;
   gboolean is_utf8 = FALSE;
-  GQuark error_domain = 0;
-  gint error_code = -1;
-  const gchar *error_message = "(missing error message)";
+  GQuark error_domain;
+  gint error_code;
+  const gchar *error_message;
 
   g_return_val_if_fail (json_obj != NULL, NULL);
   g_return_val_if_fail (requested_name != NULL, NULL);
   g_return_val_if_fail (error != NULL && *error == NULL, NULL);
 
-  if (json_object_has_member (json_obj, "resulting-name"))
-    resulting_name = json_object_get_string_member (json_obj, "resulting-name");
-
-  if (json_object_has_member (json_obj, "charset"))
-    charset = json_object_get_string_member (json_obj, "charset");
-
-  if (json_object_has_member (json_obj, "is_utf8"))
-    is_utf8 = json_object_get_boolean_member (json_obj, "is_utf8");
-
-  if (json_object_has_member (json_obj, "error-domain"))
-    error_domain = g_quark_from_string (json_object_get_string_member (json_obj, "error-domain"));
-
-  if (json_object_has_member (json_obj, "error-code"))
-    error_code = json_object_get_int_member (json_obj, "error-code");
-
-  if (json_object_has_member (json_obj, "error"))
-    error_message = json_object_get_string_member (json_obj, "error");
+  resulting_name = json_object_get_string_member_with_default (json_obj, "resulting-name", NULL);
+  charset = json_object_get_string_member_with_default (json_obj, "charset", NULL);
+  is_utf8 = json_object_get_boolean_member_with_default (json_obj, "is_utf8", FALSE);
+  error_domain = g_quark_from_string (json_object_get_string_member_with_default (json_obj,
+                                                                                  "error-domain",
+                                                                                  NULL));
+  error_code = json_object_get_int_member_with_default (json_obj, "error-code", -1);
+  error_message = json_object_get_string_member_with_default (json_obj, "error",
+                                                              "(missing error message)");
 
   if (resulting_name != NULL && charset != NULL)
     {
diff --git a/steam-runtime-tools/meson.build b/steam-runtime-tools/meson.build
index e710cc5e2..2d69c4042 100644
--- a/steam-runtime-tools/meson.build
+++ b/steam-runtime-tools/meson.build
@@ -32,6 +32,8 @@ libsteamrt_sources = [
     'glib-backports-internal.h',
     'graphics-internal.h',
     'graphics.c',
+    'json-glib-backports.c',
+    'json-glib-backports-internal.h',
     'library-internal.h',
     'library.c',
     'locale-internal.h',
diff --git a/steam-runtime-tools/os.c b/steam-runtime-tools/os.c
index 3f0a4a00a..196d5261f 100644
--- a/steam-runtime-tools/os.c
+++ b/steam-runtime-tools/os.c
@@ -28,6 +28,7 @@
 #include <string.h>
 
 #include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/json-glib-backports-internal.h"
 
 #include <glib.h>
 
@@ -272,9 +273,7 @@ _srt_os_release_populate_from_report (JsonObject *json_obj,
         }
 
       self->populated = TRUE;
-
-      if (json_object_has_member (json_sub_obj, "id"))
-        self->id = g_strdup (json_object_get_string_member (json_sub_obj, "id"));
+      self->id = g_strdup (json_object_get_string_member_with_default (json_sub_obj, "id", NULL));
 
       if (json_object_has_member (json_sub_obj, "id_like"))
         {
@@ -301,25 +300,25 @@ _srt_os_release_populate_from_report (JsonObject *json_obj,
             }
         }
 
-      if (json_object_has_member (json_sub_obj, "name"))
-        self->name = g_strdup (json_object_get_string_member (json_sub_obj, "name"));
-
-      if (json_object_has_member (json_sub_obj, "pretty_name"))
-        self->pretty_name = g_strdup (json_object_get_string_member (json_sub_obj, "pretty_name"));
-
-      if (json_object_has_member (json_sub_obj, "version_id"))
-        self->version_id = g_strdup (json_object_get_string_member (json_sub_obj, "version_id"));
-
-      if (json_object_has_member (json_sub_obj, "version_codename"))
-        self->version_codename = g_strdup (json_object_get_string_member (json_sub_obj, "version_codename"));
-
-      if (json_object_has_member (json_sub_obj, "build_id"))
-        self->build_id = g_strdup (json_object_get_string_member (json_sub_obj, "build_id"));
-
-      if (json_object_has_member (json_sub_obj, "variant_id"))
-        self->variant_id = g_strdup (json_object_get_string_member (json_sub_obj, "variant_id"));
-
-      if (json_object_has_member (json_sub_obj, "variant"))
-        self->variant = g_strdup (json_object_get_string_member (json_sub_obj, "variant"));
+      self->name = g_strdup (json_object_get_string_member_with_default (json_sub_obj, "name",
+                                                                         NULL));
+      self->pretty_name = g_strdup (json_object_get_string_member_with_default (json_sub_obj,
+                                                                                "pretty_name",
+                                                                                NULL));
+      self->version_id = g_strdup (json_object_get_string_member_with_default (json_sub_obj,
+                                                                               "version_id",
+                                                                               NULL));
+      self->version_codename = g_strdup (json_object_get_string_member_with_default (json_sub_obj,
+                                                                                     "version_codename",
+                                                                                     NULL));
+      self->build_id = g_strdup (json_object_get_string_member_with_default (json_sub_obj,
+                                                                             "build_id",
+                                                                             NULL));
+      self->variant_id = g_strdup (json_object_get_string_member_with_default (json_sub_obj,
+                                                                               "variant_id",
+                                                                               NULL));
+      self->variant = g_strdup (json_object_get_string_member_with_default (json_sub_obj,
+                                                                            "variant",
+                                                                            NULL));
     }
 }
diff --git a/steam-runtime-tools/steam.c b/steam-runtime-tools/steam.c
index 127742166..819fa0f67 100644
--- a/steam-runtime-tools/steam.c
+++ b/steam-runtime-tools/steam.c
@@ -37,6 +37,7 @@
 #include "steam-runtime-tools/desktop-entry-internal.h"
 #include "steam-runtime-tools/enums.h"
 #include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/json-glib-backports-internal.h"
 #include "steam-runtime-tools/utils.h"
 #include "steam-runtime-tools/utils-internal.h"
 
@@ -767,20 +768,15 @@ _srt_steam_get_from_report (JsonObject *json_obj)
             }
         }
 
-      if (json_object_has_member (json_sub_obj, "path"))
-        install_path = json_object_get_string_member (json_sub_obj, "path");
-
-      if (json_object_has_member (json_sub_obj, "data_path"))
-        data_path = json_object_get_string_member (json_sub_obj, "data_path");
-
-      if (json_object_has_member (json_sub_obj, "bin32_path"))
-        bin32_path = json_object_get_string_member (json_sub_obj, "bin32_path");
-
-      if (json_object_has_member (json_sub_obj, "steamscript_path"))
-        steamscript_path = json_object_get_string_member (json_sub_obj, "steamscript_path");
-
-      if (json_object_has_member (json_sub_obj, "steamscript_version"))
-        steamscript_version = json_object_get_string_member (json_sub_obj, "steamscript_version");
+      install_path = json_object_get_string_member_with_default (json_sub_obj, "path", NULL);
+      data_path = json_object_get_string_member_with_default (json_sub_obj, "data_path", NULL);
+      bin32_path = json_object_get_string_member_with_default (json_sub_obj, "bin32_path", NULL);
+      steamscript_path = json_object_get_string_member_with_default (json_sub_obj,
+                                                                     "steamscript_path",
+                                                                     NULL);
+      steamscript_version = json_object_get_string_member_with_default (json_sub_obj,
+                                                                        "steamscript_version",
+                                                                        NULL);
     }
 
 out:
diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c
index 346846e05..fef92aba2 100644
--- a/steam-runtime-tools/system-info.c
+++ b/steam-runtime-tools/system-info.c
@@ -25,9 +25,10 @@
 
 #include "steam-runtime-tools/system-info.h"
 
-/* Include this at the beginning so that every backports of
+/* Include these at the beginning so that every backports of
  * G_DEFINE_AUTOPTR_CLEANUP_FUNC will be visible */
 #include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/json-glib-backports-internal.h"
 
 #include "steam-runtime-tools/architecture.h"
 #include "steam-runtime-tools/architecture-internal.h"
@@ -621,8 +622,9 @@ srt_system_info_new_from_json (const char *path,
 
   json_obj = json_node_get_object (node);
 
-  if (json_object_has_member (json_obj, "can-write-uinput"))
-    info->can_write_uinput = json_object_get_boolean_member (json_obj, "can-write-uinput");
+  info->can_write_uinput = json_object_get_boolean_member_with_default (json_obj,
+                                                                        "can-write-uinput",
+                                                                        FALSE);
 
   info->steam_data = _srt_steam_get_from_report (json_obj);
 
@@ -631,11 +633,13 @@ srt_system_info_new_from_json (const char *path,
     {
       json_sub_obj = json_object_get_object_member (json_obj, "runtime");
 
-      if (json_object_has_member (json_sub_obj, "path"))
-        info->runtime.path = g_strdup (json_object_get_string_member (json_sub_obj, "path"));
+      info->runtime.path = g_strdup (json_object_get_string_member_with_default (json_sub_obj,
+                                                                                 "path",
+                                                                                 NULL));
 
-      if (json_object_has_member (json_sub_obj, "version"))
-        info->runtime.version = g_strdup (json_object_get_string_member (json_sub_obj, "version"));
+      info->runtime.version = g_strdup (json_object_get_string_member_with_default (json_sub_obj,
+                                                                                    "version",
+                                                                                    NULL));
 
       info->pinned_libs.have_data = TRUE;
 
@@ -3444,8 +3448,8 @@ _srt_system_info_get_container_info_from_report (JsonObject *json_obj,
       if (json_object_has_member (json_sub_obj, "host"))
         {
           json_host_obj = json_object_get_object_member (json_sub_obj, "host");
-          if (json_object_has_member (json_host_obj, "path"))
-            *host_path = g_strdup (json_object_get_string_member (json_host_obj, "path"));
+          *host_path = g_strdup (json_object_get_string_member_with_default (json_host_obj, "path",
+                                                                             NULL));
         }
     }
 
diff --git a/steam-runtime-tools/xdg-portal.c b/steam-runtime-tools/xdg-portal.c
index ba4c7af2e..5c32df417 100644
--- a/steam-runtime-tools/xdg-portal.c
+++ b/steam-runtime-tools/xdg-portal.c
@@ -27,7 +27,7 @@
 
 #include "steam-runtime-tools/enums.h"
 #include "steam-runtime-tools/glib-backports-internal.h"
-#include "steam-runtime-tools/json-glib-compat.h"
+#include "steam-runtime-tools/json-glib-backports-internal.h"
 #include "steam-runtime-tools/xdg-portal-internal.h"
 #include "steam-runtime-tools/utils.h"
 #include "steam-runtime-tools/utils-internal.h"
@@ -736,8 +736,7 @@ _srt_xdg_portal_get_info_from_report (JsonObject *json_obj)
                                           "issues",
                                           SRT_XDG_PORTAL_ISSUES_UNKNOWN);
 
-  if (json_object_has_member (json_portals_obj, "messages"))
-    messages = json_object_get_string_member (json_portals_obj, "messages");
+  messages = json_object_get_string_member_with_default (json_portals_obj, "messages", NULL);
 
   if (!json_object_has_member (json_portals_obj, "details"))
     return _srt_xdg_portal_new (messages, issues, NULL, NULL);
@@ -751,13 +750,11 @@ _srt_xdg_portal_get_info_from_report (JsonObject *json_obj)
       for (const GList *l = interfaces_members; l != NULL; l = l->next)
         {
           gboolean available = FALSE;
-          gint64 version = 0;
+          gint64 version;
           JsonObject *json_portal_obj = json_object_get_object_member (json_interfaces_obj, l->data);
-          if (json_object_has_member (json_portal_obj, "available"))
-            available = json_object_get_boolean_member (json_portal_obj, "available");
-
-          if (json_object_has_member (json_portal_obj, "version"))
-            version = json_object_get_int_member (json_portal_obj, "version");
+          available = json_object_get_boolean_member_with_default (json_portal_obj, "available",
+                                                                   FALSE);
+          version = json_object_get_int_member_with_default (json_portal_obj, "version", 0);
 
           g_ptr_array_add (interfaces,
                            _srt_xdg_portal_interface_new (l->data, available, version));
@@ -772,8 +769,8 @@ _srt_xdg_portal_get_info_from_report (JsonObject *json_obj)
         {
           gboolean available = FALSE;
           JsonObject *json_portal_obj = json_object_get_object_member (json_backends_obj, l->data);
-          if (json_object_has_member (json_portal_obj, "available"))
-            available = json_object_get_boolean_member (json_portal_obj, "available");
+          available = json_object_get_boolean_member_with_default (json_portal_obj, "available",
+                                                                   FALSE);
 
           g_ptr_array_add (backends, _srt_xdg_portal_backend_new (l->data, available));
         }
diff --git a/tests/system-info-cli.c b/tests/system-info-cli.c
index 10c21270b..9dd0974df 100644
--- a/tests/system-info-cli.c
+++ b/tests/system-info-cli.c
@@ -28,7 +28,7 @@
 #include <steam-runtime-tools/steam-runtime-tools.h>
 
 #include <steam-runtime-tools/glib-backports-internal.h>
-#include <steam-runtime-tools/json-glib-compat.h>
+#include <steam-runtime-tools/json-glib-backports-internal.h>
 
 #include <glib.h>
 #include <glib/gstdio.h>
-- 
GitLab