public override bool Read ()
{
switch (state) {
case ReadState.Closed:
case ReadState.EndOfFile:
case ReadState.Error:
return false;
}
// clear.
state = ReadState.Interactive;
MoveToElement ();
attr_count = 0;
attr_value_count = 0;
ns_slot = 0;
if (node.NodeType == XmlNodeType.Element) {
// push element scope
if (node_stack.Count <= ++depth) {
if (depth == quota.MaxDepth)
throw new XmlException (String.Format ("Binary XML stream quota exceeded. Depth must be less than {0}", quota.MaxDepth));
node = new NodeInfo ();
node_stack.Add (node);
} else {
node = node_stack [depth]; // reuse
node.Reset ();
}
}
current = node;
if (is_next_end_element) {
is_next_end_element = false;
node.Reset ();
ProcessEndElement ();
return true;
}
// process array node after preparing node stack.
switch (array_state) {
case XmlNodeType.Element:
ReadArrayItem ();
return true;
case XmlNodeType.Text:
ShiftToArrayItemEndElement ();
return true;
case XmlNodeType.EndElement:
if (--array_item_remaining == 0) {
array_state = XmlNodeType.None;
break;
} else {
ShiftToArrayItemElement ();
return true;
}
}
// array consumer does not expect Reset whlie it's on reading. So call it later than array check.
node.Reset ();
int ident = next >= 0 ? next : source.ReadByte ();
next = -1;
// check end of source.
if (ident < 0) {
state = ReadState.EndOfFile;
current.Reset ();
return false;
}
is_next_end_element = ident > 0x80 && (ident & 1) == 1;
ident -= is_next_end_element ? 1 : 0;
switch (ident) {
case BF.EndElement:
ProcessEndElement ();
break;
case BF.Comment:
node.Value = ReadUTF8 ();
node.ValueType = BF.Comment;
node.NodeType = XmlNodeType.Comment;
break;
case BF.ElemString:
case BF.ElemStringPrefix:
case BF.ElemIndex:
case BF.ElemIndexPrefix:
ReadElementBinary ((byte) ident);
break;
case BF.Array:
ident = ReadByteOrError ();
ReadElementBinary ((byte) ident);
ident = ReadByteOrError ();
if (ident != 0x01)
throw new XmlException (String.Format ("EndElement is expected after element in an array. The actual byte was {0:X} in hexadecimal", ident));
ident = ReadByteOrError () - 1; // -1 becauseit contains EndElement
VerifyValidArrayItemType (ident);
if (ident < 0)
throw new XmlException ("The stream has ended where the array item type is expected");
array_item_type = (byte) ident;
array_item_remaining = ReadVariantSize ();
if (array_item_remaining > quota.MaxArrayLength)
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));
array_state = XmlNodeType.Element;
break;
default:
if (BF.PrefixNElemIndexStart <= ident && ident <= BF.PrefixNElemIndexEnd ||
BF.PrefixNElemStringStart <= ident && ident <= BF.PrefixNElemStringEnd)
goto case BF.ElemString;
ReadTextOrValue ((byte) ident, node, false);
break;
}
return true;
}