str/hex: to-from hexstring conversion routines.
authorRusty Russell <rusty@rustcorp.com.au>
Thu, 14 May 2015 06:55:52 +0000 (23:55 -0700)
committerRusty Russell <rusty@rustcorp.com.au>
Thu, 14 May 2015 06:57:34 +0000 (23:57 -0700)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/str/hex/LICENSE [new symlink]
ccan/str/hex/_info [new file with mode: 0644]
ccan/str/hex/hex.c [new file with mode: 0644]
ccan/str/hex/hex.h [new file with mode: 0644]
ccan/str/hex/test/run.c [new file with mode: 0644]

diff --git a/ccan/str/hex/LICENSE b/ccan/str/hex/LICENSE
new file mode 120000 (symlink)
index 0000000..08d5d48
--- /dev/null
@@ -0,0 +1 @@
+../../../licenses/CC0
\ No newline at end of file
diff --git a/ccan/str/hex/_info b/ccan/str/hex/_info
new file mode 100644 (file)
index 0000000..8d65490
--- /dev/null
@@ -0,0 +1,39 @@
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * str/hex - hex-to-string conversions and vice-versa
+ *
+ * This code contains simple routines for hexidecimal strings.
+ *
+ * License: CC0 (Public domain)
+ * Author: Rusty Russell <rusty@rustcorp.com.au>
+ *
+ * Example:
+ *     int main(int argc, char *argv[])
+ *     {
+ *             int i;
+ *
+ *             for (i = 1; i < argc; i++) {
+ *                     char str[hex_str_size(strlen(argv[i]))];
+ *
+ *                     hex_encode(str, sizeof(str), argv[i], strlen(argv[i]));
+ *                     printf("%s ", str);
+ *             }
+ *             printf("\n");
+ *             return 0;
+ *     }
+ */
+int main(int argc, char *argv[])
+{
+       /* Expect exactly one argument */
+       if (argc != 2)
+               return 1;
+
+       if (strcmp(argv[1], "depends") == 0) {
+               return 0;
+       }
+
+       return 1;
+}
diff --git a/ccan/str/hex/hex.c b/ccan/str/hex/hex.c
new file mode 100644 (file)
index 0000000..fd4074f
--- /dev/null
@@ -0,0 +1,70 @@
+/* CC0 license (public domain) - see LICENSE file for details */
+#include <ccan/str/hex/hex.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static bool char_to_hex(unsigned char *val, char c)
+{
+       if (c >= '0' && c <= '9') {
+               *val = c - '0';
+               return true;
+       }
+       if (c >= 'a' && c <= 'f') {
+               *val = c - 'a' + 10;
+               return true;
+       }
+       if (c >= 'A' && c <= 'F') {
+               *val = c - 'A' + 10;
+               return true;
+       }
+       return false;
+}
+
+bool hex_decode(const char *str, size_t slen, void *buf, size_t bufsize)
+{
+       unsigned char v1, v2;
+       unsigned char *p = buf;
+
+       while (slen > 1) {
+               if (!char_to_hex(&v1, str[0]) || !char_to_hex(&v2, str[1]))
+                       return false;
+               if (!bufsize)
+                       return false;
+               *(p++) = (v1 << 4) | v2;
+               str += 2;
+               slen -= 2;
+               bufsize--;
+       }
+       return slen == 0 && bufsize == 0;
+}
+
+static char hexchar(unsigned int val)
+{
+       if (val < 10)
+               return '0' + val;
+       if (val < 16)
+               return 'a' + val - 10;
+       abort();
+}
+
+bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize)
+{
+       size_t used = 0;
+
+       if (destsize < 1)
+               return false;
+
+       while (used < bufsize) {
+               unsigned int c = ((const unsigned char *)buf)[used];
+               if (destsize < 3)
+                       return false;
+               *(dest++) = hexchar(c >> 4);
+               *(dest++) = hexchar(c & 0xF);
+               used++;
+               destsize -= 2;
+       }
+       *dest = '\0';
+
+       return used + 1;
+}
diff --git a/ccan/str/hex/hex.h b/ccan/str/hex/hex.h
new file mode 100644 (file)
index 0000000..0a0d5c5
--- /dev/null
@@ -0,0 +1,73 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_HEX_H
+#define CCAN_HEX_H
+#include "config.h"
+#include <stdbool.h>
+#include <stdlib.h>
+
+/**
+ * hex_decode - Unpack a hex string.
+ * @str: the hexidecimal string
+ * @slen: the length of @str
+ * @buf: the buffer to write the data into
+ * @bufsize: the length of @buf
+ *
+ * Returns false if there are any characters which aren't 0-9, a-f or A-F,
+ * of the string wasn't the right length for @bufsize.
+ *
+ * Example:
+ *     unsigned char data[20];
+ *
+ *     if (!hex_decode(argv[1], strlen(argv[1]), data, 20))
+ *             printf("String is malformed!\n");
+ */
+bool hex_decode(const char *str, size_t slen, void *buf, size_t bufsize);
+
+/**
+ * hex_encode - Create a nul-terminated hex string
+ * @buf: the buffer to read the data from
+ * @bufsize: the length of @buf
+ * @dest: the string to fill
+ * @destsize: the max size of the string
+ *
+ * Returns true if the string, including terminator, fit in @destsize;
+ *
+ * Example:
+ *     unsigned char buf[] = { 0x1F, 0x2F };
+ *     char str[5];
+ *
+ *     if (!hex_encode(buf, sizeof(buf), str, sizeof(str)))
+ *             abort();
+ */
+bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize);
+
+/**
+ * hex_str_size - Calculate how big a nul-terminated hex string is
+ * @bytes: bytes of data to represent
+ *
+ * Example:
+ *     unsigned char buf[] = { 0x1F, 0x2F };
+ *     char str[hex_str_size(sizeof(buf))];
+ *
+ *     hex_encode(buf, sizeof(buf), str, sizeof(str));
+ */
+static inline size_t hex_str_size(size_t bytes)
+{
+       return 2 * bytes + 1;
+}
+
+/**
+ * hex_data_size - Calculate how many bytes of data in a hex string
+ * @strlen: the length of the string (with or without NUL)
+ *
+ * Example:
+ *     const char str[] = "1F2F";
+ *     unsigned char buf[hex_data_size(sizeof(str))];
+ *
+ *     hex_decode(str, strlen(str), buf, sizeof(buf));
+ */
+static inline size_t hex_data_size(size_t strlen)
+{
+       return strlen / 2;
+}
+#endif /* PETTYCOIN_HEX_H */
diff --git a/ccan/str/hex/test/run.c b/ccan/str/hex/test/run.c
new file mode 100644 (file)
index 0000000..e4c1a6c
--- /dev/null
@@ -0,0 +1,42 @@
+#include <ccan/str/hex/hex.h>
+/* Include the C files directly. */
+#include <ccan/str/hex/hex.c>
+#include <ccan/tap/tap.h>
+#include <string.h>
+
+int main(void)
+{
+       const char teststr[] = "0123456789abcdefABCDEF";
+       const char bad_teststr[] = "0123456789abcdefABCDEF1O";
+       const unsigned char testdata[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
+                                          0xcd, 0xef, 0xAB, 0xCD, 0xEF };
+       unsigned char data[11];
+       char str[23];
+       size_t i;
+       
+       plan_tests(10 + sizeof(str));
+       
+       ok1(hex_str_size(sizeof(testdata)) == sizeof(teststr));
+       /* This gives right result with or without nul included */
+       ok1(hex_data_size(strlen(teststr)) == sizeof(testdata));
+       ok1(hex_data_size(sizeof(teststr)) == sizeof(testdata));
+
+       ok1(hex_decode(teststr, strlen(teststr), data, sizeof(data)));
+       ok1(memcmp(data, testdata, sizeof(testdata)) == 0);
+       ok1(hex_encode(testdata, sizeof(testdata), str, sizeof(str)));
+       ok1(strcmp(str, "0123456789abcdefabcdef") == 0);
+
+       /* Bad char */
+       ok1(!hex_decode(bad_teststr, strlen(bad_teststr), data, sizeof(data)));
+       /* Bad hex string len */
+       ok1(!hex_decode(teststr, strlen(teststr) - 1, data, sizeof(data)));
+       /* Bad buffer len */
+       ok1(!hex_decode(teststr, strlen(teststr), data, sizeof(data) - 1));
+
+       /* Bad deststring size. */
+       for (i = 1; i <= sizeof(str); i++)
+               ok1(!hex_encode(testdata, sizeof(testdata), str, sizeof(str)-i));
+
+       /* This exits depending on whether all tests passed */
+       return exit_status();
+}