/// <summary>
        /// Generates a new array with the contents of this writer. Beware, the content shouldn't exceed .NET memory array limit of nearly 2 GiB.
        /// </summary>
        /// <returns>The array.</returns>
        public byte[] ToArray()
        {
            long size = 0;

            ManagedBinaryMemoryWriterSegment segment = this.segment;

            while (segment != null)
            {
                size += segment.Length;

                segment = segment.Next;
            }

            if (size > 2147000000)
            {
                throw new OutOfMemoryException("Array buffers can't exceed 2147000000 bytes. Write to a stream, if you generated bigger data than the near 2 GiB limit.");
            }

            byte[] data = new byte[size];

            int position = 0;

            segment = this.segment;

            while (segment != null)
            {
                segment.ToArray(data, ref position);

                segment = segment.Next;
            }

            return(data);
        }
        /// <summary>
        /// Saves writer content to the given byte[] and it's offset.
        /// </summary>
        /// <param name="data">The byte[].</param>
        /// <param name="offset">The offset.</param>
        /// <returns></returns>
        public int ToArray(byte[] data, int offset)
        {
            long size = 0;

            ManagedBinaryMemoryWriterSegment segment = this.segment;

            while (segment != null)
            {
                size += segment.Length;

                segment = segment.Next;
            }

            if (data.Length < size + offset)
            {
                throw new ArgumentException("Not enough memory in data.", "data");
            }

            int position = offset;

            segment = this.segment;

            while (segment != null)
            {
                segment.ToArray(data, ref position);

                segment = segment.Next;
            }

            return((int)size);
        }
        /// <summary>
        /// Writes a string in UTF-8 encoding.
        /// </summary>
        /// <param name="text">The string to write.</param>
        /// <returns>The number of bytes written.</returns>
        public unsafe int WriteVanillaString(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return(0);
            }

            int requiredSize = Encoding.UTF8.GetByteCount(text);

            if (size < requiredSize)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, requiredSize + 1024);
                Next.Write(text);
                return(requiredSize);
            }

            fixed(char *chars = text)
            fixed(byte *bData = data)
            requiredSize      = Encoding.UTF8.GetBytes(chars, text.Length, bData + position, size);

            size     -= requiredSize;
            position += requiredSize;

            return(requiredSize);
        }
        /// <summary>
        /// Fills length bytes memory with data.
        /// </summary>
        /// <param name="data">The byte to fill teh data.</param>
        /// <param name="length">The amount of bytes to fill.</param>
        public unsafe void Fill(byte data, int length)
        {
            if (length > size)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, length > 1024 ? length : 1024);
                Next.Fill(data, length);
                return;
            }

            size -= length;

            if (length > 80)
            {
                ulong oData = ((ulong)data << 56) | ((ulong)data << 48) | ((ulong)data << 40) | ((ulong)data << 32) | ((ulong)data << 24) | ((ulong)data << 16) | ((ulong)data << 8) | (ulong)data;

                while (length > 7)
                {
                    fixed(byte *bData = this.data)
                    * (ulong *)(bData + position) = oData;

                    length   -= 8;
                    position += 8;
                }
            }

            while (length-- > 0)
            {
                this.data[position++] = data;
            }
        }
        /// <summary>
        /// Writes a byte.
        /// </summary>
        /// <param name="data">The byte to write.</param>
        public void Write(byte data)
        {
            if (size < 1)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                Next.Write(data);
                return;
            }

            this.data[position++] = data;
            size--;
        }
        /// <summary>
        /// Saves writer content to the given pointer.
        /// </summary>
        /// <param name="ptr">The Pointer we write to.</param>
        /// <returns>The amount of bytes written.</returns>
        public unsafe long ToPointer(byte *ptr)
        {
            long size = 0;
            ManagedBinaryMemoryWriterSegment segment = this.segment;

            while (segment != null)
            {
                size += segment.ToPointer(ref ptr);

                segment = segment.Next;
            }

            return((int)size);
        }
        /// <summary>
        /// Fills length bytes memory with random data.
        /// </summary>
        /// <param name="rng">The random number generator to use.</param>
        /// <param name="length">The amount of bytes to fill.</param>
        public void Fill(RNGCryptoServiceProvider rng, int length)
        {
            if (length > size)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, length > 1024 ? length : 1024);
                Next.Fill(rng, length);
                return;
            }

            rng.GetBytes(data, position, length);

            position += length;
            size     -= length;
        }
        /// <summary>
        /// Writes a datetime.
        /// </summary>
        /// <param name="data">The datetime to write.</param>
        public unsafe void Write(DateTime data)
        {
            if (size < 8)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                Next.Write(data);
                return;
            }

            fixed(byte *bData = this.data)
            * (long *)(bData + position) = data.Ticks;

            position += 8;
            size     -= 8;
        }
        /// <summary>
        /// Writes a signed byte.
        /// </summary>
        /// <param name="data">The signed byte to write.</param>
        public unsafe void Write(sbyte data)
        {
            if (size < 1)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                Next.Write(data);
                return;
            }

            fixed(byte *bData = this.data)
            * (sbyte *)(bData + position) = data;

            position++;
            size--;
        }
        /// <summary>
        /// Saves writer content to this stream.
        /// </summary>
        /// <param name="stream">The stream to save to.</param>
        /// <returns>The bytes written.</returns>
        public long ToStream(Stream stream)
        {
            long size = 0;

            ManagedBinaryMemoryWriterSegment segment = this.segment;

            while (segment != null)
            {
                size += segment.ToStream(stream);

                segment = segment.Next;
            }

            return(size);
        }
        /// <summary>
        /// Writes a float.
        /// </summary>
        /// <param name="data">The float to write.</param>
        public unsafe void Write(float data)
        {
            if (size < 4)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                Next.Write(data);
                return;
            }

            fixed(byte *bData = this.data)
            * (float *)(bData + position) = data;

            position += 4;
            size     -= 4;
        }
        /// <summary>
        /// Writes a char.
        /// </summary>
        /// <param name="data">The char to write.</param>
        public void Write(char data)
        {
            if (data < 128)
            {
                if (size < 1)
                {
                    Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                    Next.Write(data);
                    return;
                }

                this.data[position++] = (byte)data;

                size--;

                return;
            }

            if (data < 2048)
            {
                if (size < 2)
                {
                    Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                    Next.Write(data);
                    return;
                }

                this.data[position++] = (byte)((data >> 6) | 0b11000000);
                this.data[position++] = (byte)((data & 0b00111111) | 0b10000000);

                size -= 2;

                return;
            }

            if (size < 3)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                Next.Write(data);
                return;
            }

            this.data[position++] = (byte)((data >> 12) | 0b11100000);
            this.data[position++] = (byte)(((data >> 6) & 0b00111111) | 0b10000000);
            this.data[position++] = (byte)((data & 0b00111111) | 0b10000000);

            size -= 3;
        }
        /// <summary>
        /// Writes a 3 byte integer.
        /// </summary>
        /// <param name="data">The integer to write.</param>
        public unsafe void WriteUInt24(int data)
        {
            if (size < 3)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                Next.Write(data);
                return;
            }

            this.data[position++] = (byte)(data / 65536);

            fixed(byte *bData = this.data)
            * (ushort *)(bData + position) = (ushort)data;

            position += 2;
            size     -= 3;
        }
        /// <summary>
        /// Fills length bytes memory with random data.
        /// </summary>
        /// <param name="rng">The random number generator to use.</param>
        /// <param name="length">The amount of bytes to fill.</param>
        public unsafe void Fill(Random rng, int length)
        {
            if (length > size)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, length > 1024 ? length : 1024);
                Next.Fill(rng, length);
                return;
            }

            fixed(byte *bData = data)
            {
                for (; length >= 4; position += 4, size -= 4, length -= 4)
                {
                    *(int *)(bData + position) = rng.Next(int.MinValue, int.MaxValue);
                }

                for (; length >= 0; position++, size--, length--)
                {
                    *(int *)(bData + position) = (byte)rng.Next(256);
                }
            }
        }
        /// <summary>
        /// Writes a decimal.
        /// </summary>
        /// <param name="data">The decimal to write.</param>
        public unsafe void Write(decimal data)
        {
            if (size < 16)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                Next.Write(data);
                return;
            }

            int[] values = decimal.GetBits(data);

            fixed(byte *bData = this.data)
            {
                *(int *)(bData + position)      = values[0];
                *(int *)(bData + position + 4)  = values[1];
                *(int *)(bData + position + 8)  = values[2];
                *(int *)(bData + position + 12) = values[3];
            }

            size     -= 16;
            position += 16;
        }
        /// <summary>
        /// Writes count bytes from the current position into data starting at offset.
        /// </summary>
        /// <param name="data">The byte array where data will be read from.</param>
        /// <param name="offset">The position in the byte array where those data will be read from.</param>
        /// <param name="count">The amount of bytes which will be read.</param>
        /// <remarks>BEWARE: This method is also NOT DOING input checks of the given parameters.</remarks>
        public unsafe void WriteBytes(byte[] data, int offset, int count)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data", "data can't be null.");
            }

            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset", "offset can't be negative.");
            }

            if (count < 0)
            {
                throw new ArgumentOutOfRangeException("count", "count can't be negative.");
            }

            if (offset + count > data.Length)
            {
                throw new ArgumentOutOfRangeException("count", "offset + count bigger than data.Length.");
            }

            if (size < count)
            {
                Next = new ManagedBinaryMemoryWriterSegment(writer, count > 1024 ? count : 1024);
                Next.WriteBytes(data, offset, count);
                return;
            }

            fixed(byte *bData = this.data)
            fixed(byte *pData = data)
            Buffer.MemoryCopy(pData + offset, bData + position, count, count);

            position += count;
            size     -= count;
        }
 /// <summary>
 /// Instantiates a managed binary memory writer.
 /// </summary>
 public ManagedBinaryMemoryWriter()
 {
     segment        = new ManagedBinaryMemoryWriterSegment(this, 64);
     currentSegment = segment;
 }
 internal void MoveSegment(ManagedBinaryMemoryWriterSegment segment)
 {
     currentSegment = segment;
 }
        /// <summary>
        /// Writes a string in UTF-8 encoding with 7 bit encoded length prefix.
        /// </summary>
        /// <param name="text">The string to write.</param>
        public unsafe void Write(string text)
        {
            if (text == null)
            {
                if (size < 1)
                {
                    Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                    Next.Write(text);
                    return;
                }

                data[position++] = 0x00;
                size--;

                return;
            }

            int length = Encoding.UTF8.GetByteCount(text);

            if (length < 128)
            {
                if (size < length + 1)
                {
                    Next = new ManagedBinaryMemoryWriterSegment(writer, 1024);
                    Next.Write(text);
                    return;
                }

                data[position++] = (byte)length;

                fixed(char *chars = text)
                fixed(byte *bData = data)
                Encoding.UTF8.GetBytes(chars, text.Length, bData + position, size - 1);

                size -= length + 1;
            }
            else if (length < 16384)
            {
                if (size < length + 2)
                {
                    Next = new ManagedBinaryMemoryWriterSegment(writer, length + 1024);
                    Next.Write(text);
                    return;
                }

                data[position++] = (byte)(length | 0x80);
                data[position++] = (byte)(length >> 7);

                fixed(char *chars = text)
                fixed(byte *bData = data)
                Encoding.UTF8.GetBytes(chars, text.Length, bData + position, size - 2);

                size -= length + 2;
            }
            else if (length < 2097152)
            {
                if (size < length + 3)
                {
                    Next = new ManagedBinaryMemoryWriterSegment(writer, length + 1024);
                    Next.Write(text);
                    return;
                }

                data[position++] = (byte)(length | 0x80);
                data[position++] = (byte)((length >> 7) | 0x80);
                data[position++] = (byte)(length >> 14);

                fixed(char *chars = text)
                fixed(byte *bData = data)
                Encoding.UTF8.GetBytes(chars, text.Length, bData + position, size - 3);

                size -= length + 3;
            }
            else if (length < 268435456)
            {
                if (size < length + 4)
                {
                    Next = new ManagedBinaryMemoryWriterSegment(writer, length + 1024);
                    Next.Write(text);
                    return;
                }

                data[position++] = (byte)(length | 0x80);
                data[position++] = (byte)((length >> 7) | 0x80);
                data[position++] = (byte)((length >> 14) | 0x80);
                data[position++] = (byte)(length >> 21);

                fixed(char *chars = text)
                fixed(byte *bData = data)
                Encoding.UTF8.GetBytes(chars, text.Length, bData + position, size - 4);

                size -= length + 4;
            }
            else
            {
                if (size < length + 5)
                {
                    Next = new ManagedBinaryMemoryWriterSegment(writer, length + 5);
                    Next.Write(text);
                    return;
                }

                data[position++] = (byte)(length | 0x80);
                data[position++] = (byte)((length >> 7) | 0x80);
                data[position++] = (byte)((length >> 14) | 0x80);
                data[position++] = (byte)((length >> 21) | 0x80);
                data[position++] = (byte)(length >> 28);

                fixed(char *chars = text)
                fixed(byte *bData = data)
                Encoding.UTF8.GetBytes(chars, text.Length, bData + position, size - 5);

                size -= length + 5;
            }

            position += length;
        }