Skip to content

Commit

Permalink
Conform encoding-label matching to Encoding spec
Browse files Browse the repository at this point in the history
This change makes the parser’s encoding-name matching conform to the current
Encoding spec at https://encoding.spec.whatwg.org/#concept-encoding-get —
which requires that only leading and trailing whitespace be removed from
a string before checking if it matches any valid encoding name.

Otherwise, without this change, the parser instead implements
https://www.unicode.org/reports/tr22/tr22-8.html#Charset_Alias_Matching —
which requires deleting “all characters except a-z, A-Z, and 0-9” from
a string before checking if it matches any valid encoding name. That
difference makes us fail two html5-tests cases.

Relates to #47
  • Loading branch information
sideshowbarker committed Aug 21, 2020
1 parent 98fd522 commit be5b11b
Showing 1 changed file with 250 additions and 14 deletions.
264 changes: 250 additions & 14 deletions src/nu/validator/htmlparser/io/Encoding.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,238 @@ public class Encoding {
"xutf32lebom", "xutf16oppositeendian", "xutf16platformendian",
"xutf32oppositeendian", "xutf32platformendian" };

private static String[] NOT_OBSCURE = { "big5", "big5hkscs", "eucjp",
"euckr", "gb18030", "gbk", "iso2022jp", "iso2022kr", "iso88591",
"iso885913", "iso885915", "iso88592", "iso88593", "iso88594",
"iso88595", "iso88596", "iso88597", "iso88598", "iso88599",
"koi8r", "shiftjis", "tis620", "usascii", "utf16", "utf16be",
"utf16le", "utf8", "windows1250", "windows1251", "windows1252",
"windows1253", "windows1254", "windows1255", "windows1256",
"windows1257", "windows1258" };

/* From the table at https://encoding.spec.whatwg.org/#names-and-labels,
* everything in the Labels column, sorted */
private static String[] NOT_OBSCURE = { //
"866", //
"ansi_x3.4-1968", //
"arabic", //
"ascii", //
"asmo-708", //
"big5", //
"big5-hkscs", //
"chinese", //
"cn-big5", //
"cp1250", //
"cp1251", //
"cp1252", //
"cp1253", //
"cp1254", //
"cp1255", //
"cp1256", //
"cp1257", //
"cp1258", //
"cp819", //
"cp866", //
"csbig5", //
"cseuckr", //
"cseucpkdfmtjapanese", //
"csgb2312", //
"csibm866", //
"csiso2022jp", //
"csiso2022kr", //
"csiso58gb231280", //
"csiso88596e", //
"csiso88596i", //
"csiso88598e", //
"csiso88598i", //
"csisolatin1", //
"csisolatin2", //
"csisolatin3", //
"csisolatin4", //
"csisolatin5", //
"csisolatin6", //
"csisolatin9", //
"csisolatinarabic", //
"csisolatincyrillic", //
"csisolatingreek", //
"csisolatinhebrew", //
"cskoi8r", //
"csksc56011987", //
"csmacintosh", //
"csshiftjis", //
"csunicode", //
"cyrillic", //
"dos-874", //
"ecma-114", //
"ecma-118", //
"elot_928", //
"euc-jp", //
"euc-kr", //
"gb18030", //
"gb2312", //
"gb_2312", //
"gb_2312-80", //
"gbk", //
"greek", //
"greek8", //
"hebrew", //
"hz-gb-2312", //
"ibm819", //
"ibm866", //
"iso-10646-ucs-2", //
"iso-2022-cn", //
"iso-2022-cn-ext", //
"iso-2022-jp", //
"iso-2022-kr", //
"iso-8859-1", //
"iso-8859-10", //
"iso-8859-11", //
"iso-8859-13", //
"iso-8859-14", //
"iso-8859-15", //
"iso-8859-16", //
"iso-8859-2", //
"iso-8859-3", //
"iso-8859-4", //
"iso-8859-5", //
"iso-8859-6", //
"iso-8859-6-e", //
"iso-8859-6-i", //
"iso-8859-7", //
"iso-8859-8", //
"iso-8859-8-e", //
"iso-8859-8-i", //
"iso-8859-9", //
"iso-ir-100", //
"iso-ir-101", //
"iso-ir-109", //
"iso-ir-110", //
"iso-ir-126", //
"iso-ir-127", //
"iso-ir-138", //
"iso-ir-144", //
"iso-ir-148", //
"iso-ir-149", //
"iso-ir-157", //
"iso-ir-58", //
"iso8859-1", //
"iso8859-10", //
"iso8859-11", //
"iso8859-13", //
"iso8859-14", //
"iso8859-15", //
"iso8859-2", //
"iso8859-3", //
"iso8859-4", //
"iso8859-5", //
"iso8859-6", //
"iso8859-7", //
"iso8859-8", //
"iso8859-9", //
"iso88591", //
"iso885910", //
"iso885911", //
"iso885913", //
"iso885914", //
"iso885915", //
"iso88592", //
"iso88593", //
"iso88594", //
"iso88595", //
"iso88596", //
"iso88597", //
"iso88598", //
"iso88599", //
"iso_8859-1", //
"iso_8859-15", //
"iso_8859-1:1987", //
"iso_8859-2", //
"iso_8859-2:1987", //
"iso_8859-3", //
"iso_8859-3:1988", //
"iso_8859-4", //
"iso_8859-4:1988", //
"iso_8859-5", //
"iso_8859-5:1988", //
"iso_8859-6", //
"iso_8859-6:1987", //
"iso_8859-7", //
"iso_8859-7:1987", //
"iso_8859-8", //
"iso_8859-8:1988", //
"iso_8859-9", //
"iso_8859-9:1989", //
"koi", //
"koi8", //
"koi8-r", //
"koi8-ru", //
"koi8-u", //
"koi8_r", //
"korean", //
"ks_c_5601-1987", //
"ks_c_5601-1989", //
"ksc5601", //
"ksc_5601", //
"l1", //
"l2", //
"l3", //
"l4", //
"l5", //
"l6", //
"l9", //
"latin1", //
"latin2", //
"latin3", //
"latin4", //
"latin5", //
"latin6", //
"logical", //
"mac", //
"macintosh", //
"ms932", //
"ms_kanji", //
"replacement", //
"shift-jis", //
"shift_jis", //
"sjis", //
"sun_eu_greek", //
"tis-620", //
"ucs-2", //
"unicode", //
"unicode-1-1-utf-8", //
"unicode11utf8", //
"unicode20utf8", //
"unicodefeff", //
"unicodefffe", //
"us-ascii", //
"utf-16", //
"utf-16be", //
"utf-16le", //
"utf-8", //
"utf8", //
"visual", //
"windows-1250", //
"windows-1251", //
"windows-1252", //
"windows-1253", //
"windows-1254", //
"windows-1255", //
"windows-1256", //
"windows-1257", //
"windows-1258", //
"windows-31j", //
"windows-874", //
"windows-949", //
"x-cp1250", //
"x-cp1251", //
"x-cp1252", //
"x-cp1253", //
"x-cp1254", //
"x-cp1255", //
"x-cp1256", //
"x-cp1257", //
"x-cp1258", //
"x-euc-jp", //
"x-gbk", //
"x-mac-cyrillic", //
"x-mac-roman", //
"x-mac-ukrainian", //
"x-sjis", //
"x-unicode20utf8", //
"x-user-defined", //
"x-x-big5", //
};
private static Map<String, Encoding> encodingByCookedName = new HashMap<String, Encoding>();

private final String canonName;
Expand Down Expand Up @@ -106,11 +329,12 @@ public class Encoding {
Charset cs = entry.getValue();
String name = toNameKey(cs.name());
String canonName = toAsciiLowerCase(cs.name());
if (!isBanned(name)) {
if (!isBanned(stripDashAndUnderscore(name))) {
name = name.intern();
boolean asciiSuperset = asciiMapsToBasicLatin(testBuf, cs);
Encoding enc = new Encoding(canonName.intern(), cs,
asciiSuperset, isObscure(name), isShouldNot(name),
asciiSuperset, isObscure(name),
isShouldNot(stripDashAndUnderscore(name)),
isLikelyEbcdic(name, asciiSuperset));
encodings.add(enc);
Set<String> aliases = cs.aliases();
Expand Down Expand Up @@ -254,16 +478,28 @@ public static String toNameKey(String str) {
if (c >= 'A' && c <= 'Z') {
c += 0x20;
}
if (!((c >= '\t' && c <= '\r') || (c >= '\u0020' && c <= '\u002F')
|| (c >= '\u003A' && c <= '\u0040')
|| (c >= '\u005B' && c <= '\u0060') || (c >= '\u007B' && c <= '\u007E'))) {
if (!(c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r')) {
buf[j] = c;
j++;
}
}
return new String(buf, 0, j);
}

public static String stripDashAndUnderscore(String str) {
if (str == null) {
return null;
}
char[] buf = new char[str.length()];
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '-' || c == '_') {
buf[i] = c;
}
}
return new String(buf);
}

public static String toAsciiLowerCase(String str) {
if (str == null) {
return null;
Expand Down

0 comments on commit be5b11b

Please sign in to comment.