|
@@ -292,7 +292,6 @@ type
|
|
FAttrTag: Cardinal;
|
|
FAttrTag: Cardinal;
|
|
FDTDProcessed: Boolean;
|
|
FDTDProcessed: Boolean;
|
|
FFragmentMode: Boolean;
|
|
FFragmentMode: Boolean;
|
|
- FToken: TXMLToken;
|
|
|
|
FNext: TXMLToken;
|
|
FNext: TXMLToken;
|
|
FCurrEntity: TEntityDecl;
|
|
FCurrEntity: TEntityDecl;
|
|
FIDMap: THashTable;
|
|
FIDMap: THashTable;
|
|
@@ -336,7 +335,7 @@ type
|
|
function SkipUntilSeq(const Delim: TSetOfChar; c1: WideChar; c2: WideChar = #0): Boolean;
|
|
function SkipUntilSeq(const Delim: TSetOfChar; c1: WideChar; c2: WideChar = #0): Boolean;
|
|
procedure CheckMaxChars(ToAdd: Cardinal);
|
|
procedure CheckMaxChars(ToAdd: Cardinal);
|
|
function AllocNodeData(AIndex: Integer): PNodeData;
|
|
function AllocNodeData(AIndex: Integer): PNodeData;
|
|
- function AllocAttributeData(AName: PHashItem): PNodeData;
|
|
|
|
|
|
+ function AllocAttributeData: PNodeData;
|
|
function AllocAttributeValueChunk(APrev: PNodeData): PNodeData;
|
|
function AllocAttributeValueChunk(APrev: PNodeData): PNodeData;
|
|
procedure CleanupAttribute(aNode: PNodeData);
|
|
procedure CleanupAttribute(aNode: PNodeData);
|
|
procedure CleanupAttributes;
|
|
procedure CleanupAttributes;
|
|
@@ -376,7 +375,7 @@ type
|
|
function ExpectName: WideString; // [5]
|
|
function ExpectName: WideString; // [5]
|
|
function ParseLiteral(var ToFill: TWideCharBuf; aType: TLiteralType;
|
|
function ParseLiteral(var ToFill: TWideCharBuf; aType: TLiteralType;
|
|
Required: Boolean): Boolean;
|
|
Required: Boolean): Boolean;
|
|
- function ExpectAttValue(attrData: PNodeData; NonCDATA: Boolean): Boolean; // [10]
|
|
|
|
|
|
+ procedure ExpectAttValue(attrData: PNodeData; NonCDATA: Boolean); // [10]
|
|
procedure ParseComment(discard: Boolean); // [15]
|
|
procedure ParseComment(discard: Boolean); // [15]
|
|
procedure ParsePI; // [16]
|
|
procedure ParsePI; // [16]
|
|
procedure CreatePINode;
|
|
procedure CreatePINode;
|
|
@@ -1563,9 +1562,9 @@ const
|
|
{ Parse attribute literal, producing plain string value in AttrData.FValueStr.
|
|
{ Parse attribute literal, producing plain string value in AttrData.FValueStr.
|
|
If entity references are encountered and FExpandEntities=False, also builds
|
|
If entity references are encountered and FExpandEntities=False, also builds
|
|
a node chain starting from AttrData.FNext. Node chain is built only for the
|
|
a node chain starting from AttrData.FNext. Node chain is built only for the
|
|
- first level. If NonCDATA=True, additionally normalizes whitespace in string value.
|
|
|
|
- Returns True if value actually needed normalization }
|
|
|
|
-function TXMLReader.ExpectAttValue(AttrData: PNodeData; NonCDATA: Boolean): Boolean;
|
|
|
|
|
|
+ first level. If NonCDATA=True, additionally normalizes whitespace in string value. }
|
|
|
|
+
|
|
|
|
+procedure TXMLReader.ExpectAttValue(AttrData: PNodeData; NonCDATA: Boolean);
|
|
var
|
|
var
|
|
wc: WideChar;
|
|
wc: WideChar;
|
|
Delim: WideChar;
|
|
Delim: WideChar;
|
|
@@ -1637,9 +1636,9 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
if nonCDATA then
|
|
if nonCDATA then
|
|
- BufNormalize(FValue, Result)
|
|
|
|
|
|
+ BufNormalize(FValue, attrData^.FDenormalized)
|
|
else
|
|
else
|
|
- Result := False;
|
|
|
|
|
|
+ attrData^.FDenormalized := False;
|
|
SetString(attrData^.FValueStr, FValue.Buffer, FValue.Length);
|
|
SetString(attrData^.FValueStr, FValue.Buffer, FValue.Length);
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -2678,6 +2677,9 @@ end;
|
|
procedure TXMLReader.ValidateCurrentNode;
|
|
procedure TXMLReader.ValidateCurrentNode;
|
|
var
|
|
var
|
|
ElDef: TElementDecl;
|
|
ElDef: TElementDecl;
|
|
|
|
+ AttDef: TAttributeDef;
|
|
|
|
+ attr: PNodeData;
|
|
|
|
+ i: Integer;
|
|
begin
|
|
begin
|
|
case FCurrNode^.FNodeType of
|
|
case FCurrNode^.FNodeType of
|
|
ntElement:
|
|
ntElement:
|
|
@@ -2699,6 +2701,32 @@ begin
|
|
|
|
|
|
if not FValidators[FNesting-1].IsElementAllowed(ElDef) then
|
|
if not FValidators[FNesting-1].IsElementAllowed(ElDef) then
|
|
DoErrorPos(esError, 'Element ''%s'' is not allowed in this context',[FCurrNode^.FQName^.Key], FCurrNode^.FLoc);
|
|
DoErrorPos(esError, 'Element ''%s'' is not allowed in this context',[FCurrNode^.FQName^.Key], FCurrNode^.FLoc);
|
|
|
|
+
|
|
|
|
+ { Validate attributes }
|
|
|
|
+ for i := 1 to FAttrCount do
|
|
|
|
+ begin
|
|
|
|
+ attr := @FNodeStack[FNesting+i];
|
|
|
|
+ AttDef := TAttributeDef(attr^.FTypeInfo);
|
|
|
|
+ if AttDef = nil then
|
|
|
|
+ DoErrorPos(esError, 'Using undeclared attribute ''%s'' on element ''%s''',
|
|
|
|
+ [attr^.FQName^.Key, FCurrNode^.FQName^.Key], attr^.FLoc)
|
|
|
|
+ else if ((AttDef.DataType <> dtCdata) or (AttDef.Default = adFixed)) then
|
|
|
|
+ begin
|
|
|
|
+ if FStandalone and AttDef.ExternallyDeclared then
|
|
|
|
+ { TODO: perhaps should use different and more descriptive messages }
|
|
|
|
+ if attr^.FDenormalized then
|
|
|
|
+ DoErrorPos(esError, 'Standalone constraint violation', attr^.FLoc2)
|
|
|
|
+ else if i > FSpecifiedAttrs then
|
|
|
|
+ DoError(esError, 'Standalone constraint violation');
|
|
|
|
+
|
|
|
|
+ // TODO: what about normalization of AttDef.Value? (Currently it IS normalized)
|
|
|
|
+ if (AttDef.Default = adFixed) and (AttDef.Data^.FValueStr <> attr^.FValueStr) then
|
|
|
|
+ DoErrorPos(esError, 'Value of attribute ''%s'' does not match its #FIXED default',[attr^.FQName^.Key], attr^.FLoc2);
|
|
|
|
+ if not ValidateAttrSyntax(AttDef, attr^.FValueStr) then
|
|
|
|
+ DoErrorPos(esError, 'Attribute ''%s'' type mismatch', [attr^.FQName^.Key], attr^.FLoc2);
|
|
|
|
+ ValidateAttrValue(AttDef, attr);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
ntEndElement:
|
|
ntEndElement:
|
|
@@ -2911,7 +2939,6 @@ begin
|
|
if FNext = xtPopEmptyElement then
|
|
if FNext = xtPopEmptyElement then
|
|
begin
|
|
begin
|
|
FNext := xtPopElement;
|
|
FNext := xtPopElement;
|
|
- FToken := xtEndElement;
|
|
|
|
FCurrNode^.FNodeType := ntEndElement;
|
|
FCurrNode^.FNodeType := ntEndElement;
|
|
if FAttrCleanupFlag then
|
|
if FAttrCleanupFlag then
|
|
CleanupAttributes;
|
|
CleanupAttributes;
|
|
@@ -3020,7 +3047,6 @@ begin
|
|
if FCDSectionsAsText then
|
|
if FCDSectionsAsText then
|
|
Continue;
|
|
Continue;
|
|
SetNodeInfoWithValue(ntCDATA);
|
|
SetNodeInfoWithValue(ntCDATA);
|
|
- FToken := xtCDSect;
|
|
|
|
FNext := xtText;
|
|
FNext := xtText;
|
|
Result := True;
|
|
Result := True;
|
|
Exit;
|
|
Exit;
|
|
@@ -3055,7 +3081,6 @@ begin
|
|
if FValue.Length <> 0 then
|
|
if FValue.Length <> 0 then
|
|
begin
|
|
begin
|
|
SetNodeInfoWithValue(textNodeTypes[nonWs]);
|
|
SetNodeInfoWithValue(textNodeTypes[nonWs]);
|
|
- if nonWs then FToken := xtText else FToken := xtWhitespace;
|
|
|
|
FNext := tok;
|
|
FNext := tok;
|
|
Result := True;
|
|
Result := True;
|
|
Exit;
|
|
Exit;
|
|
@@ -3065,7 +3090,6 @@ begin
|
|
else // not (FNext in [xtText, xtCDSect])
|
|
else // not (FNext in [xtText, xtCDSect])
|
|
tok := FNext;
|
|
tok := FNext;
|
|
|
|
|
|
- FToken := tok;
|
|
|
|
FNext := xtText;
|
|
FNext := xtText;
|
|
|
|
|
|
case tok of
|
|
case tok of
|
|
@@ -3170,10 +3194,7 @@ begin
|
|
begin
|
|
begin
|
|
b := TBinding(FCurrNode^.FPrefix^.Data);
|
|
b := TBinding(FCurrNode^.FPrefix^.Data);
|
|
if not (Assigned(b) and (b.uri <> '')) then
|
|
if not (Assigned(b) and (b.uri <> '')) then
|
|
- begin
|
|
|
|
- FTokenStart := FCurrNode^.FLoc;
|
|
|
|
- FatalError('Unbound element name prefix "%s"', [FCurrNode^.FPrefix^.Key],-1);
|
|
|
|
- end;
|
|
|
|
|
|
+ DoErrorPos(esFatal, 'Unbound element name prefix "%s"', [FCurrNode^.FPrefix^.Key],FCurrNode^.FLoc);
|
|
FCurrNode^.FNsUri := FNameTable.FindOrAdd(PWideChar(b.uri), Length(b.uri));
|
|
FCurrNode^.FNsUri := FNameTable.FindOrAdd(PWideChar(b.uri), Length(b.uri));
|
|
end
|
|
end
|
|
else
|
|
else
|
|
@@ -3226,22 +3247,11 @@ var
|
|
attrData: PNodeData;
|
|
attrData: PNodeData;
|
|
AttDef: TAttributeDef;
|
|
AttDef: TAttributeDef;
|
|
i: Integer;
|
|
i: Integer;
|
|
- normalized: Boolean;
|
|
|
|
-
|
|
|
|
-procedure CheckValue;
|
|
|
|
-begin
|
|
|
|
- // TODO: what about normalization of AttDef.Value? (Currently it IS normalized)
|
|
|
|
- if (AttDef.Default = adFixed) and (AttDef.Data^.FValueStr <> attrData^.FValueStr) then
|
|
|
|
- ValidationError('Value of attribute ''%s'' does not match its #FIXED default',[attrData^.FQName^.Key], -1);
|
|
|
|
- if not ValidateAttrSyntax(AttDef, attrData^.FValueStr) then
|
|
|
|
- ValidationError('Attribute ''%s'' type mismatch', [attrData^.FQName^.Key], -1);
|
|
|
|
- ValidateAttrValue(AttDef, attrData);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
begin
|
|
begin
|
|
CheckName;
|
|
CheckName;
|
|
attrName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
|
|
attrName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
|
|
- attrData := AllocAttributeData(attrName);
|
|
|
|
|
|
+ attrData := AllocAttributeData;
|
|
|
|
+ attrData^.FQName := attrName;
|
|
attrData^.FColonPos := FColonPos;
|
|
attrData^.FColonPos := FColonPos;
|
|
StoreLocation(attrData^.FLoc);
|
|
StoreLocation(attrData^.FLoc);
|
|
Dec(attrData^.FLoc.LinePos, FName.Length);
|
|
Dec(attrData^.FLoc.LinePos, FName.Length);
|
|
@@ -3250,10 +3260,7 @@ begin
|
|
if Assigned(ElDef) then
|
|
if Assigned(ElDef) then
|
|
begin
|
|
begin
|
|
AttDef := ElDef.GetAttrDef(attrName);
|
|
AttDef := ElDef.GetAttrDef(attrName);
|
|
- if AttDef = nil then
|
|
|
|
- ValidationError('Using undeclared attribute ''%s'' on element ''%s''',
|
|
|
|
- [attrName^.Key, FNodeStack[FNesting].FQName^.Key], FName.Length)
|
|
|
|
- else
|
|
|
|
|
|
+ if Assigned(AttDef) then
|
|
AttDef.Tag := FAttrTag; // indicates that this one is specified
|
|
AttDef.Tag := FAttrTag; // indicates that this one is specified
|
|
end
|
|
end
|
|
else
|
|
else
|
|
@@ -3284,15 +3291,9 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
ExpectEq;
|
|
ExpectEq;
|
|
- normalized := ExpectAttValue(attrData, Assigned(AttDef) and (AttDef.DataType <> dtCDATA));
|
|
|
|
|
|
+ ExpectAttValue(attrData, Assigned(AttDef) and (AttDef.DataType <> dtCDATA));
|
|
|
|
+ attrData^.FLoc2 := FTokenStart;
|
|
|
|
|
|
- if Assigned(AttDef) and ((AttDef.DataType <> dtCdata) or (AttDef.Default = adFixed)) then
|
|
|
|
- begin
|
|
|
|
- if normalized and FStandalone and AttDef.ExternallyDeclared then
|
|
|
|
- StandaloneError(-1);
|
|
|
|
-
|
|
|
|
- CheckValue;
|
|
|
|
- end;
|
|
|
|
if Assigned(attrData^.FNsUri) then
|
|
if Assigned(attrData^.FNsUri) then
|
|
begin
|
|
begin
|
|
if (not AddBinding(attrData)) and FCanonical then
|
|
if (not AddBinding(attrData)) and FCanonical then
|
|
@@ -3348,9 +3349,7 @@ begin
|
|
begin
|
|
begin
|
|
case AttDef.Default of
|
|
case AttDef.Default of
|
|
adDefault, adFixed: begin
|
|
adDefault, adFixed: begin
|
|
- if FStandalone and AttDef.ExternallyDeclared then
|
|
|
|
- StandaloneError;
|
|
|
|
- attrData := AllocAttributeData(nil);
|
|
|
|
|
|
+ attrData := AllocAttributeData;
|
|
attrData^ := AttDef.Data^;
|
|
attrData^ := AttDef.Data^;
|
|
if FCanonical then
|
|
if FCanonical then
|
|
attrData^.FIsDefault := False;
|
|
attrData^.FIsDefault := False;
|
|
@@ -3396,13 +3395,13 @@ begin
|
|
(nsUri = FStduri_xmlns) then
|
|
(nsUri = FStduri_xmlns) then
|
|
begin
|
|
begin
|
|
if (Pfx = FStdPrefix_xml) or (Pfx = FStdPrefix_xmlns) then
|
|
if (Pfx = FStdPrefix_xml) or (Pfx = FStdPrefix_xmlns) then
|
|
- FatalError('Illegal usage of reserved prefix ''%s''', [Pfx^.Key])
|
|
|
|
|
|
+ DoErrorPos(esFatal, 'Illegal usage of reserved prefix ''%s''', [Pfx^.Key], attrData^.FLoc)
|
|
else
|
|
else
|
|
- FatalError('Illegal usage of reserved namespace URI ''%s''', [attrData^.FValueStr]);
|
|
|
|
|
|
+ DoErrorPos(esFatal, 'Illegal usage of reserved namespace URI ''%s''', [attrData^.FValueStr], attrData^.FLoc2);
|
|
end;
|
|
end;
|
|
|
|
|
|
if (attrData^.FValueStr = '') and not (FXML11 or (Pfx^.Key = '')) then
|
|
if (attrData^.FValueStr = '') and not (FXML11 or (Pfx^.Key = '')) then
|
|
- FatalError('Illegal undefining of namespace'); { position - ? }
|
|
|
|
|
|
+ DoErrorPos(esFatal, 'Illegal undefining of namespace', attrData^.FLoc2);
|
|
|
|
|
|
Result := (Pfx^.Data = nil) or (TBinding(Pfx^.Data).uri <> attrData^.FValueStr);
|
|
Result := (Pfx^.Data = nil) or (TBinding(Pfx^.Data).uri <> attrData^.FValueStr);
|
|
if Result then
|
|
if Result then
|
|
@@ -3426,10 +3425,7 @@ begin
|
|
Pfx := attrData^.FPrefix;
|
|
Pfx := attrData^.FPrefix;
|
|
b := TBinding(Pfx^.Data);
|
|
b := TBinding(Pfx^.Data);
|
|
if not (Assigned(b) and (b.uri <> '')) then
|
|
if not (Assigned(b) and (b.uri <> '')) then
|
|
- begin
|
|
|
|
- FTokenStart := attrData^.FLoc;
|
|
|
|
- FatalError('Unbound attribute name prefix "%s"', [Pfx^.Key], -1);
|
|
|
|
- end;
|
|
|
|
|
|
+ DoErrorPos(esFatal, 'Unbound attribute name prefix "%s"', [Pfx^.Key], attrData^.FLoc);
|
|
|
|
|
|
{ detect duplicates }
|
|
{ detect duplicates }
|
|
J := attrData^.FColonPos+1;
|
|
J := attrData^.FColonPos+1;
|
|
@@ -3500,7 +3496,7 @@ begin
|
|
case AttrDef.DataType of
|
|
case AttrDef.DataType of
|
|
dtId: begin
|
|
dtId: begin
|
|
if not AddID(attrData) then
|
|
if not AddID(attrData) then
|
|
- ValidationError('The ID ''%s'' is not unique', [attrData^.FValueStr], -1);
|
|
|
|
|
|
+ DoErrorPos(esError, 'The ID ''%s'' is not unique', [attrData^.FValueStr], attrData^.FLoc2);
|
|
end;
|
|
end;
|
|
|
|
|
|
dtIdRef, dtIdRefs: begin
|
|
dtIdRef, dtIdRefs: begin
|
|
@@ -3610,11 +3606,10 @@ begin
|
|
aNodeData^.FIDEntry := e;
|
|
aNodeData^.FIDEntry := e;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TXMLReader.AllocAttributeData(AName: PHashItem): PNodeData;
|
|
|
|
|
|
+function TXMLReader.AllocAttributeData: PNodeData;
|
|
begin
|
|
begin
|
|
Result := AllocNodeData(FNesting + FAttrCount + 1);
|
|
Result := AllocNodeData(FNesting + FAttrCount + 1);
|
|
Result^.FNodeType := ntAttribute;
|
|
Result^.FNodeType := ntAttribute;
|
|
- Result^.FQName := AName;
|
|
|
|
Result^.FPrefix := nil;
|
|
Result^.FPrefix := nil;
|
|
Result^.FNsUri := nil;
|
|
Result^.FNsUri := nil;
|
|
Result^.FIDEntry := nil;
|
|
Result^.FIDEntry := nil;
|