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
) {
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