private object ExportGeneric(ExportState state) { var input = this.Data; var type = input.ReadValueU16(LittleEndian); var flags = (GFF.FieldFlags)input.ReadValueU16(LittleEndian); var offset = input.ReadValueU32(LittleEndian); if (state.References.ContainsKey(offset) == true) { return(state.References[offset]); } var def = new GFF.FieldDefinition(); def.Id = 0; def.Offset = 0; if ((flags & GFF.FieldFlags.IsStructure) != 0) { flags &= ~GFF.FieldFlags.IsStructure; def.Type = GFF.FieldType.Structure; def.StructureId = type; } else { def.Type = (GFF.FieldType)type; } def.Flags = flags; var instance = this.ExportField(def, offset, state); state.References.Add(offset, instance); return(instance); }
private static bool ValidateField( GFF.FieldDefinition def, Type nativeType) { // i'm too lazy to write this code right now :) return(true); }
private void ImportTypeToStructures(Type root) { var structs = new List <GFF.StructureDefinition>(); var map = new Dictionary <Type, GFF.StructureDefinition>(); var types = new List <Type>(); var queue = new Queue <Type>(); queue.Enqueue(root); // discover non-native types we need to add while (queue.Count > 0) { var type = queue.Dequeue(); types.Add(type); foreach (var field in type.GetFields()) { var subtype = field.FieldType; if (GFF.Builtin.FromNativeType(subtype) != GFF.FieldType.Structure) { continue; } if (subtype.IsGenericType == true && subtype.GetGenericTypeDefinition() == typeof(List <>)) { subtype = subtype.GetGenericArguments()[0]; } if (types.Contains(subtype) == true || queue.Contains(subtype) == true) { continue; } queue.Enqueue(subtype); } } if (types.Count > 0xFFFF) { throw new InvalidOperationException(); } // now define them foreach (var type in types) { var structDef = new GFF.StructureDefinition(); var reflected = GFF.ReflectedStructureType.For(type); map.Add(type, structDef); structs.Add(structDef); structDef.Id = reflected.Id; uint offset = 0; foreach (var kvp in reflected.Fields) { var subtype = kvp.Value.Field.FieldType; var fieldDef = new GFF.FieldDefinition(); if (subtype.IsGenericType == true && subtype.GetGenericTypeDefinition() == typeof(List <>)) { subtype = subtype.GetGenericArguments()[0]; fieldDef.Flags |= GFF.FieldFlags.IsList; } else if (subtype.IsArray == true) { fieldDef.Flags |= GFF.FieldFlags.IsList; } fieldDef.Id = kvp.Key; fieldDef.Type = GFF.Builtin .FromNativeType(subtype, kvp.Value.Type); fieldDef.Offset = offset; fieldDef.NativeType = subtype; structDef.Fields.Add(fieldDef); if ((fieldDef.Flags & GFF.FieldFlags.IsList) != 0) { offset += 4; } else if (fieldDef.Type == GFF.FieldType.Structure) { throw new NotImplementedException(); } else { offset += GFF.Builtin.SizeOf(fieldDef.Type); } } structDef.DataSize = offset; } // update ids foreach (var type in types) { var structDef = map[type]; foreach (var fieldDef in structDef.Fields) { if (fieldDef.Type == GFF.FieldType.Structure) { var structRef = map[fieldDef.NativeType]; int index = structs.IndexOf(structRef); if (index < 0) { throw new InvalidOperationException(); } fieldDef.StructureReference = structRef; fieldDef.StructureId = (ushort)index; } } } this.Structures = structs; }
private object ExportTypeField(GFF.FieldDefinition def, Type type, long offset) { if (ValidateField(def, type) == false) { throw new FormatException("field validation failed"); } var endian = this.Endian; var input = this.Data; input.Seek(offset + def.Offset, SeekOrigin.Begin); if (def.IsReference == true) { throw new NotSupportedException(); } if (def.IsList == true) { var listOffset = input.ReadValueU32(endian); if (listOffset == 0xFFFFFFFF) { if (def.Type == GFF.FieldType.UInt8 && type == typeof(byte[])) { return(new byte[0]); } else { return(Activator.CreateInstance(type)); } } input.Seek(listOffset, SeekOrigin.Begin); var count = input.ReadValueU32(endian); 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(endian); if (dataOffset == 0xFFFFFFFF) { return(""); } if (this.FileVersion < 1) { input.Seek(dataOffset, SeekOrigin.Begin); var length = input.ReadValueU32(endian); list.Add(input.ReadString(length * 2, true, endian == Endian.Little ? Encoding.Unicode : Encoding.BigEndianUnicode)); } else { input.Seek(dataOffset, SeekOrigin.Begin); list.Add(this.StringTable[(int)dataOffset]); } itemOffset += 4; input.Seek(itemOffset, SeekOrigin.Begin); } return(list); } case GFF.FieldType.Structure: { long itemOffset = input.Position; var subtype = type.GetGenericArguments()[0]; var subdef = this.Structures[def.StructureId]; var list = (IList)Activator.CreateInstance(type); for (uint i = 0; i < count; i++) { list.Add(this.ExportTypeStructure( subdef, subtype, itemOffset)); itemOffset += subdef.DataSize; } return(list); } default: { if (def.Type == GFF.FieldType.UInt8 && type == typeof(byte[])) { var list = new byte[count]; input.Read(list, 0, list.Length); return(list); } else { var list = (IList)Activator.CreateInstance(type); for (uint i = 0; i < count; i++) { list.Add(GFF.Builtin.Deserialize(input, def.Type, endian)); } return(list); } } } } else { switch (def.Type) { case GFF.FieldType.String: { var dataOffset = input.ReadValueU32(endian); if (dataOffset == 0xFFFFFFFF) { return(""); } if (this.FileVersion < 1) { input.Seek(dataOffset, SeekOrigin.Begin); var count = input.ReadValueU32(endian); return(input.ReadString(count * 2, true, endian == Endian.Little ? Encoding.Unicode : Encoding.BigEndianUnicode)); } else { return(this.StringTable[(int)dataOffset]); } } case GFF.FieldType.TalkString: { var tlk = new GFF.Builtins.TalkString(); tlk.Id = input.ReadValueU32(endian); var dataOffset = input.ReadValueU32(endian); 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(endian); tlk.String = input.ReadString(count * 2, true, endian == Endian.Little ? 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.ExportTypeStructure(subdef, type, input.Position)); } default: { return(GFF.Builtin.Deserialize(input, def.Type, endian)); } } } }
private void ImportTypeField(GFF.FieldDefinition def, Type type, object value, long offset, ref long newOffset) { if (ValidateField(def, type) == false) { throw new FormatException("field validation failed"); } var endian = this.Endian; var output = this.Data; output.Seek(offset + def.Offset, SeekOrigin.Begin); if (def.IsList == true) { output.WriteValueU32((uint)newOffset, endian); output.Seek(newOffset, SeekOrigin.Begin); output.WriteValueS32(((IList)value).Count, endian); 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); } var list = (IList)value; newOffset += list.Count * itemSize; switch (def.Type) { case GFF.FieldType.String: { throw new NotImplementedException(); } case GFF.FieldType.Structure: { var subtype = type.GetGenericArguments()[0]; var subdef = this.Structures[def.StructureId]; long itemOffset = output.Position; foreach (var item in list) { this.ImportTypeStructure( subdef, item, itemOffset, ref newOffset); itemOffset += itemSize; } break; } default: { if (def.Type == GFF.FieldType.UInt8 && type == 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, endian); itemOffset += itemSize; } } break; } } } else { switch (def.Type) { case GFF.FieldType.String: { var s = (string)value; if (s.Length == 0) { output.WriteValueU32(0xFFFFFFFF, endian); } else { var length = s.Length + 1; output.WriteValueU32((uint)newOffset, endian); output.Seek(newOffset, SeekOrigin.Begin); output.WriteValueS32(length, endian); output.WriteString(s, endian == Endian.Little ? Encoding.Unicode : Encoding.BigEndianUnicode); output.WriteValueU16(0, endian); newOffset += 4 + (2 * length); } break; } case GFF.FieldType.Structure: { var subdef = this.Structures[def.StructureId]; this.ImportTypeStructure( subdef, value, output.Position, ref newOffset); break; } default: { GFF.Builtin.Serialize(output, def.Type, value, endian); break; } } } }
public void Deserialize(Stream input) { input.Seek(0, SeekOrigin.Begin); var magic = input.ReadValueU32(Endian.Big); if (magic != 0x47464620) { throw new FormatException(); } var version = input.ReadValueU32(Endian.Big); if (version != 0x56342E30 && // 4.0 version != 0x56342E31) // 4.1 { throw new FormatException("unsupported version"); } this.FileVersion = (byte)(version - 0x56342E30); this.FilePlatform = input.ReadValueEnum <GFF.FilePlatform>(Endian.Big); this.FormatType = input.ReadValueEnum <GFF.FormatType>(Endian.Big); this.FormatVersion = input.ReadValueU32(Endian.Big); var endian = this.FilePlatform == GFF.FilePlatform.PC ? Endian.Little : Endian.Big; var structCount = input.ReadValueU32(endian); var stringCount = this.FileVersion < 1 ? 0 : input.ReadValueU32(endian); var stringOffset = this.FileVersion < 1 ? 0 : input.ReadValueU32(endian); var dataOffset = input.ReadValueU32(endian); if (this.FileVersion < 1) { stringOffset = dataOffset; } else { if (dataOffset < stringOffset) { throw new FormatException(); } } this.Structures.Clear(); for (uint i = 0; i < structCount; i++) { var structDef = new GFF.StructureDefinition(); //structDef.Id = input.ReadValueU32(endian); structDef.Id = input.ReadValueU32(Endian.Big); var fieldCount = input.ReadValueU32(endian); var fieldOffset = input.ReadValueU32(endian); structDef.DataSize = input.ReadValueU32(endian); long nextOffset = input.Position; structDef.Fields.Clear(); input.Seek(fieldOffset, SeekOrigin.Begin); for (uint j = 0; j < fieldCount; j++) { var fieldDef = new GFF.FieldDefinition(); fieldDef.Id = input.ReadValueS32(endian); var rawFlags = input.ReadValueU32(endian); fieldDef.Offset = input.ReadValueU32(endian); var type = (ushort)(rawFlags & 0xFFFF); var flags = (GFF.FieldFlags)((rawFlags >> 16) & 0xFFFF); if ((flags & GFF.FieldFlags.IsStructure) != 0) { flags &= ~GFF.FieldFlags.IsStructure; fieldDef.Type = GFF.FieldType.Structure; fieldDef.StructureId = type; } else { fieldDef.Type = (GFF.FieldType)type; } fieldDef.Flags = flags; structDef.Fields.Add(fieldDef); } this.Structures.Add(structDef); input.Seek(nextOffset, SeekOrigin.Begin); } if (this.FileVersion >= 1) { input.Seek(stringOffset, SeekOrigin.Begin); this.StringTable = new List <string>(); for (uint i = 0; i < stringCount; i++) { this.StringTable.Add(input.ReadStringZ(Encoding.UTF8)); } } input.Seek(dataOffset, SeekOrigin.Begin); this.Data = input.ReadToMemoryStream(input.Length - dataOffset); }
private object ExportGeneric(ExportState state) { var input = this.Data; var type = input.ReadValueU16(LittleEndian); var flags = (GFF.FieldFlags)input.ReadValueU16(LittleEndian); var offset = input.ReadValueU32(LittleEndian); if (state.References.ContainsKey(offset) == true) { return state.References[offset]; } var def = new GFF.FieldDefinition(); def.Id = 0; def.Offset = 0; if ((flags & GFF.FieldFlags.IsStructure) != 0) { flags &= ~GFF.FieldFlags.IsStructure; def.Type = GFF.FieldType.Structure; def.StructureId = type; } else { def.Type = (GFF.FieldType)type; } def.Flags = flags; var instance = this.ExportField(def, offset, state); state.References.Add(offset, instance); return instance; }
private void ImportField(GFF.FieldDefinition def, GenericKeyValue data, long offset, ref long newOffset, ImportState state) { var endian = this.Endian; 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, endian); } else { output.WriteValueU32((uint)newOffset, endian); output.Seek(newOffset, SeekOrigin.Begin); output.WriteValueS32(list.Count, endian); 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, (GenericKeyValue)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, endian); 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, endian); } else { var length = s.Length + 1; output.WriteValueU32((uint)newOffset, endian); output.Seek(newOffset, SeekOrigin.Begin); output.WriteValueS32(length, endian); output.WriteString(s, endian == Endian.Little ? Encoding.Unicode : Encoding.BigEndianUnicode); output.WriteValueU16(0, endian); newOffset += 4 + (2 * length); } break; } case GFF.FieldType.TalkString: { var s = data.As <GFF.Builtins.TalkString>(); output.WriteValueU32(s.Id, endian); if (s.String == null) { output.WriteValueU32(0xFFFFFFFF, endian); } else if (s.String.Length == 0) { output.WriteValueU32(0, endian); } else { var length = s.String.Length + 1; output.WriteValueU32((uint)newOffset, endian); output.Seek(newOffset, SeekOrigin.Begin); output.WriteValueS32(length, endian); output.WriteString(s.String, endian == Endian.Little ? Encoding.Unicode : Encoding.BigEndianUnicode); output.WriteValueU16(0, endian); newOffset += 4 + (2 * length); } break; } case GFF.FieldType.Structure: { if (def.IsReference == true) { if (data == null || data.Values == null) { output.WriteValueU32(0xFFFFFFFF, endian); } else { output.WriteValueU32((uint)newOffset, endian); 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, endian); break; } } } }
private object ExportField(GFF.FieldDefinition def, long offset, ExportState state) { var endian = this.Endian; var input = this.Data; input.Seek(offset + def.Offset, SeekOrigin.Begin); if (def.IsReference == true && def.IsList == true) { var listOffset = input.ReadValueU32(endian); if (listOffset == 0xFFFFFFFF) { return(null); } input.Seek(listOffset, SeekOrigin.Begin); var count = input.ReadValueU32(endian); 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(endian); 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(endian); 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(endian); if (dataOffset == 0xFFFFFFFF) { list.Add(null); } else { if (this.FileVersion < 1) { input.Seek(dataOffset, SeekOrigin.Begin); var length = input.ReadValueU32(endian); list.Add(input.ReadString(length * 2, true, endian == Endian.Little ? 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 <GenericKeyValue>(); 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, endian)); } 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(endian); 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(endian); if (dataOffset == 0xFFFFFFFF) { return(""); } if (this.FileVersion < 1) { input.Seek(dataOffset, SeekOrigin.Begin); var count = input.ReadValueU32(endian); return(input.ReadString(count * 2, true, endian == Endian.Little ? Encoding.Unicode : Encoding.BigEndianUnicode)); } else { return(this.StringTable[(int)dataOffset]); } } case GFF.FieldType.TalkString: { var tlk = new GFF.Builtins.TalkString(); tlk.Id = input.ReadValueU32(endian); var dataOffset = input.ReadValueU32(endian); 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(endian); tlk.String = input.ReadString(count * 2, true, endian == Endian.Little ? 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, endian)); } } } }
public void Deserialize(Stream input) { input.Seek(0, SeekOrigin.Begin); var magic = input.ReadValueU32(false); if (magic != 0x47464620) { throw new FormatException(); } var version = input.ReadValueU32(false); if (version != 0x56342E30 && // 4.0 version != 0x56342E31) // 4.1 { throw new FormatException("unsupported version"); } this.FileVersion = (byte)(version - 0x56342E30); this.FilePlatform = input.ReadValueEnum<GFF.FilePlatform>(false); this.FormatType = input.ReadValueEnum<GFF.FormatType>(false); this.FormatVersion = input.ReadValueU32(false); var littleEndian = this.FilePlatform == GFF.FilePlatform.PC; var structCount = input.ReadValueU32(littleEndian); var stringCount = this.FileVersion < 1 ? 0 : input.ReadValueU32(littleEndian); var stringOffset = this.FileVersion < 1 ? 0 : input.ReadValueU32(littleEndian); var dataOffset = input.ReadValueU32(littleEndian); if (this.FileVersion < 1) { stringOffset = dataOffset; } else { if (dataOffset < stringOffset) { throw new FormatException(); } } this.Structures.Clear(); for (uint i = 0; i < structCount; i++) { var structDef = new GFF.StructureDefinition(); //structDef.Id = input.ReadValueU32(littleEndian); structDef.Id = input.ReadValueU32(false); var fieldCount = input.ReadValueU32(littleEndian); var fieldOffset = input.ReadValueU32(littleEndian); structDef.DataSize = input.ReadValueU32(littleEndian); long nextOffset = input.Position; structDef.Fields.Clear(); input.Seek(fieldOffset, SeekOrigin.Begin); for (uint j = 0; j < fieldCount; j++) { var fieldDef = new GFF.FieldDefinition(); fieldDef.Id = input.ReadValueS32(littleEndian); var rawFlags = input.ReadValueU32(littleEndian); fieldDef.Offset = input.ReadValueU32(littleEndian); var type = (ushort)(rawFlags & 0xFFFF); var flags = (GFF.FieldFlags)((rawFlags >> 16) & 0xFFFF); if ((flags & GFF.FieldFlags.IsStructure) != 0) { flags &= ~GFF.FieldFlags.IsStructure; fieldDef.Type = GFF.FieldType.Structure; fieldDef.StructureId = type; } else { fieldDef.Type = (GFF.FieldType)type; } fieldDef.Flags = flags; structDef.Fields.Add(fieldDef); } this.Structures.Add(structDef); input.Seek(nextOffset, SeekOrigin.Begin); } if (this.FileVersion >= 1) { input.Seek(stringOffset, SeekOrigin.Begin); this.StringTable = new List<string>(); for (uint i = 0; i < stringCount; i++) { this.StringTable.Add(input.ReadStringZ(Encoding.UTF8)); } } input.Seek(dataOffset, SeekOrigin.Begin); this.Data = input.ReadToMemoryStream(input.Length - dataOffset); }