DTDReader.cs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644
  1. //
  2. // System.Xml.DTDReader
  3. //
  4. // Author:
  5. // Atsushi Enomoto ([email protected])
  6. //
  7. // (C)2003 Atsushi Enomoto
  8. // (C)2004 Novell Inc.
  9. //
  10. // FIXME:
  11. // When a parameter entity contains cp section, it should be closed
  12. // within that declaration.
  13. //
  14. // Resolution to external entities from different BaseURI fails (it is
  15. // the same as MS.NET 1.1, but should be fixed in the future).
  16. //
  17. //
  18. // Permission is hereby granted, free of charge, to any person obtaining
  19. // a copy of this software and associated documentation files (the
  20. // "Software"), to deal in the Software without restriction, including
  21. // without limitation the rights to use, copy, modify, merge, publish,
  22. // distribute, sublicense, and/or sell copies of the Software, and to
  23. // permit persons to whom the Software is furnished to do so, subject to
  24. // the following conditions:
  25. //
  26. // The above copyright notice and this permission notice shall be
  27. // included in all copies or substantial portions of the Software.
  28. //
  29. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  30. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  31. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  32. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  33. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  34. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  35. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  36. //
  37. using System;
  38. using System.Collections;
  39. using System.Globalization;
  40. using System.IO;
  41. using System.Text;
  42. using Mono.Xml;
  43. using System.Xml.Schema;
  44. namespace System.Xml
  45. {
  46. internal class DTDReader : IXmlLineInfo
  47. {
  48. private XmlParserInput currentInput;
  49. private Stack parserInputStack;
  50. private string entityReferenceName;
  51. private char [] nameBuffer;
  52. private int nameLength;
  53. private int nameCapacity;
  54. private const int initialNameCapacity = 256;
  55. private StringBuilder valueBuffer;
  56. private int currentLinkedNodeLineNumber;
  57. private int currentLinkedNodeLinePosition;
  58. // Parameter entity placeholder
  59. private int dtdIncludeSect;
  60. private bool normalization;
  61. private bool processingInternalSubset;
  62. string cachedPublicId;
  63. string cachedSystemId;
  64. DTDObjectModel DTD;
  65. #if DTD_HANDLE_EVENTS
  66. public event ValidationEventHandler ValidationEventHandler;
  67. #endif
  68. // .ctor()
  69. public DTDReader (DTDObjectModel dtd,
  70. int startLineNumber,
  71. int startLinePosition)
  72. {
  73. this.DTD = dtd;
  74. currentLinkedNodeLineNumber = startLineNumber;
  75. currentLinkedNodeLinePosition = startLinePosition;
  76. Init ();
  77. }
  78. // Properties
  79. public string BaseURI {
  80. get { return currentInput.BaseURI; }
  81. }
  82. public bool Normalization {
  83. get { return normalization; }
  84. set { normalization = value; }
  85. }
  86. public int LineNumber {
  87. get { return currentInput.LineNumber; }
  88. }
  89. public int LinePosition {
  90. get { return currentInput.LinePosition; }
  91. }
  92. public bool HasLineInfo ()
  93. {
  94. return true;
  95. }
  96. // Methods
  97. private XmlException NotWFError (string message)
  98. {
  99. return new XmlException (this as IXmlLineInfo, BaseURI, message);
  100. }
  101. private void Init ()
  102. {
  103. parserInputStack = new Stack ();
  104. entityReferenceName = String.Empty;
  105. nameBuffer = new char [initialNameCapacity];
  106. nameLength = 0;
  107. nameCapacity = initialNameCapacity;
  108. valueBuffer = new StringBuilder (512);
  109. }
  110. internal DTDObjectModel GenerateDTDObjectModel ()
  111. {
  112. // now compile DTD
  113. int originalParserDepth = parserInputStack.Count;
  114. bool more;
  115. if (DTD.InternalSubset != null && DTD.InternalSubset.Length > 0) {
  116. this.processingInternalSubset = true;
  117. XmlParserInput original = currentInput;
  118. currentInput = new XmlParserInput (
  119. new StringReader (DTD.InternalSubset),
  120. DTD.BaseURI,
  121. currentLinkedNodeLineNumber,
  122. currentLinkedNodeLinePosition);
  123. currentInput.InitialState = false;
  124. do {
  125. more = ProcessDTDSubset ();
  126. if (PeekChar () == -1 && parserInputStack.Count > 0)
  127. PopParserInput ();
  128. } while (more || parserInputStack.Count > originalParserDepth);
  129. if (dtdIncludeSect != 0)
  130. throw NotWFError ("INCLUDE section is not ended correctly.");
  131. currentInput = original;
  132. this.processingInternalSubset = false;
  133. }
  134. if (DTD.SystemId != null && DTD.SystemId != String.Empty && DTD.Resolver != null) {
  135. PushParserInput (DTD.SystemId);
  136. do {
  137. more = ProcessDTDSubset ();
  138. if (PeekChar () == -1 && parserInputStack.Count > 1)
  139. PopParserInput ();
  140. } while (more || parserInputStack.Count > originalParserDepth + 1);
  141. if (dtdIncludeSect != 0)
  142. throw NotWFError ("INCLUDE section is not ended correctly.");
  143. PopParserInput ();
  144. }
  145. ArrayList sc = new ArrayList ();
  146. // Entity recursion check.
  147. foreach (DTDEntityDeclaration ent in DTD.EntityDecls.Values) {
  148. if (ent.NotationName != null) {
  149. ent.ScanEntityValue (sc);
  150. sc.Clear ();
  151. }
  152. }
  153. // release unnecessary memory usage
  154. DTD.ExternalResources.Clear ();
  155. return DTD;
  156. }
  157. // Read any one of following:
  158. // elementdecl, AttlistDecl, EntityDecl, NotationDecl,
  159. // PI, Comment, Parameter Entity, or doctype termination char(']')
  160. //
  161. // Returns true if it may have any more contents, or false if not.
  162. private bool ProcessDTDSubset ()
  163. {
  164. SkipWhitespace ();
  165. int c2 = ReadChar ();
  166. switch(c2)
  167. {
  168. case -1:
  169. return false;
  170. case '%':
  171. // It affects on entity references' well-formedness
  172. if (this.processingInternalSubset)
  173. DTD.InternalSubsetHasPEReference = true;
  174. string peName = ReadName ();
  175. Expect (';');
  176. string peValue = GetPEValue (peName);
  177. if (peValue == String.Empty)
  178. break;
  179. currentInput.InsertParameterEntityBuffer (peValue);
  180. // int currentLine = currentInput.LineNumber;
  181. // int currentColumn = currentInput.LinePosition;
  182. while (currentInput.HasPEBuffer)
  183. ProcessDTDSubset ();
  184. SkipWhitespace ();
  185. // FIXME: Implement correct nest-level check.
  186. // Don't depend on lineinfo (might not be supplied)
  187. // if (currentInput.LineNumber != currentLine ||
  188. // currentInput.LinePosition != currentColumn)
  189. // throw NotWFError ("Incorrectly nested parameter entity.");
  190. break;
  191. case '<':
  192. int c = ReadChar ();
  193. switch(c)
  194. {
  195. case '?':
  196. // Only read, no store.
  197. ReadProcessingInstruction ();
  198. break;
  199. case '!':
  200. CompileDeclaration ();
  201. break;
  202. case -1:
  203. throw NotWFError ("Unexpected end of stream.");
  204. default:
  205. throw NotWFError ("Syntax Error after '<' character: " + (char) c);
  206. }
  207. break;
  208. case ']':
  209. if (dtdIncludeSect == 0)
  210. throw NotWFError ("Unbalanced end of INCLUDE/IGNORE section.");
  211. // End of inclusion
  212. Expect ("]>");
  213. dtdIncludeSect--;
  214. SkipWhitespace ();
  215. break;
  216. default:
  217. throw NotWFError (String.Format ("Syntax Error inside doctypedecl markup : {0}({1})", c2, (char) c2));
  218. }
  219. currentInput.InitialState = false;
  220. return true;
  221. }
  222. private void CompileDeclaration ()
  223. {
  224. switch(ReadChar ())
  225. {
  226. case '-':
  227. Expect ('-');
  228. // Only read, no store.
  229. ReadComment ();
  230. break;
  231. case 'E':
  232. switch(ReadChar ())
  233. {
  234. case 'N':
  235. Expect ("TITY");
  236. if (!SkipWhitespace ())
  237. throw NotWFError (
  238. "Whitespace is required after '<!ENTITY' in DTD entity declaration.");
  239. LOOPBACK:
  240. if (PeekChar () == '%') {
  241. ReadChar ();
  242. if (!SkipWhitespace ()) {
  243. ExpandPERef ();
  244. goto LOOPBACK;
  245. } else {
  246. // FIXME: Is this allowed? <!ENTITY % %name; ...>
  247. // (i.e. Can PE name be replaced by another PE?)
  248. TryExpandPERef ();
  249. if (XmlChar.IsNameChar (PeekChar ()))
  250. ReadParameterEntityDecl ();
  251. else
  252. throw NotWFError ("expected name character");
  253. }
  254. break;
  255. }
  256. DTDEntityDeclaration ent = ReadEntityDecl ();
  257. if (DTD.EntityDecls [ent.Name] == null)
  258. DTD.EntityDecls.Add (ent.Name, ent);
  259. break;
  260. case 'L':
  261. Expect ("EMENT");
  262. DTDElementDeclaration el = ReadElementDecl ();
  263. DTD.ElementDecls.Add (el.Name, el);
  264. break;
  265. default:
  266. throw NotWFError ("Syntax Error after '<!E' (ELEMENT or ENTITY must be found)");
  267. }
  268. break;
  269. case 'A':
  270. Expect ("TTLIST");
  271. DTDAttListDeclaration atl = ReadAttListDecl ();
  272. DTD.AttListDecls.Add (atl.Name, atl);
  273. break;
  274. case 'N':
  275. Expect ("OTATION");
  276. DTDNotationDeclaration not = ReadNotationDecl ();
  277. DTD.NotationDecls.Add (not.Name, not);
  278. break;
  279. case '[':
  280. // conditional sections
  281. SkipWhitespace ();
  282. TryExpandPERef ();
  283. Expect ('I');
  284. switch (ReadChar ()) {
  285. case 'N':
  286. Expect ("CLUDE");
  287. ExpectAfterWhitespace ('[');
  288. dtdIncludeSect++;
  289. break;
  290. case 'G':
  291. Expect ("NORE");
  292. ReadIgnoreSect ();
  293. break;
  294. }
  295. break;
  296. default:
  297. throw NotWFError ("Syntax Error after '<!' characters.");
  298. }
  299. }
  300. private void ReadIgnoreSect ()
  301. {
  302. ExpectAfterWhitespace ('[');
  303. int dtdIgnoreSect = 1;
  304. while (dtdIgnoreSect > 0) {
  305. switch (ReadChar ()) {
  306. case -1:
  307. throw NotWFError ("Unexpected IGNORE section end.");
  308. case '<':
  309. if (PeekChar () != '!')
  310. break;
  311. ReadChar ();
  312. if (PeekChar () != '[')
  313. break;
  314. ReadChar ();
  315. dtdIgnoreSect++;
  316. break;
  317. case ']':
  318. if (PeekChar () != ']')
  319. break;
  320. ReadChar ();
  321. if (PeekChar () != '>')
  322. break;
  323. ReadChar ();
  324. dtdIgnoreSect--;
  325. break;
  326. }
  327. }
  328. if (dtdIgnoreSect != 0)
  329. throw NotWFError ("IGNORE section is not ended correctly.");
  330. }
  331. // The reader is positioned on the head of the name.
  332. private DTDElementDeclaration ReadElementDecl ()
  333. {
  334. DTDElementDeclaration decl = new DTDElementDeclaration (DTD);
  335. decl.IsInternalSubset = this.processingInternalSubset;
  336. if (!SkipWhitespace ())
  337. throw NotWFError ("Whitespace is required between '<!ELEMENT' and name in DTD element declaration.");
  338. TryExpandPERef ();
  339. decl.Name = ReadName ();
  340. if (!SkipWhitespace ())
  341. throw NotWFError ("Whitespace is required between name and content in DTD element declaration.");
  342. TryExpandPERef ();
  343. ReadContentSpec (decl);
  344. SkipWhitespace ();
  345. // This expanding is only allowed as a non-validating parser.
  346. TryExpandPERef ();
  347. Expect ('>');
  348. return decl;
  349. }
  350. // read 'children'(BNF) of contentspec
  351. private void ReadContentSpec (DTDElementDeclaration decl)
  352. {
  353. TryExpandPERef ();
  354. switch(ReadChar ())
  355. {
  356. case 'E':
  357. decl.IsEmpty = true;
  358. Expect ("MPTY");
  359. break;
  360. case 'A':
  361. decl.IsAny = true;
  362. Expect ("NY");
  363. break;
  364. case '(':
  365. DTDContentModel model = decl.ContentModel;
  366. SkipWhitespace ();
  367. TryExpandPERef ();
  368. if(PeekChar () == '#') {
  369. // Mixed Contents. "#PCDATA" must appear first.
  370. decl.IsMixedContent = true;
  371. model.Occurence = DTDOccurence.ZeroOrMore;
  372. model.OrderType = DTDContentOrderType.Or;
  373. Expect ("#PCDATA");
  374. SkipWhitespace ();
  375. TryExpandPERef ();
  376. while(PeekChar () != ')') {
  377. SkipWhitespace ();
  378. if (PeekChar () == '%') {
  379. TryExpandPERef ();
  380. continue;
  381. }
  382. Expect('|');
  383. SkipWhitespace ();
  384. TryExpandPERef ();
  385. DTDContentModel elem = new DTDContentModel (DTD, decl.Name);
  386. // elem.LineNumber = currentInput.LineNumber;
  387. // elem.LinePosition = currentInput.LinePosition;
  388. elem.ElementName = ReadName ();
  389. this.AddContentModel (model.ChildModels, elem);
  390. SkipWhitespace ();
  391. TryExpandPERef ();
  392. }
  393. Expect (')');
  394. if (model.ChildModels.Count > 0)
  395. Expect ('*');
  396. else if (PeekChar () == '*')
  397. Expect ('*');
  398. } else {
  399. // Non-Mixed Contents
  400. model.ChildModels.Add (ReadCP (decl));
  401. SkipWhitespace ();
  402. do { // copied from ReadCP() ...;-)
  403. if (PeekChar () == '%') {
  404. TryExpandPERef ();
  405. continue;
  406. }
  407. if(PeekChar ()=='|') {
  408. // CPType=Or
  409. if (model.OrderType == DTDContentOrderType.Seq)
  410. throw NotWFError ("Inconsistent choice markup in sequence cp.");
  411. model.OrderType = DTDContentOrderType.Or;
  412. ReadChar ();
  413. SkipWhitespace ();
  414. AddContentModel (model.ChildModels, ReadCP (decl));
  415. SkipWhitespace ();
  416. }
  417. else if(PeekChar () == ',')
  418. {
  419. // CPType=Seq
  420. if (model.OrderType == DTDContentOrderType.Or)
  421. throw NotWFError ("Inconsistent sequence markup in choice cp.");
  422. model.OrderType = DTDContentOrderType.Seq;
  423. ReadChar ();
  424. SkipWhitespace ();
  425. model.ChildModels.Add (ReadCP (decl));
  426. SkipWhitespace ();
  427. }
  428. else
  429. break;
  430. }
  431. while(true);
  432. Expect (')');
  433. switch(PeekChar ())
  434. {
  435. case '?':
  436. model.Occurence = DTDOccurence.Optional;
  437. ReadChar ();
  438. break;
  439. case '*':
  440. model.Occurence = DTDOccurence.ZeroOrMore;
  441. ReadChar ();
  442. break;
  443. case '+':
  444. model.Occurence = DTDOccurence.OneOrMore;
  445. ReadChar ();
  446. break;
  447. }
  448. SkipWhitespace ();
  449. }
  450. SkipWhitespace ();
  451. break;
  452. default:
  453. throw NotWFError ("ContentSpec is missing.");
  454. }
  455. }
  456. // Read 'cp' (BNF) of contentdecl (BNF)
  457. private DTDContentModel ReadCP (DTDElementDeclaration elem)
  458. {
  459. DTDContentModel model = null;
  460. TryExpandPERef ();
  461. if(PeekChar () == '(') {
  462. model = new DTDContentModel (DTD, elem.Name);
  463. ReadChar ();
  464. SkipWhitespace ();
  465. model.ChildModels.Add (ReadCP (elem));
  466. SkipWhitespace ();
  467. do {
  468. if (PeekChar () == '%') {
  469. TryExpandPERef ();
  470. continue;
  471. }
  472. if(PeekChar ()=='|') {
  473. // CPType=Or
  474. if (model.OrderType == DTDContentOrderType.Seq)
  475. throw NotWFError ("Inconsistent choice markup in sequence cp.");
  476. model.OrderType = DTDContentOrderType.Or;
  477. ReadChar ();
  478. SkipWhitespace ();
  479. AddContentModel (model.ChildModels, ReadCP (elem));
  480. SkipWhitespace ();
  481. }
  482. else if(PeekChar () == ',') {
  483. // CPType=Seq
  484. if (model.OrderType == DTDContentOrderType.Or)
  485. throw NotWFError ("Inconsistent sequence markup in choice cp.");
  486. model.OrderType = DTDContentOrderType.Seq;
  487. ReadChar ();
  488. SkipWhitespace ();
  489. model.ChildModels.Add (ReadCP (elem));
  490. SkipWhitespace ();
  491. }
  492. else
  493. break;
  494. }
  495. while(true);
  496. ExpectAfterWhitespace (')');
  497. }
  498. else {
  499. TryExpandPERef ();
  500. model = new DTDContentModel (DTD, elem.Name);
  501. model.ElementName = ReadName ();
  502. }
  503. switch(PeekChar ()) {
  504. case '?':
  505. model.Occurence = DTDOccurence.Optional;
  506. ReadChar ();
  507. break;
  508. case '*':
  509. model.Occurence = DTDOccurence.ZeroOrMore;
  510. ReadChar ();
  511. break;
  512. case '+':
  513. model.Occurence = DTDOccurence.OneOrMore;
  514. ReadChar ();
  515. break;
  516. }
  517. return model;
  518. }
  519. private void AddContentModel (DTDContentModelCollection cmc, DTDContentModel cm)
  520. {
  521. if (cm.ElementName != null) {
  522. for (int i = 0; i < cmc.Count; i++) {
  523. if (cmc [i].ElementName == cm.ElementName) {
  524. HandleError (new XmlSchemaException ("Element content must be unique inside mixed content model.",
  525. this.LineNumber,
  526. this.LinePosition,
  527. null,
  528. this.BaseURI,
  529. null));
  530. return;
  531. }
  532. }
  533. }
  534. cmc.Add (cm);
  535. }
  536. // The reader is positioned on the first name char.
  537. private void ReadParameterEntityDecl ()
  538. {
  539. DTDParameterEntityDeclaration decl =
  540. new DTDParameterEntityDeclaration (DTD);
  541. decl.BaseURI = BaseURI;
  542. decl.Name = ReadName ();
  543. if (!SkipWhitespace ())
  544. throw NotWFError ("Whitespace is required after name in DTD parameter entity declaration.");
  545. if (PeekChar () == 'S' || PeekChar () == 'P') {
  546. // read publicId/systemId
  547. ReadExternalID ();
  548. decl.PublicId = cachedPublicId;
  549. decl.SystemId = cachedSystemId;
  550. SkipWhitespace ();
  551. decl.Resolve (this.DTD.Resolver);
  552. ResolveExternalEntityReplacementText (decl);
  553. } else {
  554. TryExpandPERef ();
  555. int quoteChar = ReadChar ();
  556. if (quoteChar != '\'' && quoteChar != '"')
  557. throw NotWFError ("quotation char was expected.");
  558. ClearValueBuffer ();
  559. bool loop = true;
  560. while (loop) {
  561. int c = ReadChar ();
  562. switch (c) {
  563. case -1:
  564. throw NotWFError ("unexpected end of stream in entity value definition.");
  565. case '"':
  566. if (quoteChar == '"')
  567. loop = false;
  568. else
  569. AppendValueChar ('"');
  570. break;
  571. case '\'':
  572. if (quoteChar == '\'')
  573. loop = false;
  574. else
  575. AppendValueChar ('\'');
  576. break;
  577. default:
  578. if (XmlChar.IsInvalid (c))
  579. throw NotWFError ("Invalid character was used to define parameter entity.");
  580. AppendValueChar (c);
  581. break;
  582. }
  583. }
  584. decl.LiteralEntityValue = CreateValueString ();
  585. ClearValueBuffer ();
  586. ResolveInternalEntityReplacementText (decl);
  587. }
  588. ExpectAfterWhitespace ('>');
  589. if (DTD.PEDecls [decl.Name] == null) {
  590. DTD.PEDecls.Add (decl.Name, decl);
  591. }
  592. }
  593. private void ResolveExternalEntityReplacementText (DTDEntityBase decl)
  594. {
  595. if (decl.LiteralEntityValue.StartsWith ("<?xml")) {
  596. XmlTextReader xtr = new XmlTextReader (decl.LiteralEntityValue, XmlNodeType.Element, null);
  597. if (decl is DTDEntityDeclaration) {
  598. // GE - also checked as valid contents
  599. StringBuilder sb = new StringBuilder ();
  600. xtr.Normalization = this.Normalization;
  601. xtr.Read ();
  602. while (!xtr.EOF)
  603. sb.Append (xtr.ReadOuterXml ());
  604. decl.ReplacementText = sb.ToString ();
  605. }
  606. else
  607. // PE
  608. decl.ReplacementText = xtr.GetRemainder ().ReadToEnd ();
  609. }
  610. else
  611. decl.ReplacementText = decl.LiteralEntityValue;
  612. }
  613. private void ResolveInternalEntityReplacementText (DTDEntityBase decl)
  614. {
  615. string value = decl.LiteralEntityValue;
  616. int len = value.Length;
  617. ClearValueBuffer ();
  618. for (int i = 0; i < len; i++) {
  619. int ch = value [i];
  620. int end = 0;
  621. string name;
  622. switch (ch) {
  623. case '&':
  624. i++;
  625. end = value.IndexOf (';', i);
  626. if (end < i + 1)
  627. throw new XmlException (decl, decl.BaseURI, "Invalid reference markup.");
  628. // expand charref
  629. if (value [i] == '#') {
  630. i++;
  631. ch = GetCharacterReference (decl, value, ref i, end);
  632. if (XmlChar.IsInvalid (ch))
  633. throw NotWFError ("Invalid character was used to define parameter entity.");
  634. } else {
  635. name = value.Substring (i, end - i);
  636. // don't expand "general" entity.
  637. AppendValueChar ('&');
  638. valueBuffer.Append (name);
  639. AppendValueChar (';');
  640. i = end;
  641. break;
  642. }
  643. if (XmlChar.IsInvalid (ch))
  644. throw new XmlException (decl, decl.BaseURI, "Invalid character was found in the entity declaration.");
  645. AppendValueChar (ch);
  646. break;
  647. case '%':
  648. i++;
  649. end = value.IndexOf (';', i);
  650. if (end < i + 1)
  651. throw new XmlException (decl, decl.BaseURI, "Invalid reference markup.");
  652. name = value.Substring (i, end - i);
  653. valueBuffer.Append (GetPEValue (name));
  654. i = end;
  655. break;
  656. default:
  657. AppendValueChar (ch);
  658. break;
  659. }
  660. }
  661. decl.ReplacementText = CreateValueString ();
  662. if (decl is DTDEntityDeclaration) {
  663. // GE - also checked as valid contents
  664. XmlTextReader xtr = new XmlTextReader (decl.ReplacementText, XmlNodeType.Element, null);
  665. StringBuilder sb = new StringBuilder ();
  666. xtr.Normalization = this.Normalization;
  667. xtr.Read ();
  668. while (!xtr.EOF)
  669. sb.Append (xtr.ReadOuterXml ());
  670. decl.ReplacementText = sb.ToString ();
  671. }
  672. ClearValueBuffer ();
  673. }
  674. private int GetCharacterReference (DTDEntityBase li, string value, ref int index, int end)
  675. {
  676. int ret = 0;
  677. if (value [index] == 'x') {
  678. try {
  679. ret = int.Parse (value.Substring (index + 1, end - index - 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
  680. } catch (FormatException) {
  681. throw new XmlException (li, li.BaseURI, "Invalid number for a character reference.");
  682. }
  683. } else {
  684. try {
  685. ret = int.Parse (value.Substring (index, end - index), CultureInfo.InvariantCulture);
  686. } catch (FormatException) {
  687. throw new XmlException (li, li.BaseURI, "Invalid number for a character reference.");
  688. }
  689. }
  690. index = end;
  691. return ret;
  692. }
  693. private string GetPEValue (string peName)
  694. {
  695. DTDParameterEntityDeclaration peDecl =
  696. DTD.PEDecls [peName] as DTDParameterEntityDeclaration;
  697. if (peDecl != null) {
  698. if (peDecl.IsInternalSubset)
  699. throw NotWFError ("Parameter entity is not allowed in internal subset entity '" + peName + "'");
  700. return peDecl.ReplacementText;
  701. }
  702. // See XML 1.0 section 4.1 for both WFC and VC.
  703. if ((DTD.SystemId == null && !DTD.InternalSubsetHasPEReference) || DTD.IsStandalone)
  704. throw NotWFError (String.Format ("Parameter entity '{0}' not found.",peName));
  705. HandleError (new XmlSchemaException (
  706. "Parameter entity " + peName + " not found.", null));
  707. return "";
  708. }
  709. private bool TryExpandPERef ()
  710. {
  711. if (PeekChar () != '%')
  712. return false;
  713. while (PeekChar () == '%') {
  714. TryExpandPERefSpaceKeep ();
  715. SkipWhitespace ();
  716. }
  717. return true;
  718. }
  719. // Tries to expand parameter entities, but it should not skip spaces
  720. private bool TryExpandPERefSpaceKeep ()
  721. {
  722. if (PeekChar () == '%') {
  723. if (this.processingInternalSubset)
  724. throw NotWFError ("Parameter entity reference is not allowed inside internal subset.");
  725. ReadChar ();
  726. ExpandPERef ();
  727. return true;
  728. }
  729. else
  730. return false;
  731. }
  732. // reader is positioned after '%'
  733. private void ExpandPERef ()
  734. {
  735. string peName = ReadName ();
  736. Expect (';');
  737. DTDParameterEntityDeclaration peDecl =
  738. DTD.PEDecls [peName] as DTDParameterEntityDeclaration;
  739. if (peDecl == null) {
  740. HandleError (new XmlSchemaException ("Parameter entity " + peName + " not found.", null));
  741. return; // do nothing
  742. }
  743. // FIXME: These leading/trailing ' ' is anyways supplied inside this method!
  744. // currentInput.InsertParameterEntityBuffer (" " + peDecl.ReplacementText + " ");
  745. currentInput.InsertParameterEntityBuffer (peDecl.ReplacementText);
  746. }
  747. // The reader is positioned on the head of the name.
  748. private DTDEntityDeclaration ReadEntityDecl ()
  749. {
  750. DTDEntityDeclaration decl = new DTDEntityDeclaration (DTD);
  751. decl.IsInternalSubset = this.processingInternalSubset;
  752. TryExpandPERef ();
  753. decl.Name = ReadName ();
  754. if (!SkipWhitespace ())
  755. throw NotWFError ("Whitespace is required between name and content in DTD entity declaration.");
  756. TryExpandPERef ();
  757. if (PeekChar () == 'S' || PeekChar () == 'P') {
  758. // external entity
  759. ReadExternalID ();
  760. decl.PublicId = cachedPublicId;
  761. decl.SystemId = cachedSystemId;
  762. if (SkipWhitespace ()) {
  763. if (PeekChar () == 'N') {
  764. // NDataDecl
  765. Expect ("NDATA");
  766. if (!SkipWhitespace ())
  767. throw NotWFError ("Whitespace is required after NDATA.");
  768. decl.NotationName = ReadName (); // ndata_name
  769. }
  770. }
  771. if (decl.NotationName == null) {
  772. decl.Resolve (this.DTD.Resolver);
  773. ResolveExternalEntityReplacementText (decl);
  774. } else {
  775. // Unparsed entity.
  776. decl.LiteralEntityValue = String.Empty;
  777. decl.ReplacementText = String.Empty;
  778. }
  779. }
  780. else {
  781. // literal entity
  782. ReadEntityValueDecl (decl);
  783. ResolveInternalEntityReplacementText (decl);
  784. }
  785. SkipWhitespace ();
  786. // This expanding is only allowed as a non-validating parser.
  787. TryExpandPERef ();
  788. Expect ('>');
  789. return decl;
  790. }
  791. private void ReadEntityValueDecl (DTDEntityDeclaration decl)
  792. {
  793. SkipWhitespace ();
  794. // quotation char will be finally removed on unescaping
  795. int quoteChar = ReadChar ();
  796. if (quoteChar != '\'' && quoteChar != '"')
  797. throw NotWFError ("quotation char was expected.");
  798. ClearValueBuffer ();
  799. while (PeekChar () != quoteChar) {
  800. int ch = ReadChar ();
  801. switch (ch) {
  802. case '%':
  803. string name = ReadName ();
  804. Expect (';');
  805. if (decl.IsInternalSubset)
  806. throw NotWFError (String.Format ("Parameter entity is not allowed in internal subset entity '{0}'", name));
  807. valueBuffer.Append (GetPEValue (name));
  808. break;
  809. case -1:
  810. throw NotWFError ("unexpected end of stream.");
  811. default:
  812. if (this.normalization && XmlChar.IsInvalid (ch))
  813. throw NotWFError ("Invalid character was found in the entity declaration.");
  814. AppendValueChar (ch);
  815. break;
  816. }
  817. }
  818. // string value = Dereference (CreateValueString (), false);
  819. string value = CreateValueString ();
  820. ClearValueBuffer ();
  821. Expect (quoteChar);
  822. decl.LiteralEntityValue = value;
  823. }
  824. private DTDAttListDeclaration ReadAttListDecl ()
  825. {
  826. TryExpandPERefSpaceKeep ();
  827. if (!SkipWhitespace ())
  828. throw NotWFError ("Whitespace is required between ATTLIST and name in DTD attlist declaration.");
  829. TryExpandPERef ();
  830. string name = ReadName (); // target element name
  831. DTDAttListDeclaration decl =
  832. DTD.AttListDecls [name] as DTDAttListDeclaration;
  833. if (decl == null)
  834. decl = new DTDAttListDeclaration (DTD);
  835. decl.IsInternalSubset = this.processingInternalSubset;
  836. decl.Name = name;
  837. if (!SkipWhitespace ())
  838. if (PeekChar () != '>')
  839. throw NotWFError ("Whitespace is required between name and content in non-empty DTD attlist declaration.");
  840. TryExpandPERef ();
  841. while (XmlChar.IsNameChar (PeekChar ())) {
  842. DTDAttributeDefinition def = ReadAttributeDefinition ();
  843. // There must not be two or more ID attributes.
  844. if (def.Datatype.TokenizedType == XmlTokenizedType.ID) {
  845. for (int i = 0; i < decl.Definitions.Count; i++) {
  846. DTDAttributeDefinition d = decl [i];
  847. if (d.Datatype.TokenizedType == XmlTokenizedType.ID) {
  848. HandleError (new XmlSchemaException ("AttList declaration must not contain two or more ID attributes.",
  849. def.LineNumber, def.LinePosition, null, def.BaseURI, null));
  850. break;
  851. }
  852. }
  853. }
  854. if (decl [def.Name] == null)
  855. decl.Add (def);
  856. SkipWhitespace ();
  857. TryExpandPERef ();
  858. }
  859. SkipWhitespace ();
  860. // This expanding is only allowed as a non-validating parser.
  861. TryExpandPERef ();
  862. Expect ('>');
  863. return decl;
  864. }
  865. private DTDAttributeDefinition ReadAttributeDefinition ()
  866. {
  867. DTDAttributeDefinition def = new DTDAttributeDefinition (DTD);
  868. def.IsInternalSubset = this.processingInternalSubset;
  869. // attr_name
  870. TryExpandPERef ();
  871. def.Name = ReadName ();
  872. if (!SkipWhitespace ())
  873. throw NotWFError ("Whitespace is required between name and content in DTD attribute definition.");
  874. // attr_value
  875. TryExpandPERef ();
  876. switch(PeekChar ()) {
  877. case 'C': // CDATA
  878. Expect ("CDATA");
  879. def.Datatype = XmlSchemaDatatype.FromName ("normalizedString", XmlSchema.Namespace);
  880. break;
  881. case 'I': // ID, IDREF, IDREFS
  882. Expect ("ID");
  883. if(PeekChar () == 'R') {
  884. Expect ("REF");
  885. if(PeekChar () == 'S') {
  886. // IDREFS
  887. ReadChar ();
  888. def.Datatype = XmlSchemaDatatype.FromName ("IDREFS", XmlSchema.Namespace);
  889. }
  890. else // IDREF
  891. def.Datatype = XmlSchemaDatatype.FromName ("IDREF", XmlSchema.Namespace);
  892. }
  893. else // ID
  894. def.Datatype = XmlSchemaDatatype.FromName ("ID", XmlSchema.Namespace);
  895. break;
  896. case 'E': // ENTITY, ENTITIES
  897. Expect ("ENTIT");
  898. switch(ReadChar ()) {
  899. case 'Y': // ENTITY
  900. def.Datatype = XmlSchemaDatatype.FromName ("ENTITY", XmlSchema.Namespace);
  901. break;
  902. case 'I': // ENTITIES
  903. Expect ("ES");
  904. def.Datatype = XmlSchemaDatatype.FromName ("ENTITIES", XmlSchema.Namespace);
  905. break;
  906. }
  907. break;
  908. case 'N': // NMTOKEN, NMTOKENS, NOTATION
  909. ReadChar ();
  910. switch(PeekChar ()) {
  911. case 'M':
  912. Expect ("MTOKEN");
  913. if(PeekChar ()=='S') { // NMTOKENS
  914. ReadChar ();
  915. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKENS", XmlSchema.Namespace);
  916. }
  917. else // NMTOKEN
  918. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN", XmlSchema.Namespace);
  919. break;
  920. case 'O':
  921. Expect ("OTATION");
  922. def.Datatype = XmlSchemaDatatype.FromName ("NOTATION", XmlSchema.Namespace);
  923. if (!SkipWhitespace ())
  924. throw NotWFError ("Whitespace is required between name and content in DTD attribute definition.");
  925. Expect ('(');
  926. SkipWhitespace ();
  927. def.EnumeratedNotations.Add (ReadName ()); // notation name
  928. SkipWhitespace ();
  929. while(PeekChar () == '|') {
  930. ReadChar ();
  931. SkipWhitespace ();
  932. def.EnumeratedNotations.Add (ReadName ()); // notation name
  933. SkipWhitespace ();
  934. }
  935. Expect (')');
  936. break;
  937. default:
  938. throw NotWFError ("attribute declaration syntax error.");
  939. }
  940. break;
  941. default: // Enumerated Values
  942. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN", XmlSchema.Namespace);
  943. TryExpandPERef ();
  944. Expect ('(');
  945. SkipWhitespace ();
  946. def.EnumeratedAttributeDeclaration.Add (
  947. def.Datatype.Normalize (ReadNmToken ())); // enum value
  948. SkipWhitespace ();
  949. while(PeekChar () == '|') {
  950. ReadChar ();
  951. SkipWhitespace ();
  952. def.EnumeratedAttributeDeclaration.Add (
  953. def.Datatype.Normalize (ReadNmToken ())); // enum value
  954. SkipWhitespace ();
  955. }
  956. Expect (')');
  957. break;
  958. }
  959. TryExpandPERefSpaceKeep ();
  960. if (!SkipWhitespace ())
  961. throw NotWFError ("Whitespace is required between type and occurence in DTD attribute definition.");
  962. // def_value
  963. ReadAttributeDefaultValue (def);
  964. return def;
  965. }
  966. private void ReadAttributeDefaultValue (DTDAttributeDefinition def)
  967. {
  968. if(PeekChar () == '#')
  969. {
  970. ReadChar ();
  971. switch(PeekChar ())
  972. {
  973. case 'R':
  974. Expect ("REQUIRED");
  975. def.OccurenceType = DTDAttributeOccurenceType.Required;
  976. break;
  977. case 'I':
  978. Expect ("IMPLIED");
  979. def.OccurenceType = DTDAttributeOccurenceType.Optional;
  980. break;
  981. case 'F':
  982. Expect ("FIXED");
  983. def.OccurenceType = DTDAttributeOccurenceType.Fixed;
  984. if (!SkipWhitespace ())
  985. throw NotWFError ("Whitespace is required between FIXED and actual value in DTD attribute definition.");
  986. def.UnresolvedDefaultValue = ReadDefaultAttribute ();
  987. break;
  988. }
  989. } else {
  990. // one of the enumerated value
  991. SkipWhitespace ();
  992. TryExpandPERef ();
  993. def.UnresolvedDefaultValue = ReadDefaultAttribute ();
  994. }
  995. // VC: If default value exists, it should be valid.
  996. if (def.DefaultValue != null) {
  997. string normalized = def.Datatype.Normalize (def.DefaultValue);
  998. bool breakup = false;
  999. object parsed = null;
  1000. // enumeration validity
  1001. if (def.EnumeratedAttributeDeclaration.Count > 0) {
  1002. if (!def.EnumeratedAttributeDeclaration.Contains (normalized)) {
  1003. HandleError (new XmlSchemaException ("Default value is not one of the enumerated values.",
  1004. def.LineNumber, def.LinePosition, null, def.BaseURI, null));
  1005. breakup = true;
  1006. }
  1007. }
  1008. if (def.EnumeratedNotations.Count > 0) {
  1009. if (!def.EnumeratedNotations.Contains (normalized)) {
  1010. HandleError (new XmlSchemaException ("Default value is not one of the enumerated notation values.",
  1011. def.LineNumber, def.LinePosition, null, def.BaseURI, null));
  1012. breakup = true;
  1013. }
  1014. }
  1015. // type based validity
  1016. if (!breakup) {
  1017. try {
  1018. parsed = def.Datatype.ParseValue (normalized, DTD.NameTable, null);
  1019. } catch (Exception ex) { // FIXME: (wishlist) bad catch ;-(
  1020. HandleError (new XmlSchemaException ("Invalid default value for ENTITY type.",
  1021. def.LineNumber, def.LinePosition, null, def.BaseURI, ex));
  1022. breakup = true;
  1023. }
  1024. }
  1025. if (!breakup) {
  1026. switch (def.Datatype.TokenizedType) {
  1027. case XmlTokenizedType.ENTITY:
  1028. if (DTD.EntityDecls [normalized] == null)
  1029. HandleError (new XmlSchemaException ("Specified entity declaration used by default attribute value was not found.",
  1030. def.LineNumber, def.LinePosition, null, def.BaseURI, null));
  1031. break;
  1032. case XmlTokenizedType.ENTITIES:
  1033. string [] entities = parsed as string [];
  1034. for (int i = 0; i < entities.Length; i++) {
  1035. string entity = entities [i];
  1036. if (DTD.EntityDecls [entity] == null)
  1037. HandleError (new XmlSchemaException ("Specified entity declaration used by default attribute value was not found.",
  1038. def.LineNumber, def.LinePosition, null, def.BaseURI, null));
  1039. }
  1040. break;
  1041. }
  1042. }
  1043. }
  1044. // Extra ID attribute validity check.
  1045. if (def.Datatype != null && def.Datatype.TokenizedType == XmlTokenizedType.ID)
  1046. if (def.UnresolvedDefaultValue != null)
  1047. HandleError (new XmlSchemaException ("ID attribute must not have fixed value constraint.",
  1048. def.LineNumber, def.LinePosition, null, def.BaseURI, null));
  1049. }
  1050. private DTDNotationDeclaration ReadNotationDecl()
  1051. {
  1052. DTDNotationDeclaration decl = new DTDNotationDeclaration (DTD);
  1053. if (!SkipWhitespace ())
  1054. throw NotWFError ("Whitespace is required between NOTATION and name in DTD notation declaration.");
  1055. TryExpandPERef ();
  1056. decl.Name = ReadName (); // notation name
  1057. /*
  1058. if (namespaces) { // copy from SetProperties ;-)
  1059. int indexOfColon = decl.Name.IndexOf (':');
  1060. if (indexOfColon == -1) {
  1061. decl.Prefix = String.Empty;
  1062. decl.LocalName = decl.Name;
  1063. } else {
  1064. decl.Prefix = decl.Name.Substring (0, indexOfColon);
  1065. decl.LocalName = decl.Name.Substring (indexOfColon + 1);
  1066. }
  1067. } else {
  1068. */
  1069. decl.Prefix = String.Empty;
  1070. decl.LocalName = decl.Name;
  1071. // }
  1072. SkipWhitespace ();
  1073. if(PeekChar () == 'P') {
  1074. decl.PublicId = ReadPubidLiteral ();
  1075. bool wsSkipped = SkipWhitespace ();
  1076. if (PeekChar () == '\'' || PeekChar () == '"') {
  1077. if (!wsSkipped)
  1078. throw NotWFError ("Whitespace is required between public id and system id.");
  1079. decl.SystemId = ReadSystemLiteral (false);
  1080. SkipWhitespace ();
  1081. }
  1082. } else if(PeekChar () == 'S') {
  1083. decl.SystemId = ReadSystemLiteral (true);
  1084. SkipWhitespace ();
  1085. }
  1086. if(decl.PublicId == null && decl.SystemId == null)
  1087. throw NotWFError ("public or system declaration required for \"NOTATION\" declaration.");
  1088. // This expanding is only allowed as a non-validating parser.
  1089. TryExpandPERef ();
  1090. Expect ('>');
  1091. return decl;
  1092. }
  1093. private void ReadExternalID () {
  1094. switch (PeekChar ()) {
  1095. case 'S':
  1096. cachedSystemId = ReadSystemLiteral (true);
  1097. break;
  1098. case 'P':
  1099. cachedPublicId = ReadPubidLiteral ();
  1100. if (!SkipWhitespace ())
  1101. throw NotWFError ("Whitespace is required between PUBLIC id and SYSTEM id.");
  1102. cachedSystemId = ReadSystemLiteral (false);
  1103. break;
  1104. }
  1105. }
  1106. // The reader is positioned on the first 'S' of "SYSTEM".
  1107. private string ReadSystemLiteral (bool expectSYSTEM)
  1108. {
  1109. if(expectSYSTEM) {
  1110. Expect ("SYSTEM");
  1111. if (!SkipWhitespace ())
  1112. throw NotWFError ("Whitespace is required after 'SYSTEM'.");
  1113. }
  1114. else
  1115. SkipWhitespace ();
  1116. int quoteChar = ReadChar (); // apos or quot
  1117. int c = 0;
  1118. ClearValueBuffer ();
  1119. while (c != quoteChar) {
  1120. c = ReadChar ();
  1121. if (c < 0)
  1122. throw NotWFError ("Unexpected end of stream in ExternalID.");
  1123. if (c != quoteChar)
  1124. AppendValueChar (c);
  1125. }
  1126. return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
  1127. }
  1128. private string ReadPubidLiteral()
  1129. {
  1130. Expect ("PUBLIC");
  1131. if (!SkipWhitespace ())
  1132. throw NotWFError ("Whitespace is required after 'PUBLIC'.");
  1133. int quoteChar = ReadChar ();
  1134. int c = 0;
  1135. ClearValueBuffer ();
  1136. while(c != quoteChar)
  1137. {
  1138. c = ReadChar ();
  1139. if(c < 0) throw NotWFError ("Unexpected end of stream in ExternalID.");
  1140. if(c != quoteChar && !XmlChar.IsPubidChar (c))
  1141. throw NotWFError (String.Format ("character '{0}' not allowed for PUBLIC ID", (char) c));
  1142. if (c != quoteChar)
  1143. AppendValueChar (c);
  1144. }
  1145. return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
  1146. }
  1147. // The reader is positioned on the first character
  1148. // of the name.
  1149. internal string ReadName ()
  1150. {
  1151. return ReadNameOrNmToken(false);
  1152. }
  1153. // The reader is positioned on the first character
  1154. // of the name.
  1155. private string ReadNmToken ()
  1156. {
  1157. return ReadNameOrNmToken(true);
  1158. }
  1159. private string ReadNameOrNmToken(bool isNameToken)
  1160. {
  1161. int ch = PeekChar ();
  1162. if(isNameToken) {
  1163. if (!XmlChar.IsNameChar (ch))
  1164. throw NotWFError (String.Format ("a nmtoken did not start with a legal character {0} ({1})", ch, (char) ch));
  1165. }
  1166. else {
  1167. if (!XmlChar.IsFirstNameChar (ch))
  1168. throw NotWFError (String.Format ("a name did not start with a legal character {0} ({1})", ch, (char) ch));
  1169. }
  1170. nameLength = 0;
  1171. AppendNameChar (ReadChar ());
  1172. while (XmlChar.IsNameChar (PeekChar ())) {
  1173. AppendNameChar (ReadChar ());
  1174. }
  1175. return CreateNameString ();
  1176. }
  1177. // Read the next character and compare it against the
  1178. // specified character.
  1179. private void Expect (int expected)
  1180. {
  1181. int ch = ReadChar ();
  1182. if (ch != expected) {
  1183. throw NotWFError (String.Format (CultureInfo.InvariantCulture,
  1184. "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
  1185. (char) expected,
  1186. expected,
  1187. (char) ch,
  1188. ch));
  1189. }
  1190. }
  1191. private void Expect (string expected)
  1192. {
  1193. int len = expected.Length;
  1194. for (int i=0; i< len; i++)
  1195. Expect (expected [i]);
  1196. }
  1197. private void ExpectAfterWhitespace (char c)
  1198. {
  1199. while (true) {
  1200. int i = ReadChar ();
  1201. if (XmlChar.IsWhitespace (i))
  1202. continue;
  1203. if (c != i)
  1204. throw NotWFError (String.Format (CultureInfo.InvariantCulture, "Expected {0} but found {1} [{2}].", c, (char) i, i));
  1205. break;
  1206. }
  1207. }
  1208. // Does not consume the first non-whitespace character.
  1209. private bool SkipWhitespace ()
  1210. {
  1211. bool skipped = XmlChar.IsWhitespace (PeekChar ());
  1212. while (XmlChar.IsWhitespace (PeekChar ()))
  1213. ReadChar ();
  1214. return skipped;
  1215. }
  1216. private int PeekChar ()
  1217. {
  1218. return currentInput.PeekChar ();
  1219. }
  1220. private int ReadChar ()
  1221. {
  1222. return currentInput.ReadChar ();
  1223. }
  1224. private string ExpandSurrogateChar (int ch)
  1225. {
  1226. if (ch < Char.MaxValue)
  1227. return ((char) ch).ToString ();
  1228. else {
  1229. char [] tmp = new char [] {(char) (ch / 0x10000 + 0xD800 - 1), (char) (ch % 0x10000 + 0xDC00)};
  1230. return new string (tmp);
  1231. }
  1232. }
  1233. // The reader is positioned on the first character after
  1234. // the leading '<!--'.
  1235. private void ReadComment ()
  1236. {
  1237. currentInput.InitialState = false;
  1238. while (PeekChar () != -1) {
  1239. int ch = ReadChar ();
  1240. if (ch == '-' && PeekChar () == '-') {
  1241. ReadChar ();
  1242. if (PeekChar () != '>')
  1243. throw NotWFError ("comments cannot contain '--'");
  1244. ReadChar ();
  1245. break;
  1246. }
  1247. if (XmlChar.IsInvalid (ch))
  1248. throw NotWFError ("Not allowed character was found.");
  1249. }
  1250. }
  1251. // The reader is positioned on the first character
  1252. // of the target.
  1253. //
  1254. // It may be xml declaration or processing instruction.
  1255. private void ReadProcessingInstruction ()
  1256. {
  1257. string target = ReadName ();
  1258. if (target == "xml") {
  1259. ReadTextDeclaration ();
  1260. return;
  1261. } else if (String.Compare (target, "xml", true, CultureInfo.InvariantCulture) == 0)
  1262. throw NotWFError ("Not allowed processing instruction name which starts with 'X', 'M', 'L' was found.");
  1263. currentInput.InitialState = false;
  1264. if (!SkipWhitespace ())
  1265. if (PeekChar () != '?')
  1266. throw NotWFError ("Invalid processing instruction name was found.");
  1267. while (PeekChar () != -1) {
  1268. int ch = ReadChar ();
  1269. if (ch == '?' && PeekChar () == '>') {
  1270. ReadChar ();
  1271. break;
  1272. }
  1273. }
  1274. }
  1275. // The reader is positioned after "<?xml "
  1276. private void ReadTextDeclaration ()
  1277. {
  1278. if (!currentInput.InitialState)
  1279. throw NotWFError ("Text declaration cannot appear in this state.");
  1280. currentInput.InitialState = false;
  1281. SkipWhitespace ();
  1282. // version decl
  1283. if (PeekChar () == 'v') {
  1284. Expect ("version");
  1285. ExpectAfterWhitespace ('=');
  1286. SkipWhitespace ();
  1287. int quoteChar = ReadChar ();
  1288. char [] expect1_0 = new char [3];
  1289. int versionLength = 0;
  1290. switch (quoteChar) {
  1291. case '\'':
  1292. case '"':
  1293. while (PeekChar () != quoteChar) {
  1294. if (PeekChar () == -1)
  1295. throw NotWFError ("Invalid version declaration inside text declaration.");
  1296. else if (versionLength == 3)
  1297. throw NotWFError ("Invalid version number inside text declaration.");
  1298. else {
  1299. expect1_0 [versionLength] = (char) ReadChar ();
  1300. versionLength++;
  1301. if (versionLength == 3 && new String (expect1_0) != "1.0")
  1302. throw NotWFError ("Invalid version number inside text declaration.");
  1303. }
  1304. }
  1305. ReadChar ();
  1306. SkipWhitespace ();
  1307. break;
  1308. default:
  1309. throw NotWFError ("Invalid version declaration inside text declaration.");
  1310. }
  1311. }
  1312. if (PeekChar () == 'e') {
  1313. Expect ("encoding");
  1314. ExpectAfterWhitespace ('=');
  1315. SkipWhitespace ();
  1316. int quoteChar = ReadChar ();
  1317. switch (quoteChar) {
  1318. case '\'':
  1319. case '"':
  1320. while (PeekChar () != quoteChar)
  1321. if (ReadChar () == -1)
  1322. throw NotWFError ("Invalid encoding declaration inside text declaration.");
  1323. ReadChar ();
  1324. SkipWhitespace ();
  1325. break;
  1326. default:
  1327. throw NotWFError ("Invalid encoding declaration inside text declaration.");
  1328. }
  1329. // Encoding value should be checked inside XmlInputStream.
  1330. }
  1331. else
  1332. throw NotWFError ("Encoding declaration is mandatory in text declaration.");
  1333. Expect ("?>");
  1334. }
  1335. // Note that now this method behaves differently from
  1336. // XmlTextReader's one. It calles AppendValueChar() internally.
  1337. private int ReadCharacterReference ()
  1338. {
  1339. int value = 0;
  1340. if (PeekChar () == 'x') {
  1341. ReadChar ();
  1342. while (PeekChar () != ';' && PeekChar () != -1) {
  1343. int ch = ReadChar ();
  1344. if (ch >= '0' && ch <= '9')
  1345. value = (value << 4) + ch - '0';
  1346. else if (ch >= 'A' && ch <= 'F')
  1347. value = (value << 4) + ch - 'A' + 10;
  1348. else if (ch >= 'a' && ch <= 'f')
  1349. value = (value << 4) + ch - 'a' + 10;
  1350. else
  1351. throw NotWFError (String.Format (
  1352. CultureInfo.InvariantCulture,
  1353. "invalid hexadecimal digit: {0} (#x{1:X})",
  1354. (char) ch,
  1355. ch));
  1356. }
  1357. } else {
  1358. while (PeekChar () != ';' && PeekChar () != -1) {
  1359. int ch = ReadChar ();
  1360. if (ch >= '0' && ch <= '9')
  1361. value = value * 10 + ch - '0';
  1362. else
  1363. throw NotWFError (String.Format (
  1364. CultureInfo.InvariantCulture,
  1365. "invalid decimal digit: {0} (#x{1:X})",
  1366. (char) ch,
  1367. ch));
  1368. }
  1369. }
  1370. ReadChar (); // ';'
  1371. // There is no way to save surrogate pairs...
  1372. if (XmlChar.IsInvalid (value))
  1373. throw NotWFError ("Referenced character was not allowed in XML.");
  1374. AppendValueChar (value);
  1375. return value;
  1376. }
  1377. private void AppendNameChar (int ch)
  1378. {
  1379. CheckNameCapacity ();
  1380. if (ch < Char.MaxValue)
  1381. nameBuffer [nameLength++] = (char) ch;
  1382. else {
  1383. nameBuffer [nameLength++] = (char) (ch / 0x10000 + 0xD800 - 1);
  1384. CheckNameCapacity ();
  1385. nameBuffer [nameLength++] = (char) (ch % 0x10000 + 0xDC00);
  1386. }
  1387. }
  1388. private void CheckNameCapacity ()
  1389. {
  1390. if (nameLength == nameCapacity) {
  1391. nameCapacity = nameCapacity * 2;
  1392. char [] oldNameBuffer = nameBuffer;
  1393. nameBuffer = new char [nameCapacity];
  1394. Array.Copy (oldNameBuffer, nameBuffer, nameLength);
  1395. }
  1396. }
  1397. private string CreateNameString ()
  1398. {
  1399. return DTD.NameTable.Add (nameBuffer, 0, nameLength);
  1400. }
  1401. private void AppendValueChar (int ch)
  1402. {
  1403. if (ch < Char.MaxValue)
  1404. valueBuffer.Append ((char) ch);
  1405. else
  1406. valueBuffer.Append (ExpandSurrogateChar (ch));
  1407. }
  1408. private string CreateValueString ()
  1409. {
  1410. return valueBuffer.ToString ();
  1411. }
  1412. private void ClearValueBuffer ()
  1413. {
  1414. valueBuffer.Length = 0;
  1415. }
  1416. // The reader is positioned on the quote character.
  1417. // *Keeps quote char* to value to get_QuoteChar() correctly.
  1418. private string ReadDefaultAttribute ()
  1419. {
  1420. ClearValueBuffer ();
  1421. int quoteChar = ReadChar ();
  1422. if (quoteChar != '\'' && quoteChar != '\"')
  1423. throw NotWFError ("an attribute value was not quoted");
  1424. AppendValueChar (quoteChar);
  1425. while (PeekChar () != quoteChar) {
  1426. int ch = ReadChar ();
  1427. switch (ch)
  1428. {
  1429. case '<':
  1430. throw NotWFError ("attribute values cannot contain '<'");
  1431. case -1:
  1432. throw NotWFError ("unexpected end of file in an attribute value");
  1433. case '&':
  1434. AppendValueChar (ch);
  1435. if (PeekChar () == '#')
  1436. break;
  1437. // Check XML 1.0 section 3.1 WFC.
  1438. string entName = ReadName ();
  1439. Expect (';');
  1440. if (XmlChar.GetPredefinedEntity (entName) < 0) {
  1441. DTDEntityDeclaration entDecl =
  1442. DTD == null ? null : DTD.EntityDecls [entName];
  1443. if (entDecl == null || entDecl.SystemId != null)
  1444. // WFC: Entity Declared (see 4.1)
  1445. if (DTD.IsStandalone || (DTD.SystemId == null && !DTD.InternalSubsetHasPEReference))
  1446. throw NotWFError ("Reference to external entities is not allowed in attribute value.");
  1447. }
  1448. valueBuffer.Append (entName);
  1449. AppendValueChar (';');
  1450. break;
  1451. default:
  1452. AppendValueChar (ch);
  1453. break;
  1454. }
  1455. }
  1456. ReadChar (); // quoteChar
  1457. AppendValueChar (quoteChar);
  1458. return CreateValueString ();
  1459. }
  1460. private void PushParserInput (string url)
  1461. {
  1462. Uri baseUri = null;
  1463. try {
  1464. if (DTD.BaseURI != null && DTD.BaseURI.Length > 0)
  1465. baseUri = new Uri (DTD.BaseURI);
  1466. } catch (UriFormatException) {
  1467. }
  1468. Uri absUri = DTD.Resolver.ResolveUri (baseUri, url);
  1469. string absPath = absUri.ToString ();
  1470. foreach (XmlParserInput i in parserInputStack.ToArray ()) {
  1471. if (i.BaseURI == absPath)
  1472. throw NotWFError ("Nested inclusion is not allowed: " + url);
  1473. }
  1474. parserInputStack.Push (currentInput);
  1475. try {
  1476. Stream s = DTD.Resolver.GetEntity (absUri, null, typeof (Stream)) as Stream;
  1477. currentInput = new XmlParserInput (new XmlStreamReader (s), absPath);
  1478. } catch (Exception ex) { // FIXME: (wishlist) Bad exception catch ;-(
  1479. int line = currentInput == null ? 0 : currentInput.LineNumber;
  1480. int col = currentInput == null ? 0 : currentInput.LinePosition;
  1481. string bu = (currentInput == null) ? String.Empty : currentInput.BaseURI;
  1482. HandleError (new XmlSchemaException ("Specified external entity not found. Target URL is " + url + " .",
  1483. line, col, null, bu, ex));
  1484. currentInput = new XmlParserInput (new StringReader (String.Empty), absPath);
  1485. }
  1486. }
  1487. private void PopParserInput ()
  1488. {
  1489. currentInput = parserInputStack.Pop () as XmlParserInput;
  1490. }
  1491. private void HandleError (XmlSchemaException ex)
  1492. {
  1493. #if DTD_HANDLE_EVENTS
  1494. if (this.ValidationEventHandler != null)
  1495. ValidationEventHandler (this, new ValidationEventArgs (ex, ex.Message, XmlSeverityType.Error));
  1496. #else
  1497. DTD.AddError (ex);
  1498. #endif
  1499. }
  1500. }
  1501. }