2 // XmlBinaryDictionaryReader.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005, 2007 Novell, Inc. http://www.novell.com
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
31 using System
.Collections
;
32 using System
.Collections
.Specialized
;
33 using System
.Collections
.Generic
;
34 using System
.Globalization
;
38 using QName
= System
.Xml
.XmlQualifiedName
;
39 using BF
= System
.Xml
.XmlBinaryFormat
;
44 // - support XmlDictionaryReaderQuotas.
46 internal class XmlBinaryDictionaryReader
: XmlDictionaryReader
, IXmlNamespaceResolver
48 internal interface ISource
52 int Read (byte [] data
, int offset
, int count
);
53 BinaryReader Reader { get; }
56 internal class StreamSource
: ISource
60 public StreamSource (Stream stream
)
62 this.reader
= new BinaryReader (stream
);
66 get { return (int) reader.BaseStream.Position; }
69 public BinaryReader Reader
{
70 get { return reader; }
73 public int ReadByte ()
75 if (reader
.PeekChar () < 0)
77 return reader
.ReadByte ();
80 public int Read (byte [] data
, int offset
, int count
)
82 return reader
.Read (data
, offset
, count
);
92 public NodeInfo (bool isAttr
)
94 IsAttributeValue
= isAttr
;
97 public bool IsAttributeValue
;
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
;
108 // -2 for that of element (only for attribute),
109 // 0 or more to fill later
112 string name
= String
.Empty
;
113 string local_name
= String
.Empty
;
114 string ns
= String
.Empty
;
117 public string LocalName
{
118 get { return DictLocalName != null ? DictLocalName.Value : local_name; }
120 DictLocalName
= null;
126 get { return DictNS != null ? DictNS.Value : ns; }
135 if (name
.Length
== 0)
136 name
= Prefix
.Length
> 0 ?
137 String
.Concat (Prefix
, ":", LocalName
) :
143 public virtual string Value
{
157 return DictValue
.Value
;
167 return XmlConvert
.ToString ((byte) TypedValue
);
169 return XmlConvert
.ToString ((short) TypedValue
);
171 return XmlConvert
.ToString ((int) TypedValue
);
173 return XmlConvert
.ToString ((long) TypedValue
);
175 return XmlConvert
.ToString ((float) TypedValue
);
177 return XmlConvert
.ToString ((double) TypedValue
);
179 return XmlConvert
.ToString ((DateTime
) TypedValue
, XmlDateTimeSerializationMode
.RoundtripKind
);
181 return XmlConvert
.ToString ((TimeSpan
) TypedValue
);
183 return XmlConvert
.ToString ((Guid
) TypedValue
);
185 return TypedValue
.ToString ();
189 return Convert
.ToBase64String ((byte []) TypedValue
);
191 throw new NotImplementedException ("ValueType " + ValueType
+ " on node " + NodeType
);
194 set { this.value = value; }
197 public virtual void Reset ()
200 DictLocalName
= DictNS
= null;
201 LocalName
= NS
= Prefix
= Value
= String
.Empty
;
202 NodeType
= XmlNodeType
.None
;
209 class AttrNodeInfo
: NodeInfo
211 public AttrNodeInfo (XmlBinaryDictionaryReader owner
)
216 XmlBinaryDictionaryReader owner
;
217 public int ValueIndex
;
219 public override void Reset ()
223 NodeType
= XmlNodeType
.Attribute
;
226 public override string Value
{
227 get { return owner.attr_values [ValueIndex].Value; }
232 IXmlDictionary dictionary
;
233 XmlDictionaryReaderQuotas quota
;
234 XmlBinaryReaderSession session
;
235 OnXmlDictionaryReaderClose on_close
;
236 XmlParserContext context
;
238 ReadState state
= ReadState
.Initial
;
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
> ();
248 int attr_value_count
;
249 int current_attr
= -1;
251 // used during Read()
253 // next byte in the source (one byte token ahead always
254 // happens because there is no "end of start element" mark).
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
)
293 throw new ArgumentNullException ("quotas");
294 if (dictionary
== null)
295 dictionary
= new XmlDictionary ();
296 this.dictionary
= dictionary
;
301 session
= new XmlBinaryReaderSession ();
302 this.session
= session
;
305 NameTable nt
= new NameTable ();
306 this.context
= new XmlParserContext (nt
,
307 new XmlNamespaceManager (nt
),
308 null, XmlSpace
.None
);
310 current
= node
= new NodeInfo ();
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)
382 public override string GetAttribute (int i
)
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
;
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
;
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
);
434 public override bool MoveToElement ()
436 bool ret
= current_attr
>= 0;
442 public override bool MoveToFirstAttribute ()
447 current
= attributes
[current_attr
];
451 public override bool MoveToNextAttribute ()
453 if (++current_attr
< attr_count
) {
454 current
= attributes
[current_attr
];
462 public override void MoveToAttribute (int i
)
465 throw new ArgumentOutOfRangeException (String
.Format ("Specified attribute index is {0} and should be less than {1}", i
, attr_count
));
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
) {
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
) {
493 public override bool ReadAttributeValue ()
495 if (current_attr
< 0)
497 int start
= attributes
[current_attr
].ValueIndex
;
498 int end
= current_attr
+ 1 == attr_count
? attr_value_count
: attributes
[current_attr
+ 1].ValueIndex
;
501 if (!current
.IsAttributeValue
) {
502 current
= attr_values
[start
];
505 // Actually there is no case for attribute whose value is split to more than two nodes. We could simplify the node structure.
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 ()
520 case ReadState
.Closed
:
521 case ReadState
.EndOfFile
:
522 case ReadState
.Error
:
527 state
= ReadState
.Interactive
;
530 attr_value_count
= 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
);
541 node
= node_stack
[depth
]; // reuse
547 if (is_next_end_element
) {
548 is_next_end_element
= false;
550 ProcessEndElement ();
554 // process array node after preparing node stack.
555 switch (array_state
) {
556 case XmlNodeType
.Element
:
559 case XmlNodeType
.Text
:
560 ShiftToArrayItemEndElement ();
562 case XmlNodeType
.EndElement
:
563 if (--array_item_remaining
== 0) {
564 array_state
= XmlNodeType
.None
;
567 ShiftToArrayItemElement ();
572 // array consumer does not expect Reset whlie it's on reading. So call it later than array check.
575 int ident
= next
>= 0 ? next
: source
.ReadByte ();
578 // check end of source.
580 state
= ReadState
.EndOfFile
;
585 is_next_end_element
= ident
> 0x80 && (ident
& 1) == 1;
586 ident
-= is_next_end_element
? 1 : 0;
590 ProcessEndElement ();
593 node
.Value
= ReadUTF8 ();
594 node
.ValueType
= BF
.Comment
;
595 node
.NodeType
= XmlNodeType
.Comment
;
598 case BF
.ElemStringPrefix
:
600 case BF
.ElemIndexPrefix
:
601 ReadElementBinary ((byte) ident
);
605 ident
= ReadByteOrError ();
606 ReadElementBinary ((byte) ident
);
607 ident
= ReadByteOrError ();
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
);
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
;
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);
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
)
661 return typeof (bool);
663 return typeof (short);
667 return typeof (long);
669 return typeof (float);
671 return typeof (double);
673 return typeof (decimal);
675 return typeof (DateTime
);
677 return typeof (TimeSpan
);
679 return typeof (Guid
);
684 private void ProcessEndElement ()
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
)
696 node
.NodeType
= XmlNodeType
.Element
;
697 node
.Prefix
= String
.Empty
;
698 context
.NamespaceManager
.PushScope ();
701 node
.LocalName
= ReadUTF8 ();
703 case BF
.ElemStringPrefix
:
704 node
.Prefix
= ReadUTF8 ();
705 node
.NSSlot
= ns_slot
++;
706 goto case BF
.ElemString
;
708 node
.DictLocalName
= ReadDictName ();
710 case BF
.ElemIndexPrefix
:
711 node
.Prefix
= ReadUTF8 ();
712 node
.NSSlot
= ns_slot
++;
713 goto case BF
.ElemIndex
;
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 ();
723 throw new XmlException (String
.Format ("Invalid element node type {0:X02} in hexadecimal", ident
));
729 ident
= ReadByteOrError ();
733 case BF
.AttrStringPrefix
:
735 case BF
.AttrIndexPrefix
:
736 ReadAttribute ((byte) ident
);
738 case BF
.DefaultNSString
:
739 case BF
.PrefixNSString
:
740 case BF
.DefaultNSIndex
:
741 case BF
.PrefixNSIndex
:
742 ReadNamespace ((byte) ident
);
745 if (BF
.PrefixNAttrStringStart
<= ident
&& ident
<= BF
.PrefixNAttrStringEnd
||
746 BF
.PrefixNAttrIndexStart
<= ident
&& ident
<= BF
.PrefixNAttrIndexEnd
)
747 ReadAttribute ((byte) ident
);
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
);
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
++];
771 a
.Position
= source
.Position
;
775 a
.LocalName
= ReadUTF8 ();
777 case BF
.AttrStringPrefix
:
778 a
.Prefix
= ReadUTF8 ();
779 a
.NSSlot
= ns_slot
++;
780 goto case BF
.AttrString
;
782 a
.DictLocalName
= ReadDictName ();
784 case BF
.AttrIndexPrefix
:
785 a
.Prefix
= ReadUTF8 ();
786 a
.NSSlot
= ns_slot
++;
787 goto case BF
.AttrIndex
;
789 if (BF
.PrefixNAttrStringStart
<= ident
&& ident
<= BF
.PrefixNAttrStringEnd
) {
790 a
.Prefix
= ((char) ('a' + ident
- BF
.PrefixNAttrStringStart
)).ToString ();
791 a
.LocalName
= ReadUTF8 ();
794 else if (BF
.PrefixNAttrIndexStart
<= ident
&& ident
<= BF
.PrefixNAttrIndexEnd
) {
795 a
.Prefix
= ((char) ('a' + ident
- BF
.PrefixNAttrIndexStart
)).ToString ();
796 a
.DictLocalName
= ReadDictName ();
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
++];
811 a
.Position
= source
.Position
;
813 string prefix
= null, ns
= null;
814 XmlDictionaryString dns
= null;
817 case BF
.DefaultNSString
:
818 prefix
= String
.Empty
;
821 case BF
.PrefixNSString
:
822 prefix
= ReadUTF8 ();
825 case BF
.DefaultNSIndex
:
826 prefix
= String
.Empty
;
827 dns
= ReadDictName ();
828 ns_dict_store
.Add (ns_store
.Count
, dns
);
831 case BF
.PrefixNSIndex
:
832 prefix
= ReadUTF8 ();
833 dns
= ReadDictName ();
834 ns_dict_store
.Add (ns_store
.Count
, dns
);
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
++];
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
++];
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
)
872 node
.ValueType
= ident
;
873 node
.NodeType
= XmlNodeType
.Text
;
882 node
.TypedValue
= false;
885 node
.TypedValue
= true;
888 node
.TypedValue
= ReadByteOrError ();
891 node
.TypedValue
= source
.Reader
.ReadInt16 ();
894 node
.TypedValue
= source
.Reader
.ReadInt32 ();
897 node
.TypedValue
= source
.Reader
.ReadInt64 ();
900 node
.TypedValue
= source
.Reader
.ReadSingle ();
903 node
.TypedValue
= source
.Reader
.ReadDouble ();
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
);
914 node
.TypedValue
= new DateTime (source
.Reader
.ReadInt64 ());
916 //case BF.UniqueId: // identical to .Text
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
;
929 node
.TypedValue
= new TimeSpan (source
.Reader
.ReadInt64 ());
932 byte [] guid
= new byte [16];
933 source
.Reader
.Read (guid
, 0, guid
.Length
);
934 node
.TypedValue
= new UniqueId (new Guid (guid
));
937 guid
= new byte [16];
938 source
.Reader
.Read (guid
, 0, guid
.Length
);
939 node
.TypedValue
= new Guid (guid
);
947 Encoding enc
= ident
<= BF
.Chars32
? Encoding
.UTF8
: Encoding
.Unicode
;
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
;
958 node
.Value
= String
.Empty
;
959 node
.NodeType
= XmlNodeType
.Text
;
962 node
.DictValue
= ReadDictName ();
963 node
.NodeType
= XmlNodeType
.Text
;
967 throw new ArgumentException (String
.Format ("Unexpected binary XML data at position {1}: {0:X}", ident
+ (is_next_end_element
? 1 : 0), source
.Position
));
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 ()
984 // If sizeSpec < 0, then it is variant size specifier.
985 // Otherwise it is fixed size s = sizeSpec + 1 byte(s).
988 byte got
= ReadByteOrError ();
989 size
+= (got
& 0x7F) << d
;
997 private string ReadUTF8 ()
999 int size
= ReadVariantSize ();
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
))
1018 if (dictionary
.TryLookup (key
>> 1, out 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 ()
1027 byte b
= (byte) next
;
1031 int ret
= source
.ReadByte ();
1033 throw new XmlException (String
.Format ("Unexpected end of binary stream. Position is at {0}", source
.Position
));
1037 public override void ResolveEntity ()
1039 throw new NotSupportedException ("this XmlReader does not support ResolveEntity.");
1042 public override bool TryGetBase64ContentLength (out int length
)
1045 switch (current
.ValueType
) {
1049 length
= ((byte []) current
.TypedValue
).Length
;
1055 public override string ReadContentAsString ()
1057 string value = String
.Empty
;
1060 case XmlNodeType
.Element
:
1061 case XmlNodeType
.EndElement
:
1063 case XmlNodeType
.Text
:
1071 #region read typed content
1073 public override int ReadContentAsInt ()
1075 int ret
= GetIntValue ();
1082 switch (node
.ValueType
) {
1088 return (byte) current
.TypedValue
;
1090 return (short) current
.TypedValue
;
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
;
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
;
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
;
1125 bool IsBase64Node (byte b
)
1136 // FIXME: this is not likely to consume sequential base64 nodes.
1137 public override byte [] ReadContentAsBase64 ()
1140 if (!IsBase64Node (node
.ValueType
))
1141 throw new InvalidOperationException ("Current content is not base64");
1143 while (NodeType
== XmlNodeType
.Text
&& IsBase64Node (node
.ValueType
)) {
1145 ret
= (byte []) node
.TypedValue
;
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
);
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
;
1168 public override UniqueId
ReadContentAsUniqueId ()
1170 switch (node
.ValueType
) {
1177 UniqueId ret
= new UniqueId (node
.Value
);
1181 ret
= (UniqueId
) node
.TypedValue
;
1185 throw new InvalidOperationException ("Current content is not a UniqueId");