|
Packit |
caecb6 |
/*
|
|
Packit |
caecb6 |
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* SPDX-License-Identifier: LGPL-2.1+
|
|
Packit |
caecb6 |
*/
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
#define G_LOG_DOMAIN "XbSilo"
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
#include "config.h"
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
#include <string.h>
|
|
Packit |
caecb6 |
#include <gio/gio.h>
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
#include "xb-string-private.h"
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/**
|
|
Packit |
caecb6 |
* xb_string_replace: (skip)
|
|
Packit |
caecb6 |
* @str: The #GString to operate on
|
|
Packit |
caecb6 |
* @search: The text to search for
|
|
Packit |
caecb6 |
* @replace: The text to use for substitutions
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Performs multiple search and replace operations on the given string.
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Returns: the number of replacements done, or 0 if @search is not found.
|
|
Packit |
caecb6 |
**/
|
|
Packit |
caecb6 |
guint
|
|
Packit |
caecb6 |
xb_string_replace (GString *str, const gchar *search, const gchar *replace)
|
|
Packit |
caecb6 |
{
|
|
Packit |
caecb6 |
gchar *tmp;
|
|
Packit |
caecb6 |
guint count = 0;
|
|
Packit |
caecb6 |
gsize search_idx = 0;
|
|
Packit |
caecb6 |
gsize replace_len;
|
|
Packit |
caecb6 |
gsize search_len;
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
g_return_val_if_fail (str != NULL, 0);
|
|
Packit |
caecb6 |
g_return_val_if_fail (search != NULL, 0);
|
|
Packit |
caecb6 |
g_return_val_if_fail (replace != NULL, 0);
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/* nothing to do */
|
|
Packit |
caecb6 |
if (str->len == 0)
|
|
Packit |
caecb6 |
return 0;
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
search_len = strlen (search);
|
|
Packit |
caecb6 |
replace_len = strlen (replace);
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
do {
|
|
Packit |
caecb6 |
tmp = g_strstr_len (str->str + search_idx, -1, search);
|
|
Packit |
caecb6 |
if (tmp == NULL)
|
|
Packit |
caecb6 |
break;
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/* advance the counter in case @replace contains @search */
|
|
Packit |
caecb6 |
search_idx = (gsize) (tmp - str->str);
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/* reallocate the string if required */
|
|
Packit |
caecb6 |
if (search_len > replace_len) {
|
|
Packit |
caecb6 |
g_string_erase (str,
|
|
Packit |
caecb6 |
(gssize) search_idx,
|
|
Packit |
caecb6 |
(gssize) (search_len - replace_len));
|
|
Packit |
caecb6 |
memcpy (tmp, replace, replace_len);
|
|
Packit |
caecb6 |
} else if (search_len < replace_len) {
|
|
Packit |
caecb6 |
g_string_insert_len (str,
|
|
Packit |
caecb6 |
(gssize) search_idx,
|
|
Packit |
caecb6 |
replace,
|
|
Packit |
caecb6 |
(gssize) (replace_len - search_len));
|
|
Packit |
caecb6 |
/* we have to treat this specially as it could have
|
|
Packit |
caecb6 |
* been reallocated when the insertion happened */
|
|
Packit |
caecb6 |
memcpy (str->str + search_idx, replace, replace_len);
|
|
Packit |
caecb6 |
} else {
|
|
Packit |
caecb6 |
/* just memcmp in the new string */
|
|
Packit |
caecb6 |
memcpy (tmp, replace, replace_len);
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
search_idx += replace_len;
|
|
Packit |
caecb6 |
count++;
|
|
Packit |
caecb6 |
} while (TRUE);
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
return count;
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/**
|
|
Packit |
caecb6 |
* xb_string_append_union:
|
|
Packit |
caecb6 |
* @xpath: The #GString to operate on
|
|
Packit |
caecb6 |
* @fmt: The format string
|
|
Packit |
caecb6 |
* @...: varargs for @fmt
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Appends an XPath query into the string, automatically adding the union
|
|
Packit |
caecb6 |
* operator (`|`) if required.
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Since: 0.1.2
|
|
Packit |
caecb6 |
**/
|
|
Packit |
caecb6 |
void
|
|
Packit |
caecb6 |
xb_string_append_union (GString *xpath, const gchar *fmt, ...)
|
|
Packit |
caecb6 |
{
|
|
Packit |
caecb6 |
va_list args;
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
g_return_if_fail (xpath != NULL);
|
|
Packit |
caecb6 |
g_return_if_fail (fmt != NULL);
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
if (xpath->len > 0)
|
|
Packit |
caecb6 |
g_string_append (xpath, "|");
|
|
Packit |
caecb6 |
va_start (args, fmt);
|
|
Packit |
caecb6 |
#pragma clang diagnostic ignored "-Wformat-nonliteral"
|
|
Packit |
caecb6 |
g_string_append_vprintf (xpath, fmt, args);
|
|
Packit |
caecb6 |
#pragma clang diagnostic pop
|
|
Packit |
caecb6 |
va_end (args);
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/**
|
|
Packit |
caecb6 |
* xb_string_contains: (skip)
|
|
Packit |
caecb6 |
* @text: The source string
|
|
Packit |
caecb6 |
* @search: The text to search for
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Searches for a substring match.
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Returns: %TRUE if the string @search is contained in @text.
|
|
Packit |
caecb6 |
**/
|
|
Packit |
caecb6 |
gboolean
|
|
Packit |
caecb6 |
xb_string_contains (const gchar *text, const gchar *search)
|
|
Packit |
caecb6 |
{
|
|
Packit |
caecb6 |
guint search_sz;
|
|
Packit |
caecb6 |
guint text_sz;
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/* can't possibly match */
|
|
Packit |
caecb6 |
if (text == NULL || search == NULL)
|
|
Packit |
caecb6 |
return FALSE;
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/* sanity check */
|
|
Packit |
caecb6 |
text_sz = strlen (text);
|
|
Packit |
caecb6 |
search_sz = strlen (search);
|
|
Packit |
caecb6 |
if (search_sz > text_sz)
|
|
Packit |
caecb6 |
return FALSE;
|
|
Packit |
caecb6 |
for (guint i = 0; i < text_sz - search_sz + 1; i++) {
|
|
Packit |
caecb6 |
if (strncmp (text + i, search, search_sz) == 0)
|
|
Packit |
caecb6 |
return TRUE;
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
return FALSE;
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/**
|
|
Packit |
caecb6 |
* xb_string_search: (skip)
|
|
Packit |
caecb6 |
* @text: The source string
|
|
Packit |
caecb6 |
* @search: The text to search for
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Searches for a fuzzy search match, ignoring search matches that are not at
|
|
Packit |
caecb6 |
* the start of the token.
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Returns: %TRUE if the string @search is contained in @text.
|
|
Packit |
caecb6 |
**/
|
|
Packit |
caecb6 |
gboolean
|
|
Packit |
caecb6 |
xb_string_search (const gchar *text, const gchar *search)
|
|
Packit |
caecb6 |
{
|
|
Packit |
caecb6 |
guint search_sz;
|
|
Packit |
caecb6 |
guint text_sz;
|
|
Packit |
caecb6 |
gboolean is_sow = TRUE;
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/* can't possibly match */
|
|
Packit |
caecb6 |
if (text == NULL || text[0] == '\0')
|
|
Packit |
caecb6 |
return FALSE;
|
|
Packit |
caecb6 |
if (search == NULL || search[0] == '\0')
|
|
Packit |
caecb6 |
return FALSE;
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/* sanity check */
|
|
Packit |
caecb6 |
text_sz = strlen (text);
|
|
Packit |
caecb6 |
search_sz = strlen (search);
|
|
Packit |
caecb6 |
if (search_sz > text_sz)
|
|
Packit |
caecb6 |
return FALSE;
|
|
Packit |
caecb6 |
for (guint i = 0; i < text_sz - search_sz + 1; i++) {
|
|
Packit |
caecb6 |
if (!g_ascii_isalnum (text[i])) {
|
|
Packit |
caecb6 |
is_sow = TRUE;
|
|
Packit |
caecb6 |
continue;
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
if (!is_sow)
|
|
Packit |
caecb6 |
continue;
|
|
Packit |
caecb6 |
if (g_ascii_strncasecmp (text + i, search, search_sz) == 0)
|
|
Packit |
caecb6 |
return TRUE;
|
|
Packit |
caecb6 |
/* no longer the start of the word */
|
|
Packit |
caecb6 |
is_sow = FALSE;
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
return FALSE;
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/**
|
|
Packit |
caecb6 |
* xb_string_escape:
|
|
Packit |
caecb6 |
* @str: string, e.g. `app/org.gnome.ghex/x86_64/stable`
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Escapes XPath control sequences such as newlines, tabs, and forward slashes.
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Returns: (transfer full): new string that is safe to use for queries
|
|
Packit |
caecb6 |
*
|
|
Packit |
caecb6 |
* Since: 0.1.2
|
|
Packit |
caecb6 |
**/
|
|
Packit |
caecb6 |
gchar *
|
|
Packit |
caecb6 |
xb_string_escape (const gchar *str)
|
|
Packit |
caecb6 |
{
|
|
Packit |
caecb6 |
GString *tmp = g_string_new (str);
|
|
Packit |
caecb6 |
xb_string_replace (tmp, "/", "\\/");
|
|
Packit |
caecb6 |
xb_string_replace (tmp, "\t", "\\t");
|
|
Packit |
caecb6 |
xb_string_replace (tmp, "\n", "\\n");
|
|
Packit |
caecb6 |
return g_string_free (tmp, FALSE);
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
gchar *
|
|
Packit |
caecb6 |
xb_string_xml_escape (const gchar *str)
|
|
Packit |
caecb6 |
{
|
|
Packit |
caecb6 |
GString *tmp = g_string_new (str);
|
|
Packit |
caecb6 |
xb_string_replace (tmp, "&", "&");
|
|
Packit |
caecb6 |
xb_string_replace (tmp, "<", "<");
|
|
Packit |
caecb6 |
xb_string_replace (tmp, ">", ">");
|
|
Packit |
caecb6 |
xb_string_replace (tmp, "\"", """);
|
|
Packit |
caecb6 |
return g_string_free (tmp, FALSE);
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
/* private */
|
|
Packit |
caecb6 |
gboolean
|
|
Packit |
caecb6 |
xb_string_isspace (const gchar *str, gssize strsz)
|
|
Packit |
caecb6 |
{
|
|
Packit |
caecb6 |
gsize strsz_safe;
|
|
Packit |
caecb6 |
if (str == NULL)
|
|
Packit |
caecb6 |
return TRUE;
|
|
Packit |
caecb6 |
strsz_safe = strsz >= 0 ? (gsize) strsz : strlen (str);
|
|
Packit |
caecb6 |
for (gsize i = 0; i < strsz_safe; i++) {
|
|
Packit |
caecb6 |
if (!g_ascii_isspace (str[i]))
|
|
Packit |
caecb6 |
return FALSE;
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
return TRUE;
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
void
|
|
Packit |
caecb6 |
xb_guid_compute_for_data (XbGuid *out, const guint8 *buf, gsize bufsz)
|
|
Packit |
caecb6 |
{
|
|
Packit |
caecb6 |
guint8 buf_tmp[20] = { 0x0 };
|
|
Packit |
caecb6 |
gsize buf_tmpsz = sizeof(buf_tmp);
|
|
Packit |
caecb6 |
g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA1);
|
|
Packit |
caecb6 |
if (buf != NULL && bufsz != 0)
|
|
Packit |
caecb6 |
g_checksum_update (checksum, (const guchar *) buf, bufsz);
|
|
Packit |
caecb6 |
g_checksum_get_digest (checksum, buf_tmp, &buf_tmpsz);
|
|
Packit |
caecb6 |
memcpy (out, buf_tmp, sizeof(XbGuid));
|
|
Packit |
caecb6 |
}
|
|
Packit |
caecb6 |
|
|
Packit |
caecb6 |
gchar *
|
|
Packit |
caecb6 |
xb_guid_to_string (XbGuid *guid)
|
|
Packit |
caecb6 |
{
|
|
Packit |
caecb6 |
return g_strdup_printf ("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
|
|
Packit |
caecb6 |
(guint) GUINT32_TO_BE (guid->tlo),
|
|
Packit |
caecb6 |
(guint) GUINT16_TO_BE (guid->tmi),
|
|
Packit |
caecb6 |
(guint) GUINT16_TO_BE (guid->thi),
|
|
Packit |
caecb6 |
(guint) GUINT16_TO_BE (guid->clo),
|
|
Packit |
caecb6 |
guid->nde[0], guid->nde[1],
|
|
Packit |
caecb6 |
guid->nde[2], guid->nde[3],
|
|
Packit |
caecb6 |
guid->nde[4], guid->nde[5]);
|
|
Packit |
caecb6 |
}
|