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 105
hex_encode_l(size_t l)
61
{
62 105
        return ((l) << 1) + 1;
63
}
64
65
size_t
66 61
hex_decode_l(size_t l)
67
{
68 61
        return ((l) + 1) >> 1;
69
}
70
71
static inline char
72 6470
hex2byte(const unsigned char hi, const unsigned char lo)
73
{
74 6470
        return (nibble[hi - '0'] << 4) | nibble[lo - '0'];
75
}
76
77
ssize_t
78 95
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 95
        char *p = buf;
83 95
        const char *alphabet = hex_alphabet[0];
84
85 95
        AN(buf);
86 95
        assert(enc == HEX);
87 95
        if (in == NULL || inlen == 0)
88 5
                return 0;
89 90
        if (buflen < hex_encode_l(inlen))
90 0
                return -1;
91
92 90
        if (kase == UPPER)
93 31
                alphabet = hex_alphabet[1];
94
95 6508
        for (int i = 0; i < inlen; i++) {
96 6418
                *p++ = alphabet[(in[i] & 0xf0) >> 4];
97 6418
                *p++ = alphabet[in[i] & 0x0f];
98
        }
99
100 90
        return p - buf;
101
}
102
103
ssize_t
104 103
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 103
        char *dest = buf;
109
        const char *b;
110 103
        unsigned char extranib = 0;
111 103
        ssize_t len = 0;
112
        va_list ap2;
113
114 103
        AN(buf);
115 103
        assert(dec == HEX);
116
117 103
        va_copy(ap2, ap);
118 367
        for (const char *s = p; s != vrt_magic_string_end;
119 161
             s = va_arg(ap2, const char *)) {
120 166
                if (s == NULL)
121 24
                        continue;
122 142
                b = s;
123 22957
                while (*s) {
124 22678
                        if (!isxdigit(*s++)) {
125 5
                                len = -1;
126 5
                                break;
127
                        }
128
                }
129 142
                if (len == -1)
130 5
                        break;
131 137
                len += s - b;
132
        }
133 103
        va_end(ap2);
134
135 103
        if (len == 0)
136 4
                return 0;
137 99
        if (len == -1) {
138 5
                errno = EINVAL;
139 5
                return -1;
140
        }
141 94
        if (n != -1 && len > n)
142 36
                len = n;
143
144 94
        if ((len+1) >> 1 > buflen) {
145 0
                errno = ENOMEM;
146 0
                return -1;
147
        }
148 94
        if (len & 1) {
149 13
                extranib = '0';
150 13
                len++;
151
        }
152
153 329
        for (const char *s = p; len > 0 && s != vrt_magic_string_end;
154 141
             s = va_arg(ap, const char *)) {
155 141
                if (s == NULL || *s == '\0')
156 32
                        continue;
157 109
                if (extranib) {
158 25
                        *dest++ = hex2byte(extranib, *s++);
159 25
                        len -= 2;
160
                }
161 6663
                while (len >= 2 && *s && *(s+1)) {
162 6445
                        *dest++ = hex2byte(*s, *(s+1));
163 6445
                        s += 2;
164 6445
                        len -= 2;
165
                }
166 109
                extranib = *s;
167
        }
168 94
        assert(dest <= buf + buflen);
169 94
        return dest - buf;
170
}