skyscraper8/skyscraper8/Skyscraper/IO/StreamExtensions.cs
feyris-tan 0c0932e193
Some checks failed
🚀 Pack skyscraper8 / make-zip (push) Failing after 43s
Added a method to read RF Spectrums off an object storage.
2026-05-03 21:31:47 +02:00

392 lines
12 KiB
C#

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
namespace skyscraper5.Skyscraper.IO
{
public static class StreamExtensions
{
[DebuggerStepThrough]
public static ushort ReadUInt16BE(this Stream stream)
{
byte[] buffer = new byte[2];
if (stream.Read(buffer, 0, 2) != 2)
throw new EndOfStreamException();
if (BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 2);
return BitConverter.ToUInt16(buffer, 0);
}
public static short ReadInt16LE(this Stream stream)
{
byte[] buffer = new byte[2];
if (stream.Read(buffer, 0, 2) != 2)
throw new EndOfStreamException();
if (!BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 2);
return BitConverter.ToInt16(buffer, 0);
}
public static ushort ReadUInt16LE(this Stream stream)
{
byte[] buffer = new byte[2];
if (stream.Read(buffer, 0, 2) != 2)
throw new EndOfStreamException();
if (!BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 2);
return BitConverter.ToUInt16(buffer, 0);
}
[DebuggerStepThrough]
public static uint ReadUInt32BE(this Stream stream)
{
byte[] buffer = new byte[4];
if (stream.Read(buffer, 0, 4) != 4)
throw new EndOfStreamException();
if (BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 4);
return BitConverter.ToUInt32(buffer, 0);
}
[DebuggerStepThrough]
public static uint ReadUInt32LE(this Stream stream)
{
byte[] buffer = new byte[4];
if (stream.Read(buffer, 0, 4) != 4)
throw new EndOfStreamException();
if (!BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 4);
return BitConverter.ToUInt32(buffer, 0);
}
public static int ReadInt32LE(this Stream stream)
{
byte[] buffer = new byte[4];
if (stream.Read(buffer, 0, 4) != 4)
throw new EndOfStreamException();
if (!BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 4);
return BitConverter.ToInt32(buffer, 0);
}
public static ulong ReadUInt48BE(this Stream stream)
{
ulong result = 0;
result = ReadUInt16BE(stream);
result <<= 32;
result += ReadUInt32BE(stream);
return result;
}
public static long ReadInt64LE(this Stream stream)
{
byte[] buffer = new byte[8];
if (stream.Read(buffer, 0, 8) != 8)
throw new EndOfStreamException();
if (!BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 4);
return BitConverter.ToInt64(buffer, 0);
}
public static ulong ReadUInt64LE(this Stream stream)
{
byte[] buffer = new byte[8];
if (stream.Read(buffer, 0, 8) != 8)
throw new EndOfStreamException();
if (!BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 4);
return BitConverter.ToUInt64(buffer, 0);
}
public static ulong ReadUInt64BE(this Stream stream)
{
byte[] buffer = new byte[8];
if (stream.Read(buffer, 0, 8) != 8)
throw new EndOfStreamException();
if (BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 4);
return BitConverter.ToUInt64(buffer, 0);
}
[DebuggerStepThrough]
public static byte[] ReadBytes(this Stream stream, long length)
{
if (length > Int32.MaxValue)
throw new ArgumentOutOfRangeException();
if (length == 0)
return new byte[0];
if (length < 0)
throw new ArgumentOutOfRangeException();
int length32 = (int)length;
byte[] buffer = new byte[length32];
if (stream.Read(buffer, 0, length32) != length32)
throw new EndOfStreamException();
return buffer;
}
[DebuggerStepThrough]
public static sbyte[] ReadSBytes(this Stream stream, long length)
{
if (length > Int32.MaxValue)
throw new ArgumentOutOfRangeException();
if (length == 0)
return new sbyte[0];
if (length < 0)
throw new ArgumentOutOfRangeException();
int length32 = (int)length;
sbyte[] buffer = new sbyte[length32];
for (int i = 0; i < length32; i++)
{
buffer[i] = (sbyte)stream.ReadUInt8();
}
return buffer;
}
[DebuggerStepThrough]
public static byte ReadUInt8(this Stream stream)
{
byte[] buffer = new byte[1];
if (stream.Read(buffer, 0, 1) != 1)
throw new EndOfStreamException();
return buffer[0];
}
[DebuggerStepThrough]
public static long GetAvailableBytes(this Stream stream)
{
if (stream is GZipStream)
{
GZipStream gzip = (GZipStream)stream;
long baseStreamPosition = gzip.BaseStream.Length - gzip.BaseStream.Position;
return baseStreamPosition;
}
return stream.Length - stream.Position;
}
public static void WriteUInt8Repeat(this Stream stream, byte uint8, int repetitions)
{
byte[] buffer = new byte[repetitions];
Array.Fill(buffer, uint8);
stream.Write(buffer, 0, repetitions);
}
public static uint ReadUInt24BE(this Stream stream)
{
uint result = stream.ReadUInt16BE();
result <<= 8;
result += stream.ReadUInt8();
return result;
}
public static double ReadDouble(this Stream stream)
{
byte[] buffer = new byte[8];
if (stream.Read(buffer, 0, 8) != 8)
throw new EndOfStreamException();
if (!BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 8);
return BitConverter.ToDouble(buffer, 0);
}
public static void WriteUInt8(this Stream stream, byte value)
{
byte[] buffer = new byte[1];
buffer[0] = value;
stream.Write(buffer, 0, 1);
}
public static void WriteUInt16BE(this Stream stream, ushort value)
{
byte[] buffer = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian)
(buffer[0], buffer[1]) = (buffer[1], buffer[0]);
stream.Write(buffer, 0, 2);
}
public static void WriteUInt16LE(this Stream stream, ushort value)
{
byte[] buffer = BitConverter.GetBytes(value);
if (!BitConverter.IsLittleEndian)
(buffer[0], buffer[1]) = (buffer[1], buffer[0]);
stream.Write(buffer, 0, 2);
}
public static void WriteInt32BE(this Stream stream, int value)
{
byte[] buffer = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian)
(buffer[0], buffer[1], buffer[2], buffer[3]) = (buffer[3], buffer[2], buffer[1], buffer[0]);
stream.Write(buffer, 0, 4);
}
public static void WriteUInt32BE(this Stream stream, uint value)
{
byte[] buffer = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian)
(buffer[0], buffer[1], buffer[2], buffer[3]) = (buffer[3], buffer[2], buffer[1], buffer[0]);
stream.Write(buffer, 0, 4);
}
public static void WriteUInt32LE(this Stream stream, uint value)
{
byte[] buffer = BitConverter.GetBytes(value);
if (!BitConverter.IsLittleEndian)
(buffer[0], buffer[1], buffer[2], buffer[3]) = (buffer[3], buffer[2], buffer[1], buffer[0]);
stream.Write(buffer, 0, 4);
}
public static void WriteInt32LE(this Stream stream, int value)
{
byte[] buffer = BitConverter.GetBytes(value);
if (!BitConverter.IsLittleEndian)
(buffer[0], buffer[1], buffer[2], buffer[3]) = (buffer[3], buffer[2], buffer[1], buffer[0]);
stream.Write(buffer, 0, 4);
}
public static void WriteInt64LE(this Stream stream, long value)
{
byte[] buffer = BitConverter.GetBytes(value);
if (!BitConverter.IsLittleEndian)
(buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]) = (buffer[7], buffer[6], buffer[5], buffer[4], buffer[3], buffer[2], buffer[1], buffer[0]);
stream.Write(buffer, 0, 8);
}
public static string ReadUTF8FixedLength(this Stream stream, int length)
{
byte[] buffer = new byte[length];
if (stream.Read(buffer, 0, length) != length)
throw new EndOfStreamException();
return Encoding.UTF8.GetString(buffer);
}
public static string ReadUTF16NullTerminated(this Stream stream)
{
StringBuilder sb = new StringBuilder();
do
{
char c = (char)stream.ReadUInt16LE();
if (c == 0)
return sb.ToString();
sb.Append(c);
} while (stream.Position != stream.Length);
return sb.ToString();
}
[DebuggerStepThrough]
public static string ReadAsciiNullTerminated(this Stream stream)
{
StringBuilder sb = new StringBuilder();
do
{
char c = (char)stream.ReadUInt8();
if (c == 0)
return sb.ToString();
sb.Append(c);
} while(stream.Position != stream.Length);
return sb.ToString();
}
/// <summary>
/// Writes a variable-length integer to the stream.
/// (code generated by ChatGPT, model GPT-4o)
/// </summary>
public static void WriteVarInt(this Stream stream, long value)
{
while ((value & ~0x7F) != 0) // More than 7 bits left?
{
stream.WriteByte((byte)((value & 0x7F) | 0x80)); // Write 7 bits + set highest bit
value >>= 7; // Shift right by 7 bits
}
stream.WriteByte((byte)value); // Write last byte (highest bit unset)
}
/// <summary>
/// Reads a variable-length integer from the stream.
/// (code generated by ChatGPT, model GPT-4o)
/// </summary>
public static int ReadVarInt(this Stream stream)
{
int result = 0;
int shift = 0;
byte currentByte;
do
{
currentByte = (byte)stream.ReadByte();
result |= (currentByte & 0x7F) << shift; // Extract 7 bits and shift
shift += 7;
}
while ((currentByte & 0x80) != 0); // Continue while highest bit is set
return result;
}
public static double ReadFloat64LE(this Stream stream)
{
byte[] buffer = new byte[8];
if (stream.Read(buffer, 0, 8) != 8)
throw new EndOfStreamException();
if (!BitConverter.IsLittleEndian)
Array.Reverse(buffer);
return BitConverter.ToDouble(buffer, 0);
}
public static void WriteFloat64LE(this Stream stream, double value)
{
byte[] buffer = BitConverter.GetBytes(value);
if (!BitConverter.IsLittleEndian)
Array.Reverse(buffer);
stream.Write(buffer, 0, 8);
}
public static byte Peek(this Stream stream)
{
if (!stream.CanSeek)
throw new NotSupportedException("Stream is not peekable");
if (stream.Position == stream.Length)
throw new EndOfStreamException();
byte readUInt8 = stream.ReadUInt8();
stream.Position--;
return readUInt8;
}
public static void DumpToFile(this Stream stream, string filename)
{
FileStream fileStream = File.OpenWrite(filename);
stream.CopyTo(fileStream);
fileStream.Flush(true);
fileStream.Close();
fileStream.Dispose();
}
public static int TryReadExactly(this Stream stream, byte[] buffer, int offset, int count)
{
int totalRead = 0;
while (totalRead < count)
{
int bytesRead = stream.Read(buffer, offset + totalRead, count - totalRead);
if (bytesRead == 0)
{
// End of stream
break;
}
totalRead += bytesRead;
}
return totalRead;
}
}
}