Straightening handling of base URI and SystemID:

- TXMLCharSource.PublicID removed, it is unused.
* Base URI of an entity is stored in FURI field of entity, and passed to ResolveEntity.
* When error happens while parsing an internal entity, report the URI where that entity was declared, not where it was included.

git-svn-id: trunk@13921 -
This commit is contained in:
sergei 2009-10-22 23:41:24 +00:00
parent 40069c3112
commit 06b5b65534

View File

@ -195,10 +195,8 @@ type
LFPos: PWideChar; LFPos: PWideChar;
FXML11Rules: Boolean; FXML11Rules: Boolean;
FSystemID: WideString; FSystemID: WideString;
FPublicID: WideString;
FCharCount: Cardinal; FCharCount: Cardinal;
function GetSystemID: WideString; function GetSystemID: WideString;
function GetPublicID: WideString;
protected protected
function Reload: Boolean; virtual; function Reload: Boolean; virtual;
public public
@ -212,7 +210,6 @@ type
function SetEncoding(const AEncoding: string): Boolean; virtual; function SetEncoding(const AEncoding: string): Boolean; virtual;
function Matches(const arg: WideString): Boolean; function Matches(const arg: WideString): Boolean;
property SystemID: WideString read GetSystemID write FSystemID; property SystemID: WideString read GetSystemID write FSystemID;
property PublicID: WideString read GetPublicID write FPublicID;
end; end;
TXMLDecodingSource = class(TXMLCharSource) TXMLDecodingSource = class(TXMLCharSource)
@ -429,7 +426,7 @@ type
procedure ExpectChoiceOrSeq(CP: TContentParticle); procedure ExpectChoiceOrSeq(CP: TContentParticle);
procedure ParseElementDecl; procedure ParseElementDecl;
procedure ParseNotationDecl; procedure ParseNotationDecl;
function ResolveEntity(const AbsSysID, PublicID, BaseURI: WideString; out Source: TXMLCharSource): Boolean; function ResolveEntity(const SystemID, PublicID, BaseURI: 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; PrefixPtr: PWideChar; PrefixLen: Integer); procedure AddBinding(Attr: TDOMAttr; PrefixPtr: PWideChar; PrefixLen: Integer);
@ -836,16 +833,6 @@ begin
Result := True; // always succeed Result := True; // always succeed
end; end;
function TXMLCharSource.GetPublicID: WideString;
begin
if FPublicID <> '' then
Result := FPublicID
else if Assigned(FParent) then
Result := FParent.PublicID
else
Result := '';
end;
function TXMLCharSource.GetSystemID: WideString; function TXMLCharSource.GetSystemID: WideString;
begin begin
if FSystemID <> '' then if FSystemID <> '' then
@ -1193,14 +1180,17 @@ begin
Loc.LinePos := FSource.FBuf-FSource.LFPos; Loc.LinePos := FSource.FBuf-FSource.LFPos;
end; end;
function TXMLReader.ResolveEntity(const AbsSysID, PublicID, BaseURI: WideString; out Source: TXMLCharSource): Boolean; function TXMLReader.ResolveEntity(const SystemID, PublicID, BaseURI: 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 ResolveRelativeURI(BaseURI, 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
@ -1216,7 +1206,6 @@ begin
Stream := THandleOwnerStream.Create(fd); Stream := THandleOwnerStream.Create(fd);
Source := TXMLStreamInputSource.Create(Stream, True); Source := TXMLStreamInputSource.Create(Stream, True);
Source.SystemID := AbsSysID; // <- Revisit: Really need absolute sysID? Source.SystemID := AbsSysID; // <- Revisit: Really need absolute sysID?
Source.PublicID := PublicID;
end; end;
end; end;
Result := Assigned(Source); Result := Assigned(Source);
@ -1270,9 +1259,15 @@ end;
procedure TXMLReader.DoErrorPos(Severity: TErrorSeverity; const descr: string; const ErrPos: TLocation); procedure TXMLReader.DoErrorPos(Severity: TErrorSeverity; const descr: string; const ErrPos: TLocation);
var var
E: EXMLReadError; E: EXMLReadError;
sysid: WideString;
begin begin
if Assigned(FSource) then if Assigned(FSource) then
E := EXMLReadError.CreateFmt('In ''%s'' (line %d pos %d): %s', [FSource.SystemID, ErrPos.Line, ErrPos.LinePos, descr]) begin
sysid := FSource.FSystemID;
if (sysid = '') and Assigned(FSource.FEntity) then
sysid := TDOMEntityEx(FSource.FEntity).FURI;
E := EXMLReadError.CreateFmt('In ''%s'' (line %d pos %d): %s', [sysid, ErrPos.Line, ErrPos.LinePos, descr]);
end
else else
E := EXMLReadError.Create(descr); E := EXMLReadError.Create(descr);
E.FSeverity := Severity; E.FSeverity := Severity;
@ -1745,7 +1740,7 @@ var
begin begin
if (AEntity.SystemID <> '') and not AEntity.FResolved then if (AEntity.SystemID <> '') and not AEntity.FResolved then
begin begin
Result := ResolveEntity(AEntity.FURI, AEntity.PublicID, '', Src); Result := ResolveEntity(AEntity.SystemID, AEntity.PublicID, AEntity.FURI, 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
@ -1756,10 +1751,11 @@ 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;
// needed in case of prefetched external PE
if AEntity.SystemID <> '' then
Src.SystemID := AEntity.FURI;
end; end;
AEntity.FOnStack := True; AEntity.FOnStack := True;
@ -1897,6 +1893,7 @@ begin
PEnt.FCharCount := FValue.Length; PEnt.FCharCount := FValue.Length;
PEnt.FStartLocation.Line := 1; PEnt.FStartLocation.Line := 1;
PEnt.FStartLocation.LinePos := 1; PEnt.FStartLocation.LinePos := 1;
PEnt.FURI := FSource.SystemID; // replace base URI with absolute one
finally finally
ContextPop; ContextPop;
PEnt.FResolved := True; PEnt.FResolved := True;
@ -2114,7 +2111,6 @@ 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');
@ -2160,8 +2156,7 @@ begin
if (FDocType.SystemID <> '') then if (FDocType.SystemID <> '') then
begin begin
ResolveRelativeURI(FSource.SystemID, FDocType.SystemID, DoctypeURI); if ResolveEntity(FDocType.SystemID, FDocType.PublicID, FSource.SystemID, Src) then
if ResolveEntity(DocTypeURI, FDocType.PublicID, '', Src) then
begin begin
Initialize(Src); Initialize(Src);
try try
@ -2587,6 +2582,8 @@ begin
CheckNCName; CheckNCName;
ExpectWhitespace; ExpectWhitespace;
// remember where the entity is declared
Entity.FURI := FSource.SystemID;
if (FSource.FBuf^ = '"') or (FSource.FBuf^ = '''') then if (FSource.FBuf^ = '"') or (FSource.FBuf^ = '''') then
begin begin
NDataAllowed := False; NDataAllowed := False;
@ -2598,14 +2595,8 @@ begin
SetString(Entity.FReplacementText, FEntityValue.Buffer, FEntityValue.Length); SetString(Entity.FReplacementText, FEntityValue.Buffer, FEntityValue.Length);
Entity.FCharCount := FEntityValue.Length; Entity.FCharCount := FEntityValue.Length;
end end
else else if not ParseExternalID(Entity.FSystemID, Entity.FPublicID, False) then
begin FatalError('Expected entity value or external ID');
if not ParseExternalID(Entity.FSystemID, Entity.FPublicID, False) then
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