* Initial work to store element/attribute names as "namespaceURI+localname" pairs: remember pointers to reserved namespace URIs and use them for comparison.

git-svn-id: trunk@24305 -
This commit is contained in:
sergei 2013-04-23 05:42:25 +00:00
parent e6dc52bac8
commit 6bb05dbc06

View File

@ -451,6 +451,8 @@ type
FMaxPoolSize: Integer; FMaxPoolSize: Integer;
FPools: PNodePoolArray; FPools: PNodePoolArray;
FXmlStandalone: Boolean; FXmlStandalone: Boolean;
FStdUri_xml: PHashItem;
FStdUri_xmlns: PHashItem;
function GetDocumentElement: TDOMElement; function GetDocumentElement: TDOMElement;
function GetDocType: TDOMDocumentType; function GetDocType: TDOMDocumentType;
function GetNodeType: Integer; override; function GetNodeType: Integer; override;
@ -465,6 +467,7 @@ type
function Alloc(AClass: TDOMNodeClass): TDOMNode; function Alloc(AClass: TDOMNodeClass): TDOMNode;
procedure SetXMLVersion(const aValue: DOMString); virtual; procedure SetXMLVersion(const aValue: DOMString); virtual;
procedure SetXMLStandalone(aValue: Boolean); virtual; procedure SetXMLStandalone(aValue: Boolean); virtual;
function ValidateQName(const nsUri, qName: DOMString; out nsidx: PHashItem): Integer;
public public
function IndexOfNS(const nsURI: DOMString; AddIfAbsent: Boolean = False): Integer; function IndexOfNS(const nsURI: DOMString; AddIfAbsent: Boolean = False): Integer;
function InsertBefore(NewChild, RefChild: TDOMNode): TDOMNode; override; function InsertBefore(NewChild, RefChild: TDOMNode): TDOMNode; override;
@ -2108,10 +2111,8 @@ end;
// DOMImplementation // DOMImplementation
// ------------------------------------------------------- // -------------------------------------------------------
{ if nsIdx = -1, checks only the name. Otherwise additionally checks if the prefix is { Non-negative return value is Pos(':', QName), negative is DOM error code. }
valid for standard namespace specified by nsIdx. function CheckQName(const QName: DOMString): Integer;
Non-negative return value is Pos(':', QName), negative is DOM error code. }
function CheckQName(const QName: DOMString; nsIdx: Integer): Integer;
var var
I, L: Integer; I, L: Integer;
begin begin
@ -2139,14 +2140,6 @@ begin
Exit; Exit;
end; end;
end; end;
if nsIdx < 0 then Exit;
// QName contains prefix, but no namespace
if ((nsIdx = 0) and (Result > 0)) or
// Bad usage of 'http://www.w3.org/2000/xmlns/'
((((L = 5) or (Result = 6)) and (Pos(DOMString('xmlns'), QName) = 1)) <> (nsIdx = 2)) or
// Bad usage of 'http://www.w3.org/XML/1998/namespace'
((Result = 4) and (Pos(DOMString('xml'), QName) = 1) and (nsIdx <> 1)) then
Result := -NAMESPACE_ERR;
end; end;
function TDOMImplementation.HasFeature(const feature, version: DOMString): function TDOMImplementation.HasFeature(const feature, version: DOMString):
@ -2166,7 +2159,7 @@ var
res: Integer; res: Integer;
model: TDTDModel; model: TDTDModel;
begin begin
res := CheckQName(QualifiedName, -1); res := CheckQName(QualifiedName);
if res < 0 then if res < 0 then
raise EDOMError.Create(-res, 'Implementation.CreateDocumentType'); raise EDOMError.Create(-res, 'Implementation.CreateDocumentType');
model := TDTDModel.Create(nil); // !!nowhere to get nametable from at this time model := TDTDModel.Create(nil); // !!nowhere to get nametable from at this time
@ -2218,6 +2211,8 @@ begin
FNamespaces[1] := stduri_xml; FNamespaces[1] := stduri_xml;
FNamespaces[2] := stduri_xmlns; FNamespaces[2] := stduri_xmlns;
FEmptyNode := TDOMElement.Create(Self); FEmptyNode := TDOMElement.Create(Self);
FStdUri_xml := FNames.FindOrAdd(stduri_xml);
FStdUri_xmlns := FNames.FindOrAdd(stduri_xmlns);
end; end;
destructor TDOMDocument.Destroy; destructor TDOMDocument.Destroy;
@ -2536,19 +2531,36 @@ begin
FNodeLists.RemoveData(aList); FNodeLists.RemoveData(aList);
end; end;
function TDOMDocument.ValidateQName(const nsUri, qName: DOMString;
out nsidx: PHashItem): Integer;
begin
nsidx := FNames.FindOrAdd(DOMPChar(nsUri), Length(nsUri));
Result := CheckQName(qName);
if Result >= 0 then
begin
// QName contains prefix, but no namespace
if ((nsUri = '') and (Result > 0)) or
// Bad usage of 'http://www.w3.org/2000/xmlns/'
((((Length(QName) = 5) or (Result = 6)) and (Pos(DOMString('xmlns'), QName) = 1)) <> (nsIdx = FStdUri_xmlns)) or
// Bad usage of 'http://www.w3.org/XML/1998/namespace'
((Result = 4) and (Pos(DOMString('xml'), QName) = 1) and (nsIdx <> FStdUri_xml)) then
Result := -NAMESPACE_ERR;
end;
end;
function TDOMDocument.CreateAttributeNS(const nsURI, function TDOMDocument.CreateAttributeNS(const nsURI,
QualifiedName: DOMString): TDOMAttr; QualifiedName: DOMString): TDOMAttr;
var var
idx, PrefIdx: Integer; PrefIdx: Integer;
nsidx: PHashItem;
begin begin
idx := IndexOfNS(nsURI, True); PrefIdx := ValidateQName(nsURI, QualifiedName, nsidx);
PrefIdx := CheckQName(QualifiedName, idx);
if PrefIdx < 0 then if PrefIdx < 0 then
raise EDOMError.Create(-PrefIdx, 'Document.CreateAttributeNS'); raise EDOMError.Create(-PrefIdx, 'Document.CreateAttributeNS');
TDOMNode(Result) := Alloc(TDOMAttr); TDOMNode(Result) := Alloc(TDOMAttr);
Result.Create(Self); Result.Create(Self);
Result.FNSI.QName := FNames.FindOrAdd(DOMPChar(QualifiedName), Length(QualifiedName)); Result.FNSI.QName := FNames.FindOrAdd(DOMPChar(QualifiedName), Length(QualifiedName));
Result.FNSI.NSIndex := Word(idx); Result.FNSI.NSIndex := Word(IndexOfNS(nsURI, True));
Result.FNSI.PrefixLen := Word(PrefIdx); Result.FNSI.PrefixLen := Word(PrefIdx);
Include(Result.FFlags, nfLevel2); Include(Result.FFlags, nfLevel2);
Include(Result.FFlags, nfSpecified); Include(Result.FFlags, nfSpecified);
@ -2557,16 +2569,16 @@ end;
function TDOMDocument.CreateElementNS(const nsURI, function TDOMDocument.CreateElementNS(const nsURI,
QualifiedName: DOMString): TDOMElement; QualifiedName: DOMString): TDOMElement;
var var
idx, PrefIdx: Integer; PrefIdx: Integer;
nsidx: PHashItem;
begin begin
idx := IndexOfNS(nsURI, True); PrefIdx := ValidateQName(nsURI, QualifiedName, nsidx);
PrefIdx := CheckQName(QualifiedName, idx);
if PrefIdx < 0 then if PrefIdx < 0 then
raise EDOMError.Create(-PrefIdx, 'Document.CreateElementNS'); raise EDOMError.Create(-PrefIdx, 'Document.CreateElementNS');
TDOMNode(Result) := Alloc(TDOMElement); TDOMNode(Result) := Alloc(TDOMElement);
Result.Create(Self); Result.Create(Self);
Result.FNSI.QName := FNames.FindOrAdd(DOMPChar(QualifiedName), Length(QualifiedName)); Result.FNSI.QName := FNames.FindOrAdd(DOMPChar(QualifiedName), Length(QualifiedName));
Result.FNSI.NSIndex := Word(idx); Result.FNSI.NSIndex := Word(IndexOfNS(nsURI, True));
Result.FNSI.PrefixLen := Word(PrefIdx); Result.FNSI.PrefixLen := Word(PrefIdx);
Include(Result.FFlags, nfLevel2); Include(Result.FFlags, nfLevel2);
Result.AttachDefaultAttrs; Result.AttachDefaultAttrs;
@ -2972,31 +2984,28 @@ end;
procedure TDOMElement.RestoreDefaultAttr(AttrDef: TAttributeDef); procedure TDOMElement.RestoreDefaultAttr(AttrDef: TAttributeDef);
var var
Attr: TDOMAttr; Attr: TDOMAttr;
ColonPos: Integer; AttrData: TNodeData;
AttrName, nsuri: DOMString; nsuri: DOMString;
begin begin
if nfDestroying in FOwnerDocument.FFlags then if nfDestroying in FOwnerDocument.FFlags then
Exit; Exit;
Attr := LoadAttribute(FOwnerDocument, AttrDef.Data); { Copy data and maybe fixup namespace fields }
AttrData := AttrDef.Data^;
AttrName := Attr.Name; if AttrDef.IsNamespaceDecl then
ColonPos := Pos(WideChar(':'), AttrName); AttrData.FNsUri := FOwnerDocument.FStdUri_xmlns
if Pos(DOMString('xmlns'), AttrName) = 1 then else if AttrData.FColonPos > 0 then
begin begin
if (Length(AttrName) = 5) or (ColonPos = 6) then if (AttrData.FColonPos = 3) and (Pos(DOMString('xml'), AttrData.FQName^.Key) = 1) then
Attr.SetNSI(stduri_xmlns, ColonPos); AttrData.FNsUri := FOwnerDocument.FStdUri_xml
end
else if ColonPos > 0 then
begin
if (ColonPos = 4) and (Pos(DOMString('xml'), AttrName) = 1) then
Attr.SetNSI(stduri_xml, 4)
else else
begin begin
nsuri := LookupNamespaceURI(Copy(AttrName, 1, ColonPos-1)); nsuri := LookupNamespaceURI(Copy(AttrData.FQName^.Key, 1, AttrData.FColonPos));
// TODO: what if prefix isn't defined? // TODO: what if prefix isn't defined?
Attr.SetNSI(nsuri, ColonPos); AttrData.FNsUri := FOwnerDocument.FNames.FindOrAdd(nsuri);
end
end; end;
end;
Attr := LoadAttribute(FOwnerDocument, @AttrData);
// TODO: this is cheat, should look at config['namespaces'] instead. // TODO: this is cheat, should look at config['namespaces'] instead.
// revisit when it is implemented. // revisit when it is implemented.
if nfLevel2 in FFlags then if nfLevel2 in FFlags then
@ -3087,10 +3096,11 @@ var
I: Cardinal; I: Cardinal;
Attr: TDOMAttr; Attr: TDOMAttr;
idx, prefIdx: Integer; idx, prefIdx: Integer;
nsidx: PHashItem;
begin begin
Changing; Changing;
idx := FOwnerDocument.IndexOfNS(nsURI, True); idx := FOwnerDocument.IndexOfNS(nsURI, True);
prefIdx := CheckQName(qualifiedName, idx); prefIdx := FOwnerDocument.ValidateQName(nsURI, qualifiedName, nsidx);
if prefIdx < 0 then if prefIdx < 0 then
raise EDOMError.Create(-prefIdx, 'Element.SetAttributeNS'); raise EDOMError.Create(-prefIdx, 'Element.SetAttributeNS');