From 0e548a83c0856d537ecb1e1bfb6ef9d8770934e9 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 12 Dec 2013 22:33:39 +0100 Subject: [PATCH] - detect proper encoding for html5's - [performance fix] avoid (light) parsing of html content if there is no charset\s*= pattern inside the string --- .../src/com/intellij/xml/util/HtmlUtil.java | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java index ff1fedcc8542..85410a764d94 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java @@ -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 or 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 charsetNameRef = new Ref(); try { new HtmlBuilderDriver(content).build(new XmlBuilder() { @NonNls final Set inTag = new THashSet(); 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;