|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: SerializationInfo
**
**
** Purpose: The structure for holding all of the data needed
** for object serialization and deserialization.
**
**
===========================================================*/
namespace System.Runtime.Serialization
{
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Remoting;
#if FEATURE_REMOTING
using System.Runtime.Remoting.Proxies;
#endif
using System.Globalization;
using System.Diagnostics.Contracts;
using System.Security;
#if FEATURE_CORECLR
using System.Runtime.CompilerServices;
#endif
[System.Runtime.InteropServices.ComVisible(true)]
public sealed class SerializationInfo
{
private const int defaultSize = 4;
private const string s_mscorlibAssemblySimpleName = "mscorlib";
private const string s_mscorlibFileName = s_mscorlibAssemblySimpleName + ".dll";
// Even though we have a dictionary, we're still keeping all the arrays around for back-compat.
// Otherwise we may run into potentially breaking behaviors like GetEnumerator() not returning entries in the same order they were added.
internal String[] m_members;
internal Object[] m_data;
internal Type[] m_types;
private Dictionary<string, int> m_nameToIndex;
internal int m_currMember;
internal IFormatterConverter m_converter;
private String m_fullTypeName;
private String m_assemName;
private Type objectType;
private bool isFullTypeNameSetExplicit;
private bool isAssemblyNameSetExplicit;
#if FEATURE_SERIALIZATION
private bool requireSameTokenInPartialTrust;
#endif
[CLSCompliant(false)]
public SerializationInfo(Type type, IFormatterConverter converter)
#if FEATURE_SERIALIZATION
: this(type, converter, false)
{
}
[CLSCompliant(false)]
public SerializationInfo(Type type, IFormatterConverter converter, bool requireSameTokenInPartialTrust)
#endif
{
if ((object)type == null)
{
throw new ArgumentNullException("type");
}
if (converter == null)
{
throw new ArgumentNullException("converter");
}
Contract.EndContractBlock();
objectType = type;
m_fullTypeName = type.FullName;
m_assemName = type.Module.Assembly.FullName;
m_members = new String[defaultSize];
m_data = new Object[defaultSize];
m_types = new Type[defaultSize];
m_nameToIndex = new Dictionary<string, int>();
m_converter = converter;
#if FEATURE_SERIALIZATION
this.requireSameTokenInPartialTrust = requireSameTokenInPartialTrust;
#endif
}
public String FullTypeName
{
get
{
return m_fullTypeName;
}
set
{
if (null == value)
{
throw new ArgumentNullException("value");
}
Contract.EndContractBlock();
m_fullTypeName = value;
isFullTypeNameSetExplicit = true;
}
}
public String AssemblyName
{
get
{
return m_assemName;
}
#if FEATURE_SERIALIZATION
[SecuritySafeCritical]
#endif
set
{
if (null == value)
{
throw new ArgumentNullException("value");
}
Contract.EndContractBlock();
#if FEATURE_SERIALIZATION
if (this.requireSameTokenInPartialTrust)
{
DemandForUnsafeAssemblyNameAssignments(this.m_assemName, value);
}
#endif
m_assemName = value;
isAssemblyNameSetExplicit = true;
}
}
#if FEATURE_SERIALIZATION
[SecuritySafeCritical]
#endif
public void SetType(Type type)
{
if ((object)type == null)
{
throw new ArgumentNullException("type");
}
Contract.EndContractBlock();
#if FEATURE_SERIALIZATION
if (this.requireSameTokenInPartialTrust)
{
DemandForUnsafeAssemblyNameAssignments(this.ObjectType.Assembly.FullName, type.Assembly.FullName);
}
#endif
if (!Object.ReferenceEquals(objectType, type))
{
objectType = type;
m_fullTypeName = type.FullName;
m_assemName = type.Module.Assembly.FullName;
isFullTypeNameSetExplicit = false;
isAssemblyNameSetExplicit = false;
}
}
private static bool Compare(byte[] a, byte[] b)
{
// if either or both assemblies do not have public key token, we should demand, hence, returning false will force a demand
if (a == null || b == null || a.Length == 0 || b.Length == 0 || a.Length != b.Length)
{
return false;
}
else
{
for (int i = 0; i < a.Length; i++)
{
if (a[i] != b[i]) return false;
}
return true;
}
}
[SecuritySafeCritical]
internal static void DemandForUnsafeAssemblyNameAssignments(string originalAssemblyName, string newAssemblyName)
{
if (!IsAssemblyNameAssignmentSafe(originalAssemblyName, newAssemblyName))
{
CodeAccessPermission.Demand(PermissionType.SecuritySerialization);
}
}
internal static bool IsAssemblyNameAssignmentSafe(string originalAssemblyName, string newAssemblyName)
{
if (originalAssemblyName == newAssemblyName)
{
return true;
}
AssemblyName originalAssembly = new AssemblyName(originalAssemblyName);
AssemblyName newAssembly = new AssemblyName(newAssemblyName);
// mscorlib will get loaded by the runtime regardless of its string casing or its public key token,
// so setting the assembly name to mscorlib must always be protected by a demand
if (string.Equals(newAssembly.Name, s_mscorlibAssemblySimpleName, StringComparison.OrdinalIgnoreCase) ||
string.Equals(newAssembly.Name, s_mscorlibFileName, StringComparison.OrdinalIgnoreCase))
{
return false;
}
return Compare(originalAssembly.GetPublicKeyToken(), newAssembly.GetPublicKeyToken());
}
public int MemberCount
{
get
{
return m_currMember;
}
}
public Type ObjectType
{
get
{
return objectType;
}
}
public bool IsFullTypeNameSetExplicit
{
get
{
return isFullTypeNameSetExplicit;
}
}
public bool IsAssemblyNameSetExplicit
{
get
{
return isAssemblyNameSetExplicit;
}
}
public SerializationInfoEnumerator GetEnumerator()
{
return new SerializationInfoEnumerator(m_members, m_data, m_types, m_currMember);
}
private void ExpandArrays()
{
int newSize;
Contract.Assert(m_members.Length == m_currMember, "[SerializationInfo.ExpandArrays]m_members.Length == m_currMember");
newSize = (m_currMember * 2);
//
// In the pathological case, we may wrap
//
if (newSize < m_currMember)
{
if (Int32.MaxValue > m_currMember)
{
newSize = Int32.MaxValue;
}
}
//
// Allocate more space and copy the data
//
String[] newMembers = new String[newSize];
Object[] newData = new Object[newSize];
Type[] newTypes = new Type[newSize];
Array.Copy(m_members, newMembers, m_currMember);
Array.Copy(m_data, newData, m_currMember);
Array.Copy(m_types, newTypes, m_currMember);
//
// Assign the new arrys back to the member vars.
//
m_members = newMembers;
m_data = newData;
m_types = newTypes;
}
public void AddValue(String name, Object value, Type type)
{
if (null == name)
{
throw new ArgumentNullException("name");
}
if ((object)type == null)
{
throw new ArgumentNullException("type");
}
Contract.EndContractBlock();
AddValueInternal(name, value, type);
}
public void AddValue(String name, Object value)
{
if (null == value)
{
AddValue(name, value, typeof(Object));
}
else
{
AddValue(name, value, value.GetType());
}
}
public void AddValue(String name, bool value)
{
AddValue(name, (Object)value, typeof(bool));
}
public void AddValue(String name, char value)
{
AddValue(name, (Object)value, typeof(char));
}
[CLSCompliant(false)]
public void AddValue(String name, sbyte value)
{
AddValue(name, (Object)value, typeof(sbyte));
}
public void AddValue(String name, byte value)
{
AddValue(name, (Object)value, typeof(byte));
}
public void AddValue(String name, short value)
{
AddValue(name, (Object)value, typeof(short));
}
[CLSCompliant(false)]
public void AddValue(String name, ushort value)
{
AddValue(name, (Object)value, typeof(ushort));
}
public void AddValue(String name, int value)
{
AddValue(name, (Object)value, typeof(int));
}
[CLSCompliant(false)]
public void AddValue(String name, uint value)
{
AddValue(name, (Object)value, typeof(uint));
}
public void AddValue(String name, long value)
{
AddValue(name, (Object)value, typeof(long));
}
[CLSCompliant(false)]
public void AddValue(String name, ulong value)
{
AddValue(name, (Object)value, typeof(ulong));
}
public void AddValue(String name, float value)
{
AddValue(name, (Object)value, typeof(float));
}
public void AddValue(String name, double value)
{
AddValue(name, (Object)value, typeof(double));
}
public void AddValue(String name, decimal value)
{
AddValue(name, (Object)value, typeof(decimal));
}
public void AddValue(String name, DateTime value)
{
AddValue(name, (Object)value, typeof(DateTime));
}
internal void AddValueInternal(String name, Object value, Type type)
{
if (m_nameToIndex.ContainsKey(name))
{
BCLDebug.Trace("SER", "[SerializationInfo.AddValue]Tried to add ", name, " twice to the SI.");
throw new SerializationException(Environment.GetResourceString("Serialization_SameNameTwice"));
}
m_nameToIndex.Add(name, m_currMember);
//
// If we need to expand the arrays, do so.
//
if (m_currMember >= m_members.Length)
{
ExpandArrays();
}
//
// Add the data and then advance the counter.
//
m_members[m_currMember] = name;
m_data[m_currMember] = value;
m_types[m_currMember] = type;
m_currMember++;
}
/*=================================UpdateValue==================================
**Action: Finds the value if it exists in the current data. If it does, we replace
** the values, if not, we append it to the end. This is useful to the
** ObjectManager when it's performing fixups, but shouldn't be used by
** clients. Exposing out this functionality would allow children to overwrite
** their parent's values.
**Returns: void
**Arguments: name -- the name of the data to be updated.
** value -- the new value.
** type -- the type of the data being added.
**Exceptions: None. All error checking is done with asserts.
==============================================================================*/
internal void UpdateValue(String name, Object value, Type type)
{
Contract.Assert(null != name, "[SerializationInfo.UpdateValue]name!=null");
Contract.Assert(null != value, "[SerializationInfo.UpdateValue]value!=null");
Contract.Assert(null != (object)type, "[SerializationInfo.UpdateValue]type!=null");
int index = FindElement(name);
if (index < 0)
{
AddValueInternal(name, value, type);
}
else
{
m_data[index] = value;
m_types[index] = type;
}
}
private int FindElement(String name)
{
if (null == name)
{
throw new ArgumentNullException("name");
}
Contract.EndContractBlock();
BCLDebug.Trace("SER", "[SerializationInfo.FindElement]Looking for ", name, " CurrMember is: ", m_currMember);
int index;
if (m_nameToIndex.TryGetValue(name, out index))
{
return index;
}
return -1;
}
/*==================================GetElement==================================
**Action: Use FindElement to get the location of a particular member and then return
** the value of the element at that location. The type of the member is
** returned in the foundType field.
**Returns: The value of the element at the position associated with name.
**Arguments: name -- the name of the element to find.
** foundType -- the type of the element associated with the given name.
**Exceptions: None. FindElement does null checking and throws for elements not
** found.
==============================================================================*/
private Object GetElement(String name, out Type foundType)
{
int index = FindElement(name);
if (index == -1)
{
throw new SerializationException(Environment.GetResourceString("Serialization_NotFound", name));
}
Contract.Assert(index < m_data.Length, "[SerializationInfo.GetElement]index<m_data.Length");
Contract.Assert(index < m_types.Length, "[SerializationInfo.GetElement]index<m_types.Length");
foundType = m_types[index];
Contract.Assert((object)foundType != null, "[SerializationInfo.GetElement]foundType!=null");
return m_data[index];
}
[System.Runtime.InteropServices.ComVisible(true)]
//
private Object GetElementNoThrow(String name, out Type foundType)
{
int index = FindElement(name);
if (index == -1)
{
foundType = null;
return null;
}
Contract.Assert(index < m_data.Length, "[SerializationInfo.GetElement]index<m_data.Length");
Contract.Assert(index < m_types.Length, "[SerializationInfo.GetElement]index<m_types.Length");
foundType = m_types[index];
Contract.Assert((object)foundType != null, "[SerializationInfo.GetElement]foundType!=null");
return m_data[index];
}
//
// The user should call one of these getters to get the data back in the
// form requested.
//
[System.Security.SecuritySafeCritical] // auto-generated
public Object GetValue(String name, Type type)
{
if ((object)type == null)
{
throw new ArgumentNullException("type");
}
Contract.EndContractBlock();
RuntimeType rt = type as RuntimeType;
if (rt == null)
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"));
Type foundType;
Object value;
value = GetElement(name, out foundType);
#if FEATURE_REMOTING
if (RemotingServices.IsTransparentProxy(value))
{
RealProxy proxy = RemotingServices.GetRealProxy(value);
if (RemotingServices.ProxyCheckCast(proxy, rt))
return value;
}
else
#endif
if (Object.ReferenceEquals(foundType, type) || type.IsAssignableFrom(foundType) || value == null)
{
return value;
}
Contract.Assert(m_converter != null, "[SerializationInfo.GetValue]m_converter!=null");
return m_converter.Convert(value, type);
}
[System.Security.SecuritySafeCritical] // auto-generated
[System.Runtime.InteropServices.ComVisible(true)]
//
internal Object GetValueNoThrow(String name, Type type)
{
Type foundType;
Object value;
Contract.Assert((object)type != null, "[SerializationInfo.GetValue]type ==null");
Contract.Assert(type is RuntimeType, "[SerializationInfo.GetValue]type is not a runtime type");
value = GetElementNoThrow(name, out foundType);
if (value == null)
return null;
#if FEATURE_REMOTING
if (RemotingServices.IsTransparentProxy(value))
{
RealProxy proxy = RemotingServices.GetRealProxy(value);
if (RemotingServices.ProxyCheckCast(proxy, (RuntimeType)type))
return value;
}
else
#endif
if (Object.ReferenceEquals(foundType, type) || type.IsAssignableFrom(foundType) || value == null)
{
return value;
}
Contract.Assert(m_converter != null, "[SerializationInfo.GetValue]m_converter!=null");
return m_converter.Convert(value, type);
}
public bool GetBoolean(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(bool)))
{
return (bool)value;
}
return m_converter.ToBoolean(value);
}
public char GetChar(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(char)))
{
return (char)value;
}
return m_converter.ToChar(value);
}
[CLSCompliant(false)]
public sbyte GetSByte(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(sbyte)))
{
return (sbyte)value;
}
return m_converter.ToSByte(value);
}
public byte GetByte(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(byte)))
{
return (byte)value;
}
return m_converter.ToByte(value);
}
public short GetInt16(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(short)))
{
return (short)value;
}
return m_converter.ToInt16(value);
}
[CLSCompliant(false)]
public ushort GetUInt16(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(ushort)))
{
return (ushort)value;
}
return m_converter.ToUInt16(value);
}
public int GetInt32(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(int)))
{
return (int)value;
}
return m_converter.ToInt32(value);
}
[CLSCompliant(false)]
public uint GetUInt32(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(uint)))
{
return (uint)value;
}
return m_converter.ToUInt32(value);
}
public long GetInt64(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(long)))
{
return (long)value;
}
return m_converter.ToInt64(value);
}
[CLSCompliant(false)]
public ulong GetUInt64(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(ulong)))
{
return (ulong)value;
}
return m_converter.ToUInt64(value);
}
public float GetSingle(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(float)))
{
return (float)value;
}
return m_converter.ToSingle(value);
}
public double GetDouble(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(double)))
{
return (double)value;
}
return m_converter.ToDouble(value);
}
public decimal GetDecimal(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(decimal)))
{
return (decimal)value;
}
return m_converter.ToDecimal(value);
}
public DateTime GetDateTime(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(DateTime)))
{
return (DateTime)value;
}
return m_converter.ToDateTime(value);
}
public String GetString(String name)
{
Type foundType;
Object value;
value = GetElement(name, out foundType);
if (Object.ReferenceEquals(foundType, typeof(String)) || value == null)
{
return (String)value;
}
return m_converter.ToString(value);
}
internal string[] MemberNames
{
get
{
return m_members;
}
}
internal object[] MemberValues
{
get
{
return m_data;
}
}
}
}
|