Blame shared/nm-glib-aux/nm-json-aux.c

Packit Service b23acc
// SPDX-License-Identifier: LGPL-2.1+
Packit Service b23acc
/*
Packit Service b23acc
 * Copyright (C) 2019 Red Hat, Inc.
Packit Service b23acc
 */
Packit Service b23acc
Packit Service b23acc
#include "nm-default.h"
Packit Service b23acc
Packit Service b23acc
#include "nm-json-aux.h"
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_gstr_append_string_len (GString *gstr,
Packit Service b23acc
                         const char *str,
Packit Service b23acc
                         gsize len)
Packit Service b23acc
{
Packit Service b23acc
	g_string_append_c (gstr, '\"');
Packit Service b23acc
Packit Service b23acc
	while (len > 0) {
Packit Service b23acc
		gsize n;
Packit Service b23acc
		const char *end;
Packit Service b23acc
		gboolean valid;
Packit Service b23acc
Packit Service b23acc
		nm_assert (len > 0);
Packit Service b23acc
Packit Service b23acc
		valid = g_utf8_validate (str, len, &end;;
Packit Service b23acc
Packit Service b23acc
		nm_assert (   end
Packit Service b23acc
		           && end >= str
Packit Service b23acc
		           && end <= &str[len]);
Packit Service b23acc
Packit Service b23acc
		if (end > str) {
Packit Service b23acc
			const char *s;
Packit Service b23acc
Packit Service b23acc
			for (s = str; s < end; s++) {
Packit Service b23acc
				nm_assert (s[0] != '\0');
Packit Service b23acc
Packit Service b23acc
				if (s[0] < 0x20) {
Packit Service b23acc
					const char *text;
Packit Service b23acc
Packit Service b23acc
					switch (s[0]) {
Packit Service b23acc
					case '\\': text = "\\\\"; break;
Packit Service b23acc
					case '\"': text = "\\\""; break;
Packit Service b23acc
					case '\b': text = "\\b";  break;
Packit Service b23acc
					case '\f': text = "\\f";  break;
Packit Service b23acc
					case '\n': text = "\\n";  break;
Packit Service b23acc
					case '\r': text = "\\r";  break;
Packit Service b23acc
					case '\t': text = "\\t";  break;
Packit Service b23acc
					default:
Packit Service b23acc
						g_string_append_printf (gstr, "\\u%04X", (guint) s[0]);
Packit Service b23acc
						continue;
Packit Service b23acc
					}
Packit Service b23acc
					g_string_append (gstr, text);
Packit Service b23acc
					continue;
Packit Service b23acc
				}
Packit Service b23acc
Packit Service b23acc
				if (NM_IN_SET (s[0], '\\', '\"'))
Packit Service b23acc
					g_string_append_c (gstr, '\\');
Packit Service b23acc
				g_string_append_c (gstr, s[0]);
Packit Service b23acc
			}
Packit Service b23acc
		} else
Packit Service b23acc
			nm_assert (!valid);
Packit Service b23acc
Packit Service b23acc
		if (valid) {
Packit Service b23acc
			nm_assert (end == &str[len]);
Packit Service b23acc
			break;
Packit Service b23acc
		}
Packit Service b23acc
Packit Service b23acc
		nm_assert (end < &str[len]);
Packit Service b23acc
Packit Service b23acc
		if (end[0] == '\0') {
Packit Service b23acc
			/* there is a NUL byte in the string. Technically this is valid UTF-8, so we
Packit Service b23acc
			 * encode it there. However, this will likely result in a truncated string when
Packit Service b23acc
			 * parsing. */
Packit Service b23acc
			g_string_append (gstr, "\\u0000");
Packit Service b23acc
		} else {
Packit Service b23acc
			/* the character is not valid UTF-8. There is nothing we can do about it, because
Packit Service b23acc
			 * JSON can only contain UTF-8 and even the escape sequences can only escape Unicode
Packit Service b23acc
			 * codepoints (but not binary).
Packit Service b23acc
			 *
Packit Service b23acc
			 * The argument is not a a string (in any known encoding), hence we cannot represent
Packit Service b23acc
			 * it as a JSON string (which are unicode strings).
Packit Service b23acc
			 *
Packit Service b23acc
			 * Print an underscore instead of the invalid char :) */
Packit Service b23acc
			g_string_append_c (gstr, '_');
Packit Service b23acc
		}
Packit Service b23acc
Packit Service b23acc
		n = str - end;
Packit Service b23acc
		nm_assert (n < len);
Packit Service b23acc
		n++;
Packit Service b23acc
		str += n;
Packit Service b23acc
		len -= n;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	g_string_append_c (gstr, '\"');
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_json_aux_gstr_append_string_len (GString *gstr,
Packit Service b23acc
                                    const char *str,
Packit Service b23acc
                                    gsize n)
Packit Service b23acc
{
Packit Service b23acc
	g_return_if_fail (gstr);
Packit Service b23acc
Packit Service b23acc
	_gstr_append_string_len (gstr, str, n);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_json_aux_gstr_append_string (GString *gstr,
Packit Service b23acc
                                const char *str)
Packit Service b23acc
{
Packit Service b23acc
	g_return_if_fail (gstr);
Packit Service b23acc
Packit Service b23acc
	if (!str)
Packit Service b23acc
		g_string_append (gstr, "null");
Packit Service b23acc
	else
Packit Service b23acc
		_gstr_append_string_len (gstr, str, strlen (str));
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_json_aux_gstr_append_obj_name (GString *gstr,
Packit Service b23acc
                                  const char *key,
Packit Service b23acc
                                  char start_container)
Packit Service b23acc
{
Packit Service b23acc
	g_return_if_fail (gstr);
Packit Service b23acc
	g_return_if_fail (key);
Packit Service b23acc
Packit Service b23acc
	nm_json_aux_gstr_append_string (gstr, key);
Packit Service b23acc
Packit Service b23acc
	if (start_container != '\0') {
Packit Service b23acc
		nm_assert (NM_IN_SET (start_container, '[', '{'));
Packit Service b23acc
		g_string_append_printf (gstr, ": %c ", start_container);
Packit Service b23acc
	} else
Packit Service b23acc
		g_string_append (gstr, ": ");
Packit Service b23acc
}