XmlTextReader.cs 81 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121
  1. //
  2. // System.Xml.XmlTextReader
  3. //
  4. // Author:
  5. // Jason Diamond ([email protected])
  6. // Adam Treat ([email protected])
  7. // Atsushi Enomoto ([email protected])
  8. //
  9. // (C) 2001, 2002 Jason Diamond http://injektilo.org/
  10. //
  11. // FIXME:
  12. //
  13. // NameTables aren't being used completely yet.
  14. //
  15. // Some thought needs to be given to performance. There's too many
  16. // strings being allocated.
  17. //
  18. // If current node is on an Attribute, Prefix might be null, and
  19. // in several fields which uses XmlReader, it should be considered.
  20. //
  21. using System;
  22. using System.Collections;
  23. using System.Collections.Specialized;
  24. using System.IO;
  25. using System.Text;
  26. using System.Xml.Schema;
  27. using Mono.Xml;
  28. using Mono.Xml.Native;
  29. namespace System.Xml
  30. {
  31. public class XmlTextReader : XmlReader, IXmlLineInfo
  32. {
  33. #region Constructors
  34. protected XmlTextReader ()
  35. {
  36. }
  37. public XmlTextReader (Stream input)
  38. : this (new XmlStreamReader (input))
  39. {
  40. }
  41. public XmlTextReader (string url)
  42. : this(url, new NameTable ())
  43. {
  44. }
  45. public XmlTextReader (TextReader input)
  46. : this (input, new NameTable ())
  47. {
  48. }
  49. protected XmlTextReader (XmlNameTable nt)
  50. : this (String.Empty, null, XmlNodeType.None, null)
  51. {
  52. }
  53. public XmlTextReader (Stream input, XmlNameTable nt)
  54. : this(new XmlStreamReader (input), nt)
  55. {
  56. }
  57. public XmlTextReader (string url, Stream input)
  58. : this (url, new XmlStreamReader (input))
  59. {
  60. }
  61. public XmlTextReader (string url, TextReader input)
  62. : this (url, input, new NameTable ())
  63. {
  64. }
  65. public XmlTextReader (string url, XmlNameTable nt)
  66. : this (url, new XmlStreamReader (url, null, null), nt)
  67. {
  68. }
  69. public XmlTextReader (TextReader input, XmlNameTable nt)
  70. : this (String.Empty, input, nt)
  71. {
  72. }
  73. public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
  74. : this (context != null ? context.BaseURI : String.Empty,
  75. new XmlStreamReader (xmlFragment),
  76. fragType,
  77. context)
  78. {
  79. }
  80. public XmlTextReader (string url, Stream input, XmlNameTable nt)
  81. : this (url, new XmlStreamReader (input), nt)
  82. {
  83. }
  84. public XmlTextReader (string url, TextReader input, XmlNameTable nt)
  85. : this (url, input, XmlNodeType.Document, null)
  86. {
  87. }
  88. public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
  89. : this (context != null ? context.BaseURI : String.Empty,
  90. new StringReader (xmlFragment),
  91. fragType,
  92. context)
  93. {
  94. }
  95. XmlTextReader (string url, TextReader fragment, XmlNodeType fragType, XmlParserContext context)
  96. {
  97. InitializeContext (url, context, fragment, fragType);
  98. }
  99. #endregion
  100. #region Properties
  101. public override int AttributeCount
  102. {
  103. get { return attributeCount; }
  104. }
  105. public override string BaseURI
  106. {
  107. get { return parserContext.BaseURI; }
  108. }
  109. public override int Depth
  110. {
  111. get {
  112. if (currentAttributeValue >= 0)
  113. return elementDepth + 2; // inside attribute value.
  114. else if (currentAttribute >= 0)
  115. return elementDepth + 1;
  116. return elementDepth;
  117. }
  118. }
  119. public Encoding Encoding
  120. {
  121. get { return parserContext.Encoding; }
  122. }
  123. public override bool EOF
  124. {
  125. get
  126. {
  127. return
  128. readState == ReadState.EndOfFile ||
  129. readState == ReadState.Closed;
  130. }
  131. }
  132. public override bool HasValue
  133. {
  134. get {
  135. if (this.valueBuilderAvailable)
  136. return valueBuilder.Length != 0;
  137. else
  138. return cursorToken.Value != null;
  139. }
  140. }
  141. public override bool IsDefault
  142. {
  143. get
  144. {
  145. // XmlTextReader does not expand default attributes.
  146. return false;
  147. }
  148. }
  149. public override bool IsEmptyElement
  150. {
  151. get { return cursorToken.IsEmptyElement; }
  152. }
  153. public override string this [int i]
  154. {
  155. get { return GetAttribute (i); }
  156. }
  157. public override string this [string name]
  158. {
  159. get { return GetAttribute (name); }
  160. }
  161. public override string this [string localName, string namespaceName]
  162. {
  163. get { return GetAttribute (localName, namespaceName); }
  164. }
  165. public int LineNumber
  166. {
  167. get {
  168. if (useProceedingLineInfo)
  169. return currentInput.LineNumber;
  170. else
  171. return cursorToken.LineNumber;
  172. }
  173. }
  174. public int LinePosition
  175. {
  176. get {
  177. if (useProceedingLineInfo)
  178. return currentInput.LinePosition;
  179. else
  180. return cursorToken.LinePosition;
  181. }
  182. }
  183. public override string LocalName
  184. {
  185. get { return cursorToken.LocalName; }
  186. }
  187. public override string Name
  188. {
  189. get { return cursorToken.Name; }
  190. }
  191. public bool Namespaces
  192. {
  193. get { return namespaces; }
  194. set {
  195. if (readState != ReadState.Initial)
  196. throw new InvalidOperationException ("Namespaces have to be set before reading.");
  197. namespaces = value;
  198. }
  199. }
  200. public override string NamespaceURI
  201. {
  202. get { return cursorToken.NamespaceURI; }
  203. }
  204. public override XmlNameTable NameTable
  205. {
  206. get { return parserContext.NameTable; }
  207. }
  208. public override XmlNodeType NodeType
  209. {
  210. get { return cursorToken.NodeType; }
  211. }
  212. [MonoTODO]
  213. public bool Normalization
  214. {
  215. get { return normalization; }
  216. set { normalization = value; }
  217. }
  218. public override string Prefix
  219. {
  220. get { return cursorToken.Prefix; }
  221. }
  222. public override char QuoteChar
  223. {
  224. get { return cursorToken.QuoteChar; }
  225. }
  226. public override ReadState ReadState
  227. {
  228. get { return readState; }
  229. }
  230. public override string Value
  231. {
  232. get { return cursorToken.Value != null ? cursorToken.Value : String.Empty; }
  233. }
  234. public WhitespaceHandling WhitespaceHandling
  235. {
  236. get { return whitespaceHandling; }
  237. set { whitespaceHandling = value; }
  238. }
  239. public override string XmlLang
  240. {
  241. get { return parserContext.XmlLang; }
  242. }
  243. public XmlResolver XmlResolver
  244. {
  245. set { resolver = value; }
  246. }
  247. public override XmlSpace XmlSpace
  248. {
  249. get { return parserContext.XmlSpace; }
  250. }
  251. #endregion
  252. #region Methods
  253. public override void Close ()
  254. {
  255. readState = ReadState.Closed;
  256. foreach (XmlParserInput input in parserInputStack.ToArray ())
  257. input.Close ();
  258. this.currentInput.Close ();
  259. cursorToken.Clear ();
  260. currentToken.Clear ();
  261. attributeCount = 0;
  262. }
  263. public override string GetAttribute (int i)
  264. {
  265. if (i > attributeCount)
  266. throw new ArgumentOutOfRangeException ("i is smaller than AttributeCount");
  267. else {
  268. return attributeTokens [i].Value;
  269. }
  270. }
  271. // MS.NET 1.0 msdn says that this method returns String.Empty
  272. // for absent attribute, but in fact it returns null.
  273. // This description is corrected in MS.NET 1.1 msdn.
  274. public override string GetAttribute (string name)
  275. {
  276. for (int i = 0; i < attributeCount; i++)
  277. if (attributeTokens [i].Name == name)
  278. return attributeTokens [i].Value;
  279. return null;
  280. }
  281. private int GetIndexOfQualifiedAttribute (string localName, string namespaceURI)
  282. {
  283. for (int i = 0; i < attributeCount; i++) {
  284. XmlAttributeTokenInfo ti = attributeTokens [i];
  285. if (ti.LocalName == localName && ti.NamespaceURI == namespaceURI)
  286. return i;
  287. }
  288. return -1;
  289. }
  290. internal XmlParserContext GetInternalParserContext ()
  291. {
  292. return parserContext;
  293. }
  294. public override string GetAttribute (string localName, string namespaceURI)
  295. {
  296. int idx = this.GetIndexOfQualifiedAttribute (localName, namespaceURI);
  297. if (idx < 0)
  298. return null;
  299. return attributeTokens [idx].Value;
  300. }
  301. [MonoTODO]
  302. public TextReader GetRemainder ()
  303. {
  304. throw new NotImplementedException ();
  305. }
  306. bool IXmlLineInfo.HasLineInfo ()
  307. {
  308. return true;
  309. }
  310. public override string LookupNamespace (string prefix)
  311. {
  312. return parserContext.NamespaceManager.LookupNamespace (prefix);
  313. }
  314. public override void MoveToAttribute (int i)
  315. {
  316. if (i >= attributeCount)
  317. throw new ArgumentOutOfRangeException ("attribute index out of range.");
  318. currentAttribute = i;
  319. currentAttributeValue = -1;
  320. cursorToken = attributeTokens [i];
  321. }
  322. public override bool MoveToAttribute (string name)
  323. {
  324. for (int i = 0; i < attributeCount; i++) {
  325. XmlAttributeTokenInfo ti = attributeTokens [i];
  326. if (ti.Name == name) {
  327. MoveToAttribute (i);
  328. return true;
  329. }
  330. }
  331. return false;
  332. }
  333. public override bool MoveToAttribute (string localName, string namespaceName)
  334. {
  335. int idx = GetIndexOfQualifiedAttribute (localName, namespaceName);
  336. if (idx < 0)
  337. return false;
  338. MoveToAttribute (idx);
  339. return true;
  340. }
  341. public override bool MoveToElement ()
  342. {
  343. if (currentToken == null) // for attribute .ctor()
  344. return false;
  345. if (currentAttribute >= 0) {
  346. currentAttribute = -1;
  347. currentAttributeValue = -1;
  348. cursorToken = currentToken;
  349. return true;
  350. }
  351. else
  352. return false;
  353. }
  354. public override bool MoveToFirstAttribute ()
  355. {
  356. if (attributeCount == 0)
  357. return false;
  358. MoveToElement ();
  359. return MoveToNextAttribute ();
  360. }
  361. public override bool MoveToNextAttribute ()
  362. {
  363. if (currentAttribute == 0 && attributeCount == 0)
  364. return false;
  365. if (currentAttribute + 1 < attributeCount) {
  366. currentAttribute++;
  367. currentAttributeValue = -1;
  368. cursorToken = attributeTokens [currentAttribute];
  369. return true;
  370. }
  371. else
  372. return false;
  373. }
  374. public override bool Read ()
  375. {
  376. if (startNodeType == XmlNodeType.Attribute) {
  377. if (currentAttribute == 0)
  378. return false; // already read.
  379. ClearAttributes ();
  380. IncrementAttributeToken ();
  381. ReadAttributeValueTokens ('"');
  382. cursorToken = attributeTokens [0];
  383. currentAttributeValue = -1;
  384. readState = ReadState.Interactive;
  385. return true;
  386. }
  387. bool more = false;
  388. readState = ReadState.Interactive;
  389. currentLinkedNodeLineNumber = currentInput.LineNumber;
  390. currentLinkedNodeLinePosition = currentInput.LinePosition;
  391. useProceedingLineInfo = true;
  392. cursorToken = currentToken;
  393. attributeCount = 0;
  394. currentAttribute = currentAttributeValue = -1;
  395. currentToken.Clear ();
  396. // It was moved from end of ReadStartTag ().
  397. if (depthUp)
  398. ++depth;
  399. depthUp = false;
  400. more = ReadContent ();
  401. if (depth == 0 && !allowMultipleRoot && (IsEmptyElement || NodeType == XmlNodeType.EndElement))
  402. currentState = XmlNodeType.EndElement;
  403. if (maybeTextDecl != 0)
  404. maybeTextDecl--;
  405. if (!more && startNodeType == XmlNodeType.Document && currentState != XmlNodeType.EndElement)
  406. throw new XmlException ("Document element did not appear.");
  407. useProceedingLineInfo = false;
  408. return more;
  409. }
  410. public override bool ReadAttributeValue ()
  411. {
  412. if (readState == ReadState.Initial && startNodeType == XmlNodeType.Attribute) {
  413. Read ();
  414. }
  415. if (currentAttribute < 0)
  416. return false;
  417. XmlAttributeTokenInfo ti = attributeTokens [currentAttribute];
  418. if (currentAttributeValue < 0)
  419. currentAttributeValue = ti.ValueTokenStartIndex - 1;
  420. if (currentAttributeValue < ti.ValueTokenEndIndex) {
  421. currentAttributeValue++;
  422. cursorToken = attributeValueTokens [currentAttributeValue];
  423. return true;
  424. }
  425. else
  426. return false;
  427. }
  428. [MonoTODO]
  429. public int ReadBase64 (byte [] buffer, int offset, int length)
  430. {
  431. throw new NotImplementedException ();
  432. }
  433. [MonoTODO]
  434. public int ReadBinHex (byte [] buffer, int offset, int length)
  435. {
  436. throw new NotImplementedException ();
  437. }
  438. [MonoTODO]
  439. public int ReadChars (char [] buffer, int offset, int length)
  440. {
  441. throw new NotImplementedException ();
  442. }
  443. #if NET_1_0
  444. public override string ReadInnerXml ()
  445. {
  446. if (readState != ReadState.Interactive)
  447. return String.Empty;
  448. switch (NodeType) {
  449. case XmlNodeType.Attribute:
  450. return value.Substring (1, value.Length - 2);
  451. case XmlNodeType.Element:
  452. if (IsEmptyElement)
  453. return String.Empty;
  454. int startDepth = depth;
  455. if (innerXmlBuilder == null)
  456. innerXmlBuilder = new StringBuilder ();
  457. innerXmlBuilder.Length = 0;
  458. bool loop = true;
  459. do {
  460. Read ();
  461. if (NodeType ==XmlNodeType.None)
  462. throw new XmlException ("unexpected end of xml.");
  463. else if (NodeType == XmlNodeType.EndElement && depth == startDepth) {
  464. loop = false;
  465. Read ();
  466. }
  467. else
  468. innerXmlBuilder.Append (currentTag);
  469. } while (loop);
  470. string xml = innerXmlBuilder.ToString ();
  471. innerXmlBuilder.Length = 0;
  472. return xml;
  473. case XmlNodeType.None:
  474. // MS document is incorrect. Seems not to progress.
  475. return String.Empty;
  476. default:
  477. Read ();
  478. return String.Empty;
  479. }
  480. }
  481. public override string ReadOuterXml ()
  482. {
  483. if (readState != ReadState.Interactive)
  484. return String.Empty;
  485. switch (NodeType) {
  486. case XmlNodeType.Attribute:
  487. // strictly incompatible with MS... (it holds spaces attribute between name, value and "=" char (very trivial).
  488. return String.Format ("{0}={1}{2}{1}", Name, QuoteChar, ReadInnerXml ());
  489. case XmlNodeType.Element:
  490. bool isEmpty = IsEmptyElement;
  491. string startTag = currentTag.ToString ();
  492. string name = Name;
  493. if (NodeType == XmlNodeType.Element && !isEmpty)
  494. return String.Format ("{0}{1}</{2}>", startTag, ReadInnerXml (), name);
  495. else
  496. return currentTag.ToString ();
  497. case XmlNodeType.None:
  498. // MS document is incorrect. Seems not to progress.
  499. return String.Empty;
  500. default:
  501. Read ();
  502. return String.Empty;
  503. }
  504. }
  505. #endif
  506. public override string ReadString ()
  507. {
  508. return ReadStringInternal ();
  509. }
  510. public void ResetState ()
  511. {
  512. Init ();
  513. }
  514. public override void ResolveEntity ()
  515. {
  516. // XmlTextReader does not resolve entities.
  517. throw new InvalidOperationException ("XmlTextReader cannot resolve external entities.");
  518. }
  519. #endregion
  520. #region Internals
  521. // Parsed DTD Objects
  522. internal DTDObjectModel DTD {
  523. get { return parserContext.Dtd; }
  524. }
  525. internal bool MaybeTextDecl {
  526. set { if (value) this.maybeTextDecl = 2; }
  527. }
  528. #endregion
  529. #region Privates
  530. internal class XmlTokenInfo
  531. {
  532. public XmlTokenInfo (XmlTextReader xtr)
  533. {
  534. Reader = xtr;
  535. Clear ();
  536. }
  537. string valueCache;
  538. protected XmlTextReader Reader;
  539. public string Name;
  540. public string LocalName;
  541. public string Prefix;
  542. public string NamespaceURI;
  543. public bool IsEmptyElement;
  544. public char QuoteChar;
  545. public int LineNumber;
  546. public int LinePosition;
  547. public XmlNodeType NodeType;
  548. public virtual string Value {
  549. get {
  550. if (valueCache != null)
  551. return valueCache;
  552. else if (Reader.valueBuilderAvailable) {
  553. valueCache = Reader.valueBuilder.ToString ();
  554. return valueCache;
  555. }
  556. return valueCache;
  557. }
  558. set {
  559. valueCache = value;
  560. }
  561. }
  562. public virtual void Clear ()
  563. {
  564. valueCache = null;
  565. NodeType = XmlNodeType.None;
  566. Name = LocalName = Prefix = NamespaceURI = String.Empty;
  567. IsEmptyElement = false;
  568. QuoteChar = '"';
  569. LineNumber = LinePosition = 0;
  570. }
  571. internal virtual void FillNames ()
  572. {
  573. if (Reader.Namespaces) {
  574. int indexOfColon = Name.IndexOf (':');
  575. if (indexOfColon == -1) {
  576. Prefix = String.Empty;
  577. LocalName = Name;
  578. } else {
  579. Prefix = Reader.NameTable.Add (Name.Substring (0, indexOfColon));
  580. LocalName = Reader.NameTable.Add (Name.Substring (indexOfColon + 1));
  581. }
  582. // NamespaceURI
  583. switch (NodeType) {
  584. case XmlNodeType.Attribute:
  585. if (Prefix == string.Empty)
  586. NamespaceURI = string.Empty;
  587. else
  588. NamespaceURI = Reader.LookupNamespace (Prefix);
  589. break;
  590. case XmlNodeType.Element:
  591. case XmlNodeType.EndElement:
  592. NamespaceURI = Reader.LookupNamespace (Prefix);
  593. break;
  594. default:
  595. NamespaceURI = "";
  596. break;
  597. }
  598. } else {
  599. Prefix = String.Empty;
  600. LocalName = Name;
  601. }
  602. }
  603. }
  604. internal class XmlAttributeTokenInfo : XmlTokenInfo
  605. {
  606. public XmlAttributeTokenInfo (XmlTextReader reader)
  607. : base (reader)
  608. {
  609. NodeType = XmlNodeType.Attribute;
  610. }
  611. public int ValueTokenStartIndex;
  612. public int ValueTokenEndIndex;
  613. string valueCache;
  614. public override string Value {
  615. get {
  616. if (valueCache != null)
  617. return valueCache;
  618. // An empty value should return String.Empty.
  619. if (ValueTokenStartIndex == ValueTokenEndIndex) {
  620. XmlTokenInfo ti = Reader.attributeValueTokens [ValueTokenStartIndex];
  621. if (ti.NodeType == XmlNodeType.Text)
  622. valueCache = ti.Value;
  623. else
  624. valueCache = String.Concat ("&", ti.Name, ";");
  625. return valueCache;
  626. }
  627. StringBuilder sb = new StringBuilder ();
  628. for (int i = ValueTokenStartIndex; i <= ValueTokenEndIndex; i++) {
  629. XmlTokenInfo ti = Reader.attributeValueTokens [i];
  630. if (ti.NodeType == XmlNodeType.Text)
  631. sb.Append (ti.Value);
  632. else {
  633. sb.Append ('&');
  634. sb.Append (ti.Name);
  635. sb.Append (';');
  636. }
  637. }
  638. valueCache = sb.ToString ();
  639. return valueCache;
  640. }
  641. set {
  642. valueCache = value;
  643. }
  644. }
  645. public override void Clear ()
  646. {
  647. base.Clear ();
  648. valueCache = null;
  649. NodeType = XmlNodeType.Attribute;
  650. ValueTokenStartIndex = ValueTokenEndIndex = 0;
  651. }
  652. internal override void FillNames ()
  653. {
  654. base.FillNames ();
  655. if (Prefix == "xmlns" || Name == "xmlns")
  656. NamespaceURI = XmlNamespaceManager.XmlnsXmlns;
  657. }
  658. }
  659. private XmlTokenInfo cursorToken;
  660. private XmlTokenInfo currentToken;
  661. private XmlAttributeTokenInfo currentAttributeToken;
  662. private XmlTokenInfo currentAttributeValueToken;
  663. private XmlAttributeTokenInfo [] attributeTokens = new XmlAttributeTokenInfo [10];
  664. private XmlTokenInfo [] attributeValueTokens = new XmlTokenInfo [10];
  665. private int currentAttribute;
  666. private int currentAttributeValue;
  667. private int attributeCount;
  668. private XmlParserContext parserContext;
  669. private XmlParserInput currentInput;
  670. private Stack parserInputStack;
  671. private ReadState readState;
  672. private int depth;
  673. private int elementDepth;
  674. private bool depthUp;
  675. private bool popScope;
  676. private Stack elementStack;
  677. private bool allowMultipleRoot;
  678. private bool isStandalone;
  679. private StringBuilder valueBuilder;
  680. private bool valueBuilderAvailable = false;
  681. private bool returnEntityReference;
  682. private string entityReferenceName;
  683. private char [] nameBuffer;
  684. private int nameLength;
  685. private int nameCapacity;
  686. private const int initialNameCapacity = 256;
  687. private StringBuilder valueBuffer;
  688. private int currentLinkedNodeLineNumber;
  689. private int currentLinkedNodeLinePosition;
  690. private bool useProceedingLineInfo;
  691. // A buffer for ReadContent for ReadOuterXml
  692. private StringBuilder currentTag {
  693. get {
  694. return currentInput.CurrentMarkup;
  695. }
  696. }
  697. // Parameter entity placeholder
  698. private Hashtable parameterEntities;
  699. private int dtdIncludeSect;
  700. private XmlNodeType startNodeType;
  701. // State machine attribute.
  702. // XmlDeclaration: after the first node.
  703. // DocumentType: after doctypedecl
  704. // Element: inside document element
  705. // EndElement: after document element
  706. private XmlNodeType currentState;
  707. private int maybeTextDecl;
  708. private XmlResolver resolver = new XmlUrlResolver ();
  709. // These values are never re-initialized.
  710. private bool namespaces = true;
  711. private WhitespaceHandling whitespaceHandling = WhitespaceHandling.All;
  712. private bool normalization = false;
  713. private void Init ()
  714. {
  715. readState = ReadState.Initial;
  716. currentState = XmlNodeType.None;
  717. maybeTextDecl = 0;
  718. allowMultipleRoot = false;
  719. depth = 0;
  720. depthUp = false;
  721. popScope = false;
  722. parserInputStack = new Stack ();
  723. elementStack = new Stack();
  724. currentAttribute = -1;
  725. currentAttributeValue = -1;
  726. returnEntityReference = false;
  727. entityReferenceName = String.Empty;
  728. nameBuffer = new char [initialNameCapacity];
  729. nameLength = 0;
  730. nameCapacity = initialNameCapacity;
  731. valueBuffer = new StringBuilder (512);
  732. parameterEntities = new Hashtable ();
  733. currentToken = new XmlTokenInfo (this);
  734. cursorToken = currentToken;
  735. }
  736. private void InitializeContext (string url, XmlParserContext context, TextReader fragment, XmlNodeType fragType)
  737. {
  738. startNodeType = fragType;
  739. parserContext = context;
  740. if (context == null) {
  741. XmlNameTable nt = new NameTable ();
  742. parserContext = new XmlParserContext (nt,
  743. new XmlNamespaceManager (nt),
  744. String.Empty,
  745. XmlSpace.None);
  746. }
  747. if (url != null && url != String.Empty) {
  748. string path = Path.GetFullPath ("./a");
  749. Uri uri = new Uri (new Uri (path), url);
  750. parserContext.BaseURI = uri.ToString ();
  751. }
  752. Init ();
  753. switch (fragType) {
  754. case XmlNodeType.Attribute:
  755. fragment = new StringReader (fragment.ReadToEnd ().Replace ("\"", "&quot;"));
  756. break;
  757. case XmlNodeType.Element:
  758. currentState = XmlNodeType.Element;
  759. allowMultipleRoot = true;
  760. break;
  761. case XmlNodeType.Document:
  762. break;
  763. default:
  764. throw new XmlException (String.Format ("NodeType {0} is not allowed to create XmlTextReader.", fragType));
  765. }
  766. this.currentInput = new XmlParserInput (fragment, url);
  767. }
  768. // Use this method rather than setting the properties
  769. // directly so that all the necessary properties can
  770. // be changed in harmony with each other. Maybe the
  771. // fields should be in a seperate class to help enforce
  772. // this.
  773. private void SetProperties (
  774. XmlNodeType nodeType,
  775. string name,
  776. bool isEmptyElement,
  777. string value,
  778. bool clearAttributes)
  779. {
  780. SetProperties (currentToken, nodeType, name, isEmptyElement, value, clearAttributes);
  781. currentToken.LineNumber = this.currentLinkedNodeLineNumber;
  782. currentToken.LinePosition = this.currentLinkedNodeLinePosition;
  783. }
  784. private void SetProperties (
  785. XmlTokenInfo token,
  786. XmlNodeType nodeType,
  787. string name,
  788. bool isEmptyElement,
  789. string value,
  790. bool clearAttributes)
  791. {
  792. this.valueBuilderAvailable = false;
  793. token.Clear ();
  794. token.NodeType = nodeType;
  795. token.Name = name;
  796. token.IsEmptyElement = isEmptyElement;
  797. token.Value = value;
  798. this.elementDepth = depth;
  799. if (clearAttributes)
  800. ClearAttributes ();
  801. token.FillNames ();
  802. }
  803. private void SetProperties (
  804. XmlNodeType nodeType,
  805. string name,
  806. bool isEmptyElement,
  807. bool clearAttributes,
  808. StringBuilder value) {
  809. SetProperties (nodeType, name, isEmptyElement, (string)null, clearAttributes);
  810. this.valueBuilderAvailable = true;
  811. this.valueBuilder = value;
  812. }
  813. private void ClearAttributes ()
  814. {
  815. for (int i = 0; i < attributeCount; i++)
  816. attributeTokens [i].Clear ();
  817. attributeCount = 0;
  818. currentAttribute = -1;
  819. currentAttributeValue = -1;
  820. }
  821. private int PeekChar ()
  822. {
  823. return currentInput.PeekChar ();
  824. }
  825. private int ReadChar ()
  826. {
  827. return currentInput.ReadChar ();
  828. }
  829. // This should really keep track of some state so
  830. // that it's not possible to have more than one document
  831. // element or text outside of the document element.
  832. private bool ReadContent ()
  833. {
  834. currentTag.Length = 0;
  835. if (popScope) {
  836. parserContext.NamespaceManager.PopScope ();
  837. popScope = false;
  838. }
  839. if (returnEntityReference)
  840. SetEntityReferenceProperties ();
  841. else {
  842. switch (PeekChar ()) {
  843. case '<':
  844. ReadChar ();
  845. ReadTag ();
  846. break;
  847. case '\r': goto case ' ';
  848. case '\n': goto case ' ';
  849. case '\t': goto case ' ';
  850. case ' ':
  851. if (whitespaceHandling == WhitespaceHandling.All ||
  852. whitespaceHandling == WhitespaceHandling.Significant)
  853. ReadWhitespace ();
  854. else {
  855. SkipWhitespace ();
  856. return ReadContent ();
  857. }
  858. break;
  859. case -1:
  860. if (depth > 0)
  861. throw new XmlException ("unexpected end of file. Current depth is " + depth);
  862. readState = ReadState.EndOfFile;
  863. SetProperties (
  864. XmlNodeType.None, // nodeType
  865. String.Empty, // name
  866. false, // isEmptyElement
  867. (string) null, // value
  868. true // clearAttributes
  869. );
  870. return false;
  871. default:
  872. ReadText (true);
  873. break;
  874. }
  875. }
  876. if (NodeType == XmlNodeType.XmlDeclaration && maybeTextDecl == 1)
  877. return ReadContent ();
  878. return this.ReadState != ReadState.EndOfFile;
  879. }
  880. private void SetEntityReferenceProperties ()
  881. {
  882. /*
  883. if (resolver != null) {
  884. if (DTD == null)
  885. throw new XmlException (this as IXmlLineInfo,
  886. "Entity reference is not allowed without document type declaration.");
  887. else if((!DTD.InternalSubsetHasPEReference || isStandalone) &&
  888. DTD.EntityDecls [entityReferenceName] == null)
  889. throw new XmlException (this as IXmlLineInfo,
  890. "Required entity declaration for '" + entityReferenceName + "' was not found.");
  891. string dummy = DTD.EntityDecls [entityReferenceName].EntityValue;
  892. }
  893. */
  894. SetProperties (
  895. XmlNodeType.EntityReference, // nodeType
  896. entityReferenceName, // name
  897. false, // isEmptyElement
  898. (string) null, // value
  899. true // clearAttributes
  900. );
  901. returnEntityReference = false;
  902. entityReferenceName = String.Empty;
  903. }
  904. // The leading '<' has already been consumed.
  905. private void ReadTag ()
  906. {
  907. switch (PeekChar ())
  908. {
  909. case '/':
  910. ReadChar ();
  911. ReadEndTag ();
  912. break;
  913. case '?':
  914. ReadChar ();
  915. ReadProcessingInstruction ();
  916. break;
  917. case '!':
  918. ReadChar ();
  919. ReadDeclaration ();
  920. break;
  921. default:
  922. ReadStartTag ();
  923. break;
  924. }
  925. }
  926. // The leading '<' has already been consumed.
  927. private void ReadStartTag ()
  928. {
  929. if (currentState == XmlNodeType.EndElement)
  930. throw new XmlException (this as IXmlLineInfo,
  931. "Element cannot appear in this state.");
  932. currentState = XmlNodeType.Element;
  933. parserContext.NamespaceManager.PushScope ();
  934. string name = ReadName ();
  935. if (currentState == XmlNodeType.EndElement)
  936. throw new XmlException (this as IXmlLineInfo,"document has terminated, cannot open new element");
  937. bool isEmptyElement = false;
  938. ClearAttributes ();
  939. SkipWhitespace ();
  940. if (XmlChar.IsFirstNameChar (PeekChar ()))
  941. ReadAttributes (false);
  942. cursorToken = this.currentToken;
  943. // fill namespaces
  944. for (int i = 0; i < attributeCount; i++)
  945. attributeTokens [i].FillNames ();
  946. // quick name check
  947. for (int i = 0; i < attributeCount; i++)
  948. for (int j = i + 1; j < attributeCount; j++)
  949. if (Object.ReferenceEquals (attributeTokens [i].Name, attributeTokens [j].Name) ||
  950. (Object.ReferenceEquals (attributeTokens [i].LocalName, attributeTokens [j].LocalName) &&
  951. Object.ReferenceEquals (attributeTokens [i].NamespaceURI, attributeTokens [j].NamespaceURI)))
  952. throw new XmlException (this as IXmlLineInfo,
  953. "Attribute name and qualified name must be identical.");
  954. string baseUri = GetAttribute ("xml:base");
  955. if (baseUri != null)
  956. parserContext.BaseURI = baseUri;
  957. string xmlLang = GetAttribute ("xml:lang");
  958. if (xmlLang != null)
  959. parserContext.XmlLang = xmlLang;
  960. string xmlSpaceAttr = GetAttribute ("xml:space");
  961. if (xmlSpaceAttr != null) {
  962. if (xmlSpaceAttr == "preserve")
  963. parserContext.XmlSpace = XmlSpace.Preserve;
  964. else if (xmlSpaceAttr == "default")
  965. parserContext.XmlSpace = XmlSpace.Default;
  966. else
  967. throw new XmlException (this as IXmlLineInfo,String.Format ("Invalid xml:space value: {0}", xmlSpaceAttr));
  968. }
  969. if (PeekChar () == '/') {
  970. ReadChar ();
  971. isEmptyElement = true;
  972. popScope = true;
  973. }
  974. else {
  975. depthUp = true;
  976. elementStack.Push (name);
  977. parserContext.PushScope ();
  978. }
  979. Expect ('>');
  980. SetProperties (
  981. XmlNodeType.Element, // nodeType
  982. name, // name
  983. isEmptyElement, // isEmptyElement
  984. (string) null, // value
  985. false // clearAttributes
  986. );
  987. }
  988. // The reader is positioned on the first character
  989. // of the element's name.
  990. private void ReadEndTag ()
  991. {
  992. if (currentState != XmlNodeType.Element)
  993. throw new XmlException (this as IXmlLineInfo,
  994. "End tag cannot appear in this state.");
  995. string name = ReadName ();
  996. if (elementStack.Count == 0)
  997. throw new XmlException (this as IXmlLineInfo,"closing element without matching opening element");
  998. string expected = (string)elementStack.Pop();
  999. if (expected != name)
  1000. throw new XmlException (this as IXmlLineInfo,String.Format ("unmatched closing element: expected {0} but found {1}", expected, name));
  1001. parserContext.PopScope ();
  1002. SkipWhitespace ();
  1003. Expect ('>');
  1004. --depth;
  1005. SetProperties (
  1006. XmlNodeType.EndElement, // nodeType
  1007. name, // name
  1008. false, // isEmptyElement
  1009. (string) null, // value
  1010. true // clearAttributes
  1011. );
  1012. popScope = true;
  1013. }
  1014. private void AppendNameChar (int ch)
  1015. {
  1016. CheckNameCapacity ();
  1017. nameBuffer [nameLength++] = (char)ch;
  1018. }
  1019. private void CheckNameCapacity ()
  1020. {
  1021. if (nameLength == nameCapacity) {
  1022. nameCapacity = nameCapacity * 2;
  1023. char [] oldNameBuffer = nameBuffer;
  1024. nameBuffer = new char [nameCapacity];
  1025. Array.Copy (oldNameBuffer, nameBuffer, nameLength);
  1026. }
  1027. }
  1028. private string CreateNameString ()
  1029. {
  1030. return parserContext.NameTable.Add (nameBuffer, 0, nameLength);
  1031. }
  1032. private void AppendValueChar (int ch)
  1033. {
  1034. valueBuffer.Append ((char)ch);
  1035. }
  1036. private string CreateValueString ()
  1037. {
  1038. return valueBuffer.ToString ();
  1039. }
  1040. private void ClearValueBuffer ()
  1041. {
  1042. valueBuffer.Length = 0;
  1043. }
  1044. // The reader is positioned on the first character
  1045. // of the text.
  1046. private void ReadText (bool notWhitespace)
  1047. {
  1048. if (currentState != XmlNodeType.Element)
  1049. throw new XmlException (this as IXmlLineInfo,
  1050. "Text node cannot appear in this state.");
  1051. if (notWhitespace)
  1052. ClearValueBuffer ();
  1053. int ch = PeekChar ();
  1054. int previousCloseBracketLine = 0;
  1055. int previousCloseBracketColumn = 0;
  1056. while (ch != '<' && ch != -1) {
  1057. if (ch == '&') {
  1058. ReadChar ();
  1059. if (ReadReference (false))
  1060. break;
  1061. } else {
  1062. if (XmlConstructs.IsInvalid (ch))
  1063. throw new XmlException (this as IXmlLineInfo,
  1064. "Not allowed character was found.");
  1065. AppendValueChar (ReadChar ());
  1066. if (ch == ']') {
  1067. if (previousCloseBracketColumn == LinePosition - 1 &&
  1068. previousCloseBracketLine == LineNumber)
  1069. if (PeekChar () == '>')
  1070. throw new XmlException (this as IXmlLineInfo,
  1071. "Inside text content, character sequence ']]>' is not allowed.");
  1072. previousCloseBracketColumn = LinePosition;
  1073. previousCloseBracketLine = LineNumber;
  1074. }
  1075. }
  1076. ch = PeekChar ();
  1077. notWhitespace = true;
  1078. }
  1079. if (returnEntityReference && valueBuffer.Length == 0) {
  1080. SetEntityReferenceProperties ();
  1081. } else {
  1082. XmlNodeType nodeType = notWhitespace ? XmlNodeType.Text :
  1083. this.XmlSpace == XmlSpace.Preserve ? XmlNodeType.SignificantWhitespace : XmlNodeType.Whitespace;
  1084. SetProperties (
  1085. nodeType, // nodeType
  1086. String.Empty, // name
  1087. false, // isEmptyElement
  1088. true, // clearAttributes
  1089. valueBuffer // value
  1090. );
  1091. }
  1092. }
  1093. // The leading '&' has already been consumed.
  1094. // Returns true if the entity reference isn't a simple
  1095. // character reference or one of the predefined entities.
  1096. // This allows the ReadText method to break so that the
  1097. // next call to Read will return the EntityReference node.
  1098. private bool ReadReference (bool ignoreEntityReferences)
  1099. {
  1100. if (PeekChar () == '#') {
  1101. ReadChar ();
  1102. ReadCharacterReference ();
  1103. } else
  1104. ReadEntityReference (ignoreEntityReferences);
  1105. return returnEntityReference;
  1106. }
  1107. private void ReadCharacterReference ()
  1108. {
  1109. int value = 0;
  1110. if (PeekChar () == 'x') {
  1111. ReadChar ();
  1112. while (PeekChar () != ';' && PeekChar () != -1) {
  1113. int ch = ReadChar ();
  1114. if (ch >= '0' && ch <= '9')
  1115. value = (value << 4) + ch - '0';
  1116. else if (ch >= 'A' && ch <= 'F')
  1117. value = (value << 4) + ch - 'A' + 10;
  1118. else if (ch >= 'a' && ch <= 'f')
  1119. value = (value << 4) + ch - 'a' + 10;
  1120. else
  1121. throw new XmlException (this as IXmlLineInfo,
  1122. String.Format (
  1123. "invalid hexadecimal digit: {0} (#x{1:X})",
  1124. (char)ch,
  1125. ch));
  1126. }
  1127. } else {
  1128. while (PeekChar () != ';' && PeekChar () != -1) {
  1129. int ch = ReadChar ();
  1130. if (ch >= '0' && ch <= '9')
  1131. value = value * 10 + ch - '0';
  1132. else
  1133. throw new XmlException (this as IXmlLineInfo,
  1134. String.Format (
  1135. "invalid decimal digit: {0} (#x{1:X})",
  1136. (char)ch,
  1137. ch));
  1138. }
  1139. }
  1140. ReadChar (); // ';'
  1141. // FIXME: how to handle such chars larger than 0xffff?
  1142. if (value < 0xffff && !XmlConstructs.IsValid (value))
  1143. throw new XmlException (this as IXmlLineInfo,
  1144. "Referenced character was not allowed in XML.");
  1145. AppendValueChar (value);
  1146. }
  1147. private void ReadEntityReference (bool ignoreEntityReferences)
  1148. {
  1149. nameLength = 0;
  1150. int ch = PeekChar ();
  1151. while (ch != ';' && ch != -1) {
  1152. AppendNameChar (ReadChar ());
  1153. ch = PeekChar ();
  1154. }
  1155. Expect (';');
  1156. string name = CreateNameString ();
  1157. if (!XmlChar.IsName (name))
  1158. throw new XmlException (this as IXmlLineInfo,
  1159. "Invalid entity reference name was found.");
  1160. char predefined = XmlChar.GetPredefinedEntity (name);
  1161. if (predefined != 0)
  1162. AppendValueChar (predefined);
  1163. else {
  1164. if (ignoreEntityReferences) {
  1165. AppendValueChar ('&');
  1166. foreach (char ch2 in name) {
  1167. AppendValueChar (ch2);
  1168. }
  1169. AppendValueChar (';');
  1170. } else {
  1171. returnEntityReference = true;
  1172. entityReferenceName = name;
  1173. }
  1174. }
  1175. }
  1176. // The reader is positioned on the first character of
  1177. // the attribute name.
  1178. private void ReadAttributes (bool endsWithQuestion)
  1179. {
  1180. int peekChar = -1;
  1181. bool requireWhitespace = false;
  1182. currentAttribute = -1;
  1183. currentAttributeValue = -1;
  1184. do {
  1185. if (!SkipWhitespace () && requireWhitespace)
  1186. throw new XmlException ("Unexpected token. Name is required here.");
  1187. IncrementAttributeToken ();
  1188. currentAttributeToken.LineNumber = currentInput.LineNumber;
  1189. currentAttributeToken.LinePosition = currentInput.LinePosition;
  1190. currentAttributeToken.Name = ReadName ();
  1191. SkipWhitespace ();
  1192. Expect ('=');
  1193. SkipWhitespace ();
  1194. ReadAttributeValueTokens (-1);
  1195. attributeCount++;
  1196. if (currentAttributeToken.Name == "xmlns")
  1197. parserContext.NamespaceManager.AddNamespace (String.Empty, GetAttribute (currentAttribute));
  1198. else if (currentAttributeToken.Name.StartsWith ("xmlns:")) {
  1199. string nsPrefix = NameTable.Add (currentAttributeToken.Name.Substring (6));
  1200. parserContext.NamespaceManager.AddNamespace (nsPrefix, GetAttribute (currentAttribute));
  1201. }
  1202. if (!SkipWhitespace ())
  1203. requireWhitespace = true;
  1204. peekChar = PeekChar ();
  1205. if (endsWithQuestion) {
  1206. if (peekChar == '?')
  1207. break;
  1208. }
  1209. else if (peekChar == '/' || peekChar == '>')
  1210. break;
  1211. } while (peekChar != -1);
  1212. currentAttribute = -1;
  1213. currentAttributeValue = -1;
  1214. }
  1215. private void AddAttribute (string name, string value)
  1216. {
  1217. IncrementAttributeToken ();
  1218. XmlAttributeTokenInfo ati = attributeTokens [currentAttribute];
  1219. ati.Name = "SYSTEM";
  1220. ati.FillNames ();
  1221. IncrementAttributeValueToken ();
  1222. XmlTokenInfo vti = attributeValueTokens [currentAttributeValue];
  1223. vti.Value = value;
  1224. SetProperties (vti, XmlNodeType.Text, name, false, value, false);
  1225. attributeCount++;
  1226. }
  1227. private void IncrementAttributeToken ()
  1228. {
  1229. currentAttribute++;
  1230. if (attributeTokens.Length == currentAttribute) {
  1231. XmlAttributeTokenInfo [] newArray =
  1232. new XmlAttributeTokenInfo [attributeTokens.Length * 2];
  1233. attributeTokens.CopyTo (newArray, 0);
  1234. attributeTokens = newArray;
  1235. }
  1236. if (attributeTokens [currentAttribute] == null)
  1237. attributeTokens [currentAttribute] = new XmlAttributeTokenInfo (this);
  1238. currentAttributeToken = attributeTokens [currentAttribute];
  1239. currentAttributeToken.Clear ();
  1240. }
  1241. private void IncrementAttributeValueToken ()
  1242. {
  1243. ClearValueBuffer ();
  1244. currentAttributeValue++;
  1245. if (attributeValueTokens.Length == currentAttributeValue) {
  1246. XmlTokenInfo [] newArray = new XmlTokenInfo [attributeValueTokens.Length * 2];
  1247. attributeValueTokens.CopyTo (newArray, 0);
  1248. attributeValueTokens = newArray;
  1249. }
  1250. if (attributeValueTokens [currentAttributeValue] == null)
  1251. attributeValueTokens [currentAttributeValue] = new XmlTokenInfo (this);
  1252. currentAttributeValueToken = attributeValueTokens [currentAttributeValue];
  1253. currentAttributeValueToken.Clear ();
  1254. }
  1255. private void ReadAttributeValueTokens (int dummyQuoteChar)
  1256. {
  1257. int quoteChar = (dummyQuoteChar < 0) ? ReadChar () : dummyQuoteChar;
  1258. if (quoteChar != '\'' && quoteChar != '\"')
  1259. throw new XmlException (this as IXmlLineInfo,"an attribute value was not quoted");
  1260. currentAttributeToken.QuoteChar = (char) quoteChar;
  1261. IncrementAttributeValueToken ();
  1262. currentAttributeToken.ValueTokenStartIndex = currentAttributeValue;
  1263. currentAttributeValueToken.LineNumber = currentInput.LineNumber;
  1264. currentAttributeValueToken.LinePosition = currentInput.LinePosition;
  1265. bool incrementToken = false;
  1266. bool isNewToken = true;
  1267. bool loop = true;
  1268. while (loop && PeekChar () != quoteChar) {
  1269. if (incrementToken) {
  1270. IncrementAttributeValueToken ();
  1271. currentAttributeValueToken.LineNumber = currentInput.LineNumber;
  1272. currentAttributeValueToken.LinePosition = currentInput.LinePosition;
  1273. incrementToken = false;
  1274. isNewToken = true;
  1275. }
  1276. int ch = ReadChar ();
  1277. switch (ch)
  1278. {
  1279. case '<':
  1280. throw new XmlException (this as IXmlLineInfo,"attribute values cannot contain '<'");
  1281. case -1:
  1282. if (dummyQuoteChar < 0)
  1283. throw new XmlException (this as IXmlLineInfo,"unexpected end of file in an attribute value");
  1284. else // Attribute value constructor.
  1285. loop = false;
  1286. break;
  1287. case '&':
  1288. int startPosition = currentTag.Length - 1;
  1289. if (PeekChar () == '#') {
  1290. ReadChar ();
  1291. this.ReadCharacterReference ();
  1292. break;
  1293. }
  1294. // Check XML 1.0 section 3.1 WFC.
  1295. string entName = ReadName ();
  1296. Expect (';');
  1297. int predefined = XmlChar.GetPredefinedEntity (entName);
  1298. if (predefined == 0) {
  1299. DTDEntityDeclaration entDecl =
  1300. DTD == null ? null : DTD.EntityDecls [entName];
  1301. if (entDecl != null && entDecl.SystemId != null)
  1302. // if (!startNodeType == XmlNodeType.Attribute && (entDecl == null || entDecl.SystemId != null))
  1303. throw new XmlException (this as IXmlLineInfo,
  1304. "Reference to external entities is not allowed in the value of an attribute.");
  1305. currentAttributeValueToken.Value = CreateValueString ();
  1306. currentAttributeValueToken.NodeType = XmlNodeType.Text;
  1307. if (!isNewToken)
  1308. IncrementAttributeValueToken ();
  1309. currentAttributeValueToken.Name = entName;
  1310. currentAttributeValueToken.Value = String.Empty;
  1311. currentAttributeValueToken.NodeType = XmlNodeType.EntityReference;
  1312. incrementToken = true;
  1313. }
  1314. else
  1315. AppendValueChar (predefined);
  1316. break;
  1317. default:
  1318. AppendValueChar (ch);
  1319. break;
  1320. }
  1321. isNewToken = false;
  1322. }
  1323. if (!incrementToken) {
  1324. currentAttributeValueToken.Value = CreateValueString ();
  1325. currentAttributeValueToken.NodeType = XmlNodeType.Text;
  1326. currentAttributeToken.ValueTokenEndIndex = currentAttributeValue;
  1327. }
  1328. if (dummyQuoteChar < 0)
  1329. ReadChar (); // quoteChar
  1330. }
  1331. // The reader is positioned on the quote character.
  1332. // *Keeps quote char* to value to get_QuoteChar() correctly.
  1333. // Not it is used only for DTD.
  1334. private string ReadAttribute (bool isDefaultValue)
  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. /*
  1350. case '&':
  1351. if (isDefaultValue) {
  1352. AppendValueChar (ch);
  1353. break;
  1354. }
  1355. AppendValueChar (ch);
  1356. if (PeekChar () == '#')
  1357. break;
  1358. // Check XML 1.0 section 3.1 WFC.
  1359. string entName = ReadName ();
  1360. Expect (';');
  1361. if (XmlChar.GetPredefinedEntity (entName) == 0) {
  1362. DTDEntityDeclaration entDecl =
  1363. DTD == null ? null : DTD.EntityDecls [entName];
  1364. if (entDecl == null || entDecl.SystemId != null)
  1365. throw new XmlException (this as IXmlLineInfo,
  1366. "Reference to external entities is not allowed in attribute value.");
  1367. }
  1368. valueBuffer.Append (entName);
  1369. AppendValueChar (';');
  1370. break;
  1371. */
  1372. default:
  1373. AppendValueChar (ch);
  1374. break;
  1375. }
  1376. }
  1377. ReadChar (); // quoteChar
  1378. AppendValueChar (quoteChar);
  1379. return CreateValueString ();
  1380. }
  1381. // The reader is positioned on the first character
  1382. // of the target.
  1383. //
  1384. // It may be xml declaration or processing instruction.
  1385. private void ReadProcessingInstruction ()
  1386. {
  1387. string target = ReadName ();
  1388. if (target == "xml") {
  1389. ReadXmlDeclaration ();
  1390. return;
  1391. } else if (target.ToLower () == "xml")
  1392. throw new XmlException (this as IXmlLineInfo,
  1393. "Not allowed processing instruction name which starts with 'X', 'M', 'L' was found.");
  1394. if (currentState == XmlNodeType.None)
  1395. currentState = XmlNodeType.XmlDeclaration;
  1396. if (!SkipWhitespace ())
  1397. if (PeekChar () != '?')
  1398. throw new XmlException (this as IXmlLineInfo,
  1399. "Invalid processing instruction name was found.");
  1400. ClearValueBuffer ();
  1401. while (PeekChar () != -1) {
  1402. int ch = ReadChar ();
  1403. if (ch == '?' && PeekChar () == '>') {
  1404. ReadChar ();
  1405. break;
  1406. }
  1407. AppendValueChar ((char)ch);
  1408. }
  1409. SetProperties (
  1410. XmlNodeType.ProcessingInstruction, // nodeType
  1411. target, // name
  1412. false, // isEmptyElement
  1413. true, // clearAttributes
  1414. valueBuffer // value
  1415. );
  1416. }
  1417. // The reader is positioned after "<?xml "
  1418. private void ReadXmlDeclaration ()
  1419. {
  1420. if (currentState != XmlNodeType.None) {
  1421. if (maybeTextDecl == 0)
  1422. throw new XmlException (this as IXmlLineInfo,
  1423. "XML declaration cannot appear in this state.");
  1424. }
  1425. // Is this required?
  1426. if (maybeTextDecl != 0)
  1427. currentState = XmlNodeType.XmlDeclaration;
  1428. ClearAttributes ();
  1429. ReadAttributes (true); // They must have "version."
  1430. string version = GetAttribute ("version");
  1431. string message = null;
  1432. if (parserInputStack.Count == 0) {
  1433. if (maybeTextDecl == 0 && (attributeTokens [0].Name != "version" || version != "1.0"))
  1434. message = "Version 1.0 declaration is required in XML Declaration.";
  1435. else if (attributeCount > 1 &&
  1436. (attributeTokens [1].Name != "encoding" &&
  1437. attributeTokens [1].Name != "standalone"))
  1438. message = "Invalid Xml Declaration markup was found.";
  1439. else if (attributeCount > 2 && attributeTokens [2].Name != "standalone")
  1440. message = "Invalid Xml Declaration markup was found.";
  1441. string sa = GetAttribute ("standalone");
  1442. if (sa != null && sa != "yes" && sa != "no")
  1443. message = "Only 'yes' or 'no' is allowed for standalone.";
  1444. this.isStandalone = (sa == "yes");
  1445. } else {
  1446. int currentCheck = 0;
  1447. if (attributeTokens [0].Name == "version") {
  1448. if (version != "1.0")
  1449. message = "Version 1.0 declaration is required in Text Declaration.";
  1450. currentCheck = 1;
  1451. }
  1452. if (attributeCount <= currentCheck || attributeTokens [currentCheck].Name != "encoding")
  1453. message = "Invalid Text Declaration markup was found. encoding specification is required.";
  1454. }
  1455. if (message != null)
  1456. throw new XmlException (this as IXmlLineInfo, message);
  1457. Expect ("?>");
  1458. if (maybeTextDecl != 0)
  1459. if (this ["standalone"] != null)
  1460. throw new XmlException (this as IXmlLineInfo,
  1461. "Invalid text declaration.");
  1462. if (maybeTextDecl == 2)
  1463. maybeTextDecl = 1;
  1464. SetProperties (
  1465. XmlNodeType.XmlDeclaration, // nodeType
  1466. "xml", // name
  1467. false, // isEmptyElement
  1468. currentInput.CurrentMarkup.ToString (6, currentInput.CurrentMarkup.Length - 6), // value
  1469. false // clearAttributes
  1470. );
  1471. }
  1472. // The reader is positioned on the first character after
  1473. // the leading '<!'.
  1474. private void ReadDeclaration ()
  1475. {
  1476. int ch = PeekChar ();
  1477. switch (ch)
  1478. {
  1479. case '-':
  1480. Expect ("--");
  1481. ReadComment ();
  1482. break;
  1483. case '[':
  1484. ReadChar ();
  1485. Expect ("CDATA[");
  1486. ReadCDATA ();
  1487. break;
  1488. case 'D':
  1489. Expect ("DOCTYPE");
  1490. ReadDoctypeDecl ();
  1491. break;
  1492. default:
  1493. throw new XmlException (this as IXmlLineInfo,
  1494. "Unexpected declaration markup was found.");
  1495. }
  1496. }
  1497. // The reader is positioned on the first character after
  1498. // the leading '<!--'.
  1499. private void ReadComment ()
  1500. {
  1501. if (currentState == XmlNodeType.None)
  1502. currentState = XmlNodeType.XmlDeclaration;
  1503. ClearValueBuffer ();
  1504. while (PeekChar () != -1) {
  1505. int ch = ReadChar ();
  1506. if (ch == '-' && PeekChar () == '-') {
  1507. ReadChar ();
  1508. if (PeekChar () != '>')
  1509. throw new XmlException (this as IXmlLineInfo,"comments cannot contain '--'");
  1510. ReadChar ();
  1511. break;
  1512. }
  1513. if (XmlConstructs.IsInvalid (ch))
  1514. throw new XmlException (this as IXmlLineInfo,
  1515. "Not allowed character was found.");
  1516. AppendValueChar ((char)ch);
  1517. }
  1518. SetProperties (
  1519. XmlNodeType.Comment, // nodeType
  1520. String.Empty, // name
  1521. false, // isEmptyElement
  1522. true, // clearAttributes
  1523. valueBuffer // value
  1524. );
  1525. }
  1526. // The reader is positioned on the first character after
  1527. // the leading '<![CDATA['.
  1528. private void ReadCDATA ()
  1529. {
  1530. if (currentState != XmlNodeType.Element)
  1531. throw new XmlException (this as IXmlLineInfo,
  1532. "CDATA section cannot appear in this state.");
  1533. ClearValueBuffer ();
  1534. bool skip = false;
  1535. int ch = 0;
  1536. while (PeekChar () != -1) {
  1537. if (!skip)
  1538. ch = ReadChar ();
  1539. skip = false;
  1540. if (ch == ']' && PeekChar () == ']') {
  1541. ch = ReadChar (); // ']'
  1542. if (PeekChar () == '>') {
  1543. ReadChar (); // '>'
  1544. break;
  1545. } else {
  1546. skip = true;
  1547. // AppendValueChar (']');
  1548. // AppendValueChar (']');
  1549. // ch = ReadChar ();
  1550. }
  1551. }
  1552. AppendValueChar ((char)ch);
  1553. }
  1554. SetProperties (
  1555. XmlNodeType.CDATA, // nodeType
  1556. String.Empty, // name
  1557. false, // isEmptyElement
  1558. true, // clearAttributes
  1559. valueBuffer // value
  1560. );
  1561. }
  1562. // The reader is positioned on the first character after
  1563. // the leading '<!DOCTYPE'.
  1564. private void ReadDoctypeDecl ()
  1565. {
  1566. switch (currentState) {
  1567. case XmlNodeType.DocumentType:
  1568. case XmlNodeType.Element:
  1569. case XmlNodeType.EndElement:
  1570. throw new XmlException (this as IXmlLineInfo,
  1571. "Document type cannot appear in this state.");
  1572. }
  1573. currentState = XmlNodeType.DocumentType;
  1574. string doctypeName = null;
  1575. string publicId = null;
  1576. string systemId = null;
  1577. int intSubsetStartLine = 0;
  1578. int intSubsetStartColumn = 0;
  1579. SkipWhitespace ();
  1580. doctypeName = ReadName ();
  1581. SkipWhitespace ();
  1582. switch(PeekChar ())
  1583. {
  1584. case 'S':
  1585. systemId = ReadSystemLiteral (true);
  1586. break;
  1587. case 'P':
  1588. publicId = ReadPubidLiteral ();
  1589. if (!SkipWhitespace ())
  1590. throw new XmlException (this as IXmlLineInfo,
  1591. "Whitespace is required between PUBLIC id and SYSTEM id.");
  1592. systemId = ReadSystemLiteral (false);
  1593. break;
  1594. }
  1595. SkipWhitespace ();
  1596. if(PeekChar () == '[')
  1597. {
  1598. // read markupdecl etc. or end of decl
  1599. ReadChar ();
  1600. intSubsetStartLine = this.LineNumber;
  1601. intSubsetStartColumn = this.LinePosition;
  1602. int startPos = currentTag.Length;
  1603. ReadInternalSubset ();
  1604. int endPos = currentTag.Length - 1;
  1605. parserContext.InternalSubset = currentTag.ToString (startPos, endPos - startPos);
  1606. }
  1607. // end of DOCTYPE decl.
  1608. SkipWhitespace ();
  1609. Expect ('>');
  1610. GenerateDTDObjectModel (doctypeName, publicId,
  1611. systemId, parserContext.InternalSubset,
  1612. intSubsetStartLine, intSubsetStartColumn);
  1613. // set properties for <!DOCTYPE> node
  1614. SetProperties (
  1615. XmlNodeType.DocumentType, // nodeType
  1616. doctypeName, // name
  1617. false, // isEmptyElement
  1618. parserContext.InternalSubset, // value
  1619. true // clearAttributes
  1620. );
  1621. if (publicId != null)
  1622. AddAttribute ("PUBLIC", publicId);
  1623. if (systemId != null)
  1624. AddAttribute ("SYSTEM", systemId);
  1625. }
  1626. internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
  1627. string systemId, string internalSubset)
  1628. {
  1629. return GenerateDTDObjectModel (name, publicId, systemId, internalSubset, 0, 0);
  1630. }
  1631. internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
  1632. string systemId, string internalSubset, int intSubsetStartLine, int intSubsetStartColumn)
  1633. {
  1634. // now compile DTD
  1635. parserContext.Dtd = new DTDObjectModel (); // merges both internal and external subsets in the meantime,
  1636. DTD.BaseURI = BaseURI;
  1637. DTD.Name = name;
  1638. DTD.PublicId = publicId;
  1639. DTD.SystemId = systemId;
  1640. DTD.InternalSubset = internalSubset;
  1641. DTD.XmlResolver = resolver;
  1642. int originalParserDepth = parserInputStack.Count;
  1643. bool more;
  1644. if (internalSubset != null && internalSubset.Length > 0) {
  1645. XmlParserInput original = currentInput;
  1646. currentInput = new XmlParserInput (new StringReader (internalSubset), BaseURI, intSubsetStartLine, intSubsetStartColumn);
  1647. do {
  1648. more = CompileDTDSubset ();
  1649. if (PeekChar () == -1 && parserInputStack.Count > 0)
  1650. PopParserInput ();
  1651. } while (more || parserInputStack.Count > originalParserDepth);
  1652. if (dtdIncludeSect != 0)
  1653. throw new XmlException (this as IXmlLineInfo,"INCLUDE section is not ended correctly.");
  1654. currentInput = original;
  1655. }
  1656. if (systemId != null && systemId != String.Empty && resolver != null) {
  1657. PushParserInput (systemId);
  1658. do {
  1659. more = this.CompileDTDSubset ();
  1660. if (PeekChar () == -1 && parserInputStack.Count > 1)
  1661. PopParserInput ();
  1662. } while (more || parserInputStack.Count > originalParserDepth + 1);
  1663. PopParserInput ();
  1664. }
  1665. return DTD;
  1666. }
  1667. private void PushParserInput (string url)
  1668. {
  1669. Uri baseUri = null;
  1670. try {
  1671. baseUri = new Uri (BaseURI);
  1672. } catch (UriFormatException) {
  1673. }
  1674. Uri absUri = resolver.ResolveUri (baseUri, url);
  1675. string absPath = absUri.ToString ();
  1676. foreach (XmlParserInput i in parserInputStack.ToArray ()) {
  1677. if (i.BaseURI == absPath)
  1678. throw new XmlException (this as IXmlLineInfo, "Nested inclusion is not allowed: " + url);
  1679. }
  1680. parserInputStack.Push (currentInput);
  1681. currentInput = new XmlParserInput (new XmlStreamReader (url, false, resolver, BaseURI), absPath);
  1682. parserContext.PushScope ();
  1683. parserContext.BaseURI = absPath;
  1684. maybeTextDecl = 2;
  1685. }
  1686. private void PopParserInput ()
  1687. {
  1688. currentInput = parserInputStack.Pop () as XmlParserInput;
  1689. parserContext.PopScope ();
  1690. }
  1691. private enum DtdInputState
  1692. {
  1693. Free = 1,
  1694. ElementDecl,
  1695. AttlistDecl,
  1696. EntityDecl,
  1697. NotationDecl,
  1698. PI,
  1699. Comment,
  1700. InsideSingleQuoted,
  1701. InsideDoubleQuoted,
  1702. }
  1703. private class DtdInputStateStack
  1704. {
  1705. Stack intern = new Stack ();
  1706. public DtdInputStateStack ()
  1707. {
  1708. Push (DtdInputState.Free);
  1709. }
  1710. public DtdInputState Peek ()
  1711. {
  1712. return (DtdInputState) intern.Peek ();
  1713. }
  1714. public DtdInputState Pop ()
  1715. {
  1716. return (DtdInputState) intern.Pop ();
  1717. }
  1718. public void Push (DtdInputState val)
  1719. {
  1720. intern.Push (val);
  1721. }
  1722. }
  1723. DtdInputStateStack stateStack = new DtdInputStateStack ();
  1724. DtdInputState State {
  1725. get { return stateStack.Peek (); }
  1726. }
  1727. // Simply read but not generate any result.
  1728. private void ReadInternalSubset ()
  1729. {
  1730. bool continueParse = true;
  1731. while (continueParse) {
  1732. switch (ReadChar ()) {
  1733. case ']':
  1734. switch (State) {
  1735. case DtdInputState.Free:
  1736. continueParse = false;
  1737. break;
  1738. case DtdInputState.InsideDoubleQuoted:
  1739. continue;
  1740. case DtdInputState.InsideSingleQuoted:
  1741. continue;
  1742. default:
  1743. throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
  1744. }
  1745. break;
  1746. case -1:
  1747. throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
  1748. case '<':
  1749. if (State == DtdInputState.InsideDoubleQuoted ||
  1750. State == DtdInputState.InsideSingleQuoted)
  1751. continue; // well-formed
  1752. switch (ReadChar ()) {
  1753. case '?':
  1754. stateStack.Push (DtdInputState.PI);
  1755. break;
  1756. case '!':
  1757. switch (ReadChar ()) {
  1758. case 'E':
  1759. switch (ReadChar ()) {
  1760. case 'L':
  1761. Expect ("EMENT");
  1762. stateStack.Push (DtdInputState.ElementDecl);
  1763. break;
  1764. case 'N':
  1765. Expect ("TITY");
  1766. stateStack.Push (DtdInputState.EntityDecl);
  1767. break;
  1768. default:
  1769. throw new XmlException (this as IXmlLineInfo,"unexpected token '<!E'.");
  1770. }
  1771. break;
  1772. case 'A':
  1773. Expect ("TTLIST");
  1774. stateStack.Push (DtdInputState.AttlistDecl);
  1775. break;
  1776. case 'N':
  1777. Expect ("OTATION");
  1778. stateStack.Push (DtdInputState.NotationDecl);
  1779. break;
  1780. case '-':
  1781. Expect ("-");
  1782. stateStack.Push (DtdInputState.Comment);
  1783. break;
  1784. }
  1785. break;
  1786. default:
  1787. throw new XmlException (this as IXmlLineInfo,"unexpected '>'.");
  1788. }
  1789. break;
  1790. case '\'':
  1791. if (State == DtdInputState.InsideSingleQuoted)
  1792. stateStack.Pop ();
  1793. else if (State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.Comment)
  1794. stateStack.Push (DtdInputState.InsideSingleQuoted);
  1795. break;
  1796. case '"':
  1797. if (State == DtdInputState.InsideDoubleQuoted)
  1798. stateStack.Pop ();
  1799. else if (State != DtdInputState.InsideSingleQuoted && State != DtdInputState.Comment)
  1800. stateStack.Push (DtdInputState.InsideDoubleQuoted);
  1801. break;
  1802. case '>':
  1803. switch (State) {
  1804. case DtdInputState.ElementDecl:
  1805. goto case DtdInputState.NotationDecl;
  1806. case DtdInputState.AttlistDecl:
  1807. goto case DtdInputState.NotationDecl;
  1808. case DtdInputState.EntityDecl:
  1809. goto case DtdInputState.NotationDecl;
  1810. case DtdInputState.NotationDecl:
  1811. stateStack.Pop ();
  1812. break;
  1813. case DtdInputState.InsideDoubleQuoted:
  1814. continue;
  1815. case DtdInputState.InsideSingleQuoted:
  1816. continue; // well-formed
  1817. case DtdInputState.Comment:
  1818. continue;
  1819. default:
  1820. throw new XmlException (this as IXmlLineInfo,"unexpected token '>'");
  1821. }
  1822. break;
  1823. case '?':
  1824. if (State == DtdInputState.PI) {
  1825. if (ReadChar () == '>')
  1826. stateStack.Pop ();
  1827. }
  1828. break;
  1829. case '-':
  1830. if (State == DtdInputState.Comment) {
  1831. if (PeekChar () == '-') {
  1832. ReadChar ();
  1833. Expect ('>');
  1834. stateStack.Pop ();
  1835. }
  1836. }
  1837. break;
  1838. case '%':
  1839. if (State != DtdInputState.Free && State != DtdInputState.EntityDecl && State != DtdInputState.Comment && State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.InsideSingleQuoted)
  1840. throw new XmlException (this as IXmlLineInfo,"Parameter Entity Reference cannot appear as a part of markupdecl (see XML spec 2.8).");
  1841. break;
  1842. }
  1843. }
  1844. }
  1845. // Read any one of following:
  1846. // elementdecl, AttlistDecl, EntityDecl, NotationDecl,
  1847. // PI, Comment, Parameter Entity, or doctype termination char(']')
  1848. //
  1849. // Returns true if it may have any more contents, or false if not.
  1850. private bool CompileDTDSubset()
  1851. {
  1852. SkipWhitespace ();
  1853. switch(PeekChar ())
  1854. {
  1855. case -1:
  1856. return false;
  1857. case '%':
  1858. // It affects on entity references' well-formedness
  1859. if (this.parserInputStack.Count == 0)
  1860. DTD.InternalSubsetHasPEReference = true;
  1861. ReadChar ();
  1862. string peName = ReadName ();
  1863. Expect (';');
  1864. currentInput.InsertParameterEntityBuffer (GetPEValue (peName));
  1865. int currentLine = currentInput.LineNumber;
  1866. int currentColumn = currentInput.LinePosition;
  1867. while (currentInput.HasPEBuffer)
  1868. CompileDTDSubset ();
  1869. if (currentInput.LineNumber != currentLine ||
  1870. currentInput.LinePosition != currentColumn)
  1871. throw new XmlException (this as IXmlLineInfo,
  1872. "Incorrectly nested parameter entity.");
  1873. break;
  1874. case '<':
  1875. ReadChar ();
  1876. switch(ReadChar ())
  1877. {
  1878. case '?':
  1879. // Only read, no store.
  1880. ReadProcessingInstruction ();
  1881. break;
  1882. case '!':
  1883. CompileDeclaration ();
  1884. break;
  1885. default:
  1886. throw new XmlException (this as IXmlLineInfo,"Syntax Error after '<' character.");
  1887. }
  1888. break;
  1889. case ']':
  1890. if (dtdIncludeSect == 0)
  1891. throw new XmlException (this as IXmlLineInfo, "Unbalanced end of INCLUDE/IGNORE section.");
  1892. // End of inclusion
  1893. Expect ("]]>");
  1894. dtdIncludeSect--;
  1895. SkipWhitespace ();
  1896. return false;
  1897. default:
  1898. throw new XmlException (this as IXmlLineInfo,String.Format ("Syntax Error inside doctypedecl markup : {0}({1})", PeekChar (), (char) PeekChar ()));
  1899. }
  1900. return true;
  1901. }
  1902. private void CompileDeclaration ()
  1903. {
  1904. switch(ReadChar ())
  1905. {
  1906. case '-':
  1907. Expect ('-');
  1908. // Only read, no store.
  1909. ReadComment ();
  1910. break;
  1911. case 'E':
  1912. switch(ReadChar ())
  1913. {
  1914. case 'N':
  1915. Expect ("TITY");
  1916. if (!SkipWhitespace ())
  1917. throw new XmlException (this as IXmlLineInfo,
  1918. "Whitespace is required after '<!ENTITY' in DTD entity declaration.");
  1919. LOOPBACK:
  1920. if (PeekChar () == '%') {
  1921. ReadChar ();
  1922. if (!SkipWhitespace ()) {
  1923. ImportAsPERef ();
  1924. goto LOOPBACK;
  1925. } else {
  1926. TryExpandPERef ();
  1927. SkipWhitespace ();
  1928. if (XmlChar.IsNameChar (PeekChar ()))
  1929. ReadParameterEntityDecl ();
  1930. else
  1931. throw new XmlException (this as IXmlLineInfo,"expected name character");
  1932. }
  1933. break;
  1934. }
  1935. DTDEntityDeclaration ent = ReadEntityDecl ();
  1936. if (DTD.EntityDecls [ent.Name] == null)
  1937. DTD.EntityDecls.Add (ent.Name, ent);
  1938. break;
  1939. case 'L':
  1940. Expect ("EMENT");
  1941. DTDElementDeclaration el = ReadElementDecl ();
  1942. DTD.ElementDecls.Add (el.Name, el);
  1943. break;
  1944. default:
  1945. throw new XmlException (this as IXmlLineInfo,"Syntax Error after '<!E' (ELEMENT or ENTITY must be found)");
  1946. }
  1947. break;
  1948. case 'A':
  1949. Expect ("TTLIST");
  1950. DTDAttListDeclaration atl = ReadAttListDecl ();
  1951. // if (DTD.AttListDecls.ContainsKey (atl.Name))
  1952. DTD.AttListDecls.Add (atl.Name, atl);
  1953. break;
  1954. case 'N':
  1955. Expect ("OTATION");
  1956. DTDNotationDeclaration not = ReadNotationDecl ();
  1957. DTD.NotationDecls.Add (not.Name, not);
  1958. break;
  1959. case '[':
  1960. // conditional sections
  1961. SkipWhitespace ();
  1962. TryExpandPERef ();
  1963. SkipWhitespace ();
  1964. Expect ('I');
  1965. switch (ReadChar ()) {
  1966. case 'N':
  1967. Expect ("CLUDE");
  1968. SkipWhitespace ();
  1969. Expect ('[');
  1970. dtdIncludeSect++;
  1971. break;
  1972. case 'G':
  1973. Expect ("NORE");
  1974. ReadIgnoreSect ();
  1975. break;
  1976. }
  1977. break;
  1978. default:
  1979. throw new XmlException (this as IXmlLineInfo,"Syntax Error after '<!' characters.");
  1980. }
  1981. }
  1982. private void ReadIgnoreSect ()
  1983. {
  1984. bool skip = false;
  1985. SkipWhitespace ();
  1986. Expect ('[');
  1987. int dtdIgnoreSect = 1;
  1988. while (dtdIgnoreSect > 0) {
  1989. switch (skip ? PeekChar () : ReadChar ()) {
  1990. case -1:
  1991. throw new XmlException (this as IXmlLineInfo,"Unexpected IGNORE section end.");
  1992. case '<':
  1993. if (ReadChar () == '!' && ReadChar () == '[')
  1994. dtdIgnoreSect++;
  1995. break;
  1996. case ']':
  1997. if (ReadChar () == ']') {
  1998. if (ReadChar () == '>')
  1999. dtdIgnoreSect--;
  2000. else
  2001. skip = true;
  2002. }
  2003. break;
  2004. }
  2005. skip = false;
  2006. }
  2007. }
  2008. // The reader is positioned on the head of the name.
  2009. private DTDElementDeclaration ReadElementDecl ()
  2010. {
  2011. DTDElementDeclaration decl = new DTDElementDeclaration (DTD);
  2012. if (!SkipWhitespace ())
  2013. throw new XmlException (this as IXmlLineInfo,
  2014. "Whitespace is required between '<!ELEMENT' and name in DTD element declaration.");
  2015. TryExpandPERef ();
  2016. SkipWhitespace ();
  2017. decl.Name = ReadName ();
  2018. if (!SkipWhitespace ())
  2019. throw new XmlException (this as IXmlLineInfo,
  2020. "Whitespace is required between name and content in DTD element declaration.");
  2021. TryExpandPERef ();
  2022. ReadContentSpec (decl);
  2023. SkipWhitespace ();
  2024. // This expanding is only allowed as a non-validating parser.
  2025. TryExpandPERef ();
  2026. SkipWhitespace ();
  2027. Expect ('>');
  2028. return decl;
  2029. }
  2030. // read 'children'(BNF) of contentspec
  2031. private void ReadContentSpec (DTDElementDeclaration decl)
  2032. {
  2033. TryExpandPERef ();
  2034. SkipWhitespace ();
  2035. switch(PeekChar ())
  2036. {
  2037. case 'E':
  2038. decl.IsEmpty = true;
  2039. Expect ("EMPTY");
  2040. break;
  2041. case 'A':
  2042. decl.IsAny = true;
  2043. Expect ("ANY");
  2044. break;
  2045. case '(':
  2046. DTDContentModel model = decl.ContentModel;
  2047. ReadChar ();
  2048. SkipWhitespace ();
  2049. TryExpandPERef ();
  2050. SkipWhitespace ();
  2051. if(PeekChar () == '#') {
  2052. // Mixed Contents. "#PCDATA" must appear first.
  2053. decl.IsMixedContent = true;
  2054. model.Occurence = DTDOccurence.ZeroOrMore;
  2055. model.OrderType = DTDContentOrderType.Or;
  2056. Expect ("#PCDATA");
  2057. SkipWhitespace ();
  2058. TryExpandPERef ();
  2059. SkipWhitespace ();
  2060. while(PeekChar () != ')') {
  2061. Expect('|');
  2062. SkipWhitespace ();
  2063. TryExpandPERef ();
  2064. SkipWhitespace ();
  2065. DTDContentModel elem = new DTDContentModel (DTD, decl.Name);
  2066. elem.ElementName = ReadName ();
  2067. model.ChildModels.Add (elem);
  2068. SkipWhitespace ();
  2069. TryExpandPERef ();
  2070. SkipWhitespace ();
  2071. }
  2072. Expect (')');
  2073. if (model.ChildModels.Count > 0)
  2074. Expect ('*');
  2075. else if (PeekChar () == '*')
  2076. Expect ('*');
  2077. } else {
  2078. // Non-Mixed Contents
  2079. model.ChildModels.Add (ReadCP (decl));
  2080. SkipWhitespace ();
  2081. do { // copied from ReadCP() ...;-)
  2082. TryExpandPERef ();
  2083. SkipWhitespace ();
  2084. if(PeekChar ()=='|') {
  2085. // CPType=Or
  2086. if (model.OrderType == DTDContentOrderType.Seq)
  2087. throw new XmlException (this as IXmlLineInfo,
  2088. "Inconsistent choice markup in sequence cp.");
  2089. model.OrderType = DTDContentOrderType.Or;
  2090. ReadChar ();
  2091. SkipWhitespace ();
  2092. model.ChildModels.Add (ReadCP (decl));
  2093. SkipWhitespace ();
  2094. }
  2095. else if(PeekChar () == ',')
  2096. {
  2097. // CPType=Seq
  2098. if (model.OrderType == DTDContentOrderType.Or)
  2099. throw new XmlException (this as IXmlLineInfo,
  2100. "Inconsistent sequence markup in choice cp.");
  2101. model.OrderType = DTDContentOrderType.Seq;
  2102. ReadChar ();
  2103. SkipWhitespace ();
  2104. model.ChildModels.Add (ReadCP (decl));
  2105. SkipWhitespace ();
  2106. }
  2107. else
  2108. break;
  2109. }
  2110. while(true);
  2111. Expect (')');
  2112. switch(PeekChar ())
  2113. {
  2114. case '?':
  2115. model.Occurence = DTDOccurence.Optional;
  2116. ReadChar ();
  2117. break;
  2118. case '*':
  2119. model.Occurence = DTDOccurence.ZeroOrMore;
  2120. ReadChar ();
  2121. break;
  2122. case '+':
  2123. model.Occurence = DTDOccurence.OneOrMore;
  2124. ReadChar ();
  2125. break;
  2126. }
  2127. SkipWhitespace ();
  2128. }
  2129. SkipWhitespace ();
  2130. break;
  2131. }
  2132. }
  2133. // Read 'cp' (BNF) of contentdecl (BNF)
  2134. private DTDContentModel ReadCP (DTDElementDeclaration elem)
  2135. {
  2136. DTDContentModel model = null;
  2137. TryExpandPERef ();
  2138. SkipWhitespace ();
  2139. if(PeekChar () == '(') {
  2140. model = new DTDContentModel (DTD, elem.Name);
  2141. ReadChar ();
  2142. SkipWhitespace ();
  2143. model.ChildModels.Add (ReadCP (elem));
  2144. SkipWhitespace ();
  2145. do {
  2146. TryExpandPERef ();
  2147. SkipWhitespace ();
  2148. if(PeekChar ()=='|') {
  2149. // CPType=Or
  2150. if (model.OrderType == DTDContentOrderType.Seq)
  2151. throw new XmlException (this as IXmlLineInfo,
  2152. "Inconsistent choice markup in sequence cp.");
  2153. model.OrderType = DTDContentOrderType.Or;
  2154. ReadChar ();
  2155. SkipWhitespace ();
  2156. model.ChildModels.Add (ReadCP (elem));
  2157. SkipWhitespace ();
  2158. }
  2159. else if(PeekChar () == ',') {
  2160. // CPType=Seq
  2161. if (model.OrderType == DTDContentOrderType.Or)
  2162. throw new XmlException (this as IXmlLineInfo,
  2163. "Inconsistent sequence markup in choice cp.");
  2164. model.OrderType = DTDContentOrderType.Seq;
  2165. ReadChar ();
  2166. SkipWhitespace ();
  2167. model.ChildModels.Add (ReadCP (elem));
  2168. SkipWhitespace ();
  2169. }
  2170. else
  2171. break;
  2172. }
  2173. while(true);
  2174. SkipWhitespace ();
  2175. Expect (')');
  2176. }
  2177. else {
  2178. TryExpandPERef ();
  2179. model = new DTDContentModel (DTD, elem.Name);
  2180. SkipWhitespace ();
  2181. model.ElementName = ReadName ();
  2182. }
  2183. switch(PeekChar ()) {
  2184. case '?':
  2185. model.Occurence = DTDOccurence.Optional;
  2186. ReadChar ();
  2187. break;
  2188. case '*':
  2189. model.Occurence = DTDOccurence.ZeroOrMore;
  2190. ReadChar ();
  2191. break;
  2192. case '+':
  2193. model.Occurence = DTDOccurence.OneOrMore;
  2194. ReadChar ();
  2195. break;
  2196. }
  2197. return model;
  2198. }
  2199. // The reader is positioned on the first name char.
  2200. private void ReadParameterEntityDecl ()
  2201. {
  2202. DTDParameterEntityDeclaration decl =
  2203. new DTDParameterEntityDeclaration();
  2204. decl.BaseURI = BaseURI;
  2205. decl.Name = ReadName ();
  2206. if (!SkipWhitespace ())
  2207. throw new XmlException (this as IXmlLineInfo,
  2208. "Whitespace is required after name in DTD parameter entity declaration.");
  2209. if (PeekChar () == 'S' || PeekChar () == 'P') {
  2210. // throw new NotImplementedException ("External parameter entity reference is not implemented yet.");
  2211. // read publicId/systemId
  2212. ReadExternalID ();
  2213. decl.PublicId = GetAttribute ("PUBLIC");
  2214. decl.SystemId = GetAttribute ("SYSTEM");
  2215. SkipWhitespace ();
  2216. decl.Resolve (resolver);
  2217. }
  2218. else {
  2219. TryExpandPERef ();
  2220. int quoteChar = ReadChar ();
  2221. int start = currentTag.Length;
  2222. ClearValueBuffer ();
  2223. bool loop = true;
  2224. while (loop) {
  2225. int c = PeekChar ();
  2226. switch (c) {
  2227. case -1:
  2228. throw new XmlException ("unexpected end of stream in entity value definition.");
  2229. case '"':
  2230. ReadChar ();
  2231. if (quoteChar == '"')
  2232. loop = false;
  2233. else
  2234. AppendValueChar ('"');
  2235. break;
  2236. case '\'':
  2237. ReadChar ();
  2238. if (quoteChar == '\'')
  2239. loop = false;
  2240. else
  2241. AppendValueChar ('\'');
  2242. break;
  2243. case '&':
  2244. ReadChar ();
  2245. if (PeekChar () == '#') {
  2246. ReadChar ();
  2247. ReadCharacterReference ();
  2248. }
  2249. else
  2250. AppendValueChar ('&');
  2251. break;
  2252. case '%':
  2253. ReadChar ();
  2254. string peName = ReadName ();
  2255. Expect (';');
  2256. valueBuffer.Append (GetPEValue (peName));
  2257. break;
  2258. default:
  2259. AppendValueChar (ReadChar ());
  2260. break;
  2261. }
  2262. }
  2263. decl.LiteralValue = CreateValueString (); // currentTag.ToString (start, currentTag.Length - start - 1);
  2264. ClearValueBuffer ();
  2265. }
  2266. SkipWhitespace ();
  2267. Expect ('>');
  2268. if (parameterEntities [decl.Name] == null) {
  2269. parameterEntities.Add (decl.Name, decl);
  2270. }
  2271. }
  2272. private string GetPEValue (string peName)
  2273. {
  2274. DTDParameterEntityDeclaration peDecl =
  2275. this.parameterEntities [peName] as DTDParameterEntityDeclaration;
  2276. if (peDecl != null)
  2277. return peDecl.Value;
  2278. // See XML 1.0 section 4.1 for both WFC and VC.
  2279. if ((DTD.SystemId == null && !DTD.InternalSubsetHasPEReference) || this.isStandalone)
  2280. throw new XmlException (this as IXmlLineInfo,
  2281. "Parameter entity " + peName + " not found.");
  2282. DTD.AddError (new XmlSchemaException (
  2283. "Parameter entity " + peName + " not found.", null));
  2284. return "";
  2285. }
  2286. private void TryExpandPERef ()
  2287. {
  2288. if (PeekChar () == '%') {
  2289. // ReadChar ();
  2290. // if (!XmlChar.IsNameChar (PeekChar ()))
  2291. // return;
  2292. // ExpandPERef ();
  2293. ImportAsPERef ();
  2294. }
  2295. }
  2296. // reader is positioned on '%'
  2297. private void ImportAsPERef ()
  2298. {
  2299. ReadChar ();
  2300. string peName = ReadName ();
  2301. Expect (';');
  2302. DTDParameterEntityDeclaration peDecl =
  2303. this.parameterEntities [peName] as DTDParameterEntityDeclaration;
  2304. if (peDecl == null) {
  2305. DTD.AddError (new XmlSchemaException ("Parameter entity " + peName + " not found.", null));
  2306. return; // do nothing
  2307. }
  2308. currentInput.InsertParameterEntityBuffer (" " + peDecl.Value + " ");
  2309. }
  2310. // The reader is positioned on the head of the name.
  2311. private DTDEntityDeclaration ReadEntityDecl ()
  2312. {
  2313. DTDEntityDeclaration decl = new DTDEntityDeclaration (DTD);
  2314. decl.IsInternalSubset = (parserInputStack.Count == 0);
  2315. TryExpandPERef ();
  2316. SkipWhitespace ();
  2317. decl.Name = ReadName ();
  2318. if (!SkipWhitespace ())
  2319. throw new XmlException (this as IXmlLineInfo,
  2320. "Whitespace is required between name and content in DTD entity declaration.");
  2321. TryExpandPERef ();
  2322. SkipWhitespace ();
  2323. if (PeekChar () == 'S' || PeekChar () == 'P') {
  2324. // external entity
  2325. ReadExternalID ();
  2326. decl.PublicId = GetAttribute ("PUBLIC");
  2327. decl.SystemId = GetAttribute ("SYSTEM");
  2328. if (SkipWhitespace ()) {
  2329. if (PeekChar () == 'N') {
  2330. // NDataDecl
  2331. Expect ("NDATA");
  2332. if (!SkipWhitespace ())
  2333. throw new XmlException (this as IXmlLineInfo,
  2334. "Whitespace is required after NDATA.");
  2335. decl.NotationName = ReadName (); // ndata_name
  2336. }
  2337. }
  2338. decl.ScanEntityValue (new StringCollection ());
  2339. }
  2340. else {
  2341. // literal entity
  2342. ReadEntityValueDecl (decl);
  2343. }
  2344. SkipWhitespace ();
  2345. // This expanding is only allowed as a non-validating parser.
  2346. TryExpandPERef ();
  2347. SkipWhitespace ();
  2348. Expect ('>');
  2349. return decl;
  2350. }
  2351. private void ReadEntityValueDecl (DTDEntityDeclaration decl)
  2352. {
  2353. SkipWhitespace ();
  2354. // quotation char will be finally removed on unescaping
  2355. int quoteChar = ReadChar ();
  2356. int start = currentTag.Length;
  2357. if (quoteChar != '\'' && quoteChar != '"')
  2358. throw new XmlException ("quotation char was expected.");
  2359. ClearValueBuffer ();
  2360. while (PeekChar () != quoteChar) {
  2361. switch (PeekChar ()) {
  2362. case '%':
  2363. ReadChar ();
  2364. string name = ReadName ();
  2365. Expect (';');
  2366. if (decl.IsInternalSubset)
  2367. throw new XmlException (this as IXmlLineInfo,
  2368. "Parameter entity is not allowed in internal subset entity '" + name + "'");
  2369. valueBuffer.Append (GetPEValue (name));
  2370. break;
  2371. case -1:
  2372. throw new XmlException ("unexpected end of stream.");
  2373. default:
  2374. AppendValueChar (ReadChar ());
  2375. break;
  2376. }
  2377. }
  2378. string value = Dereference (CreateValueString (), false);
  2379. ClearValueBuffer ();
  2380. Expect (quoteChar);
  2381. decl.LiteralEntityValue = value;
  2382. }
  2383. private DTDAttListDeclaration ReadAttListDecl ()
  2384. {
  2385. SkipWhitespace ();
  2386. TryExpandPERef ();
  2387. SkipWhitespace ();
  2388. string name = ReadName (); // target element name
  2389. DTDAttListDeclaration decl =
  2390. DTD.AttListDecls [name] as DTDAttListDeclaration;
  2391. if (decl == null)
  2392. decl = new DTDAttListDeclaration (DTD);
  2393. decl.Name = name;
  2394. if (!SkipWhitespace ())
  2395. if (PeekChar () != '>')
  2396. throw new XmlException (this as IXmlLineInfo,
  2397. "Whitespace is required between name and content in non-empty DTD attlist declaration.");
  2398. TryExpandPERef ();
  2399. SkipWhitespace ();
  2400. while (XmlChar.IsNameChar ((char) PeekChar ())) {
  2401. DTDAttributeDefinition def = ReadAttributeDefinition ();
  2402. if (decl [def.Name] == null)
  2403. decl.Add (def);
  2404. SkipWhitespace ();
  2405. TryExpandPERef ();
  2406. SkipWhitespace ();
  2407. }
  2408. SkipWhitespace ();
  2409. // This expanding is only allowed as a non-validating parser.
  2410. TryExpandPERef ();
  2411. SkipWhitespace ();
  2412. Expect ('>');
  2413. return decl;
  2414. }
  2415. private DTDAttributeDefinition ReadAttributeDefinition ()
  2416. {
  2417. DTDAttributeDefinition def = new DTDAttributeDefinition ();
  2418. // attr_name
  2419. TryExpandPERef ();
  2420. SkipWhitespace ();
  2421. def.Name = ReadName ();
  2422. if (!SkipWhitespace ())
  2423. throw new XmlException (this as IXmlLineInfo,
  2424. "Whitespace is required between name and content in DTD attribute definition.");
  2425. // attr_value
  2426. TryExpandPERef ();
  2427. SkipWhitespace ();
  2428. switch(PeekChar ()) {
  2429. case 'C': // CDATA
  2430. Expect ("CDATA");
  2431. def.Datatype = XmlSchemaDatatype.FromName ("normalizedString");
  2432. break;
  2433. case 'I': // ID, IDREF, IDREFS
  2434. Expect ("ID");
  2435. if(PeekChar () == 'R') {
  2436. Expect ("REF");
  2437. if(PeekChar () == 'S') {
  2438. // IDREFS
  2439. ReadChar ();
  2440. def.Datatype = XmlSchemaDatatype.FromName ("IDREFS");
  2441. }
  2442. else // IDREF
  2443. def.Datatype = XmlSchemaDatatype.FromName ("IDREF");
  2444. }
  2445. else // ID
  2446. def.Datatype = XmlSchemaDatatype.FromName ("ID");
  2447. break;
  2448. case 'E': // ENTITY, ENTITIES
  2449. Expect ("ENTIT");
  2450. switch(ReadChar ()) {
  2451. case 'Y': // ENTITY
  2452. def.Datatype = XmlSchemaDatatype.FromName ("ENTITY");
  2453. break;
  2454. case 'I': // ENTITIES
  2455. Expect ("ES");
  2456. def.Datatype = XmlSchemaDatatype.FromName ("ENTITIES");
  2457. break;
  2458. }
  2459. break;
  2460. case 'N': // NMTOKEN, NMTOKENS, NOTATION
  2461. ReadChar ();
  2462. switch(PeekChar ()) {
  2463. case 'M':
  2464. Expect ("MTOKEN");
  2465. if(PeekChar ()=='S') { // NMTOKENS
  2466. ReadChar ();
  2467. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKENS");
  2468. }
  2469. else // NMTOKEN
  2470. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN");
  2471. break;
  2472. case 'O':
  2473. Expect ("OTATION");
  2474. def.Datatype = XmlSchemaDatatype.FromName ("NOTATION");
  2475. if (!SkipWhitespace ())
  2476. throw new XmlException (this as IXmlLineInfo,
  2477. "Whitespace is required between name and content in DTD attribute definition.");
  2478. Expect ('(');
  2479. SkipWhitespace ();
  2480. def.EnumeratedNotations.Add (ReadName ()); // notation name
  2481. SkipWhitespace ();
  2482. while(PeekChar () == '|') {
  2483. ReadChar ();
  2484. SkipWhitespace ();
  2485. def.EnumeratedNotations.Add (ReadName ()); // notation name
  2486. SkipWhitespace ();
  2487. }
  2488. Expect (')');
  2489. break;
  2490. default:
  2491. throw new XmlException ("attribute declaration syntax error.");
  2492. }
  2493. break;
  2494. default: // Enumerated Values
  2495. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN");
  2496. TryExpandPERef ();
  2497. SkipWhitespace ();
  2498. Expect ('(');
  2499. SkipWhitespace ();
  2500. def.EnumeratedAttributeDeclaration.Add (
  2501. def.Datatype.Normalize (ReadNmToken ())); // enum value
  2502. SkipWhitespace ();
  2503. while(PeekChar () == '|') {
  2504. ReadChar ();
  2505. SkipWhitespace ();
  2506. def.EnumeratedAttributeDeclaration.Add (
  2507. def.Datatype.Normalize (ReadNmToken ())); // enum value
  2508. SkipWhitespace ();
  2509. }
  2510. Expect (')');
  2511. break;
  2512. }
  2513. TryExpandPERef ();
  2514. if (!SkipWhitespace ())
  2515. throw new XmlException (this as IXmlLineInfo,
  2516. "Whitespace is required between type and occurence in DTD attribute definition.");
  2517. // def_value
  2518. if(PeekChar () == '#')
  2519. {
  2520. ReadChar ();
  2521. switch(PeekChar ())
  2522. {
  2523. case 'R':
  2524. Expect ("REQUIRED");
  2525. def.OccurenceType = DTDAttributeOccurenceType.Required;
  2526. break;
  2527. case 'I':
  2528. Expect ("IMPLIED");
  2529. def.OccurenceType = DTDAttributeOccurenceType.Optional;
  2530. break;
  2531. case 'F':
  2532. Expect ("FIXED");
  2533. def.OccurenceType = DTDAttributeOccurenceType.Fixed;
  2534. if (!SkipWhitespace ())
  2535. throw new XmlException (this as IXmlLineInfo,
  2536. "Whitespace is required between FIXED and actual value in DTD attribute definition.");
  2537. def.UnresolvedDefaultValue = ReadAttribute (true);
  2538. break;
  2539. }
  2540. } else {
  2541. // one of the enumerated value
  2542. TryExpandPERef ();
  2543. SkipWhitespace ();
  2544. def.UnresolvedDefaultValue = ReadAttribute (true);
  2545. }
  2546. return def;
  2547. }
  2548. private DTDNotationDeclaration ReadNotationDecl()
  2549. {
  2550. DTDNotationDeclaration decl = new DTDNotationDeclaration ();
  2551. TryExpandPERef ();
  2552. SkipWhitespace ();
  2553. decl.Name = ReadName (); // notation name
  2554. if (namespaces) { // copy from SetProperties ;-)
  2555. int indexOfColon = decl.Name.IndexOf (':');
  2556. if (indexOfColon == -1) {
  2557. decl.Prefix = String.Empty;
  2558. decl.LocalName = decl.Name;
  2559. } else {
  2560. decl.Prefix = decl.Name.Substring (0, indexOfColon);
  2561. decl.LocalName = decl.Name.Substring (indexOfColon + 1);
  2562. }
  2563. } else {
  2564. decl.Prefix = String.Empty;
  2565. decl.LocalName = decl.Name;
  2566. }
  2567. SkipWhitespace ();
  2568. if(PeekChar () == 'P') {
  2569. decl.PublicId = ReadPubidLiteral ();
  2570. bool wsSkipped = SkipWhitespace ();
  2571. if (PeekChar () == '\'' || PeekChar () == '"') {
  2572. if (!wsSkipped)
  2573. throw new XmlException (this as IXmlLineInfo,
  2574. "Whitespace is required between public id and system id.");
  2575. decl.SystemId = ReadSystemLiteral (false);
  2576. SkipWhitespace ();
  2577. }
  2578. } else if(PeekChar () == 'S') {
  2579. decl.SystemId = ReadSystemLiteral (true);
  2580. SkipWhitespace ();
  2581. }
  2582. if(decl.PublicId == null && decl.SystemId == null)
  2583. throw new XmlException ("public or system declaration required for \"NOTATION\" declaration.");
  2584. // This expanding is only allowed as a non-validating parser.
  2585. TryExpandPERef ();
  2586. SkipWhitespace ();
  2587. Expect ('>');
  2588. return decl;
  2589. }
  2590. private void ReadExternalID () {
  2591. this.ClearAttributes ();
  2592. switch (PeekChar ()) {
  2593. case 'S':
  2594. string systemId = ReadSystemLiteral (true);
  2595. AddAttribute ("SYSTEM", systemId);
  2596. break;
  2597. case 'P':
  2598. string publicId = ReadPubidLiteral ();
  2599. if (!SkipWhitespace ())
  2600. throw new XmlException (this as IXmlLineInfo,
  2601. "Whitespace is required between PUBLIC id and SYSTEM id.");
  2602. systemId = ReadSystemLiteral (false);
  2603. AddAttribute ("PUBLIC", publicId);
  2604. AddAttribute ("SYSTEM", systemId);
  2605. break;
  2606. }
  2607. }
  2608. // The reader is positioned on the first 'S' of "SYSTEM".
  2609. private string ReadSystemLiteral (bool expectSYSTEM)
  2610. {
  2611. if(expectSYSTEM) {
  2612. Expect ("SYSTEM");
  2613. if (!SkipWhitespace ())
  2614. throw new XmlException (this as IXmlLineInfo,
  2615. "Whitespace is required after 'SYSTEM'.");
  2616. }
  2617. else
  2618. SkipWhitespace ();
  2619. int quoteChar = ReadChar (); // apos or quot
  2620. int startPos = currentTag.Length;
  2621. int c = 0;
  2622. ClearValueBuffer ();
  2623. while (c != quoteChar) {
  2624. c = ReadChar ();
  2625. if (c < 0)
  2626. throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
  2627. if (c != quoteChar)
  2628. AppendValueChar (c);
  2629. }
  2630. return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
  2631. }
  2632. private string ReadPubidLiteral()
  2633. {
  2634. Expect ("PUBLIC");
  2635. if (!SkipWhitespace ())
  2636. throw new XmlException (this as IXmlLineInfo,
  2637. "Whitespace is required after 'PUBLIC'.");
  2638. int quoteChar = ReadChar ();
  2639. int startPos = currentTag.Length;
  2640. int c = 0;
  2641. ClearValueBuffer ();
  2642. while(c != quoteChar)
  2643. {
  2644. c = ReadChar ();
  2645. if(c < 0) throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
  2646. if(c != quoteChar && !XmlChar.IsPubidChar (c))
  2647. throw new XmlException (this as IXmlLineInfo,"character '" + (char)c + "' not allowed for PUBLIC ID");
  2648. if (c != quoteChar)
  2649. AppendValueChar (c);
  2650. }
  2651. return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
  2652. }
  2653. // The reader is positioned on the first character
  2654. // of the name.
  2655. internal string ReadName ()
  2656. {
  2657. return ReadNameOrNmToken(false);
  2658. }
  2659. // The reader is positioned on the first character
  2660. // of the name.
  2661. private string ReadNmToken ()
  2662. {
  2663. return ReadNameOrNmToken(true);
  2664. }
  2665. private string ReadNameOrNmToken(bool isNameToken)
  2666. {
  2667. int ch = PeekChar ();
  2668. if(isNameToken) {
  2669. if (!XmlChar.IsNameChar ((char) ch))
  2670. throw new XmlException (this as IXmlLineInfo,String.Format ("a nmtoken did not start with a legal character {0} ({1})", ch, (char)ch));
  2671. }
  2672. else {
  2673. if (!XmlChar.IsFirstNameChar (ch))
  2674. throw new XmlException (this as IXmlLineInfo,String.Format ("a name did not start with a legal character {0} ({1})", ch, (char)ch));
  2675. }
  2676. nameLength = 0;
  2677. AppendNameChar (ReadChar ());
  2678. while (XmlChar.IsNameChar (PeekChar ())) {
  2679. AppendNameChar (ReadChar ());
  2680. }
  2681. return CreateNameString ();
  2682. }
  2683. // Read the next character and compare it against the
  2684. // specified character.
  2685. private void Expect (int expected)
  2686. {
  2687. int ch = ReadChar ();
  2688. if (ch != expected) {
  2689. throw new XmlException (this as IXmlLineInfo,
  2690. String.Format (
  2691. "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
  2692. (char)expected,
  2693. expected,
  2694. (char)ch,
  2695. ch));
  2696. }
  2697. }
  2698. private void Expect (string expected)
  2699. {
  2700. int len = expected.Length;
  2701. for(int i=0; i< len; i++)
  2702. Expect (expected[i]);
  2703. }
  2704. // Does not consume the first non-whitespace character.
  2705. private bool SkipWhitespace ()
  2706. {
  2707. //FIXME: Should not skip if whitespaceHandling == WhiteSpaceHandling.None
  2708. bool skipped = XmlChar.IsWhitespace (PeekChar ());
  2709. while (XmlChar.IsWhitespace (PeekChar ()))
  2710. ReadChar ();
  2711. return skipped;
  2712. }
  2713. private void ReadWhitespace ()
  2714. {
  2715. if (currentState == XmlNodeType.None)
  2716. currentState = XmlNodeType.XmlDeclaration;
  2717. ClearValueBuffer ();
  2718. int ch = PeekChar ();
  2719. do {
  2720. AppendValueChar (ReadChar ());
  2721. } while ((ch = PeekChar ()) != -1 && XmlChar.IsWhitespace (ch));
  2722. if (currentState == XmlNodeType.Element && ch != -1 && ch != '<')
  2723. ReadText (false);
  2724. else {
  2725. XmlNodeType nodeType = (this.XmlSpace == XmlSpace.Preserve) ?
  2726. XmlNodeType.SignificantWhitespace : XmlNodeType.Whitespace;
  2727. SetProperties (nodeType,
  2728. String.Empty,
  2729. false,
  2730. true,
  2731. valueBuffer);
  2732. }
  2733. return; // (PeekChar () != -1);
  2734. }
  2735. private string Dereference (string unresolved, bool expandPredefined)
  2736. {
  2737. StringBuilder resolved = new StringBuilder();
  2738. int pos = 0;
  2739. int next = unresolved.IndexOf ('&');
  2740. if(next < 0)
  2741. return unresolved;
  2742. while(next >= 0) {
  2743. if(pos < next)
  2744. resolved.Append (unresolved.Substring (pos, next - pos));// - 1);
  2745. int endPos = unresolved.IndexOf (';', next+1);
  2746. string entityName =
  2747. unresolved.Substring (next + 1, endPos - next - 1);
  2748. if(entityName [0] == '#') {
  2749. char c;
  2750. // character entity
  2751. if(entityName [1] == 'x') {
  2752. // hexadecimal
  2753. c = (char) int.Parse ("0" + entityName.Substring (2),
  2754. System.Globalization.NumberStyles.HexNumber);
  2755. } else {
  2756. // decimal
  2757. c = (char) int.Parse (entityName.Substring (1));
  2758. }
  2759. resolved.Append (c);
  2760. } else {
  2761. char predefined = XmlChar.GetPredefinedEntity (entityName);
  2762. if (expandPredefined && predefined != 0)
  2763. resolved.Append (predefined);
  2764. else
  2765. // With respect to "Value", MS document is helpless
  2766. // and the implemention returns inconsistent value
  2767. // (e.g. XML: "&ent; &amp;ent;" ---> Value: "&ent; &ent;".)
  2768. resolved.Append ("&" + entityName + ";");
  2769. }
  2770. pos = endPos + 1;
  2771. if(pos > unresolved.Length)
  2772. break;
  2773. next = unresolved.IndexOf('&', pos);
  2774. }
  2775. resolved.Append (unresolved.Substring(pos));
  2776. return resolved.ToString();
  2777. }
  2778. #endregion
  2779. }
  2780. }