XmlBinaryDictionaryReader.cs 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. //
  2. // XmlBinaryDictionaryReader.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // Copyright (C) 2005, 2007 Novell, Inc. http://www.novell.com
  8. //
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Collections;
  31. using System.Collections.Specialized;
  32. using System.Collections.Generic;
  33. using System.Globalization;
  34. using System.IO;
  35. using System.Text;
  36. using QName = System.Xml.XmlQualifiedName;
  37. using BF = System.Xml.XmlBinaryFormat;
  38. namespace System.Xml
  39. {
  40. // FIXME:
  41. // - support XmlDictionaryReaderQuotas.
  42. internal class XmlBinaryDictionaryReader : XmlDictionaryReader, IXmlNamespaceResolver
  43. {
  44. internal interface ISource
  45. {
  46. int Position { get; }
  47. int ReadByte ();
  48. int Read (byte [] data, int offset, int count);
  49. BinaryReader Reader { get; }
  50. }
  51. internal class StreamSource : ISource
  52. {
  53. BinaryReader reader;
  54. public StreamSource (Stream stream)
  55. {
  56. this.reader = new BinaryReader (stream);
  57. }
  58. public int Position {
  59. get { return (int) reader.BaseStream.Position; }
  60. }
  61. public BinaryReader Reader {
  62. get { return reader; }
  63. }
  64. public int ReadByte ()
  65. {
  66. if (reader.PeekChar () < 0)
  67. return -1;
  68. return reader.ReadByte ();
  69. }
  70. public int Read (byte [] data, int offset, int count)
  71. {
  72. return reader.Read (data, offset, count);
  73. }
  74. }
  75. class NodeInfo
  76. {
  77. public NodeInfo ()
  78. {
  79. }
  80. public NodeInfo (bool isAttr)
  81. {
  82. IsAttributeValue = isAttr;
  83. }
  84. public bool IsAttributeValue;
  85. public int Position;
  86. public string Prefix;
  87. public XmlDictionaryString DictLocalName;
  88. public XmlDictionaryString DictNS;
  89. public XmlDictionaryString DictValue; // BF.TextIndex
  90. public XmlNodeType NodeType;
  91. public object TypedValue;
  92. public byte ValueType;
  93. // -1 for nothing,
  94. // -2 for that of element (only for attribute),
  95. // 0 or more to fill later
  96. public int NSSlot;
  97. string name = String.Empty;
  98. string local_name = String.Empty;
  99. string ns = String.Empty;
  100. string value;
  101. public string LocalName {
  102. get { return DictLocalName != null ? DictLocalName.Value : local_name; }
  103. set {
  104. DictLocalName = null;
  105. local_name = value;
  106. }
  107. }
  108. public string NS {
  109. get { return DictNS != null ? DictNS.Value : ns; }
  110. set {
  111. DictNS = null;
  112. ns = value;
  113. }
  114. }
  115. public string Name {
  116. get {
  117. if (name.Length == 0)
  118. name = Prefix.Length > 0 ?
  119. String.Concat (Prefix, ":", LocalName) :
  120. LocalName;
  121. return name;
  122. }
  123. }
  124. public virtual string Value {
  125. get {
  126. switch (ValueType) {
  127. case 0:
  128. case BF.Comment:
  129. case BF.Chars8:
  130. case BF.Chars16:
  131. case BF.Chars32:
  132. case BF.EmptyText:
  133. case BF.Utf16_8:
  134. case BF.Utf16_16:
  135. case BF.Utf16_32:
  136. return value;
  137. case BF.TextIndex:
  138. return DictValue.Value;
  139. case BF.Zero:
  140. case BF.One:
  141. return XmlConvert.ToString ((int) TypedValue);
  142. case BF.Int8:
  143. return XmlConvert.ToString ((byte) TypedValue);
  144. case BF.Int16:
  145. return XmlConvert.ToString ((short) TypedValue);
  146. case BF.Int32:
  147. return XmlConvert.ToString ((int) TypedValue);
  148. case BF.Int64:
  149. return XmlConvert.ToString ((long) TypedValue);
  150. case BF.Single:
  151. return XmlConvert.ToString ((float) TypedValue);
  152. case BF.Double:
  153. return XmlConvert.ToString ((double) TypedValue);
  154. case BF.DateTime:
  155. return XmlConvert.ToString ((DateTime) TypedValue, XmlDateTimeSerializationMode.RoundtripKind);
  156. case BF.TimeSpan:
  157. return XmlConvert.ToString ((TimeSpan) TypedValue);
  158. case BF.Guid:
  159. return XmlConvert.ToString ((Guid) TypedValue);
  160. case BF.UniqueId:
  161. return TypedValue.ToString ();
  162. case BF.Bytes8:
  163. case BF.Bytes16:
  164. case BF.Bytes32:
  165. return Convert.ToBase64String ((byte []) TypedValue);
  166. default:
  167. throw new NotImplementedException ("ValueType " + ValueType + " on node " + NodeType);
  168. }
  169. }
  170. set { this.value = value; }
  171. }
  172. public virtual void Reset ()
  173. {
  174. Position = 0;
  175. DictLocalName = DictNS = null;
  176. LocalName = NS = Prefix = Value = String.Empty;
  177. NodeType = XmlNodeType.None;
  178. TypedValue = null;
  179. ValueType = 0;
  180. NSSlot = -1;
  181. }
  182. }
  183. class AttrNodeInfo : NodeInfo
  184. {
  185. public AttrNodeInfo (XmlBinaryDictionaryReader owner)
  186. {
  187. this.owner = owner;
  188. }
  189. XmlBinaryDictionaryReader owner;
  190. public int ValueIndex;
  191. public override void Reset ()
  192. {
  193. base.Reset ();
  194. ValueIndex = -1;
  195. NodeType = XmlNodeType.Attribute;
  196. }
  197. public override string Value {
  198. get { return owner.attr_values [ValueIndex].Value; }
  199. }
  200. }
  201. ISource source;
  202. IXmlDictionary dictionary;
  203. XmlDictionaryReaderQuotas quota;
  204. XmlBinaryReaderSession session;
  205. OnXmlDictionaryReaderClose on_close;
  206. XmlParserContext context;
  207. ReadState state = ReadState.Initial;
  208. NodeInfo node;
  209. NodeInfo current;
  210. List<AttrNodeInfo> attributes = new List<AttrNodeInfo> ();
  211. List<NodeInfo> attr_values = new List<NodeInfo> ();
  212. List<NodeInfo> node_stack = new List<NodeInfo> ();
  213. List<QName> ns_store = new List<QName> ();
  214. Dictionary<int,XmlDictionaryString> ns_dict_store =
  215. new Dictionary<int,XmlDictionaryString> ();
  216. int attr_count;
  217. int attr_value_count;
  218. int current_attr = -1;
  219. int depth = 0;
  220. // used during Read()
  221. int ns_slot;
  222. // next byte in the source (one byte token ahead always
  223. // happens because there is no "end of start element" mark).
  224. int next = -1;
  225. bool is_next_end_element;
  226. // temporary buffer for utf8enc.GetString()
  227. byte [] tmp_buffer = new byte [128];
  228. UTF8Encoding utf8enc = new UTF8Encoding ();
  229. // See comment at Read()
  230. int array_item_remaining;
  231. byte array_item_type;
  232. XmlNodeType array_state;
  233. public XmlBinaryDictionaryReader (byte [] buffer, int offset,
  234. int count, IXmlDictionary dictionary,
  235. XmlDictionaryReaderQuotas quota,
  236. XmlBinaryReaderSession session,
  237. OnXmlDictionaryReaderClose onClose)
  238. {
  239. source = /*new ArraySource (buffer, offset, count);*/
  240. new StreamSource (new MemoryStream (buffer, offset, count));
  241. Initialize (dictionary, quota, session, onClose);
  242. }
  243. public XmlBinaryDictionaryReader (Stream stream,
  244. IXmlDictionary dictionary,
  245. XmlDictionaryReaderQuotas quota,
  246. XmlBinaryReaderSession session,
  247. OnXmlDictionaryReaderClose onClose)
  248. {
  249. source = new StreamSource (stream);
  250. Initialize (dictionary, quota, session, onClose);
  251. }
  252. private void Initialize (IXmlDictionary dictionary,
  253. XmlDictionaryReaderQuotas quotas,
  254. XmlBinaryReaderSession session,
  255. OnXmlDictionaryReaderClose onClose)
  256. {
  257. if (quotas == null)
  258. throw new ArgumentNullException ("quotas");
  259. if (dictionary == null)
  260. dictionary = new XmlDictionary ();
  261. this.dictionary = dictionary;
  262. this.quota = quotas;
  263. if (session == null)
  264. session = new XmlBinaryReaderSession ();
  265. this.session = session;
  266. on_close = onClose;
  267. NameTable nt = new NameTable ();
  268. this.context = new XmlParserContext (nt,
  269. new XmlNamespaceManager (nt),
  270. null, XmlSpace.None);
  271. current = node = new NodeInfo ();
  272. current.Reset ();
  273. }
  274. public override int AttributeCount {
  275. get { return attr_count; }
  276. }
  277. public override string BaseURI {
  278. get { return context.BaseURI; }
  279. }
  280. public override int Depth {
  281. get { return current == node ? depth : NodeType == XmlNodeType.Attribute ? depth + 1 : depth + 2; }
  282. }
  283. public override bool EOF {
  284. get { return state == ReadState.EndOfFile || state == ReadState.Error; }
  285. }
  286. public override bool HasValue {
  287. get { return Value.Length > 0; }
  288. }
  289. public override bool IsEmptyElement {
  290. get { return false; }
  291. }
  292. public override XmlNodeType NodeType {
  293. get { return current.NodeType; }
  294. }
  295. public override string Prefix {
  296. get { return current_attr >= 0 ? attributes [current_attr].Prefix : current.Prefix; }
  297. }
  298. // looks like it may return attribute's name even if it is on its value node.
  299. public override string LocalName {
  300. get { return current_attr >= 0 ? attributes [current_attr].LocalName : current.LocalName; }
  301. }
  302. public override string Name {
  303. get { return current_attr >= 0 ? attributes [current_attr].Name : current.Name; }
  304. }
  305. public override string NamespaceURI {
  306. get { return current_attr >= 0 ? attributes [current_attr].NS : current.NS; }
  307. }
  308. public override XmlNameTable NameTable {
  309. get { return context.NameTable; }
  310. }
  311. public override XmlDictionaryReaderQuotas Quotas {
  312. get { return quota; }
  313. }
  314. public override ReadState ReadState {
  315. get { return state; }
  316. }
  317. public override string Value {
  318. get { return current.Value; }
  319. }
  320. public override void Close ()
  321. {
  322. if (on_close != null)
  323. on_close (this);
  324. }
  325. public override string GetAttribute (int i)
  326. {
  327. if (i >= attr_count)
  328. throw new ArgumentOutOfRangeException (String.Format ("Specified attribute index is {0} and should be less than {1}", i, attr_count));
  329. return attributes [i].Value;
  330. }
  331. public override string GetAttribute (string name)
  332. {
  333. for (int i = 0; i < attributes.Count; i++)
  334. if (attributes [i].Name == name)
  335. return attributes [i].Value;
  336. return null;
  337. }
  338. public override string GetAttribute (string localName, string ns)
  339. {
  340. for (int i = 0; i < attributes.Count; i++)
  341. if (attributes [i].LocalName == localName &&
  342. attributes [i].NS == ns)
  343. return attributes [i].Value;
  344. return null;
  345. }
  346. public IDictionary<string,string> GetNamespacesInScope (
  347. XmlNamespaceScope scope)
  348. {
  349. return context.NamespaceManager.GetNamespacesInScope (scope);
  350. }
  351. public string LookupPrefix (string ns)
  352. {
  353. return context.NamespaceManager.LookupPrefix (NameTable.Get (ns));
  354. }
  355. public override string LookupNamespace (string prefix)
  356. {
  357. return context.NamespaceManager.LookupNamespace (
  358. NameTable.Get (prefix));
  359. }
  360. public override bool IsArray (out Type type)
  361. {
  362. if (array_state == XmlNodeType.Element) {
  363. type = GetArrayType (array_item_type);
  364. return true;
  365. } else {
  366. type = null;
  367. return false;
  368. }
  369. }
  370. public override bool MoveToElement ()
  371. {
  372. bool ret = current_attr >= 0;
  373. current_attr = -1;
  374. current = node;
  375. return ret;
  376. }
  377. public override bool MoveToFirstAttribute ()
  378. {
  379. if (attr_count == 0)
  380. return false;
  381. current_attr = 0;
  382. current = attributes [current_attr];
  383. return true;
  384. }
  385. public override bool MoveToNextAttribute ()
  386. {
  387. if (++current_attr < attr_count) {
  388. current = attributes [current_attr];
  389. return true;
  390. } else {
  391. --current_attr;
  392. return false;
  393. }
  394. }
  395. public override void MoveToAttribute (int i)
  396. {
  397. if (i >= attr_count)
  398. throw new ArgumentOutOfRangeException (String.Format ("Specified attribute index is {0} and should be less than {1}", i, attr_count));
  399. current_attr = i;
  400. current = attributes [i];
  401. }
  402. public override bool MoveToAttribute (string name)
  403. {
  404. for (int i = 0; i < attributes.Count; i++) {
  405. if (attributes [i].Name == name) {
  406. MoveToAttribute (i);
  407. return true;
  408. }
  409. }
  410. return false;
  411. }
  412. public override bool MoveToAttribute (string localName, string ns)
  413. {
  414. for (int i = 0; i < attributes.Count; i++) {
  415. if (attributes [i].LocalName == localName &&
  416. attributes [i].NS == ns) {
  417. MoveToAttribute (i);
  418. return true;
  419. }
  420. }
  421. return false;
  422. }
  423. public override bool ReadAttributeValue ()
  424. {
  425. if (current_attr < 0)
  426. return false;
  427. int start = attributes [current_attr].ValueIndex;
  428. int end = current_attr + 1 == attr_count ? attr_value_count : attributes [current_attr + 1].ValueIndex;
  429. if (start == end)
  430. return false;
  431. if (!current.IsAttributeValue) {
  432. current = attr_values [start];
  433. return true;
  434. }
  435. // Actually there is no case for attribute whose value is split to more than two nodes. We could simplify the node structure.
  436. return false;
  437. }
  438. // When reading an array (0x03), it requires extraneously
  439. // complex procedure for XmlReader. First, it reads element,
  440. // type of operation and length of the items. And this XmlReader
  441. // has to return Element state. On the next Read(), it proceeds
  442. // to the value node of the first item of the array, so it
  443. // reads the value stream. On the next Read(), it proceeds to
  444. // EndElement, so it should not read anything from stream while
  445. // it has to move to the node state to EndElement.
  446. public override bool Read ()
  447. {
  448. switch (state) {
  449. case ReadState.Closed:
  450. case ReadState.EndOfFile:
  451. case ReadState.Error:
  452. return false;
  453. }
  454. // clear.
  455. state = ReadState.Interactive;
  456. MoveToElement ();
  457. attr_count = 0;
  458. attr_value_count = 0;
  459. ns_slot = 0;
  460. if (node.NodeType == XmlNodeType.Element) {
  461. // push element scope
  462. if (++depth == quota.MaxDepth)
  463. throw new XmlException (String.Format ("Binary XML stream quota exceeded. Depth must be less than {0}", quota.MaxDepth));
  464. if (node_stack.Count <= depth) {
  465. node_stack.Add (node);
  466. node = new NodeInfo ();
  467. }
  468. else
  469. node = node_stack [depth];
  470. current = node;
  471. }
  472. if (is_next_end_element) {
  473. is_next_end_element = false;
  474. node.Reset ();
  475. ProcessEndElement ();
  476. return true;
  477. }
  478. // process array node after preparing node stack.
  479. switch (array_state) {
  480. case XmlNodeType.Element:
  481. ReadArrayItem ();
  482. return true;
  483. case XmlNodeType.Text:
  484. ShiftToArrayItemEndElement ();
  485. return true;
  486. case XmlNodeType.EndElement:
  487. if (--array_item_remaining == 0) {
  488. array_state = XmlNodeType.None;
  489. break;
  490. } else {
  491. ShiftToArrayItemElement ();
  492. return true;
  493. }
  494. }
  495. // array consumer does not expect Reset whlie it's on reading. So call it later than array check.
  496. node.Reset ();
  497. int ident = next >= 0 ? next : source.ReadByte ();
  498. next = -1;
  499. // check end of source.
  500. if (ident < 0) {
  501. state = ReadState.EndOfFile;
  502. current.Reset ();
  503. return false;
  504. }
  505. is_next_end_element = ident > 0x80 && (ident & 1) == 1;
  506. ident -= is_next_end_element ? 1 : 0;
  507. switch (ident) {
  508. case BF.EndElement:
  509. ProcessEndElement ();
  510. break;
  511. case BF.Comment:
  512. node.Value = ReadUTF8 ();
  513. node.ValueType = BF.Comment;
  514. node.NodeType = XmlNodeType.Comment;
  515. break;
  516. case BF.ElemString:
  517. case BF.ElemStringPrefix:
  518. case BF.ElemIndex:
  519. case BF.ElemIndexPrefix:
  520. ReadElementBinary ((byte) ident);
  521. break;
  522. case BF.Array:
  523. ident = ReadByteOrError ();
  524. ReadElementBinary ((byte) ident);
  525. ident = ReadByteOrError ();
  526. if (ident != 0x01)
  527. throw new XmlException (String.Format ("EndElement is expected after element in an array. The actual byte was {0:X} in hexadecimal", ident));
  528. ident = ReadByteOrError () - 1; // -1 becauseit contains EndElement
  529. VerifyValidArrayItemType (ident);
  530. if (ident < 0)
  531. throw new XmlException ("The stream has ended where the array item type is expected");
  532. array_item_type = (byte) ident;
  533. array_item_remaining = ReadVariantSize ();
  534. if (array_item_remaining > quota.MaxArrayLength)
  535. throw new Exception (String.Format ("Binary xml stream exceeded max array length quota. Items are {0} and should be less than quota.MaxArrayLength", quota.MaxArrayLength));
  536. array_state = XmlNodeType.Element;
  537. break;
  538. default:
  539. if (BF.PrefixNElemIndexStart <= ident && ident <= BF.PrefixNElemIndexEnd ||
  540. BF.PrefixNElemStringStart <= ident && ident <= BF.PrefixNElemStringEnd)
  541. goto case BF.ElemString;
  542. ReadTextOrValue ((byte) ident, node, false);
  543. break;
  544. }
  545. return true;
  546. }
  547. void ReadArrayItem ()
  548. {
  549. ReadTextOrValue (array_item_type, node, false);
  550. array_state = XmlNodeType.Text;
  551. }
  552. void ShiftToArrayItemEndElement ()
  553. {
  554. ProcessEndElement ();
  555. array_state = XmlNodeType.EndElement;
  556. }
  557. void ShiftToArrayItemElement ()
  558. {
  559. node.NodeType = XmlNodeType.Element;
  560. context.NamespaceManager.PushScope ();
  561. array_state = XmlNodeType.Element;
  562. }
  563. void VerifyValidArrayItemType (int ident)
  564. {
  565. if (GetArrayType (ident) == null)
  566. throw new XmlException (String.Format ("Unexpected array item type {0:X} in hexadecimal", ident));
  567. }
  568. Type GetArrayType (int ident)
  569. {
  570. switch (ident) {
  571. case BF.Bool:
  572. return typeof (bool);
  573. case BF.Int16:
  574. return typeof (short);
  575. case BF.Int32:
  576. return typeof (int);
  577. case BF.Int64:
  578. return typeof (long);
  579. case BF.Single:
  580. return typeof (float);
  581. case BF.Double:
  582. return typeof (double);
  583. case BF.Decimal:
  584. return typeof (decimal);
  585. case BF.DateTime:
  586. return typeof (DateTime);
  587. case BF.TimeSpan:
  588. return typeof (TimeSpan);
  589. case BF.Guid:
  590. return typeof (Guid);
  591. }
  592. return null;
  593. }
  594. private void ProcessEndElement ()
  595. {
  596. if (depth == 0)
  597. throw new XmlException ("Unexpected end of element while there is no element started.");
  598. current = node = node_stack [--depth];
  599. node.NodeType = XmlNodeType.EndElement;
  600. context.NamespaceManager.PopScope ();
  601. }
  602. private void ReadElementBinary (int ident)
  603. {
  604. // element
  605. node.NodeType = XmlNodeType.Element;
  606. node.Prefix = String.Empty;
  607. context.NamespaceManager.PushScope ();
  608. switch (ident) {
  609. case BF.ElemString:
  610. node.LocalName = ReadUTF8 ();
  611. break;
  612. case BF.ElemStringPrefix:
  613. node.Prefix = ReadUTF8 ();
  614. node.NSSlot = ns_slot++;
  615. goto case BF.ElemString;
  616. case BF.ElemIndex:
  617. node.DictLocalName = ReadDictName ();
  618. break;
  619. case BF.ElemIndexPrefix:
  620. node.Prefix = ReadUTF8 ();
  621. node.NSSlot = ns_slot++;
  622. goto case BF.ElemIndex;
  623. default:
  624. if (BF.PrefixNElemIndexStart <= ident && ident <= BF.PrefixNElemIndexEnd) {
  625. node.Prefix = ((char) (ident - BF.PrefixNElemIndexStart + 'a')).ToString ();
  626. node.DictLocalName = ReadDictName ();
  627. } else if (BF.PrefixNElemStringStart <= ident && ident <= BF.PrefixNElemStringEnd) {
  628. node.Prefix = ((char) (ident - BF.PrefixNElemStringStart + 'a')).ToString ();
  629. node.LocalName = ReadUTF8 ();
  630. }
  631. else
  632. throw new XmlException (String.Format ("Invalid element node type {0:X02} in hexadecimal", ident));
  633. break;
  634. }
  635. bool loop = true;
  636. do {
  637. ident = ReadByteOrError ();
  638. switch (ident) {
  639. case BF.AttrString:
  640. case BF.AttrStringPrefix:
  641. case BF.AttrIndex:
  642. case BF.AttrIndexPrefix:
  643. ReadAttribute ((byte) ident);
  644. break;
  645. case BF.DefaultNSString:
  646. case BF.PrefixNSString:
  647. case BF.DefaultNSIndex:
  648. case BF.PrefixNSIndex:
  649. ReadNamespace ((byte) ident);
  650. break;
  651. default:
  652. if (BF.PrefixNAttrStringStart <= ident && ident <= BF.PrefixNAttrStringEnd ||
  653. BF.PrefixNAttrIndexStart <= ident && ident <= BF.PrefixNAttrIndexEnd)
  654. ReadAttribute ((byte) ident);
  655. else {
  656. next = ident;
  657. loop = false;
  658. }
  659. break;
  660. }
  661. } while (loop);
  662. node.NS = context.NamespaceManager.LookupNamespace (node.Prefix) ?? String.Empty;
  663. foreach (AttrNodeInfo a in attributes)
  664. if (a.Prefix.Length > 0)
  665. a.NS = context.NamespaceManager.LookupNamespace (a.Prefix);
  666. ns_store.Clear ();
  667. ns_dict_store.Clear ();
  668. }
  669. private void ReadAttribute (byte ident)
  670. {
  671. if (attributes.Count == attr_count)
  672. attributes.Add (new AttrNodeInfo (this));
  673. AttrNodeInfo a = attributes [attr_count++];
  674. a.Reset ();
  675. a.Position = source.Position;
  676. switch (ident) {
  677. case BF.AttrString:
  678. a.LocalName = ReadUTF8 ();
  679. break;
  680. case BF.AttrStringPrefix:
  681. a.Prefix = ReadUTF8 ();
  682. a.NSSlot = ns_slot++;
  683. goto case BF.AttrString;
  684. case BF.AttrIndex:
  685. a.DictLocalName = ReadDictName ();
  686. break;
  687. case BF.AttrIndexPrefix:
  688. a.Prefix = ReadUTF8 ();
  689. a.NSSlot = ns_slot++;
  690. goto case BF.AttrIndex;
  691. default:
  692. if (BF.PrefixNAttrStringStart <= ident && ident <= BF.PrefixNAttrStringEnd) {
  693. a.Prefix = ((char) ('a' + ident - BF.PrefixNAttrStringStart)).ToString ();
  694. a.LocalName = ReadUTF8 ();
  695. break;
  696. }
  697. else if (BF.PrefixNAttrIndexStart <= ident && ident <= BF.PrefixNAttrIndexEnd) {
  698. a.Prefix = ((char) ('a' + ident - BF.PrefixNAttrIndexStart)).ToString ();
  699. a.DictLocalName = ReadDictName ();
  700. break;
  701. }
  702. else throw new XmlException (String.Format ("Unexpected attribute node type: 0x{0:X02}", ident));
  703. }
  704. ReadAttributeValueBinary (a);
  705. }
  706. private void ReadNamespace (byte ident)
  707. {
  708. // create attrubute slot.
  709. if (attributes.Count == attr_count)
  710. attributes.Add (new AttrNodeInfo (this));
  711. AttrNodeInfo a = attributes [attr_count++];
  712. a.Reset ();
  713. a.Position = source.Position;
  714. string prefix = null, ns = null;
  715. XmlDictionaryString dns = null;
  716. switch (ident) {
  717. case BF.DefaultNSString:
  718. prefix = String.Empty;
  719. ns = ReadUTF8 ();
  720. break;
  721. case BF.PrefixNSString:
  722. prefix = ReadUTF8 ();
  723. ns = ReadUTF8 ();
  724. break;
  725. case BF.DefaultNSIndex:
  726. prefix = String.Empty;
  727. dns = ReadDictName ();
  728. ns_dict_store.Add (ns_store.Count, dns);
  729. ns = dns.Value;
  730. break;
  731. case BF.PrefixNSIndex:
  732. prefix = ReadUTF8 ();
  733. dns = ReadDictName ();
  734. ns_dict_store.Add (ns_store.Count, dns);
  735. ns = dns.Value;
  736. break;
  737. }
  738. // fill attribute slot.
  739. a.Prefix = prefix.Length > 0 ? "xmlns" : String.Empty;
  740. a.LocalName = prefix.Length > 0 ? prefix : "xmlns";
  741. a.NS = "http://www.w3.org/2000/xmlns/";
  742. a.ValueIndex = attr_value_count;
  743. if (attr_value_count == attr_values.Count)
  744. attr_values.Add (new NodeInfo (true));
  745. NodeInfo v = attr_values [attr_value_count++];
  746. v.Reset ();
  747. v.Value = ns;
  748. v.ValueType = BF.Chars8;
  749. v.NodeType = XmlNodeType.Text;
  750. ns_store.Add (new QName (prefix, ns));
  751. context.NamespaceManager.AddNamespace (prefix, ns);
  752. }
  753. private void ReadAttributeValueBinary (AttrNodeInfo a)
  754. {
  755. a.ValueIndex = attr_value_count;
  756. if (attr_value_count == attr_values.Count)
  757. attr_values.Add (new NodeInfo (true));
  758. NodeInfo v = attr_values [attr_value_count++];
  759. v.Reset ();
  760. int ident = ReadByteOrError ();
  761. bool end = ident > 0x80 && (ident & 1) == 1;
  762. ident -= end ? 1 : 0;
  763. ReadTextOrValue ((byte) ident, v, true);
  764. }
  765. private bool ReadTextOrValue (byte ident, NodeInfo node, bool canSkip)
  766. {
  767. node.Value = null;
  768. node.ValueType = ident;
  769. node.NodeType = XmlNodeType.Text;
  770. switch (ident) {
  771. case BF.Zero:
  772. node.TypedValue = 0;
  773. break;
  774. case BF.One:
  775. node.TypedValue = 1;
  776. break;
  777. case BF.BoolFalse:
  778. node.TypedValue = false;
  779. break;
  780. case BF.BoolTrue:
  781. node.TypedValue = true;
  782. break;
  783. case BF.Int8:
  784. node.TypedValue = ReadByteOrError ();
  785. break;
  786. case BF.Int16:
  787. node.TypedValue = source.Reader.ReadInt16 ();
  788. break;
  789. case BF.Int32:
  790. node.TypedValue = source.Reader.ReadInt32 ();
  791. break;
  792. case BF.Int64:
  793. node.TypedValue = source.Reader.ReadInt64 ();
  794. break;
  795. case BF.Single:
  796. node.TypedValue = source.Reader.ReadSingle ();
  797. break;
  798. case BF.Double:
  799. node.TypedValue = source.Reader.ReadDouble ();
  800. break;
  801. case BF.Decimal:
  802. int [] bits = new int [4];
  803. bits [3] = source.Reader.ReadInt32 ();
  804. bits [2] = source.Reader.ReadInt32 ();
  805. bits [0] = source.Reader.ReadInt32 ();
  806. bits [1] = source.Reader.ReadInt32 ();
  807. node.TypedValue = new Decimal (bits);
  808. break;
  809. case BF.DateTime:
  810. node.TypedValue = new DateTime (source.Reader.ReadInt64 ());
  811. break;
  812. //case BF.UniqueId: // identical to .Text
  813. case BF.Bytes8:
  814. case BF.Bytes16:
  815. case BF.Bytes32:
  816. int size =
  817. (ident == BF.Bytes8) ? source.Reader.ReadByte () :
  818. (ident == BF.Bytes16) ? source.Reader.ReadUInt16 () :
  819. source.Reader.ReadInt32 ();
  820. byte [] base64 = Alloc (size);
  821. source.Reader.Read (base64, 0, base64.Length);
  822. node.TypedValue = base64;
  823. break;
  824. case BF.TimeSpan:
  825. node.TypedValue = new TimeSpan (source.Reader.ReadInt64 ());
  826. break;
  827. case BF.UniqueId:
  828. byte [] guid = new byte [16];
  829. source.Reader.Read (guid, 0, guid.Length);
  830. node.TypedValue = new UniqueId (new Guid (guid));
  831. break;
  832. case BF.Guid:
  833. guid = new byte [16];
  834. source.Reader.Read (guid, 0, guid.Length);
  835. node.TypedValue = new Guid (guid);
  836. break;
  837. case BF.Chars8:
  838. case BF.Chars16:
  839. case BF.Chars32:
  840. case BF.Utf16_8:
  841. case BF.Utf16_16:
  842. case BF.Utf16_32:
  843. Encoding enc = ident <= BF.Chars32 ? Encoding.UTF8 : Encoding.Unicode;
  844. size =
  845. (ident == BF.Chars8 || ident == BF.Utf16_8) ? source.Reader.ReadByte () :
  846. (ident == BF.Chars16 || ident == BF.Utf16_16) ? source.Reader.ReadUInt16 () :
  847. source.Reader.ReadInt32 ();
  848. byte [] bytes = Alloc (size);
  849. source.Reader.Read (bytes, 0, size);
  850. node.Value = enc.GetString (bytes, 0, size);
  851. node.NodeType = XmlNodeType.Text;
  852. break;
  853. case BF.EmptyText:
  854. node.Value = String.Empty;
  855. node.NodeType = XmlNodeType.Text;
  856. break;
  857. case BF.TextIndex:
  858. node.DictValue = ReadDictName ();
  859. node.NodeType = XmlNodeType.Text;
  860. break;
  861. default:
  862. if (!canSkip)
  863. throw new ArgumentException (String.Format ("Unexpected binary XML data at position {1}: {0:X}", ident + (is_next_end_element ? 1 : 0), source.Position));
  864. next = ident;
  865. return false;
  866. }
  867. return true;
  868. }
  869. byte [] Alloc (int size)
  870. {
  871. if (size > quota.MaxStringContentLength || size < 0)
  872. throw new XmlException (String.Format ("Text content buffer exceeds the quota limitation at {2}. {0} bytes and should be less than {1} bytes", size, quota.MaxStringContentLength, source.Position));
  873. return new byte [size];
  874. }
  875. private int ReadVariantSize ()
  876. {
  877. int size = 0;
  878. // If sizeSpec < 0, then it is variant size specifier.
  879. // Otherwise it is fixed size s = sizeSpec + 1 byte(s).
  880. int d = 0;
  881. do {
  882. byte got = ReadByteOrError ();
  883. size += (got & 0x7F) << d;
  884. d += 7;
  885. if (got < 0x80)
  886. break;
  887. } while (true);
  888. return size;
  889. }
  890. private string ReadUTF8 ()
  891. {
  892. int size = ReadVariantSize ();
  893. if (size == 0)
  894. return String.Empty;
  895. if (tmp_buffer.Length < size) {
  896. int extlen = tmp_buffer.Length * 2;
  897. tmp_buffer = Alloc (size < extlen ? extlen : size);
  898. }
  899. size = source.Read (tmp_buffer, 0, size);
  900. return utf8enc.GetString (tmp_buffer, 0, size);
  901. }
  902. private XmlDictionaryString ReadDictName ()
  903. {
  904. int key = ReadVariantSize ();
  905. XmlDictionaryString s;
  906. if ((key & 1) == 1) {
  907. if (session.TryLookup (key >> 1, out s))
  908. return s;
  909. } else {
  910. if (dictionary.TryLookup (key >> 1, out s))
  911. return s;
  912. }
  913. throw new XmlException (String.Format ("Input XML binary stream is invalid. No matching XML dictionary string entry at {0}. Binary stream position at {1}", key, source.Position));
  914. }
  915. private byte ReadByteOrError ()
  916. {
  917. if (next >= 0) {
  918. byte b = (byte) next;
  919. next = -1;
  920. return b;
  921. }
  922. int ret = source.ReadByte ();
  923. if (ret < 0)
  924. throw new XmlException (String.Format ("Unexpected end of binary stream. Position is at {0}", source.Position));
  925. return (byte) ret;
  926. }
  927. public override void ResolveEntity ()
  928. {
  929. throw new NotSupportedException ("this XmlReader does not support ResolveEntity.");
  930. }
  931. public override bool TryGetBase64ContentLength (out int length)
  932. {
  933. length = 0;
  934. switch (current.ValueType) {
  935. case BF.Bytes8:
  936. case BF.Bytes16:
  937. case BF.Bytes32:
  938. length = ((byte []) current.TypedValue).Length;
  939. return true;
  940. }
  941. return false;
  942. }
  943. public override string ReadContentAsString ()
  944. {
  945. string value = String.Empty;
  946. do {
  947. switch (NodeType) {
  948. case XmlNodeType.Element:
  949. case XmlNodeType.EndElement:
  950. return value;
  951. case XmlNodeType.Text:
  952. value += Value;
  953. break;
  954. }
  955. } while (Read ());
  956. return value;
  957. }
  958. #region read typed content
  959. public override int ReadContentAsInt ()
  960. {
  961. int ret = GetIntValue ();
  962. Read ();
  963. return ret;
  964. }
  965. int GetIntValue ()
  966. {
  967. switch (node.ValueType) {
  968. case BF.Zero:
  969. return 0;
  970. case BF.One:
  971. return 1;
  972. case BF.Int8:
  973. return (byte) current.TypedValue;
  974. case BF.Int16:
  975. return (short) current.TypedValue;
  976. case BF.Int32:
  977. return (int) current.TypedValue;
  978. }
  979. throw new InvalidOperationException ("Current content is not an integer");
  980. }
  981. public override long ReadContentAsLong ()
  982. {
  983. if (node.ValueType == BF.Int64) {
  984. long v = (long) current.TypedValue;
  985. Read ();
  986. return v;
  987. }
  988. return ReadContentAsInt ();
  989. }
  990. public override float ReadContentAsFloat ()
  991. {
  992. if (node.ValueType != BF.Single)
  993. throw new InvalidOperationException ("Current content is not a single");
  994. float v = (float) current.TypedValue;
  995. Read ();
  996. return v;
  997. }
  998. public override double ReadContentAsDouble ()
  999. {
  1000. if (node.ValueType != BF.Double)
  1001. throw new InvalidOperationException ("Current content is not a double");
  1002. double v = (double) current.TypedValue;
  1003. Read ();
  1004. return v;
  1005. }
  1006. bool IsBase64Node (byte b)
  1007. {
  1008. switch (b) {
  1009. case BF.Bytes8:
  1010. case BF.Bytes16:
  1011. case BF.Bytes32:
  1012. return true;
  1013. }
  1014. return false;
  1015. }
  1016. // FIXME: this is not likely to consume sequential base64 nodes.
  1017. public override byte [] ReadContentAsBase64 ()
  1018. {
  1019. byte [] ret = null;
  1020. if (!IsBase64Node (node.ValueType))
  1021. throw new InvalidOperationException ("Current content is not base64");
  1022. while (NodeType == XmlNodeType.Text && IsBase64Node (node.ValueType)) {
  1023. if (ret == null)
  1024. ret = (byte []) node.TypedValue;
  1025. else {
  1026. byte [] tmp = (byte []) node.TypedValue;
  1027. byte [] tmp2 = Alloc (ret.Length + tmp.Length);
  1028. Array.Copy (ret, tmp2, ret.Length);
  1029. Array.Copy (tmp, 0, tmp2, ret.Length, tmp.Length);
  1030. ret = tmp2;
  1031. }
  1032. Read ();
  1033. //MoveToContent ();
  1034. }
  1035. return ret;
  1036. }
  1037. public override Guid ReadContentAsGuid ()
  1038. {
  1039. if (node.ValueType != BF.Guid)
  1040. throw new InvalidOperationException ("Current content is not a Guid");
  1041. Guid ret = (Guid) node.TypedValue;
  1042. Read ();
  1043. return ret;
  1044. }
  1045. public override UniqueId ReadContentAsUniqueId ()
  1046. {
  1047. switch (node.ValueType) {
  1048. case BF.Chars8:
  1049. case BF.Chars16:
  1050. case BF.Chars32:
  1051. case BF.Utf16_8:
  1052. case BF.Utf16_16:
  1053. case BF.Utf16_32:
  1054. UniqueId ret = new UniqueId (node.Value);
  1055. Read ();
  1056. return ret;
  1057. case BF.UniqueId:
  1058. ret = (UniqueId) node.TypedValue;
  1059. Read ();
  1060. return ret;
  1061. default:
  1062. throw new InvalidOperationException ("Current content is not a UniqueId");
  1063. }
  1064. }
  1065. #endregion
  1066. }
  1067. }