third_party: add boringssl, libtpms, swtpm

This isn't yet used, but will soon be used as the main swtpm
implementation (instead of whatever is provided by the ambient
environment and/or sandbox).

Change-Id: I8c8cc7fd7841f10e14d6390595805a8b905d4f4e
Reviewed-on: https://review.monogon.dev/c/monogon/+/3127
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/third_party/libtpms/BUILD.bazel b/third_party/libtpms/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/libtpms/BUILD.bazel
diff --git a/third_party/libtpms/external.bzl b/third_party/libtpms/external.bzl
new file mode 100644
index 0000000..d6052b4
--- /dev/null
+++ b/third_party/libtpms/external.bzl
@@ -0,0 +1,23 @@
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+def libtpms_external(name, version):
+    sums = {
+        # master at 2024/01/09 (0.10.0 prerelease).
+        "93a827aeccd3ab2178281571b1545dcfffa2991b": "e509e0ba109f77da517b5e58a9f093beb040525e6be51de06d1153c8278c70d1",
+    }
+
+    http_archive(
+        name = name,
+        patch_args = ["-p1"],
+        patches = [
+            "//third_party/libtpms/patches:0001-boringssl-compat-new-SHA-types.patch",
+            "//third_party/libtpms/patches:0002-boringssl-compat-removed-const_DES_cblock.patch",
+            "//third_party/libtpms/patches:0003-boringssl-compat-removed-EC_POINTs_mul.patch",
+            "//third_party/libtpms/patches:0004-boringssl-compat-removed-camellia-support.patch",
+            "//third_party/libtpms/patches:0005-boringssl-compat-remove-constant-time-flags-UNSAFE.patch",
+            "//third_party/libtpms/patches:0006-bazel-support-implement.patch",
+        ],
+        sha256 = sums[version],
+        strip_prefix = "libtpms-" + version,
+        urls = ["https://github.com/stefanberger/libtpms/archive/%s.tar.gz" % version],
+    )
diff --git a/third_party/libtpms/patches/0001-boringssl-compat-new-SHA-types.patch b/third_party/libtpms/patches/0001-boringssl-compat-new-SHA-types.patch
new file mode 100644
index 0000000..b4d25f4
--- /dev/null
+++ b/third_party/libtpms/patches/0001-boringssl-compat-new-SHA-types.patch
@@ -0,0 +1,57 @@
+From 51935c4f084265833951e5439b682913bfbac03a Mon Sep 17 00:00:00 2001
+From: Serge Bazanski <serge@monogon.tech>
+Date: Tue, 4 Jun 2024 12:58:10 +0200
+Subject: [PATCH 1/6] boringssl compat: new SHA types
+
+See: https://github.com/google/boringssl/commit/51011b4a262046a3d9a2eb5690e54af80377f15a
+---
+ src/tpm2/NVMarshal.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/src/tpm2/NVMarshal.c b/src/tpm2/NVMarshal.c
+index a4a9498..6d42a97 100644
+--- a/src/tpm2/NVMarshal.c
++++ b/src/tpm2/NVMarshal.c
+@@ -58,6 +58,9 @@
+ #define TPM_HAVE_TPM2_DECLARATIONS
+ #include "tpm_library_intern.h"
+ 
++#define SHA_LONG uint32_t
++#define SHA_LONG64 uint64_t
++
+ /*
+  * The TPM2 maintains a pcrAllocated shadow variable; the current active one is
+  * in gp.pcrAllocated and the one to be active after reboot is in NVRAM. So,
+@@ -1943,9 +1946,9 @@ tpmHashStateSHA512_Marshal(SHA512_CTX *data, BYTE **buffer, INT32 *size,
+     written += SHA_LONG64_Marshal(&data->Nl, buffer, size);
+     written += SHA_LONG64_Marshal(&data->Nh, buffer, size);
+ 
+-    array_size = sizeof(data->u.p);
++    array_size = sizeof(data->p);
+     written += UINT16_Marshal(&array_size, buffer, size);
+-    written += Array_Marshal(&data->u.p[0], array_size, buffer, size);
++    written += Array_Marshal(&data->p[0], array_size, buffer, size);
+ 
+     written += UINT32_Marshal(&data->num, buffer, size);
+     written += UINT32_Marshal(&data->md_len, buffer, size);
+@@ -2005,14 +2008,14 @@ tpmHashStateSHA512_Unmarshal(SHA512_CTX *data, BYTE **buffer, INT32 *size,
+         rc = UINT16_Unmarshal(&array_size, buffer, size);
+     }
+     if (rc == TPM_RC_SUCCESS &&
+-        array_size != sizeof(data->u.p)) {
++        array_size != sizeof(data->p)) {
+         TPMLIB_LogTPM2Error("HASH_STATE_SHA512: Bad array size for u.p; "
+                             "expected %zu, got %u\n",
+-                            sizeof(data->u.p), array_size);
++                            sizeof(data->p), array_size);
+         rc = TPM_RC_BAD_PARAMETER;
+     }
+     if (rc == TPM_RC_SUCCESS) {
+-        rc = Array_Unmarshal(&data->u.p[0], array_size, buffer, size);
++        rc = Array_Unmarshal(&data->p[0], array_size, buffer, size);
+     }
+     if (rc == TPM_RC_SUCCESS) {
+         rc = UINT32_Unmarshal(&data->num, buffer, size);
+-- 
+2.42.0
+
diff --git a/third_party/libtpms/patches/0002-boringssl-compat-removed-const_DES_cblock.patch b/third_party/libtpms/patches/0002-boringssl-compat-removed-const_DES_cblock.patch
new file mode 100644
index 0000000..555ded5
--- /dev/null
+++ b/third_party/libtpms/patches/0002-boringssl-compat-removed-const_DES_cblock.patch
@@ -0,0 +1,54 @@
+From 42c0bd4522b06361bdbbb1fec182bdc363db9982 Mon Sep 17 00:00:00 2001
+From: Serge Bazanski <serge@monogon.tech>
+Date: Tue, 4 Jun 2024 12:58:37 +0200
+Subject: [PATCH 2/6] boringssl compat: removed const_DES_cblock
+
+This was some kind of hack for GCC 2.8.1 that never made it into
+BoringSSL.
+---
+ src/tpm2/crypto/openssl/TpmToOsslDesSupport.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/src/tpm2/crypto/openssl/TpmToOsslDesSupport.c b/src/tpm2/crypto/openssl/TpmToOsslDesSupport.c
+index d27aad2..9f972d6 100644
+--- a/src/tpm2/crypto/openssl/TpmToOsslDesSupport.c
++++ b/src/tpm2/crypto/openssl/TpmToOsslDesSupport.c
+@@ -78,14 +78,14 @@ TDES_set_encrypt_key(
+ 		     tpmKeyScheduleTDES          *keySchedule
+ 		     )
+ {
+-    DES_set_key_unchecked((const_DES_cblock *)key, &keySchedule[0]);
+-    DES_set_key_unchecked((const_DES_cblock *)&key[8], &keySchedule[1]);
++    DES_set_key_unchecked((const DES_cblock *)key, &keySchedule[0]);
++    DES_set_key_unchecked((const DES_cblock *)&key[8], &keySchedule[1]);
+     // If is two-key, copy the schedule for K1 into K3, otherwise, compute the
+     // the schedule for K3
+     if(keySizeInBits == 128)
+ 	keySchedule[2] = keySchedule[0];
+     else
+-	DES_set_key_unchecked((const_DES_cblock *)&key[16],
++	DES_set_key_unchecked((const DES_cblock *)&key[16],
+ 			      &keySchedule[2]);
+ }
+ /* B.2.3.1.3.2. TDES_encyrpt() */
+@@ -97,7 +97,7 @@ void TDES_encrypt(
+ 		  tpmKeyScheduleTDES      *ks
+ 		  )
+ {
+-    DES_ecb3_encrypt((const_DES_cblock *)in, (DES_cblock *)out,
++    DES_ecb3_encrypt((const DES_cblock *)in, (DES_cblock *)out,
+ 		     &ks[0], &ks[1], &ks[2],
+ 		     DES_ENCRYPT);
+ }
+@@ -111,7 +111,7 @@ void TDES_decrypt(
+ 		  tpmKeyScheduleTDES   *ks
+ 		  )
+ {
+-    DES_ecb3_encrypt((const_DES_cblock *)in, (DES_cblock *)out,
++    DES_ecb3_encrypt((const DES_cblock *)in, (DES_cblock *)out,
+ 		     &ks[0], &ks[1], &ks[2],
+ 		     DES_DECRYPT);
+ }
+-- 
+2.42.0
+
diff --git a/third_party/libtpms/patches/0003-boringssl-compat-removed-EC_POINTs_mul.patch b/third_party/libtpms/patches/0003-boringssl-compat-removed-EC_POINTs_mul.patch
new file mode 100644
index 0000000..8b5669a
--- /dev/null
+++ b/third_party/libtpms/patches/0003-boringssl-compat-removed-EC_POINTs_mul.patch
@@ -0,0 +1,42 @@
+From 2cd6a191b0940d03d557941eda3395bdafbdb662 Mon Sep 17 00:00:00 2001
+From: Serge Bazanski <serge@monogon.tech>
+Date: Tue, 4 Jun 2024 12:59:11 +0200
+Subject: [PATCH 3/6] boringssl compat: removed EC_POINTs_mul
+
+This was deprecated in OpenSSL 3.0, we just need to 'fix' the ifdef
+guard to use the undeprecated APIs.
+---
+ src/tpm2/crypto/openssl/BnToOsslMath.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+diff --git a/src/tpm2/crypto/openssl/BnToOsslMath.c b/src/tpm2/crypto/openssl/BnToOsslMath.c
+index 1b9fb81..7d13ce8 100644
+--- a/src/tpm2/crypto/openssl/BnToOsslMath.c
++++ b/src/tpm2/crypto/openssl/BnToOsslMath.c
+@@ -622,7 +622,6 @@ LIB_EXPORT BOOL BnEccModMult2(bigPoint            R,  // OUT: computed point
+ 	EC_POINT_mul(E->G, pR, bnD, pQ, bnU, E->CTX);
+     else
+ 	{
+-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ 	    EC_POINT *pR1 = EC_POINT_new(E->G);
+ 	    EC_POINT *pR2 = EC_POINT_new(E->G);
+ 	    int OK;
+@@ -635,15 +634,6 @@ LIB_EXPORT BOOL BnEccModMult2(bigPoint            R,  // OUT: computed point
+ 
+ 	    EC_POINT_clear_free(pR1);
+ 	    EC_POINT_clear_free(pR2);
+-#else
+-	    const EC_POINT* points[2];
+-	    const BIGNUM*   scalars[2];
+-	    points[0]  = pS;
+-	    points[1]  = pQ;
+-	    scalars[0] = bnD;
+-	    scalars[1] = bnU;
+-	    EC_POINTs_mul(E->G, pR, NULL, 2, points, scalars, E->CTX);
+-#endif
+ 	}
+     PointFromOssl(R, pR, E);
+     EC_POINT_clear_free(pR); // libtpms changed
+-- 
+2.42.0
+
diff --git a/third_party/libtpms/patches/0004-boringssl-compat-removed-camellia-support.patch b/third_party/libtpms/patches/0004-boringssl-compat-removed-camellia-support.patch
new file mode 100644
index 0000000..231d1d5
--- /dev/null
+++ b/third_party/libtpms/patches/0004-boringssl-compat-removed-camellia-support.patch
@@ -0,0 +1,33 @@
+From 00f0c95d643bc714f3361fa4f10dee3bf9f9384e Mon Sep 17 00:00:00 2001
+From: Serge Bazanski <serge@monogon.tech>
+Date: Tue, 4 Jun 2024 12:59:30 +0200
+Subject: [PATCH 4/6] boringssl compat: removed camellia support
+
+BoringSSL removed Camellia support out of principle, we don't care for
+it either and the TPM spec doesn't mandate it.
+---
+ src/tpm2/TpmProfile_Common.h | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/tpm2/TpmProfile_Common.h b/src/tpm2/TpmProfile_Common.h
+index a4bf462..78842a6 100644
+--- a/src/tpm2/TpmProfile_Common.h
++++ b/src/tpm2/TpmProfile_Common.h
+@@ -133,11 +133,11 @@
+ 
+ #define     SM4_128                     (NO  * ALG_SM4)
+ 
+-#define ALG_CAMELLIA                ALG_YES
++#define ALG_CAMELLIA                ALG_NO
+ 
+-#define     CAMELLIA_128                (YES * ALG_CAMELLIA)
++#define     CAMELLIA_128                (NO  * ALG_CAMELLIA)
+ #define     CAMELLIA_192                (NO  * ALG_CAMELLIA)
+-#define     CAMELLIA_256                (YES * ALG_CAMELLIA)
++#define     CAMELLIA_256                (NO  * ALG_CAMELLIA)
+ 
+ #define ALG_TDES                        ALG_YES /* libtpms enabled */
+ 
+-- 
+2.42.0
+
diff --git a/third_party/libtpms/patches/0005-boringssl-compat-remove-constant-time-flags-UNSAFE.patch b/third_party/libtpms/patches/0005-boringssl-compat-remove-constant-time-flags-UNSAFE.patch
new file mode 100644
index 0000000..795ee1e
--- /dev/null
+++ b/third_party/libtpms/patches/0005-boringssl-compat-remove-constant-time-flags-UNSAFE.patch
@@ -0,0 +1,176 @@
+From 98df8cd09ec7a5b91f05c665529ed6f579f231d9 Mon Sep 17 00:00:00 2001
+From: Serge Bazanski <serge@monogon.tech>
+Date: Tue, 4 Jun 2024 13:53:48 +0200
+Subject: [PATCH 5/6] boringssl compat: remove constant time flags (UNSAFE)
+
+OpenSSL has a quirky little API to mark bignums as 'secret' ie.
+'constant time' which is supposed to influence operations performed on
+them to be constant time.
+
+This API was tricky to use and caused security issues, so it was removed
+by BoringSSL.
+
+https://github.com/google/boringssl/commit/0a211dfe91588d2986a8735e1969dd9202a8b025
+
+Ideally we would replace all relevent BN_mod_exp calls with
+constant-time versions, but that's not trivial to do: the constant time
+versions of modular exponentiation and multiplicative inverse operations
+rely on Montgomery modular multiplication which seems to reduce the
+domain of the exponent to |0, N>. Unfortunately libtpms has plenty of
+eg. ModExp operations that work on exponents outside this range. OpenSSL
+seems to not have applied the constant time request to BN_mod_exp if
+that was the case, but BoringSSL refuses to perform constant time
+operations then.
+
+As I'm not a cryptographer and not able to fix this properly (or even
+fully reason about this), I'm just adding a big fat warning to be shown
+whenever potentially unsafe operations are now performed.
+---
+ src/monogon_unsafe.c                   | 28 ++++++++++++++++++++++++++
+ src/tpm2/crypto/openssl/BnToOsslMath.c | 10 +++++----
+ src/tpm2/crypto/openssl/ExpDCache.c    |  5 +++--
+ 3 files changed, 37 insertions(+), 6 deletions(-)
+ create mode 100644 src/monogon_unsafe.c
+
+diff --git a/src/monogon_unsafe.c b/src/monogon_unsafe.c
+new file mode 100644
+index 0000000..abaef79
+--- /dev/null
++++ b/src/monogon_unsafe.c
+@@ -0,0 +1,28 @@
++#include <stdio.h>
++#include <stdlib.h>
++
++// This library was built against BoringSSL without the BN constant time API,
++// thus all cryptographic operations are performed timing-unsafe which might
++// lead to side channel leaks. This is fine for Monogon's usecase (swtpm in
++// tests) but this code must not end up being used to secure any real systems.
++//
++// Note: I am not sure this code was safe from side channels in the first
++// place. See RsaPrivateKeyOp and compare with BoringSSL's
++// rsa_default_private_transform implementation... ~q3k
++
++static int _warned = 0;
++
++void monogon_warn_unsafe_library(void)
++{
++    if (getenv("MONOGON_LIBTPMS_ACKNOWLEDGE_UNSAFE") != NULL) {
++        return;
++    }
++    if (_warned) {
++        return;
++    }
++    _warned = 1;
++    fprintf(stderr, "--------------------------------------------------------------------------------\n");
++    fprintf(stderr, "WARNING: This fork of libtpms/swtpm contains UNSAFE cryptographic operations and\n");
++    fprintf(stderr, "         MUST NOT be used to secure sensitive data.\n");
++    fprintf(stderr, "--------------------------------------------------------------------------------\n");
++}
+diff --git a/src/tpm2/crypto/openssl/BnToOsslMath.c b/src/tpm2/crypto/openssl/BnToOsslMath.c
+index 7d13ce8..54d5916 100644
+--- a/src/tpm2/crypto/openssl/BnToOsslMath.c
++++ b/src/tpm2/crypto/openssl/BnToOsslMath.c
+@@ -83,6 +83,8 @@
+ //#include "Tpm.h"
+ #include "BnOssl.h"
+ 
++extern void monogon_warn_unsafe_library();
++
+ #ifdef MATH_LIB_OSSL
+ #  include "BnToOsslMath_fp.h"
+ 
+@@ -133,6 +135,7 @@ BOOL OsslToTpmBn(bigNum bn, const BIGNUM* osslBn)	// libtpms: added 'const'
+ // function prototype. Instead, use BnNewVariable().
+ BIGNUM* BigInitialized(BIGNUM* toInit, bigConst initializer)
+ {
++    monogon_warn_unsafe_library();
+ #if 1		// libtpms: added begin
+     BIGNUM *_toInit;
+     unsigned char buffer[LARGEST_NUMBER + 1];
+@@ -147,7 +150,6 @@ BIGNUM* BigInitialized(BIGNUM* toInit, bigConst initializer)
+ #if 1		// libtpms: added begin
+     BnToBytes(initializer, buffer, &buffer_len);	/* TPM to bin */
+     _toInit = BN_bin2bn(buffer, buffer_len, NULL);	/* bin to ossl */
+-    BN_set_flags(_toInit, BN_FLG_CONSTTIME);
+     BN_copy(toInit, _toInit);
+     BN_clear_free(_toInit);
+ #else		// libtpms: added end
+@@ -355,13 +357,13 @@ LIB_EXPORT BOOL BnGcd(bigNum   gcd,      // OUT: the common divisor
+ 		      bigConst number2   // IN:
+ 		      )
+ {
++    monogon_warn_unsafe_library();
+     OSSL_ENTER();
+     BIGNUM* bnGcd = BN_NEW();
+     BOOL    OK    = TRUE;
+     BIG_INITIALIZED(bn1, number1);
+     BIG_INITIALIZED(bn2, number2);
+     //
+-    BN_set_flags(bn1, BN_FLG_CONSTTIME); // number1 is secret prime number
+     GOTO_ERROR_UNLESS(BN_gcd(bnGcd, bn1, bn2, CTX));
+     GOTO_ERROR_UNLESS(OsslToTpmBn(gcd, bnGcd));
+     goto Exit;
+@@ -387,6 +389,7 @@ LIB_EXPORT BOOL BnModExp(bigNum   result,    // OUT: the result
+ 			 bigConst modulus    // IN:
+ 			 )
+ {
++    monogon_warn_unsafe_library();
+     OSSL_ENTER();
+     BIGNUM* bnResult = BN_NEW();
+     BOOL    OK       = TRUE;
+@@ -394,7 +397,6 @@ LIB_EXPORT BOOL BnModExp(bigNum   result,    // OUT: the result
+     BIG_INITIALIZED(bnE, exponent);
+     BIG_INITIALIZED(bnM, modulus);
+     //
+-    BN_set_flags(bnE, BN_FLG_CONSTTIME); // exponent may be private
+     GOTO_ERROR_UNLESS(BN_mod_exp(bnResult, bnN, bnE, bnM, CTX));
+     GOTO_ERROR_UNLESS(OsslToTpmBn(result, bnResult));
+     goto Exit;
+@@ -416,13 +418,13 @@ LIB_EXPORT BOOL BnModExp(bigNum   result,    // OUT: the result
+ //      FALSE(0)        failure in operation
+ LIB_EXPORT BOOL BnModInverse(bigNum result, bigConst number, bigConst modulus)
+ {
++    monogon_warn_unsafe_library();
+     OSSL_ENTER();
+     BIGNUM* bnResult = BN_NEW();
+     BOOL    OK       = TRUE;
+     BIG_INITIALIZED(bnN, number);
+     BIG_INITIALIZED(bnM, modulus);
+     //
+-    BN_set_flags(bnN, BN_FLG_CONSTTIME); // number may be private
+     GOTO_ERROR_UNLESS(BN_mod_inverse(bnResult, bnN, bnM, CTX) != NULL);
+     GOTO_ERROR_UNLESS(OsslToTpmBn(result, bnResult));
+     goto Exit;
+diff --git a/src/tpm2/crypto/openssl/ExpDCache.c b/src/tpm2/crypto/openssl/ExpDCache.c
+index 5aeaf14..133e9ed 100644
+--- a/src/tpm2/crypto/openssl/ExpDCache.c
++++ b/src/tpm2/crypto/openssl/ExpDCache.c
+@@ -61,6 +61,8 @@
+ #include "Tpm.h"
+ #include "ExpDCache_fp.h"
+ 
++extern void monogon_warn_unsafe_library(void);
++
+ /* Implement a cache for the private exponent D so it doesn't need to be
+  * recalculated every time from P, Q, E and N (modulus). The cache has a
+  * number of entries that cache D and use P, Q, and E for lookup.
+@@ -169,6 +171,7 @@ BIGNUM *ExpDCacheFind(const BIGNUM *P, const BIGNUM *N, const BIGNUM *E, BIGNUM
+     unsigned myage;
+     BIGNUM *D;
+ 
++    monogon_warn_unsafe_library();
+     for (i = 0; i < ARRAY_SIZE(ExpDCache); i++) {
+         if (BN_cmp(ExpDCache[i].P, P) == 0 && BN_cmp(ExpDCache[i].N, N) == 0 &&
+             BN_cmp(ExpDCache[i].E, E) == 0) {
+@@ -190,8 +193,6 @@ BIGNUM *ExpDCacheFind(const BIGNUM *P, const BIGNUM *N, const BIGNUM *E, BIGNUM
+                 *Q = NULL;
+                 return NULL;
+             }
+-            BN_set_flags(*Q, BN_FLG_CONSTTIME);
+-            BN_set_flags(D, BN_FLG_CONSTTIME);
+             return D;
+         }
+     }
+-- 
+2.42.0
+
diff --git a/third_party/libtpms/patches/0006-bazel-support-implement.patch b/third_party/libtpms/patches/0006-bazel-support-implement.patch
new file mode 100644
index 0000000..8152a55
--- /dev/null
+++ b/third_party/libtpms/patches/0006-bazel-support-implement.patch
@@ -0,0 +1,106 @@
+From fa72e847a7fb503daa25b5007edb28483a0f6e42 Mon Sep 17 00:00:00 2001
+From: Serge Bazanski <serge@monogon.tech>
+Date: Tue, 4 Jun 2024 14:31:54 +0200
+Subject: [PATCH 6/6] bazel support: implement
+
+---
+ BUILD.bazel              | 45 ++++++++++++++++++++++++++++++++++++++++
+ WORKSPACE                |  0
+ include/libtpms/config.h |  3 +++
+ src/tpm_library.c        |  1 +
+ src/tpm_tpm2_interface.c |  1 +
+ 5 files changed, 50 insertions(+)
+ create mode 100644 BUILD.bazel
+ create mode 100644 WORKSPACE
+ create mode 100644 include/libtpms/config.h
+
+diff --git a/BUILD.bazel b/BUILD.bazel
+new file mode 100644
+index 0000000..591942d
+--- /dev/null
++++ b/BUILD.bazel
+@@ -0,0 +1,45 @@
++cc_library(
++    name = "libtpms_tpm2",
++    includes = [
++        "include",
++    ],
++    copts = [
++        "-Iexternal/libtpms/include/libtpms",
++        "-Iexternal/libtpms/src",
++        "-Iexternal/libtpms/src/tpm2",
++        "-Iexternal/libtpms/src/tpm2/crypto",
++        "-Iexternal/libtpms/src/tpm2/crypto/openssl",
++    ],
++    defines = [
++        "TPM_LIBTPMS_CALLBACKS",
++        "TPM_NV_DISK",
++    ],
++    deps = [
++        "@boringssl//:ssl",
++    ],
++    textual_hdrs = [
++        "src/tpm2/EccConstantData.inl",
++    ],
++    srcs = glob([
++        "include/config.h",
++        "include/libtpms/*.h",
++
++        "src/*.h",
++        "src/*.c",
++
++        "src/tpm2/*.h",
++        "src/tpm2/*.c",
++
++        "src/tpm2/crypto/*.h",
++        "src/tpm2/crypto/openssl/*.h",
++        "src/tpm2/crypto/openssl/*.c",
++
++        "src/monogon_unsafe.c",
++    ], [
++        # No TPM1.2 support.
++        "src/tpm_tpm12*",
++    ]),
++    visibility = [
++        "//visibility:public",
++    ],
++)
+diff --git a/WORKSPACE b/WORKSPACE
+new file mode 100644
+index 0000000..e69de29
+diff --git a/include/libtpms/config.h b/include/libtpms/config.h
+new file mode 100644
+index 0000000..bb4316e
+--- /dev/null
++++ b/include/libtpms/config.h
+@@ -0,0 +1,3 @@
++#pragma once
++
++#define WITH_TPM2 1
+diff --git a/src/tpm_library.c b/src/tpm_library.c
+index 20153b7..a3c5694 100644
+--- a/src/tpm_library.c
++++ b/src/tpm_library.c
+@@ -63,6 +63,7 @@
+ #include "tpm_debug.h"
+ #include "tpm_error.h"
+ #include "tpm_library.h"
++#include "tpm_library_conf.h"
+ #include "tpm_library_intern.h"
+ #include "tpm_nvfilename.h"
+ #include "tpm_tis.h"
+diff --git a/src/tpm_tpm2_interface.c b/src/tpm_tpm2_interface.c
+index 4570d78..7e51b5e 100644
+--- a/src/tpm_tpm2_interface.c
++++ b/src/tpm_tpm2_interface.c
+@@ -65,6 +65,7 @@
+ #include "tpm_nvfile.h" // TPM_NVRAM_Loaddata()
+ #include "tpm_error.h"
+ #include "tpm_library_intern.h"
++#include "tpm_library_conf.h"
+ #include "tpm_nvfilename.h"
+ 
+ extern BOOL      g_inFailureMode;
+-- 
+2.42.0
+
diff --git a/third_party/libtpms/patches/BUILD.bazel b/third_party/libtpms/patches/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/libtpms/patches/BUILD.bazel
diff --git a/third_party/swtpm/BUILD.bazel b/third_party/swtpm/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/swtpm/BUILD.bazel
diff --git a/third_party/swtpm/external.bzl b/third_party/swtpm/external.bzl
new file mode 100644
index 0000000..903bb33
--- /dev/null
+++ b/third_party/swtpm/external.bzl
@@ -0,0 +1,21 @@
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+def swtpm_external(name, version):
+    sums = {
+        # master at 2024/06/04
+        "0c9a6c4a12a63b86ab472e69e95bd75853d4fa96": "169ddb139597fa808e112d452457445c79ed521bb34f999066d20de9214056ce",
+    }
+
+    http_archive(
+        name = name,
+        patch_args = ["-p1"],
+        patches = [
+            "//third_party/swtpm/patches:0001-bazel-compat-glib.h-glib-glib.h.patch",
+            "//third_party/swtpm/patches:0002-swtpm_localca-replace-gmp-mpz-dependency-with-boring.patch",
+            "//third_party/swtpm/patches:0003-swtpm_setup-replace-dep-on-JSON-GLib-with-sheredom-j.patch",
+            "//third_party/swtpm/patches:0004-bazel-support-implement.patch",
+        ],
+        sha256 = sums[version],
+        strip_prefix = "swtpm-" + version,
+        urls = ["https://github.com/stefanberger/swtpm/archive/%s.tar.gz" % version],
+    )
diff --git a/third_party/swtpm/patches/0001-bazel-compat-glib.h-glib-glib.h.patch b/third_party/swtpm/patches/0001-bazel-compat-glib.h-glib-glib.h.patch
new file mode 100644
index 0000000..de98cd3
--- /dev/null
+++ b/third_party/swtpm/patches/0001-bazel-compat-glib.h-glib-glib.h.patch
@@ -0,0 +1,197 @@
+From c7932ca7f91b92002048e0e59470b0af6156aa8d Mon Sep 17 00:00:00 2001
+From: Serge Bazanski <serge@monogon.tech>
+Date: Tue, 4 Jun 2024 11:59:31 +0200
+Subject: [PATCH 1/4] bazel compat: <glib.h> -> "glib/glib.h"
+
+---
+ src/swtpm/cuse_tpm.c                    | 2 +-
+ src/swtpm/threadpool.c                  | 2 +-
+ src/swtpm_localca/swtpm_localca.c       | 2 +-
+ src/swtpm_localca/swtpm_localca.h       | 2 +-
+ src/swtpm_localca/swtpm_localca_utils.h | 2 +-
+ src/swtpm_setup/swtpm.c                 | 2 +-
+ src/swtpm_setup/swtpm.h                 | 2 +-
+ src/swtpm_setup/swtpm_setup.c           | 6 +++---
+ src/swtpm_setup/swtpm_setup.h           | 2 +-
+ src/swtpm_setup/swtpm_setup_utils.c     | 2 +-
+ src/swtpm_setup/swtpm_setup_utils.h     | 2 +-
+ src/utils/swtpm_utils.c                 | 2 +-
+ src/utils/swtpm_utils.h                 | 2 +-
+ 13 files changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/src/swtpm/cuse_tpm.c b/src/swtpm/cuse_tpm.c
+index 5977b63..4bcc503 100644
+--- a/src/swtpm/cuse_tpm.c
++++ b/src/swtpm/cuse_tpm.c
+@@ -56,7 +56,7 @@
+ 
+ #include <fuse/cuse_lowlevel.h>
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ #include <libtpms/tpm_library.h>
+ #include <libtpms/tpm_tis.h>
+diff --git a/src/swtpm/threadpool.c b/src/swtpm/threadpool.c
+index 770c16a..95d0085 100644
+--- a/src/swtpm/threadpool.c
++++ b/src/swtpm/threadpool.c
+@@ -37,7 +37,7 @@
+ 
+ #include <stdbool.h>
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ #include "threadpool.h"
+ 
+diff --git a/src/swtpm_localca/swtpm_localca.c b/src/swtpm_localca/swtpm_localca.c
+index 3a9fa6f..2842f22 100644
+--- a/src/swtpm_localca/swtpm_localca.c
++++ b/src/swtpm_localca/swtpm_localca.c
+@@ -22,7 +22,7 @@
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ #include <gmp.h>
+ 
+diff --git a/src/swtpm_localca/swtpm_localca.h b/src/swtpm_localca/swtpm_localca.h
+index c1cb19f..e203a4d 100644
+--- a/src/swtpm_localca/swtpm_localca.h
++++ b/src/swtpm_localca/swtpm_localca.h
+@@ -10,7 +10,7 @@
+ #ifndef SWTPM_LOCALCA_H
+ #define SWTPM_LOCALCA_H
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ extern gchar *gl_LOGFILE;
+ 
+diff --git a/src/swtpm_localca/swtpm_localca_utils.h b/src/swtpm_localca/swtpm_localca_utils.h
+index 2fd33b8..487738a 100644
+--- a/src/swtpm_localca/swtpm_localca_utils.h
++++ b/src/swtpm_localca/swtpm_localca_utils.h
+@@ -10,7 +10,7 @@
+ #ifndef SWTPM_LOCALCA_UTILS_H
+ #define SWTPM_LOCALCA_UTILS_H
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ gchar *get_config_value(gchar **config_file_lines, const gchar *varname, const gchar *fallback);
+ int get_config_envvars(gchar **config_file_lines, gchar  ***env);
+diff --git a/src/swtpm_setup/swtpm.c b/src/swtpm_setup/swtpm.c
+index 822215e..66eac0b 100644
+--- a/src/swtpm_setup/swtpm.c
++++ b/src/swtpm_setup/swtpm.c
+@@ -21,7 +21,7 @@
+ #include <sys/wait.h>
+ #include <unistd.h>
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ #include <openssl/bn.h>
+ #include <openssl/evp.h>
+diff --git a/src/swtpm_setup/swtpm.h b/src/swtpm_setup/swtpm.h
+index 2f81dce..1377d38 100644
+--- a/src/swtpm_setup/swtpm.h
++++ b/src/swtpm_setup/swtpm.h
+@@ -10,7 +10,7 @@
+ #ifndef SWTPM_SETUP_SWTPM_H
+ #define SWTPM_SETUP_SWTPM_H
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ #include <pwd.h>
+ 
+ #include <openssl/sha.h>
+diff --git a/src/swtpm_setup/swtpm_setup.c b/src/swtpm_setup/swtpm_setup.c
+index 8f87ad4..96e8b9f 100644
+--- a/src/swtpm_setup/swtpm_setup.c
++++ b/src/swtpm_setup/swtpm_setup.c
+@@ -23,9 +23,9 @@
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ 
+-#include <glib.h>
+-#include <glib/gstdio.h>
+-#include <glib/gprintf.h>
++#include "glib/glib.h"
++#include "glib/gstdio.h"
++#include "glib/gprintf.h"
+ 
+ #include <glib-object.h>
+ #include <json-glib/json-glib.h>
+diff --git a/src/swtpm_setup/swtpm_setup.h b/src/swtpm_setup/swtpm_setup.h
+index 913b36f..b87e501 100644
+--- a/src/swtpm_setup/swtpm_setup.h
++++ b/src/swtpm_setup/swtpm_setup.h
+@@ -10,7 +10,7 @@
+ #ifndef SWTPM_SETUP_H
+ #define SWTPM_SETUP_H
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ extern gchar *gl_LOGFILE;
+ 
+diff --git a/src/swtpm_setup/swtpm_setup_utils.c b/src/swtpm_setup/swtpm_setup_utils.c
+index 923e175..eddae73 100644
+--- a/src/swtpm_setup/swtpm_setup_utils.c
++++ b/src/swtpm_setup/swtpm_setup_utils.c
+@@ -17,7 +17,7 @@
+ #include <sys/utsname.h>
+ #include <unistd.h>
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ #include "swtpm_conf.h"
+ #include "swtpm_utils.h"
+diff --git a/src/swtpm_setup/swtpm_setup_utils.h b/src/swtpm_setup/swtpm_setup_utils.h
+index d074d3a..6c4be5e 100644
+--- a/src/swtpm_setup/swtpm_setup_utils.h
++++ b/src/swtpm_setup/swtpm_setup_utils.h
+@@ -10,7 +10,7 @@
+ #ifndef SWTPM_SETUP_UTILS_H
+ #define SWTPM_SETUP_UTILS_H
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ gchar *get_config_value(gchar **config_file_lines, const gchar *configname);
+ int create_config_files(gboolean overwrite, gboolean root_flag,
+diff --git a/src/utils/swtpm_utils.c b/src/utils/swtpm_utils.c
+index 35a4243..db32615 100644
+--- a/src/utils/swtpm_utils.c
++++ b/src/utils/swtpm_utils.c
+@@ -20,7 +20,7 @@
+ #include <string.h>
+ #include <unistd.h>
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ #include "swtpm_utils.h"
+ 
+diff --git a/src/utils/swtpm_utils.h b/src/utils/swtpm_utils.h
+index 22f1f4b..78ef97b 100644
+--- a/src/utils/swtpm_utils.h
++++ b/src/utils/swtpm_utils.h
+@@ -12,7 +12,7 @@
+ 
+ #include <pwd.h>
+ 
+-#include <glib.h>
++#include "glib/glib.h"
+ 
+ #define min(X,Y) ((X) < (Y) ? (X) : (Y))
+ #define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))
+-- 
+2.42.0
+
diff --git a/third_party/swtpm/patches/0002-swtpm_localca-replace-gmp-mpz-dependency-with-boring.patch b/third_party/swtpm/patches/0002-swtpm_localca-replace-gmp-mpz-dependency-with-boring.patch
new file mode 100644
index 0000000..21a2552
--- /dev/null
+++ b/third_party/swtpm/patches/0002-swtpm_localca-replace-gmp-mpz-dependency-with-boring.patch
@@ -0,0 +1,80 @@
+From 9410d7d0e3093380bb9d5cff3241107ff55435dd Mon Sep 17 00:00:00 2001
+From: Serge Bazanski <serge@monogon.tech>
+Date: Tue, 4 Jun 2024 12:06:17 +0200
+Subject: [PATCH 2/4] swtpm_localca: replace gmp/mpz dependency with boringssl
+ bignum
+
+---
+ src/swtpm_localca/swtpm_localca.c | 26 +++++++++++++-------------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+diff --git a/src/swtpm_localca/swtpm_localca.c b/src/swtpm_localca/swtpm_localca.c
+index 2842f22..d42d3a2 100644
+--- a/src/swtpm_localca/swtpm_localca.c
++++ b/src/swtpm_localca/swtpm_localca.c
+@@ -24,7 +24,8 @@
+ 
+ #include "glib/glib.h"
+ 
+-#include <gmp.h>
++#include <openssl/bn.h>
++#include <openssl/crypto.h>
+ 
+ #include "swtpm_conf.h"
+ #include "swtpm_utils.h"
+@@ -313,7 +314,8 @@ static int get_next_serial(const gchar *certserial, const gchar *lockfile,
+     g_autofree gchar *buffer = NULL;
+     char serialbuffer[50];
+     size_t buffer_len;
+-    mpz_t serial;
++    BIGNUM *serial = BN_new();
++    char *serial_dec = NULL;
+     int lockfd;
+     int ret = 1;
+ 
+@@ -328,22 +330,18 @@ static int get_next_serial(const gchar *certserial, const gchar *lockfile,
+     if (read_file(certserial, &buffer, &buffer_len) != 0)
+         goto error;
+ 
+-    mpz_init(serial);
+-
+     if (buffer_len > 0 && buffer_len <= 49) {
+         memcpy(serialbuffer, buffer, buffer_len);
+         serialbuffer[buffer_len] = 0;
+ 
+-        if (gmp_sscanf(serialbuffer, "%Zu", serial) != 1)
+-            goto new_serial;
+-        mpz_add_ui(serial, serial, 1);
+-
+-        if ((mpz_sizeinbase(serial, 2) + 7) / 8 > 20)
++        if (BN_dec2bn(&serial, serialbuffer) == 0)
+             goto new_serial;
++        BN_add_word(serial, 1);
+ 
+-        if (gmp_snprintf(serialbuffer,
++        serial_dec = BN_bn2dec(serial);
++        if (snprintf(serialbuffer,
+                          sizeof(serialbuffer),
+-                         "%Zu", serial) >= (int)sizeof(serialbuffer))
++                         "%s", serial_dec) >= (int)sizeof(serialbuffer))
+             goto new_serial;
+     } else {
+ new_serial:
+@@ -356,10 +354,12 @@ new_serial:
+     write_file(certserial, (unsigned char *)*serial_str, strlen(*serial_str));
+     ret = 0;
+ 
+-    mpz_clear(serial);
+-
+ error:
+     unlock_file(lockfd);
++    if (serial_dec) {
++        OPENSSL_free(serial_dec);
++    }
++    BN_free(serial);
+ 
+     return ret;
+ }
+-- 
+2.42.0
+
diff --git a/third_party/swtpm/patches/0003-swtpm_setup-replace-dep-on-JSON-GLib-with-sheredom-j.patch b/third_party/swtpm/patches/0003-swtpm_setup-replace-dep-on-JSON-GLib-with-sheredom-j.patch
new file mode 100644
index 0000000..5d13017
--- /dev/null
+++ b/third_party/swtpm/patches/0003-swtpm_setup-replace-dep-on-JSON-GLib-with-sheredom-j.patch
@@ -0,0 +1,3681 @@
+From be2cc81e58d33e09aef534d517c5dda0d7f12272 Mon Sep 17 00:00:00 2001
+From: Serge Bazanski <serge@monogon.tech>
+Date: Tue, 4 Jun 2024 12:49:01 +0200
+Subject: [PATCH 3/4] swtpm_setup: replace dep on JSON-GLib with
+ sheredom/json.h
+
+Turns out swtpm_setup requests capability info from `swtpm` by shelling
+out to it then parsing JSON output.
+
+Pulling in JSON-Glib as a library sounds like pain. Let's just use a
+simple single-file JSON parser library.
+
+There will be no comment on using JSON for this from me.
+---
+ include/json.h                | 3462 +++++++++++++++++++++++++++++++++
+ src/swtpm_setup/swtpm_setup.c |  150 +-
+ 2 files changed, 3554 insertions(+), 58 deletions(-)
+ create mode 100644 include/json.h
+
+diff --git a/include/json.h b/include/json.h
+new file mode 100644
+index 0000000..7116d85
+--- /dev/null
++++ b/include/json.h
+@@ -0,0 +1,3462 @@
++/*
++   The latest version of this library is available on GitHub;
++   https://github.com/sheredom/json.h.
++*/
++
++/*
++   This is free and unencumbered software released into the public domain.
++
++   Anyone is free to copy, modify, publish, use, compile, sell, or
++   distribute this software, either in source code form or as a compiled
++   binary, for any purpose, commercial or non-commercial, and by any
++   means.
++
++   In jurisdictions that recognize copyright laws, the author or authors
++   of this software dedicate any and all copyright interest in the
++   software to the public domain. We make this dedication for the benefit
++   of the public at large and to the detriment of our heirs and
++   successors. We intend this dedication to be an overt act of
++   relinquishment in perpetuity of all present and future rights to this
++   software under copyright law.
++
++   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 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.
++
++   For more information, please refer to <http://unlicense.org/>.
++*/
++
++#ifndef SHEREDOM_JSON_H_INCLUDED
++#define SHEREDOM_JSON_H_INCLUDED
++
++#if defined(_MSC_VER)
++#pragma warning(push)
++
++/* disable warning: no function prototype given: converting '()' to '(void)' */
++#pragma warning(disable : 4255)
++
++/* disable warning: '__cplusplus' is not defined as a preprocessor macro,
++ * replacing with '0' for '#if/#elif' */
++#pragma warning(disable : 4668)
++
++/* disable warning: 'bytes padding added after construct' */
++#pragma warning(disable : 4820)
++#endif
++
++#include <stddef.h>
++#include <string.h>
++
++#if defined(__TINYC__)
++#define JSON_ATTRIBUTE(a) __attribute((a))
++#else
++#define JSON_ATTRIBUTE(a) __attribute__((a))
++#endif
++
++#if defined(_MSC_VER) || defined(__WATCOMC__)
++#define json_weak __inline
++#elif defined(__clang__) || defined(__GNUC__) || defined(__TINYC__)
++#define json_weak JSON_ATTRIBUTE(weak)
++#else
++#error Non clang, non gcc, non MSVC, non tcc, non WATCOM compiler found!
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++struct json_value_s;
++struct json_parse_result_s;
++
++enum json_parse_flags_e {
++  json_parse_flags_default = 0,
++
++  /* allow trailing commas in objects and arrays. For example, both [true,] and
++     {"a" : null,} would be allowed with this option on. */
++  json_parse_flags_allow_trailing_comma = 0x1,
++
++  /* allow unquoted keys for objects. For example, {a : null} would be allowed
++     with this option on. */
++  json_parse_flags_allow_unquoted_keys = 0x2,
++
++  /* allow a global unbracketed object. For example, a : null, b : true, c : {}
++     would be allowed with this option on. */
++  json_parse_flags_allow_global_object = 0x4,
++
++  /* allow objects to use '=' instead of ':' between key/value pairs. For
++     example, a = null, b : true would be allowed with this option on. */
++  json_parse_flags_allow_equals_in_object = 0x8,
++
++  /* allow that objects don't have to have comma separators between key/value
++     pairs. */
++  json_parse_flags_allow_no_commas = 0x10,
++
++  /* allow c-style comments (either variants) to be ignored in the input JSON
++     file. */
++  json_parse_flags_allow_c_style_comments = 0x20,
++
++  /* deprecated flag, unused. */
++  json_parse_flags_deprecated = 0x40,
++
++  /* record location information for each value. */
++  json_parse_flags_allow_location_information = 0x80,
++
++  /* allow strings to be 'single quoted'. */
++  json_parse_flags_allow_single_quoted_strings = 0x100,
++
++  /* allow numbers to be hexadecimal. */
++  json_parse_flags_allow_hexadecimal_numbers = 0x200,
++
++  /* allow numbers like +123 to be parsed. */
++  json_parse_flags_allow_leading_plus_sign = 0x400,
++
++  /* allow numbers like .0123 or 123. to be parsed. */
++  json_parse_flags_allow_leading_or_trailing_decimal_point = 0x800,
++
++  /* allow Infinity, -Infinity, NaN, -NaN. */
++  json_parse_flags_allow_inf_and_nan = 0x1000,
++
++  /* allow multi line string values. */
++  json_parse_flags_allow_multi_line_strings = 0x2000,
++
++  /* allow simplified JSON to be parsed. Simplified JSON is an enabling of a set
++     of other parsing options. */
++  json_parse_flags_allow_simplified_json =
++      (json_parse_flags_allow_trailing_comma |
++       json_parse_flags_allow_unquoted_keys |
++       json_parse_flags_allow_global_object |
++       json_parse_flags_allow_equals_in_object |
++       json_parse_flags_allow_no_commas),
++
++  /* allow JSON5 to be parsed. JSON5 is an enabling of a set of other parsing
++     options. */
++  json_parse_flags_allow_json5 =
++      (json_parse_flags_allow_trailing_comma |
++       json_parse_flags_allow_unquoted_keys |
++       json_parse_flags_allow_c_style_comments |
++       json_parse_flags_allow_single_quoted_strings |
++       json_parse_flags_allow_hexadecimal_numbers |
++       json_parse_flags_allow_leading_plus_sign |
++       json_parse_flags_allow_leading_or_trailing_decimal_point |
++       json_parse_flags_allow_inf_and_nan |
++       json_parse_flags_allow_multi_line_strings)
++};
++
++/* Parse a JSON text file, returning a pointer to the root of the JSON
++ * structure. json_parse performs 1 call to malloc for the entire encoding.
++ * Returns 0 if an error occurred (malformed JSON input, or malloc failed). */
++json_weak struct json_value_s *json_parse(const void *src, size_t src_size);
++
++/* Parse a JSON text file, returning a pointer to the root of the JSON
++ * structure. json_parse performs 1 call to alloc_func_ptr for the entire
++ * encoding. Returns 0 if an error occurred (malformed JSON input, or malloc
++ * failed). If an error occurred, the result struct (if not NULL) will explain
++ * the type of error, and the location in the input it occurred. If
++ * alloc_func_ptr is null then malloc is used. */
++json_weak struct json_value_s *
++json_parse_ex(const void *src, size_t src_size, size_t flags_bitset,
++              void *(*alloc_func_ptr)(void *, size_t), void *user_data,
++              struct json_parse_result_s *result);
++
++/* Extracts a value and all the data that makes it up into a newly created
++ * value. json_extract_value performs 1 call to malloc for the entire encoding.
++ */
++json_weak struct json_value_s *
++json_extract_value(const struct json_value_s *value);
++
++/* Extracts a value and all the data that makes it up into a newly created
++ * value. json_extract_value performs 1 call to alloc_func_ptr for the entire
++ * encoding. If alloc_func_ptr is null then malloc is used. */
++json_weak struct json_value_s *
++json_extract_value_ex(const struct json_value_s *value,
++                      void *(*alloc_func_ptr)(void *, size_t), void *user_data);
++
++/* Write out a minified JSON utf-8 string. This string is an encoding of the
++ * minimal string characters required to still encode the same data.
++ * json_write_minified performs 1 call to malloc for the entire encoding. Return
++ * 0 if an error occurred (malformed JSON input, or malloc failed). The out_size
++ * parameter is optional as the utf-8 string is null terminated. */
++json_weak void *json_write_minified(const struct json_value_s *value,
++                                    size_t *out_size);
++
++/* Write out a pretty JSON utf-8 string. This string is encoded such that the
++ * resultant JSON is pretty in that it is easily human readable. The indent and
++ * newline parameters allow a user to specify what kind of indentation and
++ * newline they want (two spaces / three spaces / tabs? \r, \n, \r\n ?). Both
++ * indent and newline can be NULL, indent defaults to two spaces ("  "), and
++ * newline defaults to linux newlines ('\n' as the newline character).
++ * json_write_pretty performs 1 call to malloc for the entire encoding. Return 0
++ * if an error occurred (malformed JSON input, or malloc failed). The out_size
++ * parameter is optional as the utf-8 string is null terminated. */
++json_weak void *json_write_pretty(const struct json_value_s *value,
++                                  const char *indent, const char *newline,
++                                  size_t *out_size);
++
++/* Reinterpret a JSON value as a string. Returns null is the value was not a
++ * string. */
++json_weak struct json_string_s *
++json_value_as_string(struct json_value_s *const value);
++
++/* Reinterpret a JSON value as a number. Returns null is the value was not a
++ * number. */
++json_weak struct json_number_s *
++json_value_as_number(struct json_value_s *const value);
++
++/* Reinterpret a JSON value as an object. Returns null is the value was not an
++ * object. */
++json_weak struct json_object_s *
++json_value_as_object(struct json_value_s *const value);
++
++/* Reinterpret a JSON value as an array. Returns null is the value was not an
++ * array. */
++json_weak struct json_array_s *
++json_value_as_array(struct json_value_s *const value);
++
++/* Whether the value is true. */
++json_weak int json_value_is_true(const struct json_value_s *const value);
++
++/* Whether the value is false. */
++json_weak int json_value_is_false(const struct json_value_s *const value);
++
++/* Whether the value is null. */
++json_weak int json_value_is_null(const struct json_value_s *const value);
++
++/* The various types JSON values can be. Used to identify what a value is. */
++typedef enum json_type_e {
++  json_type_string,
++  json_type_number,
++  json_type_object,
++  json_type_array,
++  json_type_true,
++  json_type_false,
++  json_type_null
++
++} json_type_t;
++
++/* A JSON string value. */
++typedef struct json_string_s {
++  /* utf-8 string */
++  const char *string;
++  /* The size (in bytes) of the string */
++  size_t string_size;
++
++} json_string_t;
++
++/* A JSON string value (extended). */
++typedef struct json_string_ex_s {
++  /* The JSON string this extends. */
++  struct json_string_s string;
++
++  /* The character offset for the value in the JSON input. */
++  size_t offset;
++
++  /* The line number for the value in the JSON input. */
++  size_t line_no;
++
++  /* The row number for the value in the JSON input, in bytes. */
++  size_t row_no;
++
++} json_string_ex_t;
++
++/* A JSON number value. */
++typedef struct json_number_s {
++  /* ASCII string containing representation of the number. */
++  const char *number;
++  /* the size (in bytes) of the number. */
++  size_t number_size;
++
++} json_number_t;
++
++/* an element of a JSON object. */
++typedef struct json_object_element_s {
++  /* the name of this element. */
++  struct json_string_s *name;
++  /* the value of this element. */
++  struct json_value_s *value;
++  /* the next object element (can be NULL if the last element in the object). */
++  struct json_object_element_s *next;
++
++} json_object_element_t;
++
++/* a JSON object value. */
++typedef struct json_object_s {
++  /* a linked list of the elements in the object. */
++  struct json_object_element_s *start;
++  /* the number of elements in the object. */
++  size_t length;
++
++} json_object_t;
++
++/* an element of a JSON array. */
++typedef struct json_array_element_s {
++  /* the value of this element. */
++  struct json_value_s *value;
++  /* the next array element (can be NULL if the last element in the array). */
++  struct json_array_element_s *next;
++
++} json_array_element_t;
++
++/* a JSON array value. */
++typedef struct json_array_s {
++  /* a linked list of the elements in the array. */
++  struct json_array_element_s *start;
++  /* the number of elements in the array. */
++  size_t length;
++
++} json_array_t;
++
++/* a JSON value. */
++typedef struct json_value_s {
++  /* a pointer to either a json_string_s, json_number_s, json_object_s, or. */
++  /* json_array_s. Should be cast to the appropriate struct type based on what.
++   */
++  /* the type of this value is. */
++  void *payload;
++  /* must be one of json_type_e. If type is json_type_true, json_type_false, or.
++   */
++  /* json_type_null, payload will be NULL. */
++  size_t type;
++
++} json_value_t;
++
++/* a JSON value (extended). */
++typedef struct json_value_ex_s {
++  /* the JSON value this extends. */
++  struct json_value_s value;
++
++  /* the character offset for the value in the JSON input. */
++  size_t offset;
++
++  /* the line number for the value in the JSON input. */
++  size_t line_no;
++
++  /* the row number for the value in the JSON input, in bytes. */
++  size_t row_no;
++
++} json_value_ex_t;
++
++/* a parsing error code. */
++enum json_parse_error_e {
++  /* no error occurred (huzzah!). */
++  json_parse_error_none = 0,
++
++  /* expected either a comma or a closing '}' or ']' to close an object or. */
++  /* array! */
++  json_parse_error_expected_comma_or_closing_bracket,
++
++  /* colon separating name/value pair was missing! */
++  json_parse_error_expected_colon,
++
++  /* expected string to begin with '"'! */
++  json_parse_error_expected_opening_quote,
++
++  /* invalid escaped sequence in string! */
++  json_parse_error_invalid_string_escape_sequence,
++
++  /* invalid number format! */
++  json_parse_error_invalid_number_format,
++
++  /* invalid value! */
++  json_parse_error_invalid_value,
++
++  /* reached end of buffer before object/array was complete! */
++  json_parse_error_premature_end_of_buffer,
++
++  /* string was malformed! */
++  json_parse_error_invalid_string,
++
++  /* a call to malloc, or a user provider allocator, failed. */
++  json_parse_error_allocator_failed,
++
++  /* the JSON input had unexpected trailing characters that weren't part of the.
++     JSON value. */
++  json_parse_error_unexpected_trailing_characters,
++
++  /* catch-all error for everything else that exploded (real bad chi!). */
++  json_parse_error_unknown
++};
++
++/* error report from json_parse_ex(). */
++typedef struct json_parse_result_s {
++  /* the error code (one of json_parse_error_e). */
++  size_t error;
++
++  /* the character offset for the error in the JSON input. */
++  size_t error_offset;
++
++  /* the line number for the error in the JSON input. */
++  size_t error_line_no;
++
++  /* the row number for the error, in bytes. */
++  size_t error_row_no;
++
++} json_parse_result_t;
++
++#ifdef __cplusplus
++} /* extern "C". */
++#endif
++
++#include <stdlib.h>
++
++#if defined(_MSC_VER)
++#pragma warning(pop)
++#endif
++
++#if defined(_MSC_VER) && (_MSC_VER < 1920)
++#define json_uintmax_t unsigned __int64
++#else
++#include <inttypes.h>
++#define json_uintmax_t uintmax_t
++#endif
++
++#if defined(_MSC_VER)
++#define json_strtoumax _strtoui64
++#else
++#define json_strtoumax strtoumax
++#endif
++
++#if defined(__cplusplus) && (__cplusplus >= 201103L)
++#define json_null nullptr
++#else
++#define json_null 0
++#endif
++
++#if defined(__clang__)
++#pragma clang diagnostic push
++
++/* we do one big allocation via malloc, then cast aligned slices of this for. */
++/* our structures - we don't have a way to tell the compiler we know what we. */
++/* are doing, so disable the warning instead! */
++#pragma clang diagnostic ignored "-Wcast-align"
++
++/* We use C style casts everywhere. */
++#pragma clang diagnostic ignored "-Wold-style-cast"
++
++/* We need long long for strtoull. */
++#pragma clang diagnostic ignored "-Wc++11-long-long"
++
++/* Who cares if nullptr doesn't work with C++98, we don't use it there! */
++#pragma clang diagnostic ignored "-Wc++98-compat"
++#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
++
++#if __has_warning("-Wunsafe-buffer-usage")
++#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
++#endif
++
++#elif defined(_MSC_VER)
++#pragma warning(push)
++
++/* disable 'function selected for inline expansion' warning. */
++#pragma warning(disable : 4711)
++
++/* disable '#pragma warning: there is no warning number' warning. */
++#pragma warning(disable : 4619)
++
++/* disable 'warning number not a valid compiler warning' warning. */
++#pragma warning(disable : 4616)
++
++/* disable 'Compiler will insert Spectre mitigation for memory load if
++ * /Qspectre. */
++/* switch specified' warning. */
++#pragma warning(disable : 5045)
++#endif
++
++struct json_parse_state_s {
++  const char *src;
++  size_t size;
++  size_t offset;
++  size_t flags_bitset;
++  char *data;
++  char *dom;
++  size_t dom_size;
++  size_t data_size;
++  size_t line_no;     /* line counter for error reporting. */
++  size_t line_offset; /* (offset-line_offset) is the character number (in
++                         bytes). */
++  size_t error;
++};
++
++json_weak int json_hexadecimal_digit(const char c);
++int json_hexadecimal_digit(const char c) {
++  if ('0' <= c && c <= '9') {
++    return c - '0';
++  }
++  if ('a' <= c && c <= 'f') {
++    return c - 'a' + 10;
++  }
++  if ('A' <= c && c <= 'F') {
++    return c - 'A' + 10;
++  }
++  return -1;
++}
++
++json_weak int json_hexadecimal_value(const char *c, const unsigned long size,
++                                     unsigned long *result);
++int json_hexadecimal_value(const char *c, const unsigned long size,
++                           unsigned long *result) {
++  const char *p;
++  int digit;
++
++  if (size > sizeof(unsigned long) * 2) {
++    return 0;
++  }
++
++  *result = 0;
++  for (p = c; (unsigned long)(p - c) < size; ++p) {
++    *result <<= 4;
++    digit = json_hexadecimal_digit(*p);
++    if (digit < 0 || digit > 15) {
++      return 0;
++    }
++    *result |= (unsigned char)digit;
++  }
++  return 1;
++}
++
++json_weak int json_skip_whitespace(struct json_parse_state_s *state);
++int json_skip_whitespace(struct json_parse_state_s *state) {
++  size_t offset = state->offset;
++  const size_t size = state->size;
++  const char *const src = state->src;
++
++  if (offset >= state->size) {
++    return 0;
++  }
++
++  /* the only valid whitespace according to ECMA-404 is ' ', '\n', '\r' and
++   * '\t'. */
++  switch (src[offset]) {
++  default:
++    return 0;
++  case ' ':
++  case '\r':
++  case '\t':
++  case '\n':
++    break;
++  }
++
++  do {
++    switch (src[offset]) {
++    default:
++      /* Update offset. */
++      state->offset = offset;
++      return 1;
++    case ' ':
++    case '\r':
++    case '\t':
++      break;
++    case '\n':
++      state->line_no++;
++      state->line_offset = offset;
++      break;
++    }
++
++    offset++;
++  } while (offset < size);
++
++  /* Update offset. */
++  state->offset = offset;
++  return 1;
++}
++
++json_weak int json_skip_c_style_comments(struct json_parse_state_s *state);
++int json_skip_c_style_comments(struct json_parse_state_s *state) {
++  /* to have a C-style comment we need at least 2 characters of space */
++  if ((state->offset + 2) > state->size) {
++    return 0;
++  }
++
++  /* do we have a comment? */
++  if ('/' == state->src[state->offset]) {
++    if ('/' == state->src[state->offset + 1]) {
++      /* we had a comment of the form // */
++
++      /* skip first '/' */
++      state->offset++;
++
++      /* skip second '/' */
++      state->offset++;
++
++      while (state->offset < state->size) {
++        switch (state->src[state->offset]) {
++        default:
++          /* skip the character in the comment */
++          state->offset++;
++          break;
++        case '\n':
++          /* if we have a newline, our comment has ended! Skip the newline */
++          state->offset++;
++
++          /* we entered a newline, so move our line info forward */
++          state->line_no++;
++          state->line_offset = state->offset;
++          return 1;
++        }
++      }
++
++      /* we reached the end of the JSON file! */
++      return 1;
++    } else if ('*' == state->src[state->offset + 1]) {
++      /* we had a comment in the C-style long form */
++
++      /* skip '/' */
++      state->offset++;
++
++      /* skip '*' */
++      state->offset++;
++
++      while (state->offset + 1 < state->size) {
++        if (('*' == state->src[state->offset]) &&
++            ('/' == state->src[state->offset + 1])) {
++          /* we reached the end of our comment! */
++          state->offset += 2;
++          return 1;
++        } else if ('\n' == state->src[state->offset]) {
++          /* we entered a newline, so move our line info forward */
++          state->line_no++;
++          state->line_offset = state->offset;
++        }
++
++        /* skip character within comment */
++        state->offset++;
++      }
++
++      /* comment wasn't ended correctly which is a failure */
++      return 1;
++    }
++  }
++
++  /* we didn't have any comment, which is ok too! */
++  return 0;
++}
++
++json_weak int json_skip_all_skippables(struct json_parse_state_s *state);
++int json_skip_all_skippables(struct json_parse_state_s *state) {
++  /* skip all whitespace and other skippables until there are none left. note
++   * that the previous version suffered from read past errors should. the
++   * stream end on json_skip_c_style_comments eg. '{"a" ' with comments flag.
++   */
++
++  int did_consume = 0;
++  const size_t size = state->size;
++
++  if (json_parse_flags_allow_c_style_comments & state->flags_bitset) {
++    do {
++      if (state->offset == size) {
++        state->error = json_parse_error_premature_end_of_buffer;
++        return 1;
++      }
++
++      did_consume = json_skip_whitespace(state);
++
++      /* This should really be checked on access, not in front of every call.
++       */
++      if (state->offset >= size) {
++        state->error = json_parse_error_premature_end_of_buffer;
++        return 1;
++      }
++
++      did_consume |= json_skip_c_style_comments(state);
++    } while (0 != did_consume);
++  } else {
++    do {
++      if (state->offset == size) {
++        state->error = json_parse_error_premature_end_of_buffer;
++        return 1;
++      }
++
++      did_consume = json_skip_whitespace(state);
++    } while (0 != did_consume);
++  }
++
++  if (state->offset == size) {
++    state->error = json_parse_error_premature_end_of_buffer;
++    return 1;
++  }
++
++  return 0;
++}
++
++json_weak int json_get_value_size(struct json_parse_state_s *state,
++                                  int is_global_object);
++
++json_weak int json_get_string_size(struct json_parse_state_s *state,
++                                   size_t is_key);
++int json_get_string_size(struct json_parse_state_s *state, size_t is_key) {
++  size_t offset = state->offset;
++  const size_t size = state->size;
++  size_t data_size = 0;
++  const char *const src = state->src;
++  const int is_single_quote = '\'' == src[offset];
++  const char quote_to_use = is_single_quote ? '\'' : '"';
++  const size_t flags_bitset = state->flags_bitset;
++  unsigned long codepoint;
++  unsigned long high_surrogate = 0;
++
++  if ((json_parse_flags_allow_location_information & flags_bitset) != 0 &&
++      is_key != 0) {
++    state->dom_size += sizeof(struct json_string_ex_s);
++  } else {
++    state->dom_size += sizeof(struct json_string_s);
++  }
++
++  if ('"' != src[offset]) {
++    /* if we are allowed single quoted strings check for that too. */
++    if (!((json_parse_flags_allow_single_quoted_strings & flags_bitset) &&
++          is_single_quote)) {
++      state->error = json_parse_error_expected_opening_quote;
++      state->offset = offset;
++      return 1;
++    }
++  }
++
++  /* skip leading '"' or '\''. */
++  offset++;
++
++  while ((offset < size) && (quote_to_use != src[offset])) {
++    /* add space for the character. */
++    data_size++;
++
++    switch (src[offset]) {
++    default:
++      break;
++    case '\0':
++    case '\t':
++      state->error = json_parse_error_invalid_string;
++      state->offset = offset;
++      return 1;
++    }
++
++    if ('\\' == src[offset]) {
++      /* skip reverse solidus character. */
++      offset++;
++
++      if (offset == size) {
++        state->error = json_parse_error_premature_end_of_buffer;
++        state->offset = offset;
++        return 1;
++      }
++
++      switch (src[offset]) {
++      default:
++        state->error = json_parse_error_invalid_string_escape_sequence;
++        state->offset = offset;
++        return 1;
++      case '"':
++      case '\\':
++      case '/':
++      case 'b':
++      case 'f':
++      case 'n':
++      case 'r':
++      case 't':
++        /* all valid characters! */
++        offset++;
++        break;
++      case 'u':
++        if (!(offset + 5 < size)) {
++          /* invalid escaped unicode sequence! */
++          state->error = json_parse_error_invalid_string_escape_sequence;
++          state->offset = offset;
++          return 1;
++        }
++
++        codepoint = 0;
++        if (!json_hexadecimal_value(&src[offset + 1], 4, &codepoint)) {
++          /* escaped unicode sequences must contain 4 hexadecimal digits! */
++          state->error = json_parse_error_invalid_string_escape_sequence;
++          state->offset = offset;
++          return 1;
++        }
++
++        /* Valid sequence!
++         * see: https://en.wikipedia.org/wiki/UTF-8#Invalid_code_points.
++         *      1       7       U + 0000        U + 007F        0xxxxxxx.
++         *      2       11      U + 0080        U + 07FF        110xxxxx
++         * 10xxxxxx.
++         *      3       16      U + 0800        U + FFFF        1110xxxx
++         * 10xxxxxx        10xxxxxx.
++         *      4       21      U + 10000       U + 10FFFF      11110xxx
++         * 10xxxxxx        10xxxxxx        10xxxxxx.
++         * Note: the high and low surrogate halves used by UTF-16 (U+D800
++         * through U+DFFF) and code points not encodable by UTF-16 (those after
++         * U+10FFFF) are not legal Unicode values, and their UTF-8 encoding must
++         * be treated as an invalid byte sequence. */
++
++        if (high_surrogate != 0) {
++          /* we previously read the high half of the \uxxxx\uxxxx pair, so now
++           * we expect the low half. */
++          if (codepoint >= 0xdc00 &&
++              codepoint <= 0xdfff) { /* low surrogate range. */
++            data_size += 3;
++            high_surrogate = 0;
++          } else {
++            state->error = json_parse_error_invalid_string_escape_sequence;
++            state->offset = offset;
++            return 1;
++          }
++        } else if (codepoint <= 0x7f) {
++          data_size += 0;
++        } else if (codepoint <= 0x7ff) {
++          data_size += 1;
++        } else if (codepoint >= 0xd800 &&
++                   codepoint <= 0xdbff) { /* high surrogate range. */
++          /* The codepoint is the first half of a "utf-16 surrogate pair". so we
++           * need the other half for it to be valid: \uHHHH\uLLLL. */
++          if (offset + 11 > size || '\\' != src[offset + 5] ||
++              'u' != src[offset + 6]) {
++            state->error = json_parse_error_invalid_string_escape_sequence;
++            state->offset = offset;
++            return 1;
++          }
++          high_surrogate = codepoint;
++        } else if (codepoint >= 0xd800 &&
++                   codepoint <= 0xdfff) { /* low surrogate range. */
++          /* we did not read the other half before. */
++          state->error = json_parse_error_invalid_string_escape_sequence;
++          state->offset = offset;
++          return 1;
++        } else {
++          data_size += 2;
++        }
++        /* escaped codepoints after 0xffff are supported in json through utf-16
++         * surrogate pairs: \uD83D\uDD25 for U+1F525. */
++
++        offset += 5;
++        break;
++      }
++    } else if (('\r' == src[offset]) || ('\n' == src[offset])) {
++      if (!(json_parse_flags_allow_multi_line_strings & flags_bitset)) {
++        /* invalid escaped unicode sequence! */
++        state->error = json_parse_error_invalid_string_escape_sequence;
++        state->offset = offset;
++        return 1;
++      }
++
++      offset++;
++    } else {
++      /* skip character (valid part of sequence). */
++      offset++;
++    }
++  }
++
++  /* If the offset is equal to the size, we had a non-terminated string! */
++  if (offset == size) {
++    state->error = json_parse_error_premature_end_of_buffer;
++    state->offset = offset - 1;
++    return 1;
++  }
++
++  /* skip trailing '"' or '\''. */
++  offset++;
++
++  /* add enough space to store the string. */
++  state->data_size += data_size;
++
++  /* one more byte for null terminator ending the string! */
++  state->data_size++;
++
++  /* update offset. */
++  state->offset = offset;
++
++  return 0;
++}
++
++json_weak int is_valid_unquoted_key_char(const char c);
++int is_valid_unquoted_key_char(const char c) {
++  return (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
++          ('A' <= c && c <= 'Z') || ('_' == c));
++}
++
++json_weak int json_get_key_size(struct json_parse_state_s *state);
++int json_get_key_size(struct json_parse_state_s *state) {
++  const size_t flags_bitset = state->flags_bitset;
++
++  if (json_parse_flags_allow_unquoted_keys & flags_bitset) {
++    size_t offset = state->offset;
++    const size_t size = state->size;
++    const char *const src = state->src;
++    size_t data_size = state->data_size;
++
++    /* if we are allowing unquoted keys, first grok for a quote... */
++    if ('"' == src[offset]) {
++      /* ... if we got a comma, just parse the key as a string as normal. */
++      return json_get_string_size(state, 1);
++    } else if ((json_parse_flags_allow_single_quoted_strings & flags_bitset) &&
++               ('\'' == src[offset])) {
++      /* ... if we got a comma, just parse the key as a string as normal. */
++      return json_get_string_size(state, 1);
++    } else {
++      while ((offset < size) && is_valid_unquoted_key_char(src[offset])) {
++        offset++;
++        data_size++;
++      }
++
++      /* one more byte for null terminator ending the string! */
++      data_size++;
++
++      if (json_parse_flags_allow_location_information & flags_bitset) {
++        state->dom_size += sizeof(struct json_string_ex_s);
++      } else {
++        state->dom_size += sizeof(struct json_string_s);
++      }
++
++      /* update offset. */
++      state->offset = offset;
++
++      /* update data_size. */
++      state->data_size = data_size;
++
++      return 0;
++    }
++  } else {
++    /* we are only allowed to have quoted keys, so just parse a string! */
++    return json_get_string_size(state, 1);
++  }
++}
++
++json_weak int json_get_object_size(struct json_parse_state_s *state,
++                                   int is_global_object);
++int json_get_object_size(struct json_parse_state_s *state,
++                         int is_global_object) {
++  const size_t flags_bitset = state->flags_bitset;
++  const char *const src = state->src;
++  const size_t size = state->size;
++  size_t elements = 0;
++  int allow_comma = 0;
++  int found_closing_brace = 0;
++
++  if (is_global_object) {
++    /* if we found an opening '{' of an object, we actually have a normal JSON
++     * object at the root of the DOM... */
++    if (!json_skip_all_skippables(state) && '{' == state->src[state->offset]) {
++      /* . and we don't actually have a global object after all! */
++      is_global_object = 0;
++    }
++  }
++
++  if (!is_global_object) {
++    if ('{' != src[state->offset]) {
++      state->error = json_parse_error_unknown;
++      return 1;
++    }
++
++    /* skip leading '{'. */
++    state->offset++;
++  }
++
++  state->dom_size += sizeof(struct json_object_s);
++
++  if ((state->offset == size) && !is_global_object) {
++    state->error = json_parse_error_premature_end_of_buffer;
++    return 1;
++  }
++
++  do {
++    if (!is_global_object) {
++      if (json_skip_all_skippables(state)) {
++        state->error = json_parse_error_premature_end_of_buffer;
++        return 1;
++      }
++
++      if ('}' == src[state->offset]) {
++        /* skip trailing '}'. */
++        state->offset++;
++
++        found_closing_brace = 1;
++
++        /* finished the object! */
++        break;
++      }
++    } else {
++      /* we don't require brackets, so that means the object ends when the input
++       * stream ends! */
++      if (json_skip_all_skippables(state)) {
++        break;
++      }
++    }
++
++    /* if we parsed at least one element previously, grok for a comma. */
++    if (allow_comma) {
++      if (',' == src[state->offset]) {
++        /* skip comma. */
++        state->offset++;
++        allow_comma = 0;
++      } else if (json_parse_flags_allow_no_commas & flags_bitset) {
++        /* we don't require a comma, and we didn't find one, which is ok! */
++        allow_comma = 0;
++      } else {
++        /* otherwise we are required to have a comma, and we found none. */
++        state->error = json_parse_error_expected_comma_or_closing_bracket;
++        return 1;
++      }
++
++      if (json_parse_flags_allow_trailing_comma & flags_bitset) {
++        continue;
++      } else {
++        if (json_skip_all_skippables(state)) {
++          state->error = json_parse_error_premature_end_of_buffer;
++          return 1;
++        }
++      }
++    }
++
++    if (json_get_key_size(state)) {
++      /* key parsing failed! */
++      state->error = json_parse_error_invalid_string;
++      return 1;
++    }
++
++    if (json_skip_all_skippables(state)) {
++      state->error = json_parse_error_premature_end_of_buffer;
++      return 1;
++    }
++
++    if (json_parse_flags_allow_equals_in_object & flags_bitset) {
++      const char current = src[state->offset];
++      if ((':' != current) && ('=' != current)) {
++        state->error = json_parse_error_expected_colon;
++        return 1;
++      }
++    } else {
++      if (':' != src[state->offset]) {
++        state->error = json_parse_error_expected_colon;
++        return 1;
++      }
++    }
++
++    /* skip colon. */
++    state->offset++;
++
++    if (json_skip_all_skippables(state)) {
++      state->error = json_parse_error_premature_end_of_buffer;
++      return 1;
++    }
++
++    if (json_get_value_size(state, /* is_global_object = */ 0)) {
++      /* value parsing failed! */
++      return 1;
++    }
++
++    /* successfully parsed a name/value pair! */
++    elements++;
++    allow_comma = 1;
++  } while (state->offset < size);
++
++  if ((state->offset == size) && !is_global_object && !found_closing_brace) {
++    state->error = json_parse_error_premature_end_of_buffer;
++    return 1;
++  }
++
++  state->dom_size += sizeof(struct json_object_element_s) * elements;
++
++  return 0;
++}
++
++json_weak int json_get_array_size(struct json_parse_state_s *state);
++int json_get_array_size(struct json_parse_state_s *state) {
++  const size_t flags_bitset = state->flags_bitset;
++  size_t elements = 0;
++  int allow_comma = 0;
++  const char *const src = state->src;
++  const size_t size = state->size;
++
++  if ('[' != src[state->offset]) {
++    /* expected array to begin with leading '['. */
++    state->error = json_parse_error_unknown;
++    return 1;
++  }
++
++  /* skip leading '['. */
++  state->offset++;
++
++  state->dom_size += sizeof(struct json_array_s);
++
++  while (state->offset < size) {
++    if (json_skip_all_skippables(state)) {
++      state->error = json_parse_error_premature_end_of_buffer;
++      return 1;
++    }
++
++    if (']' == src[state->offset]) {
++      /* skip trailing ']'. */
++      state->offset++;
++
++      state->dom_size += sizeof(struct json_array_element_s) * elements;
++
++      /* finished the object! */
++      return 0;
++    }
++
++    /* if we parsed at least once element previously, grok for a comma. */
++    if (allow_comma) {
++      if (',' == src[state->offset]) {
++        /* skip comma. */
++        state->offset++;
++        allow_comma = 0;
++      } else if (!(json_parse_flags_allow_no_commas & flags_bitset)) {
++        state->error = json_parse_error_expected_comma_or_closing_bracket;
++        return 1;
++      }
++
++      if (json_parse_flags_allow_trailing_comma & flags_bitset) {
++        allow_comma = 0;
++        continue;
++      } else {
++        if (json_skip_all_skippables(state)) {
++          state->error = json_parse_error_premature_end_of_buffer;
++          return 1;
++        }
++      }
++    }
++
++    if (json_get_value_size(state, /* is_global_object = */ 0)) {
++      /* value parsing failed! */
++      return 1;
++    }
++
++    /* successfully parsed an array element! */
++    elements++;
++    allow_comma = 1;
++  }
++
++  /* we consumed the entire input before finding the closing ']' of the array!
++   */
++  state->error = json_parse_error_premature_end_of_buffer;
++  return 1;
++}
++
++json_weak int json_get_number_size(struct json_parse_state_s *state);
++int json_get_number_size(struct json_parse_state_s *state) {
++  const size_t flags_bitset = state->flags_bitset;
++  size_t offset = state->offset;
++  const size_t size = state->size;
++  int had_leading_digits = 0;
++  const char *const src = state->src;
++
++  state->dom_size += sizeof(struct json_number_s);
++
++  if ((json_parse_flags_allow_hexadecimal_numbers & flags_bitset) &&
++      (offset + 1 < size) && ('0' == src[offset]) &&
++      (('x' == src[offset + 1]) || ('X' == src[offset + 1]))) {
++    /* skip the leading 0x that identifies a hexadecimal number. */
++    offset += 2;
++
++    /* consume hexadecimal digits. */
++    while ((offset < size) && (('0' <= src[offset] && src[offset] <= '9') ||
++                               ('a' <= src[offset] && src[offset] <= 'f') ||
++                               ('A' <= src[offset] && src[offset] <= 'F'))) {
++      offset++;
++    }
++  } else {
++    int found_sign = 0;
++    int inf_or_nan = 0;
++
++    if ((offset < size) &&
++        (('-' == src[offset]) ||
++         ((json_parse_flags_allow_leading_plus_sign & flags_bitset) &&
++          ('+' == src[offset])))) {
++      /* skip valid leading '-' or '+'. */
++      offset++;
++
++      found_sign = 1;
++    }
++
++    if (json_parse_flags_allow_inf_and_nan & flags_bitset) {
++      const char inf[9] = "Infinity";
++      const size_t inf_strlen = sizeof(inf) - 1;
++      const char nan[4] = "NaN";
++      const size_t nan_strlen = sizeof(nan) - 1;
++
++      if (offset + inf_strlen < size) {
++        int found = 1;
++        size_t i;
++        for (i = 0; i < inf_strlen; i++) {
++          if (inf[i] != src[offset + i]) {
++            found = 0;
++            break;
++          }
++        }
++
++        if (found) {
++          /* We found our special 'Infinity' keyword! */
++          offset += inf_strlen;
++
++          inf_or_nan = 1;
++        }
++      }
++
++      if (offset + nan_strlen < size) {
++        int found = 1;
++        size_t i;
++        for (i = 0; i < nan_strlen; i++) {
++          if (nan[i] != src[offset + i]) {
++            found = 0;
++            break;
++          }
++        }
++
++        if (found) {
++          /* We found our special 'NaN' keyword! */
++          offset += nan_strlen;
++
++          inf_or_nan = 1;
++        }
++      }
++
++      if (inf_or_nan) {
++        if (offset < size) {
++          switch (src[offset]) {
++          default:
++            break;
++          case '0':
++          case '1':
++          case '2':
++          case '3':
++          case '4':
++          case '5':
++          case '6':
++          case '7':
++          case '8':
++          case '9':
++          case 'e':
++          case 'E':
++            /* cannot follow an inf or nan with digits! */
++            state->error = json_parse_error_invalid_number_format;
++            state->offset = offset;
++            return 1;
++          }
++        }
++      }
++    }
++
++    if (found_sign && !inf_or_nan && (offset < size) &&
++        !('0' <= src[offset] && src[offset] <= '9')) {
++      /* check if we are allowing leading '.'. */
++      if (!(json_parse_flags_allow_leading_or_trailing_decimal_point &
++            flags_bitset) ||
++          ('.' != src[offset])) {
++        /* a leading '-' must be immediately followed by any digit! */
++        state->error = json_parse_error_invalid_number_format;
++        state->offset = offset;
++        return 1;
++      }
++    }
++
++    if ((offset < size) && ('0' == src[offset])) {
++      /* skip valid '0'. */
++      offset++;
++
++      /* we need to record whether we had any leading digits for checks later.
++       */
++      had_leading_digits = 1;
++
++      if ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) {
++        /* a leading '0' must not be immediately followed by any digit! */
++        state->error = json_parse_error_invalid_number_format;
++        state->offset = offset;
++        return 1;
++      }
++    }
++
++    /* the main digits of our number next. */
++    while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) {
++      offset++;
++
++      /* we need to record whether we had any leading digits for checks later.
++       */
++      had_leading_digits = 1;
++    }
++
++    if ((offset < size) && ('.' == src[offset])) {
++      offset++;
++
++      if ((offset >= size) || !('0' <= src[offset] && src[offset] <= '9')) {
++        if (!(json_parse_flags_allow_leading_or_trailing_decimal_point &
++              flags_bitset) ||
++            !had_leading_digits) {
++          /* a decimal point must be followed by at least one digit. */
++          state->error = json_parse_error_invalid_number_format;
++          state->offset = offset;
++          return 1;
++        }
++      }
++
++      /* a decimal point can be followed by more digits of course! */
++      while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) {
++        offset++;
++      }
++    }
++
++    if ((offset < size) && ('e' == src[offset] || 'E' == src[offset])) {
++      /* our number has an exponent! Skip 'e' or 'E'. */
++      offset++;
++
++      if ((offset < size) && ('-' == src[offset] || '+' == src[offset])) {
++        /* skip optional '-' or '+'. */
++        offset++;
++      }
++
++      if ((offset < size) && !('0' <= src[offset] && src[offset] <= '9')) {
++        /* an exponent must have at least one digit! */
++        state->error = json_parse_error_invalid_number_format;
++        state->offset = offset;
++        return 1;
++      }
++
++      /* consume exponent digits. */
++      do {
++        offset++;
++      } while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9'));
++    }
++  }
++
++  if (offset < size) {
++    switch (src[offset]) {
++    case ' ':
++    case '\t':
++    case '\r':
++    case '\n':
++    case '}':
++    case ',':
++    case ']':
++      /* all of the above are ok. */
++      break;
++    case '=':
++      if (json_parse_flags_allow_equals_in_object & flags_bitset) {
++        break;
++      }
++
++      state->error = json_parse_error_invalid_number_format;
++      state->offset = offset;
++      return 1;
++    default:
++      state->error = json_parse_error_invalid_number_format;
++      state->offset = offset;
++      return 1;
++    }
++  }
++
++  state->data_size += offset - state->offset;
++
++  /* one more byte for null terminator ending the number string! */
++  state->data_size++;
++
++  /* update offset. */
++  state->offset = offset;
++
++  return 0;
++}
++
++json_weak int json_get_value_size(struct json_parse_state_s *state,
++                                  int is_global_object);
++int json_get_value_size(struct json_parse_state_s *state,
++                        int is_global_object) {
++  const size_t flags_bitset = state->flags_bitset;
++  const char *const src = state->src;
++  size_t offset;
++  const size_t size = state->size;
++
++  if (json_parse_flags_allow_location_information & flags_bitset) {
++    state->dom_size += sizeof(struct json_value_ex_s);
++  } else {
++    state->dom_size += sizeof(struct json_value_s);
++  }
++
++  if (is_global_object) {
++    return json_get_object_size(state, /* is_global_object = */ 1);
++  } else {
++    if (json_skip_all_skippables(state)) {
++      state->error = json_parse_error_premature_end_of_buffer;
++      return 1;
++    }
++
++    /* can cache offset now. */
++    offset = state->offset;
++
++    switch (src[offset]) {
++    case '"':
++      return json_get_string_size(state, 0);
++    case '\'':
++      if (json_parse_flags_allow_single_quoted_strings & flags_bitset) {
++        return json_get_string_size(state, 0);
++      } else {
++        /* invalid value! */
++        state->error = json_parse_error_invalid_value;
++        return 1;
++      }
++    case '{':
++      return json_get_object_size(state, /* is_global_object = */ 0);
++    case '[':
++      return json_get_array_size(state);
++    case '-':
++    case '0':
++    case '1':
++    case '2':
++    case '3':
++    case '4':
++    case '5':
++    case '6':
++    case '7':
++    case '8':
++    case '9':
++      return json_get_number_size(state);
++    case '+':
++      if (json_parse_flags_allow_leading_plus_sign & flags_bitset) {
++        return json_get_number_size(state);
++      } else {
++        /* invalid value! */
++        state->error = json_parse_error_invalid_number_format;
++        return 1;
++      }
++    case '.':
++      if (json_parse_flags_allow_leading_or_trailing_decimal_point &
++          flags_bitset) {
++        return json_get_number_size(state);
++      } else {
++        /* invalid value! */
++        state->error = json_parse_error_invalid_number_format;
++        return 1;
++      }
++    default:
++      if ((offset + 4) <= size && 't' == src[offset + 0] &&
++          'r' == src[offset + 1] && 'u' == src[offset + 2] &&
++          'e' == src[offset + 3]) {
++        state->offset += 4;
++        return 0;
++      } else if ((offset + 5) <= size && 'f' == src[offset + 0] &&
++                 'a' == src[offset + 1] && 'l' == src[offset + 2] &&
++                 's' == src[offset + 3] && 'e' == src[offset + 4]) {
++        state->offset += 5;
++        return 0;
++      } else if ((offset + 4) <= size && 'n' == state->src[offset + 0] &&
++                 'u' == state->src[offset + 1] &&
++                 'l' == state->src[offset + 2] &&
++                 'l' == state->src[offset + 3]) {
++        state->offset += 4;
++        return 0;
++      } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) &&
++                 (offset + 3) <= size && 'N' == src[offset + 0] &&
++                 'a' == src[offset + 1] && 'N' == src[offset + 2]) {
++        return json_get_number_size(state);
++      } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) &&
++                 (offset + 8) <= size && 'I' == src[offset + 0] &&
++                 'n' == src[offset + 1] && 'f' == src[offset + 2] &&
++                 'i' == src[offset + 3] && 'n' == src[offset + 4] &&
++                 'i' == src[offset + 5] && 't' == src[offset + 6] &&
++                 'y' == src[offset + 7]) {
++        return json_get_number_size(state);
++      }
++
++      /* invalid value! */
++      state->error = json_parse_error_invalid_value;
++      return 1;
++    }
++  }
++}
++
++json_weak void json_parse_value(struct json_parse_state_s *state,
++                                int is_global_object,
++                                struct json_value_s *value);
++
++json_weak void json_parse_string(struct json_parse_state_s *state,
++                                 struct json_string_s *string);
++void json_parse_string(struct json_parse_state_s *state,
++                       struct json_string_s *string) {
++  size_t offset = state->offset;
++  size_t bytes_written = 0;
++  const char *const src = state->src;
++  const char quote_to_use = '\'' == src[offset] ? '\'' : '"';
++  char *data = state->data;
++  unsigned long high_surrogate = 0;
++  unsigned long codepoint;
++
++  string->string = data;
++
++  /* skip leading '"' or '\''. */
++  offset++;
++
++  while (quote_to_use != src[offset]) {
++    if ('\\' == src[offset]) {
++      /* skip the reverse solidus. */
++      offset++;
++
++      switch (src[offset++]) {
++      default:
++        return; /* we cannot ever reach here. */
++      case 'u': {
++        codepoint = 0;
++        if (!json_hexadecimal_value(&src[offset], 4, &codepoint)) {
++          return; /* this shouldn't happen as the value was already validated.
++                   */
++        }
++
++        offset += 4;
++
++        if (codepoint <= 0x7fu) {
++          data[bytes_written++] = (char)codepoint; /* 0xxxxxxx. */
++        } else if (codepoint <= 0x7ffu) {
++          data[bytes_written++] =
++              (char)(0xc0u | (codepoint >> 6)); /* 110xxxxx. */
++          data[bytes_written++] =
++              (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */
++        } else if (codepoint >= 0xd800 &&
++                   codepoint <= 0xdbff) { /* high surrogate. */
++          high_surrogate = codepoint;
++          continue; /* we need the low half to form a complete codepoint. */
++        } else if (codepoint >= 0xdc00 &&
++                   codepoint <= 0xdfff) { /* low surrogate. */
++          /* combine with the previously read half to obtain the complete
++           * codepoint. */
++          const unsigned long surrogate_offset =
++              0x10000u - (0xD800u << 10) - 0xDC00u;
++          codepoint = (high_surrogate << 10) + codepoint + surrogate_offset;
++          high_surrogate = 0;
++          data[bytes_written++] =
++              (char)(0xF0u | (codepoint >> 18)); /* 11110xxx. */
++          data[bytes_written++] =
++              (char)(0x80u | ((codepoint >> 12) & 0x3fu)); /* 10xxxxxx. */
++          data[bytes_written++] =
++              (char)(0x80u | ((codepoint >> 6) & 0x3fu)); /* 10xxxxxx. */
++          data[bytes_written++] =
++              (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */
++        } else {
++          /* we assume the value was validated and thus is within the valid
++           * range. */
++          data[bytes_written++] =
++              (char)(0xe0u | (codepoint >> 12)); /* 1110xxxx. */
++          data[bytes_written++] =
++              (char)(0x80u | ((codepoint >> 6) & 0x3fu)); /* 10xxxxxx. */
++          data[bytes_written++] =
++              (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */
++        }
++      } break;
++      case '"':
++        data[bytes_written++] = '"';
++        break;
++      case '\\':
++        data[bytes_written++] = '\\';
++        break;
++      case '/':
++        data[bytes_written++] = '/';
++        break;
++      case 'b':
++        data[bytes_written++] = '\b';
++        break;
++      case 'f':
++        data[bytes_written++] = '\f';
++        break;
++      case 'n':
++        data[bytes_written++] = '\n';
++        break;
++      case 'r':
++        data[bytes_written++] = '\r';
++        break;
++      case 't':
++        data[bytes_written++] = '\t';
++        break;
++      case '\r':
++        data[bytes_written++] = '\r';
++
++        /* check if we have a "\r\n" sequence. */
++        if ('\n' == src[offset]) {
++          data[bytes_written++] = '\n';
++          offset++;
++        }
++
++        break;
++      case '\n':
++        data[bytes_written++] = '\n';
++        break;
++      }
++    } else {
++      /* copy the character. */
++      data[bytes_written++] = src[offset++];
++    }
++  }
++
++  /* skip trailing '"' or '\''. */
++  offset++;
++
++  /* record the size of the string. */
++  string->string_size = bytes_written;
++
++  /* add null terminator to string. */
++  data[bytes_written++] = '\0';
++
++  /* move data along. */
++  state->data += bytes_written;
++
++  /* update offset. */
++  state->offset = offset;
++}
++
++json_weak void json_parse_key(struct json_parse_state_s *state,
++                              struct json_string_s *string);
++void json_parse_key(struct json_parse_state_s *state,
++                    struct json_string_s *string) {
++  if (json_parse_flags_allow_unquoted_keys & state->flags_bitset) {
++    const char *const src = state->src;
++    char *const data = state->data;
++    size_t offset = state->offset;
++
++    /* if we are allowing unquoted keys, check for quoted anyway... */
++    if (('"' == src[offset]) || ('\'' == src[offset])) {
++      /* ... if we got a quote, just parse the key as a string as normal. */
++      json_parse_string(state, string);
++    } else {
++      size_t size = 0;
++
++      string->string = state->data;
++
++      while (is_valid_unquoted_key_char(src[offset])) {
++        data[size++] = src[offset++];
++      }
++
++      /* add null terminator to string. */
++      data[size] = '\0';
++
++      /* record the size of the string. */
++      string->string_size = size++;
++
++      /* move data along. */
++      state->data += size;
++
++      /* update offset. */
++      state->offset = offset;
++    }
++  } else {
++    /* we are only allowed to have quoted keys, so just parse a string! */
++    json_parse_string(state, string);
++  }
++}
++
++json_weak void json_parse_object(struct json_parse_state_s *state,
++                                 int is_global_object,
++                                 struct json_object_s *object);
++void json_parse_object(struct json_parse_state_s *state, int is_global_object,
++                       struct json_object_s *object) {
++  const size_t flags_bitset = state->flags_bitset;
++  const size_t size = state->size;
++  const char *const src = state->src;
++  size_t elements = 0;
++  int allow_comma = 0;
++  struct json_object_element_s *previous = json_null;
++
++  if (is_global_object) {
++    /* if we skipped some whitespace, and then found an opening '{' of an. */
++    /* object, we actually have a normal JSON object at the root of the DOM...
++     */
++    if ('{' == src[state->offset]) {
++      /* . and we don't actually have a global object after all! */
++      is_global_object = 0;
++    }
++  }
++
++  if (!is_global_object) {
++    /* skip leading '{'. */
++    state->offset++;
++  }
++
++  (void)json_skip_all_skippables(state);
++
++  /* reset elements. */
++  elements = 0;
++
++  while (state->offset < size) {
++    struct json_object_element_s *element = json_null;
++    struct json_string_s *string = json_null;
++    struct json_value_s *value = json_null;
++
++    if (!is_global_object) {
++      (void)json_skip_all_skippables(state);
++
++      if ('}' == src[state->offset]) {
++        /* skip trailing '}'. */
++        state->offset++;
++
++        /* finished the object! */
++        break;
++      }
++    } else {
++      if (json_skip_all_skippables(state)) {
++        /* global object ends when the file ends! */
++        break;
++      }
++    }
++
++    /* if we parsed at least one element previously, grok for a comma. */
++    if (allow_comma) {
++      if (',' == src[state->offset]) {
++        /* skip comma. */
++        state->offset++;
++        allow_comma = 0;
++        continue;
++      }
++    }
++
++    element = (struct json_object_element_s *)state->dom;
++
++    state->dom += sizeof(struct json_object_element_s);
++
++    if (json_null == previous) {
++      /* this is our first element, so record it in our object. */
++      object->start = element;
++    } else {
++      previous->next = element;
++    }
++
++    previous = element;
++
++    if (json_parse_flags_allow_location_information & flags_bitset) {
++      struct json_string_ex_s *string_ex =
++          (struct json_string_ex_s *)state->dom;
++      state->dom += sizeof(struct json_string_ex_s);
++
++      string_ex->offset = state->offset;
++      string_ex->line_no = state->line_no;
++      string_ex->row_no = state->offset - state->line_offset;
++
++      string = &(string_ex->string);
++    } else {
++      string = (struct json_string_s *)state->dom;
++      state->dom += sizeof(struct json_string_s);
++    }
++
++    element->name = string;
++
++    (void)json_parse_key(state, string);
++
++    (void)json_skip_all_skippables(state);
++
++    /* skip colon or equals. */
++    state->offset++;
++
++    (void)json_skip_all_skippables(state);
++
++    if (json_parse_flags_allow_location_information & flags_bitset) {
++      struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state->dom;
++      state->dom += sizeof(struct json_value_ex_s);
++
++      value_ex->offset = state->offset;
++      value_ex->line_no = state->line_no;
++      value_ex->row_no = state->offset - state->line_offset;
++
++      value = &(value_ex->value);
++    } else {
++      value = (struct json_value_s *)state->dom;
++      state->dom += sizeof(struct json_value_s);
++    }
++
++    element->value = value;
++
++    json_parse_value(state, /* is_global_object = */ 0, value);
++
++    /* successfully parsed a name/value pair! */
++    elements++;
++    allow_comma = 1;
++  }
++
++  /* if we had at least one element, end the linked list. */
++  if (previous) {
++    previous->next = json_null;
++  }
++
++  if (0 == elements) {
++    object->start = json_null;
++  }
++
++  object->length = elements;
++}
++
++json_weak void json_parse_array(struct json_parse_state_s *state,
++                                struct json_array_s *array);
++void json_parse_array(struct json_parse_state_s *state,
++                      struct json_array_s *array) {
++  const char *const src = state->src;
++  const size_t size = state->size;
++  size_t elements = 0;
++  int allow_comma = 0;
++  struct json_array_element_s *previous = json_null;
++
++  /* skip leading '['. */
++  state->offset++;
++
++  (void)json_skip_all_skippables(state);
++
++  /* reset elements. */
++  elements = 0;
++
++  do {
++    struct json_array_element_s *element = json_null;
++    struct json_value_s *value = json_null;
++
++    (void)json_skip_all_skippables(state);
++
++    if (']' == src[state->offset]) {
++      /* skip trailing ']'. */
++      state->offset++;
++
++      /* finished the array! */
++      break;
++    }
++
++    /* if we parsed at least one element previously, grok for a comma. */
++    if (allow_comma) {
++      if (',' == src[state->offset]) {
++        /* skip comma. */
++        state->offset++;
++        allow_comma = 0;
++        continue;
++      }
++    }
++
++    element = (struct json_array_element_s *)state->dom;
++
++    state->dom += sizeof(struct json_array_element_s);
++
++    if (json_null == previous) {
++      /* this is our first element, so record it in our array. */
++      array->start = element;
++    } else {
++      previous->next = element;
++    }
++
++    previous = element;
++
++    if (json_parse_flags_allow_location_information & state->flags_bitset) {
++      struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state->dom;
++      state->dom += sizeof(struct json_value_ex_s);
++
++      value_ex->offset = state->offset;
++      value_ex->line_no = state->line_no;
++      value_ex->row_no = state->offset - state->line_offset;
++
++      value = &(value_ex->value);
++    } else {
++      value = (struct json_value_s *)state->dom;
++      state->dom += sizeof(struct json_value_s);
++    }
++
++    element->value = value;
++
++    json_parse_value(state, /* is_global_object = */ 0, value);
++
++    /* successfully parsed an array element! */
++    elements++;
++    allow_comma = 1;
++  } while (state->offset < size);
++
++  /* end the linked list. */
++  if (previous) {
++    previous->next = json_null;
++  }
++
++  if (0 == elements) {
++    array->start = json_null;
++  }
++
++  array->length = elements;
++}
++
++json_weak void json_parse_number(struct json_parse_state_s *state,
++                                 struct json_number_s *number);
++void json_parse_number(struct json_parse_state_s *state,
++                       struct json_number_s *number) {
++  const size_t flags_bitset = state->flags_bitset;
++  size_t offset = state->offset;
++  const size_t size = state->size;
++  size_t bytes_written = 0;
++  const char *const src = state->src;
++  char *data = state->data;
++
++  number->number = data;
++
++  if (json_parse_flags_allow_hexadecimal_numbers & flags_bitset) {
++    if (('0' == src[offset]) &&
++        (('x' == src[offset + 1]) || ('X' == src[offset + 1]))) {
++      /* consume hexadecimal digits. */
++      while ((offset < size) &&
++             (('0' <= src[offset] && src[offset] <= '9') ||
++              ('a' <= src[offset] && src[offset] <= 'f') ||
++              ('A' <= src[offset] && src[offset] <= 'F') ||
++              ('x' == src[offset]) || ('X' == src[offset]))) {
++        data[bytes_written++] = src[offset++];
++      }
++    }
++  }
++
++  while (offset < size) {
++    int end = 0;
++
++    switch (src[offset]) {
++    case '0':
++    case '1':
++    case '2':
++    case '3':
++    case '4':
++    case '5':
++    case '6':
++    case '7':
++    case '8':
++    case '9':
++    case '.':
++    case 'e':
++    case 'E':
++    case '+':
++    case '-':
++      data[bytes_written++] = src[offset++];
++      break;
++    default:
++      end = 1;
++      break;
++    }
++
++    if (0 != end) {
++      break;
++    }
++  }
++
++  if (json_parse_flags_allow_inf_and_nan & flags_bitset) {
++    const size_t inf_strlen = 8; /* = strlen("Infinity");. */
++    const size_t nan_strlen = 3; /* = strlen("NaN");. */
++
++    if (offset + inf_strlen < size) {
++      if ('I' == src[offset]) {
++        size_t i;
++        /* We found our special 'Infinity' keyword! */
++        for (i = 0; i < inf_strlen; i++) {
++          data[bytes_written++] = src[offset++];
++        }
++      }
++    }
++
++    if (offset + nan_strlen < size) {
++      if ('N' == src[offset]) {
++        size_t i;
++        /* We found our special 'NaN' keyword! */
++        for (i = 0; i < nan_strlen; i++) {
++          data[bytes_written++] = src[offset++];
++        }
++      }
++    }
++  }
++
++  /* record the size of the number. */
++  number->number_size = bytes_written;
++  /* add null terminator to number string. */
++  data[bytes_written++] = '\0';
++  /* move data along. */
++  state->data += bytes_written;
++  /* update offset. */
++  state->offset = offset;
++}
++
++json_weak void json_parse_value(struct json_parse_state_s *state,
++                                int is_global_object,
++                                struct json_value_s *value);
++void json_parse_value(struct json_parse_state_s *state, int is_global_object,
++                      struct json_value_s *value) {
++  const size_t flags_bitset = state->flags_bitset;
++  const char *const src = state->src;
++  const size_t size = state->size;
++  size_t offset;
++
++  (void)json_skip_all_skippables(state);
++
++  /* cache offset now. */
++  offset = state->offset;
++
++  if (is_global_object) {
++    value->type = json_type_object;
++    value->payload = state->dom;
++    state->dom += sizeof(struct json_object_s);
++    json_parse_object(state, /* is_global_object = */ 1,
++                      (struct json_object_s *)value->payload);
++  } else {
++    switch (src[offset]) {
++    case '"':
++    case '\'':
++      value->type = json_type_string;
++      value->payload = state->dom;
++      state->dom += sizeof(struct json_string_s);
++      json_parse_string(state, (struct json_string_s *)value->payload);
++      break;
++    case '{':
++      value->type = json_type_object;
++      value->payload = state->dom;
++      state->dom += sizeof(struct json_object_s);
++      json_parse_object(state, /* is_global_object = */ 0,
++                        (struct json_object_s *)value->payload);
++      break;
++    case '[':
++      value->type = json_type_array;
++      value->payload = state->dom;
++      state->dom += sizeof(struct json_array_s);
++      json_parse_array(state, (struct json_array_s *)value->payload);
++      break;
++    case '-':
++    case '+':
++    case '0':
++    case '1':
++    case '2':
++    case '3':
++    case '4':
++    case '5':
++    case '6':
++    case '7':
++    case '8':
++    case '9':
++    case '.':
++      value->type = json_type_number;
++      value->payload = state->dom;
++      state->dom += sizeof(struct json_number_s);
++      json_parse_number(state, (struct json_number_s *)value->payload);
++      break;
++    default:
++      if ((offset + 4) <= size && 't' == src[offset + 0] &&
++          'r' == src[offset + 1] && 'u' == src[offset + 2] &&
++          'e' == src[offset + 3]) {
++        value->type = json_type_true;
++        value->payload = json_null;
++        state->offset += 4;
++      } else if ((offset + 5) <= size && 'f' == src[offset + 0] &&
++                 'a' == src[offset + 1] && 'l' == src[offset + 2] &&
++                 's' == src[offset + 3] && 'e' == src[offset + 4]) {
++        value->type = json_type_false;
++        value->payload = json_null;
++        state->offset += 5;
++      } else if ((offset + 4) <= size && 'n' == src[offset + 0] &&
++                 'u' == src[offset + 1] && 'l' == src[offset + 2] &&
++                 'l' == src[offset + 3]) {
++        value->type = json_type_null;
++        value->payload = json_null;
++        state->offset += 4;
++      } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) &&
++                 (offset + 3) <= size && 'N' == src[offset + 0] &&
++                 'a' == src[offset + 1] && 'N' == src[offset + 2]) {
++        value->type = json_type_number;
++        value->payload = state->dom;
++        state->dom += sizeof(struct json_number_s);
++        json_parse_number(state, (struct json_number_s *)value->payload);
++      } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) &&
++                 (offset + 8) <= size && 'I' == src[offset + 0] &&
++                 'n' == src[offset + 1] && 'f' == src[offset + 2] &&
++                 'i' == src[offset + 3] && 'n' == src[offset + 4] &&
++                 'i' == src[offset + 5] && 't' == src[offset + 6] &&
++                 'y' == src[offset + 7]) {
++        value->type = json_type_number;
++        value->payload = state->dom;
++        state->dom += sizeof(struct json_number_s);
++        json_parse_number(state, (struct json_number_s *)value->payload);
++      }
++      break;
++    }
++  }
++}
++
++struct json_value_s *
++json_parse_ex(const void *src, size_t src_size, size_t flags_bitset,
++              void *(*alloc_func_ptr)(void *user_data, size_t size),
++              void *user_data, struct json_parse_result_s *result) {
++  struct json_parse_state_s state;
++  void *allocation;
++  struct json_value_s *value;
++  size_t total_size;
++  int input_error;
++
++  if (result) {
++    result->error = json_parse_error_none;
++    result->error_offset = 0;
++    result->error_line_no = 0;
++    result->error_row_no = 0;
++  }
++
++  if (json_null == src) {
++    /* invalid src pointer was null! */
++    return json_null;
++  }
++
++  state.src = (const char *)src;
++  state.size = src_size;
++  state.offset = 0;
++  state.line_no = 1;
++  state.line_offset = 0;
++  state.error = json_parse_error_none;
++  state.dom_size = 0;
++  state.data_size = 0;
++  state.flags_bitset = flags_bitset;
++
++  input_error = json_get_value_size(
++      &state, (int)(json_parse_flags_allow_global_object & state.flags_bitset));
++
++  if (0 == input_error) {
++    json_skip_all_skippables(&state);
++
++    if (state.offset != state.size) {
++      /* our parsing didn't have an error, but there are characters remaining in
++       * the input that weren't part of the JSON! */
++
++      state.error = json_parse_error_unexpected_trailing_characters;
++      input_error = 1;
++    }
++  }
++
++  if (input_error) {
++    /* parsing value's size failed (most likely an invalid JSON DOM!). */
++    if (result) {
++      result->error = state.error;
++      result->error_offset = state.offset;
++      result->error_line_no = state.line_no;
++      result->error_row_no = state.offset - state.line_offset;
++    }
++    return json_null;
++  }
++
++  /* our total allocation is the combination of the dom and data sizes (we. */
++  /* first encode the structure of the JSON, and then the data referenced by. */
++  /* the JSON values). */
++  total_size = state.dom_size + state.data_size;
++
++  if (json_null == alloc_func_ptr) {
++    allocation = malloc(total_size);
++  } else {
++    allocation = alloc_func_ptr(user_data, total_size);
++  }
++
++  if (json_null == allocation) {
++    /* malloc failed! */
++    if (result) {
++      result->error = json_parse_error_allocator_failed;
++      result->error_offset = 0;
++      result->error_line_no = 0;
++      result->error_row_no = 0;
++    }
++
++    return json_null;
++  }
++
++  /* reset offset so we can reuse it. */
++  state.offset = 0;
++
++  /* reset the line information so we can reuse it. */
++  state.line_no = 1;
++  state.line_offset = 0;
++
++  state.dom = (char *)allocation;
++  state.data = state.dom + state.dom_size;
++
++  if (json_parse_flags_allow_location_information & state.flags_bitset) {
++    struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state.dom;
++    state.dom += sizeof(struct json_value_ex_s);
++
++    value_ex->offset = state.offset;
++    value_ex->line_no = state.line_no;
++    value_ex->row_no = state.offset - state.line_offset;
++
++    value = &(value_ex->value);
++  } else {
++    value = (struct json_value_s *)state.dom;
++    state.dom += sizeof(struct json_value_s);
++  }
++
++  json_parse_value(
++      &state, (int)(json_parse_flags_allow_global_object & state.flags_bitset),
++      value);
++
++  return (struct json_value_s *)allocation;
++}
++
++struct json_value_s *json_parse(const void *src, size_t src_size) {
++  return json_parse_ex(src, src_size, json_parse_flags_default, json_null,
++                       json_null, json_null);
++}
++
++struct json_extract_result_s {
++  size_t dom_size;
++  size_t data_size;
++};
++
++struct json_value_s *json_extract_value(const struct json_value_s *value) {
++  return json_extract_value_ex(value, json_null, json_null);
++}
++
++json_weak struct json_extract_result_s
++json_extract_get_number_size(const struct json_number_s *const number);
++json_weak struct json_extract_result_s
++json_extract_get_string_size(const struct json_string_s *const string);
++json_weak struct json_extract_result_s
++json_extract_get_object_size(const struct json_object_s *const object);
++json_weak struct json_extract_result_s
++json_extract_get_array_size(const struct json_array_s *const array);
++json_weak struct json_extract_result_s
++json_extract_get_value_size(const struct json_value_s *const value);
++
++struct json_extract_result_s
++json_extract_get_number_size(const struct json_number_s *const number) {
++  struct json_extract_result_s result;
++  result.dom_size = sizeof(struct json_number_s);
++  result.data_size = number->number_size;
++  return result;
++}
++
++struct json_extract_result_s
++json_extract_get_string_size(const struct json_string_s *const string) {
++  struct json_extract_result_s result;
++  result.dom_size = sizeof(struct json_string_s);
++  result.data_size = string->string_size + 1;
++  return result;
++}
++
++struct json_extract_result_s
++json_extract_get_object_size(const struct json_object_s *const object) {
++  struct json_extract_result_s result;
++  size_t i;
++  const struct json_object_element_s *element = object->start;
++
++  result.dom_size = sizeof(struct json_object_s) +
++                    (sizeof(struct json_object_element_s) * object->length);
++  result.data_size = 0;
++
++  for (i = 0; i < object->length; i++) {
++    const struct json_extract_result_s string_result =
++        json_extract_get_string_size(element->name);
++    const struct json_extract_result_s value_result =
++        json_extract_get_value_size(element->value);
++
++    result.dom_size += string_result.dom_size;
++    result.data_size += string_result.data_size;
++
++    result.dom_size += value_result.dom_size;
++    result.data_size += value_result.data_size;
++
++    element = element->next;
++  }
++
++  return result;
++}
++
++struct json_extract_result_s
++json_extract_get_array_size(const struct json_array_s *const array) {
++  struct json_extract_result_s result;
++  size_t i;
++  const struct json_array_element_s *element = array->start;
++
++  result.dom_size = sizeof(struct json_array_s) +
++                    (sizeof(struct json_array_element_s) * array->length);
++  result.data_size = 0;
++
++  for (i = 0; i < array->length; i++) {
++    const struct json_extract_result_s value_result =
++        json_extract_get_value_size(element->value);
++
++    result.dom_size += value_result.dom_size;
++    result.data_size += value_result.data_size;
++
++    element = element->next;
++  }
++
++  return result;
++}
++
++struct json_extract_result_s
++json_extract_get_value_size(const struct json_value_s *const value) {
++  struct json_extract_result_s result = {0, 0};
++
++  switch (value->type) {
++  default:
++    break;
++  case json_type_object:
++    result = json_extract_get_object_size(
++        (const struct json_object_s *)value->payload);
++    break;
++  case json_type_array:
++    result = json_extract_get_array_size(
++        (const struct json_array_s *)value->payload);
++    break;
++  case json_type_number:
++    result = json_extract_get_number_size(
++        (const struct json_number_s *)value->payload);
++    break;
++  case json_type_string:
++    result = json_extract_get_string_size(
++        (const struct json_string_s *)value->payload);
++    break;
++  }
++
++  result.dom_size += sizeof(struct json_value_s);
++
++  return result;
++}
++
++struct json_extract_state_s {
++  char *dom;
++  char *data;
++};
++
++json_weak void json_extract_copy_value(struct json_extract_state_s *const state,
++                                       const struct json_value_s *const value);
++void json_extract_copy_value(struct json_extract_state_s *const state,
++                             const struct json_value_s *const value) {
++  struct json_string_s *string;
++  struct json_number_s *number;
++  struct json_object_s *object;
++  struct json_array_s *array;
++  struct json_value_s *new_value;
++
++  memcpy(state->dom, value, sizeof(struct json_value_s));
++  new_value = (struct json_value_s *)state->dom;
++  state->dom += sizeof(struct json_value_s);
++  new_value->payload = state->dom;
++
++  if (json_type_string == value->type) {
++    memcpy(state->dom, value->payload, sizeof(struct json_string_s));
++    string = (struct json_string_s *)state->dom;
++    state->dom += sizeof(struct json_string_s);
++
++    memcpy(state->data, string->string, string->string_size + 1);
++    string->string = state->data;
++    state->data += string->string_size + 1;
++  } else if (json_type_number == value->type) {
++    memcpy(state->dom, value->payload, sizeof(struct json_number_s));
++    number = (struct json_number_s *)state->dom;
++    state->dom += sizeof(struct json_number_s);
++
++    memcpy(state->data, number->number, number->number_size);
++    number->number = state->data;
++    state->data += number->number_size;
++  } else if (json_type_object == value->type) {
++    struct json_object_element_s *element;
++    size_t i;
++
++    memcpy(state->dom, value->payload, sizeof(struct json_object_s));
++    object = (struct json_object_s *)state->dom;
++    state->dom += sizeof(struct json_object_s);
++
++    element = object->start;
++    object->start = (struct json_object_element_s *)state->dom;
++
++    for (i = 0; i < object->length; i++) {
++      struct json_value_s *previous_value;
++      struct json_object_element_s *previous_element;
++
++      memcpy(state->dom, element, sizeof(struct json_object_element_s));
++      element = (struct json_object_element_s *)state->dom;
++      state->dom += sizeof(struct json_object_element_s);
++
++      string = element->name;
++      memcpy(state->dom, string, sizeof(struct json_string_s));
++      string = (struct json_string_s *)state->dom;
++      state->dom += sizeof(struct json_string_s);
++      element->name = string;
++
++      memcpy(state->data, string->string, string->string_size + 1);
++      string->string = state->data;
++      state->data += string->string_size + 1;
++
++      previous_value = element->value;
++      element->value = (struct json_value_s *)state->dom;
++      json_extract_copy_value(state, previous_value);
++
++      previous_element = element;
++      element = element->next;
++
++      if (element) {
++        previous_element->next = (struct json_object_element_s *)state->dom;
++      }
++    }
++  } else if (json_type_array == value->type) {
++    struct json_array_element_s *element;
++    size_t i;
++
++    memcpy(state->dom, value->payload, sizeof(struct json_array_s));
++    array = (struct json_array_s *)state->dom;
++    state->dom += sizeof(struct json_array_s);
++
++    element = array->start;
++    array->start = (struct json_array_element_s *)state->dom;
++
++    for (i = 0; i < array->length; i++) {
++      struct json_value_s *previous_value;
++      struct json_array_element_s *previous_element;
++
++      memcpy(state->dom, element, sizeof(struct json_array_element_s));
++      element = (struct json_array_element_s *)state->dom;
++      state->dom += sizeof(struct json_array_element_s);
++
++      previous_value = element->value;
++      element->value = (struct json_value_s *)state->dom;
++      json_extract_copy_value(state, previous_value);
++
++      previous_element = element;
++      element = element->next;
++
++      if (element) {
++        previous_element->next = (struct json_array_element_s *)state->dom;
++      }
++    }
++  }
++}
++
++struct json_value_s *json_extract_value_ex(const struct json_value_s *value,
++                                           void *(*alloc_func_ptr)(void *,
++                                                                   size_t),
++                                           void *user_data) {
++  void *allocation;
++  struct json_extract_result_s result;
++  struct json_extract_state_s state;
++  size_t total_size;
++
++  if (json_null == value) {
++    /* invalid value was null! */
++    return json_null;
++  }
++
++  result = json_extract_get_value_size(value);
++  total_size = result.dom_size + result.data_size;
++
++  if (json_null == alloc_func_ptr) {
++    allocation = malloc(total_size);
++  } else {
++    allocation = alloc_func_ptr(user_data, total_size);
++  }
++
++  state.dom = (char *)allocation;
++  state.data = state.dom + result.dom_size;
++
++  json_extract_copy_value(&state, value);
++
++  return (struct json_value_s *)allocation;
++}
++
++struct json_string_s *json_value_as_string(struct json_value_s *const value) {
++  if (value->type != json_type_string) {
++    return json_null;
++  }
++
++  return (struct json_string_s *)value->payload;
++}
++
++struct json_number_s *json_value_as_number(struct json_value_s *const value) {
++  if (value->type != json_type_number) {
++    return json_null;
++  }
++
++  return (struct json_number_s *)value->payload;
++}
++
++struct json_object_s *json_value_as_object(struct json_value_s *const value) {
++  if (value->type != json_type_object) {
++    return json_null;
++  }
++
++  return (struct json_object_s *)value->payload;
++}
++
++struct json_array_s *json_value_as_array(struct json_value_s *const value) {
++  if (value->type != json_type_array) {
++    return json_null;
++  }
++
++  return (struct json_array_s *)value->payload;
++}
++
++int json_value_is_true(const struct json_value_s *const value) {
++  return value->type == json_type_true;
++}
++
++int json_value_is_false(const struct json_value_s *const value) {
++  return value->type == json_type_false;
++}
++
++int json_value_is_null(const struct json_value_s *const value) {
++  return value->type == json_type_null;
++}
++
++json_weak int
++json_write_minified_get_value_size(const struct json_value_s *value,
++                                   size_t *size);
++
++json_weak int json_write_get_number_size(const struct json_number_s *number,
++                                         size_t *size);
++int json_write_get_number_size(const struct json_number_s *number,
++                               size_t *size) {
++  json_uintmax_t parsed_number;
++  size_t i;
++
++  if (number->number_size >= 2) {
++    switch (number->number[1]) {
++    default:
++      break;
++    case 'x':
++    case 'X':
++      /* the number is a json_parse_flags_allow_hexadecimal_numbers hexadecimal
++       * so we have to do extra work to convert it to a non-hexadecimal for JSON
++       * output. */
++      parsed_number = json_strtoumax(number->number, json_null, 0);
++
++      i = 0;
++
++      while (0 != parsed_number) {
++        parsed_number /= 10;
++        i++;
++      }
++
++      *size += i;
++      return 0;
++    }
++  }
++
++  /* check to see if the number has leading/trailing decimal point. */
++  i = 0;
++
++  /* skip any leading '+' or '-'. */
++  if ((i < number->number_size) &&
++      (('+' == number->number[i]) || ('-' == number->number[i]))) {
++    i++;
++  }
++
++  /* check if we have infinity. */
++  if ((i < number->number_size) && ('I' == number->number[i])) {
++    const char *inf = "Infinity";
++    size_t k;
++
++    for (k = i; k < number->number_size; k++) {
++      const char c = *inf++;
++
++      /* Check if we found the Infinity string! */
++      if ('\0' == c) {
++        break;
++      } else if (c != number->number[k]) {
++        break;
++      }
++    }
++
++    if ('\0' == *inf) {
++      /* Inf becomes 1.7976931348623158e308 because JSON can't support it. */
++      *size += 22;
++
++      /* if we had a leading '-' we need to record it in the JSON output. */
++      if ('-' == number->number[0]) {
++        *size += 1;
++      }
++    }
++
++    return 0;
++  }
++
++  /* check if we have nan. */
++  if ((i < number->number_size) && ('N' == number->number[i])) {
++    const char *nan = "NaN";
++    size_t k;
++
++    for (k = i; k < number->number_size; k++) {
++      const char c = *nan++;
++
++      /* Check if we found the NaN string! */
++      if ('\0' == c) {
++        break;
++      } else if (c != number->number[k]) {
++        break;
++      }
++    }
++
++    if ('\0' == *nan) {
++      /* NaN becomes 1 because JSON can't support it. */
++      *size += 1;
++
++      return 0;
++    }
++  }
++
++  /* if we had a leading decimal point. */
++  if ((i < number->number_size) && ('.' == number->number[i])) {
++    /* 1 + because we had a leading decimal point. */
++    *size += 1;
++    goto cleanup;
++  }
++
++  for (; i < number->number_size; i++) {
++    const char c = number->number[i];
++    if (!('0' <= c && c <= '9')) {
++      break;
++    }
++  }
++
++  /* if we had a trailing decimal point. */
++  if ((i + 1 == number->number_size) && ('.' == number->number[i])) {
++    /* 1 + because we had a trailing decimal point. */
++    *size += 1;
++    goto cleanup;
++  }
++
++cleanup:
++  *size += number->number_size; /* the actual string of the number. */
++
++  /* if we had a leading '+' we don't record it in the JSON output. */
++  if ('+' == number->number[0]) {
++    *size -= 1;
++  }
++
++  return 0;
++}
++
++json_weak int json_write_get_string_size(const struct json_string_s *string,
++                                         size_t *size);
++int json_write_get_string_size(const struct json_string_s *string,
++                               size_t *size) {
++  size_t i;
++  for (i = 0; i < string->string_size; i++) {
++    switch (string->string[i]) {
++    case '"':
++    case '\\':
++    case '\b':
++    case '\f':
++    case '\n':
++    case '\r':
++    case '\t':
++      *size += 2;
++      break;
++    default:
++      *size += 1;
++      break;
++    }
++  }
++
++  *size += 2; /* need to encode the surrounding '"' characters. */
++
++  return 0;
++}
++
++json_weak int
++json_write_minified_get_array_size(const struct json_array_s *array,
++                                   size_t *size);
++int json_write_minified_get_array_size(const struct json_array_s *array,
++                                       size_t *size) {
++  struct json_array_element_s *element;
++
++  *size += 2; /* '[' and ']'. */
++
++  if (1 < array->length) {
++    *size += array->length - 1; /* ','s seperate each element. */
++  }
++
++  for (element = array->start; json_null != element; element = element->next) {
++    if (json_write_minified_get_value_size(element->value, size)) {
++      /* value was malformed! */
++      return 1;
++    }
++  }
++
++  return 0;
++}
++
++json_weak int
++json_write_minified_get_object_size(const struct json_object_s *object,
++                                    size_t *size);
++int json_write_minified_get_object_size(const struct json_object_s *object,
++                                        size_t *size) {
++  struct json_object_element_s *element;
++
++  *size += 2; /* '{' and '}'. */
++
++  *size += object->length; /* ':'s seperate each name/value pair. */
++
++  if (1 < object->length) {
++    *size += object->length - 1; /* ','s seperate each element. */
++  }
++
++  for (element = object->start; json_null != element; element = element->next) {
++    if (json_write_get_string_size(element->name, size)) {
++      /* string was malformed! */
++      return 1;
++    }
++
++    if (json_write_minified_get_value_size(element->value, size)) {
++      /* value was malformed! */
++      return 1;
++    }
++  }
++
++  return 0;
++}
++
++json_weak int
++json_write_minified_get_value_size(const struct json_value_s *value,
++                                   size_t *size);
++int json_write_minified_get_value_size(const struct json_value_s *value,
++                                       size_t *size) {
++  switch (value->type) {
++  default:
++    /* unknown value type found! */
++    return 1;
++  case json_type_number:
++    return json_write_get_number_size((struct json_number_s *)value->payload,
++                                      size);
++  case json_type_string:
++    return json_write_get_string_size((struct json_string_s *)value->payload,
++                                      size);
++  case json_type_array:
++    return json_write_minified_get_array_size(
++        (struct json_array_s *)value->payload, size);
++  case json_type_object:
++    return json_write_minified_get_object_size(
++        (struct json_object_s *)value->payload, size);
++  case json_type_true:
++    *size += 4; /* the string "true". */
++    return 0;
++  case json_type_false:
++    *size += 5; /* the string "false". */
++    return 0;
++  case json_type_null:
++    *size += 4; /* the string "null". */
++    return 0;
++  }
++}
++
++json_weak char *json_write_minified_value(const struct json_value_s *value,
++                                          char *data);
++
++json_weak char *json_write_number(const struct json_number_s *number,
++                                  char *data);
++char *json_write_number(const struct json_number_s *number, char *data) {
++  json_uintmax_t parsed_number, backup;
++  size_t i;
++
++  if (number->number_size >= 2) {
++    switch (number->number[1]) {
++    default:
++      break;
++    case 'x':
++    case 'X':
++      /* The number is a json_parse_flags_allow_hexadecimal_numbers hexadecimal
++       * so we have to do extra work to convert it to a non-hexadecimal for JSON
++       * output. */
++      parsed_number = json_strtoumax(number->number, json_null, 0);
++
++      /* We need a copy of parsed number twice, so take a backup of it. */
++      backup = parsed_number;
++
++      i = 0;
++
++      while (0 != parsed_number) {
++        parsed_number /= 10;
++        i++;
++      }
++
++      /* Restore parsed_number to its original value stored in the backup. */
++      parsed_number = backup;
++
++      /* Now use backup to take a copy of i, or the length of the string. */
++      backup = i;
++
++      do {
++        *(data + i - 1) = '0' + (char)(parsed_number % 10);
++        parsed_number /= 10;
++        i--;
++      } while (0 != parsed_number);
++
++      data += backup;
++
++      return data;
++    }
++  }
++
++  /* check to see if the number has leading/trailing decimal point. */
++  i = 0;
++
++  /* skip any leading '-'. */
++  if ((i < number->number_size) &&
++      (('+' == number->number[i]) || ('-' == number->number[i]))) {
++    i++;
++  }
++
++  /* check if we have infinity. */
++  if ((i < number->number_size) && ('I' == number->number[i])) {
++    const char *inf = "Infinity";
++    size_t k;
++
++    for (k = i; k < number->number_size; k++) {
++      const char c = *inf++;
++
++      /* Check if we found the Infinity string! */
++      if ('\0' == c) {
++        break;
++      } else if (c != number->number[k]) {
++        break;
++      }
++    }
++
++    if ('\0' == *inf++) {
++      const char *dbl_max;
++
++      /* if we had a leading '-' we need to record it in the JSON output. */
++      if ('-' == number->number[0]) {
++        *data++ = '-';
++      }
++
++      /* Inf becomes 1.7976931348623158e308 because JSON can't support it. */
++      for (dbl_max = "1.7976931348623158e308"; '\0' != *dbl_max; dbl_max++) {
++        *data++ = *dbl_max;
++      }
++
++      return data;
++    }
++  }
++
++  /* check if we have nan. */
++  if ((i < number->number_size) && ('N' == number->number[i])) {
++    const char *nan = "NaN";
++    size_t k;
++
++    for (k = i; k < number->number_size; k++) {
++      const char c = *nan++;
++
++      /* Check if we found the NaN string! */
++      if ('\0' == c) {
++        break;
++      } else if (c != number->number[k]) {
++        break;
++      }
++    }
++
++    if ('\0' == *nan++) {
++      /* NaN becomes 0 because JSON can't support it. */
++      *data++ = '0';
++      return data;
++    }
++  }
++
++  /* if we had a leading decimal point. */
++  if ((i < number->number_size) && ('.' == number->number[i])) {
++    i = 0;
++
++    /* skip any leading '+'. */
++    if ('+' == number->number[i]) {
++      i++;
++    }
++
++    /* output the leading '-' if we had one. */
++    if ('-' == number->number[i]) {
++      *data++ = '-';
++      i++;
++    }
++
++    /* insert a '0' to fix the leading decimal point for JSON output. */
++    *data++ = '0';
++
++    /* and output the rest of the number as normal. */
++    for (; i < number->number_size; i++) {
++      *data++ = number->number[i];
++    }
++
++    return data;
++  }
++
++  for (; i < number->number_size; i++) {
++    const char c = number->number[i];
++    if (!('0' <= c && c <= '9')) {
++      break;
++    }
++  }
++
++  /* if we had a trailing decimal point. */
++  if ((i + 1 == number->number_size) && ('.' == number->number[i])) {
++    i = 0;
++
++    /* skip any leading '+'. */
++    if ('+' == number->number[i]) {
++      i++;
++    }
++
++    /* output the leading '-' if we had one. */
++    if ('-' == number->number[i]) {
++      *data++ = '-';
++      i++;
++    }
++
++    /* and output the rest of the number as normal. */
++    for (; i < number->number_size; i++) {
++      *data++ = number->number[i];
++    }
++
++    /* insert a '0' to fix the trailing decimal point for JSON output. */
++    *data++ = '0';
++
++    return data;
++  }
++
++  i = 0;
++
++  /* skip any leading '+'. */
++  if ('+' == number->number[i]) {
++    i++;
++  }
++
++  for (; i < number->number_size; i++) {
++    *data++ = number->number[i];
++  }
++
++  return data;
++}
++
++json_weak char *json_write_string(const struct json_string_s *string,
++                                  char *data);
++char *json_write_string(const struct json_string_s *string, char *data) {
++  size_t i;
++
++  *data++ = '"'; /* open the string. */
++
++  for (i = 0; i < string->string_size; i++) {
++    switch (string->string[i]) {
++    case '"':
++      *data++ = '\\'; /* escape the control character. */
++      *data++ = '"';
++      break;
++    case '\\':
++      *data++ = '\\'; /* escape the control character. */
++      *data++ = '\\';
++      break;
++    case '\b':
++      *data++ = '\\'; /* escape the control character. */
++      *data++ = 'b';
++      break;
++    case '\f':
++      *data++ = '\\'; /* escape the control character. */
++      *data++ = 'f';
++      break;
++    case '\n':
++      *data++ = '\\'; /* escape the control character. */
++      *data++ = 'n';
++      break;
++    case '\r':
++      *data++ = '\\'; /* escape the control character. */
++      *data++ = 'r';
++      break;
++    case '\t':
++      *data++ = '\\'; /* escape the control character. */
++      *data++ = 't';
++      break;
++    default:
++      *data++ = string->string[i];
++      break;
++    }
++  }
++
++  *data++ = '"'; /* close the string. */
++
++  return data;
++}
++
++json_weak char *json_write_minified_array(const struct json_array_s *array,
++                                          char *data);
++char *json_write_minified_array(const struct json_array_s *array, char *data) {
++  struct json_array_element_s *element = json_null;
++
++  *data++ = '['; /* open the array. */
++
++  for (element = array->start; json_null != element; element = element->next) {
++    if (element != array->start) {
++      *data++ = ','; /* ','s seperate each element. */
++    }
++
++    data = json_write_minified_value(element->value, data);
++
++    if (json_null == data) {
++      /* value was malformed! */
++      return json_null;
++    }
++  }
++
++  *data++ = ']'; /* close the array. */
++
++  return data;
++}
++
++json_weak char *json_write_minified_object(const struct json_object_s *object,
++                                           char *data);
++char *json_write_minified_object(const struct json_object_s *object,
++                                 char *data) {
++  struct json_object_element_s *element = json_null;
++
++  *data++ = '{'; /* open the object. */
++
++  for (element = object->start; json_null != element; element = element->next) {
++    if (element != object->start) {
++      *data++ = ','; /* ','s seperate each element. */
++    }
++
++    data = json_write_string(element->name, data);
++
++    if (json_null == data) {
++      /* string was malformed! */
++      return json_null;
++    }
++
++    *data++ = ':'; /* ':'s seperate each name/value pair. */
++
++    data = json_write_minified_value(element->value, data);
++
++    if (json_null == data) {
++      /* value was malformed! */
++      return json_null;
++    }
++  }
++
++  *data++ = '}'; /* close the object. */
++
++  return data;
++}
++
++json_weak char *json_write_minified_value(const struct json_value_s *value,
++                                          char *data);
++char *json_write_minified_value(const struct json_value_s *value, char *data) {
++  switch (value->type) {
++  default:
++    /* unknown value type found! */
++    return json_null;
++  case json_type_number:
++    return json_write_number((struct json_number_s *)value->payload, data);
++  case json_type_string:
++    return json_write_string((struct json_string_s *)value->payload, data);
++  case json_type_array:
++    return json_write_minified_array((struct json_array_s *)value->payload,
++                                     data);
++  case json_type_object:
++    return json_write_minified_object((struct json_object_s *)value->payload,
++                                      data);
++  case json_type_true:
++    data[0] = 't';
++    data[1] = 'r';
++    data[2] = 'u';
++    data[3] = 'e';
++    return data + 4;
++  case json_type_false:
++    data[0] = 'f';
++    data[1] = 'a';
++    data[2] = 'l';
++    data[3] = 's';
++    data[4] = 'e';
++    return data + 5;
++  case json_type_null:
++    data[0] = 'n';
++    data[1] = 'u';
++    data[2] = 'l';
++    data[3] = 'l';
++    return data + 4;
++  }
++}
++
++void *json_write_minified(const struct json_value_s *value, size_t *out_size) {
++  size_t size = 0;
++  char *data = json_null;
++  char *data_end = json_null;
++
++  if (json_null == value) {
++    return json_null;
++  }
++
++  if (json_write_minified_get_value_size(value, &size)) {
++    /* value was malformed! */
++    return json_null;
++  }
++
++  size += 1; /* for the '\0' null terminating character. */
++
++  data = (char *)malloc(size);
++
++  if (json_null == data) {
++    /* malloc failed! */
++    return json_null;
++  }
++
++  data_end = json_write_minified_value(value, data);
++
++  if (json_null == data_end) {
++    /* bad chi occurred! */
++    free(data);
++    return json_null;
++  }
++
++  /* null terminated the string. */
++  *data_end = '\0';
++
++  if (json_null != out_size) {
++    *out_size = size;
++  }
++
++  return data;
++}
++
++json_weak int json_write_pretty_get_value_size(const struct json_value_s *value,
++                                               size_t depth, size_t indent_size,
++                                               size_t newline_size,
++                                               size_t *size);
++
++json_weak int json_write_pretty_get_array_size(const struct json_array_s *array,
++                                               size_t depth, size_t indent_size,
++                                               size_t newline_size,
++                                               size_t *size);
++int json_write_pretty_get_array_size(const struct json_array_s *array,
++                                     size_t depth, size_t indent_size,
++                                     size_t newline_size, size_t *size) {
++  struct json_array_element_s *element;
++
++  *size += 1; /* '['. */
++
++  if (0 < array->length) {
++    /* if we have any elements we need to add a newline after our '['. */
++    *size += newline_size;
++
++    *size += array->length - 1; /* ','s seperate each element. */
++
++    for (element = array->start; json_null != element;
++         element = element->next) {
++      /* each element gets an indent. */
++      *size += (depth + 1) * indent_size;
++
++      if (json_write_pretty_get_value_size(element->value, depth + 1,
++                                           indent_size, newline_size, size)) {
++        /* value was malformed! */
++        return 1;
++      }
++
++      /* each element gets a newline too. */
++      *size += newline_size;
++    }
++
++    /* since we wrote out some elements, need to add a newline and indentation.
++     */
++    /* to the trailing ']'. */
++    *size += depth * indent_size;
++  }
++
++  *size += 1; /* ']'. */
++
++  return 0;
++}
++
++json_weak int
++json_write_pretty_get_object_size(const struct json_object_s *object,
++                                  size_t depth, size_t indent_size,
++                                  size_t newline_size, size_t *size);
++int json_write_pretty_get_object_size(const struct json_object_s *object,
++                                      size_t depth, size_t indent_size,
++                                      size_t newline_size, size_t *size) {
++  struct json_object_element_s *element;
++
++  *size += 1; /* '{'. */
++
++  if (0 < object->length) {
++    *size += newline_size; /* need a newline next. */
++
++    *size += object->length - 1; /* ','s seperate each element. */
++
++    for (element = object->start; json_null != element;
++         element = element->next) {
++      /* each element gets an indent and newline. */
++      *size += (depth + 1) * indent_size;
++      *size += newline_size;
++
++      if (json_write_get_string_size(element->name, size)) {
++        /* string was malformed! */
++        return 1;
++      }
++
++      *size += 3; /* seperate each name/value pair with " : ". */
++
++      if (json_write_pretty_get_value_size(element->value, depth + 1,
++                                           indent_size, newline_size, size)) {
++        /* value was malformed! */
++        return 1;
++      }
++    }
++
++    *size += depth * indent_size;
++  }
++
++  *size += 1; /* '}'. */
++
++  return 0;
++}
++
++json_weak int json_write_pretty_get_value_size(const struct json_value_s *value,
++                                               size_t depth, size_t indent_size,
++                                               size_t newline_size,
++                                               size_t *size);
++int json_write_pretty_get_value_size(const struct json_value_s *value,
++                                     size_t depth, size_t indent_size,
++                                     size_t newline_size, size_t *size) {
++  switch (value->type) {
++  default:
++    /* unknown value type found! */
++    return 1;
++  case json_type_number:
++    return json_write_get_number_size((struct json_number_s *)value->payload,
++                                      size);
++  case json_type_string:
++    return json_write_get_string_size((struct json_string_s *)value->payload,
++                                      size);
++  case json_type_array:
++    return json_write_pretty_get_array_size(
++        (struct json_array_s *)value->payload, depth, indent_size, newline_size,
++        size);
++  case json_type_object:
++    return json_write_pretty_get_object_size(
++        (struct json_object_s *)value->payload, depth, indent_size,
++        newline_size, size);
++  case json_type_true:
++    *size += 4; /* the string "true". */
++    return 0;
++  case json_type_false:
++    *size += 5; /* the string "false". */
++    return 0;
++  case json_type_null:
++    *size += 4; /* the string "null". */
++    return 0;
++  }
++}
++
++json_weak char *json_write_pretty_value(const struct json_value_s *value,
++                                        size_t depth, const char *indent,
++                                        const char *newline, char *data);
++
++json_weak char *json_write_pretty_array(const struct json_array_s *array,
++                                        size_t depth, const char *indent,
++                                        const char *newline, char *data);
++char *json_write_pretty_array(const struct json_array_s *array, size_t depth,
++                              const char *indent, const char *newline,
++                              char *data) {
++  size_t k, m;
++  struct json_array_element_s *element;
++
++  *data++ = '['; /* open the array. */
++
++  if (0 < array->length) {
++    for (k = 0; '\0' != newline[k]; k++) {
++      *data++ = newline[k];
++    }
++
++    for (element = array->start; json_null != element;
++         element = element->next) {
++      if (element != array->start) {
++        *data++ = ','; /* ','s seperate each element. */
++
++        for (k = 0; '\0' != newline[k]; k++) {
++          *data++ = newline[k];
++        }
++      }
++
++      for (k = 0; k < depth + 1; k++) {
++        for (m = 0; '\0' != indent[m]; m++) {
++          *data++ = indent[m];
++        }
++      }
++
++      data = json_write_pretty_value(element->value, depth + 1, indent, newline,
++                                     data);
++
++      if (json_null == data) {
++        /* value was malformed! */
++        return json_null;
++      }
++    }
++
++    for (k = 0; '\0' != newline[k]; k++) {
++      *data++ = newline[k];
++    }
++
++    for (k = 0; k < depth; k++) {
++      for (m = 0; '\0' != indent[m]; m++) {
++        *data++ = indent[m];
++      }
++    }
++  }
++
++  *data++ = ']'; /* close the array. */
++
++  return data;
++}
++
++json_weak char *json_write_pretty_object(const struct json_object_s *object,
++                                         size_t depth, const char *indent,
++                                         const char *newline, char *data);
++char *json_write_pretty_object(const struct json_object_s *object, size_t depth,
++                               const char *indent, const char *newline,
++                               char *data) {
++  size_t k, m;
++  struct json_object_element_s *element;
++
++  *data++ = '{'; /* open the object. */
++
++  if (0 < object->length) {
++    for (k = 0; '\0' != newline[k]; k++) {
++      *data++ = newline[k];
++    }
++
++    for (element = object->start; json_null != element;
++         element = element->next) {
++      if (element != object->start) {
++        *data++ = ','; /* ','s seperate each element. */
++
++        for (k = 0; '\0' != newline[k]; k++) {
++          *data++ = newline[k];
++        }
++      }
++
++      for (k = 0; k < depth + 1; k++) {
++        for (m = 0; '\0' != indent[m]; m++) {
++          *data++ = indent[m];
++        }
++      }
++
++      data = json_write_string(element->name, data);
++
++      if (json_null == data) {
++        /* string was malformed! */
++        return json_null;
++      }
++
++      /* " : "s seperate each name/value pair. */
++      *data++ = ' ';
++      *data++ = ':';
++      *data++ = ' ';
++
++      data = json_write_pretty_value(element->value, depth + 1, indent, newline,
++                                     data);
++
++      if (json_null == data) {
++        /* value was malformed! */
++        return json_null;
++      }
++    }
++
++    for (k = 0; '\0' != newline[k]; k++) {
++      *data++ = newline[k];
++    }
++
++    for (k = 0; k < depth; k++) {
++      for (m = 0; '\0' != indent[m]; m++) {
++        *data++ = indent[m];
++      }
++    }
++  }
++
++  *data++ = '}'; /* close the object. */
++
++  return data;
++}
++
++json_weak char *json_write_pretty_value(const struct json_value_s *value,
++                                        size_t depth, const char *indent,
++                                        const char *newline, char *data);
++char *json_write_pretty_value(const struct json_value_s *value, size_t depth,
++                              const char *indent, const char *newline,
++                              char *data) {
++  switch (value->type) {
++  default:
++    /* unknown value type found! */
++    return json_null;
++  case json_type_number:
++    return json_write_number((struct json_number_s *)value->payload, data);
++  case json_type_string:
++    return json_write_string((struct json_string_s *)value->payload, data);
++  case json_type_array:
++    return json_write_pretty_array((struct json_array_s *)value->payload, depth,
++                                   indent, newline, data);
++  case json_type_object:
++    return json_write_pretty_object((struct json_object_s *)value->payload,
++                                    depth, indent, newline, data);
++  case json_type_true:
++    data[0] = 't';
++    data[1] = 'r';
++    data[2] = 'u';
++    data[3] = 'e';
++    return data + 4;
++  case json_type_false:
++    data[0] = 'f';
++    data[1] = 'a';
++    data[2] = 'l';
++    data[3] = 's';
++    data[4] = 'e';
++    return data + 5;
++  case json_type_null:
++    data[0] = 'n';
++    data[1] = 'u';
++    data[2] = 'l';
++    data[3] = 'l';
++    return data + 4;
++  }
++}
++
++void *json_write_pretty(const struct json_value_s *value, const char *indent,
++                        const char *newline, size_t *out_size) {
++  size_t size = 0;
++  size_t indent_size = 0;
++  size_t newline_size = 0;
++  char *data = json_null;
++  char *data_end = json_null;
++
++  if (json_null == value) {
++    return json_null;
++  }
++
++  if (json_null == indent) {
++    indent = "  "; /* default to two spaces. */
++  }
++
++  if (json_null == newline) {
++    newline = "\n"; /* default to linux newlines. */
++  }
++
++  while ('\0' != indent[indent_size]) {
++    ++indent_size; /* skip non-null terminating characters. */
++  }
++
++  while ('\0' != newline[newline_size]) {
++    ++newline_size; /* skip non-null terminating characters. */
++  }
++
++  if (json_write_pretty_get_value_size(value, 0, indent_size, newline_size,
++                                       &size)) {
++    /* value was malformed! */
++    return json_null;
++  }
++
++  size += 1; /* for the '\0' null terminating character. */
++
++  data = (char *)malloc(size);
++
++  if (json_null == data) {
++    /* malloc failed! */
++    return json_null;
++  }
++
++  data_end = json_write_pretty_value(value, 0, indent, newline, data);
++
++  if (json_null == data_end) {
++    /* bad chi occurred! */
++    free(data);
++    return json_null;
++  }
++
++  /* null terminated the string. */
++  *data_end = '\0';
++
++  if (json_null != out_size) {
++    *out_size = size;
++  }
++
++  return data;
++}
++
++#if defined(__clang__)
++#pragma clang diagnostic pop
++#elif defined(_MSC_VER)
++#pragma warning(pop)
++#endif
++
++#endif /* SHEREDOM_JSON_H_INCLUDED. */
+diff --git a/src/swtpm_setup/swtpm_setup.c b/src/swtpm_setup/swtpm_setup.c
+index 96e8b9f..ade5e34 100644
+--- a/src/swtpm_setup/swtpm_setup.c
++++ b/src/swtpm_setup/swtpm_setup.c
+@@ -5,6 +5,7 @@
+  * Author: Stefan Berger, stefanb@linux.ibm.com
+  *
+  * Copyright (c) IBM Corporation, 2021
++ * Copyright (c) Monogon SE, 2024
+  */
+ 
+ #include "config.h"
+@@ -27,8 +28,7 @@
+ #include "glib/gstdio.h"
+ #include "glib/gprintf.h"
+ 
+-#include <glib-object.h>
+-#include <json-glib/json-glib.h>
++#include "json.h"
+ 
+ #include <libtpms/tpm_nvfilename.h>
+ 
+@@ -99,78 +99,112 @@ static int tpm_get_specs_and_attributes(struct swtpm *swtpm, gchar ***params)
+ {
+     int ret;
+     g_autofree gchar *json = NULL;
+-    JsonParser *jp = NULL;
+-    GError *error = NULL;
+-    JsonReader *jr = NULL;
+-    JsonNode *root;
+-    static const struct parse_rule {
+-         const char *node1;
+-         const char *node2;
+-         gboolean is_int;
+-         const char *optname;
+-    } parser_rules[7] = {
+-         {"TPMSpecification", "family", FALSE, "--tpm-spec-family"},
+-         {"TPMSpecification", "level", TRUE, "--tpm-spec-level"},
+-         {"TPMSpecification", "revision", TRUE, "--tpm-spec-revision"},
+-         {"TPMAttributes", "manufacturer", FALSE, "--tpm-manufacturer"},
+-         {"TPMAttributes", "model", FALSE, "--tpm-model"},
+-         {"TPMAttributes", "version", FALSE, "--tpm-version"},
+-         {NULL, NULL, FALSE, NULL},
+-    };
+-    size_t idx;
++    struct json_value_s *root = NULL;
++    struct json_object_s *obj = NULL;
++
++    *params = NULL;
+ 
+     ret = swtpm->cops->ctrl_get_tpm_specs_and_attrs(swtpm, &json);
+     if (ret != 0) {
+         logerr(gl_LOGFILE, "Could not get the TPM spec and attribute parameters.\n");
+-        return 1;
++        ret = 1;
++        goto error;
+     }
+ 
+-    jp = json_parser_new();
++    root = json_parse(json, strlen(json));
++    if (root == 0) {
++        logerr(gl_LOGFILE, "Could not parse JSON from TPM spec and attribute parameters.\n");
++        ret = 1;
++        goto error;
++    }
++    obj = json_value_as_object(root);
++    if (obj == NULL) {
++        logerr(gl_LOGFILE, "JSON root is not an object.\n");
++        ret = 1;
++        goto error;
++    }
+ 
+-    if (!json_parser_load_from_data(jp, json, -1, &error)) {
+-        logerr(gl_LOGFILE, "JSON parser failed: %s\n", error->message);
+-        g_error_free(error);
++    struct json_object_s *TPMSpecification = NULL;
++    struct json_object_s *TPMAttributes = NULL;
++    for (struct json_object_element_s *el = obj->start; el != NULL; el = el->next) {
++        if (strcmp(el->name->string, "TPMSpecification") == 0) {
++            TPMSpecification = json_value_as_object(el->value);
++            continue;
++        }
++        if (strcmp(el->name->string, "TPMAttributes") == 0) {
++            TPMAttributes = json_value_as_object(el->value);
++            continue;
++        }
++    }
++    if (TPMSpecification == NULL) {
++        logerr(gl_LOGFILE, "TPMSpecification not found in JSON.\n");
++        ret = 1;
++        goto error;
++    }
++    if (TPMAttributes == NULL) {
++        logerr(gl_LOGFILE, "TPMAttributes not found in JSON.\n");
++        ret = 1;
+         goto error;
+     }
+ 
+-    *params = NULL;
+-    root = json_parser_get_root(jp);
+-
+-    for (idx = 0; parser_rules[idx].node1 != NULL; idx++) {
+-        jr = json_reader_new(root);
+-        if (json_reader_read_member(jr, parser_rules[idx].node1) &&
+-            json_reader_read_member(jr, parser_rules[idx].node2)) {
+-            gchar *str;
+-
+-            if (parser_rules[idx].is_int)
+-                str = g_strdup_printf("%ld", (long)json_reader_get_int_value(jr));
+-            else
+-                str = g_strdup(json_reader_get_string_value(jr));
+-
+-            *params = concat_arrays(*params,
+-                                    (gchar*[]){
+-                                        g_strdup(parser_rules[idx].optname),
+-                                        str,
+-                                        NULL
+-                                    }, TRUE);
+-        } else {
+-            logerr(gl_LOGFILE, "Could not find [%s][%s] in '%s'\n",
+-                   parser_rules[idx].node1, parser_rules[idx].node2, json);
+-            ret = 1;
+-            break;
++    const char *spec_family = NULL;
++    const char *spec_level = NULL;
++    const char *spec_revision = NULL;
++    const char *attr_manufacturer = NULL;
++    const char *attr_model = NULL;
++    const char *attr_version = NULL;
++
++    for (struct json_object_element_s *el = TPMSpecification->start; el != NULL; el = el->next) {
++        if (strcmp(el->name->string, "family") == 0 && el->value->type == json_type_string) {
++            spec_family = json_value_as_string(el->value)->string;
++            continue;
++        }
++        if (strcmp(el->name->string, "level") == 0 && el->value->type == json_type_number) {
++            spec_level = json_value_as_number(el->value)->number;
++            continue;
++        }
++        if (strcmp(el->name->string, "revision") == 0 && el->value->type == json_type_number) {
++            spec_revision = json_value_as_number(el->value)->number;
++            continue;
++        }
++    }
++    for (struct json_object_element_s *el = TPMAttributes->start; el != NULL; el = el->next) {
++        if (strcmp(el->name->string, "manufacturer") == 0 && el->value->type == json_type_string) {
++            attr_manufacturer = json_value_as_string(el->value)->string;
++            continue;
++        }
++        if (strcmp(el->name->string, "model") == 0 && el->value->type == json_type_string) {
++            attr_model = json_value_as_string(el->value)->string;
++            continue;
++        }
++        if (strcmp(el->name->string, "version") == 0 && el->value->type == json_type_string) {
++            attr_version = json_value_as_string(el->value)->string;
++            continue;
+         }
+-        g_object_unref(jr);
+-        jr = NULL;
+     }
+ 
++    if (!spec_family) { logerr(gl_LOGFILE, "family not found in TPMSpecifiction.\n"); ret = 1; goto error; }
++    if (!spec_level) { logerr(gl_LOGFILE, "level not found in TPMSpecifiction.\n"); ret = 1; goto error; }
++    if (!spec_revision) { logerr(gl_LOGFILE, "revision not found in TPMSpecifiction.\n"); ret = 1; goto error; }
++    if (!attr_manufacturer) { logerr(gl_LOGFILE, "manufacturer not found in TPMAttributes.\n"); ret = 1; goto error; }
++    if (!attr_model) { logerr(gl_LOGFILE, "model not found in TPMAttributes.\n"); ret = 1; goto error; }
++    if (!attr_version) { logerr(gl_LOGFILE, "version not found in TPMAttributes.\n"); ret = 1; goto error; }
++
++    *params = concat_arrays(*params, (gchar*[]) {
++            g_strdup("--tpm-spec-family"), g_strdup(spec_family),
++            g_strdup("--tpm-spec-revision"), g_strdup(spec_revision),
++            g_strdup("--tpm-spec-level"), g_strdup(spec_level),
++            g_strdup("--tpm-manufacturer"), g_strdup(attr_manufacturer),
++            g_strdup("--tpm-model"), g_strdup(attr_model),
++            g_strdup("--tpm-version"), g_strdup(attr_version),
++            NULL }, TRUE);
++error:
+     if (ret) {
+         g_strfreev(*params);
+-        *params = NULL;
+-        g_object_unref(jr);
+     }
+-error:
+-    g_object_unref(jp);
+-
++    if (root) {
++        free(root);
++    }
+     return ret;
+ }
+ 
+-- 
+2.42.0
+
diff --git a/third_party/swtpm/patches/0004-bazel-support-implement.patch b/third_party/swtpm/patches/0004-bazel-support-implement.patch
new file mode 100644
index 0000000..15245c6
--- /dev/null
+++ b/third_party/swtpm/patches/0004-bazel-support-implement.patch
@@ -0,0 +1,212 @@
+From 3b2ea39444bf97d7847fdb1a3ca70f9d58ffe22a Mon Sep 17 00:00:00 2001
+From: Serge Bazanski <serge@monogon.tech>
+Date: Tue, 4 Jun 2024 15:10:02 +0200
+Subject: [PATCH 4/4] bazel support: implement
+
+---
+ .gitignore             |  2 -
+ BUILD.bazel            | 94 ++++++++++++++++++++++++++++++++++++++++++
+ WORKSPACE              |  0
+ include/config.h       |  8 ++++
+ include/swtpm.h        |  5 +++
+ src/swtpm/main.c       |  2 +-
+ src/utils/swtpm_conf.h | 22 ++++++++++
+ 7 files changed, 130 insertions(+), 3 deletions(-)
+ create mode 100644 BUILD.bazel
+ create mode 100644 WORKSPACE
+ create mode 100644 include/config.h
+ create mode 100644 include/swtpm.h
+ create mode 100644 src/utils/swtpm_conf.h
+
+diff --git a/.gitignore b/.gitignore
+index c669f06..9982dd0 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -35,7 +35,6 @@ Makefile
+ /m4/*
+ /.pc/*
+ /patches/*
+-/include/swtpm.h
+ /man/man3/*.3
+ /man/man5/*.5
+ /man/man8/*.8
+@@ -60,7 +59,6 @@ Makefile
+ /src/swtpm_ioctl/swtpm_ioctl
+ /src/swtpm_localca/swtpm_localca
+ /src/swtpm_setup/swtpm_setup
+-/src/utils/swtpm_conf.h
+ /test-driver
+ tests/*.log
+ tests/*.trs
+diff --git a/BUILD.bazel b/BUILD.bazel
+new file mode 100644
+index 0000000..acddc0e
+--- /dev/null
++++ b/BUILD.bazel
+@@ -0,0 +1,94 @@
++cc_binary(
++    name = "swtpm",
++    deps = [
++        "@libtpms//:libtpms_tpm2",
++        "@glib//glib",
++    ],
++    srcs = glob([
++        "src/swtpm/*.h",
++        "src/swtpm/*.c",
++        "src/utils/*.h",
++        "src/utils/*.c",
++        "include/*.h",
++        "include/swtpm/*.h",
++    ], [
++        # No CUSE support.
++        "src/swtpm/cuse_tpm.c",
++        # Only used in utils.
++        "src/utils/swtpm_utils.c",
++    ]),
++    copts = [
++        "-Iexternal/swtpm/include",
++        "-Iexternal/swtpm/include/swtpm",
++        "-Iexternal/swtpm/src/utils",
++    ],
++    visibility = [
++        "//visibility:public",
++    ],
++)
++
++cc_binary(
++    name = "swtpm_localca",
++    deps = [
++        "@libtpms//:libtpms_tpm2",
++        "@glib//glib",
++    ],
++    srcs = glob([
++        "src/swtpm_localca/*.h",
++        "src/swtpm_localca/*.c",
++        "include/*.h",
++        "include/swtpm/*.h",
++        "src/utils/*.h",
++        "src/utils/*.c",
++    ], []),
++    copts = [
++        "-Iexternal/swtpm/include",
++        "-Iexternal/swtpm/include/swtpm",
++        "-Iexternal/swtpm/src/utils",
++    ],
++    visibility = [
++        "//visibility:public",
++    ],
++)
++
++cc_binary(
++    name = "swtpm_setup",
++    deps = [
++        "@libtpms//:libtpms_tpm2",
++        "@glib//glib",
++    ],
++    srcs = glob([
++        "src/swtpm_setup/*.h",
++        "src/swtpm_setup/*.c",
++        "include/*.h",
++        "include/swtpm/*.h",
++        "src/utils/*.h",
++        "src/utils/*.c",
++    ], []),
++    copts = [
++        "-Iexternal/swtpm/include",
++        "-Iexternal/swtpm/include/swtpm",
++        "-Iexternal/swtpm/src/utils",
++    ],
++    visibility = [
++        "//visibility:public",
++    ],
++)
++
++cc_binary(
++    name = "swtpm_cert",
++    deps = [
++        "@boringssl//:ssl",
++    ],
++    srcs = glob([
++        "src/swtpm_cert/*.h",
++        "src/swtpm_cert/*.c",
++        "include/*.h",
++    ], []),
++    copts = [
++        "-Iexternal/swtpm/include",
++    ],
++    visibility = [
++        "//visibility:public",
++    ],
++)
+diff --git a/WORKSPACE b/WORKSPACE
+new file mode 100644
+index 0000000..e69de29
+diff --git a/include/config.h b/include/config.h
+new file mode 100644
+index 0000000..d3829d6
+--- /dev/null
++++ b/include/config.h
+@@ -0,0 +1,8 @@
++#pragma once
++#define _GNU_SOURCE
++
++#define VERSION "0.8.2-monogon"
++
++// A bunch of files in swtpm depend on stdint types but never include them.
++// Just inject them through here.
++#include <stdint.h>
+diff --git a/include/swtpm.h b/include/swtpm.h
+new file mode 100644
+index 0000000..2eddeec
+--- /dev/null
++++ b/include/swtpm.h
+@@ -0,0 +1,5 @@
++#pragma once
++
++#define SWTPM_VER_MAJOR 0
++#define SWTPM_VER_MINOR 8
++#define SWTPM_VER_MICRO 2
+diff --git a/src/swtpm/main.c b/src/swtpm/main.c
+index 4864e85..633ca33 100644
+--- a/src/swtpm/main.c
++++ b/src/swtpm/main.c
+@@ -83,7 +83,7 @@ int main(int argc, char **argv)
+     } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+         usage(stdout, argv[0]);
+     } else if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) {
+-        fprintf(stdout, "TPM emulator version %d.%d.%d, "
++        fprintf(stdout, "TPM emulator version %d.%d.%d-monogon, "
+                 "Copyright (c) 2014-2022 IBM Corp. and others\n",
+                 SWTPM_VER_MAJOR,
+                 SWTPM_VER_MINOR,
+diff --git a/src/utils/swtpm_conf.h b/src/utils/swtpm_conf.h
+new file mode 100644
+index 0000000..de8afdb
+--- /dev/null
++++ b/src/utils/swtpm_conf.h
+@@ -0,0 +1,22 @@
++/* SPDX-License-Identifier: BSD-3-Clause */
++/*
++ * swtpm_conf.h: Compile-time constants
++ *
++ * Author: Stefan Berger, stefanb@linux.ibm.com
++ *
++ * Copyright (c) IBM Corporation, 2021,2023
++ */
++
++#ifndef SWTPM_SETUP_CONF_H
++#define SWTPM_SETUP_CONF_H
++
++#define SWTPM_VER_MAJOR 0
++#define SWTPM_VER_MINOR 8
++#define SWTPM_VER_MICRO 2
++
++#define SYSCONFDIR "/unused"
++#define BINDIR "/unused"
++
++#define DEFAULT_PCR_BANKS "sha256"
++
++#endif /* SWTPM_SETUP_CONF_H */
+-- 
+2.42.0
+
diff --git a/third_party/swtpm/patches/BUILD.bazel b/third_party/swtpm/patches/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/swtpm/patches/BUILD.bazel