Browse Source

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 -

sergei 16 years ago
parent
commit
06b5b65534
1 changed files with 22 additions and 31 deletions
  1. 22 31
      packages/fcl-xml/src/xmlread.pp

+ 22 - 31
packages/fcl-xml/src/xmlread.pp

@@ -195,10 +195,8 @@ type
     LFPos: PWideChar;
     FXML11Rules: Boolean;
     FSystemID: WideString;
-    FPublicID: WideString;
     FCharCount: Cardinal;
     function GetSystemID: WideString;
-    function GetPublicID: WideString;
   protected
     function Reload: Boolean; virtual;
   public
@@ -212,7 +210,6 @@ type
     function SetEncoding(const AEncoding: string): Boolean; virtual;
     function Matches(const arg: WideString): Boolean;
     property SystemID: WideString read GetSystemID write FSystemID;
-    property PublicID: WideString read GetPublicID write FPublicID;
   end;
 
   TXMLDecodingSource = class(TXMLCharSource)
@@ -429,7 +426,7 @@ type
     procedure ExpectChoiceOrSeq(CP: TContentParticle);
     procedure ParseElementDecl;
     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 ProcessNamespaceAtts(Element: TDOMElement);
     procedure AddBinding(Attr: TDOMAttr; PrefixPtr: PWideChar; PrefixLen: Integer);
@@ -836,16 +833,6 @@ begin
   Result := True; // always succeed
 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;
 begin
   if FSystemID <> '' then
@@ -1193,14 +1180,17 @@ begin
   Loc.LinePos := FSource.FBuf-FSource.LFPos;
 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
+  AbsSysID: WideString;
   Filename: string;
   Stream: TStream;
   fd: THandle;
 begin
   Source := nil;
   Result := False;
+  if not ResolveRelativeURI(BaseURI, SystemID, AbsSysID) then
+    Exit;
   { TODO: alternative resolvers
     These may be 'internal' resolvers or a handler set by application.
     Internal resolvers should probably produce a TStream
@@ -1216,7 +1206,6 @@ begin
       Stream := THandleOwnerStream.Create(fd);
       Source := TXMLStreamInputSource.Create(Stream, True);
       Source.SystemID := AbsSysID;    // <- Revisit: Really need absolute sysID?
-      Source.PublicID := PublicID;
     end;
   end;
   Result := Assigned(Source);
@@ -1270,9 +1259,15 @@ end;
 procedure TXMLReader.DoErrorPos(Severity: TErrorSeverity; const descr: string; const ErrPos: TLocation);
 var
   E: EXMLReadError;
+  sysid: WideString;
 begin
   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
     E := EXMLReadError.Create(descr);
   E.FSeverity := Severity;
@@ -1745,7 +1740,7 @@ var
 begin
   if (AEntity.SystemID <> '') and not AEntity.FResolved then
   begin
-    Result := ResolveEntity(AEntity.FURI, AEntity.PublicID, '', Src);
+    Result := ResolveEntity(AEntity.SystemID, AEntity.PublicID, AEntity.FURI, Src);
     if not Result then
     begin
       // TODO: a detailed message like SysErrorMessage(GetLastError) would be great here 
@@ -1756,10 +1751,11 @@ begin
   else
   begin
     Src := TXMLCharSource.Create(AEntity.FReplacementText);
-    // needed in case of prefetched external PE
-    Src.SystemID := AEntity.FURI;
     Src.FLineNo := AEntity.FStartLocation.Line;
     Src.LFPos := Src.FBuf - AEntity.FStartLocation.LinePos;
+    // needed in case of prefetched external PE
+    if AEntity.SystemID <> '' then
+      Src.SystemID := AEntity.FURI;
   end;
 
   AEntity.FOnStack := True;
@@ -1897,6 +1893,7 @@ begin
       PEnt.FCharCount := FValue.Length;
       PEnt.FStartLocation.Line := 1;
       PEnt.FStartLocation.LinePos := 1;
+      PEnt.FURI := FSource.SystemID;    // replace base URI with absolute one
     finally
       ContextPop;
       PEnt.FResolved := True;
@@ -2114,7 +2111,6 @@ end;
 procedure TXMLReader.ParseDoctypeDecl;    // [28]
 var
   Src: TXMLCharSource;
-  DoctypeURI: WideString;
 begin
   if FState >= rsDTD then
     FatalError('Markup declaration is not allowed here');
@@ -2160,8 +2156,7 @@ begin
 
   if (FDocType.SystemID <> '') then
   begin
-    ResolveRelativeURI(FSource.SystemID, FDocType.SystemID, DoctypeURI);
-    if ResolveEntity(DocTypeURI, FDocType.PublicID, '', Src) then
+    if ResolveEntity(FDocType.SystemID, FDocType.PublicID, FSource.SystemID, Src) then
     begin
       Initialize(Src);
       try
@@ -2587,6 +2582,8 @@ begin
     CheckNCName;
     ExpectWhitespace;
 
+    // remember where the entity is declared
+    Entity.FURI := FSource.SystemID;
     if (FSource.FBuf^ = '"') or (FSource.FBuf^ = '''') then
     begin
       NDataAllowed := False;
@@ -2598,14 +2595,8 @@ begin
       SetString(Entity.FReplacementText, FEntityValue.Buffer, FEntityValue.Length);
       Entity.FCharCount := FEntityValue.Length;
     end
-    else
-    begin
-      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;
+    else if not ParseExternalID(Entity.FSystemID, Entity.FPublicID, False) then
+      FatalError('Expected entity value or external ID');
 
     if NDataAllowed then                // [76]
     begin