public void WriteTo(IBinaryStream stream) { foreach (var entry in Entries) { stream.WriteLE(entry.AbsoluteOffset); } stream.Write(RemainBytes); }
/// <summary> /// Writes specified header to a stream. /// </summary> /// <param name="header">The header.</param> /// <param name="stream">The stream.</param> /// <param name="position">The position.</param> public static unsafe void Write(BinaryObjectHeader header, IBinaryStream stream, int position) { Debug.Assert(stream != null); Debug.Assert(position >= 0); stream.Seek(position, SeekOrigin.Begin); if (BitConverter.IsLittleEndian) { stream.Write((byte *)&header, Size); } else { header.Write(stream); } }
protected override void WriteArgs(IBinaryStream writer) { if (IsOffset) { WriteString(writer); } else { var startOffset = (int)writer.Position + 9; var endOffset = (int)writer.Position + 9 + writer.GetStringZByteCount(Content); writer.WriteLE(startOffset); writer.Write((byte)0x01); writer.WriteLE(endOffset); WriteString(writer); } }
/// <summary> /// Tests the stream. /// </summary> private static unsafe void TestStream(IBinaryStream stream, bool sameArr, Action flush) { Action seek = () => Assert.AreEqual(0, stream.Seek(0, SeekOrigin.Begin)); Action<Action, Func<object>, object> check = (write, read, expectedResult) => { seek(); write(); flush(); seek(); Assert.AreEqual(expectedResult, read()); }; // Arrays. Assert.AreEqual(sameArr, stream.IsSameArray(stream.GetArray())); Assert.IsFalse(stream.IsSameArray(new byte[1])); Assert.IsFalse(stream.IsSameArray(stream.GetArrayCopy())); // byte* byte* bytes = stackalloc byte[10]; *bytes = 1; *(bytes + 1) = 2; stream.Write(bytes, 2); Assert.AreEqual(2, stream.Position); flush(); seek(); Assert.AreEqual(sameArr ? 256 : 2, stream.Remaining); byte* bytes2 = stackalloc byte[2]; stream.Read(bytes2, 2); Assert.AreEqual(1, *bytes2); Assert.AreEqual(2, *(bytes2 + 1)); // char* seek(); char* chars = stackalloc char[10]; *chars = 'a'; *(chars + 1) = 'b'; Assert.AreEqual(2, stream.WriteString(chars, 2, 2, Encoding.ASCII)); flush(); seek(); stream.Read(bytes2, 2); Assert.AreEqual('a', *bytes2); Assert.AreEqual('b', *(bytes2 + 1)); // Others. check(() => stream.Write(new byte[] {3, 4, 5}, 1, 2), () => stream.ReadByteArray(2), new byte[] {4, 5}); check(() => stream.WriteBool(true), () => stream.ReadBool(), true); check(() => stream.WriteBoolArray(new[] {true, false}), () => stream.ReadBoolArray(2), new[] {true, false}); check(() => stream.WriteByte(4), () => stream.ReadByte(), 4); check(() => stream.WriteByteArray(new byte[] {4, 5, 6}), () => stream.ReadByteArray(3), new byte[] {4, 5, 6}); check(() => stream.WriteChar('x'), () => stream.ReadChar(), 'x'); check(() => stream.WriteCharArray(new[] {'a', 'b'}), () => stream.ReadCharArray(2), new[] {'a', 'b'}); check(() => stream.WriteDouble(4), () => stream.ReadDouble(), 4d); check(() => stream.WriteDoubleArray(new[] {4d}), () => stream.ReadDoubleArray(1), new[] {4d}); check(() => stream.WriteFloat(4), () => stream.ReadFloat(), 4f); check(() => stream.WriteFloatArray(new[] {4f}), () => stream.ReadFloatArray(1), new[] {4f}); check(() => stream.WriteInt(4), () => stream.ReadInt(), 4); check(() => stream.WriteInt(0, 4), () => stream.ReadInt(), 4); check(() => stream.WriteIntArray(new[] {4}), () => stream.ReadIntArray(1), new[] {4}); check(() => stream.WriteLong(4), () => stream.ReadLong(), 4L); check(() => stream.WriteLongArray(new[] {4L}), () => stream.ReadLongArray(1), new[] {4L}); check(() => stream.WriteShort(4), () => stream.ReadShort(), (short)4); check(() => stream.WriteShortArray(new short[] {4}), () => stream.ReadShortArray(1), new short[] {4}); }
/// <summary> /// Internal mutation routine. /// </summary> /// <param name="inStream">Input stream.</param> /// <param name="outStream">Output stream.</param> /// <param name="ctx">Context.</param> /// <param name="changeHash">WHether hash should be changed.</param> /// <param name="vals">Values to be replaced.</param> /// <returns>Mutated object.</returns> private void Mutate0(Context ctx, BinaryHeapStream inStream, IBinaryStream outStream, bool changeHash, IDictionary <int, BinaryBuilderField> vals) { int inStartPos = inStream.Position; int outStartPos = outStream.Position; byte inHdr = inStream.ReadByte(); if (inHdr == BinaryUtils.HdrNull) { outStream.WriteByte(BinaryUtils.HdrNull); } else if (inHdr == BinaryUtils.HdrHnd) { int inHnd = inStream.ReadInt(); int oldPos = inStartPos - inHnd; int newPos; if (ctx.OldToNew(oldPos, out newPos)) { // Handle is still valid. outStream.WriteByte(BinaryUtils.HdrHnd); outStream.WriteInt(outStartPos - newPos); } else { // Handle is invalid, write full object. int inRetPos = inStream.Position; inStream.Seek(oldPos, SeekOrigin.Begin); Mutate0(ctx, inStream, outStream, false, EmptyVals); inStream.Seek(inRetPos, SeekOrigin.Begin); } } else if (inHdr == BinaryUtils.HdrFull) { var inHeader = BinaryObjectHeader.Read(inStream, inStartPos); BinaryUtils.ValidateProtocolVersion(inHeader.Version); int hndPos; if (ctx.AddOldToNew(inStartPos, outStartPos, out hndPos)) { // Object could be cached in parent builder. BinaryBuilderField cachedVal; if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal)) { WriteField(ctx, cachedVal); } else { // New object, write in full form. var inSchema = BinaryObjectSchemaSerializer.ReadSchema(inStream, inStartPos, inHeader, _desc.Schema, _binary.Marshaller.Ignite); var outSchema = BinaryObjectSchemaHolder.Current; var schemaIdx = outSchema.PushSchema(); try { // Skip header as it is not known at this point. outStream.Seek(BinaryObjectHeader.Size, SeekOrigin.Current); if (inSchema != null) { foreach (var inField in inSchema) { BinaryBuilderField fieldVal; var fieldFound = vals.TryGetValue(inField.Id, out fieldVal); if (fieldFound && fieldVal == BinaryBuilderField.RmvMarker) { continue; } outSchema.PushField(inField.Id, outStream.Position - outStartPos); if (!fieldFound) { fieldFound = _parent._cache != null && _parent._cache.TryGetValue(inField.Offset + inStartPos, out fieldVal); } if (fieldFound) { WriteField(ctx, fieldVal); vals.Remove(inField.Id); } else { // Field is not tracked, re-write as is. inStream.Seek(inField.Offset + inStartPos, SeekOrigin.Begin); Mutate0(ctx, inStream, outStream, false, EmptyVals); } } } // Write remaining new fields. foreach (var valEntry in vals) { if (valEntry.Value == BinaryBuilderField.RmvMarker) { continue; } outSchema.PushField(valEntry.Key, outStream.Position - outStartPos); WriteField(ctx, valEntry.Value); } var flags = inHeader.IsUserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; if (inHeader.IsCustomDotNetType) { flags |= BinaryObjectHeader.Flag.CustomDotNetType; } // Write raw data. int outRawOff = outStream.Position - outStartPos; if (inHeader.HasRaw) { var inRawOff = inHeader.GetRawOffset(inStream, inStartPos); var inRawLen = inHeader.SchemaOffset - inRawOff; flags |= BinaryObjectHeader.Flag.HasRaw; outStream.Write(inStream.InternalArray, inStartPos + inRawOff, inRawLen); } // Write schema int outSchemaOff = outRawOff; var schemaPos = outStream.Position; int outSchemaId; if (inHeader.IsCompactFooter) { flags |= BinaryObjectHeader.Flag.CompactFooter; } var hasSchema = outSchema.WriteSchema(outStream, schemaIdx, out outSchemaId, ref flags); if (hasSchema) { outSchemaOff = schemaPos - outStartPos; flags |= BinaryObjectHeader.Flag.HasSchema; if (inHeader.HasRaw) { outStream.WriteInt(outRawOff); } if (_desc.Schema.Get(outSchemaId) == null) { _desc.Schema.Add(outSchemaId, outSchema.GetSchema(schemaIdx)); } } var outLen = outStream.Position - outStartPos; var outHash = inHeader.HashCode; if (changeHash) { // Get from identity resolver. outHash = BinaryArrayEqualityComparer.GetHashCode(outStream, outStartPos + BinaryObjectHeader.Size, schemaPos - outStartPos - BinaryObjectHeader.Size); } var outHeader = new BinaryObjectHeader(inHeader.TypeId, outHash, outLen, outSchemaId, outSchemaOff, flags); BinaryObjectHeader.Write(outHeader, outStream, outStartPos); outStream.Seek(outStartPos + outLen, SeekOrigin.Begin); // seek to the end of the object } finally { outSchema.PopSchema(schemaIdx); } } } else { // Object has already been written, write as handle. outStream.WriteByte(BinaryUtils.HdrHnd); outStream.WriteInt(outStartPos - hndPos); } // Synchronize input stream position. inStream.Seek(inStartPos + inHeader.Length, SeekOrigin.Begin); } else { // Try writing as well-known type with fixed size. outStream.WriteByte(inHdr); if (!WriteAsPredefined(inHdr, inStream, outStream, ctx)) { throw new IgniteException("Unexpected header [position=" + (inStream.Position - 1) + ", header=" + inHdr + ']'); } } }
/// <summary> /// Transfer bytes from one stream to another. /// </summary> /// <param name="inStream">Input stream.</param> /// <param name="outStream">Output stream.</param> /// <param name="cnt">Bytes count.</param> private static void TransferBytes(BinaryHeapStream inStream, IBinaryStream outStream, int cnt) { outStream.Write(inStream.InternalArray, inStream.Position, cnt); inStream.Seek(cnt, SeekOrigin.Current); }
/** <inheritDoc /> */ public override void Write(byte[] buffer, int offset, int count) { _stream.Write(buffer, offset, count); }
protected override void WriteArgs(IBinaryStream writer) { writer.Write(Args); }
/// <summary> /// Tests the stream. /// </summary> private static unsafe void TestStream(IBinaryStream stream, bool sameArr, Action flush) { Action seek = () => Assert.AreEqual(0, stream.Seek(0, SeekOrigin.Begin)); Action <Action, Func <object>, object> check = (write, read, expectedResult) => { seek(); write(); flush(); seek(); Assert.AreEqual(expectedResult, read()); }; // Arrays. if (stream.CanGetArray) { Assert.AreEqual(sameArr, stream.IsSameArray(stream.GetArray())); } Assert.IsFalse(stream.IsSameArray(new byte[1])); Assert.IsFalse(stream.IsSameArray(stream.GetArrayCopy())); // byte* byte *bytes = stackalloc byte[10]; *bytes = 1; *(bytes + 1) = 2; stream.Write(bytes, 2); Assert.AreEqual(2, stream.Position); var proc = new SumStreamProcessor(); Assert.AreEqual(0, stream.Apply(proc, 0)); Assert.AreEqual(1, stream.Apply(proc, 1)); Assert.AreEqual(3, stream.Apply(proc, 2)); flush(); seek(); Assert.AreEqual(sameArr ? 256 : 2, stream.Remaining); byte *bytes2 = stackalloc byte[2]; stream.Read(bytes2, 2); Assert.AreEqual(1, *bytes2); Assert.AreEqual(2, *(bytes2 + 1)); // char* seek(); char *chars = stackalloc char[10]; *chars = 'a'; *(chars + 1) = 'b'; Assert.AreEqual(2, stream.WriteString(chars, 2, 2, Encoding.ASCII)); flush(); seek(); stream.Read(bytes2, 2); Assert.AreEqual('a', *bytes2); Assert.AreEqual('b', *(bytes2 + 1)); // Others. check(() => stream.Write(new byte[] { 3, 4, 5 }, 1, 2), () => stream.ReadByteArray(2), new byte[] { 4, 5 }); check(() => stream.WriteBool(true), () => stream.ReadBool(), true); check(() => stream.WriteBoolArray(new[] { true, false }), () => stream.ReadBoolArray(2), new[] { true, false }); check(() => stream.WriteByte(4), () => stream.ReadByte(), 4); check(() => stream.WriteByteArray(new byte[] { 4, 5, 6 }), () => stream.ReadByteArray(3), new byte[] { 4, 5, 6 }); check(() => stream.WriteChar('x'), () => stream.ReadChar(), 'x'); check(() => stream.WriteCharArray(new[] { 'a', 'b' }), () => stream.ReadCharArray(2), new[] { 'a', 'b' }); check(() => stream.WriteDouble(4), () => stream.ReadDouble(), 4d); check(() => stream.WriteDoubleArray(new[] { 4d }), () => stream.ReadDoubleArray(1), new[] { 4d }); check(() => stream.WriteFloat(4), () => stream.ReadFloat(), 4f); check(() => stream.WriteFloatArray(new[] { 4f }), () => stream.ReadFloatArray(1), new[] { 4f }); check(() => stream.WriteInt(4), () => stream.ReadInt(), 4); check(() => stream.WriteInt(0, 4), () => stream.ReadInt(), 4); check(() => stream.WriteIntArray(new[] { 4 }), () => stream.ReadIntArray(1), new[] { 4 }); check(() => stream.WriteLong(4), () => stream.ReadLong(), 4L); check(() => stream.WriteLongArray(new[] { 4L }), () => stream.ReadLongArray(1), new[] { 4L }); check(() => stream.WriteShort(4), () => stream.ReadShort(), (short)4); check(() => stream.WriteShortArray(new short[] { 4 }), () => stream.ReadShortArray(1), new short[] { 4 }); }
/// <summary> /// Writes an array of fields to a stream. /// </summary> /// <param name="fields">Fields.</param> /// <param name="stream">Stream.</param> /// <param name="offset">Offset in the array.</param> /// <param name="count">Field count to write.</param> /// <param name="compact">Compact mode without field ids.</param> /// <returns> /// Flags according to offset sizes: <see cref="BinaryObjectHeader.Flag.OffsetOneByte" />, /// <see cref="BinaryObjectHeader.Flag.OffsetTwoBytes" />, or 0. /// </returns> public static unsafe BinaryObjectHeader.Flag WriteSchema(BinaryObjectSchemaField[] fields, IBinaryStream stream, int offset, int count, bool compact) { Debug.Assert(fields != null); Debug.Assert(stream != null); Debug.Assert(count > 0); Debug.Assert(offset >= 0); Debug.Assert(offset < fields.Length); unchecked { // Last field is the farthest in the stream var maxFieldOffset = fields[offset + count - 1].Offset; if (compact) { if (maxFieldOffset <= byte.MaxValue) { for (int i = offset; i < count + offset; i++) stream.WriteByte((byte)fields[i].Offset); return BinaryObjectHeader.Flag.OffsetOneByte; } if (maxFieldOffset <= ushort.MaxValue) { for (int i = offset; i < count + offset; i++) stream.WriteShort((short)fields[i].Offset); return BinaryObjectHeader.Flag.OffsetTwoBytes; } for (int i = offset; i < count + offset; i++) stream.WriteInt(fields[i].Offset); } else { if (maxFieldOffset <= byte.MaxValue) { for (int i = offset; i < count + offset; i++) { var field = fields[i]; stream.WriteInt(field.Id); stream.WriteByte((byte)field.Offset); } return BinaryObjectHeader.Flag.OffsetOneByte; } if (maxFieldOffset <= ushort.MaxValue) { for (int i = offset; i < count + offset; i++) { var field = fields[i]; stream.WriteInt(field.Id); stream.WriteShort((short)field.Offset); } return BinaryObjectHeader.Flag.OffsetTwoBytes; } if (BitConverter.IsLittleEndian) { fixed (BinaryObjectSchemaField* ptr = &fields[offset]) { stream.Write((byte*)ptr, count / BinaryObjectSchemaField.Size); } } else { for (int i = offset; i < count + offset; i++) { var field = fields[i]; stream.WriteInt(field.Id); stream.WriteInt(field.Offset); } } } return BinaryObjectHeader.Flag.None; } }