2 * convert from text form of arbitrary data (e.g., keys) to binary
3 * Copyright (C) 2000 Henry Spencer.
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Library General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 * License for more details.
21 /* converters and misc */
22 static int unhex(const char *, char *, size_t);
23 static int unb64(const char *, char *, size_t);
24 static int untext(const char *, char *, size_t);
25 static const char *badch(const char *, int, char *, size_t);
27 /* internal error codes for converters */
28 #define SHORT (-2) /* internal buffer too short */
29 #define BADPAD (-3) /* bad base64 padding */
30 #define BADCH0 (-4) /* invalid character 0 */
31 #define BADCH1 (-5) /* invalid character 1 */
32 #define BADCH2 (-6) /* invalid character 2 */
33 #define BADCH3 (-7) /* invalid character 3 */
34 #define BADOFF(code) (BADCH0-(code))
37 * @brief convert text to data, with verbose error reports
39 * If some of this looks slightly odd, it's because it has changed
40 * repeatedly (from the original atodata()) without a major rewrite.
43 * @param srclen 0 means apply strlen()
44 * @param base 0 means figure it out
45 * @param dst need not be valid if dstlen is 0
47 * @param lenp where to record length (NULL is nowhere)
48 * @param errp error buffer
50 * @return NULL on success, else literal or errp
52 const char *ttodatav(const char *src
, size_t srclen
, int base
, char *dst
, size_t dstlen
, size_t *lenp
, char *errp
, size_t errlen
, unsigned int flags
)
54 size_t ingroup
; /* number of input bytes converted at once */
55 char buf
[4]; /* output from conversion */
56 int nbytes
; /* size of output */
57 int (*decode
)(const char *, char *, size_t);
67 dst
= buf
; /* point it somewhere valid */
72 return "input too short to be valid";
74 return "input does not begin with format prefix";
89 return "unknown format prefix";
103 if(flags
& TTODATAV_IGNORESPACE
) {
114 return "unknown base";
120 char stage
[4]; /* staging area for group */
123 /* Grab ingroup characters into stage,
124 * squeezing out blanks if we are supposed to ignore them.
126 for (sl
= 0; sl
< ingroup
; src
++, srclen
--) {
128 return "input ends in mid-byte, perhaps truncated";
129 else if (!(skipSpace
&& (*src
== ' ' || *src
== '\t')))
133 nbytes
= (*decode
)(stage
, buf
, sizeof(buf
));
139 return badch(stage
, nbytes
, errp
, errlen
);
141 return "internal buffer too short (\"can't happen\")";
143 return "bad (non-zero) padding at end of base64 input";
146 return "unknown internal error";
147 for (i
= 0; i
< nbytes
; i
++) {
152 while (srclen
>= 1 && skipSpace
&& (*src
== ' ' || *src
== '\t')){
156 if (underscoreok
&& srclen
> 1 && *src
== '_') {
157 /* srclen > 1 means not last character */
164 return "no data bytes specified by input";
171 * @brief ttodata - convert text to data
174 * @param srclen 0 means apply strlen()
175 * @param base 0 means figure it out
176 * @param dst need not be valid if dstlen is 0
178 * @param lenp where to record length (NULL is nowhere)
179 * @return NULL on success, else literal
181 const char *ttodata(const char *src
, size_t srclen
, int base
, char *dst
, size_t dstlen
, size_t *lenp
)
183 return ttodatav(src
, srclen
, base
, dst
, dstlen
, lenp
, (char *)NULL
,
184 (size_t)0, TTODATAV_SPACECOUNTS
);
188 * @brief atodata - convert ASCII to data
190 * backward-compatibility interface
196 * @return 0 for failure, true length for success
198 size_t atodata(const char *src
, size_t srclen
, char *dst
, size_t dstlen
)
203 err
= ttodata(src
, srclen
, 0, dst
, dstlen
, &len
);
210 * @brief atobytes - convert ASCII to data bytes
212 * another backward-compatibility interface
214 const char *atobytes(const char *src
, size_t srclen
, char *dst
, size_t dstlen
, size_t *lenp
)
216 return ttodata(src
, srclen
, 0, dst
, dstlen
, lenp
);
220 * @brief unhex - convert two ASCII hex digits to byte
222 * @param src known to be full length
223 * @param dstnumber of result bytes, or error code
224 * @param dstlen not large enough is a failure
227 static int unhex(const char *src
, char *dst
, size_t dstlen
)
231 static char hex
[] = "0123456789abcdef";
236 p
= strchr(hex
, *src
);
238 p
= strchr(hex
, tolower(*src
));
241 byte
= (p
- hex
) << 4;
244 p
= strchr(hex
, *src
);
246 p
= strchr(hex
, tolower(*src
));
256 * @brief unb64 - convert four ASCII base64 digits to three bytes
258 * Note that a base64 digit group is padded out with '=' if it represents
259 * less than three bytes: one byte is dd==, two is ddd=, three is dddd.
261 * @param src known to be full length
264 * @return number of result bytes, or error code
266 static int unb64(const char *src
, char *dst
, size_t dstlen
)
271 static char base64
[] =
272 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
277 p
= strchr(base64
, *src
++);
281 byte1
= (p
- base64
) << 2; /* first six bits */
283 p
= strchr(base64
, *src
++);
288 byte2
= p
- base64
; /* next six: two plus four */
289 *dst
++ = byte1
| (byte2
>> 4);
290 byte1
= (byte2
& 0xf) << 4;
292 p
= strchr(base64
, *src
++);
294 if (*(src
-1) == '=' && *src
== '=') {
295 if (byte1
!= 0) /* bad padding */
302 byte2
= p
- base64
; /* next six: four plus two */
303 *dst
++ = byte1
| (byte2
>> 2);
304 byte1
= (byte2
& 0x3) << 6;
306 p
= strchr(base64
, *src
++);
308 if (*(src
-1) == '=') {
309 if (byte1
!= 0) /* bad padding */
315 byte2
= p
- base64
; /* last six */
316 *dst
++ = byte1
| byte2
;
322 * @brief untext - convert one ASCII character to byte
324 * @param src known to be full length
326 * @param dstlen not large enough is a failure
327 * @return number of result bytes, or error code
329 static int untext(const char *src
, char *dst
, size_t dstlen
)
339 * @brief badch - produce a nice complaint about an unknown character
341 * If the compiler complains that the array bigenough[] has a negative
342 * size, that means the TTODATAV_BUF constant has been set too small.
346 * @param errp might be NULL
348 * @return literal or errp
350 static const char *badch(const char *src
, int errcode
, char *errp
, size_t errlen
)
352 static const char pre
[] = "unknown character (`";
353 static const char suf
[] = "') in input";
355 # define REQD (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf))
357 char bigenough
[TTODATAV_BUF
- REQD
]; /* see above */
361 if (errp
== NULL
|| errlen
< REQD
)
362 return "unknown character in input";
364 ch
= *(src
+ BADOFF(errcode
));
370 buf
[1] = ((ch
& 0700) >> 6) + '0';
371 buf
[2] = ((ch
& 0070) >> 3) + '0';
372 buf
[3] = ((ch
& 0007) >> 0) + '0';
377 return (const char *)errp
;