ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From voze...@apache.org
Subject [1/3] ignite git commit: IGNITE-1770: DotNet part.
Date Thu, 29 Oct 2015 15:56:45 GMT
Repository: ignite
Updated Branches:
  refs/heads/ignite-1770 42da3fa5f -> 0356a86cd


http://git-wip-us.apache.org/repos/asf/ignite/blob/ebb59902/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
index c9d6172..7f9569a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
@@ -37,9 +37,6 @@ namespace Apache.Ignite.Core.Impl.Portable
      */
     static class PortableUtils
     {
-        /** Cache empty dictionary. */
-        public static readonly IDictionary<int, int> EmptyFields = new Dictionary<int,
int>();
-
         /** Header of NULL object. */
         public const byte HdrNull = 101;
 
@@ -52,21 +49,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         /** Protocol versnion. */
         public const byte ProtoVer = 1;
 
-        /** Full header length. */
-        public const int FullHdrLen = 19;
-
-        /** Offset: hash code. */
-        public const int OffsetTypeId = 3;
-
-        /** Offset: hash code. */
-        public const int OffsetHashCode = 7;
-
-        /** Offset: length. */
-        public const int OffsetLen = 11;
-
-        /** Offset: raw data offset. */
-        public const int OffsetRaw = 15;
-
         /** Type: object. */
         public const byte TypeObject = HdrFull;
 
@@ -253,9 +235,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         /** Indicates object array. */
         public const int ObjTypeId = -1;
 
-        /** Length of tpye ID. */
-        public const int LengthTypeId = 1;
-
         /** Length of array size. */
         public const int LengthArraySize = 4;
 
@@ -1589,56 +1568,6 @@ namespace Apache.Ignite.Core.Impl.Portable
             return id;
         }
 
-        /**
-         * <summary>Get fields map for the given object.</summary>
-         * <param name="stream">Stream.</param>
-         * <param name="typeId">Type ID.</param>
-         * <param name="rawDataOffset">Raw data offset.</param>
-         * <returns>Dictionary with field ID as key and field position as value.</returns>
-         */
-        public static IDictionary<int, int> ObjectFields(IPortableStream stream, int
typeId, int rawDataOffset)
-        {
-            int endPos = stream.Position + rawDataOffset - FullHdrLen;
-
-            // First loop detects amount of fields in the object.
-            int retPos = stream.Position;
-            int cnt = 0;
-
-            while (stream.Position < endPos)
-            {
-                cnt++;
-
-                stream.Seek(4, SeekOrigin.Current);
-                int len = stream.ReadInt();
-
-                stream.Seek(stream.Position + len, SeekOrigin.Begin);
-            }
-
-            if (cnt == 0)
-                return EmptyFields;
-
-            stream.Seek(retPos, SeekOrigin.Begin);
-
-            IDictionary<int, int> fields = new Dictionary<int, int>(cnt);
-
-            // Second loop populates fields.
-            while (stream.Position < endPos)
-            {
-                int id = stream.ReadInt();
-                int len = stream.ReadInt();
-
-                if (fields.ContainsKey(id))
-                    throw new PortableException("Object contains duplicate field IDs [typeId="
+
-                        typeId + ", fieldId=" + id + ']');
-
-                fields[id] = stream.Position; // Add field ID and length.
-
-                stream.Seek(stream.Position + len, SeekOrigin.Begin);
-            }
-
-            return fields;
-        }
-
         /// <summary>
         /// Compare contents of two byte array chunks.
         /// </summary>
@@ -1731,13 +1660,11 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// <summary>
         /// Validate protocol version.
         /// </summary>
-        /// <param name="stream">Stream.</param>
-        public static void ValidateProtocolVersion(IPortableStream stream)
+        /// <param name="version">The version.</param>
+        public static void ValidateProtocolVersion(byte version)
         {
-            byte ver = stream.ReadByte();
-
-            if (ver != ProtoVer)
-                throw new PortableException("Unsupported protocol version: " + ver);
+            if (version != ProtoVer)
+                throw new PortableException("Unsupported protocol version: " + version);
         }
 
         /**
@@ -1851,6 +1778,28 @@ namespace Apache.Ignite.Core.Impl.Portable
         }
 
         /// <summary>
+        /// Gets the schema id as a Fnv1 hash.
+        /// </summary>
+        /// <param name="schema">The schema.</param>
+        /// <returns>
+        /// Schema id.
+        /// </returns>
+        public static int GetSchemaId(ResizeableArray<PortableObjectSchemaField> schema)
+        {
+            var hash = Fnv1Hash.Basis;
+
+            if (schema == null || schema.Count == 0)
+                return hash;
+
+            var arr = schema.Array;
+
+            for (int i = 0; i < schema.Count; i++)
+                hash = Fnv1Hash.Update(hash, arr[i].Id);
+
+            return hash;
+        }
+
+        /// <summary>
         /// Reverses the byte order of an unsigned long.
         /// </summary>
         private static ulong ReverseByteOrder(ulong l)

http://git-wip-us.apache.org/repos/asf/ignite/blob/ebb59902/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
index ab7adaa..e17449d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
@@ -21,7 +21,7 @@ namespace Apache.Ignite.Core.Impl.Portable
     using System.Collections;
     using System.Collections.Generic;
     using System.IO;
-
+    using Apache.Ignite.Core.Impl.Common;
     using Apache.Ignite.Core.Impl.Portable.IO;
     using Apache.Ignite.Core.Impl.Portable.Metadata;
     using Apache.Ignite.Core.Impl.Portable.Structure;
@@ -58,15 +58,22 @@ namespace Apache.Ignite.Core.Impl.Portable
         /** Current mapper. */
         private IPortableIdMapper _curMapper;
         
+        /** Current object start position. */
+        private int _curPos;
+
         /** Current raw position. */
-        private long _curRawPos;
+        private int _curRawPos;
 
-        /** Current type structure tracker, */
-        private PortableStructureTracker _curStruct;
-        
         /** Whether we are currently detaching an object. */
         private bool _detaching;
 
+        /** Current type structure tracker, */
+        private PortableStructureTracker _curStruct;
+
+        /** Current schema. */
+        private ResizeableArray<PortableObjectSchemaField> _curSchema;
+
+
         /// <summary>
         /// Gets the marshaller.
         /// </summary>
@@ -84,7 +91,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             WriteFieldId(fieldName, PU.TypeBool);
 
-            _stream.WriteInt(PU.LengthTypeId + 1);
             _stream.WriteByte(PU.TypeBool);
             _stream.WriteBool(val);
         }
@@ -111,7 +117,6 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                _stream.WriteInt(PU.LengthTypeId + PU.LengthArraySize + val.Length);
                 _stream.WriteByte(PU.TypeArrayBool);
                 PU.WriteBooleanArray(val, _stream);
             }
@@ -141,7 +146,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             WriteFieldId(fieldName, PU.TypeBool);
 
-            _stream.WriteInt(PU.LengthTypeId + 1);
             _stream.WriteByte(PU.TypeByte);
             _stream.WriteByte(val);
         }
@@ -168,7 +172,6 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                _stream.WriteInt(PU.LengthTypeId + PU.LengthArraySize + val.Length);
                 _stream.WriteByte(PU.TypeArrayByte);
                 PU.WriteByteArray(val, _stream);
             }
@@ -198,7 +201,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             WriteFieldId(fieldName, PU.TypeShort);
 
-            _stream.WriteInt(PU.LengthTypeId + 2);
             _stream.WriteByte(PU.TypeShort);
             _stream.WriteShort(val);
         }
@@ -225,7 +227,6 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                _stream.WriteInt(PU.LengthTypeId + PU.LengthArraySize + (val.Length <<
1));
                 _stream.WriteByte(PU.TypeArrayShort);
                 PU.WriteShortArray(val, _stream);
             }
@@ -255,7 +256,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             WriteFieldId(fieldName, PU.TypeChar);
 
-            _stream.WriteInt(PU.LengthTypeId + 2);
             _stream.WriteByte(PU.TypeChar);
             _stream.WriteChar(val);
         }
@@ -282,7 +282,6 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                _stream.WriteInt(PU.LengthTypeId + PU.LengthArraySize + (val.Length <<
1));
                 _stream.WriteByte(PU.TypeArrayChar);
                 PU.WriteCharArray(val, _stream);
             }
@@ -312,7 +311,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             WriteFieldId(fieldName, PU.TypeInt);
 
-            _stream.WriteInt(PU.LengthTypeId + 4);
             _stream.WriteByte(PU.TypeInt);
             _stream.WriteInt(val);
         }
@@ -339,7 +337,6 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                _stream.WriteInt(PU.LengthTypeId + PU.LengthArraySize + (val.Length <<
2));
                 _stream.WriteByte(PU.TypeArrayInt);
                 PU.WriteIntArray(val, _stream);
             }
@@ -369,7 +366,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             WriteFieldId(fieldName, PU.TypeLong);
 
-            _stream.WriteInt(PU.LengthTypeId + 8);
             _stream.WriteByte(PU.TypeLong);
             _stream.WriteLong(val);
         }
@@ -396,7 +392,6 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                _stream.WriteInt(PU.LengthTypeId + PU.LengthArraySize + (val.Length <<
3));
                 _stream.WriteByte(PU.TypeArrayLong);
                 PU.WriteLongArray(val, _stream);
             }
@@ -426,7 +421,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             WriteFieldId(fieldName, PU.TypeFloat);
 
-            _stream.WriteInt(PU.LengthTypeId + 4);
             _stream.WriteByte(PU.TypeFloat);
             _stream.WriteFloat(val);
         }
@@ -453,7 +447,6 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                _stream.WriteInt(PU.LengthTypeId + PU.LengthArraySize + (val.Length <<
2));
                 _stream.WriteByte(PU.TypeArrayFloat);
                 PU.WriteFloatArray(val, _stream);
             }
@@ -483,7 +476,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             WriteFieldId(fieldName, PU.TypeDouble);
 
-            _stream.WriteInt(PU.LengthTypeId + 8);
             _stream.WriteByte(PU.TypeDouble);
             _stream.WriteDouble(val);
         }
@@ -510,7 +502,6 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                _stream.WriteInt(PU.LengthTypeId + PU.LengthArraySize + (val.Length <<
3));
                 _stream.WriteByte(PU.TypeArrayDouble);
                 PU.WriteDoubleArray(val, _stream);
             }
@@ -544,12 +535,8 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                int pos = SkipFieldLength();
-
                 _stream.WriteByte(PU.TypeDecimal);
                 PortableUtils.WriteDecimal(val.Value, _stream);
-
-                WriteFieldLength(_stream, pos);
             }
         }
 
@@ -581,12 +568,8 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                int pos = SkipFieldLength();
-
                 _stream.WriteByte(PU.TypeArrayDecimal);
                 PU.WriteDecimalArray(val, _stream);
-
-                WriteFieldLength(_stream, pos);
             }
         }
         
@@ -618,8 +601,6 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                _stream.WriteInt(PU.LengthTypeId + 12);
-
                 _stream.WriteByte(PortableUtils.TypeTimestamp);
                 PortableUtils.WriteTimestamp(val.Value, _stream);
             }
@@ -653,12 +634,8 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                int pos = SkipFieldLength();
-
                 _stream.WriteByte(PortableUtils.TypeArrayTimestamp);
                 PortableUtils.WriteTimestampArray(val, _stream);
-
-                WriteFieldLength(_stream, pos);
             }
         }
 
@@ -690,12 +667,8 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                int pos = SkipFieldLength();
-
                 _stream.WriteByte(PU.TypeString);
                 PU.WriteString(val, _stream);
-
-                WriteFieldLength(_stream, pos);
             }
         }
 
@@ -727,12 +700,8 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                int pos = SkipFieldLength();
-
                 _stream.WriteByte(PU.TypeArrayString);
                 PU.WriteStringArray(val, _stream);
-
-                WriteFieldLength(_stream, pos);
             }
         }
 
@@ -764,8 +733,6 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                _stream.WriteInt(PU.LengthTypeId + 16);
-
                 _stream.WriteByte(PU.TypeGuid);
                 PU.WriteGuid(val.Value, _stream);
             }
@@ -799,12 +766,8 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                int pos = SkipFieldLength();
-
                 _stream.WriteByte(PU.TypeArrayGuid);
                 PU.WriteGuidArray(val, _stream);
-
-                WriteFieldLength(_stream, pos);
             }
         }
 
@@ -833,8 +796,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             WriteFieldId(fieldName, PU.TypeEnum);
 
-            _stream.WriteInt(PU.LengthTypeId + 16);
-
             _stream.WriteByte(PU.TypeEnum);
             PortableUtils.WriteEnum(_stream, (Enum)(object)val);
         }
@@ -864,12 +825,8 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                int pos = SkipFieldLength();
-
                 _stream.WriteByte(PU.TypeArrayEnum);
                 PortableUtils.WriteArray(val, this);
-
-                WriteFieldLength(_stream, pos);
             }
         }
 
@@ -902,13 +859,7 @@ namespace Apache.Ignite.Core.Impl.Portable
             if (val == null)
                 WriteNullField();
             else
-            {
-                int pos = SkipFieldLength();
-
                 Write(val);
-
-                WriteFieldLength(_stream, pos);
-            }
         }
 
         /// <summary>
@@ -935,12 +886,8 @@ namespace Apache.Ignite.Core.Impl.Portable
                 WriteNullField();
             else
             {
-                int pos = SkipFieldLength();
-
                 _stream.WriteByte(PU.TypeArray);
                 PortableUtils.WriteArray(val, this);
-
-                WriteFieldLength(_stream, pos);
             }
         }
 
@@ -981,13 +928,7 @@ namespace Apache.Ignite.Core.Impl.Portable
             if (val == null)
                 WriteNullField();
             else
-            {
-                int pos = SkipFieldLength();
-
                 WriteCollection(val);
-
-                WriteFieldLength(_stream, pos);
-            }
         }
 
         /// <summary>
@@ -1012,13 +953,7 @@ namespace Apache.Ignite.Core.Impl.Portable
             if (val == null)
                 WriteNullField();
             else
-            {
-                int pos = SkipFieldLength();
-
                 WriteDictionary(val);
-
-                WriteFieldLength(_stream, pos);
-            }
         }
 
         /// <summary>
@@ -1036,7 +971,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// </summary>
         private void WriteNullField()
         {
-            _stream.WriteInt(1);
             _stream.WriteByte(PU.HdrNull);
         }
 
@@ -1129,44 +1063,51 @@ namespace Apache.Ignite.Core.Impl.Portable
                 if (!(desc.Serializer is IPortableSystemTypeSerializer) && WriteHandle(pos,
obj))
                     return;
 
-                // Write header.
-                _stream.WriteByte(PU.HdrFull);
-                _stream.WriteByte(PU.ProtoVer);
-                _stream.WriteBool(desc.UserType);
-                _stream.WriteInt(desc.TypeId);
-                _stream.WriteInt(obj.GetHashCode());
-
-                // Skip length as it is not known in the first place.
-                _stream.Seek(8, SeekOrigin.Current);
+                // Skip header length as not everything is known now
+                _stream.Seek(PortableObjectHeader.Size, SeekOrigin.Current);
 
                 // Preserve old frame.
                 int oldTypeId = _curTypeId;
                 IPortableNameMapper oldConverter = _curConverter;
                 IPortableIdMapper oldMapper = _curMapper;
-                long oldRawPos = _curRawPos;
+                int oldRawPos = _curRawPos;
+                var oldPos = _curPos;
                 
                 var oldStruct = _curStruct;
+                var oldSchema = _curSchema;
 
                 // Push new frame.
                 _curTypeId = desc.TypeId;
                 _curConverter = desc.NameConverter;
                 _curMapper = desc.Mapper;
                 _curRawPos = 0;
+                _curPos = pos;
 
                 _curStruct = new PortableStructureTracker(desc, desc.WriterTypeStructure);
+                _curSchema = null;
 
                 // Write object fields.
                 desc.Serializer.WritePortable(obj, this);
 
-                // Calculate and write length.
-                int len = _stream.Position - pos;
+                // Write schema
+                var hasSchema = _curSchema != null;
+                var schemaOffset = hasSchema ? _stream.Position - pos : PortableObjectHeader.Size;
 
-                _stream.WriteInt(pos + PU.OffsetLen, len);
-                
-                if (_curRawPos != 0)
-                    _stream.WriteInt(pos + PU.OffsetRaw, (int)(_curRawPos - pos));
-                else
-                    _stream.WriteInt(pos + PU.OffsetRaw, len);
+                if (hasSchema)
+                    PortableObjectSchemaField.WriteArray(_curSchema.Array, _stream, _curSchema.Count);
+
+                // Calculate and write header.
+                if (hasSchema && _curRawPos > 0)
+                    _stream.WriteInt(_curRawPos - pos); // raw offset is in the last 4 bytes
+
+                var len = _stream.Position - pos;
+
+                var header = new PortableObjectHeader(desc.UserType, desc.TypeId, obj.GetHashCode(),
len,
+                    PU.GetSchemaId(_curSchema), schemaOffset, !hasSchema);
+
+                PortableObjectHeader.Write(header, _stream, pos);
+
+                Stream.Seek(pos + len, SeekOrigin.Begin);  // Seek to the end
 
                 // Apply structure updates if any.
                 _curStruct.UpdateWriterStructure(this);
@@ -1176,8 +1117,10 @@ namespace Apache.Ignite.Core.Impl.Portable
                 _curConverter = oldConverter;
                 _curMapper = oldMapper;
                 _curRawPos = oldRawPos;
+                _curPos = oldPos;
 
                 _curStruct = oldStruct;
+                _curSchema = oldSchema;
             }
             else
             {
@@ -1416,7 +1359,7 @@ namespace Apache.Ignite.Core.Impl.Portable
 
             return true;
         }
-        
+
         /// <summary>
         /// Write field ID.
         /// </summary>
@@ -1427,35 +1370,14 @@ namespace Apache.Ignite.Core.Impl.Portable
             if (_curRawPos != 0)
                 throw new PortableException("Cannot write named fields after raw data is
written.");
 
-            _stream.WriteInt(_curStruct.GetFieldId(fieldName, fieldTypeId));
-        }
+            var fieldId = _curStruct.GetFieldId(fieldName, fieldTypeId);
 
-        /// <summary>
-        /// Skip field lenght and return position where it is to be written.
-        /// </summary>
-        /// <returns></returns>
-        private int SkipFieldLength()
-        {
-            int pos = _stream.Position;
+            _curSchema = _curSchema ?? new ResizeableArray<PortableObjectSchemaField>(4);
 
-            _stream.Seek(4, SeekOrigin.Current);
-
-            return pos;
+            _curSchema.Add(new PortableObjectSchemaField(fieldId, _stream.Position - _curPos));
         }
 
         /// <summary>
-        /// Write field length.
-        /// </summary>
-        /// <param name="stream">Stream.</param>
-        /// <param name="pos">Position where length should reside</param>
-        private static void WriteFieldLength(IPortableStream stream, int pos)
-        {
-            // Length is is a difference between current position and previously recorder

-            // length placeholder position minus 4 bytes for the length itself.
-            stream.WriteInt(pos, stream.Position - pos - 4);
-        }
-        
-        /// <summary>
         /// Saves metadata for this session.
         /// </summary>
         /// <param name="typeId">Type ID.</param>

http://git-wip-us.apache.org/repos/asf/ignite/blob/ebb59902/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortablesImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortablesImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortablesImpl.cs
index 451386b..f48f120 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortablesImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortablesImpl.cs
@@ -164,17 +164,15 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// <returns>Empty portable object.</returns>
         private PortableUserObject PortableFromDescriptor(IPortableTypeDescriptor desc)
         {
-            PortableHeapStream stream = new PortableHeapStream(18);
+            var len = PortableObjectHeader.Size;
 
-            stream.WriteByte(PortableUtils.HdrFull);
-            stream.WriteByte(PortableUtils.ProtoVer);
-            stream.WriteBool(true);
-            stream.WriteInt(desc.TypeId);
-            stream.WriteInt(0); // Hash.
-            stream.WriteInt(PortableUtils.FullHdrLen); // Length.
-            stream.WriteInt(PortableUtils.FullHdrLen); // Raw data offset.
+            var hdr = new PortableObjectHeader(desc.UserType, desc.TypeId, 0, len, 0, len,
true);
 
-            return new PortableUserObject(_marsh, stream.InternalArray, 0, desc.TypeId, 0);
+            var stream = new PortableHeapStream(len);
+
+            PortableObjectHeader.Write(hdr, stream, 0);
+
+            return new PortableUserObject(_marsh, stream.InternalArray, 0, hdr);
         }
 
         /// <summary>


Mime
View raw message