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 == null ? 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 = null;
443 if (ElementName != null) {
444 XmlSchemaElement el = new XmlSchemaElement ();
446 el.RefName = new XmlQualifiedName (ElementName);
449 XmlSchemaGroupBase gb =
450 (OrderType == DTDContentOrderType.Seq) ?
452 new XmlSchemaSequence () :
453 new XmlSchemaChoice ();
455 foreach (DTDContentModel cm in ChildModels.Items)
456 gb.Items.Add (cm.CreateXsdParticle ());
460 case DTDOccurence.Optional:
463 case DTDOccurence.OneOrMore:
464 p.MaxOccursString = "unbounded";
466 case DTDOccurence.ZeroOrMore:
468 p.MaxOccursString = "unbounded";
474 private DTDAutomata CompileInternal ()
476 if (ElementDecl.IsAny)
478 if (ElementDecl.IsEmpty)
481 DTDAutomata basis = GetBasicContentAutomata ();
483 case DTDOccurence.One:
485 case DTDOccurence.Optional:
486 return Choice (root.Empty, basis);
487 case DTDOccurence.OneOrMore:
488 return new DTDOneOrMoreAutomata (root, basis);
489 case DTDOccurence.ZeroOrMore:
490 return Choice (root.Empty, new DTDOneOrMoreAutomata (root, basis));
492 throw new InvalidOperationException ();
495 private DTDAutomata GetBasicContentAutomata ()
497 if (ElementName != null)
498 return new DTDElementAutomata (root, ElementName);
499 switch (ChildModels.Count) {
503 return ChildModels [0].GetAutomata ();
506 DTDAutomata current = null;
507 int childCount = ChildModels.Count;
509 case DTDContentOrderType.Seq:
511 ChildModels [childCount - 2].GetAutomata (),
512 ChildModels [childCount - 1].GetAutomata ());
513 for (int i = childCount - 2; i > 0; i--)
515 ChildModels [i - 1].GetAutomata (), current);
517 case DTDContentOrderType.Or:
519 ChildModels [childCount - 2].GetAutomata (),
520 ChildModels [childCount - 1].GetAutomata ());
521 for (int i = childCount - 2; i > 0; i--)
523 ChildModels [i - 1].GetAutomata (), current);
526 throw new InvalidOperationException ("Invalid pattern specification");
530 private DTDAutomata Sequence (DTDAutomata l, DTDAutomata r)
532 return root.Factory.Sequence (l, r);
535 private DTDAutomata Choice (DTDAutomata l, DTDAutomata r)
537 return l.MakeChoice (r);
541 internal class DTDContentModelCollection
543 ArrayList contentModel = new ArrayList ();
545 public DTDContentModelCollection ()
550 get { return contentModel; }
553 public DTDContentModel this [int i] {
554 get { return contentModel [i] as DTDContentModel; }
558 get { return contentModel.Count; }
561 public void Add (DTDContentModel model)
563 contentModel.Add (model);
567 internal abstract class DTDNode : IXmlLineInfo
570 bool isInternalSubset;
575 public virtual string BaseURI {
576 get { return baseURI; }
577 set { baseURI = value; }
580 public bool IsInternalSubset {
581 get { return isInternalSubset; }
582 set { isInternalSubset = value; }
585 public int LineNumber {
586 get { return lineNumber; }
587 set { lineNumber = value; }
590 public int LinePosition {
591 get { return linePosition; }
592 set { linePosition = value; }
595 public bool HasLineInfo ()
597 return lineNumber != 0;
600 internal void SetRoot (DTDObjectModel root)
604 this.BaseURI = root.BaseURI;
607 protected DTDObjectModel Root {
611 internal XmlException NotWFError (string message)
613 return new XmlException (this as IXmlLineInfo, BaseURI, message);
616 public void SetLineInfo (XmlSchemaObject obj)
618 obj.SourceUri = BaseURI;
619 obj.LineNumber = LineNumber;
620 obj.LinePosition = LinePosition;
624 internal class DTDElementDeclaration : DTDNode
627 DTDContentModel contentModel;
633 internal DTDElementDeclaration (DTDObjectModel root)
640 set { name = value; }
642 public bool IsEmpty {
643 get { return isEmpty; }
644 set { isEmpty = value; }
648 get { return isAny; }
649 set { isAny = value; }
652 public bool IsMixedContent {
653 get { return isMixedContent; }
654 set { isMixedContent = value; }
657 public DTDContentModel ContentModel {
659 if (contentModel == null)
660 contentModel = new DTDContentModel (root, Name);
665 public DTDAttListDeclaration Attributes {
667 return Root.AttListDecls [Name];
671 internal XmlSchemaElement CreateXsdElement ()
673 XmlSchemaElement el = new XmlSchemaElement ();
677 el.SchemaType = new XmlSchemaComplexType ();
678 SetLineInfo (el.SchemaType);
681 el.SchemaTypeName = new XmlQualifiedName (
682 "anyType", XmlSchema.Namespace);
684 XmlSchemaComplexType ct = new XmlSchemaComplexType ();
686 foreach (DTDAttributeDefinition a in
687 Attributes.Definitions)
688 ct.Attributes.Add (a.CreateXsdAttribute ());
691 ct.Particle = ContentModel.CreateXsdParticle ();
698 internal class DTDAttributeDefinition : DTDNode
701 XmlSchemaDatatype datatype;
702 ArrayList enumeratedLiterals;
703 string unresolvedDefault;
704 ArrayList enumeratedNotations;
705 DTDAttributeOccurenceType occurenceType = DTDAttributeOccurenceType.None;
706 string resolvedDefaultValue;
707 string resolvedNormalizedDefaultValue;
709 internal DTDAttributeDefinition (DTDObjectModel root)
719 public XmlSchemaDatatype Datatype {
720 get { return datatype; }
721 set { datatype = value; }
724 public DTDAttributeOccurenceType OccurenceType {
725 get { return this.occurenceType; }
726 set { this.occurenceType = value; }
729 // entity reference inside enumerated values are not allowed,
730 // but on the other hand, they are allowed inside default value.
731 // Then I decided to use string ArrayList for enumerated values,
732 // and unresolved string value for DefaultValue.
733 public ArrayList EnumeratedAttributeDeclaration {
735 if (enumeratedLiterals == null)
736 enumeratedLiterals = new ArrayList ();
737 return this.enumeratedLiterals;
741 public ArrayList EnumeratedNotations {
743 if (enumeratedNotations == null)
744 enumeratedNotations = new ArrayList ();
745 return this.enumeratedNotations;
749 public string DefaultValue {
751 if (resolvedDefaultValue == null)
752 resolvedDefaultValue = ComputeDefaultValue ();
753 return resolvedDefaultValue;
757 public string NormalizedDefaultValue {
759 if (resolvedNormalizedDefaultValue == null) {
760 string s = ComputeDefaultValue ();
762 object o = Datatype.ParseValue (s, null, null);
763 resolvedNormalizedDefaultValue =
765 String.Join (" ", (string []) o) :
766 o is IFormattable ? ((IFormattable) o).ToString (null, CultureInfo.InvariantCulture) : o.ToString ();
767 } catch (Exception) {
768 // This is for non-error-reporting reader
769 resolvedNormalizedDefaultValue = Datatype.Normalize (s);
772 return resolvedNormalizedDefaultValue;
776 public string UnresolvedDefaultValue {
777 get { return this.unresolvedDefault; }
778 set { this.unresolvedDefault = value; }
781 public char QuoteChar {
783 return UnresolvedDefaultValue.Length > 0 ?
784 this.UnresolvedDefaultValue [0] :
789 internal XmlSchemaAttribute CreateXsdAttribute ()
791 XmlSchemaAttribute a = new XmlSchemaAttribute ();
794 a.DefaultValue = resolvedNormalizedDefaultValue;
796 XmlQualifiedName qname = XmlQualifiedName.Empty;
797 ArrayList enumeration = null;
798 if (enumeratedNotations != null && enumeratedNotations.Count > 0) {
799 qname = new XmlQualifiedName ("NOTATION", XmlSchema.Namespace);
800 enumeration = enumeratedNotations;
802 else if (enumeratedLiterals != null)
803 enumeration = enumeratedLiterals;
805 switch (Datatype.TokenizedType) {
806 case XmlTokenizedType.ID:
807 qname = new XmlQualifiedName ("ID", XmlSchema.Namespace); break;
808 case XmlTokenizedType.IDREF:
809 qname = new XmlQualifiedName ("IDREF", XmlSchema.Namespace); break;
810 case XmlTokenizedType.IDREFS:
811 qname = new XmlQualifiedName ("IDREFS", XmlSchema.Namespace); break;
812 case XmlTokenizedType.ENTITY:
813 qname = new XmlQualifiedName ("ENTITY", XmlSchema.Namespace); break;
814 case XmlTokenizedType.ENTITIES:
815 qname = new XmlQualifiedName ("ENTITIES", XmlSchema.Namespace); break;
816 case XmlTokenizedType.NMTOKEN:
817 qname = new XmlQualifiedName ("NMTOKEN", XmlSchema.Namespace); break;
818 case XmlTokenizedType.NMTOKENS:
819 qname = new XmlQualifiedName ("NMTOKENS", XmlSchema.Namespace); break;
820 case XmlTokenizedType.NOTATION:
821 qname = new XmlQualifiedName ("NOTATION", XmlSchema.Namespace); break;
825 if (enumeration != null) {
826 XmlSchemaSimpleType st = new XmlSchemaSimpleType ();
828 XmlSchemaSimpleTypeRestriction r =
829 new XmlSchemaSimpleTypeRestriction ();
831 r.BaseTypeName = qname;
832 foreach (string name in enumeratedNotations) {
833 XmlSchemaEnumerationFacet f =
834 new XmlSchemaEnumerationFacet ();
840 else if (qname != XmlQualifiedName.Empty)
841 a.SchemaTypeName = qname;
845 internal string ComputeDefaultValue ()
847 if (UnresolvedDefaultValue == null)
850 StringBuilder sb = new StringBuilder ();
853 string value = this.UnresolvedDefaultValue;
854 while ((next = value.IndexOf ('&', pos)) >= 0) {
855 int semicolon = value.IndexOf (';', next);
856 if (value [next + 1] == '#') {
857 // character reference.
858 char c = value [next + 2];
859 NumberStyles style = NumberStyles.Integer;
861 if (c == 'x' || c == 'X') {
862 spec = value.Substring (next + 3, semicolon - next - 3);
863 style |= NumberStyles.HexNumber;
866 spec = value.Substring (next + 2, semicolon - next - 2);
867 sb.Append ((char) int.Parse (spec, style, CultureInfo.InvariantCulture));
869 sb.Append (value.Substring (pos, next - 1));
870 string name = value.Substring (next + 1, semicolon - 2);
871 int predefined = XmlChar.GetPredefinedEntity (name);
873 sb.Append (predefined);
875 sb.Append (Root.ResolveEntity (name));
879 sb.Append (value.Substring (pos));
881 string ret = sb.ToString (1, sb.Length - 2);
888 internal class DTDAttListDeclaration : DTDNode
891 Hashtable attributeOrders = new Hashtable ();
892 ArrayList attributes = new ArrayList ();
894 internal DTDAttListDeclaration (DTDObjectModel root)
901 set { name = value; }
904 public DTDAttributeDefinition this [int i] {
905 get { return Get (i); }
908 public DTDAttributeDefinition this [string name] {
909 get { return Get (name); }
912 public DTDAttributeDefinition Get (int i)
914 return attributes [i] as DTDAttributeDefinition;
917 public DTDAttributeDefinition Get (string name)
919 object o = attributeOrders [name];
921 return attributes [(int) o] as DTDAttributeDefinition;
926 public IList Definitions {
927 get { return attributes; }
930 public void Add (DTDAttributeDefinition def)
932 if (attributeOrders [def.Name] != null)
933 throw new InvalidOperationException (String.Format (
934 "Attribute definition for {0} was already added at element {1}.",
935 def.Name, this.Name));
937 attributeOrders.Add (def.Name, attributes.Count);
938 attributes.Add (def);
942 get { return attributeOrders.Count; }
946 internal class DTDEntityBase : DTDNode
952 string replacementText;
954 // Exception loadException;
957 protected DTDEntityBase (DTDObjectModel root)
962 internal bool IsInvalid {
963 get { return isInvalid; }
964 set { isInvalid = value; }
967 public bool LoadFailed {
968 get { return loadFailed; }
969 set { loadFailed = value; }
974 set { name = value; }
977 public string PublicId {
978 get { return publicId; }
979 set { publicId = value; }
982 public string SystemId {
983 get { return systemId; }
984 set { systemId = value; }
987 public string LiteralEntityValue {
988 get { return literalValue; }
989 set { literalValue = value; }
992 public string ReplacementText {
993 get { return replacementText; }
994 set { replacementText = value; }
997 public void Resolve (XmlResolver resolver)
999 if (resolver == null || SystemId == null || SystemId.Length == 0) {
1001 LiteralEntityValue = String.Empty;
1007 if (BaseURI != null && BaseURI.Length > 0)
1008 baseUri = new Uri (BaseURI);
1009 } catch (UriFormatException) {
1012 Uri absUri = resolver.ResolveUri (baseUri, SystemId);
1013 string absPath = absUri != null ? absUri.ToString () : String.Empty;
1014 if (Root.ExternalResources.ContainsKey (absPath))
1015 LiteralEntityValue = (string) Root.ExternalResources [absPath];
1018 s = resolver.GetEntity (absUri, null, typeof (Stream)) as Stream;
1019 XmlTextReaderImpl xtr = new XmlTextReaderImpl (absPath, s, Root.NameTable);
1020 // Don't skip Text declaration here. LiteralEntityValue contains it. See spec 4.5
1021 this.BaseURI = absPath;
1022 LiteralEntityValue = xtr.GetRemainder ().ReadToEnd ();
1024 Root.ExternalResources.Add (absPath, LiteralEntityValue);
1025 if (Root.ExternalResources.Count > DTDObjectModel.AllowedExternalEntitiesMax)
1026 throw new InvalidOperationException ("The total amount of external entities exceeded the allowed number.");
1028 } catch (Exception ex) {
1029 // loadException = ex;
1030 LiteralEntityValue = String.Empty;
1032 // throw NotWFError ("Cannot resolve external entity. URI is " + absPath + " .");
1040 internal class DTDEntityDeclaration : DTDEntityBase
1043 string notationName;
1045 ArrayList ReferencingEntities = new ArrayList ();
1049 bool hasExternalReference;
1051 internal DTDEntityDeclaration (DTDObjectModel root) : base (root)
1055 public string NotationName {
1056 get { return notationName; }
1057 set { notationName = value; }
1060 public bool HasExternalReference {
1063 ScanEntityValue (new ArrayList ());
1064 return hasExternalReference;
1068 public string EntityValue {
1071 return String.Empty;
1073 if (PublicId == null && SystemId == null && LiteralEntityValue == null)
1074 return String.Empty;
1076 if (entityValue == null) {
1077 if (NotationName != null)
1079 else if (SystemId == null || SystemId == String.Empty) {
1080 entityValue = ReplacementText;
1081 if (entityValue == null)
1082 entityValue = String.Empty;
1084 entityValue = ReplacementText;
1086 // Check illegal recursion.
1087 ScanEntityValue (new ArrayList ());
1093 // It returns whether the entity contains references to external entities.
1094 public void ScanEntityValue (ArrayList refs)
1096 // To modify this code, beware nesting between this and EntityValue.
1097 string value = EntityValue;
1098 if (this.SystemId != null)
1099 hasExternalReference = true;
1102 throw NotWFError ("Entity recursion was found.");
1106 foreach (string referenced in refs)
1107 if (this.ReferencingEntities.Contains (referenced))
1108 throw NotWFError (String.Format (
1109 "Nested entity was found between {0} and {1}",
1115 int len = value.Length;
1117 for (int i=0; i<len; i++) {
1118 switch (value [i]) {
1125 string name = value.Substring (start, i - start);
1126 if (name.Length == 0)
1127 throw NotWFError ("Entity reference name is missing.");
1128 if (name [0] == '#')
1129 break; // character reference
1130 if (XmlChar.GetPredefinedEntity (name) >= 0)
1131 break; // predefined reference
1133 this.ReferencingEntities.Add (name);
1134 DTDEntityDeclaration decl = Root.EntityDecls [name];
1136 if (decl.SystemId != null)
1137 hasExternalReference = true;
1139 decl.ScanEntityValue (refs);
1140 foreach (string str in decl.ReferencingEntities)
1141 ReferencingEntities.Add (str);
1143 value = value.Remove (start - 1, name.Length + 2);
1144 value = value.Insert (start - 1, decl.EntityValue);
1145 i -= name.Length + 1; // not +2, because of immediate i++ .
1153 Root.AddError (new XmlSchemaException ("Invalid reference character '&' is specified.",
1154 this.LineNumber, this.LinePosition, null, this.BaseURI, null));
1160 internal class DTDNotationDeclaration : DTDNode
1168 public string Name {
1169 get { return name; }
1170 set { name = value; }
1173 public string PublicId {
1174 get { return publicId; }
1175 set { publicId = value; }
1178 public string SystemId {
1179 get { return systemId; }
1180 set { systemId = value; }
1183 public string LocalName {
1184 get { return localName; }
1185 set { localName = value; }
1188 public string Prefix {
1189 get { return prefix; }
1190 set { prefix = value; }
1193 internal DTDNotationDeclaration (DTDObjectModel root)
1199 internal class DTDParameterEntityDeclarationCollection
1201 Hashtable peDecls = new Hashtable ();
1202 DTDObjectModel root;
1204 public DTDParameterEntityDeclarationCollection (DTDObjectModel root)
1209 public DTDParameterEntityDeclaration this [string name] {
1210 get { return peDecls [name] as DTDParameterEntityDeclaration; }
1213 public void Add (string name, DTDParameterEntityDeclaration decl)
1215 // PEDecl can be overriden.
1216 if (peDecls [name] != null)
1218 decl.SetRoot (root);
1219 peDecls.Add (name, decl);
1222 public ICollection Keys {
1223 get { return peDecls.Keys; }
1226 public ICollection Values {
1227 get { return peDecls.Values; }
1231 internal class DTDParameterEntityDeclaration : DTDEntityBase
1233 internal DTDParameterEntityDeclaration (DTDObjectModel root) : base (root)
1238 internal enum DTDContentOrderType
1245 internal enum DTDAttributeOccurenceType
1253 internal enum DTDOccurence