private WireMessage Read(IStreamReader reader)
        {
            var dataTypeCd = reader.ReadByte() - NotNullFlag;

            if (dataTypeCd > 0)
            {
                var message = new WireMessage();

                var buffer = StringBytesCache.Acquire();
                try
                {
                    var sizeOfDataTypeCd = WireMessageFieldSizeOf.DataTypeCd;

                    reader.Read(buffer, 0, WireMessageSizeOf.ConstantFields - sizeOfDataTypeCd);

                    message.MessageType = (MessageType)buffer[WireMessageBufferOffsetOf.MessageType - sizeOfDataTypeCd];
                    message.State       = (WireMessageState)buffer[WireMessageBufferOffsetOf.State - sizeOfDataTypeCd];

                    var timeoutMSec = buffer.ToInt(WireMessageBufferOffsetOf.TimeoutMSec - sizeOfDataTypeCd);
                    message.TimeoutMSec = timeoutMSec != int.MinValue ? timeoutMSec : (int?)null;

                    message.Id = new WireMessageId(
                        buffer.ToInt(WireMessageBufferOffsetOf.IdMajor - sizeOfDataTypeCd),
                        buffer.ToInt(WireMessageBufferOffsetOf.IdMajorRevision - sizeOfDataTypeCd),
                        buffer.ToInt(WireMessageBufferOffsetOf.IdMinor - sizeOfDataTypeCd),
                        buffer.ToInt(WireMessageBufferOffsetOf.IdMinorRevision - sizeOfDataTypeCd),
                        buffer.ToInt(WireMessageBufferOffsetOf.IdProcessId - sizeOfDataTypeCd)
                        );
                }
                finally
                {
                    StringBytesCache.Release(buffer);
                }

                message.From = Aid.Parse(ReadString(reader));
                message.To   = Aid.Parse(ReadString(reader));

                var isNullByte = reader.ReadByte();
                if (isNullByte != NullFlag)
                {
                    var header = new Dictionary <string, string>();
                    message.Header = header;

                    var count = reader.ReadInt32();
                    if (count > 0)
                    {
                        string key;
                        for (var i = 0; i < count; i++)
                        {
                            key = ReadString(reader);
                            if (key != null)
                            {
                                header[key] = ReadString(reader);
                            }
                        }
                    }
                }

                isNullByte = reader.ReadByte();
                if (isNullByte != NullFlag)
                {
                    var len = reader.ReadInt32();
                    if (len > 0)
                    {
                        using (var tempStream = new ChunkedStream())
                        {
                            var chunkSize = tempStream.ChunkSize;
                            while (len > 0)
                            {
                                var bytes = reader.ReadBytes(chunkSize);

                                var readLen = bytes?.Length ?? 0;
                                if (readLen == 0)
                                {
                                    throw new Exception(SerializationErrors.StreamNotContainingValidWireMessage);
                                }

                                len -= readLen;
                                tempStream.Write(bytes, 0, readLen);
                            }

                            tempStream.Position = 0;
                            message.Exception   = GetSerializer().Deserialize <Exception>(tempStream);
                        }
                    }
                }

                ReadData(dataTypeCd, message, reader);

                return(message);
            }
            return(null);
        }