XmlTextReader.cs 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106
  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. return ti.Value;
  623. valueCache = '&' + ti.Name + ';';
  624. return valueCache;
  625. }
  626. StringBuilder sb = new StringBuilder ();
  627. for (int i = ValueTokenStartIndex; i <= ValueTokenEndIndex; i++) {
  628. XmlTokenInfo ti = Reader.attributeValueTokens [i];
  629. if (ti.NodeType == XmlNodeType.Text)
  630. sb.Append (ti.Value);
  631. else {
  632. sb.Append ('&');
  633. sb.Append (ti.Name);
  634. sb.Append (';');
  635. }
  636. }
  637. valueCache = sb.ToString ();
  638. return valueCache;
  639. }
  640. set {
  641. valueCache = value;
  642. }
  643. }
  644. public override void Clear ()
  645. {
  646. base.Clear ();
  647. valueCache = null;
  648. NodeType = XmlNodeType.Attribute;
  649. ValueTokenStartIndex = ValueTokenEndIndex = 0;
  650. }
  651. internal override void FillNames ()
  652. {
  653. base.FillNames ();
  654. if (Prefix == "xmlns" || Name == "xmlns")
  655. NamespaceURI = XmlNamespaceManager.XmlnsXmlns;
  656. }
  657. }
  658. private XmlTokenInfo cursorToken;
  659. private XmlTokenInfo currentToken;
  660. private XmlAttributeTokenInfo currentAttributeToken;
  661. private XmlTokenInfo currentAttributeValueToken;
  662. private XmlAttributeTokenInfo [] attributeTokens = new XmlAttributeTokenInfo [10];
  663. private XmlTokenInfo [] attributeValueTokens = new XmlTokenInfo [10];
  664. private int currentAttribute;
  665. private int currentAttributeValue;
  666. private int attributeCount;
  667. private XmlParserContext parserContext;
  668. private XmlParserInput currentInput;
  669. private Stack parserInputStack;
  670. private ReadState readState;
  671. private int depth;
  672. private int elementDepth;
  673. private bool depthUp;
  674. private bool popScope;
  675. private Stack elementStack;
  676. private bool allowMultipleRoot;
  677. private bool isStandalone;
  678. private StringBuilder valueBuilder;
  679. private bool valueBuilderAvailable = false;
  680. private bool returnEntityReference;
  681. private string entityReferenceName;
  682. private char [] nameBuffer;
  683. private int nameLength;
  684. private int nameCapacity;
  685. private const int initialNameCapacity = 256;
  686. private StringBuilder valueBuffer;
  687. private int currentLinkedNodeLineNumber;
  688. private int currentLinkedNodeLinePosition;
  689. private bool useProceedingLineInfo;
  690. // A buffer for ReadContent for ReadOuterXml
  691. private StringBuilder currentTag {
  692. get {
  693. return currentInput.CurrentMarkup;
  694. }
  695. }
  696. // Parameter entity placeholder
  697. private Hashtable parameterEntities;
  698. private int dtdIncludeSect;
  699. private XmlNodeType startNodeType;
  700. // State machine attribute.
  701. // XmlDeclaration: after the first node.
  702. // DocumentType: after doctypedecl
  703. // Element: inside document element
  704. // EndElement: after document element
  705. private XmlNodeType currentState;
  706. private int maybeTextDecl;
  707. private XmlResolver resolver = new XmlUrlResolver ();
  708. // These values are never re-initialized.
  709. private bool namespaces = true;
  710. private WhitespaceHandling whitespaceHandling = WhitespaceHandling.All;
  711. private bool normalization = false;
  712. private void Init ()
  713. {
  714. readState = ReadState.Initial;
  715. currentState = XmlNodeType.None;
  716. maybeTextDecl = 0;
  717. allowMultipleRoot = false;
  718. depth = 0;
  719. depthUp = false;
  720. popScope = false;
  721. parserInputStack = new Stack ();
  722. elementStack = new Stack();
  723. currentAttribute = -1;
  724. currentAttributeValue = -1;
  725. returnEntityReference = false;
  726. entityReferenceName = String.Empty;
  727. nameBuffer = new char [initialNameCapacity];
  728. nameLength = 0;
  729. nameCapacity = initialNameCapacity;
  730. valueBuffer = new StringBuilder (512);
  731. parameterEntities = new Hashtable ();
  732. currentToken = new XmlTokenInfo (this);
  733. cursorToken = currentToken;
  734. }
  735. private void InitializeContext (string url, XmlParserContext context, TextReader fragment, XmlNodeType fragType)
  736. {
  737. startNodeType = fragType;
  738. parserContext = context;
  739. if (context == null) {
  740. XmlNameTable nt = new NameTable ();
  741. parserContext = new XmlParserContext (nt,
  742. new XmlNamespaceManager (nt),
  743. String.Empty,
  744. XmlSpace.None);
  745. }
  746. if (url != null && url != String.Empty) {
  747. string path = Path.GetFullPath ("./a");
  748. Uri uri = new Uri (new Uri (path), url);
  749. parserContext.BaseURI = uri.ToString ();
  750. }
  751. Init ();
  752. switch (fragType) {
  753. case XmlNodeType.Attribute:
  754. fragment = new StringReader (fragment.ReadToEnd ().Replace ("\"", "&quot;"));
  755. break;
  756. case XmlNodeType.Element:
  757. currentState = XmlNodeType.Element;
  758. allowMultipleRoot = true;
  759. break;
  760. case XmlNodeType.Document:
  761. break;
  762. default:
  763. throw new XmlException (String.Format ("NodeType {0} is not allowed to create XmlTextReader.", fragType));
  764. }
  765. this.currentInput = new XmlParserInput (fragment, url);
  766. }
  767. // Use this method rather than setting the properties
  768. // directly so that all the necessary properties can
  769. // be changed in harmony with each other. Maybe the
  770. // fields should be in a seperate class to help enforce
  771. // this.
  772. private void SetProperties (
  773. XmlNodeType nodeType,
  774. string name,
  775. bool isEmptyElement,
  776. string value,
  777. bool clearAttributes)
  778. {
  779. this.valueBuilderAvailable = false;
  780. currentToken.Clear ();
  781. currentToken.NodeType = nodeType;
  782. currentToken.Name = name;
  783. currentToken.IsEmptyElement = isEmptyElement;
  784. currentToken.Value = value;
  785. currentToken.LineNumber = this.currentLinkedNodeLineNumber;
  786. currentToken.LinePosition = this.currentLinkedNodeLinePosition;
  787. this.elementDepth = depth;
  788. if (clearAttributes)
  789. ClearAttributes ();
  790. currentToken.FillNames ();
  791. }
  792. private void SetProperties (
  793. XmlNodeType nodeType,
  794. string name,
  795. bool isEmptyElement,
  796. bool clearAttributes,
  797. StringBuilder value) {
  798. SetProperties (nodeType, name, isEmptyElement, (string)null, clearAttributes);
  799. this.valueBuilderAvailable = true;
  800. this.valueBuilder = value;
  801. }
  802. private void ClearAttributes ()
  803. {
  804. for (int i = 0; i < attributeCount; i++)
  805. attributeTokens [i].Clear ();
  806. attributeCount = 0;
  807. currentAttribute = -1;
  808. currentAttributeValue = -1;
  809. }
  810. private int PeekChar ()
  811. {
  812. return currentInput.PeekChar ();
  813. }
  814. private int ReadChar ()
  815. {
  816. return currentInput.ReadChar ();
  817. }
  818. // This should really keep track of some state so
  819. // that it's not possible to have more than one document
  820. // element or text outside of the document element.
  821. private bool ReadContent ()
  822. {
  823. currentTag.Length = 0;
  824. if (popScope) {
  825. parserContext.NamespaceManager.PopScope ();
  826. popScope = false;
  827. }
  828. if (returnEntityReference)
  829. SetEntityReferenceProperties ();
  830. else {
  831. switch (PeekChar ()) {
  832. case '<':
  833. ReadChar ();
  834. ReadTag ();
  835. break;
  836. case '\r': goto case ' ';
  837. case '\n': goto case ' ';
  838. case '\t': goto case ' ';
  839. case ' ':
  840. if (whitespaceHandling == WhitespaceHandling.All ||
  841. whitespaceHandling == WhitespaceHandling.Significant)
  842. ReadWhitespace ();
  843. else {
  844. SkipWhitespace ();
  845. return ReadContent ();
  846. }
  847. break;
  848. case -1:
  849. if (depth > 0)
  850. throw new XmlException ("unexpected end of file. Current depth is " + depth);
  851. readState = ReadState.EndOfFile;
  852. SetProperties (
  853. XmlNodeType.None, // nodeType
  854. String.Empty, // name
  855. false, // isEmptyElement
  856. (string) null, // value
  857. true // clearAttributes
  858. );
  859. return false;
  860. default:
  861. ReadText (true);
  862. break;
  863. }
  864. }
  865. if (NodeType == XmlNodeType.XmlDeclaration && maybeTextDecl == 1)
  866. return ReadContent ();
  867. return this.ReadState != ReadState.EndOfFile;
  868. }
  869. private void SetEntityReferenceProperties ()
  870. {
  871. /*
  872. if (resolver != null) {
  873. if (DTD == null)
  874. throw new XmlException (this as IXmlLineInfo,
  875. "Entity reference is not allowed without document type declaration.");
  876. else if((!DTD.InternalSubsetHasPEReference || isStandalone) &&
  877. DTD.EntityDecls [entityReferenceName] == null)
  878. throw new XmlException (this as IXmlLineInfo,
  879. "Required entity declaration for '" + entityReferenceName + "' was not found.");
  880. string dummy = DTD.EntityDecls [entityReferenceName].EntityValue;
  881. }
  882. */
  883. SetProperties (
  884. XmlNodeType.EntityReference, // nodeType
  885. entityReferenceName, // name
  886. false, // isEmptyElement
  887. (string) null, // value
  888. true // clearAttributes
  889. );
  890. returnEntityReference = false;
  891. entityReferenceName = String.Empty;
  892. }
  893. // The leading '<' has already been consumed.
  894. private void ReadTag ()
  895. {
  896. switch (PeekChar ())
  897. {
  898. case '/':
  899. ReadChar ();
  900. ReadEndTag ();
  901. break;
  902. case '?':
  903. ReadChar ();
  904. ReadProcessingInstruction ();
  905. break;
  906. case '!':
  907. ReadChar ();
  908. ReadDeclaration ();
  909. break;
  910. default:
  911. ReadStartTag ();
  912. break;
  913. }
  914. }
  915. // The leading '<' has already been consumed.
  916. private void ReadStartTag ()
  917. {
  918. if (currentState == XmlNodeType.EndElement)
  919. throw new XmlException (this as IXmlLineInfo,
  920. "Element cannot appear in this state.");
  921. currentState = XmlNodeType.Element;
  922. parserContext.NamespaceManager.PushScope ();
  923. string name = ReadName ();
  924. if (currentState == XmlNodeType.EndElement)
  925. throw new XmlException (this as IXmlLineInfo,"document has terminated, cannot open new element");
  926. bool isEmptyElement = false;
  927. ClearAttributes ();
  928. SkipWhitespace ();
  929. if (XmlChar.IsFirstNameChar (PeekChar ()))
  930. ReadAttributes (false);
  931. // fill namespaces
  932. for (int i = 0; i < attributeCount; i++)
  933. attributeTokens [i].FillNames ();
  934. // quick name check
  935. for (int i = 0; i < attributeCount; i++)
  936. for (int j = i + 1; j < attributeCount; j++)
  937. if (Object.ReferenceEquals (attributeTokens [i].Name, attributeTokens [j].Name) ||
  938. (Object.ReferenceEquals (attributeTokens [i].LocalName, attributeTokens [j].LocalName) &&
  939. Object.ReferenceEquals (attributeTokens [i].NamespaceURI, attributeTokens [j].NamespaceURI)))
  940. throw new XmlException (this as IXmlLineInfo,
  941. "Attribute name and qualified name must be identical.");
  942. string baseUri = GetAttribute ("xml:base");
  943. if (baseUri != null)
  944. parserContext.BaseURI = baseUri;
  945. string xmlLang = GetAttribute ("xml:lang");
  946. if (xmlLang != null)
  947. parserContext.XmlLang = xmlLang;
  948. string xmlSpaceAttr = GetAttribute ("xml:space");
  949. if (xmlSpaceAttr != null) {
  950. if (xmlSpaceAttr == "preserve")
  951. parserContext.XmlSpace = XmlSpace.Preserve;
  952. else if (xmlSpaceAttr == "default")
  953. parserContext.XmlSpace = XmlSpace.Default;
  954. else
  955. throw new XmlException (this as IXmlLineInfo,String.Format ("Invalid xml:space value: {0}", xmlSpaceAttr));
  956. }
  957. if (PeekChar () == '/') {
  958. ReadChar ();
  959. isEmptyElement = true;
  960. popScope = true;
  961. }
  962. else {
  963. depthUp = true;
  964. elementStack.Push (name);
  965. parserContext.PushScope ();
  966. }
  967. Expect ('>');
  968. SetProperties (
  969. XmlNodeType.Element, // nodeType
  970. name, // name
  971. isEmptyElement, // isEmptyElement
  972. (string) null, // value
  973. false // clearAttributes
  974. );
  975. }
  976. // The reader is positioned on the first character
  977. // of the element's name.
  978. private void ReadEndTag ()
  979. {
  980. if (currentState != XmlNodeType.Element)
  981. throw new XmlException (this as IXmlLineInfo,
  982. "End tag cannot appear in this state.");
  983. string name = ReadName ();
  984. if (elementStack.Count == 0)
  985. throw new XmlException (this as IXmlLineInfo,"closing element without matching opening element");
  986. string expected = (string)elementStack.Pop();
  987. if (expected != name)
  988. throw new XmlException (this as IXmlLineInfo,String.Format ("unmatched closing element: expected {0} but found {1}", expected, name));
  989. parserContext.PopScope ();
  990. SkipWhitespace ();
  991. Expect ('>');
  992. --depth;
  993. SetProperties (
  994. XmlNodeType.EndElement, // nodeType
  995. name, // name
  996. false, // isEmptyElement
  997. (string) null, // value
  998. true // clearAttributes
  999. );
  1000. popScope = true;
  1001. }
  1002. private void AppendNameChar (int ch)
  1003. {
  1004. CheckNameCapacity ();
  1005. nameBuffer [nameLength++] = (char)ch;
  1006. }
  1007. private void CheckNameCapacity ()
  1008. {
  1009. if (nameLength == nameCapacity) {
  1010. nameCapacity = nameCapacity * 2;
  1011. char [] oldNameBuffer = nameBuffer;
  1012. nameBuffer = new char [nameCapacity];
  1013. Array.Copy (oldNameBuffer, nameBuffer, nameLength);
  1014. }
  1015. }
  1016. private string CreateNameString ()
  1017. {
  1018. return parserContext.NameTable.Add (nameBuffer, 0, nameLength);
  1019. }
  1020. private void AppendValueChar (int ch)
  1021. {
  1022. valueBuffer.Append ((char)ch);
  1023. }
  1024. private string CreateValueString ()
  1025. {
  1026. return valueBuffer.ToString ();
  1027. }
  1028. private void ClearValueBuffer ()
  1029. {
  1030. valueBuffer.Length = 0;
  1031. }
  1032. // The reader is positioned on the first character
  1033. // of the text.
  1034. private void ReadText (bool notWhitespace)
  1035. {
  1036. if (currentState != XmlNodeType.Element)
  1037. throw new XmlException (this as IXmlLineInfo,
  1038. "Text node cannot appear in this state.");
  1039. if (notWhitespace)
  1040. ClearValueBuffer ();
  1041. int ch = PeekChar ();
  1042. int previousCloseBracketLine = 0;
  1043. int previousCloseBracketColumn = 0;
  1044. while (ch != '<' && ch != -1) {
  1045. if (ch == '&') {
  1046. ReadChar ();
  1047. if (ReadReference (false))
  1048. break;
  1049. } else {
  1050. if (XmlConstructs.IsInvalid (ch))
  1051. throw new XmlException (this as IXmlLineInfo,
  1052. "Not allowed character was found.");
  1053. AppendValueChar (ReadChar ());
  1054. if (ch == ']') {
  1055. if (previousCloseBracketColumn == LinePosition - 1 &&
  1056. previousCloseBracketLine == LineNumber)
  1057. if (PeekChar () == '>')
  1058. throw new XmlException (this as IXmlLineInfo,
  1059. "Inside text content, character sequence ']]>' is not allowed.");
  1060. previousCloseBracketColumn = LinePosition;
  1061. previousCloseBracketLine = LineNumber;
  1062. }
  1063. }
  1064. ch = PeekChar ();
  1065. notWhitespace = true;
  1066. }
  1067. if (returnEntityReference && valueBuffer.Length == 0) {
  1068. SetEntityReferenceProperties ();
  1069. } else {
  1070. XmlNodeType nodeType = notWhitespace ?
  1071. XmlNodeType.Text : XmlNodeType.Whitespace;
  1072. SetProperties (
  1073. nodeType, // nodeType
  1074. String.Empty, // name
  1075. false, // isEmptyElement
  1076. true, // clearAttributes
  1077. valueBuffer // value
  1078. );
  1079. }
  1080. }
  1081. // The leading '&' has already been consumed.
  1082. // Returns true if the entity reference isn't a simple
  1083. // character reference or one of the predefined entities.
  1084. // This allows the ReadText method to break so that the
  1085. // next call to Read will return the EntityReference node.
  1086. private bool ReadReference (bool ignoreEntityReferences)
  1087. {
  1088. if (PeekChar () == '#') {
  1089. ReadChar ();
  1090. ReadCharacterReference ();
  1091. } else
  1092. ReadEntityReference (ignoreEntityReferences);
  1093. return returnEntityReference;
  1094. }
  1095. private void ReadCharacterReference ()
  1096. {
  1097. int value = 0;
  1098. if (PeekChar () == 'x') {
  1099. ReadChar ();
  1100. while (PeekChar () != ';' && PeekChar () != -1) {
  1101. int ch = ReadChar ();
  1102. if (ch >= '0' && ch <= '9')
  1103. value = (value << 4) + ch - '0';
  1104. else if (ch >= 'A' && ch <= 'F')
  1105. value = (value << 4) + ch - 'A' + 10;
  1106. else if (ch >= 'a' && ch <= 'f')
  1107. value = (value << 4) + ch - 'a' + 10;
  1108. else
  1109. throw new XmlException (this as IXmlLineInfo,
  1110. String.Format (
  1111. "invalid hexadecimal digit: {0} (#x{1:X})",
  1112. (char)ch,
  1113. ch));
  1114. }
  1115. } else {
  1116. while (PeekChar () != ';' && PeekChar () != -1) {
  1117. int ch = ReadChar ();
  1118. if (ch >= '0' && ch <= '9')
  1119. value = value * 10 + ch - '0';
  1120. else
  1121. throw new XmlException (this as IXmlLineInfo,
  1122. String.Format (
  1123. "invalid decimal digit: {0} (#x{1:X})",
  1124. (char)ch,
  1125. ch));
  1126. }
  1127. }
  1128. ReadChar (); // ';'
  1129. // FIXME: how to handle such chars larger than 0xffff?
  1130. if (value < 0xffff && !XmlConstructs.IsValid (value))
  1131. throw new XmlException (this as IXmlLineInfo,
  1132. "Referenced character was not allowed in XML.");
  1133. AppendValueChar (value);
  1134. }
  1135. private void ReadEntityReference (bool ignoreEntityReferences)
  1136. {
  1137. nameLength = 0;
  1138. int ch = PeekChar ();
  1139. while (ch != ';' && ch != -1) {
  1140. AppendNameChar (ReadChar ());
  1141. ch = PeekChar ();
  1142. }
  1143. Expect (';');
  1144. string name = CreateNameString ();
  1145. if (!XmlChar.IsName (name))
  1146. throw new XmlException (this as IXmlLineInfo,
  1147. "Invalid entity reference name was found.");
  1148. char predefined = XmlChar.GetPredefinedEntity (name);
  1149. if (predefined != 0)
  1150. AppendValueChar (predefined);
  1151. else {
  1152. if (ignoreEntityReferences) {
  1153. AppendValueChar ('&');
  1154. foreach (char ch2 in name) {
  1155. AppendValueChar (ch2);
  1156. }
  1157. AppendValueChar (';');
  1158. } else {
  1159. returnEntityReference = true;
  1160. entityReferenceName = name;
  1161. }
  1162. }
  1163. }
  1164. // The reader is positioned on the first character of
  1165. // the attribute name.
  1166. private void ReadAttributes (bool endsWithQuestion)
  1167. {
  1168. int peekChar = -1;
  1169. bool requireWhitespace = false;
  1170. currentAttribute = -1;
  1171. currentAttributeValue = -1;
  1172. do {
  1173. if (!SkipWhitespace () && requireWhitespace)
  1174. throw new XmlException ("Unexpected token. Name is required here.");
  1175. IncrementAttributeToken ();
  1176. currentAttributeToken.LineNumber = currentInput.LineNumber;
  1177. currentAttributeToken.LinePosition = currentInput.LinePosition;
  1178. currentAttributeToken.Name = ReadName ();
  1179. SkipWhitespace ();
  1180. Expect ('=');
  1181. SkipWhitespace ();
  1182. ReadAttributeValueTokens (-1);
  1183. attributeCount++;
  1184. if (currentAttributeToken.Name == "xmlns")
  1185. parserContext.NamespaceManager.AddNamespace (String.Empty, GetAttribute (currentAttribute));
  1186. else if (currentAttributeToken.Name.StartsWith ("xmlns:")) {
  1187. string nsPrefix = NameTable.Add (currentAttributeToken.Name.Substring (6));
  1188. parserContext.NamespaceManager.AddNamespace (nsPrefix, GetAttribute (currentAttribute));
  1189. }
  1190. if (!SkipWhitespace ())
  1191. requireWhitespace = true;
  1192. peekChar = PeekChar ();
  1193. if (endsWithQuestion) {
  1194. if (peekChar == '?')
  1195. break;
  1196. }
  1197. else if (peekChar == '/' || peekChar == '>')
  1198. break;
  1199. } while (peekChar != -1);
  1200. currentAttribute = -1;
  1201. currentAttributeValue = -1;
  1202. }
  1203. private void AddAttribute (string name, string value)
  1204. {
  1205. IncrementAttributeToken ();
  1206. XmlAttributeTokenInfo ati = attributeTokens [currentAttribute];
  1207. ati.Name = "SYSTEM";
  1208. ati.FillNames ();
  1209. IncrementAttributeValueToken ();
  1210. XmlTokenInfo vti = attributeValueTokens [currentAttributeValue];
  1211. vti.Value = value;
  1212. currentToken = vti;
  1213. SetProperties (XmlNodeType.Text, name, false, value, false);
  1214. attributeCount++;
  1215. }
  1216. private void IncrementAttributeToken ()
  1217. {
  1218. currentAttribute++;
  1219. if (attributeTokens.Length == currentAttribute) {
  1220. XmlAttributeTokenInfo [] newArray =
  1221. new XmlAttributeTokenInfo [attributeTokens.Length * 2];
  1222. attributeTokens.CopyTo (newArray, 0);
  1223. attributeTokens = newArray;
  1224. }
  1225. if (attributeTokens [currentAttribute] == null)
  1226. attributeTokens [currentAttribute] = new XmlAttributeTokenInfo (this);
  1227. currentAttributeToken = attributeTokens [currentAttribute];
  1228. currentAttributeToken.Clear ();
  1229. }
  1230. private void IncrementAttributeValueToken ()
  1231. {
  1232. ClearValueBuffer ();
  1233. currentAttributeValue++;
  1234. if (attributeValueTokens.Length == currentAttributeValue) {
  1235. XmlTokenInfo [] newArray = new XmlTokenInfo [attributeValueTokens.Length * 2];
  1236. attributeValueTokens.CopyTo (newArray, 0);
  1237. attributeValueTokens = newArray;
  1238. }
  1239. if (attributeValueTokens [currentAttributeValue] == null)
  1240. attributeValueTokens [currentAttributeValue] = new XmlTokenInfo (this);
  1241. currentAttributeValueToken = attributeValueTokens [currentAttributeValue];
  1242. currentAttributeValueToken.Clear ();
  1243. }
  1244. private void ReadAttributeValueTokens (int dummyQuoteChar)
  1245. {
  1246. int quoteChar = (dummyQuoteChar < 0) ? ReadChar () : dummyQuoteChar;
  1247. if (quoteChar != '\'' && quoteChar != '\"')
  1248. throw new XmlException (this as IXmlLineInfo,"an attribute value was not quoted");
  1249. currentAttributeToken.QuoteChar = (char) quoteChar;
  1250. IncrementAttributeValueToken ();
  1251. currentAttributeToken.ValueTokenStartIndex = currentAttributeValue;
  1252. currentAttributeValueToken.LineNumber = currentInput.LineNumber;
  1253. currentAttributeValueToken.LinePosition = currentInput.LinePosition;
  1254. bool incrementToken = false;
  1255. bool isNewToken = true;
  1256. bool loop = true;
  1257. while (loop && PeekChar () != quoteChar) {
  1258. if (incrementToken) {
  1259. IncrementAttributeValueToken ();
  1260. currentAttributeValueToken.LineNumber = currentInput.LineNumber;
  1261. currentAttributeValueToken.LinePosition = currentInput.LinePosition;
  1262. incrementToken = false;
  1263. isNewToken = true;
  1264. }
  1265. int ch = ReadChar ();
  1266. switch (ch)
  1267. {
  1268. case '<':
  1269. throw new XmlException (this as IXmlLineInfo,"attribute values cannot contain '<'");
  1270. case -1:
  1271. if (dummyQuoteChar < 0)
  1272. throw new XmlException (this as IXmlLineInfo,"unexpected end of file in an attribute value");
  1273. else // Attribute value constructor.
  1274. loop = false;
  1275. break;
  1276. case '&':
  1277. int startPosition = currentTag.Length - 1;
  1278. if (PeekChar () == '#') {
  1279. ReadChar ();
  1280. this.ReadCharacterReference ();
  1281. break;
  1282. }
  1283. // Check XML 1.0 section 3.1 WFC.
  1284. string entName = ReadName ();
  1285. Expect (';');
  1286. int predefined = XmlChar.GetPredefinedEntity (entName);
  1287. if (predefined == 0) {
  1288. DTDEntityDeclaration entDecl =
  1289. DTD == null ? null : DTD.EntityDecls [entName];
  1290. if (entDecl != null && entDecl.SystemId != null)
  1291. // if (!startNodeType == XmlNodeType.Attribute && (entDecl == null || entDecl.SystemId != null))
  1292. throw new XmlException (this as IXmlLineInfo,
  1293. "Reference to external entities is not allowed in the value of an attribute.");
  1294. currentAttributeValueToken.Value = CreateValueString ();
  1295. currentAttributeValueToken.NodeType = XmlNodeType.Text;
  1296. if (!isNewToken)
  1297. IncrementAttributeValueToken ();
  1298. currentAttributeValueToken.Name = entName;
  1299. currentAttributeValueToken.Value = String.Empty;
  1300. currentAttributeValueToken.NodeType = XmlNodeType.EntityReference;
  1301. incrementToken = true;
  1302. }
  1303. else
  1304. AppendValueChar (predefined);
  1305. break;
  1306. default:
  1307. AppendValueChar (ch);
  1308. break;
  1309. }
  1310. isNewToken = false;
  1311. }
  1312. if (!incrementToken) {
  1313. currentAttributeValueToken.Value = CreateValueString ();
  1314. currentAttributeValueToken.NodeType = XmlNodeType.Text;
  1315. currentAttributeToken.ValueTokenEndIndex = currentAttributeValue;
  1316. }
  1317. if (dummyQuoteChar < 0)
  1318. ReadChar (); // quoteChar
  1319. }
  1320. // The reader is positioned on the quote character.
  1321. // *Keeps quote char* to value to get_QuoteChar() correctly.
  1322. // Not it is used only for DTD.
  1323. private string ReadAttribute (bool isDefaultValue)
  1324. {
  1325. ClearValueBuffer ();
  1326. int quoteChar = ReadChar ();
  1327. if (quoteChar != '\'' && quoteChar != '\"')
  1328. throw new XmlException (this as IXmlLineInfo,"an attribute value was not quoted");
  1329. AppendValueChar (quoteChar);
  1330. while (PeekChar () != quoteChar) {
  1331. int ch = ReadChar ();
  1332. switch (ch)
  1333. {
  1334. case '<':
  1335. throw new XmlException (this as IXmlLineInfo,"attribute values cannot contain '<'");
  1336. case -1:
  1337. throw new XmlException (this as IXmlLineInfo,"unexpected end of file in an attribute value");
  1338. /*
  1339. case '&':
  1340. if (isDefaultValue) {
  1341. AppendValueChar (ch);
  1342. break;
  1343. }
  1344. AppendValueChar (ch);
  1345. if (PeekChar () == '#')
  1346. break;
  1347. // Check XML 1.0 section 3.1 WFC.
  1348. string entName = ReadName ();
  1349. Expect (';');
  1350. if (XmlChar.GetPredefinedEntity (entName) == 0) {
  1351. DTDEntityDeclaration entDecl =
  1352. DTD == null ? null : DTD.EntityDecls [entName];
  1353. if (entDecl == null || entDecl.SystemId != null)
  1354. throw new XmlException (this as IXmlLineInfo,
  1355. "Reference to external entities is not allowed in attribute value.");
  1356. }
  1357. valueBuffer.Append (entName);
  1358. AppendValueChar (';');
  1359. break;
  1360. */
  1361. default:
  1362. AppendValueChar (ch);
  1363. break;
  1364. }
  1365. }
  1366. ReadChar (); // quoteChar
  1367. AppendValueChar (quoteChar);
  1368. return CreateValueString ();
  1369. }
  1370. // The reader is positioned on the first character
  1371. // of the target.
  1372. //
  1373. // It may be xml declaration or processing instruction.
  1374. private void ReadProcessingInstruction ()
  1375. {
  1376. string target = ReadName ();
  1377. if (target == "xml") {
  1378. ReadXmlDeclaration ();
  1379. return;
  1380. } else if (target.ToLower () == "xml")
  1381. throw new XmlException (this as IXmlLineInfo,
  1382. "Not allowed processing instruction name which starts with 'X', 'M', 'L' was found.");
  1383. if (currentState == XmlNodeType.None)
  1384. currentState = XmlNodeType.XmlDeclaration;
  1385. if (!SkipWhitespace ())
  1386. if (PeekChar () != '?')
  1387. throw new XmlException (this as IXmlLineInfo,
  1388. "Invalid processing instruction name was found.");
  1389. ClearValueBuffer ();
  1390. while (PeekChar () != -1) {
  1391. int ch = ReadChar ();
  1392. if (ch == '?' && PeekChar () == '>') {
  1393. ReadChar ();
  1394. break;
  1395. }
  1396. AppendValueChar ((char)ch);
  1397. }
  1398. SetProperties (
  1399. XmlNodeType.ProcessingInstruction, // nodeType
  1400. target, // name
  1401. false, // isEmptyElement
  1402. true, // clearAttributes
  1403. valueBuffer // value
  1404. );
  1405. }
  1406. // The reader is positioned after "<?xml "
  1407. private void ReadXmlDeclaration ()
  1408. {
  1409. if (currentState != XmlNodeType.None) {
  1410. if (maybeTextDecl == 0)
  1411. throw new XmlException (this as IXmlLineInfo,
  1412. "XML declaration cannot appear in this state.");
  1413. }
  1414. // Is this required?
  1415. if (maybeTextDecl != 0)
  1416. currentState = XmlNodeType.XmlDeclaration;
  1417. ClearAttributes ();
  1418. ReadAttributes (true); // They must have "version."
  1419. string version = GetAttribute ("version");
  1420. string message = null;
  1421. if (parserInputStack.Count == 0) {
  1422. if (maybeTextDecl == 0 && (attributeTokens [0].Name != "version" || version != "1.0"))
  1423. message = "Version 1.0 declaration is required in XML Declaration.";
  1424. else if (attributeCount > 1 &&
  1425. (attributeTokens [1].Name != "encoding" &&
  1426. attributeTokens [1].Name != "standalone"))
  1427. message = "Invalid Xml Declaration markup was found.";
  1428. else if (attributeCount > 2 && attributeTokens [2].Name != "standalone")
  1429. message = "Invalid Xml Declaration markup was found.";
  1430. string sa = GetAttribute ("standalone");
  1431. if (sa != null && sa != "yes" && sa != "no")
  1432. message = "Only 'yes' or 'no' is allowed for standalone.";
  1433. this.isStandalone = (sa == "yes");
  1434. } else {
  1435. int currentCheck = 0;
  1436. if (attributeTokens [0].Name == "version") {
  1437. if (version != "1.0")
  1438. message = "Version 1.0 declaration is required in Text Declaration.";
  1439. currentCheck = 1;
  1440. }
  1441. if (attributeCount <= currentCheck || attributeTokens [currentCheck].Name != "encoding")
  1442. message = "Invalid Text Declaration markup was found. encoding specification is required.";
  1443. }
  1444. if (message != null)
  1445. throw new XmlException (this as IXmlLineInfo, message);
  1446. Expect ("?>");
  1447. if (maybeTextDecl != 0)
  1448. if (this ["standalone"] != null)
  1449. throw new XmlException (this as IXmlLineInfo,
  1450. "Invalid text declaration.");
  1451. if (maybeTextDecl == 2)
  1452. maybeTextDecl = 1;
  1453. SetProperties (
  1454. XmlNodeType.XmlDeclaration, // nodeType
  1455. "xml", // name
  1456. false, // isEmptyElement
  1457. currentInput.CurrentMarkup.ToString (6, currentInput.CurrentMarkup.Length - 6), // value
  1458. false // clearAttributes
  1459. );
  1460. }
  1461. // The reader is positioned on the first character after
  1462. // the leading '<!'.
  1463. private void ReadDeclaration ()
  1464. {
  1465. int ch = PeekChar ();
  1466. switch (ch)
  1467. {
  1468. case '-':
  1469. Expect ("--");
  1470. ReadComment ();
  1471. break;
  1472. case '[':
  1473. ReadChar ();
  1474. Expect ("CDATA[");
  1475. ReadCDATA ();
  1476. break;
  1477. case 'D':
  1478. Expect ("DOCTYPE");
  1479. ReadDoctypeDecl ();
  1480. break;
  1481. default:
  1482. throw new XmlException (this as IXmlLineInfo,
  1483. "Unexpected declaration markup was found.");
  1484. }
  1485. }
  1486. // The reader is positioned on the first character after
  1487. // the leading '<!--'.
  1488. private void ReadComment ()
  1489. {
  1490. if (currentState == XmlNodeType.None)
  1491. currentState = XmlNodeType.XmlDeclaration;
  1492. ClearValueBuffer ();
  1493. while (PeekChar () != -1) {
  1494. int ch = ReadChar ();
  1495. if (ch == '-' && PeekChar () == '-') {
  1496. ReadChar ();
  1497. if (PeekChar () != '>')
  1498. throw new XmlException (this as IXmlLineInfo,"comments cannot contain '--'");
  1499. ReadChar ();
  1500. break;
  1501. }
  1502. if (XmlConstructs.IsInvalid (ch))
  1503. throw new XmlException (this as IXmlLineInfo,
  1504. "Not allowed character was found.");
  1505. AppendValueChar ((char)ch);
  1506. }
  1507. SetProperties (
  1508. XmlNodeType.Comment, // nodeType
  1509. String.Empty, // name
  1510. false, // isEmptyElement
  1511. true, // clearAttributes
  1512. valueBuffer // value
  1513. );
  1514. }
  1515. // The reader is positioned on the first character after
  1516. // the leading '<![CDATA['.
  1517. private void ReadCDATA ()
  1518. {
  1519. if (currentState != XmlNodeType.Element)
  1520. throw new XmlException (this as IXmlLineInfo,
  1521. "CDATA section cannot appear in this state.");
  1522. ClearValueBuffer ();
  1523. bool skip = false;
  1524. int ch = 0;
  1525. while (PeekChar () != -1) {
  1526. if (!skip)
  1527. ch = ReadChar ();
  1528. skip = false;
  1529. if (ch == ']' && PeekChar () == ']') {
  1530. ch = ReadChar (); // ']'
  1531. if (PeekChar () == '>') {
  1532. ReadChar (); // '>'
  1533. break;
  1534. } else {
  1535. skip = true;
  1536. // AppendValueChar (']');
  1537. // AppendValueChar (']');
  1538. // ch = ReadChar ();
  1539. }
  1540. }
  1541. AppendValueChar ((char)ch);
  1542. }
  1543. SetProperties (
  1544. XmlNodeType.CDATA, // nodeType
  1545. String.Empty, // name
  1546. false, // isEmptyElement
  1547. true, // clearAttributes
  1548. valueBuffer // value
  1549. );
  1550. }
  1551. // The reader is positioned on the first character after
  1552. // the leading '<!DOCTYPE'.
  1553. private void ReadDoctypeDecl ()
  1554. {
  1555. switch (currentState) {
  1556. case XmlNodeType.DocumentType:
  1557. case XmlNodeType.Element:
  1558. case XmlNodeType.EndElement:
  1559. throw new XmlException (this as IXmlLineInfo,
  1560. "Document type cannot appear in this state.");
  1561. }
  1562. currentState = XmlNodeType.DocumentType;
  1563. string doctypeName = null;
  1564. string publicId = null;
  1565. string systemId = null;
  1566. int intSubsetStartLine = 0;
  1567. int intSubsetStartColumn = 0;
  1568. SkipWhitespace ();
  1569. doctypeName = ReadName ();
  1570. SkipWhitespace ();
  1571. switch(PeekChar ())
  1572. {
  1573. case 'S':
  1574. systemId = ReadSystemLiteral (true);
  1575. break;
  1576. case 'P':
  1577. publicId = ReadPubidLiteral ();
  1578. if (!SkipWhitespace ())
  1579. throw new XmlException (this as IXmlLineInfo,
  1580. "Whitespace is required between PUBLIC id and SYSTEM id.");
  1581. systemId = ReadSystemLiteral (false);
  1582. break;
  1583. }
  1584. SkipWhitespace ();
  1585. if(PeekChar () == '[')
  1586. {
  1587. // read markupdecl etc. or end of decl
  1588. ReadChar ();
  1589. intSubsetStartLine = this.LineNumber;
  1590. intSubsetStartColumn = this.LinePosition;
  1591. int startPos = currentTag.Length;
  1592. ReadInternalSubset ();
  1593. int endPos = currentTag.Length - 1;
  1594. parserContext.InternalSubset = currentTag.ToString (startPos, endPos - startPos);
  1595. }
  1596. // end of DOCTYPE decl.
  1597. SkipWhitespace ();
  1598. Expect ('>');
  1599. GenerateDTDObjectModel (doctypeName, publicId,
  1600. systemId, parserContext.InternalSubset,
  1601. intSubsetStartLine, intSubsetStartColumn);
  1602. // set properties for <!DOCTYPE> node
  1603. SetProperties (
  1604. XmlNodeType.DocumentType, // nodeType
  1605. doctypeName, // name
  1606. false, // isEmptyElement
  1607. parserContext.InternalSubset, // value
  1608. true // clearAttributes
  1609. );
  1610. if (publicId != null)
  1611. AddAttribute ("PUBLIC", publicId);
  1612. if (systemId != null)
  1613. AddAttribute ("SYSTEM", systemId);
  1614. }
  1615. internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
  1616. string systemId, string internalSubset)
  1617. {
  1618. return GenerateDTDObjectModel (name, publicId, systemId, internalSubset, 0, 0);
  1619. }
  1620. internal DTDObjectModel GenerateDTDObjectModel (string name, string publicId,
  1621. string systemId, string internalSubset, int intSubsetStartLine, int intSubsetStartColumn)
  1622. {
  1623. // now compile DTD
  1624. parserContext.Dtd = new DTDObjectModel (); // merges both internal and external subsets in the meantime,
  1625. DTD.BaseURI = BaseURI;
  1626. DTD.Name = name;
  1627. DTD.PublicId = publicId;
  1628. DTD.SystemId = systemId;
  1629. DTD.InternalSubset = internalSubset;
  1630. DTD.XmlResolver = resolver;
  1631. int originalParserDepth = parserInputStack.Count;
  1632. bool more;
  1633. if (internalSubset != null && internalSubset.Length > 0) {
  1634. XmlParserInput original = currentInput;
  1635. currentInput = new XmlParserInput (new StringReader (internalSubset), BaseURI, intSubsetStartLine, intSubsetStartColumn);
  1636. do {
  1637. more = CompileDTDSubset ();
  1638. if (PeekChar () == -1 && parserInputStack.Count > 0)
  1639. PopParserInput ();
  1640. } while (more || parserInputStack.Count > originalParserDepth);
  1641. if (dtdIncludeSect != 0)
  1642. throw new XmlException (this as IXmlLineInfo,"INCLUDE section is not ended correctly.");
  1643. currentInput = original;
  1644. }
  1645. if (systemId != null && systemId != String.Empty && resolver != null) {
  1646. PushParserInput (systemId);
  1647. do {
  1648. more = this.CompileDTDSubset ();
  1649. if (PeekChar () == -1 && parserInputStack.Count > 1)
  1650. PopParserInput ();
  1651. } while (more || parserInputStack.Count > originalParserDepth + 1);
  1652. PopParserInput ();
  1653. }
  1654. return DTD;
  1655. }
  1656. private void PushParserInput (string url)
  1657. {
  1658. Uri baseUri = null;
  1659. try {
  1660. baseUri = new Uri (BaseURI);
  1661. } catch (UriFormatException) {
  1662. }
  1663. Uri absUri = resolver.ResolveUri (baseUri, url);
  1664. string absPath = absUri.ToString ();
  1665. foreach (XmlParserInput i in parserInputStack.ToArray ()) {
  1666. if (i.BaseURI == absPath)
  1667. throw new XmlException (this as IXmlLineInfo, "Nested inclusion is not allowed: " + url);
  1668. }
  1669. parserInputStack.Push (currentInput);
  1670. currentInput = new XmlParserInput (new XmlStreamReader (url, false, resolver, BaseURI), absPath);
  1671. parserContext.PushScope ();
  1672. parserContext.BaseURI = absPath;
  1673. maybeTextDecl = 2;
  1674. }
  1675. private void PopParserInput ()
  1676. {
  1677. currentInput = parserInputStack.Pop () as XmlParserInput;
  1678. parserContext.PopScope ();
  1679. }
  1680. private enum DtdInputState
  1681. {
  1682. Free = 1,
  1683. ElementDecl,
  1684. AttlistDecl,
  1685. EntityDecl,
  1686. NotationDecl,
  1687. PI,
  1688. Comment,
  1689. InsideSingleQuoted,
  1690. InsideDoubleQuoted,
  1691. }
  1692. private class DtdInputStateStack
  1693. {
  1694. Stack intern = new Stack ();
  1695. public DtdInputStateStack ()
  1696. {
  1697. Push (DtdInputState.Free);
  1698. }
  1699. public DtdInputState Peek ()
  1700. {
  1701. return (DtdInputState) intern.Peek ();
  1702. }
  1703. public DtdInputState Pop ()
  1704. {
  1705. return (DtdInputState) intern.Pop ();
  1706. }
  1707. public void Push (DtdInputState val)
  1708. {
  1709. intern.Push (val);
  1710. }
  1711. }
  1712. DtdInputStateStack stateStack = new DtdInputStateStack ();
  1713. DtdInputState State {
  1714. get { return stateStack.Peek (); }
  1715. }
  1716. // Simply read but not generate any result.
  1717. private void ReadInternalSubset ()
  1718. {
  1719. bool continueParse = true;
  1720. while (continueParse) {
  1721. switch (ReadChar ()) {
  1722. case ']':
  1723. switch (State) {
  1724. case DtdInputState.Free:
  1725. continueParse = false;
  1726. break;
  1727. case DtdInputState.InsideDoubleQuoted:
  1728. continue;
  1729. case DtdInputState.InsideSingleQuoted:
  1730. continue;
  1731. default:
  1732. throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
  1733. }
  1734. break;
  1735. case -1:
  1736. throw new XmlException (this as IXmlLineInfo,"unexpected end of file at DTD.");
  1737. case '<':
  1738. if (State == DtdInputState.InsideDoubleQuoted ||
  1739. State == DtdInputState.InsideSingleQuoted)
  1740. continue; // well-formed
  1741. switch (ReadChar ()) {
  1742. case '?':
  1743. stateStack.Push (DtdInputState.PI);
  1744. break;
  1745. case '!':
  1746. switch (ReadChar ()) {
  1747. case 'E':
  1748. switch (ReadChar ()) {
  1749. case 'L':
  1750. Expect ("EMENT");
  1751. stateStack.Push (DtdInputState.ElementDecl);
  1752. break;
  1753. case 'N':
  1754. Expect ("TITY");
  1755. stateStack.Push (DtdInputState.EntityDecl);
  1756. break;
  1757. default:
  1758. throw new XmlException (this as IXmlLineInfo,"unexpected token '<!E'.");
  1759. }
  1760. break;
  1761. case 'A':
  1762. Expect ("TTLIST");
  1763. stateStack.Push (DtdInputState.AttlistDecl);
  1764. break;
  1765. case 'N':
  1766. Expect ("OTATION");
  1767. stateStack.Push (DtdInputState.NotationDecl);
  1768. break;
  1769. case '-':
  1770. Expect ("-");
  1771. stateStack.Push (DtdInputState.Comment);
  1772. break;
  1773. }
  1774. break;
  1775. default:
  1776. throw new XmlException (this as IXmlLineInfo,"unexpected '>'.");
  1777. }
  1778. break;
  1779. case '\'':
  1780. if (State == DtdInputState.InsideSingleQuoted)
  1781. stateStack.Pop ();
  1782. else if (State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.Comment)
  1783. stateStack.Push (DtdInputState.InsideSingleQuoted);
  1784. break;
  1785. case '"':
  1786. if (State == DtdInputState.InsideDoubleQuoted)
  1787. stateStack.Pop ();
  1788. else if (State != DtdInputState.InsideSingleQuoted && State != DtdInputState.Comment)
  1789. stateStack.Push (DtdInputState.InsideDoubleQuoted);
  1790. break;
  1791. case '>':
  1792. switch (State) {
  1793. case DtdInputState.ElementDecl:
  1794. goto case DtdInputState.NotationDecl;
  1795. case DtdInputState.AttlistDecl:
  1796. goto case DtdInputState.NotationDecl;
  1797. case DtdInputState.EntityDecl:
  1798. goto case DtdInputState.NotationDecl;
  1799. case DtdInputState.NotationDecl:
  1800. stateStack.Pop ();
  1801. break;
  1802. case DtdInputState.InsideDoubleQuoted:
  1803. continue;
  1804. case DtdInputState.InsideSingleQuoted:
  1805. continue; // well-formed
  1806. case DtdInputState.Comment:
  1807. continue;
  1808. default:
  1809. throw new XmlException (this as IXmlLineInfo,"unexpected token '>'");
  1810. }
  1811. break;
  1812. case '?':
  1813. if (State == DtdInputState.PI) {
  1814. if (ReadChar () == '>')
  1815. stateStack.Pop ();
  1816. }
  1817. break;
  1818. case '-':
  1819. if (State == DtdInputState.Comment) {
  1820. if (PeekChar () == '-') {
  1821. ReadChar ();
  1822. Expect ('>');
  1823. stateStack.Pop ();
  1824. }
  1825. }
  1826. break;
  1827. case '%':
  1828. if (State != DtdInputState.Free && State != DtdInputState.EntityDecl && State != DtdInputState.Comment && State != DtdInputState.InsideDoubleQuoted && State != DtdInputState.InsideSingleQuoted)
  1829. throw new XmlException (this as IXmlLineInfo,"Parameter Entity Reference cannot appear as a part of markupdecl (see XML spec 2.8).");
  1830. break;
  1831. }
  1832. }
  1833. }
  1834. // Read any one of following:
  1835. // elementdecl, AttlistDecl, EntityDecl, NotationDecl,
  1836. // PI, Comment, Parameter Entity, or doctype termination char(']')
  1837. //
  1838. // Returns true if it may have any more contents, or false if not.
  1839. private bool CompileDTDSubset()
  1840. {
  1841. SkipWhitespace ();
  1842. switch(PeekChar ())
  1843. {
  1844. case -1:
  1845. return false;
  1846. case '%':
  1847. // It affects on entity references' well-formedness
  1848. if (this.parserInputStack.Count == 0)
  1849. DTD.InternalSubsetHasPEReference = true;
  1850. ReadChar ();
  1851. string peName = ReadName ();
  1852. Expect (';');
  1853. currentInput.InsertParameterEntityBuffer (GetPEValue (peName));
  1854. int currentLine = currentInput.LineNumber;
  1855. int currentColumn = currentInput.LinePosition;
  1856. while (currentInput.HasPEBuffer)
  1857. CompileDTDSubset ();
  1858. if (currentInput.LineNumber != currentLine ||
  1859. currentInput.LinePosition != currentColumn)
  1860. throw new XmlException (this as IXmlLineInfo,
  1861. "Incorrectly nested parameter entity.");
  1862. break;
  1863. case '<':
  1864. ReadChar ();
  1865. switch(ReadChar ())
  1866. {
  1867. case '?':
  1868. // Only read, no store.
  1869. ReadProcessingInstruction ();
  1870. break;
  1871. case '!':
  1872. CompileDeclaration ();
  1873. break;
  1874. default:
  1875. throw new XmlException (this as IXmlLineInfo,"Syntax Error after '<' character.");
  1876. }
  1877. break;
  1878. case ']':
  1879. if (dtdIncludeSect == 0)
  1880. throw new XmlException (this as IXmlLineInfo, "Unbalanced end of INCLUDE/IGNORE section.");
  1881. // End of inclusion
  1882. Expect ("]]>");
  1883. dtdIncludeSect--;
  1884. SkipWhitespace ();
  1885. return false;
  1886. default:
  1887. throw new XmlException (this as IXmlLineInfo,String.Format ("Syntax Error inside doctypedecl markup : {0}({1})", PeekChar (), (char) PeekChar ()));
  1888. }
  1889. return true;
  1890. }
  1891. private void CompileDeclaration ()
  1892. {
  1893. switch(ReadChar ())
  1894. {
  1895. case '-':
  1896. Expect ('-');
  1897. // Only read, no store.
  1898. ReadComment ();
  1899. break;
  1900. case 'E':
  1901. switch(ReadChar ())
  1902. {
  1903. case 'N':
  1904. Expect ("TITY");
  1905. if (!SkipWhitespace ())
  1906. throw new XmlException (this as IXmlLineInfo,
  1907. "Whitespace is required after '<!ENTITY' in DTD entity declaration.");
  1908. LOOPBACK:
  1909. if (PeekChar () == '%') {
  1910. ReadChar ();
  1911. if (!SkipWhitespace ()) {
  1912. ImportAsPERef ();
  1913. goto LOOPBACK;
  1914. } else {
  1915. TryExpandPERef ();
  1916. SkipWhitespace ();
  1917. if (XmlChar.IsNameChar (PeekChar ()))
  1918. ReadParameterEntityDecl ();
  1919. else
  1920. throw new XmlException (this as IXmlLineInfo,"expected name character");
  1921. }
  1922. break;
  1923. }
  1924. DTDEntityDeclaration ent = ReadEntityDecl ();
  1925. if (DTD.EntityDecls [ent.Name] == null)
  1926. DTD.EntityDecls.Add (ent.Name, ent);
  1927. break;
  1928. case 'L':
  1929. Expect ("EMENT");
  1930. DTDElementDeclaration el = ReadElementDecl ();
  1931. DTD.ElementDecls.Add (el.Name, el);
  1932. break;
  1933. default:
  1934. throw new XmlException (this as IXmlLineInfo,"Syntax Error after '<!E' (ELEMENT or ENTITY must be found)");
  1935. }
  1936. break;
  1937. case 'A':
  1938. Expect ("TTLIST");
  1939. DTDAttListDeclaration atl = ReadAttListDecl ();
  1940. // if (DTD.AttListDecls.ContainsKey (atl.Name))
  1941. DTD.AttListDecls.Add (atl.Name, atl);
  1942. break;
  1943. case 'N':
  1944. Expect ("OTATION");
  1945. DTDNotationDeclaration not = ReadNotationDecl ();
  1946. DTD.NotationDecls.Add (not.Name, not);
  1947. break;
  1948. case '[':
  1949. // conditional sections
  1950. SkipWhitespace ();
  1951. TryExpandPERef ();
  1952. SkipWhitespace ();
  1953. Expect ('I');
  1954. switch (ReadChar ()) {
  1955. case 'N':
  1956. Expect ("CLUDE");
  1957. SkipWhitespace ();
  1958. Expect ('[');
  1959. dtdIncludeSect++;
  1960. break;
  1961. case 'G':
  1962. Expect ("NORE");
  1963. ReadIgnoreSect ();
  1964. break;
  1965. }
  1966. break;
  1967. default:
  1968. throw new XmlException (this as IXmlLineInfo,"Syntax Error after '<!' characters.");
  1969. }
  1970. }
  1971. private void ReadIgnoreSect ()
  1972. {
  1973. bool skip = false;
  1974. SkipWhitespace ();
  1975. Expect ('[');
  1976. int dtdIgnoreSect = 1;
  1977. while (dtdIgnoreSect > 0) {
  1978. switch (skip ? PeekChar () : ReadChar ()) {
  1979. case -1:
  1980. throw new XmlException (this as IXmlLineInfo,"Unexpected IGNORE section end.");
  1981. case '<':
  1982. if (ReadChar () == '!' && ReadChar () == '[')
  1983. dtdIgnoreSect++;
  1984. break;
  1985. case ']':
  1986. if (ReadChar () == ']') {
  1987. if (ReadChar () == '>')
  1988. dtdIgnoreSect--;
  1989. else
  1990. skip = true;
  1991. }
  1992. break;
  1993. }
  1994. skip = false;
  1995. }
  1996. }
  1997. // The reader is positioned on the head of the name.
  1998. private DTDElementDeclaration ReadElementDecl ()
  1999. {
  2000. DTDElementDeclaration decl = new DTDElementDeclaration (DTD);
  2001. if (!SkipWhitespace ())
  2002. throw new XmlException (this as IXmlLineInfo,
  2003. "Whitespace is required between '<!ELEMENT' and name in DTD element declaration.");
  2004. TryExpandPERef ();
  2005. SkipWhitespace ();
  2006. decl.Name = ReadName ();
  2007. if (!SkipWhitespace ())
  2008. throw new XmlException (this as IXmlLineInfo,
  2009. "Whitespace is required between name and content in DTD element declaration.");
  2010. TryExpandPERef ();
  2011. ReadContentSpec (decl);
  2012. SkipWhitespace ();
  2013. // This expanding is only allowed as a non-validating parser.
  2014. TryExpandPERef ();
  2015. SkipWhitespace ();
  2016. Expect ('>');
  2017. return decl;
  2018. }
  2019. // read 'children'(BNF) of contentspec
  2020. private void ReadContentSpec (DTDElementDeclaration decl)
  2021. {
  2022. TryExpandPERef ();
  2023. SkipWhitespace ();
  2024. switch(PeekChar ())
  2025. {
  2026. case 'E':
  2027. decl.IsEmpty = true;
  2028. Expect ("EMPTY");
  2029. break;
  2030. case 'A':
  2031. decl.IsAny = true;
  2032. Expect ("ANY");
  2033. break;
  2034. case '(':
  2035. DTDContentModel model = decl.ContentModel;
  2036. ReadChar ();
  2037. SkipWhitespace ();
  2038. TryExpandPERef ();
  2039. SkipWhitespace ();
  2040. if(PeekChar () == '#') {
  2041. // Mixed Contents. "#PCDATA" must appear first.
  2042. decl.IsMixedContent = true;
  2043. model.Occurence = DTDOccurence.ZeroOrMore;
  2044. model.OrderType = DTDContentOrderType.Or;
  2045. Expect ("#PCDATA");
  2046. SkipWhitespace ();
  2047. TryExpandPERef ();
  2048. SkipWhitespace ();
  2049. while(PeekChar () != ')') {
  2050. Expect('|');
  2051. SkipWhitespace ();
  2052. TryExpandPERef ();
  2053. SkipWhitespace ();
  2054. DTDContentModel elem = new DTDContentModel (DTD, decl.Name);
  2055. elem.ElementName = ReadName ();
  2056. model.ChildModels.Add (elem);
  2057. SkipWhitespace ();
  2058. TryExpandPERef ();
  2059. SkipWhitespace ();
  2060. }
  2061. Expect (')');
  2062. if (model.ChildModels.Count > 0)
  2063. Expect ('*');
  2064. else if (PeekChar () == '*')
  2065. Expect ('*');
  2066. } else {
  2067. // Non-Mixed Contents
  2068. model.ChildModels.Add (ReadCP (decl));
  2069. SkipWhitespace ();
  2070. do { // copied from ReadCP() ...;-)
  2071. TryExpandPERef ();
  2072. SkipWhitespace ();
  2073. if(PeekChar ()=='|') {
  2074. // CPType=Or
  2075. if (model.OrderType == DTDContentOrderType.Seq)
  2076. throw new XmlException (this as IXmlLineInfo,
  2077. "Inconsistent choice markup in sequence cp.");
  2078. model.OrderType = DTDContentOrderType.Or;
  2079. ReadChar ();
  2080. SkipWhitespace ();
  2081. model.ChildModels.Add (ReadCP (decl));
  2082. SkipWhitespace ();
  2083. }
  2084. else if(PeekChar () == ',')
  2085. {
  2086. // CPType=Seq
  2087. if (model.OrderType == DTDContentOrderType.Or)
  2088. throw new XmlException (this as IXmlLineInfo,
  2089. "Inconsistent sequence markup in choice cp.");
  2090. model.OrderType = DTDContentOrderType.Seq;
  2091. ReadChar ();
  2092. SkipWhitespace ();
  2093. model.ChildModels.Add (ReadCP (decl));
  2094. SkipWhitespace ();
  2095. }
  2096. else
  2097. break;
  2098. }
  2099. while(true);
  2100. Expect (')');
  2101. switch(PeekChar ())
  2102. {
  2103. case '?':
  2104. model.Occurence = DTDOccurence.Optional;
  2105. ReadChar ();
  2106. break;
  2107. case '*':
  2108. model.Occurence = DTDOccurence.ZeroOrMore;
  2109. ReadChar ();
  2110. break;
  2111. case '+':
  2112. model.Occurence = DTDOccurence.OneOrMore;
  2113. ReadChar ();
  2114. break;
  2115. }
  2116. SkipWhitespace ();
  2117. }
  2118. SkipWhitespace ();
  2119. break;
  2120. }
  2121. }
  2122. // Read 'cp' (BNF) of contentdecl (BNF)
  2123. private DTDContentModel ReadCP (DTDElementDeclaration elem)
  2124. {
  2125. DTDContentModel model = null;
  2126. TryExpandPERef ();
  2127. SkipWhitespace ();
  2128. if(PeekChar () == '(') {
  2129. model = new DTDContentModel (DTD, elem.Name);
  2130. ReadChar ();
  2131. SkipWhitespace ();
  2132. model.ChildModels.Add (ReadCP (elem));
  2133. SkipWhitespace ();
  2134. do {
  2135. TryExpandPERef ();
  2136. SkipWhitespace ();
  2137. if(PeekChar ()=='|') {
  2138. // CPType=Or
  2139. if (model.OrderType == DTDContentOrderType.Seq)
  2140. throw new XmlException (this as IXmlLineInfo,
  2141. "Inconsistent choice markup in sequence cp.");
  2142. model.OrderType = DTDContentOrderType.Or;
  2143. ReadChar ();
  2144. SkipWhitespace ();
  2145. model.ChildModels.Add (ReadCP (elem));
  2146. SkipWhitespace ();
  2147. }
  2148. else if(PeekChar () == ',') {
  2149. // CPType=Seq
  2150. if (model.OrderType == DTDContentOrderType.Or)
  2151. throw new XmlException (this as IXmlLineInfo,
  2152. "Inconsistent sequence markup in choice cp.");
  2153. model.OrderType = DTDContentOrderType.Seq;
  2154. ReadChar ();
  2155. SkipWhitespace ();
  2156. model.ChildModels.Add (ReadCP (elem));
  2157. SkipWhitespace ();
  2158. }
  2159. else
  2160. break;
  2161. }
  2162. while(true);
  2163. SkipWhitespace ();
  2164. Expect (')');
  2165. }
  2166. else {
  2167. TryExpandPERef ();
  2168. model = new DTDContentModel (DTD, elem.Name);
  2169. SkipWhitespace ();
  2170. model.ElementName = ReadName ();
  2171. }
  2172. switch(PeekChar ()) {
  2173. case '?':
  2174. model.Occurence = DTDOccurence.Optional;
  2175. ReadChar ();
  2176. break;
  2177. case '*':
  2178. model.Occurence = DTDOccurence.ZeroOrMore;
  2179. ReadChar ();
  2180. break;
  2181. case '+':
  2182. model.Occurence = DTDOccurence.OneOrMore;
  2183. ReadChar ();
  2184. break;
  2185. }
  2186. return model;
  2187. }
  2188. // The reader is positioned on the first name char.
  2189. private void ReadParameterEntityDecl ()
  2190. {
  2191. DTDParameterEntityDeclaration decl =
  2192. new DTDParameterEntityDeclaration();
  2193. decl.BaseURI = BaseURI;
  2194. decl.Name = ReadName ();
  2195. if (!SkipWhitespace ())
  2196. throw new XmlException (this as IXmlLineInfo,
  2197. "Whitespace is required after name in DTD parameter entity declaration.");
  2198. if (PeekChar () == 'S' || PeekChar () == 'P') {
  2199. // throw new NotImplementedException ("External parameter entity reference is not implemented yet.");
  2200. // read publicId/systemId
  2201. ReadExternalID ();
  2202. decl.PublicId = GetAttribute ("PUBLIC");
  2203. decl.SystemId = GetAttribute ("SYSTEM");
  2204. SkipWhitespace ();
  2205. decl.Resolve (resolver);
  2206. }
  2207. else {
  2208. TryExpandPERef ();
  2209. int quoteChar = ReadChar ();
  2210. int start = currentTag.Length;
  2211. ClearValueBuffer ();
  2212. bool loop = true;
  2213. while (loop) {
  2214. int c = PeekChar ();
  2215. switch (c) {
  2216. case -1:
  2217. throw new XmlException ("unexpected end of stream in entity value definition.");
  2218. case '"':
  2219. ReadChar ();
  2220. if (quoteChar == '"')
  2221. loop = false;
  2222. else
  2223. AppendValueChar ('"');
  2224. break;
  2225. case '\'':
  2226. ReadChar ();
  2227. if (quoteChar == '\'')
  2228. loop = false;
  2229. else
  2230. AppendValueChar ('\'');
  2231. break;
  2232. case '&':
  2233. ReadChar ();
  2234. if (PeekChar () == '#') {
  2235. ReadChar ();
  2236. ReadCharacterReference ();
  2237. }
  2238. else
  2239. AppendValueChar ('&');
  2240. break;
  2241. case '%':
  2242. ReadChar ();
  2243. string peName = ReadName ();
  2244. Expect (';');
  2245. valueBuffer.Append (GetPEValue (peName));
  2246. break;
  2247. default:
  2248. AppendValueChar (ReadChar ());
  2249. break;
  2250. }
  2251. }
  2252. decl.LiteralValue = CreateValueString (); // currentTag.ToString (start, currentTag.Length - start - 1);
  2253. ClearValueBuffer ();
  2254. }
  2255. SkipWhitespace ();
  2256. Expect ('>');
  2257. if (parameterEntities [decl.Name] == null) {
  2258. parameterEntities.Add (decl.Name, decl);
  2259. }
  2260. }
  2261. private string GetPEValue (string peName)
  2262. {
  2263. DTDParameterEntityDeclaration peDecl =
  2264. this.parameterEntities [peName] as DTDParameterEntityDeclaration;
  2265. if (peDecl != null)
  2266. return peDecl.Value;
  2267. // See XML 1.0 section 4.1 for both WFC and VC.
  2268. if ((DTD.SystemId == null && !DTD.InternalSubsetHasPEReference) || this.isStandalone)
  2269. throw new XmlException (this as IXmlLineInfo,
  2270. "Parameter entity " + peName + " not found.");
  2271. DTD.AddError (new XmlSchemaException (
  2272. "Parameter entity " + peName + " not found.", null));
  2273. return "";
  2274. }
  2275. private void TryExpandPERef ()
  2276. {
  2277. if (PeekChar () == '%') {
  2278. // ReadChar ();
  2279. // if (!XmlChar.IsNameChar (PeekChar ()))
  2280. // return;
  2281. // ExpandPERef ();
  2282. ImportAsPERef ();
  2283. }
  2284. }
  2285. // reader is positioned on '%'
  2286. private void ImportAsPERef ()
  2287. {
  2288. ReadChar ();
  2289. string peName = ReadName ();
  2290. Expect (';');
  2291. DTDParameterEntityDeclaration peDecl =
  2292. this.parameterEntities [peName] as DTDParameterEntityDeclaration;
  2293. if (peDecl == null) {
  2294. DTD.AddError (new XmlSchemaException ("Parameter entity " + peName + " not found.", null));
  2295. return; // do nothing
  2296. }
  2297. currentInput.InsertParameterEntityBuffer (" " + peDecl.Value + " ");
  2298. }
  2299. // The reader is positioned on the head of the name.
  2300. private DTDEntityDeclaration ReadEntityDecl ()
  2301. {
  2302. DTDEntityDeclaration decl = new DTDEntityDeclaration (DTD);
  2303. decl.IsInternalSubset = (parserInputStack.Count == 0);
  2304. TryExpandPERef ();
  2305. SkipWhitespace ();
  2306. decl.Name = ReadName ();
  2307. if (!SkipWhitespace ())
  2308. throw new XmlException (this as IXmlLineInfo,
  2309. "Whitespace is required between name and content in DTD entity declaration.");
  2310. TryExpandPERef ();
  2311. SkipWhitespace ();
  2312. if (PeekChar () == 'S' || PeekChar () == 'P') {
  2313. // external entity
  2314. ReadExternalID ();
  2315. decl.PublicId = GetAttribute ("PUBLIC");
  2316. decl.SystemId = GetAttribute ("SYSTEM");
  2317. if (SkipWhitespace ()) {
  2318. if (PeekChar () == 'N') {
  2319. // NDataDecl
  2320. Expect ("NDATA");
  2321. if (!SkipWhitespace ())
  2322. throw new XmlException (this as IXmlLineInfo,
  2323. "Whitespace is required after NDATA.");
  2324. decl.NotationName = ReadName (); // ndata_name
  2325. }
  2326. }
  2327. decl.ScanEntityValue (new StringCollection ());
  2328. }
  2329. else {
  2330. // literal entity
  2331. ReadEntityValueDecl (decl);
  2332. }
  2333. SkipWhitespace ();
  2334. // This expanding is only allowed as a non-validating parser.
  2335. TryExpandPERef ();
  2336. SkipWhitespace ();
  2337. Expect ('>');
  2338. return decl;
  2339. }
  2340. private void ReadEntityValueDecl (DTDEntityDeclaration decl)
  2341. {
  2342. SkipWhitespace ();
  2343. // quotation char will be finally removed on unescaping
  2344. int quoteChar = ReadChar ();
  2345. int start = currentTag.Length;
  2346. if (quoteChar != '\'' && quoteChar != '"')
  2347. throw new XmlException ("quotation char was expected.");
  2348. ClearValueBuffer ();
  2349. while (PeekChar () != quoteChar) {
  2350. switch (PeekChar ()) {
  2351. case '%':
  2352. ReadChar ();
  2353. string name = ReadName ();
  2354. Expect (';');
  2355. if (decl.IsInternalSubset)
  2356. throw new XmlException (this as IXmlLineInfo,
  2357. "Parameter entity is not allowed in internal subset entity '" + name + "'");
  2358. valueBuffer.Append (GetPEValue (name));
  2359. break;
  2360. case -1:
  2361. throw new XmlException ("unexpected end of stream.");
  2362. default:
  2363. AppendValueChar (ReadChar ());
  2364. break;
  2365. }
  2366. }
  2367. string value = Dereference (CreateValueString (), false);
  2368. ClearValueBuffer ();
  2369. Expect (quoteChar);
  2370. decl.LiteralEntityValue = value;
  2371. }
  2372. private DTDAttListDeclaration ReadAttListDecl ()
  2373. {
  2374. SkipWhitespace ();
  2375. TryExpandPERef ();
  2376. SkipWhitespace ();
  2377. string name = ReadName (); // target element name
  2378. DTDAttListDeclaration decl =
  2379. DTD.AttListDecls [name] as DTDAttListDeclaration;
  2380. if (decl == null)
  2381. decl = new DTDAttListDeclaration (DTD);
  2382. decl.Name = name;
  2383. if (!SkipWhitespace ())
  2384. if (PeekChar () != '>')
  2385. throw new XmlException (this as IXmlLineInfo,
  2386. "Whitespace is required between name and content in non-empty DTD attlist declaration.");
  2387. TryExpandPERef ();
  2388. SkipWhitespace ();
  2389. while (XmlChar.IsNameChar ((char) PeekChar ())) {
  2390. DTDAttributeDefinition def = ReadAttributeDefinition ();
  2391. if (decl [def.Name] == null)
  2392. decl.Add (def);
  2393. SkipWhitespace ();
  2394. TryExpandPERef ();
  2395. SkipWhitespace ();
  2396. }
  2397. SkipWhitespace ();
  2398. // This expanding is only allowed as a non-validating parser.
  2399. TryExpandPERef ();
  2400. SkipWhitespace ();
  2401. Expect ('>');
  2402. return decl;
  2403. }
  2404. private DTDAttributeDefinition ReadAttributeDefinition ()
  2405. {
  2406. DTDAttributeDefinition def = new DTDAttributeDefinition ();
  2407. // attr_name
  2408. TryExpandPERef ();
  2409. SkipWhitespace ();
  2410. def.Name = ReadName ();
  2411. if (!SkipWhitespace ())
  2412. throw new XmlException (this as IXmlLineInfo,
  2413. "Whitespace is required between name and content in DTD attribute definition.");
  2414. // attr_value
  2415. TryExpandPERef ();
  2416. SkipWhitespace ();
  2417. switch(PeekChar ()) {
  2418. case 'C': // CDATA
  2419. Expect ("CDATA");
  2420. def.Datatype = XmlSchemaDatatype.FromName ("normalizedString");
  2421. break;
  2422. case 'I': // ID, IDREF, IDREFS
  2423. Expect ("ID");
  2424. if(PeekChar () == 'R') {
  2425. Expect ("REF");
  2426. if(PeekChar () == 'S') {
  2427. // IDREFS
  2428. ReadChar ();
  2429. def.Datatype = XmlSchemaDatatype.FromName ("IDREFS");
  2430. }
  2431. else // IDREF
  2432. def.Datatype = XmlSchemaDatatype.FromName ("IDREF");
  2433. }
  2434. else // ID
  2435. def.Datatype = XmlSchemaDatatype.FromName ("ID");
  2436. break;
  2437. case 'E': // ENTITY, ENTITIES
  2438. Expect ("ENTIT");
  2439. switch(ReadChar ()) {
  2440. case 'Y': // ENTITY
  2441. def.Datatype = XmlSchemaDatatype.FromName ("ENTITY");
  2442. break;
  2443. case 'I': // ENTITIES
  2444. Expect ("ES");
  2445. def.Datatype = XmlSchemaDatatype.FromName ("ENTITIES");
  2446. break;
  2447. }
  2448. break;
  2449. case 'N': // NMTOKEN, NMTOKENS, NOTATION
  2450. ReadChar ();
  2451. switch(PeekChar ()) {
  2452. case 'M':
  2453. Expect ("MTOKEN");
  2454. if(PeekChar ()=='S') { // NMTOKENS
  2455. ReadChar ();
  2456. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKENS");
  2457. }
  2458. else // NMTOKEN
  2459. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN");
  2460. break;
  2461. case 'O':
  2462. Expect ("OTATION");
  2463. def.Datatype = XmlSchemaDatatype.FromName ("NOTATION");
  2464. if (!SkipWhitespace ())
  2465. throw new XmlException (this as IXmlLineInfo,
  2466. "Whitespace is required between name and content in DTD attribute definition.");
  2467. Expect ('(');
  2468. SkipWhitespace ();
  2469. def.EnumeratedNotations.Add (ReadName ()); // notation name
  2470. SkipWhitespace ();
  2471. while(PeekChar () == '|') {
  2472. ReadChar ();
  2473. SkipWhitespace ();
  2474. def.EnumeratedNotations.Add (ReadName ()); // notation name
  2475. SkipWhitespace ();
  2476. }
  2477. Expect (')');
  2478. break;
  2479. default:
  2480. throw new XmlException ("attribute declaration syntax error.");
  2481. }
  2482. break;
  2483. default: // Enumerated Values
  2484. def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN");
  2485. TryExpandPERef ();
  2486. SkipWhitespace ();
  2487. Expect ('(');
  2488. SkipWhitespace ();
  2489. def.EnumeratedAttributeDeclaration.Add (
  2490. def.Datatype.Normalize (ReadNmToken ())); // enum value
  2491. SkipWhitespace ();
  2492. while(PeekChar () == '|') {
  2493. ReadChar ();
  2494. SkipWhitespace ();
  2495. def.EnumeratedAttributeDeclaration.Add (
  2496. def.Datatype.Normalize (ReadNmToken ())); // enum value
  2497. SkipWhitespace ();
  2498. }
  2499. Expect (')');
  2500. break;
  2501. }
  2502. TryExpandPERef ();
  2503. if (!SkipWhitespace ())
  2504. throw new XmlException (this as IXmlLineInfo,
  2505. "Whitespace is required between type and occurence in DTD attribute definition.");
  2506. // def_value
  2507. if(PeekChar () == '#')
  2508. {
  2509. ReadChar ();
  2510. switch(PeekChar ())
  2511. {
  2512. case 'R':
  2513. Expect ("REQUIRED");
  2514. def.OccurenceType = DTDAttributeOccurenceType.Required;
  2515. break;
  2516. case 'I':
  2517. Expect ("IMPLIED");
  2518. def.OccurenceType = DTDAttributeOccurenceType.Optional;
  2519. break;
  2520. case 'F':
  2521. Expect ("FIXED");
  2522. def.OccurenceType = DTDAttributeOccurenceType.Fixed;
  2523. if (!SkipWhitespace ())
  2524. throw new XmlException (this as IXmlLineInfo,
  2525. "Whitespace is required between FIXED and actual value in DTD attribute definition.");
  2526. def.UnresolvedDefaultValue = ReadAttribute (true);
  2527. break;
  2528. }
  2529. } else {
  2530. // one of the enumerated value
  2531. TryExpandPERef ();
  2532. SkipWhitespace ();
  2533. def.UnresolvedDefaultValue = ReadAttribute (true);
  2534. }
  2535. return def;
  2536. }
  2537. private DTDNotationDeclaration ReadNotationDecl()
  2538. {
  2539. DTDNotationDeclaration decl = new DTDNotationDeclaration ();
  2540. TryExpandPERef ();
  2541. SkipWhitespace ();
  2542. decl.Name = ReadName (); // notation name
  2543. if (namespaces) { // copy from SetProperties ;-)
  2544. int indexOfColon = decl.Name.IndexOf (':');
  2545. if (indexOfColon == -1) {
  2546. decl.Prefix = String.Empty;
  2547. decl.LocalName = decl.Name;
  2548. } else {
  2549. decl.Prefix = decl.Name.Substring (0, indexOfColon);
  2550. decl.LocalName = decl.Name.Substring (indexOfColon + 1);
  2551. }
  2552. } else {
  2553. decl.Prefix = String.Empty;
  2554. decl.LocalName = decl.Name;
  2555. }
  2556. SkipWhitespace ();
  2557. if(PeekChar () == 'P') {
  2558. decl.PublicId = ReadPubidLiteral ();
  2559. bool wsSkipped = SkipWhitespace ();
  2560. if (PeekChar () == '\'' || PeekChar () == '"') {
  2561. if (!wsSkipped)
  2562. throw new XmlException (this as IXmlLineInfo,
  2563. "Whitespace is required between public id and system id.");
  2564. decl.SystemId = ReadSystemLiteral (false);
  2565. SkipWhitespace ();
  2566. }
  2567. } else if(PeekChar () == 'S') {
  2568. decl.SystemId = ReadSystemLiteral (true);
  2569. SkipWhitespace ();
  2570. }
  2571. if(decl.PublicId == null && decl.SystemId == null)
  2572. throw new XmlException ("public or system declaration required for \"NOTATION\" declaration.");
  2573. // This expanding is only allowed as a non-validating parser.
  2574. TryExpandPERef ();
  2575. SkipWhitespace ();
  2576. Expect ('>');
  2577. return decl;
  2578. }
  2579. private void ReadExternalID () {
  2580. this.ClearAttributes ();
  2581. switch (PeekChar ()) {
  2582. case 'S':
  2583. string systemId = ReadSystemLiteral (true);
  2584. AddAttribute ("SYSTEM", systemId);
  2585. break;
  2586. case 'P':
  2587. string publicId = ReadPubidLiteral ();
  2588. if (!SkipWhitespace ())
  2589. throw new XmlException (this as IXmlLineInfo,
  2590. "Whitespace is required between PUBLIC id and SYSTEM id.");
  2591. systemId = ReadSystemLiteral (false);
  2592. AddAttribute ("PUBLIC", publicId);
  2593. AddAttribute ("SYSTEM", systemId);
  2594. break;
  2595. }
  2596. }
  2597. // The reader is positioned on the first 'S' of "SYSTEM".
  2598. private string ReadSystemLiteral (bool expectSYSTEM)
  2599. {
  2600. if(expectSYSTEM) {
  2601. Expect ("SYSTEM");
  2602. if (!SkipWhitespace ())
  2603. throw new XmlException (this as IXmlLineInfo,
  2604. "Whitespace is required after 'SYSTEM'.");
  2605. }
  2606. else
  2607. SkipWhitespace ();
  2608. int quoteChar = ReadChar (); // apos or quot
  2609. int startPos = currentTag.Length;
  2610. int c = 0;
  2611. ClearValueBuffer ();
  2612. while (c != quoteChar) {
  2613. c = ReadChar ();
  2614. if (c < 0)
  2615. throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
  2616. if (c != quoteChar)
  2617. AppendValueChar (c);
  2618. }
  2619. return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
  2620. }
  2621. private string ReadPubidLiteral()
  2622. {
  2623. Expect ("PUBLIC");
  2624. if (!SkipWhitespace ())
  2625. throw new XmlException (this as IXmlLineInfo,
  2626. "Whitespace is required after 'PUBLIC'.");
  2627. int quoteChar = ReadChar ();
  2628. int startPos = currentTag.Length;
  2629. int c = 0;
  2630. ClearValueBuffer ();
  2631. while(c != quoteChar)
  2632. {
  2633. c = ReadChar ();
  2634. if(c < 0) throw new XmlException (this as IXmlLineInfo,"Unexpected end of stream in ExternalID.");
  2635. if(c != quoteChar && !XmlChar.IsPubidChar (c))
  2636. throw new XmlException (this as IXmlLineInfo,"character '" + (char)c + "' not allowed for PUBLIC ID");
  2637. if (c != quoteChar)
  2638. AppendValueChar (c);
  2639. }
  2640. return CreateValueString (); //currentTag.ToString (startPos, currentTag.Length - 1 - startPos);
  2641. }
  2642. // The reader is positioned on the first character
  2643. // of the name.
  2644. internal string ReadName ()
  2645. {
  2646. return ReadNameOrNmToken(false);
  2647. }
  2648. // The reader is positioned on the first character
  2649. // of the name.
  2650. private string ReadNmToken ()
  2651. {
  2652. return ReadNameOrNmToken(true);
  2653. }
  2654. private string ReadNameOrNmToken(bool isNameToken)
  2655. {
  2656. int ch = PeekChar ();
  2657. if(isNameToken) {
  2658. if (!XmlChar.IsNameChar ((char) ch))
  2659. throw new XmlException (this as IXmlLineInfo,String.Format ("a nmtoken did not start with a legal character {0} ({1})", ch, (char)ch));
  2660. }
  2661. else {
  2662. if (!XmlChar.IsFirstNameChar (ch))
  2663. throw new XmlException (this as IXmlLineInfo,String.Format ("a name did not start with a legal character {0} ({1})", ch, (char)ch));
  2664. }
  2665. nameLength = 0;
  2666. AppendNameChar (ReadChar ());
  2667. while (XmlChar.IsNameChar (PeekChar ())) {
  2668. AppendNameChar (ReadChar ());
  2669. }
  2670. return CreateNameString ();
  2671. }
  2672. // Read the next character and compare it against the
  2673. // specified character.
  2674. private void Expect (int expected)
  2675. {
  2676. int ch = ReadChar ();
  2677. if (ch != expected) {
  2678. throw new XmlException (this as IXmlLineInfo,
  2679. String.Format (
  2680. "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
  2681. (char)expected,
  2682. expected,
  2683. (char)ch,
  2684. ch));
  2685. }
  2686. }
  2687. private void Expect (string expected)
  2688. {
  2689. int len = expected.Length;
  2690. for(int i=0; i< len; i++)
  2691. Expect (expected[i]);
  2692. }
  2693. // Does not consume the first non-whitespace character.
  2694. private bool SkipWhitespace ()
  2695. {
  2696. //FIXME: Should not skip if whitespaceHandling == WhiteSpaceHandling.None
  2697. bool skipped = XmlChar.IsWhitespace (PeekChar ());
  2698. while (XmlChar.IsWhitespace (PeekChar ()))
  2699. ReadChar ();
  2700. return skipped;
  2701. }
  2702. private void ReadWhitespace ()
  2703. {
  2704. if (currentState == XmlNodeType.None)
  2705. currentState = XmlNodeType.XmlDeclaration;
  2706. ClearValueBuffer ();
  2707. int ch = PeekChar ();
  2708. do {
  2709. AppendValueChar (ReadChar ());
  2710. } while ((ch = PeekChar ()) != -1 && XmlChar.IsWhitespace (ch));
  2711. if (currentState == XmlNodeType.Element && ch != -1 && ch != '<')
  2712. ReadText (false);
  2713. else
  2714. SetProperties (XmlNodeType.Whitespace,
  2715. String.Empty,
  2716. false,
  2717. true,
  2718. valueBuffer);
  2719. return; // (PeekChar () != -1);
  2720. }
  2721. private string Dereference (string unresolved, bool expandPredefined)
  2722. {
  2723. StringBuilder resolved = new StringBuilder();
  2724. int pos = 0;
  2725. int next = unresolved.IndexOf ('&');
  2726. if(next < 0)
  2727. return unresolved;
  2728. while(next >= 0) {
  2729. if(pos < next)
  2730. resolved.Append (unresolved.Substring (pos, next - pos));// - 1);
  2731. int endPos = unresolved.IndexOf (';', next+1);
  2732. string entityName =
  2733. unresolved.Substring (next + 1, endPos - next - 1);
  2734. if(entityName [0] == '#') {
  2735. char c;
  2736. // character entity
  2737. if(entityName [1] == 'x') {
  2738. // hexadecimal
  2739. c = (char) int.Parse ("0" + entityName.Substring (2),
  2740. System.Globalization.NumberStyles.HexNumber);
  2741. } else {
  2742. // decimal
  2743. c = (char) int.Parse (entityName.Substring (1));
  2744. }
  2745. resolved.Append (c);
  2746. } else {
  2747. char predefined = XmlChar.GetPredefinedEntity (entityName);
  2748. if (expandPredefined && predefined != 0)
  2749. resolved.Append (predefined);
  2750. else
  2751. // With respect to "Value", MS document is helpless
  2752. // and the implemention returns inconsistent value
  2753. // (e.g. XML: "&ent; &amp;ent;" ---> Value: "&ent; &ent;".)
  2754. resolved.Append ("&" + entityName + ";");
  2755. }
  2756. pos = endPos + 1;
  2757. if(pos > unresolved.Length)
  2758. break;
  2759. next = unresolved.IndexOf('&', pos);
  2760. }
  2761. resolved.Append (unresolved.Substring(pos));
  2762. return resolved.ToString();
  2763. }
  2764. #endregion
  2765. }
  2766. }