// Patrik Torstensson\r
//\r
// (C) 2003 Lluis Sanchez Gual\r
-\r
-// FIXME: Implement the missing binary elements\r
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
\r
using System;\r
using System.Runtime.Serialization;\r
using System.Collections;\r
using System.Reflection;\r
using System.Runtime.Remoting.Messaging;\r
+using System.Globalization;\r
\r
namespace System.Runtime.Serialization.Formatters.Binary\r
{\r
\r
object _lastObject = null;\r
long _lastObjectID = 0;\r
- long _rootObjectID = 0;\r
+ long _rootObjectID = 0;
+ byte[] arrayBuffer;
+ int ArrayBufferLength = 4096;\r
\r
class TypeMetadata\r
{\r
ReadRefTypeObjectInstance (reader, out objectId, out value, out info);\r
break;\r
\r
+ case BinaryElement.UntypedRuntimeObject:\r
+ ReadObjectInstance (reader, true, false, out objectId, out value, out info);\r
+ break;\r
+\r
+ case BinaryElement.UntypedExternalObject:\r
+ ReadObjectInstance (reader, false, false, out objectId, out value, out info);\r
+ break;\r
+\r
case BinaryElement.RuntimeObject:\r
- ReadObjectInstance (reader, true, out objectId, out value, out info);\r
+ ReadObjectInstance (reader, true, true, out objectId, out value, out info);\r
break;\r
\r
case BinaryElement.ExternalObject:\r
- ReadObjectInstance (reader, false, out objectId, out value, out info);\r
+ ReadObjectInstance (reader, false, true, out objectId, out value, out info);\r
break;\r
\r
case BinaryElement.String:\r
_registeredAssemblies [id] = assemblyName;\r
}\r
\r
- private void ReadObjectInstance (BinaryReader reader, bool isRuntimeObject, out long objectId, out object value, out SerializationInfo info)\r
+ private void ReadObjectInstance (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo, out long objectId, out object value, out SerializationInfo info)\r
{\r
objectId = (long) reader.ReadUInt32 ();\r
\r
- TypeMetadata metadata = ReadTypeMetadata (reader, isRuntimeObject);\r
+ TypeMetadata metadata = ReadTypeMetadata (reader, isRuntimeObject, hasTypeInfo);\r
ReadObjectContent (reader, metadata, objectId, out value, out info);\r
}\r
\r
private void ReadGenericArray (BinaryReader reader, out long objectId, out object val)\r
{\r
objectId = (long) reader.ReadUInt32 ();\r
- ArrayStructure structure = (ArrayStructure) reader.ReadByte();\r
+ // Array structure
+ reader.ReadByte();\r
\r
int rank = reader.ReadInt32();\r
\r
int length = reader.ReadInt32 ();\r
Type elementType = ReadType (reader, TypeTag.PrimitiveType);\r
\r
- Array array = Array.CreateInstance (elementType, length);\r
- for (int n = 0; n < length; n++)\r
- array.SetValue (ReadPrimitiveTypeValue (reader, elementType), n);\r
+ switch (Type.GetTypeCode (elementType))\r
+ {\r
+ case TypeCode.Boolean: {\r
+ bool[] arr = new bool [length];\r
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadBoolean();\r
+ val = arr;\r
+ break;\r
+ }\r
\r
- val = array;\r
+ case TypeCode.Byte: {\r
+ byte[] arr = new byte [length];\r
+ int pos = 0;\r
+ while (pos < length) {\r
+ int nr = reader.Read (arr, pos, length - pos);\r
+ if (nr == 0) break;\r
+ pos += nr;\r
+ }\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.Char: {\r
+ char[] arr = new char [length];\r
+ int pos = 0;\r
+ while (pos < length) {\r
+ int nr = reader.Read (arr, pos, length - pos);\r
+ if (nr == 0) break;\r
+ pos += nr;\r
+ }\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.DateTime: {\r
+ DateTime[] arr = new DateTime [length];\r
+ for (int n = 0; n < length; n++) arr [n] = new DateTime (reader.ReadInt64());\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.Decimal: {\r
+ Decimal[] arr = new Decimal [length];\r
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadDecimal();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.Double: {\r
+ Double[] arr = new Double [length];
+ if (length > 2)\r
+ BlockRead (reader, arr, 8);
+ else\r
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadDouble();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.Int16: {\r
+ short[] arr = new short [length];\r
+ if (length > 2)\r
+ BlockRead (reader, arr, 2);
+ else
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadInt16();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.Int32: {\r
+ int[] arr = new int [length];\r
+ if (length > 2)\r
+ BlockRead (reader, arr, 4);
+ else
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadInt32();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.Int64: {\r
+ long[] arr = new long [length];
+ if (length > 2)\r
+ BlockRead (reader, arr, 8);
+ else\r
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadInt64();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.SByte: {\r
+ sbyte[] arr = new sbyte [length];\r
+ if (length > 2)\r
+ BlockRead (reader, arr, 1);
+ else\r
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadSByte();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.Single: {\r
+ float[] arr = new float [length];\r
+ if (length > 2)\r
+ BlockRead (reader, arr, 4);
+ else\r
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadSingle();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.UInt16: {\r
+ ushort[] arr = new ushort [length];\r
+ if (length > 2)\r
+ BlockRead (reader, arr, 2);
+ else\r
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt16();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.UInt32: {\r
+ uint[] arr = new uint [length];\r
+ if (length > 2)\r
+ BlockRead (reader, arr, 4);
+ else\r
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt32();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.UInt64: {\r
+ ulong[] arr = new ulong [length];\r
+ if (length > 2)\r
+ BlockRead (reader, arr, 8);
+ else\r
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt64();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ case TypeCode.String: {\r
+ string[] arr = new string [length];\r
+ for (int n = 0; n < length; n++) arr [n] = reader.ReadString();\r
+ val = arr;\r
+ break;\r
+ }\r
+\r
+ default: {\r
+ if (elementType == typeof(TimeSpan)) {\r
+ TimeSpan[] arr = new TimeSpan [length];\r
+ for (int n = 0; n < length; n++) arr [n] = new TimeSpan (reader.ReadInt64 ());\r
+ val = arr;\r
+ }\r
+ else\r
+ throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);\r
+ break;\r
+ }\r
+ } \r
}\r
\r
+ private void BlockRead (BinaryReader reader, Array array, int dataSize)\r
+ {
+ int totalSize = Buffer.ByteLength (array);
+
+ if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
+ arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
+
+ int pos = 0;
+ while (totalSize > 0) {
+ int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
+ int ap = 0;
+ do {
+ int nr = reader.Read (arrayBuffer, ap, size - ap);\r
+ if (nr == 0) break;\r
+ ap += nr;
+ } while (ap < size);
+
+ if (!BitConverter.IsLittleEndian && dataSize > 1)
+ BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
+
+ Buffer.BlockCopy (arrayBuffer, 0, array, pos, size);
+ totalSize -= size;
+ pos += size;
+ }
+ }
+
+\r
private void ReadArrayOfObject (BinaryReader reader, out long objectId, out object array)\r
{\r
ReadSimpleArray (reader, typeof (object), out objectId, out array);\r
val = array;\r
}\r
\r
- private TypeMetadata ReadTypeMetadata (BinaryReader reader, bool isRuntimeObject)\r
+ private TypeMetadata ReadTypeMetadata (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo)\r
{\r
TypeMetadata metadata = new TypeMetadata();\r
\r
Type[] types = new Type[fieldCount];\r
string[] names = new string[fieldCount];\r
\r
- TypeTag[] codes = new TypeTag[fieldCount];\r
-\r
for (int n=0; n<fieldCount; n++)\r
names [n] = reader.ReadString ();\r
\r
- for (int n=0; n<fieldCount; n++)\r
- codes [n] = (TypeTag) reader.ReadByte ();\r
-\r
- for (int n=0; n<fieldCount; n++)\r
- types [n] = ReadType (reader, codes[n]);\r
+ if (hasTypeInfo)\r
+ {\r
+ TypeTag[] codes = new TypeTag[fieldCount];\r
\r
+ for (int n=0; n<fieldCount; n++)\r
+ codes [n] = (TypeTag) reader.ReadByte ();\r
+ \r
+ for (int n=0; n<fieldCount; n++)\r
+ types [n] = ReadType (reader, codes[n]);\r
+ }\r
+ \r
// Gets the type\r
\r
if (!isRuntimeObject) \r
metadata.MemberInfos = new MemberInfo [fieldCount];\r
for (int n=0; n<fieldCount; n++)\r
{\r
- MemberInfo[] members = null;\r
+ FieldInfo field = null;\r
string memberName = names[n];\r
\r
int i = memberName.IndexOf ('+');\r
Type t = metadata.Type.BaseType;\r
while (t != null) {\r
if (t.Name == baseTypeName) {\r
- members = t.GetMember (memberName, MemberTypes.Field | MemberTypes.Property, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
+ field = t.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
break;\r
}\r
else\r
}\r
}\r
else\r
- members = metadata.Type.GetMember (memberName, MemberTypes.Field | MemberTypes.Property, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
+ field = metadata.Type.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
\r
- if (members == null || members.Length == 0) throw new SerializationException ("Field \"" + names[n] + "\" not found in class " + metadata.Type.FullName);\r
- if (members.Length > 1) throw new SerializationException ("There are two public members named \"" + names[n] + "\" in the class hirearchy of " + metadata.Type.FullName);\r
- metadata.MemberInfos [n] = members[0];\r
+ if (field == null) throw new SerializationException ("Field \"" + names[n] + "\" not found in class " + metadata.Type.FullName);\r
+ metadata.MemberInfos [n] = field;\r
+ \r
+ if (!hasTypeInfo) {\r
+ types [n] = field.FieldType;\r
+ }\r
}\r
metadata.MemberNames = null; // Info now in MemberInfos\r
}\r
{\r
string assemblyName = (string)_registeredAssemblies[assemblyId];\r
\r
- if (_binder == null)\r
- {\r
- Assembly assembly = Assembly.Load (assemblyName);\r
- return assembly.GetType (className, true);\r
+ if (_binder != null) {\r
+ Type t = _binder.BindToType (assemblyName, className);\r
+ if (t != null) return t;\r
}\r
- else\r
- return _binder.BindToType (assemblyName, className);\r
+ \r
+ Assembly assembly = Assembly.Load (assemblyName);\r
+ return assembly.GetType (className, true);\r
}\r
\r
public Type ReadType (BinaryReader reader, TypeTag code)\r
return new DateTime (reader.ReadInt64());\r
\r
case TypeCode.Decimal:\r
- return reader.ReadDecimal();\r
+ return Decimal.Parse (reader.ReadString(), CultureInfo.InvariantCulture);\r
\r
case TypeCode.Double:\r
return reader.ReadDouble();\r