public override void Read(BinaryReader reader, Resource resource) { // NTRO only in version 0? if (resource.IntrospectionManifest == null) { var block = new ResourceIntrospectionManifest.ResourceDiskStruct(); var field = new ResourceIntrospectionManifest.ResourceDiskStruct.Field { FieldName = "m_bitpackedsoundinfo", Type = DataType.UInt32, }; block.FieldIntrospection.Add(field); field = new ResourceIntrospectionManifest.ResourceDiskStruct.Field { FieldName = "m_loopStart", Type = DataType.Int32, OnDiskOffset = 4, }; block.FieldIntrospection.Add(field); field = new ResourceIntrospectionManifest.ResourceDiskStruct.Field { FieldName = "m_flDuration", Type = DataType.Float, OnDiskOffset = 12, }; block.FieldIntrospection.Add(field); resource.Blocks[BlockType.NTRO] = new ResourceIntrospectionManifest(); resource.IntrospectionManifest.ReferencedStructs.Add(block); } reader.BaseStream.Position = Offset; base.Read(reader, resource); LoopStart = ((NTROValue <int>)Output["m_loopStart"]).Value; Duration = ((NTROValue <float>)Output["m_flDuration"]).Value; var bitpackedSoundInfo = ((NTROValue <uint>)Output["m_bitpackedsoundinfo"]).Value; Type = (AudioFileType)ExtractSub(bitpackedSoundInfo, 0, 2); Bits = ExtractSub(bitpackedSoundInfo, 2, 5); Channels = ExtractSub(bitpackedSoundInfo, 7, 2); SampleSize = ExtractSub(bitpackedSoundInfo, 9, 3); AudioFormat = ExtractSub(bitpackedSoundInfo, 12, 2); SampleRate = ExtractSub(bitpackedSoundInfo, 14, 17); if (Type > AudioFileType.MP3) { throw new NotImplementedException($"Unknown audio file format '{Type}', please report this on GitHub."); } }
private const int SIGNATURE = 55987030; // "VKV\x03" aka valve keyvalue, version 3 public override void Read(BinaryReader reader, Resource resource) { if (resource.IntrospectionManifest == null) { var block = new ResourceIntrospectionManifest.ResourceDiskStruct(); var field = new ResourceIntrospectionManifest.ResourceDiskStruct.Field { FieldName = "m_Signature", Count = 1, Type = DataType.Int32 }; block.FieldIntrospection.Add(field); field = new ResourceIntrospectionManifest.ResourceDiskStruct.Field { FieldName = "m_Encoding", Count = 4, OnDiskOffset = 4, Type = DataType.Boolean }; block.FieldIntrospection.Add(field); field = new ResourceIntrospectionManifest.ResourceDiskStruct.Field { FieldName = "m_Format", Count = 4, OnDiskOffset = 20, Type = DataType.Boolean }; block.FieldIntrospection.Add(field); resource.Blocks[BlockType.NTRO] = new ResourceIntrospectionManifest(); resource.IntrospectionManifest.ReferencedStructs.Add(block); } base.Read(reader, resource); reader.BaseStream.Position = Offset; // TODO: Use parsed NTRO data if (reader.ReadUInt32() != SIGNATURE) { throw new InvalidDataException("Wrong signature."); } reader.BaseStream.Position += 32; // encoding + format (guids?) // TODO }
private void ReadFieldIntrospection(ResourceIntrospectionManifest.ResourceDiskStruct.Field field, ref NTROStruct structEntry) { var count = (uint)field.Count; var pointer = false; // TODO: get rid of this if (count == 0) { count = 1; } long prevOffset = 0; if (field.Indirections.Count > 0) { // TODO if (field.Indirections.Count > 1) { throw new NotImplementedException("More than one indirection, not yet handled."); } // TODO if (field.Count > 0) { throw new NotImplementedException("Indirection.Count > 0 && field.Count > 0"); } var indirection = field.Indirections[0]; // TODO: depth needs fixing? var offset = Reader.ReadUInt32(); if (indirection == 0x03) { pointer = true; if (offset == 0) { structEntry.Add(field.FieldName, new NTROValue <byte?>(field.Type, null, true)); //being byte shouldn't matter return; } prevOffset = Reader.BaseStream.Position; Reader.BaseStream.Position += offset - 4; } else if (indirection == 0x04) { count = Reader.ReadUInt32(); prevOffset = Reader.BaseStream.Position; if (count > 0) { Reader.BaseStream.Position += offset - 8; } } else { throw new NotImplementedException(string.Format("Unknown indirection. ({0})", indirection)); } } //if (pointer) //{ // Writer.Write("{0} {1}* = (ptr) ->", ValveDataType(field.Type), field.FieldName); //} if (field.Count > 0 || field.Indirections.Count > 0) { var ntroValues = new NTROArray(field.Type, (int)count, pointer, field.Indirections.Count > 0); for (var i = 0; i < count; i++) { ntroValues[i] = ReadField(field, pointer); } structEntry.Add(field.FieldName, ntroValues); } else { for (var i = 0; i < count; i++) { structEntry.Add(field.FieldName, ReadField(field, pointer)); } } if (prevOffset > 0) { Reader.BaseStream.Position = prevOffset; } }
private NTROValue ReadField(ResourceIntrospectionManifest.ResourceDiskStruct.Field field, bool pointer) { switch (field.Type) { case DataType.Struct: var newStruct = Resource.IntrospectionManifest.ReferencedStructs.First(x => x.Id == field.TypeData); return(new NTROValue <NTROStruct>(field.Type, ReadStructure(newStruct, Reader.BaseStream.Position), pointer)); case DataType.Enum: // TODO: Lookup in ReferencedEnums return(new NTROValue <uint>(field.Type, Reader.ReadUInt32(), pointer)); case DataType.SByte: return(new NTROValue <sbyte>(field.Type, Reader.ReadSByte(), pointer)); case DataType.Byte: return(new NTROValue <byte>(field.Type, Reader.ReadByte(), pointer)); case DataType.Boolean: return(new NTROValue <bool>(field.Type, Reader.ReadByte() == 1 ? true : false, pointer)); case DataType.Int16: return(new NTROValue <short>(field.Type, Reader.ReadInt16(), pointer)); case DataType.UInt16: return(new NTROValue <ushort>(field.Type, Reader.ReadUInt16(), pointer)); case DataType.Int32: return(new NTROValue <int>(field.Type, Reader.ReadInt32(), pointer)); case DataType.UInt32: return(new NTROValue <uint>(field.Type, Reader.ReadUInt32(), pointer)); case DataType.Float: return(new NTROValue <float>(field.Type, Reader.ReadSingle(), pointer)); case DataType.Int64: return(new NTROValue <long>(field.Type, Reader.ReadInt64(), pointer)); case DataType.ExternalReference: var id = Reader.ReadUInt64(); var value = id > 0 ? Resource.ExternalReferences?.ResourceRefInfoList.FirstOrDefault(c => c.Id == id) : null; return(new NTROValue <ResourceExtRefList.ResourceReferenceInfo>(field.Type, value, pointer)); case DataType.UInt64: return(new NTROValue <ulong>(field.Type, Reader.ReadUInt64(), pointer)); case DataType.Vector: var vector3 = new Vector3( Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle()); return(new NTROValue <Vector3>(field.Type, vector3, pointer)); case DataType.Quaternion: case DataType.Color: case DataType.Fltx4: case DataType.Vector4D: case DataType.Vector4D_44: var vector4 = new Vector4( Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle()); return(new NTROValue <Vector4>(field.Type, vector4, pointer)); case DataType.String4: case DataType.String: return(new NTROValue <string>(field.Type, Reader.ReadOffsetString(Encoding.UTF8), pointer)); case DataType.Matrix3x4: case DataType.Matrix3x4a: var matrix3x4a = new Matrix3x4( Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle()); return(new NTROValue <Matrix3x4>(field.Type, matrix3x4a, pointer)); case DataType.CTransform: var transform = new CTransform( Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle()); return(new NTROValue <CTransform>(field.Type, transform, pointer)); default: throw new NotImplementedException($"Unknown data type: {field.Type} (name: {field.FieldName})"); } }
private NTROSerialization.NTROValue ReadField(ResourceIntrospectionManifest.ResourceDiskStruct.Field field, bool pointer) { switch (field.Type) { case DataType.Struct: var newStruct = Resource.IntrospectionManifest.ReferencedStructs.First(x => x.Id == field.TypeData); return(new NTROSerialization.NTROValue <NTROSerialization.NTROStruct>(field.Type, ReadStructure(newStruct, Reader.BaseStream.Position), pointer)); case DataType.Enum: // TODO: Lookup in ReferencedEnums return(new NTROSerialization.NTROValue <uint>(field.Type, Reader.ReadUInt32(), pointer)); case DataType.SByte: return(new NTROSerialization.NTROValue <sbyte>(field.Type, Reader.ReadSByte(), pointer)); case DataType.Byte: return(new NTROSerialization.NTROValue <byte>(field.Type, Reader.ReadByte(), pointer)); case DataType.Boolean: return(new NTROSerialization.NTROValue <bool>(field.Type, Reader.ReadByte() == 1 ? true : false, pointer)); case DataType.Int16: return(new NTROSerialization.NTROValue <short>(field.Type, Reader.ReadInt16(), pointer)); case DataType.UInt16: return(new NTROSerialization.NTROValue <ushort>(field.Type, Reader.ReadUInt16(), pointer)); case DataType.Int32: return(new NTROSerialization.NTROValue <int>(field.Type, Reader.ReadInt32(), pointer)); case DataType.UInt32: return(new NTROSerialization.NTROValue <uint>(field.Type, Reader.ReadUInt32(), pointer)); case DataType.Float: return(new NTROSerialization.NTROValue <float>(field.Type, Reader.ReadSingle(), pointer)); case DataType.Int64: return(new NTROSerialization.NTROValue <long>(field.Type, Reader.ReadInt64(), pointer)); case DataType.ExternalReference: // Handled elsewhere case DataType.UInt64: return(new NTROSerialization.NTROValue <ulong>(field.Type, Reader.ReadUInt64(), pointer)); case DataType.Vector: var vector3 = new NTROSerialization.Vector3( Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle() ); return(new NTROSerialization.NTROValue <NTROSerialization.Vector3>(field.Type, vector3, pointer)); case DataType.Quaternion: case DataType.Color: case DataType.Fltx4: case DataType.Vector4D: var vector4 = new NTROSerialization.Vector4( Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle() ); return(new NTROSerialization.NTROValue <NTROSerialization.Vector4>(field.Type, vector4, pointer)); case DataType.String4: case DataType.String: return(new NTROSerialization.NTROValue <string>(field.Type, Reader.ReadOffsetString(Encoding.UTF8), pointer)); case DataType.Matrix3x4: case DataType.Matrix3x4a: var matrix3x4a = new NTROSerialization.Matrix3x4( Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle() ); return(new NTROSerialization.NTROValue <NTROSerialization.Matrix3x4>(field.Type, matrix3x4a, pointer)); case DataType.CTransform: var transform = new NTROSerialization.CTransform( Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle() ); return(new NTROSerialization.NTROValue <NTROSerialization.CTransform>(field.Type, transform, pointer)); default: throw new NotImplementedException(string.Format("Unknown data type: {0}", field.Type)); } }
private void ReadFieldIntrospection(ResourceIntrospectionManifest.ResourceDiskStruct.Field field) { uint count = (uint)field.Count; bool multiple = false; // TODO: get rid of this bool pointer = false; // TODO: get rid of this if (count == 0) { count = 1; } long prevOffset = 0; if (field.Indirections.Count > 0) { // TODO if (field.Indirections.Count > 1) { throw new NotImplementedException("More than one indirection, not yet handled."); } // TODO if (field.Count > 0) { throw new NotImplementedException("Indirection.Count > 0 && field.Count > 0"); } var indirection = field.Indirections[0]; // TODO: depth needs fixing? var offset = Reader.ReadUInt32(); if (indirection == 0x03) { pointer = true; if (offset == 0) { Writer.WriteLine("{0} {1}* = (ptr) ->NULL", ValveDataType(field.Type), field.FieldName); return; } prevOffset = Reader.BaseStream.Position; Reader.BaseStream.Position += offset - 4; } else if (indirection == 0x04) { count = Reader.ReadUInt32(); prevOffset = Reader.BaseStream.Position; if (count > 0) { multiple = true; Reader.BaseStream.Position += offset - 8; } } else { throw new NotImplementedException(string.Format("Unknown indirection. ({0})", indirection)); } } if (pointer) { Writer.Write("{0} {1}* = (ptr) ->", ValveDataType(field.Type), field.FieldName); } else if (field.Count > 0 || field.Indirections.Count > 0) { // TODO: This is matching Valve's incosistency if (field.Type == DataType.Byte && field.Indirections.Count > 0) { Writer.WriteLine("{0}[{2}] {1} =", ValveDataType(field.Type), field.FieldName, count); } else { Writer.WriteLine("{0} {1}[{2}] =", ValveDataType(field.Type), field.FieldName, count); } Writer.WriteLine("["); Writer.Indent++; } else { Writer.Write("{0} {1} = ", ValveDataType(field.Type), field.FieldName); } for (var i = 0; i < count; i++) { ReadField(field, multiple); } if (!pointer && (field.Count > 0 || field.Indirections.Count > 0)) { Writer.Indent--; Writer.WriteLine("]"); } if (prevOffset > 0) { Reader.BaseStream.Position = prevOffset; } }
private void ReadField(ResourceIntrospectionManifest.ResourceDiskStruct.Field field, bool multiple) { switch (field.Type) { case DataType.Struct: var newStruct = Resource.IntrospectionManifest.ReferencedStructs.First(x => x.Id == field.TypeData); ReadStructure(newStruct, Reader.BaseStream.Position); break; case DataType.Enum: // TODO: Lookup in ReferencedEnums Writer.WriteLine("{0}", Reader.ReadUInt32()); break; case DataType.SByte: Writer.WriteLine("{0}", Reader.ReadSByte()); break; case DataType.Byte: // TODO: Valve print it as hex, why? // TODO: if there are more than one uint8's, valve prints them without 0x, and on a single line if (multiple) { Writer.WriteLine("{0:X2}", Reader.ReadByte()); } else { Writer.WriteLine("0x{0:X2}", Reader.ReadByte()); } break; case DataType.Boolean: Writer.WriteLine("{0}", Reader.ReadByte() == 1 ? "true" : "false"); break; case DataType.Int16: Writer.WriteLine("{0}", Reader.ReadInt16()); break; case DataType.UInt16: // TODO: Valve print it as hex, why? Writer.WriteLine("0x{0:X4}", Reader.ReadUInt16()); break; case DataType.Int32: Writer.WriteLine("{0}", Reader.ReadInt32()); break; case DataType.UInt32: // TODO: Valve print it as hex, why? Writer.WriteLine("0x{0:X8}", Reader.ReadUInt32()); break; case DataType.Float: Writer.WriteLine("{0:F6}", Reader.ReadSingle()); break; case DataType.Int64: Writer.WriteLine("{0}", Reader.ReadInt64()); break; case DataType.UInt64: // TODO: Valve print it as hex, why? Writer.WriteLine("0x{0:X16}", Reader.ReadUInt64()); break; case DataType.ExternalReference: Writer.WriteLine("ID: {0:X16}", Reader.ReadUInt64()); break; case DataType.Vector: var vector3 = new [] { Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle() }; Writer.WriteLine("({0:F6}, {1:F6}, {2:F6})", vector3[0], vector3[1], vector3[2]); break; case DataType.Quaternion: case DataType.Color: case DataType.Fltx4: case DataType.Vector4D: var vector4 = new [] { Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle() }; if (field.Type == DataType.Quaternion) { Writer.WriteLine("{{x: {0:F}, y: {1:F}, z: {2:F}, w: {3}}}", vector4[0], vector4[1], vector4[2], vector4[3].ToString("F")); } else { Writer.WriteLine("({0:F6}, {1:F6}, {2:F6}, {3:F6})", vector4[0], vector4[1], vector4[2], vector4[3]); } break; case DataType.String4: case DataType.String: Writer.WriteLine("\"{0}\"", Reader.ReadOffsetString(Encoding.UTF8)); break; case DataType.Matrix3x4: case DataType.Matrix3x4a: var matrix3x4a = new [] { Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle() }; Writer.WriteLine(); Writer.WriteLine("{0:F4} {1:F4} {2:F4} {3:F4}", matrix3x4a[0], matrix3x4a[1], matrix3x4a[2], matrix3x4a[3]); Writer.WriteLine("{0:F4} {1:F4} {2:F4} {3:F4}", matrix3x4a[4], matrix3x4a[5], matrix3x4a[6], matrix3x4a[7]); Writer.WriteLine("{0:F4} {1:F4} {2:F4} {3:F4}", matrix3x4a[8], matrix3x4a[9], matrix3x4a[10], matrix3x4a[11]); break; case DataType.CTransform: var transform = new [] { Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle() // TODO: unused? }; // http://stackoverflow.com/a/15085178/2200891 Writer.WriteLine("q={{{0:F}, {1:F}, {2:F}; w={3}}} p={{{4:F}, {5:F}, {6}}}", transform[4], transform[5], transform[6], transform[7].ToString("F"), transform[0], transform[1], transform[2].ToString("F")); break; default: throw new NotImplementedException(string.Format("Unknown data type: {0}", field.Type)); } }
public override void Read(BinaryReader reader, Resource resource) { // NTRO only in version 0? if (resource.IntrospectionManifest == null) { var block = new ResourceIntrospectionManifest.ResourceDiskStruct(); var field = new ResourceIntrospectionManifest.ResourceDiskStruct.Field { FieldName = "m_bitpackedsoundinfo", Type = DataType.UInt32, }; block.FieldIntrospection.Add(field); field = new ResourceIntrospectionManifest.ResourceDiskStruct.Field { FieldName = "m_loopStart", Type = DataType.Int32, OnDiskOffset = 4, }; block.FieldIntrospection.Add(field); field = new ResourceIntrospectionManifest.ResourceDiskStruct.Field { FieldName = "m_flDuration", Type = DataType.Float, OnDiskOffset = 12, }; block.FieldIntrospection.Add(field); resource.Blocks.Add(new ResourceIntrospectionManifest()); resource.IntrospectionManifest.ReferencedStructs.Add(block); } reader.BaseStream.Position = Offset; base.Read(reader, resource); LoopStart = ((NTROValue <int>)Output["m_loopStart"]).Value; Duration = ((NTROValue <float>)Output["m_flDuration"]).Value; var bitpackedSoundInfo = ((NTROValue <uint>)Output["m_bitpackedsoundinfo"]).Value; // If these 5 bits are 0, it is the new format instead of the old if (ExtractSub(bitpackedSoundInfo, 27, 5) == 0) { // New format SampleRate = ExtractSub(bitpackedSoundInfo, 0, 16); SoundType = GetTypeFromNewFormat(ExtractSub(bitpackedSoundInfo, 16, 2)); // unknown = ExtractSub(bitpackedSoundInfo, 18, 2); Bits = ExtractSub(bitpackedSoundInfo, 20, 7); SampleSize = Bits / 8; Channels = 1; AudioFormat = 1; } else { // Old format SoundType = (AudioFileType)ExtractSub(bitpackedSoundInfo, 0, 2); Bits = ExtractSub(bitpackedSoundInfo, 2, 5); Channels = ExtractSub(bitpackedSoundInfo, 7, 2); SampleSize = ExtractSub(bitpackedSoundInfo, 9, 3); AudioFormat = ExtractSub(bitpackedSoundInfo, 12, 2); SampleRate = ExtractSub(bitpackedSoundInfo, 14, 17); } if (SoundType > AudioFileType.MP3) { throw new NotImplementedException($"Unknown audio file format '{SoundType}', please report this on GitHub."); } }