diff --git a/NiflySharp/BaseTypes/NiHeader.cs b/NiflySharp/BaseTypes/NiHeader.cs index b63e792..508e7db 100644 --- a/NiflySharp/BaseTypes/NiHeader.cs +++ b/NiflySharp/BaseTypes/NiHeader.cs @@ -1,6 +1,7 @@ using NiflySharp.Stream; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; @@ -216,7 +217,9 @@ public void Read(NiStreamReader stream) Version.FileVersion = vfile; if (vfile >= NiVersion.ToFile(20, 0, 0, 3)) + { Endian = (NiEndian)stream.Reader.ReadByte(); + } else Endian = NiEndian.Little; @@ -256,7 +259,7 @@ public void Read(NiStreamReader stream) for (int i = 0; i < embedData.Capacity; i++) embedData.Add(stream.Reader.ReadByte()); } - + stream.Reader.Endian = Endian; if (vfile >= NiFileVersion.V5_0_0_1) { blockTypes = new List(stream.Reader.ReadUInt16()); @@ -367,7 +370,7 @@ public void Write(NiStreamWriter stream) stream.Writer.Write(embedData.Count); embedData.ForEach(ed => stream.Writer.Write(ed)); } - + stream.Writer.Endian = Endian; if (Version.FileVersion >= NiFileVersion.V5_0_0_1) { stream.Writer.Write((ushort)blockTypes.Count); diff --git a/NiflySharp/NifFile.cs b/NiflySharp/NifFile.cs index 79e0daa..cf95570 100644 --- a/NiflySharp/NifFile.cs +++ b/NiflySharp/NifFile.cs @@ -186,7 +186,7 @@ public int Load(System.IO.Stream stream, NifFileLoadOptions options = null) Clear(); return 1; } - + /* if (!(Header.Version.FileVersion >= NiVersion.ToFile(20, 2, 0, 7) && (Header.Version.UserVersion == 11 || Header.Version.UserVersion == 12))) { @@ -195,7 +195,6 @@ public int Load(System.IO.Stream stream, NifFileLoadOptions options = null) return 2; } */ - var streamReversible = new NiStreamReversible(streamReader); Blocks = new List(Header.BlockCount); @@ -212,6 +211,16 @@ public int Load(System.IO.Stream stream, NifFileLoadOptions options = null) blockTypeStr = nistr.Content; } + int dataStreamUsage = 0; + int dataStreamAccess = 0; + if (blockTypeStr.StartsWith("NiDataStream\x01")) + { + var parts = blockTypeStr.Split('\x01'); + blockTypeStr = parts[0]; + dataStreamUsage = int.Parse(parts[1]); + dataStreamAccess = int.Parse(parts[2]); + } + NiObject block = null; INiStreamable blockStreamable = null; @@ -236,6 +245,17 @@ public int Load(System.IO.Stream stream, NifFileLoadOptions options = null) block = blockStreamable as NiObject; } + if (blockTypeStr == "NiDataStream") + { + NiDataStream dataStream = block as NiDataStream; + if (dataStream != null) + { + dataStream.Usage = (DataStreamUsage)dataStreamUsage; + dataStream.Access = (DataStreamAccess)dataStreamAccess; + } + + } + if (block != null) Blocks.Add(block); } @@ -315,6 +335,7 @@ public int Save(System.IO.Stream stream, NifFileSaveOptions options = null) Header.Write(streamWriter); var streamReversible = new NiStreamReversible(streamWriter); + long blockStartPos = streamWriter.Writer.BaseStream.Position; // Retrieve block sizes from stream after writing each block diff --git a/NiflySharp/Stream/CustomBinaryReader.cs b/NiflySharp/Stream/CustomBinaryReader.cs new file mode 100644 index 0000000..6dd9858 --- /dev/null +++ b/NiflySharp/Stream/CustomBinaryReader.cs @@ -0,0 +1,116 @@ +using System; +using System.Buffers.Binary; +using System.Text; +using System.IO; + +namespace NiflySharp.Stream +{ + public class CustomBinaryReader : BinaryReader + { + public NiEndian Endian { get; set; } = NiEndian.Little; + + public CustomBinaryReader(System.IO.Stream input) + : base(input) + { + } + + public CustomBinaryReader(System.IO.Stream input, Encoding encoding) + : base(input, encoding) + { + } + + public CustomBinaryReader(System.IO.Stream input, Encoding encoding, bool leaveOpen) + : base(input, encoding, leaveOpen) + { + } + + private ReadOnlySpan ReadSpan(int byteCount) + { + byte[] buffer = new byte[byteCount]; + int read = BaseStream.Read(buffer, 0, byteCount); + if (read != byteCount) + throw new EndOfStreamException(); + return buffer; + } + + public override short ReadInt16() + { + var span = ReadSpan(2); + return Endian == NiEndian.Big + ? BinaryPrimitives.ReadInt16BigEndian(span) + : BinaryPrimitives.ReadInt16LittleEndian(span); + } + + public override ushort ReadUInt16() + { + var span = ReadSpan(2); + return Endian == NiEndian.Big + ? BinaryPrimitives.ReadUInt16BigEndian(span) + : BinaryPrimitives.ReadUInt16LittleEndian(span); + } + + public override int ReadInt32() + { + var span = ReadSpan(4); + return Endian == NiEndian.Big + ? BinaryPrimitives.ReadInt32BigEndian(span) + : BinaryPrimitives.ReadInt32LittleEndian(span); + } + + public override uint ReadUInt32() + { + var span = ReadSpan(4); + return Endian == NiEndian.Big + ? BinaryPrimitives.ReadUInt32BigEndian(span) + : BinaryPrimitives.ReadUInt32LittleEndian(span); + } + + public override long ReadInt64() + { + var span = ReadSpan(8); + return Endian == NiEndian.Big + ? BinaryPrimitives.ReadInt64BigEndian(span) + : BinaryPrimitives.ReadInt64LittleEndian(span); + } + + public override ulong ReadUInt64() + { + var span = ReadSpan(8); + return Endian == NiEndian.Big + ? BinaryPrimitives.ReadUInt64BigEndian(span) + : BinaryPrimitives.ReadUInt64LittleEndian(span); + } + + public override float ReadSingle() + { + var span = ReadSpan(4); + if (Endian == NiEndian.Big) + { + byte[] reversed = span.ToArray(); + Array.Reverse(reversed); + return BitConverter.ToSingle(reversed, 0); + } + return BitConverter.ToSingle(span); + } + + public override double ReadDouble() + { + var span = ReadSpan(8); + if (Endian == NiEndian.Big) + { + byte[] reversed = span.ToArray(); + Array.Reverse(reversed); + return BitConverter.ToDouble(reversed, 0); + } + return BitConverter.ToDouble(span); + } + + public override Half ReadHalf() + { + var span = ReadSpan(2); + return Endian == NiEndian.Big + ? BinaryPrimitives.ReadHalfBigEndian(span) + : BinaryPrimitives.ReadHalfLittleEndian(span); + } + } +} diff --git a/NiflySharp/Stream/CustomBinaryWriter.cs b/NiflySharp/Stream/CustomBinaryWriter.cs new file mode 100644 index 0000000..54bdcbf --- /dev/null +++ b/NiflySharp/Stream/CustomBinaryWriter.cs @@ -0,0 +1,164 @@ +using NiflySharp; +using System; +using System.Buffers.Binary; +using System.Text; +using System.IO; + +namespace NiflySharp.Stream +{ + public class CustomBinaryWriter : BinaryWriter + { + public NiEndian Endian { get; set; } = NiEndian.Little; + + public CustomBinaryWriter(System.IO.Stream output) + : base(output) + { + } + + public CustomBinaryWriter(System.IO.Stream output, Encoding encoding) + : base(output, encoding) + { + } + + public CustomBinaryWriter(System.IO.Stream output, Encoding encoding, bool leaveOpen) + : base(output, encoding, leaveOpen) + { + } + + protected CustomBinaryWriter() + { + } + + private void WriteSpan(ReadOnlySpan span) + { + OutStream.Write(span); + } + + public override void Write(short value) + { + Span buffer = stackalloc byte[2]; + if (Endian == NiEndian.Big) + BinaryPrimitives.WriteInt16BigEndian(buffer, value); + else + BinaryPrimitives.WriteInt16LittleEndian(buffer, value); + + WriteSpan(buffer); + } + + public override void Write(ushort value) + { + Span buffer = stackalloc byte[2]; + if (Endian == NiEndian.Big) + BinaryPrimitives.WriteUInt16BigEndian(buffer, value); + else + BinaryPrimitives.WriteUInt16LittleEndian(buffer, value); + + WriteSpan(buffer); + } + + public override void Write(int value) + { + Span buffer = stackalloc byte[4]; + if (Endian == NiEndian.Big) + BinaryPrimitives.WriteInt32BigEndian(buffer, value); + else + BinaryPrimitives.WriteInt32LittleEndian(buffer, value); + + WriteSpan(buffer); + } + + public override void Write(uint value) + { + Span buffer = stackalloc byte[4]; + if (Endian == NiEndian.Big) + BinaryPrimitives.WriteUInt32BigEndian(buffer, value); + else + BinaryPrimitives.WriteUInt32LittleEndian(buffer, value); + + WriteSpan(buffer); + } + + public override void Write(long value) + { + Span buffer = stackalloc byte[8]; + if (Endian == NiEndian.Big) + BinaryPrimitives.WriteInt64BigEndian(buffer, value); + else + BinaryPrimitives.WriteInt64LittleEndian(buffer, value); + + WriteSpan(buffer); + } + + public override void Write(ulong value) + { + Span buffer = stackalloc byte[8]; + if (Endian == NiEndian.Big) + BinaryPrimitives.WriteUInt64BigEndian(buffer, value); + else + BinaryPrimitives.WriteUInt64LittleEndian(buffer, value); + + WriteSpan(buffer); + } + + public override void Write(float value) + { + Span buffer = stackalloc byte[4]; + BitConverter.TryWriteBytes(buffer, value); + + if (Endian == NiEndian.Big) + { + buffer[0] = buffer[3]; + buffer[1] = buffer[2]; + buffer[2] = buffer[1]; + buffer[3] = buffer[0]; + } + + WriteSpan(buffer); + } + + public override void Write(double value) + { + Span buffer = stackalloc byte[8]; + BitConverter.TryWriteBytes(buffer, value); + + if (Endian == NiEndian.Big) + { + buffer[0] = buffer[7]; + buffer[1] = buffer[6]; + buffer[2] = buffer[5]; + buffer[3] = buffer[4]; + buffer[4] = buffer[3]; + buffer[5] = buffer[2]; + buffer[6] = buffer[1]; + buffer[7] = buffer[0]; + } + + WriteSpan(buffer); + } + + public override void Write(Half value) + { + Span buffer = stackalloc byte[2]; + if (Endian == NiEndian.Big) + BinaryPrimitives.WriteHalfBigEndian(buffer, value); + else + BinaryPrimitives.WriteHalfLittleEndian(buffer, value); + + WriteSpan(buffer); + } + + public override void Write(decimal value) + { + Span buffer = stackalloc byte[16]; + int[] bits = decimal.GetBits(value); + for (int i = 0; i < 4; i++) + { + if (Endian == NiEndian.Big) + BinaryPrimitives.WriteInt32BigEndian(buffer.Slice(i * 4, 4), bits[i]); + else + BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(i * 4, 4), bits[i]); + } + WriteSpan(buffer); + } + } +} diff --git a/NiflySharp/Stream/NiStreamReader.cs b/NiflySharp/Stream/NiStreamReader.cs index 2b748b9..0a752dc 100644 --- a/NiflySharp/Stream/NiStreamReader.cs +++ b/NiflySharp/Stream/NiStreamReader.cs @@ -1,17 +1,16 @@ -using System.IO; -using System.Text; +using System.Text; namespace NiflySharp.Stream { public class NiStreamReader { - public BinaryReader Reader { get; } + public CustomBinaryReader Reader { get; } public NifFile File { get; } public NiStreamReader(System.IO.Stream stream, NifFile file) { - Reader = new BinaryReader(stream, Encoding.UTF8, true); + Reader = new CustomBinaryReader(stream, Encoding.UTF8, true); File = file; } diff --git a/NiflySharp/Stream/NiStreamReversible.cs b/NiflySharp/Stream/NiStreamReversible.cs index 0e5cd4d..76de6a0 100644 --- a/NiflySharp/Stream/NiStreamReversible.cs +++ b/NiflySharp/Stream/NiStreamReversible.cs @@ -936,4 +936,4 @@ public void SyncGeneric(ref ValueT t, TypeSyncInfo typeSyncInfo) } } } -} +} \ No newline at end of file diff --git a/NiflySharp/Stream/NiStreamWriter.cs b/NiflySharp/Stream/NiStreamWriter.cs index 12f4431..3896e3c 100644 --- a/NiflySharp/Stream/NiStreamWriter.cs +++ b/NiflySharp/Stream/NiStreamWriter.cs @@ -1,11 +1,10 @@ -using System.IO; -using System.Text; +using System.Text; namespace NiflySharp.Stream { public class NiStreamWriter { - public BinaryWriter Writer { get; } + public CustomBinaryWriter Writer { get; } public NifFile File { get; } @@ -13,7 +12,7 @@ public class NiStreamWriter public NiStreamWriter(System.IO.Stream stream, NifFile file) { - Writer = new BinaryWriter(stream, Encoding.UTF8, true); + Writer = new CustomBinaryWriter(stream, Encoding.UTF8, true); File = file; } }