DTDReader.cs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647
  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 char [] nameBuffer;
  51. private int nameLength;
  52. private int nameCapacity;
  53. private const int initialNameCapacity = 256;
  54. private StringBuilder valueBuffer;
  55. private int currentLinkedNodeLineNumber;
  56. private int currentLinkedNodeLinePosition;
  57. // Parameter entity placeholder
  58. private int dtdIncludeSect;
  59. private bool normalization;
  60. private bool processingInternalSubset;
  61. string cachedPublicId;
  62. string cachedSystemId;
  63. DTDObjectModel DTD;
  64. #if DTD_HANDLE_EVENTS
  65. public event ValidationEventHandler ValidationEventHandler;
  66. #endif
  67. // .ctor()
  68. public DTDReader (DTDObjectModel dtd,
  69. int startLineNumber,
  70. int startLinePosition)
  71. {
  72. this.DTD = dtd;
  73. currentLinkedNodeLineNumber = startLineNumber;
  74. currentLinkedNodeLinePosition = startLinePosition;
  75. Init ();
  76. }
  77. // Properties
  78. public string BaseURI {
  79. get { return currentInput.BaseURI; }
  80. }
  81. public bool Normalization {
  82. get { return normalization; }
  83. set { normalization = value; }
  84. }
  85. public int LineNumber {
  86. get { return currentInput.LineNumber; }
  87. }
  88. public int LinePosition {
  89. get { return currentInput.LinePosition; }
  90. }
  91. public bool HasLineInfo ()
  92. {
  93. return true;
  94. }
  95. // Methods
  96. private XmlException NotWFError (string message)
  97. {
  98. return new XmlException (this as IXmlLineInfo, BaseURI, message);
  99. }
  100. private void Init ()
  101. {
  102. parserInputStack = new Stack ();
  103. nameBuffer = new char [initialNameCapacity];
  104. nameLength = 0;
  105. nameCapacity = initialNameCapacity;
  106. valueBuffer = new StringBuilder (512);
  107. }
  108. internal DTDObjectModel GenerateDTDObjectModel ()
  109. {
  110. // now compile DTD
  111. int originalParserDepth = parserInputStack.Count;
  112. bool more;
  113. if (DTD.InternalSubset != null && DTD.InternalSubset.Length > 0) {
  114. this.processingInternalSubset = true;
  115. XmlParserInput original = currentInput;
  116. currentInput = new XmlParserInput (
  117. new StringReader (DTD.InternalSubset),
  118. DTD.BaseURI,
  119. currentLinkedNodeLineNumber,
  120. currentLinkedNodeLinePosition);
  121. currentInput.InitialState = false;
  122. do {
  123. more = ProcessDTDSubset ();
  124. if (PeekChar () == -1 && parserInputStack.Count > 0)
  125. PopParserInput ();
  126. } while (more || parserInputStack.Count > originalParserDepth);
  127. if (dtdIncludeSect != 0)
  128. throw NotWFError ("INCLUDE section is not ended correctly.");
  129. currentInput = original;
  130. this.processingInternalSubset = false;
  131. }
  132. if (DTD.SystemId != null && DTD.SystemId != String.Empty && DTD.Resolver != null) {
  133. PushParserInput (DTD.SystemId);
  134. do {
  135. more = ProcessDTDSubset ();
  136. if (PeekChar () == -1 && parserInputStack.Count > 1)
  137. PopParserInput ();
  138. } while (more || parserInputStack.Count > originalParserDepth + 1);
  139. if (dtdIncludeSect != 0)
  140. throw NotWFError ("INCLUDE section is not ended correctly.");
  141. PopParserInput ();
  142. }
  143. ArrayList sc = new ArrayList ();
  144. // Entity recursion check.
  145. foreach (DTDEntityDeclaration ent in DTD.EntityDecls.Values) {
  146. if (ent.NotationName != null) {
  147. ent.ScanEntityValue (sc);
  148. sc.Clear ();
  149. }
  150. }
  151. // release unnecessary memory usage
  152. DTD.ExternalResources.Clear ();
  153. return DTD;
  154. }
  155. // Read any one of following:
  156. // elementdecl, AttlistDecl, EntityDecl, NotationDecl,
  157. // PI, Comment, Parameter Entity, or doctype termination char(']')
  158. //
  159. // Returns true if it may have any more contents, or false if not.
  160. private bool ProcessDTDSubset ()
  161. {
  162. SkipWhitespace ();
  163. int c2 = ReadChar ();
  164. switch(c2)
  165. {
  166. case -1:
  167. return false;
  168. case '%':
  169. // It affects on entity references' well-formedness
  170. if (this.processingInternalSubset)
  171. DTD.InternalSubsetHasPEReference = true;
  172. string peName = ReadName ();
  173. Expect (';');
  174. string peValue = GetPEValue (peName);
  175. if (peValue == String.Empty)
  176. break;
  177. currentInput.InsertParameterEntityBuffer (peValue);
  178. // int currentLine = currentInput.LineNumber;
  179. // int currentColumn = currentInput.LinePosition;
  180. while (currentInput.HasPEBuffer)
  181. ProcessDTDSubset ();
  182. SkipWhitespace ();
  183. // FIXME: Implement correct nest-level check.
  184. // Don't depend on lineinfo (might not be supplied)
  185. // if (currentInput.LineNumber != currentLine ||
  186. // currentInput.LinePosition != currentColumn)
  187. // throw NotWFError ("Incorrectly nested parameter entity.");
  188. break;
  189. case '<':
  190. int c = ReadChar ();
  191. switch(c)
  192. {
  193. case '?':
  194. // Only read, no store.
  195. ReadProcessingInstruction ();
  196. break;
  197. case '!':
  198. CompileDeclaration ();
  199. break;
  200. case -1:
  201. throw NotWFError ("Unexpected end of stream.");
  202. default:
  203. throw NotWFError ("Syntax Error after '<' character: " + (char) c);
  204. }
  205. break;
  206. case ']':
  207. if (dtdIncludeSect == 0)
  208. throw NotWFError ("Unbalanced end of INCLUDE/IGNORE section.");
  209. // End of inclusion
  210. Expect ("]>");
  211. dtdIncludeSect--;
  212. SkipWhitespace ();
  213. break;
  214. default:
  215. throw NotWFError (String.Format ("Syntax Error inside doctypedecl markup : {0}({1})", c2, (char) c2));
  216. }
  217. currentInput.InitialState = false;
  218. return true;
  219. }
  220. private void CompileDeclaration ()
  221. {
  222. switch(ReadChar ())
  223. {
  224. case '-':
  225. Expect ('-');
  226. // Only read, no store.
  227. ReadComment ();
  228. break;
  229. case 'E':
  230. switch(ReadChar ())
  231. {
  232. case 'N':
  233. Expect ("TITY");
  234. if (!SkipWhitespace ())
  235. throw NotWFError (
  236. "Whitespace is required after '<!ENTITY' in DTD entity declaration.");
  237. LOOPBACK:
  238. if (PeekChar () == '%') {
  239. ReadChar ();
  240. if (!SkipWhitespace ()) {
  241. ExpandPERef ();
  242. goto LOOPBACK;
  243. } else {
  244. // FIXME: Is this allowed? <!ENTITY % %name; ...>
  245. // (i.e. Can PE name be replaced by another PE?)
  246. TryExpandPERef ();
  247. if (XmlChar.IsNameChar (PeekChar ()))
  248. ReadParameterEntityDecl ();
  249. else
  250. throw NotWFError ("expected name character");
  251. }
  252. break;
  253. }
  254. DTDEntityDeclaration ent = ReadEntityDecl ();
  255. if (DTD.EntityDecls [ent.Name] == null)
  256. DTD.EntityDecls.Add (ent.Name, ent);
  257. break;
  258. case 'L':
  259. Expect ("EMENT");
  260. DTDElementDeclaration el = ReadElementDecl ();
  261. DTD.ElementDecls.Add (el.Name, el);
  262. break;
  263. default:
  264. throw NotWFError ("Syntax Error after '<!E' (ELEMENT or ENTITY must be found)");
  265. }
  266. break;
  267. case 'A':
  268. Expect ("TTLIST");
  269. DTDAttListDeclaration atl = ReadAttListDecl ();
  270. DTD.AttListDecls.Add (atl.Name, atl);
  271. break;
  272. case 'N':
  273. Expect ("OTATION");
  274. DTDNotationDeclaration not = ReadNotationDecl ();
  275. DTD.NotationDecls.Add (not.Name, not);
  276. break;
  277. case '[':
  278. // conditional sections
  279. SkipWhitespace ();
  280. TryExpandPERef ();
  281. Expect ('I');
  282. switch (ReadChar ()) {
  283. case 'N':
  284. Expect ("CLUDE");
  285. ExpectAfterWhitespace ('[');
  286. dtdIncludeSect++;
  287. break;
  288. case 'G':
  289. Expect ("NORE");
  290. ReadIgnoreSect ();
  291. break;
  292. }
  293. break;
  294. default:
  295. throw NotWFError ("Syntax Error after '<!' characters.");
  296. }
  297. }
  298. private void ReadIgnoreSect ()
  299. {
  300. ExpectAfterWhitespace ('[');
  301. int dtdIgnoreSect = 1;
  302. while (dtdIgnoreSect > 0) {
  303. switch (ReadChar ()) {
  304. case -1:
  305. throw NotWFError ("Unexpected IGNORE section end.");
  306. case '<':
  307. if (PeekChar () != '!')
  308. break;
  309. ReadChar ();
  310. if (PeekChar () != '[')
  311. break;
  312. ReadChar ();
  313. dtdIgnoreSect++;
  314. break;
  315. case ']':
  316. if (PeekChar () != ']')
  317. break;
  318. ReadChar ();
  319. if (PeekChar () != '>')
  320. break;
  321. ReadChar ();
  322. dtdIgnoreSect--;
  323. break;
  324. }
  325. }
  326. if (dtdIgnoreSect != 0)
  327. throw NotWFError ("IGNORE section is not ended correctly.");
  328. }
  329. // The reader is positioned on the head of the name.
  330. private DTDElementDeclaration ReadElementDecl ()
  331. {
  332. DTDElementDeclaration decl = new DTDElementDeclaration (DTD);
  333. decl.IsInternalSubset = this.processingInternalSubset;
  334. if (!SkipWhitespace ())
  335. throw NotWFError ("Whitespace is required between '<!ELEMENT' and name in DTD element declaration.");
  336. TryExpandPERef ();
  337. decl.Name = ReadName ();
  338. if (!SkipWhitespace ())
  339. throw NotWFError ("Whitespace is required between name and content in DTD element declaration.");
  340. TryExpandPERef ();
  341. ReadContentSpec (decl);
  342. SkipWhitespace ();
  343. // This expanding is only allowed as a non-validating parser.
  344. TryExpandPERef ();
  345. Expect ('>');
  346. return decl;
  347. }
  348. // read 'children'(BNF) of contentspec
  349. private void ReadContentSpec (DTDElementDeclaration decl)
  350. {
  351. TryExpandPERef ();
  352. switch(ReadChar ())
  353. {
  354. case 'E':
  355. decl.IsEmpty = true;
  356. Expect ("MPTY");
  357. break;
  358. case 'A':
  359. decl.IsAny = true;
  360. Expect ("NY");
  361. break;
  362. case '(':
  363. DTDContentModel model = decl.ContentModel;
  364. SkipWhitespace ();
  365. TryExpandPERef ();
  366. if(PeekChar () == '#') {
  367. // Mixed Contents. "#PCDATA" must appear first.
  368. decl.IsMixedContent = true;
  369. model.Occurence = DTDOccurence.ZeroOrMore;
  370. model.OrderType = DTDContentOrderType.Or;
  371. Expect ("#PCDATA");
  372. SkipWhitespace ();
  373. TryExpandPERef ();
  374. while(PeekChar () != ')') {
  375. SkipWhitespace ();
  376. if (PeekChar () == '%') {
  377. TryExpandPERef ();
  378. continue;
  379. }
  380. Expect('|');
  381. SkipWhitespace ();
  382. TryExpandPERef ();
  383. DTDContentModel elem = new DTDContentModel (DTD, decl.Name);
  384. // elem.LineNumber = currentInput.LineNumber;
  385. // elem.LinePosition = currentInput.LinePosition;
  386. elem.ElementName = ReadName ();
  387. this.AddContentModel (model.ChildModels, elem);
  388. SkipWhitespace ();
  389. TryExpandPERef ();
  390. }
  391. Expect (')');
  392. if (model.ChildModels.Count > 0)
  393. Expect ('*');
  394. else if (PeekChar () == '*')
  395. Expect ('*');
  396. } else {
  397. // Non-Mixed Contents
  398. model.ChildModels.Add (ReadCP (decl));
  399. SkipWhitespace ();
  400. do { // copied from ReadCP() ...;-)
  401. if (PeekChar () == '%') {
  402. TryExpandPERef ();
  403. continue;
  404. }
  405. if(PeekChar ()=='|') {
  406. // CPType=Or
  407. if (model.OrderType == DTDContentOrderType.Seq)
  408. throw NotWFError ("Inconsistent choice markup in sequence cp.");
  409. model.OrderType = DTDContentOrderType.Or;
  410. ReadChar ();
  411. SkipWhitespace ();
  412. AddContentModel (model.ChildModels, ReadCP (decl));
  413. SkipWhitespace ();
  414. }
  415. else if(PeekChar () == ',')
  416. {
  417. // CPType=Seq
  418. if (model.OrderType == DTDContentOrderType.Or)
  419. throw NotWFError ("Inconsistent sequence markup in choice cp.");
  420. model.OrderType = DTDContentOrderType.Seq;
  421. ReadChar ();
  422. SkipWhitespace ();
  423. model.ChildModels.Add (ReadCP (decl));
  424. SkipWhitespace ();
  425. }
  426. else
  427. break;
  428. }
  429. while(true);
  430. Expect (')');
  431. switch(PeekChar ())
  432. {
  433. case '?':
  434. model.Occurence = DTDOccurence.Optional;
  435. ReadChar ();
  436. break;
  437. case '*':
  438. model.Occurence = DTDOccurence.ZeroOrMore;
  439. ReadChar ();
  440. break;
  441. case '+':
  442. model.Occurence = DTDOccurence.OneOrMore;
  443. ReadChar ();
  444. break;
  445. }
  446. SkipWhitespace ();
  447. }
  448. SkipWhitespace ();
  449. break;
  450. default:
  451. throw NotWFError ("ContentSpec is missing.");
  452. }
  453. }
  454. // Read 'cp' (BNF) of contentdecl (BNF)
  455. private DTDContentModel ReadCP (DTDElementDeclaration elem)
  456. {
  457. DTDContentModel model = null;
  458. TryExpandPERef ();
  459. if(PeekChar () == '(') {
  460. model = new DTDContentModel (DTD, elem.Name);
  461. ReadChar ();
  462. SkipWhitespace ();
  463. model.ChildModels.Add (ReadCP (elem));
  464. SkipWhitespace ();
  465. do {
  466. if (PeekChar () == '%') {
  467. TryExpandPERef ();
  468. continue;
  469. }
  470. if(PeekChar ()=='|') {
  471. // CPType=Or
  472. if (model.OrderType == DTDContentOrderType.Seq)
  473. throw NotWFError ("Inconsistent choice markup in sequence cp.");
  474. model.OrderType = DTDContentOrderType.Or;
  475. ReadChar ();
  476. SkipWhitespace ();
  477. AddContentModel (model.ChildModels, ReadCP (elem));
  478. SkipWhitespace ();
  479. }
  480. else if(PeekChar () == ',') {
  481. // CPType=Seq
  482. if (model.OrderType == DTDContentOrderType.Or)
  483. throw NotWFError ("Inconsistent sequence markup in choice cp.");
  484. model.OrderType = DTDContentOrderType.Seq;
  485. ReadChar ();
  486. SkipWhitespace ();
  487. model.ChildModels.Add (ReadCP (elem));
  488. SkipWhitespace ();
  489. }
  490. else
  491. break;
  492. }
  493. while(true);
  494. ExpectAfterWhitespace (')');
  495. }
  496. else {
  497. TryExpandPERef ();
  498. model = new DTDContentModel (DTD, elem.Name);
  499. model.ElementName = ReadName ();
  500. }
  501. switch(PeekChar ()) {
  502. case '?':
  503. model.Occurence = DTDOccurence.Optional;
  504. ReadChar ();
  505. break;
  506. case '*':
  507. model.Occurence = DTDOccurence.ZeroOrMore;
  508. ReadChar ();
  509. break;
  510. case '+':
  511. model.Occurence = DTDOccurence.OneOrMore;
  512. ReadChar ();
  513. break;
  514. }
  515. return model;
  516. }
  517. private void AddContentModel (DTDContentModelCollection cmc, DTDContentModel cm)
  518. {
  519. if (cm.ElementName != null) {
  520. for (int i = 0; i < cmc.Count; i++) {
  521. if (cmc [i].ElementName == cm.ElementName) {
  522. HandleError (new XmlSchemaException ("Element content must be unique inside mixed content model.",
  523. this.LineNumber,
  524. this.LinePosition,
  525. null,
  526. this.BaseURI,
  527. null));
  528. return;
  529. }
  530. }
  531. }
  532. cmc.Add (cm);
  533. }
  534. // The reader is positioned on the first name char.
  535. private void ReadParameterEntityDecl ()
  536. {
  537. DTDParameterEntityDeclaration decl =
  538. new DTDParameterEntityDeclaration (DTD);
  539. decl.BaseURI = BaseURI;
  540. decl.Name = ReadName ();
  541. if (!SkipWhitespace ())
  542. throw NotWFError ("Whitespace is required after name in DTD parameter entity declaration.");
  543. if (PeekChar () == 'S' || PeekChar () == 'P') {
  544. // read publicId/systemId
  545. ReadExternalID ();
  546. decl.PublicId = cachedPublicId;
  547. decl.SystemId = cachedSystemId;
  548. SkipWhitespace ();
  549. decl.Resolve (this.DTD.Resolver);
  550. ResolveExternalEntityReplacementText (decl);
  551. } else {
  552. TryExpandPERef ();
  553. int quoteChar = ReadChar ();
  554. if (quoteChar != '\'' && quoteChar != '"')
  555. throw NotWFError ("quotation char was expected.");
  556. ClearValueBuffer ();
  557. bool loop = true;
  558. while (loop) {
  559. int c = ReadChar ();
  560. switch (c) {
  561. case -1:
  562. throw NotWFError ("unexpected end of stream in entity value definition.");
  563. case '"':
  564. if (quoteChar == '"')
  565. loop = false;
  566. else
  567. AppendValueChar ('"');
  568. break;
  569. case '\'':
  570. if (quoteChar == '\'')
  571. loop = false;
  572. else
  573. AppendValueChar ('\'');
  574. break;
  575. default:
  576. if (XmlChar.IsInvalid (c))
  577. throw NotWFError ("Invalid character was used to define parameter entity.");
  578. AppendValueChar (c);
  579. break;
  580. }
  581. }
  582. decl.LiteralEntityValue = CreateValueString ();
  583. ClearValueBuffer ();
  584. ResolveInternalEntityReplacementText (decl);
  585. }
  586. ExpectAfterWhitespace ('>');
  587. if (DTD.PEDecls [decl.Name] == null) {
  588. DTD.PEDecls.Add (decl.Name, decl);
  589. }
  590. }
  591. private void ResolveExternalEntityReplacementText (DTDEntityBase decl)
  592. {
  593. if (decl.LiteralEntityValue.StartsWith ("<?xml")) {
  594. // FIXME: not always it should be read in Element context
  595. XmlTextReader xtr = new XmlTextReader (decl.LiteralEntityValue, XmlNodeType.Element, null);
  596. if (decl is DTDEntityDeclaration && DTD.EntityDecls [decl.Name] == null) {
  597. // GE - also checked as valid contents
  598. StringBuilder sb = new StringBuilder ();
  599. xtr.Normalization = this.Normalization;
  600. xtr.Read ();
  601. while (!xtr.EOF)
  602. sb.Append (xtr.ReadOuterXml ());
  603. decl.ReplacementText = sb.ToString ();
  604. }
  605. else
  606. // PE
  607. decl.ReplacementText = xtr.GetRemainder ().ReadToEnd ();
  608. }
  609. else
  610. decl.ReplacementText = decl.LiteralEntityValue;
  611. }
  612. private void ResolveInternalEntityReplacementText (DTDEntityBase decl)
  613. {
  614. string value = decl.LiteralEntityValue;
  615. int len = value.Length;
  616. ClearValueBuffer ();
  617. for (int i = 0; i < len; i++) {
  618. int ch = value [i];
  619. int end = 0;
  620. string name;
  621. switch (ch) {
  622. case '&':
  623. i++;
  624. end = value.IndexOf (';', i);
  625. if (end < i + 1)
  626. throw new XmlException (decl, decl.BaseURI, "Invalid reference markup.");
  627. // expand charref
  628. if (value [i] == '#') {
  629. i++;
  630. ch = GetCharacterReference (decl, value, ref i, end);
  631. if (XmlChar.IsInvalid (ch))
  632. throw NotWFError ("Invalid character was used to define parameter entity.");
  633. } else {
  634. name = value.Substring (i, end - i);
  635. // don't expand "general" entity.
  636. AppendValueChar ('&');
  637. valueBuffer.Append (name);
  638. AppendValueChar (';');
  639. i = end;
  640. break;
  641. }
  642. if (XmlChar.IsInvalid (ch))
  643. throw new XmlException (decl, decl.BaseURI, "Invalid character was found in the entity declaration.");
  644. AppendValueChar (ch);
  645. break;
  646. case '%':
  647. i++;
  648. end = value.IndexOf (';', i);
  649. if (end < i + 1)
  650. throw new XmlException (decl, decl.BaseURI, "Invalid reference markup.");
  651. name = value.Substring (i, end - i);
  652. valueBuffer.Append (GetPEValue (name));
  653. i = end;
  654. break;
  655. default:
  656. AppendValueChar (ch);
  657. break;
  658. }
  659. }
  660. decl.ReplacementText = CreateValueString ();
  661. if (decl is DTDEntityDeclaration && DTD.EntityDecls [decl.Name] == null) {
  662. // GE - also checked as valid contents
  663. // FIXME: not always it should be read in Element context
  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. // The reader is positioned on the first character after
  1225. // the leading '<!--'.
  1226. private void ReadComment ()
  1227. {
  1228. currentInput.InitialState = false;
  1229. while (PeekChar () != -1) {
  1230. int ch = ReadChar ();
  1231. if (ch == '-' && PeekChar () == '-') {
  1232. ReadChar ();
  1233. if (PeekChar () != '>')
  1234. throw NotWFError ("comments cannot contain '--'");
  1235. ReadChar ();
  1236. break;
  1237. }
  1238. if (XmlChar.IsInvalid (ch))
  1239. throw NotWFError ("Not allowed character was found.");
  1240. }
  1241. }
  1242. // The reader is positioned on the first character
  1243. // of the target.
  1244. //
  1245. // It may be xml declaration or processing instruction.
  1246. private void ReadProcessingInstruction ()
  1247. {
  1248. string target = ReadName ();
  1249. if (target == "xml") {
  1250. ReadTextDeclaration ();
  1251. return;
  1252. } else if (String.Compare (target, "xml", true, CultureInfo.InvariantCulture) == 0)
  1253. throw NotWFError ("Not allowed processing instruction name which starts with 'X', 'M', 'L' was found.");
  1254. currentInput.InitialState = false;
  1255. if (!SkipWhitespace ())
  1256. if (PeekChar () != '?')
  1257. throw NotWFError ("Invalid processing instruction name was found.");
  1258. while (PeekChar () != -1) {
  1259. int ch = ReadChar ();
  1260. if (ch == '?' && PeekChar () == '>') {
  1261. ReadChar ();
  1262. break;
  1263. }
  1264. }
  1265. }
  1266. // The reader is positioned after "<?xml "
  1267. private void ReadTextDeclaration ()
  1268. {
  1269. if (!currentInput.InitialState)
  1270. throw NotWFError ("Text declaration cannot appear in this state.");
  1271. currentInput.InitialState = false;
  1272. SkipWhitespace ();
  1273. // version decl
  1274. if (PeekChar () == 'v') {
  1275. Expect ("version");
  1276. ExpectAfterWhitespace ('=');
  1277. SkipWhitespace ();
  1278. int quoteChar = ReadChar ();
  1279. char [] expect1_0 = new char [3];
  1280. int versionLength = 0;
  1281. switch (quoteChar) {
  1282. case '\'':
  1283. case '"':
  1284. while (PeekChar () != quoteChar) {
  1285. if (PeekChar () == -1)
  1286. throw NotWFError ("Invalid version declaration inside text declaration.");
  1287. else if (versionLength == 3)
  1288. throw NotWFError ("Invalid version number inside text declaration.");
  1289. else {
  1290. expect1_0 [versionLength] = (char) ReadChar ();
  1291. versionLength++;
  1292. if (versionLength == 3 && new String (expect1_0) != "1.0")
  1293. throw NotWFError ("Invalid version number inside text declaration.");
  1294. }
  1295. }
  1296. ReadChar ();
  1297. SkipWhitespace ();
  1298. break;
  1299. default:
  1300. throw NotWFError ("Invalid version declaration inside text declaration.");
  1301. }
  1302. }
  1303. if (PeekChar () == 'e') {
  1304. Expect ("encoding");
  1305. ExpectAfterWhitespace ('=');
  1306. SkipWhitespace ();
  1307. int quoteChar = ReadChar ();
  1308. switch (quoteChar) {
  1309. case '\'':
  1310. case '"':
  1311. while (PeekChar () != quoteChar)
  1312. if (ReadChar () == -1)
  1313. throw NotWFError ("Invalid encoding declaration inside text declaration.");
  1314. ReadChar ();
  1315. SkipWhitespace ();
  1316. break;
  1317. default:
  1318. throw NotWFError ("Invalid encoding declaration inside text declaration.");
  1319. }
  1320. // Encoding value should be checked inside XmlInputStream.
  1321. }
  1322. else
  1323. throw NotWFError ("Encoding declaration is mandatory in text declaration.");
  1324. Expect ("?>");
  1325. }
  1326. // Note that now this method behaves differently from
  1327. // XmlTextReader's one. It calles AppendValueChar() internally.
  1328. private int ReadCharacterReference ()
  1329. {
  1330. int value = 0;
  1331. if (PeekChar () == 'x') {
  1332. ReadChar ();
  1333. while (PeekChar () != ';' && PeekChar () != -1) {
  1334. int ch = ReadChar ();
  1335. if (ch >= '0' && ch <= '9')
  1336. value = (value << 4) + ch - '0';
  1337. else if (ch >= 'A' && ch <= 'F')
  1338. value = (value << 4) + ch - 'A' + 10;
  1339. else if (ch >= 'a' && ch <= 'f')
  1340. value = (value << 4) + ch - 'a' + 10;
  1341. else
  1342. throw NotWFError (String.Format (
  1343. CultureInfo.InvariantCulture,
  1344. "invalid hexadecimal digit: {0} (#x{1:X})",
  1345. (char) ch,
  1346. ch));
  1347. }
  1348. } else {
  1349. while (PeekChar () != ';' && PeekChar () != -1) {
  1350. int ch = ReadChar ();
  1351. if (ch >= '0' && ch <= '9')
  1352. value = value * 10 + ch - '0';
  1353. else
  1354. throw NotWFError (String.Format (
  1355. CultureInfo.InvariantCulture,
  1356. "invalid decimal digit: {0} (#x{1:X})",
  1357. (char) ch,
  1358. ch));
  1359. }
  1360. }
  1361. ReadChar (); // ';'
  1362. // There is no way to save surrogate pairs...
  1363. if (XmlChar.IsInvalid (value))
  1364. throw NotWFError ("Referenced character was not allowed in XML.");
  1365. AppendValueChar (value);
  1366. return value;
  1367. }
  1368. private void AppendNameChar (int ch)
  1369. {
  1370. CheckNameCapacity ();
  1371. if (ch < Char.MaxValue)
  1372. nameBuffer [nameLength++] = (char) ch;
  1373. else {
  1374. nameBuffer [nameLength++] = (char) (ch / 0x10000 + 0xD800 - 1);
  1375. CheckNameCapacity ();
  1376. nameBuffer [nameLength++] = (char) (ch % 0x10000 + 0xDC00);
  1377. }
  1378. }
  1379. private void CheckNameCapacity ()
  1380. {
  1381. if (nameLength == nameCapacity) {
  1382. nameCapacity = nameCapacity * 2;
  1383. char [] oldNameBuffer = nameBuffer;
  1384. nameBuffer = new char [nameCapacity];
  1385. Array.Copy (oldNameBuffer, nameBuffer, nameLength);
  1386. }
  1387. }
  1388. private string CreateNameString ()
  1389. {
  1390. return DTD.NameTable.Add (nameBuffer, 0, nameLength);
  1391. }
  1392. private void AppendValueChar (int ch)
  1393. {
  1394. //See http://www.faqs.org/rfcs/rfc2781.html for used algorithm
  1395. if (ch < 0x10000) {
  1396. valueBuffer.Append ((char) ch);
  1397. return;
  1398. }
  1399. if (ch > 0x10FFFF)
  1400. throw new XmlException ("The numeric entity value is too large", null, LineNumber, LinePosition);
  1401. else
  1402. {
  1403. int utag = ch - 0x10000;
  1404. valueBuffer.Append((char) ((utag >> 10) + 0xD800));
  1405. valueBuffer.Append((char) ((utag & 0x3FF) + 0xDC00));
  1406. }
  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. TryExpandPERef ();
  1422. int quoteChar = ReadChar ();
  1423. if (quoteChar != '\'' && quoteChar != '\"')
  1424. throw NotWFError ("an attribute value was not quoted");
  1425. AppendValueChar (quoteChar);
  1426. while (PeekChar () != quoteChar) {
  1427. int ch = ReadChar ();
  1428. switch (ch)
  1429. {
  1430. case '<':
  1431. throw NotWFError ("attribute values cannot contain '<'");
  1432. case -1:
  1433. throw NotWFError ("unexpected end of file in an attribute value");
  1434. case '&':
  1435. AppendValueChar (ch);
  1436. if (PeekChar () == '#')
  1437. break;
  1438. // Check XML 1.0 section 3.1 WFC.
  1439. string entName = ReadName ();
  1440. Expect (';');
  1441. if (XmlChar.GetPredefinedEntity (entName) < 0) {
  1442. DTDEntityDeclaration entDecl =
  1443. DTD == null ? null : DTD.EntityDecls [entName];
  1444. if (entDecl == null || entDecl.SystemId != null)
  1445. // WFC: Entity Declared (see 4.1)
  1446. if (DTD.IsStandalone || (DTD.SystemId == null && !DTD.InternalSubsetHasPEReference))
  1447. throw NotWFError ("Reference to external entities is not allowed in attribute value.");
  1448. }
  1449. valueBuffer.Append (entName);
  1450. AppendValueChar (';');
  1451. break;
  1452. default:
  1453. AppendValueChar (ch);
  1454. break;
  1455. }
  1456. }
  1457. ReadChar (); // quoteChar
  1458. AppendValueChar (quoteChar);
  1459. return CreateValueString ();
  1460. }
  1461. private void PushParserInput (string url)
  1462. {
  1463. Uri baseUri = null;
  1464. try {
  1465. if (DTD.BaseURI != null && DTD.BaseURI.Length > 0)
  1466. baseUri = new Uri (DTD.BaseURI);
  1467. } catch (UriFormatException) {
  1468. }
  1469. Uri absUri = DTD.Resolver.ResolveUri (baseUri, url);
  1470. string absPath = absUri != null ? absUri.ToString () : String.Empty;
  1471. foreach (XmlParserInput i in parserInputStack.ToArray ()) {
  1472. if (i.BaseURI == absPath)
  1473. throw NotWFError ("Nested inclusion is not allowed: " + url);
  1474. }
  1475. parserInputStack.Push (currentInput);
  1476. Stream s = null;
  1477. try {
  1478. s = DTD.Resolver.GetEntity (absUri, null, typeof (Stream)) as Stream;
  1479. currentInput = new XmlParserInput (new XmlStreamReader (s), absPath);
  1480. } catch (Exception ex) { // FIXME: (wishlist) Bad exception catch ;-(
  1481. if (s != null)
  1482. s.Close ();
  1483. int line = currentInput == null ? 0 : currentInput.LineNumber;
  1484. int col = currentInput == null ? 0 : currentInput.LinePosition;
  1485. string bu = (currentInput == null) ? String.Empty : currentInput.BaseURI;
  1486. HandleError (new XmlSchemaException ("Specified external entity not found. Target URL is " + url + " .",
  1487. line, col, null, bu, ex));
  1488. currentInput = new XmlParserInput (new StringReader (String.Empty), absPath);
  1489. }
  1490. }
  1491. private void PopParserInput ()
  1492. {
  1493. currentInput.Close ();
  1494. currentInput = parserInputStack.Pop () as XmlParserInput;
  1495. }
  1496. private void HandleError (XmlSchemaException ex)
  1497. {
  1498. #if DTD_HANDLE_EVENTS
  1499. if (this.ValidationEventHandler != null)
  1500. ValidationEventHandler (this, new ValidationEventArgs (ex, ex.Message, XmlSeverityType.Error));
  1501. #else
  1502. DTD.AddError (ex);
  1503. #endif
  1504. }
  1505. }
  1506. }