Beispiel #1
0
 public static bool TryWrite(ref ResizableMemory <byte> writer, bool value, StandardFormat standardFormat)
 {
     if (standardFormat.IsDefault)
     {
         if (value)
         {
             _trueValue.Span.CopyTo(writer.RequestSpan(6));
             writer.Advance(6);
         }
         else
         {
             _falseValue.Span.CopyTo(writer.RequestSpan(7));
             writer.Advance(7);
         }
     }
     else
     {
         int start = writer.Length;
         writer.Push((byte)EtfTokenType.Binary);
         writer.Advance(4);
         if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
         {
             return(false);
         }
         int length = writer.Length - start - 5;
         writer.Array[start + 1] = (byte)(length >> 24);
         writer.Array[start + 2] = (byte)(length >> 16);
         writer.Array[start + 3] = (byte)(length >> 8);
         writer.Array[start + 4] = (byte)length;
     }
     return(true);
 }
Beispiel #2
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, int value, StandardFormat standardFormat)
        {
            if (standardFormat.IsDefault)
            {
                if (value <= byte.MaxValue && value >= byte.MinValue)
                {
                    return(TryWrite(ref writer, (byte)value, standardFormat));
                }

                writer.Push((byte)EtfTokenType.Integer);
                BinaryPrimitives.WriteInt32BigEndian(writer.RequestSpan(4), value);
                writer.Advance(4);
            }
            else
            {
                int start = writer.Length;
                writer.Push((byte)EtfTokenType.Binary);
                writer.Advance(4);
                if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
                {
                    return(false);
                }
                int length = writer.Length - start - 5;
                writer.Array[start + 1] = (byte)(length >> 24);
                writer.Array[start + 2] = (byte)(length >> 16);
                writer.Array[start + 3] = (byte)(length >> 8);
                writer.Array[start + 4] = (byte)length;
            }
            return(true);
        }
Beispiel #3
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, long value, StandardFormat standardFormat)
        {
            if (standardFormat.IsDefault)
            {
                if (value <= byte.MaxValue && value >= byte.MinValue)
                {
                    return(TryWrite(ref writer, (byte)value, standardFormat));
                }
                if (value <= int.MaxValue && value >= int.MinValue)
                {
                    return(TryWrite(ref writer, (int)value, standardFormat));
                }

                writer.Push((byte)EtfTokenType.SmallBig);
                writer.Push(8);
                if (value >= 0)
                {
                    writer.Push(0);
                    BinaryPrimitives.WriteUInt64LittleEndian(writer.RequestSpan(8), (ulong)value);
                }
                else
                {
                    writer.Push(1);
                    if (value == long.MinValue)
                    {
                        BinaryPrimitives.WriteUInt64LittleEndian(writer.RequestSpan(8), 9223372036854775808);
                    }
                    else
                    {
                        BinaryPrimitives.WriteUInt64LittleEndian(writer.RequestSpan(8), (ulong)-value);
                    }
                }
                writer.Advance(8);
            }
            else
            {
                int start = writer.Length;
                writer.Push((byte)EtfTokenType.Binary);
                writer.Advance(4);
                if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
                {
                    return(false);
                }
                int length = writer.Length - start - 5;
                writer.Array[start + 1] = (byte)(length >> 24);
                writer.Array[start + 2] = (byte)(length >> 16);
                writer.Array[start + 3] = (byte)(length >> 8);
                writer.Array[start + 4] = (byte)length;
            }
            return(true);
        }
Beispiel #4
0
        public override bool TryWrite(ref ResizableMemory <byte> writer, T[] value, PropertyMap propMap = null)
        {
            if (value == null)
            {
                return(EtfWriter.TryWriteNull(ref writer));
            }

            var start = writer.Length;

            writer.Push((byte)EtfTokenType.List);
            writer.Advance(4);

            uint count = 0;

            for (int i = 0; i < value.Length; i++)
            {
                if (!_innerConverter.CanWrite(value[i], propMap))
                {
                    continue;
                }
                if (!_innerConverter.TryWrite(ref writer, value[i], propMap))
                {
                    return(false);
                }
                count++;
            }

            writer.Array[start + 1] = (byte)(count >> 24);
            writer.Array[start + 2] = (byte)(count >> 16);
            writer.Array[start + 3] = (byte)(count >> 8);
            writer.Array[start + 4] = (byte)count;

            writer.Push((byte)EtfTokenType.Nil); // Tail
            return(true);
        }
Beispiel #5
0
        public static bool TryWriteString(ref ResizableMemory <byte> writer, ReadOnlySpan <byte> value)
        {
            var dstSpan = writer.RequestSpan(value.Length);

            value.CopyTo(dstSpan);
            writer.Advance(value.Length);
            return(true);
        }
Beispiel #6
0
        public static bool TryWriteNull(ref ResizableMemory <byte> writer)
        {
            var        data      = writer.RequestSpan(4); // null
            const uint nullValue = ('n' << 24) + ('u' << 16) + ('l' << 8) + ('l' << 0);

            BinaryPrimitives.WriteUInt32BigEndian(data, nullValue);
            writer.Advance(4);
            return(true);
        }
        public static bool TryWrite(ref ResizableMemory <byte> writer, Guid value, StandardFormat standardFormat)
        {
            var data = writer.RequestSpan(38); // {ABCDEFGH-ABCD-ABCD-ABCD-ABCDEFGHIJKL}

            if (!Utf8Formatter.TryFormat(value, data, out int bytesWritten, standardFormat))
            {
                return(false);
            }
            writer.Advance(bytesWritten);
            return(true);
        }
        public static bool TryWrite(ref ResizableMemory <byte> writer, TimeSpan value, StandardFormat standardFormat)
        {
            var data = writer.RequestSpan(26); // -10675199.02:48:05.4775808

            if (!Utf8Formatter.TryFormat(value, data, out int bytesWritten, standardFormat))
            {
                return(false);
            }
            writer.Advance(bytesWritten);
            return(true);
        }
        public static bool TryWrite(ref ResizableMemory <byte> writer, DateTimeOffset value, StandardFormat standardFormat)
        {
            var data = writer.RequestSpan(33); // 9999-12-31T11:59:59.999999+00:00

            if (!Utf8Formatter.TryFormat(value, data, out int bytesWritten, standardFormat))
            {
                return(false);
            }
            writer.Advance(bytesWritten);
            return(true);
        }
        public static bool TryWrite(ref ResizableMemory <byte> writer, uint value, StandardFormat standardFormat)
        {
            var data = writer.RequestSpan(16); // 4,294,967,295.00

            if (!Utf8Formatter.TryFormat(value, data, out int bytesWritten, standardFormat))
            {
                return(false);
            }
            writer.Advance(bytesWritten);
            return(true);
        }
        public static bool TryWrite(ref ResizableMemory <byte> writer, double value, StandardFormat standardFormat)
        {
            var data = writer.RequestSpan(22); // -1.79769313486232E+308

            if (!Utf8Formatter.TryFormat(value, data, out int bytesWritten, standardFormat))
            {
                return(false);
            }
            writer.Advance(bytesWritten);
            return(true);
        }
        public static bool TryWrite(ref ResizableMemory <byte> writer, ulong value, StandardFormat standardFormat)
        {
            var data = writer.RequestSpan(29); // 18,446,744,073,709,551,615.00

            if (!Utf8Formatter.TryFormat(value, data, out int bytesWritten, standardFormat))
            {
                return(false);
            }
            writer.Advance(bytesWritten);
            return(true);
        }
        public static bool TryWrite(ref ResizableMemory <byte> writer, decimal value, StandardFormat standardFormat)
        {
            var data = writer.RequestSpan(30); // -79228162514264337593543950336

            if (!Utf8Formatter.TryFormat(value, data, out int bytesWritten, standardFormat))
            {
                return(false);
            }
            writer.Advance(bytesWritten);
            return(true);
        }
        public static bool TryWrite(ref ResizableMemory <byte> writer, float value, StandardFormat standardFormat)
        {
            var data = writer.RequestSpan(14); // -3.402823E+038

            if (!Utf8Formatter.TryFormat(value, data, out int bytesWritten, standardFormat))
            {
                return(false);
            }
            writer.Advance(bytesWritten);
            return(true);
        }
Beispiel #15
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, long value, StandardFormat standardFormat)
        {
            var data = writer.RequestSpan(29); // -9,223,372,036,854,775,808.00

            if (!Utf8Formatter.TryFormat(value, data, out int bytesWritten, standardFormat))
            {
                return(false);
            }
            writer.Advance(bytesWritten);
            return(true);
        }
        public static bool TryWrite(ref ResizableMemory <byte> writer, DateTime value, StandardFormat standardFormat)
        {
            // TODO: Will this break in other locales?
            var data = writer.RequestSpan(31); // Fri, 31 Dec 9999 11:59:59 ACWST

            if (!Utf8Formatter.TryFormat(value, data, out int bytesWritten, standardFormat))
            {
                return(false);
            }
            writer.Advance(bytesWritten);
            return(true);
        }
        public static bool TryWrite(ref ResizableMemory <byte> writer, float value, StandardFormat standardFormat)
        {
            // TODO: Untested, does Discord have any endpoints that accept floats?
            if (standardFormat.IsDefault)
            {
                writer.Push((byte)EtfTokenType.NewFloat);

                // Swap endian
                Span <double> src      = stackalloc double[] { value };
                var           srcBytes = MemoryMarshal.AsBytes(src);
                var           dst      = writer.RequestSpan(8);

                dst[0] = srcBytes[7];
                dst[1] = srcBytes[6];
                dst[2] = srcBytes[5];
                dst[3] = srcBytes[4];
                dst[4] = srcBytes[3];
                dst[5] = srcBytes[2];
                dst[6] = srcBytes[1];
                dst[7] = srcBytes[0];
                writer.Advance(8);
            }
            else
            {
                int start = writer.Length;
                writer.Push((byte)EtfTokenType.Binary);
                writer.Advance(4);
                if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
                {
                    return(false);
                }
                int length = writer.Length - start - 5;
                writer.Array[start + 1] = (byte)(length >> 24);
                writer.Array[start + 2] = (byte)(length >> 16);
                writer.Array[start + 3] = (byte)(length >> 8);
                writer.Array[start + 4] = (byte)length;
            }
            return(true);
        }
Beispiel #18
0
        public override async Task <InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            var request = context.HttpContext.Request;
            var buffer  = new ResizableMemory <byte>(1024 * 4);

            try
            {
                var read = await request.Body.ReadAsync(buffer.RequestMemory(1024 * 4));

                while (read > 0)
                {
                    buffer.Advance(read);
                    read = await request.Body.ReadAsync(buffer.RequestMemory(1024 * 4));
                }

                if (encoding == Encoding.UTF8)
                {
                    var obj = _serializer.ReadUtf8(context.ModelType, buffer.AsReadOnlySpan());
                    return(InputFormatterResult.Success(obj));
                }
                else if (encoding == Encoding.Unicode)
                {
                    var obj = _serializer.ReadUtf16(context.ModelType, buffer.AsReadOnlySpan());
                    return(InputFormatterResult.Success(obj));
                }
                else
                {
                    throw new ArgumentOutOfRangeException(nameof(encoding));
                }
            }
            catch (SerializationException)
            {
                return(InputFormatterResult.Failure());
            }
            catch (Exception ex)
            {
                throw new InputFormatterException($"Failed to deserialize {context.ModelType}", ex);
            }
            finally { buffer.Return(); }
        }
        public static bool TryWriteUtf8Bytes(ref ResizableMemory <byte> writer, ReadOnlySpan <byte> value)
        {
            if (value.Length > ushort.MaxValue)
            {
                return(false);
            }

            writer.Push((byte)EtfTokenType.Binary);
            BinaryPrimitives.WriteUInt32BigEndian(writer.RequestSpan(4), (uint)value.Length);
            writer.Advance(4);
            if (!Utf8Writer.TryWriteString(ref writer, value))
            {
                return(false);
            }
            return(true);
        }
Beispiel #20
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, string value)
        {
            var valueBytes = MemoryMarshal.AsBytes(value.AsSpan());

            if (Encodings.Utf16.ToUtf8Length(valueBytes, out var length) != OperationStatus.Done)
            {
                return(false);
            }
            var data = writer.RequestSpan(length);

            if (Encodings.Utf16.ToUtf8(valueBytes, data, out _, out _) != OperationStatus.Done)
            {
                return(false);
            }
            writer.Advance(length);
            return(true);
        }
Beispiel #21
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, DateTime value, StandardFormat standardFormat)
        {
            int start = writer.Length;

            writer.Push((byte)EtfTokenType.Binary);
            writer.Advance(4);
            if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
            {
                return(false);
            }
            int length = writer.Length - start - 5;

            writer.Array[start + 1] = (byte)(length >> 24);
            writer.Array[start + 2] = (byte)(length >> 16);
            writer.Array[start + 3] = (byte)(length >> 8);
            writer.Array[start + 4] = (byte)length;
            return(true);
        }
Beispiel #22
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, char value)
        {
            ReadOnlySpan <char> chars = stackalloc char[] { value };
            var valueBytes            = MemoryMarshal.AsBytes(chars);

            if (Encodings.Utf16.ToUtf8Length(valueBytes, out var length) != OperationStatus.Done)
            {
                return(false);
            }
            var data = writer.RequestSpan(length);

            if (Encodings.Utf16.ToUtf8(valueBytes, data, out _, out _) != OperationStatus.Done)
            {
                return(false);
            }
            writer.Advance(length);
            return(true);
        }
        public override bool TryWrite(ref ResizableMemory <byte> writer, T value, PropertyMap propMap = null)
        {
            if (value == null)
            {
                return(EtfWriter.TryWriteNull(ref writer));
            }

            var start = writer.Length;

            writer.Push((byte)EtfTokenType.Map);
            writer.Advance(4);

            uint count      = 0;
            var  properties = _map.Properties;

            for (int i = 0; i < properties.Count; i++)
            {
                var key          = properties[i].Key;
                var innerPropMap = properties[i].Value as PropertyMap <T>;
                if (!innerPropMap.CanWrite(value))
                {
                    continue;
                }

                if (!EtfWriter.TryWriteUtf8Key(ref writer, key.Span))
                {
                    return(false);
                }
                if (!innerPropMap.TryWrite(value, ref writer))
                {
                    return(false);
                }
                count++;
            }

            writer.Array[start + 1] = (byte)(count >> 24);
            writer.Array[start + 2] = (byte)(count >> 16);
            writer.Array[start + 3] = (byte)(count >> 8);
            writer.Array[start + 4] = (byte)count;
            return(true);
        }
Beispiel #24
0
        public override bool TryWrite(ref ResizableMemory <byte> writer, Dictionary <string, T> value, PropertyMap propMap = null)
        {
            if (value == null)
            {
                return(EtfWriter.TryWriteNull(ref writer));
            }

            var start = writer.Length;

            writer.Push((byte)EtfTokenType.Map);
            writer.Advance(4);

            uint count = 0;

            foreach (var pair in value)
            {
                if (!_innerConverter.CanWrite(pair.Value, propMap))
                {
                    continue;
                }

                if (!EtfWriter.TryWriteUtf16Key(ref writer, pair.Key))
                {
                    return(false);
                }
                if (!_innerConverter.TryWrite(ref writer, pair.Value, propMap))
                {
                    return(false);
                }
                count++;
            }

            writer.Array[start + 1] = (byte)(count >> 24);
            writer.Array[start + 2] = (byte)(count >> 16);
            writer.Array[start + 3] = (byte)(count >> 8);
            writer.Array[start + 4] = (byte)count;
            return(true);
        }
Beispiel #25
0
 public static bool TryWriteNull(ref ResizableMemory <byte> writer)
 {
     _nilValue.Span.CopyTo(writer.RequestSpan(5));
     writer.Advance(5);
     return(true);
 }
Beispiel #26
0
        public static bool TryWriteUtf8Bytes(ref ResizableMemory <byte> writer, ReadOnlySpan <byte> value)
        {
            int i     = 0;
            int start = 0;

            for (; i < value.Length; i++)
            {
                byte b = value[i];

                // Special chars
                switch (b)
                {
                case (byte)'"':
                case (byte)'\\':
                    //case (byte)'/':
                    if (i != start)
                    {
                        int bytes  = i - start;
                        var buffer = writer.RequestSpan(bytes);
                        value.Slice(start, bytes).CopyTo(buffer);
                        writer.Advance(bytes);
                    }
                    writer.Push((byte)'\\');
                    writer.Push(b);

                    start = i + 1;
                    continue;
                }


                if (b < 32) // Control codes
                {
                    if (i != start)
                    {
                        int bytes  = i - start;
                        var buffer = writer.RequestSpan(bytes);
                        value.Slice(start, bytes).CopyTo(buffer);
                        writer.Advance(bytes);
                    }
                    switch (b)
                    {
                    case (byte)'\b':
                        writer.Push((byte)'\\');
                        writer.Push((byte)'b');
                        break;

                    case (byte)'\f':
                        writer.Push((byte)'\\');
                        writer.Push((byte)'f');
                        break;

                    case (byte)'\n':
                        writer.Push((byte)'\\');
                        writer.Push((byte)'n');
                        break;

                    case (byte)'\r':
                        writer.Push((byte)'\\');
                        writer.Push((byte)'r');
                        break;

                    case (byte)'\t':
                        writer.Push((byte)'\\');
                        writer.Push((byte)'t');
                        break;

                    default:
                        var escape = writer.RequestSpan(6);
                        escape[0] = (byte)'\\';
                        escape[1] = (byte)'u';
                        escape[2] = (byte)'0';
                        escape[3] = (byte)'0';
                        escape[4] = ToHex((byte)(b >> 4));
                        escape[5] = ToHex((byte)(b & 0xF));
                        writer.Advance(6);
                        break;
                    }
                    start = i + 1;
                }
                else if (b >= 192) // Multi-byte chars
                {
                    if (i != start)
                    {
                        int bytes  = i - start;
                        var buffer = writer.RequestSpan(bytes);
                        value.Slice(start, i - start).CopyTo(buffer);
                        writer.Advance(bytes);
                    }
                    int seqStart = i;
                    int length   = 1;
                    for (; length < 4 && i < value.Length - 1 && value[i + 1] >= 128; length++, i++)
                    {
                    }

                    Span <ushort> utf16Value = stackalloc ushort[2];
                    if (Encodings.Utf8.ToUtf16(value.Slice(seqStart, length), MemoryMarshal.AsBytes(utf16Value), out _, out int bytesWritten) != OperationStatus.Done)
                    {
                        return(false);
                    }

                    for (int j = 0; j < bytesWritten / 2; j++)
                    {
                        var buffer2 = writer.RequestSpan(6);
                        buffer2[0] = (byte)'\\';
                        buffer2[1] = (byte)'u';
                        buffer2[2] = ToHex((byte)((utf16Value[j] >> 12) & 0xF));
                        buffer2[3] = ToHex((byte)((utf16Value[j] >> 8) & 0xF));
                        buffer2[4] = ToHex((byte)((utf16Value[j] >> 4) & 0xF));
                        buffer2[5] = ToHex((byte)(utf16Value[j] & 0xF));
                        writer.Advance(6);
                    }

                    start = i + 1;
                }
                else if (b >= 128) // Multi-byte chars out of sequence
                {
                    return(false);
                }
            }
            // Append last part to builder
            if (i != start)
            {
                int bytes  = i - start;
                var buffer = writer.RequestSpan(bytes);
                value.Slice(start, bytes).CopyTo(buffer);
                writer.Advance(bytes);
            }
            return(true);
        }
Beispiel #27
0
        public override HttpContent SerializeBody <T>(T body, RequestBodySerializerInfo info)
        {
            if (body == null)
            {
                return(null);
            }

            if (body is IFormData form)
            {
                var pairs   = form.GetFormData();
                var content = new MultipartFormDataContent();
                foreach (var pair in pairs)
                {
                    if (pair.Value is MultipartFile file)
                    {
                        var stream = file.Stream;
                        if (stream.CanSeek)
                        {
                            long remaining = stream.Length - stream.Position;
                            if (remaining > int.MaxValue)
                            {
                                throw new InvalidOperationException("Uploading files larger than Int32.MaxValue bytes is unsupported");
                            }
                            else if (remaining <= 0)
                            {
                                content.Add(new ByteArrayContent(Array.Empty <byte>()), pair.Key, (string)file.Filename);
                                continue;
                            }
                            var arr = new byte[remaining];
                            stream.Read(arr, 0, arr.Length);
                            content.Add(new ByteArrayContent(arr), pair.Key, (string)file.Filename);
                        }
                        else
                        {
                            var buffer = new ResizableMemory <byte>(4096); // 4 KB
                            while (true)
                            {
                                var segment     = buffer.RequestSegment(4096);
                                int bytesCopied = file.Stream.Read(segment.Array, segment.Offset, segment.Count);
                                if (bytesCopied == 0)
                                {
                                    break;
                                }
                                buffer.Advance(bytesCopied);
                            }
                            content.Add(new ByteArrayContent(buffer.ToArray()), pair.Key, (string)file.Filename);
                        }
                    }
                    else
                    {
                        content.Add(new StringContent(_serializer.WriteUtf16String(pair.Value), Encoding.UTF8, "application/json"), pair.Key);
                    }
                }
                return(content);
            }
            else
            {
                var arr     = _serializer.Write(body).AsSegment();
                var content = new ByteArrayContent(arr.Array, arr.Offset, arr.Count);
                content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                return(content);
            }
        }