lib: conf: make it possible to parse files wrapped in {}, to allow standard JSON

A bit of refactoring was needed in order to avoid breaking as-section
loading, which expects the entire file to be an object or array and doesn't
parse it.

Fixes: #633
This commit is contained in:
George Kiagiadakis 2024-05-31 18:35:32 +03:00
parent 9847ca129a
commit a3d5c8088b

View file

@ -204,8 +204,12 @@ open_and_load_sections (WpConf * self, const gchar *path, GError ** error)
const gchar *as_section = NULL; const gchar *as_section = NULL;
if (self->properties) { if (self->properties) {
/* as-section="some.name" means that the entire file will be stored as a
single JSON value that will be accessible through wp_conf_get_section()
using "some.name" - no parsing is done; the value is expected to be a
container */
as_section = wp_properties_get (self->properties, "as-section"); as_section = wp_properties_get (self->properties, "as-section");
wp_info_object (self, "Opening as section %s", as_section); wp_debug_object (self, "Reading config file as single section: %s", as_section);
} }
g_autoptr (GMappedFile) file = g_mapped_file_new (path, FALSE, error); g_autoptr (GMappedFile) file = g_mapped_file_new (path, FALSE, error);
@ -220,12 +224,45 @@ open_and_load_sections (WpConf * self, const gchar *path, GError ** error)
return FALSE; return FALSE;
} }
g_autoptr (GArray) sections = g_array_new (FALSE, FALSE, sizeof (WpConfSection));
g_array_set_clear_func (sections, (GDestroyNotify) wp_conf_section_clear);
g_autoptr (WpSpaJson) json = wp_spa_json_new_wrap_stringn ( g_autoptr (WpSpaJson) json = wp_spa_json_new_wrap_stringn (
g_mapped_file_get_contents (file), g_mapped_file_get_length (file)); g_mapped_file_get_contents (file), g_mapped_file_get_length (file));
g_autoptr (WpSpaJsonParser) parser = wp_spa_json_parser_new_undefined (json);
g_autoptr (GArray) sections = g_array_new (FALSE, FALSE, sizeof (WpConfSection));
g_array_set_clear_func (sections, (GDestroyNotify) wp_conf_section_clear); if (as_section) {
WpConfSection section = { 0, };
if (!wp_spa_json_is_container (json)) {
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT,
"invalid single-section config file start (expected an object or array): %.*s",
(int) wp_spa_json_get_size (json), wp_spa_json_get_data (json));
return FALSE;
}
section.name = g_strdup (as_section);
section.value = g_steal_pointer (&json);
section.location = g_strdup (path);
g_array_append_val (sections, section);
}
else {
/* if !is_object && !is_string, but we can't test it this way because
is_string expects quotes and we want to support strings without quotes */
if (wp_spa_json_is_array (json) ||
wp_spa_json_is_int (json) ||
wp_spa_json_is_float (json) ||
wp_spa_json_is_boolean (json) ||
wp_spa_json_is_null (json))
{
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT,
"invalid config file start (expected an object or a section name): %.*s",
(int) wp_spa_json_get_size (json), wp_spa_json_get_data (json));
return FALSE;
}
g_autoptr (WpSpaJsonParser) parser = wp_spa_json_is_object (json) ?
wp_spa_json_parser_new_object (json) :
wp_spa_json_parser_new_undefined (json);
while (TRUE) { while (TRUE) {
g_auto (WpConfSection) section = { 0, }; g_auto (WpConfSection) section = { 0, };
@ -236,7 +273,8 @@ open_and_load_sections (WpConf * self, const gchar *path, GError ** error)
if (!tmp) if (!tmp)
break; break;
if ((wp_spa_json_is_container (tmp) && !as_section) || /* if !is_string, but we want to supprt strings without quotes */
if (wp_spa_json_is_container (tmp) ||
wp_spa_json_is_int (tmp) || wp_spa_json_is_int (tmp) ||
wp_spa_json_is_float (tmp) || wp_spa_json_is_float (tmp) ||
wp_spa_json_is_boolean (tmp) || wp_spa_json_is_boolean (tmp) ||
@ -248,12 +286,9 @@ open_and_load_sections (WpConf * self, const gchar *path, GError ** error)
return FALSE; return FALSE;
} }
if (as_section) {
wp_info_object (self, "Parsing object file as section %s", as_section);
section.name = g_strdup (as_section);
} else {
section.name = wp_spa_json_parse_string (tmp); section.name = wp_spa_json_parse_string (tmp);
g_clear_pointer (&tmp, wp_spa_json_unref); g_clear_pointer (&tmp, wp_spa_json_unref);
/* parse the section contents */ /* parse the section contents */
tmp = wp_spa_json_parser_get_json (parser); tmp = wp_spa_json_parser_get_json (parser);
if (!tmp) { if (!tmp) {
@ -261,13 +296,13 @@ open_and_load_sections (WpConf * self, const gchar *path, GError ** error)
"section '%s' has no value", section.name); "section '%s' has no value", section.name);
return FALSE; return FALSE;
} }
}
section.value = g_steal_pointer (&tmp); section.value = g_steal_pointer (&tmp);
section.location = g_strdup (path); section.location = g_strdup (path);
g_array_append_val (sections, section); g_array_append_val (sections, section);
memset (&section, 0, sizeof (section)); memset (&section, 0, sizeof (section));
} }
}
/* store the mapped file and the sections; note that the stored WpSpaJson /* store the mapped file and the sections; note that the stored WpSpaJson
still point to the data in the GMappedFile, so this is why we keep the still point to the data in the GMappedFile, so this is why we keep the