private static ObjectPart ParseRootPart(XmlTextReader reader, ObjectGroup group, UGUI currentOwner, XmlDeserializationOptions options)
        {
            ObjectPart rootPart = null;

            if (reader.IsEmptyElement)
            {
                throw new InvalidObjectXmlException();
            }
            for (; ;)
            {
                if (!reader.Read())
                {
                    throw new InvalidObjectXmlException();
                }

                string nodeName       = reader.Name;
                bool   isEmptyElement = reader.IsEmptyElement;

                switch (reader.NodeType)
                {
                case XmlNodeType.Element:
                    switch (nodeName)
                    {
                    case "SceneObjectPart":
                        if (rootPart != null)
                        {
                            throw new InvalidObjectXmlException();
                        }
                        if (isEmptyElement)
                        {
                            throw new InvalidObjectXmlException();
                        }
                        if (rootPart != null)
                        {
                            throw new InvalidObjectXmlException();
                        }
                        rootPart = ObjectPart.FromXml(reader, group, currentOwner, options);
                        group.Add(LINK_ROOT, rootPart.ID, rootPart);
                        break;

                    default:
                        reader.ReadToEndElement();
                        break;
                    }
                    break;

                case XmlNodeType.EndElement:
                    if (nodeName != "RootPart")
                    {
                        throw new InvalidObjectXmlException();
                    }
                    return(rootPart);

                default:
                    break;
                }
            }
        }
        public static ObjectGroup FromXml(XmlTextReader reader, UGUI currentOwner, bool inRootPart = false, XmlDeserializationOptions options = XmlDeserializationOptions.None)
        {
            var        group    = new ObjectGroup();
            ObjectPart rootPart = null;

            if (reader.IsEmptyElement)
            {
                throw new InvalidObjectXmlException();
            }

            for (; ;)
            {
                if (inRootPart)
                {
                    inRootPart = false;
                }
                else if (!reader.Read())
                {
                    throw new InvalidObjectXmlException();
                }

                bool   isEmptyElement = reader.IsEmptyElement;
                string nodeName       = reader.Name;
                switch (reader.NodeType)
                {
                case XmlNodeType.Element:
                    switch (nodeName)
                    {
                    case "RootPart":
                        if (isEmptyElement)
                        {
                            throw new InvalidObjectXmlException();
                        }
                        if (rootPart != null)
                        {
                            throw new InvalidObjectXmlException();
                        }
                        rootPart = ParseRootPart(reader, group, currentOwner, options);
                        break;

                    case "SceneObjectPart":
                        if (rootPart != null)
                        {
                            throw new InvalidObjectXmlException();
                        }
                        if (isEmptyElement)
                        {
                            throw new InvalidObjectXmlException();
                        }
                        if (rootPart != null)
                        {
                            throw new InvalidObjectXmlException();
                        }
                        rootPart = ObjectPart.FromXml(reader, group, currentOwner, options);
                        group.Add(LINK_ROOT, rootPart.ID, rootPart);
                        break;

                    case "OtherParts":
                        if (isEmptyElement)
                        {
                            break;
                        }
                        FromXmlOtherParts(reader, group, currentOwner, options);
                        break;

                    case "GroupScriptStates":
                        if (isEmptyElement)
                        {
                            break;
                        }
                        FromXmlGroupScriptStates(reader, group);
                        break;

                    case "KeyframeMotion":
                        if (isEmptyElement)
                        {
                            break;
                        }
                        reader.ReadToEndElement();
                        break;

                    default:
                        reader.ReadToEndElement();
                        break;
                    }
                    break;

                case XmlNodeType.EndElement:
                    if (nodeName != "SceneObjectGroup")
                    {
                        throw new InvalidObjectXmlException();
                    }

                    foreach (ObjectPart part in group.Values)
                    {
                        part.Owner = currentOwner;
                        if ((options & XmlDeserializationOptions.RestoreIDs) == 0)
                        {
                            foreach (UUID key in part.Inventory.Keys1)
                            {
                                UUID newid = UUID.Random;
                                part.Inventory[key].SetNewID(newid);
                                part.Inventory.ChangeKey(newid, key);
                            }
                        }
                    }
                    group.FinalizeObject();
                    return(group);

                default:
                    break;
                }
            }
        }
        private static void FromXmlOtherParts(XmlTextReader reader, ObjectGroup group, UGUI currentOwner, XmlDeserializationOptions options)
        {
            ObjectPart part;
            var        links = new SortedDictionary <int, ObjectPart>();

            if (reader.IsEmptyElement)
            {
                throw new InvalidObjectXmlException();
            }

            for (; ;)
            {
                if (!reader.Read())
                {
                    throw new InvalidObjectXmlException();
                }

                bool   isEmptyElement = reader.IsEmptyElement;
                string nodeName       = reader.Name;

                switch (reader.NodeType)
                {
                case XmlNodeType.Element:
                    switch (nodeName)
                    {
                    case "Part":
                        if (isEmptyElement)
                        {
                            throw new InvalidObjectXmlException();
                        }
                        part = ParseOtherPart(reader, group, currentOwner, options);
                        links.Add(part.LoadedLinkNumber, part);
                        break;

                    case "SceneObjectPart":
                        if (isEmptyElement)
                        {
                            throw new InvalidObjectXmlException();
                        }
                        part = ObjectPart.FromXml(reader, null, currentOwner, options);
                        try
                        {
                            part.LoadedLinkNumber = links.Count + 2;
                            links.Add(part.LoadedLinkNumber, part);
                        }
                        catch
                        {
                            throw new ObjectDeserializationFailedDueKeyException();
                        }
                        break;

                    default:
                        reader.ReadToEndElement();
                        break;
                    }
                    break;

                case XmlNodeType.EndElement:
                    if (nodeName != "OtherParts")
                    {
                        throw new InvalidObjectXmlException();
                    }
                    foreach (KeyValuePair <int, ObjectPart> kvp in links)
                    {
                        group.Add(kvp.Key, kvp.Value.ID, kvp.Value);
                    }
                    return;

                default:
                    break;
                }
            }
        }