2 // Mono.Xml.DTDObjectModel
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // (C)2003 Atsushi Enomoto
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.Globalization;
36 using System.Xml.Schema;
37 using Mono.Xml.Schema;
40 using XmlTextReaderImpl = Mono.Xml2.XmlTextReader;
42 using XmlTextReaderImpl = System.Xml.XmlTextReader;
47 internal class DTDObjectModel
49 // This specifies the max number of dependent external entities
50 // per a DTD can consume. A malicious external document server
51 // might send users' document processing server a large number
52 // of external entities.
53 public const int AllowedExternalEntitiesMax = 256;
55 DTDAutomataFactory factory;
56 DTDElementAutomata rootAutomata;
57 DTDEmptyAutomata emptyAutomata;
58 DTDAnyAutomata anyAutomata;
59 DTDInvalidAutomata invalidAutomata;
61 DTDElementDeclarationCollection elementDecls;
62 DTDAttListDeclarationCollection attListDecls;
63 DTDParameterEntityDeclarationCollection peDecls;
64 DTDEntityDeclarationCollection entityDecls;
65 DTDNotationDeclarationCollection notationDecls;
66 ArrayList validationErrors;
68 XmlNameTable nameTable;
70 Hashtable externalResources;
77 bool intSubsetHasPERef;
82 public DTDObjectModel (XmlNameTable nameTable)
84 this.nameTable = nameTable;
85 elementDecls = new DTDElementDeclarationCollection (this);
86 attListDecls = new DTDAttListDeclarationCollection (this);
87 entityDecls = new DTDEntityDeclarationCollection (this);
88 peDecls = new DTDParameterEntityDeclarationCollection (this);
89 notationDecls = new DTDNotationDeclarationCollection (this);
90 factory = new DTDAutomataFactory (this);
91 validationErrors = new ArrayList ();
92 externalResources = new Hashtable ();
95 public string BaseURI {
96 get { return baseURI; }
97 set { baseURI = value; }
100 public bool IsStandalone {
101 get { return isStandalone; }
102 set { isStandalone = value; }
107 set { name = value; }
110 public XmlNameTable NameTable {
111 get { return nameTable; }
114 public string PublicId {
115 get { return publicId; }
116 set { publicId = value; }
119 public string SystemId {
120 get { return systemId; }
121 set { systemId = value; }
124 public string InternalSubset {
125 get { return intSubset; }
126 set { intSubset = value; }
129 public bool InternalSubsetHasPEReference {
130 get { return intSubsetHasPERef; }
131 set { intSubsetHasPERef = value; }
134 public int LineNumber {
135 get { return lineNumber; }
136 set { lineNumber = value; }
139 public int LinePosition {
140 get { return linePosition; }
141 set { linePosition = value; }
144 internal XmlSchema CreateXsdSchema ()
146 XmlSchema s = new XmlSchema ();
147 s.SourceUri = BaseURI;
148 s.LineNumber = LineNumber;
149 s.LinePosition = LinePosition;
150 foreach (DTDElementDeclaration el in ElementDecls.Values)
151 s.Items.Add (el.CreateXsdElement ());
155 public string ResolveEntity (string name)
157 DTDEntityDeclaration decl = EntityDecls [name]
158 as DTDEntityDeclaration;
160 AddError (new XmlSchemaException ("Required entity was not found.",
161 this.LineNumber, this.LinePosition, null, this.BaseURI, null));
165 return decl.EntityValue;
168 internal XmlResolver Resolver {
169 get { return resolver; }
172 public XmlResolver XmlResolver {
173 set { resolver = value; }
176 internal Hashtable ExternalResources {
177 get { return externalResources; }
180 public DTDAutomataFactory Factory {
181 get { return factory; }
184 public DTDElementDeclaration RootElement {
185 get { return ElementDecls [Name]; }
188 public DTDElementDeclarationCollection ElementDecls {
189 get { return elementDecls; }
192 public DTDAttListDeclarationCollection AttListDecls {
193 get { return attListDecls; }
196 public DTDEntityDeclarationCollection EntityDecls {
197 get { return entityDecls; }
200 public DTDParameterEntityDeclarationCollection PEDecls {
201 get { return peDecls; }
204 public DTDNotationDeclarationCollection NotationDecls {
205 get { return notationDecls; }
208 public DTDAutomata RootAutomata {
210 if (rootAutomata == null)
211 rootAutomata = new DTDElementAutomata (this, this.Name);
216 public DTDEmptyAutomata Empty {
218 if (emptyAutomata == null)
219 emptyAutomata = new DTDEmptyAutomata (this);
220 return emptyAutomata;
224 public DTDAnyAutomata Any {
226 if (anyAutomata == null)
227 anyAutomata = new DTDAnyAutomata (this);
232 public DTDInvalidAutomata Invalid {
234 if (invalidAutomata == null)
235 invalidAutomata = new DTDInvalidAutomata (this);
236 return invalidAutomata;
240 public XmlSchemaException [] Errors {
241 get { return validationErrors.ToArray (typeof (XmlSchemaException)) as XmlSchemaException []; }
244 public void AddError (XmlSchemaException ex)
246 validationErrors.Add (ex);
250 internal string GenerateEntityAttributeText (string entityName)
252 DTDEntityDeclaration entity = EntityDecls [entityName] as DTDEntityDeclaration;
255 return entity.EntityValue;
258 internal XmlTextReaderImpl GenerateEntityContentReader (string entityName, XmlParserContext context)
260 DTDEntityDeclaration entity = EntityDecls [entityName] as DTDEntityDeclaration;
264 if (entity.SystemId != null) {
265 Uri baseUri = entity.BaseURI == String.Empty ? null : new Uri (entity.BaseURI);
266 Stream stream = resolver.GetEntity (resolver.ResolveUri (baseUri, entity.SystemId), null, typeof (Stream)) as Stream;
267 return new XmlTextReaderImpl (stream, XmlNodeType.Element, context);
270 return new XmlTextReaderImpl (entity.EntityValue, XmlNodeType.Element, context);
275 internal class DTDCollectionBase : DictionaryBase
279 protected DTDCollectionBase (DTDObjectModel root)
284 protected DTDObjectModel Root {
288 public ICollection Keys {
289 get { return InnerHashtable.Keys; }
292 public ICollection Values {
293 get { return InnerHashtable.Values; }
297 internal class DTDElementDeclarationCollection : DTDCollectionBase
300 public DTDElementDeclarationCollection (DTDObjectModel root) : base (root) {}
302 public DTDElementDeclaration this [string name] {
303 get { return Get (name); }
306 public DTDElementDeclaration Get (string name)
308 return InnerHashtable [name] as DTDElementDeclaration;
311 public void Add (string name, DTDElementDeclaration decl)
313 if (InnerHashtable.Contains (name)) {
314 Root.AddError (new XmlSchemaException (String.Format (
315 "Element declaration for {0} was already added.",
320 InnerHashtable.Add (name, decl);
324 internal class DTDAttListDeclarationCollection : DTDCollectionBase
326 public DTDAttListDeclarationCollection (DTDObjectModel root) : base (root) {}
328 public DTDAttListDeclaration this [string name] {
329 get { return InnerHashtable [name] as DTDAttListDeclaration; }
332 public void Add (string name, DTDAttListDeclaration decl)
334 DTDAttListDeclaration existing = this [name];
335 if (existing != null) {
336 // It is valid, that is additive declaration.
337 foreach (DTDAttributeDefinition def in decl.Definitions)
338 if (decl.Get (def.Name) == null)
342 InnerHashtable.Add (name, decl);
347 internal class DTDEntityDeclarationCollection : DTDCollectionBase
349 public DTDEntityDeclarationCollection (DTDObjectModel root) : base (root) {}
351 public DTDEntityDeclaration this [string name] {
352 get { return InnerHashtable [name] as DTDEntityDeclaration; }
355 public void Add (string name, DTDEntityDeclaration decl)
357 if (InnerHashtable [name] != null)
358 throw new InvalidOperationException (String.Format (
359 "Entity declaration for {0} was already added.",
362 InnerHashtable.Add (name, decl);
366 internal class DTDNotationDeclarationCollection : DTDCollectionBase
368 public DTDNotationDeclarationCollection (DTDObjectModel root) : base (root) {}
370 public DTDNotationDeclaration this [string name] {
371 get { return InnerHashtable [name] as DTDNotationDeclaration; }
374 public void Add (string name, DTDNotationDeclaration decl)
376 if (InnerHashtable [name] != null)
377 throw new InvalidOperationException (String.Format (
378 "Notation declaration for {0} was already added.",
381 InnerHashtable.Add (name, decl);
385 // This class contains either ElementName or ChildModels.
386 internal class DTDContentModel : DTDNode
389 DTDAutomata compiledAutomata;
391 string ownerElementName;
393 DTDContentOrderType orderType = DTDContentOrderType.None;
394 DTDContentModelCollection childModels = new DTDContentModelCollection ();
395 DTDOccurence occurence = DTDOccurence.One;
397 internal DTDContentModel (DTDObjectModel root, string ownerElementName)
400 this.ownerElementName = ownerElementName;
403 public DTDContentModelCollection ChildModels {
404 get { return childModels; }
405 set { childModels = value; }
408 public DTDElementDeclaration ElementDecl {
409 get { return root.ElementDecls [ownerElementName]; }
412 public string ElementName {
413 get { return elementName; }
414 set { elementName = value; }
417 public DTDOccurence Occurence {
418 get { return occurence; }
419 set { occurence = value; }
422 public DTDContentOrderType OrderType {
423 get { return orderType; }
424 set { orderType = value; }
427 public DTDAutomata GetAutomata ()
429 if (compiledAutomata == null)
431 return compiledAutomata;
434 public DTDAutomata Compile ()
436 compiledAutomata = CompileInternal ();
437 return compiledAutomata;
440 internal XmlSchemaParticle CreateXsdParticle ()
442 XmlSchemaParticle p = CreateXsdParticleCore ();
447 case DTDOccurence.Optional:
450 case DTDOccurence.OneOrMore:
451 p.MaxOccursString = "unbounded";
453 case DTDOccurence.ZeroOrMore:
455 p.MaxOccursString = "unbounded";
461 XmlSchemaParticle CreateXsdParticleCore ()
463 XmlSchemaParticle p = null;
464 if (ElementName != null) {
465 XmlSchemaElement el = new XmlSchemaElement ();
467 el.RefName = new XmlQualifiedName (ElementName);
470 else if (ChildModels.Count == 0)
473 XmlSchemaGroupBase gb =
474 (OrderType == DTDContentOrderType.Seq) ?
476 new XmlSchemaSequence () :
477 new XmlSchemaChoice ();
479 foreach (DTDContentModel cm in ChildModels.Items) {
480 XmlSchemaParticle c = cm.CreateXsdParticle ();
489 private DTDAutomata CompileInternal ()
491 if (ElementDecl.IsAny)
493 if (ElementDecl.IsEmpty)
496 DTDAutomata basis = GetBasicContentAutomata ();
498 case DTDOccurence.One:
500 case DTDOccurence.Optional:
501 return Choice (root.Empty, basis);
502 case DTDOccurence.OneOrMore:
503 return new DTDOneOrMoreAutomata (root, basis);
504 case DTDOccurence.ZeroOrMore:
505 return Choice (root.Empty, new DTDOneOrMoreAutomata (root, basis));
507 throw new InvalidOperationException ();
510 private DTDAutomata GetBasicContentAutomata ()
512 if (ElementName != null)
513 return new DTDElementAutomata (root, ElementName);
514 switch (ChildModels.Count) {
518 return ChildModels [0].GetAutomata ();
521 DTDAutomata current = null;
522 int childCount = ChildModels.Count;
524 case DTDContentOrderType.Seq:
526 ChildModels [childCount - 2].GetAutomata (),
527 ChildModels [childCount - 1].GetAutomata ());
528 for (int i = childCount - 2; i > 0; i--)
530 ChildModels [i - 1].GetAutomata (), current);
532 case DTDContentOrderType.Or:
534 ChildModels [childCount - 2].GetAutomata (),
535 ChildModels [childCount - 1].GetAutomata ());
536 for (int i = childCount - 2; i > 0; i--)
538 ChildModels [i - 1].GetAutomata (), current);
541 throw new InvalidOperationException ("Invalid pattern specification");
545 private DTDAutomata Sequence (DTDAutomata l, DTDAutomata r)
547 return root.Factory.Sequence (l, r);
550 private DTDAutomata Choice (DTDAutomata l, DTDAutomata r)
552 return l.MakeChoice (r);
556 internal class DTDContentModelCollection
558 ArrayList contentModel = new ArrayList ();
560 public DTDContentModelCollection ()
565 get { return contentModel; }
568 public DTDContentModel this [int i] {
569 get { return contentModel [i] as DTDContentModel; }
573 get { return contentModel.Count; }
576 public void Add (DTDContentModel model)
578 contentModel.Add (model);
582 internal abstract class DTDNode : IXmlLineInfo
585 bool isInternalSubset;
590 public virtual string BaseURI {
591 get { return baseURI; }
592 set { baseURI = value; }
595 public bool IsInternalSubset {
596 get { return isInternalSubset; }
597 set { isInternalSubset = value; }
600 public int LineNumber {
601 get { return lineNumber; }
602 set { lineNumber = value; }
605 public int LinePosition {
606 get { return linePosition; }
607 set { linePosition = value; }
610 public bool HasLineInfo ()
612 return lineNumber != 0;
615 internal void SetRoot (DTDObjectModel root)
619 this.BaseURI = root.BaseURI;
622 protected DTDObjectModel Root {
626 internal XmlException NotWFError (string message)
628 return new XmlException (this as IXmlLineInfo, BaseURI, message);
631 public void SetLineInfo (XmlSchemaObject obj)
633 obj.SourceUri = BaseURI;
634 obj.LineNumber = LineNumber;
635 obj.LinePosition = LinePosition;
639 internal class DTDElementDeclaration : DTDNode
642 DTDContentModel contentModel;
648 internal DTDElementDeclaration (DTDObjectModel root)
655 set { name = value; }
657 public bool IsEmpty {
658 get { return isEmpty; }
659 set { isEmpty = value; }
663 get { return isAny; }
664 set { isAny = value; }
667 public bool IsMixedContent {
668 get { return isMixedContent; }
669 set { isMixedContent = value; }
672 public DTDContentModel ContentModel {
674 if (contentModel == null)
675 contentModel = new DTDContentModel (root, Name);
680 public DTDAttListDeclaration Attributes {
682 return Root.AttListDecls [Name];
686 internal XmlSchemaElement CreateXsdElement ()
688 XmlSchemaElement el = new XmlSchemaElement ();
692 XmlSchemaComplexType ct = new XmlSchemaComplexType ();
694 if (Attributes != null) {
696 foreach (DTDAttributeDefinition a in
697 Attributes.Definitions)
698 ct.Attributes.Add (a.CreateXsdAttribute ());
703 XmlSchemaAny any = new XmlSchemaAny ();
705 any.MaxOccursString = "unbounded";
711 ct.Particle = ContentModel.CreateXsdParticle ();
716 el.SchemaType = new XmlSchemaComplexType ();
717 SetLineInfo (el.SchemaType);
720 el.SchemaTypeName = new XmlQualifiedName (
721 "anyType", XmlSchema.Namespace);
723 XmlSchemaComplexType ct = new XmlSchemaComplexType ();
725 if (Attributes != null)
726 foreach (DTDAttributeDefinition a in
727 Attributes.Definitions)
728 ct.Attributes.Add (a.CreateXsdAttribute ());
731 ct.Particle = ContentModel.CreateXsdParticle ();
739 internal class DTDAttributeDefinition : DTDNode
742 XmlSchemaDatatype datatype;
743 ArrayList enumeratedLiterals;
744 string unresolvedDefault;
745 ArrayList enumeratedNotations;
746 DTDAttributeOccurenceType occurenceType = DTDAttributeOccurenceType.None;
747 string resolvedDefaultValue;
748 string resolvedNormalizedDefaultValue;
750 internal DTDAttributeDefinition (DTDObjectModel root)
760 public XmlSchemaDatatype Datatype {
761 get { return datatype; }
762 set { datatype = value; }
765 public DTDAttributeOccurenceType OccurenceType {
766 get { return this.occurenceType; }
767 set { this.occurenceType = value; }
770 // entity reference inside enumerated values are not allowed,
771 // but on the other hand, they are allowed inside default value.
772 // Then I decided to use string ArrayList for enumerated values,
773 // and unresolved string value for DefaultValue.
774 public ArrayList EnumeratedAttributeDeclaration {
776 if (enumeratedLiterals == null)
777 enumeratedLiterals = new ArrayList ();
778 return this.enumeratedLiterals;
782 public ArrayList EnumeratedNotations {
784 if (enumeratedNotations == null)
785 enumeratedNotations = new ArrayList ();
786 return this.enumeratedNotations;
790 public string DefaultValue {
792 if (resolvedDefaultValue == null)
793 resolvedDefaultValue = ComputeDefaultValue ();
794 return resolvedDefaultValue;
798 public string NormalizedDefaultValue {
800 if (resolvedNormalizedDefaultValue == null) {
801 string s = ComputeDefaultValue ();
803 object o = Datatype.ParseValue (s, null, null);
804 resolvedNormalizedDefaultValue =
806 String.Join (" ", (string []) o) :
807 o is IFormattable ? ((IFormattable) o).ToString (null, CultureInfo.InvariantCulture) : o.ToString ();
808 } catch (Exception) {
809 // This is for non-error-reporting reader
810 resolvedNormalizedDefaultValue = Datatype.Normalize (s);
813 return resolvedNormalizedDefaultValue;
817 public string UnresolvedDefaultValue {
818 get { return this.unresolvedDefault; }
819 set { this.unresolvedDefault = value; }
822 public char QuoteChar {
824 return UnresolvedDefaultValue.Length > 0 ?
825 this.UnresolvedDefaultValue [0] :
830 internal XmlSchemaAttribute CreateXsdAttribute ()
832 XmlSchemaAttribute a = new XmlSchemaAttribute ();
835 a.DefaultValue = resolvedNormalizedDefaultValue;
836 if (OccurenceType != DTDAttributeOccurenceType.Required)
837 a.Use = XmlSchemaUse.Optional;
839 XmlQualifiedName qname = XmlQualifiedName.Empty;
840 ArrayList enumeration = null;
841 if (enumeratedNotations != null && enumeratedNotations.Count > 0) {
842 qname = new XmlQualifiedName ("NOTATION", XmlSchema.Namespace);
843 enumeration = enumeratedNotations;
845 else if (enumeratedLiterals != null)
846 enumeration = enumeratedLiterals;
848 switch (Datatype.TokenizedType) {
849 case XmlTokenizedType.ID:
850 qname = new XmlQualifiedName ("ID", XmlSchema.Namespace); break;
851 case XmlTokenizedType.IDREF:
852 qname = new XmlQualifiedName ("IDREF", XmlSchema.Namespace); break;
853 case XmlTokenizedType.IDREFS:
854 qname = new XmlQualifiedName ("IDREFS", XmlSchema.Namespace); break;
855 case XmlTokenizedType.ENTITY:
856 qname = new XmlQualifiedName ("ENTITY", XmlSchema.Namespace); break;
857 case XmlTokenizedType.ENTITIES:
858 qname = new XmlQualifiedName ("ENTITIES", XmlSchema.Namespace); break;
859 case XmlTokenizedType.NMTOKEN:
860 qname = new XmlQualifiedName ("NMTOKEN", XmlSchema.Namespace); break;
861 case XmlTokenizedType.NMTOKENS:
862 qname = new XmlQualifiedName ("NMTOKENS", XmlSchema.Namespace); break;
863 case XmlTokenizedType.NOTATION:
864 qname = new XmlQualifiedName ("NOTATION", XmlSchema.Namespace); break;
868 if (enumeration != null) {
869 XmlSchemaSimpleType st = new XmlSchemaSimpleType ();
871 XmlSchemaSimpleTypeRestriction r =
872 new XmlSchemaSimpleTypeRestriction ();
874 r.BaseTypeName = qname;
875 if (enumeratedNotations != null) {
876 foreach (string name in enumeratedNotations) {
877 XmlSchemaEnumerationFacet f =
878 new XmlSchemaEnumerationFacet ();
886 else if (qname != XmlQualifiedName.Empty)
887 a.SchemaTypeName = qname;
891 internal string ComputeDefaultValue ()
893 if (UnresolvedDefaultValue == null)
896 StringBuilder sb = new StringBuilder ();
899 string value = this.UnresolvedDefaultValue;
900 while ((next = value.IndexOf ('&', pos)) >= 0) {
901 int semicolon = value.IndexOf (';', next);
902 if (value [next + 1] == '#') {
903 // character reference.
904 char c = value [next + 2];
905 NumberStyles style = NumberStyles.Integer;
907 if (c == 'x' || c == 'X') {
908 spec = value.Substring (next + 3, semicolon - next - 3);
909 style |= NumberStyles.HexNumber;
912 spec = value.Substring (next + 2, semicolon - next - 2);
913 sb.Append ((char) int.Parse (spec, style, CultureInfo.InvariantCulture));
915 sb.Append (value.Substring (pos, next - 1));
916 string name = value.Substring (next + 1, semicolon - 2);
917 int predefined = XmlChar.GetPredefinedEntity (name);
919 sb.Append (predefined);
921 sb.Append (Root.ResolveEntity (name));
925 sb.Append (value.Substring (pos));
927 string ret = sb.ToString (1, sb.Length - 2);
934 internal class DTDAttListDeclaration : DTDNode
937 Hashtable attributeOrders = new Hashtable ();
938 ArrayList attributes = new ArrayList ();
940 internal DTDAttListDeclaration (DTDObjectModel root)
947 set { name = value; }
950 public DTDAttributeDefinition this [int i] {
951 get { return Get (i); }
954 public DTDAttributeDefinition this [string name] {
955 get { return Get (name); }
958 public DTDAttributeDefinition Get (int i)
960 return attributes [i] as DTDAttributeDefinition;
963 public DTDAttributeDefinition Get (string name)
965 object o = attributeOrders [name];
967 return attributes [(int) o] as DTDAttributeDefinition;
972 public IList Definitions {
973 get { return attributes; }
976 public void Add (DTDAttributeDefinition def)
978 if (attributeOrders [def.Name] != null)
979 throw new InvalidOperationException (String.Format (
980 "Attribute definition for {0} was already added at element {1}.",
981 def.Name, this.Name));
983 attributeOrders.Add (def.Name, attributes.Count);
984 attributes.Add (def);
988 get { return attributeOrders.Count; }
992 internal class DTDEntityBase : DTDNode
998 string replacementText;
1002 // Exception loadException;
1004 XmlResolver resolver;
1006 protected DTDEntityBase (DTDObjectModel root)
1011 internal bool IsInvalid {
1012 get { return isInvalid; }
1013 set { isInvalid = value; }
1016 public bool LoadFailed {
1017 get { return loadFailed; }
1018 set { loadFailed = value; }
1021 public string Name {
1022 get { return name; }
1023 set { name = value; }
1026 public string PublicId {
1027 get { return publicId; }
1028 set { publicId = value; }
1031 public string SystemId {
1032 get { return systemId; }
1033 set { systemId = value; }
1036 public string LiteralEntityValue {
1037 get { return literalValue; }
1038 set { literalValue = value; }
1041 public string ReplacementText {
1042 get { return replacementText; }
1043 set { replacementText = value; }
1046 public XmlResolver XmlResolver {
1047 set { resolver = value; }
1050 public string ActualUri {
1052 if (uriString == null) {
1053 if (resolver == null || SystemId == null || SystemId.Length == 0)
1054 uriString = BaseURI;
1058 if (BaseURI != null && BaseURI.Length > 0)
1059 baseUri = new Uri (BaseURI);
1060 } catch (UriFormatException) {
1063 absUri = resolver.ResolveUri (baseUri, SystemId);
1064 uriString = absUri != null ? absUri.ToString () : String.Empty;
1071 public void Resolve ()
1073 if (ActualUri == String.Empty) {
1075 LiteralEntityValue = String.Empty;
1079 if (Root.ExternalResources.ContainsKey (ActualUri))
1080 LiteralEntityValue = (string) Root.ExternalResources [ActualUri];
1083 s = resolver.GetEntity (absUri, null, typeof (Stream)) as Stream;
1084 XmlTextReaderImpl xtr = new XmlTextReaderImpl (ActualUri, s, Root.NameTable);
1085 // Don't skip Text declaration here. LiteralEntityValue contains it. See spec 4.5
1086 LiteralEntityValue = xtr.GetRemainder ().ReadToEnd ();
1088 Root.ExternalResources.Add (ActualUri, LiteralEntityValue);
1089 if (Root.ExternalResources.Count > DTDObjectModel.AllowedExternalEntitiesMax)
1090 throw new InvalidOperationException ("The total amount of external entities exceeded the allowed number.");
1092 } catch (Exception ex) {
1093 // loadException = ex;
1094 LiteralEntityValue = String.Empty;
1096 // throw NotWFError ("Cannot resolve external entity. URI is " + ActualUri + " .");
1104 internal class DTDEntityDeclaration : DTDEntityBase
1107 string notationName;
1109 ArrayList ReferencingEntities = new ArrayList ();
1113 bool hasExternalReference;
1115 internal DTDEntityDeclaration (DTDObjectModel root) : base (root)
1119 public string NotationName {
1120 get { return notationName; }
1121 set { notationName = value; }
1124 public bool HasExternalReference {
1127 ScanEntityValue (new ArrayList ());
1128 return hasExternalReference;
1132 public string EntityValue {
1135 return String.Empty;
1137 if (PublicId == null && SystemId == null && LiteralEntityValue == null)
1138 return String.Empty;
1140 if (entityValue == null) {
1141 if (NotationName != null)
1143 else if (SystemId == null || SystemId == String.Empty) {
1144 entityValue = ReplacementText;
1145 if (entityValue == null)
1146 entityValue = String.Empty;
1148 entityValue = ReplacementText;
1150 // Check illegal recursion.
1151 ScanEntityValue (new ArrayList ());
1157 // It returns whether the entity contains references to external entities.
1158 public void ScanEntityValue (ArrayList refs)
1160 // To modify this code, beware nesting between this and EntityValue.
1161 string value = EntityValue;
1162 if (this.SystemId != null)
1163 hasExternalReference = true;
1166 throw NotWFError ("Entity recursion was found.");
1170 foreach (string referenced in refs)
1171 if (this.ReferencingEntities.Contains (referenced))
1172 throw NotWFError (String.Format (
1173 "Nested entity was found between {0} and {1}",
1179 int len = value.Length;
1181 for (int i=0; i<len; i++) {
1182 switch (value [i]) {
1189 string name = value.Substring (start, i - start);
1190 if (name.Length == 0)
1191 throw NotWFError ("Entity reference name is missing.");
1192 if (name [0] == '#')
1193 break; // character reference
1194 if (XmlChar.GetPredefinedEntity (name) >= 0)
1195 break; // predefined reference
1197 this.ReferencingEntities.Add (name);
1198 DTDEntityDeclaration decl = Root.EntityDecls [name];
1200 if (decl.SystemId != null)
1201 hasExternalReference = true;
1203 decl.ScanEntityValue (refs);
1204 foreach (string str in decl.ReferencingEntities)
1205 ReferencingEntities.Add (str);
1207 value = value.Remove (start - 1, name.Length + 2);
1208 value = value.Insert (start - 1, decl.EntityValue);
1209 i -= name.Length + 1; // not +2, because of immediate i++ .
1217 Root.AddError (new XmlSchemaException ("Invalid reference character '&' is specified.",
1218 this.LineNumber, this.LinePosition, null, this.BaseURI, null));
1224 internal class DTDNotationDeclaration : DTDNode
1232 public string Name {
1233 get { return name; }
1234 set { name = value; }
1237 public string PublicId {
1238 get { return publicId; }
1239 set { publicId = value; }
1242 public string SystemId {
1243 get { return systemId; }
1244 set { systemId = value; }
1247 public string LocalName {
1248 get { return localName; }
1249 set { localName = value; }
1252 public string Prefix {
1253 get { return prefix; }
1254 set { prefix = value; }
1257 internal DTDNotationDeclaration (DTDObjectModel root)
1263 internal class DTDParameterEntityDeclarationCollection
1265 Hashtable peDecls = new Hashtable ();
1266 DTDObjectModel root;
1268 public DTDParameterEntityDeclarationCollection (DTDObjectModel root)
1273 public DTDParameterEntityDeclaration this [string name] {
1274 get { return peDecls [name] as DTDParameterEntityDeclaration; }
1277 public void Add (string name, DTDParameterEntityDeclaration decl)
1279 // PEDecl can be overriden.
1280 if (peDecls [name] != null)
1282 decl.SetRoot (root);
1283 peDecls.Add (name, decl);
1286 public ICollection Keys {
1287 get { return peDecls.Keys; }
1290 public ICollection Values {
1291 get { return peDecls.Values; }
1295 internal class DTDParameterEntityDeclaration : DTDEntityBase
1297 internal DTDParameterEntityDeclaration (DTDObjectModel root) : base (root)
1302 internal enum DTDContentOrderType
1309 internal enum DTDAttributeOccurenceType
1317 internal enum DTDOccurence