THRIFT-4723 Consolidate C#/netcore into new netstd language target
Client: netstd
Patch: Jens Geyer

This closes #1710
diff --git a/lib/netstd/Thrift/Protocol/Utilities/TBase64Utils.cs b/lib/netstd/Thrift/Protocol/Utilities/TBase64Utils.cs
new file mode 100644
index 0000000..90b8f88
--- /dev/null
+++ b/lib/netstd/Thrift/Protocol/Utilities/TBase64Utils.cs
@@ -0,0 +1,101 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+
+namespace Thrift.Protocol.Utilities
+{
+    // ReSharper disable once InconsistentNaming
+    internal static class TBase64Utils
+    {
+        //TODO: Constants
+        //TODO: Check for args
+        //TODO: Unitests
+
+        internal const string EncodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+        private static readonly int[] DecodeTable =
+        {
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+            -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+        };
+
+        internal static void Encode(byte[] src, int srcOff, int len, byte[] dst, int dstOff)
+        {
+            if (src == null)
+            {
+                throw new ArgumentNullException(nameof(src));
+            }
+
+            dst[dstOff] = (byte) EncodeTable[(src[srcOff] >> 2) & 0x3F];
+
+            if (len == 3)
+            {
+                dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] = (byte) EncodeTable[((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)];
+                dst[dstOff + 3] = (byte) EncodeTable[src[srcOff + 2] & 0x3F];
+            }
+            else if (len == 2)
+            {
+                dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] = (byte) EncodeTable[(src[srcOff + 1] << 2) & 0x3C];
+            }
+            else
+            {
+                // len == 1
+                dst[dstOff + 1] = (byte) EncodeTable[(src[srcOff] << 4) & 0x30];
+            }
+        }
+
+        internal static void Decode(byte[] src, int srcOff, int len, byte[] dst, int dstOff)
+        {
+            if (src == null)
+            {
+                throw new ArgumentNullException(nameof(src));
+            }
+
+            dst[dstOff] = (byte) ((DecodeTable[src[srcOff] & 0x0FF] << 2) | (DecodeTable[src[srcOff + 1] & 0x0FF] >> 4));
+
+            if (len > 2)
+            {
+                dst[dstOff + 1] =
+                    (byte)
+                    (((DecodeTable[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) | (DecodeTable[src[srcOff + 2] & 0x0FF] >> 2));
+                if (len > 3)
+                {
+                    dst[dstOff + 2] =
+                        (byte)
+                        (((DecodeTable[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) | DecodeTable[src[srcOff + 3] & 0x0FF]);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs
new file mode 100644
index 0000000..6cc1302
--- /dev/null
+++ b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs
@@ -0,0 +1,61 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+namespace Thrift.Protocol.Utilities
+{
+    // ReSharper disable once InconsistentNaming
+    public static class TJSONProtocolConstants
+    {
+        //TODO Check for performance for reusing ImmutableArray from System.Collections.Immutable (https://blogs.msdn.microsoft.com/dotnet/2013/06/24/please-welcome-immutablearrayt/)
+        // can be possible to get better performance and also better GC
+
+        public static readonly byte[] Comma = {(byte) ','};
+        public static readonly byte[] Colon = {(byte) ':'};
+        public static readonly byte[] LeftBrace = {(byte) '{'};
+        public static readonly byte[] RightBrace = {(byte) '}'};
+        public static readonly byte[] LeftBracket = {(byte) '['};
+        public static readonly byte[] RightBracket = {(byte) ']'};
+        public static readonly byte[] Quote = {(byte) '"'};
+        public static readonly byte[] Backslash = {(byte) '\\'};
+
+        public static readonly byte[] JsonCharTable =
+        {
+            0, 0, 0, 0, 0, 0, 0, 0, (byte) 'b', (byte) 't', (byte) 'n', 0, (byte) 'f', (byte) 'r', 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            1, 1, (byte) '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+        };
+
+        public static readonly char[] EscapeChars = "\"\\/bfnrt".ToCharArray();
+        public static readonly byte[] EscapeCharValues = {(byte) '"', (byte) '\\', (byte) '/', (byte) '\b', (byte) '\f', (byte) '\n', (byte) '\r', (byte) '\t'};
+        public static readonly byte[] EscSequences = {(byte) '\\', (byte) 'u', (byte) '0', (byte) '0'};
+
+        public static class TypeNames
+        {
+            public static readonly byte[] NameBool = { (byte)'t', (byte)'f' };
+            public static readonly byte[] NameByte = { (byte)'i', (byte)'8' };
+            public static readonly byte[] NameI16 = { (byte)'i', (byte)'1', (byte)'6' };
+            public static readonly byte[] NameI32 = { (byte)'i', (byte)'3', (byte)'2' };
+            public static readonly byte[] NameI64 = { (byte)'i', (byte)'6', (byte)'4' };
+            public static readonly byte[] NameDouble = { (byte)'d', (byte)'b', (byte)'l' };
+            public static readonly byte[] NameStruct = { (byte)'r', (byte)'e', (byte)'c' };
+            public static readonly byte[] NameString = { (byte)'s', (byte)'t', (byte)'r' };
+            public static readonly byte[] NameMap = { (byte)'m', (byte)'a', (byte)'p' };
+            public static readonly byte[] NameList = { (byte)'l', (byte)'s', (byte)'t' };
+            public static readonly byte[] NameSet = { (byte)'s', (byte)'e', (byte)'t' };
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs
new file mode 100644
index 0000000..ff49ebe
--- /dev/null
+++ b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs
@@ -0,0 +1,176 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using Thrift.Protocol.Entities;
+
+namespace Thrift.Protocol.Utilities
+{
+    // ReSharper disable once InconsistentNaming
+    public static class TJSONProtocolHelper
+    {
+        public static byte[] GetTypeNameForTypeId(TType typeId)
+        {
+            switch (typeId)
+            {
+                case TType.Bool:
+                    return TJSONProtocolConstants.TypeNames.NameBool;
+                case TType.Byte:
+                    return TJSONProtocolConstants.TypeNames.NameByte;
+                case TType.I16:
+                    return TJSONProtocolConstants.TypeNames.NameI16;
+                case TType.I32:
+                    return TJSONProtocolConstants.TypeNames.NameI32;
+                case TType.I64:
+                    return TJSONProtocolConstants.TypeNames.NameI64;
+                case TType.Double:
+                    return TJSONProtocolConstants.TypeNames.NameDouble;
+                case TType.String:
+                    return TJSONProtocolConstants.TypeNames.NameString;
+                case TType.Struct:
+                    return TJSONProtocolConstants.TypeNames.NameStruct;
+                case TType.Map:
+                    return TJSONProtocolConstants.TypeNames.NameMap;
+                case TType.Set:
+                    return TJSONProtocolConstants.TypeNames.NameSet;
+                case TType.List:
+                    return TJSONProtocolConstants.TypeNames.NameList;
+                default:
+                    throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType");
+            }
+        }
+
+        public static TType GetTypeIdForTypeName(byte[] name)
+        {
+            var result = TType.Stop;
+            if (name.Length > 1)
+            {
+                switch (name[0])
+                {
+                    case (byte) 'd':
+                        result = TType.Double;
+                        break;
+                    case (byte) 'i':
+                        switch (name[1])
+                        {
+                            case (byte) '8':
+                                result = TType.Byte;
+                                break;
+                            case (byte) '1':
+                                result = TType.I16;
+                                break;
+                            case (byte) '3':
+                                result = TType.I32;
+                                break;
+                            case (byte) '6':
+                                result = TType.I64;
+                                break;
+                        }
+                        break;
+                    case (byte) 'l':
+                        result = TType.List;
+                        break;
+                    case (byte) 'm':
+                        result = TType.Map;
+                        break;
+                    case (byte) 'r':
+                        result = TType.Struct;
+                        break;
+                    case (byte) 's':
+                        if (name[1] == (byte) 't')
+                        {
+                            result = TType.String;
+                        }
+                        else if (name[1] == (byte) 'e')
+                        {
+                            result = TType.Set;
+                        }
+                        break;
+                    case (byte) 't':
+                        result = TType.Bool;
+                        break;
+                }
+            }
+            if (result == TType.Stop)
+            {
+                throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType");
+            }
+            return result;
+        }
+
+        /// <summary>
+        ///     Return true if the given byte could be a valid part of a JSON number.
+        /// </summary>
+        public static bool IsJsonNumeric(byte b)
+        {
+            switch (b)
+            {
+                case (byte)'+':
+                case (byte)'-':
+                case (byte)'.':
+                case (byte)'0':
+                case (byte)'1':
+                case (byte)'2':
+                case (byte)'3':
+                case (byte)'4':
+                case (byte)'5':
+                case (byte)'6':
+                case (byte)'7':
+                case (byte)'8':
+                case (byte)'9':
+                case (byte)'E':
+                case (byte)'e':
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        /// <summary>
+        ///     Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its
+        ///     corresponding hex value
+        /// </summary>
+        public static byte ToHexVal(byte ch)
+        {
+            if (ch >= '0' && ch <= '9')
+            {
+                return (byte)((char)ch - '0');
+            }
+
+            if (ch >= 'a' && ch <= 'f')
+            {
+                ch += 10;
+                return (byte)((char)ch - 'a');
+            }
+
+            throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected hex character");
+        }
+
+        /// <summary>
+        ///     Convert a byte containing a hex value to its corresponding hex character
+        /// </summary>
+        public static byte ToHexChar(byte val)
+        {
+            val &= 0x0F;
+            if (val < 10)
+            {
+                return (byte)((char)val + '0');
+            }
+            val -= 10;
+            return (byte)((char)val + 'a');
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs b/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs
new file mode 100644
index 0000000..18f92d8
--- /dev/null
+++ b/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs
@@ -0,0 +1,110 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocol.Entities;
+
+namespace Thrift.Protocol.Utilities
+{
+    // ReSharper disable once InconsistentNaming
+    public static class TProtocolUtil
+    {
+        public static async Task SkipAsync(TProtocol protocol, TType type, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+
+            protocol.IncrementRecursionDepth();
+            try
+            {
+                switch (type)
+                {
+                    case TType.Bool:
+                        await protocol.ReadBoolAsync(cancellationToken);
+                        break;
+                    case TType.Byte:
+                        await protocol.ReadByteAsync(cancellationToken);
+                        break;
+                    case TType.I16:
+                        await protocol.ReadI16Async(cancellationToken);
+                        break;
+                    case TType.I32:
+                        await protocol.ReadI32Async(cancellationToken);
+                        break;
+                    case TType.I64:
+                        await protocol.ReadI64Async(cancellationToken);
+                        break;
+                    case TType.Double:
+                        await protocol.ReadDoubleAsync(cancellationToken);
+                        break;
+                    case TType.String:
+                        // Don't try to decode the string, just skip it.
+                        await protocol.ReadBinaryAsync(cancellationToken);
+                        break;
+                    case TType.Struct:
+                        await protocol.ReadStructBeginAsync(cancellationToken);
+                        while (true)
+                        {
+                            var field = await protocol.ReadFieldBeginAsync(cancellationToken);
+                            if (field.Type == TType.Stop)
+                            {
+                                break;
+                            }
+                            await SkipAsync(protocol, field.Type, cancellationToken);
+                            await protocol.ReadFieldEndAsync(cancellationToken);
+                        }
+                        await protocol.ReadStructEndAsync(cancellationToken);
+                        break;
+                    case TType.Map:
+                        var map = await protocol.ReadMapBeginAsync(cancellationToken);
+                        for (var i = 0; i < map.Count; i++)
+                        {
+                            await SkipAsync(protocol, map.KeyType, cancellationToken);
+                            await SkipAsync(protocol, map.ValueType, cancellationToken);
+                        }
+                        await protocol.ReadMapEndAsync(cancellationToken);
+                        break;
+                    case TType.Set:
+                        var set = await protocol.ReadSetBeginAsync(cancellationToken);
+                        for (var i = 0; i < set.Count; i++)
+                        {
+                            await SkipAsync(protocol, set.ElementType, cancellationToken);
+                        }
+                        await protocol.ReadSetEndAsync(cancellationToken);
+                        break;
+                    case TType.List:
+                        var list = await protocol.ReadListBeginAsync(cancellationToken);
+                        for (var i = 0; i < list.Count; i++)
+                        {
+                            await SkipAsync(protocol, list.ElementType, cancellationToken);
+                        }
+                        await protocol.ReadListEndAsync(cancellationToken);
+                        break;
+                    default:
+                        throw new TProtocolException(TProtocolException.INVALID_DATA, "Unknown data type " + type.ToString("d"));
+                }
+            }
+            finally
+            {
+                protocol.DecrementRecursionDepth();
+            }
+        }
+    }
+}