117 lines
4.7 KiB
C#

using System.IO;
using System.Text;
using Syroot.BinaryData;
namespace Syroot.Worms.OnlineWorms.Server.Net
{
/// <summary>
/// Represents a stream formatting data for being sent or received from <see cref="Packet"/> instances.
/// </summary>
internal class PacketStream : Stream
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
private static readonly Encoding _win949Encoding;
private readonly Stream _baseStream;
private bool _disposed;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
static PacketStream()
{
#if NETCOREAPP2_1
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
#endif
_win949Encoding = Encoding.GetEncoding(949);
}
internal PacketStream(Stream baseStream)
{
_baseStream = baseStream;
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public override bool CanRead => _baseStream.CanRead;
public override bool CanSeek => _baseStream.CanSeek;
public override bool CanWrite => _baseStream.CanWrite;
public override long Length => _baseStream.Length;
public override long Position
{
get => _baseStream.Position;
set => _baseStream.Position = value;
}
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public override void Flush() => _baseStream.Flush();
public override int Read(byte[] buffer, int offset, int count) => _baseStream.Read(buffer, offset, count);
public override long Seek(long offset, SeekOrigin origin) => _baseStream.Seek(offset, origin);
public override void SetLength(long value) => _baseStream.SetLength(value);
public override void Write(byte[] buffer, int offset, int count) => _baseStream.Write(buffer, offset, count);
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
protected override void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
_baseStream.Dispose();
_disposed = true;
base.Dispose(disposing);
}
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Reads <paramref name="count"/> number of bytes to the given <paramref name="buffer"/>, starting at the
/// specified <paramref name="offset"/>, and returns the number of bytes read. Since this method ensures that
/// the requested number of bytes is always read, it always returns <paramref name="count"/>, and otherwise
/// throws an <see cref="IOException"/> if the required bytes could not be read.
/// </summary>
/// <param name="buffer">The byte array to write the read data to.</param>
/// <param name="offset">The offset into <paramref name="buffer"/> at which to start writing data.</param>
/// <param name="count">The number of bytes to read into <paramref name="buffer"/>.</param>
/// <exception cref="IOException">The requested number of bytes could not be read.</exception>
internal void ReadAll(byte[] buffer, int offset, int count)
{
int totalRead = 0;
while (totalRead < count)
{
// Read returns 0 only when the underlying socket is closed, otherwise it blocks.
int read = _baseStream.Read(buffer, offset + totalRead, count - totalRead);
if (read == 0)
throw new IOException("The underlying stream has closed, 0 bytes were retrieved.");
totalRead += read;
}
}
/// <summary>
/// Reads a 2-byte length-prefixed, Windows-949 enoded string.
/// </summary>
/// <returns>The read value.</returns>
internal string ReadString()
{
return _baseStream.ReadString(StringCoding.Int16CharCount, _win949Encoding);
}
internal byte[] ReadToEnd()
{
return _baseStream.ReadBytes((int)(Length - Position));
}
/// <summary>
/// Writes a 2-byte length-prefixed, Windows-949 encoded string.
/// </summary>
/// <param name="value">The value to write.</param>
internal void WriteString(string value)
{
_baseStream.WriteString(value, StringCoding.Int16CharCount, _win949Encoding);
}
}
}