From: Rusty Russell Date: Thu, 14 May 2015 06:55:52 +0000 (-0700) Subject: str/hex: to-from hexstring conversion routines. X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=fc3a762c6629caf4af8c490c8f9ccff5ac9e5a16 str/hex: to-from hexstring conversion routines. Signed-off-by: Rusty Russell --- diff --git a/ccan/str/hex/LICENSE b/ccan/str/hex/LICENSE new file mode 120000 index 00000000..08d5d486 --- /dev/null +++ b/ccan/str/hex/LICENSE @@ -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 index 00000000..8d65490c --- /dev/null +++ b/ccan/str/hex/_info @@ -0,0 +1,39 @@ +#include "config.h" +#include +#include + +/** + * str/hex - hex-to-string conversions and vice-versa + * + * This code contains simple routines for hexidecimal strings. + * + * License: CC0 (Public domain) + * Author: Rusty Russell + * + * 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 index 00000000..fd4074f3 --- /dev/null +++ b/ccan/str/hex/hex.c @@ -0,0 +1,70 @@ +/* CC0 license (public domain) - see LICENSE file for details */ +#include +#include +#include +#include + +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 index 00000000..0a0d5c5a --- /dev/null +++ b/ccan/str/hex/hex.h @@ -0,0 +1,73 @@ +/* CC0 (Public domain) - see LICENSE file for details */ +#ifndef CCAN_HEX_H +#define CCAN_HEX_H +#include "config.h" +#include +#include + +/** + * 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 index 00000000..e4c1a6c5 --- /dev/null +++ b/ccan/str/hex/test/run.c @@ -0,0 +1,42 @@ +#include +/* Include the C files directly. */ +#include +#include +#include + +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(); +}