public static EventStreamHeader FromBuffer(byte[] buffer, int offset, ref int newOffset) { newOffset = offset; byte nameLength = buffer[newOffset++]; var header = new EventStreamHeader(Encoding.UTF8.GetString(buffer, newOffset, nameLength)); newOffset += nameLength; header.HeaderType = (EventStreamHeaderType)buffer[newOffset++]; Int16 valueLength = 0; switch (header.HeaderType) { case EventStreamHeaderType.BoolTrue: header.HeaderValue = true; break; case EventStreamHeaderType.BoolFalse: header.HeaderValue = false; break; case EventStreamHeaderType.Byte: header.HeaderValue = buffer[newOffset]; newOffset += _sizeOfByte; break; case EventStreamHeaderType.Int16: header.HeaderValue = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, newOffset)); newOffset += _sizeOfInt16; break; case EventStreamHeaderType.Int32: header.HeaderValue = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, newOffset)); newOffset += _sizeOfInt32; break; case EventStreamHeaderType.Int64: header.HeaderValue = IPAddress.NetworkToHostOrder(BitConverter.ToInt64(buffer, newOffset)); newOffset += _sizeOfInt64; break; case EventStreamHeaderType.ByteBuf: valueLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, newOffset)); newOffset += _sizeOfInt16; header.HeaderValue = new byte[valueLength]; Buffer.BlockCopy(buffer, newOffset, header.HeaderValue as byte[], 0, valueLength); newOffset += valueLength; break; case EventStreamHeaderType.String: valueLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, newOffset)); newOffset += _sizeOfInt16; header.HeaderValue = Encoding.UTF8.GetString(buffer, newOffset, valueLength); newOffset += valueLength; break; case EventStreamHeaderType.Timestamp: Int64 tempValue = IPAddress.NetworkToHostOrder(BitConverter.ToInt64(buffer, newOffset)); newOffset += _sizeOfInt64; //keep in mind on the windows APIs (and hence NetStandard as well) the epoch is 1/1/1900, //and we're using unix epoch. So we compensate here. header.HeaderValue = _unixEpoch.AddMilliseconds(tempValue); break; case EventStreamHeaderType.UUID: var guidCpy = new byte[16]; valueLength = _sizeOfGuid; Buffer.BlockCopy(buffer, newOffset, guidCpy, 0, valueLength); newOffset += valueLength; header.HeaderValue = new Guid(guidCpy); break; default: throw new EventStreamParseException(string.Format(CultureInfo.InvariantCulture, "Header Type: {0} is an unknown type.", header.HeaderType)); } return(header); }
/// <summary> /// Builds a message from buffer. /// </summary> /// <param name="buffer">buffer to read</param> /// <param name="offset">offset to start reading</param> /// <param name="length">buffer length.</param> /// <returns> /// parsed instance of EventStreamMessage. Doesn't return null, /// does throw if CRCs don't match. /// </returns> public static EventStreamMessage FromBuffer(byte[] buffer, int offset, int length) { var currentOffset = offset; //get the total length of the message var totalLength = BitConverter.ToInt32(buffer, currentOffset); //endianness conversion totalLength = EndianConversionUtility.NetworkToHostOrder(totalLength); currentOffset += SizeOfInt32; //get the length of the headers block. var headersLength = BitConverter.ToInt32(buffer, currentOffset); //endianness conversion headersLength = EndianConversionUtility.NetworkToHostOrder(headersLength); currentOffset += SizeOfInt32; //get the prelude crc var preludeCrc = BitConverter.ToInt32(buffer, currentOffset); //endianness conversion preludeCrc = EndianConversionUtility.NetworkToHostOrder(preludeCrc); var message = new EventStreamMessage(); message.Headers = new Dictionary <string, IEventStreamHeader>(StringComparer.Ordinal); using (var nullStream = new NullStream()) using (var runningChecksum = new CrcCalculatorStream(nullStream)) { //write up to the prelude crc to the checksum stream runningChecksum.Write(buffer, offset, currentOffset - offset); //compare the current crc to the prelude crc and make sure they match. if (preludeCrc != runningChecksum.Crc32) { throw new EventStreamChecksumFailureException(string.Format(CultureInfo.InvariantCulture, "Message Prelude Checksum failure. Expected {0} but was {1}", preludeCrc, runningChecksum.Crc32)); } //if the data length passed isn't enough for the total length, that's an error condition. if (totalLength != length) { throw new EventStreamChecksumFailureException( string.Format(CultureInfo.InvariantCulture, "Message Total Length didn't match the passed in length. Expected {0} but was {1}", length, totalLength)); } //now write the prelude crc to the checksum stream runningChecksum.Write(buffer, currentOffset, SizeOfInt32); currentOffset += SizeOfInt32; //prelude length is total message, minus framing and headers size. var payloadLength = totalLength - headersLength - FramingSize; //if we have headers, then loop over each one and parse them out. if (headersLength > 0) { int preOpOffset = currentOffset; while (currentOffset - PreludeLen < headersLength) { EventStreamHeader header = EventStreamHeader.FromBuffer(buffer, currentOffset, ref currentOffset); message.Headers.Add(header.Name, header); } //after parsing the header remember to write that data to the checksum stream runningChecksum.Write(buffer, preOpOffset, currentOffset - preOpOffset); } // now we're on the payload message.Payload = new byte[payloadLength]; Buffer.BlockCopy(buffer, currentOffset, message.Payload, 0, message.Payload.Length); runningChecksum.Write(buffer, currentOffset, message.Payload.Length); currentOffset += message.Payload.Length; //after reading the payload, get the message crc and make sure it matches. var trailingCrc = BitConverter.ToInt32(buffer, currentOffset); //endianness conversion. trailingCrc = EndianConversionUtility.NetworkToHostOrder(trailingCrc); if (trailingCrc != runningChecksum.Crc32) { throw new EventStreamChecksumFailureException( string.Format(CultureInfo.InvariantCulture, "Message Checksum failure. Expected {0} but was {1}", trailingCrc, runningChecksum.Crc32)); } } return(message); }