public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("{0} (size={1}) [", XmlBinaryNodeType.GetNodeName(nodeType), elementCount);
            bool hasEndElement = XmlBinaryNodeType.IsTextNodeWithEndElement(nodeType);

            switch (nodeType)
            {
            case XmlBinaryNodeType.BoolText:
            case XmlBinaryNodeType.BoolTextWithEndElement:
                for (int i = 0; i < BoolArray.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(',');
                    }
                    sb.Append(BoolArray[i]);
                }
                sb.Append(']');
                break;

            case XmlBinaryNodeType.DateTimeText:
            case XmlBinaryNodeType.DateTimeTextWithEndElement:
                for (int i = 0; i < DateTimeArray.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(", ");
                    }
                    sb.Append(DateTimeArray[i].ToString("u"));
                }
                sb.Append(']');
                break;

            case XmlBinaryNodeType.DecimalText:
            case XmlBinaryNodeType.DecimalTextWithEndElement:
                for (int i = 0; i < DecimalArray.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(", ");
                    }
                    sb.Append(DecimalArray[i]);
                }
                sb.Append(']');
                break;

            case XmlBinaryNodeType.DoubleText:
            case XmlBinaryNodeType.DoubleTextWithEndElement:
                for (int i = 0; i < DoubleArray.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(", ");
                    }
                    sb.Append(DoubleArray[i]);
                }
                sb.Append(']');
                break;

            case XmlBinaryNodeType.GuidText:
            case XmlBinaryNodeType.GuidTextWithEndElement:
                for (int i = 0; i < GuidArray.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(", ");
                    }
                    sb.Append(GuidArray[i].ToString("B"));
                }
                sb.Append(']');
                break;

            case XmlBinaryNodeType.Int16Text:
            case XmlBinaryNodeType.Int16TextWithEndElement:
                for (int i = 0; i < ShortArray.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(',');
                    }
                    sb.Append(ShortArray[i]);
                }
                sb.Append(']');
                break;

            case XmlBinaryNodeType.Int32Text:
            case XmlBinaryNodeType.Int32TextWithEndElement:
                for (int i = 0; i < IntArray.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(',');
                    }
                    sb.Append(IntArray[i]);
                }
                sb.Append(']');
                break;

            case XmlBinaryNodeType.Int64Text:
            case XmlBinaryNodeType.Int64TextWithEndElement:
                for (int i = 0; i < LongArray.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(',');
                    }
                    sb.Append(LongArray[i]);
                }
                sb.Append(']');
                break;

            case XmlBinaryNodeType.FloatText:
            case XmlBinaryNodeType.FloatTextWithEndElement:
                for (int i = 0; i < FloatArray.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(", ");
                    }
                    sb.Append(FloatArray[i]);
                }
                sb.Append(']');
                break;

            case XmlBinaryNodeType.TimeSpanText:
            case XmlBinaryNodeType.TimeSpanTextWithEndElement:
                for (int i = 0; i < TimeSpanArray.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(", ");
                    }
                    sb.Append(TimeSpanArray[i]);
                }
                break;

            default:
                if (!allowInvalidNodeTypes)
                {
                    throw new Exception(
                              String.Format("Don't know how to work with type {0:X2} ({1})",
                                            nodeType, XmlBinaryNodeType.GetNodeName(nodeType)));
                }
                break;
            }
            return(sb.ToString());
        }
        public string ToString(IXmlDictionary staticDictionary, XmlBinaryReaderSession readerSession, bool printChildren)
        {
            StringBuilder sb          = new StringBuilder();
            int           actualDepth = depth;

            if (nodeType == XmlBinaryNodeType.EndElement)
            {
                actualDepth--;
            }
            string identString = "  ";

            if (printChildren)
            {
                for (int i = 0; i < actualDepth; i++)
                {
                    sb.Append(identString);
                }
            }

            sb.Append(XmlBinaryNodeType.GetNodeName(nodeType));
            switch (nodeType)
            {
            case XmlBinaryNodeType.EndElement:
                sb.Append(".");
                break;

            case XmlBinaryNodeType.ShortElement:
            case XmlBinaryNodeType.ShortDictionaryElement:
            case XmlBinaryNodeType.Element:
            case XmlBinaryNodeType.DictionaryElement:
            case XmlBinaryNodeType.PrefixElementA:
            case XmlBinaryNodeType.PrefixElementB:
            case XmlBinaryNodeType.PrefixElementC:
            case XmlBinaryNodeType.PrefixElementD:
            case XmlBinaryNodeType.PrefixElementE:
            case XmlBinaryNodeType.PrefixElementF:
            case XmlBinaryNodeType.PrefixElementG:
            case XmlBinaryNodeType.PrefixElementH:
            case XmlBinaryNodeType.PrefixElementI:
            case XmlBinaryNodeType.PrefixElementJ:
            case XmlBinaryNodeType.PrefixElementK:
            case XmlBinaryNodeType.PrefixElementL:
            case XmlBinaryNodeType.PrefixElementM:
            case XmlBinaryNodeType.PrefixElementN:
            case XmlBinaryNodeType.PrefixElementO:
            case XmlBinaryNodeType.PrefixElementP:
            case XmlBinaryNodeType.PrefixElementQ:
            case XmlBinaryNodeType.PrefixElementR:
            case XmlBinaryNodeType.PrefixElementS:
            case XmlBinaryNodeType.PrefixElementT:
            case XmlBinaryNodeType.PrefixElementU:
            case XmlBinaryNodeType.PrefixElementV:
            case XmlBinaryNodeType.PrefixElementW:
            case XmlBinaryNodeType.PrefixElementX:
            case XmlBinaryNodeType.PrefixElementY:
            case XmlBinaryNodeType.PrefixElementZ:
            case XmlBinaryNodeType.PrefixDictionaryElementA:
            case XmlBinaryNodeType.PrefixDictionaryElementB:
            case XmlBinaryNodeType.PrefixDictionaryElementC:
            case XmlBinaryNodeType.PrefixDictionaryElementD:
            case XmlBinaryNodeType.PrefixDictionaryElementE:
            case XmlBinaryNodeType.PrefixDictionaryElementF:
            case XmlBinaryNodeType.PrefixDictionaryElementG:
            case XmlBinaryNodeType.PrefixDictionaryElementH:
            case XmlBinaryNodeType.PrefixDictionaryElementI:
            case XmlBinaryNodeType.PrefixDictionaryElementJ:
            case XmlBinaryNodeType.PrefixDictionaryElementK:
            case XmlBinaryNodeType.PrefixDictionaryElementL:
            case XmlBinaryNodeType.PrefixDictionaryElementM:
            case XmlBinaryNodeType.PrefixDictionaryElementN:
            case XmlBinaryNodeType.PrefixDictionaryElementO:
            case XmlBinaryNodeType.PrefixDictionaryElementP:
            case XmlBinaryNodeType.PrefixDictionaryElementQ:
            case XmlBinaryNodeType.PrefixDictionaryElementR:
            case XmlBinaryNodeType.PrefixDictionaryElementS:
            case XmlBinaryNodeType.PrefixDictionaryElementT:
            case XmlBinaryNodeType.PrefixDictionaryElementU:
            case XmlBinaryNodeType.PrefixDictionaryElementV:
            case XmlBinaryNodeType.PrefixDictionaryElementW:
            case XmlBinaryNodeType.PrefixDictionaryElementX:
            case XmlBinaryNodeType.PrefixDictionaryElementY:
            case XmlBinaryNodeType.PrefixDictionaryElementZ:
                sb.Append(": ");
                if (this.Prefix != null && !XmlBinaryNodeType.IsPrefixNode(this.NodeType))
                {
                    sb.AppendFormat("{0}:", this.Prefix);
                }
                if (XmlBinaryNodeType.IsDictionaryElementNode(nodeType))
                {
                    this.ThrowIfMissingRequiredProperty("DictionaryLocalName", this.DictionaryLocalName);
                    string value = this.DictionaryLocalName.GetValue(staticDictionary, readerSession);
                    sb.AppendFormat("dict[key={0}{1}{2}]",
                                    this.DictionaryLocalName.DictionaryId,
                                    this.DictionaryLocalName.IsSession ? " (session)" : "",
                                    value == null ? "" : "value=" + value);
                }
                else
                {
                    this.ThrowIfMissingRequiredProperty("LocalName", this.LocalName);
                    sb.Append(this.LocalName);
                }
                break;

            case XmlBinaryNodeType.EmptyText:
            case XmlBinaryNodeType.EmptyTextWithEndElement:
            case XmlBinaryNodeType.ZeroText:
            case XmlBinaryNodeType.ZeroTextWithEndElement:
            case XmlBinaryNodeType.OneText:
            case XmlBinaryNodeType.OneTextWithEndElement:
            case XmlBinaryNodeType.FalseText:
            case XmlBinaryNodeType.FalseTextWithEndElement:
            case XmlBinaryNodeType.TrueText:
            case XmlBinaryNodeType.TrueTextWithEndElement:
            case XmlBinaryNodeType.Chars8Text:
            case XmlBinaryNodeType.Chars8TextWithEndElement:
            case XmlBinaryNodeType.Chars16Text:
            case XmlBinaryNodeType.Chars16TextWithEndElement:
            case XmlBinaryNodeType.Chars32Text:
            case XmlBinaryNodeType.Chars32TextWithEndElement:
            case XmlBinaryNodeType.UnicodeChars8Text:
            case XmlBinaryNodeType.UnicodeChars8TextWithEndElement:
            case XmlBinaryNodeType.UnicodeChars16Text:
            case XmlBinaryNodeType.UnicodeChars16TextWithEndElement:
            case XmlBinaryNodeType.UnicodeChars32Text:
            case XmlBinaryNodeType.UnicodeChars32TextWithEndElement:
            case XmlBinaryNodeType.Comment:
                this.ThrowIfMissingRequiredProperty("Text", this.Text);
                sb.AppendFormat(" (length={0}): \"{1}\"", this.Text.Length, this.Text);
                break;

            case XmlBinaryNodeType.DictionaryText:
            case XmlBinaryNodeType.DictionaryTextWithEndElement:
                this.ThrowIfMissingRequiredProperty("DictionaryText", this.DictionaryText);
                string dicTextValue = this.DictionaryText.GetValue(staticDictionary, readerSession);
                sb.AppendFormat(": dict[key={0}{1}{2}]",
                                this.DictionaryText.DictionaryId,
                                this.DictionaryText.IsSession ? "(session)" : "",
                                dicTextValue == null ? "" : ",value=\"" + dicTextValue + "\"");
                break;

            case XmlBinaryNodeType.Int8Text:
            case XmlBinaryNodeType.Int8TextWithEndElement:
            case XmlBinaryNodeType.Int16Text:
            case XmlBinaryNodeType.Int16TextWithEndElement:
            case XmlBinaryNodeType.Int32Text:
            case XmlBinaryNodeType.Int32TextWithEndElement:
                sb.AppendFormat(": {0}", this.IntValue);
                break;

            case XmlBinaryNodeType.Int64Text:
            case XmlBinaryNodeType.Int64TextWithEndElement:
                sb.AppendFormat(": {0}", this.LongValue);
                break;

            case XmlBinaryNodeType.UInt64Text:
            case XmlBinaryNodeType.UInt64TextWithEndElement:
                sb.AppendFormat(": {0}", (ulong)this.LongValue);
                break;

            case XmlBinaryNodeType.FloatText:
            case XmlBinaryNodeType.FloatTextWithEndElement:
                sb.AppendFormat(": {0}", this.FloatValue);
                break;

            case XmlBinaryNodeType.DoubleText:
            case XmlBinaryNodeType.DoubleTextWithEndElement:
                sb.AppendFormat(": {0}", this.DoubleValue);
                break;

            case XmlBinaryNodeType.DecimalText:
            case XmlBinaryNodeType.DecimalTextWithEndElement:
                sb.AppendFormat(": {0}", this.DecimalValue);
                break;

            case XmlBinaryNodeType.DateTimeText:
            case XmlBinaryNodeType.DateTimeTextWithEndElement:
                sb.AppendFormat(": {0} ({1})", this.DateTimeValue, this.DateTimeValue.Kind);
                break;

            case XmlBinaryNodeType.TimeSpanText:
            case XmlBinaryNodeType.TimeSpanTextWithEndElement:
                sb.AppendFormat(": {0}", this.TimeSpanValue);
                break;

            case XmlBinaryNodeType.Bytes8Text:
            case XmlBinaryNodeType.Bytes8TextWithEndElement:
            case XmlBinaryNodeType.Bytes16Text:
            case XmlBinaryNodeType.Bytes16TextWithEndElement:
            case XmlBinaryNodeType.Bytes32Text:
            case XmlBinaryNodeType.Bytes32TextWithEndElement:
                this.ThrowIfMissingRequiredProperty("Bytes", this.Bytes);
                sb.AppendFormat(" (size={0}): ", this.Bytes.Length);
                sb.Append('{');
                for (int i = 0; i < this.Bytes.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(',');
                    }
                    sb.AppendFormat("{0:X2}", this.Bytes[i]);
                }
                sb.Append('}');
                break;

            case XmlBinaryNodeType.GuidText:
            case XmlBinaryNodeType.GuidTextWithEndElement:
                sb.Append(": ");
                sb.Append(this.GuidValue.ToString("B"));
                break;

            case XmlBinaryNodeType.UniqueIdText:
            case XmlBinaryNodeType.UniqueIdTextWithEndElement:
                sb.Append(": ");
                this.ThrowIfMissingRequiredProperty("UniqueIdValue", this.UniqueIdValue);
                sb.Append(this.UniqueIdValue.ToString());
                break;

            case XmlBinaryNodeType.ShortAttribute:
            case XmlBinaryNodeType.ShortDictionaryAttribute:
            case XmlBinaryNodeType.Attribute:
            case XmlBinaryNodeType.DictionaryAttribute:
            case XmlBinaryNodeType.PrefixAttributeA:
            case XmlBinaryNodeType.PrefixAttributeB:
            case XmlBinaryNodeType.PrefixAttributeC:
            case XmlBinaryNodeType.PrefixAttributeD:
            case XmlBinaryNodeType.PrefixAttributeE:
            case XmlBinaryNodeType.PrefixAttributeF:
            case XmlBinaryNodeType.PrefixAttributeG:
            case XmlBinaryNodeType.PrefixAttributeH:
            case XmlBinaryNodeType.PrefixAttributeI:
            case XmlBinaryNodeType.PrefixAttributeJ:
            case XmlBinaryNodeType.PrefixAttributeK:
            case XmlBinaryNodeType.PrefixAttributeL:
            case XmlBinaryNodeType.PrefixAttributeM:
            case XmlBinaryNodeType.PrefixAttributeN:
            case XmlBinaryNodeType.PrefixAttributeO:
            case XmlBinaryNodeType.PrefixAttributeP:
            case XmlBinaryNodeType.PrefixAttributeQ:
            case XmlBinaryNodeType.PrefixAttributeR:
            case XmlBinaryNodeType.PrefixAttributeS:
            case XmlBinaryNodeType.PrefixAttributeT:
            case XmlBinaryNodeType.PrefixAttributeU:
            case XmlBinaryNodeType.PrefixAttributeV:
            case XmlBinaryNodeType.PrefixAttributeW:
            case XmlBinaryNodeType.PrefixAttributeX:
            case XmlBinaryNodeType.PrefixAttributeY:
            case XmlBinaryNodeType.PrefixAttributeZ:
            case XmlBinaryNodeType.PrefixDictionaryAttributeA:
            case XmlBinaryNodeType.PrefixDictionaryAttributeB:
            case XmlBinaryNodeType.PrefixDictionaryAttributeC:
            case XmlBinaryNodeType.PrefixDictionaryAttributeD:
            case XmlBinaryNodeType.PrefixDictionaryAttributeE:
            case XmlBinaryNodeType.PrefixDictionaryAttributeF:
            case XmlBinaryNodeType.PrefixDictionaryAttributeG:
            case XmlBinaryNodeType.PrefixDictionaryAttributeH:
            case XmlBinaryNodeType.PrefixDictionaryAttributeI:
            case XmlBinaryNodeType.PrefixDictionaryAttributeJ:
            case XmlBinaryNodeType.PrefixDictionaryAttributeK:
            case XmlBinaryNodeType.PrefixDictionaryAttributeL:
            case XmlBinaryNodeType.PrefixDictionaryAttributeM:
            case XmlBinaryNodeType.PrefixDictionaryAttributeN:
            case XmlBinaryNodeType.PrefixDictionaryAttributeO:
            case XmlBinaryNodeType.PrefixDictionaryAttributeP:
            case XmlBinaryNodeType.PrefixDictionaryAttributeQ:
            case XmlBinaryNodeType.PrefixDictionaryAttributeR:
            case XmlBinaryNodeType.PrefixDictionaryAttributeS:
            case XmlBinaryNodeType.PrefixDictionaryAttributeT:
            case XmlBinaryNodeType.PrefixDictionaryAttributeU:
            case XmlBinaryNodeType.PrefixDictionaryAttributeV:
            case XmlBinaryNodeType.PrefixDictionaryAttributeW:
            case XmlBinaryNodeType.PrefixDictionaryAttributeX:
            case XmlBinaryNodeType.PrefixDictionaryAttributeY:
            case XmlBinaryNodeType.PrefixDictionaryAttributeZ:
                sb.Append(": ");
                if (this.Prefix != null && !XmlBinaryNodeType.IsPrefixNode(this.NodeType))
                {
                    sb.AppendFormat("{0}:", this.Prefix);
                }
                if (XmlBinaryNodeType.IsDictionaryAttributeNode(nodeType))
                {
                    this.ThrowIfMissingRequiredProperty("DictionaryLocalName", this.DictionaryLocalName);
                    string prefixDictAttrValue = this.DictionaryLocalName.GetValue(staticDictionary, readerSession);
                    sb.AppendFormat("dict[key={0}{1}{2}]",
                                    this.DictionaryLocalName.DictionaryId,
                                    this.DictionaryLocalName.IsSession ? "(session)" : "",
                                    prefixDictAttrValue == null ? "" : ",value=" + prefixDictAttrValue);
                }
                else
                {
                    this.ThrowIfMissingRequiredProperty("LocalName", this.LocalName);
                    sb.Append(this.LocalName);
                }
                break;

            case XmlBinaryNodeType.ShortXmlnsAttribute:
            case XmlBinaryNodeType.XmlnsAttribute:
            case XmlBinaryNodeType.ShortDictionaryXmlnsAttribute:
            case XmlBinaryNodeType.DictionaryXmlnsAttribute:
                sb.Append(": xmlns");
                if (this.Prefix != null)
                {
                    sb.Append(':');
                    sb.Append(this.Prefix);
                }
                sb.Append('=');
                if (XmlBinaryNodeType.IsDictionaryAttributeNode(nodeType))
                {
                    this.ThrowIfMissingRequiredProperty("DictionaryNamespaceURI", this.DictionaryNamespaceURI);
                    string namespaceUriDictValue = this.DictionaryNamespaceURI.GetValue(staticDictionary, readerSession);
                    sb.AppendFormat("dict[key={0}{1}{2}]",
                                    this.DictionaryNamespaceURI.DictionaryId,
                                    this.DictionaryNamespaceURI.IsSession ? "(session)" : "",
                                    namespaceUriDictValue == null ? "" : ",value=" + namespaceUriDictValue);
                }
                else
                {
                    sb.AppendFormat("\"{0}\"", this.NamespaceURI);
                }
                break;

            case XmlBinaryNodeType.Array:
                sb.Append(':');
                if (printChildren)
                {
                    sb.Append(Environment.NewLine);
                    sb.Append(this.Children[0].ToString(staticDictionary, readerSession));     // element node
                    for (int i = 0; i < this.Children[0].Depth; i++)
                    {
                        sb.Append(identString);
                    }
                    sb.Append(this.ArrayElements.ToString());
                    sb.Append(Environment.NewLine);
                    if (this.Children.Count > 1)      // also has an EndElement node
                    {
                        sb.Append(this.Children[1].ToString(staticDictionary, readerSession));
                    }
                }
                break;

            case XmlBinaryNodeType.StartListText:
            case XmlBinaryNodeType.StartListTextWithEndElement:
                sb.Append(":");
                break;

            case XmlBinaryNodeType.EndListText:
            case XmlBinaryNodeType.EndListTextWithEndElement:
                sb.Append(".");
                break;

            default:
                throw new ArgumentException(String.Format("Error, the code is not ready to handle the type {0:X2} ({1}) yet", nodeType, XmlBinaryNodeType.GetNodeName(nodeType)));
            }

            if (nodeType != XmlBinaryNodeType.Array) // already taken care of
            {
                if (printChildren)
                {
                    sb.Append(Environment.NewLine);
                    for (int i = 0; i < children.Count; i++)
                    {
                        sb.Append(children[i].ToString(staticDictionary, readerSession));
                    }
                }
            }

            return(sb.ToString());
        }
        private void ParseArray(XmlBinaryNode parent)
        {
            Parse(ref parent, false, true);
            if ((offset + 1) >= xmlDoc.Length)
            {
                ThrowOffsetException("Inside array");
            }
            byte arrayNodeType = xmlDoc[offset];

            offset++;
            int elementCount = ReadMB32();

            parent.ArrayElements = new BinaryArrayElements(arrayNodeType, elementCount);
            for (int i = 0; i < elementCount; i++)
            {
                switch (arrayNodeType)
                {
                case XmlBinaryNodeType.BoolTextWithEndElement:
                    if (i == 0)
                    {
                        parent.ArrayElements.BoolArray = new bool[elementCount];
                    }
                    if (offset >= xmlDoc.Length)
                    {
                        ThrowOffsetException("Error in BoolArray");
                    }
                    parent.ArrayElements.BoolArray[i] = (xmlDoc[offset] != 0x00);
                    offset++;
                    break;

                case XmlBinaryNodeType.DateTimeTextWithEndElement:
                    if (i == 0)
                    {
                        parent.ArrayElements.DateTimeArray = new DateTime[elementCount];
                    }
                    parent.ArrayElements.DateTimeArray[i] = ReadDateTime();
                    break;

                case XmlBinaryNodeType.DecimalTextWithEndElement:
                    if (i == 0)
                    {
                        parent.ArrayElements.DecimalArray = new decimal[elementCount];
                    }
                    parent.ArrayElements.DecimalArray[i] = ReadDecimal();
                    break;

                case XmlBinaryNodeType.DoubleTextWithEndElement:
                    if (i == 0)
                    {
                        parent.ArrayElements.DoubleArray = new double[elementCount];
                    }
                    parent.ArrayElements.DoubleArray[i] = ReadDouble();
                    break;

                case XmlBinaryNodeType.GuidTextWithEndElement:
                    if (i == 0)
                    {
                        parent.ArrayElements.GuidArray = new Guid[elementCount];
                    }
                    parent.ArrayElements.GuidArray[i] = ReadGuid();
                    break;

                case XmlBinaryNodeType.Int16TextWithEndElement:
                    if (i == 0)
                    {
                        parent.ArrayElements.ShortArray = new short[elementCount];
                    }
                    parent.ArrayElements.ShortArray[i] = (short)ReadInt(2);
                    break;

                case XmlBinaryNodeType.Int32TextWithEndElement:
                    if (i == 0)
                    {
                        parent.ArrayElements.IntArray = new int[elementCount];
                    }
                    parent.ArrayElements.IntArray[i] = ReadInt(4);
                    break;

                case XmlBinaryNodeType.Int64TextWithEndElement:
                    if (i == 0)
                    {
                        parent.ArrayElements.LongArray = new long[elementCount];
                    }
                    parent.ArrayElements.LongArray[i] = ReadLong();
                    break;

                case XmlBinaryNodeType.FloatTextWithEndElement:
                    if (i == 0)
                    {
                        parent.ArrayElements.FloatArray = new float[elementCount];
                    }
                    parent.ArrayElements.FloatArray[i] = ReadFloat();
                    break;

                case XmlBinaryNodeType.TimeSpanTextWithEndElement:
                    if (i == 0)
                    {
                        parent.ArrayElements.TimeSpanArray = new TimeSpan[elementCount];
                    }
                    parent.ArrayElements.TimeSpanArray[i] = TimeSpan.FromTicks(ReadLong());
                    break;

                default:
                    throw new ArgumentException(String.Format("Invalid array node type: {0:X2} - {1}",
                                                              arrayNodeType, XmlBinaryNodeType.GetNodeName(arrayNodeType)));
                }
            }
            if (XmlBinaryNodeType.IsTextNodeWithEndElement(arrayNodeType))
            {
                depth--;
            }
        }
        private void Parse(ref XmlBinaryNode parent, bool insideAttribute, bool insideArray)
        {
            if (offset >= xmlDoc.Length)
            {
                return;
            }
            bool first = true;

            while (offset < xmlDoc.Length)
            {
                if (!first && insideAttribute)
                {
                    return;
                }
                first = false;
                byte nodeType = xmlDoc[offset];
                if (XmlBinaryNodeType.IsTextNode(nodeType) || XmlBinaryNodeType.IsTextNodeWithEndElement(nodeType))
                {
                    ParseContentNode(parent);
                    if (XmlBinaryNodeType.IsTextNodeWithEndElement(nodeType))
                    {
                        depth--;
                        return;
                    }
                }
                else
                {
                    offset++;
                    XmlBinaryNode newNode = new XmlBinaryNode(nodeType, depth);
                    if (parent == null)
                    {
                        parent = newNode;
                    }
                    else
                    {
                        parent.AddChild(newNode);
                    }
                    switch (nodeType)
                    {
                    case XmlBinaryNodeType.EndElement:
                        depth--;
                        return;

                    case XmlBinaryNodeType.Comment:
                        newNode.Text = ReadString(0);
                        break;

                    case XmlBinaryNodeType.ShortElement:
                    case XmlBinaryNodeType.ShortDictionaryElement:
                    case XmlBinaryNodeType.Element:
                    case XmlBinaryNodeType.DictionaryElement:
                    {
                        bool isDictionaryElement = XmlBinaryNodeType.IsDictionaryElementNode(nodeType);
                        bool isShortElement      = XmlBinaryNodeType.GetNodeName(nodeType).StartsWith("Short");
                        if (!isShortElement)
                        {
                            newNode.Prefix = ReadString(0);
                        }
                        if (isDictionaryElement)
                        {
                            newNode.DictionaryLocalName = ReadDictionaryString();
                        }
                        else
                        {
                            newNode.LocalName = ReadString(0);
                        }
                        int oldDepth = depth;
                        depth++;
                        Parse(ref newNode);
                        if (depth != oldDepth)
                        {
                            ThrowIncorrectDepthException("After " + XmlBinaryNodeType.GetNodeName(nodeType), oldDepth);
                        }
                        if (insideArray)
                        {
                            return;
                        }
                    }
                    break;

                    case XmlBinaryNodeType.PrefixElementA:
                    case XmlBinaryNodeType.PrefixElementB:
                    case XmlBinaryNodeType.PrefixElementC:
                    case XmlBinaryNodeType.PrefixElementD:
                    case XmlBinaryNodeType.PrefixElementE:
                    case XmlBinaryNodeType.PrefixElementF:
                    case XmlBinaryNodeType.PrefixElementG:
                    case XmlBinaryNodeType.PrefixElementH:
                    case XmlBinaryNodeType.PrefixElementI:
                    case XmlBinaryNodeType.PrefixElementJ:
                    case XmlBinaryNodeType.PrefixElementK:
                    case XmlBinaryNodeType.PrefixElementL:
                    case XmlBinaryNodeType.PrefixElementM:
                    case XmlBinaryNodeType.PrefixElementN:
                    case XmlBinaryNodeType.PrefixElementO:
                    case XmlBinaryNodeType.PrefixElementP:
                    case XmlBinaryNodeType.PrefixElementQ:
                    case XmlBinaryNodeType.PrefixElementR:
                    case XmlBinaryNodeType.PrefixElementS:
                    case XmlBinaryNodeType.PrefixElementT:
                    case XmlBinaryNodeType.PrefixElementU:
                    case XmlBinaryNodeType.PrefixElementV:
                    case XmlBinaryNodeType.PrefixElementW:
                    case XmlBinaryNodeType.PrefixElementX:
                    case XmlBinaryNodeType.PrefixElementY:
                    case XmlBinaryNodeType.PrefixElementZ:
                    case XmlBinaryNodeType.PrefixDictionaryElementA:
                    case XmlBinaryNodeType.PrefixDictionaryElementB:
                    case XmlBinaryNodeType.PrefixDictionaryElementC:
                    case XmlBinaryNodeType.PrefixDictionaryElementD:
                    case XmlBinaryNodeType.PrefixDictionaryElementE:
                    case XmlBinaryNodeType.PrefixDictionaryElementF:
                    case XmlBinaryNodeType.PrefixDictionaryElementG:
                    case XmlBinaryNodeType.PrefixDictionaryElementH:
                    case XmlBinaryNodeType.PrefixDictionaryElementI:
                    case XmlBinaryNodeType.PrefixDictionaryElementJ:
                    case XmlBinaryNodeType.PrefixDictionaryElementK:
                    case XmlBinaryNodeType.PrefixDictionaryElementL:
                    case XmlBinaryNodeType.PrefixDictionaryElementM:
                    case XmlBinaryNodeType.PrefixDictionaryElementN:
                    case XmlBinaryNodeType.PrefixDictionaryElementO:
                    case XmlBinaryNodeType.PrefixDictionaryElementP:
                    case XmlBinaryNodeType.PrefixDictionaryElementQ:
                    case XmlBinaryNodeType.PrefixDictionaryElementR:
                    case XmlBinaryNodeType.PrefixDictionaryElementS:
                    case XmlBinaryNodeType.PrefixDictionaryElementT:
                    case XmlBinaryNodeType.PrefixDictionaryElementU:
                    case XmlBinaryNodeType.PrefixDictionaryElementV:
                    case XmlBinaryNodeType.PrefixDictionaryElementW:
                    case XmlBinaryNodeType.PrefixDictionaryElementX:
                    case XmlBinaryNodeType.PrefixDictionaryElementY:
                    case XmlBinaryNodeType.PrefixDictionaryElementZ:
                    {
                        char prefixLetter;
                        bool isDictionaryElement = XmlBinaryNodeType.IsDictionaryElementNode(nodeType);
                        prefixLetter   = (char)((int)'a' + (int)nodeType - (int)(isDictionaryElement ? XmlBinaryNodeType.PrefixDictionaryElementA : XmlBinaryNodeType.PrefixElementA));
                        newNode.Prefix = new string(prefixLetter, 1);
                        if (isDictionaryElement)
                        {
                            newNode.DictionaryLocalName = ReadDictionaryString();
                        }
                        else
                        {
                            newNode.LocalName = ReadString(0);
                        }
                        int oldDepth = depth;
                        depth++;
                        Parse(ref newNode);
                        if (depth != oldDepth)
                        {
                            ThrowIncorrectDepthException("After " + XmlBinaryNodeType.GetNodeName(nodeType), oldDepth);
                        }
                        if (insideArray)
                        {
                            return;
                        }
                    }
                    break;

                    case XmlBinaryNodeType.ShortAttribute:
                    case XmlBinaryNodeType.ShortDictionaryAttribute:
                    case XmlBinaryNodeType.Attribute:
                    case XmlBinaryNodeType.DictionaryAttribute:
                    {
                        bool isDictionaryAttribute = XmlBinaryNodeType.IsDictionaryAttributeNode(nodeType);
                        bool isShortAttribute      = XmlBinaryNodeType.GetNodeName(nodeType).StartsWith("Short");
                        if (!isShortAttribute)
                        {
                            newNode.Prefix = ReadString(0);
                        }
                        if (isDictionaryAttribute)
                        {
                            newNode.DictionaryLocalName = ReadDictionaryString();
                        }
                        else
                        {
                            newNode.LocalName = ReadString(0);
                        }
                        int oldDepth = depth;
                        depth++;
                        Parse(ref newNode, true);
                        if (depth != (oldDepth + 1))
                        {
                            ThrowIncorrectDepthException("After " + XmlBinaryNodeType.GetNodeName(nodeType), oldDepth);
                        }
                        depth--;
                        if (newNode.Children.Count != 1)
                        {
                            throw new ArgumentException("Error, attribute nodes must have exactly one child, at offset " + offset);
                        }
                    }
                    break;

                    case XmlBinaryNodeType.ShortXmlnsAttribute:
                    case XmlBinaryNodeType.ShortDictionaryXmlnsAttribute:
                    case XmlBinaryNodeType.XmlnsAttribute:
                    case XmlBinaryNodeType.DictionaryXmlnsAttribute:
                    {
                        bool isDictionaryAttribute = XmlBinaryNodeType.IsDictionaryAttributeNode(nodeType);
                        bool isShortAttribute      = XmlBinaryNodeType.GetNodeName(nodeType).StartsWith("Short");
                        if (!isShortAttribute)
                        {
                            newNode.Prefix = ReadString(0);
                        }
                        if (isDictionaryAttribute)
                        {
                            newNode.DictionaryNamespaceURI = ReadDictionaryString();
                        }
                        else
                        {
                            newNode.NamespaceURI = ReadString(0);
                        }
                    }
                    break;

                    case XmlBinaryNodeType.PrefixAttributeA:
                    case XmlBinaryNodeType.PrefixAttributeB:
                    case XmlBinaryNodeType.PrefixAttributeC:
                    case XmlBinaryNodeType.PrefixAttributeD:
                    case XmlBinaryNodeType.PrefixAttributeE:
                    case XmlBinaryNodeType.PrefixAttributeF:
                    case XmlBinaryNodeType.PrefixAttributeG:
                    case XmlBinaryNodeType.PrefixAttributeH:
                    case XmlBinaryNodeType.PrefixAttributeI:
                    case XmlBinaryNodeType.PrefixAttributeJ:
                    case XmlBinaryNodeType.PrefixAttributeK:
                    case XmlBinaryNodeType.PrefixAttributeL:
                    case XmlBinaryNodeType.PrefixAttributeM:
                    case XmlBinaryNodeType.PrefixAttributeN:
                    case XmlBinaryNodeType.PrefixAttributeO:
                    case XmlBinaryNodeType.PrefixAttributeP:
                    case XmlBinaryNodeType.PrefixAttributeQ:
                    case XmlBinaryNodeType.PrefixAttributeR:
                    case XmlBinaryNodeType.PrefixAttributeS:
                    case XmlBinaryNodeType.PrefixAttributeT:
                    case XmlBinaryNodeType.PrefixAttributeU:
                    case XmlBinaryNodeType.PrefixAttributeV:
                    case XmlBinaryNodeType.PrefixAttributeW:
                    case XmlBinaryNodeType.PrefixAttributeX:
                    case XmlBinaryNodeType.PrefixAttributeY:
                    case XmlBinaryNodeType.PrefixAttributeZ:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeA:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeB:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeC:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeD:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeE:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeF:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeG:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeH:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeI:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeJ:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeK:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeL:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeM:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeN:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeO:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeP:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeQ:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeR:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeS:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeT:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeU:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeV:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeW:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeX:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeY:
                    case XmlBinaryNodeType.PrefixDictionaryAttributeZ:
                    {
                        char prefixLetter;
                        bool isDictionaryAttribute = XmlBinaryNodeType.IsDictionaryAttributeNode(nodeType);
                        prefixLetter   = (char)((int)'a' + (int)nodeType - (int)(isDictionaryAttribute ? XmlBinaryNodeType.PrefixDictionaryAttributeA : XmlBinaryNodeType.PrefixAttributeA));
                        newNode.Prefix = new string(prefixLetter, 1);
                        if (isDictionaryAttribute)
                        {
                            newNode.DictionaryLocalName = ReadDictionaryString();
                        }
                        else
                        {
                            newNode.LocalName = ReadString(0);
                        }
                        int oldDepth = depth;
                        depth++;
                        Parse(ref newNode, true);
                        if (depth != (oldDepth + 1))
                        {
                            ThrowIncorrectDepthException("After " + XmlBinaryNodeType.GetNodeName(nodeType), oldDepth);
                        }
                        depth--;
                        if (newNode.Children.Count != 1)
                        {
                            throw new ArgumentException("Error, attribute nodes must have exactly one child, at offset " + offset);
                        }
                    }
                    break;

                    case XmlBinaryNodeType.Array:
                    {
                        int oldDepth = depth;
                        depth++;
                        ParseArray(newNode);
                        if (depth != oldDepth)
                        {
                            ThrowIncorrectDepthException("After " + XmlBinaryNodeType.GetNodeName(nodeType), oldDepth);
                        }
                    }
                    break;

                    default:
                        throw new ArgumentException(String.Format("Error, the test is not ready to handle the type {0:X2} ({1}) yet", nodeType, XmlBinaryNodeType.GetNodeName(nodeType)));
                    }
                }
            }
        }
        private void ParseContentNode(XmlBinaryNode parent)
        {
            byte nodeType = xmlDoc[offset];

            offset++;
            XmlBinaryNode newNode = new XmlBinaryNode(nodeType, depth);

            parent.AddChild(newNode);
            switch (nodeType)
            {
            case XmlBinaryNodeType.Chars8Text:
            case XmlBinaryNodeType.Chars8TextWithEndElement:
                newNode.Text = ReadString(8);
                break;

            case XmlBinaryNodeType.Chars16Text:
            case XmlBinaryNodeType.Chars16TextWithEndElement:
                newNode.Text = ReadString(16);
                break;

            case XmlBinaryNodeType.Chars32Text:
            case XmlBinaryNodeType.Chars32TextWithEndElement:
                newNode.Text = ReadString(32);
                break;

            case XmlBinaryNodeType.UnicodeChars8Text:
            case XmlBinaryNodeType.UnicodeChars8TextWithEndElement:
            case XmlBinaryNodeType.UnicodeChars16Text:
            case XmlBinaryNodeType.UnicodeChars16TextWithEndElement:
            case XmlBinaryNodeType.UnicodeChars32Text:
            case XmlBinaryNodeType.UnicodeChars32TextWithEndElement:
            {
                int unicodeTextLenSize = 0;
                switch (nodeType)
                {
                case XmlBinaryNodeType.UnicodeChars8Text:
                case XmlBinaryNodeType.UnicodeChars8TextWithEndElement:
                    unicodeTextLenSize = 1;
                    break;

                case XmlBinaryNodeType.UnicodeChars16Text:
                case XmlBinaryNodeType.UnicodeChars16TextWithEndElement:
                    unicodeTextLenSize = 2;
                    break;

                case XmlBinaryNodeType.UnicodeChars32Text:
                case XmlBinaryNodeType.UnicodeChars32TextWithEndElement:
                    unicodeTextLenSize = 4;
                    break;
                }
                int unicodeTextLength = ReadInt(unicodeTextLenSize);
                if ((offset + unicodeTextLength) > xmlDoc.Length)
                {
                    ThrowOffsetException("Error reading UnicodeCharsXText");
                }
                byte[] temp = new byte[unicodeTextLength];
                Buffer.BlockCopy(xmlDoc, offset, temp, 0, unicodeTextLength);
                newNode.Text = unicodeEncoding.GetString(temp, 0, temp.Length);
                offset      += unicodeTextLength;
            }
            break;

            case XmlBinaryNodeType.Bytes8Text:
            case XmlBinaryNodeType.Bytes8TextWithEndElement:
            case XmlBinaryNodeType.Bytes16Text:
            case XmlBinaryNodeType.Bytes16TextWithEndElement:
            case XmlBinaryNodeType.Bytes32Text:
            case XmlBinaryNodeType.Bytes32TextWithEndElement:
            {
                int byteArrayLenSize = 0;
                switch (nodeType)
                {
                case XmlBinaryNodeType.Bytes8Text:
                case XmlBinaryNodeType.Bytes8TextWithEndElement:
                    byteArrayLenSize = 1;
                    break;

                case XmlBinaryNodeType.Bytes16Text:
                case XmlBinaryNodeType.Bytes16TextWithEndElement:
                    byteArrayLenSize = 2;
                    break;

                case XmlBinaryNodeType.Bytes32Text:
                case XmlBinaryNodeType.Bytes32TextWithEndElement:
                    byteArrayLenSize = 4;
                    break;
                }
                int byteArrayLength = ReadInt(byteArrayLenSize);
                if ((offset + byteArrayLength) > xmlDoc.Length)
                {
                    ThrowOffsetException("Error reading BytesXText");
                }
                newNode.Bytes = new byte[byteArrayLength];
                Buffer.BlockCopy(xmlDoc, offset, newNode.Bytes, 0, byteArrayLength);
                offset += byteArrayLength;
            }
            break;

            case XmlBinaryNodeType.Int8Text:
            case XmlBinaryNodeType.Int8TextWithEndElement:
                newNode.IntValue = ReadInt(1);
                break;

            case XmlBinaryNodeType.Int16Text:
            case XmlBinaryNodeType.Int16TextWithEndElement:
                newNode.IntValue = ReadInt(2);
                break;

            case XmlBinaryNodeType.Int32Text:
            case XmlBinaryNodeType.Int32TextWithEndElement:
                newNode.IntValue = ReadInt(4);
                break;

            case XmlBinaryNodeType.Int64Text:
            case XmlBinaryNodeType.Int64TextWithEndElement:
            case XmlBinaryNodeType.UInt64Text:
            case XmlBinaryNodeType.UInt64TextWithEndElement:
                newNode.LongValue = ReadLong();
                break;

            case XmlBinaryNodeType.FloatText:
            case XmlBinaryNodeType.FloatTextWithEndElement:
                newNode.FloatValue = ReadFloat();
                break;

            case XmlBinaryNodeType.DoubleText:
            case XmlBinaryNodeType.DoubleTextWithEndElement:
                newNode.DoubleValue = ReadDouble();
                break;

            case XmlBinaryNodeType.DecimalText:
            case XmlBinaryNodeType.DecimalTextWithEndElement:
                newNode.DecimalValue = ReadDecimal();
                break;

            case XmlBinaryNodeType.DateTimeText:
            case XmlBinaryNodeType.DateTimeTextWithEndElement:
                newNode.DateTimeValue = ReadDateTime();
                break;

            case XmlBinaryNodeType.TimeSpanText:
            case XmlBinaryNodeType.TimeSpanTextWithEndElement:
                newNode.TimeSpanValue = TimeSpan.FromTicks(ReadLong());
                break;

            case XmlBinaryNodeType.EmptyText:
            case XmlBinaryNodeType.EmptyTextWithEndElement:
                newNode.Text = "";
                break;

            case XmlBinaryNodeType.ZeroText:
            case XmlBinaryNodeType.ZeroTextWithEndElement:
                newNode.Text = "0";
                break;

            case XmlBinaryNodeType.OneText:
            case XmlBinaryNodeType.OneTextWithEndElement:
                newNode.Text = "1";
                break;

            case XmlBinaryNodeType.TrueText:
            case XmlBinaryNodeType.TrueTextWithEndElement:
                newNode.Text = "true";
                break;

            case XmlBinaryNodeType.FalseText:
            case XmlBinaryNodeType.FalseTextWithEndElement:
                newNode.Text = "false";
                break;

            case XmlBinaryNodeType.DictionaryText:
            case XmlBinaryNodeType.DictionaryTextWithEndElement:
                newNode.DictionaryText = ReadDictionaryString();
                break;

            case XmlBinaryNodeType.GuidText:
            case XmlBinaryNodeType.GuidTextWithEndElement:
                newNode.GuidValue = ReadGuid();
                break;

            case XmlBinaryNodeType.UniqueIdText:
            case XmlBinaryNodeType.UniqueIdTextWithEndElement:
            {
                byte[] uniqueIdBytes = new byte[16];
                if ((offset + uniqueIdBytes.Length) > xmlDoc.Length)
                {
                    ThrowOffsetException("Error reading UniqueId");
                }
                Buffer.BlockCopy(xmlDoc, offset, uniqueIdBytes, 0, uniqueIdBytes.Length);
                newNode.UniqueIdValue = new UniqueId(uniqueIdBytes);
                offset += uniqueIdBytes.Length;
            }
            break;

            case XmlBinaryNodeType.StartListTextWithEndElement:
                throw new ArgumentException("StartListTextWithEndElement is an invalid node!");

            case XmlBinaryNodeType.StartListText:
            {
                depth++;
                ParseList(newNode);
                depth--;
            }
            break;

            default:
                throw new ArgumentException(String.Format("Error, the test is not ready to handle the type {0:X2} ({1}) yet", nodeType, XmlBinaryNodeType.GetNodeName(nodeType)));
            }
        }