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);
249 internal string GenerateEntityAttributeText (string entityName)
251 DTDEntityDeclaration entity = EntityDecls [entityName] as DTDEntityDeclaration;
254 return entity.EntityValue;
257 internal XmlTextReaderImpl GenerateEntityContentReader (string entityName, XmlParserContext context)
259 DTDEntityDeclaration entity = EntityDecls [entityName] as DTDEntityDeclaration;
263 if (entity.SystemId != null) {
264 Uri baseUri = entity.BaseURI == String.Empty ? null : new Uri (entity.BaseURI);
265 Stream stream = resolver.GetEntity (resolver.ResolveUri (baseUri, entity.SystemId), null, typeof (Stream)) as Stream;
266 return new XmlTextReaderImpl (stream, XmlNodeType.Element, context);
269 return new XmlTextReaderImpl (entity.EntityValue, XmlNodeType.Element, context);
273 internal class DTDCollectionBase : DictionaryBase
277 protected DTDCollectionBase (DTDObjectModel root)
282 protected DTDObjectModel Root {
286 public ICollection Keys {
287 get { return InnerHashtable.Keys; }
290 public ICollection Values {
291 get { return InnerHashtable.Values; }
295 internal class DTDElementDeclarationCollection : DTDCollectionBase
298 public DTDElementDeclarationCollection (DTDObjectModel root) : base (root) {}
300 public DTDElementDeclaration this [string name] {
301 get { return Get (name); }
304 public DTDElementDeclaration Get (string name)
306 return InnerHashtable [name] as DTDElementDeclaration;
309 public void Add (string name, DTDElementDeclaration decl)
311 if (InnerHashtable.Contains (name)) {
312 Root.AddError (new XmlSchemaException (String.Format (
313 "Element declaration for {0} was already added.",
318 InnerHashtable.Add (name, decl);
322 internal class DTDAttListDeclarationCollection : DTDCollectionBase
324 public DTDAttListDeclarationCollection (DTDObjectModel root) : base (root) {}
326 public DTDAttListDeclaration this [string name] {
327 get { return InnerHashtable [name] as DTDAttListDeclaration; }
330 public void Add (string name, DTDAttListDeclaration decl)
332 DTDAttListDeclaration existing = this [name];
333 if (existing != null) {
334 // It is valid, that is additive declaration.
335 foreach (DTDAttributeDefinition def in decl.Definitions)
336 if (decl.Get (def.Name) == null)
340 InnerHashtable.Add (name, decl);
345 internal class DTDEntityDeclarationCollection : DTDCollectionBase
347 public DTDEntityDeclarationCollection (DTDObjectModel root) : base (root) {}
349 public DTDEntityDeclaration this [string name] {
350 get { return InnerHashtable [name] as DTDEntityDeclaration; }
353 public void Add (string name, DTDEntityDeclaration decl)
355 if (InnerHashtable [name] != null)
356 throw new InvalidOperationException (String.Format (
357 "Entity declaration for {0} was already added.",
360 InnerHashtable.Add (name, decl);
364 internal class DTDNotationDeclarationCollection : DTDCollectionBase
366 public DTDNotationDeclarationCollection (DTDObjectModel root) : base (root) {}
368 public DTDNotationDeclaration this [string name] {
369 get { return InnerHashtable [name] as DTDNotationDeclaration; }
372 public void Add (string name, DTDNotationDeclaration decl)
374 if (InnerHashtable [name] != null)
375 throw new InvalidOperationException (String.Format (
376 "Notation declaration for {0} was already added.",
379 InnerHashtable.Add (name, decl);
383 // This class contains either ElementName or ChildModels.
384 internal class DTDContentModel : DTDNode
387 DTDAutomata compiledAutomata;
389 string ownerElementName;
391 DTDContentOrderType orderType = DTDContentOrderType.None;
392 DTDContentModelCollection childModels = new DTDContentModelCollection ();
393 DTDOccurence occurence = DTDOccurence.One;
395 internal DTDContentModel (DTDObjectModel root, string ownerElementName)
398 this.ownerElementName = ownerElementName;
401 public DTDContentModelCollection ChildModels {
402 get { return childModels; }
403 set { childModels = value; }
406 public DTDElementDeclaration ElementDecl {
407 get { return root.ElementDecls [ownerElementName]; }
410 public string ElementName {
411 get { return elementName; }
412 set { elementName = value; }
415 public DTDOccurence Occurence {
416 get { return occurence; }
417 set { occurence = value; }
420 public DTDContentOrderType OrderType {
421 get { return orderType; }
422 set { orderType = value; }
425 public DTDAutomata GetAutomata ()
427 if (compiledAutomata == null)
429 return compiledAutomata;
432 public DTDAutomata Compile ()
434 compiledAutomata = CompileInternal ();
435 return compiledAutomata;
438 internal XmlSchemaParticle CreateXsdParticle ()
440 XmlSchemaParticle p = CreateXsdParticleCore ();
445 case DTDOccurence.Optional:
448 case DTDOccurence.OneOrMore:
449 p.MaxOccursString = "unbounded";
451 case DTDOccurence.ZeroOrMore:
453 p.MaxOccursString = "unbounded";
459 XmlSchemaParticle CreateXsdParticleCore ()
461 XmlSchemaParticle p = null;
462 if (ElementName != null) {
463 XmlSchemaElement el = new XmlSchemaElement ();
465 el.RefName = new XmlQualifiedName (ElementName);
468 else if (ChildModels.Count == 0)
471 XmlSchemaGroupBase gb =
472 (OrderType == DTDContentOrderType.Seq) ?
474 new XmlSchemaSequence () :
475 new XmlSchemaChoice ();
477 foreach (DTDContentModel cm in ChildModels.Items) {
478 XmlSchemaParticle c = cm.CreateXsdParticle ();
487 private DTDAutomata CompileInternal ()
489 if (ElementDecl.IsAny)
491 if (ElementDecl.IsEmpty)
494 DTDAutomata basis = GetBasicContentAutomata ();
496 case DTDOccurence.One:
498 case DTDOccurence.Optional:
499 return Choice (root.Empty, basis);
500 case DTDOccurence.OneOrMore:
501 return new DTDOneOrMoreAutomata (root, basis);
502 case DTDOccurence.ZeroOrMore:
503 return Choice (root.Empty, new DTDOneOrMoreAutomata (root, basis));
505 throw new InvalidOperationException ();
508 private DTDAutomata GetBasicContentAutomata ()
510 if (ElementName != null)
511 return new DTDElementAutomata (root, ElementName);
512 switch (ChildModels.Count) {
516 return ChildModels [0].GetAutomata ();
519 DTDAutomata current = null;
520 int childCount = ChildModels.Count;
522 case DTDContentOrderType.Seq:
524 ChildModels [childCount - 2].GetAutomata (),
525 ChildModels [childCount - 1].GetAutomata ());
526 for (int i = childCount - 2; i > 0; i--)
528 ChildModels [i - 1].GetAutomata (), current);
530 case DTDContentOrderType.Or:
532 ChildModels [childCount - 2].GetAutomata (),
533 ChildModels [childCount - 1].GetAutomata ());
534 for (int i = childCount - 2; i > 0; i--)
536 ChildModels [i - 1].GetAutomata (), current);
539 throw new InvalidOperationException ("Invalid pattern specification");
543 private DTDAutomata Sequence (DTDAutomata l, DTDAutomata r)
545 return root.Factory.Sequence (l, r);
548 private DTDAutomata Choice (DTDAutomata l, DTDAutomata r)
550 return l.MakeChoice (r);
554 internal class DTDContentModelCollection
556 ArrayList contentModel = new ArrayList ();
558 public DTDContentModelCollection ()
563 get { return contentModel; }
566 public DTDContentModel this [int i] {
567 get { return contentModel [i] as DTDContentModel; }
571 get { return contentModel.Count; }
574 public void Add (DTDContentModel model)
576 contentModel.Add (model);
580 internal abstract class DTDNode : IXmlLineInfo
583 bool isInternalSubset;
588 public virtual string BaseURI {
589 get { return baseURI; }
590 set { baseURI = value; }
593 public bool IsInternalSubset {
594 get { return isInternalSubset; }
595 set { isInternalSubset = value; }
598 public int LineNumber {
599 get { return lineNumber; }
600 set { lineNumber = value; }
603 public int LinePosition {
604 get { return linePosition; }
605 set { linePosition = value; }
608 public bool HasLineInfo ()
610 return lineNumber != 0;
613 internal void SetRoot (DTDObjectModel root)
617 this.BaseURI = root.BaseURI;
620 protected DTDObjectModel Root {
624 internal XmlException NotWFError (string message)
626 return new XmlException (this as IXmlLineInfo, BaseURI, message);
629 public void SetLineInfo (XmlSchemaObject obj)
631 obj.SourceUri = BaseURI;
632 obj.LineNumber = LineNumber;
633 obj.LinePosition = LinePosition;
637 internal class DTDElementDeclaration : DTDNode
640 DTDContentModel contentModel;
646 internal DTDElementDeclaration (DTDObjectModel root)
653 set { name = value; }
655 public bool IsEmpty {
656 get { return isEmpty; }
657 set { isEmpty = value; }
661 get { return isAny; }
662 set { isAny = value; }
665 public bool IsMixedContent {
666 get { return isMixedContent; }
667 set { isMixedContent = value; }
670 public DTDContentModel ContentModel {
672 if (contentModel == null)
673 contentModel = new DTDContentModel (root, Name);
678 public DTDAttListDeclaration Attributes {
680 return Root.AttListDecls [Name];
684 internal XmlSchemaElement CreateXsdElement ()
686 XmlSchemaElement el = new XmlSchemaElement ();
690 XmlSchemaComplexType ct = new XmlSchemaComplexType ();
692 if (Attributes != null) {
694 foreach (DTDAttributeDefinition a in
695 Attributes.Definitions)
696 ct.Attributes.Add (a.CreateXsdAttribute ());
701 XmlSchemaAny any = new XmlSchemaAny ();
703 any.MaxOccursString = "unbounded";
709 ct.Particle = ContentModel.CreateXsdParticle ();
714 el.SchemaType = new XmlSchemaComplexType ();
715 SetLineInfo (el.SchemaType);
718 el.SchemaTypeName = new XmlQualifiedName (
719 "anyType", XmlSchema.Namespace);
721 XmlSchemaComplexType ct = new XmlSchemaComplexType ();
723 if (Attributes != null)
724 foreach (DTDAttributeDefinition a in
725 Attributes.Definitions)
726 ct.Attributes.Add (a.CreateXsdAttribute ());
729 ct.Particle = ContentModel.CreateXsdParticle ();
737 internal class DTDAttributeDefinition : DTDNode
740 XmlSchemaDatatype datatype;
741 ArrayList enumeratedLiterals;
742 string unresolvedDefault;
743 ArrayList enumeratedNotations;
744 DTDAttributeOccurenceType occurenceType = DTDAttributeOccurenceType.None;
745 string resolvedDefaultValue;
746 string resolvedNormalizedDefaultValue;
748 internal DTDAttributeDefinition (DTDObjectModel root)
758 public XmlSchemaDatatype Datatype {
759 get { return datatype; }
760 set { datatype = value; }
763 public DTDAttributeOccurenceType OccurenceType {
764 get { return this.occurenceType; }
765 set { this.occurenceType = value; }
768 // entity reference inside enumerated values are not allowed,
769 // but on the other hand, they are allowed inside default value.
770 // Then I decided to use string ArrayList for enumerated values,
771 // and unresolved string value for DefaultValue.
772 public ArrayList EnumeratedAttributeDeclaration {
774 if (enumeratedLiterals == null)
775 enumeratedLiterals = new ArrayList ();
776 return this.enumeratedLiterals;
780 public ArrayList EnumeratedNotations {
782 if (enumeratedNotations == null)
783 enumeratedNotations = new ArrayList ();
784 return this.enumeratedNotations;
788 public string DefaultValue {
790 if (resolvedDefaultValue == null)
791 resolvedDefaultValue = ComputeDefaultValue ();
792 return resolvedDefaultValue;
796 public string NormalizedDefaultValue {
798 if (resolvedNormalizedDefaultValue == null) {
799 string s = ComputeDefaultValue ();
801 object o = Datatype.ParseValue (s, null, null);
802 resolvedNormalizedDefaultValue =
804 String.Join (" ", (string []) o) :
805 o is IFormattable ? ((IFormattable) o).ToString (null, CultureInfo.InvariantCulture) : o.ToString ();
806 } catch (Exception) {
807 // This is for non-error-reporting reader
808 resolvedNormalizedDefaultValue = Datatype.Normalize (s);
811 return resolvedNormalizedDefaultValue;
815 public string UnresolvedDefaultValue {
816 get { return this.unresolvedDefault; }
817 set { this.unresolvedDefault = value; }
820 public char QuoteChar {
822 return UnresolvedDefaultValue.Length > 0 ?
823 this.UnresolvedDefaultValue [0] :
828 internal XmlSchemaAttribute CreateXsdAttribute ()
830 XmlSchemaAttribute a = new XmlSchemaAttribute ();
833 a.DefaultValue = resolvedNormalizedDefaultValue;
834 if (OccurenceType != DTDAttributeOccurenceType.Required)
835 a.Use = XmlSchemaUse.Optional;
837 XmlQualifiedName qname = XmlQualifiedName.Empty;
838 ArrayList enumeration = null;
839 if (enumeratedNotations != null && enumeratedNotations.Count > 0) {
840 qname = new XmlQualifiedName ("NOTATION", XmlSchema.Namespace);
841 enumeration = enumeratedNotations;
843 else if (enumeratedLiterals != null)
844 enumeration = enumeratedLiterals;
846 switch (Datatype.TokenizedType) {
847 case XmlTokenizedType.ID:
848 qname = new XmlQualifiedName ("ID", XmlSchema.Namespace); break;
849 case XmlTokenizedType.IDREF:
850 qname = new XmlQualifiedName ("IDREF", XmlSchema.Namespace); break;
851 case XmlTokenizedType.IDREFS:
852 qname = new XmlQualifiedName ("IDREFS", XmlSchema.Namespace); break;
853 case XmlTokenizedType.ENTITY:
854 qname = new XmlQualifiedName ("ENTITY", XmlSchema.Namespace); break;
855 case XmlTokenizedType.ENTITIES:
856 qname = new XmlQualifiedName ("ENTITIES", XmlSchema.Namespace); break;
857 case XmlTokenizedType.NMTOKEN:
858 qname = new XmlQualifiedName ("NMTOKEN", XmlSchema.Namespace); break;
859 case XmlTokenizedType.NMTOKENS:
860 qname = new XmlQualifiedName ("NMTOKENS", XmlSchema.Namespace); break;
861 case XmlTokenizedType.NOTATION:
862 qname = new XmlQualifiedName ("NOTATION", XmlSchema.Namespace); break;
866 if (enumeration != null) {
867 XmlSchemaSimpleType st = new XmlSchemaSimpleType ();
869 XmlSchemaSimpleTypeRestriction r =
870 new XmlSchemaSimpleTypeRestriction ();
872 r.BaseTypeName = qname;
873 if (enumeratedNotations != null) {
874 foreach (string name in enumeratedNotations) {
875 XmlSchemaEnumerationFacet f =
876 new XmlSchemaEnumerationFacet ();
884 else if (qname != XmlQualifiedName.Empty)
885 a.SchemaTypeName = qname;
889 internal string ComputeDefaultValue ()
891 if (UnresolvedDefaultValue == null)
894 StringBuilder sb = new StringBuilder ();
897 string value = this.UnresolvedDefaultValue;
898 while ((next = value.IndexOf ('&', pos)) >= 0) {
899 int semicolon = value.IndexOf (';', next);
900 if (value [next + 1] == '#') {
901 // character reference.
902 char c = value [next + 2];
903 NumberStyles style = NumberStyles.Integer;
905 if (c == 'x' || c == 'X') {
906 spec = value.Substring (next + 3, semicolon - next - 3);
907 style |= NumberStyles.HexNumber;
910 spec = value.Substring (next + 2, semicolon - next - 2);
911 sb.Append ((char) int.Parse (spec, style, CultureInfo.InvariantCulture));
913 sb.Append (value.Substring (pos, next - 1));
914 string name = value.Substring (next + 1, semicolon - 2);
915 int predefined = XmlChar.GetPredefinedEntity (name);
917 sb.Append (predefined);
919 sb.Append (Root.ResolveEntity (name));
923 sb.Append (value.Substring (pos));
925 string ret = sb.ToString (1, sb.Length - 2);
932 internal class DTDAttListDeclaration : DTDNode
935 Hashtable attributeOrders = new Hashtable ();
936 ArrayList attributes = new ArrayList ();
938 internal DTDAttListDeclaration (DTDObjectModel root)
945 set { name = value; }
948 public DTDAttributeDefinition this [int i] {
949 get { return Get (i); }
952 public DTDAttributeDefinition this [string name] {
953 get { return Get (name); }
956 public DTDAttributeDefinition Get (int i)
958 return attributes [i] as DTDAttributeDefinition;
961 public DTDAttributeDefinition Get (string name)
963 object o = attributeOrders [name];
965 return attributes [(int) o] as DTDAttributeDefinition;
970 public IList Definitions {
971 get { return attributes; }
974 public void Add (DTDAttributeDefinition def)
976 if (attributeOrders [def.Name] != null)
977 throw new InvalidOperationException (String.Format (
978 "Attribute definition for {0} was already added at element {1}.",
979 def.Name, this.Name));
981 attributeOrders.Add (def.Name, attributes.Count);
982 attributes.Add (def);
986 get { return attributeOrders.Count; }
990 internal class DTDEntityBase : DTDNode
996 string replacementText;
1000 // Exception loadException;
1002 XmlResolver resolver;
1004 protected DTDEntityBase (DTDObjectModel root)
1009 internal bool IsInvalid {
1010 get { return isInvalid; }
1011 set { isInvalid = value; }
1014 public bool LoadFailed {
1015 get { return loadFailed; }
1016 set { loadFailed = value; }
1019 public string Name {
1020 get { return name; }
1021 set { name = value; }
1024 public string PublicId {
1025 get { return publicId; }
1026 set { publicId = value; }
1029 public string SystemId {
1030 get { return systemId; }
1031 set { systemId = value; }
1034 public string LiteralEntityValue {
1035 get { return literalValue; }
1036 set { literalValue = value; }
1039 public string ReplacementText {
1040 get { return replacementText; }
1041 set { replacementText = value; }
1044 public XmlResolver XmlResolver {
1045 set { resolver = value; }
1048 public string ActualUri {
1050 if (uriString == null) {
1051 if (resolver == null || SystemId == null || SystemId.Length == 0)
1052 uriString = BaseURI;
1056 if (BaseURI != null && BaseURI.Length > 0)
1057 baseUri = new Uri (BaseURI);
1058 } catch (UriFormatException) {
1061 absUri = resolver.ResolveUri (baseUri, SystemId);
1062 uriString = absUri != null ? absUri.ToString () : String.Empty;
1069 public void Resolve ()
1071 if (ActualUri == String.Empty) {
1073 LiteralEntityValue = String.Empty;
1077 if (Root.ExternalResources.ContainsKey (ActualUri))
1078 LiteralEntityValue = (string) Root.ExternalResources [ActualUri];
1081 s = resolver.GetEntity (absUri, null, typeof (Stream)) as Stream;
1082 XmlTextReaderImpl xtr = new XmlTextReaderImpl (ActualUri, s, Root.NameTable);
1083 // Don't skip Text declaration here. LiteralEntityValue contains it. See spec 4.5
1084 LiteralEntityValue = xtr.GetRemainder ().ReadToEnd ();
1086 Root.ExternalResources.Add (ActualUri, LiteralEntityValue);
1087 if (Root.ExternalResources.Count > DTDObjectModel.AllowedExternalEntitiesMax)
1088 throw new InvalidOperationException ("The total amount of external entities exceeded the allowed number.");
1090 } catch (Exception ex) {
1091 // loadException = ex;
1092 LiteralEntityValue = String.Empty;
1094 // throw NotWFError ("Cannot resolve external entity. URI is " + ActualUri + " .");
1102 internal class DTDEntityDeclaration : DTDEntityBase
1105 string notationName;
1107 ArrayList ReferencingEntities = new ArrayList ();
1111 bool hasExternalReference;
1113 internal DTDEntityDeclaration (DTDObjectModel root) : base (root)
1117 public string NotationName {
1118 get { return notationName; }
1119 set { notationName = value; }
1122 public bool HasExternalReference {
1125 ScanEntityValue (new ArrayList ());
1126 return hasExternalReference;
1130 public string EntityValue {
1133 return String.Empty;
1135 if (PublicId == null && SystemId == null && LiteralEntityValue == null)
1136 return String.Empty;
1138 if (entityValue == null) {
1139 if (NotationName != null)
1141 else if (SystemId == null || SystemId == String.Empty) {
1142 entityValue = ReplacementText;
1143 if (entityValue == null)
1144 entityValue = String.Empty;
1146 entityValue = ReplacementText;
1148 // Check illegal recursion.
1149 ScanEntityValue (new ArrayList ());
1155 // It returns whether the entity contains references to external entities.
1156 public void ScanEntityValue (ArrayList refs)
1158 // To modify this code, beware nesting between this and EntityValue.
1159 string value = EntityValue;
1160 if (this.SystemId != null)
1161 hasExternalReference = true;
1164 throw NotWFError ("Entity recursion was found.");
1168 foreach (string referenced in refs)
1169 if (this.ReferencingEntities.Contains (referenced))
1170 throw NotWFError (String.Format (
1171 "Nested entity was found between {0} and {1}",
1177 int len = value.Length;
1179 for (int i=0; i<len; i++) {
1180 switch (value [i]) {
1187 string name = value.Substring (start, i - start);
1188 if (name.Length == 0)
1189 throw NotWFError ("Entity reference name is missing.");
1190 if (name [0] == '#')
1191 break; // character reference
1192 if (XmlChar.GetPredefinedEntity (name) >= 0)
1193 break; // predefined reference
1195 this.ReferencingEntities.Add (name);
1196 DTDEntityDeclaration decl = Root.EntityDecls [name];
1198 if (decl.SystemId != null)
1199 hasExternalReference = true;
1201 decl.ScanEntityValue (refs);
1202 foreach (string str in decl.ReferencingEntities)
1203 ReferencingEntities.Add (str);
1205 value = value.Remove (start - 1, name.Length + 2);
1206 value = value.Insert (start - 1, decl.EntityValue);
1207 i -= name.Length + 1; // not +2, because of immediate i++ .
1215 Root.AddError (new XmlSchemaException ("Invalid reference character '&' is specified.",
1216 this.LineNumber, this.LinePosition, null, this.BaseURI, null));
1222 internal class DTDNotationDeclaration : DTDNode
1230 public string Name {
1231 get { return name; }
1232 set { name = value; }
1235 public string PublicId {
1236 get { return publicId; }
1237 set { publicId = value; }
1240 public string SystemId {
1241 get { return systemId; }
1242 set { systemId = value; }
1245 public string LocalName {
1246 get { return localName; }
1247 set { localName = value; }
1250 public string Prefix {
1251 get { return prefix; }
1252 set { prefix = value; }
1255 internal DTDNotationDeclaration (DTDObjectModel root)
1261 internal class DTDParameterEntityDeclarationCollection
1263 Hashtable peDecls = new Hashtable ();
1264 DTDObjectModel root;
1266 public DTDParameterEntityDeclarationCollection (DTDObjectModel root)
1271 public DTDParameterEntityDeclaration this [string name] {
1272 get { return peDecls [name] as DTDParameterEntityDeclaration; }
1275 public void Add (string name, DTDParameterEntityDeclaration decl)
1277 // PEDecl can be overriden.
1278 if (peDecls [name] != null)
1280 decl.SetRoot (root);
1281 peDecls.Add (name, decl);
1284 public ICollection Keys {
1285 get { return peDecls.Keys; }
1288 public ICollection Values {
1289 get { return peDecls.Values; }
1293 internal class DTDParameterEntityDeclaration : DTDEntityBase
1295 internal DTDParameterEntityDeclaration (DTDObjectModel root) : base (root)
1300 internal enum DTDContentOrderType
1307 internal enum DTDAttributeOccurenceType
1315 internal enum DTDOccurence