1 21 22 27 28 package javax.mail.internet; 29 30 import javax.mail.MessagingException ; 31 import javax.activation.*; 32 import java.util.*; 33 import java.io.*; 34 import com.sun.mail.util.*; 35 36 114 115 public class MimeUtility { 116 117 private MimeUtility() { } 119 120 public static final int ALL = -1; 121 122 private static boolean decodeStrict = true; 123 private static boolean encodeEolStrict = false; 124 private static boolean foldEncodedWords = false; 125 private static boolean foldText = true; 126 127 static { 128 try { 129 String s = System.getProperty("mail.mime.decodetext.strict"); 130 decodeStrict = s == null || !s.equalsIgnoreCase("false"); 132 s = System.getProperty("mail.mime.encodeeol.strict"); 133 encodeEolStrict = s != null && s.equalsIgnoreCase("true"); 135 s = System.getProperty("mail.mime.foldencodedwords"); 136 foldEncodedWords = s != null && s.equalsIgnoreCase("true"); 138 s = System.getProperty("mail.mime.foldtext"); 139 foldText = s == null || !s.equalsIgnoreCase("false"); 141 } catch (SecurityException sex) { 142 } 144 } 145 146 147 170 public static String getEncoding(DataSource ds) { 171 ContentType cType = null; 172 InputStream is = null; 173 String encoding = null; 174 175 try { 176 cType = new ContentType (ds.getContentType()); 177 is = ds.getInputStream(); 178 } catch (Exception ex) { 179 return "base64"; } 181 182 boolean isText = cType.match("text/*"); 183 int i = checkAscii(is, ALL, !isText); 185 switch (i) { 186 case ALL_ASCII: 187 encoding = "7bit"; break; 189 case MOSTLY_ASCII: 190 encoding = "quoted-printable"; break; 192 default: 193 encoding = "base64"; break; 195 } 196 197 try { 199 is.close(); 200 } catch (IOException ioex) { } 201 202 return encoding; 203 } 204 205 218 public static String getEncoding(DataHandler dh) { 219 ContentType cType = null; 220 String encoding = null; 221 222 235 if (dh.getName() != null) 236 return getEncoding(dh.getDataSource()); 237 238 try { 239 cType = new ContentType (dh.getContentType()); 240 } catch (Exception ex) { 241 return "base64"; } 243 244 if (cType.match("text/*")) { 245 AsciiOutputStream aos = new AsciiOutputStream(false, false); 247 try { 248 dh.writeTo(aos); 249 } catch (IOException ex) { } switch (aos.getAscii()) { 251 case ALL_ASCII: 252 encoding = "7bit"; break; 254 case MOSTLY_ASCII: 255 encoding = "quoted-printable"; break; 257 default: 258 encoding = "base64"; break; 260 } 261 } else { AsciiOutputStream aos = 265 new AsciiOutputStream(true, encodeEolStrict); 266 try { 267 dh.writeTo(aos); 268 } catch (IOException ex) { } if (aos.getAscii() == ALL_ASCII) encoding = "7bit"; 271 else encoding = "base64"; 273 } 274 275 return encoding; 276 } 277 278 289 public static InputStream decode(InputStream is, String encoding) 290 throws MessagingException { 291 if (encoding.equalsIgnoreCase("base64")) 292 return new BASE64DecoderStream(is); 293 else if (encoding.equalsIgnoreCase("quoted-printable")) 294 return new QPDecoderStream(is); 295 else if (encoding.equalsIgnoreCase("uuencode") || 296 encoding.equalsIgnoreCase("x-uuencode") || 297 encoding.equalsIgnoreCase("x-uue")) 298 return new UUDecoderStream(is); 299 else if (encoding.equalsIgnoreCase("binary") || 300 encoding.equalsIgnoreCase("7bit") || 301 encoding.equalsIgnoreCase("8bit")) 302 return is; 303 else 304 throw new MessagingException ("Unknown encoding: " + encoding); 305 } 306 307 318 public static OutputStream encode(OutputStream os, String encoding) 319 throws MessagingException { 320 if (encoding == null) 321 return os; 322 else if (encoding.equalsIgnoreCase("base64")) 323 return new BASE64EncoderStream(os); 324 else if (encoding.equalsIgnoreCase("quoted-printable")) 325 return new QPEncoderStream(os); 326 else if (encoding.equalsIgnoreCase("uuencode") || 327 encoding.equalsIgnoreCase("x-uuencode") || 328 encoding.equalsIgnoreCase("x-uue")) 329 return new UUEncoderStream(os); 330 else if (encoding.equalsIgnoreCase("binary") || 331 encoding.equalsIgnoreCase("7bit") || 332 encoding.equalsIgnoreCase("8bit")) 333 return os; 334 else 335 throw new MessagingException ("Unknown encoding: " +encoding); 336 } 337 338 354 public static OutputStream encode(OutputStream os, String encoding, 355 String filename) 356 throws MessagingException { 357 if (encoding == null) 358 return os; 359 else if (encoding.equalsIgnoreCase("base64")) 360 return new BASE64EncoderStream(os); 361 else if (encoding.equalsIgnoreCase("quoted-printable")) 362 return new QPEncoderStream(os); 363 else if (encoding.equalsIgnoreCase("uuencode") || 364 encoding.equalsIgnoreCase("x-uuencode") || 365 encoding.equalsIgnoreCase("x-uue")) 366 return new UUEncoderStream(os, filename); 367 else if (encoding.equalsIgnoreCase("binary") || 368 encoding.equalsIgnoreCase("7bit") || 369 encoding.equalsIgnoreCase("8bit")) 370 return os; 371 else 372 throw new MessagingException ("Unknown encoding: " +encoding); 373 } 374 375 411 public static String encodeText(String text) 412 throws UnsupportedEncodingException { 413 return encodeText(text, null, null); 414 } 415 416 441 public static String encodeText(String text, String charset, 442 String encoding) 443 throws UnsupportedEncodingException { 444 return encodeWord(text, charset, encoding, false); 445 } 446 447 479 public static String decodeText(String etext) 480 throws UnsupportedEncodingException { 481 486 String lwsp = " \t\n\r"; 487 StringTokenizer st; 488 489 498 if (etext.indexOf("=?") == -1) 499 return etext; 500 501 503 st = new StringTokenizer(etext, lwsp, true); 504 StringBuffer sb = new StringBuffer (); StringBuffer wsb = new StringBuffer (); boolean prevWasEncoded = false; 507 508 while (st.hasMoreTokens()) { 509 char c; 510 String s = st.nextToken(); 511 if (((c = s.charAt(0)) == ' ') || (c == '\t') || 513 (c == '\r') || (c == '\n')) 514 wsb.append(c); 515 else { 516 String word; 518 try { 519 word = decodeWord(s); 520 if (!prevWasEncoded && wsb.length() > 0) { 522 sb.append(wsb); 526 } 527 prevWasEncoded = true; 528 } catch (ParseException pex) { 529 word = s; 531 if (!decodeStrict) 533 word = decodeInnerWords(word); 534 if (wsb.length() > 0) 536 sb.append(wsb); 537 prevWasEncoded = false; 538 } 539 sb.append(word); wsb.setLength(0); } 542 } 543 return sb.toString(); 544 } 545 546 567 public static String encodeWord(String word) 568 throws UnsupportedEncodingException { 569 return encodeWord(word, null, null); 570 } 571 572 594 public static String encodeWord(String word, String charset, 595 String encoding) 596 throws UnsupportedEncodingException { 597 return encodeWord(word, charset, encoding, true); 598 } 599 600 607 private static String encodeWord(String string, String charset, 608 String encoding, boolean encodingWord) 609 throws UnsupportedEncodingException { 610 611 int ascii = checkAscii(string); 614 if (ascii == ALL_ASCII) 615 return string; 616 617 String jcharset; 619 if (charset == null) { jcharset = getDefaultJavaCharset(); charset = getDefaultMIMECharset(); } else jcharset = javaCharset(charset); 624 625 if (encoding == null) { 627 if (ascii != MOSTLY_NONASCII) 628 encoding = "Q"; 629 else 630 encoding = "B"; 631 } 632 633 boolean b64; 634 if (encoding.equalsIgnoreCase("B")) 635 b64 = true; 636 else if (encoding.equalsIgnoreCase("Q")) 637 b64 = false; 638 else 639 throw new UnsupportedEncodingException( 640 "Unknown transfer encoding: " + encoding); 641 642 StringBuffer outb = new StringBuffer (); doEncode(string, b64, jcharset, 644 75 - 7 - charset.length(), "=?" + charset + "?" + encoding + "?", true, encodingWord, outb); 650 651 return outb.toString(); 652 } 653 654 private static void doEncode(String string, boolean b64, 655 String jcharset, int avail, String prefix, 656 boolean first, boolean encodingWord, StringBuffer buf) 657 throws UnsupportedEncodingException { 658 659 byte[] bytes = string.getBytes(jcharset); 662 int len; 663 if (b64) len = BEncoderStream.encodedLength(bytes); 665 else len = QEncoderStream.encodedLength(bytes, encodingWord); 667 668 int size; 669 if ((len > avail) && ((size = string.length()) > 1)) { 670 doEncode(string.substring(0, size/2), b64, jcharset, 673 avail, prefix, first, encodingWord, buf); 674 doEncode(string.substring(size/2, size), b64, jcharset, 675 avail, prefix, false, encodingWord, buf); 676 } else { 677 ByteArrayOutputStream os = new ByteArrayOutputStream(); 679 OutputStream eos; if (b64) eos = new BEncoderStream(os); 682 else eos = new QEncoderStream(os, encodingWord); 684 685 try { eos.write(bytes); 687 eos.close(); 688 } catch (IOException ioex) { } 689 690 byte[] encodedBytes = os.toByteArray(); if (!first) if (foldEncodedWords) 695 buf.append("\r\n "); else 697 buf.append(" "); 699 buf.append(prefix); 700 for (int i = 0; i < encodedBytes.length; i++) 701 buf.append((char)encodedBytes[i]); 702 buf.append("?="); } 704 } 705 706 719 public static String decodeWord(String eword) 720 throws ParseException , UnsupportedEncodingException { 721 722 if (!eword.startsWith("=?")) throw new ParseException (); 724 725 int start = 2; int pos; 727 if ((pos = eword.indexOf('?', start)) == -1) 728 throw new ParseException (); 729 String charset = javaCharset(eword.substring(start, pos)); 730 731 start = pos+1; 733 if ((pos = eword.indexOf('?', start)) == -1) 734 throw new ParseException (); 735 String encoding = eword.substring(start, pos); 736 737 start = pos+1; 739 if ((pos = eword.indexOf("?=", start)) == -1) 740 throw new ParseException (); 741 String word = eword.substring(start, pos); 742 743 try { 744 String decodedWord; 745 if (word.length() > 0) { 746 ByteArrayInputStream bis = 748 new ByteArrayInputStream(ASCIIUtility.getBytes(word)); 749 750 InputStream is; 752 if (encoding.equalsIgnoreCase("B")) 753 is = new BASE64DecoderStream(bis); 754 else if (encoding.equalsIgnoreCase("Q")) 755 is = new QDecoderStream(bis); 756 else 757 throw new UnsupportedEncodingException( 758 "unknown encoding: " + encoding); 759 760 int count = bis.available(); 766 byte[] bytes = new byte[count]; 767 count = is.read(bytes, 0, count); 769 770 decodedWord = count <= 0 ? "" : 773 new String (bytes, 0, count, charset); 774 } else { 775 decodedWord = ""; 777 } 778 if (pos + 2 < eword.length()) { 779 String rest = eword.substring(pos + 2); 781 if (!decodeStrict) 782 rest = decodeInnerWords(rest); 783 decodedWord += rest; 784 } 785 return decodedWord; 786 } catch (UnsupportedEncodingException uex) { 787 throw uex; 790 } catch (IOException ioex) { 791 throw new ParseException (); 793 } catch (IllegalArgumentException iex) { 794 801 throw new UnsupportedEncodingException(); 802 } 803 } 804 805 810 private static String decodeInnerWords(String word) 811 throws UnsupportedEncodingException { 812 int start = 0, i; 813 StringBuffer buf = new StringBuffer (); 814 while ((i = word.indexOf("=?", start)) >= 0) { 815 buf.append(word.substring(start, i)); 816 int end = word.indexOf("?=", i); 817 if (end < 0) 818 break; 819 String s = word.substring(i, end + 2); 820 try { 821 s = decodeWord(s); 822 } catch (ParseException pex) { 823 } 825 buf.append(s); 826 start = end + 2; 827 } 828 if (start == 0) 829 return word; 830 if (start < word.length()) 831 buf.append(word.substring(start)); 832 return buf.toString(); 833 } 834 835 851 public static String quote(String word, String specials) { 852 int len = word.length(); 853 854 858 boolean needQuoting = false; 859 for (int i = 0; i < len; i++) { 860 char c = word.charAt(i); 861 if (c == '"' || c == '\\' || c == '\r' || c == '\n') { 862 StringBuffer sb = new StringBuffer (len + 3); 864 sb.append('"'); 865 sb.append(word.substring(0, i)); 866 int lastc = 0; 867 for (int j = i; j < len; j++) { 868 char cc = word.charAt(j); 869 if ((cc == '"') || (cc == '\\') || 870 (cc == '\r') || (cc == '\n')) 871 if (cc == '\n' && lastc == '\r') 872 ; else 874 sb.append('\\'); sb.append(cc); 876 lastc = cc; 877 } 878 sb.append('"'); 879 return sb.toString(); 880 } else if (c < 040 || c >= 0177 || specials.indexOf(c) >= 0) 881 needQuoting = true; 883 } 884 885 if (needQuoting) { 886 StringBuffer sb = new StringBuffer (len + 2); 887 sb.append('"').append(word).append('"'); 888 return sb.toString(); 889 } else 890 return word; 891 } 892 893 909 public static String fold(int used, String s) { 910 if (!foldText) 911 return s; 912 913 int end; 914 char c; 915 for (end = s.length() - 1; end >= 0; end--) { 917 c = s.charAt(end); 918 if (c != ' ' && c != '\t' && c != '\r' && c != '\n') 919 break; 920 } 921 if (end != s.length() - 1) 922 s = s.substring(0, end + 1); 923 924 if (used + s.length() <= 76) 926 return s; 927 928 StringBuffer sb = new StringBuffer (s.length() + 4); 930 char lastc = 0; 931 while (used + s.length() > 76) { 932 int lastspace = -1; 933 for (int i = 0; i < s.length(); i++) { 934 if (lastspace != -1 && used + i > 76) 935 break; 936 c = s.charAt(i); 937 if (c == ' ' || c == '\t') 938 if (!(lastc == ' ' || lastc == '\t')) 939 lastspace = i; 940 lastc = c; 941 } 942 if (lastspace == -1) { 943 sb.append(s); 945 s = ""; 946 used = 0; 947 break; 948 } 949 sb.append(s.substring(0, lastspace)); 950 sb.append("\r\n"); 951 lastc = s.charAt(lastspace); 952 sb.append(lastc); 953 s = s.substring(lastspace + 1); 954 used = 1; 955 } 956 sb.append(s); 957 return sb.toString(); 958 } 959 960 968 public static String unfold(String s) { 969 if (!foldText) 970 return s; 971 972 StringBuffer sb = null; 973 int i; 974 while ((i = indexOfAny(s, "\r\n")) >= 0) { 975 int start = i; 976 int l = s.length(); 977 i++; if (i < l && s.charAt(i - 1) == '\r' && s.charAt(i) == '\n') 979 i++; if (start == 0 || s.charAt(start - 1) != '\\') { 981 char c; 982 if (i < l && ((c = s.charAt(i)) == ' ' || c == '\t')) { 985 i++; while (i < l && ((c = s.charAt(i)) == ' ' || c == '\t')) 987 i++; 988 if (sb == null) 989 sb = new StringBuffer (s.length()); 990 if (start != 0) { 991 sb.append(s.substring(0, start)); 992 sb.append(' '); 993 } 994 s = s.substring(i); 995 continue; 996 } 997 if (sb == null) 999 sb = new StringBuffer (s.length()); 1000 sb.append(s.substring(0, i)); 1001 s = s.substring(i); 1002 } else { 1003 if (sb == null) 1006 sb = new StringBuffer (s.length()); 1007 sb.append(s.substring(0, start - 1)); 1008 sb.append(s.substring(start, i)); 1009 s = s.substring(i); 1010 } 1011 } 1012 if (sb != null) { 1013 sb.append(s); 1014 return sb.toString(); 1015 } else 1016 return s; 1017 } 1018 1019 1025 private static int indexOfAny(String s, String any) { 1026 return indexOfAny(s, any, 0); 1027 } 1028 1029 private static int indexOfAny(String s, String any, int start) { 1030 try { 1031 int len = s.length(); 1032 for (int i = start; i < len; i++) { 1033 if (any.indexOf(s.charAt(i)) >= 0) 1034 return i; 1035 } 1036 return -1; 1037 } catch (StringIndexOutOfBoundsException e) { 1038 return -1; 1039 } 1040 } 1041 1042 1049 public static String javaCharset(String charset) { 1050 if (mime2java == null || charset == null) 1051 return charset; 1053 1054 String alias = (String )mime2java.get(charset.toLowerCase()); 1055 return alias == null ? charset : alias; 1056 } 1057 1058 1071 public static String mimeCharset(String charset) { 1072 if (java2mime == null || charset == null) 1073 return charset; 1075 1076 String alias = (String )java2mime.get(charset.toLowerCase()); 1077 return alias == null ? charset : alias; 1078 } 1079 1080 private static String defaultJavaCharset; 1081 private static String defaultMIMECharset; 1082 1083 1093 public static String getDefaultJavaCharset() { 1094 if (defaultJavaCharset == null) { 1095 1099 String mimecs = null; 1100 try { 1101 mimecs = System.getProperty("mail.mime.charset"); 1102 } catch (SecurityException ex) { } if (mimecs != null && mimecs.length() > 0) { 1104 defaultJavaCharset = javaCharset(mimecs); 1105 return defaultJavaCharset; 1106 } 1107 1108 try { 1109 defaultJavaCharset = System.getProperty("file.encoding", 1110 "8859_1"); 1111 } catch (SecurityException sex) { 1112 1113 class NullInputStream extends InputStream { 1114 public int read() { 1115 return 0; 1116 } 1117 } 1118 InputStreamReader reader = 1119 new InputStreamReader(new NullInputStream()); 1120 defaultJavaCharset = reader.getEncoding(); 1121 if (defaultJavaCharset == null) 1122 defaultJavaCharset = "8859_1"; 1123 } 1124 } 1125 1126 return defaultJavaCharset; 1127 } 1128 1129 1132 static String getDefaultMIMECharset() { 1133 if (defaultMIMECharset == null) { 1134 try { 1135 defaultMIMECharset = System.getProperty("mail.mime.charset"); 1136 } catch (SecurityException ex) { } } 1138 if (defaultMIMECharset == null) 1139 defaultMIMECharset = mimeCharset(getDefaultJavaCharset()); 1140 return defaultMIMECharset; 1141 } 1142 1143 private static Hashtable mime2java; 1146 private static Hashtable java2mime; 1147 1148 static { 1149 java2mime = new Hashtable(40); 1150 mime2java = new Hashtable(10); 1151 1152 try { 1153 InputStream is = 1156 javax.mail.internet.MimeUtility .class.getResourceAsStream( 1157 "/META-INF/javamail.charset.map"); 1158 1159 if (is != null) { 1160 try { 1161 is = new LineInputStream(is); 1162 1163 loadMappings((LineInputStream)is, java2mime); 1165 1166 loadMappings((LineInputStream)is, mime2java); 1168 } finally { 1169 try { 1170 is.close(); 1171 } catch (Exception cex) { 1172 } 1174 } 1175 } 1176 } catch (Exception ex) { } 1177 1178 if (java2mime.isEmpty()) { 1182 java2mime.put("8859_1", "ISO-8859-1"); 1183 java2mime.put("iso8859_1", "ISO-8859-1"); 1184 java2mime.put("iso8859-1", "ISO-8859-1"); 1185 1186 java2mime.put("8859_2", "ISO-8859-2"); 1187 java2mime.put("iso8859_2", "ISO-8859-2"); 1188 java2mime.put("iso8859-2", "ISO-8859-2"); 1189 1190 java2mime.put("8859_3", "ISO-8859-3"); 1191 java2mime.put("iso8859_3", "ISO-8859-3"); 1192 java2mime.put("iso8859-3", "ISO-8859-3"); 1193 1194 java2mime.put("8859_4", "ISO-8859-4"); 1195 java2mime.put("iso8859_4", "ISO-8859-4"); 1196 java2mime.put("iso8859-4", "ISO-8859-4"); 1197 1198 java2mime.put("8859_5", "ISO-8859-5"); 1199 java2mime.put("iso8859_5", "ISO-8859-5"); 1200 java2mime.put("iso8859-5", "ISO-8859-5"); 1201 1202 java2mime.put("8859_6", "ISO-8859-6"); 1203 java2mime.put("iso8859_6", "ISO-8859-6"); 1204 java2mime.put("iso8859-6", "ISO-8859-6"); 1205 1206 java2mime.put("8859_7", "ISO-8859-7"); 1207 java2mime.put("iso8859_7", "ISO-8859-7"); 1208 java2mime.put("iso8859-7", "ISO-8859-7"); 1209 1210 java2mime.put("8859_8", "ISO-8859-8"); 1211 java2mime.put("iso8859_8", "ISO-8859-8"); 1212 java2mime.put("iso8859-8", "ISO-8859-8"); 1213 1214 java2mime.put("8859_9", "ISO-8859-9"); 1215 java2mime.put("iso8859_9", "ISO-8859-9"); 1216 java2mime.put("iso8859-9", "ISO-8859-9"); 1217 1218 java2mime.put("sjis", "Shift_JIS"); 1219 java2mime.put("jis", "ISO-2022-JP"); 1220 java2mime.put("iso2022jp", "ISO-2022-JP"); 1221 java2mime.put("euc_jp", "euc-jp"); 1222 java2mime.put("koi8_r", "koi8-r"); 1223 java2mime.put("euc_cn", "euc-cn"); 1224 java2mime.put("euc_tw", "euc-tw"); 1225 java2mime.put("euc_kr", "euc-kr"); 1226 } 1227 if (mime2java.isEmpty()) { 1228 mime2java.put("iso-2022-cn", "ISO2022CN"); 1229 mime2java.put("iso-2022-kr", "ISO2022KR"); 1230 mime2java.put("utf-8", "UTF8"); 1231 mime2java.put("utf8", "UTF8"); 1232 mime2java.put("ja_jp.iso2022-7", "ISO2022JP"); 1233 mime2java.put("ja_jp.eucjp", "EUCJIS"); 1234 mime2java.put("euc-kr", "KSC5601"); 1235 mime2java.put("euckr", "KSC5601"); 1236 mime2java.put("us-ascii", "ISO-8859-1"); 1237 mime2java.put("x-us-ascii", "ISO-8859-1"); 1238 } 1239 } 1240 1241 private static void loadMappings(LineInputStream is, Hashtable table) { 1242 String currLine; 1243 1244 while (true) { 1245 try { 1246 currLine = is.readLine(); 1247 } catch (IOException ioex) { 1248 break; } 1250 1251 if (currLine == null) break; 1253 if (currLine.startsWith("--") && currLine.endsWith("--")) 1254 break; 1256 1257 if (currLine.trim().length() == 0 || currLine.startsWith("#")) 1259 continue; 1260 1261 StringTokenizer tk = new StringTokenizer(currLine, " \t"); 1264 try { 1265 String key = tk.nextToken(); 1266 String value = tk.nextToken(); 1267 table.put(key.toLowerCase(), value); 1268 } catch (NoSuchElementException nex) { } 1269 } 1270 } 1271 1272 static final int ALL_ASCII = 1; 1273 static final int MOSTLY_ASCII = 2; 1274 static final int MOSTLY_NONASCII = 3; 1275 1276 1284 static int checkAscii(String s) { 1285 int ascii = 0, non_ascii = 0; 1286 int l = s.length(); 1287 1288 for (int i = 0; i < l; i++) { 1289 if (nonascii((int)s.charAt(i))) non_ascii++; 1291 else 1292 ascii++; 1293 } 1294 1295 if (non_ascii == 0) 1296 return ALL_ASCII; 1297 if (ascii > non_ascii) 1298 return MOSTLY_ASCII; 1299 1300 return MOSTLY_NONASCII; 1301 } 1302 1303 1313 static int checkAscii(byte[] b) { 1314 int ascii = 0, non_ascii = 0; 1315 1316 for (int i=0; i < b.length; i++) { 1317 if (nonascii(b[i] & 0xff)) non_ascii++; 1322 else 1323 ascii++; 1324 } 1325 1326 if (non_ascii == 0) 1327 return ALL_ASCII; 1328 if (ascii > non_ascii) 1329 return MOSTLY_ASCII; 1330 1331 return MOSTLY_NONASCII; 1332 } 1333 1334 1355 static int checkAscii(InputStream is, int max, boolean breakOnNonAscii) { 1356 int ascii = 0, non_ascii = 0; 1357 int len; 1358 int block = 4096; 1359 int linelen = 0; 1360 boolean longLine = false, badEOL = false; 1361 boolean checkEOL = encodeEolStrict && breakOnNonAscii; 1362 byte buf[] = null; 1363 if (max != 0) { 1364 block = (max == ALL) ? 4096 : Math.min(max, 4096); 1365 buf = new byte[block]; 1366 } 1367 while (max != 0) { 1368 try { 1369 if ((len = is.read(buf, 0, block)) == -1) 1370 break; 1371 int lastb = 0; 1372 for (int i = 0; i < len; i++) { 1373 int b = buf[i] & 0xff; 1378 if (checkEOL && 1379 ((lastb == '\r' && b != '\n') || 1380 (lastb != '\r' && b == '\n'))) 1381 badEOL = true; 1382 if (b == '\r' || b == '\n') 1383 linelen = 0; 1384 else { 1385 linelen++; 1386 if (linelen > 998) longLine = true; 1388 } 1389 if (nonascii(b)) { if (breakOnNonAscii) return MOSTLY_NONASCII; 1392 else 1393 non_ascii++; 1394 } else 1395 ascii++; 1396 lastb = b; 1397 } 1398 } catch (IOException ioex) { 1399 break; 1400 } 1401 if (max != ALL) 1402 max -= len; 1403 } 1404 1405 if (max == 0 && breakOnNonAscii) 1406 1412 return MOSTLY_NONASCII; 1413 1414 if (non_ascii == 0) { if (badEOL) 1420 return MOSTLY_NONASCII; 1421 else if (longLine) 1423 return MOSTLY_ASCII; 1424 else 1425 return ALL_ASCII; 1426 } 1427 if (ascii > non_ascii) return MOSTLY_ASCII; 1429 return MOSTLY_NONASCII; 1430 } 1431 1432 static final boolean nonascii(int b) { 1433 return b >= 0177 || (b < 040 && b != '\r' && b != '\n' && b != '\t'); 1434 } 1435} 1436 1437 1441class AsciiOutputStream extends OutputStream { 1442 private boolean breakOnNonAscii; 1443 private int ascii = 0, non_ascii = 0; 1444 private int linelen = 0; 1445 private boolean longLine = false; 1446 private boolean badEOL = false; 1447 private boolean checkEOL = false; 1448 private int lastb = 0; 1449 private int ret = 0; 1450 1451 public AsciiOutputStream(boolean breakOnNonAscii, boolean encodeEolStrict) { 1452 this.breakOnNonAscii = breakOnNonAscii; 1453 checkEOL = encodeEolStrict && breakOnNonAscii; 1454 } 1455 1456 public void write(int b) throws IOException { 1457 check(b); 1458 } 1459 1460 public void write(byte b[]) throws IOException { 1461 write(b, 0, b.length); 1462 } 1463 1464 public void write(byte b[], int off, int len) throws IOException { 1465 len += off; 1466 for (int i = off; i < len ; i++) 1467 check(b[i]); 1468 } 1469 1470 private final void check(int b) throws IOException { 1471 b &= 0xff; 1472 if (checkEOL && 1473 ((lastb == '\r' && b != '\n') || (lastb != '\r' && b == '\n'))) 1474 badEOL = true; 1475 if (b == '\r' || b == '\n') 1476 linelen = 0; 1477 else { 1478 linelen++; 1479 if (linelen > 998) longLine = true; 1481 } 1482 if (MimeUtility.nonascii(b)) { non_ascii++; 1484 if (breakOnNonAscii) { ret = MimeUtility.MOSTLY_NONASCII; 1486 throw new EOFException(); 1487 } 1488 } else 1489 ascii++; 1490 lastb = b; 1491 } 1492 1493 1496 public int getAscii() { 1497 if (ret != 0) 1498 return ret; 1499 if (badEOL) 1504 return MimeUtility.MOSTLY_NONASCII; 1505 else if (non_ascii == 0) { if (longLine) 1508 return MimeUtility.MOSTLY_ASCII; 1509 else 1510 return MimeUtility.ALL_ASCII; 1511 } 1512 if (ascii > non_ascii) return MimeUtility.MOSTLY_ASCII; 1514 return MimeUtility.MOSTLY_NONASCII; 1515 } 1516} 1517 | Popular Tags |