Add methods to check Doctype validity and its quirks mode

This commit is contained in:
iska
2015-02-28 00:57:50 +01:00
parent 79856255da
commit 11631c7c76
5 changed files with 188 additions and 7 deletions
+1 -7
View File
@@ -8,13 +8,7 @@
#import "HTMLNode.h"
#import "HTMLDocumentType.h"
typedef NS_ENUM(short, HTMLQuirksMode)
{
HTMLQuirksModeNoQuirks,
HTMLQuirksModeQuirks,
HTMLQuirksModeLimitedQuirks
};
#import "HTMLQuirksMode.h"
@interface HTMLDocument : HTMLNode
+4
View File
@@ -7,6 +7,7 @@
//
#import "HTMLNode.h"
#import "HTMLQuirksMode.h"
@interface HTMLDocumentType : HTMLNode
@@ -18,4 +19,7 @@
publicIdentifier:(NSString *)publicIdentifier
systemIdentifier:(NSString *)systemIdentifier;
- (BOOL)isValid;
- (HTMLQuirksMode)quirksMode;
@end
+84
View File
@@ -8,6 +8,10 @@
#import "HTMLDocumentType.h"
NS_INLINE BOOL nilOrEqual(id first, id second) {
return (first == nil) || ([first isEqual:second]);
}
@implementation HTMLDocumentType
- (instancetype)initWithName:(NSString *)name
@@ -22,6 +26,86 @@
return self;
}
- (BOOL)isValid
{
if (![self.name isEqualToString:@"html"]) {
return NO;
}
if ([_publicIdentifier isEqualToString:@"-//W3C//DTD HTML 4.0//EN"] &&
nilOrEqual(_systemIdentifier, @"http://www.w3.org/TR/REC-html40/strict.dtd")) {
return YES;
}
if ([_publicIdentifier isEqualToString:@"-//W3C//DTD HTML 4.01//EN"] &&
nilOrEqual(_systemIdentifier, @"http://www.w3.org/TR/html4/strict.dtd")) {
return YES;
}
if ([_publicIdentifier isEqualToString:@"-//W3C//DTD XHTML 1.0 Strict//EN"] &&
nilOrEqual(_systemIdentifier, @"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd")) {
return YES;
}
if ([_publicIdentifier isEqualToString:@"-//W3C//DTD XHTML 1.1//EN"] &&
nilOrEqual(_systemIdentifier, @"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd")) {
return YES;
}
if (_publicIdentifier != nil) {
return NO;
}
if (_systemIdentifier && ![_systemIdentifier isEqualToString:@"about:legacy-compat"]) {
return NO;
}
return YES;
}
- (HTMLQuirksMode)quirksMode
{
if (![self.name isEqualToString:@"html"]) {
return HTMLQuirksModeQuirks;
}
if (isEqualCaseInsensitive(_publicIdentifier, @"-//W3O//DTD W3 HTML Strict 3.0//EN//") ||
isEqualCaseInsensitive(_publicIdentifier, @"-/W3C/DTD HTML 4.0 Transitional/EN") ||
isEqualCaseInsensitive(_publicIdentifier, @"HTML")) {
return HTMLQuirksModeQuirks;
}
if (isEqualCaseInsensitive(_systemIdentifier, @"http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")) {
return HTMLQuirksModeQuirks;
}
if (QuirksModePrefixMatch(_publicIdentifier)) {
return HTMLQuirksModeQuirks;
}
if (_systemIdentifier == nil) {
if (hasPrefixCaseInsensitive(_publicIdentifier, @"-//W3C//DTD HTML 4.01 Frameset//") ||
hasPrefixCaseInsensitive(_publicIdentifier, @"-//W3C//DTD HTML 4.01 Transitional//")) {
return HTMLQuirksModeQuirks;
}
}
#warning Check "iframe srcdoc"
if (hasPrefixCaseInsensitive(_publicIdentifier, @"-//W3C//DTD XHTML 1.0 Frameset//") ||
hasPrefixCaseInsensitive(_publicIdentifier, @"-//W3C//DTD XHTML 1.0 Transitional//")) {
return HTMLQuirksModeLimitedQuirks;
}
if (_systemIdentifier != nil) {
if (hasPrefixCaseInsensitive(_publicIdentifier, @"-//W3C//DTD HTML 4.01 Frameset//") ||
hasPrefixCaseInsensitive(_publicIdentifier, @"-//W3C//DTD HTML 4.01 Transitional//")) {
return HTMLQuirksModeLimitedQuirks;
}
}
return HTMLQuirksModeNoQuirks;
}
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone
+97
View File
@@ -0,0 +1,97 @@
//
// HTMLQuirksMode.h
// HTMLKit
//
// Created by Iska on 28/02/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
typedef NS_ENUM(short, HTMLQuirksMode)
{
HTMLQuirksModeNoQuirks,
HTMLQuirksModeQuirks,
HTMLQuirksModeLimitedQuirks
};
#define QUIRKS_MODE_PREFIXES \
QUIRKS_ENTRY( "+//Silmaril//dtd html Pro v0r11 19970101//" ) \
QUIRKS_ENTRY( "-//AS//DTD HTML 3.0 asWedit + extensions//" ) \
QUIRKS_ENTRY( "-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 2.0 Level 1//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 2.0 Level 2//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 2.0 Strict Level 1//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 2.0 Strict Level 2//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 2.0 Strict//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 2.0//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 2.1E//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 3.0//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 3.2 Final//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 3.2//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML 3//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML Level 0//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML Level 1//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML Level 2//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML Level 3//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML Strict Level 0//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML Strict Level 1//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML Strict Level 2//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML Strict Level 3//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML Strict//" ) \
QUIRKS_ENTRY( "-//IETF//DTD HTML//" ) \
QUIRKS_ENTRY( "-//Metrius//DTD Metrius Presentational//" ) \
QUIRKS_ENTRY( "-//Microsoft//DTD Internet Explorer 2.0 HTML Strict//" ) \
QUIRKS_ENTRY( "-//Microsoft//DTD Internet Explorer 2.0 HTML//" ) \
QUIRKS_ENTRY( "-//Microsoft//DTD Internet Explorer 2.0 Tables//" ) \
QUIRKS_ENTRY( "-//Microsoft//DTD Internet Explorer 3.0 HTML Strict//" ) \
QUIRKS_ENTRY( "-//Microsoft//DTD Internet Explorer 3.0 HTML//" ) \
QUIRKS_ENTRY( "-//Microsoft//DTD Internet Explorer 3.0 Tables//" ) \
QUIRKS_ENTRY( "-//Netscape Comm. Corp.//DTD HTML//" ) \
QUIRKS_ENTRY( "-//Netscape Comm. Corp.//DTD Strict HTML//" ) \
QUIRKS_ENTRY( "-//O'Reilly and Associates//DTD HTML 2.0//" ) \
QUIRKS_ENTRY( "-//O'Reilly and Associates//DTD HTML Extended 1.0//" ) \
QUIRKS_ENTRY( "-//O'Reilly and Associates//DTD HTML Extended Relaxed 1.0//" ) \
QUIRKS_ENTRY( "-//SQ//DTD HTML 2.0 HoTMetaL + extensions//" ) \
QUIRKS_ENTRY( "-//SoftQuad Software//DTD HoTMetaL PRO 6.0::19990601::extensions to HTML 4.0//" ) \
QUIRKS_ENTRY( "-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::extensions to HTML 4.0//" ) \
QUIRKS_ENTRY( "-//Spyglass//DTD HTML 2.0 Extended//" ) \
QUIRKS_ENTRY( "-//Sun Microsystems Corp.//DTD HotJava HTML//" ) \
QUIRKS_ENTRY( "-//Sun Microsystems Corp.//DTD HotJava Strict HTML//" ) \
QUIRKS_ENTRY( "-//W3C//DTD HTML 3 1995-03-24//" ) \
QUIRKS_ENTRY( "-//W3C//DTD HTML 3.2 Draft//" ) \
QUIRKS_ENTRY( "-//W3C//DTD HTML 3.2 Final//" ) \
QUIRKS_ENTRY( "-//W3C//DTD HTML 3.2//" ) \
QUIRKS_ENTRY( "-//W3C//DTD HTML 3.2S Draft//" ) \
QUIRKS_ENTRY( "-//W3C//DTD HTML 4.0 Frameset//" ) \
QUIRKS_ENTRY( "-//W3C//DTD HTML 4.0 Transitional//" ) \
QUIRKS_ENTRY( "-//W3C//DTD HTML Experimental 19960712//" ) \
QUIRKS_ENTRY( "-//W3C//DTD HTML Experimental 970421//" ) \
QUIRKS_ENTRY( "-//W3C//DTD W3 HTML//" ) \
QUIRKS_ENTRY( "-//W3O//DTD W3 HTML 3.0//" ) \
QUIRKS_ENTRY( "-//WebTechs//DTD Mozilla HTML 2.0//" ) \
QUIRKS_ENTRY( "-//WebTechs//DTD Mozilla HTML//" )
static NSString * HTMLQuirksModePrefixes[] = {
#define QUIRKS_ENTRY( prefix ) @prefix,
QUIRKS_MODE_PREFIXES
#undef QUIRKS_ENTRY
};
NS_INLINE BOOL isEqualCaseInsensitive(NSString *first, NSString *second) {
return [first caseInsensitiveCompare:second] == NSOrderedSame;
}
NS_INLINE BOOL hasPrefixCaseInsensitive(NSString *string, NSString *prefix) {
NSRange reange = [string rangeOfString:prefix
options:NSAnchoredSearch|NSCaseInsensitiveSearch];
return reange.location != NSNotFound;
}
NS_INLINE BOOL QuirksModePrefixMatch(NSString *publicIdentifier)
{
for (int i = 0; i < sizeof(HTMLQuirksModePrefixes) / sizeof(HTMLQuirksModePrefixes[0]); i++) {
if (hasPrefixCaseInsensitive(publicIdentifier, HTMLQuirksModePrefixes[i])) {
return YES;
}
}
return NO;
}