static void ReadMulticastFooter(int streamVersion, CKBinaryReader r, StreamLogType t, out string gId, out string mId, out int depth, out LogEntryType prevType, out DateTimeStamp prevTime) { if (streamVersion == 9) { gId = r.ReadString(); mId = r.ReadString(); depth = r.ReadNonNegativeSmallInt32(); Throw.CheckData(mId == GrandOutput.ExternalLogMonitorUniqueId || Base64UrlHelper.IsBase64UrlCharacters(mId)); } else { gId = GrandOutput.UnknownGrandOutputId; Debug.Assert(Guid.Empty.ToByteArray().Length == 16); mId = streamVersion < 8 ? new Guid(r.ReadBytes(16)).ToString() : r.ReadString(); depth = streamVersion < 6 ? r.ReadInt32() : r.ReadNonNegativeSmallInt32(); if (streamVersion >= 8) { Throw.CheckData(mId == GrandOutput.ExternalLogMonitorUniqueId || Base64UrlHelper.IsBase64UrlCharacters(mId)); } } Throw.CheckData(gId == GrandOutput.UnknownGrandOutputId || Base64UrlHelper.IsBase64UrlCharacters(gId)); Throw.CheckData(depth >= 0); prevType = LogEntryType.None; prevTime = DateTimeStamp.Unknown; if ((t & StreamLogType.IsPreviousKnown) != 0) { prevTime = new DateTimeStamp(DateTime.FromBinary(r.ReadInt64()), (t & StreamLogType.IsPreviousKnownHasUniquifier) != 0 ? r.ReadByte() : (Byte)0); prevType = (LogEntryType)r.ReadByte(); } }
static ILogEntry ReadGroupClosed(int streamVersion, CKBinaryReader r, StreamLogType t, LogLevel logLevel) { DateTimeStamp time = new DateTimeStamp(DateTime.FromBinary(r.ReadInt64()), (t & StreamLogType.HasUniquifier) != 0 ? r.ReadByte() : (Byte)0); ActivityLogGroupConclusion[] conclusions = Util.Array.Empty <ActivityLogGroupConclusion>(); if ((t & StreamLogType.HasConclusions) != 0) { int conclusionsCount = streamVersion < 6 ? r.ReadInt32() : r.ReadNonNegativeSmallInt32(); conclusions = new ActivityLogGroupConclusion[conclusionsCount]; for (int i = 0; i < conclusionsCount; i++) { CKTrait cTags = ActivityMonitor.Tags.Register(r.ReadString()); string cText = r.ReadString(); conclusions[i] = new ActivityLogGroupConclusion(cText, cTags); } } if ((t & StreamLogType.IsMultiCast) == 0) { return(new LECloseGroup(time, logLevel, conclusions)); } Guid mId; int depth; LogEntryType prevType; DateTimeStamp prevTime; ReadMulticastFooter(streamVersion, r, t, out mId, out depth, out prevType, out prevTime); return(new LEMCCloseGroup(mId, depth, prevTime, prevType, time, logLevel, conclusions)); }
public void object_pool_work() { using (var mem = new MemoryStream()) { var sA = new String('A', 100); var sB = new String('B', 100); using (var w = new CKBinaryWriter(mem, Encoding.UTF8, true)) { var pool = new CKBinaryWriter.ObjectPool <string>(w, StringComparer.InvariantCultureIgnoreCase); var p = mem.Position; p.Should().Be(0); pool.MustWrite(sA).Should().BeTrue(); w.Write(sA); pool.MustWrite(sB).Should().BeTrue(); w.Write(sB); var delta = mem.Position - p; p = mem.Position; delta.Should().Be(1 + 1 + sA.Length + 1 + 1 + sB.Length, "Marker byte + small length + UTF8 ascii string"); for (int i = 0; i < 50; ++i) { pool.MustWrite(sA).Should().BeFalse(); pool.MustWrite(sB).Should().BeFalse(); pool.MustWrite(sA.ToLowerInvariant()).Should().BeFalse(); pool.MustWrite(sB.ToLowerInvariant()).Should().BeFalse(); } delta = mem.Position - p; delta.Should().Be(50 * 4 * (1 + 1), "Marker byte + NonNegativeSmallInt32 that is actuall one byte..."); } mem.Position = 0; using (var r = new CKBinaryReader(mem, Encoding.UTF8, true)) { var pool = new CKBinaryReader.ObjectPool <string>(r); string rA = pool.TryRead(out rA).SetReadResult(r.ReadString()); rA.Should().Be(sA); string rB = pool.Read((state, reader) => reader.ReadString()); rB.Should().Be(sB); for (int i = 0; i < 50; ++i) { pool.TryRead(out var rA2).Success.Should().BeTrue(); rA2.Should().Be(rA); pool.Read((state, reader) => reader.ReadString()).Should().Be(rB); pool.Read((state, reader) => reader.ReadString()).Should().Be(rA); pool.Read((state, reader) => reader.ReadString()).Should().Be(rB); } } } }
public void object_pool_with_write_marker() { using (var mem = new MemoryStream()) { // Same string but in two different instances: the PureObjectRefEqualityComparer // does its job. var o1 = new String('B', 100); var o2 = new String('B', 100); using (var w = new CKBinaryWriter(mem, Encoding.UTF8, true)) { var pool = new CKBinaryWriter.ObjectPool <string>(w, PureObjectRefEqualityComparer <string> .Default); pool.MustWrite(o1, 3).Should().BeTrue(); w.Write(o1); pool.MustWrite(o2, 255).Should().BeTrue(); w.Write(o2); } mem.Position = 0; using (var r = new CKBinaryReader(mem, Encoding.UTF8, true)) { var pool = new CKBinaryReader.ObjectPool <string>(r); var state1 = pool.TryRead(out var s1); s1.Should().BeNull(); state1.Success.Should().BeFalse(); state1.WriteMarker.Should().Be(3); s1 = state1.SetReadResult(r.ReadString()); var state2 = pool.TryRead(out var s2); s2.Should().BeNull(); state2.Success.Should().BeFalse(); state2.WriteMarker.Should().Be(255); s2 = state2.SetReadResult(r.ReadString()); s1.Should().Be(o1).And.Be(o2); s2.Should().Be(o1).And.Be(o2); } } }
/// <summary> /// Reads a <see cref="ILogEntry"/> from the binary reader that can be a <see cref="IMulticastLogEntry"/>. /// If the first read byte is 0, read stops and null is returned. /// The 0 byte is the "end marker" that <see cref="CKMonWriterClient.Close()"/> write, but this /// method can read non zero-terminated streams (it catches an EndOfStreamException when reading the first byte and handles it silently). /// This method can throw any type of exception except <see cref="EndOfStreamException"/> /// (like <see cref="InvalidDataException"/> for instance) that must be handled by the caller. /// </summary> /// <param name="r">The binary reader.</param> /// <param name="streamVersion">The version of the stream.</param> /// <param name="badEndOfFile">True whenever the end of file is the result of an <see cref="EndOfStreamException"/>.</param> /// <returns>The log entry or null if a zero byte (end marker) has been found.</returns> static public ILogEntry?Read(CKBinaryReader r, int streamVersion, out bool badEndOfFile) { Throw.CheckNotNullArgument(r); badEndOfFile = false; StreamLogType t = StreamLogType.EndOfStream; LogLevel logLevel = LogLevel.None; try { ReadLogTypeAndLevel(r, streamVersion, out t, out logLevel); } catch (EndOfStreamException) { badEndOfFile = true; // Silently ignores here reading beyond the stream: this // kindly handles the lack of terminating 0 byte. } if (t == StreamLogType.EndOfStream) { return(null); } if ((t & StreamLogType.TypeMask) == StreamLogType.TypeGroupClosed) { return(ReadGroupClosed(streamVersion, r, t, logLevel)); } DateTimeStamp time = new DateTimeStamp(DateTime.FromBinary(r.ReadInt64()), (t & StreamLogType.HasUniquifier) != 0 ? r.ReadByte() : (Byte)0); if (time.TimeUtc.Year < 2014 || time.TimeUtc.Year > 3000) { throw new InvalidDataException("Date year before 2014 or after 3000 are considered invalid."); } CKTrait tags = ActivityMonitor.Tags.Empty; string? fileName = null; int lineNumber = 0; CKExceptionData?ex = null; string? text = null; if ((t & StreamLogType.HasTags) != 0) { tags = ActivityMonitor.Tags.Register(r.ReadString()); } if ((t & StreamLogType.HasFileName) != 0) { fileName = r.ReadString(); lineNumber = streamVersion < 6 ? r.ReadInt32() : r.ReadNonNegativeSmallInt32(); if (lineNumber > 100 * 1000) { throw new InvalidDataException("LineNumber greater than 100K is considered invalid."); } } if ((t & StreamLogType.HasException) != 0) { ex = new CKExceptionData(r); if ((t & StreamLogType.IsTextTheExceptionMessage) != 0) { text = ex.Message; } } if (text == null) { text = r.ReadString((t & StreamLogType.IsLFOnly) == 0); } string gId; string mId; int depth; LogEntryType prevType; DateTimeStamp prevTime; if ((t & StreamLogType.TypeMask) == StreamLogType.TypeLine) { if ((t & StreamLogType.IsMultiCast) == 0) { return(new LELog(text, time, fileName, lineNumber, logLevel, tags, ex)); } ReadMulticastFooter(streamVersion, r, t, out gId, out mId, out depth, out prevType, out prevTime); return(new LEMCLog(gId, mId, depth, prevTime, prevType, text, time, fileName, lineNumber, logLevel, tags, ex)); } if ((t & StreamLogType.TypeMask) != StreamLogType.TypeOpenGroup) { throw new InvalidDataException(); } if ((t & StreamLogType.IsMultiCast) == 0) { return(new LEOpenGroup(text, time, fileName, lineNumber, logLevel, tags, ex)); } ReadMulticastFooter(streamVersion, r, t, out gId, out mId, out depth, out prevType, out prevTime); return(new LEMCOpenGroup(gId, mId, depth, prevTime, prevType, text, time, fileName, lineNumber, logLevel, tags, ex)); }