1 /* $Id: mimestream.hh,v 1.7 2005/07/02 14:53:59 atterer Exp $ -*- C++ -*-
3 |_) /| Copyright (C) 2000-2002 | richard@
4 | \/¯| Richard Atterer | atterer.net
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License, version 2. See
8 the file COPYING for details.
12 Convert binary data to/from ASCII using Base64 encoding
23 # define INLINE inline
35 //______________________________________________________________________
37 /** Convert binary data to Base64 and output. Note that this does
38 *not* implement the RFC2045 requirement that lines of text be no
39 longer than 76 characters each. Furthermore, by default the data
40 is not terminated with any '='.
42 Output is a class offering the following:
43 void put(char c); // Output one ASCII character
44 typedef implementation_defined ResultType;
45 ResultType result(); // Is called by Base64Out::result()
47 template <class Output>
50 Base64Out() : bits(0) { }
51 typename Output::ResultType result() { return out.result(); }
53 /** Output operators */
54 Base64Out<Output>& operator<<(char x) { return put(x); }
55 Base64Out<Output>& operator<<(signed char x) { return put(x); }
56 Base64Out<Output>& operator<<(unsigned char x) { return put(x); }
57 /** Output the low 8 bits of an integer */
58 Base64Out<Output>& operator<<(int x) { return put(x); }
59 /** Output 32 bit integer in little-endian order */
60 Base64Out<Output>& operator<<(uint32 x) { return put(x); }
62 /** Output null-terminated string */
63 inline Base64Out<Output>& operator<<(const char* x);
64 inline Base64Out<Output>& operator<<(const signed char* x);
65 Base64Out<Output>& operator<<(const unsigned char* x);
66 inline Base64Out<Output>& operator<<(const void* x);
68 /** Output 1 character */
69 inline Base64Out<Output>& put(unsigned char x);
70 inline Base64Out<Output>& put(signed char x);
71 /** Output the low 8 bits of an integer */
72 inline Base64Out<Output>& put(int x);
73 inline Base64Out<Output>& put(char x);
74 /** Output 32 bit integer in little-endian order */
75 Base64Out<Output>& put(uint32 x);
76 /** Output n characters */
77 inline Base64Out<Output>& write(const char* x, unsigned n);
78 inline Base64Out<Output>& write(const signed char* x, unsigned n);
79 Base64Out<Output>& write(const unsigned char* x, unsigned n);
80 inline Base64Out<Output>& write(const void* x, unsigned n);
82 /** This is *not* a no-op. */
83 Base64Out<Output>& flush();
84 /** Output the appropriate number of '=' characters (0, 1 or 2)
85 given how many bytes were fed into the Base64Out<Output> object. */
86 Base64Out<Output>& trailer(streamsize n);
88 /** A bit of a hack for jigdo: If true, switch from Base64 output to
89 hexadecimal output. Default is false. */
93 /* String for MIME base64 encoding. Not entirely standard because b64
94 strings are used as filenames by jigdo. Additionally, "+" or "/" looks
95 weird in the .jigdo file. */
96 static const char* const code;
97 static const char* const hexCode;
102 //______________________________________________________________________
104 /** Output base64 data to a std::string. */
105 class Base64StringOut {
107 void put(char c) { val += c; }
108 typedef string& ResultType;
109 string& result() { return val; }
110 const string& result() const { return val; }
115 /** A string which you can output to with "str << 1234" or
116 "str.write(buf, 4096)". */
117 typedef Base64Out<Base64StringOut> Base64String;
118 //______________________________________________________________________
120 // Support functions to allow things like "b64Stream << flush;"
122 template <class Output>
123 inline Base64Out<Output>& flush(Base64Out<Output>& s) {
127 template <class Output>
128 inline Base64Out<Output>& operator<<(Base64Out<Output>& s,
129 Base64Out<Output>& (*m)(Base64Out<Output>&)) {
132 //______________________________________________________________________
134 template <class Output>
135 bool Base64Out<Output>::hex = false;
136 template <class Output>
137 const char* const Base64Out<Output>::code =
138 //"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
139 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
140 template <class Output>
141 const char* const Base64Out<Output>::hexCode = "0123456789abcdef";
143 template <class Output>
144 Base64Out<Output>& Base64Out<Output>::operator<<(const char* x) {
145 return (*this) << reinterpret_cast<const unsigned char*>(x);
147 template <class Output>
148 Base64Out<Output>& Base64Out<Output>::operator<<(const signed char* x) {
149 return (*this) << reinterpret_cast<const unsigned char*>(x);
151 template <class Output>
152 Base64Out<Output>& Base64Out<Output>::operator<<(const void* x) {
153 return (*this) << static_cast<const unsigned char*>(x);
156 template <class Output>
157 Base64Out<Output>& Base64Out<Output>::put(unsigned char x) {
159 out.put(hexCode[(x >> 4) & 15U]);
160 out.put(hexCode[x & 15U]);
163 data = (data << 8) | x;
164 bits += 2; // plus 8 new bits, less 6 which we output in next line
165 out.put(code[(data >> bits) & 63U]);
166 if (bits >= 6) { //8?
168 out.put(code[(data >> bits) & 63U]);
172 template <class Output>
173 Base64Out<Output>& Base64Out<Output>::put(signed char x) {
174 return put(static_cast<unsigned char>(x));
176 template <class Output>
177 Base64Out<Output>& Base64Out<Output>::put(char x) {
178 return put(static_cast<unsigned char>(x));
180 template <class Output>
181 Base64Out<Output>& Base64Out<Output>::put(int x) {
182 return put(static_cast<unsigned char>(x));
185 template <class Output>
186 Base64Out<Output>& Base64Out<Output>::write(const char* x, unsigned n) {
187 return write(reinterpret_cast<const unsigned char*>(x), n);
189 template <class Output>
190 Base64Out<Output>& Base64Out<Output>::write(const signed char* x, unsigned n) {
191 return write(reinterpret_cast<const unsigned char*>(x), n);
193 template <class Output>
194 Base64Out<Output>& Base64Out<Output>::write(const void* x, unsigned n) {
195 return write(static_cast<const unsigned char*>(x), n);
198 template <class Output>
199 Base64Out<Output>& Base64Out<Output>::put(uint32 x) {
201 .put(static_cast<unsigned char>(x & 0xff))
202 .put(static_cast<unsigned char>((x >> 8) & 0xff))
203 .put(static_cast<unsigned char>((x >> 16) & 0xff))
204 .put(static_cast<unsigned char>((x >> 24) & 0xff));
208 template <class Output>
209 Base64Out<Output>& Base64Out<Output>::flush() {
212 out.put(code[data & 63U]);
218 template <class Output>
219 Base64Out<Output>& Base64Out<Output>::trailer(streamsize n) {
221 if (rest == 1) out.put('=');
222 if (rest >= 1) out.put('=');
226 // Output null-terminated string
227 template <class Output>
228 Base64Out<Output>& Base64Out<Output>::operator<<(const unsigned char* x) {
230 (*this) << static_cast<byte>(*x++);
234 // Output n characters
235 template <class Output>
236 Base64Out<Output>& Base64Out<Output>::write(const unsigned char* x,
238 for (unsigned i = 0; i < n; ++i)
239 (*this) << static_cast<byte>(*x++);
242 //______________________________________________________________________
244 /** Convert a series of Base64 ASCII strings into binary data.
246 Output is a class offering the following:
247 - void put(byte b); // Output one byte of binary data
248 - typedef implementation_defined ResultType;
249 - ResultType result(); // Is called by Base64In::result() */
250 template <class Output>
253 Base64In() : bits(0), data(0) { }
254 typename Output::ResultType result() { return out.result(); }
256 /** Output operators, for handing in the ASCII Base64 string. */
257 Base64In<Output>& operator<<(char x) { return put(x); }
258 /** Convert null-terminated string */
259 inline Base64In<Output>& operator<<(const char* x);
260 /** Convert string */
261 inline Base64In<Output>& operator<<(const string& x);
262 /** Output 1 character */
263 inline Base64In<Output>& put(char x);
264 /** Convert given number of characters */
265 Base64In<Output>& put(const char* x, unsigned n);
267 /** Return the object to its initial state */
268 void reset() { bits = 0; }
271 static const byte table[];
276 //______________________________________________________________________
278 /** Helper class for mimestream-test.cc, to convert base64 characters to
280 class Base64StringIn {
282 void put(byte b) { val.push_back(b); }
283 typedef vector<byte>& ResultType;
284 vector<byte>& result() { return val; }
289 typedef Base64In<Base64StringIn> Base64StringI;
290 //______________________________________________________________________
292 // Inverse mapping for both of these:
293 //"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
294 //"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
296 template <class Output>
297 const byte Base64In<Output>::table[] = {
298 // ! " # $ % & ' ( ) * + , - . /
299 x, x, x, x, x, x, x, x, x, x, x, 62, x, 62, x, 63,
300 //0 1 2 3 4 5 6 7 8 9 : ; < = > ?
301 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, x, x, x, x, x, x,
302 //@ A B C D E F G H I J K L M N O
303 x, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
304 //P Q R S T U V W x Y Z [ \ ] ^ _
305 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, x, x, x, x, 63,
306 //` a b c d e f g h i j k l m n o
307 x, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
308 //p q r s t u v w x y z { | } ~ DEL
309 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, x, x, x, x, x
313 template <class Output>
314 Base64In<Output>& Base64In<Output>::operator<<(const char* x) {
315 unsigned len = strlen(x);
319 template <class Output>
320 Base64In<Output>& Base64In<Output>::operator<<(const string& x) {
321 return put(x.data(), x.length());
324 template <class Output>
325 Base64In<Output>& Base64In<Output>::put(char x) {
329 template <class Output>
330 Base64In<Output>& Base64In<Output>::put(const char* x, unsigned n) {
334 unsigned code = static_cast<byte>(*x);
335 if (code < 32 || code > 127) continue; // Just ignore invalid characters
336 code = table[code - 32];
337 if (code > 63) continue;
338 data = (data << 6) | code;
342 out.put(static_cast<byte>((data >> bits) & 255U));