From a27913a47d81b61ca176d927cd5d43e64c11def9 Mon Sep 17 00:00:00 2001
From: Richard Nyberg <rnyberg@murmeldjur.se>
Date: Tue, 12 Sep 2006 08:55:53 +0000
Subject: [PATCH] Add functions for conversions between binary data and ascii
 hex. Add function for reading a whole file. Enable printf format checking for
 some functions.

---
 misc/subr.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 misc/subr.h | 11 +++++++
 2 files changed, 97 insertions(+), 1 deletion(-)

diff --git a/misc/subr.c b/misc/subr.c
index ffa5d46..3198189 100644
--- a/misc/subr.c
+++ b/misc/subr.c
@@ -31,6 +31,49 @@ has_bit(const uint8_t *bits, unsigned long index)
     return bits[index / 8] & (1 << (7 - index % 8));
 }
 
+uint8_t
+hex2i(char c)
+{
+    if (c >= '0' && c <= '9')
+        return c - '0';
+    else if (c >= 'a' && c <= 'f')
+        return 10 + c - 'a';
+    else
+        abort();
+}
+
+int
+ishex(char *str)
+{
+    while (*str != '\0') {
+        if (!((*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'f')))
+            return 0;
+        str++;
+    }
+    return 1;
+}
+
+uint8_t *
+hex2bin(const char *hex, uint8_t *bin, size_t bsize)
+{
+    for (size_t i = 0; i < bsize; i++)
+        bin[i] = hex2i(hex[i * 2]) << 4 | hex2i(hex[i * 2 + 1]);
+    return bin;
+}
+
+char *
+bin2hex(const uint8_t *bin, char *hex, size_t bsize)
+{
+    size_t i;
+    const char *hexc = "0123456789abcdef";
+    for (i = 0; i < bsize; i++) {
+        hex[i * 2] = hexc[(bin[i] >> 4) & 0xf];
+        hex[i * 2 + 1] = hexc[bin[i] &0xf];
+    }
+    hex[i * 2] = '\0';
+    return hex;
+}
+
 int
 set_nonblocking(int fd)
 {
@@ -174,7 +217,7 @@ read_fully(int fd, void *buf, size_t len)
     while (off < len) {
         nread = read(fd, buf + off, len - off);
         if (nread == 0)
-            return ECONNRESET;
+            return EIO;
         else if (nread == -1)
             return errno;
         off += nread;
@@ -182,6 +225,48 @@ read_fully(int fd, void *buf, size_t len)
     return 0;
 }
 
+int
+read_whole_file(void **out, size_t *size, const char *fmt, ...)
+{
+    int err, fd;
+    int didmalloc = 0;
+    struct stat sb;
+    va_list ap;
+
+    va_start(ap, fmt);
+    err = vaopen(&fd, O_RDONLY, fmt, ap);
+    va_end(ap);
+    if (err != 0)
+        return err;
+    if (fstat(fd, &sb) != 0) {
+        err = errno;
+        goto error;
+    }
+    if (*size != 0 && *size < sb.st_size) {
+        err = EFBIG;
+        goto error;
+    }
+    *size = sb.st_size;
+    if (*out == NULL) {
+        if ((*out = malloc(*size)) == NULL) {
+            err = errno;
+            goto error;
+        }
+        didmalloc = 1;
+    }
+    if ((err = read_fully(fd, *out, *size)) != 0)
+        goto error;
+
+    close(fd);
+    return 0;
+
+error:
+    if (didmalloc)
+        free(*out);
+    close(fd);
+    return err;
+}
+
 char *
 find_btpd_dir(void)
 {
diff --git a/misc/subr.h b/misc/subr.h
index 9260ed9..bf30433 100644
--- a/misc/subr.h
+++ b/misc/subr.h
@@ -5,14 +5,18 @@
 #include <stdarg.h>
 
 #define min(x, y) ((x) <= (y) ? (x) : (y))
+#define SHAHEXSIZE 41
 
 int set_nonblocking(int fd);
 int set_blocking(int fd);
 
 int mkdirs(char *path);
 
+__attribute__((format (printf, 3, 0)))
 int vaopen(int *resfd, int flags, const char *fmt, va_list ap);
+__attribute__((format (printf, 3, 4)))
 int vopen(int *resfd, int flags, const char *fmt, ...);
+__attribute__((format (printf, 3, 4)))
 int vfopen(FILE **ret, const char *mode, const char *fmt, ...);
 int vfsync(const char *fmt, ...);
 
@@ -20,10 +24,17 @@ void set_bit(uint8_t *bits, unsigned long index);
 int has_bit(const uint8_t *bits, unsigned long index);
 void clear_bit(uint8_t *bits, unsigned long index);
 
+char *bin2hex(const uint8_t *bin, char *hex, size_t bsize);
+uint8_t *hex2bin(const char *hex, uint8_t *bin, size_t bsize);
+uint8_t hex2i(char c);
+int ishex(char *str);
+
 long rand_between(long min, long max);
 
 int read_fully(int fd, void *buf, size_t len);
 int write_fully(int fd, const void *buf, size_t len);
+__attribute__((format (printf, 3, 4)))
+int read_whole_file(void **out, size_t *size, const char *fmt, ...);
 
 char *find_btpd_dir(void);