varnish-cache/lib/libvmod_blob/hex.c
1
/*-
2
 * Copyright 2016 UPLEX - Nils Goroll Systemoptimierung
3
 * All rights reserved.
4
 *
5
 * Authors: Nils Goroll <nils.goroll@uplex.de>
6
 *          Geoffrey Simmons <geoffrey.simmons@uplex.de>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions are met:
10
 * 1. Redistributions of source code must retain the above copyright notice,
11
 *    this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright notice,
13
 *    this list of conditions and the following disclaimer in the documentation
14
 *    and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
20
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 *
27
 */
28
29
#include "config.h"
30
#include <ctype.h>
31
#include <errno.h>
32
33
#include "vmod_blob.h"
34
#include "hex.h"
35
36
#include "vdef.h"
37
#include "vrt.h"
38
#include "vas.h"
39
40
const char hex_alphabet[][16] = {
41
        "0123456789abcdef",
42
        "0123456789ABCDEF"
43
};
44
45
/*
46
 * Shift the ASCII table over so that it begins at '0', and replace the
47
 * hex digits with their binary values. This fits all of the hex digits
48
 * into 55 bytes (cacheline friendly).
49
 */
50
const uint8_t nibble[] = {
51
           0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
52
           ILL, ILL, ILL, ILL, ILL, ILL, ILL, 10,  11,  12,
53
           13,  14,  15,  ILL, ILL, ILL, ILL, ILL, ILL, ILL,
54
           ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
55
           ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, 10,
56
           11,  12,  13,  14,  15
57
};
58
59
size_t
60 354
hex_encode_l(size_t l)
61
{
62 354
        return ((l) << 1) + 1;
63
}
64
65
size_t
66 183
hex_decode_l(size_t l)
67
{
68 183
        return ((l) + 1) >> 1;
69
}
70
71
static inline char
72 19557
hex2byte(const unsigned char hi, const unsigned char lo)
73
{
74 19557
        return (nibble[hi - '0'] << 4) | nibble[lo - '0'];
75
}
76
77
ssize_t
78 324
hex_encode(const enum encoding enc, const enum case_e kase,
79
           char *restrict const buf, const size_t buflen,
80
           const char *restrict const in, const size_t inlen)
81
{
82 324
        char *p = buf;
83 324
        const char *alphabet = hex_alphabet[0];
84
85 324
        AN(buf);
86 324
        assert(enc == HEX);
87 324
        if (in == NULL || inlen == 0)
88 15
                return 0;
89 309
        if (buflen < hex_encode_l(inlen))
90 6
                return -1;
91
92 303
        if (kase == UPPER)
93 93
                alphabet = hex_alphabet[1];
94
95 20613
        for (int i = 0; i < inlen; i++) {
96 20310
                *p++ = alphabet[(in[i] & 0xf0) >> 4];
97 20310
                *p++ = alphabet[in[i] & 0x0f];
98
        }
99
100 303
        return p - buf;
101
}
102
103
ssize_t
104 345
hex_decode(const enum encoding dec, char *restrict const buf,
105
           const size_t buflen, ssize_t n,
106
           const char *restrict const p, va_list ap)
107
{
108 345
        char *dest = buf;
109
        const char *b;
110 345
        unsigned char extranib = 0;
111 345
        ssize_t len = 0;
112
        va_list ap2;
113
114 345
        AN(buf);
115 345
        assert(dec == HEX);
116
117 345
        va_copy(ap2, ap);
118 1209
        for (const char *s = p; s != vrt_magic_string_end;
119 519
             s = va_arg(ap2, const char *)) {
120 534
                if (s == NULL)
121 72
                        continue;
122 462
                b = s;
123 69297
                while (*s) {
124 68388
                        if (!isxdigit(*s++)) {
125 15
                                len = -1;
126 15
                                break;
127
                        }
128
                }
129 462
                if (len == -1)
130 15
                        break;
131 447
                len += s - b;
132
        }
133 345
        va_end(ap2);
134
135 345
        if (len == 0)
136 18
                return 0;
137 327
        if (len == -1) {
138 15
                errno = EINVAL;
139 15
                return -1;
140
        }
141 312
        if (n != -1 && len > n)
142 108
                len = n;
143
144 312
        if ((len+1) >> 1 > buflen) {
145 3
                errno = ENOMEM;
146 3
                return -1;
147
        }
148 309
        if (len & 1) {
149 39
                extranib = '0';
150 39
                len++;
151
        }
152
153 1068
        for (const char *s = p; len > 0 && s != vrt_magic_string_end;
154 450
             s = va_arg(ap, const char *)) {
155 450
                if (s == NULL || *s == '\0')
156 96
                        continue;
157 354
                if (extranib) {
158 75
                        *dest++ = hex2byte(extranib, *s++);
159 75
                        len -= 2;
160
                }
161 20190
                while (len >= 2 && *s && *(s+1)) {
162 19482
                        *dest++ = hex2byte(*s, *(s+1));
163 19482
                        s += 2;
164 19482
                        len -= 2;
165
                }
166 354
                extranib = *s;
167
        }
168 309
        assert(dest <= buf + buflen);
169 309
        return dest - buf;
170
}