chiark / gitweb /
Hands-off reader type
[disorder] / lib / base64.c
1 /*
2  * This file is part of DisOrder
3  * Copyright (C) 2005, 2007, 2008 Richard Kettlewell
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /** @file lib/base64.c
19  * @brief Support for MIME base64
20  */
21
22 #include "common.h"
23
24 #include "mem.h"
25 #include "base64.h"
26 #include "vector.h"
27
28 static const char mime_base64_table[] =
29   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
30
31 /** @brief Convert MIME base64
32  * @param s base64 data
33  * @param nsp Where to store length of converted data
34  * @return Decoded data
35  *
36  * See <a href="http://tools.ietf.org/html/rfc2045#section-6.8">RFC
37  * 2045 s6.8</a>.
38  */
39 char *mime_base64(const char *s, size_t *nsp) {
40   return generic_base64(s, nsp, mime_base64_table);
41 }
42
43 /** @brief Convert base64
44  * @param s base64 data
45  * @param nsp Where to store length of converted data
46  * @param table Table of characters to use
47  * @return Decoded data
48  *
49  * @p table should consist of 65 characters.  The first 64 will be used to
50  * represents the 64 digits and the 65th will be used as padding at the end
51  * (i.e. the role of '=' in RFC2045 base64).
52  */
53 char *generic_base64(const char *s, size_t *nsp, const char *table) {
54   struct dynstr d;
55   const char *t;
56   int b[4], n, c;
57
58   dynstr_init(&d);
59   n = 0;
60   while((c = (unsigned char)*s++)) {
61     if(c == table[64]) {
62       if(n >= 2) {
63         dynstr_append(&d, (b[0] << 2) + (b[1] >> 4));
64         if(n == 3)
65           dynstr_append(&d, (b[1] << 4) + (b[2] >> 2));
66       }
67       break;
68     } else if((t = strchr(table, c))) {
69       b[n++] = t - table;
70       if(n == 4) {
71         dynstr_append(&d, (b[0] << 2) + (b[1] >> 4));
72         dynstr_append(&d, (b[1] << 4) + (b[2] >> 2));
73         dynstr_append(&d, (b[2] << 6) + b[3]);
74         n = 0;
75       }
76     }
77   }
78   if(nsp)
79     *nsp = d.nvec;
80   dynstr_terminate(&d);
81   return d.vec;
82 }
83
84 /** @brief Convert a binary string to MIME base64
85  * @param s Bytes to convert
86  * @param ns Number of bytes to convert
87  * @return Encoded data
88  *
89  * This function does not attempt to split up lines.
90  *
91  * See <a href="http://tools.ietf.org/html/rfc2045#section-6.8">RFC
92  * 2045 s6.8</a>.
93  */
94 char *mime_to_base64(const uint8_t *s, size_t ns) {
95   return generic_to_base64(s, ns, mime_base64_table);
96 }
97
98 /** @brief Convert a binary string to base64
99  * @param s Bytes to convert
100  * @param ns Number of bytes to convert
101  * @param table Table of characters to use
102  * @return Encoded data
103  *
104  * This function does not attempt to split up lines.
105  *
106  * @p table should consist of 65 characters.  The first 64 will be used to
107  * represents the 64 digits and the 65th will be used as padding at the end
108  * (i.e. the role of '=' in RFC2045 base64).
109  */
110 char *generic_to_base64(const uint8_t *s, size_t ns, const char *table) {
111   struct dynstr d[1];
112
113   dynstr_init(d);
114   while(ns >= 3) {
115     /* Input bytes with output bits: AAAAAABB BBBBCCCC CCDDDDDD */
116     /* Output bytes with input bits: 000000 001111 111122 222222 */
117     dynstr_append(d, table[s[0] >> 2]);
118     dynstr_append(d, table[((s[0] & 3) << 4)
119                                        + (s[1] >> 4)]);
120     dynstr_append(d, table[((s[1] & 15) << 2)
121                                        + (s[2] >> 6)]);
122     dynstr_append(d, table[s[2] & 63]);
123     ns -= 3;
124     s += 3;
125   }
126   if(ns > 0) {
127     dynstr_append(d, table[s[0] >> 2]);
128     switch(ns) {
129     case 1:
130       dynstr_append(d, table[(s[0] & 3) << 4]);
131       dynstr_append(d, table[64]);
132       dynstr_append(d, table[64]);
133       break;
134     case 2:
135       dynstr_append(d, table[((s[0] & 3) << 4)
136                                          + (s[1] >> 4)]);
137       dynstr_append(d, table[(s[1] & 15) << 2]);
138       dynstr_append(d, table[64]);
139       break;
140     }
141   }
142   dynstr_terminate(d);
143   return d->vec;
144 }
145
146 /*
147 Local Variables:
148 c-basic-offset:2
149 comment-column:40
150 fill-column:79
151 End:
152 */