XmlBinaryDictionaryReader.cs 31 KB

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