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