]> git.ozlabs.org Git - ccan/blob - ccan/str/base32/base32.c
Fix "for loop initial declarations are only allowed in C99 mode" compile errors.
[ccan] / ccan / str / base32 / base32.c
1 /* CC0 license (public domain) - see LICENSE file for details */
2 #include "base32.h"
3 #include <assert.h>
4 #include <ccan/endian/endian.h>
5 #include <string.h> /* for memcpy, memset */
6
7 const char *base32_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
8
9 /* RFC 4648:
10  *
11  * (1) The final quantum of encoding input is an integral multiple of 40
12  *     bits; here, the final unit of encoded output will be an integral
13  *     multiple of 8 characters with no "=" padding.
14  *
15  * (2) The final quantum of encoding input is exactly 8 bits; here, the
16  *     final unit of encoded output will be two characters followed by
17  *     six "=" padding characters.
18  *
19  * (3) The final quantum of encoding input is exactly 16 bits; here, the
20  *     final unit of encoded output will be four characters followed by
21  *     four "=" padding characters.
22  *
23  * (4) The final quantum of encoding input is exactly 24 bits; here, the
24  *     final unit of encoded output will be five characters followed by
25  *     three "=" padding characters.
26  *
27  * (5) The final quantum of encoding input is exactly 32 bits; here, the
28  *     final unit of encoded output will be seven characters followed by
29  *     one "=" padding character.
30  */
31 static size_t padlen(size_t remainder)
32 {
33         switch (remainder) {
34         case 0:
35                 return 0;
36         case 1:
37                 return 6;
38         case 2:
39                 return 4;
40         case 3:
41                 return 3;
42         case 4:
43                 return 1;
44         default:
45                 abort();
46         }
47 }
48
49 size_t base32_str_size(size_t bytes)
50 {
51         return (bytes + 4) / 5 * 8 + 1;
52 }
53
54 size_t base32_data_size(const char *str, size_t strlen)
55 {
56         /* 8 chars == 5 bytes, round up to avoid overflow even though
57          * not required for well-formed strings. */
58         size_t max = (strlen + 7) / 8 * 5, padding = 0;
59
60         /* Count trailing padding bytes. */
61         while (strlen && str[strlen-1] == base32_chars[32] && padding < 6) {
62                 strlen--;
63                 padding++;
64         }
65
66         return max - (padding * 5 + 7)  / 8;
67 }
68
69 static bool decode_8_chars(const char c[8], beint64_t *res, int *bytes)
70 {
71         uint64_t acc = 0;
72         size_t num_pad = 0;
73         int i;
74         for (i = 0; i < 8; i++) {
75                 const char *p;
76
77                 acc <<= 5;
78                 p = memchr(base32_chars, c[i], 32);
79                 if (!p) {
80                         if (c[i] == base32_chars[32]) {
81                                 num_pad++;
82                                 continue;
83                         }
84                         return false;
85                 }
86                 /* Can't have padding then non-pad */
87                 if (num_pad)
88                         return false;
89                 acc |= (p - base32_chars);
90         }
91         *res = cpu_to_be64(acc);
92
93         /* Can't have 2 or 5 padding bytes */
94         if (num_pad == 5 || num_pad == 2)
95                 return false;
96         *bytes = (40 - num_pad * 5) / 8;
97         return true;
98 }
99
100 bool base32_decode(const char *str, size_t slen, void *buf, size_t bufsize)
101 {
102         while (slen >= 8) {
103                 beint64_t val;
104                 int bytes;
105                 if (!decode_8_chars(str, &val, &bytes))
106                         return false;
107                 str += 8;
108                 slen -= 8;
109                 /* Copy bytes into dst. */
110                 if (bufsize < bytes)
111                         return false;
112                 memcpy(buf, (char *)&val + 3, bytes);
113                 buf = (char *)buf + bytes;
114                 bufsize -= bytes;
115         }
116         return slen == 0 && bufsize == 0;
117 }
118
119 static void encode_8_chars(char *dest, const uint8_t *buf, int bytes)
120 {
121         beint64_t val = 0;
122         uint64_t res;
123         int bits = bytes * 8;
124
125         assert(bytes > 0 && bytes <= 5);
126         memcpy((char *)&val + 3, buf, bytes);
127         res = be64_to_cpu(val);
128
129         while (bits > 0) {
130                 *dest = base32_chars[(res >> 35) & 0x1F];
131                 dest++;
132                 res <<= 5;
133                 bits -= 5;
134         }
135
136         if (bytes != 5)
137                 memset(dest, base32_chars[32], padlen(bytes));
138 }
139
140 bool base32_encode(const void *buf, size_t bufsize, char *dest, size_t destsize)
141 {
142         while (bufsize) {
143                 int bytes = 5;
144
145                 if (bytes > bufsize)
146                         bytes = bufsize;
147
148                 if (destsize < 8)
149                         return false;
150                 encode_8_chars(dest, buf, bytes);
151                 buf = (const char *)buf + bytes;
152                 bufsize -= bytes;
153                 destsize -= 8;
154                 dest += 8;
155         }
156         if (destsize != 1)
157                 return false;
158         *dest = '\0';
159         return true;
160 }