- detect proper encoding for html5's <meta charset="charsetname">

- [performance fix] avoid (light) parsing of html content if there is no charset\s*= pattern inside the string
This commit is contained in:
Maxim.Mossienko
2013-12-12 22:33:39 +01:00
parent 08677f9974
commit 0e548a83c0
@@ -27,6 +27,7 @@ import com.intellij.lang.xhtml.XHTMLLanguage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
@@ -65,7 +66,8 @@ public class HtmlUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.xml.util.HtmlUtil");
@NonNls private static final String JSFC = "jsfc";
@NonNls private static final String CHARSET_PREFIX = "charset=";
@NonNls private static final String CHARSET = "charset";
@NonNls private static final String CHARSET_PREFIX = CHARSET+"=";
@NonNls private static final String HTML5_DATA_ATTR_PREFIX = "data-";
public static final String[] CONTENT_TYPES =
@@ -444,11 +446,23 @@ public class HtmlUtil {
}
public static Charset detectCharsetFromMetaHttpEquiv(@NotNull String content) {
// check for <meta http-equiv="charset=CharsetName" > or <meta charset="CharsetName"> and return Charset
// because we will lightly parse and explicit charset isn't used very often do quick check for applicability
int charPrefix = content.indexOf(CHARSET);
do {
if (charPrefix == -1) return null;
int charsetPrefixEnd = charPrefix + CHARSET.length();
while (charsetPrefixEnd < content.length() && Character.isWhitespace(content.charAt(charsetPrefixEnd))) ++charsetPrefixEnd;
if (charsetPrefixEnd < content.length() && content.charAt(charsetPrefixEnd) == '=') break;
charPrefix = content.indexOf(CHARSET, charsetPrefixEnd);
} while(true);
final Ref<String> charsetNameRef = new Ref<String>();
try {
new HtmlBuilderDriver(content).build(new XmlBuilder() {
@NonNls final Set<String> inTag = new THashSet<String>();
boolean metHttpEquiv = false;
boolean metHttml5Charset = false;
@Override
public void doctype(@Nullable final CharSequence publicId,
@@ -473,13 +487,18 @@ public class HtmlUtil {
@Override
public void endTag(final CharSequence localName, final String namespace, final int startoffset, final int endoffset) {
@NonNls final String name = localName.toString().toLowerCase();
if ("meta".equals(name) && metHttpEquiv && contentAttributeValue != null) {
int start = contentAttributeValue.indexOf(CHARSET_PREFIX);
if (start == -1) return;
start += CHARSET_PREFIX.length();
int end = contentAttributeValue.indexOf(';', start);
if (end == -1) end = contentAttributeValue.length();
String charsetName = contentAttributeValue.substring(start, end);
if ("meta".equals(name) && (metHttpEquiv || metHttml5Charset) && contentAttributeValue != null) {
String charsetName = null;
if (metHttpEquiv) {
int start = contentAttributeValue.indexOf(CHARSET_PREFIX);
if (start == -1) return;
start += CHARSET_PREFIX.length();
int end = contentAttributeValue.indexOf(';', start);
if (end == -1) end = contentAttributeValue.length();
charsetName = contentAttributeValue.substring(start, end);
} else /*if (metHttml5Charset) */ {
charsetName = StringUtil.stripQuotesAroundValue(contentAttributeValue);
}
charsetNameRef.set(charsetName);
terminate();
}
@@ -488,6 +507,7 @@ public class HtmlUtil {
}
inTag.remove(name);
metHttpEquiv = false;
metHttml5Charset = false;
contentAttributeValue = null;
}
@@ -500,6 +520,9 @@ public class HtmlUtil {
@NonNls String value = v.toString().toLowerCase();
if (name.equals("http-equiv")) {
metHttpEquiv |= value.equals("content-type");
} else if (name.equals(CHARSET)) {
metHttml5Charset = true;
contentAttributeValue = value;
}
if (name.equals("content")) {
contentAttributeValue = value;