diff --git a/src/System.Runtime.Serialization.Formatters/ref/System.Runtime.Serialization.Formatters.cs b/src/System.Runtime.Serialization.Formatters/ref/System.Runtime.Serialization.Formatters.cs
index 7e28f2e27b28..957d8d31e98a 100644
--- a/src/System.Runtime.Serialization.Formatters/ref/System.Runtime.Serialization.Formatters.cs
+++ b/src/System.Runtime.Serialization.Formatters/ref/System.Runtime.Serialization.Formatters.cs
@@ -29,6 +29,12 @@ public SerializableAttribute()
namespace System.Runtime.Serialization
{
+ [System.AttributeUsageAttribute(System.AttributeTargets.Field, Inherited = false)]
+ public sealed partial class OptionalFieldAttribute : System.Attribute
+ {
+ public OptionalFieldAttribute() { }
+ public int VersionAdded { get { return default(int); } set { } }
+ }
[CLSCompliant(false)]
public interface IFormatterConverter
{
@@ -137,3 +143,199 @@ private SerializationInfoEnumerator() { }
public void Reset() { throw null; }
}
}
+namespace System.Runtime.Serialization
+{
+ [System.CLSCompliantAttribute(false)]
+ public abstract partial class Formatter : System.Runtime.Serialization.IFormatter
+ {
+ protected System.Runtime.Serialization.ObjectIDGenerator m_idGenerator;
+ protected System.Collections.Queue m_objectQueue;
+ protected Formatter() { }
+ public abstract System.Runtime.Serialization.SerializationBinder Binder { get; set; }
+ public abstract System.Runtime.Serialization.StreamingContext Context { get; set; }
+ public abstract System.Runtime.Serialization.ISurrogateSelector SurrogateSelector { get; set; }
+ public abstract object Deserialize(System.IO.Stream serializationStream);
+ protected virtual object GetNext(out long objID) { objID = default(long); return default(object); }
+ protected virtual long Schedule(object obj) { return default(long); }
+ public abstract void Serialize(System.IO.Stream serializationStream, object graph);
+ protected abstract void WriteArray(object obj, string name, System.Type memberType);
+ protected abstract void WriteBoolean(bool val, string name);
+ protected abstract void WriteByte(byte val, string name);
+ protected abstract void WriteChar(char val, string name);
+ protected abstract void WriteDateTime(System.DateTime val, string name);
+ protected abstract void WriteDecimal(decimal val, string name);
+ protected abstract void WriteDouble(double val, string name);
+ protected abstract void WriteInt16(short val, string name);
+ protected abstract void WriteInt32(int val, string name);
+ protected abstract void WriteInt64(long val, string name);
+ protected virtual void WriteMember(string memberName, object data) { }
+ protected abstract void WriteObjectRef(object obj, string name, System.Type memberType);
+ [System.CLSCompliantAttribute(false)]
+ protected abstract void WriteSByte(sbyte val, string name);
+ protected abstract void WriteSingle(float val, string name);
+ protected abstract void WriteTimeSpan(System.TimeSpan val, string name);
+ [System.CLSCompliantAttribute(false)]
+ protected abstract void WriteUInt16(ushort val, string name);
+ [System.CLSCompliantAttribute(false)]
+ protected abstract void WriteUInt32(uint val, string name);
+ [System.CLSCompliantAttribute(false)]
+ protected abstract void WriteUInt64(ulong val, string name);
+ protected abstract void WriteValueType(object obj, string name, System.Type memberType);
+ }
+ public partial class FormatterConverter : System.Runtime.Serialization.IFormatterConverter
+ {
+ public FormatterConverter() { }
+ public object Convert(object value, System.Type type) { return default(object); }
+ public object Convert(object value, System.TypeCode typeCode) { return default(object); }
+ public bool ToBoolean(object value) { return default(bool); }
+ public byte ToByte(object value) { return default(byte); }
+ public char ToChar(object value) { return default(char); }
+ public System.DateTime ToDateTime(object value) { return default(System.DateTime); }
+ public decimal ToDecimal(object value) { return default(decimal); }
+ public double ToDouble(object value) { return default(double); }
+ public short ToInt16(object value) { return default(short); }
+ public int ToInt32(object value) { return default(int); }
+ public long ToInt64(object value) { return default(long); }
+ [System.CLSCompliantAttribute(false)]
+ public sbyte ToSByte(object value) { return default(sbyte); }
+ public float ToSingle(object value) { return default(float); }
+ public string ToString(object value) { return default(string); }
+ [System.CLSCompliantAttribute(false)]
+ public ushort ToUInt16(object value) { return default(ushort); }
+ [System.CLSCompliantAttribute(false)]
+ public uint ToUInt32(object value) { return default(uint); }
+ [System.CLSCompliantAttribute(false)]
+ public ulong ToUInt64(object value) { return default(ulong); }
+ }
+ public static partial class FormatterServices
+ {
+ public static void CheckTypeSecurity(System.Type t, System.Runtime.Serialization.Formatters.TypeFilterLevel securityLevel) { }
+ public static object[] GetObjectData(object obj, System.Reflection.MemberInfo[] members) { return default(object[]); }
+ public static object GetSafeUninitializedObject(System.Type type) { return default(object); }
+ public static System.Reflection.MemberInfo[] GetSerializableMembers(System.Type type) { return default(System.Reflection.MemberInfo[]); }
+ public static System.Reflection.MemberInfo[] GetSerializableMembers(System.Type type, System.Runtime.Serialization.StreamingContext context) { return default(System.Reflection.MemberInfo[]); }
+ public static System.Runtime.Serialization.ISerializationSurrogate GetSurrogateForCyclicalReference(System.Runtime.Serialization.ISerializationSurrogate innerSurrogate) { return default(System.Runtime.Serialization.ISerializationSurrogate); }
+ public static System.Type GetTypeFromAssembly(System.Reflection.Assembly assem, string name) { return default(System.Type); }
+ public static object GetUninitializedObject(System.Type type) { return default(object); }
+ public static object PopulateObjectMembers(object obj, System.Reflection.MemberInfo[] members, object[] data) { return default(object); }
+ }
+ public partial interface IFormatter
+ {
+ System.Runtime.Serialization.SerializationBinder Binder { get; set; }
+ System.Runtime.Serialization.StreamingContext Context { get; set; }
+ System.Runtime.Serialization.ISurrogateSelector SurrogateSelector { get; set; }
+ object Deserialize(System.IO.Stream serializationStream);
+ void Serialize(System.IO.Stream serializationStream, object graph);
+ }
+ public partial interface ISerializationSurrogate
+ {
+ void GetObjectData(object obj, System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context);
+ object SetObjectData(object obj, System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.ISurrogateSelector selector);
+ }
+ public partial interface ISurrogateSelector
+ {
+ void ChainSelector(System.Runtime.Serialization.ISurrogateSelector selector);
+ System.Runtime.Serialization.ISurrogateSelector GetNextSelector();
+ System.Runtime.Serialization.ISerializationSurrogate GetSurrogate(System.Type type, System.Runtime.Serialization.StreamingContext context, out System.Runtime.Serialization.ISurrogateSelector selector);
+ }
+ public partial class ObjectIDGenerator
+ {
+ public ObjectIDGenerator() { }
+ public virtual long GetId(object obj, out bool firstTime) { firstTime = default(bool); return default(long); }
+ public virtual long HasId(object obj, out bool firstTime) { firstTime = default(bool); return default(long); }
+ }
+ public partial class ObjectManager
+ {
+ public ObjectManager(System.Runtime.Serialization.ISurrogateSelector selector, System.Runtime.Serialization.StreamingContext context) { }
+ public virtual void DoFixups() { }
+ public virtual object GetObject(long objectID) { return default(object); }
+ public virtual void RaiseDeserializationEvent() { }
+ public void RaiseOnDeserializingEvent(object obj) { }
+ public virtual void RecordArrayElementFixup(long arrayToBeFixed, int index, long objectRequired) { }
+ public virtual void RecordArrayElementFixup(long arrayToBeFixed, int[] indices, long objectRequired) { }
+ public virtual void RecordDelayedFixup(long objectToBeFixed, string memberName, long objectRequired) { }
+ public virtual void RecordFixup(long objectToBeFixed, System.Reflection.MemberInfo member, long objectRequired) { }
+ public virtual void RegisterObject(object obj, long objectID) { }
+ public void RegisterObject(object obj, long objectID, System.Runtime.Serialization.SerializationInfo info) { }
+ public void RegisterObject(object obj, long objectID, System.Runtime.Serialization.SerializationInfo info, long idOfContainingObj, System.Reflection.MemberInfo member) { }
+ public void RegisterObject(object obj, long objectID, System.Runtime.Serialization.SerializationInfo info, long idOfContainingObj, System.Reflection.MemberInfo member, int[] arrayIndex) { }
+ }
+ public abstract partial class SerializationBinder
+ {
+ protected SerializationBinder() { }
+ public virtual void BindToName(System.Type serializedType, out string assemblyName, out string typeName) { assemblyName = default(string); typeName = default(string); }
+ public abstract System.Type BindToType(string assemblyName, string typeName);
+ }
+ public sealed partial class SerializationObjectManager
+ {
+ public SerializationObjectManager(System.Runtime.Serialization.StreamingContext context) { }
+ public void RaiseOnSerializedEvent() { }
+ public void RegisterObject(object obj) { }
+ }
+ public partial class SurrogateSelector : System.Runtime.Serialization.ISurrogateSelector
+ {
+ public SurrogateSelector() { }
+ public virtual void AddSurrogate(System.Type type, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.ISerializationSurrogate surrogate) { }
+ public virtual void ChainSelector(System.Runtime.Serialization.ISurrogateSelector selector) { }
+ public virtual System.Runtime.Serialization.ISurrogateSelector GetNextSelector() { return default(System.Runtime.Serialization.ISurrogateSelector); }
+ public virtual System.Runtime.Serialization.ISerializationSurrogate GetSurrogate(System.Type type, System.Runtime.Serialization.StreamingContext context, out System.Runtime.Serialization.ISurrogateSelector selector) { selector = default(System.Runtime.Serialization.ISurrogateSelector); return default(System.Runtime.Serialization.ISerializationSurrogate); }
+ public virtual void RemoveSurrogate(System.Type type, System.Runtime.Serialization.StreamingContext context) { }
+ }
+} // end of System.Runtime.Serialization
+namespace System.Runtime.Serialization.Formatters
+{
+ public enum FormatterAssemblyStyle
+ {
+ Full = 1,
+ Simple = 0,
+ }
+ public enum FormatterTypeStyle
+ {
+ TypesAlways = 1,
+ TypesWhenNeeded = 0,
+ XsdString = 2,
+ }
+ public partial interface IFieldInfo
+ {
+ string[] FieldNames { get; set; }
+ System.Type[] FieldTypes { get; set; }
+ }
+ public enum TypeFilterLevel
+ {
+ Full = 3,
+ Low = 2,
+ }
+} // end of System.Runtime.Serialization.Formatters
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ public sealed partial class BinaryFormatter : System.Runtime.Serialization.IFormatter
+ {
+ public BinaryFormatter() { }
+ public BinaryFormatter(System.Runtime.Serialization.ISurrogateSelector selector, System.Runtime.Serialization.StreamingContext context) { }
+ public System.Runtime.Serialization.Formatters.FormatterAssemblyStyle AssemblyFormat { get { return default(System.Runtime.Serialization.Formatters.FormatterAssemblyStyle); } set { } }
+ public System.Runtime.Serialization.SerializationBinder Binder { get { return default(System.Runtime.Serialization.SerializationBinder); } set { } }
+ public System.Runtime.Serialization.StreamingContext Context { get { return default(System.Runtime.Serialization.StreamingContext); } set { } }
+ public System.Runtime.Serialization.Formatters.TypeFilterLevel FilterLevel { get { return default(System.Runtime.Serialization.Formatters.TypeFilterLevel); } set { } }
+ public System.Runtime.Serialization.ISurrogateSelector SurrogateSelector { get { return default(System.Runtime.Serialization.ISurrogateSelector); } set { } }
+ public System.Runtime.Serialization.Formatters.FormatterTypeStyle TypeFormat { get { return default(System.Runtime.Serialization.Formatters.FormatterTypeStyle); } set { } }
+ public object Deserialize(System.IO.Stream serializationStream) { return default(object); }
+ public object Deserialize(System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) { return default(object); }
+ public void Serialize(System.IO.Stream serializationStream, object graph) { }
+ public void Serialize(System.IO.Stream serializationStream, object graph, System.Runtime.Remoting.Messaging.Header[] headers) { }
+ public object UnsafeDeserialize(System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) { return default(object); }
+ }
+} // end of System.Runtime.Serialization.Formatters.Binary
+namespace System.Runtime.Remoting.Messaging
+{
+ public partial class Header
+ {
+ public string HeaderNamespace;
+ public bool MustUnderstand;
+ public string Name;
+ public object Value;
+ public Header(string _Name, object _Value) { }
+ public Header(string _Name, object _Value, bool _MustUnderstand) { }
+ public Header(string _Name, object _Value, bool _MustUnderstand, string _HeaderNamespace) { }
+ }
+ public delegate object HeaderHandler(System.Runtime.Remoting.Messaging.Header[] headers);
+}
\ No newline at end of file
diff --git a/src/System.Runtime.Serialization.Formatters/ref/project.json b/src/System.Runtime.Serialization.Formatters/ref/project.json
index 30f6e3acca92..0c3d0845831d 100644
--- a/src/System.Runtime.Serialization.Formatters/ref/project.json
+++ b/src/System.Runtime.Serialization.Formatters/ref/project.json
@@ -1,5 +1,8 @@
{
"dependencies": {
+ "System.Collections.NonGeneric": "4.0.0",
+ "System.IO": "4.0.10",
+ "System.Reflection": "4.1.0",
"System.Runtime": "4.0.20",
"System.Runtime.Extensions": "4.0.10",
"System.Runtime.Serialization.Primitives": "4.1.1"
diff --git a/src/System.Runtime.Serialization.Formatters/src/Resources/Strings.resx b/src/System.Runtime.Serialization.Formatters/src/Resources/Strings.resx
index 859b6cfd9b97..cdffbcec4b46 100644
--- a/src/System.Runtime.Serialization.Formatters/src/Resources/Strings.resx
+++ b/src/System.Runtime.Serialization.Formatters/src/Resources/Strings.resx
@@ -129,4 +129,223 @@
Enumeration has either not started or has already finished.
+
+ Type '{0}' in Assembly '{1}' is not marked as serializable.
+
+
+ Parameters 'members' and 'data' must have the same length.
+
+
+ Parameters 'members' and 'data' must have the same length.
+
+
+ Only FieldInfo, PropertyInfo, and SerializationMemberInfo are recognized.
+
+
+ Object has never been assigned an objectID.
+
+
+ Object cannot be null.
+
+
+ The internal array cannot expand to greater than Int32.MaxValue elements.
+
+
+ The FieldInfo object is not valid.
+
+
+ A fixup is registered to the object with ID {0}, but the object does not appear in the graph.
+
+
+ The object with ID {0} implements the IObjectReference interface for which all dependencies cannot be resolved. The likely cause is two instances of IObjectReference that have a mutual dependency on each other.
+
+
+ The object with ID {0} was referenced in a fixup but does not exist.
+
+
+ {0}.SetObjectData returns a value that is neither null nor equal to the first parameter. Such Surrogates cannot be part of cyclical reference.
+
+
+ The implementation of the IObjectReference interface returns too many nested references to other objects that implement IObjectReference.
+
+
+ The object with ID {0} was referenced in a fixup but has not been registered.
+
+
+ A fixup on an object implementing ISerializable or having a surrogate was discovered for an object which does not have a SerializationInfo available.
+
+
+ Unable to load type {0} required for deserialization.
+
+
+ ValueType fixup on Arrays is not implemented.
+
+
+ Fixing up a partially available ValueType chain is not implemented.
+
+
+ Cannot perform fixup.
+
+
+ objectID cannot be less than or equal to zero.
+
+
+ An object cannot be registered twice.
+
+
+ The given object does not implement the ISerializable interface.
+
+
+ The constructor to deserialize an object of type '{0}' was not found.
+
+
+ The object with ID {0} was referenced in a fixup but does not exist.
+
+
+ Unable to load type {0} required for deserialization.
+
+
+ The ObjectManager found an invalid number of fixups. This usually indicates a problem in the Formatter.
+
+
+ A member fixup was registered for an object which implements ISerializable or has a surrogate. In this situation, a delayed fixup must be used.
+
+
+ Object IDs must be greater than zero.
+
+
+ The ID of the containing object cannot be the same as the object ID.
+
+
+ Only system-provided types can be passed to the GetUninitializedObject method. '{0}' is not a valid instance of a type.
+
+
+ Array must not be of length zero.
+
+
+ When supplying the ID of a containing object, the FieldInfo that identifies the current field within that object must also be supplied.
+
+
+ Cannot supply both a MemberInfo and an Array to indicate the parent of a value type.
+
+
+ Invalid BinaryFormatter stream.
+
+
+ Header reflection error: number of value members: {0}.
+
+
+ Parameter '{0}' cannot be null.
+
+
+ Attempting to deserialize an empty stream.
+
+
+ Binary stream '{0}' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.
+
+
+ Invalid expected type.
+
+
+ End of Stream encountered before parsing was completed.
+
+
+ Cross-AppDomain BinaryFormatter error; expected '{0}' but received '{1}'.
+
+
+ No map for object '{0}'.
+
+
+ No assembly information is available for object on the wire, '{0}'.
+
+
+ Invalid ObjectTypeEnum {0}.
+
+
+ No assembly ID for object type '{0}'.
+
+
+ Invalid ObjectTypeEnum {0}.
+
+
+ Invalid array type '{0}'.
+
+
+ Invalid type code in stream '{0}'.
+
+
+ Invalid write type request '{0}'.
+
+
+ Invalid read type request '{0}'.
+
+
+ Unable to find assembly '{0}'.
+
+
+ The input stream is not a valid binary format. The starting contents (in bytes) are: {0} ...
+
+
+ Stream cannot be null.
+
+
+ No top object.
+
+
+ Invalid element '{0}'.
+
+
+ Top object cannot be instantiated for element '{0}'.
+
+
+ Array element type is Object, 'dt' attribute is null.
+
+
+ Type is missing for member of type Object '{0}'.
+
+
+ Object Graph cannot be null.
+
+
+ Object {0} has never been assigned an objectID.
+
+
+ MemberInfo type {0} cannot be serialized.
+
+
+ When supplying a FieldInfo for fixing up a nested type, a valid ID for that containing object must also be supplied.
+
+
+ Parse error. Current element is not compatible with the next element, {0}.
+
+
+ MemberInfo requested for ISerializable type.
+
+
+ MemberInfo cannot be obtained for ISerialized Object '{0}'.
+
+
+ Types not available for ISerializable object '{0}'.
+
+
+ Member '{0}' in class '{1}' is not present in the serialized stream and is not marked with {2}.
+
+
+ No MemberInfo for Object {0}.
+
+
+ Selector is already on the list of checked selectors.
+
+
+ Type {0} and the types derived from it (such as {1}) are not permitted to be deserialized at this security level.
+
+
+ Selector contained a cycle.
+
+
+ Adding selector will introduce a cycle.
+
+
+ Unable to read beyond the end of the stream.
+
\ No newline at end of file
diff --git a/src/System.Runtime.Serialization.Formatters/src/System.Runtime.Serialization.Formatters.csproj b/src/System.Runtime.Serialization.Formatters/src/System.Runtime.Serialization.Formatters.csproj
index dff3e166d3bf..021342f09eba 100644
--- a/src/System.Runtime.Serialization.Formatters/src/System.Runtime.Serialization.Formatters.csproj
+++ b/src/System.Runtime.Serialization.Formatters/src/System.Runtime.Serialization.Formatters.csproj
@@ -12,18 +12,66 @@
.NETStandard,Version=v1.4
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/NonSerializedAttribute.cs b/src/System.Runtime.Serialization.Formatters/src/System/NonSerializedAttribute.cs
index 0d8e5dacfbea..b65789c14ebe 100644
--- a/src/System.Runtime.Serialization.Formatters/src/System/NonSerializedAttribute.cs
+++ b/src/System.Runtime.Serialization.Formatters/src/System/NonSerializedAttribute.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
namespace System
{
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/DeserializationEventHandler.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/DeserializationEventHandler.cs
new file mode 100644
index 000000000000..2d960a3948c1
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/DeserializationEventHandler.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.Serialization
+{
+ [Serializable]
+ internal delegate void DeserializationEventHandler(object sender);
+
+ [Serializable]
+ internal delegate void SerializationEventHandler(StreamingContext context);
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatter.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatter.cs
new file mode 100644
index 000000000000..3ae49ca5526b
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatter.cs
@@ -0,0 +1,192 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Globalization;
+using System.Collections;
+using System.Reflection;
+
+namespace System.Runtime.Serialization
+{
+ [Serializable]
+ [CLSCompliant(false)]
+ public abstract class Formatter : IFormatter
+ {
+ protected readonly ObjectIDGenerator m_idGenerator;
+ protected readonly Queue m_objectQueue;
+
+ protected Formatter()
+ {
+ m_objectQueue = new Queue();
+ m_idGenerator = new ObjectIDGenerator();
+ }
+
+ public abstract object Deserialize(Stream serializationStream);
+
+ protected virtual object GetNext(out long objID)
+ {
+ if (m_objectQueue.Count == 0)
+ {
+ objID = 0;
+ return null;
+ }
+
+ object obj = m_objectQueue.Dequeue();
+
+ bool isNew;
+ objID = m_idGenerator.HasId(obj, out isNew);
+ if (isNew)
+ {
+ throw new SerializationException(SR.Serialization_NoID);
+ }
+
+ return obj;
+ }
+
+ protected virtual long Schedule(object obj)
+ {
+ if (obj == null)
+ {
+ return 0;
+ }
+
+ bool isNew;
+ long id = m_idGenerator.GetId(obj, out isNew);
+
+ if (isNew)
+ {
+ m_objectQueue.Enqueue(obj);
+ }
+ return id;
+ }
+
+ public abstract void Serialize(Stream serializationStream, object graph);
+
+ protected abstract void WriteArray(object obj, string name, Type memberType);
+
+ protected abstract void WriteBoolean(bool val, string name);
+
+ protected abstract void WriteByte(byte val, string name);
+
+ protected abstract void WriteChar(char val, string name);
+
+ protected abstract void WriteDateTime(DateTime val, string name);
+
+ protected abstract void WriteDecimal(decimal val, string name);
+
+ protected abstract void WriteDouble(double val, string name);
+
+ protected abstract void WriteInt16(short val, string name);
+
+ protected abstract void WriteInt32(int val, string name);
+
+ protected abstract void WriteInt64(long val, string name);
+
+ protected abstract void WriteObjectRef(object obj, string name, Type memberType);
+
+ protected virtual void WriteMember(string memberName, object data)
+ {
+ if (data == null)
+ {
+ WriteObjectRef(data, memberName, typeof(object));
+ return;
+ }
+
+ Type varType = data.GetType();
+
+ if (varType == typeof(bool))
+ {
+ WriteBoolean(Convert.ToBoolean(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(char))
+ {
+ WriteChar(Convert.ToChar(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(sbyte))
+ {
+ WriteSByte(Convert.ToSByte(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(byte))
+ {
+ WriteByte(Convert.ToByte(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(short))
+ {
+ WriteInt16(Convert.ToInt16(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(int))
+ {
+ WriteInt32(Convert.ToInt32(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(long))
+ {
+ WriteInt64(Convert.ToInt64(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(float))
+ {
+ WriteSingle(Convert.ToSingle(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(double))
+ {
+ WriteDouble(Convert.ToDouble(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(DateTime))
+ {
+ WriteDateTime(Convert.ToDateTime(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(decimal))
+ {
+ WriteDecimal(Convert.ToDecimal(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(ushort))
+ {
+ WriteUInt16(Convert.ToUInt16(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(uint))
+ {
+ WriteUInt32(Convert.ToUInt32(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType == typeof(ulong))
+ {
+ WriteUInt64(Convert.ToUInt64(data, CultureInfo.InvariantCulture), memberName);
+ }
+ else if (varType.IsArray)
+ {
+ WriteArray(data, memberName, varType);
+ }
+ else if (varType.GetTypeInfo().IsValueType)
+ {
+ WriteValueType(data, memberName, varType);
+ }
+ else
+ {
+ WriteObjectRef(data, memberName, varType);
+ }
+ }
+
+ [CLSCompliant(false)]
+ protected abstract void WriteSByte(sbyte val, string name);
+
+ protected abstract void WriteSingle(float val, string name);
+
+ protected abstract void WriteTimeSpan(TimeSpan val, string name);
+
+ [CLSCompliant(false)]
+ protected abstract void WriteUInt16(ushort val, string name);
+
+ [CLSCompliant(false)]
+ protected abstract void WriteUInt32(uint val, string name);
+
+ [CLSCompliant(false)]
+ protected abstract void WriteUInt64(ulong val, string name);
+
+ protected abstract void WriteValueType(object obj, string name, Type memberType);
+
+ public abstract ISurrogateSelector SurrogateSelector { get; set; }
+
+ public abstract SerializationBinder Binder { get; set; }
+
+ public abstract StreamingContext Context { get; set; }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/FormatterConverter.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/FormatterConverter.cs
new file mode 100644
index 000000000000..d928b28fce3b
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/FormatterConverter.cs
@@ -0,0 +1,124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Globalization;
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.Serialization
+{
+ public class FormatterConverter : IFormatterConverter
+ {
+ public object Convert(object value, Type type)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
+ }
+
+ public object Convert(object value, TypeCode typeCode)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ChangeType(value, typeCode, CultureInfo.InvariantCulture);
+ }
+
+ public bool ToBoolean(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToBoolean(value, CultureInfo.InvariantCulture);
+ }
+
+ public char ToChar(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToChar(value, CultureInfo.InvariantCulture);
+ }
+
+ [CLSCompliant(false)]
+ public sbyte ToSByte(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToSByte(value, CultureInfo.InvariantCulture);
+ }
+
+ public byte ToByte(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToByte(value, CultureInfo.InvariantCulture);
+ }
+
+ public short ToInt16(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToInt16(value, CultureInfo.InvariantCulture);
+ }
+
+ [CLSCompliant(false)]
+ public ushort ToUInt16(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToUInt16(value, CultureInfo.InvariantCulture);
+ }
+
+ public int ToInt32(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToInt32(value, CultureInfo.InvariantCulture);
+ }
+
+ [CLSCompliant(false)]
+ public uint ToUInt32(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToUInt32(value, CultureInfo.InvariantCulture);
+ }
+
+ public long ToInt64(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToInt64(value, CultureInfo.InvariantCulture);
+ }
+
+ [CLSCompliant(false)]
+ public ulong ToUInt64(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToUInt64(value, CultureInfo.InvariantCulture);
+ }
+
+ public float ToSingle(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToSingle(value, CultureInfo.InvariantCulture);
+ }
+
+ public double ToDouble(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToDouble(value, CultureInfo.InvariantCulture);
+ }
+
+ public decimal ToDecimal(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToDecimal(value, CultureInfo.InvariantCulture);
+ }
+
+ public DateTime ToDateTime(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToDateTime(value, CultureInfo.InvariantCulture);
+ }
+
+ public string ToString(object value)
+ {
+ if (value == null) ThrowValueNullException();
+ return System.Convert.ToString(value, CultureInfo.InvariantCulture);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ThrowValueNullException()
+ {
+ throw new ArgumentNullException("value");
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/FormatterServices.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/FormatterServices.cs
new file mode 100644
index 000000000000..51ecf99a4fe0
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/FormatterServices.cs
@@ -0,0 +1,299 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Reflection;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Globalization;
+using System.Diagnostics;
+using System.Runtime.Serialization.Formatters;
+
+namespace System.Runtime.Serialization
+{
+ public static class FormatterServices
+ {
+ private static readonly ConcurrentDictionary s_memberInfoTable = new ConcurrentDictionary();
+
+ private static FieldInfo[] GetSerializableFields(Type type)
+ {
+ if (type.GetTypeInfo().IsInterface)
+ {
+ return Array.Empty();
+ }
+
+ if (!type.GetTypeInfo().IsSerializable)
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_NonSerType, type.GetTypeInfo().FullName, type.GetTypeInfo().Assembly.FullName));
+ }
+
+ var results = new List();
+ for (Type t = type; t != typeof(object); t = t.GetTypeInfo().BaseType)
+ {
+ foreach (FieldInfo field in t.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
+ {
+ if ((field.Attributes & FieldAttributes.NotSerialized) != FieldAttributes.NotSerialized)
+ {
+ results.Add(field);
+ }
+ }
+ }
+ return results.ToArray();
+ }
+
+ public static MemberInfo[] GetSerializableMembers(Type type)
+ {
+ return GetSerializableMembers(type, new StreamingContext(StreamingContextStates.All));
+ }
+
+ public static MemberInfo[] GetSerializableMembers(Type type, StreamingContext context)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException(nameof(type));
+ }
+
+ // If we've already gathered the members for this type, just return them.
+ // Otherwise, get them and add them.
+ var mh = new MemberHolder(type, context);
+ MemberInfo[] members;
+ if (!s_memberInfoTable.TryGetValue(mh, out members))
+ {
+ members = GetSerializableFields(type);
+ s_memberInfoTable.TryAdd(mh, members);
+ }
+ return members;
+ }
+
+ public static void CheckTypeSecurity(Type t, TypeFilterLevel securityLevel)
+ {
+ // nop
+ }
+
+ // TODO #8133: Fix this to avoid reflection
+ private static readonly Func s_getUninitializedObjectDelegate = (Func)
+ typeof(string).GetTypeInfo().Assembly.GetType("System.Runtime.Serialization.FormatterServices")
+ ?.GetMethod("GetUninitializedObject", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
+ ?.CreateDelegate(typeof(Func));
+
+ public static object GetUninitializedObject(Type type)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException(nameof(type));
+ }
+
+ return s_getUninitializedObjectDelegate(type);
+ }
+
+ public static object GetSafeUninitializedObject(Type type) => GetUninitializedObject(type);
+
+ internal static bool UnsafeTypeForwardersIsEnabled() => true;
+
+ internal static void SerializationSetValue(MemberInfo fi, object target, object value)
+ {
+ Debug.Assert(fi != null);
+
+ var serField = fi as FieldInfo;
+ if (serField != null)
+ {
+ serField.SetValue(target, value);
+ return;
+ }
+
+ throw new ArgumentException(SR.Argument_InvalidFieldInfo);
+ }
+
+ public static object PopulateObjectMembers(object obj, MemberInfo[] members, object[] data)
+ {
+ if (obj == null)
+ {
+ throw new ArgumentNullException(nameof(obj));
+ }
+ if (members == null)
+ {
+ throw new ArgumentNullException(nameof(members));
+ }
+ if (data == null)
+ {
+ throw new ArgumentNullException(nameof(data));
+ }
+ if (members.Length != data.Length)
+ {
+ throw new ArgumentException(SR.Argument_DataLengthDifferent);
+ }
+
+ for (int i = 0; i < members.Length; i++)
+ {
+ MemberInfo member = members[i];
+ if (member == null)
+ {
+ throw new ArgumentNullException(nameof(members), SR.Format(SR.ArgumentNull_NullMember, i));
+ }
+
+ // If we find an empty, it means that the value was never set during deserialization.
+ // This is either a forward reference or a null. In either case, this may break some of the
+ // invariants mantained by the setter, so we'll do nothing with it for right now.
+ object value = data[i];
+ if (value == null)
+ {
+ continue;
+ }
+
+ // If it's a field, set its value.
+ FieldInfo field = member as FieldInfo;
+ if (field != null)
+ {
+ field.SetValue(obj, data[i]);
+ continue;
+ }
+
+ // Otherwise, it's not supported.
+ throw new SerializationException(SR.Serialization_UnknownMemberInfo);
+ }
+
+ return obj;
+ }
+
+ public static object[] GetObjectData(object obj, MemberInfo[] members)
+ {
+ if (obj == null)
+ {
+ throw new ArgumentNullException(nameof(obj));
+ }
+ if (members == null)
+ {
+ throw new ArgumentNullException(nameof(members));
+ }
+
+ object[] data = new object[members.Length];
+ for (int i = 0; i < members.Length; i++)
+ {
+ MemberInfo member = members[i];
+ if (member == null)
+ {
+ throw new ArgumentNullException(nameof(members), SR.Format(SR.ArgumentNull_NullMember, i));
+ }
+
+ FieldInfo field = member as FieldInfo;
+ if (field == null)
+ {
+ throw new SerializationException(SR.Serialization_UnknownMemberInfo);
+ }
+
+ data[i] = field.GetValue(obj);
+ }
+ return data;
+ }
+
+ public static ISerializationSurrogate GetSurrogateForCyclicalReference(ISerializationSurrogate innerSurrogate)
+ {
+ if (innerSurrogate == null)
+ {
+ throw new ArgumentNullException(nameof(innerSurrogate));
+ }
+ return new SurrogateForCyclicalReference(innerSurrogate);
+ }
+
+ public static Type GetTypeFromAssembly(Assembly assem, string name)
+ {
+ if (assem == null)
+ {
+ throw new ArgumentNullException(nameof(assem));
+ }
+ return assem.GetType(name, throwOnError: false, ignoreCase: false);
+ }
+
+ internal static Assembly LoadAssemblyFromString(string assemblyName)
+ {
+ return Assembly.Load(new AssemblyName(assemblyName));
+ }
+
+ internal static Assembly LoadAssemblyFromStringNoThrow(string assemblyName)
+ {
+ try
+ {
+ return LoadAssemblyFromString(assemblyName);
+ }
+ catch (Exception) { }
+ return null;
+ }
+
+ internal static string GetClrAssemblyName(Type type, out bool hasTypeForwardedFrom)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException(nameof(type));
+ }
+
+ foreach (Attribute first in type.GetTypeInfo().GetCustomAttributes(typeof(TypeForwardedFromAttribute), false))
+ {
+ hasTypeForwardedFrom = true;
+ return ((TypeForwardedFromAttribute)first).AssemblyFullName;
+ }
+
+ hasTypeForwardedFrom = false;
+ return type.GetTypeInfo().Assembly.FullName;
+ }
+
+ internal static string GetClrTypeFullName(Type type)
+ {
+ return type.IsArray ?
+ GetClrTypeFullNameForArray(type) :
+ GetClrTypeFullNameForNonArrayTypes(type);
+ }
+
+ private static string GetClrTypeFullNameForArray(Type type)
+ {
+ int rank = type.GetArrayRank();
+ Debug.Assert(rank >= 1);
+ string typeName = GetClrTypeFullName(type.GetElementType());
+ return rank == 1 ?
+ typeName + "[]" :
+ typeName + "[" + new string(',', rank - 1) + "]";
+ }
+
+ private static string GetClrTypeFullNameForNonArrayTypes(Type type)
+ {
+ if (!type.GetTypeInfo().IsGenericType)
+ {
+ return type.FullName;
+ }
+
+ var builder = new StringBuilder(type.GetGenericTypeDefinition().FullName).Append("[");
+
+ bool hasTypeForwardedFrom;
+ foreach (Type genericArgument in type.GetGenericArguments())
+ {
+ builder.Append("[").Append(GetClrTypeFullName(genericArgument)).Append(", ");
+ builder.Append(GetClrAssemblyName(genericArgument, out hasTypeForwardedFrom)).Append("],");
+ }
+
+ //remove the last comma and close typename for generic with a close bracket
+ return builder.Remove(builder.Length - 1, 1).Append("]").ToString();
+ }
+ }
+
+ internal sealed class SurrogateForCyclicalReference : ISerializationSurrogate
+ {
+ private readonly ISerializationSurrogate _innerSurrogate;
+
+ internal SurrogateForCyclicalReference(ISerializationSurrogate innerSurrogate)
+ {
+ Debug.Assert(innerSurrogate != null);
+ _innerSurrogate = innerSurrogate;
+ }
+
+ public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
+ {
+ _innerSurrogate.GetObjectData(obj, info, context);
+ }
+
+ public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
+ {
+ return _innerSurrogate.SetObjectData(obj, info, context, selector);
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryArray.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryArray.cs
new file mode 100644
index 000000000000..1d5e39c43d38
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryArray.cs
@@ -0,0 +1,158 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryArray : IStreamable
+ {
+ internal int _objectId;
+ internal int _rank;
+ internal int[] _lengthA;
+ internal int[] _lowerBoundA;
+ internal BinaryTypeEnum _binaryTypeEnum;
+ internal object _typeInformation;
+ internal int _assemId = 0;
+ private BinaryHeaderEnum _binaryHeaderEnum;
+ internal BinaryArrayTypeEnum _binaryArrayTypeEnum;
+
+ internal BinaryArray() { }
+
+ internal BinaryArray(BinaryHeaderEnum binaryHeaderEnum)
+ {
+ _binaryHeaderEnum = binaryHeaderEnum;
+ }
+
+ internal void Set(int objectId, int rank, int[] lengthA, int[] lowerBoundA, BinaryTypeEnum binaryTypeEnum, object typeInformation, BinaryArrayTypeEnum binaryArrayTypeEnum, int assemId)
+ {
+ _objectId = objectId;
+ _binaryArrayTypeEnum = binaryArrayTypeEnum;
+ _rank = rank;
+ _lengthA = lengthA;
+ _lowerBoundA = lowerBoundA;
+ _binaryTypeEnum = binaryTypeEnum;
+ _typeInformation = typeInformation;
+ _assemId = assemId;
+
+ _binaryHeaderEnum = BinaryHeaderEnum.Array;
+ if (binaryArrayTypeEnum == BinaryArrayTypeEnum.Single)
+ {
+ if (binaryTypeEnum == BinaryTypeEnum.Primitive)
+ {
+ _binaryHeaderEnum = BinaryHeaderEnum.ArraySinglePrimitive;
+ }
+ else if (binaryTypeEnum == BinaryTypeEnum.String)
+ {
+ _binaryHeaderEnum = BinaryHeaderEnum.ArraySingleString;
+ }
+ else if (binaryTypeEnum == BinaryTypeEnum.Object)
+ {
+ _binaryHeaderEnum = BinaryHeaderEnum.ArraySingleObject;
+ }
+ }
+ }
+
+ public void Write(BinaryFormatterWriter output)
+ {
+ switch (_binaryHeaderEnum)
+ {
+ case BinaryHeaderEnum.ArraySinglePrimitive:
+ output.WriteByte((byte)_binaryHeaderEnum);
+ output.WriteInt32(_objectId);
+ output.WriteInt32(_lengthA[0]);
+ output.WriteByte((byte)((InternalPrimitiveTypeE)_typeInformation));
+ break;
+ case BinaryHeaderEnum.ArraySingleString:
+ output.WriteByte((byte)_binaryHeaderEnum);
+ output.WriteInt32(_objectId);
+ output.WriteInt32(_lengthA[0]);
+ break;
+ case BinaryHeaderEnum.ArraySingleObject:
+ output.WriteByte((byte)_binaryHeaderEnum);
+ output.WriteInt32(_objectId);
+ output.WriteInt32(_lengthA[0]);
+ break;
+ default:
+ output.WriteByte((byte)_binaryHeaderEnum);
+ output.WriteInt32(_objectId);
+ output.WriteByte((byte)_binaryArrayTypeEnum);
+ output.WriteInt32(_rank);
+ for (int i = 0; i < _rank; i++)
+ {
+ output.WriteInt32(_lengthA[i]);
+ }
+ if ((_binaryArrayTypeEnum == BinaryArrayTypeEnum.SingleOffset) ||
+ (_binaryArrayTypeEnum == BinaryArrayTypeEnum.JaggedOffset) ||
+ (_binaryArrayTypeEnum == BinaryArrayTypeEnum.RectangularOffset))
+ {
+ for (int i = 0; i < _rank; i++)
+ {
+ output.WriteInt32(_lowerBoundA[i]);
+ }
+ }
+ output.WriteByte((byte)_binaryTypeEnum);
+ BinaryTypeConverter.WriteTypeInfo(_binaryTypeEnum, _typeInformation, _assemId, output);
+ break;
+ }
+ }
+
+ public void Read(BinaryParser input)
+ {
+ switch (_binaryHeaderEnum)
+ {
+ case BinaryHeaderEnum.ArraySinglePrimitive:
+ _objectId = input.ReadInt32();
+ _lengthA = new int[1];
+ _lengthA[0] = input.ReadInt32();
+ _binaryArrayTypeEnum = BinaryArrayTypeEnum.Single;
+ _rank = 1;
+ _lowerBoundA = new int[_rank];
+ _binaryTypeEnum = BinaryTypeEnum.Primitive;
+ _typeInformation = (InternalPrimitiveTypeE)input.ReadByte();
+ break;
+ case BinaryHeaderEnum.ArraySingleString:
+ _objectId = input.ReadInt32();
+ _lengthA = new int[1];
+ _lengthA[0] = input.ReadInt32();
+ _binaryArrayTypeEnum = BinaryArrayTypeEnum.Single;
+ _rank = 1;
+ _lowerBoundA = new int[_rank];
+ _binaryTypeEnum = BinaryTypeEnum.String;
+ _typeInformation = null;
+ break;
+ case BinaryHeaderEnum.ArraySingleObject:
+ _objectId = input.ReadInt32();
+ _lengthA = new int[1];
+ _lengthA[0] = input.ReadInt32();
+ _binaryArrayTypeEnum = BinaryArrayTypeEnum.Single;
+ _rank = 1;
+ _lowerBoundA = new int[_rank];
+ _binaryTypeEnum = BinaryTypeEnum.Object;
+ _typeInformation = null;
+ break;
+ default:
+ _objectId = input.ReadInt32();
+ _binaryArrayTypeEnum = (BinaryArrayTypeEnum)input.ReadByte();
+ _rank = input.ReadInt32();
+ _lengthA = new int[_rank];
+ _lowerBoundA = new int[_rank];
+ for (int i = 0; i < _rank; i++)
+ {
+ _lengthA[i] = input.ReadInt32();
+ }
+ if ((_binaryArrayTypeEnum == BinaryArrayTypeEnum.SingleOffset) ||
+ (_binaryArrayTypeEnum == BinaryArrayTypeEnum.JaggedOffset) ||
+ (_binaryArrayTypeEnum == BinaryArrayTypeEnum.RectangularOffset))
+ {
+ for (int i = 0; i < _rank; i++)
+ {
+ _lowerBoundA[i] = input.ReadInt32();
+ }
+ }
+ _binaryTypeEnum = (BinaryTypeEnum)input.ReadByte();
+ _typeInformation = BinaryTypeConverter.ReadTypeInfo(_binaryTypeEnum, input, out _assemId);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryAssembly.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryAssembly.cs
new file mode 100644
index 000000000000..14b357b1d77e
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryAssembly.cs
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryAssembly : IStreamable
+ {
+ internal int _assemId;
+ internal string _assemblyString;
+
+ internal BinaryAssembly() { }
+
+ internal void Set(int assemId, string assemblyString)
+ {
+ _assemId = assemId;
+ _assemblyString = assemblyString;
+ }
+
+ public void Write(BinaryFormatterWriter output)
+ {
+ output.WriteByte((byte)BinaryHeaderEnum.Assembly);
+ output.WriteInt32(_assemId);
+ output.WriteString(_assemblyString);
+ }
+
+ public void Read(BinaryParser input)
+ {
+ _assemId = input.ReadInt32();
+ _assemblyString = input.ReadString();
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryAssemblyInfo.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryAssemblyInfo.cs
new file mode 100644
index 000000000000..b99501741473
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryAssemblyInfo.cs
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Reflection;
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryAssemblyInfo
+ {
+ internal string _assemblyString;
+ private Assembly _assembly;
+
+ internal BinaryAssemblyInfo(string assemblyString)
+ {
+ _assemblyString = assemblyString;
+ }
+
+ internal BinaryAssemblyInfo(string assemblyString, Assembly assembly) : this(assemblyString)
+ {
+ _assembly = assembly;
+ }
+
+ internal Assembly GetAssembly()
+ {
+ if (_assembly == null)
+ {
+ _assembly = FormatterServices.LoadAssemblyFromStringNoThrow(_assemblyString);
+ if (_assembly == null)
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_AssemblyNotFound, _assemblyString));
+ }
+ }
+ return _assembly;
+ }
+ }
+}
+
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryCrossAppDomainAssembly.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryCrossAppDomainAssembly.cs
new file mode 100644
index 000000000000..8acb6a062849
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryCrossAppDomainAssembly.cs
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryCrossAppDomainAssembly : IStreamable
+ {
+ internal int _assemId;
+ internal int _assemblyIndex;
+
+ internal BinaryCrossAppDomainAssembly()
+ {
+ }
+
+ public void Write(BinaryFormatterWriter output)
+ {
+ output.WriteByte((byte)BinaryHeaderEnum.CrossAppDomainAssembly);
+ output.WriteInt32(_assemId);
+ output.WriteInt32(_assemblyIndex);
+ }
+
+ public void Read(BinaryParser input)
+ {
+ _assemId = input.ReadInt32();
+ _assemblyIndex = input.ReadInt32();
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryCrossAppDomainMap.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryCrossAppDomainMap.cs
new file mode 100644
index 000000000000..f0b3537ecef4
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryCrossAppDomainMap.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryCrossAppDomainMap : IStreamable
+ {
+ internal int _crossAppDomainArrayIndex;
+
+ public void Write(BinaryFormatterWriter output)
+ {
+ output.WriteByte((byte)BinaryHeaderEnum.CrossAppDomainMap);
+ output.WriteInt32(_crossAppDomainArrayIndex);
+ }
+
+ public void Read(BinaryParser input)
+ {
+ _crossAppDomainArrayIndex = input.ReadInt32();
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryCrossAppDomainString.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryCrossAppDomainString.cs
new file mode 100644
index 000000000000..9ac4a9a6866f
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryCrossAppDomainString.cs
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryCrossAppDomainString : IStreamable
+ {
+ internal int _objectId;
+ internal int _value;
+
+ internal BinaryCrossAppDomainString()
+ {
+ }
+
+ public void Write(BinaryFormatterWriter output)
+ {
+ output.WriteByte((byte)BinaryHeaderEnum.CrossAppDomainString);
+ output.WriteInt32(_objectId);
+ output.WriteInt32(_value);
+ }
+
+ public void Read(BinaryParser input)
+ {
+ _objectId = input.ReadInt32();
+ _value = input.ReadInt32();
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryEnums.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryEnums.cs
new file mode 100644
index 000000000000..376245005850
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryEnums.cs
@@ -0,0 +1,188 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ // BinaryHeaderEnum is the first byte on binary records (except for primitive types which do not have a header)
+ [Serializable]
+ internal enum BinaryHeaderEnum
+ {
+ SerializedStreamHeader = 0,
+ Object = 1,
+ ObjectWithMap = 2,
+ ObjectWithMapAssemId = 3,
+ ObjectWithMapTyped = 4,
+ ObjectWithMapTypedAssemId = 5,
+ ObjectString = 6,
+ Array = 7,
+ MemberPrimitiveTyped = 8,
+ MemberReference = 9,
+ ObjectNull = 10,
+ MessageEnd = 11,
+ Assembly = 12,
+ ObjectNullMultiple256 = 13,
+ ObjectNullMultiple = 14,
+ ArraySinglePrimitive = 15,
+ ArraySingleObject = 16,
+ ArraySingleString = 17,
+ CrossAppDomainMap = 18,
+ CrossAppDomainString = 19,
+ CrossAppDomainAssembly = 20,
+ MethodCall = 21,
+ MethodReturn = 22,
+ }
+
+ // BinaryTypeEnum is used specify the type on the wire. Additional information is transmitted with Primitive and Object types
+ [Serializable]
+ internal enum BinaryTypeEnum
+ {
+ Primitive = 0,
+ String = 1,
+ Object = 2,
+ ObjectUrt = 3,
+ ObjectUser = 4,
+ ObjectArray = 5,
+ StringArray = 6,
+ PrimitiveArray = 7,
+ }
+
+ [Serializable]
+ internal enum BinaryArrayTypeEnum
+ {
+ Single = 0,
+ Jagged = 1,
+ Rectangular = 2,
+ SingleOffset = 3,
+ JaggedOffset = 4,
+ RectangularOffset = 5,
+ }
+
+ // Enums are for internal use by the XML and Binary Serializers
+
+ // Formatter Enums
+ [Serializable]
+ internal enum InternalSerializerTypeE
+ {
+ Soap = 1,
+ Binary = 2,
+ }
+
+ // ParseRecord Enums
+ [Serializable]
+ internal enum InternalParseTypeE
+ {
+ Empty = 0,
+ SerializedStreamHeader = 1,
+ Object = 2,
+ Member = 3,
+ ObjectEnd = 4,
+ MemberEnd = 5,
+ Headers = 6,
+ HeadersEnd = 7,
+ SerializedStreamHeaderEnd = 8,
+ Envelope = 9,
+ EnvelopeEnd = 10,
+ Body = 11,
+ BodyEnd = 12,
+ }
+
+ [Serializable]
+ internal enum InternalObjectTypeE
+ {
+ Empty = 0,
+ Object = 1,
+ Array = 2,
+ }
+
+ [Serializable]
+ internal enum InternalObjectPositionE
+ {
+ Empty = 0,
+ Top = 1,
+ Child = 2,
+ Headers = 3,
+ }
+
+ [Serializable]
+ internal enum InternalArrayTypeE
+ {
+ Empty = 0,
+ Single = 1,
+ Jagged = 2,
+ Rectangular = 3,
+ Base64 = 4,
+ }
+
+ [Serializable]
+ internal enum InternalMemberTypeE
+ {
+ Empty = 0,
+ Header = 1,
+ Field = 2,
+ Item = 3,
+ }
+
+ [Serializable]
+ internal enum InternalMemberValueE
+ {
+ Empty = 0,
+ InlineValue = 1,
+ Nested = 2,
+ Reference = 3,
+ Null = 4,
+ }
+
+ // Data Type Enums
+ [Serializable]
+ internal enum InternalPrimitiveTypeE
+ {
+ Invalid = 0,
+ Boolean = 1,
+ Byte = 2,
+ Char = 3,
+ Currency = 4,
+ Decimal = 5,
+ Double = 6,
+ Int16 = 7,
+ Int32 = 8,
+ Int64 = 9,
+ SByte = 10,
+ Single = 11,
+ TimeSpan = 12,
+ DateTime = 13,
+ UInt16 = 14,
+ UInt32 = 15,
+ UInt64 = 16,
+
+ // Used in only for MethodCall or MethodReturn header
+ Null = 17,
+ String = 18,
+ }
+
+ // ValueType Fixup Enum
+ [Serializable]
+ internal enum ValueFixupEnum
+ {
+ Empty = 0,
+ Array = 1,
+ Header = 2,
+ Member = 3,
+ }
+
+ // name space
+ [Serializable]
+ internal enum InternalNameSpaceE
+ {
+ None = 0,
+ Soap = 1,
+ XdrPrimitive = 2,
+ XdrString = 3,
+ UrtSystem = 4,
+ UrtUser = 5,
+ UserNameSpace = 6,
+ MemberName = 7,
+ Interop = 8,
+ CallElement = 9
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryFormatter.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryFormatter.cs
new file mode 100644
index 000000000000..05d7fd961457
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryFormatter.cs
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Collections.Generic;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.InteropServices;
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ public sealed class BinaryFormatter : IFormatter
+ {
+ private static readonly Dictionary s_typeNameCache = new Dictionary();
+
+ internal ISurrogateSelector _surrogates;
+ internal StreamingContext _context;
+ internal SerializationBinder _binder;
+ internal FormatterTypeStyle _typeFormat = FormatterTypeStyle.TypesAlways; // For version resiliency, always put out types
+ internal FormatterAssemblyStyle _assemblyFormat = FormatterAssemblyStyle.Simple;
+ internal TypeFilterLevel _securityLevel = TypeFilterLevel.Full;
+ internal object[] _crossAppDomainArray = null;
+
+ public FormatterTypeStyle TypeFormat { get { return _typeFormat; } set { _typeFormat = value; } }
+ public FormatterAssemblyStyle AssemblyFormat { get { return _assemblyFormat; } set { _assemblyFormat = value; } }
+ public TypeFilterLevel FilterLevel { get { return _securityLevel; } set { _securityLevel = value; } }
+ public ISurrogateSelector SurrogateSelector { get { return _surrogates; } set { _surrogates = value; } }
+ public SerializationBinder Binder { get { return _binder; } set { _binder = value; } }
+ public StreamingContext Context { get { return _context; } set { _context = value; } }
+
+ public BinaryFormatter() : this(null, new StreamingContext(StreamingContextStates.All))
+ {
+ }
+
+ public BinaryFormatter(ISurrogateSelector selector, StreamingContext context)
+ {
+ _surrogates = selector;
+ _context = context;
+ }
+
+ public object Deserialize(Stream serializationStream) => Deserialize(serializationStream, null);
+
+ internal object Deserialize(Stream serializationStream, HeaderHandler handler, bool check)
+ {
+ if (serializationStream == null)
+ {
+ throw new ArgumentNullException(nameof(serializationStream), SR.Format(SR.ArgumentNull_WithParamName, serializationStream));
+ }
+ if (serializationStream.CanSeek && (serializationStream.Length == 0))
+ {
+ throw new SerializationException(SR.Serialization_Stream);
+ }
+
+ var formatterEnums = new InternalFE()
+ {
+ _FEtypeFormat = _typeFormat,
+ _FEserializerTypeEnum = InternalSerializerTypeE.Binary,
+ _FEassemblyFormat = _assemblyFormat,
+ _FEsecurityLevel = _securityLevel,
+ };
+
+ var reader = new ObjectReader(serializationStream, _surrogates, _context, formatterEnums, _binder)
+ {
+ _crossAppDomainArray = _crossAppDomainArray
+ };
+ var parser = new BinaryParser(serializationStream, reader);
+ return reader.Deserialize(handler, parser, check);
+ }
+
+ public object Deserialize(Stream serializationStream, HeaderHandler handler) =>
+ Deserialize(serializationStream, handler, check: true);
+
+ [ComVisible(false)]
+ public object UnsafeDeserialize(Stream serializationStream, HeaderHandler handler) =>
+ Deserialize(serializationStream, handler, check: false);
+
+ public void Serialize(Stream serializationStream, object graph) =>
+ Serialize(serializationStream, graph, headers: null);
+
+ public void Serialize(Stream serializationStream, object graph, Header[] headers) =>
+ Serialize(serializationStream, graph, headers, check: true);
+
+ internal void Serialize(Stream serializationStream, object graph, Header[] headers, bool check)
+ {
+ if (serializationStream == null)
+ {
+ throw new ArgumentNullException(nameof(serializationStream), SR.Format(SR.ArgumentNull_WithParamName, serializationStream));
+ }
+
+ var formatterEnums = new InternalFE()
+ {
+ _FEtypeFormat = _typeFormat,
+ _FEserializerTypeEnum = InternalSerializerTypeE.Binary,
+ _FEassemblyFormat = _assemblyFormat,
+ };
+
+ var sow = new ObjectWriter(_surrogates, _context, formatterEnums, _binder);
+ BinaryFormatterWriter binaryWriter = new BinaryFormatterWriter(serializationStream, sow, _typeFormat);
+ sow.Serialize(graph, headers, binaryWriter, check);
+ _crossAppDomainArray = sow._crossAppDomainArray;
+ }
+
+ internal static TypeInformation GetTypeInformation(Type type)
+ {
+ lock (s_typeNameCache)
+ {
+ TypeInformation typeInformation;
+ if (!s_typeNameCache.TryGetValue(type, out typeInformation))
+ {
+ bool hasTypeForwardedFrom;
+ string assemblyName = FormatterServices.GetClrAssemblyName(type, out hasTypeForwardedFrom);
+ typeInformation = new TypeInformation(FormatterServices.GetClrTypeFullName(type), assemblyName, hasTypeForwardedFrom);
+ s_typeNameCache.Add(type, typeInformation);
+ }
+ return typeInformation;
+ }
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryFormatterWriter.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryFormatterWriter.cs
new file mode 100644
index 000000000000..ea449f62351c
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryFormatterWriter.cs
@@ -0,0 +1,527 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryFormatterWriter
+ {
+ private const int ChunkSize = 4096;
+
+ private readonly Stream _outputStream;
+ private readonly FormatterTypeStyle _formatterTypeStyle;
+ private readonly ObjectWriter _objectWriter = null;
+ private readonly BinaryWriter _dataWriter = null;
+
+ private int _consecutiveNullArrayEntryCount = 0;
+ private Dictionary _objectMapTable;
+
+ private BinaryObject _binaryObject;
+ private BinaryObjectWithMap _binaryObjectWithMap;
+ private BinaryObjectWithMapTyped _binaryObjectWithMapTyped;
+ private BinaryObjectString _binaryObjectString;
+ private BinaryArray _binaryArray;
+ private byte[] _byteBuffer = null;
+ private MemberPrimitiveUnTyped _memberPrimitiveUnTyped;
+ private MemberPrimitiveTyped _memberPrimitiveTyped;
+ private ObjectNull _objectNull;
+ private MemberReference _memberReference;
+ private BinaryAssembly _binaryAssembly;
+
+ internal BinaryFormatterWriter(Stream outputStream, ObjectWriter objectWriter, FormatterTypeStyle formatterTypeStyle)
+ {
+ _outputStream = outputStream;
+ _formatterTypeStyle = formatterTypeStyle;
+ _objectWriter = objectWriter;
+ _dataWriter = new BinaryWriter(outputStream, Encoding.UTF8);
+ }
+
+ internal void WriteBegin() { }
+
+ internal void WriteEnd()
+ {
+ _dataWriter.Flush();
+ }
+
+ internal void WriteBoolean(bool value) => _dataWriter.Write(value);
+
+ internal void WriteByte(byte value) => _dataWriter.Write(value);
+
+ private void WriteBytes(byte[] value) => _dataWriter.Write(value);
+
+ private void WriteBytes(byte[] byteA, int offset, int size) => _dataWriter.Write(byteA, offset, size);
+
+ internal void WriteChar(char value) => _dataWriter.Write(value);
+
+ internal void WriteChars(char[] value) => _dataWriter.Write(value);
+
+ internal void WriteDecimal(decimal value) => WriteString(value.ToString(CultureInfo.InvariantCulture));
+
+ internal void WriteSingle(float value) => _dataWriter.Write(value);
+
+ internal void WriteDouble(double value) => _dataWriter.Write(value);
+
+ internal void WriteInt16(short value) => _dataWriter.Write(value);
+
+ internal void WriteInt32(int value) => _dataWriter.Write(value);
+
+ internal void WriteInt64(long value) => _dataWriter.Write(value);
+
+ internal void WriteSByte(sbyte value) => WriteByte((byte)value);
+
+ internal void WriteString(string value) => _dataWriter.Write(value);
+
+ internal void WriteTimeSpan(TimeSpan value) => WriteInt64(value.Ticks);
+
+ internal void WriteDateTime(DateTime value) => WriteInt64(value.Ticks); // in desktop, this uses ToBinaryRaw
+
+ internal void WriteUInt16(ushort value) => _dataWriter.Write(value);
+
+ internal void WriteUInt32(uint value) => _dataWriter.Write(value);
+
+ internal void WriteUInt64(ulong value) => _dataWriter.Write(value);
+
+ internal void WriteObjectEnd(NameInfo memberNameInfo, NameInfo typeNameInfo) { }
+
+ internal void WriteSerializationHeaderEnd()
+ {
+ var record = new MessageEnd();
+ record.Write(this);
+ }
+
+ internal void WriteSerializationHeader(int topId, int headerId, int minorVersion, int majorVersion)
+ {
+ var record = new SerializationHeaderRecord(BinaryHeaderEnum.SerializedStreamHeader, topId, headerId, minorVersion, majorVersion);
+ record.Write(this);
+ }
+
+ internal void WriteObject(NameInfo nameInfo, NameInfo typeNameInfo, int numMembers, string[] memberNames, Type[] memberTypes, WriteObjectInfo[] memberObjectInfos)
+ {
+ InternalWriteItemNull();
+ int assemId;
+ int objectId = (int)nameInfo._NIobjectId;
+
+ string objectName = objectId < 0 ?
+ objectName = typeNameInfo.NIname : // Nested Object
+ objectName = nameInfo.NIname; // Non-Nested
+
+ if (_objectMapTable == null)
+ {
+ _objectMapTable = new Dictionary();
+ }
+
+ ObjectMapInfo objectMapInfo;
+ if (_objectMapTable.TryGetValue(objectName, out objectMapInfo) &&
+ objectMapInfo.IsCompatible(numMembers, memberNames, memberTypes))
+ {
+ // Object
+ if (_binaryObject == null)
+ {
+ _binaryObject = new BinaryObject();
+ }
+
+ _binaryObject.Set(objectId, objectMapInfo._objectId);
+ _binaryObject.Write(this);
+ }
+ else if (!typeNameInfo._NItransmitTypeOnObject)
+ {
+ // ObjectWithMap
+ if (_binaryObjectWithMap == null)
+ {
+ _binaryObjectWithMap = new BinaryObjectWithMap();
+ }
+
+ // BCL types are not placed into table
+ assemId = (int)typeNameInfo._NIassemId;
+ _binaryObjectWithMap.Set(objectId, objectName, numMembers, memberNames, assemId);
+
+ _binaryObjectWithMap.Write(this);
+ if (objectMapInfo == null)
+ {
+ _objectMapTable.Add(objectName, new ObjectMapInfo(objectId, numMembers, memberNames, memberTypes));
+ }
+ }
+ else
+ {
+ // ObjectWithMapTyped
+ var binaryTypeEnumA = new BinaryTypeEnum[numMembers];
+ var typeInformationA = new object[numMembers];
+ var assemIdA = new int[numMembers];
+ for (int i = 0; i < numMembers; i++)
+ {
+ object typeInformation = null;
+ binaryTypeEnumA[i] = BinaryTypeConverter.GetBinaryTypeInfo(memberTypes[i], memberObjectInfos[i], null, _objectWriter, out typeInformation, out assemId);
+ typeInformationA[i] = typeInformation;
+ assemIdA[i] = assemId;
+ }
+
+ if (_binaryObjectWithMapTyped == null)
+ {
+ _binaryObjectWithMapTyped = new BinaryObjectWithMapTyped();
+ }
+
+ // BCL types are not placed in table
+ assemId = (int)typeNameInfo._NIassemId;
+ _binaryObjectWithMapTyped.Set(objectId, objectName, numMembers, memberNames, binaryTypeEnumA, typeInformationA, assemIdA, assemId);
+ _binaryObjectWithMapTyped.Write(this);
+ if (objectMapInfo == null)
+ {
+ _objectMapTable.Add(objectName, new ObjectMapInfo(objectId, numMembers, memberNames, memberTypes));
+ }
+ }
+ }
+
+ internal void WriteObjectString(int objectId, string value)
+ {
+ InternalWriteItemNull();
+
+ if (_binaryObjectString == null)
+ {
+ _binaryObjectString = new BinaryObjectString();
+ }
+
+ _binaryObjectString.Set(objectId, value);
+ _binaryObjectString.Write(this);
+ }
+
+ internal void WriteSingleArray(NameInfo memberNameInfo, NameInfo arrayNameInfo, WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, int length, int lowerBound, Array array)
+ {
+ InternalWriteItemNull();
+ BinaryArrayTypeEnum binaryArrayTypeEnum;
+ var lengthA = new int[1];
+ lengthA[0] = length;
+ int[] lowerBoundA = null;
+ object typeInformation = null;
+
+ if (lowerBound == 0)
+ {
+ binaryArrayTypeEnum = BinaryArrayTypeEnum.Single;
+ }
+ else
+ {
+ binaryArrayTypeEnum = BinaryArrayTypeEnum.SingleOffset;
+ lowerBoundA = new int[1];
+ lowerBoundA[0] = lowerBound;
+ }
+
+ int assemId;
+ BinaryTypeEnum binaryTypeEnum = BinaryTypeConverter.GetBinaryTypeInfo(
+ arrayElemTypeNameInfo._NItype, objectInfo, arrayElemTypeNameInfo.NIname, _objectWriter, out typeInformation, out assemId);
+
+ if (_binaryArray == null)
+ {
+ _binaryArray = new BinaryArray();
+ }
+ _binaryArray.Set((int)arrayNameInfo._NIobjectId, 1, lengthA, lowerBoundA, binaryTypeEnum, typeInformation, binaryArrayTypeEnum, assemId);
+
+ _binaryArray.Write(this);
+
+ if (Converter.IsWriteAsByteArray(arrayElemTypeNameInfo._NIprimitiveTypeEnum) && (lowerBound == 0))
+ {
+ //array is written out as an array of bytes
+ if (arrayElemTypeNameInfo._NIprimitiveTypeEnum == InternalPrimitiveTypeE.Byte)
+ {
+ WriteBytes((byte[])array);
+ }
+ else if (arrayElemTypeNameInfo._NIprimitiveTypeEnum == InternalPrimitiveTypeE.Char)
+ {
+ WriteChars((char[])array);
+ }
+ else
+ {
+ WriteArrayAsBytes(array, Converter.TypeLength(arrayElemTypeNameInfo._NIprimitiveTypeEnum));
+ }
+ }
+ }
+
+ private void WriteArrayAsBytes(Array array, int typeLength)
+ {
+ InternalWriteItemNull();
+ int byteLength = array.Length * typeLength;
+ int arrayOffset = 0;
+ if (_byteBuffer == null)
+ {
+ _byteBuffer = new byte[ChunkSize];
+ }
+
+ while (arrayOffset < array.Length)
+ {
+ int numArrayItems = Math.Min(ChunkSize / typeLength, array.Length - arrayOffset);
+ int bufferUsed = numArrayItems * typeLength;
+ Buffer.BlockCopy(array, arrayOffset * typeLength, _byteBuffer, 0, bufferUsed);
+ if (!BitConverter.IsLittleEndian)
+ {
+ // we know that we are writing a primitive type, so just do a simple swap
+ for (int i = 0; i < bufferUsed; i += typeLength)
+ {
+ for (int j = 0; j < typeLength / 2; j++)
+ {
+ byte tmp = _byteBuffer[i + j];
+ _byteBuffer[i + j] = _byteBuffer[i + typeLength - 1 - j];
+ _byteBuffer[i + typeLength - 1 - j] = tmp;
+ }
+ }
+ }
+ WriteBytes(_byteBuffer, 0, bufferUsed);
+ arrayOffset += numArrayItems;
+ }
+ }
+
+ internal void WriteJaggedArray(NameInfo memberNameInfo, NameInfo arrayNameInfo, WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, int length, int lowerBound)
+ {
+ InternalWriteItemNull();
+ BinaryArrayTypeEnum binaryArrayTypeEnum;
+ var lengthA = new int[1];
+ lengthA[0] = length;
+ int[] lowerBoundA = null;
+ object typeInformation = null;
+ int assemId = 0;
+
+ if (lowerBound == 0)
+ {
+ binaryArrayTypeEnum = BinaryArrayTypeEnum.Jagged;
+ }
+ else
+ {
+ binaryArrayTypeEnum = BinaryArrayTypeEnum.JaggedOffset;
+ lowerBoundA = new int[1];
+ lowerBoundA[0] = lowerBound;
+ }
+
+ BinaryTypeEnum binaryTypeEnum = BinaryTypeConverter.GetBinaryTypeInfo(arrayElemTypeNameInfo._NItype, objectInfo, arrayElemTypeNameInfo.NIname, _objectWriter, out typeInformation, out assemId);
+
+ if (_binaryArray == null)
+ {
+ _binaryArray = new BinaryArray();
+ }
+ _binaryArray.Set((int)arrayNameInfo._NIobjectId, 1, lengthA, lowerBoundA, binaryTypeEnum, typeInformation, binaryArrayTypeEnum, assemId);
+
+ _binaryArray.Write(this);
+ }
+
+ internal void WriteRectangleArray(NameInfo memberNameInfo, NameInfo arrayNameInfo, WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, int rank, int[] lengthA, int[] lowerBoundA)
+ {
+ InternalWriteItemNull();
+
+ BinaryArrayTypeEnum binaryArrayTypeEnum = BinaryArrayTypeEnum.Rectangular;
+ object typeInformation = null;
+ int assemId = 0;
+ BinaryTypeEnum binaryTypeEnum = BinaryTypeConverter.GetBinaryTypeInfo(arrayElemTypeNameInfo._NItype, objectInfo, arrayElemTypeNameInfo.NIname, _objectWriter, out typeInformation, out assemId);
+
+ if (_binaryArray == null)
+ {
+ _binaryArray = new BinaryArray();
+ }
+
+ for (int i = 0; i < rank; i++)
+ {
+ if (lowerBoundA[i] != 0)
+ {
+ binaryArrayTypeEnum = BinaryArrayTypeEnum.RectangularOffset;
+ break;
+ }
+ }
+
+ _binaryArray.Set((int)arrayNameInfo._NIobjectId, rank, lengthA, lowerBoundA, binaryTypeEnum, typeInformation, binaryArrayTypeEnum, assemId);
+ _binaryArray.Write(this);
+ }
+
+ internal void WriteObjectByteArray(NameInfo memberNameInfo, NameInfo arrayNameInfo, WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, int length, int lowerBound, byte[] byteA)
+ {
+ InternalWriteItemNull();
+ WriteSingleArray(memberNameInfo, arrayNameInfo, objectInfo, arrayElemTypeNameInfo, length, lowerBound, byteA);
+ }
+
+ internal void WriteMember(NameInfo memberNameInfo, NameInfo typeNameInfo, object value)
+ {
+ InternalWriteItemNull();
+ InternalPrimitiveTypeE typeInformation = typeNameInfo._NIprimitiveTypeEnum;
+
+ // Writes Members with primitive values
+ if (memberNameInfo._NItransmitTypeOnMember)
+ {
+ if (_memberPrimitiveTyped == null)
+ {
+ _memberPrimitiveTyped = new MemberPrimitiveTyped();
+ }
+ _memberPrimitiveTyped.Set(typeInformation, value);
+ _memberPrimitiveTyped.Write(this);
+ }
+ else
+ {
+ if (_memberPrimitiveUnTyped == null)
+ {
+ _memberPrimitiveUnTyped = new MemberPrimitiveUnTyped();
+ }
+ _memberPrimitiveUnTyped.Set(typeInformation, value);
+ _memberPrimitiveUnTyped.Write(this);
+ }
+ }
+
+ internal void WriteNullMember(NameInfo memberNameInfo, NameInfo typeNameInfo)
+ {
+ InternalWriteItemNull();
+ if (_objectNull == null)
+ {
+ _objectNull = new ObjectNull();
+ }
+
+ if (!memberNameInfo._NIisArrayItem)
+ {
+ _objectNull.SetNullCount(1);
+ _objectNull.Write(this);
+ _consecutiveNullArrayEntryCount = 0;
+ }
+ }
+
+ internal void WriteMemberObjectRef(NameInfo memberNameInfo, int idRef)
+ {
+ InternalWriteItemNull();
+ if (_memberReference == null)
+ {
+ _memberReference = new MemberReference();
+ }
+ _memberReference.Set(idRef);
+ _memberReference.Write(this);
+ }
+
+ internal void WriteMemberNested(NameInfo memberNameInfo)
+ {
+ InternalWriteItemNull();
+ }
+
+ internal void WriteMemberString(NameInfo memberNameInfo, NameInfo typeNameInfo, string value)
+ {
+ InternalWriteItemNull();
+ WriteObjectString((int)typeNameInfo._NIobjectId, value);
+ }
+
+ internal void WriteItem(NameInfo itemNameInfo, NameInfo typeNameInfo, object value)
+ {
+ InternalWriteItemNull();
+ WriteMember(itemNameInfo, typeNameInfo, value);
+ }
+
+ internal void WriteNullItem(NameInfo itemNameInfo, NameInfo typeNameInfo)
+ {
+ _consecutiveNullArrayEntryCount++;
+ InternalWriteItemNull();
+ }
+
+ internal void WriteDelayedNullItem()
+ {
+ _consecutiveNullArrayEntryCount++;
+ }
+
+ internal void WriteItemEnd() => InternalWriteItemNull();
+
+ private void InternalWriteItemNull()
+ {
+ if (_consecutiveNullArrayEntryCount > 0)
+ {
+ if (_objectNull == null)
+ {
+ _objectNull = new ObjectNull();
+ }
+ _objectNull.SetNullCount(_consecutiveNullArrayEntryCount);
+ _objectNull.Write(this);
+ _consecutiveNullArrayEntryCount = 0;
+ }
+ }
+
+ internal void WriteItemObjectRef(NameInfo nameInfo, int idRef)
+ {
+ InternalWriteItemNull();
+ WriteMemberObjectRef(nameInfo, idRef);
+ }
+
+ internal void WriteAssembly(Type type, string assemblyString, int assemId, bool isNew)
+ {
+ //If the file being tested wasn't built as an assembly, then we're going to get null back
+ //for the assembly name. This is very unfortunate.
+ InternalWriteItemNull();
+ if (assemblyString == null)
+ {
+ assemblyString = string.Empty;
+ }
+
+ if (isNew)
+ {
+ if (_binaryAssembly == null)
+ {
+ _binaryAssembly = new BinaryAssembly();
+ }
+ _binaryAssembly.Set(assemId, assemblyString);
+ _binaryAssembly.Write(this);
+ }
+ }
+
+ // Method to write a value onto a stream given its primitive type code
+ internal void WriteValue(InternalPrimitiveTypeE code, object value)
+ {
+ switch (code)
+ {
+ case InternalPrimitiveTypeE.Boolean: WriteBoolean(Convert.ToBoolean(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.Byte: WriteByte(Convert.ToByte(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.Char: WriteChar(Convert.ToChar(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.Double: WriteDouble(Convert.ToDouble(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.Int16: WriteInt16(Convert.ToInt16(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.Int32: WriteInt32(Convert.ToInt32(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.Int64: WriteInt64(Convert.ToInt64(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.SByte: WriteSByte(Convert.ToSByte(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.Single: WriteSingle(Convert.ToSingle(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.UInt16: WriteUInt16(Convert.ToUInt16(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.UInt32: WriteUInt32(Convert.ToUInt32(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.UInt64: WriteUInt64(Convert.ToUInt64(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.Decimal: WriteDecimal(Convert.ToDecimal(value, CultureInfo.InvariantCulture)); break;
+ case InternalPrimitiveTypeE.TimeSpan: WriteTimeSpan((TimeSpan)value); break;
+ case InternalPrimitiveTypeE.DateTime: WriteDateTime((DateTime)value); break;
+ default: throw new SerializationException(SR.Format(SR.Serialization_TypeCode, code.ToString()));
+ }
+ }
+
+ private sealed class ObjectMapInfo
+ {
+ internal readonly int _objectId;
+ private readonly int _numMembers;
+ private readonly string[] _memberNames;
+ private readonly Type[] _memberTypes;
+
+ internal ObjectMapInfo(int objectId, int numMembers, string[] memberNames, Type[] memberTypes)
+ {
+ _objectId = objectId;
+ _numMembers = numMembers;
+ _memberNames = memberNames;
+ _memberTypes = memberTypes;
+ }
+
+ internal bool IsCompatible(int numMembers, string[] memberNames, Type[] memberTypes)
+ {
+ if (_numMembers != numMembers)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < numMembers; i++)
+ {
+ if (!(_memberNames[i].Equals(memberNames[i])))
+ {
+ return false;
+ }
+
+ if ((memberTypes != null) && (_memberTypes[i] != memberTypes[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObject.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObject.cs
new file mode 100644
index 000000000000..d1656e89b6b6
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObject.cs
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryObject : IStreamable
+ {
+ internal int _objectId;
+ internal int _mapId;
+
+ internal BinaryObject() { }
+
+ internal void Set(int objectId, int mapId)
+ {
+ _objectId = objectId;
+ _mapId = mapId;
+ }
+
+ public void Write(BinaryFormatterWriter output)
+ {
+ output.WriteByte((byte)BinaryHeaderEnum.Object);
+ output.WriteInt32(_objectId);
+ output.WriteInt32(_mapId);
+ }
+
+ public void Read(BinaryParser input)
+ {
+ _objectId = input.ReadInt32();
+ _mapId = input.ReadInt32();
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectInfo.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectInfo.cs
new file mode 100644
index 000000000000..7265ee7b93ed
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectInfo.cs
@@ -0,0 +1,720 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ // This class contains information about an object. It is used so that
+ // the rest of the Formatter routines can use a common interface for
+ // a normal object, an ISerializable object, and a surrogate object
+ internal sealed class WriteObjectInfo
+ {
+ internal int _objectInfoId;
+ internal object _obj;
+ internal Type _objectType;
+
+ internal bool _isSi = false;
+ internal bool _isNamed = false;
+ internal bool _isArray = false;
+
+ internal SerializationInfo _si = null;
+ internal SerObjectInfoCache _cache = null;
+
+ internal object[] _memberData = null;
+ internal ISerializationSurrogate _serializationSurrogate = null;
+ internal StreamingContext _context;
+ internal SerObjectInfoInit _serObjectInfoInit = null;
+
+ // Writing and Parsing information
+ internal long _objectId;
+ internal long _assemId;
+
+ // Binder information
+ private string _binderTypeName;
+ private string _binderAssemblyString;
+
+ internal WriteObjectInfo() { }
+
+ internal void ObjectEnd()
+ {
+ PutObjectInfo(_serObjectInfoInit, this);
+ }
+
+ private void InternalInit()
+ {
+ _obj = null;
+ _objectType = null;
+ _isSi = false;
+ _isNamed = false;
+ _isArray = false;
+ _si = null;
+ _cache = null;
+ _memberData = null;
+
+ // Writing and Parsing information
+ _objectId = 0;
+ _assemId = 0;
+
+ // Binder information
+ _binderTypeName = null;
+ _binderAssemblyString = null;
+ }
+
+ internal static WriteObjectInfo Serialize(object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
+ {
+ WriteObjectInfo woi = GetObjectInfo(serObjectInfoInit);
+ woi.InitSerialize(obj, surrogateSelector, context, serObjectInfoInit, converter, objectWriter, binder);
+ return woi;
+ }
+
+ // Write constructor
+ internal void InitSerialize(object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
+ {
+ _context = context;
+ _obj = obj;
+ _serObjectInfoInit = serObjectInfoInit;
+ _objectType = obj.GetType();
+
+ if (_objectType.IsArray)
+ {
+ _isArray = true;
+ InitNoMembers();
+ return;
+ }
+
+ InvokeSerializationBinder(binder);
+ objectWriter.ObjectManager.RegisterObject(obj);
+
+ ISurrogateSelector surrogateSelectorTemp;
+ if (surrogateSelector != null && (_serializationSurrogate = surrogateSelector.GetSurrogate(_objectType, context, out surrogateSelectorTemp)) != null)
+ {
+ _si = new SerializationInfo(_objectType, converter);
+ if (!_objectType.GetTypeInfo().IsPrimitive)
+ {
+ _serializationSurrogate.GetObjectData(obj, _si, context);
+ }
+ InitSiWrite();
+ }
+ else if (obj is ISerializable)
+ {
+ if (!_objectType.GetTypeInfo().IsSerializable)
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_NonSerType, _objectType.FullName, _objectType.GetTypeInfo().Assembly.FullName));
+ }
+ _si = new SerializationInfo(_objectType, converter, !FormatterServices.UnsafeTypeForwardersIsEnabled());
+ ((ISerializable)obj).GetObjectData(_si, context);
+ InitSiWrite();
+ CheckTypeForwardedFrom(_cache, _objectType, _binderAssemblyString);
+ }
+ else
+ {
+ InitMemberInfo();
+ CheckTypeForwardedFrom(_cache, _objectType, _binderAssemblyString);
+ }
+ }
+
+ internal static WriteObjectInfo Serialize(Type objectType, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, SerializationBinder binder)
+ {
+ WriteObjectInfo woi = GetObjectInfo(serObjectInfoInit);
+ woi.InitSerialize(objectType, surrogateSelector, context, serObjectInfoInit, converter, binder);
+ return woi;
+ }
+
+ // Write Constructor used for array types or null members
+ internal void InitSerialize(Type objectType, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, SerializationBinder binder)
+ {
+ _objectType = objectType;
+ _context = context;
+ _serObjectInfoInit = serObjectInfoInit;
+
+ if (objectType.IsArray)
+ {
+ InitNoMembers();
+ return;
+ }
+
+ InvokeSerializationBinder(binder);
+
+ ISurrogateSelector surrogateSelectorTemp = null;
+ if (surrogateSelector != null)
+ {
+ _serializationSurrogate = surrogateSelector.GetSurrogate(objectType, context, out surrogateSelectorTemp);
+ }
+
+ if (_serializationSurrogate != null)
+ {
+ // surrogate does not have this problem since user has pass in through the BF's ctor
+ _si = new SerializationInfo(objectType, converter);
+ _cache = new SerObjectInfoCache(objectType);
+ _isSi = true;
+ }
+ else if (!ReferenceEquals(objectType, Converter.s_typeofObject) && Converter.s_typeofISerializable.IsAssignableFrom(objectType))
+ {
+ _si = new SerializationInfo(objectType, converter, !FormatterServices.UnsafeTypeForwardersIsEnabled());
+ _cache = new SerObjectInfoCache(objectType);
+ CheckTypeForwardedFrom(_cache, objectType, _binderAssemblyString);
+ _isSi = true;
+ }
+
+ if (!_isSi)
+ {
+ InitMemberInfo();
+ CheckTypeForwardedFrom(_cache, objectType, _binderAssemblyString);
+ }
+ }
+
+ private void InitSiWrite()
+ {
+ SerializationInfoEnumerator siEnum = null;
+ _isSi = true;
+ siEnum = _si.GetEnumerator();
+ int infoLength = 0;
+
+ infoLength = _si.MemberCount;
+
+ int count = infoLength;
+
+ // For ISerializable cache cannot be saved because each object instance can have different values
+ // BinaryWriter only puts the map on the wire if the ISerializable map cannot be reused.
+ TypeInformation typeInformation = null;
+ string fullTypeName = _si.FullTypeName;
+ string assemblyString = _si.AssemblyName;
+ bool hasTypeForwardedFrom = false;
+
+ if (!_si.IsFullTypeNameSetExplicit)
+ {
+ typeInformation = BinaryFormatter.GetTypeInformation(_si.ObjectType);
+ fullTypeName = typeInformation.FullTypeName;
+ hasTypeForwardedFrom = typeInformation.HasTypeForwardedFrom;
+ }
+
+ if (!_si.IsAssemblyNameSetExplicit)
+ {
+ if (typeInformation == null)
+ {
+ typeInformation = BinaryFormatter.GetTypeInformation(_si.ObjectType);
+ }
+ assemblyString = typeInformation.AssemblyString;
+ hasTypeForwardedFrom = typeInformation.HasTypeForwardedFrom;
+ }
+
+ _cache = new SerObjectInfoCache(fullTypeName, assemblyString, hasTypeForwardedFrom);
+
+ _cache._memberNames = new string[count];
+ _cache._memberTypes = new Type[count];
+ _memberData = new object[count];
+
+ siEnum = _si.GetEnumerator();
+ for (int i = 0; siEnum.MoveNext(); i++)
+ {
+ _cache._memberNames[i] = siEnum.Name;
+ _cache._memberTypes[i] = siEnum.ObjectType;
+ _memberData[i] = siEnum.Value;
+ }
+
+ _isNamed = true;
+ }
+
+ private static void CheckTypeForwardedFrom(SerObjectInfoCache cache, Type objectType, string binderAssemblyString)
+ {
+ // nop
+ }
+
+ private void InitNoMembers()
+ {
+ if (!_serObjectInfoInit._seenBeforeTable.TryGetValue(_objectType, out _cache))
+ {
+ _cache = new SerObjectInfoCache(_objectType);
+ _serObjectInfoInit._seenBeforeTable.Add(_objectType, _cache);
+ }
+ }
+
+ private void InitMemberInfo()
+ {
+ if (!_serObjectInfoInit._seenBeforeTable.TryGetValue(_objectType, out _cache))
+ {
+ _cache = new SerObjectInfoCache(_objectType);
+
+ _cache._memberInfos = FormatterServices.GetSerializableMembers(_objectType, _context);
+ int count = _cache._memberInfos.Length;
+ _cache._memberNames = new string[count];
+ _cache._memberTypes = new Type[count];
+
+ // Calculate new arrays
+ for (int i = 0; i < count; i++)
+ {
+ _cache._memberNames[i] = _cache._memberInfos[i].Name;
+ _cache._memberTypes[i] = ((FieldInfo)_cache._memberInfos[i]).FieldType;
+ }
+ _serObjectInfoInit._seenBeforeTable.Add(_objectType, _cache);
+ }
+
+ if (_obj != null)
+ {
+ _memberData = FormatterServices.GetObjectData(_obj, _cache._memberInfos);
+ }
+
+ _isNamed = true;
+ }
+
+ internal string GetTypeFullName() => _binderTypeName ?? _cache._fullTypeName;
+
+ internal string GetAssemblyString() => _binderAssemblyString ?? _cache._assemblyString;
+
+ private void InvokeSerializationBinder(SerializationBinder binder) =>
+ binder?.BindToName(_objectType, out _binderAssemblyString, out _binderTypeName);
+
+ internal void GetMemberInfo(out string[] outMemberNames, out Type[] outMemberTypes, out object[] outMemberData)
+ {
+ outMemberNames = _cache._memberNames;
+ outMemberTypes = _cache._memberTypes;
+ outMemberData = _memberData;
+
+ if (_isSi && !_isNamed)
+ {
+ throw new SerializationException(SR.Serialization_ISerializableMemberInfo);
+ }
+ }
+
+ private static WriteObjectInfo GetObjectInfo(SerObjectInfoInit serObjectInfoInit)
+ {
+ WriteObjectInfo objectInfo;
+
+ if (!serObjectInfoInit._oiPool.IsEmpty())
+ {
+ objectInfo = (WriteObjectInfo)serObjectInfoInit._oiPool.Pop();
+ objectInfo.InternalInit();
+ }
+ else
+ {
+ objectInfo = new WriteObjectInfo();
+ objectInfo._objectInfoId = serObjectInfoInit._objectInfoIdCount++;
+ }
+
+ return objectInfo;
+ }
+
+ private static void PutObjectInfo(SerObjectInfoInit serObjectInfoInit, WriteObjectInfo objectInfo) =>
+ serObjectInfoInit._oiPool.Push(objectInfo);
+ }
+
+ internal sealed class ReadObjectInfo
+ {
+ internal int _objectInfoId;
+ internal static int _readObjectInfoCounter;
+
+ internal Type _objectType;
+
+ internal ObjectManager _objectManager;
+
+ internal int _count;
+
+ internal bool _isSi = false;
+ internal bool _isTyped = false;
+ internal bool _isSimpleAssembly = false;
+
+ internal SerObjectInfoCache _cache;
+
+ internal string[] _wireMemberNames;
+ internal Type[] _wireMemberTypes;
+
+ private int _lastPosition = 0;
+
+ internal ISerializationSurrogate _serializationSurrogate = null;
+ internal StreamingContext _context;
+
+ // Si Read
+ internal List _memberTypesList;
+ internal SerObjectInfoInit _serObjectInfoInit = null;
+ internal IFormatterConverter _formatterConverter;
+
+ internal ReadObjectInfo() { }
+
+ internal void ObjectEnd() { }
+
+ internal void PrepareForReuse()
+ {
+ _lastPosition = 0;
+ }
+
+ internal static ReadObjectInfo Create(Type objectType, ISurrogateSelector surrogateSelector, StreamingContext context, ObjectManager objectManager, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, bool bSimpleAssembly)
+ {
+ ReadObjectInfo roi = GetObjectInfo(serObjectInfoInit);
+ roi.Init(objectType, surrogateSelector, context, objectManager, serObjectInfoInit, converter, bSimpleAssembly);
+ return roi;
+ }
+
+ internal void Init(Type objectType, ISurrogateSelector surrogateSelector, StreamingContext context, ObjectManager objectManager, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, bool bSimpleAssembly)
+ {
+ _objectType = objectType;
+ _objectManager = objectManager;
+ _context = context;
+ _serObjectInfoInit = serObjectInfoInit;
+ _formatterConverter = converter;
+ _isSimpleAssembly = bSimpleAssembly;
+
+ InitReadConstructor(objectType, surrogateSelector, context);
+ }
+
+ internal static ReadObjectInfo Create(Type objectType, string[] memberNames, Type[] memberTypes, ISurrogateSelector surrogateSelector, StreamingContext context, ObjectManager objectManager, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, bool bSimpleAssembly)
+ {
+ ReadObjectInfo roi = GetObjectInfo(serObjectInfoInit);
+ roi.Init(objectType, memberNames, memberTypes, surrogateSelector, context, objectManager, serObjectInfoInit, converter, bSimpleAssembly);
+ return roi;
+ }
+
+ internal void Init(Type objectType, string[] memberNames, Type[] memberTypes, ISurrogateSelector surrogateSelector, StreamingContext context, ObjectManager objectManager, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, bool bSimpleAssembly)
+ {
+ _objectType = objectType;
+ _objectManager = objectManager;
+ _wireMemberNames = memberNames;
+ _wireMemberTypes = memberTypes;
+ _context = context;
+ _serObjectInfoInit = serObjectInfoInit;
+ _formatterConverter = converter;
+ _isSimpleAssembly = bSimpleAssembly;
+ if (memberTypes != null)
+ {
+ _isTyped = true;
+ }
+ if (objectType != null)
+ {
+ InitReadConstructor(objectType, surrogateSelector, context);
+ }
+ }
+
+ private void InitReadConstructor(Type objectType, ISurrogateSelector surrogateSelector, StreamingContext context)
+ {
+ if (objectType.IsArray)
+ {
+ InitNoMembers();
+ return;
+ }
+
+ ISurrogateSelector surrogateSelectorTemp = null;
+ if (surrogateSelector != null)
+ {
+ _serializationSurrogate = surrogateSelector.GetSurrogate(objectType, context, out surrogateSelectorTemp);
+ }
+
+ if (_serializationSurrogate != null)
+ {
+ _isSi = true;
+ }
+ else if (!ReferenceEquals(objectType, Converter.s_typeofObject) && Converter.s_typeofISerializable.IsAssignableFrom(objectType))
+ {
+ _isSi = true;
+ }
+
+ if (_isSi)
+ {
+ InitSiRead();
+ }
+ else
+ {
+ InitMemberInfo();
+ }
+ }
+
+ private void InitSiRead()
+ {
+ if (_memberTypesList != null)
+ {
+ _memberTypesList = new List(20);
+ }
+ }
+
+ private void InitNoMembers()
+ {
+ _cache = new SerObjectInfoCache(_objectType);
+ }
+
+ private void InitMemberInfo()
+ {
+ _cache = new SerObjectInfoCache(_objectType);
+ _cache._memberInfos = FormatterServices.GetSerializableMembers(_objectType, _context);
+ _count = _cache._memberInfos.Length;
+ _cache._memberNames = new string[_count];
+ _cache._memberTypes = new Type[_count];
+
+ // Calculate new arrays
+ for (int i = 0; i < _count; i++)
+ {
+ _cache._memberNames[i] = _cache._memberInfos[i].Name;
+ _cache._memberTypes[i] = GetMemberType(_cache._memberInfos[i]);
+ }
+
+ _isTyped = true;
+ }
+
+ // Get the memberInfo for a memberName
+ internal MemberInfo GetMemberInfo(string name)
+ {
+ if (_cache == null)
+ {
+ return null;
+ }
+
+ if (_isSi)
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_MemberInfo, _objectType + " " + name));
+ }
+
+ if (_cache._memberInfos == null)
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_NoMemberInfo, _objectType + " " + name));
+ }
+
+ int position = Position(name);
+ return position != -1 ? _cache._memberInfos[position] : null;
+ }
+
+ // Get the ObjectType for a memberName
+ internal Type GetType(string name)
+ {
+ int position = Position(name);
+ if (position == -1)
+ {
+ return null;
+ }
+
+ Type type = _isTyped ? _cache._memberTypes[position] : _memberTypesList[position];
+ if (type == null)
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_ISerializableTypes, _objectType + " " + name));
+ }
+
+ return type;
+ }
+
+ // Adds the value for a memberName
+ internal void AddValue(string name, object value, ref SerializationInfo si, ref object[] memberData)
+ {
+ if (_isSi)
+ {
+ si.AddValue(name, value);
+ }
+ else
+ {
+ // If a member in the stream is not found, ignore it
+ int position = Position(name);
+ if (position != -1)
+ {
+ memberData[position] = value;
+ }
+ }
+ }
+
+ internal void InitDataStore(ref SerializationInfo si, ref object[] memberData)
+ {
+ if (_isSi)
+ {
+ if (si == null)
+ {
+ si = new SerializationInfo(_objectType, _formatterConverter);
+ }
+ }
+ else
+ {
+ if (memberData == null && _cache != null)
+ {
+ memberData = new object[_cache._memberNames.Length];
+ }
+ }
+ }
+
+ // Records an objectId in a member when the actual object for that member is not yet known
+ internal void RecordFixup(long objectId, string name, long idRef)
+ {
+ if (_isSi)
+ {
+ _objectManager.RecordDelayedFixup(objectId, name, idRef);
+ }
+ else
+ {
+ int position = Position(name);
+ if (position != -1)
+ {
+ _objectManager.RecordFixup(objectId, _cache._memberInfos[position], idRef);
+ }
+ }
+ }
+
+ // Fills in the values for an object
+ internal void PopulateObjectMembers(object obj, object[] memberData)
+ {
+ if (!_isSi && memberData != null)
+ {
+ FormatterServices.PopulateObjectMembers(obj, _cache._memberInfos, memberData);
+ }
+ }
+
+ // Specifies the position in the memberNames array of this name
+ private int Position(string name)
+ {
+ if (_cache == null)
+ {
+ return -1;
+ }
+
+ if (_cache._memberNames.Length > 0 && _cache._memberNames[_lastPosition].Equals(name))
+ {
+ return _lastPosition;
+ }
+ else if ((++_lastPosition < _cache._memberNames.Length) && (_cache._memberNames[_lastPosition].Equals(name)))
+ {
+ return _lastPosition;
+ }
+ else
+ {
+ // Search for name
+ for (int i = 0; i < _cache._memberNames.Length; i++)
+ {
+ if (_cache._memberNames[i].Equals(name))
+ {
+ _lastPosition = i;
+ return _lastPosition;
+ }
+ }
+
+ _lastPosition = 0;
+ return -1;
+ }
+ }
+
+ // Return the member Types in order of memberNames
+ internal Type[] GetMemberTypes(string[] inMemberNames, Type objectType)
+ {
+ if (_isSi)
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_ISerializableTypes, objectType));
+ }
+
+ if (_cache == null)
+ {
+ return null;
+ }
+
+ if (_cache._memberTypes == null)
+ {
+ _cache._memberTypes = new Type[_count];
+ for (int i = 0; i < _count; i++)
+ {
+ _cache._memberTypes[i] = GetMemberType(_cache._memberInfos[i]);
+ }
+ }
+
+ bool memberMissing = false;
+ if (inMemberNames.Length < _cache._memberInfos.Length)
+ {
+ memberMissing = true;
+ }
+
+ Type[] outMemberTypes = new Type[_cache._memberInfos.Length];
+ bool isFound = false;
+ for (int i = 0; i < _cache._memberInfos.Length; i++)
+ {
+ if (!memberMissing && inMemberNames[i].Equals(_cache._memberInfos[i].Name))
+ {
+ outMemberTypes[i] = _cache._memberTypes[i];
+ }
+ else
+ {
+ // MemberNames on wire in different order then memberInfos returned by reflection
+ isFound = false;
+ for (int j = 0; j < inMemberNames.Length; j++)
+ {
+ if (_cache._memberInfos[i].Name.Equals(inMemberNames[j]))
+ {
+ outMemberTypes[i] = _cache._memberTypes[i];
+ isFound = true;
+ break;
+ }
+ }
+ if (!isFound)
+ {
+ // A field on the type isn't found. See if the field has OptionalFieldAttribute. We only throw
+ // when the assembly format is set appropriately.
+ if (!_isSimpleAssembly &&
+ _cache._memberInfos[i].GetCustomAttribute(typeof(OptionalFieldAttribute), inherit: false) == null)
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_MissingMember, _cache._memberNames[i], objectType, typeof(OptionalFieldAttribute).FullName));
+ }
+ }
+ }
+ }
+
+ return outMemberTypes;
+ }
+
+ // Retrieves the member type from the MemberInfo
+ internal Type GetMemberType(MemberInfo objMember)
+ {
+ if (objMember is FieldInfo)
+ {
+ return ((FieldInfo)objMember).FieldType;
+ }
+
+ throw new SerializationException(SR.Format(SR.Serialization_SerMemberInfo, objMember.GetType()));
+ }
+
+
+ private static ReadObjectInfo GetObjectInfo(SerObjectInfoInit serObjectInfoInit)
+ {
+ ReadObjectInfo roi = new ReadObjectInfo();
+ roi._objectInfoId = Interlocked.Increment(ref _readObjectInfoCounter);
+ return roi;
+ }
+ }
+
+ internal sealed class SerObjectInfoInit
+ {
+ internal readonly Dictionary _seenBeforeTable = new Dictionary();
+ internal int _objectInfoIdCount = 1;
+ internal SerStack _oiPool = new SerStack("SerObjectInfo Pool");
+ }
+
+ internal sealed class SerObjectInfoCache
+ {
+ internal readonly string _fullTypeName;
+ internal readonly string _assemblyString;
+ internal readonly bool _hasTypeForwardedFrom;
+
+ internal MemberInfo[] _memberInfos;
+ internal string[] _memberNames;
+ internal Type[] _memberTypes;
+
+ internal SerObjectInfoCache(string typeName, string assemblyName, bool hasTypeForwardedFrom)
+ {
+ _fullTypeName = typeName;
+ _assemblyString = assemblyName;
+ _hasTypeForwardedFrom = hasTypeForwardedFrom;
+ }
+
+ internal SerObjectInfoCache(Type type)
+ {
+ TypeInformation typeInformation = BinaryFormatter.GetTypeInformation(type);
+ _fullTypeName = typeInformation.FullTypeName;
+ _assemblyString = typeInformation.AssemblyString;
+ _hasTypeForwardedFrom = typeInformation.HasTypeForwardedFrom;
+ }
+ }
+
+ internal sealed class TypeInformation
+ {
+ internal TypeInformation(string fullTypeName, string assemblyString, bool hasTypeForwardedFrom)
+ {
+ FullTypeName = fullTypeName;
+ AssemblyString = assemblyString;
+ HasTypeForwardedFrom = hasTypeForwardedFrom;
+ }
+
+ internal string FullTypeName { get; }
+ internal string AssemblyString { get; }
+ internal bool HasTypeForwardedFrom { get; }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectReader.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectReader.cs
new file mode 100644
index 000000000000..03c16fefce20
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectReader.cs
@@ -0,0 +1,1088 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Runtime.Remoting.Messaging;
+using System.Diagnostics;
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class ObjectReader
+ {
+ // System.Serializer information
+ internal Stream _stream;
+ internal ISurrogateSelector _surrogates;
+ internal StreamingContext _context;
+ internal ObjectManager _objectManager;
+ internal InternalFE _formatterEnums;
+ internal SerializationBinder _binder;
+
+ // Top object and headers
+ internal long _topId;
+ internal bool _isSimpleAssembly = false;
+ internal object _handlerObject;
+ internal object _topObject;
+ internal Header[] _headers;
+ internal HeaderHandler _handler;
+ internal SerObjectInfoInit _serObjectInfoInit;
+ internal IFormatterConverter _formatterConverter;
+
+ // Stack of Object ParseRecords
+ internal SerStack _stack;
+
+ // ValueType Fixup Stack
+ private SerStack _valueFixupStack;
+
+ // Cross AppDomain
+ internal object[] _crossAppDomainArray; //Set by the BinaryFormatter
+
+ //MethodCall and MethodReturn are handled special for perf reasons
+ private bool _fullDeserialization;
+
+ private SerStack ValueFixupStack => _valueFixupStack ?? (_valueFixupStack = new SerStack("ValueType Fixup Stack"));
+
+ // Older formatters generate ids for valuetypes using a different counter than ref types. Newer ones use
+ // a single counter, only value types have a negative value. Need a way to handle older formats.
+ private const int ThresholdForValueTypeIds = int.MaxValue;
+ private bool _oldFormatDetected = false;
+ private IntSizedArray _valTypeObjectIdTable;
+
+ private readonly NameCache _typeCache = new NameCache();
+
+ internal object TopObject
+ {
+ get { return _topObject; }
+ set
+ {
+ _topObject = value;
+ if (_objectManager != null)
+ {
+ _objectManager.TopObject = value;
+ }
+ }
+ }
+
+ internal ObjectReader(Stream stream, ISurrogateSelector selector, StreamingContext context, InternalFE formatterEnums, SerializationBinder binder)
+ {
+ if (stream == null)
+ {
+ throw new ArgumentNullException(nameof(stream), SR.ArgumentNull_Stream);
+ }
+
+ _stream = stream;
+ _surrogates = selector;
+ _context = context;
+ _binder = binder;
+ _formatterEnums = formatterEnums;
+ }
+
+ internal object Deserialize(HeaderHandler handler, BinaryParser serParser, bool fCheck)
+ {
+ if (serParser == null)
+ {
+ throw new ArgumentNullException(nameof(serParser), SR.Format(SR.ArgumentNull_WithParamName, serParser));
+ }
+
+ _fullDeserialization = false;
+ TopObject = null;
+ _topId = 0;
+
+ _isSimpleAssembly = (_formatterEnums._FEassemblyFormat == FormatterAssemblyStyle.Simple);
+
+ _handler = handler;
+
+ if (_fullDeserialization)
+ {
+ // Reinitialize
+ _objectManager = new ObjectManager(_surrogates, _context, false, false);
+ _serObjectInfoInit = new SerObjectInfoInit();
+ }
+
+ // Will call back to ParseObject, ParseHeader for each object found
+ serParser.Run();
+
+ if (_fullDeserialization)
+ {
+ _objectManager.DoFixups();
+ }
+
+ if (TopObject == null)
+ {
+ throw new SerializationException(SR.Serialization_TopObject);
+ }
+
+ //if TopObject has a surrogate then the actual object may be changed during special fixup
+ //So refresh it using topID.
+ if (HasSurrogate(TopObject.GetType()) && _topId != 0)//Not yet resolved
+ {
+ TopObject = _objectManager.GetObject(_topId);
+ }
+
+ if (TopObject is IObjectReference)
+ {
+ TopObject = ((IObjectReference)TopObject).GetRealObject(_context);
+ }
+
+ if (_fullDeserialization)
+ {
+ _objectManager.RaiseDeserializationEvent(); // This will raise both IDeserialization and [OnDeserialized] events
+ }
+
+ // Return the headers if there is a handler
+ if (handler != null)
+ {
+ _handlerObject = handler(_headers);
+ }
+
+ return TopObject;
+ }
+
+ private bool HasSurrogate(Type t)
+ {
+ ISurrogateSelector ignored;
+ return _surrogates != null && _surrogates.GetSurrogate(t, _context, out ignored) != null;
+ }
+
+ private void CheckSerializable(Type t)
+ {
+ if (!t.GetTypeInfo().IsSerializable && !HasSurrogate(t))
+ {
+ throw new SerializationException(string.Format(CultureInfo.InvariantCulture, SR.Serialization_NonSerType, t.FullName, t.GetTypeInfo().Assembly.FullName));
+ }
+ }
+
+ private void InitFullDeserialization()
+ {
+ _fullDeserialization = true;
+ _stack = new SerStack("ObjectReader Object Stack");
+ _objectManager = new ObjectManager(_surrogates, _context, false, false);
+ if (_formatterConverter == null)
+ {
+ _formatterConverter = new FormatterConverter();
+ }
+ }
+
+ internal object CrossAppDomainArray(int index)
+ {
+ Debug.Assert(index < _crossAppDomainArray.Length, "[System.Runtime.Serialization.Formatters.BinaryObjectReader index out of range for CrossAppDomainArray]");
+ return _crossAppDomainArray[index];
+ }
+
+ internal ReadObjectInfo CreateReadObjectInfo(Type objectType)
+ {
+ return ReadObjectInfo.Create(objectType, _surrogates, _context, _objectManager, _serObjectInfoInit, _formatterConverter, _isSimpleAssembly);
+ }
+
+ internal ReadObjectInfo CreateReadObjectInfo(Type objectType, string[] memberNames, Type[] memberTypes)
+ {
+ return ReadObjectInfo.Create(objectType, memberNames, memberTypes, _surrogates, _context, _objectManager, _serObjectInfoInit, _formatterConverter, _isSimpleAssembly);
+ }
+
+ internal void Parse(ParseRecord pr)
+ {
+ switch (pr._PRparseTypeEnum)
+ {
+ case InternalParseTypeE.SerializedStreamHeader:
+ ParseSerializedStreamHeader(pr);
+ break;
+ case InternalParseTypeE.SerializedStreamHeaderEnd:
+ ParseSerializedStreamHeaderEnd(pr);
+ break;
+ case InternalParseTypeE.Object:
+ ParseObject(pr);
+ break;
+ case InternalParseTypeE.ObjectEnd:
+ ParseObjectEnd(pr);
+ break;
+ case InternalParseTypeE.Member:
+ ParseMember(pr);
+ break;
+ case InternalParseTypeE.MemberEnd:
+ ParseMemberEnd(pr);
+ break;
+ case InternalParseTypeE.Body:
+ case InternalParseTypeE.BodyEnd:
+ case InternalParseTypeE.Envelope:
+ case InternalParseTypeE.EnvelopeEnd:
+ break;
+ case InternalParseTypeE.Empty:
+ default:
+ throw new SerializationException(SR.Format(SR.Serialization_XMLElement, pr._PRname));
+ }
+ }
+
+ // Styled ParseError output
+ private void ParseError(ParseRecord processing, ParseRecord onStack)
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_ParseError, onStack._PRname + " " + onStack._PRparseTypeEnum + " " + processing._PRname + " " + processing._PRparseTypeEnum));
+ }
+
+ // Parse the SerializedStreamHeader element. This is the first element in the stream if present
+ private void ParseSerializedStreamHeader(ParseRecord pr) => _stack.Push(pr);
+
+ // Parse the SerializedStreamHeader end element. This is the last element in the stream if present
+ private void ParseSerializedStreamHeaderEnd(ParseRecord pr) => _stack.Pop();
+
+ // New object encountered in stream
+ private void ParseObject(ParseRecord pr)
+ {
+ if (!_fullDeserialization)
+ {
+ InitFullDeserialization();
+ }
+
+ if (pr._PRobjectPositionEnum == InternalObjectPositionE.Top)
+ {
+ _topId = pr._PRobjectId;
+ }
+
+ if (pr._PRparseTypeEnum == InternalParseTypeE.Object)
+ {
+ _stack.Push(pr); // Nested objects member names are already on stack
+ }
+
+ if (pr._PRobjectTypeEnum == InternalObjectTypeE.Array)
+ {
+ ParseArray(pr);
+ return;
+ }
+
+ // If the Type is null, this means we have a typeload issue
+ // mark the object with TypeLoadExceptionHolder
+ if (pr._PRdtType == null)
+ {
+ pr._PRnewObj = new TypeLoadExceptionHolder(pr._PRkeyDt);
+ return;
+ }
+
+ if (ReferenceEquals(pr._PRdtType, Converter.s_typeofString))
+ {
+ // String as a top level object
+ if (pr._PRvalue != null)
+ {
+ pr._PRnewObj = pr._PRvalue;
+ if (pr._PRobjectPositionEnum == InternalObjectPositionE.Top)
+ {
+ TopObject = pr._PRnewObj;
+ return;
+ }
+ else
+ {
+ _stack.Pop();
+ RegisterObject(pr._PRnewObj, pr, (ParseRecord)_stack.Peek());
+ return;
+ }
+ }
+ else
+ {
+ // xml Doesn't have the value until later
+ return;
+ }
+ }
+ else
+ {
+ CheckSerializable(pr._PRdtType);
+ pr._PRnewObj = FormatterServices.GetUninitializedObject(pr._PRdtType);
+
+ // Run the OnDeserializing methods
+ _objectManager.RaiseOnDeserializingEvent(pr._PRnewObj);
+ }
+
+ if (pr._PRnewObj == null)
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_TopObjectInstantiate, pr._PRdtType));
+ }
+
+ if (pr._PRobjectPositionEnum == InternalObjectPositionE.Top)
+ {
+ TopObject = pr._PRnewObj;
+ }
+
+ if (pr._PRobjectInfo == null)
+ {
+ pr._PRobjectInfo = ReadObjectInfo.Create(pr._PRdtType, _surrogates, _context, _objectManager, _serObjectInfoInit, _formatterConverter, _isSimpleAssembly);
+ }
+ }
+
+ // End of object encountered in stream
+ private void ParseObjectEnd(ParseRecord pr)
+ {
+ ParseRecord objectPr = (ParseRecord)_stack.Peek() ?? pr;
+
+ if (objectPr._PRobjectPositionEnum == InternalObjectPositionE.Top)
+ {
+ if (ReferenceEquals(objectPr._PRdtType, Converter.s_typeofString))
+ {
+ objectPr._PRnewObj = objectPr._PRvalue;
+ TopObject = objectPr._PRnewObj;
+ return;
+ }
+ }
+
+ _stack.Pop();
+ ParseRecord parentPr = (ParseRecord)_stack.Peek();
+
+ if (objectPr._PRnewObj == null)
+ {
+ return;
+ }
+
+ if (objectPr._PRobjectTypeEnum == InternalObjectTypeE.Array)
+ {
+ if (objectPr._PRobjectPositionEnum == InternalObjectPositionE.Top)
+ {
+ TopObject = objectPr._PRnewObj;
+ }
+
+ RegisterObject(objectPr._PRnewObj, objectPr, parentPr);
+ return;
+ }
+
+ objectPr._PRobjectInfo.PopulateObjectMembers(objectPr._PRnewObj, objectPr._PRmemberData);
+
+ // Registration is after object is populated
+ if ((!objectPr._PRisRegistered) && (objectPr._PRobjectId > 0))
+ {
+ RegisterObject(objectPr._PRnewObj, objectPr, parentPr);
+ }
+
+ if (objectPr._PRisValueTypeFixup)
+ {
+ ValueFixup fixup = (ValueFixup)ValueFixupStack.Pop(); //Value fixup
+ fixup.Fixup(objectPr, parentPr); // Value fixup
+ }
+
+ if (objectPr._PRobjectPositionEnum == InternalObjectPositionE.Top)
+ {
+ TopObject = objectPr._PRnewObj;
+ }
+
+ objectPr._PRobjectInfo.ObjectEnd();
+ }
+
+ // Array object encountered in stream
+ private void ParseArray(ParseRecord pr)
+ {
+ long genId = pr._PRobjectId;
+
+ if (pr._PRarrayTypeEnum == InternalArrayTypeE.Base64)
+ {
+ // ByteArray
+ pr._PRnewObj = pr._PRvalue.Length > 0 ?
+ Convert.FromBase64String(pr._PRvalue) :
+ Array.Empty();
+
+ if (_stack.Peek() == pr)
+ {
+ _stack.Pop();
+ }
+ if (pr._PRobjectPositionEnum == InternalObjectPositionE.Top)
+ {
+ TopObject = pr._PRnewObj;
+ }
+
+ ParseRecord parentPr = (ParseRecord)_stack.Peek();
+
+ // Base64 can be registered at this point because it is populated
+ RegisterObject(pr._PRnewObj, pr, parentPr);
+ }
+ else if ((pr._PRnewObj != null) && Converter.IsWriteAsByteArray(pr._PRarrayElementTypeCode))
+ {
+ // Primtive typed Array has already been read
+ if (pr._PRobjectPositionEnum == InternalObjectPositionE.Top)
+ {
+ TopObject = pr._PRnewObj;
+ }
+
+ ParseRecord parentPr = (ParseRecord)_stack.Peek();
+
+ // Primitive typed array can be registered at this point because it is populated
+ RegisterObject(pr._PRnewObj, pr, parentPr);
+ }
+ else if ((pr._PRarrayTypeEnum == InternalArrayTypeE.Jagged) || (pr._PRarrayTypeEnum == InternalArrayTypeE.Single))
+ {
+ // Multidimensional jagged array or single array
+ bool couldBeValueType = true;
+ if ((pr._PRlowerBoundA == null) || (pr._PRlowerBoundA[0] == 0))
+ {
+ if (ReferenceEquals(pr._PRarrayElementType, Converter.s_typeofString))
+ {
+ pr._PRobjectA = new string[pr._PRlengthA[0]];
+ pr._PRnewObj = pr._PRobjectA;
+ couldBeValueType = false;
+ }
+ else if (ReferenceEquals(pr._PRarrayElementType, Converter.s_typeofObject))
+ {
+ pr._PRobjectA = new object[pr._PRlengthA[0]];
+ pr._PRnewObj = pr._PRobjectA;
+ couldBeValueType = false;
+ }
+ else if (pr._PRarrayElementType != null)
+ {
+ pr._PRnewObj = Array.CreateInstance(pr._PRarrayElementType, pr._PRlengthA[0]);
+ }
+ pr._PRisLowerBound = false;
+ }
+ else
+ {
+ if (pr._PRarrayElementType != null)
+ {
+ pr._PRnewObj = Array.CreateInstance(pr._PRarrayElementType, pr._PRlengthA, pr._PRlowerBoundA);
+ }
+ pr._PRisLowerBound = true;
+ }
+
+ if (pr._PRarrayTypeEnum == InternalArrayTypeE.Single)
+ {
+ if (!pr._PRisLowerBound && (Converter.IsWriteAsByteArray(pr._PRarrayElementTypeCode)))
+ {
+ pr._PRprimitiveArray = new PrimitiveArray(pr._PRarrayElementTypeCode, (Array)pr._PRnewObj);
+ }
+ else if (couldBeValueType && pr._PRarrayElementType != null)
+ {
+ if (!pr._PRarrayElementType.GetTypeInfo().IsValueType && !pr._PRisLowerBound)
+ {
+ pr._PRobjectA = (object[])pr._PRnewObj;
+ }
+ }
+ }
+
+ // For binary, headers comes in as an array of header objects
+ if (pr._PRobjectPositionEnum == InternalObjectPositionE.Headers)
+ {
+ _headers = (Header[])pr._PRnewObj;
+ }
+
+ pr._PRindexMap = new int[1];
+ }
+ else if (pr._PRarrayTypeEnum == InternalArrayTypeE.Rectangular)
+ {
+ // Rectangle array
+
+ pr._PRisLowerBound = false;
+ if (pr._PRlowerBoundA != null)
+ {
+ for (int i = 0; i < pr._PRrank; i++)
+ {
+ if (pr._PRlowerBoundA[i] != 0)
+ {
+ pr._PRisLowerBound = true;
+ }
+ }
+ }
+
+ if (pr._PRarrayElementType != null)
+ {
+ pr._PRnewObj = !pr._PRisLowerBound ?
+ Array.CreateInstance(pr._PRarrayElementType, pr._PRlengthA) :
+ Array.CreateInstance(pr._PRarrayElementType, pr._PRlengthA, pr._PRlowerBoundA);
+ }
+
+ // Calculate number of items
+ int sum = 1;
+ for (int i = 0; i < pr._PRrank; i++)
+ {
+ sum = sum * pr._PRlengthA[i];
+ }
+ pr._PRindexMap = new int[pr._PRrank];
+ pr._PRrectangularMap = new int[pr._PRrank];
+ pr._PRlinearlength = sum;
+ }
+ else
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_ArrayType, pr._PRarrayTypeEnum));
+ }
+ }
+
+ // Builds a map for each item in an incoming rectangle array. The map specifies where the item is placed in the output Array Object
+ private void NextRectangleMap(ParseRecord pr)
+ {
+ // For each invocation, calculate the next rectangular array position
+ // example
+ // indexMap 0 [0,0,0]
+ // indexMap 1 [0,0,1]
+ // indexMap 2 [0,0,2]
+ // indexMap 3 [0,0,3]
+ // indexMap 4 [0,1,0]
+ for (int irank = pr._PRrank - 1; irank > -1; irank--)
+ {
+ // Find the current or lower dimension which can be incremented.
+ if (pr._PRrectangularMap[irank] < pr._PRlengthA[irank] - 1)
+ {
+ // The current dimension is at maximum. Increase the next lower dimension by 1
+ pr._PRrectangularMap[irank]++;
+ if (irank < pr._PRrank - 1)
+ {
+ // The current dimension and higher dimensions are zeroed.
+ for (int i = irank + 1; i < pr._PRrank; i++)
+ {
+ pr._PRrectangularMap[i] = 0;
+ }
+ }
+ Array.Copy(pr._PRrectangularMap, 0, pr._PRindexMap, 0, pr._PRrank);
+ break;
+ }
+ }
+ }
+
+
+ // Array object item encountered in stream
+ private void ParseArrayMember(ParseRecord pr)
+ {
+ ParseRecord objectPr = (ParseRecord)_stack.Peek();
+
+ // Set up for inserting value into correct array position
+ if (objectPr._PRarrayTypeEnum == InternalArrayTypeE.Rectangular)
+ {
+ if (objectPr._PRmemberIndex > 0)
+ {
+ NextRectangleMap(objectPr); // Rectangle array, calculate position in array
+ }
+ if (objectPr._PRisLowerBound)
+ {
+ for (int i = 0; i < objectPr._PRrank; i++)
+ {
+ objectPr._PRindexMap[i] = objectPr._PRrectangularMap[i] + objectPr._PRlowerBoundA[i];
+ }
+ }
+ }
+ else
+ {
+ objectPr._PRindexMap[0] = !objectPr._PRisLowerBound ?
+ objectPr._PRmemberIndex : // Zero based array
+ objectPr._PRlowerBoundA[0] + objectPr._PRmemberIndex; // Lower Bound based array
+ }
+
+ // Set Array element according to type of element
+
+ if (pr._PRmemberValueEnum == InternalMemberValueE.Reference)
+ {
+ // Object Reference
+
+ // See if object has already been instantiated
+ object refObj = _objectManager.GetObject(pr._PRidRef);
+ if (refObj == null)
+ {
+ // Object not instantiated
+ // Array fixup manager
+ int[] fixupIndex = new int[objectPr._PRrank];
+ Array.Copy(objectPr._PRindexMap, 0, fixupIndex, 0, objectPr._PRrank);
+
+ _objectManager.RecordArrayElementFixup(objectPr._PRobjectId, fixupIndex, pr._PRidRef);
+ }
+ else
+ {
+ if (objectPr._PRobjectA != null)
+ {
+ objectPr._PRobjectA[objectPr._PRindexMap[0]] = refObj;
+ }
+ else
+ {
+ ((Array)objectPr._PRnewObj).SetValue(refObj, objectPr._PRindexMap); // Object has been instantiated
+ }
+ }
+ }
+ else if (pr._PRmemberValueEnum == InternalMemberValueE.Nested)
+ {
+ //Set up dtType for ParseObject
+ if (pr._PRdtType == null)
+ {
+ pr._PRdtType = objectPr._PRarrayElementType;
+ }
+
+ ParseObject(pr);
+ _stack.Push(pr);
+
+ if (objectPr._PRarrayElementType != null)
+ {
+ if ((objectPr._PRarrayElementType.GetTypeInfo().IsValueType) && (pr._PRarrayElementTypeCode == InternalPrimitiveTypeE.Invalid))
+ {
+ pr._PRisValueTypeFixup = true; //Valuefixup
+ ValueFixupStack.Push(new ValueFixup((Array)objectPr._PRnewObj, objectPr._PRindexMap)); //valuefixup
+ }
+ else
+ {
+ if (objectPr._PRobjectA != null)
+ {
+ objectPr._PRobjectA[objectPr._PRindexMap[0]] = pr._PRnewObj;
+ }
+ else
+ {
+ ((Array)objectPr._PRnewObj).SetValue(pr._PRnewObj, objectPr._PRindexMap);
+ }
+ }
+ }
+ }
+ else if (pr._PRmemberValueEnum == InternalMemberValueE.InlineValue)
+ {
+ if ((ReferenceEquals(objectPr._PRarrayElementType, Converter.s_typeofString)) || (ReferenceEquals(pr._PRdtType, Converter.s_typeofString)))
+ {
+ // String in either a string array, or a string element of an object array
+ ParseString(pr, objectPr);
+ if (objectPr._PRobjectA != null)
+ {
+ objectPr._PRobjectA[objectPr._PRindexMap[0]] = pr._PRvalue;
+ }
+ else
+ {
+ ((Array)objectPr._PRnewObj).SetValue(pr._PRvalue, objectPr._PRindexMap);
+ }
+ }
+ else if (objectPr._PRisArrayVariant)
+ {
+ // Array of type object
+ if (pr._PRkeyDt == null)
+ {
+ throw new SerializationException(SR.Serialization_ArrayTypeObject);
+ }
+
+ object var = null;
+
+ if (ReferenceEquals(pr._PRdtType, Converter.s_typeofString))
+ {
+ ParseString(pr, objectPr);
+ var = pr._PRvalue;
+ }
+ else if (ReferenceEquals(pr._PRdtTypeCode, InternalPrimitiveTypeE.Invalid))
+ {
+ CheckSerializable(pr._PRdtType);
+ // Not nested and invalid, so it is an empty object
+ var = FormatterServices.GetUninitializedObject(pr._PRdtType);
+ }
+ else
+ {
+ var = pr._PRvarValue != null ?
+ pr._PRvarValue :
+ Converter.FromString(pr._PRvalue, pr._PRdtTypeCode);
+ }
+ if (objectPr._PRobjectA != null)
+ {
+ objectPr._PRobjectA[objectPr._PRindexMap[0]] = var;
+ }
+ else
+ {
+ ((Array)objectPr._PRnewObj).SetValue(var, objectPr._PRindexMap); // Primitive type
+ }
+ }
+ else
+ {
+ // Primitive type
+ if (objectPr._PRprimitiveArray != null)
+ {
+ // Fast path for Soap primitive arrays. Binary was handled in the BinaryParser
+ objectPr._PRprimitiveArray.SetValue(pr._PRvalue, objectPr._PRindexMap[0]);
+ }
+ else
+ {
+ object var = pr._PRvarValue != null ?
+ pr._PRvarValue :
+ Converter.FromString(pr._PRvalue, objectPr._PRarrayElementTypeCode);
+ if (objectPr._PRobjectA != null)
+ {
+ objectPr._PRobjectA[objectPr._PRindexMap[0]] = var;
+ }
+ else
+ {
+ ((Array)objectPr._PRnewObj).SetValue(var, objectPr._PRindexMap); // Primitive type
+ }
+ }
+ }
+ }
+ else if (pr._PRmemberValueEnum == InternalMemberValueE.Null)
+ {
+ objectPr._PRmemberIndex += pr._consecutiveNullArrayEntryCount - 1; //also incremented again below
+ }
+ else
+ {
+ ParseError(pr, objectPr);
+ }
+
+ objectPr._PRmemberIndex++;
+ }
+
+ private void ParseArrayMemberEnd(ParseRecord pr)
+ {
+ // If this is a nested array object, then pop the stack
+ if (pr._PRmemberValueEnum == InternalMemberValueE.Nested)
+ {
+ ParseObjectEnd(pr);
+ }
+ }
+
+ // Object member encountered in stream
+ private void ParseMember(ParseRecord pr)
+ {
+ ParseRecord objectPr = (ParseRecord)_stack.Peek();
+ string objName = objectPr?._PRname;
+
+ switch (pr._PRmemberTypeEnum)
+ {
+ case InternalMemberTypeE.Item:
+ ParseArrayMember(pr);
+ return;
+ case InternalMemberTypeE.Field:
+ break;
+ }
+
+ //if ((pr.PRdtType == null) && !objectPr.PRobjectInfo.isSi)
+ if (pr._PRdtType == null && objectPr._PRobjectInfo._isTyped)
+ {
+ pr._PRdtType = objectPr._PRobjectInfo.GetType(pr._PRname);
+
+ if (pr._PRdtType != null)
+ {
+ pr._PRdtTypeCode = Converter.ToCode(pr._PRdtType);
+ }
+ }
+
+ if (pr._PRmemberValueEnum == InternalMemberValueE.Null)
+ {
+ // Value is Null
+ objectPr._PRobjectInfo.AddValue(pr._PRname, null, ref objectPr._PRsi, ref objectPr._PRmemberData);
+ }
+ else if (pr._PRmemberValueEnum == InternalMemberValueE.Nested)
+ {
+ ParseObject(pr);
+ _stack.Push(pr);
+
+ if ((pr._PRobjectInfo != null) && pr._PRobjectInfo._objectType != null && (pr._PRobjectInfo._objectType.GetTypeInfo().IsValueType))
+ {
+ pr._PRisValueTypeFixup = true; //Valuefixup
+ ValueFixupStack.Push(new ValueFixup(objectPr._PRnewObj, pr._PRname, objectPr._PRobjectInfo));//valuefixup
+ }
+ else
+ {
+ objectPr._PRobjectInfo.AddValue(pr._PRname, pr._PRnewObj, ref objectPr._PRsi, ref objectPr._PRmemberData);
+ }
+ }
+ else if (pr._PRmemberValueEnum == InternalMemberValueE.Reference)
+ {
+ // See if object has already been instantiated
+ object refObj = _objectManager.GetObject(pr._PRidRef);
+ if (refObj == null)
+ {
+ objectPr._PRobjectInfo.AddValue(pr._PRname, null, ref objectPr._PRsi, ref objectPr._PRmemberData);
+ objectPr._PRobjectInfo.RecordFixup(objectPr._PRobjectId, pr._PRname, pr._PRidRef); // Object not instantiated
+ }
+ else
+ {
+ objectPr._PRobjectInfo.AddValue(pr._PRname, refObj, ref objectPr._PRsi, ref objectPr._PRmemberData);
+ }
+ }
+
+ else if (pr._PRmemberValueEnum == InternalMemberValueE.InlineValue)
+ {
+ // Primitive type or String
+ if (ReferenceEquals(pr._PRdtType, Converter.s_typeofString))
+ {
+ ParseString(pr, objectPr);
+ objectPr._PRobjectInfo.AddValue(pr._PRname, pr._PRvalue, ref objectPr._PRsi, ref objectPr._PRmemberData);
+ }
+ else if (pr._PRdtTypeCode == InternalPrimitiveTypeE.Invalid)
+ {
+ // The member field was an object put the value is Inline either bin.Base64 or invalid
+ if (pr._PRarrayTypeEnum == InternalArrayTypeE.Base64)
+ {
+ objectPr._PRobjectInfo.AddValue(pr._PRname, Convert.FromBase64String(pr._PRvalue), ref objectPr._PRsi, ref objectPr._PRmemberData);
+ }
+ else if (ReferenceEquals(pr._PRdtType, Converter.s_typeofObject))
+ {
+ throw new SerializationException(SR.Format(SR.Serialization_TypeMissing, pr._PRname));
+ }
+ else
+ {
+ ParseString(pr, objectPr); // Register the object if it has an objectId
+ // Object Class with no memberInfo data
+ // only special case where AddValue is needed?
+ if (ReferenceEquals(pr._PRdtType, Converter.s_typeofSystemVoid))
+ {
+ objectPr._PRobjectInfo.AddValue(pr._PRname, pr._PRdtType, ref objectPr._PRsi, ref objectPr._PRmemberData);
+ }
+ else if (objectPr._PRobjectInfo._isSi)
+ {
+ // ISerializable are added as strings, the conversion to type is done by the
+ // ISerializable object
+ objectPr._PRobjectInfo.AddValue(pr._PRname, pr._PRvalue, ref objectPr._PRsi, ref objectPr._PRmemberData);
+ }
+ }
+ }
+ else
+ {
+ object var = pr._PRvarValue != null ?
+ pr._PRvarValue :
+ Converter.FromString(pr._PRvalue, pr._PRdtTypeCode);
+ objectPr._PRobjectInfo.AddValue(pr._PRname, var, ref objectPr._PRsi, ref objectPr._PRmemberData);
+ }
+ }
+ else
+ {
+ ParseError(pr, objectPr);
+ }
+ }
+
+ // Object member end encountered in stream
+ private void ParseMemberEnd(ParseRecord pr)
+ {
+ switch (pr._PRmemberTypeEnum)
+ {
+ case InternalMemberTypeE.Item:
+ ParseArrayMemberEnd(pr);
+ return;
+ case InternalMemberTypeE.Field:
+ if (pr._PRmemberValueEnum == InternalMemberValueE.Nested)
+ {
+ ParseObjectEnd(pr);
+ }
+ break;
+ default:
+ ParseError(pr, (ParseRecord)_stack.Peek());
+ break;
+ }
+ }
+
+ // Processes a string object by getting an internal ID for it and registering it with the objectManager
+ private void ParseString(ParseRecord pr, ParseRecord parentPr)
+ {
+ // Process String class
+ if ((!pr._PRisRegistered) && (pr._PRobjectId > 0))
+ {
+ // String is treated as an object if it has an id
+ //m_objectManager.RegisterObject(pr.PRvalue, pr.PRobjectId);
+ RegisterObject(pr._PRvalue, pr, parentPr, true);
+ }
+ }
+
+ private void RegisterObject(object obj, ParseRecord pr, ParseRecord objectPr)
+ {
+ RegisterObject(obj, pr, objectPr, false);
+ }
+
+ private void RegisterObject(object obj, ParseRecord pr, ParseRecord objectPr, bool bIsString)
+ {
+ if (!pr._PRisRegistered)
+ {
+ pr._PRisRegistered = true;
+
+ SerializationInfo si = null;
+ long parentId = 0;
+ MemberInfo memberInfo = null;
+ int[] indexMap = null;
+
+ if (objectPr != null)
+ {
+ indexMap = objectPr._PRindexMap;
+ parentId = objectPr._PRobjectId;
+
+ if (objectPr._PRobjectInfo != null)
+ {
+ if (!objectPr._PRobjectInfo._isSi)
+ {
+ // ParentId is only used if there is a memberInfo
+ memberInfo = objectPr._PRobjectInfo.GetMemberInfo(pr._PRname);
+ }
+ }
+ }
+ // SerializationInfo is always needed for ISerialization
+ si = pr._PRsi;
+
+ if (bIsString)
+ {
+ _objectManager.RegisterString((string)obj, pr._PRobjectId, si, parentId, memberInfo);
+ }
+ else
+ {
+ _objectManager.RegisterObject(obj, pr._PRobjectId, si, parentId, memberInfo, indexMap);
+ }
+ }
+ }
+
+ // Assigns an internal ID associated with the binary id number
+ internal long GetId(long objectId)
+ {
+ if (!_fullDeserialization)
+ {
+ InitFullDeserialization();
+ }
+
+ if (objectId > 0)
+ {
+ return objectId;
+ }
+
+ if (_oldFormatDetected || objectId == -1)
+ {
+ // Alarm bells. This is an old format. Deal with it.
+ _oldFormatDetected = true;
+ if (_valTypeObjectIdTable == null)
+ {
+ _valTypeObjectIdTable = new IntSizedArray();
+ }
+
+ long tempObjId = 0;
+ if ((tempObjId = _valTypeObjectIdTable[(int)objectId]) == 0)
+ {
+ tempObjId = ThresholdForValueTypeIds + objectId;
+ _valTypeObjectIdTable[(int)objectId] = (int)tempObjId;
+ }
+ return tempObjId;
+ }
+
+ return -1 * objectId;
+ }
+
+ internal Type Bind(string assemblyString, string typeString)
+ {
+ Type type = null;
+ if (_binder != null)
+ {
+ type = _binder.BindToType(assemblyString, typeString);
+ }
+ if (type == null)
+ {
+ type = FastBindToType(assemblyString, typeString);
+ }
+ return type;
+ }
+
+ internal sealed class TypeNAssembly
+ {
+ public Type Type;
+ public string AssemblyName;
+ }
+
+ internal Type FastBindToType(string assemblyName, string typeName)
+ {
+ Type type = null;
+
+ TypeNAssembly entry = (TypeNAssembly)_typeCache.GetCachedValue(typeName);
+
+ if (entry == null || entry.AssemblyName != assemblyName)
+ {
+ Assembly assm = null;
+ if (_isSimpleAssembly)
+ {
+ try
+ {
+ Assembly.Load(new AssemblyName(assemblyName));
+ }
+ catch { }
+
+ if (assm == null)
+ {
+ return null;
+ }
+
+ GetSimplyNamedTypeFromAssembly(assm, typeName, ref type);
+ }
+ else
+ {
+ try
+ {
+ assm = Assembly.Load(new AssemblyName(assemblyName));
+ }
+ catch { }
+
+ if (assm == null)
+ {
+ return null;
+ }
+
+ type = FormatterServices.GetTypeFromAssembly(assm, typeName);
+ }
+
+ if (type == null)
+ {
+ return null;
+ }
+
+ // before adding it to cache, let us do the security check
+ CheckTypeForwardedTo(assm, type.GetTypeInfo().Assembly, type);
+
+ entry = new TypeNAssembly();
+ entry.Type = type;
+ entry.AssemblyName = assemblyName;
+ _typeCache.SetCachedValue(entry);
+ }
+ return entry.Type;
+ }
+
+ private static void GetSimplyNamedTypeFromAssembly(Assembly assm, string typeName, ref Type type)
+ {
+ // Catching any exceptions that could be thrown from a failure on assembly load
+ // This is necessary, for example, if there are generic parameters that are qualified with a version of the assembly that predates the one available
+ try
+ {
+ type = FormatterServices.GetTypeFromAssembly(assm, typeName);
+ }
+ catch (TypeLoadException) { }
+ catch (FileNotFoundException) { }
+ catch (FileLoadException) { }
+ catch (BadImageFormatException) { }
+ }
+
+ private string _previousAssemblyString;
+ private string _previousName;
+ private Type _previousType;
+
+ internal Type GetType(BinaryAssemblyInfo assemblyInfo, string name)
+ {
+ Type objectType = null;
+
+ if (((_previousName != null) && (_previousName.Length == name.Length) && (_previousName.Equals(name))) &&
+ ((_previousAssemblyString != null) && (_previousAssemblyString.Length == assemblyInfo._assemblyString.Length) && (_previousAssemblyString.Equals(assemblyInfo._assemblyString))))
+ {
+ objectType = _previousType;
+ }
+ else
+ {
+ objectType = Bind(assemblyInfo._assemblyString, name);
+ if (objectType == null)
+ {
+ Assembly sourceAssembly = assemblyInfo.GetAssembly();
+
+ if (_isSimpleAssembly)
+ {
+ GetSimplyNamedTypeFromAssembly(sourceAssembly, name, ref objectType);
+ }
+ else
+ {
+ objectType = FormatterServices.GetTypeFromAssembly(sourceAssembly, name);
+ }
+
+ // here let us do the security check
+ if (objectType != null)
+ {
+ CheckTypeForwardedTo(sourceAssembly, objectType.GetTypeInfo().Assembly, objectType);
+ }
+ }
+
+ _previousAssemblyString = assemblyInfo._assemblyString;
+ _previousName = name;
+ _previousType = objectType;
+ }
+ //Console.WriteLine("name "+name+" assembly "+assemblyInfo.assemblyString+" objectType "+objectType);
+ return objectType;
+ }
+
+ private static void CheckTypeForwardedTo(Assembly sourceAssembly, Assembly destAssembly, Type resolvedType)
+ {
+ // nop on core
+ }
+
+ internal sealed class TopLevelAssemblyTypeResolver
+ {
+ private readonly Assembly _topLevelAssembly;
+
+ public TopLevelAssemblyTypeResolver(Assembly topLevelAssembly)
+ {
+ _topLevelAssembly = topLevelAssembly;
+ }
+
+ public Type ResolveType(Assembly assembly, string simpleTypeName, bool ignoreCase) =>
+ (assembly ?? _topLevelAssembly).GetType(simpleTypeName, false, ignoreCase);
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectString.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectString.cs
new file mode 100644
index 000000000000..ebcfc97740a9
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectString.cs
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryObjectString : IStreamable
+ {
+ internal int _objectId;
+ internal string _value;
+
+ internal BinaryObjectString() { }
+
+ internal void Set(int objectId, string value)
+ {
+ _objectId = objectId;
+ _value = value;
+ }
+
+ public void Write(BinaryFormatterWriter output)
+ {
+ output.WriteByte((byte)BinaryHeaderEnum.ObjectString);
+ output.WriteInt32(_objectId);
+ output.WriteString(_value);
+ }
+
+ public void Read(BinaryParser input)
+ {
+ _objectId = input.ReadInt32();
+ _value = input.ReadString();
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectWithMap.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectWithMap.cs
new file mode 100644
index 000000000000..c25e5e85f5f3
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectWithMap.cs
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryObjectWithMap : IStreamable
+ {
+ internal BinaryHeaderEnum _binaryHeaderEnum;
+ internal int _objectId;
+ internal string _name;
+ internal int _numMembers;
+ internal string[] _memberNames;
+ internal int _assemId;
+
+ internal BinaryObjectWithMap() { }
+
+ internal BinaryObjectWithMap(BinaryHeaderEnum binaryHeaderEnum)
+ {
+ _binaryHeaderEnum = binaryHeaderEnum;
+ }
+
+ internal void Set(int objectId, string name, int numMembers, string[] memberNames, int assemId)
+ {
+ _objectId = objectId;
+ _name = name;
+ _numMembers = numMembers;
+ _memberNames = memberNames;
+ _assemId = assemId;
+
+ _binaryHeaderEnum = assemId > 0 ?
+ BinaryHeaderEnum.ObjectWithMapAssemId :
+ BinaryHeaderEnum.ObjectWithMap;
+ }
+
+ public void Write(BinaryFormatterWriter output)
+ {
+ output.WriteByte((byte)_binaryHeaderEnum);
+ output.WriteInt32(_objectId);
+ output.WriteString(_name);
+
+ output.WriteInt32(_numMembers);
+ for (int i = 0; i < _numMembers; i++)
+ {
+ output.WriteString(_memberNames[i]);
+ }
+
+ if (_assemId > 0)
+ {
+ output.WriteInt32(_assemId);
+ }
+ }
+
+ public void Read(BinaryParser input)
+ {
+ _objectId = input.ReadInt32();
+ _name = input.ReadString();
+ _numMembers = input.ReadInt32();
+
+ _memberNames = new string[_numMembers];
+ for (int i = 0; i < _numMembers; i++)
+ {
+ _memberNames[i] = input.ReadString();
+ }
+
+ if (_binaryHeaderEnum == BinaryHeaderEnum.ObjectWithMapAssemId)
+ {
+ _assemId = input.ReadInt32();
+ }
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectWithMapTyped.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectWithMapTyped.cs
new file mode 100644
index 000000000000..df140dfc0d94
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectWithMapTyped.cs
@@ -0,0 +1,106 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class BinaryObjectWithMapTyped : IStreamable
+ {
+ internal BinaryHeaderEnum _binaryHeaderEnum;
+ internal int _objectId;
+ internal string _name;
+ internal int _numMembers;
+ internal string[] _memberNames;
+ internal BinaryTypeEnum[] _binaryTypeEnumA;
+ internal object[] _typeInformationA;
+ internal int[] _memberAssemIds;
+ internal int _assemId;
+
+ internal BinaryObjectWithMapTyped() { }
+
+ internal BinaryObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum)
+ {
+ _binaryHeaderEnum = binaryHeaderEnum;
+ }
+
+ internal void Set(int objectId, string name, int numMembers, string[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, object[] typeInformationA, int[] memberAssemIds, int assemId)
+ {
+ _objectId = objectId;
+ _assemId = assemId;
+ _name = name;
+ _numMembers = numMembers;
+ _memberNames = memberNames;
+ _binaryTypeEnumA = binaryTypeEnumA;
+ _typeInformationA = typeInformationA;
+ _memberAssemIds = memberAssemIds;
+ _assemId = assemId;
+
+ _binaryHeaderEnum = assemId > 0 ?
+ BinaryHeaderEnum.ObjectWithMapTypedAssemId :
+ BinaryHeaderEnum.ObjectWithMapTyped;
+ }
+
+
+ public void Write(BinaryFormatterWriter output)
+ {
+ output.WriteByte((byte)_binaryHeaderEnum);
+ output.WriteInt32(_objectId);
+ output.WriteString(_name);
+
+ output.WriteInt32(_numMembers);
+ for (int i = 0; i < _numMembers; i++)
+ {
+ output.WriteString(_memberNames[i]);
+ }
+ for (int i = 0; i < _numMembers; i++)
+ {
+ output.WriteByte((byte)_binaryTypeEnumA[i]);
+ }
+ for (int i = 0; i < _numMembers; i++)
+ {
+ BinaryTypeConverter.WriteTypeInfo(_binaryTypeEnumA[i], _typeInformationA[i], _memberAssemIds[i], output);
+ }
+
+ if (_assemId > 0)
+ {
+ output.WriteInt32(_assemId);
+ }
+ }
+
+ public void Read(BinaryParser input)
+ {
+ // binaryHeaderEnum has already been read
+ _objectId = input.ReadInt32();
+ _name = input.ReadString();
+ _numMembers = input.ReadInt32();
+ _memberNames = new string[_numMembers];
+ _binaryTypeEnumA = new BinaryTypeEnum[_numMembers];
+ _typeInformationA = new object[_numMembers];
+ _memberAssemIds = new int[_numMembers];
+ for (int i = 0; i < _numMembers; i++)
+ {
+ _memberNames[i] = input.ReadString();
+ }
+ for (int i = 0; i < _numMembers; i++)
+ {
+ _binaryTypeEnumA[i] = (BinaryTypeEnum)input.ReadByte();
+ }
+ for (int i = 0; i < _numMembers; i++)
+ {
+ if (_binaryTypeEnumA[i] != BinaryTypeEnum.ObjectUrt && _binaryTypeEnumA[i] != BinaryTypeEnum.ObjectUser)
+ {
+ _typeInformationA[i] = BinaryTypeConverter.ReadTypeInfo(_binaryTypeEnumA[i], input, out _memberAssemIds[i]);
+ }
+ else
+ {
+ BinaryTypeConverter.ReadTypeInfo(_binaryTypeEnumA[i], input, out _memberAssemIds[i]);
+ }
+ }
+
+ if (_binaryHeaderEnum == BinaryHeaderEnum.ObjectWithMapTypedAssemId)
+ {
+ _assemId = input.ReadInt32();
+ }
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectWriter.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectWriter.cs
new file mode 100644
index 000000000000..3f0f8b831f48
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectWriter.cs
@@ -0,0 +1,1051 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Reflection;
+using System.Collections.Generic;
+using System.Runtime.Remoting.Messaging;
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+ internal sealed class ObjectWriter
+ {
+ private Queue