private object ExportField(GFF.FieldDefinition def, long offset, ExportState state) { var input = this.Data; input.Seek(offset + def.Offset, SeekOrigin.Begin); if (def.IsReference == true && def.IsList == true) { var listOffset = input.ReadValueU32(LittleEndian); if (listOffset == 0xFFFFFFFF) { return null; } input.Seek(listOffset, SeekOrigin.Begin); var count = input.ReadValueU32(LittleEndian); long itemOffset = input.Position; var list = new List<object>(); for (uint i = 0; i < count; i++) { list.Add(this.ExportGeneric(state)); itemOffset += 8; input.Seek(itemOffset, SeekOrigin.Begin); } return list; } else if (def.IsList == true) { //var type = GFF.Builtin.ToNativeType(def.Type); var listOffset = input.ReadValueU32(LittleEndian); if (listOffset == 0xFFFFFFFF) { /*if (def.Type == GFF.FieldType.UInt8) { return new byte[0]; } else { throw new NotSupportedException(); }*/ return null; } input.Seek(listOffset, SeekOrigin.Begin); var count = input.ReadValueU32(LittleEndian); switch (def.Type) { case GFF.FieldType.String: { long itemOffset = input.Position; var list = new List<string>(); for (uint i = 0; i < count; i++) { var dataOffset = input.ReadValueU32(LittleEndian); if (dataOffset == 0xFFFFFFFF) { list.Add(null); } else { if (this.FileVersion < 1) { input.Seek(dataOffset, SeekOrigin.Begin); var length = input.ReadValueU32(LittleEndian); list.Add(input.ReadString(length * 2, true, LittleEndian == true ? Encoding.Unicode : Encoding.BigEndianUnicode)); } else { list.Add(this.StringTable[(int)dataOffset]); } } itemOffset += 4; input.Seek(itemOffset, SeekOrigin.Begin); } return list; } case GFF.FieldType.Structure: { long itemOffset = input.Position; var subdef = this.Structures[def.StructureId]; var list = new List<KeyValue>(); for (uint i = 0; i < count; i++) { list.Add(this.ExportStructure( subdef, itemOffset, state)); itemOffset += subdef.DataSize; } return list; } default: { if (def.Type == GFF.FieldType.UInt8) { var list = new byte[count]; input.Read(list, 0, list.Length); return list; } else { var type = GFF.Builtin.ToNativeType(def.Type); var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(type)); for (uint i = 0; i < count; i++) { list.Add(GFF.Builtin.Deserialize(input, def.Type, LittleEndian)); } return list; } } } } else { if (def.IsReference == true && def.Type == GFF.FieldType.Generic) { return this.ExportGeneric(state); } else if (def.IsReference == true) { var referenceOffset = input.ReadValueU32(LittleEndian); if (referenceOffset == 0xFFFFFFFF) { return null; } else if (state.References.ContainsKey(referenceOffset) == true) { return state.References[referenceOffset]; } input.Seek(referenceOffset, SeekOrigin.Begin); } switch (def.Type) { case GFF.FieldType.Generic: { throw new FormatException(); } case GFF.FieldType.String: { var dataOffset = input.ReadValueU32(LittleEndian); if (dataOffset == 0xFFFFFFFF) { return ""; } if (this.FileVersion < 1) { input.Seek(dataOffset, SeekOrigin.Begin); var count = input.ReadValueU32(LittleEndian); return input.ReadString(count * 2, true, LittleEndian == true ? Encoding.Unicode : Encoding.BigEndianUnicode); } else { return this.StringTable[(int)dataOffset]; } } case GFF.FieldType.TalkString: { var tlk = new GFF.Builtins.TalkString(); tlk.Id = input.ReadValueU32(LittleEndian); var dataOffset = input.ReadValueU32(LittleEndian); if (dataOffset == 0xFFFFFFFF) { tlk.String = null; } else if (dataOffset == 0) { tlk.String = ""; } else { if (this.FileVersion < 1) { input.Seek(dataOffset, SeekOrigin.Begin); var count = input.ReadValueU32(LittleEndian); tlk.String = input.ReadString(count * 2, true, LittleEndian == true ? Encoding.Unicode : Encoding.BigEndianUnicode); } else { tlk.String = this.StringTable[(int)dataOffset]; } } return tlk; } case GFF.FieldType.Structure: { var subdef = this.Structures[def.StructureId]; return this.ExportStructure(subdef, input.Position, state); } default: { return GFF.Builtin.Deserialize(input, def.Type, LittleEndian); } } } }
private void ImportStructure(GFF.StructureDefinition def, KeyValue data, long offset, ref long newOffset, ImportState state) { foreach (var fieldDef in def.Fields) { if (fieldDef.Id == 16208) { } KeyValue value; if (data.Values.ContainsKey(fieldDef.Id) == false) { //throw new InvalidOperationException(); value = new KeyValue(fieldDef.Type, null); } else { value = data[fieldDef.Id]; } this.ImportField(fieldDef, value, offset, ref newOffset, state); } }
private KeyValue ExportStructure(GFF.StructureDefinition def, long offset, ExportState state) { var kv = new KeyValue(GFF.FieldType.Structure, null); kv.StructureId = def.Id; foreach (var fieldDef in def.Fields) { var value = this.ExportField(fieldDef, offset, state); if (value is KeyValue) { kv[fieldDef.Id] = (KeyValue)value; } else { kv[fieldDef.Id] = new KeyValue(fieldDef.Type, value); } } return kv; }
private void ImportField(GFF.FieldDefinition def, KeyValue data, long offset, ref long newOffset, ImportState state) { var output = this.Data; output.Seek(offset + def.Offset, SeekOrigin.Begin); if (def.IsList == true) { if (def.IsReference == true && (data.Value != null || def.Type != GFF.FieldType.Generic)) { throw new NotSupportedException(); } var list = (IList)data.Value; if (list == null) { output.WriteValueU32(0xFFFFFFFF, LittleEndian); } else { output.WriteValueU32((uint)newOffset, LittleEndian); output.Seek(newOffset, SeekOrigin.Begin); output.WriteValueS32(list.Count, LittleEndian); newOffset += 4; uint itemSize; if (def.Type == GFF.FieldType.Structure) { var subdef = this.Structures[def.StructureId]; itemSize = subdef.DataSize; } else { itemSize = GFF.Builtin.SizeOf(def.Type); } newOffset += list.Count * itemSize; switch (def.Type) { case GFF.FieldType.String: { throw new NotImplementedException(); } case GFF.FieldType.Structure: { var subdef = this.Structures[def.StructureId]; long itemOffset = output.Position; foreach (var item in list) { this.ImportStructure( subdef, (KeyValue)item, itemOffset, ref newOffset, state); itemOffset += itemSize; } break; } default: { if (def.Type == GFF.FieldType.UInt8 && list.GetType() == typeof(byte[])) { var bytes = (byte[])list; output.Write(bytes, 0, bytes.Length); } else { long itemOffset = output.Position; foreach (var item in list) { GFF.Builtin.Serialize(output, def.Type, item, LittleEndian); itemOffset += itemSize; } } break; } } } } else { if (def.IsReference == true && def.Type != GFF.FieldType.Structure) { throw new NotSupportedException(); } switch (def.Type) { case GFF.FieldType.String: { var s = data.As<string>(); if (s == null || s.Length == 0) { output.WriteValueU32(0xFFFFFFFF, LittleEndian); } else { var length = s.Length + 1; output.WriteValueU32((uint)newOffset, LittleEndian); output.Seek(newOffset, SeekOrigin.Begin); output.WriteValueS32(length, LittleEndian); output.WriteString(s, LittleEndian ? Encoding.Unicode : Encoding.BigEndianUnicode); output.WriteValueU16(0, LittleEndian); newOffset += 4 + (2 * length); } break; } case GFF.FieldType.TalkString: { var s = data.As<GFF.Builtins.TalkString>(); output.WriteValueU32(s.Id, LittleEndian); if (s.String == null) { output.WriteValueU32(0xFFFFFFFF, LittleEndian); } else if (s.String.Length == 0) { output.WriteValueU32(0, LittleEndian); } else { var length = s.String.Length + 1; output.WriteValueU32((uint)newOffset, LittleEndian); output.Seek(newOffset, SeekOrigin.Begin); output.WriteValueS32(length, LittleEndian); output.WriteString(s.String, LittleEndian ? Encoding.Unicode : Encoding.BigEndianUnicode); output.WriteValueU16(0, LittleEndian); newOffset += 4 + (2 * length); } break; } case GFF.FieldType.Structure: { if (def.IsReference == true) { if (data == null || data.Values == null) { output.WriteValueU32(0xFFFFFFFF, LittleEndian); } else { output.WriteValueU32((uint)newOffset, LittleEndian); output.Seek(newOffset, SeekOrigin.Begin); var subdef = this.Structures[def.StructureId]; newOffset += subdef.DataSize; this.ImportStructure( subdef, data, output.Position, ref newOffset, state); } } else { var subdef = this.Structures[def.StructureId]; this.ImportStructure( subdef, data, output.Position, ref newOffset, state); } break; } default: { GFF.Builtin.Serialize(output, def.Type, data.Value, LittleEndian); break; } } } }
private void PrintStructure(GFF.StructureDefinition def, int level) { var queue = new Queue<GFF.StructureDefinition>(); if (Printed.Contains(def) == false) { Printed.Add(def); } PrintLine(level, "[GFF.StructureDefinition(0x{0:X8})] // {1}", def.Id, ParseId(def.Id)); PrintLine(level, "public class {0}", ParseId(def.Id)); PrintLine(level, "{{"); foreach (var fieldDef in def.Fields) { string type; if (fieldDef.Type == GFF.FieldType.Structure) { var subdef = this.Structures[fieldDef.StructureId]; type = ParseId(subdef.Id); if (queue.Contains(subdef) == false) { queue.Enqueue(subdef); } } else { type = fieldDef.Type.ToString(); } if (fieldDef.Type == GFF.FieldType.Color || fieldDef.Type == GFF.FieldType.Matrix4x4 || fieldDef.Type == GFF.FieldType.Quaternion || fieldDef.Type == GFF.FieldType.TalkString || fieldDef.Type == GFF.FieldType.Vector3 || fieldDef.Type == GFF.FieldType.Vector4) { type = "GFF.Builtins." + type; } if (fieldDef.Type == GFF.FieldType.UInt8 && fieldDef.IsList == true) { type = "byte[]"; } else if (fieldDef.IsList == true) { type = "List<" + type + ">"; } if (fieldDef.IsReference == true) { type = "*" + type; } PrintLine(level + 1, ""); PrintLine(level + 1, "[GFF.FieldDefinition({0})]", fieldDef.Id); PrintLine(level + 1, "public {0} Unknown{1};", type, fieldDef.Id); } if (queue.Count > 0) { while (queue.Count > 0) { PrintLine(level + 1, ""); PrintStructure(queue.Dequeue(), level + 1); } } PrintLine(level, "}}"); }