XmlBinaryDictionaryReader.cs 31 KB

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