diff options
| author | Neels Hofmeyr <neels@hofmeyr.de> | 2017-10-07 04:39:14 +0200 | 
|---|---|---|
| committer | Neels Hofmeyr <neels@hofmeyr.de> | 2017-10-09 16:30:45 +0200 | 
| commit | 4335badd0e85341a2515c00e5b73d6a921ecdd1b (patch) | |
| tree | c08b51738fc0e134af7fc7fbb9f9f274851a40b1 | |
| parent | 1a02e36c4c940d7b326fa58a9f8080f79b558bba (diff) | |
utils: add osmo_is_hexstr(), add unit test
Will be used by OsmoHLR to validate VTY and CTRL input.
Change-Id: Idf75946eb0a84e145adad13fc7c78bb7a267aa0a
| -rw-r--r-- | include/osmocom/core/utils.h | 5 | ||||
| -rw-r--r-- | src/utils.c | 33 | ||||
| -rw-r--r-- | tests/utils/utils_test.c | 63 | ||||
| -rw-r--r-- | tests/utils/utils_test.ok | 31 | 
4 files changed, 132 insertions, 0 deletions
| diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h index 855e6539..5f412139 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 @@ uint8_t *osmo_encode_big_endian(uint64_t value, size_t data_len);  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 1c176f86..b4345c74 100644 --- a/src/utils.c +++ b/src/utils.c @@ -375,4 +375,37 @@ size_t osmo_strlcpy(char *dst, const char *src, size_t siz)  	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; +	if (!pos) +		return min_digits < 1; +	for (len = 0; *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) +		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 cad162d9..4a4b121f 100644 --- a/tests/utils/utils_test.c +++ b/tests/utils/utils_test.c @@ -219,6 +219,68 @@ static void test_idtag_parsing(void)  	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 @@ int main(int argc, char **argv)  	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 e9be0187..45156f7f 100644 --- a/tests/utils/utils_test.ok +++ b/tests/utils/utils_test.ok @@ -26,3 +26,34 @@ Hexparse with uneven amount of digits  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 | 
