001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package org.apache.geronimo.util.encoders; 020 021 import java.io.IOException; 022 import java.io.OutputStream; 023 024 public class Base64Encoder 025 implements Encoder 026 { 027 protected final byte[] encodingTable = 028 { 029 (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', 030 (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', 031 (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', 032 (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', 033 (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', 034 (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', 035 (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', 036 (byte)'v', 037 (byte)'w', (byte)'x', (byte)'y', (byte)'z', 038 (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', 039 (byte)'7', (byte)'8', (byte)'9', 040 (byte)'+', (byte)'/' 041 }; 042 043 protected byte padding = (byte)'='; 044 045 /* 046 * set up the decoding table. 047 */ 048 protected final byte[] decodingTable = new byte[128]; 049 050 protected void initialiseDecodingTable() 051 { 052 for (int i = 0; i < encodingTable.length; i++) 053 { 054 decodingTable[encodingTable[i]] = (byte)i; 055 } 056 } 057 058 public Base64Encoder() 059 { 060 initialiseDecodingTable(); 061 } 062 063 /** 064 * encode the input data producing a base 64 output stream. 065 * 066 * @return the number of bytes produced. 067 */ 068 public int encode( 069 byte[] data, 070 int off, 071 int length, 072 OutputStream out) 073 throws IOException 074 { 075 int modulus = length % 3; 076 int dataLength = (length - modulus); 077 int a1, a2, a3; 078 079 for (int i = off; i < off + dataLength; i += 3) 080 { 081 a1 = data[i] & 0xff; 082 a2 = data[i + 1] & 0xff; 083 a3 = data[i + 2] & 0xff; 084 085 out.write(encodingTable[(a1 >>> 2) & 0x3f]); 086 out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]); 087 out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]); 088 out.write(encodingTable[a3 & 0x3f]); 089 } 090 091 /* 092 * process the tail end. 093 */ 094 int b1, b2, b3; 095 int d1, d2; 096 097 switch (modulus) 098 { 099 case 0: /* nothing left to do */ 100 break; 101 case 1: 102 d1 = data[off + dataLength] & 0xff; 103 b1 = (d1 >>> 2) & 0x3f; 104 b2 = (d1 << 4) & 0x3f; 105 106 out.write(encodingTable[b1]); 107 out.write(encodingTable[b2]); 108 out.write(padding); 109 out.write(padding); 110 break; 111 case 2: 112 d1 = data[off + dataLength] & 0xff; 113 d2 = data[off + dataLength + 1] & 0xff; 114 115 b1 = (d1 >>> 2) & 0x3f; 116 b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f; 117 b3 = (d2 << 2) & 0x3f; 118 119 out.write(encodingTable[b1]); 120 out.write(encodingTable[b2]); 121 out.write(encodingTable[b3]); 122 out.write(padding); 123 break; 124 } 125 126 return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4); 127 } 128 129 private boolean ignore( 130 char c) 131 { 132 return (c == '\n' || c =='\r' || c == '\t' || c == ' '); 133 } 134 135 /** 136 * decode the base 64 encoded byte data writing it to the given output stream, 137 * whitespace characters will be ignored. 138 * 139 * @return the number of bytes produced. 140 */ 141 public int decode( 142 byte[] data, 143 int off, 144 int length, 145 OutputStream out) 146 throws IOException 147 { 148 byte[] bytes; 149 byte b1, b2, b3, b4; 150 int outLen = 0; 151 152 int end = off + length; 153 154 while (end > 0) 155 { 156 if (!ignore((char)data[end - 1])) 157 { 158 break; 159 } 160 161 end--; 162 } 163 164 int i = off; 165 int finish = end - 4; 166 167 while (i < finish) 168 { 169 while ((i < finish) && ignore((char)data[i])) 170 { 171 i++; 172 } 173 174 b1 = decodingTable[data[i++]]; 175 176 while ((i < finish) && ignore((char)data[i])) 177 { 178 i++; 179 } 180 181 b2 = decodingTable[data[i++]]; 182 183 while ((i < finish) && ignore((char)data[i])) 184 { 185 i++; 186 } 187 188 b3 = decodingTable[data[i++]]; 189 190 while ((i < finish) && ignore((char)data[i])) 191 { 192 i++; 193 } 194 195 b4 = decodingTable[data[i++]]; 196 197 out.write((b1 << 2) | (b2 >> 4)); 198 out.write((b2 << 4) | (b3 >> 2)); 199 out.write((b3 << 6) | b4); 200 201 outLen += 3; 202 } 203 204 if (data[end - 2] == padding) 205 { 206 b1 = decodingTable[data[end - 4]]; 207 b2 = decodingTable[data[end - 3]]; 208 209 out.write((b1 << 2) | (b2 >> 4)); 210 211 outLen += 1; 212 } 213 else if (data[end - 1] == padding) 214 { 215 b1 = decodingTable[data[end - 4]]; 216 b2 = decodingTable[data[end - 3]]; 217 b3 = decodingTable[data[end - 2]]; 218 219 out.write((b1 << 2) | (b2 >> 4)); 220 out.write((b2 << 4) | (b3 >> 2)); 221 222 outLen += 2; 223 } 224 else 225 { 226 b1 = decodingTable[data[end - 4]]; 227 b2 = decodingTable[data[end - 3]]; 228 b3 = decodingTable[data[end - 2]]; 229 b4 = decodingTable[data[end - 1]]; 230 231 out.write((b1 << 2) | (b2 >> 4)); 232 out.write((b2 << 4) | (b3 >> 2)); 233 out.write((b3 << 6) | b4); 234 235 outLen += 3; 236 } 237 238 return outLen; 239 } 240 241 /** 242 * decode the base 64 encoded String data writing it to the given output stream, 243 * whitespace characters will be ignored. 244 * 245 * @return the number of bytes produced. 246 */ 247 public int decode( 248 String data, 249 OutputStream out) 250 throws IOException 251 { 252 byte[] bytes; 253 byte b1, b2, b3, b4; 254 int length = 0; 255 256 int end = data.length(); 257 258 while (end > 0) 259 { 260 if (!ignore(data.charAt(end - 1))) 261 { 262 break; 263 } 264 265 end--; 266 } 267 268 int i = 0; 269 int finish = end - 4; 270 271 while (i < finish) 272 { 273 while ((i < finish) && ignore(data.charAt(i))) 274 { 275 i++; 276 } 277 278 b1 = decodingTable[data.charAt(i++)]; 279 280 while ((i < finish) && ignore(data.charAt(i))) 281 { 282 i++; 283 } 284 b2 = decodingTable[data.charAt(i++)]; 285 286 while ((i < finish) && ignore(data.charAt(i))) 287 { 288 i++; 289 } 290 b3 = decodingTable[data.charAt(i++)]; 291 292 while ((i < finish) && ignore(data.charAt(i))) 293 { 294 i++; 295 } 296 b4 = decodingTable[data.charAt(i++)]; 297 298 out.write((b1 << 2) | (b2 >> 4)); 299 out.write((b2 << 4) | (b3 >> 2)); 300 out.write((b3 << 6) | b4); 301 302 length += 3; 303 } 304 305 if (data.charAt(end - 2) == padding) 306 { 307 b1 = decodingTable[data.charAt(end - 4)]; 308 b2 = decodingTable[data.charAt(end - 3)]; 309 310 out.write((b1 << 2) | (b2 >> 4)); 311 312 length += 1; 313 } 314 else if (data.charAt(end - 1) == padding) 315 { 316 b1 = decodingTable[data.charAt(end - 4)]; 317 b2 = decodingTable[data.charAt(end - 3)]; 318 b3 = decodingTable[data.charAt(end - 2)]; 319 320 out.write((b1 << 2) | (b2 >> 4)); 321 out.write((b2 << 4) | (b3 >> 2)); 322 323 length += 2; 324 } 325 else 326 { 327 b1 = decodingTable[data.charAt(end - 4)]; 328 b2 = decodingTable[data.charAt(end - 3)]; 329 b3 = decodingTable[data.charAt(end - 2)]; 330 b4 = decodingTable[data.charAt(end - 1)]; 331 332 out.write((b1 << 2) | (b2 >> 4)); 333 out.write((b2 << 4) | (b3 >> 2)); 334 out.write((b3 << 6) | b4); 335 336 length += 3; 337 } 338 339 return length; 340 } 341 }