Skip to content

Instantly share code, notes, and snippets.

@xinmyname
Created April 3, 2018 21:36
Show Gist options
  • Save xinmyname/4a2a033d9211ddb32bccefca7cf3d802 to your computer and use it in GitHub Desktop.
Save xinmyname/4a2a033d9211ddb32bccefca7cf3d802 to your computer and use it in GitHub Desktop.
C# Stream Extensions for reading/writing protocol buffers
using System;
using System.IO;
using Google.Protobuf;
namespace ProtoCore
{
public static class StreamExtensions
{
public static void Write(this Stream stream, IMessage message)
{
byte[] messageData = message.ToByteArray();
stream.WriteLength(messageData.Length);
stream.Write(messageData, 0, messageData.Length);
}
public static T Read<T>(this Stream stream) where T : IMessage<T>, new()
{
int length = stream.ReadLength();
var messageData = new byte[length];
stream.Read(messageData, 0, length);
var parser = new MessageParser<T>(() => new T());
return parser.ParseFrom(messageData, 0, length);
}
private static void WriteLength(this Stream stream, int length)
{
if (length < 64)
stream.WriteByte((byte)length);
else if (length < 16384)
{
var encodedLength = (ushort)(((length & 0xFF) << 8) | (length >> 8) | 0x40);
stream.Write(BitConverter.GetBytes(encodedLength), 0, sizeof(ushort));
}
else if (length < 1_073_741_824)
{
long longLen = length;
var encodedLength = (ulong) (
((longLen & 0xFF) << 24) |
((longLen & 0xFF00) << 8) |
((longLen & 0xFF0000) >> 8) |
((longLen & 0xFF000000) >> 24) | 0x80);
stream.Write(BitConverter.GetBytes(encodedLength), 0, sizeof(ulong));
}
else
throw new ArgumentException($"Length ({length}) is too long to be represented in byte stream.", nameof(length));
}
private static int ReadLength(this Stream stream)
{
int hiByte = stream.ReadByte();
if ((hiByte & 0x80) != 0)
{
var lenData = new byte[4];
lenData[3] = (byte) (hiByte & 0x3F);
lenData[2] = (byte) stream.ReadByte();
lenData[1] = (byte) stream.ReadByte();
lenData[0] = (byte) stream.ReadByte();
int len = BitConverter.ToInt32(lenData, 0);
return len;
}
if ((hiByte & 0x40) != 0)
{
var lenData = new byte[2];
lenData[1] = (byte) (hiByte & 0x3F);
lenData[0] = (byte)stream.ReadByte();
int len = BitConverter.ToInt16(lenData, 0);
return len;
}
return hiByte;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment