コード例 #1
0
        /// <summary>
        /// Parses <see cref="TableMapEvent"/> from the buffer.
        /// </summary>
        public IBinlogEvent ParseEvent(EventHeader header, ref PacketReader reader)
        {
            var tableId = reader.ReadLongLittleEndian(6);

            // Reserved bytes and database name length
            reader.Advance(3);
            var databaseName = reader.ReadNullTerminatedString();

            // Table name length
            reader.Advance(1);
            var tableName = reader.ReadNullTerminatedString();

            var columnsNumber = (int)reader.ReadLengthEncodedNumber();
            var columnTypes   = reader.ReadByteArraySlow(columnsNumber);

            var metadataLength = (int)reader.ReadLengthEncodedNumber();
            var metadata       = ParseMetadata(ref reader, columnTypes);

            var nullBitmap = reader.ReadBitmapLittleEndian(columnsNumber);

            TableMetadata tableMetadata = null;

            if (!reader.IsEmpty())
            {
                // Table metadata is supported in MySQL 5.6+ and MariaDB 10.5+.
                tableMetadata = new TableMetadata(ref reader, columnTypes);
            }

            return(new TableMapEvent(header, tableId, databaseName, tableName, columnTypes, metadata, nullBitmap, tableMetadata));
        }
コード例 #2
0
        public void Test_Advance_ReturnsIsEmpty()
        {
            var payload = new byte[] { 76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109 };
            var reader  = new PacketReader(payload);

            reader.Advance(5);
            Assert.False(reader.IsEmpty());
            Assert.Equal(5, reader.Consumed);

            reader.Advance(6);
            Assert.True(reader.IsEmpty());
            Assert.Equal(11, reader.Consumed);
        }
コード例 #3
0
        /// <summary>
        /// Parses <see cref="RowsQueryEvent"/> from the buffer.
        /// </summary>
        public IBinlogEvent ParseEvent(EventHeader header, ref PacketReader reader)
        {
            reader.Advance(1);
            var query = reader.ReadStringToEndOfFile();

            return(new RowsQueryEvent(header, query));
        }
コード例 #4
0
        /// <summary>
        /// Skips empty holes made by partial updates (MySQL 8.0.16+)
        /// </summary>
        private void Advance(ref PacketReader reader, int startIndex, int offset)
        {
            int holeSize = offset - (reader.Consumed - startIndex);

            if (holeSize > 0)
            {
                reader.Advance(holeSize);
            }
        }
コード例 #5
0
        /// <summary>
        /// Parses <see cref="FormatDescriptionEvent"/> from the buffer.
        /// </summary>
        public IBinlogEvent ParseEvent(EventHeader header, ref PacketReader reader)
        {
            var binlogVersion = reader.ReadInt16LittleEndian();
            var serverVersion = reader.ReadString(50).Trim((char)0);

            // Redundant timestamp & header length which is always 19
            reader.Advance(5);

            // Get size of the event payload to determine beginning of the checksum part
            reader.Advance((int)EventType.FORMAT_DESCRIPTION_EVENT - 1);
            var eventPayloadLength = reader.ReadByte();

            var checksumType = ChecksumType.NONE;

            if (eventPayloadLength != header.EventLength - EventConstants.HeaderSize)
            {
                reader.Advance(eventPayloadLength - (EventTypesOffset + (int)EventType.FORMAT_DESCRIPTION_EVENT));
                checksumType = (ChecksumType)reader.ReadByte();
            }

            return(new FormatDescriptionEvent(header, binlogVersion, serverVersion, checksumType));
        }
コード例 #6
0
        /// <summary>
        /// Parses the header in a rows event.
        /// </summary>
        protected (long tableId, int flags, int columnsNumber) ParseHeader(ref PacketReader reader)
        {
            long tableId = reader.ReadLongLittleEndian(6);
            int  flags   = reader.ReadUInt16LittleEndian();

            // Ignore extra data from newer versions of events
            if (RowsEventVersion == 2)
            {
                int extraDataLength = reader.ReadUInt16LittleEndian();
                reader.Advance(extraDataLength - 2);
            }

            var columnsNumber = (int)reader.ReadLengthEncodedNumber();

            return(tableId, flags, columnsNumber);
        }
コード例 #7
0
        /// <summary>
        /// Parses <see cref="QueryEvent"/> from the buffer.
        /// </summary>
        public IBinlogEvent ParseEvent(EventHeader header, ref PacketReader reader)
        {
            long threadId = (uint)reader.ReadInt32LittleEndian();
            long duration = (uint)reader.ReadInt32LittleEndian();

            // DatabaseName length is null terminated
            reader.Advance(1);

            var errorCode            = reader.ReadInt16LittleEndian();
            var statusVariableLength = reader.ReadInt16LittleEndian();
            var statusVariables      = reader.ReadByteArraySlow(statusVariableLength);
            var databaseName         = reader.ReadNullTerminatedString();
            var sqlStatement         = reader.ReadStringToEndOfFile();

            return(new QueryEvent(header, threadId, duration, errorCode, statusVariables, databaseName, sqlStatement));
        }
コード例 #8
0
        private void ParseArrayOrObject(ref PacketReader reader, ValueType valueType, bool small, bool isObject)
        {
            int startIndex     = reader.Consumed;
            int valueSize      = small ? 2 : 4;
            int elementsNumber = ReadJsonSize(ref reader, small);
            int bytesNumber    = ReadJsonSize(ref reader, small);

            // Key entries
            int[] keyOffset = isObject ? new int[elementsNumber] : null;
            int[] keyLength = isObject ? new int[elementsNumber] : null;
            if (isObject)
            {
                for (int i = 0; i < elementsNumber; i++)
                {
                    keyOffset[i] = ReadJsonSize(ref reader, small);
                    keyLength[i] = reader.ReadUInt16LittleEndian();
                }
            }

            // Value entries
            var entries = new ValueEntry[elementsNumber];

            for (int i = 0; i < elementsNumber; i++)
            {
                ValueType type = ReadValueType(ref reader);
                if (type == ValueType.LITERAL)
                {
                    entries[i] = ValueEntry.FromInlined(type, ReadLiteral(ref reader));
                    reader.Advance(valueSize - 1);
                }
                else if (type == ValueType.INT16)
                {
                    entries[i] = ValueEntry.FromInlined(type, (Int16)reader.ReadUInt16LittleEndian());
                    reader.Advance(valueSize - 2);
                }
                else if (type == ValueType.UINT16)
                {
                    entries[i] = ValueEntry.FromInlined(type, (UInt16)reader.ReadUInt16LittleEndian());
                    reader.Advance(valueSize - 2);
                }
                else if (type == ValueType.INT32 && !small)
                {
                    entries[i] = ValueEntry.FromInlined(type, (Int32)reader.ReadUInt32LittleEndian());
                }
                else if (type == ValueType.UINT32 && !small)
                {
                    entries[i] = ValueEntry.FromInlined(type, (UInt32)reader.ReadUInt32LittleEndian());
                }
                else
                {
                    int offset = ReadJsonSize(ref reader, small);
                    if (offset >= bytesNumber)
                    {
                        throw new FormatException("The offset in JSON value was too long");
                    }
                    entries[i] = ValueEntry.FromOffset(type, offset);
                }
            }

            // Key rows
            string[] keys = null;
            if (isObject)
            {
                keys = new string[elementsNumber];
                for (int i = 0; i < elementsNumber; i++)
                {
                    // 1 - Remove a hole between keys
                    Advance(ref reader, startIndex, keyOffset[i]);
                    keys[i] = reader.ReadString(keyLength[i]) ?? string.Empty /* JSON can have empty keys */;
                }
            }

            // Value rows
            if (isObject)
            {
                _writer.WriteStartObject();
            }
            else
            {
                _writer.WriteStartArray();
            }
            for (int i = 0; i < elementsNumber; i++)
            {
                if (isObject)
                {
                    _writer.WriteKey(keys[i]);
                }

                ValueEntry entry = entries[i];
                if (!entry.Inlined)
                {
                    // 2 - Remove a hole between values
                    Advance(ref reader, startIndex, entry.Offset);
                    ParseNode(ref reader, entry.Type);
                }

                else if (entry.Value == null)
                {
                    _writer.WriteNull();
                }
                else if (entry.Type == ValueType.LITERAL)
                {
                    _writer.WriteValue((bool)entry.Value);
                }

                else if (entry.Type == ValueType.INT16)
                {
                    _writer.WriteValue((Int16)entry.Value);
                }
                else if (entry.Type == ValueType.UINT16)
                {
                    _writer.WriteValue((UInt16)entry.Value);
                }
                else if (entry.Type == ValueType.INT32)
                {
                    _writer.WriteValue((Int32)entry.Value);
                }
                else if (entry.Type == ValueType.UINT32)
                {
                    _writer.WriteValue((UInt32)entry.Value);
                }
            }
            if (isObject)
            {
                _writer.WriteEndObject();
            }
            else
            {
                _writer.WriteEndArray();
            }

            // 3 - Remove a hole from the end
            Advance(ref reader, startIndex, bytesNumber);
        }
コード例 #9
0
        public static RSAParameters DecodePublicKey(byte[] x509Key)
        {
            using var memoryOwner = new MemoryOwner(new ReadOnlySequence <byte>(x509Key));
            var reader = new PacketReader(memoryOwner.Memory.Span);

            var twobytes  = reader.ReadInt16LittleEndian();
            var skipBytes = twobytes switch
            {
                0x8130 => 1,
                0x8230 => 2,
                _ => throw new FormatException()
            };

            reader.Advance(skipBytes);

            var sequence = reader.ReadByteArraySlow(15);

            if (!sequence.SequenceEqual(OidSequence))
            {
                throw new FormatException("Sequence is not OID");
            }

            twobytes  = reader.ReadInt16LittleEndian();
            skipBytes = twobytes switch
            {
                0x8103 => 1,
                0x8203 => 2,
                _ => throw new FormatException()
            };
            reader.Advance(skipBytes);

            if (reader.ReadByte() != 0x00)
            {
                throw new FormatException(); // Null byte
            }
            twobytes  = reader.ReadInt16LittleEndian();
            skipBytes = twobytes switch
            {
                0x8130 => 1,
                0x8230 => 2,
                _ => throw new FormatException()
            };
            reader.Advance(skipBytes);

            // Read modulus size
            twobytes = reader.ReadInt16LittleEndian();
            int modulusSize = twobytes switch
            {
                0x8102 => reader.ReadByte(),
                0x8202 => reader.ReadInt16BigEndian(),
                _ => throw new FormatException()
            };

            byte[] modulus = reader.ReadByteArraySlow(modulusSize);
            if (modulus[0] == 0x00)
            {
                modulus = modulus.Skip(1).ToArray();
            }

            if (reader.ReadByte() != 0x02)
            {
                throw new FormatException();
            }

            var exponentSize = reader.ReadByte();

            byte[] exponent = reader.ReadByteArraySlow(exponentSize);
            return(new RSAParameters {
                Modulus = modulus, Exponent = exponent
            });
        }
    }
}