/* json-util.c - Helper funtions for the JSON based interface to gpgme
* Copyright (C) 2018, 2025 g10 Code GmbH
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include
#include
#include
#include
#include
#ifdef HAVE_LOCALE_H
#include
#endif
#include "json-common.h"
void
xoutofcore (const char *type)
{
gpg_error_t err = gpg_error_from_syserror ();
log_error ("%s failed: %s\n", type, gpg_strerror (err));
exit (2);
}
/* Free a NULL terminated array */
void
xfree_array (char **array)
{
if (array)
{
int idx;
for (idx = 0; array[idx]; idx++)
xfree (array[idx]);
xfree (array);
}
}
const char *
data_type_to_string (gpgme_data_type_t dt)
{
const char *s = "[?]";
switch (dt)
{
case GPGME_DATA_TYPE_INVALID : s = "invalid"; break;
case GPGME_DATA_TYPE_UNKNOWN : s = "unknown"; break;
case GPGME_DATA_TYPE_PGP_SIGNED : s = "PGP-signed"; break;
case GPGME_DATA_TYPE_PGP_SIGNATURE: s = "PGP-signature"; break;
case GPGME_DATA_TYPE_PGP_ENCRYPTED: s = "PGP-encrypted"; break;
case GPGME_DATA_TYPE_PGP_OTHER : s = "PGP"; break;
case GPGME_DATA_TYPE_PGP_KEY : s = "PGP-key"; break;
case GPGME_DATA_TYPE_CMS_SIGNED : s = "CMS-signed"; break;
case GPGME_DATA_TYPE_CMS_ENCRYPTED: s = "CMS-encrypted"; break;
case GPGME_DATA_TYPE_CMS_OTHER : s = "CMS"; break;
case GPGME_DATA_TYPE_X509_CERT : s = "X.509"; break;
case GPGME_DATA_TYPE_PKCS12 : s = "PKCS12"; break;
}
return s;
}
/* Create a JSON error object. If JSON is not NULL the error message
* is appended to that object. An existing "type" item will be replaced. */
static cjson_t
error_object_v (cjson_t json, const char *message, va_list arg_ptr,
gpg_error_t err)
{
cjson_t response, j_tmp;
char *msg;
msg = gpgrt_vbsprintf (message, arg_ptr);
if (!msg)
xoutofcore ("error_object");
response = json? json : xjson_CreateObject ();
if (!(j_tmp = cJSON_GetObjectItem (response, "type")))
xjson_AddStringToObject (response, "type", "error");
else /* Replace existing "type". */
{
j_tmp = cJSON_CreateString ("error");
if (!j_tmp)
xoutofcore ("cJSON_CreateString");
cJSON_ReplaceItemInObject (response, "type", j_tmp);
}
xjson_AddStringToObject (response, "msg", msg);
xfree (msg);
xjson_AddNumberToObject (response, "code", err);
return response;
}
/* Call cJSON_Print but terminate in case of an error. */
char *
xjson_Print (cjson_t object)
{
char *buf;
buf = cJSON_Print (object);
if (!buf)
xoutofcore ("cJSON_Print");
return buf;
}
/* Call cJSON_CreateObject but terminate in case of an error. */
cjson_t
xjson_CreateObject (void)
{
cjson_t json = cJSON_CreateObject ();
if (!json)
xoutofcore ("cJSON_CreateObject");
return json;
}
/* Call cJSON_CreateArray but terminate in case of an error. */
cjson_t
xjson_CreateArray (void)
{
cjson_t json = cJSON_CreateArray ();
if (!json)
xoutofcore ("cJSON_CreateArray");
return json;
}
/* Wrapper around cJSON_AddStringToObject which returns an gpg-error
* code instead of the NULL or the new object. */
gpg_error_t
cjson_AddStringToObject (cjson_t object, const char *name, const char *string)
{
if (!cJSON_AddStringToObject (object, name, string))
return gpg_error_from_syserror ();
return 0;
}
/* Same as cjson_AddStringToObject but prints an error message and
* terminates the process. */
void
xjson_AddStringToObject (cjson_t object, const char *name, const char *string)
{
if (!cJSON_AddStringToObject (object, name, string))
xoutofcore ("cJSON_AddStringToObject");
}
/* Same as xjson_AddStringToObject but ignores NULL strings */
void
xjson_AddStringToObject0 (cjson_t object, const char *name, const char *string)
{
if (!string)
return;
xjson_AddStringToObject (object, name, string);
}
/* Wrapper around cJSON_AddBoolToObject which terminates the process
* in case of an error. */
void
xjson_AddBoolToObject (cjson_t object, const char *name, int abool)
{
if (!cJSON_AddBoolToObject (object, name, abool))
xoutofcore ("cJSON_AddStringToObject");
return ;
}
/* Wrapper around cJSON_AddNumberToObject which terminates the process
* in case of an error. */
void
xjson_AddNumberToObject (cjson_t object, const char *name, double dbl)
{
if (!cJSON_AddNumberToObject (object, name, dbl))
xoutofcore ("cJSON_AddNumberToObject");
return ;
}
/* Wrapper around cJSON_AddItemToObject which terminates the process
* in case of an error. */
void
xjson_AddItemToObject (cjson_t object, const char *name, cjson_t item)
{
if (!cJSON_AddItemToObject (object, name, item))
xoutofcore ("cJSON_AddItemToObject");
return ;
}
cjson_t
error_object (cjson_t json, const char *message, ...)
{
cjson_t response;
va_list arg_ptr;
va_start (arg_ptr, message);
response = error_object_v (json, message, arg_ptr, 0);
va_end (arg_ptr);
return response;
}
cjson_t
gpg_error_object (cjson_t json, gpg_error_t err, const char *message, ...)
{
cjson_t response;
va_list arg_ptr;
va_start (arg_ptr, message);
response = error_object_v (json, message, arg_ptr, err);
va_end (arg_ptr);
return response;
}
char *
error_object_string (const char *message, ...)
{
cjson_t response;
va_list arg_ptr;
char *msg;
va_start (arg_ptr, message);
response = error_object_v (NULL, message, arg_ptr, 0);
va_end (arg_ptr);
msg = xjson_Print (response);
cJSON_Delete (response);
return msg;
}