XmlBinaryDictionaryReader.cs 31 KB

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