| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642 |
- //
- // System.Xml.DTDReader
- //
- // Author:
- // Atsushi Enomoto ([email protected])
- //
- // (C)2003 Atsushi Enomoto
- // (C)2004 Novell Inc.
- //
- // FIXME:
- // When a parameter entity contains cp section, it should be closed
- // within that declaration.
- //
- // Resolution to external entities from different BaseURI fails (it is
- // the same as MS.NET 1.1, but should be fixed in the future).
- //
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Collections;
- using System.Globalization;
- using System.IO;
- using System.Text;
- using Mono.Xml;
- using System.Xml.Schema;
- namespace System.Xml
- {
- internal class DTDReader : IXmlLineInfo
- {
- private XmlParserInput currentInput;
- private Stack parserInputStack;
- private char [] nameBuffer;
- private int nameLength;
- private int nameCapacity;
- private const int initialNameCapacity = 256;
- private StringBuilder valueBuffer;
- private int currentLinkedNodeLineNumber;
- private int currentLinkedNodeLinePosition;
- // Parameter entity placeholder
- private int dtdIncludeSect;
- private bool normalization;
- private bool processingInternalSubset;
- string cachedPublicId;
- string cachedSystemId;
- DTDObjectModel DTD;
- #if DTD_HANDLE_EVENTS
- public event ValidationEventHandler ValidationEventHandler;
- #endif
- // .ctor()
- public DTDReader (DTDObjectModel dtd,
- int startLineNumber,
- int startLinePosition)
- {
- this.DTD = dtd;
- currentLinkedNodeLineNumber = startLineNumber;
- currentLinkedNodeLinePosition = startLinePosition;
- Init ();
- }
- // Properties
- public string BaseURI {
- get { return currentInput.BaseURI; }
- }
- public bool Normalization {
- get { return normalization; }
- set { normalization = value; }
- }
- public int LineNumber {
- get { return currentInput.LineNumber; }
- }
- public int LinePosition {
- get { return currentInput.LinePosition; }
- }
- public bool HasLineInfo ()
- {
- return true;
- }
- // Methods
- private XmlException NotWFError (string message)
- {
- return new XmlException (this as IXmlLineInfo, BaseURI, message);
- }
- private void Init ()
- {
- parserInputStack = new Stack ();
- nameBuffer = new char [initialNameCapacity];
- nameLength = 0;
- nameCapacity = initialNameCapacity;
-
- valueBuffer = new StringBuilder (512);
- }
- internal DTDObjectModel GenerateDTDObjectModel ()
- {
- // now compile DTD
- int originalParserDepth = parserInputStack.Count;
- bool more;
- if (DTD.InternalSubset != null && DTD.InternalSubset.Length > 0) {
- this.processingInternalSubset = true;
- XmlParserInput original = currentInput;
- currentInput = new XmlParserInput (
- new StringReader (DTD.InternalSubset),
- DTD.BaseURI,
- currentLinkedNodeLineNumber,
- currentLinkedNodeLinePosition);
- currentInput.InitialState = false;
- do {
- more = ProcessDTDSubset ();
- if (PeekChar () == -1 && parserInputStack.Count > 0)
- PopParserInput ();
- } while (more || parserInputStack.Count > originalParserDepth);
- if (dtdIncludeSect != 0)
- throw NotWFError ("INCLUDE section is not ended correctly.");
- currentInput = original;
- this.processingInternalSubset = false;
- }
- if (DTD.SystemId != null && DTD.SystemId != String.Empty && DTD.Resolver != null) {
- PushParserInput (DTD.SystemId);
- do {
- more = ProcessDTDSubset ();
- if (PeekChar () == -1 && parserInputStack.Count > 1)
- PopParserInput ();
- } while (more || parserInputStack.Count > originalParserDepth + 1);
- if (dtdIncludeSect != 0)
- throw NotWFError ("INCLUDE section is not ended correctly.");
- PopParserInput ();
- }
- ArrayList sc = new ArrayList ();
- // Entity recursion check.
- foreach (DTDEntityDeclaration ent in DTD.EntityDecls.Values) {
- if (ent.NotationName != null) {
- ent.ScanEntityValue (sc);
- sc.Clear ();
- }
- }
- // release unnecessary memory usage
- DTD.ExternalResources.Clear ();
- return DTD;
- }
- // Read any one of following:
- // elementdecl, AttlistDecl, EntityDecl, NotationDecl,
- // PI, Comment, Parameter Entity, or doctype termination char(']')
- //
- // Returns true if it may have any more contents, or false if not.
- private bool ProcessDTDSubset ()
- {
- SkipWhitespace ();
- int c2 = ReadChar ();
- switch(c2)
- {
- case -1:
- return false;
- case '%':
- // It affects on entity references' well-formedness
- if (this.processingInternalSubset)
- DTD.InternalSubsetHasPEReference = true;
- string peName = ReadName ();
- Expect (';');
- string peValue = GetPEValue (peName);
- if (peValue == String.Empty)
- break;
- currentInput.InsertParameterEntityBuffer (peValue);
- // int currentLine = currentInput.LineNumber;
- // int currentColumn = currentInput.LinePosition;
- while (currentInput.HasPEBuffer)
- ProcessDTDSubset ();
- SkipWhitespace ();
- // FIXME: Implement correct nest-level check.
- // Don't depend on lineinfo (might not be supplied)
- // if (currentInput.LineNumber != currentLine ||
- // currentInput.LinePosition != currentColumn)
- // throw NotWFError ("Incorrectly nested parameter entity.");
- break;
- case '<':
- int c = ReadChar ();
- switch(c)
- {
- case '?':
- // Only read, no store.
- ReadProcessingInstruction ();
- break;
- case '!':
- CompileDeclaration ();
- break;
- case -1:
- throw NotWFError ("Unexpected end of stream.");
- default:
- throw NotWFError ("Syntax Error after '<' character: " + (char) c);
- }
- break;
- case ']':
- if (dtdIncludeSect == 0)
- throw NotWFError ("Unbalanced end of INCLUDE/IGNORE section.");
- // End of inclusion
- Expect ("]>");
- dtdIncludeSect--;
- SkipWhitespace ();
- break;
- default:
- throw NotWFError (String.Format ("Syntax Error inside doctypedecl markup : {0}({1})", c2, (char) c2));
- }
- currentInput.InitialState = false;
- return true;
- }
- private void CompileDeclaration ()
- {
- switch(ReadChar ())
- {
- case '-':
- Expect ('-');
- // Only read, no store.
- ReadComment ();
- break;
- case 'E':
- switch(ReadChar ())
- {
- case 'N':
- Expect ("TITY");
- if (!SkipWhitespace ())
- throw NotWFError (
- "Whitespace is required after '<!ENTITY' in DTD entity declaration.");
- LOOPBACK:
- if (PeekChar () == '%') {
- ReadChar ();
- if (!SkipWhitespace ()) {
- ExpandPERef ();
- goto LOOPBACK;
- } else {
- // FIXME: Is this allowed? <!ENTITY % %name; ...>
- // (i.e. Can PE name be replaced by another PE?)
- TryExpandPERef ();
- if (XmlChar.IsNameChar (PeekChar ()))
- ReadParameterEntityDecl ();
- else
- throw NotWFError ("expected name character");
- }
- break;
- }
- DTDEntityDeclaration ent = ReadEntityDecl ();
- if (DTD.EntityDecls [ent.Name] == null)
- DTD.EntityDecls.Add (ent.Name, ent);
- break;
- case 'L':
- Expect ("EMENT");
- DTDElementDeclaration el = ReadElementDecl ();
- DTD.ElementDecls.Add (el.Name, el);
- break;
- default:
- throw NotWFError ("Syntax Error after '<!E' (ELEMENT or ENTITY must be found)");
- }
- break;
- case 'A':
- Expect ("TTLIST");
- DTDAttListDeclaration atl = ReadAttListDecl ();
- DTD.AttListDecls.Add (atl.Name, atl);
- break;
- case 'N':
- Expect ("OTATION");
- DTDNotationDeclaration not = ReadNotationDecl ();
- DTD.NotationDecls.Add (not.Name, not);
- break;
- case '[':
- // conditional sections
- SkipWhitespace ();
- TryExpandPERef ();
- Expect ('I');
- switch (ReadChar ()) {
- case 'N':
- Expect ("CLUDE");
- ExpectAfterWhitespace ('[');
- dtdIncludeSect++;
- break;
- case 'G':
- Expect ("NORE");
- ReadIgnoreSect ();
- break;
- }
- break;
- default:
- throw NotWFError ("Syntax Error after '<!' characters.");
- }
- }
- private void ReadIgnoreSect ()
- {
- ExpectAfterWhitespace ('[');
- int dtdIgnoreSect = 1;
- while (dtdIgnoreSect > 0) {
- switch (ReadChar ()) {
- case -1:
- throw NotWFError ("Unexpected IGNORE section end.");
- case '<':
- if (PeekChar () != '!')
- break;
- ReadChar ();
- if (PeekChar () != '[')
- break;
- ReadChar ();
- dtdIgnoreSect++;
- break;
- case ']':
- if (PeekChar () != ']')
- break;
- ReadChar ();
- if (PeekChar () != '>')
- break;
- ReadChar ();
- dtdIgnoreSect--;
- break;
- }
- }
- if (dtdIgnoreSect != 0)
- throw NotWFError ("IGNORE section is not ended correctly.");
- }
- // The reader is positioned on the head of the name.
- private DTDElementDeclaration ReadElementDecl ()
- {
- DTDElementDeclaration decl = new DTDElementDeclaration (DTD);
- decl.IsInternalSubset = this.processingInternalSubset;
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required between '<!ELEMENT' and name in DTD element declaration.");
- TryExpandPERef ();
- decl.Name = ReadName ();
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required between name and content in DTD element declaration.");
- TryExpandPERef ();
- ReadContentSpec (decl);
- SkipWhitespace ();
- // This expanding is only allowed as a non-validating parser.
- TryExpandPERef ();
- Expect ('>');
- return decl;
- }
- // read 'children'(BNF) of contentspec
- private void ReadContentSpec (DTDElementDeclaration decl)
- {
- TryExpandPERef ();
- switch(ReadChar ())
- {
- case 'E':
- decl.IsEmpty = true;
- Expect ("MPTY");
- break;
- case 'A':
- decl.IsAny = true;
- Expect ("NY");
- break;
- case '(':
- DTDContentModel model = decl.ContentModel;
- SkipWhitespace ();
- TryExpandPERef ();
- if(PeekChar () == '#') {
- // Mixed Contents. "#PCDATA" must appear first.
- decl.IsMixedContent = true;
- model.Occurence = DTDOccurence.ZeroOrMore;
- model.OrderType = DTDContentOrderType.Or;
- Expect ("#PCDATA");
- SkipWhitespace ();
- TryExpandPERef ();
- while(PeekChar () != ')') {
- SkipWhitespace ();
- if (PeekChar () == '%') {
- TryExpandPERef ();
- continue;
- }
- Expect('|');
- SkipWhitespace ();
- TryExpandPERef ();
- DTDContentModel elem = new DTDContentModel (DTD, decl.Name);
- // elem.LineNumber = currentInput.LineNumber;
- // elem.LinePosition = currentInput.LinePosition;
- elem.ElementName = ReadName ();
- this.AddContentModel (model.ChildModels, elem);
- SkipWhitespace ();
- TryExpandPERef ();
- }
- Expect (')');
- if (model.ChildModels.Count > 0)
- Expect ('*');
- else if (PeekChar () == '*')
- Expect ('*');
- } else {
- // Non-Mixed Contents
- model.ChildModels.Add (ReadCP (decl));
- SkipWhitespace ();
- do { // copied from ReadCP() ...;-)
- if (PeekChar () == '%') {
- TryExpandPERef ();
- continue;
- }
- if(PeekChar ()=='|') {
- // CPType=Or
- if (model.OrderType == DTDContentOrderType.Seq)
- throw NotWFError ("Inconsistent choice markup in sequence cp.");
- model.OrderType = DTDContentOrderType.Or;
- ReadChar ();
- SkipWhitespace ();
- AddContentModel (model.ChildModels, ReadCP (decl));
- SkipWhitespace ();
- }
- else if(PeekChar () == ',')
- {
- // CPType=Seq
- if (model.OrderType == DTDContentOrderType.Or)
- throw NotWFError ("Inconsistent sequence markup in choice cp.");
- model.OrderType = DTDContentOrderType.Seq;
- ReadChar ();
- SkipWhitespace ();
- model.ChildModels.Add (ReadCP (decl));
- SkipWhitespace ();
- }
- else
- break;
- }
- while(true);
- Expect (')');
- switch(PeekChar ())
- {
- case '?':
- model.Occurence = DTDOccurence.Optional;
- ReadChar ();
- break;
- case '*':
- model.Occurence = DTDOccurence.ZeroOrMore;
- ReadChar ();
- break;
- case '+':
- model.Occurence = DTDOccurence.OneOrMore;
- ReadChar ();
- break;
- }
- SkipWhitespace ();
- }
- SkipWhitespace ();
- break;
- default:
- throw NotWFError ("ContentSpec is missing.");
- }
- }
- // Read 'cp' (BNF) of contentdecl (BNF)
- private DTDContentModel ReadCP (DTDElementDeclaration elem)
- {
- DTDContentModel model = null;
- TryExpandPERef ();
- if(PeekChar () == '(') {
- model = new DTDContentModel (DTD, elem.Name);
- ReadChar ();
- SkipWhitespace ();
- model.ChildModels.Add (ReadCP (elem));
- SkipWhitespace ();
- do {
- if (PeekChar () == '%') {
- TryExpandPERef ();
- continue;
- }
- if(PeekChar ()=='|') {
- // CPType=Or
- if (model.OrderType == DTDContentOrderType.Seq)
- throw NotWFError ("Inconsistent choice markup in sequence cp.");
- model.OrderType = DTDContentOrderType.Or;
- ReadChar ();
- SkipWhitespace ();
- AddContentModel (model.ChildModels, ReadCP (elem));
- SkipWhitespace ();
- }
- else if(PeekChar () == ',') {
- // CPType=Seq
- if (model.OrderType == DTDContentOrderType.Or)
- throw NotWFError ("Inconsistent sequence markup in choice cp.");
- model.OrderType = DTDContentOrderType.Seq;
- ReadChar ();
- SkipWhitespace ();
- model.ChildModels.Add (ReadCP (elem));
- SkipWhitespace ();
- }
- else
- break;
- }
- while(true);
- ExpectAfterWhitespace (')');
- }
- else {
- TryExpandPERef ();
- model = new DTDContentModel (DTD, elem.Name);
- model.ElementName = ReadName ();
- }
- switch(PeekChar ()) {
- case '?':
- model.Occurence = DTDOccurence.Optional;
- ReadChar ();
- break;
- case '*':
- model.Occurence = DTDOccurence.ZeroOrMore;
- ReadChar ();
- break;
- case '+':
- model.Occurence = DTDOccurence.OneOrMore;
- ReadChar ();
- break;
- }
- return model;
- }
- private void AddContentModel (DTDContentModelCollection cmc, DTDContentModel cm)
- {
- if (cm.ElementName != null) {
- for (int i = 0; i < cmc.Count; i++) {
- if (cmc [i].ElementName == cm.ElementName) {
- HandleError (new XmlSchemaException ("Element content must be unique inside mixed content model.",
- this.LineNumber,
- this.LinePosition,
- null,
- this.BaseURI,
- null));
- return;
- }
- }
- }
- cmc.Add (cm);
- }
- // The reader is positioned on the first name char.
- private void ReadParameterEntityDecl ()
- {
- DTDParameterEntityDeclaration decl =
- new DTDParameterEntityDeclaration (DTD);
- decl.BaseURI = BaseURI;
- decl.Name = ReadName ();
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required after name in DTD parameter entity declaration.");
- if (PeekChar () == 'S' || PeekChar () == 'P') {
- // read publicId/systemId
- ReadExternalID ();
- decl.PublicId = cachedPublicId;
- decl.SystemId = cachedSystemId;
- SkipWhitespace ();
- decl.Resolve (this.DTD.Resolver);
- ResolveExternalEntityReplacementText (decl);
- } else {
- TryExpandPERef ();
- int quoteChar = ReadChar ();
- if (quoteChar != '\'' && quoteChar != '"')
- throw NotWFError ("quotation char was expected.");
- ClearValueBuffer ();
- bool loop = true;
- while (loop) {
- int c = ReadChar ();
- switch (c) {
- case -1:
- throw NotWFError ("unexpected end of stream in entity value definition.");
- case '"':
- if (quoteChar == '"')
- loop = false;
- else
- AppendValueChar ('"');
- break;
- case '\'':
- if (quoteChar == '\'')
- loop = false;
- else
- AppendValueChar ('\'');
- break;
- default:
- if (XmlChar.IsInvalid (c))
- throw NotWFError ("Invalid character was used to define parameter entity.");
- AppendValueChar (c);
- break;
- }
- }
- decl.LiteralEntityValue = CreateValueString ();
- ClearValueBuffer ();
- ResolveInternalEntityReplacementText (decl);
- }
- ExpectAfterWhitespace ('>');
- if (DTD.PEDecls [decl.Name] == null) {
- DTD.PEDecls.Add (decl.Name, decl);
- }
- }
- private void ResolveExternalEntityReplacementText (DTDEntityBase decl)
- {
- if (decl.LiteralEntityValue.StartsWith ("<?xml")) {
- XmlTextReader xtr = new XmlTextReader (decl.LiteralEntityValue, XmlNodeType.Element, null);
- if (decl is DTDEntityDeclaration) {
- // GE - also checked as valid contents
- StringBuilder sb = new StringBuilder ();
- xtr.Normalization = this.Normalization;
- xtr.Read ();
- while (!xtr.EOF)
- sb.Append (xtr.ReadOuterXml ());
- decl.ReplacementText = sb.ToString ();
- }
- else
- // PE
- decl.ReplacementText = xtr.GetRemainder ().ReadToEnd ();
- }
- else
- decl.ReplacementText = decl.LiteralEntityValue;
- }
- private void ResolveInternalEntityReplacementText (DTDEntityBase decl)
- {
- string value = decl.LiteralEntityValue;
- int len = value.Length;
- ClearValueBuffer ();
- for (int i = 0; i < len; i++) {
- int ch = value [i];
- int end = 0;
- string name;
- switch (ch) {
- case '&':
- i++;
- end = value.IndexOf (';', i);
- if (end < i + 1)
- throw new XmlException (decl, decl.BaseURI, "Invalid reference markup.");
- // expand charref
- if (value [i] == '#') {
- i++;
- ch = GetCharacterReference (decl, value, ref i, end);
- if (XmlChar.IsInvalid (ch))
- throw NotWFError ("Invalid character was used to define parameter entity.");
- } else {
- name = value.Substring (i, end - i);
- // don't expand "general" entity.
- AppendValueChar ('&');
- valueBuffer.Append (name);
- AppendValueChar (';');
- i = end;
- break;
- }
- if (XmlChar.IsInvalid (ch))
- throw new XmlException (decl, decl.BaseURI, "Invalid character was found in the entity declaration.");
- AppendValueChar (ch);
- break;
- case '%':
- i++;
- end = value.IndexOf (';', i);
- if (end < i + 1)
- throw new XmlException (decl, decl.BaseURI, "Invalid reference markup.");
- name = value.Substring (i, end - i);
- valueBuffer.Append (GetPEValue (name));
- i = end;
- break;
- default:
- AppendValueChar (ch);
- break;
- }
- }
- decl.ReplacementText = CreateValueString ();
- if (decl is DTDEntityDeclaration) {
- // GE - also checked as valid contents
- XmlTextReader xtr = new XmlTextReader (decl.ReplacementText, XmlNodeType.Element, null);
- StringBuilder sb = new StringBuilder ();
- xtr.Normalization = this.Normalization;
- xtr.Read ();
- while (!xtr.EOF)
- sb.Append (xtr.ReadOuterXml ());
- decl.ReplacementText = sb.ToString ();
- }
- ClearValueBuffer ();
- }
- private int GetCharacterReference (DTDEntityBase li, string value, ref int index, int end)
- {
- int ret = 0;
- if (value [index] == 'x') {
- try {
- ret = int.Parse (value.Substring (index + 1, end - index - 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
- } catch (FormatException) {
- throw new XmlException (li, li.BaseURI, "Invalid number for a character reference.");
- }
- } else {
- try {
- ret = int.Parse (value.Substring (index, end - index), CultureInfo.InvariantCulture);
- } catch (FormatException) {
- throw new XmlException (li, li.BaseURI, "Invalid number for a character reference.");
- }
- }
- index = end;
- return ret;
- }
- private string GetPEValue (string peName)
- {
- DTDParameterEntityDeclaration peDecl =
- DTD.PEDecls [peName] as DTDParameterEntityDeclaration;
- if (peDecl != null) {
- if (peDecl.IsInternalSubset)
- throw NotWFError ("Parameter entity is not allowed in internal subset entity '" + peName + "'");
- return peDecl.ReplacementText;
- }
- // See XML 1.0 section 4.1 for both WFC and VC.
- if ((DTD.SystemId == null && !DTD.InternalSubsetHasPEReference) || DTD.IsStandalone)
- throw NotWFError (String.Format ("Parameter entity '{0}' not found.",peName));
- HandleError (new XmlSchemaException (
- "Parameter entity " + peName + " not found.", null));
- return "";
- }
- private bool TryExpandPERef ()
- {
- if (PeekChar () != '%')
- return false;
- while (PeekChar () == '%') {
- TryExpandPERefSpaceKeep ();
- SkipWhitespace ();
- }
- return true;
- }
- // Tries to expand parameter entities, but it should not skip spaces
- private bool TryExpandPERefSpaceKeep ()
- {
- if (PeekChar () == '%') {
- if (this.processingInternalSubset)
- throw NotWFError ("Parameter entity reference is not allowed inside internal subset.");
- ReadChar ();
- ExpandPERef ();
- return true;
- }
- else
- return false;
- }
- // reader is positioned after '%'
- private void ExpandPERef ()
- {
- string peName = ReadName ();
- Expect (';');
- DTDParameterEntityDeclaration peDecl =
- DTD.PEDecls [peName] as DTDParameterEntityDeclaration;
- if (peDecl == null) {
- HandleError (new XmlSchemaException ("Parameter entity " + peName + " not found.", null));
- return; // do nothing
- }
- // FIXME: These leading/trailing ' ' is anyways supplied inside this method!
- // currentInput.InsertParameterEntityBuffer (" " + peDecl.ReplacementText + " ");
- currentInput.InsertParameterEntityBuffer (peDecl.ReplacementText);
- }
- // The reader is positioned on the head of the name.
- private DTDEntityDeclaration ReadEntityDecl ()
- {
- DTDEntityDeclaration decl = new DTDEntityDeclaration (DTD);
- decl.IsInternalSubset = this.processingInternalSubset;
- TryExpandPERef ();
- decl.Name = ReadName ();
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required between name and content in DTD entity declaration.");
- TryExpandPERef ();
- if (PeekChar () == 'S' || PeekChar () == 'P') {
- // external entity
- ReadExternalID ();
- decl.PublicId = cachedPublicId;
- decl.SystemId = cachedSystemId;
- if (SkipWhitespace ()) {
- if (PeekChar () == 'N') {
- // NDataDecl
- Expect ("NDATA");
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required after NDATA.");
- decl.NotationName = ReadName (); // ndata_name
- }
- }
- if (decl.NotationName == null) {
- decl.Resolve (this.DTD.Resolver);
- ResolveExternalEntityReplacementText (decl);
- } else {
- // Unparsed entity.
- decl.LiteralEntityValue = String.Empty;
- decl.ReplacementText = String.Empty;
- }
- }
- else {
- // literal entity
- ReadEntityValueDecl (decl);
- ResolveInternalEntityReplacementText (decl);
- }
- SkipWhitespace ();
- // This expanding is only allowed as a non-validating parser.
- TryExpandPERef ();
- Expect ('>');
- return decl;
- }
- private void ReadEntityValueDecl (DTDEntityDeclaration decl)
- {
- SkipWhitespace ();
- // quotation char will be finally removed on unescaping
- int quoteChar = ReadChar ();
- if (quoteChar != '\'' && quoteChar != '"')
- throw NotWFError ("quotation char was expected.");
- ClearValueBuffer ();
- while (PeekChar () != quoteChar) {
- int ch = ReadChar ();
- switch (ch) {
- case '%':
- string name = ReadName ();
- Expect (';');
- if (decl.IsInternalSubset)
- throw NotWFError (String.Format ("Parameter entity is not allowed in internal subset entity '{0}'", name));
- valueBuffer.Append (GetPEValue (name));
- break;
- case -1:
- throw NotWFError ("unexpected end of stream.");
- default:
- if (this.normalization && XmlChar.IsInvalid (ch))
- throw NotWFError ("Invalid character was found in the entity declaration.");
- AppendValueChar (ch);
- break;
- }
- }
- // string value = Dereference (CreateValueString (), false);
- string value = CreateValueString ();
- ClearValueBuffer ();
- Expect (quoteChar);
- decl.LiteralEntityValue = value;
- }
- private DTDAttListDeclaration ReadAttListDecl ()
- {
- TryExpandPERefSpaceKeep ();
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required between ATTLIST and name in DTD attlist declaration.");
- TryExpandPERef ();
- string name = ReadName (); // target element name
- DTDAttListDeclaration decl =
- DTD.AttListDecls [name] as DTDAttListDeclaration;
- if (decl == null)
- decl = new DTDAttListDeclaration (DTD);
- decl.IsInternalSubset = this.processingInternalSubset;
- decl.Name = name;
- if (!SkipWhitespace ())
- if (PeekChar () != '>')
- throw NotWFError ("Whitespace is required between name and content in non-empty DTD attlist declaration.");
- TryExpandPERef ();
- while (XmlChar.IsNameChar (PeekChar ())) {
- DTDAttributeDefinition def = ReadAttributeDefinition ();
- // There must not be two or more ID attributes.
- if (def.Datatype.TokenizedType == XmlTokenizedType.ID) {
- for (int i = 0; i < decl.Definitions.Count; i++) {
- DTDAttributeDefinition d = decl [i];
- if (d.Datatype.TokenizedType == XmlTokenizedType.ID) {
- HandleError (new XmlSchemaException ("AttList declaration must not contain two or more ID attributes.",
- def.LineNumber, def.LinePosition, null, def.BaseURI, null));
- break;
- }
- }
- }
- if (decl [def.Name] == null)
- decl.Add (def);
- SkipWhitespace ();
- TryExpandPERef ();
- }
- SkipWhitespace ();
- // This expanding is only allowed as a non-validating parser.
- TryExpandPERef ();
- Expect ('>');
- return decl;
- }
- private DTDAttributeDefinition ReadAttributeDefinition ()
- {
- DTDAttributeDefinition def = new DTDAttributeDefinition (DTD);
- def.IsInternalSubset = this.processingInternalSubset;
- // attr_name
- TryExpandPERef ();
- def.Name = ReadName ();
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required between name and content in DTD attribute definition.");
- // attr_value
- TryExpandPERef ();
- switch(PeekChar ()) {
- case 'C': // CDATA
- Expect ("CDATA");
- def.Datatype = XmlSchemaDatatype.FromName ("normalizedString", XmlSchema.Namespace);
- break;
- case 'I': // ID, IDREF, IDREFS
- Expect ("ID");
- if(PeekChar () == 'R') {
- Expect ("REF");
- if(PeekChar () == 'S') {
- // IDREFS
- ReadChar ();
- def.Datatype = XmlSchemaDatatype.FromName ("IDREFS", XmlSchema.Namespace);
- }
- else // IDREF
- def.Datatype = XmlSchemaDatatype.FromName ("IDREF", XmlSchema.Namespace);
- }
- else // ID
- def.Datatype = XmlSchemaDatatype.FromName ("ID", XmlSchema.Namespace);
- break;
- case 'E': // ENTITY, ENTITIES
- Expect ("ENTIT");
- switch(ReadChar ()) {
- case 'Y': // ENTITY
- def.Datatype = XmlSchemaDatatype.FromName ("ENTITY", XmlSchema.Namespace);
- break;
- case 'I': // ENTITIES
- Expect ("ES");
- def.Datatype = XmlSchemaDatatype.FromName ("ENTITIES", XmlSchema.Namespace);
- break;
- }
- break;
- case 'N': // NMTOKEN, NMTOKENS, NOTATION
- ReadChar ();
- switch(PeekChar ()) {
- case 'M':
- Expect ("MTOKEN");
- if(PeekChar ()=='S') { // NMTOKENS
- ReadChar ();
- def.Datatype = XmlSchemaDatatype.FromName ("NMTOKENS", XmlSchema.Namespace);
- }
- else // NMTOKEN
- def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN", XmlSchema.Namespace);
- break;
- case 'O':
- Expect ("OTATION");
- def.Datatype = XmlSchemaDatatype.FromName ("NOTATION", XmlSchema.Namespace);
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required between name and content in DTD attribute definition.");
- Expect ('(');
- SkipWhitespace ();
- def.EnumeratedNotations.Add (ReadName ()); // notation name
- SkipWhitespace ();
- while(PeekChar () == '|') {
- ReadChar ();
- SkipWhitespace ();
- def.EnumeratedNotations.Add (ReadName ()); // notation name
- SkipWhitespace ();
- }
- Expect (')');
- break;
- default:
- throw NotWFError ("attribute declaration syntax error.");
- }
- break;
- default: // Enumerated Values
- def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN", XmlSchema.Namespace);
- TryExpandPERef ();
- Expect ('(');
- SkipWhitespace ();
- def.EnumeratedAttributeDeclaration.Add (
- def.Datatype.Normalize (ReadNmToken ())); // enum value
- SkipWhitespace ();
- while(PeekChar () == '|') {
- ReadChar ();
- SkipWhitespace ();
- def.EnumeratedAttributeDeclaration.Add (
- def.Datatype.Normalize (ReadNmToken ())); // enum value
- SkipWhitespace ();
- }
- Expect (')');
- break;
- }
- TryExpandPERefSpaceKeep ();
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required between type and occurence in DTD attribute definition.");
- // def_value
- ReadAttributeDefaultValue (def);
- return def;
- }
- private void ReadAttributeDefaultValue (DTDAttributeDefinition def)
- {
- if(PeekChar () == '#')
- {
- ReadChar ();
- switch(PeekChar ())
- {
- case 'R':
- Expect ("REQUIRED");
- def.OccurenceType = DTDAttributeOccurenceType.Required;
- break;
- case 'I':
- Expect ("IMPLIED");
- def.OccurenceType = DTDAttributeOccurenceType.Optional;
- break;
- case 'F':
- Expect ("FIXED");
- def.OccurenceType = DTDAttributeOccurenceType.Fixed;
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required between FIXED and actual value in DTD attribute definition.");
- def.UnresolvedDefaultValue = ReadDefaultAttribute ();
- break;
- }
- } else {
- // one of the enumerated value
- SkipWhitespace ();
- TryExpandPERef ();
- def.UnresolvedDefaultValue = ReadDefaultAttribute ();
- }
- // VC: If default value exists, it should be valid.
- if (def.DefaultValue != null) {
- string normalized = def.Datatype.Normalize (def.DefaultValue);
- bool breakup = false;
- object parsed = null;
- // enumeration validity
- if (def.EnumeratedAttributeDeclaration.Count > 0) {
- if (!def.EnumeratedAttributeDeclaration.Contains (normalized)) {
- HandleError (new XmlSchemaException ("Default value is not one of the enumerated values.",
- def.LineNumber, def.LinePosition, null, def.BaseURI, null));
- breakup = true;
- }
- }
- if (def.EnumeratedNotations.Count > 0) {
- if (!def.EnumeratedNotations.Contains (normalized)) {
- HandleError (new XmlSchemaException ("Default value is not one of the enumerated notation values.",
- def.LineNumber, def.LinePosition, null, def.BaseURI, null));
- breakup = true;
- }
- }
- // type based validity
- if (!breakup) {
- try {
- parsed = def.Datatype.ParseValue (normalized, DTD.NameTable, null);
- } catch (Exception ex) { // FIXME: (wishlist) bad catch ;-(
- HandleError (new XmlSchemaException ("Invalid default value for ENTITY type.",
- def.LineNumber, def.LinePosition, null, def.BaseURI, ex));
- breakup = true;
- }
- }
- if (!breakup) {
- switch (def.Datatype.TokenizedType) {
- case XmlTokenizedType.ENTITY:
- if (DTD.EntityDecls [normalized] == null)
- HandleError (new XmlSchemaException ("Specified entity declaration used by default attribute value was not found.",
- def.LineNumber, def.LinePosition, null, def.BaseURI, null));
- break;
- case XmlTokenizedType.ENTITIES:
- string [] entities = parsed as string [];
- for (int i = 0; i < entities.Length; i++) {
- string entity = entities [i];
- if (DTD.EntityDecls [entity] == null)
- HandleError (new XmlSchemaException ("Specified entity declaration used by default attribute value was not found.",
- def.LineNumber, def.LinePosition, null, def.BaseURI, null));
- }
- break;
- }
- }
- }
- // Extra ID attribute validity check.
- if (def.Datatype != null && def.Datatype.TokenizedType == XmlTokenizedType.ID)
- if (def.UnresolvedDefaultValue != null)
- HandleError (new XmlSchemaException ("ID attribute must not have fixed value constraint.",
- def.LineNumber, def.LinePosition, null, def.BaseURI, null));
- }
- private DTDNotationDeclaration ReadNotationDecl()
- {
- DTDNotationDeclaration decl = new DTDNotationDeclaration (DTD);
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required between NOTATION and name in DTD notation declaration.");
- TryExpandPERef ();
- decl.Name = ReadName (); // notation name
- /*
- if (namespaces) { // copy from SetProperties ;-)
- int indexOfColon = decl.Name.IndexOf (':');
- if (indexOfColon == -1) {
- decl.Prefix = String.Empty;
- decl.LocalName = decl.Name;
- } else {
- decl.Prefix = decl.Name.Substring (0, indexOfColon);
- decl.LocalName = decl.Name.Substring (indexOfColon + 1);
- }
- } else {
- */
- decl.Prefix = String.Empty;
- decl.LocalName = decl.Name;
- // }
- SkipWhitespace ();
- if(PeekChar () == 'P') {
- decl.PublicId = ReadPubidLiteral ();
- bool wsSkipped = SkipWhitespace ();
- if (PeekChar () == '\'' || PeekChar () == '"') {
- if (!wsSkipped)
- throw NotWFError ("Whitespace is required between public id and system id.");
- decl.SystemId = ReadSystemLiteral (false);
- SkipWhitespace ();
- }
- } else if(PeekChar () == 'S') {
- decl.SystemId = ReadSystemLiteral (true);
- SkipWhitespace ();
- }
- if(decl.PublicId == null && decl.SystemId == null)
- throw NotWFError ("public or system declaration required for \"NOTATION\" declaration.");
- // This expanding is only allowed as a non-validating parser.
- TryExpandPERef ();
- Expect ('>');
- return decl;
- }
- private void ReadExternalID () {
- switch (PeekChar ()) {
- case 'S':
- cachedSystemId = ReadSystemLiteral (true);
- break;
- case 'P':
- cachedPublicId = ReadPubidLiteral ();
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required between PUBLIC id and SYSTEM id.");
- cachedSystemId = ReadSystemLiteral (false);
- break;
- }
- }
- // The reader is positioned on the first 'S' of "SYSTEM".
- private string ReadSystemLiteral (bool expectSYSTEM)
- {
- if(expectSYSTEM) {
- Expect ("SYSTEM");
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required after 'SYSTEM'.");
- }
- else
- SkipWhitespace ();
- int quoteChar = ReadChar (); // apos or quot
- int c = 0;
- ClearValueBuffer ();
- while (c != quoteChar) {
- c = ReadChar ();
- if (c < 0)
- throw NotWFError ("Unexpected end of stream in ExternalID.");
- if (c != quoteChar)
- AppendValueChar (c);
- }
- return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
- }
- private string ReadPubidLiteral()
- {
- Expect ("PUBLIC");
- if (!SkipWhitespace ())
- throw NotWFError ("Whitespace is required after 'PUBLIC'.");
- int quoteChar = ReadChar ();
- int c = 0;
- ClearValueBuffer ();
- while(c != quoteChar)
- {
- c = ReadChar ();
- if(c < 0) throw NotWFError ("Unexpected end of stream in ExternalID.");
- if(c != quoteChar && !XmlChar.IsPubidChar (c))
- throw NotWFError (String.Format ("character '{0}' not allowed for PUBLIC ID", (char) c));
- if (c != quoteChar)
- AppendValueChar (c);
- }
- return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
- }
- // The reader is positioned on the first character
- // of the name.
- internal string ReadName ()
- {
- return ReadNameOrNmToken(false);
- }
- // The reader is positioned on the first character
- // of the name.
- private string ReadNmToken ()
- {
- return ReadNameOrNmToken(true);
- }
- private string ReadNameOrNmToken(bool isNameToken)
- {
- int ch = PeekChar ();
- if(isNameToken) {
- if (!XmlChar.IsNameChar (ch))
- throw NotWFError (String.Format ("a nmtoken did not start with a legal character {0} ({1})", ch, (char) ch));
- }
- else {
- if (!XmlChar.IsFirstNameChar (ch))
- throw NotWFError (String.Format ("a name did not start with a legal character {0} ({1})", ch, (char) ch));
- }
- nameLength = 0;
- AppendNameChar (ReadChar ());
- while (XmlChar.IsNameChar (PeekChar ())) {
- AppendNameChar (ReadChar ());
- }
- return CreateNameString ();
- }
- // Read the next character and compare it against the
- // specified character.
- private void Expect (int expected)
- {
- int ch = ReadChar ();
- if (ch != expected) {
- throw NotWFError (String.Format (CultureInfo.InvariantCulture,
- "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
- (char) expected,
- expected,
- (char) ch,
- ch));
- }
- }
- private void Expect (string expected)
- {
- int len = expected.Length;
- for (int i=0; i< len; i++)
- Expect (expected [i]);
- }
- private void ExpectAfterWhitespace (char c)
- {
- while (true) {
- int i = ReadChar ();
- if (XmlChar.IsWhitespace (i))
- continue;
- if (c != i)
- throw NotWFError (String.Format (CultureInfo.InvariantCulture, "Expected {0} but found {1} [{2}].", c, (char) i, i));
- break;
- }
- }
- // Does not consume the first non-whitespace character.
- private bool SkipWhitespace ()
- {
- bool skipped = XmlChar.IsWhitespace (PeekChar ());
- while (XmlChar.IsWhitespace (PeekChar ()))
- ReadChar ();
- return skipped;
- }
- private int PeekChar ()
- {
- return currentInput.PeekChar ();
- }
- private int ReadChar ()
- {
- return currentInput.ReadChar ();
- }
- private string ExpandSurrogateChar (int ch)
- {
- if (ch < Char.MaxValue)
- return ((char) ch).ToString ();
- else {
- char [] tmp = new char [] {(char) (ch / 0x10000 + 0xD800 - 1), (char) (ch % 0x10000 + 0xDC00)};
- return new string (tmp);
- }
- }
- // The reader is positioned on the first character after
- // the leading '<!--'.
- private void ReadComment ()
- {
- currentInput.InitialState = false;
- while (PeekChar () != -1) {
- int ch = ReadChar ();
- if (ch == '-' && PeekChar () == '-') {
- ReadChar ();
- if (PeekChar () != '>')
- throw NotWFError ("comments cannot contain '--'");
- ReadChar ();
- break;
- }
- if (XmlChar.IsInvalid (ch))
- throw NotWFError ("Not allowed character was found.");
- }
- }
- // The reader is positioned on the first character
- // of the target.
- //
- // It may be xml declaration or processing instruction.
- private void ReadProcessingInstruction ()
- {
- string target = ReadName ();
- if (target == "xml") {
- ReadTextDeclaration ();
- return;
- } else if (String.Compare (target, "xml", true, CultureInfo.InvariantCulture) == 0)
- throw NotWFError ("Not allowed processing instruction name which starts with 'X', 'M', 'L' was found.");
- currentInput.InitialState = false;
- if (!SkipWhitespace ())
- if (PeekChar () != '?')
- throw NotWFError ("Invalid processing instruction name was found.");
- while (PeekChar () != -1) {
- int ch = ReadChar ();
- if (ch == '?' && PeekChar () == '>') {
- ReadChar ();
- break;
- }
- }
- }
- // The reader is positioned after "<?xml "
- private void ReadTextDeclaration ()
- {
- if (!currentInput.InitialState)
- throw NotWFError ("Text declaration cannot appear in this state.");
- currentInput.InitialState = false;
- SkipWhitespace ();
- // version decl
- if (PeekChar () == 'v') {
- Expect ("version");
- ExpectAfterWhitespace ('=');
- SkipWhitespace ();
- int quoteChar = ReadChar ();
- char [] expect1_0 = new char [3];
- int versionLength = 0;
- switch (quoteChar) {
- case '\'':
- case '"':
- while (PeekChar () != quoteChar) {
- if (PeekChar () == -1)
- throw NotWFError ("Invalid version declaration inside text declaration.");
- else if (versionLength == 3)
- throw NotWFError ("Invalid version number inside text declaration.");
- else {
- expect1_0 [versionLength] = (char) ReadChar ();
- versionLength++;
- if (versionLength == 3 && new String (expect1_0) != "1.0")
- throw NotWFError ("Invalid version number inside text declaration.");
- }
- }
- ReadChar ();
- SkipWhitespace ();
- break;
- default:
- throw NotWFError ("Invalid version declaration inside text declaration.");
- }
- }
- if (PeekChar () == 'e') {
- Expect ("encoding");
- ExpectAfterWhitespace ('=');
- SkipWhitespace ();
- int quoteChar = ReadChar ();
- switch (quoteChar) {
- case '\'':
- case '"':
- while (PeekChar () != quoteChar)
- if (ReadChar () == -1)
- throw NotWFError ("Invalid encoding declaration inside text declaration.");
- ReadChar ();
- SkipWhitespace ();
- break;
- default:
- throw NotWFError ("Invalid encoding declaration inside text declaration.");
- }
- // Encoding value should be checked inside XmlInputStream.
- }
- else
- throw NotWFError ("Encoding declaration is mandatory in text declaration.");
- Expect ("?>");
- }
- // Note that now this method behaves differently from
- // XmlTextReader's one. It calles AppendValueChar() internally.
- private int ReadCharacterReference ()
- {
- int value = 0;
- if (PeekChar () == 'x') {
- ReadChar ();
- while (PeekChar () != ';' && PeekChar () != -1) {
- int ch = ReadChar ();
- if (ch >= '0' && ch <= '9')
- value = (value << 4) + ch - '0';
- else if (ch >= 'A' && ch <= 'F')
- value = (value << 4) + ch - 'A' + 10;
- else if (ch >= 'a' && ch <= 'f')
- value = (value << 4) + ch - 'a' + 10;
- else
- throw NotWFError (String.Format (
- CultureInfo.InvariantCulture,
- "invalid hexadecimal digit: {0} (#x{1:X})",
- (char) ch,
- ch));
- }
- } else {
- while (PeekChar () != ';' && PeekChar () != -1) {
- int ch = ReadChar ();
- if (ch >= '0' && ch <= '9')
- value = value * 10 + ch - '0';
- else
- throw NotWFError (String.Format (
- CultureInfo.InvariantCulture,
- "invalid decimal digit: {0} (#x{1:X})",
- (char) ch,
- ch));
- }
- }
- ReadChar (); // ';'
- // There is no way to save surrogate pairs...
- if (XmlChar.IsInvalid (value))
- throw NotWFError ("Referenced character was not allowed in XML.");
- AppendValueChar (value);
- return value;
- }
- private void AppendNameChar (int ch)
- {
- CheckNameCapacity ();
- if (ch < Char.MaxValue)
- nameBuffer [nameLength++] = (char) ch;
- else {
- nameBuffer [nameLength++] = (char) (ch / 0x10000 + 0xD800 - 1);
- CheckNameCapacity ();
- nameBuffer [nameLength++] = (char) (ch % 0x10000 + 0xDC00);
- }
- }
- private void CheckNameCapacity ()
- {
- if (nameLength == nameCapacity) {
- nameCapacity = nameCapacity * 2;
- char [] oldNameBuffer = nameBuffer;
- nameBuffer = new char [nameCapacity];
- Array.Copy (oldNameBuffer, nameBuffer, nameLength);
- }
- }
- private string CreateNameString ()
- {
- return DTD.NameTable.Add (nameBuffer, 0, nameLength);
- }
- private void AppendValueChar (int ch)
- {
- if (ch < Char.MaxValue)
- valueBuffer.Append ((char) ch);
- else
- valueBuffer.Append (ExpandSurrogateChar (ch));
- }
- private string CreateValueString ()
- {
- return valueBuffer.ToString ();
- }
-
- private void ClearValueBuffer ()
- {
- valueBuffer.Length = 0;
- }
- // The reader is positioned on the quote character.
- // *Keeps quote char* to value to get_QuoteChar() correctly.
- private string ReadDefaultAttribute ()
- {
- ClearValueBuffer ();
- TryExpandPERef ();
- int quoteChar = ReadChar ();
- if (quoteChar != '\'' && quoteChar != '\"')
- throw NotWFError ("an attribute value was not quoted");
- AppendValueChar (quoteChar);
- while (PeekChar () != quoteChar) {
- int ch = ReadChar ();
- switch (ch)
- {
- case '<':
- throw NotWFError ("attribute values cannot contain '<'");
- case -1:
- throw NotWFError ("unexpected end of file in an attribute value");
- case '&':
- AppendValueChar (ch);
- if (PeekChar () == '#')
- break;
- // Check XML 1.0 section 3.1 WFC.
- string entName = ReadName ();
- Expect (';');
- if (XmlChar.GetPredefinedEntity (entName) < 0) {
- DTDEntityDeclaration entDecl =
- DTD == null ? null : DTD.EntityDecls [entName];
- if (entDecl == null || entDecl.SystemId != null)
- // WFC: Entity Declared (see 4.1)
- if (DTD.IsStandalone || (DTD.SystemId == null && !DTD.InternalSubsetHasPEReference))
- throw NotWFError ("Reference to external entities is not allowed in attribute value.");
- }
- valueBuffer.Append (entName);
- AppendValueChar (';');
- break;
- default:
- AppendValueChar (ch);
- break;
- }
- }
- ReadChar (); // quoteChar
- AppendValueChar (quoteChar);
- return CreateValueString ();
- }
- private void PushParserInput (string url)
- {
- Uri baseUri = null;
- try {
- if (DTD.BaseURI != null && DTD.BaseURI.Length > 0)
- baseUri = new Uri (DTD.BaseURI);
- } catch (UriFormatException) {
- }
- Uri absUri = DTD.Resolver.ResolveUri (baseUri, url);
- string absPath = absUri != null ? absUri.ToString () : String.Empty;
- foreach (XmlParserInput i in parserInputStack.ToArray ()) {
- if (i.BaseURI == absPath)
- throw NotWFError ("Nested inclusion is not allowed: " + url);
- }
- parserInputStack.Push (currentInput);
- try {
- Stream s = DTD.Resolver.GetEntity (absUri, null, typeof (Stream)) as Stream;
- currentInput = new XmlParserInput (new XmlStreamReader (s), absPath);
- } catch (Exception ex) { // FIXME: (wishlist) Bad exception catch ;-(
- int line = currentInput == null ? 0 : currentInput.LineNumber;
- int col = currentInput == null ? 0 : currentInput.LinePosition;
- string bu = (currentInput == null) ? String.Empty : currentInput.BaseURI;
- HandleError (new XmlSchemaException ("Specified external entity not found. Target URL is " + url + " .",
- line, col, null, bu, ex));
- currentInput = new XmlParserInput (new StringReader (String.Empty), absPath);
- }
- }
- private void PopParserInput ()
- {
- currentInput = parserInputStack.Pop () as XmlParserInput;
- }
- private void HandleError (XmlSchemaException ex)
- {
- #if DTD_HANDLE_EVENTS
- if (this.ValidationEventHandler != null)
- ValidationEventHandler (this, new ValidationEventArgs (ex, ex.Message, XmlSeverityType.Error));
- #else
- DTD.AddError (ex);
- #endif
- }
- }
- }
|