aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/ChangeLog6
-rw-r--r--common/convert.c89
-rw-r--r--common/t-convert.c171
-rw-r--r--common/util.h3
4 files changed, 266 insertions, 3 deletions
diff --git a/common/ChangeLog b/common/ChangeLog
index 3842b9c68..e517872d2 100644
--- a/common/ChangeLog
+++ b/common/ChangeLog
@@ -1,3 +1,9 @@
+2008-09-03 Werner Koch <[email protected]>
+
+ * convert.c (hex2str): New.
+ (hex2str_alloc): New.
+ * t-convert.c (test_hex2str): New.
+
2008-08-19 Werner Koch <[email protected]>
* iobuf.c: Avoid passing a NULL (iobuf_t)->desc to the log
diff --git a/common/convert.c b/common/convert.c
index 7aa6354d6..c946b81b1 100644
--- a/common/convert.c
+++ b/common/convert.c
@@ -1,5 +1,5 @@
/* convert.c - Hex conversion functions.
- * Copyright (C) 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2006, 2008 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -30,7 +30,7 @@
/* Convert STRING consisting of hex characters into its binary
representation and store that at BUFFER. BUFFER needs to be of
- LENGTH bytes. The function check that the STRING will convert
+ LENGTH bytes. The function checks that the STRING will convert
exactly to LENGTH bytes. The string is delimited by either end of
string or a white space character. The function returns -1 on
error or the length of the parsed string. */
@@ -100,6 +100,7 @@ hexcolon2bin (const char *string, void *buffer, size_t length)
}
+
static char *
do_bin2hex (const void *buffer, size_t length, char *stringbuf, int with_colon)
{
@@ -160,3 +161,87 @@ bin2hexcolon (const void *buffer, size_t length, char *stringbuf)
}
+
+/* Convert HEXSTRING consisting of hex characters into string and
+ store that at BUFFER. HEXSTRING is either delimited by end of
+ string or a white space character. The function makes sure that
+ the resulting string in BUFFER is terminated by a Nul character.
+ BUFSIZE is the availabe length of BUFFER; if the converted result
+ plus a possible required Nul character does not fit into this
+ buffer, the function returns NULL and won't change the existing
+ conent of buffer. In-place conversion is possible as long as
+ BUFFER points to HEXSTRING.
+
+ If BUFFER is NULL and bufsize is 0 the function scans HEXSTRING but
+ does not store anything. This may be used to find the end of
+ hexstring.
+
+ On sucess the function returns a pointer to the next character
+ after HEXSTRING (which is either end-of-string or a the next white
+ space). If BUFLEN is not NULL the strlen of buffer is stored
+ there; this will even be done if BUFFER has been passed as NULL. */
+const char *
+hex2str (const char *hexstring, char *buffer, size_t bufsize, size_t *buflen)
+{
+ const char *s = hexstring;
+ int idx, count;
+ int need_nul = 0;
+
+ if (buflen)
+ *buflen = 0;
+
+ for (s=hexstring, count=0; hexdigitp (s) && hexdigitp (s+1); s += 2, count++)
+ ;
+ if (*s && (!isascii (*s) || !isspace (*s)) )
+ return NULL; /* Not followed by Nul or white space. */
+ need_nul = !(s[-2] == '0' && s[-1] == '0');
+ if (need_nul)
+ count++;
+
+ if (buffer)
+ {
+ if (count > bufsize)
+ return NULL; /* Too long. */
+
+ for (s=hexstring, idx=0; hexdigitp (s) && hexdigitp (s+1); s += 2)
+ ((unsigned char*)buffer)[idx++] = xtoi_2 (s);
+ if (need_nul)
+ buffer[idx] = 0;
+ }
+
+ if (buflen)
+ *buflen = count - 1;
+ return s;
+}
+
+
+/* Same as hex2str but this function allocated a new string. Returns
+ NULL on error. If R_COUNT is not NULL, the number of scanned bytes
+ will be stored there. ERRNO is set on error. */
+char *
+hex2str_alloc (const char *hexstring, size_t *r_count)
+{
+ const char *tail;
+ size_t nbytes;
+ char *result;
+
+ tail = hex2str (hexstring, NULL, 0, &nbytes);
+ if (!tail)
+ {
+ if (r_count)
+ *r_count = 0;
+ errno = EINVAL;
+ return NULL;
+ }
+ if (r_count)
+ *r_count = tail - hexstring;
+ result = xtrymalloc (nbytes+1);
+ if (!result)
+ return NULL;
+ if (!hex2str (hexstring, result, nbytes+1, NULL))
+ BUG ();
+ return result;
+}
+
+
+
diff --git a/common/t-convert.c b/common/t-convert.c
index ede1e463d..caf743f1f 100644
--- a/common/t-convert.c
+++ b/common/t-convert.c
@@ -1,5 +1,5 @@
/* t-convert.c - Module test for convert.c
- * Copyright (C) 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2006, 2008 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -20,6 +20,7 @@
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
+#include <assert.h>
#include "util.h"
@@ -275,6 +276,173 @@ test_bin2hexcolon (void)
+static void
+test_hex2str (void)
+{
+ static struct {
+ const char *hex;
+ const char *str;
+ int off;
+ int no_alloc_test;
+ } tests[] = {
+ /* Simple tests. */
+ { "112233445566778899aabbccddeeff1122",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
+ 34 },
+ { "112233445566778899aabbccddeeff1122 blah",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
+ 34 },
+ { "112233445566778899aabbccddeeff1122\tblah",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
+ 34 },
+ { "112233445566778899aabbccddeeff1122\nblah",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
+ 34 },
+ /* Valid tests yielding an empty string. */
+ { "00",
+ "",
+ 2 },
+ { "00 x",
+ "",
+ 2 },
+ { "",
+ "",
+ 0 },
+ { " ",
+ "",
+ 0 },
+ /* Test trailing Nul feature. */
+ { "112233445566778899aabbccddeeff112200",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
+ 36 },
+ { "112233445566778899aabbccddeeff112200 ",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
+ 36 },
+ /* Test buffer size. (buffer is of length 20) */
+ { "6162636465666768696A6b6c6D6e6f70717273",
+ "abcdefghijklmnopqrs",
+ 38 },
+ { "6162636465666768696A6b6c6D6e6f7071727300",
+ "abcdefghijklmnopqrs",
+ 40 },
+ { "6162636465666768696A6b6c6D6e6f7071727374",
+ NULL,
+ 0, 1 },
+ { "6162636465666768696A6b6c6D6e6f707172737400",
+ NULL,
+ 0, 1 },
+ { "6162636465666768696A6b6c6D6e6f707172737475",
+ NULL,
+ 0, 1 },
+
+ /* Invalid tests. */
+ { "112233445566778899aabbccddeeff1122334", NULL, 0 },
+ { "112233445566778899AABBCCDDEEFF1122334", NULL, 0 },
+ { "112233445566778899AABBCCDDEEFG11223344", NULL, 0 },
+ { "0:0112233445566778899aabbccddeeff11223344", NULL, 0 },
+ { "112233445566778899aabbccddeeff11223344:", NULL, 0 },
+ { "112233445566778899aabbccddeeff112233445", NULL, 0 },
+ { "112233445566778899aabbccddeeff1122334455", NULL, 0, 1 },
+ { "112233445566778899aabbccddeeff11223344blah", NULL, 0 },
+ { "0", NULL, 0 },
+ { "00:", NULL, 0 },
+ { "00x", NULL, 0 },
+
+ { NULL, NULL, 0 }
+ };
+
+ int idx;
+ char buffer[20];
+ const char *tail;
+ size_t count;
+ char *result;
+
+ for (idx=0; tests[idx].hex; idx++)
+ {
+ tail = hex2str (tests[idx].hex, buffer, sizeof buffer, &count);
+ if (tests[idx].str)
+ {
+ /* Good case test. */
+ if (!tail)
+ fail (idx);
+ else if (strcmp (tests[idx].str, buffer))
+ fail (idx);
+ else if (tail - tests[idx].hex != tests[idx].off)
+ fail (idx);
+ else if (strlen (buffer) != count)
+ fail (idx);
+ }
+ else
+ {
+ /* Bad case test. */
+ if (tail)
+ fail (idx);
+ }
+ }
+
+ /* Same tests again using in-place conversion. */
+ for (idx=0; tests[idx].hex; idx++)
+ {
+ char tmpbuf[100];
+
+ assert (strlen (tests[idx].hex)+1 < sizeof tmpbuf);
+ strcpy (tmpbuf, tests[idx].hex);
+
+ /* Note: we still need to use 20 as buffer length because our
+ tests assume that. */
+ tail = hex2str (tmpbuf, tmpbuf, 20, &count);
+ if (tests[idx].str)
+ {
+ /* Good case test. */
+ if (!tail)
+ fail (idx);
+ else if (strcmp (tests[idx].str, tmpbuf))
+ fail (idx);
+ else if (tail - tmpbuf != tests[idx].off)
+ fail (idx);
+ else if (strlen (tmpbuf) != count)
+ fail (idx);
+ }
+ else
+ {
+ /* Bad case test. */
+ if (tail)
+ fail (idx);
+ if (strcmp (tmpbuf, tests[idx].hex))
+ fail (idx); /* Buffer was modified. */
+ }
+ }
+
+ /* Test the allocation variant. */
+ for (idx=0; tests[idx].hex; idx++)
+ {
+ if (tests[idx].no_alloc_test)
+ continue;
+
+ result = hex2str_alloc (tests[idx].hex, &count);
+ if (tests[idx].str)
+ {
+ /* Good case test. */
+ if (!result)
+ fail (idx);
+ else if (strcmp (tests[idx].str, result))
+ fail (idx);
+ else if (count != tests[idx].off)
+ fail (idx);
+ }
+ else
+ {
+ /* Bad case test. */
+ if (result)
+ fail (idx);
+ }
+ xfree (result);
+ }
+}
+
+
+
+
int
main (int argc, char **argv)
@@ -284,6 +452,7 @@ main (int argc, char **argv)
test_hexcolon2bin ();
test_bin2hex ();
test_bin2hexcolon ();
+ test_hex2str ();
return 0;
}
diff --git a/common/util.h b/common/util.h
index 5b564a2c6..572fa1a6a 100644
--- a/common/util.h
+++ b/common/util.h
@@ -189,6 +189,9 @@ int hex2bin (const char *string, void *buffer, size_t length);
int hexcolon2bin (const char *string, void *buffer, size_t length);
char *bin2hex (const void *buffer, size_t length, char *stringbuf);
char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
+const char *hex2str (const char *hexstring,
+ char *buffer, size_t bufsize, size_t *buflen);
+char *hex2str_alloc (const char *hexstring, size_t *r_count);
/*-- homedir.c --*/