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 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(); }
private static void ImportInstanceInfo(XPathNavigator instanceNode, AdfFile adf) { InstanceInfo instance = new InstanceInfo() { Name = instanceNode.GetAttribute("name", ""), NameHash = uint.Parse(instanceNode.GetAttribute("name-hash", "")), }; TypeDefinitionType type; Enum.TryParse(instanceNode.GetAttribute("type", ""), out type); uint typeHash = uint.Parse(instanceNode.GetAttribute("type-hash", ""), CultureInfo.InvariantCulture); string typeString = instanceNode.GetAttribute("type-name", ""); instance.Type = adf.Runtime.GetTypeDefinition(typeHash); instance.TypeHash = instance.Type.NameHash; if (!int.TryParse(instanceNode.GetAttribute("inline-array-copy-index", ""), out instance.InlineArrayIndex)) { instance.InlineArrayIndex = -1; } if (!uint.TryParse(instanceNode.GetAttribute("inline-array-copy-minsz", ""), out instance.MinInlineArraySize)) { instance.MinInlineArraySize = 0; } if (type != instance.Type.Type) { throw new InvalidOperationException("do not touch things like type and type-name in the xml file, yo"); } instance.Members = new List <AdfFile.InstanceMemberInfo>(); // Hold the contents of the last Array (A[int8]) List <byte> stringArray = new List <byte>(); // parse members instance.Members.Add(null); // prepare the future var memberNode = instanceNode.SelectSingleNode("member"); instance.Members[0] = (ImportInstanceMemberInfo(memberNode, instance, adf, stringArray)); var stringArrayMemberIndex = 0; foreach (var member in instance.Members) { if (member.Id == 2) { break; } ++stringArrayMemberIndex; } var stringArrayMember = instance.Members[stringArrayMemberIndex]; // Generate the string array (type is array of int8) foreach (byte b in stringArray) // the foreach is sooo overkill... { var subMember = new AdfFile.InstanceMemberInfo() { Type = TypeDefinitionType.Primitive, TypeHash = AdfTypeHashes.Primitive.Int8, Name = null, }; subMember.Data.WriteByte(b); stringArrayMember.Members.Add(subMember); } // add instance to ADF structure adf.AddInstanceInfo(instance); }
private static AdfFile.InstanceMemberInfo ImportTextOffset(XPathNavigator memberNode, AdfFile.InstanceMemberInfo member, InstanceInfo ii, AdfFile adf, List <byte> stringArray) { member.TypeHash = AdfTypeHashes.Primitive.UInt32; member.Data.WriteValueU32((uint)stringArray.Count); // write the offset byte[] str = Encoding.UTF8.GetBytes(memberNode.Value); stringArray.AddRange(str); stringArray.Add(0); // the null byte to terminate the string return(member); }
private static AdfFile.InstanceMemberInfo ImportInstanceMemberInfo(XPathNavigator memberNode, AdfFile.InstanceInfo ii, AdfFile adf, List <byte> stringArray) { AdfFile.InstanceMemberInfo member = new AdfFile.InstanceMemberInfo(); member.Name = memberNode.GetAttribute("name", ""); string stringId = memberNode.GetAttribute("id", ""); string ownIACopy = memberNode.GetAttribute("own-copy-of-inline-arrays", ""); if (!string.IsNullOrEmpty(stringId)) { member.Id = long.Parse(stringId, CultureInfo.InvariantCulture); } else { member.Id = -1; } member.isReferenceToId = !string.IsNullOrEmpty(memberNode.GetAttribute("is-reference", "")); if (!string.IsNullOrEmpty(ownIACopy)) { member.HasOwnCopyOfInlineArrays = true; } Enum.TryParse(memberNode.GetAttribute("gbltype", ""), out member.Type); string typeString = memberNode.GetAttribute("type", ""); if (member.Name == "TextOffset" || member.Name == "NameOffset") // hardcoded :( thingy to handle string lookup { return(ImportTextOffset(memberNode, member, ii, adf, stringArray)); } // Load the value if (member.Type == TypeDefinitionType.Primitive) { switch (typeString) { case "int8": member.Data.WriteValueS8(sbyte.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int8; break; case "uint8": member.Data.WriteValueU8(byte.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt8; break; case "int16": member.Data.WriteValueS16(short.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int16; break; case "uint16": member.Data.WriteValueU16(ushort.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt16; break; case "int32": member.Data.WriteValueS32(int.Parse(memberNode.Value, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int32; break; case "uint32": member.Data.WriteValueU32(uint.Parse(memberNode.Value, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt32; break; case "int64": member.Data.WriteValueS64(long.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int64; break; case "uint64": member.Data.WriteValueU64(ulong.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt64; break; case "float": member.Data.WriteValueF32(float.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Float; break; case "double": member.Data.WriteValueF64(double.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Double; break; case "string": string strRef = memberNode.GetAttribute("reference-string-from", ""); if (!string.IsNullOrEmpty(strRef)) { member.ReferenceToString = true; member.StringTableId = int.Parse(strRef, CultureInfo.InvariantCulture); } member.StringData = memberNode.Value; member.TypeHash = AdfTypeHashes.String; break; } } else { uint typeHash = uint.Parse(memberNode.GetAttribute("type-hash", ""), CultureInfo.InvariantCulture); member.TypeDef = adf.Runtime.GetTypeDefinition(typeHash); member.TypeHash = typeHash; if (member.TypeDef.Type != member.Type) { throw new InvalidOperationException("do not touch things like type and type-name in the xml file, yo"); } if (member.Type == TypeDefinitionType.StringHash) { member.StringData = memberNode.Value; } if (member.Type == TypeDefinitionType.Array && member.isReferenceToId == true && member.Id != -1) { // No child, create an empty element if (!memberNode.HasChildren) { var subMember = new AdfFile.InstanceMemberInfo() { Name = member.Name, Id = member.Id, isReferenceToId = false, Type = member.Type, TypeHash = member.TypeHash, TypeDef = member.TypeDef, HasOwnCopyOfInlineArrays = false, // maybe _that_ will cause some issues... }; ii.Members.Add(subMember); return(member); } // the child node is in fact a global element. XPathNavigator subMemberNode = memberNode.SelectSingleNode("member"); ii.Members.Add(ImportInstanceMemberInfo(subMemberNode, ii, adf, stringArray)); return(member); } } // handle sub members var subMembersList = memberNode.Select("member"); foreach (XPathNavigator subMemberNode in subMembersList) { var subMember = ImportInstanceMemberInfo(subMemberNode, ii, adf, stringArray); if (member.Name != "SortedPairs") // another hardcoded thing { member.Members.Add(subMember); } else // insert the new member at the right place { subMember.Members[0].Data.Position = 0; uint hash = subMember.Members[0].Data.ReadValueU32(); subMember.Members[0].Data.Position = 0; int i = 0; for (; i < member.Members.Count; ++i) { member.Members[i].Members[0].Data.Position = 0; uint cmpHash = member.Members[i].Members[0].Data.ReadValueU32(); member.Members[i].Members[0].Data.Position = 0; if (cmpHash > hash) { break; } } member.Members.Insert(i, subMember); } } return(member); }
private static void ExportInstanceMember(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.FileOffset > 0) { writer.WriteAttributeString("offset-in-file", imi.FileOffset.ToString("X8", CultureInfo.InvariantCulture)); } 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(CultureInfo.InvariantCulture)); break; case AdfTypeHashes.Primitive.UInt32: writer.WriteAttributeString("type", "uint32"); writer.WriteValue(imi.Data.ReadValueU32().ToString(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: break; case TypeDefinitionType.InlineArray: break; case TypeDefinitionType.Structure: break; case TypeDefinitionType.StringHash: writer.WriteValue(imi.StringData); break; } } bool isString = false; if (imi.Type == TypeDefinitionType.Array && imi.TypeDef.ElementTypeHash == AdfTypeHashes.Primitive.Int8 && imi.Members.Count > 1) { // check if that's a string. First thing: the name should be *text* or *string* (for stringlookups) // Second thing, it should end with 0 sbyte last = (sbyte)imi.Members.Last().Data.ReadByte(); imi.Members.Last().Data.Position = 0; var nameMatchingRegexp = new System.Text.RegularExpressions.Regex("(.*Text.*)|(.*String.*)"); if (last == 0 && nameMatchingRegexp.IsMatch(imi.Name)) { isString = true; // yeah try the string writer.WriteAttributeString("int8-array-is-string-array", "yay"); // write the string List <byte> accum = new List <byte>(); foreach (var member in imi.Members) { byte current = (byte)member.Data.ReadByte(); if (current != 0) { accum.Add(current); } else // write the string { writer.WriteStartElement("inline-string"); string t = Encoding.UTF8.GetString(accum.ToArray()); accum.Clear(); writer.WriteValue(t); writer.WriteEndElement(); } } } } if (!isString) { foreach (var member in imi.Members) { ExportInstanceMember(member, writer); } } writer.WriteEndElement(); }
private static AdfFile.InstanceMemberInfo ImportInstanceMemberInfo(XPathNavigator memberNode, AdfFile adf) { AdfFile.InstanceMemberInfo member = new AdfFile.InstanceMemberInfo(); member.Name = memberNode.GetAttribute("name", ""); string stringId = memberNode.GetAttribute("id", ""); string ownIACopy = memberNode.GetAttribute("own-copy-of-inline-arrays", ""); if (!string.IsNullOrEmpty(stringId)) { member.Id = long.Parse(stringId, CultureInfo.InvariantCulture); } member.isReferenceToId = !string.IsNullOrEmpty(memberNode.GetAttribute("is-reference", "")); if (!string.IsNullOrEmpty(ownIACopy)) { member.HasOwnCopyOfInlineArrays = true; } Enum.TryParse(memberNode.GetAttribute("gbltype", ""), out member.Type); string typeString = memberNode.GetAttribute("type", ""); // Load the value if (member.Type == TypeDefinitionType.Primitive) { switch (typeString) { case "int8": member.Data.WriteValueS8(sbyte.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int8; break; case "uint8": member.Data.WriteValueU8(byte.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt8; break; case "int16": member.Data.WriteValueS16(short.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int16; break; case "uint16": member.Data.WriteValueU16(ushort.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt16; break; case "int32": member.Data.WriteValueS32(int.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int32; break; case "uint32": member.Data.WriteValueU32(uint.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt32; break; case "int64": member.Data.WriteValueS64(long.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int64; break; case "uint64": member.Data.WriteValueU64(ulong.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt64; break; case "float": member.Data.WriteValueF32(float.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Float; break; case "double": member.Data.WriteValueF64(double.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Double; break; case "string": string strRef = memberNode.GetAttribute("reference-string-from", ""); if (!string.IsNullOrEmpty(strRef)) { member.ReferenceToString = true; member.StringTableId = int.Parse(strRef, CultureInfo.InvariantCulture); } member.StringData = memberNode.Value; member.TypeHash = AdfTypeHashes.String; break; } } else { uint typeHash = uint.Parse(memberNode.GetAttribute("type-hash", ""), CultureInfo.InvariantCulture); member.TypeDef = adf.Runtime.GetTypeDefinition(typeHash); member.TypeHash = typeHash; if (member.TypeDef.Type != member.Type) { throw new InvalidOperationException("do not touch things like type and type-name in the xml file, yo"); } if (member.Type == TypeDefinitionType.StringHash) { member.StringData = memberNode.Value; } } // handle sub members if (memberNode.GetAttribute("int8-array-is-string-array", "") == "yay") { // we found an array of inline-strings var subMembersList = memberNode.Select("inline-string"); foreach (XPathNavigator subMemberNode in subMembersList) { // it is an inline string. Get its value and write the string byte[] str = Encoding.UTF8.GetBytes(subMemberNode.Value); foreach (byte b in str) { AdfFile.InstanceMemberInfo subMember = new AdfFile.InstanceMemberInfo(); subMember.TypeHash = AdfTypeHashes.Primitive.Int8; subMember.Type = TypeDefinitionType.Primitive; subMember.Data.WriteValueU8(b); member.Members.Add(subMember); } AdfFile.InstanceMemberInfo lastByteMember = new AdfFile.InstanceMemberInfo(); lastByteMember.TypeHash = AdfTypeHashes.Primitive.Int8; lastByteMember.Type = TypeDefinitionType.Primitive; lastByteMember.Data.WriteValueU8(0); member.Members.Add(lastByteMember); } } else { var subMembersList = memberNode.Select("member"); foreach (XPathNavigator subMemberNode in subMembersList) { member.Members.Add(ImportInstanceMemberInfo(subMemberNode, adf)); } } return(member); }