1 21 22 package org.armedbear.j.mail; 23 24 import java.io.ByteArrayOutputStream ; 25 import java.io.IOException ; 26 import java.io.OutputStream ; 27 import org.armedbear.j.Debug; 28 import org.armedbear.j.FastStringReader; 29 import org.armedbear.j.Log; 30 import org.armedbear.j.Utilities; 31 32 public final class Base64Decoder 33 { 34 private final static int BAD = 127; 35 private final static int END = -1; 36 37 public static boolean decode(String input, OutputStream outputStream) 38 throws IOException 39 { 40 FastStringReader reader = new FastStringReader(input); 41 String extra = null; 42 String s; 43 while ((s = reader.readLine()) != null) { 44 s = s.trim(); 45 if (extra != null) { 46 s = extra.concat(s); 47 extra = null; 48 } 49 int length = s.length(); 50 if ((length % 4) != 0) { 51 length = (length / 4) * 4; 52 extra = s.substring(length); 53 s = s.substring(0, length); 54 } 55 for (int i = 0; i < length; i += 4) { 56 if (i+4 < length) { 57 if (!decode(s, i, outputStream)) 59 return false; 60 } else { 61 if (!decodeFinal(s, i, outputStream)) 63 return false; 64 } 65 } 66 } 67 if (extra != null) 68 return decodeFinal(extra, 0, outputStream); 69 return true; 70 } 71 72 public static byte[] decode(String s) 73 { 74 try { 75 ByteArrayOutputStream out = new ByteArrayOutputStream (80); 76 int length = s.length(); 77 for (int i = 0; i < length; i += 4) { 78 if (i+4 < length) { 79 if (!decode(s, i, out)) 81 return null; 82 } else { 83 if (!decodeFinal(s, i, out)) 85 return null; 86 } 87 } 88 return out.toByteArray(); 89 } 90 catch (IOException e) { 91 Log.error(e); 92 return null; 93 } 94 } 95 96 private static boolean decode(String input, int offset, OutputStream out) 98 throws IOException 99 { 100 byte byte1 = values[input.charAt(offset)]; 102 if (byte1 == BAD) { 103 error(input, offset); 104 return false; 105 } 106 byte byte2 = values[input.charAt(offset+1)]; 107 if (byte2 == BAD) { 108 error(input, offset+1); 109 return false; 110 } 111 byte byte3 = values[input.charAt(offset+2)]; 112 if (byte3 == BAD) { 113 error(input, offset+2); 114 return false; 115 } 116 byte byte4 = values[input.charAt(offset+3)]; 117 if (byte4 == BAD) { 118 error(input, offset+3); 119 return false; 120 } 121 int n = (byte1 << 18) + (byte2 << 12) + (byte3 << 6) + byte4; 122 out.write((byte)(0xff & (n >> 16))); 123 out.write((byte)(0xff & (n >> 8))); 124 out.write((byte)(0xff & n)); 125 return true; 126 } 127 128 private static boolean decodeFinal(String input, int offset, 134 OutputStream out) throws IOException 135 { 136 byte b0 = 0; 137 byte b1 = 0; 138 byte b2 = 0; 139 byte b3 = 0; 140 int numPaddingChars = 0; 141 Debug.assertTrue(offset < input.length()); 142 b0 = values[input.charAt(offset)]; 143 if (b0 == END) 144 return true; if (b0 == BAD) { 146 error(input, offset); 147 return false; 148 } 149 if (offset + 1 >= input.length()) { 150 Log.error("Base64Decoder.decodeFinal premature end of input"); 151 error(input, offset + 1); 152 return false; 153 } 154 b1 = values[input.charAt(offset + 1)]; 155 if (b1 == END || b1 == BAD) { 156 error(input, offset + 1); 159 return false; 160 } 161 if (offset + 2 < input.length()) 162 b2 = values[input.charAt(offset + 2)]; 163 else 164 b2 = END; 165 if (b2 == BAD) { 166 error(input, offset + 2); 167 return false; 168 } 169 if (b2 == END) { 170 b2 = 0; 171 numPaddingChars = 2; 172 } else { 173 if (offset + 3 < input.length()) 175 b3 = values[input.charAt(offset + 3)]; 176 else 177 b3 = END; 178 if (b3 == BAD) { 179 error(input, offset + 3); 180 return false; 181 } 182 if (b3 == END) { 183 b3 = 0; 184 numPaddingChars = 1; 185 } 186 } 187 int n = (b0 << 18) | (b1 << 12) | (b2 << 6) | b3; 188 out.write((byte)(0xff & (n >> 16))); 189 if (numPaddingChars < 2) { 190 out.write((byte)(0xff & (n >> 8))); 191 if (numPaddingChars == 0) 192 out.write((byte)(0xff & n)); 193 } 194 return true; 195 } 196 197 private static void error(String input, int offset) 198 { 199 Log.error("Base64Decoder error at offset " + offset); 200 Log.error("Base64Decoder input = |" + input + "|"); 201 Log.error("Base64Decoder " + Utilities.spaces(offset) + '^'); 202 } 203 204 private static final byte values[] = 205 { 206 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 62, BAD, BAD, BAD, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, BAD, BAD, BAD, END, BAD, BAD, BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, BAD, BAD, BAD, BAD, BAD, BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 223 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 224 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 225 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 226 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 227 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 228 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 229 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 230 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 231 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 232 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 233 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 234 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 235 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 236 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 237 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD 238 }; 239 } 240 | Popular Tags |