2010-05-27 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Runtime.Serialization / System.Xml / XmlBinaryDictionaryReader.cs
blob07b47c1b5cd3303f0ef10095d085953781e1df99
1 //
2 // XmlBinaryDictionaryReader.cs
3 //
4 // Author:
5 // Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005, 2007 Novell, Inc. http://www.novell.com
8 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System;
31 using System.Collections;
32 using System.Collections.Specialized;
33 using System.Collections.Generic;
34 using System.Globalization;
35 using System.IO;
36 using System.Text;
38 using QName = System.Xml.XmlQualifiedName;
39 using BF = System.Xml.XmlBinaryFormat;
41 namespace System.Xml
43 // FIXME:
44 // - support XmlDictionaryReaderQuotas.
46 internal class XmlBinaryDictionaryReader : XmlDictionaryReader, IXmlNamespaceResolver
48 internal interface ISource
50 int Position { get; }
51 int ReadByte ();
52 int Read (byte [] data, int offset, int count);
53 BinaryReader Reader { get; }
56 internal class StreamSource : ISource
58 BinaryReader reader;
60 public StreamSource (Stream stream)
62 this.reader = new BinaryReader (stream);
65 public int Position {
66 get { return (int) reader.BaseStream.Position; }
69 public BinaryReader Reader {
70 get { return reader; }
73 public int ReadByte ()
75 if (reader.PeekChar () < 0)
76 return -1;
77 return reader.ReadByte ();
80 public int Read (byte [] data, int offset, int count)
82 return reader.Read (data, offset, count);
86 class NodeInfo
88 public NodeInfo ()
92 public NodeInfo (bool isAttr)
94 IsAttributeValue = isAttr;
97 public bool IsAttributeValue;
98 public int Position;
99 public string Prefix;
100 public XmlDictionaryString DictLocalName;
101 public XmlDictionaryString DictNS;
102 public XmlDictionaryString DictValue; // BF.TextIndex
103 public XmlNodeType NodeType;
104 public object TypedValue;
105 public byte ValueType;
107 // -1 for nothing,
108 // -2 for that of element (only for attribute),
109 // 0 or more to fill later
110 public int NSSlot;
112 string name = String.Empty;
113 string local_name = String.Empty;
114 string ns = String.Empty;
115 string value;
117 public string LocalName {
118 get { return DictLocalName != null ? DictLocalName.Value : local_name; }
119 set {
120 DictLocalName = null;
121 local_name = value;
125 public string NS {
126 get { return DictNS != null ? DictNS.Value : ns; }
127 set {
128 DictNS = null;
129 ns = value;
133 public string Name {
134 get {
135 if (name.Length == 0)
136 name = Prefix.Length > 0 ?
137 String.Concat (Prefix, ":", LocalName) :
138 LocalName;
139 return name;
143 public virtual string Value {
144 get {
145 switch (ValueType) {
146 case 0:
147 case BF.Comment:
148 case BF.Chars8:
149 case BF.Chars16:
150 case BF.Chars32:
151 case BF.EmptyText:
152 case BF.Utf16_8:
153 case BF.Utf16_16:
154 case BF.Utf16_32:
155 return value;
156 case BF.TextIndex:
157 return DictValue.Value;
158 case BF.Zero:
159 return "0";
160 case BF.One:
161 return "1";
162 case BF.BoolTrue:
163 return "true";
164 case BF.BoolFalse:
165 return "false";
166 case BF.Int8:
167 return XmlConvert.ToString ((byte) TypedValue);
168 case BF.Int16:
169 return XmlConvert.ToString ((short) TypedValue);
170 case BF.Int32:
171 return XmlConvert.ToString ((int) TypedValue);
172 case BF.Int64:
173 return XmlConvert.ToString ((long) TypedValue);
174 case BF.Single:
175 return XmlConvert.ToString ((float) TypedValue);
176 case BF.Double:
177 return XmlConvert.ToString ((double) TypedValue);
178 case BF.DateTime:
179 return XmlConvert.ToString ((DateTime) TypedValue, XmlDateTimeSerializationMode.RoundtripKind);
180 case BF.TimeSpan:
181 return XmlConvert.ToString ((TimeSpan) TypedValue);
182 case BF.Guid:
183 return XmlConvert.ToString ((Guid) TypedValue);
184 case BF.UniqueId:
185 return TypedValue.ToString ();
186 case BF.Bytes8:
187 case BF.Bytes16:
188 case BF.Bytes32:
189 return Convert.ToBase64String ((byte []) TypedValue);
190 default:
191 throw new NotImplementedException ("ValueType " + ValueType + " on node " + NodeType);
194 set { this.value = value; }
197 public virtual void Reset ()
199 Position = 0;
200 DictLocalName = DictNS = null;
201 LocalName = NS = Prefix = Value = String.Empty;
202 NodeType = XmlNodeType.None;
203 TypedValue = null;
204 ValueType = 0;
205 NSSlot = -1;
209 class AttrNodeInfo : NodeInfo
211 public AttrNodeInfo (XmlBinaryDictionaryReader owner)
213 this.owner = owner;
216 XmlBinaryDictionaryReader owner;
217 public int ValueIndex;
219 public override void Reset ()
221 base.Reset ();
222 ValueIndex = -1;
223 NodeType = XmlNodeType.Attribute;
226 public override string Value {
227 get { return owner.attr_values [ValueIndex].Value; }
231 ISource source;
232 IXmlDictionary dictionary;
233 XmlDictionaryReaderQuotas quota;
234 XmlBinaryReaderSession session;
235 OnXmlDictionaryReaderClose on_close;
236 XmlParserContext context;
238 ReadState state = ReadState.Initial;
239 NodeInfo node;
240 NodeInfo current;
241 List<AttrNodeInfo> attributes = new List<AttrNodeInfo> ();
242 List<NodeInfo> attr_values = new List<NodeInfo> ();
243 List<NodeInfo> node_stack = new List<NodeInfo> ();
244 List<QName> ns_store = new List<QName> ();
245 Dictionary<int,XmlDictionaryString> ns_dict_store =
246 new Dictionary<int,XmlDictionaryString> ();
247 int attr_count;
248 int attr_value_count;
249 int current_attr = -1;
250 int depth = 0;
251 // used during Read()
252 int ns_slot;
253 // next byte in the source (one byte token ahead always
254 // happens because there is no "end of start element" mark).
255 int next = -1;
256 bool is_next_end_element;
257 // temporary buffer for utf8enc.GetString()
258 byte [] tmp_buffer = new byte [128];
259 UTF8Encoding utf8enc = new UTF8Encoding ();
261 // See comment at Read()
262 int array_item_remaining;
263 byte array_item_type;
264 XmlNodeType array_state;
266 public XmlBinaryDictionaryReader (byte [] buffer, int offset,
267 int count, IXmlDictionary dictionary,
268 XmlDictionaryReaderQuotas quota,
269 XmlBinaryReaderSession session,
270 OnXmlDictionaryReaderClose onClose)
272 source = /*new ArraySource (buffer, offset, count);*/
273 new StreamSource (new MemoryStream (buffer, offset, count));
274 Initialize (dictionary, quota, session, onClose);
277 public XmlBinaryDictionaryReader (Stream stream,
278 IXmlDictionary dictionary,
279 XmlDictionaryReaderQuotas quota,
280 XmlBinaryReaderSession session,
281 OnXmlDictionaryReaderClose onClose)
283 source = new StreamSource (stream);
284 Initialize (dictionary, quota, session, onClose);
287 private void Initialize (IXmlDictionary dictionary,
288 XmlDictionaryReaderQuotas quotas,
289 XmlBinaryReaderSession session,
290 OnXmlDictionaryReaderClose onClose)
292 if (quotas == null)
293 throw new ArgumentNullException ("quotas");
294 if (dictionary == null)
295 dictionary = new XmlDictionary ();
296 this.dictionary = dictionary;
298 this.quota = quotas;
300 if (session == null)
301 session = new XmlBinaryReaderSession ();
302 this.session = session;
304 on_close = onClose;
305 NameTable nt = new NameTable ();
306 this.context = new XmlParserContext (nt,
307 new XmlNamespaceManager (nt),
308 null, XmlSpace.None);
310 current = node = new NodeInfo ();
311 current.Reset ();
312 node_stack.Add (node);
315 public override int AttributeCount {
316 get { return attr_count; }
319 public override string BaseURI {
320 get { return context.BaseURI; }
323 public override int Depth {
324 get { return current == node ? depth : NodeType == XmlNodeType.Attribute ? depth + 1 : depth + 2; }
327 public override bool EOF {
328 get { return state == ReadState.EndOfFile || state == ReadState.Error; }
331 public override bool HasValue {
332 get { return Value.Length > 0; }
335 public override bool IsEmptyElement {
336 get { return false; }
339 public override XmlNodeType NodeType {
340 get { return current.NodeType; }
343 public override string Prefix {
344 get { return current_attr >= 0 ? attributes [current_attr].Prefix : current.Prefix; }
347 // looks like it may return attribute's name even if it is on its value node.
348 public override string LocalName {
349 get { return current_attr >= 0 ? attributes [current_attr].LocalName : current.LocalName; }
352 public override string Name {
353 get { return current_attr >= 0 ? attributes [current_attr].Name : current.Name; }
356 public override string NamespaceURI {
357 get { return current_attr >= 0 ? attributes [current_attr].NS : current.NS; }
360 public override XmlNameTable NameTable {
361 get { return context.NameTable; }
364 public override XmlDictionaryReaderQuotas Quotas {
365 get { return quota; }
368 public override ReadState ReadState {
369 get { return state; }
372 public override string Value {
373 get { return current.Value; }
376 public override void Close ()
378 if (on_close != null)
379 on_close (this);
382 public override string GetAttribute (int i)
384 if (i >= attr_count)
385 throw new ArgumentOutOfRangeException (String.Format ("Specified attribute index is {0} and should be less than {1}", i, attr_count));
386 return attributes [i].Value;
389 public override string GetAttribute (string name)
391 for (int i = 0; i < attr_count; i++)
392 if (attributes [i].Name == name)
393 return attributes [i].Value;
394 return null;
397 public override string GetAttribute (string localName, string ns)
399 for (int i = 0; i < attr_count; i++)
400 if (attributes [i].LocalName == localName &&
401 attributes [i].NS == ns)
402 return attributes [i].Value;
403 return null;
406 public IDictionary<string,string> GetNamespacesInScope (
407 XmlNamespaceScope scope)
409 return context.NamespaceManager.GetNamespacesInScope (scope);
412 public string LookupPrefix (string ns)
414 return context.NamespaceManager.LookupPrefix (NameTable.Get (ns));
417 public override string LookupNamespace (string prefix)
419 return context.NamespaceManager.LookupNamespace (
420 NameTable.Get (prefix));
423 public override bool IsArray (out Type type)
425 if (array_state == XmlNodeType.Element) {
426 type = GetArrayType (array_item_type);
427 return true;
428 } else {
429 type = null;
430 return false;
434 public override bool MoveToElement ()
436 bool ret = current_attr >= 0;
437 current_attr = -1;
438 current = node;
439 return ret;
442 public override bool MoveToFirstAttribute ()
444 if (attr_count == 0)
445 return false;
446 current_attr = 0;
447 current = attributes [current_attr];
448 return true;
451 public override bool MoveToNextAttribute ()
453 if (++current_attr < attr_count) {
454 current = attributes [current_attr];
455 return true;
456 } else {
457 --current_attr;
458 return false;
462 public override void MoveToAttribute (int i)
464 if (i >= attr_count)
465 throw new ArgumentOutOfRangeException (String.Format ("Specified attribute index is {0} and should be less than {1}", i, attr_count));
466 current_attr = i;
467 current = attributes [i];
470 public override bool MoveToAttribute (string name)
472 for (int i = 0; i < attributes.Count; i++) {
473 if (attributes [i].Name == name) {
474 MoveToAttribute (i);
475 return true;
478 return false;
481 public override bool MoveToAttribute (string localName, string ns)
483 for (int i = 0; i < attributes.Count; i++) {
484 if (attributes [i].LocalName == localName &&
485 attributes [i].NS == ns) {
486 MoveToAttribute (i);
487 return true;
490 return false;
493 public override bool ReadAttributeValue ()
495 if (current_attr < 0)
496 return false;
497 int start = attributes [current_attr].ValueIndex;
498 int end = current_attr + 1 == attr_count ? attr_value_count : attributes [current_attr + 1].ValueIndex;
499 if (start == end)
500 return false;
501 if (!current.IsAttributeValue) {
502 current = attr_values [start];
503 return true;
505 // Actually there is no case for attribute whose value is split to more than two nodes. We could simplify the node structure.
506 return false;
509 // When reading an array (0x03), it requires extraneously
510 // complex procedure for XmlReader. First, it reads element,
511 // type of operation and length of the items. And this XmlReader
512 // has to return Element state. On the next Read(), it proceeds
513 // to the value node of the first item of the array, so it
514 // reads the value stream. On the next Read(), it proceeds to
515 // EndElement, so it should not read anything from stream while
516 // it has to move to the node state to EndElement.
517 public override bool Read ()
519 switch (state) {
520 case ReadState.Closed:
521 case ReadState.EndOfFile:
522 case ReadState.Error:
523 return false;
526 // clear.
527 state = ReadState.Interactive;
528 MoveToElement ();
529 attr_count = 0;
530 attr_value_count = 0;
531 ns_slot = 0;
533 if (node.NodeType == XmlNodeType.Element) {
534 // push element scope
535 if (node_stack.Count <= ++depth) {
536 if (depth == quota.MaxDepth)
537 throw new XmlException (String.Format ("Binary XML stream quota exceeded. Depth must be less than {0}", quota.MaxDepth));
538 node = new NodeInfo ();
539 node_stack.Add (node);
540 } else {
541 node = node_stack [depth]; // reuse
542 node.Reset ();
545 current = node;
547 if (is_next_end_element) {
548 is_next_end_element = false;
549 node.Reset ();
550 ProcessEndElement ();
551 return true;
554 // process array node after preparing node stack.
555 switch (array_state) {
556 case XmlNodeType.Element:
557 ReadArrayItem ();
558 return true;
559 case XmlNodeType.Text:
560 ShiftToArrayItemEndElement ();
561 return true;
562 case XmlNodeType.EndElement:
563 if (--array_item_remaining == 0) {
564 array_state = XmlNodeType.None;
565 break;
566 } else {
567 ShiftToArrayItemElement ();
568 return true;
572 // array consumer does not expect Reset whlie it's on reading. So call it later than array check.
573 node.Reset ();
575 int ident = next >= 0 ? next : source.ReadByte ();
576 next = -1;
578 // check end of source.
579 if (ident < 0) {
580 state = ReadState.EndOfFile;
581 current.Reset ();
582 return false;
585 is_next_end_element = ident > 0x80 && (ident & 1) == 1;
586 ident -= is_next_end_element ? 1 : 0;
588 switch (ident) {
589 case BF.EndElement:
590 ProcessEndElement ();
591 break;
592 case BF.Comment:
593 node.Value = ReadUTF8 ();
594 node.ValueType = BF.Comment;
595 node.NodeType = XmlNodeType.Comment;
596 break;
597 case BF.ElemString:
598 case BF.ElemStringPrefix:
599 case BF.ElemIndex:
600 case BF.ElemIndexPrefix:
601 ReadElementBinary ((byte) ident);
602 break;
604 case BF.Array:
605 ident = ReadByteOrError ();
606 ReadElementBinary ((byte) ident);
607 ident = ReadByteOrError ();
608 if (ident != 0x01)
609 throw new XmlException (String.Format ("EndElement is expected after element in an array. The actual byte was {0:X} in hexadecimal", ident));
610 ident = ReadByteOrError () - 1; // -1 becauseit contains EndElement
611 VerifyValidArrayItemType (ident);
612 if (ident < 0)
613 throw new XmlException ("The stream has ended where the array item type is expected");
614 array_item_type = (byte) ident;
615 array_item_remaining = ReadVariantSize ();
616 if (array_item_remaining > quota.MaxArrayLength)
617 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));
618 array_state = XmlNodeType.Element;
619 break;
621 default:
622 if (BF.PrefixNElemIndexStart <= ident && ident <= BF.PrefixNElemIndexEnd ||
623 BF.PrefixNElemStringStart <= ident && ident <= BF.PrefixNElemStringEnd)
624 goto case BF.ElemString;
625 ReadTextOrValue ((byte) ident, node, false);
626 break;
629 return true;
632 void ReadArrayItem ()
634 ReadTextOrValue (array_item_type, node, false);
635 array_state = XmlNodeType.Text;
638 void ShiftToArrayItemEndElement ()
640 ProcessEndElement ();
641 array_state = XmlNodeType.EndElement;
644 void ShiftToArrayItemElement ()
646 node.NodeType = XmlNodeType.Element;
647 context.NamespaceManager.PushScope ();
648 array_state = XmlNodeType.Element;
651 void VerifyValidArrayItemType (int ident)
653 if (GetArrayType (ident) == null)
654 throw new XmlException (String.Format ("Unexpected array item type {0:X} in hexadecimal", ident));
657 Type GetArrayType (int ident)
659 switch (ident) {
660 case BF.Bool:
661 return typeof (bool);
662 case BF.Int16:
663 return typeof (short);
664 case BF.Int32:
665 return typeof (int);
666 case BF.Int64:
667 return typeof (long);
668 case BF.Single:
669 return typeof (float);
670 case BF.Double:
671 return typeof (double);
672 case BF.Decimal:
673 return typeof (decimal);
674 case BF.DateTime:
675 return typeof (DateTime);
676 case BF.TimeSpan:
677 return typeof (TimeSpan);
678 case BF.Guid:
679 return typeof (Guid);
681 return null;
684 private void ProcessEndElement ()
686 if (depth == 0)
687 throw new XmlException ("Unexpected end of element while there is no element started.");
688 current = node = node_stack [--depth];
689 node.NodeType = XmlNodeType.EndElement;
690 context.NamespaceManager.PopScope ();
693 private void ReadElementBinary (int ident)
695 // element
696 node.NodeType = XmlNodeType.Element;
697 node.Prefix = String.Empty;
698 context.NamespaceManager.PushScope ();
699 switch (ident) {
700 case BF.ElemString:
701 node.LocalName = ReadUTF8 ();
702 break;
703 case BF.ElemStringPrefix:
704 node.Prefix = ReadUTF8 ();
705 node.NSSlot = ns_slot++;
706 goto case BF.ElemString;
707 case BF.ElemIndex:
708 node.DictLocalName = ReadDictName ();
709 break;
710 case BF.ElemIndexPrefix:
711 node.Prefix = ReadUTF8 ();
712 node.NSSlot = ns_slot++;
713 goto case BF.ElemIndex;
714 default:
715 if (BF.PrefixNElemIndexStart <= ident && ident <= BF.PrefixNElemIndexEnd) {
716 node.Prefix = ((char) (ident - BF.PrefixNElemIndexStart + 'a')).ToString ();
717 node.DictLocalName = ReadDictName ();
718 } else if (BF.PrefixNElemStringStart <= ident && ident <= BF.PrefixNElemStringEnd) {
719 node.Prefix = ((char) (ident - BF.PrefixNElemStringStart + 'a')).ToString ();
720 node.LocalName = ReadUTF8 ();
722 else
723 throw new XmlException (String.Format ("Invalid element node type {0:X02} in hexadecimal", ident));
724 break;
727 bool loop = true;
728 do {
729 ident = ReadByteOrError ();
731 switch (ident) {
732 case BF.AttrString:
733 case BF.AttrStringPrefix:
734 case BF.AttrIndex:
735 case BF.AttrIndexPrefix:
736 ReadAttribute ((byte) ident);
737 break;
738 case BF.DefaultNSString:
739 case BF.PrefixNSString:
740 case BF.DefaultNSIndex:
741 case BF.PrefixNSIndex:
742 ReadNamespace ((byte) ident);
743 break;
744 default:
745 if (BF.PrefixNAttrStringStart <= ident && ident <= BF.PrefixNAttrStringEnd ||
746 BF.PrefixNAttrIndexStart <= ident && ident <= BF.PrefixNAttrIndexEnd)
747 ReadAttribute ((byte) ident);
748 else {
749 next = ident;
750 loop = false;
752 break;
754 } while (loop);
756 node.NS = context.NamespaceManager.LookupNamespace (node.Prefix) ?? String.Empty;
757 foreach (AttrNodeInfo a in attributes)
758 if (a.Prefix.Length > 0)
759 a.NS = context.NamespaceManager.LookupNamespace (a.Prefix);
761 ns_store.Clear ();
762 ns_dict_store.Clear ();
765 private void ReadAttribute (byte ident)
767 if (attributes.Count == attr_count)
768 attributes.Add (new AttrNodeInfo (this));
769 AttrNodeInfo a = attributes [attr_count++];
770 a.Reset ();
771 a.Position = source.Position;
773 switch (ident) {
774 case BF.AttrString:
775 a.LocalName = ReadUTF8 ();
776 break;
777 case BF.AttrStringPrefix:
778 a.Prefix = ReadUTF8 ();
779 a.NSSlot = ns_slot++;
780 goto case BF.AttrString;
781 case BF.AttrIndex:
782 a.DictLocalName = ReadDictName ();
783 break;
784 case BF.AttrIndexPrefix:
785 a.Prefix = ReadUTF8 ();
786 a.NSSlot = ns_slot++;
787 goto case BF.AttrIndex;
788 default:
789 if (BF.PrefixNAttrStringStart <= ident && ident <= BF.PrefixNAttrStringEnd) {
790 a.Prefix = ((char) ('a' + ident - BF.PrefixNAttrStringStart)).ToString ();
791 a.LocalName = ReadUTF8 ();
792 break;
794 else if (BF.PrefixNAttrIndexStart <= ident && ident <= BF.PrefixNAttrIndexEnd) {
795 a.Prefix = ((char) ('a' + ident - BF.PrefixNAttrIndexStart)).ToString ();
796 a.DictLocalName = ReadDictName ();
797 break;
799 else throw new XmlException (String.Format ("Unexpected attribute node type: 0x{0:X02}", ident));
801 ReadAttributeValueBinary (a);
804 private void ReadNamespace (byte ident)
806 // create attrubute slot.
807 if (attributes.Count == attr_count)
808 attributes.Add (new AttrNodeInfo (this));
809 AttrNodeInfo a = attributes [attr_count++];
810 a.Reset ();
811 a.Position = source.Position;
813 string prefix = null, ns = null;
814 XmlDictionaryString dns = null;
816 switch (ident) {
817 case BF.DefaultNSString:
818 prefix = String.Empty;
819 ns = ReadUTF8 ();
820 break;
821 case BF.PrefixNSString:
822 prefix = ReadUTF8 ();
823 ns = ReadUTF8 ();
824 break;
825 case BF.DefaultNSIndex:
826 prefix = String.Empty;
827 dns = ReadDictName ();
828 ns_dict_store.Add (ns_store.Count, dns);
829 ns = dns.Value;
830 break;
831 case BF.PrefixNSIndex:
832 prefix = ReadUTF8 ();
833 dns = ReadDictName ();
834 ns_dict_store.Add (ns_store.Count, dns);
835 ns = dns.Value;
836 break;
839 // fill attribute slot.
840 a.Prefix = prefix.Length > 0 ? "xmlns" : String.Empty;
841 a.LocalName = prefix.Length > 0 ? prefix : "xmlns";
842 a.NS = "http://www.w3.org/2000/xmlns/";
843 a.ValueIndex = attr_value_count;
844 if (attr_value_count == attr_values.Count)
845 attr_values.Add (new NodeInfo (true));
846 NodeInfo v = attr_values [attr_value_count++];
847 v.Reset ();
848 v.Value = ns;
849 v.ValueType = BF.Chars8;
850 v.NodeType = XmlNodeType.Text;
852 ns_store.Add (new QName (prefix, ns));
853 context.NamespaceManager.AddNamespace (prefix, ns);
856 private void ReadAttributeValueBinary (AttrNodeInfo a)
858 a.ValueIndex = attr_value_count;
859 if (attr_value_count == attr_values.Count)
860 attr_values.Add (new NodeInfo (true));
861 NodeInfo v = attr_values [attr_value_count++];
862 v.Reset ();
863 int ident = ReadByteOrError ();
864 bool end = ident > 0x80 && (ident & 1) == 1;
865 ident -= end ? 1 : 0;
866 ReadTextOrValue ((byte) ident, v, true);
869 private bool ReadTextOrValue (byte ident, NodeInfo node, bool canSkip)
871 node.Value = null;
872 node.ValueType = ident;
873 node.NodeType = XmlNodeType.Text;
874 switch (ident) {
875 case BF.Zero:
876 node.TypedValue = 0;
877 break;
878 case BF.One:
879 node.TypedValue = 1;
880 break;
881 case BF.BoolFalse:
882 node.TypedValue = false;
883 break;
884 case BF.BoolTrue:
885 node.TypedValue = true;
886 break;
887 case BF.Int8:
888 node.TypedValue = ReadByteOrError ();
889 break;
890 case BF.Int16:
891 node.TypedValue = source.Reader.ReadInt16 ();
892 break;
893 case BF.Int32:
894 node.TypedValue = source.Reader.ReadInt32 ();
895 break;
896 case BF.Int64:
897 node.TypedValue = source.Reader.ReadInt64 ();
898 break;
899 case BF.Single:
900 node.TypedValue = source.Reader.ReadSingle ();
901 break;
902 case BF.Double:
903 node.TypedValue = source.Reader.ReadDouble ();
904 break;
905 case BF.Decimal:
906 int [] bits = new int [4];
907 bits [3] = source.Reader.ReadInt32 ();
908 bits [2] = source.Reader.ReadInt32 ();
909 bits [0] = source.Reader.ReadInt32 ();
910 bits [1] = source.Reader.ReadInt32 ();
911 node.TypedValue = new Decimal (bits);
912 break;
913 case BF.DateTime:
914 node.TypedValue = new DateTime (source.Reader.ReadInt64 ());
915 break;
916 //case BF.UniqueId: // identical to .Text
917 case BF.Bytes8:
918 case BF.Bytes16:
919 case BF.Bytes32:
920 int size =
921 (ident == BF.Bytes8) ? source.Reader.ReadByte () :
922 (ident == BF.Bytes16) ? source.Reader.ReadUInt16 () :
923 source.Reader.ReadInt32 ();
924 byte [] base64 = Alloc (size);
925 source.Reader.Read (base64, 0, base64.Length);
926 node.TypedValue = base64;
927 break;
928 case BF.TimeSpan:
929 node.TypedValue = new TimeSpan (source.Reader.ReadInt64 ());
930 break;
931 case BF.UniqueId:
932 byte [] guid = new byte [16];
933 source.Reader.Read (guid, 0, guid.Length);
934 node.TypedValue = new UniqueId (new Guid (guid));
935 break;
936 case BF.Guid:
937 guid = new byte [16];
938 source.Reader.Read (guid, 0, guid.Length);
939 node.TypedValue = new Guid (guid);
940 break;
941 case BF.Chars8:
942 case BF.Chars16:
943 case BF.Chars32:
944 case BF.Utf16_8:
945 case BF.Utf16_16:
946 case BF.Utf16_32:
947 Encoding enc = ident <= BF.Chars32 ? Encoding.UTF8 : Encoding.Unicode;
948 size =
949 (ident == BF.Chars8 || ident == BF.Utf16_8) ? source.Reader.ReadByte () :
950 (ident == BF.Chars16 || ident == BF.Utf16_16) ? source.Reader.ReadUInt16 () :
951 source.Reader.ReadInt32 ();
952 byte [] bytes = Alloc (size);
953 source.Reader.Read (bytes, 0, size);
954 node.Value = enc.GetString (bytes, 0, size);
955 node.NodeType = XmlNodeType.Text;
956 break;
957 case BF.EmptyText:
958 node.Value = String.Empty;
959 node.NodeType = XmlNodeType.Text;
960 break;
961 case BF.TextIndex:
962 node.DictValue = ReadDictName ();
963 node.NodeType = XmlNodeType.Text;
964 break;
965 default:
966 if (!canSkip)
967 throw new ArgumentException (String.Format ("Unexpected binary XML data at position {1}: {0:X}", ident + (is_next_end_element ? 1 : 0), source.Position));
968 next = ident;
969 return false;
971 return true;
974 byte [] Alloc (int size)
976 if (size > quota.MaxStringContentLength || size < 0)
977 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));
978 return new byte [size];
981 private int ReadVariantSize ()
983 int size = 0;
984 // If sizeSpec < 0, then it is variant size specifier.
985 // Otherwise it is fixed size s = sizeSpec + 1 byte(s).
986 int d = 0;
987 do {
988 byte got = ReadByteOrError ();
989 size += (got & 0x7F) << d;
990 d += 7;
991 if (got < 0x80)
992 break;
993 } while (true);
994 return size;
997 private string ReadUTF8 ()
999 int size = ReadVariantSize ();
1000 if (size == 0)
1001 return String.Empty;
1002 if (tmp_buffer.Length < size) {
1003 int extlen = tmp_buffer.Length * 2;
1004 tmp_buffer = Alloc (size < extlen ? extlen : size);
1006 size = source.Read (tmp_buffer, 0, size);
1007 return utf8enc.GetString (tmp_buffer, 0, size);
1010 private XmlDictionaryString ReadDictName ()
1012 int key = ReadVariantSize ();
1013 XmlDictionaryString s;
1014 if ((key & 1) == 1) {
1015 if (session.TryLookup (key >> 1, out s))
1016 return s;
1017 } else {
1018 if (dictionary.TryLookup (key >> 1, out s))
1019 return s;
1021 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));
1024 private byte ReadByteOrError ()
1026 if (next >= 0) {
1027 byte b = (byte) next;
1028 next = -1;
1029 return b;
1031 int ret = source.ReadByte ();
1032 if (ret < 0)
1033 throw new XmlException (String.Format ("Unexpected end of binary stream. Position is at {0}", source.Position));
1034 return (byte) ret;
1037 public override void ResolveEntity ()
1039 throw new NotSupportedException ("this XmlReader does not support ResolveEntity.");
1042 public override bool TryGetBase64ContentLength (out int length)
1044 length = 0;
1045 switch (current.ValueType) {
1046 case BF.Bytes8:
1047 case BF.Bytes16:
1048 case BF.Bytes32:
1049 length = ((byte []) current.TypedValue).Length;
1050 return true;
1052 return false;
1055 public override string ReadContentAsString ()
1057 string value = String.Empty;
1058 do {
1059 switch (NodeType) {
1060 case XmlNodeType.Element:
1061 case XmlNodeType.EndElement:
1062 return value;
1063 case XmlNodeType.Text:
1064 value += Value;
1065 break;
1067 } while (Read ());
1068 return value;
1071 #region read typed content
1073 public override int ReadContentAsInt ()
1075 int ret = GetIntValue ();
1076 Read ();
1077 return ret;
1080 int GetIntValue ()
1082 switch (node.ValueType) {
1083 case BF.Zero:
1084 return 0;
1085 case BF.One:
1086 return 1;
1087 case BF.Int8:
1088 return (byte) current.TypedValue;
1089 case BF.Int16:
1090 return (short) current.TypedValue;
1091 case BF.Int32:
1092 return (int) current.TypedValue;
1094 throw new InvalidOperationException (String.Format ("Current content is not an integer. (Internal value type:{0:X02})", (int) node.ValueType));
1097 public override long ReadContentAsLong ()
1099 if (node.ValueType == BF.Int64) {
1100 long v = (long) current.TypedValue;
1101 Read ();
1102 return v;
1104 return ReadContentAsInt ();
1107 public override float ReadContentAsFloat ()
1109 if (node.ValueType != BF.Single)
1110 throw new InvalidOperationException ("Current content is not a single");
1111 float v = (float) current.TypedValue;
1112 Read ();
1113 return v;
1116 public override double ReadContentAsDouble ()
1118 if (node.ValueType != BF.Double)
1119 throw new InvalidOperationException ("Current content is not a double");
1120 double v = (double) current.TypedValue;
1121 Read ();
1122 return v;
1125 bool IsBase64Node (byte b)
1127 switch (b) {
1128 case BF.Bytes8:
1129 case BF.Bytes16:
1130 case BF.Bytes32:
1131 return true;
1133 return false;
1136 // FIXME: this is not likely to consume sequential base64 nodes.
1137 public override byte [] ReadContentAsBase64 ()
1139 byte [] ret = null;
1140 if (!IsBase64Node (node.ValueType))
1141 throw new InvalidOperationException ("Current content is not base64");
1143 while (NodeType == XmlNodeType.Text && IsBase64Node (node.ValueType)) {
1144 if (ret == null)
1145 ret = (byte []) node.TypedValue;
1146 else {
1147 byte [] tmp = (byte []) node.TypedValue;
1148 byte [] tmp2 = Alloc (ret.Length + tmp.Length);
1149 Array.Copy (ret, tmp2, ret.Length);
1150 Array.Copy (tmp, 0, tmp2, ret.Length, tmp.Length);
1151 ret = tmp2;
1153 Read ();
1154 //MoveToContent ();
1156 return ret;
1159 public override Guid ReadContentAsGuid ()
1161 if (node.ValueType != BF.Guid)
1162 throw new InvalidOperationException ("Current content is not a Guid");
1163 Guid ret = (Guid) node.TypedValue;
1164 Read ();
1165 return ret;
1168 public override UniqueId ReadContentAsUniqueId ()
1170 switch (node.ValueType) {
1171 case BF.Chars8:
1172 case BF.Chars16:
1173 case BF.Chars32:
1174 case BF.Utf16_8:
1175 case BF.Utf16_16:
1176 case BF.Utf16_32:
1177 UniqueId ret = new UniqueId (node.Value);
1178 Read ();
1179 return ret;
1180 case BF.UniqueId:
1181 ret = (UniqueId) node.TypedValue;
1182 Read ();
1183 return ret;
1184 default:
1185 throw new InvalidOperationException ("Current content is not a UniqueId");
1189 #endregion