private static void ExportTextOffset(AdfFile.InstanceInfo ii, AdfFile.InstanceMemberInfo imi, XmlWriter writer)
        {
            int offset           = imi.Data.ReadValueS32();
            int stringArrayIndex = 0;

            foreach (var m in ii.Members)
            {
                if (m.Id == 2)
                {
                    break;
                }
                ++stringArrayIndex;
            }
            var stringArray = ii.Members[stringArrayIndex];

            List <byte> accum = new List <byte>();

            for (int i = offset; true; ++i)
            {
                byte current = (byte)stringArray.Members[i].Data.ReadByte();
                stringArray.Members[i].Data.Position = 0;

                if (current != 0)
                {
                    accum.Add(current);
                }
                else // write the string
                {
                    string t = Encoding.UTF8.GetString(accum.ToArray());
                    writer.WriteValue(t);
                    break;
                }
            }
        }
        private static void ExportInstanceInfo(AdfFile.InstanceInfo ii, XmlWriter writer)
        {
            // Unlike the ADF exporter, we will inline most of the arrays and completly split the big string array
            // We will still use the same style (attribute naming, ...) to have a simple Importer
            writer.WriteStartElement("instance");
            writer.WriteAttributeString("name", ii.Name);
            writer.WriteAttributeString("name-hash", ii.NameHash.ToString(CultureInfo.InvariantCulture));
            writer.WriteAttributeString("type", ii.Type.Type.ToString());
            writer.WriteAttributeString("type-hash", ii.Type.NameHash.ToString(CultureInfo.InvariantCulture));
            writer.WriteAttributeString("type-name", ii.Type.Name);
            if (ii.InlineArrayIndex != -1)
            {
                writer.WriteAttributeString("inline-array-copy-index", ii.InlineArrayIndex.ToString(CultureInfo.InvariantCulture));
            }
            if (ii.MinInlineArraySize > 0)
            {
                writer.WriteAttributeString("inline-array-copy-minsz", ii.MinInlineArraySize.ToString(CultureInfo.InvariantCulture));
            }

            // We only do the first member, cause everything else is tied to it by references.
            {
                writer.WriteStartElement("member");
                var member = ii.Members[0];
                writer.WriteAttributeString("name", member.Name);
                writer.WriteAttributeString("gbltype", member.Type.ToString());
                writer.WriteAttributeString("id", member.Id.ToString());
                writer.WriteAttributeString("type-hash", member.TypeDef.NameHash.ToString(CultureInfo.InvariantCulture));
                writer.WriteAttributeString("type", member.TypeDef.Name);

                // and we only do the first element of that structure (named "Languages"). The Text array will be recreated.
                ExportInstanceMember(ii, member.Members[0], writer);

                { // the second element is just here to keep track of its informations (again, simpler importer)
                    writer.WriteStartElement("member");
                    var subMember = member.Members[1];
                    writer.WriteAttributeString("name", subMember.Name);
                    writer.WriteAttributeString("gbltype", subMember.Type.ToString());
                    writer.WriteAttributeString("id", subMember.Id.ToString());
                    writer.WriteAttributeString("is-reference", "yay");
                    writer.WriteAttributeString("type-hash", subMember.TypeDef.NameHash.ToString(CultureInfo.InvariantCulture));
                    writer.WriteAttributeString("type", subMember.TypeDef.Name);
                    writer.WriteEndElement(); // subMember
                }
                writer.WriteEndElement();     // member
            }
            writer.WriteEndElement();         // instance
        }
        private static void ExportInstanceInfo(AdfFile.InstanceInfo ii, XmlWriter writer)
        {
            writer.WriteStartElement("instance");
            writer.WriteAttributeString("name", ii.Name);
            writer.WriteAttributeString("name-hash", ii.NameHash.ToString(CultureInfo.InvariantCulture));
            writer.WriteAttributeString("type", ii.Type.Type.ToString());
            writer.WriteAttributeString("type-hash", ii.Type.NameHash.ToString(CultureInfo.InvariantCulture));
            writer.WriteAttributeString("type-name", ii.Type.Name);
            if (ii.InlineArrayIndex != -1)
            {
                writer.WriteAttributeString("inline-array-copy-index", ii.InlineArrayIndex.ToString(CultureInfo.InvariantCulture));
            }
            if (ii.MinInlineArraySize > 0)
            {
                writer.WriteAttributeString("inline-array-copy-minsz", ii.MinInlineArraySize.ToString(CultureInfo.InvariantCulture));
            }

            foreach (var member in ii.Members)
            {
                ExportInstanceMember(member, writer);
            }

            writer.WriteEndElement();
        }
        private static void ExportInstanceMember(AdfFile.InstanceInfo ii, AdfFile.InstanceMemberInfo imi, XmlWriter writer)
        {
            writer.WriteStartElement("member");
            if (!String.IsNullOrEmpty(imi.Name))
            {
                writer.WriteAttributeString("name", imi.Name);
            }
            writer.WriteAttributeString("gbltype", imi.Type.ToString());
            if (imi.isReferenceToId)
            {
                writer.WriteAttributeString("is-reference", "yay");
            }
            if (imi.Id >= 0 || imi.isReferenceToId)
            {
                writer.WriteAttributeString("id", imi.Id.ToString());
            }
            if (imi.HasOwnCopyOfInlineArrays)
            {
                writer.WriteAttributeString("own-copy-of-inline-arrays", "yay");
            }

            if (imi.Name == "TextOffset" || imi.Name == "NameOffset") // hardcoded :( thingy to handle string lookup
            {
                writer.WriteAttributeString("type", "int32");
                ExportTextOffset(ii, imi, writer);
                writer.WriteEndElement();
                return;
            }

            // normal (except for the inlining of arrays)
            if (imi.Type == TypeDefinitionType.Primitive)
            {
                switch (imi.TypeHash)
                {
                case AdfTypeHashes.Primitive.Int8:
                    writer.WriteAttributeString("type", "int8");
                    writer.WriteValue(imi.Data.ReadValueS8().ToString(CultureInfo.InvariantCulture));
                    break;

                case AdfTypeHashes.Primitive.UInt8:
                    writer.WriteAttributeString("type", "uint8");
                    writer.WriteValue(imi.Data.ReadValueU8().ToString(CultureInfo.InvariantCulture));
                    break;

                case AdfTypeHashes.Primitive.Int16:
                    writer.WriteAttributeString("type", "int16");
                    writer.WriteValue(imi.Data.ReadValueS16().ToString(CultureInfo.InvariantCulture));
                    break;

                case AdfTypeHashes.Primitive.UInt16:
                    writer.WriteAttributeString("type", "uint16");
                    writer.WriteValue(imi.Data.ReadValueU16().ToString(CultureInfo.InvariantCulture));
                    break;

                case AdfTypeHashes.Primitive.Int32:
                    writer.WriteAttributeString("type", "int32");
                    writer.WriteValue(imi.Data.ReadValueS32().ToString("X8", CultureInfo.InvariantCulture));
                    break;

                case AdfTypeHashes.Primitive.UInt32:
                    writer.WriteAttributeString("type", "uint32");
                    writer.WriteValue(imi.Data.ReadValueU32().ToString("X8", CultureInfo.InvariantCulture));
                    break;

                case AdfTypeHashes.Primitive.Float:
                    writer.WriteAttributeString("type", "float");
                    // G18 'cause it may seems stupid but that's what it takes to have matching checksums
                    writer.WriteValue(imi.Data.ReadValueF32().ToString("G18", CultureInfo.InvariantCulture));
                    break;

                case AdfTypeHashes.Primitive.Int64:
                    writer.WriteAttributeString("type", "int64");
                    writer.WriteValue(imi.Data.ReadValueS64().ToString("G", CultureInfo.InvariantCulture));
                    break;

                case AdfTypeHashes.Primitive.UInt64:
                    writer.WriteAttributeString("type", "uint64");
                    writer.WriteValue(imi.Data.ReadValueU64().ToString(CultureInfo.InvariantCulture));
                    break;

                case AdfTypeHashes.Primitive.Double:
                    writer.WriteValue(imi.Data.ReadValueF64().ToString(CultureInfo.InvariantCulture));
                    break;

                case AdfTypeHashes.String:
                    writer.WriteAttributeString("type", "string");
                    if (imi.ReferenceToString == true)
                    {
                        writer.WriteAttributeString("reference-string-from", imi.StringTableId.ToString(CultureInfo.InvariantCulture));
                    }
                    writer.WriteValue(imi.StringData);
                    break;
                }
            }
            else
            {
                writer.WriteAttributeString("type-hash", imi.TypeDef.NameHash.ToString(CultureInfo.InvariantCulture));
                writer.WriteAttributeString("type", imi.TypeDef.Name);
                switch (imi.Type)
                {
                case TypeDefinitionType.Array:     // we have a ref, get the ID and inline it:
                    if (imi.Id != 2 && imi.isReferenceToId == true)
                    {
                        int index = 0;
                        foreach (var m in ii.Members)
                        {
                            if (m.Id == imi.Id)
                            {
                                break;
                            }
                            ++index;
                        }
                        ExportInstanceMember(ii, ii.Members[index], writer);
                    }
                    else if (imi.Id == 2 && imi.isReferenceToId == true)
                    {
                    }
                    break;

                case TypeDefinitionType.InlineArray:
                    break;

                case TypeDefinitionType.Structure:
                    break;

                case TypeDefinitionType.StringHash:
                    writer.WriteValue(imi.StringData);
                    break;
                }
            }

            foreach (var member in imi.Members)
            {
                ExportInstanceMember(ii, member, writer);
            }

            writer.WriteEndElement();
        }