/// <summary>
    /// Unsigned VarInt format
    /// </summary>
    public static void WriteUInt64(CitoStream stream, int val)
    {
        byte[] buffer = new byte[10];
        int    count  = 0;

        while (true)
        {
#if !CITO
            buffer[count] = (byte)(val & 0x7F);
#else
            buffer[count] = (val & 0x7F).LowByte;
#endif
            val = ProtoPlatform.logical_right_shift(val, 7);
            if (val == 0)
            {
                break;
            }

            buffer[count] |= 0x80;

            count += 1;
        }

        stream.Write(buffer, 0, count + 1);
    }
    /// <summary>
    /// Read the value for an unknown key as bytes.
    /// Used to preserve unknown keys during deserialization.
    /// Requires the message option preserveunknown=true.
    /// </summary>
    public static byte[] ReadValueBytes(CitoStream stream, Key key)
    {
        byte[] b;
        int    offset = 0;

        switch (key.GetWireType())
        {
        case Wire.Fixed32:
            b = new byte[4];
            while (offset < 4)
            {
                offset += stream.Read(b, offset, 4 - offset);
            }
            return(b);

        case Wire.Fixed64:
            b = new byte[8];
            while (offset < 8)
            {
                offset += stream.Read(b, offset, 8 - offset);
            }
            return(b);

        case Wire.LengthDelimited:
            //Read and include length in value buffer
            int length          = ProtocolParser.ReadUInt32(stream);
            CitoMemoryStream ms = new CitoMemoryStream();
            {
                //TODO: pass b directly to MemoryStream constructor or skip usage of it completely
                ProtocolParser.WriteUInt32(ms, length);
                b = new byte[length + ms.Length()];
                byte[] arr = ms.ToArray();
                for (int i = 0; i < ProtoPlatform.ArrayLength(arr); i++)
                {
                    b[i] = arr[i];
                }
                offset = ms.Length();
            }

            //Read data into buffer
            while (offset < ProtoPlatform.ArrayLength(b))
            {
                offset += stream.Read(b, offset, ProtoPlatform.ArrayLength(b) - offset);
            }
            return(b);

        case Wire.Varint:
            return(ProtocolParser.ReadVarIntBytes(stream));

        default:
#if !CITO
            throw new NotImplementedException("Unknown wire type: " + key.GetWireType());
#else
            return(null);
#endif
        }
    }
    public static byte[] ReadVarIntBytes(CitoStream stream)
    {
        byte[] buffer = new byte[10];
        int    offset = 0;

        while (true)
        {
            int b = stream.ReadByte();
            if (b < 0)
#if !CITO
            { throw new IOException("Stream ended too early"); }
#else
            { return(null); }
#endif
#if !CITO
            buffer[offset] = (byte)b;
#else
            buffer[offset] = b.LowByte;
#endif
            offset += 1;
            if ((b & 0x80) == 0)
            {
                break; //end of varint
            }
            if (offset >= ProtoPlatform.ArrayLength(buffer))
#if !CITO
            { throw new InvalidDataException("VarInt too long, more than 10 bytes"); }
#else
            { return(null); }
#endif
        }
        byte[] ret = new byte[offset];
        for (int i = 0; i < offset; i++)
        {
            ret[i] = buffer[i];
        }
        return(ret);
    }
 /// <summary>
 /// Writes length delimited byte array
 /// </summary>
 public static void WriteBytes(CitoStream stream, byte[] val)
 {
     WriteUInt32_(stream, ProtoPlatform.ArrayLength(val));
     stream.Write(val, 0, ProtoPlatform.ArrayLength(val));
 }
 public static void WriteString(CitoStream stream, string val)
 {
     WriteBytes(stream, ProtoPlatform.StringToBytes(val));
 }
 public static string ReadString(CitoStream stream)
 {
     byte[] bytes = ReadBytes(stream);
     return(ProtoPlatform.BytesToString(bytes, 0));
 }