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 "hex.h"
34
35
#include "vdef.h"
36
#include "vrt.h"
37
#include "vas.h"
38
39
#include "vmod_blob.h"
40
41
const char hex_alphabet[][16] = {
42
        "0123456789abcdef",
43
        "0123456789ABCDEF"
44
};
45
46
/*
47
 * Shift the ASCII table over so that it begins at '0', and replace the
48
 * hex digits with their binary values. This fits all of the hex digits
49
 * into 55 bytes (cacheline friendly).
50
 */
51
const uint8_t nibble[] = {
52
           0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
53
           ILL, ILL, ILL, ILL, ILL, ILL, ILL, 10,  11,  12,
54
           13,  14,  15,  ILL, ILL, ILL, ILL, ILL, ILL, ILL,
55
           ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
56
           ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, 10,
57
           11,  12,  13,  14,  15
58
};
59
60
size_t
61 590
hex_encode_l(size_t l)
62
{
63 590
        return ((l) << 1) + 1;
64
}
65
66
size_t
67 305
hex_decode_l(size_t l)
68
{
69 305
        return ((l) + 1) >> 1;
70
}
71
72
static inline char
73 32595
hex2byte(const unsigned char hi, const unsigned char lo)
74
{
75 32595
        return (nibble[hi - '0'] << 4) | nibble[lo - '0'];
76
}
77
78
ssize_t
79 540
hex_encode(const enum encoding enc, const enum case_e kase,
80
           char *restrict const buf, const size_t buflen,
81
           const char *restrict const in, const size_t inlen)
82
{
83 540
        char *p = buf;
84 540
        const char *alphabet = hex_alphabet[0];
85
86 540
        AN(buf);
87 540
        assert(enc == HEX);
88 540
        if (in == NULL || inlen == 0)
89 25
                return 0;
90 515
        if (buflen < hex_encode_l(inlen))
91 10
                return -1;
92
93 505
        if (kase == UPPER)
94 155
                alphabet = hex_alphabet[1];
95
96 34355
        for (int i = 0; i < inlen; i++) {
97 33850
                *p++ = alphabet[(in[i] & 0xf0) >> 4];
98 33850
                *p++ = alphabet[in[i] & 0x0f];
99
        }
100
101 505
        return p - buf;
102
}
103
104
ssize_t
105 575
hex_decode(const enum encoding dec, char *restrict const buf,
106
           const size_t buflen, ssize_t n,
107
           const struct strands *restrict const strings)
108
{
109 575
        char *dest = buf;
110
        const char *b;
111 575
        unsigned char extranib = 0;
112 575
        size_t len = 0;
113
114 575
        AN(buf);
115 575
        AN(strings);
116 575
        assert(dec == HEX);
117
118 1440
        for (int i = 0; i < strings->n; i++) {
119 890
                const char *s = strings->p[i];
120
121 890
                if (s == NULL)
122 120
                        continue;
123 770
                b = s;
124 115495
                while (*s) {
125 113980
                        if (!isxdigit(*s++)) {
126 25
                                errno = EINVAL;
127 25
                                return (-1);
128
                        }
129
                }
130 745
                len += s - b;
131
        }
132
133 550
        if (len == 0)
134 30
                return 0;
135 520
        if (n != -1 && len > n)
136 180
                len = n;
137
138 520
        if (((len+1) >> 1) > buflen) {
139 5
                errno = ENOMEM;
140 5
                return -1;
141
        }
142 515
        if (len & 1) {
143 65
                extranib = '0';
144 65
                len++;
145
        }
146
147 1265
        for (int i = 0; len > 0 && i < strings->n; i++) {
148 750
                const char *s = strings->p[i];
149
150 750
                if (s == NULL || *s == '\0')
151 160
                        continue;
152 590
                if (extranib) {
153 125
                        *dest++ = hex2byte(extranib, *s++);
154 125
                        len -= 2;
155
                }
156 33650
                while (len >= 2 && *s && *(s+1)) {
157 32470
                        *dest++ = hex2byte(*s, *(s+1));
158 32470
                        s += 2;
159 32470
                        len -= 2;
160
                }
161 590
                extranib = *s;
162
        }
163 515
        assert(dest <= buf + buflen);
164 515
        return dest - buf;
165
}