1 /* |
1 /* |
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
508 return etext; |
508 return etext; |
509 |
509 |
510 // Encoded words found. Start decoding ... |
510 // Encoded words found. Start decoding ... |
511 |
511 |
512 st = new StringTokenizer(etext, lwsp, true); |
512 st = new StringTokenizer(etext, lwsp, true); |
513 StringBuffer sb = new StringBuffer(); // decode buffer |
513 StringBuilder sb = new StringBuilder(); // decode buffer |
514 StringBuffer wsb = new StringBuffer(); // white space buffer |
514 StringBuilder wsb = new StringBuilder(); // white space buffer |
515 boolean prevWasEncoded = false; |
515 boolean prevWasEncoded = false; |
516 |
516 |
517 while (st.hasMoreTokens()) { |
517 while (st.hasMoreTokens()) { |
518 char c; |
518 char c; |
519 String s = st.nextToken(); |
519 String s = st.nextToken(); |
646 b64 = false; |
646 b64 = false; |
647 else |
647 else |
648 throw new UnsupportedEncodingException( |
648 throw new UnsupportedEncodingException( |
649 "Unknown transfer encoding: " + encoding); |
649 "Unknown transfer encoding: " + encoding); |
650 |
650 |
651 StringBuffer outb = new StringBuffer(); // the output buffer |
651 StringBuilder outb = new StringBuilder(); // the output buffer |
652 doEncode(string, b64, jcharset, |
652 doEncode(string, b64, jcharset, |
653 // As per RFC 2047, size of an encoded string should not |
653 // As per RFC 2047, size of an encoded string should not |
654 // exceed 75 bytes. |
654 // exceed 75 bytes. |
655 // 7 = size of "=?", '?', 'B'/'Q', '?', "?=" |
655 // 7 = size of "=?", '?', 'B'/'Q', '?', "?=" |
656 75 - 7 - charset.length(), // the available space |
656 75 - 7 - charset.length(), // the available space |
660 return outb.toString(); |
660 return outb.toString(); |
661 } |
661 } |
662 |
662 |
663 private static void doEncode(String string, boolean b64, |
663 private static void doEncode(String string, boolean b64, |
664 String jcharset, int avail, String prefix, |
664 String jcharset, int avail, String prefix, |
665 boolean first, boolean encodingWord, StringBuffer buf) |
665 boolean first, boolean encodingWord, StringBuilder buf) |
666 throws UnsupportedEncodingException { |
666 throws UnsupportedEncodingException { |
667 |
667 |
668 // First find out what the length of the encoded version of |
668 // First find out what the length of the encoded version of |
669 // 'string' would be. |
669 // 'string' would be. |
670 byte[] bytes = string.getBytes(jcharset); |
670 byte[] bytes = string.getBytes(jcharset); |
810 * produce such incorrect encodings. |
810 * produce such incorrect encodings. |
811 */ |
811 */ |
812 private static String decodeInnerWords(String word) |
812 private static String decodeInnerWords(String word) |
813 throws UnsupportedEncodingException { |
813 throws UnsupportedEncodingException { |
814 int start = 0, i; |
814 int start = 0, i; |
815 StringBuffer buf = new StringBuffer(); |
815 StringBuilder buf = new StringBuilder(); |
816 while ((i = word.indexOf("=?", start)) >= 0) { |
816 while ((i = word.indexOf("=?", start)) >= 0) { |
817 buf.append(word.substring(start, i)); |
817 buf.append(word.substring(start, i)); |
818 int end = word.indexOf("?=", i); |
818 int end = word.indexOf("?=", i); |
819 if (end < 0) |
819 if (end < 0) |
820 break; |
820 break; |
860 boolean needQuoting = false; |
860 boolean needQuoting = false; |
861 for (int i = 0; i < len; i++) { |
861 for (int i = 0; i < len; i++) { |
862 char c = word.charAt(i); |
862 char c = word.charAt(i); |
863 if (c == '"' || c == '\\' || c == '\r' || c == '\n') { |
863 if (c == '"' || c == '\\' || c == '\r' || c == '\n') { |
864 // need to escape them and then quote the whole string |
864 // need to escape them and then quote the whole string |
865 StringBuffer sb = new StringBuffer(len + 3); |
865 StringBuilder sb = new StringBuilder(len + 3); |
866 sb.append('"'); |
866 sb.append('"'); |
867 sb.append(word.substring(0, i)); |
867 sb.append(word.substring(0, i)); |
868 int lastc = 0; |
868 int lastc = 0; |
869 for (int j = i; j < len; j++) { |
869 for (int j = i; j < len; j++) { |
870 char cc = word.charAt(j); |
870 char cc = word.charAt(j); |
925 // if the string fits now, just return it |
925 // if the string fits now, just return it |
926 if (used + s.length() <= 76) |
926 if (used + s.length() <= 76) |
927 return s; |
927 return s; |
928 |
928 |
929 // have to actually fold the string |
929 // have to actually fold the string |
930 StringBuffer sb = new StringBuffer(s.length() + 4); |
930 StringBuilder sb = new StringBuilder(s.length() + 4); |
931 char lastc = 0; |
931 char lastc = 0; |
932 while (used + s.length() > 76) { |
932 while (used + s.length() > 76) { |
933 int lastspace = -1; |
933 int lastspace = -1; |
934 for (int i = 0; i < s.length(); i++) { |
934 for (int i = 0; i < s.length(); i++) { |
935 if (lastspace != -1 && used + i > 76) |
935 if (lastspace != -1 && used + i > 76) |
984 if (i < l && ((c = s.charAt(i)) == ' ' || c == '\t')) { |
984 if (i < l && ((c = s.charAt(i)) == ' ' || c == '\t')) { |
985 i++; // skip whitespace |
985 i++; // skip whitespace |
986 while (i < l && ((c = s.charAt(i)) == ' ' || c == '\t')) |
986 while (i < l && ((c = s.charAt(i)) == ' ' || c == '\t')) |
987 i++; |
987 i++; |
988 if (sb == null) |
988 if (sb == null) |
989 sb = new StringBuffer(s.length()); |
989 sb = new StringBuilder(s.length()); |
990 if (start != 0) { |
990 if (start != 0) { |
991 sb.append(s.substring(0, start)); |
991 sb.append(s.substring(0, start)); |
992 sb.append(' '); |
992 sb.append(' '); |
993 } |
993 } |
994 s = s.substring(i); |
994 s = s.substring(i); |
995 continue; |
995 continue; |
996 } |
996 } |
997 // it's not a continuation line, just leave it in |
997 // it's not a continuation line, just leave it in |
998 if (sb == null) |
998 if (sb == null) |
999 sb = new StringBuffer(s.length()); |
999 sb = new StringBuilder(s.length()); |
1000 sb.append(s.substring(0, i)); |
1000 sb.append(s.substring(0, i)); |
1001 s = s.substring(i); |
1001 s = s.substring(i); |
1002 } else { |
1002 } else { |
1003 // there's a backslash at "start - 1" |
1003 // there's a backslash at "start - 1" |
1004 // strip it out, but leave in the line break |
1004 // strip it out, but leave in the line break |
1005 if (sb == null) |
1005 if (sb == null) |
1006 sb = new StringBuffer(s.length()); |
1006 sb = new StringBuilder(s.length()); |
1007 sb.append(s.substring(0, start - 1)); |
1007 sb.append(s.substring(0, start - 1)); |
1008 sb.append(s.substring(start, i)); |
1008 sb.append(s.substring(start, i)); |
1009 s = s.substring(i); |
1009 s = s.substring(i); |
1010 } |
1010 } |
1011 } |
1011 } |
1049 public static String javaCharset(String charset) { |
1049 public static String javaCharset(String charset) { |
1050 if (mime2java == null || charset == null) |
1050 if (mime2java == null || charset == null) |
1051 // no mapping table, or charset parameter is null |
1051 // no mapping table, or charset parameter is null |
1052 return charset; |
1052 return charset; |
1053 |
1053 |
1054 String alias = (String)mime2java.get(charset.toLowerCase()); |
1054 String alias = mime2java.get(charset.toLowerCase()); |
1055 return alias == null ? charset : alias; |
1055 return alias == null ? charset : alias; |
1056 } |
1056 } |
1057 |
1057 |
1058 /** |
1058 /** |
1059 * Convert a java charset into its MIME charset name. <p> |
1059 * Convert a java charset into its MIME charset name. <p> |
1071 public static String mimeCharset(String charset) { |
1071 public static String mimeCharset(String charset) { |
1072 if (java2mime == null || charset == null) |
1072 if (java2mime == null || charset == null) |
1073 // no mapping table or charset param is null |
1073 // no mapping table or charset param is null |
1074 return charset; |
1074 return charset; |
1075 |
1075 |
1076 String alias = (String)java2mime.get(charset.toLowerCase()); |
1076 String alias = java2mime.get(charset.toLowerCase()); |
1077 return alias == null ? charset : alias; |
1077 return alias == null ? charset : alias; |
1078 } |
1078 } |
1079 |
1079 |
1080 private static String defaultJavaCharset; |
1080 private static String defaultJavaCharset; |
1081 private static String defaultMIMECharset; |
1081 private static String defaultMIMECharset; |
1138 return defaultMIMECharset; |
1138 return defaultMIMECharset; |
1139 } |
1139 } |
1140 |
1140 |
1141 // Tables to map MIME charset names to Java names and vice versa. |
1141 // Tables to map MIME charset names to Java names and vice versa. |
1142 // XXX - Should eventually use J2SE 1.4 java.nio.charset.Charset |
1142 // XXX - Should eventually use J2SE 1.4 java.nio.charset.Charset |
1143 private static Hashtable mime2java; |
1143 private static Hashtable<String, String> mime2java; |
1144 private static Hashtable java2mime; |
1144 private static Hashtable<String, String> java2mime; |
1145 |
1145 |
1146 static { |
1146 static { |
1147 java2mime = new Hashtable(40); |
1147 java2mime = new Hashtable<String, String>(40); |
1148 mime2java = new Hashtable(10); |
1148 mime2java = new Hashtable<String, String>(10); |
1149 |
1149 |
1150 try { |
1150 try { |
1151 // Use this class's classloader to load the mapping file |
1151 // Use this class's classloader to load the mapping file |
1152 // XXX - we should use SecuritySupport, but it's in another package |
1152 // XXX - we should use SecuritySupport, but it's in another package |
1153 InputStream is = |
1153 InputStream is = |
1227 mime2java.put("us-ascii", "ISO-8859-1"); |
1227 mime2java.put("us-ascii", "ISO-8859-1"); |
1228 mime2java.put("x-us-ascii", "ISO-8859-1"); |
1228 mime2java.put("x-us-ascii", "ISO-8859-1"); |
1229 } |
1229 } |
1230 } |
1230 } |
1231 |
1231 |
1232 private static void loadMappings(LineInputStream is, Hashtable table) { |
1232 private static void loadMappings(LineInputStream is, Hashtable<String, String> table) { |
1233 String currLine; |
1233 String currLine; |
1234 |
1234 |
1235 while (true) { |
1235 while (true) { |
1236 try { |
1236 try { |
1237 currLine = is.readLine(); |
1237 currLine = is.readLine(); |