/// <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));
        }
        /// <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 |= BinaryObjectSchemaSerializer.WriteSchema(_fields, stream, schemaOffset, count,
                (flags & BinaryObjectHeader.Flag.CompactFooter) == BinaryObjectHeader.Flag.CompactFooter);

            for (var i = schemaOffset; i < _idx; i++)
                schemaId = Fnv1Hash.Update(schemaId, _fields[i].Id);

            return true;
        }
        /// <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 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], 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(), stream.ReadShort());
                }
                else
                {
                    for (var i = 0; i < schemaSize; i++)
                        res[i] = new BinaryObjectSchemaField(stream.ReadInt(), stream.ReadInt());
                }
            }

            return res;
        }
        /// <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.ClusterGroup.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;
        }