libnm: cleanup _nm_utils_hexstr2bin*() helper

Add 3 variants of _nm_utils_hexstr2bin*():

  - _nm_utils_hexstr2bin_full(), which takes a preallocated
    buffer and fills it.
  - _nm_utils_hexstr2bin_alloc() which returns a malloc'ed
    buffer
  - _nm_utils_hexstr2bin_buf(), which fills a preallocated
    buffer of a specific size.
This commit is contained in:
Thomas Haller
2018-09-27 16:29:55 +02:00
parent b537c0388a
commit be6c7fa5f6
3 changed files with 105 additions and 36 deletions

View File

@@ -214,11 +214,23 @@ const char *nm_utils_hwaddr_ntoa_buf (gconstpointer addr, gsize addr_len, gboole
char *_nm_utils_bin2hexstr_full (gconstpointer addr, gsize length, const char delimiter, gboolean upper_case, char *out); char *_nm_utils_bin2hexstr_full (gconstpointer addr, gsize length, const char delimiter, gboolean upper_case, char *out);
guint8 *_nm_utils_hexstr2bin_full (const char *asc, guint8 *_nm_utils_hexstr2bin_full (const char *hexstr,
gboolean allow_0x_prefix,
gboolean delimiter_required, gboolean delimiter_required,
const char *delimiter_candidates, const char *delimiter_candidates,
gsize required_len,
guint8 *buffer, guint8 *buffer,
gsize buffer_length, gsize buffer_len,
gsize *out_len);
#define _nm_utils_hexstr2bin_buf(hexstr, allow_0x_prefix, delimiter_required, delimiter_candidates, buffer) \
_nm_utils_hexstr2bin_full ((hexstr), (allow_0x_prefix), (delimiter_required), (delimiter_candidates), G_N_ELEMENTS (buffer), (buffer), G_N_ELEMENTS (buffer), NULL)
guint8 *_nm_utils_hexstr2bin_alloc (const char *hexstr,
gboolean allow_0x_prefix,
gboolean delimiter_required,
const char *delimiter_candidates,
gsize required_len,
gsize *out_len); gsize *out_len);
GSList * _nm_utils_hash_values_to_slist (GHashTable *hash); GSList * _nm_utils_hash_values_to_slist (GHashTable *hash);

View File

@@ -3527,60 +3527,68 @@ nm_utils_hwaddr_len (int type)
} }
guint8 * guint8 *
_nm_utils_hexstr2bin_full (const char *asc, _nm_utils_hexstr2bin_full (const char *hexstr,
gboolean allow_0x_prefix,
gboolean delimiter_required, gboolean delimiter_required,
const char *delimiter_candidates, const char *delimiter_candidates,
gsize required_len,
guint8 *buffer, guint8 *buffer,
gsize buffer_length, gsize buffer_len,
gsize *out_len) gsize *out_len)
{ {
const char *in = asc; const char *in = hexstr;
guint8 *out = buffer; guint8 *out = buffer;
gboolean delimiter_has = TRUE; gboolean delimiter_has = TRUE;
guint8 delimiter = '\0'; guint8 delimiter = '\0';
gsize len;
nm_assert (asc); nm_assert (hexstr);
nm_assert (buffer); nm_assert (buffer);
nm_assert (buffer_length); nm_assert (required_len > 0 || out_len);
nm_assert (out_len);
if ( allow_0x_prefix
&& in[0] == '0'
&& in[1] == 'x')
in += 2;
while (TRUE) { while (TRUE) {
const guint8 d1 = in[0]; const guint8 d1 = in[0];
guint8 d2; guint8 d2;
int i1, i2;
if (!g_ascii_isxdigit (d1)) i1 = nm_utils_hexchar_to_int (d1);
return NULL; if (i1 < 0)
goto fail;
#define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - ('A' - 10))
/* If there's no leading zero (ie "aa:b:cc") then fake it */ /* If there's no leading zero (ie "aa:b:cc") then fake it */
d2 = in[1]; d2 = in[1];
if (d2 && g_ascii_isxdigit (d2)) { if ( d2
*out++ = (HEXVAL (d1) << 4) + HEXVAL (d2); && (i2 = nm_utils_hexchar_to_int (d2)) >= 0) {
*out++ = (i1 << 4) + i2;
d2 = in[2]; d2 = in[2];
if (!d2) if (!d2)
break; break;
in += 2; in += 2;
} else { } else {
/* Fake leading zero */ /* Fake leading zero */
*out++ = HEXVAL (d1); *out++ = i1;
if (!d2) { if (!d2) {
if (!delimiter_has) { if (!delimiter_has) {
/* when using no delimiter, there must be pairs of hex chars */ /* when using no delimiter, there must be pairs of hex chars */
return NULL; goto fail;
} }
break; break;
} }
in += 1; in += 1;
} }
if (--buffer_length == 0) if (--buffer_len == 0)
return NULL; goto fail;
if (delimiter_has) { if (delimiter_has) {
if (d2 != delimiter) { if (d2 != delimiter) {
if (delimiter) if (delimiter)
return NULL; goto fail;
if (delimiter_candidates) { if (delimiter_candidates) {
while (delimiter_candidates[0]) { while (delimiter_candidates[0]) {
if (delimiter_candidates++[0] == d2) if (delimiter_candidates++[0] == d2)
@@ -3589,7 +3597,7 @@ _nm_utils_hexstr2bin_full (const char *asc,
} }
if (!delimiter) { if (!delimiter) {
if (delimiter_required) if (delimiter_required)
return NULL; goto fail;
delimiter_has = FALSE; delimiter_has = FALSE;
continue; continue;
} }
@@ -3598,11 +3606,66 @@ _nm_utils_hexstr2bin_full (const char *asc,
} }
} }
*out_len = out - buffer; len = out - buffer;
if ( required_len == 0
|| len == required_len) {
NM_SET_OUT (out_len, len);
return buffer; return buffer;
} }
#define hwaddr_aton(asc, buffer, buffer_length, out_len) _nm_utils_hexstr2bin_full ((asc), TRUE, ":-", (buffer), (buffer_length), (out_len)) fail:
NM_SET_OUT (out_len, 0);
return NULL;
}
guint8 *
_nm_utils_hexstr2bin_alloc (const char *hexstr,
gboolean allow_0x_prefix,
gboolean delimiter_required,
const char *delimiter_candidates,
gsize required_len,
gsize *out_len)
{
guint8 *buffer;
gsize buffer_len, len;
g_return_val_if_fail (hexstr, NULL);
nm_assert (required_len > 0 || out_len);
if ( allow_0x_prefix
&& hexstr[0] == '0'
&& hexstr[1] == 'x')
hexstr += 2;
if (!hexstr[0])
goto fail;
if (required_len > 0)
buffer_len = required_len;
else
buffer_len = strlen (hexstr) / 2 + 3;
buffer = g_malloc (buffer_len);
if (_nm_utils_hexstr2bin_full (hexstr,
FALSE,
delimiter_required,
delimiter_candidates,
required_len,
buffer,
buffer_len,
&len)) {
NM_SET_OUT (out_len, len);
return buffer;
}
g_free (buffer);
fail:
NM_SET_OUT (out_len, 0);
return NULL;
}
/** /**
* nm_utils_hexstr2bin: * nm_utils_hexstr2bin:
@@ -3619,23 +3682,17 @@ GBytes *
nm_utils_hexstr2bin (const char *hex) nm_utils_hexstr2bin (const char *hex)
{ {
guint8 *buffer; guint8 *buffer;
gsize buffer_length, len; gsize len;
g_return_val_if_fail (hex != NULL, NULL); buffer = _nm_utils_hexstr2bin_alloc (hex, TRUE, FALSE, ":", 0, &len);
if (!buffer)
if (hex[0] == '0' && hex[1] == 'x')
hex += 2;
buffer_length = strlen (hex) / 2 + 3;
buffer = g_malloc (buffer_length);
if (!_nm_utils_hexstr2bin_full (hex, FALSE, ":", buffer, buffer_length, &len)) {
g_free (buffer);
return NULL; return NULL;
}
buffer = g_realloc (buffer, len); buffer = g_realloc (buffer, len);
return g_bytes_new_take (buffer, len); return g_bytes_new_take (buffer, len);
} }
#define hwaddr_aton(asc, buffer, buffer_len, out_len) _nm_utils_hexstr2bin_full ((asc), FALSE, TRUE, ":-", 0, (buffer), (buffer_len), (out_len))
/** /**
* nm_utils_hwaddr_atoba: * nm_utils_hwaddr_atoba:
* @asc: the ASCII representation of a hardware address * @asc: the ASCII representation of a hardware address
@@ -4514,7 +4571,7 @@ _nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin)
return TRUE; return TRUE;
} }
if (_nm_utils_hexstr2bin_full (duid, FALSE, ":", duid_arr, sizeof (duid_arr), &duid_len)) { if (_nm_utils_hexstr2bin_full (duid, FALSE, FALSE, ":", 0, duid_arr, sizeof (duid_arr), &duid_len)) {
/* MAX DUID length is 128 octects + the type code (2 octects). */ /* MAX DUID length is 128 octects + the type code (2 octects). */
if ( duid_len > 2 if ( duid_len > 2
&& duid_len <= (128 + 2)) { && duid_len <= (128 + 2)) {

View File

@@ -189,7 +189,7 @@ _secret_password_raw_to_bytes (const char *ifcfg_key,
password_raw += 2; password_raw += 2;
secret = nm_secret_buf_new (strlen (password_raw) / 2 + 3); secret = nm_secret_buf_new (strlen (password_raw) / 2 + 3);
if (!_nm_utils_hexstr2bin_full (password_raw, FALSE, ":", secret->bin, secret->len, &len)) { if (!_nm_utils_hexstr2bin_full (password_raw, FALSE, FALSE, ":", 0, secret->bin, secret->len, &len)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid hex password in %s", "Invalid hex password in %s",
ifcfg_key); ifcfg_key);