|
@@ -66,6 +66,8 @@ type
|
|
FCDSectionsAsText: Boolean;
|
|
FCDSectionsAsText: Boolean;
|
|
FResolveExternals: Boolean;
|
|
FResolveExternals: Boolean;
|
|
FNamespaces: Boolean;
|
|
FNamespaces: Boolean;
|
|
|
|
+ FDisallowDoctype: Boolean;
|
|
|
|
+ FMaxChars: Cardinal;
|
|
public
|
|
public
|
|
property Validate: Boolean read FValidate write FValidate;
|
|
property Validate: Boolean read FValidate write FValidate;
|
|
property PreserveWhitespace: Boolean read FPreserveWhitespace write FPreserveWhitespace;
|
|
property PreserveWhitespace: Boolean read FPreserveWhitespace write FPreserveWhitespace;
|
|
@@ -74,6 +76,8 @@ type
|
|
property CDSectionsAsText: Boolean read FCDSectionsAsText write FCDSectionsAsText;
|
|
property CDSectionsAsText: Boolean read FCDSectionsAsText write FCDSectionsAsText;
|
|
property ResolveExternals: Boolean read FResolveExternals write FResolveExternals;
|
|
property ResolveExternals: Boolean read FResolveExternals write FResolveExternals;
|
|
property Namespaces: Boolean read FNamespaces write FNamespaces;
|
|
property Namespaces: Boolean read FNamespaces write FNamespaces;
|
|
|
|
+ property DisallowDoctype: Boolean read FDisallowDoctype write FDisallowDoctype;
|
|
|
|
+ property MaxChars: Cardinal read FMaxChars write FMaxChars;
|
|
end;
|
|
end;
|
|
|
|
|
|
// NOTE: DOM 3 LS ACTION_TYPE enumeration starts at 1
|
|
// NOTE: DOM 3 LS ACTION_TYPE enumeration starts at 1
|
|
@@ -162,7 +166,9 @@ type
|
|
FOnStack: Boolean;
|
|
FOnStack: Boolean;
|
|
FBetweenDecls: Boolean;
|
|
FBetweenDecls: Boolean;
|
|
FReplacementText: DOMString;
|
|
FReplacementText: DOMString;
|
|
|
|
+ FURI: DOMString;
|
|
FStartLocation: TLocation;
|
|
FStartLocation: TLocation;
|
|
|
|
+ FCharCount: Cardinal;
|
|
end;
|
|
end;
|
|
|
|
|
|
PWideCharBuf = ^TWideCharBuf;
|
|
PWideCharBuf = ^TWideCharBuf;
|
|
@@ -186,6 +192,7 @@ type
|
|
FXML11Rules: Boolean;
|
|
FXML11Rules: Boolean;
|
|
FSystemID: WideString;
|
|
FSystemID: WideString;
|
|
FPublicID: WideString;
|
|
FPublicID: WideString;
|
|
|
|
+ FCharCount: Cardinal;
|
|
function GetSystemID: WideString;
|
|
function GetSystemID: WideString;
|
|
function GetPublicID: WideString;
|
|
function GetPublicID: WideString;
|
|
protected
|
|
protected
|
|
@@ -233,6 +240,7 @@ type
|
|
FStream: TStream;
|
|
FStream: TStream;
|
|
FCapacity: Integer;
|
|
FCapacity: Integer;
|
|
FOwnStream: Boolean;
|
|
FOwnStream: Boolean;
|
|
|
|
+ FEof: Boolean;
|
|
public
|
|
public
|
|
constructor Create(AStream: TStream; AOwnStream: Boolean);
|
|
constructor Create(AStream: TStream; AOwnStream: Boolean);
|
|
destructor Destroy; override;
|
|
destructor Destroy; override;
|
|
@@ -279,6 +287,7 @@ type
|
|
end;
|
|
end;
|
|
|
|
|
|
TElementValidator = object
|
|
TElementValidator = object
|
|
|
|
+ FElement: TDOMElement;
|
|
FElementDef: TDOMElementDef;
|
|
FElementDef: TDOMElementDef;
|
|
FCurCP: TContentParticle;
|
|
FCurCP: TContentParticle;
|
|
FFailed: Boolean;
|
|
FFailed: Boolean;
|
|
@@ -289,6 +298,7 @@ type
|
|
TXMLReadState = (rsProlog, rsDTD, rsRoot, rsEpilog);
|
|
TXMLReadState = (rsProlog, rsDTD, rsRoot, rsEpilog);
|
|
|
|
|
|
TElementContentType = (
|
|
TElementContentType = (
|
|
|
|
+ ctUndeclared,
|
|
ctAny,
|
|
ctAny,
|
|
ctEmpty,
|
|
ctEmpty,
|
|
ctMixed,
|
|
ctMixed,
|
|
@@ -353,12 +363,12 @@ type
|
|
FCDSectionsAsText: Boolean;
|
|
FCDSectionsAsText: Boolean;
|
|
FResolveExternals: Boolean;
|
|
FResolveExternals: Boolean;
|
|
FNamespaces: Boolean;
|
|
FNamespaces: Boolean;
|
|
|
|
+ FDisallowDoctype: Boolean;
|
|
|
|
+ FMaxChars: Cardinal;
|
|
|
|
|
|
procedure RaiseExpectedQmark;
|
|
procedure RaiseExpectedQmark;
|
|
- procedure GetChar;
|
|
|
|
procedure Initialize(ASource: TXMLCharSource);
|
|
procedure Initialize(ASource: TXMLCharSource);
|
|
function DoParseAttValue(Delim: WideChar): Boolean;
|
|
function DoParseAttValue(Delim: WideChar): Boolean;
|
|
- procedure DoParseFragment;
|
|
|
|
function ContextPush(AEntity: TDOMEntityEx): Boolean;
|
|
function ContextPush(AEntity: TDOMEntityEx): Boolean;
|
|
function ContextPop: Boolean;
|
|
function ContextPop: Boolean;
|
|
procedure XML11_BuildTables;
|
|
procedure XML11_BuildTables;
|
|
@@ -373,6 +383,7 @@ type
|
|
procedure CallErrorHandler(E: EXMLReadError);
|
|
procedure CallErrorHandler(E: EXMLReadError);
|
|
function FindOrCreateElDef: TDOMElementDef;
|
|
function FindOrCreateElDef: TDOMElementDef;
|
|
function SkipUntilSeq(const Delim: TSetOfChar; const More: array of WideChar): Boolean;
|
|
function SkipUntilSeq(const Delim: TSetOfChar; const More: array of WideChar): Boolean;
|
|
|
|
+ procedure CheckMaxChars;
|
|
protected
|
|
protected
|
|
FCursor: TDOMNode_WithChildren;
|
|
FCursor: TDOMNode_WithChildren;
|
|
FNesting: Integer;
|
|
FNesting: Integer;
|
|
@@ -406,6 +417,8 @@ type
|
|
procedure ParseDoctypeDecl; // [28]
|
|
procedure ParseDoctypeDecl; // [28]
|
|
procedure ParseMarkupDecl; // [29]
|
|
procedure ParseMarkupDecl; // [29]
|
|
procedure ParseElement; // [39]
|
|
procedure ParseElement; // [39]
|
|
|
|
+ procedure ParseEndTag; // [42]
|
|
|
|
+ procedure DoEndElement(ErrOffset: Integer);
|
|
procedure ParseAttribute(Elem: TDOMElement; ElDef: TDOMElementDef);
|
|
procedure ParseAttribute(Elem: TDOMElement; ElDef: TDOMElementDef);
|
|
procedure ParseContent; // [43]
|
|
procedure ParseContent; // [43]
|
|
function ResolvePredefined: Boolean;
|
|
function ResolvePredefined: Boolean;
|
|
@@ -422,13 +435,13 @@ type
|
|
procedure ExpectChoiceOrSeq(CP: TContentParticle);
|
|
procedure ExpectChoiceOrSeq(CP: TContentParticle);
|
|
procedure ParseElementDecl;
|
|
procedure ParseElementDecl;
|
|
procedure ParseNotationDecl;
|
|
procedure ParseNotationDecl;
|
|
- function ResolveEntity(const SystemID, PublicID: WideString; out Source: TXMLCharSource): Boolean;
|
|
|
|
|
|
+ function ResolveEntity(const AbsSysID, PublicID: WideString; out Source: TXMLCharSource): Boolean;
|
|
procedure ProcessDefaultAttributes(Element: TDOMElement; Map: TDOMNamedNodeMap);
|
|
procedure ProcessDefaultAttributes(Element: TDOMElement; Map: TDOMNamedNodeMap);
|
|
procedure ProcessNamespaceAtts(Element: TDOMElement);
|
|
procedure ProcessNamespaceAtts(Element: TDOMElement);
|
|
procedure AddBinding(Attr: TDOMAttr; Prefix: PHashItem; var Chain: TBinding);
|
|
procedure AddBinding(Attr: TDOMAttr; Prefix: PHashItem; var Chain: TBinding);
|
|
procedure EndNamespaceScope(var Chain: TBinding);
|
|
procedure EndNamespaceScope(var Chain: TBinding);
|
|
|
|
|
|
- procedure PushVC(aElDef: TDOMElementDef);
|
|
|
|
|
|
+ procedure PushVC(aElement: TDOMElement; aElDef: TDOMElementDef);
|
|
procedure PopVC;
|
|
procedure PopVC;
|
|
procedure UpdateConstraints;
|
|
procedure UpdateConstraints;
|
|
procedure ValidateDTD;
|
|
procedure ValidateDTD;
|
|
@@ -458,7 +471,6 @@ type
|
|
public
|
|
public
|
|
FExternallyDeclared: Boolean;
|
|
FExternallyDeclared: Boolean;
|
|
ContentType: TElementContentType;
|
|
ContentType: TElementContentType;
|
|
- HasElementDecl: Boolean;
|
|
|
|
IDAttr: TDOMAttrDef;
|
|
IDAttr: TDOMAttrDef;
|
|
NotationAttr: TDOMAttrDef;
|
|
NotationAttr: TDOMAttrDef;
|
|
RootCP: TContentParticle;
|
|
RootCP: TContentParticle;
|
|
@@ -795,6 +807,7 @@ begin
|
|
FBuf := PWideChar(AData);
|
|
FBuf := PWideChar(AData);
|
|
FBufEnd := FBuf + Length(AData);
|
|
FBufEnd := FBuf + Length(AData);
|
|
LFPos := FBuf-1;
|
|
LFPos := FBuf-1;
|
|
|
|
+ FCharCount := Length(AData);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TXMLCharSource.Initialize;
|
|
procedure TXMLCharSource.Initialize;
|
|
@@ -947,7 +960,12 @@ begin
|
|
if rslt = 0 then
|
|
if rslt = 0 then
|
|
Break
|
|
Break
|
|
else if rslt < 0 then
|
|
else if rslt < 0 then
|
|
- DecodingError('Invalid character in input stream');
|
|
|
|
|
|
+ DecodingError('Invalid character in input stream')
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ Inc(FCharCount, rslt);
|
|
|
|
+ FReader.CheckMaxChars;
|
|
|
|
+ end;
|
|
until False;
|
|
until False;
|
|
|
|
|
|
FBufEnd^ := #0;
|
|
FBufEnd^ := #0;
|
|
@@ -1082,7 +1100,8 @@ var
|
|
OldBuf: PChar;
|
|
OldBuf: PChar;
|
|
begin
|
|
begin
|
|
Assert(FCharBufEnd - FCharBuf < Slack-4);
|
|
Assert(FCharBufEnd - FCharBuf < Slack-4);
|
|
-
|
|
|
|
|
|
+ if FEof then
|
|
|
|
+ Exit;
|
|
OldBuf := FCharBuf;
|
|
OldBuf := FCharBuf;
|
|
Remainder := FCharBufEnd - FCharBuf;
|
|
Remainder := FCharBufEnd - FCharBuf;
|
|
if Remainder < 0 then
|
|
if Remainder < 0 then
|
|
@@ -1091,6 +1110,8 @@ begin
|
|
if Remainder > 0 then
|
|
if Remainder > 0 then
|
|
Move(OldBuf^, FCharBuf^, Remainder);
|
|
Move(OldBuf^, FCharBuf^, Remainder);
|
|
BytesRead := FStream.Read(FAllocated[Slack-4], FCapacity);
|
|
BytesRead := FStream.Read(FAllocated[Slack-4], FCapacity);
|
|
|
|
+ if BytesRead < FCapacity then
|
|
|
|
+ FEof := True;
|
|
FCharBufEnd := FAllocated + (Slack-4) + BytesRead;
|
|
FCharBufEnd := FAllocated + (Slack-4) + BytesRead;
|
|
PWideChar(FCharBufEnd)^ := #0;
|
|
PWideChar(FCharBufEnd)^ := #0;
|
|
end;
|
|
end;
|
|
@@ -1152,20 +1173,14 @@ begin
|
|
Loc.LinePos := FSource.FBuf-FSource.LFPos;
|
|
Loc.LinePos := FSource.FBuf-FSource.LFPos;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TXMLReader.ResolveEntity(const SystemID, PublicID: WideString; out Source: TXMLCharSource): Boolean;
|
|
|
|
|
|
+function TXMLReader.ResolveEntity(const AbsSysID, PublicID: WideString; out Source: TXMLCharSource): Boolean;
|
|
var
|
|
var
|
|
- AbsSysID: WideString;
|
|
|
|
Filename: string;
|
|
Filename: string;
|
|
Stream: TStream;
|
|
Stream: TStream;
|
|
fd: THandle;
|
|
fd: THandle;
|
|
begin
|
|
begin
|
|
Source := nil;
|
|
Source := nil;
|
|
Result := False;
|
|
Result := False;
|
|
- if not Assigned(FSource) then
|
|
|
|
- AbsSysID := SystemID
|
|
|
|
- else
|
|
|
|
- if not ResolveRelativeURI(FSource.SystemID, SystemID, AbsSysID) then
|
|
|
|
- Exit;
|
|
|
|
{ TODO: alternative resolvers
|
|
{ TODO: alternative resolvers
|
|
These may be 'internal' resolvers or a handler set by application.
|
|
These may be 'internal' resolvers or a handler set by application.
|
|
Internal resolvers should probably produce a TStream
|
|
Internal resolvers should probably produce a TStream
|
|
@@ -1195,11 +1210,6 @@ begin
|
|
FSource.Initialize;
|
|
FSource.Initialize;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TXMLReader.GetChar;
|
|
|
|
-begin
|
|
|
|
- FSource.NextChar;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
procedure TXMLReader.RaiseExpectedQmark;
|
|
procedure TXMLReader.RaiseExpectedQmark;
|
|
begin
|
|
begin
|
|
FatalError('Expected single or double quote');
|
|
FatalError('Expected single or double quote');
|
|
@@ -1260,6 +1270,23 @@ begin
|
|
E.Free;
|
|
E.Free;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TXMLReader.CheckMaxChars;
|
|
|
|
+var
|
|
|
|
+ src: TXMLCharSource;
|
|
|
|
+ total: Cardinal;
|
|
|
|
+begin
|
|
|
|
+ if FMaxChars = 0 then
|
|
|
|
+ Exit;
|
|
|
|
+ src := FSource;
|
|
|
|
+ total := 0;
|
|
|
|
+ repeat
|
|
|
|
+ Inc(total, src.FCharCount);
|
|
|
|
+ if total > FMaxChars then
|
|
|
|
+ FatalError('Exceeded character count limit');
|
|
|
|
+ src := src.FParent;
|
|
|
|
+ until src = nil;
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TXMLReader.CallErrorHandler(E: EXMLReadError);
|
|
procedure TXMLReader.CallErrorHandler(E: EXMLReadError);
|
|
begin
|
|
begin
|
|
try
|
|
try
|
|
@@ -1406,6 +1433,8 @@ begin
|
|
FIgnoreComments := FCtrl.Options.IgnoreComments;
|
|
FIgnoreComments := FCtrl.Options.IgnoreComments;
|
|
FResolveExternals := FCtrl.Options.ResolveExternals;
|
|
FResolveExternals := FCtrl.Options.ResolveExternals;
|
|
FNamespaces := FCtrl.Options.Namespaces;
|
|
FNamespaces := FCtrl.Options.Namespaces;
|
|
|
|
+ FDisallowDoctype := FCtrl.Options.DisallowDoctype;
|
|
|
|
+ FMaxChars := FCtrl.Options.MaxChars;
|
|
end;
|
|
end;
|
|
|
|
|
|
destructor TXMLReader.Destroy;
|
|
destructor TXMLReader.Destroy;
|
|
@@ -1442,11 +1471,12 @@ end;
|
|
procedure TXMLReader.ProcessXML(ASource: TXMLCharSource);
|
|
procedure TXMLReader.ProcessXML(ASource: TXMLCharSource);
|
|
begin
|
|
begin
|
|
doc := TXMLDocument.Create;
|
|
doc := TXMLDocument.Create;
|
|
|
|
+ doc.documentURI := ASource.SystemID; // TODO: to be changed to URI or BaseURI
|
|
FCursor := doc;
|
|
FCursor := doc;
|
|
FState := rsProlog;
|
|
FState := rsProlog;
|
|
FNesting := 0;
|
|
FNesting := 0;
|
|
Initialize(ASource);
|
|
Initialize(ASource);
|
|
- DoParseFragment;
|
|
|
|
|
|
+ ParseContent;
|
|
|
|
|
|
if FState < rsRoot then
|
|
if FState < rsRoot then
|
|
FatalError('Root element is missing');
|
|
FatalError('Root element is missing');
|
|
@@ -1462,7 +1492,7 @@ begin
|
|
FState := rsRoot;
|
|
FState := rsRoot;
|
|
Initialize(ASource);
|
|
Initialize(ASource);
|
|
FXML11 := doc.InheritsFrom(TXMLDocument) and (TXMLDocument(doc).XMLVersion = '1.1');
|
|
FXML11 := doc.InheritsFrom(TXMLDocument) and (TXMLDocument(doc).XMLVersion = '1.1');
|
|
- DoParseFragment;
|
|
|
|
|
|
+ ParseContent;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TXMLReader.CheckName(aFlags: TCheckNameFlags): Boolean;
|
|
function TXMLReader.CheckName(aFlags: TCheckNameFlags): Boolean;
|
|
@@ -1526,6 +1556,7 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
BufAppendChunk(FName, FSource.FBuf, p);
|
|
BufAppendChunk(FName, FSource.FBuf, p);
|
|
|
|
+ Result := (FName.Length > 0);
|
|
|
|
|
|
FSource.FBuf := p;
|
|
FSource.FBuf := p;
|
|
if (p^ <> #0) or not FSource.Reload then
|
|
if (p^ <> #0) or not FSource.Reload then
|
|
@@ -1533,7 +1564,6 @@ begin
|
|
|
|
|
|
p := FSource.FBuf;
|
|
p := FSource.FBuf;
|
|
until False;
|
|
until False;
|
|
- Result := (FName.Length > 0);
|
|
|
|
if not (Result or (cnOptional in aFlags)) then
|
|
if not (Result or (cnOptional in aFlags)) then
|
|
RaiseNameNotFound;
|
|
RaiseNameNotFound;
|
|
end;
|
|
end;
|
|
@@ -1615,7 +1645,7 @@ begin
|
|
else
|
|
else
|
|
Break;
|
|
Break;
|
|
end;
|
|
end;
|
|
- GetChar;
|
|
|
|
|
|
+ FSource.NextChar;
|
|
until Value > $10FFFF
|
|
until Value > $10FFFF
|
|
else
|
|
else
|
|
repeat
|
|
repeat
|
|
@@ -1624,7 +1654,7 @@ begin
|
|
else
|
|
else
|
|
Break;
|
|
Break;
|
|
end;
|
|
end;
|
|
- GetChar;
|
|
|
|
|
|
+ FSource.NextChar;
|
|
until Value > $10FFFF;
|
|
until Value > $10FFFF;
|
|
|
|
|
|
case Value of
|
|
case Value of
|
|
@@ -1693,22 +1723,13 @@ begin
|
|
Result := wc <> #0;
|
|
Result := wc <> #0;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TXMLReader.DoParseFragment;
|
|
|
|
-begin
|
|
|
|
- // SAX: ContentHandler.StartDocument() - here?
|
|
|
|
- ParseContent;
|
|
|
|
- if FSource.FBuf^ <> #0 then
|
|
|
|
- FatalError('End-tag is not allowed here');
|
|
|
|
- // SAX: ContentHandler.EndDocument() - here? or somewhere in destructor?
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
function TXMLReader.ContextPush(AEntity: TDOMEntityEx): Boolean;
|
|
function TXMLReader.ContextPush(AEntity: TDOMEntityEx): Boolean;
|
|
var
|
|
var
|
|
Src: TXMLCharSource;
|
|
Src: TXMLCharSource;
|
|
begin
|
|
begin
|
|
- if AEntity.SystemID <> '' then
|
|
|
|
|
|
+ if (AEntity.SystemID <> '') and not AEntity.FResolved then
|
|
begin
|
|
begin
|
|
- Result := ResolveEntity(AEntity.SystemID, AEntity.PublicID, Src);
|
|
|
|
|
|
+ Result := ResolveEntity(AEntity.FURI, AEntity.PublicID, Src);
|
|
if not Result then
|
|
if not Result then
|
|
begin
|
|
begin
|
|
// TODO: a detailed message like SysErrorMessage(GetLastError) would be great here
|
|
// TODO: a detailed message like SysErrorMessage(GetLastError) would be great here
|
|
@@ -1719,6 +1740,8 @@ begin
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
Src := TXMLCharSource.Create(AEntity.FReplacementText);
|
|
Src := TXMLCharSource.Create(AEntity.FReplacementText);
|
|
|
|
+ // needed in case of prefetched external PE
|
|
|
|
+ Src.SystemID := AEntity.FURI;
|
|
Src.FLineNo := AEntity.FStartLocation.Line;
|
|
Src.FLineNo := AEntity.FStartLocation.Line;
|
|
Src.LFPos := Src.FBuf - AEntity.FStartLocation.LinePos;
|
|
Src.LFPos := Src.FBuf - AEntity.FStartLocation.LinePos;
|
|
end;
|
|
end;
|
|
@@ -1743,6 +1766,7 @@ begin
|
|
if Assigned(FSource.FEntity) then
|
|
if Assigned(FSource.FEntity) then
|
|
begin
|
|
begin
|
|
TDOMEntityEx(FSource.FEntity).FOnStack := False;
|
|
TDOMEntityEx(FSource.FEntity).FOnStack := False;
|
|
|
|
+ TDOMEntityEx(FSource.FEntity).FCharCount := FSource.FCharCount;
|
|
// [28a] PE that was started between MarkupDecls may not end inside MarkupDecl
|
|
// [28a] PE that was started between MarkupDecls may not end inside MarkupDecl
|
|
Error := TDOMEntityEx(FSource.FEntity).FBetweenDecls and FInsideDecl;
|
|
Error := TDOMEntityEx(FSource.FEntity).FBetweenDecls and FInsideDecl;
|
|
end;
|
|
end;
|
|
@@ -1760,9 +1784,11 @@ var
|
|
RefName: WideString;
|
|
RefName: WideString;
|
|
Child: TDOMNode;
|
|
Child: TDOMNode;
|
|
SaveCursor: TDOMNode_WithChildren;
|
|
SaveCursor: TDOMNode_WithChildren;
|
|
|
|
+ cnt: Cardinal;
|
|
begin
|
|
begin
|
|
AEntity := nil;
|
|
AEntity := nil;
|
|
SetString(RefName, FName.Buffer, FName.Length);
|
|
SetString(RefName, FName.Buffer, FName.Length);
|
|
|
|
+ cnt := FName.Length+2;
|
|
|
|
|
|
if Assigned(FDocType) then
|
|
if Assigned(FDocType) then
|
|
AEntity := FDocType.Entities.GetNamedItem(RefName) as TDOMEntityEx;
|
|
AEntity := FDocType.Entities.GetNamedItem(RefName) as TDOMEntityEx;
|
|
@@ -1770,19 +1796,19 @@ begin
|
|
if AEntity = nil then
|
|
if AEntity = nil then
|
|
begin
|
|
begin
|
|
if FStandalone or (FDocType = nil) or not (FHavePERefs or (FDocType.SystemID <> '')) then
|
|
if FStandalone or (FDocType = nil) or not (FHavePERefs or (FDocType.SystemID <> '')) then
|
|
- FatalError('Reference to undefined entity ''%s''', [RefName], FName.Length+2)
|
|
|
|
|
|
+ FatalError('Reference to undefined entity ''%s''', [RefName], cnt)
|
|
else
|
|
else
|
|
- ValidationError('Undefined entity ''%s'' referenced', [RefName], FName.Length+2);
|
|
|
|
|
|
+ ValidationError('Undefined entity ''%s'' referenced', [RefName], cnt);
|
|
FCursor.AppendChild(doc.CreateEntityReference(RefName));
|
|
FCursor.AppendChild(doc.CreateEntityReference(RefName));
|
|
Exit;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
if InAttr and (AEntity.SystemID <> '') then
|
|
if InAttr and (AEntity.SystemID <> '') then
|
|
- FatalError('External entity reference is not allowed in attribute value', FName.Length+2);
|
|
|
|
|
|
+ FatalError('External entity reference is not allowed in attribute value', cnt);
|
|
if FStandalone and AEntity.FExternallyDeclared then
|
|
if FStandalone and AEntity.FExternallyDeclared then
|
|
- FatalError('Standalone constraint violation', FName.Length+2);
|
|
|
|
|
|
+ FatalError('Standalone constraint violation', cnt);
|
|
if AEntity.NotationName <> '' then
|
|
if AEntity.NotationName <> '' then
|
|
- FatalError('Reference to unparsed entity ''%s''', [RefName], FName.Length+2);
|
|
|
|
|
|
+ FatalError('Reference to unparsed entity ''%s''', [RefName], cnt);
|
|
|
|
|
|
if not AEntity.FResolved then
|
|
if not AEntity.FResolved then
|
|
begin
|
|
begin
|
|
@@ -1798,7 +1824,7 @@ begin
|
|
if InAttr then
|
|
if InAttr then
|
|
DoParseAttValue(#0)
|
|
DoParseAttValue(#0)
|
|
else
|
|
else
|
|
- DoParseFragment;
|
|
|
|
|
|
+ ParseContent;
|
|
AEntity.FResolved := True;
|
|
AEntity.FResolved := True;
|
|
finally
|
|
finally
|
|
AEntity.SetReadOnly(True);
|
|
AEntity.SetReadOnly(True);
|
|
@@ -1808,6 +1834,9 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
+ // charcount of the entity included is known at this point
|
|
|
|
+ Inc(FSource.FCharCount, AEntity.FCharCount - cnt);
|
|
|
|
+ CheckMaxChars;
|
|
if (not FExpandEntities) or (not AEntity.FResolved) then
|
|
if (not FExpandEntities) or (not AEntity.FResolved) then
|
|
begin
|
|
begin
|
|
// This will clone Entity children
|
|
// This will clone Entity children
|
|
@@ -1841,6 +1870,27 @@ begin
|
|
if PEnt.FOnStack then
|
|
if PEnt.FOnStack then
|
|
FatalError('Entity ''%%%s'' recursively references itself', [PEnt.NodeName]);
|
|
FatalError('Entity ''%%%s'' recursively references itself', [PEnt.NodeName]);
|
|
|
|
|
|
|
|
+ { cache an external PE so it's only fetched once }
|
|
|
|
+ if (PEnt.SystemID <> '') and not PEnt.FResolved then
|
|
|
|
+ begin
|
|
|
|
+ if ContextPush(PEnt) then
|
|
|
|
+ try
|
|
|
|
+ FValue.Length := 0;
|
|
|
|
+ FSource.SkipUntil(FValue, [#0]);
|
|
|
|
+ SetString(PEnt.FReplacementText, FValue.Buffer, FValue.Length);
|
|
|
|
+ PEnt.FCharCount := FValue.Length;
|
|
|
|
+ PEnt.FStartLocation.Line := 1;
|
|
|
|
+ PEnt.FStartLocation.LinePos := 1;
|
|
|
|
+ finally
|
|
|
|
+ ContextPop;
|
|
|
|
+ PEnt.FResolved := True;
|
|
|
|
+ FValue.Length := 0;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ Inc(FSource.FCharCount, PEnt.FCharCount);
|
|
|
|
+ CheckMaxChars;
|
|
|
|
+
|
|
PEnt.FBetweenDecls := not FInsideDecl;
|
|
PEnt.FBetweenDecls := not FInsideDecl;
|
|
ContextPush(PEnt);
|
|
ContextPush(PEnt);
|
|
FHavePERefs := True;
|
|
FHavePERefs := True;
|
|
@@ -1853,7 +1903,7 @@ begin
|
|
if (FSource.FBuf^ <> '''') and (FSource.FBuf^ <> '"') then
|
|
if (FSource.FBuf^ <> '''') and (FSource.FBuf^ <> '"') then
|
|
RaiseExpectedQmark;
|
|
RaiseExpectedQmark;
|
|
Delim := FSource.FBuf^;
|
|
Delim := FSource.FBuf^;
|
|
- GetChar; // skip quote
|
|
|
|
|
|
+ FSource.NextChar; // skip quote
|
|
StoreLocation(FTokenStart);
|
|
StoreLocation(FTokenStart);
|
|
if not DoParseAttValue(Delim) then
|
|
if not DoParseAttValue(Delim) then
|
|
FatalError('Literal has no closing quote',-1);
|
|
FatalError('Literal has no closing quote',-1);
|
|
@@ -1866,7 +1916,7 @@ begin
|
|
if (FSource.FBuf^ = '''') or (FSource.FBuf^ = '"') then
|
|
if (FSource.FBuf^ = '''') or (FSource.FBuf^ = '"') then
|
|
begin
|
|
begin
|
|
Delim := FSource.FBuf^;
|
|
Delim := FSource.FBuf^;
|
|
- GetChar; // skip quote
|
|
|
|
|
|
+ FSource.NextChar; // skip quote
|
|
StoreLocation(FTokenStart);
|
|
StoreLocation(FTokenStart);
|
|
FValue.Length := 0;
|
|
FValue.Length := 0;
|
|
if Delim = '''' then
|
|
if Delim = '''' then
|
|
@@ -1955,7 +2005,7 @@ var
|
|
Name, Value: WideString;
|
|
Name, Value: WideString;
|
|
PINode: TDOMProcessingInstruction;
|
|
PINode: TDOMProcessingInstruction;
|
|
begin
|
|
begin
|
|
- GetChar; // skip '?'
|
|
|
|
|
|
+ FSource.NextChar; // skip '?'
|
|
Name := ExpectName;
|
|
Name := ExpectName;
|
|
CheckNCName;
|
|
CheckNCName;
|
|
with FName do
|
|
with FName do
|
|
@@ -2083,9 +2133,12 @@ end;
|
|
procedure TXMLReader.ParseDoctypeDecl; // [28]
|
|
procedure TXMLReader.ParseDoctypeDecl; // [28]
|
|
var
|
|
var
|
|
Src: TXMLCharSource;
|
|
Src: TXMLCharSource;
|
|
|
|
+ DoctypeURI: WideString;
|
|
begin
|
|
begin
|
|
if FState >= rsDTD then
|
|
if FState >= rsDTD then
|
|
FatalError('Markup declaration is not allowed here');
|
|
FatalError('Markup declaration is not allowed here');
|
|
|
|
+ if FDisallowDoctype then
|
|
|
|
+ FatalError('Document type is prohibited by parser settings');
|
|
|
|
|
|
ExpectString('DOCTYPE');
|
|
ExpectString('DOCTYPE');
|
|
SkipS(True);
|
|
SkipS(True);
|
|
@@ -2123,7 +2176,8 @@ begin
|
|
|
|
|
|
if (FDocType.SystemID <> '') then
|
|
if (FDocType.SystemID <> '') then
|
|
begin
|
|
begin
|
|
- if ResolveEntity(FDocType.SystemID, FDocType.PublicID, Src) then
|
|
|
|
|
|
+ ResolveRelativeURI(FSource.SystemID, FDocType.SystemID, DoctypeURI);
|
|
|
|
+ if ResolveEntity(DocTypeURI, FDocType.PublicID, Src) then
|
|
begin
|
|
begin
|
|
Initialize(Src);
|
|
Initialize(Src);
|
|
try
|
|
try
|
|
@@ -2148,7 +2202,7 @@ begin
|
|
SkipS;
|
|
SkipS;
|
|
if FSource.FBuf^ <> '=' then
|
|
if FSource.FBuf^ <> '=' then
|
|
FatalError('Expected "="');
|
|
FatalError('Expected "="');
|
|
- GetChar;
|
|
|
|
|
|
+ FSource.NextChar;
|
|
SkipS;
|
|
SkipS;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -2209,7 +2263,7 @@ begin
|
|
ExpectChoiceOrSeq(CurrentCP);
|
|
ExpectChoiceOrSeq(CurrentCP);
|
|
if CurrentEntity <> FSource.FEntity then
|
|
if CurrentEntity <> FSource.FEntity then
|
|
BadPENesting;
|
|
BadPENesting;
|
|
- GetChar;
|
|
|
|
|
|
+ FSource.NextChar;
|
|
end
|
|
end
|
|
else
|
|
else
|
|
CurrentCP.Def := FindOrCreateElDef;
|
|
CurrentCP.Def := FindOrCreateElDef;
|
|
@@ -2228,7 +2282,7 @@ begin
|
|
else
|
|
else
|
|
if FSource.FBuf^ <> Delim then
|
|
if FSource.FBuf^ <> Delim then
|
|
FatalError(Delim);
|
|
FatalError(Delim);
|
|
- GetChar; // skip delimiter
|
|
|
|
|
|
+ FSource.NextChar; // skip delimiter
|
|
until False;
|
|
until False;
|
|
if Delim = '|' then
|
|
if Delim = '|' then
|
|
CP.CPType := ctChoice
|
|
CP.CPType := ctChoice
|
|
@@ -2246,10 +2300,10 @@ var
|
|
ExtDecl: Boolean;
|
|
ExtDecl: Boolean;
|
|
begin
|
|
begin
|
|
CP := nil;
|
|
CP := nil;
|
|
- Typ := ctAny; // satisfy compiler
|
|
|
|
|
|
+ Typ := ctUndeclared; // satisfy compiler
|
|
ExpectWhitespace;
|
|
ExpectWhitespace;
|
|
ElDef := FindOrCreateElDef;
|
|
ElDef := FindOrCreateElDef;
|
|
- if ElDef.HasElementDecl then
|
|
|
|
|
|
+ if ElDef.ContentType <> ctUndeclared then
|
|
ValidationError('Duplicate declaration of element ''%s''', [ElDef.TagName], FName.Length);
|
|
ValidationError('Duplicate declaration of element ''%s''', [ElDef.TagName], FName.Length);
|
|
|
|
|
|
ExtDecl := FSource.DTDSubsetType <> dsInternal;
|
|
ExtDecl := FSource.DTDSubsetType <> dsInternal;
|
|
@@ -2285,7 +2339,7 @@ begin
|
|
end;
|
|
end;
|
|
if CurrentEntity <> FSource.FEntity then
|
|
if CurrentEntity <> FSource.FEntity then
|
|
BadPENesting;
|
|
BadPENesting;
|
|
- GetChar;
|
|
|
|
|
|
+ FSource.NextChar;
|
|
if (not CheckForChar('*')) and (CP.ChildCount > 0) then
|
|
if (not CheckForChar('*')) and (CP.ChildCount > 0) then
|
|
FatalError(WideChar('*'));
|
|
FatalError(WideChar('*'));
|
|
end
|
|
end
|
|
@@ -2295,7 +2349,7 @@ begin
|
|
ExpectChoiceOrSeq(CP);
|
|
ExpectChoiceOrSeq(CP);
|
|
if CurrentEntity <> FSource.FEntity then
|
|
if CurrentEntity <> FSource.FEntity then
|
|
BadPENesting;
|
|
BadPENesting;
|
|
- GetChar;
|
|
|
|
|
|
+ FSource.NextChar;
|
|
ParseQuantity(CP);
|
|
ParseQuantity(CP);
|
|
end;
|
|
end;
|
|
except
|
|
except
|
|
@@ -2306,9 +2360,8 @@ begin
|
|
else
|
|
else
|
|
FatalError('Invalid content specification');
|
|
FatalError('Invalid content specification');
|
|
// SAX: DeclHandler.ElementDecl(name, model);
|
|
// SAX: DeclHandler.ElementDecl(name, model);
|
|
- if not ElDef.HasElementDecl then
|
|
|
|
|
|
+ if ElDef.ContentType = ctUndeclared then
|
|
begin
|
|
begin
|
|
- ElDef.HasElementDecl := True;
|
|
|
|
ElDef.FExternallyDeclared := ExtDecl;
|
|
ElDef.FExternallyDeclared := ExtDecl;
|
|
ElDef.ContentType := Typ;
|
|
ElDef.ContentType := Typ;
|
|
ElDef.RootCP := CP;
|
|
ElDef.RootCP := CP;
|
|
@@ -2414,6 +2467,7 @@ begin
|
|
ExpectChar('(');
|
|
ExpectChar('(');
|
|
repeat
|
|
repeat
|
|
SkipWhitespace;
|
|
SkipWhitespace;
|
|
|
|
+ StoreLocation(FTokenStart);
|
|
CheckName;
|
|
CheckName;
|
|
CheckNCName;
|
|
CheckNCName;
|
|
if not AttDef.AddEnumToken(FName.Buffer, FName.Length) then
|
|
if not AttDef.AddEnumToken(FName.Buffer, FName.Length) then
|
|
@@ -2463,8 +2517,7 @@ begin
|
|
if DiscardIt then
|
|
if DiscardIt then
|
|
AttDef.Free;
|
|
AttDef.Free;
|
|
except
|
|
except
|
|
- if AttDef.OwnerElement = nil then
|
|
|
|
- AttDef.Free;
|
|
|
|
|
|
+ AttDef.Free;
|
|
raise;
|
|
raise;
|
|
end;
|
|
end;
|
|
SkipWhitespace;
|
|
SkipWhitespace;
|
|
@@ -2547,15 +2600,21 @@ begin
|
|
begin
|
|
begin
|
|
NDataAllowed := False;
|
|
NDataAllowed := False;
|
|
Delim := FSource.FBuf^;
|
|
Delim := FSource.FBuf^;
|
|
- GetChar;
|
|
|
|
|
|
+ FSource.NextChar;
|
|
StoreLocation(Entity.FStartLocation);
|
|
StoreLocation(Entity.FStartLocation);
|
|
if not ParseEntityDeclValue(Delim) then
|
|
if not ParseEntityDeclValue(Delim) then
|
|
DoErrorPos(esFatal, 'Literal has no closing quote', Entity.FStartLocation);
|
|
DoErrorPos(esFatal, 'Literal has no closing quote', Entity.FStartLocation);
|
|
SetString(Entity.FReplacementText, FEntityValue.Buffer, FEntityValue.Length);
|
|
SetString(Entity.FReplacementText, FEntityValue.Buffer, FEntityValue.Length);
|
|
|
|
+ Entity.FCharCount := FEntityValue.Length;
|
|
end
|
|
end
|
|
else
|
|
else
|
|
|
|
+ begin
|
|
if not ParseExternalID(Entity.FSystemID, Entity.FPublicID, False) then
|
|
if not ParseExternalID(Entity.FSystemID, Entity.FPublicID, False) then
|
|
FatalError('Expected entity value or external ID');
|
|
FatalError('Expected entity value or external ID');
|
|
|
|
+ { need to resolve entity's SystemID relative to the current source,
|
|
|
|
+ which may differ from the source at the point of inclusion }
|
|
|
|
+ ResolveRelativeURI(FSource.SystemID, Entity.SystemID, Entity.FURI);
|
|
|
|
+ end;
|
|
|
|
|
|
if NDataAllowed then // [76]
|
|
if NDataAllowed then // [76]
|
|
begin
|
|
begin
|
|
@@ -2564,6 +2623,7 @@ begin
|
|
if FSource.Matches('NDATA') then
|
|
if FSource.Matches('NDATA') then
|
|
begin
|
|
begin
|
|
ExpectWhitespace;
|
|
ExpectWhitespace;
|
|
|
|
+ StoreLocation(FTokenStart);
|
|
Entity.FNotationName := ExpectName;
|
|
Entity.FNotationName := ExpectName;
|
|
AddForwardRef(FNotationRefs, FName.Buffer, FName.Length);
|
|
AddForwardRef(FNotationRefs, FName.Buffer, FName.Length);
|
|
// SAX: DTDHandler.UnparsedEntityDecl(...);
|
|
// SAX: DTDHandler.UnparsedEntityDecl(...);
|
|
@@ -2771,16 +2831,24 @@ procedure TXMLReader.ParseContent;
|
|
var
|
|
var
|
|
nonWs: Boolean;
|
|
nonWs: Boolean;
|
|
wc: WideChar;
|
|
wc: WideChar;
|
|
|
|
+ StartNesting: Integer;
|
|
begin
|
|
begin
|
|
|
|
+ StartNesting := FNesting;
|
|
with FSource do
|
|
with FSource do
|
|
repeat
|
|
repeat
|
|
if FBuf^ = '<' then
|
|
if FBuf^ = '<' then
|
|
begin
|
|
begin
|
|
- if FBufEnd < FBuf + 3 then
|
|
|
|
- Reload;
|
|
|
|
Inc(FBuf);
|
|
Inc(FBuf);
|
|
- if FBuf^ = '/' then Break; // end tag case is as frequent as start tag
|
|
|
|
- if CheckName([cnOptional]) then
|
|
|
|
|
|
+ if FBufEnd < FBuf + 2 then
|
|
|
|
+ Reload;
|
|
|
|
+ if FBuf^ = '/' then
|
|
|
|
+ begin
|
|
|
|
+ if FNesting <= StartNesting then
|
|
|
|
+ FatalError('End-tag is not allowed here');
|
|
|
|
+ Inc(FBuf);
|
|
|
|
+ ParseEndTag;
|
|
|
|
+ end
|
|
|
|
+ else if CheckName([cnOptional]) then
|
|
ParseElement
|
|
ParseElement
|
|
else if FBuf^ = '!' then
|
|
else if FBuf^ = '!' then
|
|
begin
|
|
begin
|
|
@@ -2849,6 +2917,8 @@ begin
|
|
FatalError('Illegal at document level', -1);
|
|
FatalError('Illegal at document level', -1);
|
|
end;
|
|
end;
|
|
until FBuf^ = #0;
|
|
until FBuf^ = #0;
|
|
|
|
+ if FNesting > StartNesting then
|
|
|
|
+ FatalError('End-tag is missing for ''%s''', [FValidator[FNesting].FElement.NSI.QName^.Key]);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TXMLCharSource.NextChar;
|
|
procedure TXMLCharSource.NextChar;
|
|
@@ -2872,7 +2942,6 @@ var
|
|
NewElem: TDOMElement;
|
|
NewElem: TDOMElement;
|
|
ElDef: TDOMElementDef;
|
|
ElDef: TDOMElementDef;
|
|
IsEmpty: Boolean;
|
|
IsEmpty: Boolean;
|
|
- ErrOffset: Integer;
|
|
|
|
ElName: PHashItem;
|
|
ElName: PHashItem;
|
|
begin
|
|
begin
|
|
if FState > rsRoot then
|
|
if FState > rsRoot then
|
|
@@ -2894,7 +2963,7 @@ begin
|
|
|
|
|
|
// Find declaration for this element
|
|
// Find declaration for this element
|
|
ElDef := TDOMElementDef(ElName^.Data);
|
|
ElDef := TDOMElementDef(ElName^.Data);
|
|
- if (ElDef = nil) or (not ElDef.HasElementDecl) then
|
|
|
|
|
|
+ if (ElDef = nil) or (ElDef.ContentType = ctUndeclared) then
|
|
ValidationError('Using undeclared element ''%s''',[ElName^.Key], FName.Length);
|
|
ValidationError('Using undeclared element ''%s''',[ElName^.Key], FName.Length);
|
|
|
|
|
|
// Check if new element is allowed in current context
|
|
// Check if new element is allowed in current context
|
|
@@ -2913,65 +2982,69 @@ begin
|
|
if FSource.FBuf^ = '/' then
|
|
if FSource.FBuf^ = '/' then
|
|
begin
|
|
begin
|
|
IsEmpty := True;
|
|
IsEmpty := True;
|
|
- GetChar;
|
|
|
|
|
|
+ FSource.NextChar;
|
|
end;
|
|
end;
|
|
ExpectChar('>');
|
|
ExpectChar('>');
|
|
|
|
|
|
if Assigned(ElDef) and Assigned(ElDef.FAttributes) then
|
|
if Assigned(ElDef) and Assigned(ElDef.FAttributes) then
|
|
ProcessDefaultAttributes(NewElem, ElDef.FAttributes);
|
|
ProcessDefaultAttributes(NewElem, ElDef.FAttributes);
|
|
- PushVC(ElDef); // this increases FNesting
|
|
|
|
|
|
+ PushVC(NewElem, ElDef); // this increases FNesting
|
|
if FNamespaces then
|
|
if FNamespaces then
|
|
ProcessNamespaceAtts(NewElem);
|
|
ProcessNamespaceAtts(NewElem);
|
|
|
|
|
|
- // SAX: ContentHandler.StartElement(...)
|
|
|
|
- // SAX: ContentHandler.StartPrefixMapping(...)
|
|
|
|
-
|
|
|
|
- ErrOffset := 0;
|
|
|
|
if not IsEmpty then
|
|
if not IsEmpty then
|
|
begin
|
|
begin
|
|
FCursor := NewElem;
|
|
FCursor := NewElem;
|
|
if not FPreserveWhitespace then // critical for testsuite compliance
|
|
if not FPreserveWhitespace then // critical for testsuite compliance
|
|
SkipS;
|
|
SkipS;
|
|
- ParseContent;
|
|
|
|
- if FSource.FBuf^ = '/' then // Get ETag [42]
|
|
|
|
- begin
|
|
|
|
- FSource.NextChar;
|
|
|
|
- CheckName;
|
|
|
|
- if not BufEquals(FName, ElName^.Key) then
|
|
|
|
- FatalError('Unmatching element end tag (expected "</%s>")', [ElName^.Key], FName.Length);
|
|
|
|
- if FSource.FBuf^ = '>' then // this handles majority of cases
|
|
|
|
- begin
|
|
|
|
- ErrOffset := FName.Length+1;
|
|
|
|
- FSource.NextChar;
|
|
|
|
- end
|
|
|
|
- else // but if closing '>' is preceded by whitespace,
|
|
|
|
- begin // skipping it is likely to lose position info.
|
|
|
|
- StoreLocation(FTokenStart);
|
|
|
|
- Dec(FTokenStart.LinePos, FName.Length);
|
|
|
|
- ErrOffset := -1;
|
|
|
|
- SkipS;
|
|
|
|
- ExpectChar('>');
|
|
|
|
- end;
|
|
|
|
- end
|
|
|
|
- else if FSource.FBuf^ <> #0 then
|
|
|
|
- RaiseNameNotFound
|
|
|
|
- else // End of stream in content
|
|
|
|
- FatalError('End-tag is missing for ''%s''', [ElName^.Key]);
|
|
|
|
- end;
|
|
|
|
- // SAX: ContentHandler.EndElement(...)
|
|
|
|
- // SAX: ContentHandler.EndPrefixMapping(...)
|
|
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ DoEndElement(0);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TXMLReader.DoEndElement(ErrOffset: Integer);
|
|
|
|
+var
|
|
|
|
+ NewElem: TDOMElement;
|
|
|
|
+begin
|
|
|
|
+ NewElem := FValidator[FNesting].FElement;
|
|
TDOMNode(FCursor) := NewElem.ParentNode;
|
|
TDOMNode(FCursor) := NewElem.ParentNode;
|
|
if FCursor = doc then
|
|
if FCursor = doc then
|
|
FState := rsEpilog;
|
|
FState := rsEpilog;
|
|
|
|
|
|
if FValidate and FValidator[FNesting].Incomplete then
|
|
if FValidate and FValidator[FNesting].Incomplete then
|
|
- ValidationError('Element ''%s'' is missing required sub-elements', [ElName^.Key], ErrOffset);
|
|
|
|
|
|
+ ValidationError('Element ''%s'' is missing required sub-elements', [NewElem.NSI.QName^.Key], ErrOffset);
|
|
|
|
|
|
if FNamespaces then
|
|
if FNamespaces then
|
|
EndNamespaceScope(FBindingStack[FNesting]);
|
|
EndNamespaceScope(FBindingStack[FNesting]);
|
|
PopVC;
|
|
PopVC;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TXMLReader.ParseEndTag; // [42]
|
|
|
|
+var
|
|
|
|
+ ErrOffset: Integer;
|
|
|
|
+ ElName: PHashItem;
|
|
|
|
+begin
|
|
|
|
+ ElName := FValidator[FNesting].FElement.NSI.QName;
|
|
|
|
+
|
|
|
|
+ CheckName;
|
|
|
|
+ if not BufEquals(FName, ElName^.Key) then
|
|
|
|
+ FatalError('Unmatching element end tag (expected "</%s>")', [ElName^.Key], FName.Length);
|
|
|
|
+ if FSource.FBuf^ = '>' then // this handles majority of cases
|
|
|
|
+ begin
|
|
|
|
+ ErrOffset := FName.Length+1;
|
|
|
|
+ FSource.NextChar;
|
|
|
|
+ end
|
|
|
|
+ else // but if closing '>' is preceded by whitespace,
|
|
|
|
+ begin // skipping it is likely to lose position info.
|
|
|
|
+ StoreLocation(FTokenStart);
|
|
|
|
+ Dec(FTokenStart.LinePos, FName.Length);
|
|
|
|
+ ErrOffset := -1;
|
|
|
|
+ SkipS;
|
|
|
|
+ ExpectChar('>');
|
|
|
|
+ end;
|
|
|
|
+ DoEndElement(ErrOffset);
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TXMLReader.ParseAttribute(Elem: TDOMElement; ElDef: TDOMElementDef);
|
|
procedure TXMLReader.ParseAttribute(Elem: TDOMElement; ElDef: TDOMElementDef);
|
|
var
|
|
var
|
|
attr: TDOMAttr;
|
|
attr: TDOMAttr;
|
|
@@ -3038,14 +3111,8 @@ var
|
|
w: PForwardRef;
|
|
w: PForwardRef;
|
|
begin
|
|
begin
|
|
New(w);
|
|
New(w);
|
|
- SetString(w^.Value, Buf, Abs(Length));
|
|
|
|
- if Length > 0 then
|
|
|
|
- begin
|
|
|
|
- StoreLocation(w^.Loc);
|
|
|
|
- Dec(w^.Loc.LinePos, Length);
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- w^.Loc := FTokenStart;
|
|
|
|
|
|
+ SetString(w^.Value, Buf, Length);
|
|
|
|
+ w^.Loc := FTokenStart;
|
|
aList.Add(w);
|
|
aList.Add(w);
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -3299,8 +3366,7 @@ begin
|
|
EndPos := StartPos;
|
|
EndPos := StartPos;
|
|
while (EndPos <= L) and (aValue[EndPos] <> #32) do
|
|
while (EndPos <= L) and (aValue[EndPos] <> #32) do
|
|
Inc(EndPos);
|
|
Inc(EndPos);
|
|
- // pass negative length, so uses FTokenStart as location
|
|
|
|
- AddForwardRef(FIDRefs, @aValue[StartPos], StartPos-EndPos);
|
|
|
|
|
|
+ AddForwardRef(FIDRefs, @aValue[StartPos], EndPos-StartPos);
|
|
StartPos := EndPos + 1;
|
|
StartPos := EndPos + 1;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
@@ -3421,11 +3487,12 @@ begin
|
|
ValidationError('Duplicate notation declaration: ''%s''', [aName]);
|
|
ValidationError('Duplicate notation declaration: ''%s''', [aName]);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TXMLReader.PushVC(aElDef: TDOMElementDef);
|
|
|
|
|
|
+procedure TXMLReader.PushVC(aElement: TDOMElement; aElDef: TDOMElementDef);
|
|
begin
|
|
begin
|
|
Inc(FNesting);
|
|
Inc(FNesting);
|
|
if FNesting >= Length(FValidator) then
|
|
if FNesting >= Length(FValidator) then
|
|
SetLength(FValidator, FNesting * 2);
|
|
SetLength(FValidator, FNesting * 2);
|
|
|
|
+ FValidator[FNesting].FElement := aElement;
|
|
FValidator[FNesting].FElementDef := aElDef;
|
|
FValidator[FNesting].FElementDef := aElDef;
|
|
FValidator[FNesting].FCurCP := nil;
|
|
FValidator[FNesting].FCurCP := nil;
|
|
FValidator[FNesting].FFailed := False;
|
|
FValidator[FNesting].FFailed := False;
|
|
@@ -3486,7 +3553,7 @@ begin
|
|
else
|
|
else
|
|
FFailed := True; // used to prevent extra error at the end of element
|
|
FFailed := True; // used to prevent extra error at the end of element
|
|
end;
|
|
end;
|
|
- // ctAny: returns True by default
|
|
|
|
|
|
+ // ctAny, ctUndeclared: returns True by default
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
@@ -3639,8 +3706,8 @@ begin
|
|
Reader := TXMLReader.Create;
|
|
Reader := TXMLReader.Create;
|
|
try
|
|
try
|
|
Reader.ProcessXML(Src);
|
|
Reader.ProcessXML(Src);
|
|
- ADoc := TXMLDocument(Reader.Doc);
|
|
|
|
finally
|
|
finally
|
|
|
|
+ ADoc := TXMLDocument(Reader.Doc);
|
|
Reader.Free;
|
|
Reader.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
@@ -3688,7 +3755,6 @@ begin
|
|
Reader := TXMLReader.Create;
|
|
Reader := TXMLReader.Create;
|
|
try
|
|
try
|
|
Src := TXMLFileInputSource.Create(f);
|
|
Src := TXMLFileInputSource.Create(f);
|
|
- Src.SystemID := FilenameToURI(TTextRec(f).Name);
|
|
|
|
Reader.ProcessFragment(Src, AParentNode);
|
|
Reader.ProcessFragment(Src, AParentNode);
|
|
finally
|
|
finally
|
|
Reader.Free;
|
|
Reader.Free;
|
|
@@ -3737,10 +3803,9 @@ begin
|
|
Reader := TXMLReader.Create;
|
|
Reader := TXMLReader.Create;
|
|
try
|
|
try
|
|
Src := TXMLFileInputSource.Create(f);
|
|
Src := TXMLFileInputSource.Create(f);
|
|
- Src.SystemID := FilenameToURI(TTextRec(f).Name);
|
|
|
|
Reader.ProcessDTD(Src);
|
|
Reader.ProcessDTD(Src);
|
|
- ADoc := TXMLDocument(Reader.doc);
|
|
|
|
finally
|
|
finally
|
|
|
|
+ ADoc := TXMLDocument(Reader.doc);
|
|
Reader.Free;
|
|
Reader.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
@@ -3756,8 +3821,8 @@ begin
|
|
Src := TXMLStreamInputSource.Create(f, False);
|
|
Src := TXMLStreamInputSource.Create(f, False);
|
|
Src.SystemID := ABaseURI;
|
|
Src.SystemID := ABaseURI;
|
|
Reader.ProcessDTD(Src);
|
|
Reader.ProcessDTD(Src);
|
|
- ADoc := TXMLDocument(Reader.doc);
|
|
|
|
finally
|
|
finally
|
|
|
|
+ ADoc := TXMLDocument(Reader.doc);
|
|
Reader.Free;
|
|
Reader.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|