1 package org.bouncycastle.util.encoders; 2 3 import java.io.IOException; 4 import java.io.OutputStream; 5 6 public class Base64Encoder 7 implements Encoder 8 { 9 protected final byte[] encodingTable = 10 { 11 (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', 12 (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', 13 (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', 14 (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', 15 (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', 16 (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', 17 (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', 18 (byte)'v', 19 (byte)'w', (byte)'x', (byte)'y', (byte)'z', 20 (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', 21 (byte)'7', (byte)'8', (byte)'9', 22 (byte)'+', (byte)'/' 23 }; 24 25 protected byte padding = (byte)'='; 26 27 /* 28 * set up the decoding table. 29 */ 30 protected final byte[] decodingTable = new byte[128]; 31 32 protected void initialiseDecodingTable() 33 { 34 for (int i = 0; i < encodingTable.length; i++) 35 { 36 decodingTable[encodingTable[i]] = (byte)i; 37 } 38 } 39 40 public Base64Encoder() 41 { 42 initialiseDecodingTable(); 43 } 44 45 /** 46 * encode the input data producing a base 64 output stream. 47 * 48 * @return the number of bytes produced. 49 */ 50 public int encode( 51 byte[] data, 52 int off, 53 int length, 54 OutputStream out) 55 throws IOException 56 { 57 int modulus = length % 3; 58 int dataLength = (length - modulus); 59 int a1, a2, a3; 60 61 for (int i = off; i < off + dataLength; i += 3) 62 { 63 a1 = data[i] & 0xff; 64 a2 = data[i + 1] & 0xff; 65 a3 = data[i + 2] & 0xff; 66 67 out.write(encodingTable[(a1 >>> 2) & 0x3f]); 68 out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]); 69 out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]); 70 out.write(encodingTable[a3 & 0x3f]); 71 } 72 73 /* 74 * process the tail end. 75 */ 76 int b1, b2, b3; 77 int d1, d2; 78 79 switch (modulus) 80 { 81 case 0: /* nothing left to do */ 82 break; 83 case 1: 84 d1 = data[off + dataLength] & 0xff; 85 b1 = (d1 >>> 2) & 0x3f; 86 b2 = (d1 << 4) & 0x3f; 87 88 out.write(encodingTable[b1]); 89 out.write(encodingTable[b2]); 90 out.write(padding); 91 out.write(padding); 92 break; 93 case 2: 94 d1 = data[off + dataLength] & 0xff; 95 d2 = data[off + dataLength + 1] & 0xff; 96 97 b1 = (d1 >>> 2) & 0x3f; 98 b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f; 99 b3 = (d2 << 2) & 0x3f; 100 101 out.write(encodingTable[b1]); 102 out.write(encodingTable[b2]); 103 out.write(encodingTable[b3]); 104 out.write(padding); 105 break; 106 } 107 108 return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4); 109 } 110 111 private boolean ignore( 112 char c) 113 { 114 return (c == '\n' || c =='\r' || c == '\t' || c == ' '); 115 } 116 117 /** 118 * decode the base 64 encoded byte data writing it to the given output stream, 119 * whitespace characters will be ignored. 120 * 121 * @return the number of bytes produced. 122 */ 123 public int decode( 124 byte[] data, 125 int off, 126 int length, 127 OutputStream out) 128 throws IOException 129 { 130 byte b1, b2, b3, b4; 131 int outLen = 0; 132 133 int end = off + length; 134 135 while (end > off) 136 { 137 if (!ignore((char)data[end - 1])) 138 { 139 break; 140 } 141 142 end--; 143 } 144 145 int i = off; 146 int finish = end - 4; 147 148 i = nextI(data, i, finish); 149 150 while (i < finish) 151 { 152 b1 = decodingTable[data[i++]]; 153 154 i = nextI(data, i, finish); 155 156 b2 = decodingTable[data[i++]]; 157 158 i = nextI(data, i, finish); 159 160 b3 = decodingTable[data[i++]]; 161 162 i = nextI(data, i, finish); 163 164 b4 = decodingTable[data[i++]]; 165 166 out.write((b1 << 2) | (b2 >> 4)); 167 out.write((b2 << 4) | (b3 >> 2)); 168 out.write((b3 << 6) | b4); 169 170 outLen += 3; 171 172 i = nextI(data, i, finish); 173 } 174 175 outLen += decodeLastBlock(out, (char)data[end - 4], (char)data[end - 3], (char)data[end - 2], (char)data[end - 1]); 176 177 return outLen; 178 } 179 180 private int nextI(byte[] data, int i, int finish) 181 { 182 while ((i < finish) && ignore((char)data[i])) 183 { 184 i++; 185 } 186 return i; 187 } 188 189 /** 190 * decode the base 64 encoded String data writing it to the given output stream, 191 * whitespace characters will be ignored. 192 * 193 * @return the number of bytes produced. 194 */ 195 public int decode( 196 String data, 197 OutputStream out) 198 throws IOException 199 { 200 byte b1, b2, b3, b4; 201 int length = 0; 202 203 int end = data.length(); 204 205 while (end > 0) 206 { 207 if (!ignore(data.charAt(end - 1))) 208 { 209 break; 210 } 211 212 end--; 213 } 214 215 int i = 0; 216 int finish = end - 4; 217 218 i = nextI(data, i, finish); 219 220 while (i < finish) 221 { 222 b1 = decodingTable[data.charAt(i++)]; 223 224 i = nextI(data, i, finish); 225 226 b2 = decodingTable[data.charAt(i++)]; 227 228 i = nextI(data, i, finish); 229 230 b3 = decodingTable[data.charAt(i++)]; 231 232 i = nextI(data, i, finish); 233 234 b4 = decodingTable[data.charAt(i++)]; 235 236 out.write((b1 << 2) | (b2 >> 4)); 237 out.write((b2 << 4) | (b3 >> 2)); 238 out.write((b3 << 6) | b4); 239 240 length += 3; 241 242 i = nextI(data, i, finish); 243 } 244 245 length += decodeLastBlock(out, data.charAt(end - 4), data.charAt(end - 3), data.charAt(end - 2), data.charAt(end - 1)); 246 247 return length; 248 } 249 250 private int decodeLastBlock(OutputStream out, char c1, char c2, char c3, char c4) 251 throws IOException 252 { 253 byte b1, b2, b3, b4; 254 255 if (c3 == padding) 256 { 257 b1 = decodingTable[c1]; 258 b2 = decodingTable[c2]; 259 260 out.write((b1 << 2) | (b2 >> 4)); 261 262 return 1; 263 } 264 else if (c4 == padding) 265 { 266 b1 = decodingTable[c1]; 267 b2 = decodingTable[c2]; 268 b3 = decodingTable[c3]; 269 270 out.write((b1 << 2) | (b2 >> 4)); 271 out.write((b2 << 4) | (b3 >> 2)); 272 273 return 2; 274 } 275 else 276 { 277 b1 = decodingTable[c1]; 278 b2 = decodingTable[c2]; 279 b3 = decodingTable[c3]; 280 b4 = decodingTable[c4]; 281 282 out.write((b1 << 2) | (b2 >> 4)); 283 out.write((b2 << 4) | (b3 >> 2)); 284 out.write((b3 << 6) | b4); 285 286 return 3; 287 } 288 } 289 290 private int nextI(String data, int i, int finish) 291 { 292 while ((i < finish) && ignore(data.charAt(i))) 293 { 294 i++; 295 } 296 return i; 297 } 298 } 299