You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2015/10/22 11:27:37 UTC

[45/50] [abbrv] ignite git commit: Merge branch 'ignite-1282' into ignite-1651

http://git-wip-us.apache.org/repos/asf/ignite/blob/ec58b87c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
----------------------------------------------------------------------
diff --cc modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
index 0000000,c7be496..6d07757
mode 000000,100644..100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
@@@ -1,0 -1,2200 +1,2228 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one or more
+  * contributor license agreements.  See the NOTICE file distributed with
+  * this work for additional information regarding copyright ownership.
+  * The ASF licenses this file to You under the Apache License, Version 2.0
+  * (the "License"); you may not use this file except in compliance with
+  * the License.  You may obtain a copy of the License at
+  *
+  *      http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ namespace Apache.Ignite.Core.Impl.Portable
+ {
+     using System;
+     using System.Collections;
+     using System.Collections.Concurrent;
+     using System.Collections.Generic;
+     using System.Diagnostics;
+     using System.Diagnostics.CodeAnalysis;
+     using System.IO;
+     using System.Reflection;
+     using System.Runtime.InteropServices;
+     using System.Runtime.Serialization.Formatters.Binary;
++    using System.Security.Policy;
+     using System.Text;
+     using Apache.Ignite.Core.Impl.Common;
+     using Apache.Ignite.Core.Impl.Portable.IO;
+     using Apache.Ignite.Core.Portable;
+ 
+     /**
+      * <summary>Utilities for portable serialization.</summary>
+      */
+     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;
+ 
+         /** Header of object handle. */
+         public const byte HdrHnd = 102;
+ 
+         /** Header of object in fully serialized form. */
+         public const byte HdrFull = 103;
 -        
++
++        /** Protocol versnion. */
++        public const byte ProtoVer = 1;
++
+         /** Full header length. */
 -        public const int FullHdrLen = 18;
++        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 OffsetRawOff = 15;
+ 
+         /** Type: object. */
+         public const byte TypeObject = HdrFull;
+ 
+         /** Type: unsigned byte. */
+         public const byte TypeByte = 1;
+ 
+         /** Type: short. */
+         public const byte TypeShort = 2;
+ 
+         /** Type: int. */
+         public const byte TypeInt = 3;
+ 
+         /** Type: long. */
+         public const byte TypeLong = 4;
+ 
+         /** Type: float. */
+         public const byte TypeFloat = 5;
+ 
+         /** Type: double. */
+         public const byte TypeDouble = 6;
+ 
+         /** Type: char. */
+         public const byte TypeChar = 7;
+ 
+         /** Type: boolean. */
+         public const byte TypeBool = 8;
+         
+         /** Type: decimal. */
+         public const byte TypeDecimal = 30;
+ 
+         /** Type: string. */
+         public const byte TypeString = 9;
+ 
+         /** Type: GUID. */
+         public const byte TypeGuid = 10;
+ 
+         /** Type: date. */
+         public const byte TypeDate = 11;
+ 
+         /** Type: unsigned byte array. */
+         public const byte TypeArrayByte = 12;
+ 
+         /** Type: short array. */
+         public const byte TypeArrayShort = 13;
+ 
+         /** Type: int array. */
+         public const byte TypeArrayInt = 14;
+ 
+         /** Type: long array. */
+         public const byte TypeArrayLong = 15;
+ 
+         /** Type: float array. */
+         public const byte TypeArrayFloat = 16;
+ 
+         /** Type: double array. */
+         public const byte TypeArrayDouble = 17;
+ 
+         /** Type: char array. */
+         public const byte TypeArrayChar = 18;
+ 
+         /** Type: boolean array. */
+         public const byte TypeArrayBool = 19;
+ 
+         /** Type: decimal array. */
+         public const byte TypeArrayDecimal = 31;
+ 
+         /** Type: string array. */
+         public const byte TypeArrayString = 20;
+ 
+         /** Type: GUID array. */
+         public const byte TypeArrayGuid = 21;
+ 
+         /** Type: date array. */
+         public const byte TypeArrayDate = 22;
+ 
+         /** Type: object array. */
+         public const byte TypeArray = 23;
+ 
+         /** Type: collection. */
+         public const byte TypeCollection = 24;
+ 
+         /** Type: map. */
+         public const byte TypeDictionary = 25;
+ 
+         /** Type: map entry. */
+         public const byte TypeMapEntry = 26;
+ 
+         /** Type: portable object. */
+         public const byte TypePortable = 27;
+ 
+         /** Type: enum. */
+         public const byte TypeEnum = 28;
+ 
+         /** Type: enum array. */
+         public const byte TypeArrayEnum = 29;
+         
+         /** Type: native job holder. */
+         public const byte TypeNativeJobHolder = 77;
+ 
+         /** Type: native job result holder. */
+         public const byte TypePortableJobResHolder = 76;
+ 
+         /** Type: .Net configuration. */
+         public const byte TypeDotNetCfg = 202;
+ 
+         /** Type: .Net portable configuration. */
+         public const byte TypeDotNetPortableCfg = 203;
+ 
+         /** Type: .Net portable type configuration. */
+         public const byte TypeDotNetPortableTypCfg = 204;
+ 
+         /** Type: Ignite proxy. */
+         public const byte TypeIgniteProxy = 74;
+ 
+         /** Type: function wrapper. */
+         public const byte TypeComputeOutFuncJob = 80;
+ 
+         /** Type: function wrapper. */
+         public const byte TypeComputeFuncJob = 81;
+ 
+         /** Type: continuous query remote filter. */
+         public const byte TypeContinuousQueryRemoteFilterHolder = 82;
+ 
+         /** Type: Compute out func wrapper. */
+         public const byte TypeComputeOutFuncWrapper = 83;
+ 
+         /** Type: Compute func wrapper. */
+         public const byte TypeComputeFuncWrapper = 85;
+ 
+         /** Type: Compute job wrapper. */
+         public const byte TypeComputeJobWrapper = 86;
+ 
+         /** Type: Compute job wrapper. */
+         public const byte TypeSerializableHolder = 87;
+ 
+         /** Type: action wrapper. */
+         public const byte TypeComputeActionJob = 88;
+ 
+         /** Type: entry processor holder. */
+         public const byte TypeCacheEntryProcessorHolder = 89;
+ 
+         /** Type: entry predicate holder. */
+         public const byte TypeCacheEntryPredicateHolder = 90;
+         
+         /** Type: product license. */
+         public const byte TypeProductLicense = 78;
+ 
+         /** Type: message filter holder. */
+         public const byte TypeMessageListenerHolder = 92;
+ 
+         /** Type: message filter holder. */
+         public const byte TypePortableOrSerializableHolder = 93;
+ 
+         /** Type: stream receiver holder. */
+         public const byte TypeStreamReceiverHolder = 94;
+ 
+         /** Collection: custom. */
+         public const byte CollectionCustom = 0;
+ 
+         /** Collection: array list. */
+         public const byte CollectionArrayList = 1;
+ 
+         /** Collection: linked list. */
+         public const byte CollectionLinkedList = 2;
+ 
+         /** Collection: hash set. */
+         public const byte CollectionHashSet = 3;
+ 
+         /** Collection: hash set. */
+         public const byte CollectionLinkedHashSet = 4;
+ 
+         /** Collection: sorted set. */
+         public const byte CollectionSortedSet = 5;
+ 
+         /** Collection: concurrent bag. */
+         public const byte CollectionConcurrentBag = 6;
+ 
+         /** Map: custom. */
+         public const byte MapCustom = 0;
+ 
+         /** Map: hash map. */
+         public const byte MapHashMap = 1;
+ 
+         /** Map: linked hash map. */
+         public const byte MapLinkedHashMap = 2;
+ 
+         /** Map: sorted map. */
+         public const byte MapSortedMap = 3;
+ 
+         /** Map: concurrent hash map. */
+         public const byte MapConcurrentHashMap = 4;
+ 
+         /** Byte "0". */
+         public const byte ByteZero = 0;
+ 
+         /** Byte "1". */
+         public const byte ByteOne = 1;
+ 
+         /** 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;
+ 
+         /** Int type. */
+         public static readonly Type TypInt = typeof(int);
+ 
+         /** Collection type. */
+         public static readonly Type TypCollection = typeof(ICollection);
+ 
+         /** Dictionary type. */
+         public static readonly Type TypDictionary = typeof(IDictionary);
+ 
+         /** Generic collection type. */
+         public static readonly Type TypGenericCollection = typeof(ICollection<>);
+ 
+         /** Generic dictionary type. */
+         public static readonly Type TypGenericDictionary = typeof(IDictionary<,>);
+ 
+         /** Ticks for Java epoch. */
+         private static readonly long JavaDateTicks = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).Ticks;
+         
+         /** Bindig flags for static search. */
+         private static BindingFlags _bindFlagsStatic = 
+             BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
+ 
+         /** Default poratble marshaller. */
+         private static readonly PortableMarshaller Marsh = new PortableMarshaller(null);
+ 
+         /** Method: WriteGenericCollection. */
+         public static readonly MethodInfo MtdhWriteGenericCollection =
+             typeof(PortableUtils).GetMethod("WriteGenericCollection", _bindFlagsStatic);
+ 
+         /** Method: ReadGenericCollection. */
+         public static readonly MethodInfo MtdhReadGenericCollection =
+             typeof(PortableUtils).GetMethod("ReadGenericCollection", _bindFlagsStatic);
+ 
+         /** Method: WriteGenericDictionary. */
+         public static readonly MethodInfo MtdhWriteGenericDictionary =
+             typeof(PortableUtils).GetMethod("WriteGenericDictionary", _bindFlagsStatic);
+ 
+         /** Method: ReadGenericDictionary. */
+         public static readonly MethodInfo MtdhReadGenericDictionary =
+             typeof(PortableUtils).GetMethod("ReadGenericDictionary", _bindFlagsStatic);
+ 
+         /** Method: ReadGenericArray. */
+         public static readonly MethodInfo MtdhReadGenericArray =
+             typeof(PortableUtils).GetMethod("ReadGenericArray", _bindFlagsStatic);
+ 
+         /** Cached UTF8 encoding. */
+         private static readonly Encoding Utf8 = Encoding.UTF8;
+ 
+         /** Cached generic array read funcs. */
+         private static readonly CopyOnWriteConcurrentDictionary<Type, Func<PortableReaderImpl, bool, object>>
+             ArrayReaders = new CopyOnWriteConcurrentDictionary<Type, Func<PortableReaderImpl, bool, object>>();
+ 
+         /// <summary>
+         /// Default marshaller.
+         /// </summary>
+         public static PortableMarshaller Marshaller
+         {
+             get { return Marsh; }
+         }
+ 
+         /**
+          * <summary>Write boolean array.</summary>
+          * <param name="vals">Value.</param>
+          * <param name="stream">Output stream.</param>
+          */
+         public static void WriteBooleanArray(bool[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             stream.WriteBoolArray(vals);
+         }
+ 
+         /**
+          * <summary>Read boolean array.</summary>
+          * <param name="stream">Output stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static bool[] ReadBooleanArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             return stream.ReadBoolArray(len);
+         }
+ 
+         /**
+          * <summary>Write byte array.</summary>
+          * <param name="vals">Value.</param>
+          * <param name="stream">Output stream.</param>
+          * <returns>Length of written data.</returns>
+          */
+         public static void WriteByteArray(byte[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             stream.WriteByteArray(vals);
+         }
+ 
+         /**
+          * <summary>Read byte array.</summary>
+          * <param name="stream">Output stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static byte[] ReadByteArray(IPortableStream stream)
+         {
+             return stream.ReadByteArray(stream.ReadInt());
+         }
+ 
+         /**
+          * <summary>Read byte array.</summary>
+          * <param name="stream">Output stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static unsafe sbyte[] ReadSbyteArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             sbyte[] res = new sbyte[len];
+ 
+             fixed (sbyte* res0 = res)
+             {
+                 stream.Read((byte*) res0, len);
+             }
+ 
+             return res;
+         }
+ 
+         /**
+          * <summary>Read byte array.</summary>
+          * <param name="data">Data.</param>
+          * <param name="pos">Position.</param>
+          * <returns>Value.</returns>
+          */
+         public static byte[] ReadByteArray(byte[] data, int pos) {
+             int len = ReadInt(data, pos);
+ 
+             pos += 4;
+ 
+             byte[] res = new byte[len];
+ 
+             Buffer.BlockCopy(data, pos, res, 0, len);
+ 
+             return res;
+         }
+ 
+         /**
+          * <summary>Write short array.</summary>
+          * <param name="vals">Value.</param>
+          * <param name="stream">Output stream.</param>
+          */
+         public static void WriteShortArray(short[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             stream.WriteShortArray(vals);
+         }
+ 
+         /**
+          * <summary>Read short array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static unsafe ushort[] ReadUshortArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             ushort[] res = new ushort[len];
+ 
+             fixed (ushort* res0 = res)
+             {
+                 stream.Read((byte*) res0, len * 2);
+             }
+ 
+             return res;
+         }
+ 
+         /**
+          * <summary>Read short array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static short[] ReadShortArray(IPortableStream stream)
+         {
+             return stream.ReadShortArray(stream.ReadInt());
+         }
+ 
+         /**
+          * <summary>Read int value.</summary>
+          * <param name="data">Data array.</param>
+          * <param name="pos">Position.</param>
+          * <returns>Value.</returns>
+          */
+         public static int ReadInt(byte[] data, int pos) {
+             int val = data[pos];
+ 
+             val |= data[pos + 1] << 8;
+             val |= data[pos + 2] << 16;
+             val |= data[pos + 3] << 24;
+ 
+             return val;
+         }
+ 
+         /**
+          * <summary>Read long value.</summary>
+          * <param name="data">Data array.</param>
+          * <param name="pos">Position.</param>
+          * <returns>Value.</returns>
+          */
+         public static long ReadLong(byte[] data, int pos) {
+             long val = (long)(data[pos]) << 0;
+ 
+             val |= (long)(data[pos + 1]) << 8;
+             val |= (long)(data[pos + 2]) << 16;
+             val |= (long)(data[pos + 3]) << 24;
+             val |= (long)(data[pos + 4]) << 32;
+             val |= (long)(data[pos + 5]) << 40;
+             val |= (long)(data[pos + 6]) << 48;
+             val |= (long)(data[pos + 7]) << 56;
+ 
+             return val;
+         }
+ 
+         /**
+          * <summary>Write int array.</summary>
+          * <param name="vals">Value.</param>
+          * <param name="stream">Output stream.</param>
+          */
+         public static void WriteIntArray(int[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             stream.WriteIntArray(vals);
+         }
+ 
+         /**
+          * <summary>Read int array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static int[] ReadIntArray(IPortableStream stream)
+         {
+             return stream.ReadIntArray(stream.ReadInt());
+         }
+ 
+         /**
+          * <summary>Read int array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static unsafe uint[] ReadUintArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             uint[] res = new uint[len];
+ 
+             fixed (uint* res0 = res)
+             {
+                 stream.Read((byte*) res0, len * 4);
+             }
+ 
+             return res;
+         }
+ 
+         /**
+          * <summary>Write long array.</summary>
+          * <param name="vals">Value.</param>
+          * <param name="stream">Output stream.</param>
+          */
+         public static void WriteLongArray(long[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             stream.WriteLongArray(vals);
+         }
+ 
+         /**
+          * <summary>Read long array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static long[] ReadLongArray(IPortableStream stream)
+         {
+             return stream.ReadLongArray(stream.ReadInt());
+         }
+ 
+         /**
+          * <summary>Read ulong array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static unsafe ulong[] ReadUlongArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             ulong[] res = new ulong[len];
+ 
+             fixed (ulong* res0 = res)
+             {
+                 stream.Read((byte*) res0, len * 8);
+             }
+ 
+             return res;
+         }
+ 
+         /**
+          * <summary>Write char array.</summary>
+          * <param name="vals">Value.</param>
+          * <param name="stream">Output stream.</param>
+          */
+         public static void WriteCharArray(char[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             stream.WriteCharArray(vals);
+         }
+ 
+         /**
+          * <summary>Read char array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static char[] ReadCharArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             return stream.ReadCharArray(len);
+         }
+ 
+         /**
+          * <summary>Write float array.</summary>
+          * <param name="vals">Value.</param>
+          * <param name="stream">Output stream.</param>
+          */
+         public static void WriteFloatArray(float[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             stream.WriteFloatArray(vals);
+         }
+ 
+         /**
+          * <summary>Read float array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static float[] ReadFloatArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             return stream.ReadFloatArray(len);
+         }
+ 
+         /**
+          * <summary>Write double array.</summary>
+          * <param name="vals">Value.</param>
+          * <param name="stream">Output stream.</param>
+          */
+         public static void WriteDoubleArray(double[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             stream.WriteDoubleArray(vals);
+         }
+ 
+         /**
+          * <summary>Read double array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Value.</returns>
+          */
+         public static double[] ReadDoubleArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             return stream.ReadDoubleArray(len);
+         }
+ 
+         /**
+          * <summary>Write date.</summary>
+          * <param name="val">Date.</param>
+          * <param name="stream">Stream.</param>
+          */
+         public static void WriteDate(DateTime val, IPortableStream stream)
+         {
+             long high;
+             int low;
+ 
+             ToJavaDate(val, out high, out low);
+ 
+             stream.WriteLong(high);
+             stream.WriteInt(low);
+         }
+ 
+         /**
+          * <summary>Read date.</summary>
+          * <param name="stream">Stream.</param>
+          * <param name="local">Local flag.</param>
+          * <returns>Date</returns>
+          */
+         public static DateTime? ReadDate(IPortableStream stream, bool local)
+         {
+             long high = stream.ReadLong();
+             int low = stream.ReadInt();
+ 
+             return ToDotNetDate(high, low, local);
+         }
+ 
+         /// <summary>
+         /// Write date array.
+         /// </summary>
+         /// <param name="vals">Values.</param>
+         /// <param name="stream">Stream.</param>
+         public static void WriteDateArray(DateTime[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             foreach (DateTime val in vals)
+             {
+                 stream.WriteByte(TypeDate);
+ 
+                 WriteDate(val, stream);
+             }
+         }
+ 
+         /// <summary>
+         /// Write nullable date array.
+         /// </summary>
+         /// <param name="vals">Values.</param>
+         /// <param name="stream">Stream.</param>
+         public static void WriteDateArray(DateTime?[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             foreach (DateTime? val in vals)
+             {
+                 if (val.HasValue)
+                 {
+                     stream.WriteByte(TypeDate);
+ 
+                     WriteDate(val.Value, stream);
+                 }
+                 else
+                     stream.WriteByte(HdrNull);
+             }
+         }
+         
+         /**
+          * <summary>Write string in UTF8 encoding.</summary>
+          * <param name="val">String.</param>
+          * <param name="stream">Stream.</param>
+          */
+         public static unsafe void WriteString(string val, IPortableStream stream)
+         {
+             stream.WriteBool(true);
+ 
+             int charCnt = val.Length;
+ 
+             fixed (char* chars = val)
+             {
+                 int byteCnt = Utf8.GetByteCount(chars, charCnt);
+ 
+                 stream.WriteInt(byteCnt);
+ 
+                 stream.WriteString(chars, charCnt, byteCnt, Utf8);
+             }
+         }
+ 
+         /**
+          * <summary>Read string in UTF8 encoding.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>String.</returns>
+          */
+         public static string ReadString(IPortableStream stream)
+         {
+             if (stream.ReadBool())
+             {
+                 byte[] bytes = ReadByteArray(stream);
+ 
+                 return bytes != null ? Utf8.GetString(bytes) : null;
+             }
+             
+             char[] chars = ReadCharArray(stream);
+ 
+             return new string(chars);
+         }
+ 
+         /**
+          * <summary>Write string array in UTF8 encoding.</summary>
+          * <param name="vals">String array.</param>
+          * <param name="stream">Stream.</param>
+          */
+         public static void WriteStringArray(string[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             foreach (string val in vals)
+             {
+                 if (val != null)
+                 {
+                     stream.WriteByte(TypeString);
+                     WriteString(val, stream);
+                 }
+                 else
+                     stream.WriteByte(HdrNull);
+             }
+         }
+ 
+         /**
+          * <summary>Read string array in UTF8 encoding.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>String array.</returns>
+          */
+         public static string[] ReadStringArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             string[] vals = new string[len];
+ 
+             for (int i = 0; i < len; i++)
+                 vals[i] = ReadString(stream);
+ 
+             return vals;
+         }
+ 
+         /**
+          * <summary>Write decimal value.</summary>
+          * <param name="val">Decimal value.</param>
+          * <param name="stream">Stream.</param>
+          */
+         public static void WriteDecimal(decimal val, IPortableStream stream) 
+         {
+             // Vals are:
+             // [0] = lo
+             // [1] = mid
+             // [2] = high
+             // [3] = flags
+             int[] vals = decimal.GetBits(val);
+             
+             // Get start index skipping leading zeros.
+             int idx = vals[2] != 0 ? 2 : vals[1] != 0 ? 1 : vals[0] != 0 ? 0 : -1;
+                         
+             // Write scale and negative flag.
+             int scale = (vals[3] & 0x00FF0000) >> 16; 
+ 
+             stream.WriteInt(((vals[3] & 0x80000000) == 0x80000000) ? (int)((uint)scale | 0x80000000) : scale);
+ 
+             if (idx == -1)
+             {
+                 // Writing zero.
+                 stream.WriteInt(1);
+                 stream.WriteByte(0);
+             }
+             else
+             {
+                 int len = (idx + 1) << 2;
+                 
+                 // Write data.
+                 for (int i = idx; i >= 0; i--)
+                 {
+                     int curPart = vals[i];
+ 
+                     int part24 = (curPart >> 24) & 0xFF;
+                     int part16 = (curPart >> 16) & 0xFF;
+                     int part8 = (curPart >> 8) & 0xFF;
+                     int part0 = curPart & 0xFF;
+                     
+                     if (i == idx)
+                     {
+                         // Possibly skipping some values here.
+                         if (part24 != 0)
+                         {
+                             if ((part24 & 0x80) == 0x80)
+                             {
+                                 stream.WriteInt(len + 1);
+ 
+                                 stream.WriteByte(ByteZero);
+                             }
+                             else
+                                 stream.WriteInt(len);
+ 
+                             stream.WriteByte((byte)part24);
+                             stream.WriteByte((byte)part16);
+                             stream.WriteByte((byte)part8);
+                             stream.WriteByte((byte)part0);
+                         }
+                         else if (part16 != 0)
+                         {
+                             if ((part16 & 0x80) == 0x80)
+                             {
+                                 stream.WriteInt(len);
+ 
+                                 stream.WriteByte(ByteZero);
+                             }
+                             else
+                                 stream.WriteInt(len - 1);
+ 
+                             stream.WriteByte((byte)part16);
+                             stream.WriteByte((byte)part8);
+                             stream.WriteByte((byte)part0);
+                         }
+                         else if (part8 != 0)
+                         {
+                             if ((part8 & 0x80) == 0x80)
+                             {
+                                 stream.WriteInt(len - 1);
+ 
+                                 stream.WriteByte(ByteZero);
+                             }
+                             else
+                                 stream.WriteInt(len - 2);
+ 
+                             stream.WriteByte((byte)part8);
+                             stream.WriteByte((byte)part0);
+                         }
+                         else
+                         {
+                             if ((part0 & 0x80) == 0x80)
+                             {
+                                 stream.WriteInt(len - 2);
+ 
+                                 stream.WriteByte(ByteZero);
+                             }
+                             else
+                                 stream.WriteInt(len - 3);
+ 
+                             stream.WriteByte((byte)part0);
+                         }
+                     }
+                     else
+                     {
+                         stream.WriteByte((byte)part24);
+                         stream.WriteByte((byte)part16);
+                         stream.WriteByte((byte)part8);
+                         stream.WriteByte((byte)part0);
+                     }
+                 }
+             }
+         }
+ 
+         /**
+          * <summary>Read decimal value.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Decimal value.</returns>
+          */
+         public static decimal? ReadDecimal(IPortableStream stream)
+         {
+             int scale = stream.ReadInt();
+ 
+             bool neg;
+ 
+             if (scale < 0)
+             {
+                 scale = scale & 0x7FFFFFFF;
+ 
+                 neg = true;
+             }
+             else
+                 neg = false;
+ 
+             byte[] mag = ReadByteArray(stream);
+ 
+             if (scale < 0 || scale > 28)
+                 throw new PortableException("Decimal value scale overflow (must be between 0 and 28): " + scale);
+ 
+             if (mag.Length > 13)
+                 throw new PortableException("Decimal magnitude overflow (must be less than 96 bits): " + 
+                     mag.Length * 8);
+ 
+             if (mag.Length == 13 && mag[0] != 0)
+                 throw new PortableException("Decimal magnitude overflow (must be less than 96 bits): " +
+                         mag.Length * 8);
+ 
+             int hi = 0;
+             int mid = 0;
+             int lo = 0;
+ 
+             int ctr = -1;
+ 
+             for (int i = mag.Length - 12; i < mag.Length; i++)
+             {
+                 if (++ctr == 4)
+                 {
+                     mid = lo;
+                     lo = 0;
+                 }
+                 else if (ctr == 8)
+                 {
+                     hi = mid;
+                     mid = lo;
+                     lo = 0;
+                 }
+ 
+                 if (i >= 0)
+                     lo = (lo << 8) + mag[i];
+             }
+ 
+             return new decimal(lo, mid, hi, neg, (byte)scale);
+         }
+ 
+         /**
+          * <summary>Write decimal array.</summary>
+          * <param name="vals">Decimal array.</param>
+          * <param name="stream">Stream.</param>
+          */
+         public static void WriteDecimalArray(decimal?[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             foreach (var val in vals)
+             {
+                 if (val.HasValue)
+                 {
+                     stream.WriteByte(TypeDecimal);
+ 
+                     WriteDecimal(val.Value, stream);
+                 }
+                 else
+                     stream.WriteByte(HdrNull);
+             }
+         }
+ 
+         /**
+          * <summary>Read decimal array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>Decimal array.</returns>
+          */
+         public static decimal?[] ReadDecimalArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             var vals = new decimal?[len];
+ 
+             for (int i = 0; i < len; i++)
+                 vals[i] = stream.ReadByte() == HdrNull ? (decimal?) null : ReadDecimal(stream);
+ 
+             return vals;
+         }
+ 
+         /**
+          * <summary>Write GUID.</summary>
+          * <param name="val">GUID.</param>
+          * <param name="stream">Stream.</param>
+          */
+         public static unsafe void WriteGuid(Guid val, IPortableStream stream)
+         {
+             var jguid = new JavaGuid(val);
+ 
+             var ptr = &jguid;
+ 
+             stream.Write((byte*) ptr, 16);
+         }
+         
+         /**
+          * <summary>Read GUID.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>GUID</returns>
+          */
+         public static unsafe Guid? ReadGuid(IPortableStream stream)
+         {
+             JavaGuid jguid;
+ 
+             var ptr = (byte*) &jguid;
+ 
+             stream.Read(ptr, 16);
+ 
+             var dotnetGuid = new GuidAccessor(jguid);
+ 
+             return *(Guid*) (&dotnetGuid);
+         }
+ 
+         /// <summary>
+         /// Write GUID array.
+         /// </summary>
+         /// <param name="vals">Values.</param>
+         /// <param name="stream">Stream.</param>
+         public static void WriteGuidArray(Guid[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             foreach (Guid val in vals)
+             {
+                 stream.WriteByte(TypeGuid);
+ 
+                 WriteGuid(val, stream);
+             }
+         }
+ 
+         /// <summary>
+         /// Write GUID array.
+         /// </summary>
+         /// <param name="vals">Values.</param>
+         /// <param name="stream">Stream.</param>
+         public static void WriteGuidArray(Guid?[] vals, IPortableStream stream)
+         {
+             stream.WriteInt(vals.Length);
+ 
+             foreach (Guid? val in vals)
+             {
+                 if (val.HasValue)
+                 {
+                     stream.WriteByte(TypeGuid);
+ 
+                     WriteGuid(val.Value, stream);
+                 }
+                 else
+                     stream.WriteByte(HdrNull);
+             }
+         }
+ 
+         /**
+          * <summary>Read GUID array.</summary>
+          * <param name="stream">Stream.</param>
+          * <returns>GUID array.</returns>
+          */
+         public static Guid?[] ReadGuidArray(IPortableStream stream)
+         {
+             int len = stream.ReadInt();
+ 
+             Guid?[] vals = new Guid?[len];
+ 
+             for (int i = 0; i < len; i++)
+                 vals[i] = ReadGuid(stream);
+ 
+             return vals;
+         }
+         
+         /// <summary>
+         /// Write array.
+         /// </summary>
+         /// <param name="val">Array.</param>
+         /// <param name="ctx">Write context.</param>
+         /// <param name="typed">Typed flag.</param>
+         public static void WriteArray(Array val, PortableWriterImpl ctx, bool typed)
+         {
+             IPortableStream stream = ctx.Stream;
+ 
+             if (typed)
+                 stream.WriteInt(ObjTypeId);
+ 
+             stream.WriteInt(val.Length);
+ 
+             for (int i = 0; i < val.Length; i++)
+                 ctx.Write(val.GetValue(i));
+         }
+ 
+         /// <summary>
+         /// Read array.
+         /// </summary>
+         /// <param name="ctx">Read context.</param>
+         /// <param name="typed">Typed flag.</param>
+         /// <param name="elementType">Type of the element.</param>
+         /// <returns>Array.</returns>
+         public static object ReadArray(PortableReaderImpl ctx, bool typed, Type elementType)
+         {
+             Func<PortableReaderImpl, bool, object> result;
+ 
+             if (!ArrayReaders.TryGetValue(elementType, out result))
+                 result = ArrayReaders.GetOrAdd(elementType, t =>
+                     DelegateConverter.CompileFunc<Func<PortableReaderImpl, bool, object>>(null,
+                         MtdhReadGenericArray.MakeGenericMethod(t),
+                         new[] {typeof (PortableReaderImpl), typeof (bool)}, new[] {false, false, true}));
+ 
+             return result(ctx, typed);
+         }
+ 
+         /// <summary>
+         /// Read array.
+         /// </summary>
+         /// <param name="ctx">Read context.</param>
+         /// <param name="typed">Typed flag.</param>
+         /// <returns>Array.</returns>
+         public static T[] ReadGenericArray<T>(PortableReaderImpl ctx, bool typed)
+         {
+             IPortableStream stream = ctx.Stream;
+ 
+             if (typed)
+                 stream.ReadInt();
+ 
+             int len = stream.ReadInt();
+ 
+             var vals = new T[len];
+ 
+             for (int i = 0; i < len; i++)
+                 vals[i] = ctx.Deserialize<T>();
+ 
+             return vals;
+         }
+ 
+         /**
+          * <summary>Read DateTime array.</summary>
+          * <param name="stream">Stream.</param>
+          * <param name="local">Local flag.</param>
+          * <returns>Array.</returns>
+          */
+         public static DateTime?[] ReadDateArray(IPortableStream stream, bool local)
+         {
+             int len = stream.ReadInt();
+ 
+             DateTime?[] vals = new DateTime?[len];
+ 
+             for (int i = 0; i < len; i++)
+                 vals[i] = stream.ReadByte() == HdrNull ? null : ReadDate(stream, local);
+ 
+             return vals;
+         }
+ 
+         /**
+          * <summary>Write collection.</summary>
+          * <param name="val">Value.</param>
+          * <param name="ctx">Write context.</param>
+          */
+         public static void WriteCollection(ICollection val, PortableWriterImpl ctx)
+         {
+             byte colType = val.GetType() == typeof(ArrayList) ? CollectionArrayList : CollectionCustom;
+ 
+             WriteTypedCollection(val, ctx, colType);
+         }
+ 
+         /**
+          * <summary>Write non-null collection with known type.</summary>
+          * <param name="val">Value.</param>
+          * <param name="ctx">Write context.</param>
+          * <param name="colType">Collection type.</param>
+          */
+         public static void WriteTypedCollection(ICollection val, PortableWriterImpl ctx, byte colType)
+         {
+             ctx.Stream.WriteInt(val.Count);
+ 
+             ctx.Stream.WriteByte(colType);
+ 
+             foreach (object elem in val)
+                 ctx.Write(elem);
+         }
+ 
+         /**
+          * <summary>Read collection.</summary>
+          * <param name="ctx">Context.</param>
+          * <param name="factory">Factory delegate.</param>
+          * <param name="adder">Adder delegate.</param>
+          * <returns>Collection.</returns>
+          */
+         public static ICollection ReadCollection(PortableReaderImpl ctx,
+             PortableCollectionFactory factory, PortableCollectionAdder adder)
+         {
+             if (factory == null)
+                 factory = PortableSystemHandlers.CreateArrayList;
+ 
+             if (adder == null)
+                 adder = PortableSystemHandlers.AddToArrayList;
+ 
+             IPortableStream stream = ctx.Stream;
+ 
+             int len = stream.ReadInt();
+ 
+             ctx.Stream.Seek(1, SeekOrigin.Current);
+ 
+             ICollection res = factory.Invoke(len);
+ 
+             for (int i = 0; i < len; i++)
+                 adder.Invoke(res, ctx.Deserialize<object>());
+ 
+             return res;
+         }
+ 
+         /**
+          * <summary>Write generic collection.</summary>
+          * <param name="val">Value.</param>
+          * <param name="ctx">Write context.</param>
+          */
+         public static void WriteGenericCollection<T>(ICollection<T> val, PortableWriterImpl ctx)
+         {
+             Type type = val.GetType().GetGenericTypeDefinition();
+ 
+             byte colType;
+ 
+             if (type == typeof(List<>))
+                 colType = CollectionArrayList;
+             else if (type == typeof(LinkedList<>))
+                 colType = CollectionLinkedList;
+             else if (type == typeof(HashSet<>))
+                 colType = CollectionHashSet;
+             else if (type == typeof(SortedSet<>))
+                 colType = CollectionSortedSet;
+             else
+                 colType = CollectionCustom;
+ 
+             WriteTypedGenericCollection(val, ctx, colType);
+         }
+ 
+         /**
+          * <summary>Write generic non-null collection with known type.</summary>
+          * <param name="val">Value.</param>
+          * <param name="ctx">Write context.</param>
+          * <param name="colType">Collection type.</param>
+          */
+         public static void WriteTypedGenericCollection<T>(ICollection<T> val, PortableWriterImpl ctx,
+             byte colType)
+         {
+             ctx.Stream.WriteInt(val.Count);
+ 
+             ctx.Stream.WriteByte(colType);
+ 
+             foreach (T elem in val)
+                 ctx.Write(elem);
+         }
+ 
+         /**
+          * <summary>Read generic collection.</summary>
+          * <param name="ctx">Context.</param>
+          * <param name="factory">Factory delegate.</param>
+          * <returns>Collection.</returns>
+          */
+         public static ICollection<T> ReadGenericCollection<T>(PortableReaderImpl ctx,
+             PortableGenericCollectionFactory<T> factory)
+         {
+             int len = ctx.Stream.ReadInt();
+ 
+             if (len >= 0)
+             {
+                 byte colType = ctx.Stream.ReadByte();
+ 
+                 if (factory == null)
+                 {
+                     // Need to detect factory automatically.
+                     if (colType == CollectionLinkedList)
+                         factory = PortableSystemHandlers.CreateLinkedList<T>;
+                     else if (colType == CollectionHashSet)
+                         factory = PortableSystemHandlers.CreateHashSet<T>;
+                     else if (colType == CollectionSortedSet)
+                         factory = PortableSystemHandlers.CreateSortedSet<T>;
+                     else
+                         factory = PortableSystemHandlers.CreateList<T>;
+                 }
+ 
+                 ICollection<T> res = factory.Invoke(len);
+ 
+                 for (int i = 0; i < len; i++)
+                     res.Add(ctx.Deserialize<T>());
+ 
+                 return res;
+             }
+             return null;
+         }
+ 
+         /**
+          * <summary>Write dictionary.</summary>
+          * <param name="val">Value.</param>
+          * <param name="ctx">Write context.</param>
+          */
+         public static void WriteDictionary(IDictionary val, PortableWriterImpl ctx)
+         {
+             byte dictType = val.GetType() == typeof(Hashtable) ? MapHashMap : MapCustom;
+ 
+             WriteTypedDictionary(val, ctx, dictType);
+         }
+ 
+         /**
+          * <summary>Write non-null dictionary with known type.</summary>
+          * <param name="val">Value.</param>
+          * <param name="ctx">Write context.</param>
+          * <param name="dictType">Dictionary type.</param>
+          */
+         public static void WriteTypedDictionary(IDictionary val, PortableWriterImpl ctx, byte dictType)
+         {
+             ctx.Stream.WriteInt(val.Count);
+ 
+             ctx.Stream.WriteByte(dictType);
+ 
+             foreach (DictionaryEntry entry in val)
+             {
+                 ctx.Write(entry.Key);
+                 ctx.Write(entry.Value);
+             }
+         }
+ 
+         /**
+          * <summary>Read dictionary.</summary>
+          * <param name="ctx">Context.</param>
+          * <param name="factory">Factory delegate.</param>
+          * <returns>Dictionary.</returns>
+          */
+         public static IDictionary ReadDictionary(PortableReaderImpl ctx,
+             PortableDictionaryFactory factory)
+         {
+             if (factory == null)
+                 factory = PortableSystemHandlers.CreateHashtable;
+ 
+             IPortableStream stream = ctx.Stream;
+ 
+             int len = stream.ReadInt();
+ 
+             ctx.Stream.Seek(1, SeekOrigin.Current);
+ 
+             IDictionary res = factory.Invoke(len);
+ 
+             for (int i = 0; i < len; i++)
+             {
+                 object key = ctx.Deserialize<object>();
+                 object val = ctx.Deserialize<object>();
+ 
+                 res[key] = val;
+             }
+ 
+             return res;
+         }
+ 
+         /**
+          * <summary>Write generic dictionary.</summary>
+          * <param name="val">Value.</param>
+          * <param name="ctx">Write context.</param>
+          */
+         public static void WriteGenericDictionary<TK, TV>(IDictionary<TK, TV> val, PortableWriterImpl ctx)
+         {
+             Type type = val.GetType().GetGenericTypeDefinition();
+ 
+             byte dictType;
+ 
+             if (type == typeof(Dictionary<,>))
+                 dictType = MapHashMap;
+             else if (type == typeof(SortedDictionary<,>))
+                 dictType = MapSortedMap;
+             else if (type == typeof(ConcurrentDictionary<,>))
+                 dictType = MapConcurrentHashMap;
+             else
+                 dictType = MapCustom;
+ 
+             WriteTypedGenericDictionary(val, ctx, dictType);
+         }
+ 
+         /**
+          * <summary>Write generic non-null dictionary with known type.</summary>
+          * <param name="val">Value.</param>
+          * <param name="ctx">Write context.</param>
+          * <param name="dictType">Dictionary type.</param>
+          */
+         public static void WriteTypedGenericDictionary<TK, TV>(IDictionary<TK, TV> val,
+             PortableWriterImpl ctx, byte dictType)
+         {
+             ctx.Stream.WriteInt(val.Count);
+ 
+             ctx.Stream.WriteByte(dictType);
+ 
+             foreach (KeyValuePair<TK, TV> entry in val)
+             {
+                 ctx.Write(entry.Key);
+                 ctx.Write(entry.Value);
+             }
+         }
+ 
+         /**
+          * <summary>Read generic dictionary.</summary>
+          * <param name="ctx">Context.</param>
+          * <param name="factory">Factory delegate.</param>
+          * <returns>Collection.</returns>
+          */
+         public static IDictionary<TK, TV> ReadGenericDictionary<TK, TV>(PortableReaderImpl ctx,
+             PortableGenericDictionaryFactory<TK, TV> factory)
+         {
+             int len = ctx.Stream.ReadInt();
+ 
+             if (len >= 0)
+             {
+                 byte colType = ctx.Stream.ReadByte();
+ 
+                 if (factory == null)
+                 {
+                     if (colType == MapSortedMap)
+                         factory = PortableSystemHandlers.CreateSortedDictionary<TK, TV>;
+                     else if (colType == MapConcurrentHashMap)
+                         factory = PortableSystemHandlers.CreateConcurrentDictionary<TK, TV>;
+                     else
+                         factory = PortableSystemHandlers.CreateDictionary<TK, TV>;
+                 }
+ 
+                 IDictionary<TK, TV> res = factory.Invoke(len);
+ 
+                 for (int i = 0; i < len; i++)
+                 {
+                     TK key = ctx.Deserialize<TK>();
+                     TV val = ctx.Deserialize<TV>();
+ 
+                     res[key] = val;
+                 }
+ 
+                 return res;
+             }
+             return null;
+         }
+ 
+         /**
+          * <summary>Write map entry.</summary>
+          * <param name="ctx">Write context.</param>
+          * <param name="val">Value.</param>
+          */
+         public static void WriteMapEntry(PortableWriterImpl ctx, DictionaryEntry val)
+         {
+             ctx.Write(val.Key);
+             ctx.Write(val.Value);
+         }
+ 
+         /**
+          * <summary>Read map entry.</summary>
+          * <param name="ctx">Context.</param>
+          * <returns>Map entry.</returns>
+          */
+         public static DictionaryEntry ReadMapEntry(PortableReaderImpl ctx)
+         {
+             object key = ctx.Deserialize<object>();
+             object val = ctx.Deserialize<object>();
+ 
+             return new DictionaryEntry(key, val);
+         }
+ 
+         /**
+          * <summary>Write portable object.</summary>
+          * <param name="stream">Stream.</param>
+          * <param name="val">Value.</param>
+          */
+         public static void WritePortable(IPortableStream stream, PortableUserObject val)
+         {
+             WriteByteArray(val.Data, stream);
+ 
+             stream.WriteInt(val.Offset);
+         }
+ 
+         /// <summary>
+         /// Write enum.
+         /// </summary>
+         /// <param name="stream">Stream.</param>
+         /// <param name="val">Value.</param>
+         public static void WriteEnum(IPortableStream stream, Enum val)
+         {
+             if (Enum.GetUnderlyingType(val.GetType()) == TypInt)
+             {
+                 stream.WriteInt(ObjTypeId);
+                 stream.WriteInt((int) (object) val);
+             }
+             else
+                 throw new PortableException("Only Int32 underlying type is supported for enums: " +
+                     val.GetType().Name);
+         }
+ 
+         /// <summary>
+         /// Read enum.
+         /// </summary>
+         /// <param name="stream">Stream.</param>
+         /// <returns>Enumeration.</returns>
+         public static T ReadEnum<T>(IPortableStream stream)
+         {
+             if (!typeof(T).IsEnum || Enum.GetUnderlyingType(typeof(T)) == TypInt)
+             {
+                 stream.ReadInt();
+ 
+                 return TypeCaster<T>.Cast(stream.ReadInt());
+             }
+ 
+             throw new PortableException("Only Int32 underlying type is supported for enums: " +
+                                         typeof (T).Name);
+         }
+ 
+         /**
+          * <summary>Gets type key.</summary>
+          * <param name="userType">User type flag.</param>
+          * <param name="typeId">Type ID.</param>
+          * <returns>Type key.</returns>
+          */
+         public static long TypeKey(bool userType, int typeId)
+         {
+             long res = typeId;
+ 
+             if (userType)
+                 res |= (long)1 << 32;
+ 
+             return res;
+         }
+ 
+         /**
+          * <summary>Get string hash code.</summary>
+          * <param name="val">Value.</param>
+          * <returns>Hash code.</returns>
+          */
+         public static int GetStringHashCode(string val)
+         {
+             if (val == null)
+                 return 0;
+             int hash = 0;
+ 
+             for (int i = 0; i < val.Length; i++)
+             {
+                 char c = val[i];
+ 
+                 if ('A' <= c && c <= 'Z')
+                     c = (char)(c | 0x20);
+ 
+                 hash = 31 * hash + c;
+             }
+ 
+             return hash;
+         }
+ 
+         public static string CleanFieldName(string fieldName)
+         {
+             if (fieldName.StartsWith("<", StringComparison.Ordinal)
+                 && fieldName.EndsWith(">k__BackingField", StringComparison.Ordinal))
+                 return fieldName.Substring(1, fieldName.IndexOf(">", StringComparison.Ordinal) - 1);
+             
+             return fieldName;
+         }
+ 
+         /**
+          * <summary>Check whether this is predefined type.</summary>
+          * <param name="hdr">Header.</param>
+          * <returns>True is this is one of predefined types with special semantics.</returns>
+          */
+         public static bool IsPredefinedType(byte hdr)
+         {
+             switch (hdr)
+             {
+                 case TypeByte:
+                 case TypeShort:
+                 case TypeInt:
+                 case TypeLong:
+                 case TypeFloat:
+                 case TypeDouble:
+                 case TypeChar:
+                 case TypeBool:
+                 case TypeDecimal:
+                 case TypeString:
+                 case TypeGuid:
+                 case TypeDate:
+                 case TypeEnum:
+                 case TypeArrayByte:
+                 case TypeArrayShort:
+                 case TypeArrayInt:
+                 case TypeArrayLong:
+                 case TypeArrayFloat:
+                 case TypeArrayDouble:
+                 case TypeArrayChar:
+                 case TypeArrayBool:
+                 case TypeArrayDecimal:
+                 case TypeArrayString:
+                 case TypeArrayGuid:
+                 case TypeArrayDate:
+                 case TypeArrayEnum:
+                 case TypeArray:
+                 case TypeCollection:
+                 case TypeDictionary:
+                 case TypeMapEntry:
+                 case TypePortable:
+                     return true;
+                 default:
+                     return false;
+             }
+         }
+ 
+         /**
+          * <summary>Convert type name.</summary>
+          * <param name="typeName">Type name.</param>
+          * <param name="converter">Converter.</param>
+          * <returns>Converted name.</returns>
+          */
+         public static string ConvertTypeName(string typeName, IPortableNameMapper converter)
+         {
+             var typeName0 = typeName;
+ 
+             try
+             {
+                 if (converter != null)
+                     typeName = converter.GetTypeName(typeName);
+             }
+             catch (Exception e)
+             {
+                 throw new PortableException("Failed to convert type name due to converter exception " +
+                     "[typeName=" + typeName + ", converter=" + converter + ']', e);
+             }
+ 
+             if (typeName == null)
+                 throw new PortableException("Name converter returned null name for type [typeName=" +
+                     typeName0 + ", converter=" + converter + "]");
+ 
+             return typeName;
+         }
+ 
+         /**
+          * <summary>Convert field name.</summary>
+          * <param name="fieldName">Field name.</param>
+          * <param name="converter">Converter.</param>
+          * <returns>Converted name.</returns>
+          */
+         public static string ConvertFieldName(string fieldName, IPortableNameMapper converter)
+         {
+             var fieldName0 = fieldName;
+ 
+             try
+             {
+                 if (converter != null)
+                     fieldName = converter.GetFieldName(fieldName);
+             }
+             catch (Exception e)
+             {
+                 throw new PortableException("Failed to convert field name due to converter exception " +
+                     "[fieldName=" + fieldName + ", converter=" + converter + ']', e);
+             }
+ 
+             if (fieldName == null)
+                 throw new PortableException("Name converter returned null name for field [fieldName=" +
+                     fieldName0 + ", converter=" + converter + "]");
+ 
+             return fieldName;
+         }
+ 
+         /**
+          * <summary>Extract simple type name.</summary>
+          * <param name="typeName">Type name.</param>
+          * <returns>Simple type name.</returns>
+          */
+         public static string SimpleTypeName(string typeName)
+         {
+             int idx = typeName.LastIndexOf('.');
+ 
+             return idx < 0 ? typeName : typeName.Substring(idx + 1);
+         }
+ 
+         /**
+          * <summary>Resolve type ID.</summary>
+          * <param name="typeName">Type name.</param>
+          * <param name="nameMapper">Name mapper.</param>
+          * <param name="idMapper">ID mapper.</param>
+          */
+         public static int TypeId(string typeName, IPortableNameMapper nameMapper,
+             IPortableIdMapper idMapper)
+         {
+             Debug.Assert(typeName != null);
+ 
+             typeName = ConvertTypeName(typeName, nameMapper);
+ 
+             int id = 0;
+ 
+             if (idMapper != null)
+             {
+                 try
+                 {
+                     id = idMapper.GetTypeId(typeName);
+                 }
+                 catch (Exception e)
+                 {
+                     throw new PortableException("Failed to resolve type ID due to ID mapper exception " +
+                         "[typeName=" + typeName + ", idMapper=" + idMapper + ']', e);
+                 }
+             }
+ 
+             if (id == 0)
+                 id = GetStringHashCode(typeName);
+ 
+             return id;
+         }
+ 
+         /**
+          * <summary>Resolve field ID.</summary>
+          * <param name="typeId">Type ID.</param>
+          * <param name="fieldName">Field name.</param>
+          * <param name="nameMapper">Name mapper.</param>
+          * <param name="idMapper">ID mapper.</param>
+          */
+         public static int FieldId(int typeId, string fieldName, IPortableNameMapper nameMapper,
+             IPortableIdMapper idMapper)
+         {
+             Debug.Assert(typeId != 0);
+             Debug.Assert(fieldName != null);
+ 
+             fieldName = ConvertFieldName(fieldName, nameMapper);
+ 
+             int id = 0;
+ 
+             if (idMapper != null)
+             {
+                 try
+                 {
+                     id = idMapper.GetFieldId(typeId, fieldName);
+                 }
+                 catch (Exception e)
+                 {
+                     throw new PortableException("Failed to resolve field ID due to ID mapper exception " +
+                         "[typeId=" + typeId + ", fieldName=" + fieldName + ", idMapper=" + idMapper + ']', e);
+                 }
+             }
+ 
+             if (id == 0)
+                 id = GetStringHashCode(fieldName);
+ 
+             if (id == 0)
+                 throw new PortableException("Field ID is zero (please provide ID mapper or change field name) " + 
+                     "[typeId=" + typeId + ", fieldName=" + fieldName + ", idMapper=" + idMapper + ']');
+ 
+             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 - 18;
++            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>
+         /// <param name="arr1">Array 1.</param>
+         /// <param name="offset1">Offset 1.</param>
+         /// <param name="len1">Length 1.</param>
+         /// <param name="arr2">Array 2.</param>
+         /// <param name="offset2">Offset 2.</param>
+         /// <param name="len2">Length 2.</param>
+         /// <returns>True if array chunks are equal.</returns>
+         public static bool CompareArrays(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2, int len2)
+         {
+             if (len1 == len2)
+             {
+                 for (int i = 0; i < len1; i++)
+                 {
+                     if (arr1[offset1 + i] != arr2[offset2 + i])
+                         return false;
+                 }
+ 
+                 return true;
+             }
+             return false;
+         }
+ 
+         /// <summary>
+         /// Write object which is not necessary portable.
+         /// </summary>
+         /// <param name="writer">Writer.</param>
+         /// <param name="obj">Object.</param>
+         public static void WritePortableOrSerializable<T>(PortableWriterImpl writer, T obj)
+         {
+             if (writer.IsPortable(obj))
+             {
+                 writer.WriteBoolean(true);
+ 
+                 writer.WriteObject(obj);
+             }
+             else
+             {
+                 writer.WriteBoolean(false);
+ 
+                 WriteSerializable(writer, obj);
+             }
+         }
+ 
+         /// <summary>
+         /// Writes a serializable object.
+         /// </summary>
+         /// <param name="writer">Writer.</param>
+         /// <param name="obj">Object.</param>
+         public static void WriteSerializable<T>(PortableWriterImpl writer, T obj)
+         {
+             new BinaryFormatter().Serialize(new PortableStreamAdapter(writer.Stream), obj);
+         }
+ 
+         /// <summary>
+         /// Read object which is not necessary portable.
+         /// </summary>
+         /// <param name="reader">Reader.</param>
+         /// <returns>Object.</returns>
+         public static T ReadPortableOrSerializable<T>(PortableReaderImpl reader)
+         {
+             return reader.ReadBoolean()
+                 ? reader.ReadObject<T>()
+                 : ReadSerializable<T>(reader);
+         }
+ 
+         /// <summary>
+         /// Reads a serializable object.
+         /// </summary>
+         /// <param name="reader">Reader.</param>
+         /// <returns>Object.</returns>
+         public static T ReadSerializable<T>(PortableReaderImpl reader)
+         {
+             return (T) new BinaryFormatter().Deserialize(new PortableStreamAdapter(reader.Stream), null);
+         }
+ 
+         /// <summary>
+         /// Writes wrapped invocation result.
+         /// </summary>
+         /// <param name="writer">Writer.</param>
+         /// <param name="success">Success flag.</param>
+         /// <param name="res">Result.</param>
+         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
+         public static void WriteWrappedInvocationResult(PortableWriterImpl writer, bool success, object res)
+         {
+             var pos = writer.Stream.Position;
+ 
+             try
+             {
+                 if (success)
+                     writer.WriteBoolean(true);
+                 else
+                 {
+                     writer.WriteBoolean(false); // Call failed.
+                     writer.WriteBoolean(true); // Exception serialized sucessfully.
+                 }
+ 
+                 writer.Write(new PortableResultWrapper(res));
+             }
+             catch (Exception marshErr)
+             {
+                 // Failed to serialize result, fallback to plain string.
+                 writer.Stream.Seek(pos, SeekOrigin.Begin);
+ 
+                 writer.WriteBoolean(false); // Call failed.
+                 writer.WriteBoolean(false); // Cannot serialize result or exception.
+ 
+                 if (success)
+                 {
+                     writer.WriteString("Call completed successfully, but result serialization failed [resultType=" +
+                         res.GetType().Name + ", serializationErrMsg=" + marshErr.Message + ']');
+                 }
+                 else
+                 {
+                     writer.WriteString("Call completed with error, but error serialization failed [errType=" +
+                         res.GetType().Name + ", serializationErrMsg=" + marshErr.Message + ']');
+                 }
+             }
+         }
+         /// <summary>
+         /// Writes invocation result.
+         /// </summary>
+         /// <param name="writer">Writer.</param>
+         /// <param name="success">Success flag.</param>
+         /// <param name="res">Result.</param>
+         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
+         public static void WriteInvocationResult(PortableWriterImpl writer, bool success, object res)
+         {
+             var pos = writer.Stream.Position;
+ 
+             try
+             {
+                 if (success)
+                     writer.WriteBoolean(true);
+                 else
+                 {
+                     writer.WriteBoolean(false); // Call failed.
+                     writer.WriteBoolean(true); // Exception serialized sucessfully.
+                 }
+ 
+                 writer.Write(res);
+             }
+             catch (Exception marshErr)
+             {
+                 // Failed to serialize result, fallback to plain string.
+                 writer.Stream.Seek(pos, SeekOrigin.Begin);
+ 
+                 writer.WriteBoolean(false); // Call failed.
+                 writer.WriteBoolean(false); // Cannot serialize result or exception.
+ 
+                 if (success)
+                 {
+                     writer.WriteString("Call completed successfully, but result serialization failed [resultType=" +
+                         res.GetType().Name + ", serializationErrMsg=" + marshErr.Message + ']');
+                 }
+                 else
+                 {
+                     writer.WriteString("Call completed with error, but error serialization failed [errType=" +
+                         res.GetType().Name + ", serializationErrMsg=" + marshErr.Message + ']');
+                 }
+             }
+         }
+ 
+         /// <summary>
+         /// Reads wrapped invocation result.
+         /// </summary>
+         /// <param name="reader">Reader.</param>
+         /// <param name="err">Error.</param>
+         /// <returns>Result.</returns>
+         public static object ReadWrappedInvocationResult(PortableReaderImpl reader, out object err)
+         {
+             err = null;
+ 
+             if (reader.ReadBoolean())
+                 return reader.ReadObject<PortableResultWrapper>().Result;
+ 
+             if (reader.ReadBoolean())
+                 err = (Exception) reader.ReadObject<PortableResultWrapper>().Result;
+             else
+                 err = ExceptionUtils.GetException(reader.ReadString(), reader.ReadString());
+ 
+             return null;
+         }
+ 
+         /// <summary>
+         /// Reads invocation result.
+         /// </summary>
+         /// <param name="reader">Reader.</param>
+         /// <param name="err">Error.</param>
+         /// <returns>Result.</returns>
+         public static object ReadInvocationResult(PortableReaderImpl reader, out object err)
+         {
+             err = null;
+ 
+             if (reader.ReadBoolean())
+                 return reader.ReadObject<object>();
+ 
+             if (reader.ReadBoolean())
+                 err = reader.ReadObject<object>();
+             else
+                 err = ExceptionUtils.GetException(reader.ReadString(), reader.ReadString());
+ 
+             return null;
+         }
+ 
++        /// <summary>
++        /// Validate protocol version.
++        /// </summary>
++        /// <param name="stream">Stream.</param>
++        public static void ValidateProtocolVersion(IPortableStream stream)
++        {
++            byte ver = stream.ReadByte();
++
++            if (ver != ProtoVer)
++                throw new PortableException("Unsupported protocol version: " + ver);
++        }
++
+         /**
+          * <summary>Convert date to Java ticks.</summary>
+          * <param name="date">Date</param>
+          * <param name="high">High part (milliseconds).</param>
+          * <param name="low">Low part (nanoseconds)</param>
+          */
+         private static void ToJavaDate(DateTime date, out long high, out int low)
+         {
+             long diff = date.ToUniversalTime().Ticks - JavaDateTicks;
+ 
+             high = diff / TimeSpan.TicksPerMillisecond;
+ 
+             low = (int)(diff % TimeSpan.TicksPerMillisecond) * 100; 
+         }
+ 
+         /**
+          * <summary>Convert Java ticks to date.</summary>
+          * <param name="high">High part (milliseconds).</param>
+          * <param name="low">Low part (nanoseconds).</param>
+          * <param name="local">Whether the time should be treaten as local.</param>
+          * <returns>Date.</returns>
+          */
+         private static DateTime ToDotNetDate(long high, int low, bool local)
+         {
+             DateTime res = 
+                 new DateTime(JavaDateTicks + high * TimeSpan.TicksPerMillisecond + low / 100, DateTimeKind.Utc);
+ 
+             return local ? res.ToLocalTime() : res;
+         }
+ 
+         /// <summary>
+         /// Read additional configuration from the stream.
+         /// </summary>
+         /// <param name="reader">Reader.</param>
+         /// <param name="assemblies">Assemblies.</param>
+         /// <param name="cfg">Portable configuration.</param>
+         public static void ReadConfiguration(PortableReaderImpl reader, out ICollection<string> assemblies, out PortableConfiguration cfg)
+         {
+             if (reader.ReadBoolean())
+             {
+                 int assemblyCnt = reader.ReadInt();
+ 
+                 assemblies = new List<string>(assemblyCnt);
+ 
+                 for (int i = 0; i < assemblyCnt; i++)
+                     assemblies.Add(reader.ReadObject<string>());
+             }
+             else
+                 assemblies = null;
+ 
+             if (reader.ReadBoolean())
+             {
+                 cfg = new PortableConfiguration();
+ 
+                 // Read portable types in full form.
+                 if (reader.ReadBoolean())
+                 {
+                     int typesCnt = reader.ReadInt();
+ 
+                     cfg.TypeConfigurations = new List<PortableTypeConfiguration>();
+ 
+                     for (int i = 0; i < typesCnt; i++)
+                     {
+                         PortableTypeConfiguration typCfg = new PortableTypeConfiguration();
+ 
+                         typCfg.AssemblyName = reader.ReadString();
+                         typCfg.TypeName = reader.ReadString();
+                         typCfg.NameMapper = (IPortableNameMapper)CreateInstance(reader.ReadString());
+                         typCfg.IdMapper = (IPortableIdMapper)CreateInstance(reader.ReadString());
+                         typCfg.Serializer = (IPortableSerializer)CreateInstance(reader.ReadString());
+                         typCfg.AffinityKeyFieldName = reader.ReadString();
+                         typCfg.MetadataEnabled = reader.ReadObject<bool?>();
+                         typCfg.KeepDeserialized = reader.ReadObject<bool?>();
+ 
+                         cfg.TypeConfigurations.Add(typCfg);
+                     }
+                 }
+ 
+                 // Read portable types in compact form.
+                 if (reader.ReadBoolean())
+                 {
+                     int typesCnt = reader.ReadInt();
+ 
+                     cfg.Types = new List<string>(typesCnt);
+ 
+                     for (int i = 0; i < typesCnt; i++)
+                         cfg.Types.Add(reader.ReadString());
+                 }
+ 
+                 // Read the rest.
+                 cfg.DefaultNameMapper = (IPortableNameMapper)CreateInstance(reader.ReadString());
+                 cfg.DefaultIdMapper = (IPortableIdMapper)CreateInstance(reader.ReadString());
+                 cfg.DefaultSerializer = (IPortableSerializer)CreateInstance(reader.ReadString());
+                 cfg.DefaultMetadataEnabled = reader.ReadBoolean();
+                 cfg.DefaultKeepDeserialized = reader.ReadBoolean();
+             }
+             else
+                 cfg = null;
+         }
+ 
+         /// <summary>
+         /// Create new instance of specified class.
+         /// </summary>
+         /// <param name="typeName">Name of the type.</param>
+         /// <returns>New Instance.</returns>
+         public static object CreateInstance(string typeName)
+         {
+             if (typeName == null)
+                 return null;
+ 
+             foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
+             {
+                 object instance = assembly.CreateInstance(typeName);
+ 
+                 if (instance != null)
+                     return instance;
+             }
+ 
+             throw new PortableException("Failed to find class: " + typeName);
+         }
+ 
+         /// <summary>
+         /// Reverses the byte order of an unsigned long.
+         /// </summary>
+         private static ulong ReverseByteOrder(ulong l)
+         {
+             // Fastest way would be to use bswap processor instruction.
+             return ((l >> 56) & 0x00000000000000FF) | ((l >> 40) & 0x000000000000FF00) |
+                    ((l >> 24) & 0x0000000000FF0000) | ((l >> 8) & 0x00000000FF000000) |
+                    ((l << 8) & 0x000000FF00000000) | ((l << 24) & 0x0000FF0000000000) |
+                    ((l << 40) & 0x00FF000000000000) | ((l << 56) & 0xFF00000000000000);
+         }
+ 
+         /// <summary>
+         /// Struct with .Net-style Guid memory layout.
+         /// </summary>
+         [StructLayout(LayoutKind.Sequential)]
+         private struct GuidAccessor
+         {
+             public readonly ulong ABC;
+             public readonly ulong DEGHIJK;
+ 
+             /// <summary>
+             /// Initializes a new instance of the <see cref="GuidAccessor"/> struct.
+             /// </summary>
+             /// <param name="val">The value.</param>
+             public GuidAccessor(JavaGuid val)
+             {
+                 var l = val.CBA;
+ 
+                 ABC = ((l >> 32) & 0x00000000FFFFFFFF) | ((l << 48) & 0xFFFF000000000000) |
+                       ((l << 16) & 0x0000FFFF00000000);
+ 
+                 DEGHIJK = ReverseByteOrder(val.KJIHGED);
+             }
+         }
+ 
+         /// <summary>
+         /// Struct with Java-style Guid memory layout.
+         /// </summary>
+         [StructLayout(LayoutKind.Sequential)]
+         private struct JavaGuid
+         {
+             public readonly ulong CBA;
+             public readonly ulong KJIHGED;
+ 
+             /// <summary>
+             /// Initializes a new instance of the <see cref="JavaGuid"/> struct.
+             /// </summary>
+             /// <param name="val">The value.</param>
+             public unsafe JavaGuid(Guid val)
+             {
+                 // .Net returns bytes in the following order: _a(4), _b(2), _c(2), _d, _e, _g, _h, _i, _j, _k.
+                 // And _a, _b and _c are always in little endian format irrespective of system configuration.
+                 // To be compliant with Java we rearrange them as follows: _c, _b_, a_, _k, _j, _i, _h, _g, _e, _d.
+                 var accessor = *((GuidAccessor*)&val);
+ 
+                 var l = accessor.ABC;
+ 
+                 CBA = ((l << 32) & 0xFFFFFFFF00000000) | ((l >> 48) & 0x000000000000FFFF) |
+                       ((l >> 16) & 0x00000000FFFF0000);
+ 
+                 KJIHGED = ReverseByteOrder(accessor.DEGHIJK);
+             }
+         }
+     }
+ }