---
.gitignore | 1 +
include/osmocom/core/utils.h | 5 ++++
src/utils.c | 68 ++++++++++++++++++++++++++++++++----------
tests/Makefile.am | 7 +++--
tests/hex/hex_test.c | 52 ++++++++++++++++++++++++++++++++
tests/hex/hex_test.ok | 18 +++++++++++
tests/testsuite.at | 6 ++++
7 files changed, 140 insertions(+), 17 deletions(-)
create mode 100644 tests/hex/hex_test.c
create mode 100644 tests/hex/hex_test.ok
diff --git a/.gitignore b/.gitignore
index ac19b23..67d9196 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,6 +58,7 @@ tests/sms/sms_test
tests/timer/timer_test
tests/msgfile/msgfile_test
tests/ussd/ussd_test
+tests/hex/hex_test
tests/smscb/smscb_test
tests/bits/bitrev_test
tests/a5/a5_test
diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h
index 03861d7..5250094 100644
--- a/include/osmocom/core/utils.h
+++ b/include/osmocom/core/utils.h
@@ -30,6 +30,11 @@ char osmo_bcd2char(uint8_t bcd);
/* only works for numbers in ascci */
uint8_t osmo_char2bcd(char c);
+enum hex_len_policy { /* define how to deal with odd length during hex string parsing */
+ HEX_ODD_NONE, HEX_ODD_LEFT, HEX_ODD_RIGHT
+};
+
+int osmo_hexparse_ext(const char *str, uint8_t *b, int max_len, enum hex_len_policy
pol);
int osmo_hexparse(const char *str, uint8_t *b, int max_len);
char *osmo_ubit_dump(const uint8_t *bits, unsigned int len);
diff --git a/src/utils.c b/src/utils.c
index c36979c..cd11618 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -73,36 +73,74 @@ uint8_t osmo_char2bcd(char c)
return c - 0x30;
}
-/*! \brief Parse a string ocntaining hexadecimal digits
+/*! \brief Parse a string ocntaining hexadecimal digits, optionally prefixed with 0x
* \param[in] str string containing ASCII encoded hexadecimal digits
* \param[out] b output buffer
* \param[in] max_len maximum space in output buffer
*/
int osmo_hexparse(const char *str, uint8_t *b, int max_len)
+{
+ return osmo_hexparse_ext(str, b, max_len, HEX_ODD_NONE);
+}
+inline int _osmo_hexval(char c)
{
- int i, l, v;
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return 10 + (c - 'a');
+ if (c >= 'A' && c <= 'F')
+ return 10 + (c - 'A');
+ return -1;
+}
- l = strlen(str);
- if ((l&1) || ((l>>1) > max_len))
+/*! \brief Parse a string ocntaining hexadecimal digits, optionally prefixed with 0x
+ * \param[in] str string containing ASCII encoded hexadecimal digits
+ * \param[out] b output buffer
+ * \param[in] max_len maximum space in output buffer
+ * \param[in] pol defines how to treat odd length case
+ */
+int osmo_hexparse_ext(const char *str, uint8_t *b, int max_len, enum hex_len_policy pol)
+{
+ int v;
+ size_t i, left_adj = 0, right_adj = 0, l = strlen(str);
+ const char * src;
+
+ if (l > 2) { /* remove 0x prefix if any */
+ if (!strncmp(str, "0x", 2)) {
+ l -= 2;
+ str += 2;
+ }
+ }
+
+ if (l & 1) {
+ switch (pol) {
+ case HEX_ODD_LEFT:
+ left_adj = 1;
+ break;
+ case HEX_ODD_NONE:
+ return -1;
+ case HEX_ODD_RIGHT:
+ right_adj = 1;
+ break;
+ default:
+ return -1;
+ }
+ }
+ /* left_adj and right_adj are mutually exclusive so left_adj + right_adj is
either 1 or 0 */
+ if ((l>>1) > max_len + left_adj + right_adj)
return -1;
- memset(b, 0x00, max_len);
+ memset(b, 0x00, max_len + left_adj + right_adj);
for (i=0; i<l; i++) {
- char c = str[i];
- if (c >= '0' && c <= '9')
- v = c - '0';
- else if (c >= 'a' && c <= 'f')
- v = 10 + (c - 'a');
- else if (c >= 'A' && c <= 'F')
- v = 10 + (c - 'A');
- else
+ v = _osmo_hexval(str[i]);
+ if (-1 == v)
return -1;
- b[i>>1] |= v << (i&1 ? 0 : 4);
+ b[(i + left_adj) >> 1] |= v << ( (i + left_adj) & 1 ? 0 :
4);
}
- return i>>1;
+ return (l + left_adj + right_adj)/2;
}
static char hexd_buff[4096];
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b60f675..fbefab1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -4,7 +4,7 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \
smscb/smscb_test bits/bitrev_test a5/a5_test \
conv/conv_test auth/milenage_test lapd/lapd_test \
gsm0808/gsm0808_test gsm0408/gsm0408_test \
- gb/bssgp_fc_test logging/logging_test
+ gb/bssgp_fc_test hex/hex_test logging/logging_test
if ENABLE_MSGFILE
check_PROGRAMS += msgfile/msgfile_test
endif
@@ -21,6 +21,9 @@ bits_bitrev_test_LDADD = $(top_builddir)/src/libosmocore.la
conv_conv_test_SOURCES = conv/conv_test.c
conv_conv_test_LDADD = $(top_builddir)/src/libosmocore.la
+hex_hex_test_SOURCES = hex/hex_test.c
+hex_hex_test_LDADD = $(top_builddir)/src/libosmocore.la
+
gsm0808_gsm0808_test_SOURCES = gsm0808/gsm0808_test.c
gsm0808_gsm0808_test_LDADD = $(top_builddir)/src/libosmocore.la
$(top_builddir)/src/gsm/libosmogsm.la
@@ -77,7 +80,7 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \
gsm0808/gsm0808_test.ok gb/bssgp_fc_tests.err \
gb/bssgp_fc_tests.ok gb/bssgp_fc_tests.sh \
msgfile/msgfile_test.ok msgfile/msgconfig.cfg \
- logging/logging_test.ok logging/logging_test.err
+ logging/logging_test.ok hex/hex_test.ok logging/logging_test.err
DISTCLEANFILES = atconfig
diff --git a/tests/hex/hex_test.c b/tests/hex/hex_test.c
new file mode 100644
index 0000000..fa85065
--- /dev/null
+++ b/tests/hex/hex_test.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <osmocom/core/utils.h>
+
+/* ------------------------------------------------------------------------ */
+/* Test vectors */
+/* ------------------------------------------------------------------------ */
+
+char * long_rand_x = "0xa63c3b465eb79b3e06ae66eb816eace";
+char * long_rand = "39ea2e536e6a2c0d3e59110df20e4bf";
+char * small_even_x = "0xDEAD";
+char * small_even = "FACE";
+char * small_odd_x = "0xFFACE";
+char * small_odd = "bee";
+
+/* ------------------------------------------------------------------------ */
+/* Main */
+/* ------------------------------------------------------------------------ */
+
+inline void _run_tests(char * vec, size_t len)
+{
+ uint8_t test[len];
+
+ int parsed = osmo_hexparse_ext(vec, test, len, HEX_ODD_NONE);
+ printf("NONE parsed %s: %d", vec, parsed);
+ if (-1 != parsed) printf(", dumped: %s\n", osmo_hexdump_nospc(test, len));
+ else printf("\n");
+
+ parsed = osmo_hexparse_ext(vec, test, len, HEX_ODD_LEFT);
+ printf("LEFT parsed %s: %d", vec, parsed);
+ if (-1 != parsed) printf(", dumped: %s\n", osmo_hexdump_nospc(test, len));
+ else printf("\n");
+
+ parsed = osmo_hexparse_ext(vec, test, len, HEX_ODD_RIGHT);
+ printf("RIGHT parsed %s: %d", vec, parsed);
+ if (-1 != parsed) printf(", dumped: %s\n", osmo_hexdump_nospc(test, len));
+ else printf("\n");
+}
+
+int main(int argc, char argv[])
+{
+ _run_tests(long_rand_x, 16);
+ _run_tests(long_rand, 16);
+ _run_tests(small_even_x, 2);
+ _run_tests(small_even, 2);
+ _run_tests(small_odd_x, 3);
+ _run_tests(small_odd, 2);
+
+ return 0;
+}
diff --git a/tests/hex/hex_test.ok b/tests/hex/hex_test.ok
new file mode 100644
index 0000000..1419b8c
--- /dev/null
+++ b/tests/hex/hex_test.ok
@@ -0,0 +1,18 @@
+NONE parsed 0xa63c3b465eb79b3e06ae66eb816eace: -1
+LEFT parsed 0xa63c3b465eb79b3e06ae66eb816eace: 16, dumped:
0a63c3b465eb79b3e06ae66eb816eace
+RIGHT parsed 0xa63c3b465eb79b3e06ae66eb816eace: 16, dumped:
a63c3b465eb79b3e06ae66eb816eace0
+NONE parsed 39ea2e536e6a2c0d3e59110df20e4bf: -1
+LEFT parsed 39ea2e536e6a2c0d3e59110df20e4bf: 16, dumped:
039ea2e536e6a2c0d3e59110df20e4bf
+RIGHT parsed 39ea2e536e6a2c0d3e59110df20e4bf: 16, dumped:
39ea2e536e6a2c0d3e59110df20e4bf0
+NONE parsed 0xDEAD: 2, dumped: dead
+LEFT parsed 0xDEAD: 2, dumped: dead
+RIGHT parsed 0xDEAD: 2, dumped: dead
+NONE parsed FACE: 2, dumped: face
+LEFT parsed FACE: 2, dumped: face
+RIGHT parsed FACE: 2, dumped: face
+NONE parsed 0xFFACE: -1
+LEFT parsed 0xFFACE: 3, dumped: 0fface
+RIGHT parsed 0xFFACE: 3, dumped: fface0
+NONE parsed bee: -1
+LEFT parsed bee: 2, dumped: 0bee
+RIGHT parsed bee: 2, dumped: bee0
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 1cfae03..cfbcf78 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -28,6 +28,12 @@ cat $abs_srcdir/conv/conv_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/conv/conv_test], [], [expout])
AT_CLEANUP
+AT_SETUP([hex])
+AT_KEYWORDS([hex])
+cat $abs_srcdir/hex/hex_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/hex/hex_test], [], [expout])
+AT_CLEANUP
+
if ENABLE_MSGFILE
AT_SETUP([msgfile])
AT_KEYWORDS([msgfile])
--
1.7.10.4
--------------040406000709000102010704--