Mercurial > sci
comparison base64.c @ 1:5afdb14df924
sci: add support for storing results
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 08 Jun 2021 08:40:01 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:f1de39079243 | 1:5afdb14df924 |
---|---|
1 /* | |
2 * base64.h -- base64 encoding and decoding | |
3 * | |
4 * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #include <assert.h> | |
20 #include <ctype.h> | |
21 #include <errno.h> | |
22 #include <string.h> | |
23 | |
24 #include "base64.h" | |
25 | |
26 int | |
27 b64_isbase64(unsigned char ch) | |
28 { | |
29 return isalnum(ch) || ch == '+' || ch == '-' || ch == '_' || ch == '/'; | |
30 } | |
31 | |
32 int | |
33 b64_isvalid(unsigned char ch) | |
34 { | |
35 return b64_isbase64(ch) || ch == '='; | |
36 } | |
37 | |
38 unsigned char | |
39 b64_lookup(unsigned char value) | |
40 { | |
41 assert(value < 64); | |
42 | |
43 static const char *table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
44 | |
45 return table[value]; | |
46 } | |
47 | |
48 unsigned char | |
49 b64_rlookup(unsigned char ch) | |
50 { | |
51 assert(b64_isbase64(ch)); | |
52 | |
53 if (ch >= '0' && ch <= '9') | |
54 return ch + 4; | |
55 if (ch >= 'A' && ch <= 'Z') | |
56 return ch - 65; | |
57 if (ch >= 'a' && ch <= 'z') | |
58 return ch - 71; | |
59 | |
60 /* '-' is base64url support. */ | |
61 return ch == '+' || ch == '-' ? 62U : 63U; | |
62 } | |
63 | |
64 size_t | |
65 b64_encode(const char *src, size_t srcsz, char *dst, size_t dstsz) | |
66 { | |
67 assert(src); | |
68 assert(dst); | |
69 | |
70 size_t nwritten = 0; | |
71 | |
72 if (srcsz == (size_t)-1) | |
73 srcsz = strlen(src); | |
74 | |
75 while (srcsz && dstsz) { | |
76 char inputbuf[3] = {0}; | |
77 int count = 0; | |
78 | |
79 while (srcsz && count < 3) { | |
80 inputbuf[count++] = *src++; | |
81 --srcsz; | |
82 } | |
83 | |
84 if (dstsz < 4) { | |
85 errno = ERANGE; | |
86 return -1; | |
87 } | |
88 | |
89 *dst++ = b64_lookup(inputbuf[0] >> 2 & 0x3f); | |
90 *dst++ = b64_lookup((inputbuf[0] << 4 & 0x3f) | (inputbuf[1] >> 4 & 0x0f)); | |
91 | |
92 if (count < 2) | |
93 *dst++ = '='; | |
94 else | |
95 *dst++ = b64_lookup((inputbuf[1] << 2 & 0x3c) | (inputbuf[2] >> 6 & 0x03)); | |
96 | |
97 if (count < 3) | |
98 *dst++ = '='; | |
99 else | |
100 *dst++ = b64_lookup(inputbuf[2] & 0x3f); | |
101 | |
102 nwritten += 4; | |
103 dstsz -= 4; | |
104 } | |
105 | |
106 /* Not enough room to store '\0'. */ | |
107 if (dstsz == 0) { | |
108 errno = ERANGE; | |
109 return -1; | |
110 } | |
111 | |
112 *dst = '\0'; | |
113 | |
114 return nwritten; | |
115 } | |
116 | |
117 size_t | |
118 b64_decode(const char *src, size_t srcsz, char *dst, size_t dstsz) | |
119 { | |
120 assert(src); | |
121 assert(dst); | |
122 | |
123 size_t nwritten = 0; | |
124 | |
125 if (srcsz == (size_t)-1) | |
126 srcsz = strlen(src); | |
127 | |
128 while (srcsz && dstsz) { | |
129 int i = 0, r = 3; | |
130 unsigned int inputbuf[4] = {0}; | |
131 | |
132 for (; srcsz && i < 4; i++) { | |
133 if (*src == '=') { | |
134 /* | |
135 * '=' is only allowed in last 2 characters, | |
136 * otherwise it means we need less data. | |
137 */ | |
138 if (i <= 1) | |
139 goto eilseq; | |
140 | |
141 /* Less data required. */ | |
142 --r; | |
143 } else if (!b64_isvalid(*src)) | |
144 goto eilseq; | |
145 | |
146 if (b64_isbase64(*src)) | |
147 inputbuf[i] = b64_rlookup(*src); | |
148 | |
149 ++src; | |
150 --srcsz; | |
151 } | |
152 | |
153 /* Make sure we haven't seen AB=Z as well. */ | |
154 if (i != 4 || (src[-2] == '=' && src[-1] != '=')) | |
155 goto eilseq; | |
156 if ((size_t)r >= dstsz) | |
157 goto erange; | |
158 | |
159 *dst++ = ((inputbuf[0] << 2) & 0xfc) | | |
160 ((inputbuf[1] >> 4) & 0x03); | |
161 | |
162 if (r >= 2) | |
163 *dst++ = ((inputbuf[1] << 4) & 0xf0) | ((inputbuf[2] >> 2) & 0x0f); | |
164 if (r >= 3) | |
165 *dst++ = ((inputbuf[2] << 6) & 0xc0) | (inputbuf[3] & 0x3f); | |
166 | |
167 nwritten += r; | |
168 dstsz -= r; | |
169 } | |
170 | |
171 /* Not enough room to store '\0'. */ | |
172 if (dstsz == 0) | |
173 goto erange; | |
174 | |
175 *dst = '\0'; | |
176 | |
177 return nwritten; | |
178 | |
179 eilseq: | |
180 errno = EILSEQ; | |
181 return -1; | |
182 | |
183 erange: | |
184 errno = ERANGE; | |
185 return -1; | |
186 } |