Squashed 'third_party/flatbuffers/' content from commit acc9990ab

Change-Id: I48550d40d78fea996ebe74e9723a5d1f910de491
git-subtree-dir: third_party/flatbuffers
git-subtree-split: acc9990abd2206491480291b0f85f925110102ea
diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs
new file mode 100644
index 0000000..5e212dd
--- /dev/null
+++ b/net/FlatBuffers/ByteBuffer.cs
@@ -0,0 +1,891 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed 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.
+ */
+
+// There are 3 #defines that have an impact on performance / features of this ByteBuffer implementation
+//
+//      UNSAFE_BYTEBUFFER 
+//          This will use unsafe code to manipulate the underlying byte array. This
+//          can yield a reasonable performance increase.
+//
+//      BYTEBUFFER_NO_BOUNDS_CHECK
+//          This will disable the bounds check asserts to the byte array. This can
+//          yield a small performance gain in normal code..
+//
+//      ENABLE_SPAN_T
+//          This will enable reading and writing blocks of memory with a Span<T> instead if just
+//          T[].  You can also enable writing directly to shared memory or other types of memory
+//          by providing a custom implementation of ByteBufferAllocator.
+//          ENABLE_SPAN_T also requires UNSAFE_BYTEBUFFER to be defined
+//
+// Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a
+// performance gain of ~15% for some operations, however doing so is potentially 
+// dangerous. Do so at your own risk!
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+
+#if ENABLE_SPAN_T
+using System.Buffers.Binary;
+#endif
+
+#if ENABLE_SPAN_T && !UNSAFE_BYTEBUFFER
+#error ENABLE_SPAN_T requires UNSAFE_BYTEBUFFER to also be defined
+#endif
+
+namespace FlatBuffers
+{
+    public abstract class ByteBufferAllocator
+    {
+#if ENABLE_SPAN_T
+        public abstract Span<byte> Span { get; }
+        public abstract ReadOnlySpan<byte> ReadOnlySpan { get; }
+        public abstract Memory<byte> Memory { get; }
+        public abstract ReadOnlyMemory<byte> ReadOnlyMemory { get; }
+
+#else
+        public byte[] Buffer
+        {
+            get;
+            protected set;
+        }
+#endif
+
+        public int Length
+        {
+            get;
+            protected set;
+        }
+
+        public abstract void GrowFront(int newSize);
+    }
+
+    public sealed class ByteArrayAllocator : ByteBufferAllocator
+    {
+        private byte[] _buffer;
+
+        public ByteArrayAllocator(byte[] buffer)
+        {
+            _buffer = buffer;
+            InitBuffer();
+        }
+
+        public override void GrowFront(int newSize)
+        {
+            if ((Length & 0xC0000000) != 0)
+                throw new Exception(
+                    "ByteBuffer: cannot grow buffer beyond 2 gigabytes.");
+
+            if (newSize < Length)
+                throw new Exception("ByteBuffer: cannot truncate buffer.");
+
+            byte[] newBuffer = new byte[newSize];
+            System.Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length, Length);
+            _buffer = newBuffer;
+            InitBuffer();
+        }
+
+#if ENABLE_SPAN_T
+        public override Span<byte> Span => _buffer;
+        public override ReadOnlySpan<byte> ReadOnlySpan => _buffer;
+        public override Memory<byte> Memory => _buffer;
+        public override ReadOnlyMemory<byte> ReadOnlyMemory => _buffer;
+#endif
+
+        private void InitBuffer()
+        {
+            Length = _buffer.Length;
+#if !ENABLE_SPAN_T
+            Buffer = _buffer;
+#endif
+        }
+    }
+
+    /// <summary>
+    /// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers.
+    /// </summary>
+    public class ByteBuffer
+    {
+        private ByteBufferAllocator _buffer;
+        private int _pos;  // Must track start of the buffer.
+
+        public ByteBuffer(ByteBufferAllocator allocator, int position)
+        {
+            _buffer = allocator;
+            _pos = position;
+        }
+
+        public ByteBuffer(int size) : this(new byte[size]) { }
+
+        public ByteBuffer(byte[] buffer) : this(buffer, 0) { }
+
+        public ByteBuffer(byte[] buffer, int pos)
+        {
+            _buffer = new ByteArrayAllocator(buffer);
+            _pos = pos;
+        }
+
+        public int Position
+        {
+            get { return _pos; }
+            set { _pos = value; }
+        }
+
+        public int Length { get { return _buffer.Length; } }
+
+        public void Reset()
+        {
+            _pos = 0;
+        }
+
+        // Create a new ByteBuffer on the same underlying data.
+        // The new ByteBuffer's position will be same as this buffer's.
+        public ByteBuffer Duplicate()
+        {
+            return new ByteBuffer(_buffer, Position);
+        }
+
+        // Increases the size of the ByteBuffer, and copies the old data towards
+        // the end of the new buffer.
+        public void GrowFront(int newSize)
+        {
+            _buffer.GrowFront(newSize);
+        }
+
+        public byte[] ToArray(int pos, int len)
+        {
+            return ToArray<byte>(pos, len);
+        }
+
+        /// <summary>
+        /// A lookup of type sizes. Used instead of Marshal.SizeOf() which has additional
+        /// overhead, but also is compatible with generic functions for simplified code.
+        /// </summary>
+        private static Dictionary<Type, int> genericSizes = new Dictionary<Type, int>()
+        {
+            { typeof(bool),     sizeof(bool) },
+            { typeof(float),    sizeof(float) },
+            { typeof(double),   sizeof(double) },
+            { typeof(sbyte),    sizeof(sbyte) },
+            { typeof(byte),     sizeof(byte) },
+            { typeof(short),    sizeof(short) },
+            { typeof(ushort),   sizeof(ushort) },
+            { typeof(int),      sizeof(int) },
+            { typeof(uint),     sizeof(uint) },
+            { typeof(ulong),    sizeof(ulong) },
+            { typeof(long),     sizeof(long) },
+        };
+
+        /// <summary>
+        /// Get the wire-size (in bytes) of a type supported by flatbuffers.
+        /// </summary>
+        /// <param name="t">The type to get the wire size of</param>
+        /// <returns></returns>
+        public static int SizeOf<T>()
+        {
+            return genericSizes[typeof(T)];
+        }
+
+        /// <summary>
+        /// Checks if the Type provided is supported as scalar value
+        /// </summary>
+        /// <typeparam name="T">The Type to check</typeparam>
+        /// <returns>True if the type is a scalar type that is supported, falsed otherwise</returns>
+        public static bool IsSupportedType<T>()
+        {
+            return genericSizes.ContainsKey(typeof(T));
+        }
+
+        /// <summary>
+        /// Get the wire-size (in bytes) of an typed array
+        /// </summary>
+        /// <typeparam name="T">The type of the array</typeparam>
+        /// <param name="x">The array to get the size of</param>
+        /// <returns>The number of bytes the array takes on wire</returns>
+        public static int ArraySize<T>(T[] x)
+        {
+            return SizeOf<T>() * x.Length;
+        }
+
+#if ENABLE_SPAN_T
+        public static int ArraySize<T>(Span<T> x)
+        {
+            return SizeOf<T>() * x.Length;
+        }
+#endif
+
+        // Get a portion of the buffer casted into an array of type T, given
+        // the buffer position and length.
+#if ENABLE_SPAN_T
+        public T[] ToArray<T>(int pos, int len)
+            where T : struct
+        {
+            AssertOffsetAndLength(pos, len);
+            return MemoryMarshal.Cast<byte, T>(_buffer.ReadOnlySpan.Slice(pos)).Slice(0, len).ToArray();
+        }
+#else
+        public T[] ToArray<T>(int pos, int len)
+            where T : struct
+        {
+            AssertOffsetAndLength(pos, len);
+            T[] arr = new T[len];
+            Buffer.BlockCopy(_buffer.Buffer, pos, arr, 0, ArraySize(arr));
+            return arr;
+        }
+#endif
+
+        public byte[] ToSizedArray()
+        {
+            return ToArray<byte>(Position, Length - Position);
+        }
+
+        public byte[] ToFullArray()
+        {
+            return ToArray<byte>(0, Length);
+        }
+
+#if ENABLE_SPAN_T
+        public ReadOnlyMemory<byte> ToReadOnlyMemory(int pos, int len)
+        {
+            return _buffer.ReadOnlyMemory.Slice(pos, len);
+        }
+
+        public Memory<byte> ToMemory(int pos, int len)
+        {
+            return _buffer.Memory.Slice(pos, len);
+        }
+
+        public Span<byte> ToSpan(int pos, int len)
+        {
+            return _buffer.Span.Slice(pos, len);
+        }
+#else
+        public ArraySegment<byte> ToArraySegment(int pos, int len)
+        {
+            return new ArraySegment<byte>(_buffer.Buffer, pos, len);
+        }
+
+        public MemoryStream ToMemoryStream(int pos, int len)
+        {
+            return new MemoryStream(_buffer.Buffer, pos, len);
+        }
+#endif
+
+#if !UNSAFE_BYTEBUFFER
+        // Pre-allocated helper arrays for convertion.
+        private float[] floathelper = new[] { 0.0f };
+        private int[] inthelper = new[] { 0 };
+        private double[] doublehelper = new[] { 0.0 };
+        private ulong[] ulonghelper = new[] { 0UL };
+#endif // !UNSAFE_BYTEBUFFER
+
+        // Helper functions for the unsafe version.
+        static public ushort ReverseBytes(ushort input)
+        {
+            return (ushort)(((input & 0x00FFU) << 8) |
+                            ((input & 0xFF00U) >> 8));
+        }
+        static public uint ReverseBytes(uint input)
+        {
+            return ((input & 0x000000FFU) << 24) |
+                   ((input & 0x0000FF00U) <<  8) |
+                   ((input & 0x00FF0000U) >>  8) |
+                   ((input & 0xFF000000U) >> 24);
+        }
+        static public ulong ReverseBytes(ulong input)
+        {
+            return (((input & 0x00000000000000FFUL) << 56) |
+                    ((input & 0x000000000000FF00UL) << 40) |
+                    ((input & 0x0000000000FF0000UL) << 24) |
+                    ((input & 0x00000000FF000000UL) <<  8) |
+                    ((input & 0x000000FF00000000UL) >>  8) |
+                    ((input & 0x0000FF0000000000UL) >> 24) |
+                    ((input & 0x00FF000000000000UL) >> 40) |
+                    ((input & 0xFF00000000000000UL) >> 56));
+        }
+
+#if !UNSAFE_BYTEBUFFER
+        // Helper functions for the safe (but slower) version.
+        protected void WriteLittleEndian(int offset, int count, ulong data)
+        {
+            if (BitConverter.IsLittleEndian)
+            {
+                for (int i = 0; i < count; i++)
+                {
+                    _buffer.Buffer[offset + i] = (byte)(data >> i * 8);
+                }
+            }
+            else
+            {
+                for (int i = 0; i < count; i++)
+                {
+                    _buffer.Buffer[offset + count - 1 - i] = (byte)(data >> i * 8);
+                }
+            }
+        }
+
+        protected ulong ReadLittleEndian(int offset, int count)
+        {
+            AssertOffsetAndLength(offset, count);
+            ulong r = 0;
+            if (BitConverter.IsLittleEndian)
+            {
+                for (int i = 0; i < count; i++)
+                {
+                    r |= (ulong)_buffer.Buffer[offset + i] << i * 8;
+                }
+            }
+            else
+            {
+                for (int i = 0; i < count; i++)
+                {
+                    r |= (ulong)_buffer.Buffer[offset + count - 1 - i] << i * 8;
+                }
+            }
+            return r;
+        }
+#endif // !UNSAFE_BYTEBUFFER
+
+        private void AssertOffsetAndLength(int offset, int length)
+        {
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+            if (offset < 0 ||
+                offset > _buffer.Length - length)
+                throw new ArgumentOutOfRangeException();
+#endif
+        }
+
+#if ENABLE_SPAN_T
+
+        public void PutSbyte(int offset, sbyte value)
+        {
+            AssertOffsetAndLength(offset, sizeof(sbyte));
+            _buffer.Span[offset] = (byte)value;
+        }
+
+        public void PutByte(int offset, byte value)
+        {
+            AssertOffsetAndLength(offset, sizeof(byte));
+            _buffer.Span[offset] = value;
+        }
+
+        public void PutByte(int offset, byte value, int count)
+        {
+            AssertOffsetAndLength(offset, sizeof(byte) * count);
+            Span<byte> span = _buffer.Span.Slice(offset, count);
+            for (var i = 0; i < span.Length; ++i)
+                span[i] = value;
+        }
+#else
+        public void PutSbyte(int offset, sbyte value)
+        {
+            AssertOffsetAndLength(offset, sizeof(sbyte));
+            _buffer.Buffer[offset] = (byte)value;
+        }
+
+        public void PutByte(int offset, byte value)
+        {
+            AssertOffsetAndLength(offset, sizeof(byte));
+            _buffer.Buffer[offset] = value;
+        }
+
+        public void PutByte(int offset, byte value, int count)
+        {
+            AssertOffsetAndLength(offset, sizeof(byte) * count);
+            for (var i = 0; i < count; ++i)
+                _buffer.Buffer[offset + i] = value;
+        }
+#endif
+
+        // this method exists in order to conform with Java ByteBuffer standards
+        public void Put(int offset, byte value)
+        {
+            PutByte(offset, value);
+        }
+
+#if ENABLE_SPAN_T
+        public unsafe void PutStringUTF8(int offset, string value)
+        {
+            AssertOffsetAndLength(offset, value.Length);
+            fixed (char* s = value)
+            {
+                fixed (byte* buffer = &MemoryMarshal.GetReference(_buffer.Span))
+                {
+                    Encoding.UTF8.GetBytes(s, value.Length, buffer + offset, Length - offset);
+                }
+            }
+        }
+#else
+        public void PutStringUTF8(int offset, string value)
+        {
+            AssertOffsetAndLength(offset, value.Length);
+            Encoding.UTF8.GetBytes(value, 0, value.Length,
+                _buffer.Buffer, offset);
+        }
+#endif
+
+#if UNSAFE_BYTEBUFFER
+        // Unsafe but more efficient versions of Put*.
+        public void PutShort(int offset, short value)
+        {
+            PutUshort(offset, (ushort)value);
+        }
+
+        public unsafe void PutUshort(int offset, ushort value)
+        {
+            AssertOffsetAndLength(offset, sizeof(ushort));
+#if ENABLE_SPAN_T
+            Span<byte> span = _buffer.Span.Slice(offset);
+            BinaryPrimitives.WriteUInt16LittleEndian(span, value);
+#else
+            fixed (byte* ptr = _buffer.Buffer)
+            {
+                *(ushort*)(ptr + offset) = BitConverter.IsLittleEndian
+                    ? value
+                    : ReverseBytes(value);
+            }
+#endif
+        }
+
+        public void PutInt(int offset, int value)
+        {
+            PutUint(offset, (uint)value);
+        }
+
+        public unsafe void PutUint(int offset, uint value)
+        {
+            AssertOffsetAndLength(offset, sizeof(uint));
+#if ENABLE_SPAN_T
+            Span<byte> span = _buffer.Span.Slice(offset);
+            BinaryPrimitives.WriteUInt32LittleEndian(span, value);
+#else
+            fixed (byte* ptr = _buffer.Buffer)
+            {
+                *(uint*)(ptr + offset) = BitConverter.IsLittleEndian
+                    ? value
+                    : ReverseBytes(value);
+            }
+#endif
+        }
+
+        public unsafe void PutLong(int offset, long value)
+        {
+            PutUlong(offset, (ulong)value);
+        }
+
+        public unsafe void PutUlong(int offset, ulong value)
+        {
+            AssertOffsetAndLength(offset, sizeof(ulong));
+#if ENABLE_SPAN_T
+            Span<byte> span = _buffer.Span.Slice(offset);
+            BinaryPrimitives.WriteUInt64LittleEndian(span, value);
+#else
+            fixed (byte* ptr = _buffer.Buffer)
+            {
+                *(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
+                    ? value
+                    : ReverseBytes(value);
+            }
+#endif
+        }
+
+        public unsafe void PutFloat(int offset, float value)
+        {
+            AssertOffsetAndLength(offset, sizeof(float));
+#if ENABLE_SPAN_T
+            fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.Span))
+#else
+            fixed (byte* ptr = _buffer.Buffer)
+#endif
+            {
+                if (BitConverter.IsLittleEndian)
+                {
+                    *(float*)(ptr + offset) = value;
+                }
+                else
+                {
+                    *(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value));
+                }
+            }
+        }
+
+        public unsafe void PutDouble(int offset, double value)
+        {
+            AssertOffsetAndLength(offset, sizeof(double));
+#if ENABLE_SPAN_T
+            fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.Span))
+#else
+            fixed (byte* ptr = _buffer.Buffer)
+#endif
+            {
+                if (BitConverter.IsLittleEndian)
+                {
+                    *(double*)(ptr + offset) = value;
+                }
+                else
+                {
+                    *(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(&value));
+                }
+            }
+        }
+#else // !UNSAFE_BYTEBUFFER
+        // Slower versions of Put* for when unsafe code is not allowed.
+        public void PutShort(int offset, short value)
+        {
+            AssertOffsetAndLength(offset, sizeof(short));
+            WriteLittleEndian(offset, sizeof(short), (ulong)value);
+        }
+
+        public void PutUshort(int offset, ushort value)
+        {
+            AssertOffsetAndLength(offset, sizeof(ushort));
+            WriteLittleEndian(offset, sizeof(ushort), (ulong)value);
+        }
+
+        public void PutInt(int offset, int value)
+        {
+            AssertOffsetAndLength(offset, sizeof(int));
+            WriteLittleEndian(offset, sizeof(int), (ulong)value);
+        }
+
+        public void PutUint(int offset, uint value)
+        {
+            AssertOffsetAndLength(offset, sizeof(uint));
+            WriteLittleEndian(offset, sizeof(uint), (ulong)value);
+        }
+
+        public void PutLong(int offset, long value)
+        {
+            AssertOffsetAndLength(offset, sizeof(long));
+            WriteLittleEndian(offset, sizeof(long), (ulong)value);
+        }
+
+        public void PutUlong(int offset, ulong value)
+        {
+            AssertOffsetAndLength(offset, sizeof(ulong));
+            WriteLittleEndian(offset, sizeof(ulong), value);
+        }
+
+        public void PutFloat(int offset, float value)
+        {
+            AssertOffsetAndLength(offset, sizeof(float));
+            floathelper[0] = value;
+            Buffer.BlockCopy(floathelper, 0, inthelper, 0, sizeof(float));
+            WriteLittleEndian(offset, sizeof(float), (ulong)inthelper[0]);
+        }
+
+        public void PutDouble(int offset, double value)
+        {
+            AssertOffsetAndLength(offset, sizeof(double));
+            doublehelper[0] = value;
+            Buffer.BlockCopy(doublehelper, 0, ulonghelper, 0, sizeof(double));
+            WriteLittleEndian(offset, sizeof(double), ulonghelper[0]);
+        }
+
+#endif // UNSAFE_BYTEBUFFER
+
+#if ENABLE_SPAN_T
+        public sbyte GetSbyte(int index)
+        {
+            AssertOffsetAndLength(index, sizeof(sbyte));
+            return (sbyte)_buffer.ReadOnlySpan[index];
+        }
+
+        public byte Get(int index)
+        {
+            AssertOffsetAndLength(index, sizeof(byte));
+            return _buffer.ReadOnlySpan[index];
+        }
+#else
+        public sbyte GetSbyte(int index)
+        {
+            AssertOffsetAndLength(index, sizeof(sbyte));
+            return (sbyte)_buffer.Buffer[index];
+        }
+
+        public byte Get(int index)
+        {
+            AssertOffsetAndLength(index, sizeof(byte));
+            return _buffer.Buffer[index];
+        }
+#endif
+
+#if ENABLE_SPAN_T
+        public unsafe string GetStringUTF8(int startPos, int len)
+        {
+            fixed (byte* buffer = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan.Slice(startPos)))
+            {
+                return Encoding.UTF8.GetString(buffer, len);
+            }
+        }
+#else
+        public string GetStringUTF8(int startPos, int len)
+        {
+            return Encoding.UTF8.GetString(_buffer.Buffer, startPos, len);
+        }
+#endif
+
+#if UNSAFE_BYTEBUFFER
+        // Unsafe but more efficient versions of Get*.
+        public short GetShort(int offset)
+        {
+            return (short)GetUshort(offset);
+        }
+
+        public unsafe ushort GetUshort(int offset)
+        {
+            AssertOffsetAndLength(offset, sizeof(ushort));
+#if ENABLE_SPAN_T
+            ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset);
+            return BinaryPrimitives.ReadUInt16LittleEndian(span);
+#else
+            fixed (byte* ptr = _buffer.Buffer)
+            {
+                return BitConverter.IsLittleEndian
+                    ? *(ushort*)(ptr + offset)
+                    : ReverseBytes(*(ushort*)(ptr + offset));
+            }
+#endif
+        }
+
+        public int GetInt(int offset)
+        {
+            return (int)GetUint(offset);
+        }
+
+        public unsafe uint GetUint(int offset)
+        {
+            AssertOffsetAndLength(offset, sizeof(uint));
+#if ENABLE_SPAN_T
+            ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset);
+            return BinaryPrimitives.ReadUInt32LittleEndian(span);
+#else
+            fixed (byte* ptr = _buffer.Buffer)
+            {
+                return BitConverter.IsLittleEndian
+                    ? *(uint*)(ptr + offset)
+                    : ReverseBytes(*(uint*)(ptr + offset));
+            }
+#endif
+        }
+
+        public long GetLong(int offset)
+        {
+            return (long)GetUlong(offset);
+        }
+
+        public unsafe ulong GetUlong(int offset)
+        {
+            AssertOffsetAndLength(offset, sizeof(ulong));
+#if ENABLE_SPAN_T
+            ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset);
+            return BinaryPrimitives.ReadUInt64LittleEndian(span);
+#else            
+            fixed (byte* ptr = _buffer.Buffer)
+            {
+                return BitConverter.IsLittleEndian
+                    ? *(ulong*)(ptr + offset)
+                    : ReverseBytes(*(ulong*)(ptr + offset));
+            }
+#endif
+        }
+
+        public unsafe float GetFloat(int offset)
+        {
+            AssertOffsetAndLength(offset, sizeof(float));
+#if ENABLE_SPAN_T
+            fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan))
+#else
+            fixed (byte* ptr = _buffer.Buffer)
+#endif
+            {
+                if (BitConverter.IsLittleEndian)
+                {
+                    return *(float*)(ptr + offset);
+                }
+                else
+                {
+                    uint uvalue = ReverseBytes(*(uint*)(ptr + offset));
+                    return *(float*)(&uvalue);
+                }
+            }
+        }
+
+        public unsafe double GetDouble(int offset)
+        {
+            AssertOffsetAndLength(offset, sizeof(double));
+#if ENABLE_SPAN_T
+            fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan))
+#else
+            fixed (byte* ptr = _buffer.Buffer)
+#endif
+            {
+                if (BitConverter.IsLittleEndian)
+                {
+                    return *(double*)(ptr + offset);
+                }
+                else
+                {
+                    ulong uvalue = ReverseBytes(*(ulong*)(ptr + offset));
+                    return *(double*)(&uvalue);
+                }
+            }
+        }
+#else // !UNSAFE_BYTEBUFFER
+        // Slower versions of Get* for when unsafe code is not allowed.
+        public short GetShort(int index)
+        {
+            return (short)ReadLittleEndian(index, sizeof(short));
+        }
+
+        public ushort GetUshort(int index)
+        {
+            return (ushort)ReadLittleEndian(index, sizeof(ushort));
+        }
+
+        public int GetInt(int index)
+        {
+            return (int)ReadLittleEndian(index, sizeof(int));
+        }
+
+        public uint GetUint(int index)
+        {
+            return (uint)ReadLittleEndian(index, sizeof(uint));
+        }
+
+        public long GetLong(int index)
+        {
+            return (long)ReadLittleEndian(index, sizeof(long));
+        }
+
+        public ulong GetUlong(int index)
+        {
+            return ReadLittleEndian(index, sizeof(ulong));
+        }
+
+        public float GetFloat(int index)
+        {
+            int i = (int)ReadLittleEndian(index, sizeof(float));
+            inthelper[0] = i;
+            Buffer.BlockCopy(inthelper, 0, floathelper, 0, sizeof(float));
+            return floathelper[0];
+        }
+
+        public double GetDouble(int index)
+        {
+            ulong i = ReadLittleEndian(index, sizeof(double));
+            // There's Int64BitsToDouble but it uses unsafe code internally.
+            ulonghelper[0] = i;
+            Buffer.BlockCopy(ulonghelper, 0, doublehelper, 0, sizeof(double));
+            return doublehelper[0];
+        }
+#endif // UNSAFE_BYTEBUFFER
+
+        /// <summary>
+        /// Copies an array of type T into this buffer, ending at the given
+        /// offset into this buffer. The starting offset is calculated based on the length
+        /// of the array and is the value returned.
+        /// </summary>
+        /// <typeparam name="T">The type of the input data (must be a struct)</typeparam>
+        /// <param name="offset">The offset into this buffer where the copy will end</param>
+        /// <param name="x">The array to copy data from</param>
+        /// <returns>The 'start' location of this buffer now, after the copy completed</returns>
+        public int Put<T>(int offset, T[] x)
+            where T : struct
+        {
+            if (x == null)
+            {
+                throw new ArgumentNullException("Cannot put a null array");
+            }
+
+            if (x.Length == 0)
+            {
+                throw new ArgumentException("Cannot put an empty array");
+            }
+
+            if (!IsSupportedType<T>())
+            {
+                throw new ArgumentException("Cannot put an array of type "
+                    + typeof(T) + " into this buffer");
+            }
+
+            if (BitConverter.IsLittleEndian)
+            {
+                int numBytes = ByteBuffer.ArraySize(x);
+                offset -= numBytes;
+                AssertOffsetAndLength(offset, numBytes);
+                // if we are LE, just do a block copy
+#if ENABLE_SPAN_T
+                MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes));
+#else
+                Buffer.BlockCopy(x, 0, _buffer.Buffer, offset, numBytes);
+#endif
+            }
+            else
+            {
+                throw new NotImplementedException("Big Endian Support not implemented yet " +
+                    "for putting typed arrays");
+                // if we are BE, we have to swap each element by itself
+                //for(int i = x.Length - 1; i >= 0; i--)
+                //{
+                //  todo: low priority, but need to genericize the Put<T>() functions
+                //}
+            }
+            return offset;
+        }
+
+#if ENABLE_SPAN_T
+        public int Put<T>(int offset, Span<T> x)
+            where T : struct
+        {
+            if (x.Length == 0)
+            {
+                throw new ArgumentException("Cannot put an empty array");
+            }
+
+            if (!IsSupportedType<T>())
+            {
+                throw new ArgumentException("Cannot put an array of type "
+                    + typeof(T) + " into this buffer");
+            }
+
+            if (BitConverter.IsLittleEndian)
+            {
+                int numBytes = ByteBuffer.ArraySize(x);
+                offset -= numBytes;
+                AssertOffsetAndLength(offset, numBytes);
+                // if we are LE, just do a block copy
+                MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes));
+            }
+            else
+            {
+                throw new NotImplementedException("Big Endian Support not implemented yet " +
+                    "for putting typed arrays");
+                // if we are BE, we have to swap each element by itself
+                //for(int i = x.Length - 1; i >= 0; i--)
+                //{
+                //  todo: low priority, but need to genericize the Put<T>() functions
+                //}
+            }
+            return offset;
+        }
+#endif
+    }
+}
diff --git a/net/FlatBuffers/ByteBufferUtil.cs b/net/FlatBuffers/ByteBufferUtil.cs
new file mode 100644
index 0000000..66e8266
--- /dev/null
+++ b/net/FlatBuffers/ByteBufferUtil.cs
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed 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 FlatBuffers
+{
+	/// <summary>
+	/// Class that collects utility functions around `ByteBuffer`.
+	/// </summary>
+	public class ByteBufferUtil
+	{
+		// Extract the size prefix from a `ByteBuffer`.
+		public static int GetSizePrefix(ByteBuffer bb) {
+			return bb.GetInt(bb.Position);
+		}
+
+		// Create a duplicate of a size-prefixed `ByteBuffer` that has its position
+		// advanced just past the size prefix.
+		public static ByteBuffer RemoveSizePrefix(ByteBuffer bb) {
+			ByteBuffer s = bb.Duplicate();
+			s.Position += FlatBufferConstants.SizePrefixLength;
+			return s;
+		}
+	}
+}
diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs
new file mode 100644
index 0000000..27c16b3
--- /dev/null
+++ b/net/FlatBuffers/FlatBufferBuilder.cs
@@ -0,0 +1,842 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed 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;
+using System.Collections.Generic;
+using System.Text;
+
+/// @file
+/// @addtogroup flatbuffers_csharp_api
+/// @{
+
+namespace FlatBuffers
+{
+    /// <summary>
+    /// Responsible for building up and accessing a FlatBuffer formatted byte
+    /// array (via ByteBuffer).
+    /// </summary>
+    public class FlatBufferBuilder
+    {
+        private int _space;
+        private ByteBuffer _bb;
+        private int _minAlign = 1;
+
+        // The vtable for the current table (if _vtableSize >= 0)
+        private int[] _vtable = new int[16];
+        // The size of the vtable. -1 indicates no vtable
+        private int _vtableSize = -1;
+        // Starting offset of the current struct/table.
+        private int _objectStart;
+        // List of offsets of all vtables.
+        private int[] _vtables = new int[16];
+        // Number of entries in `vtables` in use.
+        private int _numVtables = 0;
+        // For the current vector being built.
+        private int _vectorNumElems = 0;
+
+        // For CreateSharedString
+        private Dictionary<string, StringOffset> _sharedStringMap = null;
+
+        /// <summary>
+        /// Create a FlatBufferBuilder with a given initial size.
+        /// </summary>
+        /// <param name="initialSize">
+        /// The initial size to use for the internal buffer.
+        /// </param>
+        public FlatBufferBuilder(int initialSize)
+        {
+            if (initialSize <= 0)
+                throw new ArgumentOutOfRangeException("initialSize",
+                    initialSize, "Must be greater than zero");
+            _space = initialSize;
+            _bb = new ByteBuffer(initialSize);
+        }
+
+        /// <summary>
+        /// Create a FlatBufferBuilder backed by the pased in ByteBuffer
+        /// </summary>
+        /// <param name="buffer">The ByteBuffer to write to</param>
+        public FlatBufferBuilder(ByteBuffer buffer)
+        {
+            _bb = buffer;
+            _space = buffer.Length;
+            buffer.Reset();
+        }
+
+        /// <summary>
+        /// Reset the FlatBufferBuilder by purging all data that it holds.
+        /// </summary>
+        public void Clear()
+        {
+            _space = _bb.Length;
+            _bb.Reset();
+            _minAlign = 1;
+            while (_vtableSize > 0) _vtable[--_vtableSize] = 0;
+            _vtableSize = -1;
+            _objectStart = 0;
+            _numVtables = 0;
+            _vectorNumElems = 0;
+        }
+
+        /// <summary>
+        /// Gets and sets a Boolean to disable the optimization when serializing
+        /// default values to a Table.
+        ///
+        /// In order to save space, fields that are set to their default value
+        /// don't get serialized into the buffer.
+        /// </summary>
+        public bool ForceDefaults { get; set; }
+
+        /// @cond FLATBUFFERS_INTERNAL
+
+        public int Offset { get { return _bb.Length - _space; } }
+
+        public void Pad(int size)
+        {
+             _bb.PutByte(_space -= size, 0, size);
+        }
+
+        // Doubles the size of the ByteBuffer, and copies the old data towards
+        // the end of the new buffer (since we build the buffer backwards).
+        void GrowBuffer()
+        {
+            _bb.GrowFront(_bb.Length << 1);
+        }
+
+        // Prepare to write an element of `size` after `additional_bytes`
+        // have been written, e.g. if you write a string, you need to align
+        // such the int length field is aligned to SIZEOF_INT, and the string
+        // data follows it directly.
+        // If all you need to do is align, `additional_bytes` will be 0.
+        public void Prep(int size, int additionalBytes)
+        {
+            // Track the biggest thing we've ever aligned to.
+            if (size > _minAlign)
+                _minAlign = size;
+            // Find the amount of alignment needed such that `size` is properly
+            // aligned after `additional_bytes`
+            var alignSize =
+                ((~((int)_bb.Length - _space + additionalBytes)) + 1) &
+                (size - 1);
+            // Reallocate the buffer if needed.
+            while (_space < alignSize + size + additionalBytes)
+            {
+                var oldBufSize = (int)_bb.Length;
+                GrowBuffer();
+                _space += (int)_bb.Length - oldBufSize;
+
+            }
+            if (alignSize > 0)
+                Pad(alignSize);
+        }
+
+        public void PutBool(bool x)
+        {
+          _bb.PutByte(_space -= sizeof(byte), (byte)(x ? 1 : 0));
+        }
+
+        public void PutSbyte(sbyte x)
+        {
+          _bb.PutSbyte(_space -= sizeof(sbyte), x);
+        }
+
+        public void PutByte(byte x)
+        {
+            _bb.PutByte(_space -= sizeof(byte), x);
+        }
+
+        public void PutShort(short x)
+        {
+            _bb.PutShort(_space -= sizeof(short), x);
+        }
+
+        public void PutUshort(ushort x)
+        {
+          _bb.PutUshort(_space -= sizeof(ushort), x);
+        }
+
+        public void PutInt(int x)
+        {
+            _bb.PutInt(_space -= sizeof(int), x);
+        }
+
+        public void PutUint(uint x)
+        {
+          _bb.PutUint(_space -= sizeof(uint), x);
+        }
+
+        public void PutLong(long x)
+        {
+            _bb.PutLong(_space -= sizeof(long), x);
+        }
+
+        public void PutUlong(ulong x)
+        {
+          _bb.PutUlong(_space -= sizeof(ulong), x);
+        }
+
+        public void PutFloat(float x)
+        {
+            _bb.PutFloat(_space -= sizeof(float), x);
+        }
+
+        /// <summary>
+        /// Puts an array of type T into this builder at the
+        /// current offset
+        /// </summary>
+        /// <typeparam name="T">The type of the input data </typeparam>
+        /// <param name="x">The array to copy data from</param>
+        public void Put<T>(T[] x)
+            where T : struct
+        {
+            _space = _bb.Put(_space, x);
+        }
+
+#if ENABLE_SPAN_T
+        /// <summary>
+        /// Puts a span of type T into this builder at the
+        /// current offset
+        /// </summary>
+        /// <typeparam name="T">The type of the input data </typeparam>
+        /// <param name="x">The span to copy data from</param>
+        public void Put<T>(Span<T> x)
+            where T : struct
+        {
+            _space = _bb.Put(_space, x);
+        }
+#endif
+
+        public void PutDouble(double x)
+        {
+            _bb.PutDouble(_space -= sizeof(double), x);
+        }
+        /// @endcond
+
+        /// <summary>
+        /// Add a `bool` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `bool` to add to the buffer.</param>
+        public void AddBool(bool x) { Prep(sizeof(byte), 0); PutBool(x); }
+
+        /// <summary>
+        /// Add a `sbyte` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `sbyte` to add to the buffer.</param>
+        public void AddSbyte(sbyte x) { Prep(sizeof(sbyte), 0); PutSbyte(x); }
+
+        /// <summary>
+        /// Add a `byte` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `byte` to add to the buffer.</param>
+        public void AddByte(byte x) { Prep(sizeof(byte), 0); PutByte(x); }
+
+        /// <summary>
+        /// Add a `short` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `short` to add to the buffer.</param>
+        public void AddShort(short x) { Prep(sizeof(short), 0); PutShort(x); }
+
+        /// <summary>
+        /// Add an `ushort` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `ushort` to add to the buffer.</param>
+        public void AddUshort(ushort x) { Prep(sizeof(ushort), 0); PutUshort(x); }
+
+        /// <summary>
+        /// Add an `int` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `int` to add to the buffer.</param>
+        public void AddInt(int x) { Prep(sizeof(int), 0); PutInt(x); }
+
+        /// <summary>
+        /// Add an `uint` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `uint` to add to the buffer.</param>
+        public void AddUint(uint x) { Prep(sizeof(uint), 0); PutUint(x); }
+
+        /// <summary>
+        /// Add a `long` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `long` to add to the buffer.</param>
+        public void AddLong(long x) { Prep(sizeof(long), 0); PutLong(x); }
+
+        /// <summary>
+        /// Add an `ulong` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `ulong` to add to the buffer.</param>
+        public void AddUlong(ulong x) { Prep(sizeof(ulong), 0); PutUlong(x); }
+
+        /// <summary>
+        /// Add a `float` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `float` to add to the buffer.</param>
+        public void AddFloat(float x) { Prep(sizeof(float), 0); PutFloat(x); }
+
+        /// <summary>
+        /// Add an array of type T to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <typeparam name="T">The type of the input data</typeparam>
+        /// <param name="x">The array to copy data from</param>
+        public void Add<T>(T[] x)
+            where T : struct
+        {
+            if (x == null)
+            {
+                throw new ArgumentNullException("Cannot add a null array");
+            }
+
+            if( x.Length == 0)
+            {
+                // don't do anything if the array is empty
+                return;
+            }
+
+            if(!ByteBuffer.IsSupportedType<T>())
+            {
+                throw new ArgumentException("Cannot add this Type array to the builder");
+            }
+
+            int size = ByteBuffer.SizeOf<T>();
+            // Need to prep on size (for data alignment) and then we pass the
+            // rest of the length (minus 1) as additional bytes
+            Prep(size, size * (x.Length - 1));
+            Put(x);
+        }
+
+#if ENABLE_SPAN_T
+        /// <summary>
+        /// Add a span of type T to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <typeparam name="T">The type of the input data</typeparam>
+        /// <param name="x">The span to copy data from</param>
+        public void Add<T>(Span<T> x)
+            where T : struct
+        {
+            if (!ByteBuffer.IsSupportedType<T>())
+            {
+                throw new ArgumentException("Cannot add this Type array to the builder");
+            }
+
+            int size = ByteBuffer.SizeOf<T>();
+            // Need to prep on size (for data alignment) and then we pass the
+            // rest of the length (minus 1) as additional bytes
+            Prep(size, size * (x.Length - 1));
+            Put(x);
+        }
+#endif
+
+        /// <summary>
+        /// Add a `double` to the buffer (aligns the data and grows if necessary).
+        /// </summary>
+        /// <param name="x">The `double` to add to the buffer.</param>
+        public void AddDouble(double x) { Prep(sizeof(double), 0);
+                                          PutDouble(x); }
+
+        /// <summary>
+        /// Adds an offset, relative to where it will be written.
+        /// </summary>
+        /// <param name="off">The offset to add to the buffer.</param>
+        public void AddOffset(int off)
+        {
+            Prep(sizeof(int), 0);  // Ensure alignment is already done.
+            if (off > Offset)
+                throw new ArgumentException();
+
+            off = Offset - off + sizeof(int);
+            PutInt(off);
+        }
+
+        /// @cond FLATBUFFERS_INTERNAL
+        public void StartVector(int elemSize, int count, int alignment)
+        {
+            NotNested();
+            _vectorNumElems = count;
+            Prep(sizeof(int), elemSize * count);
+            Prep(alignment, elemSize * count); // Just in case alignment > int.
+        }
+        /// @endcond
+
+        /// <summary>
+        /// Writes data necessary to finish a vector construction.
+        /// </summary>
+        public VectorOffset EndVector()
+        {
+            PutInt(_vectorNumElems);
+            return new VectorOffset(Offset);
+        }
+
+        /// <summary>
+        /// Creates a vector of tables.
+        /// </summary>
+        /// <param name="offsets">Offsets of the tables.</param>
+        public VectorOffset CreateVectorOfTables<T>(Offset<T>[] offsets) where T : struct
+        {
+            NotNested();
+            StartVector(sizeof(int), offsets.Length, sizeof(int));
+            for (int i = offsets.Length - 1; i >= 0; i--) AddOffset(offsets[i].Value);
+            return EndVector();
+        }
+
+        /// @cond FLATBUFFERS_INTENRAL
+        public void Nested(int obj)
+        {
+            // Structs are always stored inline, so need to be created right
+            // where they are used. You'll get this assert if you created it
+            // elsewhere.
+            if (obj != Offset)
+                throw new Exception(
+                    "FlatBuffers: struct must be serialized inline.");
+        }
+
+        public void NotNested()
+        {
+            // You should not be creating any other objects or strings/vectors
+            // while an object is being constructed
+            if (_vtableSize >= 0)
+                throw new Exception(
+                    "FlatBuffers: object serialization must not be nested.");
+        }
+
+        public void StartTable(int numfields)
+        {
+            if (numfields < 0)
+                throw new ArgumentOutOfRangeException("Flatbuffers: invalid numfields");
+
+            NotNested();
+
+            if (_vtable.Length < numfields)
+                _vtable = new int[numfields];
+
+            _vtableSize = numfields;
+            _objectStart = Offset;
+        }
+
+
+        // Set the current vtable at `voffset` to the current location in the
+        // buffer.
+        public void Slot(int voffset)
+        {
+            if (voffset >= _vtableSize)
+                throw new IndexOutOfRangeException("Flatbuffers: invalid voffset");
+
+            _vtable[voffset] = Offset;
+        }
+
+        /// <summary>
+        /// Adds a Boolean to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddBool(int o, bool x, bool d) { if (ForceDefaults || x != d) { AddBool(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds a SByte to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddSbyte(int o, sbyte x, sbyte d) { if (ForceDefaults || x != d) { AddSbyte(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds a Byte to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddByte(int o, byte x, byte d) { if (ForceDefaults || x != d) { AddByte(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds a Int16 to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddShort(int o, short x, int d) { if (ForceDefaults || x != d) { AddShort(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds a UInt16 to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddUshort(int o, ushort x, ushort d) { if (ForceDefaults || x != d) { AddUshort(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds an Int32 to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddInt(int o, int x, int d) { if (ForceDefaults || x != d) { AddInt(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds a UInt32 to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddUint(int o, uint x, uint d) { if (ForceDefaults || x != d) { AddUint(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds an Int64 to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddLong(int o, long x, long d) { if (ForceDefaults || x != d) { AddLong(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds a UInt64 to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddUlong(int o, ulong x, ulong d) { if (ForceDefaults || x != d) { AddUlong(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds a Single to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddFloat(int o, float x, double d) { if (ForceDefaults || x != d) { AddFloat(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds a Double to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddDouble(int o, double x, double d) { if (ForceDefaults || x != d) { AddDouble(x); Slot(o); } }
+
+        /// <summary>
+        /// Adds a buffer offset to the Table at index `o` in its vtable using the value `x` and default `d`
+        /// </summary>
+        /// <param name="o">The index into the vtable</param>
+        /// <param name="x">The value to put into the buffer. If the value is equal to the default
+        /// the value will be skipped.</param>
+        /// <param name="d">The default value to compare the value against</param>
+        public void AddOffset(int o, int x, int d) { if (x != d) { AddOffset(x); Slot(o); } }
+        /// @endcond
+
+        /// <summary>
+        /// Encode the string `s` in the buffer using UTF-8.
+        /// </summary>
+        /// <param name="s">The string to encode.</param>
+        /// <returns>
+        /// The offset in the buffer where the encoded string starts.
+        /// </returns>
+        public StringOffset CreateString(string s)
+        {
+            NotNested();
+            AddByte(0);
+            var utf8StringLen = Encoding.UTF8.GetByteCount(s);
+            StartVector(1, utf8StringLen, 1);
+            _bb.PutStringUTF8(_space -= utf8StringLen, s);
+            return new StringOffset(EndVector().Value);
+        }
+
+
+#if ENABLE_SPAN_T
+        /// <summary>
+        /// Creates a string in the buffer from a Span containing
+        /// a UTF8 string.
+        /// </summary>
+        /// <param name="chars">the UTF8 string to add to the buffer</param>
+        /// <returns>
+        /// The offset in the buffer where the encoded string starts.
+        /// </returns>
+        public StringOffset CreateUTF8String(Span<byte> chars)
+        {
+            NotNested();
+            AddByte(0);
+            var utf8StringLen = chars.Length;
+            StartVector(1, utf8StringLen, 1);
+            _space = _bb.Put(_space, chars);
+            return new StringOffset(EndVector().Value);
+        }
+#endif
+
+        /// <summary>
+        /// Store a string in the buffer, which can contain any binary data.
+        /// If a string with this exact contents has already been serialized before,
+        /// instead simply returns the offset of the existing string.
+        /// </summary>
+        /// <param name="s">The string to encode.</param>
+        /// <returns>
+        /// The offset in the buffer where the encoded string starts.
+        /// </returns>
+        public StringOffset CreateSharedString(string s)
+        {
+            if (_sharedStringMap == null)
+            {
+                _sharedStringMap = new Dictionary<string, StringOffset>();
+            }
+
+            if (_sharedStringMap.ContainsKey(s))
+            {
+                return _sharedStringMap[s];
+            }
+
+            var stringOffset = CreateString(s);
+            _sharedStringMap.Add(s, stringOffset);
+            return stringOffset;
+        }
+
+        /// @cond FLATBUFFERS_INTERNAL
+        // Structs are stored inline, so nothing additional is being added.
+        // `d` is always 0.
+        public void AddStruct(int voffset, int x, int d)
+        {
+            if (x != d)
+            {
+                Nested(x);
+                Slot(voffset);
+            }
+        }
+
+        public int EndTable()
+        {
+            if (_vtableSize < 0)
+                throw new InvalidOperationException(
+                  "Flatbuffers: calling EndTable without a StartTable");
+
+            AddInt((int)0);
+            var vtableloc = Offset;
+            // Write out the current vtable.
+            int i = _vtableSize - 1;
+            // Trim trailing zeroes.
+            for (; i >= 0 && _vtable[i] == 0; i--) {}
+            int trimmedSize = i + 1;
+            for (; i >= 0 ; i--) {
+                // Offset relative to the start of the table.
+                short off = (short)(_vtable[i] != 0
+                                        ? vtableloc - _vtable[i]
+                                        : 0);
+                AddShort(off);
+
+                // clear out written entry
+                _vtable[i] = 0;
+            }
+
+            const int standardFields = 2; // The fields below:
+            AddShort((short)(vtableloc - _objectStart));
+            AddShort((short)((trimmedSize + standardFields) *
+                             sizeof(short)));
+
+            // Search for an existing vtable that matches the current one.
+            int existingVtable = 0;
+            for (i = 0; i < _numVtables; i++) {
+                int vt1 = _bb.Length - _vtables[i];
+                int vt2 = _space;
+                short len = _bb.GetShort(vt1);
+                if (len == _bb.GetShort(vt2)) {
+                    for (int j = sizeof(short); j < len; j += sizeof(short)) {
+                        if (_bb.GetShort(vt1 + j) != _bb.GetShort(vt2 + j)) {
+                            goto endLoop;
+                        }
+                    }
+                    existingVtable = _vtables[i];
+                    break;
+                }
+
+                endLoop: { }
+            }
+
+            if (existingVtable != 0) {
+                // Found a match:
+                // Remove the current vtable.
+                _space = _bb.Length - vtableloc;
+                // Point table to existing vtable.
+                _bb.PutInt(_space, existingVtable - vtableloc);
+            } else {
+                // No match:
+                // Add the location of the current vtable to the list of
+                // vtables.
+                if (_numVtables == _vtables.Length)
+                {
+                    // Arrays.CopyOf(vtables num_vtables * 2);
+                    var newvtables = new int[ _numVtables * 2];
+                    Array.Copy(_vtables, newvtables, _vtables.Length);
+
+                    _vtables = newvtables;
+                };
+                _vtables[_numVtables++] = Offset;
+                // Point table to current vtable.
+                _bb.PutInt(_bb.Length - vtableloc, Offset - vtableloc);
+            }
+
+            _vtableSize = -1;
+            return vtableloc;
+        }
+
+        // This checks a required field has been set in a given table that has
+        // just been constructed.
+        public void Required(int table, int field)
+        {
+          int table_start = _bb.Length - table;
+          int vtable_start = table_start - _bb.GetInt(table_start);
+          bool ok = _bb.GetShort(vtable_start + field) != 0;
+          // If this fails, the caller will show what field needs to be set.
+          if (!ok)
+            throw new InvalidOperationException("FlatBuffers: field " + field +
+                                                " must be set");
+        }
+        /// @endcond
+
+        /// <summary>
+        /// Finalize a buffer, pointing to the given `root_table`.
+        /// </summary>
+        /// <param name="rootTable">
+        /// An offset to be added to the buffer.
+        /// </param>
+        /// <param name="sizePrefix">
+        /// Whether to prefix the size to the buffer.
+        /// </param>
+        protected void Finish(int rootTable, bool sizePrefix)
+        {
+            Prep(_minAlign, sizeof(int) + (sizePrefix ? sizeof(int) : 0));
+            AddOffset(rootTable);
+            if (sizePrefix) {
+                AddInt(_bb.Length - _space);
+            }
+            _bb.Position = _space;
+        }
+
+        /// <summary>
+        /// Finalize a buffer, pointing to the given `root_table`.
+        /// </summary>
+        /// <param name="rootTable">
+        /// An offset to be added to the buffer.
+        /// </param>
+        public void Finish(int rootTable)
+        {
+            Finish(rootTable, false);
+        }
+
+        /// <summary>
+        /// Finalize a buffer, pointing to the given `root_table`, with the size prefixed.
+        /// </summary>
+        /// <param name="rootTable">
+        /// An offset to be added to the buffer.
+        /// </param>
+        public void FinishSizePrefixed(int rootTable)
+        {
+            Finish(rootTable, true);
+        }
+
+        /// <summary>
+        /// Get the ByteBuffer representing the FlatBuffer.
+        /// </summary>
+        /// <remarks>
+        /// This is typically only called after you call `Finish()`.
+        /// The actual data starts at the ByteBuffer's current position,
+        /// not necessarily at `0`.
+        /// </remarks>
+        /// <returns>
+        /// Returns the ByteBuffer for this FlatBuffer.
+        /// </returns>
+        public ByteBuffer DataBuffer { get { return _bb; } }
+
+        /// <summary>
+        /// A utility function to copy and return the ByteBuffer data as a
+        /// `byte[]`.
+        /// </summary>
+        /// <returns>
+        /// A full copy of the FlatBuffer data.
+        /// </returns>
+        public byte[] SizedByteArray()
+        {
+            return _bb.ToSizedArray();
+        }
+
+        /// <summary>
+        /// Finalize a buffer, pointing to the given `rootTable`.
+        /// </summary>
+        /// <param name="rootTable">
+        /// An offset to be added to the buffer.
+        /// </param>
+        /// <param name="fileIdentifier">
+        /// A FlatBuffer file identifier to be added to the buffer before
+        /// `root_table`.
+        /// </param>
+        /// <param name="sizePrefix">
+        /// Whether to prefix the size to the buffer.
+        /// </param>
+        protected void Finish(int rootTable, string fileIdentifier, bool sizePrefix)
+        {
+            Prep(_minAlign, sizeof(int) + (sizePrefix ? sizeof(int) : 0) +
+                            FlatBufferConstants.FileIdentifierLength);
+            if (fileIdentifier.Length !=
+                FlatBufferConstants.FileIdentifierLength)
+                throw new ArgumentException(
+                    "FlatBuffers: file identifier must be length " +
+                    FlatBufferConstants.FileIdentifierLength,
+                    "fileIdentifier");
+            for (int i = FlatBufferConstants.FileIdentifierLength - 1; i >= 0;
+                 i--)
+            {
+               AddByte((byte)fileIdentifier[i]);
+            }
+            Finish(rootTable, sizePrefix);
+        }
+
+        /// <summary>
+        /// Finalize a buffer, pointing to the given `rootTable`.
+        /// </summary>
+        /// <param name="rootTable">
+        /// An offset to be added to the buffer.
+        /// </param>
+        /// <param name="fileIdentifier">
+        /// A FlatBuffer file identifier to be added to the buffer before
+        /// `root_table`.
+        /// </param>
+        public void Finish(int rootTable, string fileIdentifier)
+        {
+            Finish(rootTable, fileIdentifier, false);
+        }
+
+        /// <summary>
+        /// Finalize a buffer, pointing to the given `rootTable`, with the size prefixed.
+        /// </summary>
+        /// <param name="rootTable">
+        /// An offset to be added to the buffer.
+        /// </param>
+        /// <param name="fileIdentifier">
+        /// A FlatBuffer file identifier to be added to the buffer before
+        /// `root_table`.
+        /// </param>
+        public void FinishSizePrefixed(int rootTable, string fileIdentifier)
+        {
+            Finish(rootTable, fileIdentifier, true);
+        }
+    }
+}
+
+/// @}
diff --git a/net/FlatBuffers/FlatBufferConstants.cs b/net/FlatBuffers/FlatBufferConstants.cs
new file mode 100644
index 0000000..730d7ef
--- /dev/null
+++ b/net/FlatBuffers/FlatBufferConstants.cs
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed 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;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace FlatBuffers
+{
+    public static class FlatBufferConstants
+    {
+        public const int FileIdentifierLength = 4;
+        public const int SizePrefixLength = 4;
+        /** A version identifier to force a compile error if someone
+        accidentally tries to build generated code with a runtime of
+        two mismatched version. Versions need to always match, as
+        the runtime and generated code are modified in sync.
+        Changes to the C# implementation need to be sure to change
+        the version here and in the code generator on every possible
+        incompatible change */
+        public static void FLATBUFFERS_1_11_1() {}
+    }
+}
diff --git a/net/FlatBuffers/FlatBuffers.Core.csproj b/net/FlatBuffers/FlatBuffers.Core.csproj
new file mode 100644
index 0000000..4285dd7
--- /dev/null
+++ b/net/FlatBuffers/FlatBuffers.Core.csproj
@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <TargetFramework>netstandard2.0</TargetFramework>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <Compile Remove="Properties\**" />
+    </ItemGroup>
+
+    <ItemGroup>
+      <EmbeddedResource Remove="Properties\**" />
+    </ItemGroup>
+
+    <ItemGroup>
+      <None Remove="Properties\**" />
+    </ItemGroup>
+
+</Project>
diff --git a/net/FlatBuffers/FlatBuffers.csproj b/net/FlatBuffers/FlatBuffers.csproj
new file mode 100644
index 0000000..a029094
--- /dev/null
+++ b/net/FlatBuffers/FlatBuffers.csproj
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{28C00774-1E73-4A75-AD8F-844CD21A064D}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>FlatBuffers</RootNamespace>
+    <AssemblyName>FlatBuffers</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ByteBuffer.cs" />
+    <Compile Include="FlatBufferBuilder.cs" />
+    <Compile Include="FlatBufferConstants.cs" />
+    <Compile Include="IFlatbufferObject.cs" />
+    <Compile Include="Offset.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Struct.cs" />
+    <Compile Include="Table.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/net/FlatBuffers/IFlatbufferObject.cs b/net/FlatBuffers/IFlatbufferObject.cs
new file mode 100644
index 0000000..6a15aba
--- /dev/null
+++ b/net/FlatBuffers/IFlatbufferObject.cs
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed 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 FlatBuffers
+{
+    /// <summary>
+    /// This is the base for both structs and tables.
+    /// </summary>
+    public interface IFlatbufferObject
+    {
+        void __init(int _i, ByteBuffer _bb);
+
+        ByteBuffer ByteBuffer { get; }
+    }
+}
diff --git a/net/FlatBuffers/Offset.cs b/net/FlatBuffers/Offset.cs
new file mode 100644
index 0000000..2b17cec
--- /dev/null
+++ b/net/FlatBuffers/Offset.cs
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed 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 FlatBuffers
+{
+    /// <summary>
+    /// Offset class for typesafe assignments.
+    /// </summary>
+    public struct Offset<T> where T : struct
+    {
+        public int Value;
+        public Offset(int value)
+        {
+            Value = value;
+        }
+    }
+
+    public struct StringOffset
+    {
+        public int Value;
+        public StringOffset(int value)
+        {
+            Value = value;
+        }
+    }
+
+    public struct VectorOffset
+    {
+        public int Value;
+        public VectorOffset(int value)
+        {
+            Value = value;
+        }
+    }
+}
diff --git a/net/FlatBuffers/Properties/AssemblyInfo.cs b/net/FlatBuffers/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..1edfac4
--- /dev/null
+++ b/net/FlatBuffers/Properties/AssemblyInfo.cs
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed 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.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("FlatBuffers")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("FlatBuffers")]
+[assembly: AssemblyCopyright("Copyright (c) 2015 Google Inc")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("91c32e64-ef20-47df-9c9f-cec9207bc6df")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/net/FlatBuffers/Struct.cs b/net/FlatBuffers/Struct.cs
new file mode 100644
index 0000000..4f7fac9
--- /dev/null
+++ b/net/FlatBuffers/Struct.cs
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed 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 FlatBuffers
+{
+    /// <summary>
+    /// All structs in the generated code derive from this class, and add their own accessors.
+    /// </summary>
+    public struct Struct
+    {
+        public int bb_pos { get; private set; }
+        public ByteBuffer bb { get; private set; }
+
+        // Re-init the internal state with an external buffer {@code ByteBuffer} and an offset within.
+        public Struct(int _i, ByteBuffer _bb)
+        {
+            bb = _bb;
+            bb_pos = _i;
+        }
+    }
+}
diff --git a/net/FlatBuffers/Table.cs b/net/FlatBuffers/Table.cs
new file mode 100644
index 0000000..e10ba95
--- /dev/null
+++ b/net/FlatBuffers/Table.cs
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed 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;
+using System.Text;
+
+namespace FlatBuffers
+{
+    /// <summary>
+    /// All tables in the generated code derive from this struct, and add their own accessors.
+    /// </summary>
+    public struct Table
+    {
+        public int bb_pos { get; private set; }
+        public ByteBuffer bb { get; private set; }
+
+        public ByteBuffer ByteBuffer { get { return bb; } }
+
+        // Re-init the internal state with an external buffer {@code ByteBuffer} and an offset within.
+        public Table(int _i, ByteBuffer _bb)
+        {
+            bb = _bb;
+            bb_pos = _i;
+        }
+
+        // Look up a field in the vtable, return an offset into the object, or 0 if the field is not
+        // present.
+        public int __offset(int vtableOffset)
+        {
+            int vtable = bb_pos - bb.GetInt(bb_pos);
+            return vtableOffset < bb.GetShort(vtable) ? (int)bb.GetShort(vtable + vtableOffset) : 0;
+        }
+
+        public static int __offset(int vtableOffset, int offset, ByteBuffer bb)
+        {
+            int vtable = bb.Length - offset;
+            return (int)bb.GetShort(vtable + vtableOffset - bb.GetInt(vtable)) + vtable;
+        }
+
+        // Retrieve the relative offset stored at "offset"
+        public int __indirect(int offset)
+        {
+            return offset + bb.GetInt(offset);
+        }
+
+        public static int __indirect(int offset, ByteBuffer bb)
+        {
+            return offset + bb.GetInt(offset);
+        }
+
+        // Create a .NET String from UTF-8 data stored inside the flatbuffer.
+        public string __string(int offset)
+        {
+            offset += bb.GetInt(offset);
+            var len = bb.GetInt(offset);
+            var startPos = offset + sizeof(int);
+            return bb.GetStringUTF8(startPos, len);
+        }
+
+        // Get the length of a vector whose offset is stored at "offset" in this object.
+        public int __vector_len(int offset)
+        {
+            offset += bb_pos;
+            offset += bb.GetInt(offset);
+            return bb.GetInt(offset);
+        }
+
+        // Get the start of data of a vector whose offset is stored at "offset" in this object.
+        public int __vector(int offset)
+        {
+            offset += bb_pos;
+            return offset + bb.GetInt(offset) + sizeof(int);  // data starts after the length
+        }
+
+#if ENABLE_SPAN_T
+        // Get the data of a vector whoses offset is stored at "offset" in this object as an
+        // Spant&lt;byte&gt;. If the vector is not present in the ByteBuffer,
+        // then an empty span will be returned.
+        public Span<byte> __vector_as_span(int offset)
+        {
+            var o = this.__offset(offset);
+            if (0 == o)
+            {
+                return new Span<byte>();
+            }
+
+            var pos = this.__vector(o);
+            var len = this.__vector_len(o);
+            return bb.ToSpan(pos, len);
+        }
+#else
+        // Get the data of a vector whoses offset is stored at "offset" in this object as an
+        // ArraySegment&lt;byte&gt;. If the vector is not present in the ByteBuffer,
+        // then a null value will be returned.
+        public ArraySegment<byte>? __vector_as_arraysegment(int offset)
+        {
+            var o = this.__offset(offset);
+            if (0 == o)
+            {
+                return null;
+            }
+
+            var pos = this.__vector(o);
+            var len = this.__vector_len(o);
+            return bb.ToArraySegment(pos, len);
+        }
+#endif
+
+        // Get the data of a vector whoses offset is stored at "offset" in this object as an
+        // T[]. If the vector is not present in the ByteBuffer, then a null value will be
+        // returned.
+        public T[] __vector_as_array<T>(int offset)
+            where T : struct
+        {
+            if(!BitConverter.IsLittleEndian)
+            {
+                throw new NotSupportedException("Getting typed arrays on a Big Endian " +
+                    "system is not support");
+            }
+
+            var o = this.__offset(offset);
+            if (0 == o)
+            {
+                return null;
+            }
+
+            var pos = this.__vector(o);
+            var len = this.__vector_len(o);
+            return bb.ToArray<T>(pos, len);
+        }
+
+        // Initialize any Table-derived type to point to the union at the given offset.
+        public T __union<T>(int offset) where T : struct, IFlatbufferObject
+        {
+            offset += bb_pos;
+            T t = new T();
+            t.__init(offset + bb.GetInt(offset), bb);
+            return t;
+        }
+
+        public static bool __has_identifier(ByteBuffer bb, string ident)
+        {
+            if (ident.Length != FlatBufferConstants.FileIdentifierLength)
+                throw new ArgumentException("FlatBuffers: file identifier must be length " + FlatBufferConstants.FileIdentifierLength, "ident");
+
+            for (var i = 0; i < FlatBufferConstants.FileIdentifierLength; i++)
+            {
+                if (ident[i] != (char)bb.Get(bb.Position + sizeof(int) + i)) return false;
+            }
+
+            return true;
+        }
+
+        // Compare strings in the ByteBuffer.
+        public static int CompareStrings(int offset_1, int offset_2, ByteBuffer bb)
+        {
+            offset_1 += bb.GetInt(offset_1);
+            offset_2 += bb.GetInt(offset_2);
+            var len_1 = bb.GetInt(offset_1);
+            var len_2 = bb.GetInt(offset_2);
+            var startPos_1 = offset_1 + sizeof(int);
+            var startPos_2 = offset_2 + sizeof(int);
+            var len = Math.Min(len_1, len_2);
+            for(int i = 0; i < len; i++) {
+                byte b1 = bb.Get(i + startPos_1);
+                byte b2 = bb.Get(i + startPos_2);
+                if (b1 != b2)
+                    return b1 - b2;
+            }
+            return len_1 - len_2;
+        }
+
+        // Compare string from the ByteBuffer with the string object
+        public static int CompareStrings(int offset_1, byte[] key, ByteBuffer bb)
+        {
+            offset_1 += bb.GetInt(offset_1);
+            var len_1 = bb.GetInt(offset_1);
+            var len_2 = key.Length;
+            var startPos_1 = offset_1 + sizeof(int);
+            var len = Math.Min(len_1, len_2);
+            for (int i = 0; i < len; i++) {
+                byte b = bb.Get(i + startPos_1);
+                if (b != key[i])
+                    return b - key[i];
+            }
+            return len_1 - len_2;
+        }
+    }
+}