/// <summary> /// Reads the binary object in binary form. /// </summary> private BinaryObject ReadAsBinary(int binaryBytesPos, int dataLen, bool doDetach) { try { Stream.Seek(dataLen + binaryBytesPos, SeekOrigin.Begin); var offs = Stream.ReadInt(); // offset inside data var pos = binaryBytesPos + offs; var hdr = BinaryObjectHeader.Read(Stream, pos); if (!doDetach) { return(new BinaryObject(_marsh, Stream.GetArray(), pos, hdr)); } Stream.Seek(pos, SeekOrigin.Begin); return(new BinaryObject(_marsh, Stream.ReadByteArray(hdr.Length), 0, hdr)); } finally { Stream.Seek(binaryBytesPos + dataLen + 4, SeekOrigin.Begin); } }
/** <inheritDoc /> */ public IBinaryObject Build() { // Assume that resulting length will be no less than header + [fields_cnt] * 12; int estimatedCapacity = BinaryObjectHeader.Size + (_vals == null ? 0 : _vals.Count * 12); using (var outStream = new BinaryHeapStream(estimatedCapacity)) { BinaryWriter writer = _binary.Marshaller.StartMarshal(outStream); writer.SetBuilder(this); // All related builders will work in this context with this writer. _parent._ctx = new Context(writer); try { // Write. writer.Write(this); // Process metadata. _binary.Marshaller.FinishMarshal(writer); // Create binary object once metadata is processed. return(new BinaryObject(_binary.Marshaller, outStream.InternalArray, 0, BinaryObjectHeader.Read(outStream, 0))); } finally { // Cleanup. _parent._ctx.Closed = true; } } }
/// <summary> /// Reads the schema, maintains stream position. /// </summary> public static int[] GetFieldIds(BinaryObjectHeader hdr, IIgniteInternal ignite, IBinaryStream stream, int objectPos) { Debug.Assert(stream != null); if (hdr.IsCompactFooter) { // Get schema from Java return(GetFieldIds(hdr, ignite)); } var pos = stream.Position; stream.Seek(objectPos + hdr.SchemaOffset, SeekOrigin.Begin); var count = hdr.SchemaFieldCount; var offsetSize = hdr.SchemaFieldOffsetSize; var res = new int[count]; for (var i = 0; i < count; i++) { res[i] = stream.ReadInt(); stream.Seek(offsetSize, SeekOrigin.Current); // Skip offsets. } stream.Seek(pos, SeekOrigin.Begin); return(res); }
/// <summary> /// Initializes a new instance of the <see cref="BinaryObject" /> class. /// </summary> /// <param name="marsh">Marshaller.</param> /// <param name="data">Raw data of this binary object.</param> /// <param name="offset">Offset in data array.</param> /// <param name="header">The header.</param> public BinaryObject(Marshaller marsh, byte[] data, int offset, BinaryObjectHeader header) { _marsh = marsh; _data = data; _offset = offset; _header = header; }
/// <summary> /// Gets the cached schema. /// </summary> private static int[] GetCachedSchema(BinaryObjectHeader hdr, IIgniteInternal ignite) { var cachedHolder = ignite.Marshaller.GetCachedBinaryTypeHolder(hdr.TypeId); if (cachedHolder == null || cachedHolder.BinaryType == null || cachedHolder.BinaryType.Schema == null) { return(null); } return(cachedHolder.BinaryType.Schema.Get(hdr.SchemaId)); }
/// <summary> /// Initializes a new instance of the <see cref="BinaryObject" /> class. /// </summary> /// <param name="marsh">Marshaller.</param> /// <param name="data">Raw data of this binary object.</param> /// <param name="offset">Offset in data array.</param> /// <param name="header">The header.</param> public BinaryObject(Marshaller marsh, byte[] data, int offset, BinaryObjectHeader header) { Debug.Assert(marsh != null); Debug.Assert(data != null); Debug.Assert(offset >= 0 && offset < data.Length); _marsh = marsh; _data = data; _offset = offset; _header = header; }
/// <summary> /// Lazy fields initialization routine. /// </summary> private void InitializeFields() { if (_fields != null) { return; } var stream = new BinaryHeapStream(_data); var hdr = BinaryObjectHeader.Read(stream, _offset); _fields = hdr.ReadSchemaAsDictionary(stream, _offset) ?? EmptyFields; }
/// <summary> /// Create empty binary object from descriptor. /// </summary> /// <param name="desc">Descriptor.</param> /// <returns>Empty binary object.</returns> private BinaryObject BinaryFromDescriptor(IBinaryTypeDescriptor desc) { var len = BinaryObjectHeader.Size; var hdr = new BinaryObjectHeader(desc.TypeId, 0, len, 0, len, desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None); var stream = new BinaryHeapStream(len); BinaryObjectHeader.Write(hdr, stream, 0); return(new BinaryObject(_marsh, stream.InternalArray, 0, hdr)); }
/// <summary> /// Lazy fields initialization routine. /// </summary> private void InitializeFields(IBinaryTypeDescriptor desc = null) { if (_fields != null) { return; } desc = desc ?? _marsh.GetDescriptor(true, _header.TypeId); using (var stream = new BinaryHeapStream(_data)) { var hdr = BinaryObjectHeader.Read(stream, _offset); _fields = BinaryObjectSchemaSerializer.ReadSchema(stream, _offset, hdr, desc.Schema, _marsh) .ToDictionary() ?? EmptyFields; } }
/// <summary> /// Gets the field ids. /// </summary> private static int[] GetFieldIds(BinaryObjectHeader hdr, Ignite ignite) { Debug.Assert(hdr.TypeId != BinaryUtils.TypeUnregistered); int[] fieldIds = null; if (ignite != null) { fieldIds = ignite.BinaryProcessor.GetSchema(hdr.TypeId, hdr.SchemaId); } if (fieldIds == null) { throw new BinaryObjectException("Cannot find schema for object with compact footer [" + "typeId=" + hdr.TypeId + ", schemaId=" + hdr.SchemaId + ']'); } return(fieldIds); }
/// <summary> /// Gets the field ids. /// </summary> private static int[] GetFieldIds(BinaryObjectHeader hdr, BinaryObjectSchema schema, Marshaller marsh) { var fieldIds = schema.Get(hdr.SchemaId); if (fieldIds == null) { if (marsh.Ignite != null) { fieldIds = marsh.Ignite.BinaryProcessor.GetSchema(hdr.TypeId, hdr.SchemaId); } if (fieldIds == null) { throw new BinaryObjectException("Cannot find schema for object with compact footer [" + "typeId=" + hdr.TypeId + ", schemaId=" + hdr.SchemaId + ']'); } } return(fieldIds); }
/// <summary> /// Create empty binary object from descriptor. /// </summary> /// <param name="desc">Descriptor.</param> /// <returns>Empty binary object.</returns> private BinaryObject BinaryFromDescriptor(IBinaryTypeDescriptor desc) { const int len = BinaryObjectHeader.Size; var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; if (_marsh.CompactFooter && desc.UserType) { flags |= BinaryObjectHeader.Flag.CompactFooter; } var hdr = new BinaryObjectHeader(desc.TypeId, 0, len, 0, len, flags); using (var stream = new BinaryHeapStream(len)) { BinaryObjectHeader.Write(hdr, stream, 0); return(new BinaryObject(_marsh, stream.InternalArray, 0, hdr)); } }
/// <summary> /// Gets the field ids. /// </summary> private static int[] GetFieldIds(BinaryObjectHeader hdr, IIgniteInternal ignite) { Debug.Assert(hdr.TypeId != BinaryTypeId.Unregistered); int[] fieldIds = null; if (ignite != null) { fieldIds = GetCachedSchema(hdr, ignite) ?? ignite.Marshaller.GetBinaryType(hdr.TypeId).Schema.Get(hdr.SchemaId); } if (fieldIds == null) { throw new BinaryObjectException("Cannot find schema for object with compact footer [" + "typeId=" + hdr.TypeId + ", schemaId=" + hdr.SchemaId + ']'); } return(fieldIds); }
/// <summary> /// Writes collected schema to the stream and pops it. /// </summary> /// <param name="stream">The stream.</param> /// <param name="schemaOffset">The schema offset.</param> /// <param name="schemaId">The schema identifier.</param> /// <param name="flags">Flags according to offset sizes.</param> /// <returns> /// True if current schema was non empty; false otherwise. /// </returns> public bool WriteSchema(IBinaryStream stream, int schemaOffset, out int schemaId, ref BinaryObjectHeader.Flag flags) { schemaId = Fnv1Hash.Basis; var count = _idx - schemaOffset; if (count == 0) { return(false); } flags |= BinaryObjectHeader.WriteSchema(_fields, stream, schemaOffset, count); for (var i = schemaOffset; i < _idx; i++) { schemaId = Fnv1Hash.Update(schemaId, _fields[i].Id); } return(true); }
/// <summary> /// Write object. /// </summary> /// <param name="obj">Object.</param> public void Write <T>(T obj) { // Handle special case for null. // ReSharper disable once CompareNonConstrainedGenericWithNull if (obj == null) { _stream.WriteByte(BinaryUtils.HdrNull); return; } // We use GetType() of a real object instead of typeof(T) to take advantage of // automatic Nullable'1 unwrapping. Type type = obj.GetType(); // Handle common case when primitive is written. if (type.IsPrimitive) { WritePrimitive(obj, type); return; } // Handle special case for builder. if (WriteBuilderSpecials(obj)) { return; } // Are we dealing with a well-known type? var handler = BinarySystemHandlers.GetWriteHandler(type); if (handler != null) { if (handler.SupportsHandles && WriteHandle(_stream.Position, obj)) { return; } handler.Write(this, obj); return; } // Wrap objects as required. if (WrapperFunc != null && type != WrapperFunc.Method.ReturnType) { if (_isInWrapper) { _isInWrapper = false; } else { _isInWrapper = true; Write(WrapperFunc(obj)); return; } } // Suppose that we faced normal object and perform descriptor lookup. var desc = _marsh.GetDescriptor(type); // Writing normal object. var pos = _stream.Position; // Dealing with handles. if (desc.Serializer.SupportsHandles && WriteHandle(pos, obj)) { return; } // Skip header length as not everything is known now _stream.Seek(BinaryObjectHeader.Size, SeekOrigin.Current); // Write type name for unregistered types if (!desc.IsRegistered) { WriteString(Marshaller.GetTypeName(type)); } var headerSize = _stream.Position - pos; // Preserve old frame. var oldFrame = _frame; // Push new frame. _frame.RawPos = 0; _frame.Pos = pos; _frame.Struct = new BinaryStructureTracker(desc, desc.WriterTypeStructure); _frame.HasCustomTypeData = false; var schemaIdx = _schema.PushSchema(); try { // Write object fields. desc.Serializer.WriteBinary(obj, this); var dataEnd = _stream.Position; // Write schema var schemaOffset = dataEnd - pos; int schemaId; var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; if (_frame.HasCustomTypeData) { flags |= BinaryObjectHeader.Flag.CustomDotNetType; } if (Marshaller.CompactFooter && desc.UserType) { flags |= BinaryObjectHeader.Flag.CompactFooter; } var hasSchema = _schema.WriteSchema(_stream, schemaIdx, out schemaId, ref flags); if (hasSchema) { flags |= BinaryObjectHeader.Flag.HasSchema; // Calculate and write header. if (_frame.RawPos > 0) { _stream.WriteInt(_frame.RawPos - pos); // raw offset is in the last 4 bytes } // Update schema in type descriptor if (desc.Schema.Get(schemaId) == null) { desc.Schema.Add(schemaId, _schema.GetSchema(schemaIdx)); } } else { schemaOffset = headerSize; } if (_frame.RawPos > 0) { flags |= BinaryObjectHeader.Flag.HasRaw; } var len = _stream.Position - pos; var hashCode = BinaryArrayEqualityComparer.GetHashCode(Stream, pos + BinaryObjectHeader.Size, dataEnd - pos - BinaryObjectHeader.Size); var header = new BinaryObjectHeader(desc.IsRegistered ? desc.TypeId : BinaryTypeId.Unregistered, hashCode, len, schemaId, schemaOffset, flags); BinaryObjectHeader.Write(header, _stream, pos); Stream.Seek(pos + len, SeekOrigin.Begin); // Seek to the end } finally { _schema.PopSchema(schemaIdx); } // Apply structure updates if any. _frame.Struct.UpdateWriterStructure(this); // Restore old frame. _frame = oldFrame; }
/// <summary> /// Reads the schema according to this header data. /// </summary> /// <param name="stream">The stream.</param> /// <param name="position">The position.</param> /// <param name="hdr">The header.</param> /// <param name="fieldIdsFunc">The field ids function.</param> /// <returns> /// Schema. /// </returns> public static unsafe BinaryObjectSchemaField[] ReadSchema(IBinaryStream stream, int position, BinaryObjectHeader hdr, Func <int[]> fieldIdsFunc) { Debug.Assert(stream != null); Debug.Assert(fieldIdsFunc != null); var schemaSize = hdr.SchemaFieldCount; if (schemaSize == 0) { return(null); } stream.Seek(position + hdr.SchemaOffset, SeekOrigin.Begin); var res = new BinaryObjectSchemaField[schemaSize]; var offsetSize = hdr.SchemaFieldOffsetSize; if (hdr.IsCompactFooter) { var fieldIds = fieldIdsFunc(); Debug.Assert(fieldIds.Length == schemaSize); if (offsetSize == 1) { for (var i = 0; i < schemaSize; i++) { res[i] = new BinaryObjectSchemaField(fieldIds[i], stream.ReadByte()); } } else if (offsetSize == 2) { for (var i = 0; i < schemaSize; i++) { res[i] = new BinaryObjectSchemaField(fieldIds[i], (ushort)stream.ReadShort()); } } else { for (var i = 0; i < schemaSize; i++) { res[i] = new BinaryObjectSchemaField(fieldIds[i], stream.ReadInt()); } } } else { if (offsetSize == 1) { for (var i = 0; i < schemaSize; i++) { res[i] = new BinaryObjectSchemaField(stream.ReadInt(), stream.ReadByte()); } } else if (offsetSize == 2) { for (var i = 0; i < schemaSize; i++) { res[i] = new BinaryObjectSchemaField(stream.ReadInt(), (ushort)stream.ReadShort()); } } else { if (BitConverter.IsLittleEndian) { fixed(BinaryObjectSchemaField *ptr = &res[0]) { stream.Read((byte *)ptr, schemaSize * BinaryObjectSchemaField.Size); } } else { for (var i = 0; i < schemaSize; i++) { res[i] = new BinaryObjectSchemaField(stream.ReadInt(), stream.ReadInt()); } } } } return(res); }
/// <summary> /// Reads the schema according to this header data. /// </summary> /// <param name="stream">The stream.</param> /// <param name="position">The position.</param> /// <param name="hdr">The header.</param> /// <param name="schema">The schema.</param> /// <param name="ignite">The ignite.</param> /// <returns> /// Schema. /// </returns> public static BinaryObjectSchemaField[] ReadSchema(IBinaryStream stream, int position, BinaryObjectHeader hdr, BinaryObjectSchema schema, IIgniteInternal ignite) { Debug.Assert(stream != null); Debug.Assert(schema != null); return(ReadSchema(stream, position, hdr, () => GetFieldIds(hdr, schema, ignite))); }
/// <summary> /// Gets the field ids. /// </summary> private static int[] GetFieldIds(BinaryObjectHeader hdr, BinaryObjectSchema schema, IIgniteInternal ignite) { return(schema.Get(hdr.SchemaId) ?? GetFieldIds(hdr, ignite)); }
/// <summary> /// Reads the schema according to this header data. /// </summary> /// <param name="stream">The stream.</param> /// <param name="position">The position.</param> /// <param name="hdr">The header.</param> /// <param name="schema">The schema.</param> /// <param name="marsh">The marshaller.</param> /// <returns> /// Schema. /// </returns> public static BinaryObjectSchemaField[] ReadSchema(IBinaryStream stream, int position, BinaryObjectHeader hdr, BinaryObjectSchema schema, Marshaller marsh) { Debug.Assert(stream != null); Debug.Assert(schema != null); Debug.Assert(marsh != null); return(ReadSchema(stream, position, hdr, () => GetFieldIds(hdr, schema, marsh))); }
private T ReadFullObject <T>(int pos) { var hdr = BinaryObjectHeader.Read(Stream, pos); // Validate protocol version. BinaryUtils.ValidateProtocolVersion(hdr.Version); try { // Already read this object? object hndObj; if (_hnds != null && _hnds.TryGetValue(pos, out hndObj)) { return((T)hndObj); } if (hdr.IsUserType && _mode == BinaryMode.ForceBinary) { BinaryObject portObj; if (_detach) { Stream.Seek(pos, SeekOrigin.Begin); portObj = new BinaryObject(_marsh, Stream.ReadByteArray(hdr.Length), 0, hdr); } else { portObj = new BinaryObject(_marsh, Stream.GetArray(), pos, hdr); } T obj = _builder == null ? TypeCaster <T> .Cast(portObj) : TypeCaster <T> .Cast(_builder.Child(portObj)); AddHandle(pos, obj); return(obj); } else { // Find descriptor. var desc = hdr.TypeId == BinaryUtils.TypeUnregistered ? _marsh.GetDescriptor(Type.GetType(ReadString(), true)) : _marsh.GetDescriptor(hdr.IsUserType, hdr.TypeId, true); // Instantiate object. if (desc.Type == null) { if (desc is BinarySurrogateTypeDescriptor) { throw new BinaryObjectException(string.Format( "Unknown type ID: {0}. " + "This usually indicates missing BinaryConfiguration. " + "Make sure that all nodes have the same BinaryConfiguration.", hdr.TypeId)); } throw new BinaryObjectException(string.Format( "No matching type found for object [typeId={0}, typeName={1}]. " + "This usually indicates that assembly with specified type is not loaded on a node. " + "When using Apache.Ignite.exe, make sure to load assemblies with -assembly parameter.", desc.TypeId, desc.TypeName)); } // Preserve old frame. var oldFrame = _frame; // Set new frame. _frame.Hdr = hdr; _frame.Pos = pos; SetCurSchema(desc); _frame.Struct = new BinaryStructureTracker(desc, desc.ReaderTypeStructure); _frame.Raw = false; // Read object. var obj = desc.Serializer.ReadBinary <T>(this, desc, pos); _frame.Struct.UpdateReaderStructure(); // Restore old frame. _frame = oldFrame; return(obj); } } finally { // Advance stream pointer. Stream.Seek(pos + hdr.Length, SeekOrigin.Begin); } }
private T ReadFullObject <T>(int pos) { var hdr = BinaryObjectHeader.Read(Stream, pos); // Validate protocol version. BinaryUtils.ValidateProtocolVersion(hdr.Version); try { // Already read this object? object hndObj; if (_hnds != null && _hnds.TryGetValue(pos, out hndObj)) { return((T)hndObj); } if (hdr.IsUserType && _mode == BinaryMode.ForceBinary) { BinaryObject portObj; if (_detach) { Stream.Seek(pos, SeekOrigin.Begin); portObj = new BinaryObject(_marsh, Stream.ReadByteArray(hdr.Length), 0, hdr); } else { portObj = new BinaryObject(_marsh, Stream.GetArray(), pos, hdr); } T obj = _builder == null ? TypeCaster <T> .Cast(portObj) : TypeCaster <T> .Cast(_builder.Child(portObj)); AddHandle(pos, obj); return(obj); } else { // Find descriptor. IBinaryTypeDescriptor desc; if (!_descs.TryGetValue(BinaryUtils.TypeKey(hdr.IsUserType, hdr.TypeId), out desc)) { throw new BinaryObjectException("Unknown type ID: " + hdr.TypeId); } // Instantiate object. if (desc.Type == null) { throw new BinaryObjectException("No matching type found for object [typeId=" + desc.TypeId + ", typeName=" + desc.TypeName + ']'); } // Preserve old frame. var oldHdr = _curHdr; int oldPos = _curPos; var oldStruct = _curStruct; bool oldRaw = _curRaw; var oldSchema = _curSchema; var oldSchemaMap = _curSchemaMap; // Set new frame. _curHdr = hdr; _curPos = pos; SetCurSchema(desc); _curStruct = new BinaryStructureTracker(desc, desc.ReaderTypeStructure); _curRaw = false; // Read object. Stream.Seek(pos + BinaryObjectHeader.Size, SeekOrigin.Begin); object obj; var sysSerializer = desc.Serializer as IBinarySystemTypeSerializer; if (sysSerializer != null) { obj = sysSerializer.ReadInstance(this); } else { try { obj = FormatterServices.GetUninitializedObject(desc.Type); // Save handle. AddHandle(pos, obj); } catch (Exception e) { throw new BinaryObjectException("Failed to create type instance: " + desc.Type.AssemblyQualifiedName, e); } desc.Serializer.ReadBinary(obj, this); } _curStruct.UpdateReaderStructure(); // Restore old frame. _curHdr = oldHdr; _curPos = oldPos; _curStruct = oldStruct; _curRaw = oldRaw; _curSchema = oldSchema; _curSchemaMap = oldSchemaMap; // Process wrappers. We could introduce a common interface, but for only 2 if-else is faster. var wrappedSerializable = obj as SerializableObjectHolder; if (wrappedSerializable != null) { return((T)wrappedSerializable.Item); } var wrappedDateTime = obj as DateTimeHolder; if (wrappedDateTime != null) { return(TypeCaster <T> .Cast(wrappedDateTime.Item)); } return((T)obj); } } finally { // Advance stream pointer. Stream.Seek(pos + hdr.Length, SeekOrigin.Begin); } }
/// <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> /// Write object. /// </summary> /// <param name="obj">Object.</param> public void Write <T>(T obj) { // Handle special case for null. if (obj == null) { _stream.WriteByte(BinaryUtils.HdrNull); return; } // We use GetType() of a real object instead of typeof(T) to take advantage of // automatic Nullable'1 unwrapping. Type type = obj.GetType(); // Handle common case when primitive is written. if (type.IsPrimitive) { WritePrimitive(obj, type); return; } // Handle special case for builder. if (WriteBuilderSpecials(obj)) { return; } // Suppose that we faced normal object and perform descriptor lookup. IBinaryTypeDescriptor desc = type.IsEnum ? null : _marsh.GetDescriptor(type); if (desc != null) { // Writing normal object. var pos = _stream.Position; // Dealing with handles. if (!(desc.Serializer is IBinarySystemTypeSerializer) && WriteHandle(pos, obj)) { return; } // Skip header length as not everything is known now _stream.Seek(BinaryObjectHeader.Size, SeekOrigin.Current); // Preserve old frame. int oldTypeId = _curTypeId; IBinaryNameMapper oldConverter = _curConverter; IBinaryIdMapper oldMapper = _curMapper; int oldRawPos = _curRawPos; var oldPos = _curPos; var oldStruct = _curStruct; // Push new frame. _curTypeId = desc.TypeId; _curConverter = desc.NameMapper; _curMapper = desc.IdMapper; _curRawPos = 0; _curPos = pos; _curStruct = new BinaryStructureTracker(desc, desc.WriterTypeStructure); var schemaIdx = _schema.PushSchema(); try { // Write object fields. desc.Serializer.WriteBinary(obj, this); // Write schema var schemaOffset = _stream.Position - pos; int schemaId; var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; var hasSchema = _schema.WriteSchema(_stream, schemaIdx, out schemaId, ref flags); if (hasSchema) { flags |= BinaryObjectHeader.Flag.HasSchema; // Calculate and write header. if (_curRawPos > 0) { _stream.WriteInt(_curRawPos - pos); // raw offset is in the last 4 bytes } } else { schemaOffset = BinaryObjectHeader.Size; } if (_curRawPos > 0) { flags |= BinaryObjectHeader.Flag.HasRaw; } var len = _stream.Position - pos; var header = new BinaryObjectHeader(desc.TypeId, obj.GetHashCode(), len, schemaId, schemaOffset, flags); BinaryObjectHeader.Write(header, _stream, pos); Stream.Seek(pos + len, SeekOrigin.Begin); // Seek to the end } finally { _schema.PopSchema(schemaIdx); } // Apply structure updates if any. _curStruct.UpdateWriterStructure(this); // Restore old frame. _curTypeId = oldTypeId; _curConverter = oldConverter; _curMapper = oldMapper; _curRawPos = oldRawPos; _curPos = oldPos; _curStruct = oldStruct; } else { // Are we dealing with a well-known type? var handler = BinarySystemHandlers.GetWriteHandler(type); if (handler == null) // We did our best, object cannot be marshalled. { throw new BinaryObjectException("Unsupported object type [type=" + type + ", object=" + obj + ']'); } handler(this, obj); } }
private T ReadFullObject <T>(int pos) { var hdr = BinaryObjectHeader.Read(Stream, pos); // Validate protocol version. BinaryUtils.ValidateProtocolVersion(hdr.Version); try { // Already read this object? object hndObj; if (_hnds != null && _hnds.TryGetValue(pos, out hndObj)) { return((T)hndObj); } if (hdr.IsUserType && _mode == BinaryMode.ForceBinary) { BinaryObject portObj; if (_detach) { Stream.Seek(pos, SeekOrigin.Begin); portObj = new BinaryObject(_marsh, Stream.ReadByteArray(hdr.Length), 0, hdr); } else { portObj = new BinaryObject(_marsh, Stream.GetArray(), pos, hdr); } T obj = _builder == null ? TypeCaster <T> .Cast(portObj) : TypeCaster <T> .Cast(_builder.Child(portObj)); AddHandle(pos, obj); return(obj); } else { // Find descriptor. var desc = _marsh.GetDescriptor(hdr.IsUserType, hdr.TypeId); // Instantiate object. if (desc.Type == null) { if (desc is BinarySurrogateTypeDescriptor) { throw new BinaryObjectException("Unknown type ID: " + hdr.TypeId); } throw new BinaryObjectException("No matching type found for object [typeId=" + desc.TypeId + ", typeName=" + desc.TypeName + ']'); } // Preserve old frame. var oldHdr = _curHdr; int oldPos = _curPos; var oldStruct = _curStruct; bool oldRaw = _curRaw; var oldSchema = _curSchema; var oldSchemaMap = _curSchemaMap; // Set new frame. _curHdr = hdr; _curPos = pos; SetCurSchema(desc); _curStruct = new BinaryStructureTracker(desc, desc.ReaderTypeStructure); _curRaw = false; // Read object. Stream.Seek(pos + BinaryObjectHeader.Size, SeekOrigin.Begin); var obj = desc.Serializer.ReadBinary <T>(this, desc.Type, pos); _curStruct.UpdateReaderStructure(); // Restore old frame. _curHdr = oldHdr; _curPos = oldPos; _curStruct = oldStruct; _curRaw = oldRaw; _curSchema = oldSchema; _curSchemaMap = oldSchemaMap; return(obj); } } finally { // Advance stream pointer. Stream.Seek(pos + hdr.Length, SeekOrigin.Begin); } }