DTDReader.cs 42 KB

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