2.55 xs_hex.h
  1/* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
  2
  3#ifndef _XS_HEX_H
  4
  5#define _XS_HEX_H
  6
  7 int xs_is_hex_digit(char str);
  8 void xs_hex_enc_1(char **dst, const char **src);
  9 int xs_hex_dec_1(char **dst, const char **src);
 10 char *_xs_hex_enc(char *dst, const char *src, int src_size);
 11 char *_xs_hex_dec(char *dst, const char *src, int src_size);
 12
 13#ifdef _XS_H
 14 xs_str *xs_hex_enc(const xs_val *data, int size);
 15 xs_val *xs_hex_dec(const xs_str *hex, int *size);
 16 int xs_is_hex(const char *str);
 17#endif /* _XS_H */
 18
 19
 20#ifdef XS_IMPLEMENTATION
 21
 22#include <string.h>
 23
 24/** hex **/
 25
 26static char rev_hex_digits[] = "fedcba9876543210FEDCBA";
 27
 28int xs_is_hex_digit(char str)
 29/* checks if the char is an hex digit */
 30{
 31    return strchr(rev_hex_digits, str) != NULL;
 32}
 33
 34
 35void xs_hex_enc_1(char **dst, const char **src)
 36/* decodes one character into two hex digits */
 37{
 38    const char *i = *src;
 39    char *o = *dst;
 40
 41    *o++ = rev_hex_digits[0xf - (*i >> 4 & 0xf)];
 42    *o++ = rev_hex_digits[0xf - (*i      & 0xf)];
 43
 44    *src = i + 1;
 45    *dst = o;
 46}
 47
 48
 49int xs_hex_dec_1(char **dst, const char **src)
 50/* decodes two hex digits (returns 0 on error) */
 51{
 52    const char *i = *src;
 53    char *o = *dst;
 54
 55    char *d1 = strchr(rev_hex_digits, *i++);
 56    char *d2 = strchr(rev_hex_digits, *i++);
 57
 58    if (!d1 || !d2) {
 59        /* decoding error */
 60        return 0;
 61    }
 62
 63    *o++ = (0xf - ((d1 - rev_hex_digits) & 0xf)) << 4 |
 64           (0xf - ((d2 - rev_hex_digits) & 0xf));
 65
 66    *src = i;
 67    *dst = o;
 68    return 1;
 69}
 70
 71
 72char *_xs_hex_enc(char *dst, const char *src, int src_size)
 73/* hex-encodes the src buffer into dst, which has enough size */
 74{
 75    const char *e = src + src_size;
 76
 77    while (src < e)
 78        xs_hex_enc_1(&dst, &src);
 79
 80    return dst;
 81}
 82
 83
 84char *_xs_hex_dec(char *dst, const char *src, int src_size)
 85/* hex-decodes the src string int dst, which has enough size.
 86   return NULL on decoding errors or the final position of dst */
 87{
 88    if (src_size % 2)
 89        return NULL;
 90
 91    const char *e = src + src_size;
 92
 93    while (src < e) {
 94        if (!xs_hex_dec_1(&dst, &src))
 95            return NULL;
 96    }
 97
 98    return dst;
 99}
100
101
102#ifdef _XS_H
103
104xs_str *xs_hex_enc(const xs_val *data, int size)
105/* returns an hexdump of data */
106{
107    xs_str *s = xs_realloc(NULL, _xs_blk_size(size * 2 + 1));
108
109    char *q = _xs_hex_enc(s, data, size);
110
111    *q = '\0';
112
113    return s;
114}
115
116
117xs_val *xs_hex_dec(const xs_str *hex, int *size)
118/* decodes an hexdump into data */
119{
120    int sz = strlen(hex);
121    xs_val *s = NULL;
122
123    *size = sz / 2;
124    s = xs_realloc(NULL, _xs_blk_size(*size + 1));
125
126    if (!_xs_hex_dec(s, hex, sz))
127        return xs_free(s);
128
129    s[*size] = '\0';
130
131    return s;
132}
133
134
135int xs_is_hex(const char *str)
136/* returns 1 if str is an hex string */
137{
138    if (strlen(str) % 2)
139        return 0;
140
141    while (*str) {
142        if (!xs_is_hex_digit(*str++))
143            return 0;
144    }
145
146    return 1;
147}
148
149#endif /* _XS_H */
150
151#endif /* XS_IMPLEMENTATION */
152
153#endif /* _XS_HEX_H */