XmlBinaryDictionaryReader.cs 29 KB

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