chiark / gitweb /
Columns are now resizable and wide columns are ellipsized. Columns
[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 2 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, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * 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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20 /** @file lib/base64.c
21  * @brief Support for MIME base64
22  */
23
24 #include "common.h"
25
26 #include "mem.h"
27 #include "base64.h"
28 #include "vector.h"
29
30 static const char mime_base64_table[] =
31   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
32
33 /** @brief Convert MIME base64
34  * @param s base64 data
35  * @param nsp Where to store length of converted data
36  * @return Decoded data
37  *
38  * See <a href="http://tools.ietf.org/html/rfc2045#section-6.8">RFC
39  * 2045 s6.8</a>.
40  */
41 char *mime_base64(const char *s, size_t *nsp) {
42   return generic_base64(s, nsp, mime_base64_table);
43 }
44
45 /** @brief Convert base64
46  * @param s base64 data
47  * @param nsp Where to store length of converted data
48  * @param table Table of characters to use
49  * @return Decoded data
50  *
51  * @p table should consist of 65 characters.  The first 64 will be used to
52  * represents the 64 digits and the 65th will be used as padding at the end
53  * (i.e. the role of '=' in RFC2045 base64).
54  */
55 char *generic_base64(const char *s, size_t *nsp, const char *table) {
56   struct dynstr d;
57   const char *t;
58   int b[4], n, c;
59
60   dynstr_init(&d);
61   n = 0;
62   while((c = (unsigned char)*s++)) {
63     if(c == table[64]) {
64       if(n >= 2) {
65         dynstr_append(&d, (b[0] << 2) + (b[1] >> 4));
66         if(n == 3)
67           dynstr_append(&d, (b[1] << 4) + (b[2] >> 2));
68       }
69       break;
70     } else if((t = strchr(table, c))) {
71       b[n++] = t - table;
72       if(n == 4) {
73         dynstr_append(&d, (b[0] << 2) + (b[1] >> 4));
74         dynstr_append(&d, (b[1] << 4) + (b[2] >> 2));
75         dynstr_append(&d, (b[2] << 6) + b[3]);
76         n = 0;
77       }
78     }
79   }
80   if(nsp)
81     *nsp = d.nvec;
82   dynstr_terminate(&d);
83   return d.vec;
84 }
85
86 /** @brief Convert a binary string to MIME base64
87  * @param s Bytes to convert
88  * @param ns Number of bytes to convert
89  * @return Encoded data
90  *
91  * This function does not attempt to split up lines.
92  *
93  * See <a href="http://tools.ietf.org/html/rfc2045#section-6.8">RFC
94  * 2045 s6.8</a>.
95  */
96 char *mime_to_base64(const uint8_t *s, size_t ns) {
97   return generic_to_base64(s, ns, mime_base64_table);
98 }
99
100 /** @brief Convert a binary string to base64
101  * @param s Bytes to convert
102  * @param ns Number of bytes to convert
103  * @param table Table of characters to use
104  * @return Encoded data
105  *
106  * This function does not attempt to split up lines.
107  *
108  * @p table should consist of 65 characters.  The first 64 will be used to
109  * represents the 64 digits and the 65th will be used as padding at the end
110  * (i.e. the role of '=' in RFC2045 base64).
111  */
112 char *generic_to_base64(const uint8_t *s, size_t ns, const char *table) {
113   struct dynstr d[1];
114
115   dynstr_init(d);
116   while(ns >= 3) {
117     /* Input bytes with output bits: AAAAAABB BBBBCCCC CCDDDDDD */
118     /* Output bytes with input bits: 000000 001111 111122 222222 */
119     dynstr_append(d, table[s[0] >> 2]);
120     dynstr_append(d, table[((s[0] & 3) << 4)
121                                        + (s[1] >> 4)]);
122     dynstr_append(d, table[((s[1] & 15) << 2)
123                                        + (s[2] >> 6)]);
124     dynstr_append(d, table[s[2] & 63]);
125     ns -= 3;
126     s += 3;
127   }
128   if(ns > 0) {
129     dynstr_append(d, table[s[0] >> 2]);
130     switch(ns) {
131     case 1:
132       dynstr_append(d, table[(s[0] & 3) << 4]);
133       dynstr_append(d, table[64]);
134       dynstr_append(d, table[64]);
135       break;
136     case 2:
137       dynstr_append(d, table[((s[0] & 3) << 4)
138                                          + (s[1] >> 4)]);
139       dynstr_append(d, table[(s[1] & 15) << 2]);
140       dynstr_append(d, table[64]);
141       break;
142     }
143   }
144   dynstr_terminate(d);
145   return d->vec;
146 }
147
148 /*
149 Local Variables:
150 c-basic-offset:2
151 comment-column:40
152 fill-column:79
153 End:
154 */