Browse Source

* xmlread.pp: In case of reference to an undefined parameter entity, produce a validation error and ignore further DTD declarations unless the document is standalone (compliance).

git-svn-id: trunk@14293 -
sergei 15 years ago
parent
commit
9eac0ee0a4
1 changed files with 24 additions and 13 deletions
  1. 24 13
      packages/fcl-xml/src/xmlread.pp

+ 24 - 13
packages/fcl-xml/src/xmlread.pp

@@ -344,6 +344,7 @@ type
     FIntSubset: TWideCharBuf;
     FIntSubset: TWideCharBuf;
     FAttrTag: Cardinal;
     FAttrTag: Cardinal;
     FOwnsDoctype: Boolean;
     FOwnsDoctype: Boolean;
+    FDTDProcessed: Boolean;
 
 
     FNSHelper: TNSSupport;
     FNSHelper: TNSSupport;
     FWorkAtts: array of TPrefixedAttr;
     FWorkAtts: array of TPrefixedAttr;
@@ -419,7 +420,7 @@ type
     function  ResolvePredefined: Boolean;
     function  ResolvePredefined: Boolean;
     function  EntityCheck(NoExternals: Boolean = False): TDOMEntityEx;
     function  EntityCheck(NoExternals: Boolean = False): TDOMEntityEx;
     procedure AppendReference(AEntity: TDOMEntityEx);
     procedure AppendReference(AEntity: TDOMEntityEx);
-    procedure PrefetchEntity(AEntity: TDOMEntityEx);    
+    function PrefetchEntity(AEntity: TDOMEntityEx): Boolean;
     procedure StartPE;
     procedure StartPE;
     function  ParseRef(var ToFill: TWideCharBuf): Boolean;              // [67]
     function  ParseRef(var ToFill: TWideCharBuf): Boolean;              // [67]
     function  ParseExternalID(out SysID, PubID: WideString;             // [75]
     function  ParseExternalID(out SysID, PubID: WideString;             // [75]
@@ -1893,16 +1894,20 @@ begin
   PEnt := nil;
   PEnt := nil;
   if Assigned(FPEMap) then
   if Assigned(FPEMap) then
     PEnt := FPEMap.GetNamedItem(PEName) as TDOMEntityEx;
     PEnt := FPEMap.GetNamedItem(PEName) as TDOMEntityEx;
-  if PEnt = nil then    // TODO -cVC: Referencing undefined PE
-  begin                 // (These are classified as 'optional errors'...)
-//    ValidationError('Undefined parameter entity referenced: %s', [PEName]);
+  if PEnt = nil then
+  begin
+    ValidationError('Undefined parameter entity ''%s'' referenced', [PEName], FName.Length+2);
+    // cease processing declarations, unless document is standalone.
+    FDTDProcessed := FStandalone;
     Exit;
     Exit;
   end;
   end;
 
 
   { cache an external PE so it's only fetched once }
   { cache an external PE so it's only fetched once }
-  if (PEnt.SystemID <> '') and not PEnt.FPrefetched then
-    PrefetchEntity(PEnt);
-
+  if (PEnt.SystemID <> '') and (not PEnt.FPrefetched) and (not PrefetchEntity(PEnt)) then
+  begin
+    FDTDProcessed := FStandalone;
+    Exit;
+  end;
   Inc(FSource.FCharCount, PEnt.FCharCount);
   Inc(FSource.FCharCount, PEnt.FCharCount);
   CheckMaxChars;
   CheckMaxChars;
 
 
@@ -1911,9 +1916,10 @@ begin
   FHavePERefs := True;
   FHavePERefs := True;
 end;
 end;
 
 
-procedure TXMLReader.PrefetchEntity(AEntity: TDOMEntityEx);
+function TXMLReader.PrefetchEntity(AEntity: TDOMEntityEx): Boolean;
 begin
 begin
-  if ContextPush(AEntity) then
+  Result := ContextPush(AEntity);
+  if Result then
   try
   try
     FValue.Length := 0;
     FValue.Length := 0;
     FSource.SkipUntil(FValue, [#0]);
     FSource.SkipUntil(FValue, [#0]);
@@ -2245,6 +2251,7 @@ begin
   SkipS(True);
   SkipS(True);
 
 
   FDocType := TDOMDocumentTypeEx(TDOMDocumentType.Create(doc));
   FDocType := TDOMDocumentTypeEx(TDOMDocumentType.Create(doc));
+  FDTDProcessed := True;    // assume success
   FState := rsDTD;
   FState := rsDTD;
   try
   try
     FDocType.FName := ExpectName;
     FDocType.FName := ExpectName;
@@ -2292,7 +2299,10 @@ begin
       end;
       end;
     end
     end
     else
     else
+    begin
       ValidationError('Unable to resolve external DTD subset', []);
       ValidationError('Unable to resolve external DTD subset', []);
+      FDTDProcessed := FStandalone;
+    end;
   end;
   end;
   FCursor := Doc;
   FCursor := Doc;
   ValidateDTD;
   ValidateDTD;
@@ -2463,7 +2473,7 @@ begin
   else
   else
     FatalError('Invalid content specification');
     FatalError('Invalid content specification');
   // SAX: DeclHandler.ElementDecl(name, model);
   // SAX: DeclHandler.ElementDecl(name, model);
-  if ElDef.ContentType = ctUndeclared then
+  if FDTDProcessed and (ElDef.ContentType = ctUndeclared) then
   begin
   begin
     ElDef.FExternallyDeclared := ExtDecl;
     ElDef.FExternallyDeclared := ExtDecl;
     ElDef.ContentType := Typ;
     ElDef.ContentType := Typ;
@@ -2484,7 +2494,8 @@ begin
   ExpectWhitespace;
   ExpectWhitespace;
   if not ParseExternalID(SysID, PubID, True) then
   if not ParseExternalID(SysID, PubID, True) then
     FatalError('Expected external or public ID');
     FatalError('Expected external or public ID');
-  DoNotationDecl(Name, PubID, SysID);
+  if FDTDProcessed then
+    DoNotationDecl(Name, PubID, SysID);
 end;
 end;
 
 
 const
 const
@@ -2520,7 +2531,7 @@ begin
       AttDef.ExternallyDeclared := FSource.DTDSubsetType <> dsInternal;
       AttDef.ExternallyDeclared := FSource.DTDSubsetType <> dsInternal;
 // In case of duplicate declaration of the same attribute, we must discard it,
 // In case of duplicate declaration of the same attribute, we must discard it,
 // not modifying ElDef, and suppressing certain validation errors.
 // not modifying ElDef, and suppressing certain validation errors.
-      DiscardIt := Assigned(ElDef.GetAttributeNode(AttDef.Name));
+      DiscardIt := (not FDTDProcessed) or Assigned(ElDef.GetAttributeNode(AttDef.Name));
       if not DiscardIt then
       if not DiscardIt then
         ElDef.SetAttributeNode(AttDef);
         ElDef.SetAttributeNode(AttDef);
 
 
@@ -2699,7 +2710,7 @@ begin
   end;
   end;
 
 
   // Repeated declarations of same entity are legal but must be ignored
   // Repeated declarations of same entity are legal but must be ignored
-  if Map.GetNamedItem(Entity.FName) = nil then
+  if FDTDProcessed and (Map.GetNamedItem(Entity.FName) = nil) then
     Map.SetNamedItem(Entity)
     Map.SetNamedItem(Entity)
   else
   else
     Entity.Free;
     Entity.Free;