DTDValidatingReader.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  1. //
  2. // Permission is hereby granted, free of charge, to any person obtaining
  3. // a copy of this software and associated documentation files (the
  4. // "Software"), to deal in the Software without restriction, including
  5. // without limitation the rights to use, copy, modify, merge, publish,
  6. // distribute, sublicense, and/or sell copies of the Software, and to
  7. // permit persons to whom the Software is furnished to do so, subject to
  8. // the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be
  11. // included in all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  14. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  15. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  16. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  17. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  18. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  19. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  20. //
  21. using System;
  22. using System.Collections;
  23. using System.IO;
  24. using System.Text;
  25. using System.Xml;
  26. using System.Xml.Schema;
  27. namespace Mono.Xml
  28. {
  29. internal class DTDValidatingReader : XmlReader, IXmlLineInfo, IHasXmlParserContext, IHasXmlSchemaInfo
  30. {
  31. public DTDValidatingReader (XmlReader reader)
  32. : this (reader, null)
  33. {
  34. }
  35. internal DTDValidatingReader (XmlReader reader,
  36. XmlValidatingReader validatingReader)
  37. {
  38. entityReaderStack = new Stack ();
  39. entityReaderNameStack = new Stack ();
  40. entityReaderDepthStack = new Stack ();
  41. this.reader = reader;
  42. this.sourceTextReader = reader as XmlTextReader;
  43. elementStack = new Stack ();
  44. automataStack = new Stack ();
  45. attributes = new ArrayList ();
  46. attributeValues = new Hashtable ();
  47. attributeLocalNames = new Hashtable ();
  48. attributeNamespaces = new Hashtable ();
  49. this.validatingReader = validatingReader;
  50. valueBuilder = new StringBuilder ();
  51. idList = new ArrayList ();
  52. missingIDReferences = new ArrayList ();
  53. XmlTextReader xtReader = reader as XmlTextReader;
  54. if (xtReader != null) {
  55. #if DTD_HANDLE_EVENTS
  56. if (validatingReader != null)
  57. xtReader.ValidationEventHandler += new ValidationEventHandler (OnValidationEvent);
  58. #endif
  59. resolver = xtReader.Resolver;
  60. }
  61. else
  62. resolver = new XmlUrlResolver ();
  63. }
  64. Stack entityReaderStack;
  65. Stack entityReaderNameStack;
  66. Stack entityReaderDepthStack;
  67. XmlReader reader;
  68. XmlTextReader sourceTextReader;
  69. XmlTextReader nextEntityReader;
  70. DTDObjectModel dtd;
  71. Stack elementStack;
  72. Stack automataStack;
  73. string currentElement;
  74. string currentAttribute;
  75. string currentTextValue;
  76. string constructingTextValue;
  77. bool shouldResetCurrentTextValue;
  78. bool consumedAttribute;
  79. bool insideContent;
  80. DTDAutomata currentAutomata;
  81. DTDAutomata previousAutomata;
  82. bool isStandalone;
  83. ArrayList attributes;
  84. Hashtable attributeValues;
  85. Hashtable attributeLocalNames;
  86. Hashtable attributeNamespaces;
  87. StringBuilder valueBuilder;
  88. ArrayList idList;
  89. ArrayList missingIDReferences;
  90. XmlResolver resolver;
  91. EntityHandling currentEntityHandling;
  92. bool isSignificantWhitespace;
  93. bool isWhitespace;
  94. bool isText;
  95. bool nextMaybeSignificantWhitespace;
  96. // This field is used to get properties and to raise events.
  97. XmlValidatingReader validatingReader;
  98. public DTDObjectModel DTD {
  99. get { return dtd; }
  100. }
  101. public EntityHandling EntityHandling {
  102. get { return currentEntityHandling; }
  103. set { currentEntityHandling = value; }
  104. }
  105. public override void Close ()
  106. {
  107. reader.Close ();
  108. }
  109. // We had already done attribute validation, so can ignore name.
  110. public override string GetAttribute (int i)
  111. {
  112. if (currentTextValue != null)
  113. throw new IndexOutOfRangeException ("Specified index is out of range: " + i);
  114. if (dtd == null)
  115. return reader.GetAttribute (i);
  116. if (attributes.Count <= i)
  117. throw new IndexOutOfRangeException ("Specified index is out of range: " + i);
  118. string attrName = (string) attributes [i];
  119. return FilterNormalization (attrName, (string) attributeValues [attrName]);
  120. }
  121. public override string GetAttribute (string name)
  122. {
  123. if (currentTextValue != null)
  124. return null;
  125. if (dtd == null)
  126. return reader.GetAttribute (name);
  127. return FilterNormalization (name, (string) attributeValues [name]);
  128. }
  129. public override string GetAttribute (string name, string ns)
  130. {
  131. if (currentTextValue != null)
  132. return null;
  133. if (dtd == null)
  134. return reader.GetAttribute (name, ns);
  135. return reader.GetAttribute ((string) attributeLocalNames [name], ns);
  136. }
  137. bool IXmlLineInfo.HasLineInfo ()
  138. {
  139. IXmlLineInfo ixli = reader as IXmlLineInfo;
  140. if (ixli != null)
  141. return ixli.HasLineInfo ();
  142. else
  143. return false;
  144. }
  145. public override string LookupNamespace (string prefix)
  146. {
  147. // Does it mean anything with DTD?
  148. return reader.LookupNamespace (prefix);
  149. }
  150. public override void MoveToAttribute (int i)
  151. {
  152. if (currentTextValue != null)
  153. throw new IndexOutOfRangeException ("The index is out of range.");
  154. if (dtd == null) {
  155. reader.MoveToAttribute (i);
  156. currentAttribute = reader.Name;
  157. consumedAttribute = false;
  158. return;
  159. }
  160. if (currentElement == null)
  161. return;
  162. if (attributes.Count > i) {
  163. currentAttribute = (string) attributes [i];
  164. consumedAttribute = false;
  165. return;
  166. } else
  167. throw new IndexOutOfRangeException ("The index is out of range.");
  168. }
  169. public override bool MoveToAttribute (string name)
  170. {
  171. if (currentTextValue != null)
  172. return false;
  173. if (dtd == null) {
  174. bool b = reader.MoveToAttribute (name);
  175. if (b) {
  176. currentAttribute = reader.Name;
  177. consumedAttribute = false;
  178. }
  179. return b;
  180. }
  181. if (currentElement == null)
  182. return false;
  183. int idx = attributes.IndexOf (name);
  184. if (idx >= 0) {
  185. currentAttribute = name;
  186. consumedAttribute = false;
  187. return true;
  188. }
  189. return false;
  190. }
  191. public override bool MoveToAttribute (string name, string ns)
  192. {
  193. if (currentTextValue != null)
  194. return false;
  195. if (dtd == null) {
  196. bool b = reader.MoveToAttribute (name, ns);
  197. if (b) {
  198. currentAttribute = reader.Name;
  199. consumedAttribute = false;
  200. }
  201. return b;
  202. }
  203. if (reader.MoveToAttribute (name, ns)) {
  204. currentAttribute = reader.Name;
  205. consumedAttribute = false;
  206. return true;
  207. }
  208. for (int i = 0; i < attributes.Count; i++) {
  209. string iter = (string) attributes [i];
  210. if ((string) attributeLocalNames [iter] == name)
  211. return MoveToAttribute (iter);
  212. }
  213. return false;
  214. }
  215. public override bool MoveToElement ()
  216. {
  217. if (currentTextValue != null)
  218. return false;
  219. bool b = reader.MoveToElement ();
  220. if (!b && !IsDefault)
  221. return false;
  222. currentAttribute = null;
  223. consumedAttribute = false;
  224. return true;
  225. }
  226. public override bool MoveToFirstAttribute ()
  227. {
  228. if (currentTextValue != null)
  229. return false;
  230. if (dtd == null) {
  231. bool b = reader.MoveToFirstAttribute ();
  232. if (b) {
  233. currentAttribute = reader.Name;
  234. consumedAttribute = false;
  235. }
  236. return b;
  237. }
  238. if (attributes.Count == 0)
  239. return false;
  240. currentAttribute = (string) attributes [0];
  241. reader.MoveToAttribute (currentAttribute);
  242. consumedAttribute = false;
  243. return true;
  244. }
  245. public override bool MoveToNextAttribute ()
  246. {
  247. if (currentTextValue != null)
  248. return false;
  249. if (dtd == null) {
  250. bool b = reader.MoveToNextAttribute ();
  251. if (b) {
  252. currentAttribute = reader.Name;
  253. consumedAttribute = false;
  254. }
  255. return b;
  256. }
  257. if (currentAttribute == null)
  258. return MoveToFirstAttribute ();
  259. int idx = attributes.IndexOf (currentAttribute);
  260. if (idx + 1 < attributes.Count) {
  261. currentAttribute = (string) attributes [idx + 1];
  262. reader.MoveToAttribute (currentAttribute);
  263. consumedAttribute = false;
  264. return true;
  265. } else
  266. return false;
  267. }
  268. private void OnValidationEvent (object o, ValidationEventArgs e)
  269. {
  270. // if (validatingReader.HasValidationEvent)
  271. // validatingReader.OnValidationEvent (this, e);
  272. this.HandleError (e.Exception, e.Severity);
  273. }
  274. public override bool Read ()
  275. {
  276. if (currentTextValue != null)
  277. shouldResetCurrentTextValue = true;
  278. MoveToElement ();
  279. currentElement = null;
  280. currentAttribute = null;
  281. consumedAttribute = false;
  282. attributes.Clear ();
  283. attributeLocalNames.Clear ();
  284. attributeValues.Clear ();
  285. attributeNamespaces.Clear ();
  286. isWhitespace = false;
  287. isSignificantWhitespace = false;
  288. isText = false;
  289. nextMaybeSignificantWhitespace = false;
  290. bool b = ReadContent () || currentTextValue != null;
  291. if (!b && this.missingIDReferences.Count > 0) {
  292. this.HandleError ("Missing ID reference was found: " +
  293. String.Join (",", missingIDReferences.ToArray (typeof (string)) as string []),
  294. XmlSeverityType.Error);
  295. // Don't output the same errors so many times.
  296. this.missingIDReferences.Clear ();
  297. }
  298. if (validatingReader != null)
  299. EntityHandling = validatingReader.EntityHandling;
  300. return b;
  301. }
  302. private bool ReadContent ()
  303. {
  304. if (nextEntityReader != null) {
  305. if (DTD == null || DTD.EntityDecls [reader.Name] == null)
  306. throw new XmlException ("Entity '" + reader.Name + "' was not declared.");
  307. entityReaderStack.Push (reader);
  308. entityReaderNameStack.Push (reader.Name);
  309. entityReaderDepthStack.Push (Depth);
  310. reader = sourceTextReader = nextEntityReader;
  311. nextEntityReader = null;
  312. return ReadContent ();
  313. } else if (reader.EOF && entityReaderStack.Count > 0) {
  314. reader = entityReaderStack.Pop () as XmlReader;
  315. entityReaderNameStack.Pop ();
  316. entityReaderDepthStack.Pop ();
  317. sourceTextReader = reader as XmlTextReader;
  318. return ReadContent ();
  319. }
  320. bool b = !reader.EOF;
  321. if (shouldResetCurrentTextValue) {
  322. currentTextValue = null;
  323. shouldResetCurrentTextValue = false;
  324. }
  325. else
  326. b = reader.Read ();
  327. if (!insideContent && reader.NodeType == XmlNodeType.Element) {
  328. insideContent = true;
  329. if (dtd == null)
  330. currentAutomata = null;
  331. else
  332. currentAutomata = dtd.RootAutomata;
  333. }
  334. if (!b) {
  335. if (entityReaderStack.Count > 0) {
  336. if (validatingReader.EntityHandling == EntityHandling.ExpandEntities)
  337. return ReadContent ();
  338. else
  339. return true; // EndEntity
  340. }
  341. if (elementStack.Count != 0)
  342. throw new InvalidOperationException ("Unexpected end of XmlReader.");
  343. return false;
  344. }
  345. bool dontResetTextType = false;
  346. DTDElementDeclaration elem = null;
  347. switch (reader.NodeType) {
  348. case XmlNodeType.XmlDeclaration:
  349. if (GetAttribute ("standalone") == "yes")
  350. isStandalone = true;
  351. ValidateAttributes (null, false);
  352. break;
  353. case XmlNodeType.DocumentType:
  354. XmlTextReader xmlTextReader = reader as XmlTextReader;
  355. if (xmlTextReader == null) {
  356. xmlTextReader = new XmlTextReader ("", XmlNodeType.Document, null);
  357. xmlTextReader.XmlResolver = resolver;
  358. xmlTextReader.GenerateDTDObjectModel (reader.Name,
  359. reader ["PUBLIC"], reader ["SYSTEM"], reader.Value);
  360. }
  361. this.dtd = xmlTextReader.DTD;
  362. // Validity Constraints Check.
  363. if (DTD.Errors.Length > 0)
  364. for (int i = 0; i < DTD.Errors.Length; i++)
  365. HandleError (DTD.Errors [i].Message, XmlSeverityType.Error);
  366. // NData target exists.
  367. foreach (DTDEntityDeclaration ent in dtd.EntityDecls.Values)
  368. if (ent.NotationName != null && dtd.NotationDecls [ent.NotationName] == null)
  369. this.HandleError ("Target notation was not found for NData in entity declaration " + ent.Name + ".",
  370. XmlSeverityType.Error);
  371. // NOTATION exists for attribute default values
  372. foreach (DTDAttListDeclaration attListIter in dtd.AttListDecls.Values)
  373. foreach (DTDAttributeDefinition def in attListIter.Definitions)
  374. if (def.Datatype.TokenizedType == XmlTokenizedType.NOTATION) {
  375. foreach (string notation in def.EnumeratedNotations)
  376. if (dtd.NotationDecls [notation] == null)
  377. this.HandleError ("Target notation was not found for NOTATION typed attribute default " + def.Name + ".",
  378. XmlSeverityType.Error);
  379. }
  380. break;
  381. case XmlNodeType.Element:
  382. if (constructingTextValue != null) {
  383. currentTextValue = constructingTextValue;
  384. constructingTextValue = null;
  385. if (isWhitespace)
  386. ValidateWhitespaceNode ();
  387. return true;
  388. }
  389. elementStack.Push (reader.Name);
  390. // startElementDeriv
  391. // If no schema specification, then skip validation.
  392. if (currentAutomata == null) {
  393. ValidateAttributes (null, false);
  394. if (reader.IsEmptyElement)
  395. goto case XmlNodeType.EndElement;
  396. break;
  397. }
  398. previousAutomata = currentAutomata;
  399. currentAutomata = currentAutomata.TryStartElement (reader.Name);
  400. if (currentAutomata == DTD.Invalid) {
  401. HandleError (String.Format ("Invalid start element found: {0}", reader.Name),
  402. XmlSeverityType.Error);
  403. currentAutomata = previousAutomata;
  404. }
  405. elem = DTD.ElementDecls [reader.Name];
  406. if (elem == null) {
  407. HandleError (String.Format ("Element {0} is not declared.", reader.Name),
  408. XmlSeverityType.Error);
  409. currentAutomata = previousAutomata;
  410. }
  411. currentElement = Name;
  412. automataStack.Push (currentAutomata);
  413. if (elem != null) // i.e. not invalid
  414. currentAutomata = elem.ContentModel.GetAutomata ();
  415. DTDAttListDeclaration attList = dtd.AttListDecls [currentElement];
  416. if (attList != null) {
  417. // check attributes
  418. ValidateAttributes (attList, true);
  419. currentAttribute = null;
  420. } else {
  421. if (reader.HasAttributes) {
  422. HandleError (String.Format (
  423. "Attributes are found on element {0} while it has no attribute definitions.", currentElement),
  424. XmlSeverityType.Error);
  425. }
  426. // SetupValidityIgnorantAttributes ();
  427. ValidateAttributes (null, false);
  428. }
  429. // If it is empty element then directly check end element.
  430. if (reader.IsEmptyElement)
  431. goto case XmlNodeType.EndElement;
  432. break;
  433. case XmlNodeType.EndElement:
  434. if (constructingTextValue != null) {
  435. currentTextValue = constructingTextValue;
  436. constructingTextValue = null;
  437. return true;
  438. }
  439. elementStack.Pop ();
  440. // endElementDeriv
  441. // If no schema specification, then skip validation.
  442. if (currentAutomata == null)
  443. break;
  444. elem = DTD.ElementDecls [reader.Name];
  445. if (elem == null) {
  446. HandleError (String.Format ("Element {0} is not declared.", reader.Name),
  447. XmlSeverityType.Error);
  448. }
  449. previousAutomata = currentAutomata;
  450. // Don't let currentAutomata
  451. DTDAutomata tmpAutomata = currentAutomata.TryEndElement ();
  452. if (tmpAutomata == DTD.Invalid) {
  453. HandleError (String.Format ("Invalid end element found: {0}", reader.Name),
  454. XmlSeverityType.Error);
  455. currentAutomata = previousAutomata;
  456. }
  457. currentAutomata = automataStack.Pop () as DTDAutomata;
  458. break;
  459. case XmlNodeType.CDATA:
  460. if (currentTextValue != null) {
  461. currentTextValue = constructingTextValue;
  462. constructingTextValue = null;
  463. return true;
  464. }
  465. goto case XmlNodeType.Text;
  466. case XmlNodeType.SignificantWhitespace:
  467. if (!isText)
  468. isSignificantWhitespace = true;
  469. dontResetTextType = true;
  470. goto case XmlNodeType.Text;
  471. case XmlNodeType.Text:
  472. isText = true;
  473. if (!dontResetTextType) {
  474. isWhitespace = isSignificantWhitespace = false;
  475. }
  476. // If no schema specification, then skip validation.
  477. if (currentAutomata == null)
  478. break;
  479. elem = dtd.ElementDecls [elementStack.Peek () as string];
  480. // Here element should have been already validated, so
  481. // if no matching declaration is found, simply ignore.
  482. if (elem != null && !elem.IsMixedContent && !elem.IsAny) {
  483. HandleError (String.Format ("Current element {0} does not allow character data content.", elementStack.Peek () as string),
  484. XmlSeverityType.Error);
  485. currentAutomata = previousAutomata;
  486. }
  487. if (validatingReader.EntityHandling == EntityHandling.ExpandEntities) {
  488. constructingTextValue += reader.Value;
  489. return ReadContent ();
  490. }
  491. break;
  492. case XmlNodeType.Whitespace:
  493. if (nextMaybeSignificantWhitespace) {
  494. currentTextValue = reader.Value;
  495. nextMaybeSignificantWhitespace = false;
  496. goto case XmlNodeType.SignificantWhitespace;
  497. }
  498. if (!isText && !isSignificantWhitespace)
  499. isWhitespace = true;
  500. if (validatingReader.EntityHandling == EntityHandling.ExpandEntities) {
  501. constructingTextValue += reader.Value;
  502. return ReadContent ();
  503. }
  504. ValidateWhitespaceNode ();
  505. break;
  506. case XmlNodeType.EntityReference:
  507. if (validatingReader.EntityHandling == EntityHandling.ExpandEntities) {
  508. ResolveEntity ();
  509. return ReadContent ();
  510. }
  511. break;
  512. }
  513. constructingTextValue = null;
  514. MoveToElement ();
  515. return true;
  516. }
  517. private void ValidateWhitespaceNode ()
  518. {
  519. // VC Standalone Document Declaration (2.9)
  520. if (this.isStandalone && DTD != null && elementStack.Count > 0) {
  521. DTDElementDeclaration elem = DTD.ElementDecls [elementStack.Peek () as string];
  522. if (elem != null && !elem.IsInternalSubset && !elem.IsMixedContent && !elem.IsAny && !elem.IsEmpty)
  523. HandleError ("In standalone document, whitespace cannot appear in an element whose declaration explicitly contains child content model, not Mixed content.", XmlSeverityType.Error);
  524. }
  525. }
  526. private void HandleError (string message, XmlSeverityType severity)
  527. {
  528. if (validatingReader != null &&
  529. validatingReader.ValidationType == ValidationType.None)
  530. return;
  531. IXmlLineInfo info = this as IXmlLineInfo;
  532. bool hasLine = info.HasLineInfo ();
  533. XmlSchemaException ex = new XmlSchemaException (
  534. message,
  535. hasLine ? info.LineNumber : 0,
  536. hasLine ? info.LinePosition : 0,
  537. null,
  538. BaseURI,
  539. null);
  540. HandleError (ex, severity);
  541. }
  542. private void HandleError (XmlSchemaException ex, XmlSeverityType severity)
  543. {
  544. if (validatingReader != null &&
  545. validatingReader.ValidationType == ValidationType.None)
  546. return;
  547. if (validatingReader != null)
  548. this.validatingReader.OnValidationEvent (this,
  549. new ValidationEventArgs (ex, ex.Message, severity));
  550. else if (severity == XmlSeverityType.Error)
  551. throw ex;
  552. }
  553. Stack attributeValueEntityStack = new Stack ();
  554. private void ValidateAttributes (DTDAttListDeclaration decl, bool validate)
  555. {
  556. while (reader.MoveToNextAttribute ()) {
  557. string attrName = reader.Name;
  558. this.currentAttribute = attrName;
  559. attributes.Add (attrName);
  560. attributeLocalNames.Add (attrName, reader.LocalName);
  561. attributeNamespaces.Add (attrName, reader.NamespaceURI);
  562. XmlReader targetReader = reader;
  563. string attrValue = null;
  564. if (currentEntityHandling == EntityHandling.ExpandCharEntities)
  565. attrValue = reader.Value;
  566. else {
  567. while (attributeValueEntityStack.Count >= 0) {
  568. if (!targetReader.ReadAttributeValue ()) {
  569. if (attributeValueEntityStack.Count > 0) {
  570. targetReader = attributeValueEntityStack.Pop () as XmlReader;
  571. continue;
  572. } else
  573. break;
  574. }
  575. switch (targetReader.NodeType) {
  576. case XmlNodeType.EntityReference:
  577. DTDEntityDeclaration edecl = DTD.EntityDecls [targetReader.Name];
  578. if (edecl == null) {
  579. HandleError (String.Format ("Referenced entity {0} is not declared.", targetReader.Name),
  580. XmlSeverityType.Error);
  581. } else {
  582. XmlTextReader etr = new XmlTextReader (edecl.EntityValue, XmlNodeType.Attribute, ParserContext);
  583. attributeValueEntityStack.Push (targetReader);
  584. targetReader = etr;
  585. continue;
  586. }
  587. break;
  588. case XmlNodeType.EndEntity:
  589. break;
  590. default:
  591. if (attrValue != null) {
  592. valueBuilder.Append (attrValue);
  593. attrValue = null;
  594. }
  595. if (valueBuilder.Length != 0)
  596. valueBuilder.Append (targetReader.Value);
  597. else
  598. attrValue = targetReader.Value;
  599. break;
  600. }
  601. }
  602. if (attrValue == null) {
  603. attrValue = valueBuilder.ToString ();
  604. valueBuilder.Length = 0;
  605. }
  606. }
  607. reader.MoveToElement ();
  608. reader.MoveToAttribute (attrName);
  609. attributeValues.Add (attrName, attrValue);
  610. if (!validate)
  611. continue;
  612. // Validation
  613. DTDAttributeDefinition def = decl [reader.Name];
  614. if (def == null) {
  615. HandleError (String.Format ("Attribute {0} is not declared.", reader.Name),
  616. XmlSeverityType.Error);
  617. } else {
  618. // check enumeration constraint
  619. if (def.EnumeratedAttributeDeclaration.Count > 0)
  620. if (!def.EnumeratedAttributeDeclaration.Contains (
  621. FilterNormalization (reader.Name, attrValue)))
  622. HandleError (String.Format ("Attribute enumeration constraint error in attribute {0}, value {1}.",
  623. reader.Name, attrValue), XmlSeverityType.Error);
  624. if (def.EnumeratedNotations.Count > 0)
  625. if (!def.EnumeratedNotations.Contains (
  626. FilterNormalization (reader.Name, attrValue)))
  627. HandleError (String.Format ("Attribute notation enumeration constraint error in attribute {0}, value {1}.",
  628. reader.Name, attrValue), XmlSeverityType.Error);
  629. // check type constraint
  630. string normalized = null;
  631. if (def.Datatype != null)
  632. normalized = FilterNormalization (def.Name, attrValue);
  633. else
  634. normalized = attrValue;
  635. DTDEntityDeclaration ent;
  636. // Common process to get list value
  637. string [] list = null;
  638. switch (def.Datatype.TokenizedType) {
  639. case XmlTokenizedType.IDREFS:
  640. case XmlTokenizedType.ENTITIES:
  641. case XmlTokenizedType.NMTOKENS:
  642. try {
  643. list = def.Datatype.ParseValue (normalized, NameTable, null) as string [];
  644. } catch (Exception) {
  645. HandleError ("Attribute value is invalid against its data type.", XmlSeverityType.Error);
  646. list = new string [0];
  647. }
  648. break;
  649. default:
  650. try {
  651. def.Datatype.ParseValue (normalized, NameTable, null);
  652. } catch (Exception) {
  653. HandleError ("Attribute value is invalid against its data type.", XmlSeverityType.Error);
  654. }
  655. break;
  656. }
  657. switch (def.Datatype.TokenizedType) {
  658. case XmlTokenizedType.ID:
  659. if (this.idList.Contains (normalized)) {
  660. HandleError (String.Format ("Node with ID {0} was already appeared.", attrValue),
  661. XmlSeverityType.Error);
  662. } else {
  663. if (missingIDReferences.Contains (normalized))
  664. missingIDReferences.Remove (normalized);
  665. idList.Add (normalized);
  666. }
  667. break;
  668. case XmlTokenizedType.IDREF:
  669. if (!idList.Contains (normalized))
  670. missingIDReferences.Add (normalized);
  671. break;
  672. case XmlTokenizedType.IDREFS:
  673. for (int i = 0; i < list.Length; i++) {
  674. string idref = list [i];
  675. if (!idList.Contains (idref))
  676. missingIDReferences.Add (idref);
  677. }
  678. break;
  679. case XmlTokenizedType.ENTITY:
  680. ent = dtd.EntityDecls [normalized];
  681. if (ent == null)
  682. HandleError ("Reference to undeclared entity was found in attribute: " + reader.Name + ".", XmlSeverityType.Error);
  683. else if (ent.NotationName == null)
  684. HandleError ("The entity specified by entity type value must be an unparsed entity. The entity definition has no NDATA in attribute: " + reader.Name + ".", XmlSeverityType.Error);
  685. break;
  686. case XmlTokenizedType.ENTITIES:
  687. for (int i = 0; i < list.Length; i++) {
  688. string entref = list [i];
  689. ent = dtd.EntityDecls [FilterNormalization (reader.Name, entref)];
  690. if (ent == null)
  691. HandleError ("Reference to undeclared entity was found in attribute: " + reader.Name + ".", XmlSeverityType.Error);
  692. else if (ent.NotationName == null)
  693. HandleError ("The entity specified by ENTITIES type value must be an unparsed entity. The entity definition has no NDATA in attribute: " + reader.Name + ".", XmlSeverityType.Error);
  694. }
  695. break;
  696. // case XmlTokenizedType.NMTOKEN: nothing to do
  697. // case XmlTokenizedType.NMTOKENS: nothing to do
  698. }
  699. if (isStandalone && !def.IsInternalSubset && attrValue != normalized)
  700. HandleError ("In standalone document, attribute value characters must not be checked against external definition.", XmlSeverityType.Error);
  701. if (def.OccurenceType == DTDAttributeOccurenceType.Fixed &&
  702. attrValue != def.DefaultValue) {
  703. HandleError (String.Format ("Fixed attribute {0} in element {1} has invalid value {2}.",
  704. def.Name, decl.Name, attrValue),
  705. XmlSeverityType.Error);
  706. }
  707. }
  708. }
  709. if (validate)
  710. VerifyDeclaredAttributes (decl);
  711. MoveToElement ();
  712. }
  713. private void VerifyDeclaredAttributes (DTDAttListDeclaration decl)
  714. {
  715. // Check if all required attributes exist, and/or
  716. // if there is default values, then add them.
  717. for (int i = 0; i < decl.Definitions.Count; i++) {
  718. DTDAttributeDefinition def = (DTDAttributeDefinition) decl.Definitions [i];
  719. if (!attributes.Contains (def.Name)) {
  720. if (def.OccurenceType == DTDAttributeOccurenceType.Required) {
  721. HandleError (String.Format ("Required attribute {0} in element {1} not found .",
  722. def.Name, decl.Name),
  723. XmlSeverityType.Error);
  724. }
  725. else if (def.DefaultValue != null) {
  726. if (this.isStandalone && !def.IsInternalSubset)
  727. HandleError ("In standalone document, external default value definition must not be applied.", XmlSeverityType.Error);
  728. switch (validatingReader.ValidationType) {
  729. case ValidationType.Auto:
  730. if (validatingReader.Schemas.Count == 0)
  731. goto case ValidationType.DTD;
  732. break;
  733. case ValidationType.DTD:
  734. case ValidationType.None:
  735. // Other than them, ignore DTD defaults.
  736. attributes.Add (def.Name);
  737. int colonAt = def.Name.IndexOf (':');
  738. attributeLocalNames.Add (def.Name, colonAt < 0 ? def.Name : def.Name.Substring (colonAt + 1));
  739. attributeNamespaces.Add (def.Name, colonAt < 0 ? def.Name : def.Name.Substring (0, colonAt));
  740. attributeValues.Add (def.Name, def.DefaultValue);
  741. break;
  742. }
  743. }
  744. }
  745. }
  746. }
  747. public override bool ReadAttributeValue ()
  748. {
  749. if (consumedAttribute)
  750. return false;
  751. if (NodeType == XmlNodeType.Attribute &&
  752. currentEntityHandling == EntityHandling.ExpandEntities) {
  753. consumedAttribute = true;
  754. return true;
  755. }
  756. else if (IsDefault) {
  757. consumedAttribute = true;
  758. return true;
  759. }
  760. else
  761. return reader.ReadAttributeValue ();
  762. }
  763. #if NET_1_0
  764. public override string ReadInnerXml ()
  765. {
  766. // MS.NET 1.0 has a serious bug here. It skips validation.
  767. return reader.ReadInnerXml ();
  768. }
  769. public override string ReadOuterXml ()
  770. {
  771. // MS.NET 1.0 has a serious bug here. It skips validation.
  772. return reader.ReadOuterXml ();
  773. }
  774. #endif
  775. public override string ReadString ()
  776. {
  777. // It seems to be the same as ReadInnerXml().
  778. return base.ReadStringInternal ();
  779. }
  780. public override void ResolveEntity ()
  781. {
  782. if (resolver == null)
  783. return;
  784. // "reader." is required since NodeType must not be entityref by nature.
  785. if (reader.NodeType != XmlNodeType.EntityReference)
  786. throw new InvalidOperationException ("The current node is not an Entity Reference");
  787. DTDEntityDeclaration entity = DTD != null ? DTD.EntityDecls [reader.Name] as DTDEntityDeclaration : null;
  788. XmlNodeType xmlReaderNodeType =
  789. (currentAttribute != null) ? XmlNodeType.Attribute : XmlNodeType.Element;
  790. // MS.NET seems simply ignoring undeclared entity reference here ;-(
  791. if (entity != null && entity.SystemId != null) {
  792. Uri baseUri = entity.BaseURI == null ? null : new Uri (entity.BaseURI);
  793. Stream stream = resolver.GetEntity (resolver.ResolveUri (baseUri, entity.SystemId), null, typeof (Stream)) as Stream;
  794. nextEntityReader = new XmlTextReader (stream, xmlReaderNodeType, ParserContext);
  795. } else {
  796. string replacementText =
  797. (entity != null) ? entity.EntityValue : String.Empty;
  798. nextEntityReader = new XmlTextReader (replacementText, xmlReaderNodeType, ParserContext);
  799. }
  800. nextEntityReader.XmlResolver = resolver;
  801. nextEntityReader.SkipTextDeclaration ();
  802. }
  803. public override int AttributeCount {
  804. get {
  805. if (currentTextValue != null)
  806. return 0;
  807. if (dtd == null || !insideContent)
  808. return reader.AttributeCount;
  809. return attributes.Count;
  810. }
  811. }
  812. public override string BaseURI {
  813. get {
  814. return reader.BaseURI;
  815. }
  816. }
  817. public override bool CanResolveEntity {
  818. get { return true; }
  819. }
  820. public override int Depth {
  821. get {
  822. int baseNum = reader.Depth;
  823. if (entityReaderDepthStack.Count > 0) {
  824. baseNum += (int) entityReaderDepthStack.Peek ();
  825. if (NodeType != XmlNodeType.EndEntity)
  826. baseNum++;
  827. }
  828. if (currentTextValue != null && reader.NodeType == XmlNodeType.EndElement)
  829. baseNum++;
  830. return IsDefault ? baseNum + 1 : baseNum;
  831. }
  832. }
  833. public override bool EOF {
  834. get { return reader.EOF && entityReaderStack.Count == 0; }
  835. }
  836. public override bool HasValue {
  837. get {
  838. return IsDefault ? true :
  839. currentTextValue != null ? true :
  840. reader.HasValue; }
  841. }
  842. public override bool IsDefault {
  843. get {
  844. if (currentTextValue != null)
  845. return false;
  846. if (currentAttribute == null)
  847. return false;
  848. return reader.GetAttribute (currentAttribute) == null;
  849. }
  850. }
  851. public override bool IsEmptyElement {
  852. get {
  853. if (currentTextValue != null)
  854. return false;
  855. return reader.IsEmptyElement;
  856. }
  857. }
  858. public override string this [int i] {
  859. get { return GetAttribute (i); }
  860. }
  861. public override string this [string name] {
  862. get { return GetAttribute (name); }
  863. }
  864. public override string this [string name, string ns] {
  865. get { return GetAttribute (name, ns); }
  866. }
  867. public int LineNumber {
  868. get {
  869. IXmlLineInfo info = reader as IXmlLineInfo;
  870. return (info != null) ? info.LineNumber : 0;
  871. }
  872. }
  873. public int LinePosition {
  874. get {
  875. IXmlLineInfo info = reader as IXmlLineInfo;
  876. return (info != null) ? info.LinePosition : 0;
  877. }
  878. }
  879. public override string LocalName {
  880. get {
  881. if (currentTextValue != null)
  882. return String.Empty;
  883. return IsDefault ?
  884. consumedAttribute ? String.Empty : currentAttribute :
  885. reader.LocalName;
  886. }
  887. }
  888. public override string Name {
  889. get {
  890. if (currentTextValue != null)
  891. return String.Empty;
  892. return IsDefault ?
  893. consumedAttribute ? String.Empty : currentAttribute :
  894. reader.Name;
  895. }
  896. }
  897. public override string NamespaceURI {
  898. get {
  899. if (currentTextValue != null)
  900. return String.Empty;
  901. return IsDefault ?
  902. consumedAttribute ? String.Empty : String.Empty :
  903. reader.NamespaceURI;
  904. }
  905. }
  906. public override XmlNameTable NameTable {
  907. get { return reader.NameTable; }
  908. }
  909. public override XmlNodeType NodeType {
  910. get {
  911. if (currentTextValue != null)
  912. return isSignificantWhitespace ? XmlNodeType.SignificantWhitespace :
  913. isWhitespace ? XmlNodeType.Whitespace :
  914. XmlNodeType.Text;
  915. if (entityReaderStack.Count > 0 && reader.EOF)
  916. return XmlNodeType.EndEntity;
  917. // If consumedAttribute is true, then entities must be resolved.
  918. return consumedAttribute ? XmlNodeType.Text :
  919. IsDefault ? XmlNodeType.Attribute :
  920. reader.NodeType;
  921. }
  922. }
  923. public XmlParserContext ParserContext {
  924. get { return XmlSchemaUtil.GetParserContext (reader); }
  925. }
  926. public override string Prefix {
  927. get {
  928. if (currentTextValue != null)
  929. return String.Empty;
  930. if (currentAttribute != null && NodeType != XmlNodeType.Attribute)
  931. return String.Empty;
  932. return IsDefault ? String.Empty : reader.Prefix;
  933. }
  934. }
  935. public override char QuoteChar {
  936. get {
  937. // If it is not actually on an attribute, then it returns
  938. // undefined value or '"'.
  939. return reader.QuoteChar;
  940. }
  941. }
  942. public override ReadState ReadState {
  943. get {
  944. if (reader.ReadState == ReadState.EndOfFile && currentTextValue != null)
  945. return ReadState.Interactive;
  946. return reader.ReadState;
  947. }
  948. }
  949. public object SchemaType {
  950. get {
  951. if (currentElement == null)
  952. return null;
  953. DTDAttListDeclaration decl =
  954. DTD.AttListDecls [currentElement];
  955. DTDAttributeDefinition def =
  956. decl != null ? decl [currentAttribute] : null;
  957. return def != null ? def.Datatype : null;
  958. }
  959. }
  960. char [] whitespaceChars = new char [] {' '};
  961. private string FilterNormalization (string attrName, string rawValue)
  962. {
  963. if (DTD != null &&
  964. NodeType == XmlNodeType.Attribute &&
  965. sourceTextReader != null &&
  966. sourceTextReader.Normalization) {
  967. DTDAttributeDefinition def =
  968. dtd.AttListDecls [currentElement].Get (attrName);
  969. valueBuilder.Append (rawValue);
  970. valueBuilder.Replace ('\r', ' ');
  971. valueBuilder.Replace ('\n', ' ');
  972. valueBuilder.Replace ('\t', ' ');
  973. try {
  974. if (def.Datatype.TokenizedType != XmlTokenizedType.CDATA) {
  975. for (int i=0; i < valueBuilder.Length; i++) {
  976. if (valueBuilder [i] == ' ') {
  977. while (++i < valueBuilder.Length && valueBuilder [i] == ' ')
  978. valueBuilder.Remove (i, 1);
  979. }
  980. }
  981. return valueBuilder.ToString ().Trim (whitespaceChars);
  982. }
  983. else
  984. return valueBuilder.ToString ();
  985. } finally {
  986. valueBuilder.Length = 0;
  987. }
  988. }
  989. else
  990. return rawValue;
  991. }
  992. public override string Value {
  993. get {
  994. if (currentTextValue != null)
  995. return currentTextValue;
  996. // This check also covers value node of default attributes.
  997. if (IsDefault) {
  998. DTDAttributeDefinition def =
  999. dtd.AttListDecls [currentElement] [currentAttribute] as DTDAttributeDefinition;
  1000. return sourceTextReader != null && sourceTextReader.Normalization ?
  1001. def.NormalizedDefaultValue : def.DefaultValue;
  1002. }
  1003. // As to this property, MS.NET seems ignorant of EntityHandling...
  1004. else if (NodeType == XmlNodeType.Attribute)// &&
  1005. return FilterNormalization (Name, (string) attributeValues [currentAttribute]);
  1006. else if (consumedAttribute)
  1007. return FilterNormalization (Name, (string) attributeValues [this.currentAttribute]);
  1008. else
  1009. return FilterNormalization (Name, reader.Value);
  1010. }
  1011. }
  1012. public override string XmlLang {
  1013. get {
  1014. string val = this ["xml:lang"];
  1015. return val != null ? val : reader.XmlLang;
  1016. }
  1017. }
  1018. public XmlResolver XmlResolver {
  1019. set {
  1020. resolver = value;
  1021. }
  1022. }
  1023. public override XmlSpace XmlSpace {
  1024. get {
  1025. string val = this ["xml:space"];
  1026. switch (val) {
  1027. case "preserve":
  1028. return XmlSpace.Preserve;
  1029. case "default":
  1030. return XmlSpace.Default;
  1031. default:
  1032. return reader.XmlSpace;
  1033. }
  1034. }
  1035. }
  1036. }
  1037. }