mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-04-11 11:50:07 +03:00
222 lines
9.3 KiB
C#
222 lines
9.3 KiB
C#
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using Syroot.BinaryData;
|
|
|
|
namespace Syroot.Worms.Core
|
|
{
|
|
/// <summary>
|
|
/// Represents extension methods for <see cref="BinaryStream"/> instances.
|
|
/// </summary>
|
|
[DebuggerStepThrough]
|
|
internal static partial class BinaryStreamExtensions
|
|
{
|
|
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
|
|
|
// ---- Reading ----
|
|
|
|
/// <summary>
|
|
/// Reads an <see cref="ILoadable"/> instance from the current stream.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the <see cref="ILoadable"/> class to instantiate.</typeparam>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/>.</param>
|
|
/// <returns>The <see cref="ILoadable"/> instance.</returns>
|
|
internal static T Load<T>(this BinaryStream self) where T : ILoadable, new()
|
|
{
|
|
T instance = new T();
|
|
instance.Load(self.BaseStream);
|
|
return instance;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads <see cref="ILoadable"/> instances from the current stream.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the <see cref="ILoadable"/> class to instantiate.</typeparam>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/>.</param>
|
|
/// <param name="count">The number of instances to read.</param>
|
|
/// <returns>The <see cref="ILoadable"/> instances.</returns>
|
|
internal static T[] Load<T>(this BinaryStream self, int count) where T : ILoadable, new()
|
|
{
|
|
T[] instances = new T[count];
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
instances[i] = Load<T>(self);
|
|
}
|
|
return instances;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads a 0-terminated string which is stored in a fixed-size block of <paramref name="length"/> bytes.
|
|
/// </summary>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/>.</param>
|
|
/// <param name="length">The number of bytes the fixed-size blocks takes.</param>
|
|
/// <returns>The read string.</returns>
|
|
internal static string ReadFixedString(this BinaryStream self, int length)
|
|
{
|
|
string str = self.ReadString(StringCoding.ZeroTerminated);
|
|
self.Seek(length - str.Length - 1);
|
|
return str;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads <paramref name="count"/> 0-terminated strings which are stored in a fixed-size block of
|
|
/// <paramref name="length"/> bytes.
|
|
/// </summary>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/>.</param>
|
|
/// <param name="count">The number of values to read.</param>
|
|
/// <param name="length">The number of bytes the fixed-size blocks takes.</param>
|
|
/// <returns>The read string.</returns>
|
|
internal static string[] ReadFixedStrings(this BinaryStream self, int count, int length)
|
|
{
|
|
string[] strings = new string[count];
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
strings[i] = ReadFixedString(self, length);
|
|
}
|
|
return strings;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads a raw byte structure from the current stream and returns it.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the structure to read.</typeparam>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
|
/// <returns>The structure of type <typeparamref name="T"/>.</returns>
|
|
internal static T ReadStruct<T>(this BinaryStream self) where T : struct
|
|
{
|
|
// Read the raw bytes of the structure.
|
|
byte[] bytes = self.ReadBytes(Marshal.SizeOf<T>());
|
|
|
|
// Convert them to a structure instance and return it.
|
|
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
|
T instance = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
|
|
handle.Free();
|
|
|
|
return instance;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads raw byte structures from the current stream and returns them.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the structure to read.</typeparam>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
|
/// <param name="count">The number of values to read.</param>
|
|
/// <returns>The structures of type <typeparamref name="T"/>.</returns>
|
|
internal static T[] ReadStructs<T>(this BinaryStream self, int count) where T : struct
|
|
{
|
|
T[] values = new T[count];
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
values[i] = ReadStruct<T>(self);
|
|
}
|
|
return values;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the current address of the stream to which a 4-byte placeholder has been written which can be filled
|
|
/// later.
|
|
/// </summary>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
|
/// <returns>The address at which a 4-byte placeholder has been written to.</returns>
|
|
internal static uint ReserveOffset(this BinaryStream self)
|
|
{
|
|
uint offset = (uint)self.Position;
|
|
self.WriteUInt32(0);
|
|
return offset;
|
|
}
|
|
|
|
// ---- Writing ----
|
|
|
|
/// <summary>
|
|
/// Writes the given <see cref="ISaveable"/> instance into the current stream.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the <see cref="ISaveable"/> class to write.</typeparam>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/>.</param>
|
|
/// <param name="value">The instance to write into the current stream.</param>
|
|
internal static void Save<T>(this BinaryStream self, T value) where T : ISaveable
|
|
{
|
|
value.Save(self.BaseStream);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes the given <see cref="ISaveable"/> instances into the current stream.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the <see cref="ISaveable"/> class to write.</typeparam>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/>.</param>
|
|
/// <param name="values">The instances to write into the current stream.</param>
|
|
internal static void Save<T>(this BinaryStream self, T[] values) where T : ISaveable
|
|
{
|
|
foreach (T value in values)
|
|
{
|
|
Save(self, value);
|
|
}
|
|
}
|
|
|
|
internal static void SatisfyOffset(this BinaryStream self, uint offset, int value)
|
|
{
|
|
using (self.TemporarySeek(offset, SeekOrigin.Begin))
|
|
self.WriteInt32(value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes the given string into a fixed-size block of <paramref name="length"/> bytes and 0-terminates it.
|
|
/// </summary>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
|
/// <param name="value">The string to write.</param>
|
|
/// <param name="length">The number of bytes the fixed-size block takes.</param>
|
|
internal static void Write(this BinaryStream self, string value, int length)
|
|
{
|
|
byte[] bytes = self.Encoding.GetBytes(value);
|
|
self.Write(bytes);
|
|
self.Write(new byte[length - bytes.Length]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes the given strings into fixed-size blocks of <paramref name="length"/> bytes and 0-terminates them.
|
|
/// </summary>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
|
/// <param name="values">The strings to write.</param>
|
|
/// <param name="length">The number of bytes a fixed-size block takes.</param>
|
|
internal static void Write(this BinaryStream self, string[] values, int length)
|
|
{
|
|
foreach (string value in values)
|
|
{
|
|
Write(self, value, length);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes the bytes of a structure into the current stream.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the structure to read.</typeparam>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
|
/// <param name="value">The structure to write.</param>
|
|
internal static void Write<T>(this BinaryStream self, T value) where T : struct
|
|
{
|
|
// Get the raw bytes of the structure instance.
|
|
byte[] bytes = new byte[Marshal.SizeOf<T>()];
|
|
|
|
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
|
Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), false);
|
|
handle.Free();
|
|
|
|
// Write the bytes to the stream.
|
|
self.Write(bytes);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes the bytes of structures into the current stream.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the structure to read.</typeparam>
|
|
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
|
/// <param name="values">The structures to write.</param>
|
|
internal static void Write<T>(this BinaryStream self, T[] values) where T : struct
|
|
{
|
|
foreach (T value in values)
|
|
{
|
|
Write(self, value);
|
|
}
|
|
}
|
|
}
|
|
}
|