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