SharpNBT/SharpNBT/VarInt.cs

117 lines
6.4 KiB
C#

using System;
using System.IO;
using JetBrains.Annotations;
namespace SharpNBT
{
/// <summary>
/// Provides static methods for reading and writing variable-length integers that are up to 5 bytes from both streams and buffers.
/// </summary>
[PublicAPI]
public static class VarInt
{
/// <summary>
/// Encodes the given <paramref name="value"/> to a variable-length integer up to 5 bytes long, and writes it to the <paramref name="stream"/>.
/// </summary>
/// <param name="stream">A <see cref="Stream"/> instance to write the value to.</param>
/// <param name="value">The value to encode and write.</param>
/// <param name="zigzag">Flag indicating if the value will be ZigZag encoded.</param>
/// <returns>The number of bytes written to the <paramref name="stream"/>.</returns>
public static int Write([NotNull] Stream stream, int value, bool zigzag = false)
{
var buffer = Encode(value, zigzag);
stream.Write(buffer, 0, buffer.Length);
return buffer.Length;
}
/// <summary>
/// Reads up to 5 bytes from the given <paramref name="stream"/> and returns the VarInt value as a 32-bit integer.
/// </summary>
/// <param name="stream">A <see cref="Stream"/> instance to read from.</param>
/// <param name="zigzag">Flag indicating if the value is ZigZag encoded.</param>
/// <returns>The parsed value read from the <paramref name="stream"/>.</returns>
public static int Read([NotNull] Stream stream, bool zigzag = false)
{
var value = VarIntUtil.Decode(stream, 32, out var dummy);
return zigzag ? (int) VarIntUtil.DecodeZigZag(value) : unchecked((int)value);
}
/// <summary>
/// Reads up to 5 bytes from the given <paramref name="stream"/> and returns the VarInt value as a 32-bit integer.
/// </summary>
/// <param name="stream">A <see cref="Stream"/> instance to read from.</param>
/// <param name="size">A variable to store the number of bytes read from the <paramref name="stream"/>.</param>
/// <param name="zigzag">Flag indicating if the value is ZigZag encoded.</param>
/// <returns>The parsed value read from the <paramref name="stream"/>.</returns>
public static int Read([NotNull] Stream stream, out int size, bool zigzag = false)
{
var value = VarIntUtil.Decode(stream, 32, out size);
return zigzag ? (int) VarIntUtil.DecodeZigZag(value) : unchecked((int)value);
}
/// <summary>
/// Encodes the given <paramref name="value"/> and returns an array of bytes that represent it.
/// </summary>
/// <param name="value">The value to encode.</param>
/// <param name="zigzag">Flag indicating if the value will be ZigZag encoded.</param>
/// <returns>An array of bytes representing the <paramref name="value"/> as a variable length integer.</returns>
public static byte[] Encode(int value, bool zigzag = false)
{
if (zigzag)
return VarIntUtil.Encode(unchecked((ulong)VarIntUtil.EncodeZigZag(value, 32)));
return VarIntUtil.Encode(unchecked((uint)value));
}
/// <summary>
/// Decodes a buffer of bytes that represent a variable-length integer up to 5 bytes long.
/// </summary>
/// <param name="buffer">A buffer containing the data to be decoded.</param>
/// <param name="offset">The offset into the <paramref name="buffer"/> to begin reading.</param>
/// <param name="count">The maximum number of bytes that should be read from the <paramref name="buffer"/>.</param>
/// <param name="size">A variable to store the actual number of bytes read from the <paramref name="buffer"/>.</param>
/// <param name="zigzag">Flag indicating if the value is ZigZag encoded.</param>
/// <returns>The decoded value.</returns>
public static long Decode([NotNull] byte[] buffer, int offset, int count, out int size, bool zigzag = false)
{
return Decode(new ReadOnlySpan<byte>(buffer, offset, count), out size, zigzag);
}
/// <summary>
/// Decodes a buffer of bytes that represent a variable-length integer up to 5 bytes long.
/// </summary>
/// <param name="buffer">A buffer containing the data to be decoded.</param>
/// <param name="offset">The offset into the <paramref name="buffer"/> to begin reading.</param>
/// <param name="count">The maximum number of bytes that should be read from the <paramref name="buffer"/>.</param>
/// <param name="zigzag">Flag indicating if the value is ZigZag encoded.</param>
/// <returns>The decoded value.</returns>
public static long Decode([NotNull] byte[] buffer, int offset, int count, bool zigzag = false)
{
return Decode(new ReadOnlySpan<byte>(buffer, offset, count), out var dummy, zigzag);
}
/// <summary>
/// Decodes a buffer of bytes that represent a variable-length integer up to 5 bytes long.
/// </summary>
/// <param name="buffer">A buffer containing the data to be decoded.</param>
/// <param name="size">A variable to store the actual number of bytes read from the <paramref name="buffer"/>.</param>
/// <param name="zigzag">Flag indicating if the value is ZigZag encoded.</param>
/// <returns>The decoded value.</returns>
public static int Decode(ReadOnlySpan<byte> buffer, out int size, bool zigzag = false)
{
var value = VarIntUtil.Decode(buffer, 32, out size);
return zigzag ? (int) VarIntUtil.DecodeZigZag(value) : unchecked((int)value);
}
/// <summary>
/// Decodes a buffer of bytes that represent a variable-length integer up to 5 bytes long.
/// </summary>
/// <param name="buffer">A buffer containing the data to be decoded.</param>
/// <param name="zigzag">Flag indicating if the value is ZigZag encoded.</param>
/// <returns>The decoded value.</returns>
public static int Decode(ReadOnlySpan<byte> buffer, bool zigzag = false)
{
var value = VarIntUtil.Decode(buffer, 32, out var dummy);
return zigzag ? (int) VarIntUtil.DecodeZigZag(value) : unchecked((int)value);
}
}
}