[PATCH] libosmocore[master]: utils: add osmo_is_hexstr(), add unit test

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Sat Oct 7 03:13:09 UTC 2017


Review at  https://gerrit.osmocom.org/4159

utils: add osmo_is_hexstr(), add unit test

Will be used by OsmoHLR to validate VTY and CTRL input.

Change-Id: Idf75946eb0a84e145adad13fc7c78bb7a267aa0a
---
M include/osmocom/core/utils.h
M src/utils.c
M tests/utils/utils_test.c
M tests/utils/utils_test.ok
4 files changed, 130 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/59/4159/1

diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h
index 855e653..5f41213 100644
--- a/include/osmocom/core/utils.h
+++ b/include/osmocom/core/utils.h
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <stdbool.h>
+
 #include <osmocom/core/backtrace.h>
 #include <osmocom/core/talloc.h>
 
@@ -89,4 +91,7 @@
 
 size_t osmo_strlcpy(char *dst, const char *src, size_t siz);
 
+bool osmo_is_hexstr(const char *str, int min_digits, int max_digits,
+		    bool require_even);
+
 /*! @} */
diff --git a/src/utils.c b/src/utils.c
index 1c176f8..a3d6653 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -375,4 +375,35 @@
 	return ret;
 }
 
+/*! Validate that a given string is a hex string within given size limits.
+ * Note that each hex digit amounts to a nibble, so if checking for a hex
+ * string to result in N bytes, pass amount of digits as 2*N.
+ * \param str  A nul-terminated string to validate, or NULL.
+ * \param min_digits  least permitted amount of digits.
+ * \param max_digits  most permitted amount of digits.
+ * \param require_even  if true, require an even amount of digits.
+ * \returns true when the hex_str contains only hexadecimal digits (no
+ *          whitespace) and matches the requested length; also true
+ *          when min_digits <= 0 and str is NULL.
+ */
+bool osmo_is_hexstr(const char *str, int min_digits, int max_digits,
+		    bool require_even)
+{
+	int len;
+	/* Use unsigned char * to avoid a compiler warning of
+	 * "error: array subscript has type 'char' [-Werror=char-subscripts]" */
+	const unsigned char *pos = (const unsigned char *)str;
+	for (len = 0; pos && *pos && len < max_digits; len++, pos++)
+		if (!isxdigit(*pos))
+			return false;
+	if (len < min_digits)
+		return false;
+	/* With not too many digits, we should have reached *str == nul */
+	if (pos && *pos)
+		return false;
+	if (require_even && (len & 1))
+		return false;
+	return true;
+}
+
 /*! @} */
diff --git a/tests/utils/utils_test.c b/tests/utils/utils_test.c
index cad162d..4a4b121 100644
--- a/tests/utils/utils_test.c
+++ b/tests/utils/utils_test.c
@@ -219,6 +219,68 @@
 	OSMO_ASSERT(!TLVP_PRESENT(&tvp, 0x25));
 }
 
+static struct {
+	const char *str;
+	int min_digits;
+	int max_digits;
+	bool require_even;
+	bool expect_ok;
+} test_hexstrs[] = {
+	{ NULL, 0, 10, false, true },
+	{ NULL, 1, 10, false, false },
+	{ "", 0, 10, false, true },
+	{ "", 1, 10, false, false },
+	{ " ", 0, 10, false, false },
+	{ "1", 0, 10, false, true },
+	{ "1", 1, 10, false, true },
+	{ "1", 1, 10, true, false },
+	{ "1", 2, 10, false, false },
+	{ "123", 1, 10, false, true },
+	{ "123", 1, 10, true, false },
+	{ "123", 4, 10, false, false },
+	{ "1234", 4, 10, true, true },
+	{ "12345", 4, 10, true, false },
+	{ "123456", 4, 10, true, true },
+	{ "1234567", 4, 10, true, false },
+	{ "12345678", 4, 10, true, true },
+	{ "123456789", 4, 10, true, false },
+	{ "123456789a", 4, 10, true, true },
+	{ "123456789ab", 4, 10, true, false },
+	{ "123456789abc", 4, 10, true, false },
+	{ "123456789ab", 4, 10, false, false },
+	{ "123456789abc", 4, 10, false, false },
+	{ "0123456789abcdefABCDEF", 0, 100, false, true },
+	{ "0123456789 abcdef ABCDEF", 0, 100, false, false },
+	{ "foobar", 0, 100, false, false },
+	{ "BeadedBeeAced1EbbedDefacedFacade", 32, 32, true, true },
+	{ "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 32, 32, false, true },
+	{ "DeafBeddedBabeAcceededFadedDecaff", 32, 32, false, false },
+};
+
+bool test_is_hexstr()
+{
+	int i;
+	bool pass = true;
+	bool ok = true;
+	printf("\n----- %s\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(test_hexstrs); i++) {
+		ok = osmo_is_hexstr(test_hexstrs[i].str,
+				    test_hexstrs[i].min_digits,
+				    test_hexstrs[i].max_digits,
+				    test_hexstrs[i].require_even);
+		pass = pass && (ok == test_hexstrs[i].expect_ok);
+		printf("%2d: %s str='%s' min=%d max=%d even=%d expect=%s\n",
+		       i, test_hexstrs[i].expect_ok == ok ? "pass" : "FAIL",
+		       test_hexstrs[i].str,
+		       test_hexstrs[i].min_digits,
+		       test_hexstrs[i].max_digits,
+		       test_hexstrs[i].require_even,
+		       test_hexstrs[i].expect_ok ? "valid" : "invalid");
+	}
+	return pass;
+}
+
 int main(int argc, char **argv)
 {
 	static const struct log_info log_info = {};
@@ -227,5 +289,6 @@
 	hexdump_test();
 	hexparse_test();
 	test_idtag_parsing();
+	test_is_hexstr();
 	return 0;
 }
diff --git a/tests/utils/utils_test.ok b/tests/utils/utils_test.ok
index e9be018..45156f7 100644
--- a/tests/utils/utils_test.ok
+++ b/tests/utils/utils_test.ok
@@ -26,3 +26,34 @@
 rc = -1
 Hexparse with invalid char
 rc = -1
+
+----- test_is_hexstr
+ 0: pass str='(null)' min=0 max=10 even=0 expect=valid
+ 1: pass str='(null)' min=1 max=10 even=0 expect=invalid
+ 2: pass str='' min=0 max=10 even=0 expect=valid
+ 3: pass str='' min=1 max=10 even=0 expect=invalid
+ 4: pass str=' ' min=0 max=10 even=0 expect=invalid
+ 5: pass str='1' min=0 max=10 even=0 expect=valid
+ 6: pass str='1' min=1 max=10 even=0 expect=valid
+ 7: pass str='1' min=1 max=10 even=1 expect=invalid
+ 8: pass str='1' min=2 max=10 even=0 expect=invalid
+ 9: pass str='123' min=1 max=10 even=0 expect=valid
+10: pass str='123' min=1 max=10 even=1 expect=invalid
+11: pass str='123' min=4 max=10 even=0 expect=invalid
+12: pass str='1234' min=4 max=10 even=1 expect=valid
+13: pass str='12345' min=4 max=10 even=1 expect=invalid
+14: pass str='123456' min=4 max=10 even=1 expect=valid
+15: pass str='1234567' min=4 max=10 even=1 expect=invalid
+16: pass str='12345678' min=4 max=10 even=1 expect=valid
+17: pass str='123456789' min=4 max=10 even=1 expect=invalid
+18: pass str='123456789a' min=4 max=10 even=1 expect=valid
+19: pass str='123456789ab' min=4 max=10 even=1 expect=invalid
+20: pass str='123456789abc' min=4 max=10 even=1 expect=invalid
+21: pass str='123456789ab' min=4 max=10 even=0 expect=invalid
+22: pass str='123456789abc' min=4 max=10 even=0 expect=invalid
+23: pass str='0123456789abcdefABCDEF' min=0 max=100 even=0 expect=valid
+24: pass str='0123456789 abcdef ABCDEF' min=0 max=100 even=0 expect=invalid
+25: pass str='foobar' min=0 max=100 even=0 expect=invalid
+26: pass str='BeadedBeeAced1EbbedDefacedFacade' min=32 max=32 even=1 expect=valid
+27: pass str='C01ffedC1cadaeAc1d1f1edAcac1aB0a' min=32 max=32 even=0 expect=valid
+28: pass str='DeafBeddedBabeAcceededFadedDecaff' min=32 max=32 even=0 expect=invalid

-- 
To view, visit https://gerrit.osmocom.org/4159
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Idf75946eb0a84e145adad13fc7c78bb7a267aa0a
Gerrit-PatchSet: 1
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>



More information about the gerrit-log mailing list