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;
38 using System.Collections.Generic;
41 using XmlSchemaException = System.Xml.XmlException;
43 using Mono.Xml.Schema;
47 using XmlTextReaderImpl = Mono.Xml2.XmlTextReader;
49 using XmlTextReaderImpl = System.Xml.XmlTextReader;
54 internal class DTDObjectModel
56 // This specifies the max number of dependent external entities
57 // per a DTD can consume. A malicious external document server
58 // might send users' document processing server a large number
59 // of external entities.
60 public const int AllowedExternalEntitiesMax = 256;
62 DTDAutomataFactory factory;
63 DTDElementAutomata rootAutomata;
64 DTDEmptyAutomata emptyAutomata;
65 DTDAnyAutomata anyAutomata;
66 DTDInvalidAutomata invalidAutomata;
68 DTDElementDeclarationCollection elementDecls;
69 DTDAttListDeclarationCollection attListDecls;
70 DTDParameterEntityDeclarationCollection peDecls;
71 DTDEntityDeclarationCollection entityDecls;
72 DTDNotationDeclarationCollection notationDecls;
73 ArrayList validationErrors;
75 XmlNameTable nameTable;
77 Hashtable externalResources;
84 bool intSubsetHasPERef;
89 public DTDObjectModel (XmlNameTable nameTable)
91 this.nameTable = nameTable;
92 elementDecls = new DTDElementDeclarationCollection (this);
93 attListDecls = new DTDAttListDeclarationCollection (this);
94 entityDecls = new DTDEntityDeclarationCollection (this);
95 peDecls = new DTDParameterEntityDeclarationCollection (this);
96 notationDecls = new DTDNotationDeclarationCollection (this);
97 factory = new DTDAutomataFactory (this);
98 validationErrors = new ArrayList ();
99 externalResources = new Hashtable ();
102 public string BaseURI {
103 get { return baseURI; }
104 set { baseURI = value; }
107 public bool IsStandalone {
108 get { return isStandalone; }
109 set { isStandalone = value; }
114 set { name = value; }
117 public XmlNameTable NameTable {
118 get { return nameTable; }
121 public string PublicId {
122 get { return publicId; }
123 set { publicId = value; }
126 public string SystemId {
127 get { return systemId; }
128 set { systemId = value; }
131 public string InternalSubset {
132 get { return intSubset; }
133 set { intSubset = value; }
136 public bool InternalSubsetHasPEReference {
137 get { return intSubsetHasPERef; }
138 set { intSubsetHasPERef = value; }
141 public int LineNumber {
142 get { return lineNumber; }
143 set { lineNumber = value; }
146 public int LinePosition {
147 get { return linePosition; }
148 set { linePosition = value; }
152 internal XmlSchema CreateXsdSchema ()
154 XmlSchema s = new XmlSchema ();
155 s.SourceUri = BaseURI;
156 s.LineNumber = LineNumber;
157 s.LinePosition = LinePosition;
158 foreach (DTDElementDeclaration el in ElementDecls.Values)
159 s.Items.Add (el.CreateXsdElement ());
164 public string ResolveEntity (string name)
166 DTDEntityDeclaration decl = EntityDecls [name]
167 as DTDEntityDeclaration;
170 AddError (new XmlSchemaException (String.Format ("Required entity was not found: {0}", name), null, this.LineNumber, this.LinePosition));
172 AddError (new XmlSchemaException ("Required entity was not found.",
173 this.LineNumber, this.LinePosition, null, this.BaseURI, null));
178 return decl.EntityValue;
181 internal XmlResolver Resolver {
182 get { return resolver; }
185 public XmlResolver XmlResolver {
186 set { resolver = value; }
189 internal Hashtable ExternalResources {
190 get { return externalResources; }
193 public DTDAutomataFactory Factory {
194 get { return factory; }
197 public DTDElementDeclaration RootElement {
198 get { return ElementDecls [Name]; }
201 public DTDElementDeclarationCollection ElementDecls {
202 get { return elementDecls; }
205 public DTDAttListDeclarationCollection AttListDecls {
206 get { return attListDecls; }
209 public DTDEntityDeclarationCollection EntityDecls {
210 get { return entityDecls; }
213 public DTDParameterEntityDeclarationCollection PEDecls {
214 get { return peDecls; }
217 public DTDNotationDeclarationCollection NotationDecls {
218 get { return notationDecls; }
221 public DTDAutomata RootAutomata {
223 if (rootAutomata == null)
224 rootAutomata = new DTDElementAutomata (this, this.Name);
229 public DTDEmptyAutomata Empty {
231 if (emptyAutomata == null)
232 emptyAutomata = new DTDEmptyAutomata (this);
233 return emptyAutomata;
237 public DTDAnyAutomata Any {
239 if (anyAutomata == null)
240 anyAutomata = new DTDAnyAutomata (this);
245 public DTDInvalidAutomata Invalid {
247 if (invalidAutomata == null)
248 invalidAutomata = new DTDInvalidAutomata (this);
249 return invalidAutomata;
253 public XmlSchemaException [] Errors {
254 get { return validationErrors.ToArray (typeof (XmlSchemaException)) as XmlSchemaException []; }
257 public void AddError (XmlSchemaException ex)
259 validationErrors.Add (ex);
262 internal string GenerateEntityAttributeText (string entityName)
264 DTDEntityDeclaration entity = EntityDecls [entityName] as DTDEntityDeclaration;
267 return entity.EntityValue;
270 internal XmlTextReaderImpl GenerateEntityContentReader (string entityName, XmlParserContext context)
272 DTDEntityDeclaration entity = EntityDecls [entityName] as DTDEntityDeclaration;
276 if (entity.SystemId != null) {
277 Uri baseUri = entity.BaseURI == String.Empty ? null : new Uri (entity.BaseURI);
278 Stream stream = resolver.GetEntity (resolver.ResolveUri (baseUri, entity.SystemId), null, typeof (Stream)) as Stream;
279 return new XmlTextReaderImpl (stream, XmlNodeType.Element, context);
282 return new XmlTextReaderImpl (entity.EntityValue, XmlNodeType.Element, context);
287 class DictionaryBase : List<KeyValuePair<string,DTDNode>>
289 public IEnumerable<DTDNode> Values {
291 foreach (KeyValuePair<string,DTDNode> p in this)
292 yield return p.Value;
297 internal class DTDCollectionBase : DictionaryBase
301 protected DTDCollectionBase (DTDObjectModel root)
306 protected DTDObjectModel Root {
311 public DictionaryBase InnerHashtable {
315 protected void BaseAdd (string name, DTDNode value)
317 base.Add (new KeyValuePair<string,DTDNode> (name, value));
320 public bool Contains (string key)
322 foreach (KeyValuePair<string,DTDNode> p in this)
328 protected object BaseGet (string name)
330 foreach (KeyValuePair<string,DTDNode> p in this)
336 public ICollection Keys {
337 get { return InnerHashtable.Keys; }
340 public ICollection Values {
341 get { return InnerHashtable.Values; }
344 protected void BaseAdd (string name, object value)
346 InnerHashtable.Add (name, value);
349 public bool Contains (string key)
351 return InnerHashtable.Contains (key);
354 protected object BaseGet (string name)
356 return InnerHashtable [name];
361 internal class DTDElementDeclarationCollection : DTDCollectionBase
364 public DTDElementDeclarationCollection (DTDObjectModel root) : base (root) {}
366 public DTDElementDeclaration this [string name] {
367 get { return Get (name); }
370 public DTDElementDeclaration Get (string name)
372 return BaseGet (name) as DTDElementDeclaration;
375 public void Add (string name, DTDElementDeclaration decl)
377 if (Contains (name)) {
378 Root.AddError (new XmlSchemaException (String.Format (
379 "Element declaration for {0} was already added.",
384 BaseAdd (name, decl);
388 internal class DTDAttListDeclarationCollection : DTDCollectionBase
390 public DTDAttListDeclarationCollection (DTDObjectModel root) : base (root) {}
392 public DTDAttListDeclaration this [string name] {
393 get { return BaseGet (name) as DTDAttListDeclaration; }
396 public void Add (string name, DTDAttListDeclaration decl)
398 DTDAttListDeclaration existing = this [name];
399 if (existing != null) {
400 // It is valid, that is additive declaration.
401 foreach (DTDAttributeDefinition def in decl.Definitions)
402 if (decl.Get (def.Name) == null)
406 BaseAdd (name, decl);
411 internal class DTDEntityDeclarationCollection : DTDCollectionBase
413 public DTDEntityDeclarationCollection (DTDObjectModel root) : base (root) {}
415 public DTDEntityDeclaration this [string name] {
416 get { return BaseGet (name) as DTDEntityDeclaration; }
419 public void Add (string name, DTDEntityDeclaration decl)
422 throw new InvalidOperationException (String.Format (
423 "Entity declaration for {0} was already added.",
426 BaseAdd (name, decl);
430 internal class DTDNotationDeclarationCollection : DTDCollectionBase
432 public DTDNotationDeclarationCollection (DTDObjectModel root) : base (root) {}
434 public DTDNotationDeclaration this [string name] {
435 get { return BaseGet (name) as DTDNotationDeclaration; }
438 public void Add (string name, DTDNotationDeclaration decl)
441 throw new InvalidOperationException (String.Format (
442 "Notation declaration for {0} was already added.",
445 BaseAdd (name, decl);
449 // This class contains either ElementName or ChildModels.
450 internal class DTDContentModel : DTDNode
453 DTDAutomata compiledAutomata;
455 string ownerElementName;
457 DTDContentOrderType orderType = DTDContentOrderType.None;
458 DTDContentModelCollection childModels = new DTDContentModelCollection ();
459 DTDOccurence occurence = DTDOccurence.One;
461 internal DTDContentModel (DTDObjectModel root, string ownerElementName)
464 this.ownerElementName = ownerElementName;
467 public DTDContentModelCollection ChildModels {
468 get { return childModels; }
469 set { childModels = value; }
472 public DTDElementDeclaration ElementDecl {
473 get { return root.ElementDecls [ownerElementName]; }
476 public string ElementName {
477 get { return elementName; }
478 set { elementName = value; }
481 public DTDOccurence Occurence {
482 get { return occurence; }
483 set { occurence = value; }
486 public DTDContentOrderType OrderType {
487 get { return orderType; }
488 set { orderType = value; }
491 public DTDAutomata GetAutomata ()
493 if (compiledAutomata == null)
495 return compiledAutomata;
498 public DTDAutomata Compile ()
500 compiledAutomata = CompileInternal ();
501 return compiledAutomata;
505 internal XmlSchemaParticle CreateXsdParticle ()
507 XmlSchemaParticle p = CreateXsdParticleCore ();
512 case DTDOccurence.Optional:
515 case DTDOccurence.OneOrMore:
516 p.MaxOccursString = "unbounded";
518 case DTDOccurence.ZeroOrMore:
520 p.MaxOccursString = "unbounded";
526 XmlSchemaParticle CreateXsdParticleCore ()
528 XmlSchemaParticle p = null;
529 if (ElementName != null) {
530 XmlSchemaElement el = new XmlSchemaElement ();
532 el.RefName = new XmlQualifiedName (ElementName);
535 else if (ChildModels.Count == 0)
538 XmlSchemaGroupBase gb =
539 (OrderType == DTDContentOrderType.Seq) ?
541 new XmlSchemaSequence () :
542 new XmlSchemaChoice ();
544 foreach (DTDContentModel cm in ChildModels.Items) {
545 XmlSchemaParticle c = cm.CreateXsdParticle ();
555 private DTDAutomata CompileInternal ()
557 if (ElementDecl.IsAny)
559 if (ElementDecl.IsEmpty)
562 DTDAutomata basis = GetBasicContentAutomata ();
564 case DTDOccurence.One:
566 case DTDOccurence.Optional:
567 return Choice (root.Empty, basis);
568 case DTDOccurence.OneOrMore:
569 return new DTDOneOrMoreAutomata (root, basis);
570 case DTDOccurence.ZeroOrMore:
571 return Choice (root.Empty, new DTDOneOrMoreAutomata (root, basis));
573 throw new InvalidOperationException ();
576 private DTDAutomata GetBasicContentAutomata ()
578 if (ElementName != null)
579 return new DTDElementAutomata (root, ElementName);
580 switch (ChildModels.Count) {
584 return ChildModels [0].GetAutomata ();
587 DTDAutomata current = null;
588 int childCount = ChildModels.Count;
590 case DTDContentOrderType.Seq:
592 ChildModels [childCount - 2].GetAutomata (),
593 ChildModels [childCount - 1].GetAutomata ());
594 for (int i = childCount - 2; i > 0; i--)
596 ChildModels [i - 1].GetAutomata (), current);
598 case DTDContentOrderType.Or:
600 ChildModels [childCount - 2].GetAutomata (),
601 ChildModels [childCount - 1].GetAutomata ());
602 for (int i = childCount - 2; i > 0; i--)
604 ChildModels [i - 1].GetAutomata (), current);
607 throw new InvalidOperationException ("Invalid pattern specification");
611 private DTDAutomata Sequence (DTDAutomata l, DTDAutomata r)
613 return root.Factory.Sequence (l, r);
616 private DTDAutomata Choice (DTDAutomata l, DTDAutomata r)
618 return l.MakeChoice (r);
622 internal class DTDContentModelCollection
624 ArrayList contentModel = new ArrayList ();
626 public DTDContentModelCollection ()
631 get { return contentModel; }
634 public DTDContentModel this [int i] {
635 get { return contentModel [i] as DTDContentModel; }
639 get { return contentModel.Count; }
642 public void Add (DTDContentModel model)
644 contentModel.Add (model);
648 internal abstract class DTDNode : IXmlLineInfo
651 bool isInternalSubset;
656 public virtual string BaseURI {
657 get { return baseURI; }
658 set { baseURI = value; }
661 public bool IsInternalSubset {
662 get { return isInternalSubset; }
663 set { isInternalSubset = value; }
666 public int LineNumber {
667 get { return lineNumber; }
668 set { lineNumber = value; }
671 public int LinePosition {
672 get { return linePosition; }
673 set { linePosition = value; }
676 public bool HasLineInfo ()
678 return lineNumber != 0;
681 internal void SetRoot (DTDObjectModel root)
685 this.BaseURI = root.BaseURI;
688 protected DTDObjectModel Root {
692 internal XmlException NotWFError (string message)
694 return new XmlException (this as IXmlLineInfo, BaseURI, message);
698 public void SetLineInfo (XmlSchemaObject obj)
700 obj.SourceUri = BaseURI;
701 obj.LineNumber = LineNumber;
702 obj.LinePosition = LinePosition;
707 internal class DTDElementDeclaration : DTDNode
710 DTDContentModel contentModel;
716 internal DTDElementDeclaration (DTDObjectModel root)
723 set { name = value; }
725 public bool IsEmpty {
726 get { return isEmpty; }
727 set { isEmpty = value; }
731 get { return isAny; }
732 set { isAny = value; }
735 public bool IsMixedContent {
736 get { return isMixedContent; }
737 set { isMixedContent = value; }
740 public DTDContentModel ContentModel {
742 if (contentModel == null)
743 contentModel = new DTDContentModel (root, Name);
748 public DTDAttListDeclaration Attributes {
750 return Root.AttListDecls [Name];
755 internal XmlSchemaElement CreateXsdElement ()
757 XmlSchemaElement el = new XmlSchemaElement ();
761 XmlSchemaComplexType ct = new XmlSchemaComplexType ();
763 if (Attributes != null) {
765 foreach (DTDAttributeDefinition a in
766 Attributes.Definitions)
767 ct.Attributes.Add (a.CreateXsdAttribute ());
772 XmlSchemaAny any = new XmlSchemaAny ();
774 any.MaxOccursString = "unbounded";
780 ct.Particle = ContentModel.CreateXsdParticle ();
785 el.SchemaType = new XmlSchemaComplexType ();
786 SetLineInfo (el.SchemaType);
789 el.SchemaTypeName = new XmlQualifiedName (
790 "anyType", XmlSchema.Namespace);
792 XmlSchemaComplexType ct = new XmlSchemaComplexType ();
794 if (Attributes != null)
795 foreach (DTDAttributeDefinition a in
796 Attributes.Definitions)
797 ct.Attributes.Add (a.CreateXsdAttribute ());
800 ct.Particle = ContentModel.CreateXsdParticle ();
809 internal class DTDAttributeDefinition : DTDNode
812 XmlSchemaDatatype datatype;
813 ArrayList enumeratedLiterals;
814 string unresolvedDefault;
815 ArrayList enumeratedNotations;
816 DTDAttributeOccurenceType occurenceType = DTDAttributeOccurenceType.None;
817 string resolvedDefaultValue;
818 string resolvedNormalizedDefaultValue;
820 internal DTDAttributeDefinition (DTDObjectModel root)
830 public XmlSchemaDatatype Datatype {
831 get { return datatype; }
832 set { datatype = value; }
835 public DTDAttributeOccurenceType OccurenceType {
836 get { return this.occurenceType; }
837 set { this.occurenceType = value; }
840 // entity reference inside enumerated values are not allowed,
841 // but on the other hand, they are allowed inside default value.
842 // Then I decided to use string ArrayList for enumerated values,
843 // and unresolved string value for DefaultValue.
844 public ArrayList EnumeratedAttributeDeclaration {
846 if (enumeratedLiterals == null)
847 enumeratedLiterals = new ArrayList ();
848 return this.enumeratedLiterals;
852 public ArrayList EnumeratedNotations {
854 if (enumeratedNotations == null)
855 enumeratedNotations = new ArrayList ();
856 return this.enumeratedNotations;
860 public string DefaultValue {
862 if (resolvedDefaultValue == null)
863 resolvedDefaultValue = ComputeDefaultValue ();
864 return resolvedDefaultValue;
868 public string NormalizedDefaultValue {
870 if (resolvedNormalizedDefaultValue == null) {
871 string s = ComputeDefaultValue ();
873 object o = Datatype.ParseValue (s, null, null);
874 resolvedNormalizedDefaultValue =
876 String.Join (" ", (string []) o) :
877 o is IFormattable ? ((IFormattable) o).ToString (null, CultureInfo.InvariantCulture) : o.ToString ();
878 } catch (Exception) {
879 // This is for non-error-reporting reader
880 resolvedNormalizedDefaultValue = Datatype.Normalize (s);
883 return resolvedNormalizedDefaultValue;
887 public string UnresolvedDefaultValue {
888 get { return this.unresolvedDefault; }
889 set { this.unresolvedDefault = value; }
892 public char QuoteChar {
894 return UnresolvedDefaultValue.Length > 0 ?
895 this.UnresolvedDefaultValue [0] :
901 internal XmlSchemaAttribute CreateXsdAttribute ()
903 XmlSchemaAttribute a = new XmlSchemaAttribute ();
906 a.DefaultValue = resolvedNormalizedDefaultValue;
907 if (OccurenceType != DTDAttributeOccurenceType.Required)
908 a.Use = XmlSchemaUse.Optional;
910 XmlQualifiedName qname = XmlQualifiedName.Empty;
911 ArrayList enumeration = null;
912 if (enumeratedNotations != null && enumeratedNotations.Count > 0) {
913 qname = new XmlQualifiedName ("NOTATION", XmlSchema.Namespace);
914 enumeration = enumeratedNotations;
916 else if (enumeratedLiterals != null)
917 enumeration = enumeratedLiterals;
919 switch (Datatype.TokenizedType) {
920 case XmlTokenizedType.ID:
921 qname = new XmlQualifiedName ("ID", XmlSchema.Namespace); break;
922 case XmlTokenizedType.IDREF:
923 qname = new XmlQualifiedName ("IDREF", XmlSchema.Namespace); break;
924 case XmlTokenizedType.IDREFS:
925 qname = new XmlQualifiedName ("IDREFS", XmlSchema.Namespace); break;
926 case XmlTokenizedType.ENTITY:
927 qname = new XmlQualifiedName ("ENTITY", XmlSchema.Namespace); break;
928 case XmlTokenizedType.ENTITIES:
929 qname = new XmlQualifiedName ("ENTITIES", XmlSchema.Namespace); break;
930 case XmlTokenizedType.NMTOKEN:
931 qname = new XmlQualifiedName ("NMTOKEN", XmlSchema.Namespace); break;
932 case XmlTokenizedType.NMTOKENS:
933 qname = new XmlQualifiedName ("NMTOKENS", XmlSchema.Namespace); break;
934 case XmlTokenizedType.NOTATION:
935 qname = new XmlQualifiedName ("NOTATION", XmlSchema.Namespace); break;
939 if (enumeration != null) {
940 XmlSchemaSimpleType st = new XmlSchemaSimpleType ();
942 XmlSchemaSimpleTypeRestriction r =
943 new XmlSchemaSimpleTypeRestriction ();
945 r.BaseTypeName = qname;
946 if (enumeratedNotations != null) {
947 foreach (string name in enumeratedNotations) {
948 XmlSchemaEnumerationFacet f =
949 new XmlSchemaEnumerationFacet ();
957 else if (qname != XmlQualifiedName.Empty)
958 a.SchemaTypeName = qname;
963 internal string ComputeDefaultValue ()
965 if (UnresolvedDefaultValue == null)
968 StringBuilder sb = new StringBuilder ();
971 string value = this.UnresolvedDefaultValue;
972 while ((next = value.IndexOf ('&', pos)) >= 0) {
973 int semicolon = value.IndexOf (';', next);
974 if (value [next + 1] == '#') {
975 // character reference.
976 char c = value [next + 2];
977 NumberStyles style = NumberStyles.Integer;
979 if (c == 'x' || c == 'X') {
980 spec = value.Substring (next + 3, semicolon - next - 3);
981 style |= NumberStyles.HexNumber;
984 spec = value.Substring (next + 2, semicolon - next - 2);
985 sb.Append ((char) int.Parse (spec, style, CultureInfo.InvariantCulture));
987 sb.Append (value.Substring (pos, next - 1));
988 string name = value.Substring (next + 1, semicolon - 2);
989 int predefined = XmlChar.GetPredefinedEntity (name);
991 sb.Append (predefined);
993 sb.Append (Root.ResolveEntity (name));
997 sb.Append (value.Substring (pos));
999 string ret = sb.ToString (1, sb.Length - 2);
1006 internal class DTDAttListDeclaration : DTDNode
1009 Hashtable attributeOrders = new Hashtable ();
1010 ArrayList attributes = new ArrayList ();
1012 internal DTDAttListDeclaration (DTDObjectModel root)
1017 public string Name {
1018 get { return name; }
1019 set { name = value; }
1022 public DTDAttributeDefinition this [int i] {
1023 get { return Get (i); }
1026 public DTDAttributeDefinition this [string name] {
1027 get { return Get (name); }
1030 public DTDAttributeDefinition Get (int i)
1032 return attributes [i] as DTDAttributeDefinition;
1035 public DTDAttributeDefinition Get (string name)
1037 object o = attributeOrders [name];
1039 return attributes [(int) o] as DTDAttributeDefinition;
1044 public IList Definitions {
1045 get { return attributes; }
1048 public void Add (DTDAttributeDefinition def)
1050 if (attributeOrders [def.Name] != null)
1051 throw new InvalidOperationException (String.Format (
1052 "Attribute definition for {0} was already added at element {1}.",
1053 def.Name, this.Name));
1055 attributeOrders.Add (def.Name, attributes.Count);
1056 attributes.Add (def);
1060 get { return attributeOrders.Count; }
1064 internal class DTDEntityBase : DTDNode
1069 string literalValue;
1070 string replacementText;
1074 // Exception loadException;
1076 XmlResolver resolver;
1078 protected DTDEntityBase (DTDObjectModel root)
1083 internal bool IsInvalid {
1084 get { return isInvalid; }
1085 set { isInvalid = value; }
1088 public bool LoadFailed {
1089 get { return loadFailed; }
1090 set { loadFailed = value; }
1093 public string Name {
1094 get { return name; }
1095 set { name = value; }
1098 public string PublicId {
1099 get { return publicId; }
1100 set { publicId = value; }
1103 public string SystemId {
1104 get { return systemId; }
1105 set { systemId = value; }
1108 public string LiteralEntityValue {
1109 get { return literalValue; }
1110 set { literalValue = value; }
1113 public string ReplacementText {
1114 get { return replacementText; }
1115 set { replacementText = value; }
1118 public XmlResolver XmlResolver {
1119 set { resolver = value; }
1122 public string ActualUri {
1124 if (uriString == null) {
1125 if (resolver == null || SystemId == null || SystemId.Length == 0)
1126 uriString = BaseURI;
1130 if (BaseURI != null && BaseURI.Length > 0)
1131 baseUri = new Uri (BaseURI);
1132 } catch (UriFormatException) {
1135 absUri = resolver.ResolveUri (baseUri, SystemId);
1136 uriString = absUri != null ? absUri.ToString () : String.Empty;
1143 public void Resolve ()
1145 if (ActualUri == String.Empty) {
1147 LiteralEntityValue = String.Empty;
1151 if (Root.ExternalResources.ContainsKey (ActualUri))
1152 LiteralEntityValue = (string) Root.ExternalResources [ActualUri];
1155 s = resolver.GetEntity (absUri, null, typeof (Stream)) as Stream;
1156 XmlTextReaderImpl xtr = new XmlTextReaderImpl (ActualUri, s, Root.NameTable);
1157 // Don't skip Text declaration here. LiteralEntityValue contains it. See spec 4.5
1158 LiteralEntityValue = xtr.GetRemainder ().ReadToEnd ();
1160 Root.ExternalResources.Add (ActualUri, LiteralEntityValue);
1161 if (Root.ExternalResources.Count > DTDObjectModel.AllowedExternalEntitiesMax)
1162 throw new InvalidOperationException ("The total amount of external entities exceeded the allowed number.");
1164 } catch (Exception ex) {
1165 // loadException = ex;
1166 LiteralEntityValue = String.Empty;
1168 // throw NotWFError ("Cannot resolve external entity. URI is " + ActualUri + " .");
1176 internal class DTDEntityDeclaration : DTDEntityBase
1179 string notationName;
1181 ArrayList ReferencingEntities = new ArrayList ();
1185 bool hasExternalReference;
1187 internal DTDEntityDeclaration (DTDObjectModel root) : base (root)
1191 public string NotationName {
1192 get { return notationName; }
1193 set { notationName = value; }
1196 public bool HasExternalReference {
1199 ScanEntityValue (new ArrayList ());
1200 return hasExternalReference;
1204 public string EntityValue {
1207 return String.Empty;
1209 if (PublicId == null && SystemId == null && LiteralEntityValue == null)
1210 return String.Empty;
1212 if (entityValue == null) {
1213 if (NotationName != null)
1215 else if (SystemId == null || SystemId == String.Empty) {
1216 entityValue = ReplacementText;
1217 if (entityValue == null)
1218 entityValue = String.Empty;
1220 entityValue = ReplacementText;
1222 // Check illegal recursion.
1223 ScanEntityValue (new ArrayList ());
1229 // It returns whether the entity contains references to external entities.
1230 public void ScanEntityValue (ArrayList refs)
1232 // To modify this code, beware nesting between this and EntityValue.
1233 string value = EntityValue;
1234 if (this.SystemId != null)
1235 hasExternalReference = true;
1238 throw NotWFError ("Entity recursion was found.");
1242 foreach (string referenced in refs)
1243 if (this.ReferencingEntities.Contains (referenced))
1244 throw NotWFError (String.Format (
1245 "Nested entity was found between {0} and {1}",
1251 int len = value.Length;
1253 for (int i=0; i<len; i++) {
1254 switch (value [i]) {
1261 string name = value.Substring (start, i - start);
1262 if (name.Length == 0)
1263 throw NotWFError ("Entity reference name is missing.");
1264 if (name [0] == '#')
1265 break; // character reference
1266 if (XmlChar.GetPredefinedEntity (name) >= 0)
1267 break; // predefined reference
1269 this.ReferencingEntities.Add (name);
1270 DTDEntityDeclaration decl = Root.EntityDecls [name];
1272 if (decl.SystemId != null)
1273 hasExternalReference = true;
1275 decl.ScanEntityValue (refs);
1276 foreach (string str in decl.ReferencingEntities)
1277 ReferencingEntities.Add (str);
1279 value = value.Remove (start - 1, name.Length + 2);
1280 value = value.Insert (start - 1, decl.EntityValue);
1281 i -= name.Length + 1; // not +2, because of immediate i++ .
1290 Root.AddError (new XmlSchemaException (this, this.BaseURI, "Invalid reference character '&' is specified."));
1292 Root.AddError (new XmlSchemaException ("Invalid reference character '&' is specified.",
1293 this.LineNumber, this.LinePosition, null, this.BaseURI, null));
1300 internal class DTDNotationDeclaration : DTDNode
1308 public string Name {
1309 get { return name; }
1310 set { name = value; }
1313 public string PublicId {
1314 get { return publicId; }
1315 set { publicId = value; }
1318 public string SystemId {
1319 get { return systemId; }
1320 set { systemId = value; }
1323 public string LocalName {
1324 get { return localName; }
1325 set { localName = value; }
1328 public string Prefix {
1329 get { return prefix; }
1330 set { prefix = value; }
1333 internal DTDNotationDeclaration (DTDObjectModel root)
1339 internal class DTDParameterEntityDeclarationCollection
1341 Hashtable peDecls = new Hashtable ();
1342 DTDObjectModel root;
1344 public DTDParameterEntityDeclarationCollection (DTDObjectModel root)
1349 public DTDParameterEntityDeclaration this [string name] {
1350 get { return peDecls [name] as DTDParameterEntityDeclaration; }
1353 public void Add (string name, DTDParameterEntityDeclaration decl)
1355 // PEDecl can be overriden.
1356 if (peDecls [name] != null)
1358 decl.SetRoot (root);
1359 peDecls.Add (name, decl);
1362 public ICollection Keys {
1363 get { return peDecls.Keys; }
1366 public ICollection Values {
1367 get { return peDecls.Values; }
1371 internal class DTDParameterEntityDeclaration : DTDEntityBase
1373 internal DTDParameterEntityDeclaration (DTDObjectModel root) : base (root)
1378 internal enum DTDContentOrderType
1385 internal enum DTDAttributeOccurenceType
1393 internal enum DTDOccurence