1 /**
2 * Base64-enabled input and output streams
3 *
4 * This class allows easy encoding and decoding
5 * of Base64 data with a stream interface, hiding
6 * the implementation from the user.
7 *
8 * Authors:
9 * Bob Jamison <rjamison@titan.com>
10 *
11 * Copyright (C) 2004 Inkscape.org
12 *
13 * Released under GNU GPL, read the file 'COPYING' for more information
14 */
16 #include "base64stream.h"
20 namespace Inkscape
21 {
22 namespace IO
23 {
25 //#########################################################################
26 //# B A S E 6 4 I N P U T S T R E A M
27 //#########################################################################
29 static int base64decode[] =
30 {
31 /*00*/ -1, -1, -1, -1, -1, -1, -1, -1,
32 /*08*/ -1, -1, -1, -1, -1, -1, -1, -1,
33 /*10*/ -1, -1, -1, -1, -1, -1, -1, -1,
34 /*18*/ -1, -1, -1, -1, -1, -1, -1, -1,
35 /*20*/ -1, -1, -1, -1, -1, -1, -1, -1,
36 /*28*/ -1, -1, -1, 62, -1, -1, -1, 63,
37 /*30*/ 52, 53, 54, 55, 56, 57, 58, 59,
38 /*38*/ 60, 61, -1, -1, -1, -1, -1, -1,
39 /*40*/ -1, 0, 1, 2, 3, 4, 5, 6,
40 /*48*/ 7, 8, 9, 10, 11, 12, 13, 14,
41 /*50*/ 15, 16, 17, 18, 19, 20, 21, 22,
42 /*58*/ 23, 24, 25, -1, -1, -1, -1, -1,
43 /*60*/ -1, 26, 27, 28, 29, 30, 31, 32,
44 /*68*/ 33, 34, 35, 36, 37, 38, 39, 40,
45 /*70*/ 41, 42, 43, 44, 45, 46, 47, 48,
46 /*78*/ 49, 50, 51, -1, -1, -1, -1, -1
47 };
50 /**
51 *
52 */
53 Base64InputStream::Base64InputStream(InputStream &sourceStream)
54 : BasicInputStream(sourceStream)
55 {
56 outCount = 0;
57 padCount = 0;
58 closed = false;
59 done = false;
60 }
62 /**
63 *
64 */
65 Base64InputStream::~Base64InputStream()
66 {
67 close();
68 }
70 /**
71 * Returns the number of bytes that can be read (or skipped over) from
72 * this input stream without blocking by the next caller of a method for
73 * this input stream.
74 */
75 int Base64InputStream::available()
76 {
77 if (closed )
78 return 0;
79 int len = source.available() * 2 / 3;
80 return len;
81 }
84 /**
85 * Closes this input stream and releases any system resources
86 * associated with the stream.
87 */
88 void Base64InputStream::close()
89 {
90 if (closed)
91 return;
92 source.close();
93 closed = true;
94 }
96 /**
97 * Reads the next byte of data from the input stream. -1 if EOF
98 */
99 int Base64InputStream::get()
100 {
101 if (closed)
102 return -1;
104 if (outCount - padCount > 0)
105 {
106 return outBytes[3-(outCount--)];
107 }
109 if (done)
110 return -1;
112 int inBytes[4];
113 int inCount = 0;
114 while (inCount < 4)
115 {
116 int ch = source.get();
117 if (ch < 0)
118 {
119 while (inCount < 4) //pad if needed
120 {
121 inBytes[inCount++] = 0;
122 padCount++;
123 }
124 done = true;
125 break;
126 }
127 if (isspace(ch)) //ascii whitespace
128 {
129 //nothing
130 }
131 else if (ch == '=') //padding
132 {
133 inBytes[inCount++] = 0;
134 padCount++;
135 }
136 else
137 {
138 int byteVal = base64decode[ch & 0x7f];
139 //printf("char:%c %d\n", ch, byteVal);
140 if (byteVal < 0)
141 {
142 //Bad lookup value
143 }
144 inBytes[inCount++] = byteVal;
145 }
146 }
148 outBytes[0] = ((inBytes[0]<<2) & 0xfc) | ((inBytes[1]>>4) & 0x03);
149 outBytes[1] = ((inBytes[1]<<4) & 0xf0) | ((inBytes[2]>>2) & 0x0f);
150 outBytes[2] = ((inBytes[2]<<6) & 0xc0) | ((inBytes[3] ) & 0x3f);
152 outCount = 3;
154 //try again
155 if (outCount - padCount > 0)
156 {
157 return outBytes[3-(outCount--)];
158 }
160 return -1;
162 }
165 //#########################################################################
166 //# B A S E 6 4 O U T P U T S T R E A M
167 //#########################################################################
169 static char *base64encode =
170 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
172 /**
173 *
174 */
175 Base64OutputStream::Base64OutputStream(OutputStream &destinationStream)
176 : BasicOutputStream(destinationStream)
177 {
178 column = 0;
179 columnWidth = 72;
180 outBuf = 0L;
181 bitCount = 0;
182 }
184 /**
185 *
186 */
187 Base64OutputStream::~Base64OutputStream()
188 {
189 close();
190 }
192 /**
193 * Closes this output stream and releases any system resources
194 * associated with this stream.
195 */
196 void Base64OutputStream::close()
197 {
198 if (closed)
199 return;
201 //get any last bytes (1 or 2) out of the buffer
202 if (bitCount == 16)
203 {
204 outBuf <<= 2; //pad to make 18 bits
206 int indx = (int)((outBuf & 0x0003f000L) >> 12);
207 int obyte = (int)base64encode[indx & 63];
208 putCh(obyte);
210 indx = (int)((outBuf & 0x00000fc0L) >> 6);
211 obyte = (int)base64encode[indx & 63];
212 putCh(obyte);
214 indx = (int)((outBuf & 0x0000003fL) );
215 obyte = (int)base64encode[indx & 63];
216 putCh(obyte);
218 putCh('=');
219 }
220 else if (bitCount == 8)
221 {
222 outBuf <<= 4; //pad to make 12 bits
224 int indx = (int)((outBuf & 0x00000fc0L) >> 6);
225 int obyte = (int)base64encode[indx & 63];
226 putCh(obyte);
228 indx = (int)((outBuf & 0x0000003fL) );
229 obyte = (int)base64encode[indx & 63];
230 putCh(obyte);
232 putCh('=');
233 putCh('=');
234 }
236 if (columnWidth > 0) //if <=0, no newlines
237 destination.put('\n');
239 destination.close();
240 closed = true;
241 }
243 /**
244 * Flushes this output stream and forces any buffered output
245 * bytes to be written out.
246 */
247 void Base64OutputStream::flush()
248 {
249 if (closed)
250 return;
251 //dont flush here. do it on close()
252 destination.flush();
253 }
255 /**
256 * Private. Put a char to the output stream, checking for line length
257 */
258 void Base64OutputStream::putCh(int ch)
259 {
260 destination.put(ch);
261 column++;
262 if (columnWidth > 0 && column >= columnWidth)
263 {
264 destination.put('\n');
265 column = 0;
266 }
267 }
270 /**
271 * Writes the specified byte to this output stream.
272 */
273 void Base64OutputStream::put(int ch)
274 {
275 if (closed)
276 {
277 //probably throw an exception here
278 return;
279 }
281 outBuf <<= 8;
282 outBuf |= (ch & 0xff);
283 bitCount += 8;
284 if (bitCount >= 24)
285 {
286 int indx = (int)((outBuf & 0x00fc0000L) >> 18);
287 int obyte = (int)base64encode[indx & 63];
288 putCh(obyte);
290 indx = (int)((outBuf & 0x0003f000L) >> 12);
291 obyte = (int)base64encode[indx & 63];
292 putCh(obyte);
294 indx = (int)((outBuf & 0x00000fc0L) >> 6);
295 obyte = (int)base64encode[indx & 63];
296 putCh(obyte);
298 indx = (int)((outBuf & 0x0000003fL) );
299 obyte = (int)base64encode[indx & 63];
300 putCh(obyte);
302 bitCount = 0;
303 outBuf = 0L;
304 }
305 }
309 } // namespace IO
310 } // namespace Inkscape
313 //#########################################################################
314 //# E N D O F F I L E
315 //#########################################################################