DTDValidatingReader.cs 33 KB

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