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