Example #1
0
        public static T Serialize <T>(
            MemoryStream ms,
            bool tryDecodeBase64 = true) where T : IDictionary, new()
        {
            T   dictionary = new T();
            int index      = 0; // needed for repeated elements (assuming that you want to keep within a dict)

            while (ms.Position != ms.Length)
            {
                long header;
                try
                {
                    header = Varint.GetLong(ms);
                }
                catch (Exception ex)
                {
                    Debug.Write(ex.Message);
                    continue;
                }

                long fieldNumber = (long)header >> 3;
                Tag  wireType    = (Tag)(header & 0x7);

                string fieldStr = fieldNumber.ToString() + ":" + index.ToString();

                switch (wireType)
                {
                case Tag.Varint:
                    dictionary[$"{fieldStr}:varint"] = Varint.GetLong(ms);
                    break;

                case Tag.Bit32:
                    Span <byte> buf32 = new byte[4];
                    if (ms.Read(buf32) != buf32.Length)
                    {
                        throw new Exception("Invalid Bit32 length");
                    }

                    try {
                        dictionary[$"{fieldStr}:float32"] = BitConverter.ToSingle(buf32);
                    }
                    catch
                    {
                        dictionary[$"{fieldStr}:int32"] = BitConverter.ToInt32(buf32);
                    }
                    break;

                case Tag.Bit64:
                    Span <byte> buf64 = new byte[8];
                    if (ms.Read(buf64) != buf64.Length)
                    {
                        throw new Exception("Invalid Bit64 length");
                    }

                    try {
                        dictionary[$"{fieldStr}:float64"] = BitConverter.ToDouble(buf64);
                    }
                    catch
                    {
                        dictionary[$"{fieldStr}:int64"] = BitConverter.ToInt64(buf64);
                    }
                    break;

                case Tag.LengthDelimited:
                    const int MaxDelimitedLength = 1 << 22;     // Arbritrary

                    var length = Varint.GetLong(ms);

                    if (length > MaxDelimitedLength)
                    {
                        throw new Exception("Invalid delimited length");
                    }

                    byte[] buf = new byte[length];
                    if (ms.Read(buf, 0, (int)length) != length)
                    {
                        throw new Exception("Malformed LengthDelimited");
                    }

                    // no checks for repeated elements
                    try
                    {
                        string bufStr = UTF8.GetString(buf);

                        if (bufStr.Length == 0)
                        {
                            dictionary[$"{fieldStr}:string"] = String.Empty;
                            break;
                        }
                        if (!ContainsNonFeedControlCharacters(buf))
                        {
                            if (tryDecodeBase64)
                            {
                                try
                                {
                                    var payload = UrlBase64.Decode(HttpUtility.UrlDecode(bufStr));
                                    using var innerMs = new MemoryStream(payload);
                                    dictionary[$"{fieldStr}:base64"] = Serialize <T>(innerMs, tryDecodeBase64);
                                    break;
                                }
                                catch { }
                            }
                            // assume that it's a valid string, either way you can always handle it manually
                            dictionary[$"{fieldStr}:string"] = bufStr;
                            break;
                        }
                    }
                    catch (ArgumentException) {  }     // bad utf8

                    try
                    {
                        using var innerMs = new MemoryStream(buf);
                        dictionary[$"{fieldStr}:embedded"] = Serialize <T>(innerMs, tryDecodeBase64);
                    }
                    catch
                    {
                        dictionary[$"{fieldStr}:bytes"] = buf;
                    }
                    break;

                default:
                    throw new Exception($"Couldn't match wiretype : {wireType}");
                }
                index++;
            }
            return(dictionary);
        }
Example #2
0
        public static void Deserialize(MemoryStream ms, JsonElement json)
        {
            var enumerate = json.EnumerateObject();

            while (enumerate.MoveNext())
            {
                var element = enumerate.Current;

                var parts       = element.Name.ToString().Split(':');
                var fieldNumber = Convert.ToInt64(parts[0]);
                var type        = parts[parts.Length - 1];

                var header = (fieldNumber << 3) | TagMap[type];
                Varint.Write(ms, header);

                switch (type)
                {
                case "varint":
                    Varint.Write(ms, element.Value.GetInt64());
                    break;

                case "int32":
                    ms.Write(BitConverter.GetBytes(element.Value.GetInt32()));
                    break;

                case "float32":
                    ms.Write(BitConverter.GetBytes(element.Value.GetSingle()));
                    break;

                case "int64":
                    ms.Write(BitConverter.GetBytes(element.Value.GetInt64()));
                    break;

                case "float64":
                    ms.Write(BitConverter.GetBytes(element.Value.GetDouble()));
                    break;

                case "string":
                    string str = element.Value.GetString();
                    Varint.Write(ms, str.Length);
                    ms.Write(Encoding.UTF8.GetBytes(str));
                    break;

                case "base64":
                {
                    switch (element.Value.ValueKind)
                    {
                    case JsonValueKind.Object:
                    {
                        using var base64ms = new MemoryStream();
                        Deserialize(base64ms, element.Value);

                        var buf = Encoding.UTF8.GetBytes(UrlBase64.Encode(base64ms.ToArray()));
                        Varint.Write(ms, buf.Length);

                        ms.Write(buf);
                        break;
                    }

                    case JsonValueKind.String:
                        string base64str = element.Value.GetString();
                        Varint.Write(ms, base64str.Length);
                        ms.Write(Encoding.UTF8.GetBytes(base64str));
                        break;
                    }
                    break;
                }

                case "embedded":
                {
                    using var embeddedMs = new MemoryStream();
                    Deserialize(embeddedMs, element.Value);

                    Varint.Write(ms, embeddedMs.Length);

                    embeddedMs.WriteTo(ms);
                    break;
                }

                case "bytes":
                    var buffer = element.Value.GetBytesFromBase64();
                    Varint.Write(ms, buffer.Length);
                    ms.Write(buffer);
                    break;

                default:
                    throw new Exception("Unknown WireType");
                }
            }
        }
Example #3
0
        public static void Deserialize(MemoryStream ms, IDictionary protobuf)
        {
            foreach (DictionaryEntry element in protobuf)
            {
                var parts       = element.Key.ToString().Split(':');
                var fieldNumber = Convert.ToInt64(parts[0]);
                var type        = parts[parts.Length - 1];

                var header = (fieldNumber << 3) | TagMap[type];
                Varint.Write(ms, header);

                switch (type)
                {
                case "varint":
                    Varint.Write(ms, Convert.ToInt64(element.Value));
                    break;

                case "int32":
                    ms.Write(BitConverter.GetBytes((int)element.Value));
                    break;

                case "float32":
                    ms.Write(BitConverter.GetBytes((float)element.Value));
                    break;

                case "int64":
                    ms.Write(BitConverter.GetBytes((long)element.Value));
                    break;

                case "float64":
                    ms.Write(BitConverter.GetBytes((double)element.Value));
                    break;

                case "string":
                    string str = (string)element.Value;
                    Varint.Write(ms, str.Length);
                    ms.Write(Encoding.UTF8.GetBytes(str));
                    break;

                case "base64":
                {
                    using var base64ms = new MemoryStream();
                    Deserialize(base64ms, (IDictionary)element.Value);
                    base64ms.Position = 0;

                    var base64Buffer = Encoding.UTF8.GetBytes(Convert.ToBase64String(base64ms.ToArray()));
                    Varint.Write(ms, base64Buffer.Length);

                    ms.Write(base64Buffer);
                    break;
                }

                case "embedded":
                {
                    using var embeddedMs = new MemoryStream();
                    Deserialize(embeddedMs, (IDictionary)element.Value);
                    embeddedMs.Position = 0;

                    Varint.Write(ms, (long)embeddedMs.Length);
                    embeddedMs.CopyTo(ms);
                    break;
                }

                case "bytes":
                    var buffer = (byte[])element.Value;
                    Varint.Write(ms, buffer.Length);
                    ms.Write(buffer);
                    break;

                default:
                    throw new Exception("Unknown WireType");
                }
            }
        }