1 /**
2 * Phoebe DOM Implementation.
3 *
4 * Base64-enabled input and output streams
5 *
6 * This class allows easy encoding and decoding
7 * of Base64 data with a stream interface, hiding
8 * the implementation from the user.
9 *
10 * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
11 *
12 * Authors:
13 * Bob Jamison
14 *
15 * Copyright (C) 2006 Bob Jamison
16 *
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License as published by the Free Software Foundation; either
20 * version 2.1 of the License, or (at your option) any later version.
21 *
22 * This library is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 */
34 #include "base64stream.h"
37 namespace org
38 {
39 namespace w3c
40 {
41 namespace dom
42 {
43 namespace io
44 {
47 //#########################################################################
48 //# B A S E 6 4 I N P U T S T R E A M
49 //#########################################################################
51 static int base64decode[] =
52 {
53 /*00*/ -1, -1, -1, -1, -1, -1, -1, -1,
54 /*08*/ -1, -1, -1, -1, -1, -1, -1, -1,
55 /*10*/ -1, -1, -1, -1, -1, -1, -1, -1,
56 /*18*/ -1, -1, -1, -1, -1, -1, -1, -1,
57 /*20*/ -1, -1, -1, -1, -1, -1, -1, -1,
58 /*28*/ -1, -1, -1, 62, -1, -1, -1, 63,
59 /*30*/ 52, 53, 54, 55, 56, 57, 58, 59,
60 /*38*/ 60, 61, -1, -1, -1, -1, -1, -1,
61 /*40*/ -1, 0, 1, 2, 3, 4, 5, 6,
62 /*48*/ 7, 8, 9, 10, 11, 12, 13, 14,
63 /*50*/ 15, 16, 17, 18, 19, 20, 21, 22,
64 /*58*/ 23, 24, 25, -1, -1, -1, -1, -1,
65 /*60*/ -1, 26, 27, 28, 29, 30, 31, 32,
66 /*68*/ 33, 34, 35, 36, 37, 38, 39, 40,
67 /*70*/ 41, 42, 43, 44, 45, 46, 47, 48,
68 /*78*/ 49, 50, 51, -1, -1, -1, -1, -1
69 };
72 /**
73 *
74 */
75 Base64InputStream::Base64InputStream(InputStream &sourceStream)
76 : BasicInputStream(sourceStream)
77 {
78 outCount = 0;
79 padCount = 0;
80 closed = false;
81 done = false;
82 }
84 /**
85 *
86 */
87 Base64InputStream::~Base64InputStream()
88 {
89 close();
90 }
92 /**
93 * Returns the number of bytes that can be read (or skipped over) from
94 * this input stream without blocking by the next caller of a method for
95 * this input stream.
96 */
97 int Base64InputStream::available()
98 {
99 if (closed )
100 return 0;
101 int len = source.available() * 2 / 3;
102 return len;
103 }
106 /**
107 * Closes this input stream and releases any system resources
108 * associated with the stream.
109 */
110 void Base64InputStream::close()
111 {
112 if (closed)
113 return;
114 source.close();
115 closed = true;
116 }
118 /**
119 * Reads the next byte of data from the input stream. -1 if EOF
120 */
121 int Base64InputStream::get()
122 {
123 if (closed)
124 return -1;
126 if (outCount - padCount > 0)
127 {
128 return outBytes[3-(outCount--)];
129 }
131 if (done)
132 return -1;
134 int inBytes[4];
135 int inCount = 0;
136 while (inCount < 4)
137 {
138 int ch = source.get();
139 if (ch < 0)
140 {
141 while (inCount < 4) //pad if needed
142 {
143 inBytes[inCount++] = 0;
144 padCount++;
145 }
146 done = true;
147 break;
148 }
149 if (isspace(ch)) //ascii whitespace
150 {
151 //nothing
152 }
153 else if (ch == '=') //padding
154 {
155 inBytes[inCount++] = 0;
156 padCount++;
157 }
158 else
159 {
160 int byteVal = base64decode[ch & 0x7f];
161 //printf("char:%c %d\n", ch, byteVal);
162 if (byteVal < 0)
163 {
164 //Bad lookup value
165 }
166 inBytes[inCount++] = byteVal;
167 }
168 }
170 outBytes[0] = ((inBytes[0]<<2) & 0xfc) | ((inBytes[1]>>4) & 0x03);
171 outBytes[1] = ((inBytes[1]<<4) & 0xf0) | ((inBytes[2]>>2) & 0x0f);
172 outBytes[2] = ((inBytes[2]<<6) & 0xc0) | ((inBytes[3] ) & 0x3f);
174 outCount = 3;
176 //try again
177 if (outCount - padCount > 0)
178 {
179 return outBytes[3-(outCount--)];
180 }
182 return -1;
184 }
187 //#########################################################################
188 //# B A S E 6 4 O U T P U T S T R E A M
189 //#########################################################################
191 static char *base64encode =
192 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
194 /**
195 *
196 */
197 Base64OutputStream::Base64OutputStream(OutputStream &destinationStream)
198 : BasicOutputStream(destinationStream)
199 {
200 column = 0;
201 columnWidth = 72;
202 outBuf = 0L;
203 bitCount = 0;
204 }
206 /**
207 *
208 */
209 Base64OutputStream::~Base64OutputStream()
210 {
211 close();
212 }
214 /**
215 * Closes this output stream and releases any system resources
216 * associated with this stream.
217 */
218 void Base64OutputStream::close()
219 {
220 if (closed)
221 return;
223 //get any last bytes (1 or 2) out of the buffer
224 if (bitCount == 16)
225 {
226 outBuf <<= 2; //pad to make 18 bits
228 int indx = (int)((outBuf & 0x0003f000L) >> 12);
229 int obyte = (int)base64encode[indx & 63];
230 putCh(obyte);
232 indx = (int)((outBuf & 0x00000fc0L) >> 6);
233 obyte = (int)base64encode[indx & 63];
234 putCh(obyte);
236 indx = (int)((outBuf & 0x0000003fL) );
237 obyte = (int)base64encode[indx & 63];
238 putCh(obyte);
240 putCh('=');
241 }
242 else if (bitCount == 8)
243 {
244 outBuf <<= 4; //pad to make 12 bits
246 int indx = (int)((outBuf & 0x00000fc0L) >> 6);
247 int obyte = (int)base64encode[indx & 63];
248 putCh(obyte);
250 indx = (int)((outBuf & 0x0000003fL) );
251 obyte = (int)base64encode[indx & 63];
252 putCh(obyte);
254 putCh('=');
255 putCh('=');
256 }
258 if (columnWidth > 0) //if <=0, no newlines
259 destination.put('\n');
261 destination.close();
262 closed = true;
263 }
265 /**
266 * Flushes this output stream and forces any buffered output
267 * bytes to be written out.
268 */
269 void Base64OutputStream::flush()
270 {
271 if (closed)
272 return;
273 //dont flush here. do it on close()
274 destination.flush();
275 }
277 /**
278 * Private. Put a char to the output stream, checking for line length
279 */
280 void Base64OutputStream::putCh(int ch)
281 {
282 destination.put(ch);
283 column++;
284 if (columnWidth > 0 && column >= columnWidth)
285 {
286 destination.put('\n');
287 column = 0;
288 }
289 }
292 /**
293 * Writes the specified byte to this output stream.
294 */
295 int Base64OutputStream::put(XMLCh ch)
296 {
297 if (closed)
298 {
299 //probably throw an exception here
300 return -1;
301 }
303 outBuf <<= 8;
304 outBuf |= (ch & 0xff);
305 bitCount += 8;
306 if (bitCount >= 24)
307 {
308 int indx = (int)((outBuf & 0x00fc0000L) >> 18);
309 int obyte = (int)base64encode[indx & 63];
310 putCh(obyte);
312 indx = (int)((outBuf & 0x0003f000L) >> 12);
313 obyte = (int)base64encode[indx & 63];
314 putCh(obyte);
316 indx = (int)((outBuf & 0x00000fc0L) >> 6);
317 obyte = (int)base64encode[indx & 63];
318 putCh(obyte);
320 indx = (int)((outBuf & 0x0000003fL) );
321 obyte = (int)base64encode[indx & 63];
322 putCh(obyte);
324 bitCount = 0;
325 outBuf = 0L;
326 }
328 return 1;
329 }
333 } //namespace io
334 } //namespace dom
335 } //namespace w3c
336 } //namespace org
339 //#########################################################################
340 //# E N D O F F I L E
341 //#########################################################################