|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
namespace System.Runtime.Serialization.Formatters.Binary
{
internal sealed class ParseRecord
{
// Enums
internal InternalParseTypeE _parseTypeEnum = InternalParseTypeE.Empty;
internal InternalObjectTypeE _objectTypeEnum = InternalObjectTypeE.Empty;
internal InternalArrayTypeE _arrayTypeEnum = InternalArrayTypeE.Empty;
internal InternalMemberTypeE _memberTypeEnum = InternalMemberTypeE.Empty;
internal InternalMemberValueE _memberValueEnum = InternalMemberValueE.Empty;
internal InternalObjectPositionE _objectPositionEnum = InternalObjectPositionE.Empty;
// Object
internal string? _name;
// Value
internal string? _value;
internal object? _varValue;
// dt attribute
internal string? _keyDt;
internal Type? _dtType;
internal InternalPrimitiveTypeE _dtTypeCode;
// Object ID
internal long _objectId;
// Reference ID
internal long _idRef;
// Array
// Array Element Type
internal string? _arrayElementTypeString;
internal Type? _arrayElementType;
internal bool _isArrayVariant;
internal InternalPrimitiveTypeE _arrayElementTypeCode;
// Parsed array information
internal int _rank;
internal int[]? _lengthA;
internal int[]? _lowerBoundA;
// Array map for placing array elements in array
internal int[]? _indexMap;
internal int _memberIndex;
internal int _linearlength;
internal int[]? _rectangularMap;
internal bool _isLowerBound;
// MemberInfo accumulated during parsing of members
internal ReadObjectInfo? _objectInfo;
// ValueType Fixup needed
internal bool _isValueTypeFixup;
// Created object
internal object? _newObj;
internal object?[]? _objectA; //optimization, will contain object[]
internal PrimitiveArray? _primitiveArray; // for Primitive Soap arrays, optimization
internal bool _isRegistered; // Used when registering nested classes
internal object?[]? _memberData; // member data is collected here before populating
internal SerializationInfo? _si;
internal int _consecutiveNullArrayEntryCount;
internal ParseRecord() { }
// Initialize ParseRecord. Called when reusing.
internal void Init()
{
// Enums
_parseTypeEnum = InternalParseTypeE.Empty;
_objectTypeEnum = InternalObjectTypeE.Empty;
_arrayTypeEnum = InternalArrayTypeE.Empty;
_memberTypeEnum = InternalMemberTypeE.Empty;
_memberValueEnum = InternalMemberValueE.Empty;
_objectPositionEnum = InternalObjectPositionE.Empty;
// Object
_name = null;
// Value
_value = null;
// dt attribute
_keyDt = null;
_dtType = null;
_dtTypeCode = InternalPrimitiveTypeE.Invalid;
// Object ID
_objectId = 0;
// Reference ID
_idRef = 0;
// Array
// Array Element Type
_arrayElementTypeString = null;
_arrayElementType = null;
_isArrayVariant = false;
_arrayElementTypeCode = InternalPrimitiveTypeE.Invalid;
// Parsed array information
_rank = 0;
_lengthA = null;
_lowerBoundA = null;
// Array map for placing array elements in array
_indexMap = null;
_memberIndex = 0;
_linearlength = 0;
_rectangularMap = null;
_isLowerBound = false;
// ValueType Fixup needed
_isValueTypeFixup = false;
_newObj = null;
_objectA = null;
_primitiveArray = null;
_objectInfo = null;
_isRegistered = false;
_memberData = null;
_si = null;
_consecutiveNullArrayEntryCount = 0;
}
}
// Implements a stack used for parsing
internal sealed class SerStack
{
internal object?[] _objects = new object?[5];
internal string _stackId;
internal int _top = -1;
internal SerStack(string stackId)
{
_stackId = stackId;
}
// Push the object onto the stack
internal void Push(object obj)
{
if (_top == (_objects.Length - 1))
{
IncreaseCapacity();
}
_objects[++_top] = obj;
}
// Pop the object from the stack
internal object? Pop()
{
if (_top < 0)
{
return null;
}
object? obj = _objects[_top];
_objects[_top--] = null;
return obj;
}
internal void IncreaseCapacity()
{
int size = _objects.Length * 2;
object[] newItems = new object[size];
Array.Copy(_objects, newItems, _objects.Length);
_objects = newItems;
}
// Gets the object on the top of the stack
internal object? Peek() => _top < 0 ? null : _objects[_top];
// Gets the second entry in the stack.
internal object? PeekPeek() => _top < 1 ? null : _objects[_top - 1];
// The number of entries in the stack
internal bool IsEmpty() => _top <= 0;
}
// Implements a Growable array
internal sealed class SizedArray : ICloneable
{
internal object?[] _objects;
internal object?[] _negObjects;
internal SizedArray()
{
_objects = new object[16];
_negObjects = new object[4];
}
internal SizedArray(int length)
{
_objects = new object[length];
_negObjects = new object[length];
}
private SizedArray(SizedArray sizedArray)
{
_objects = new object[sizedArray._objects.Length];
sizedArray._objects.CopyTo(_objects, 0);
_negObjects = new object[sizedArray._negObjects.Length];
sizedArray._negObjects.CopyTo(_negObjects, 0);
}
public object Clone() => new SizedArray(this);
internal object? this[int index]
{
get
{
if (index < 0)
{
return -index > _negObjects.Length - 1 ? null : _negObjects[-index];
}
else
{
return index > _objects.Length - 1 ? null : _objects[index];
}
}
set
{
if (index < 0)
{
if (-index > _negObjects.Length - 1)
{
IncreaseCapacity(index);
}
_negObjects[-index] = value;
}
else
{
if (index > _objects.Length - 1)
{
IncreaseCapacity(index);
}
_objects[index] = value;
}
}
}
internal void IncreaseCapacity(int index)
{
try
{
if (index < 0)
{
int size = Math.Max(_negObjects.Length * 2, (-index) + 1);
object[] newItems = new object[size];
Array.Copy(_negObjects, newItems, _negObjects.Length);
_negObjects = newItems;
}
else
{
int size = Math.Max(_objects.Length * 2, index + 1);
object[] newItems = new object[size];
Array.Copy(_objects, newItems, _objects.Length);
_objects = newItems;
}
}
catch (Exception)
{
throw new SerializationException(SR.Serialization_CorruptedStream);
}
}
}
internal sealed class IntSizedArray : ICloneable
{
internal int[] _objects = new int[16];
internal int[] _negObjects = new int[4];
public IntSizedArray() { }
private IntSizedArray(IntSizedArray sizedArray)
{
_objects = new int[sizedArray._objects.Length];
sizedArray._objects.CopyTo(_objects, 0);
_negObjects = new int[sizedArray._negObjects.Length];
sizedArray._negObjects.CopyTo(_negObjects, 0);
}
public object Clone() => new IntSizedArray(this);
internal int this[int index]
{
get
{
if (index < 0)
{
return -index > _negObjects.Length - 1 ? 0 : _negObjects[-index];
}
else
{
return index > _objects.Length - 1 ? 0 : _objects[index];
}
}
set
{
if (index < 0)
{
if (-index > _negObjects.Length - 1)
{
IncreaseCapacity(index);
}
_negObjects[-index] = value;
}
else
{
if (index > _objects.Length - 1)
{
IncreaseCapacity(index);
}
_objects[index] = value;
}
}
}
internal void IncreaseCapacity(int index)
{
try
{
if (index < 0)
{
int size = Math.Max(_negObjects.Length * 2, (-index) + 1);
int[] newItems = new int[size];
Array.Copy(_negObjects, newItems, _negObjects.Length);
_negObjects = newItems;
}
else
{
int size = Math.Max(_objects.Length * 2, index + 1);
int[] newItems = new int[size];
Array.Copy(_objects, newItems, _objects.Length);
_objects = newItems;
}
}
catch (Exception)
{
throw new SerializationException(SR.Serialization_CorruptedStream);
}
}
}
internal sealed class NameCache
{
private static readonly ConcurrentDictionary<string, object> s_ht = new ConcurrentDictionary<string, object>();
private string? _name;
internal object? GetCachedValue(string name)
{
_name = name;
return s_ht.TryGetValue(name, out object? value) ? value : null;
}
internal void SetCachedValue(object value) => s_ht[_name!] = value;
}
// Used to fixup value types. Only currently used for valuetypes which are array items.
internal sealed class ValueFixup
{
internal ValueFixupEnum _valueFixupEnum = ValueFixupEnum.Empty;
internal Array? _arrayObj;
internal int[]? _indexMap;
internal object? _memberObject;
internal ReadObjectInfo? _objectInfo;
internal string? _memberName;
internal ValueFixup(Array arrayObj, int[] indexMap)
{
_valueFixupEnum = ValueFixupEnum.Array;
_arrayObj = arrayObj;
_indexMap = indexMap;
}
internal ValueFixup(object? memberObject, string memberName, ReadObjectInfo objectInfo)
{
_valueFixupEnum = ValueFixupEnum.Member;
_memberObject = memberObject;
_memberName = memberName;
_objectInfo = objectInfo;
}
internal void Fixup(ParseRecord record, ParseRecord parent)
{
object? obj = record._newObj;
switch (_valueFixupEnum)
{
case ValueFixupEnum.Array:
_arrayObj!.SetValue(obj, _indexMap!);
break;
case ValueFixupEnum.Header:
throw new PlatformNotSupportedException();
case ValueFixupEnum.Member:
Debug.Assert(_objectInfo!._objectManager != null);
if (_objectInfo._isSi)
{
_objectInfo._objectManager.RecordDelayedFixup(parent._objectId, _memberName!, record._objectId);
}
else
{
MemberInfo? memberInfo = _objectInfo.GetMemberInfo(_memberName);
if (memberInfo != null)
{
_objectInfo._objectManager.RecordFixup(parent._objectId, memberInfo, record._objectId);
}
}
break;
}
}
}
// Class used to transmit Enums from the XML and Binary Formatter class to the ObjectWriter and ObjectReader class
internal sealed class InternalFE
{
internal FormatterTypeStyle _typeFormat;
internal FormatterAssemblyStyle _assemblyFormat;
internal TypeFilterLevel _securityLevel;
internal InternalSerializerTypeE _serializerTypeEnum;
}
internal sealed class NameInfo
{
internal string? _fullName; // Name from SerObjectInfo.GetType
internal long _objectId;
internal long _assemId;
internal InternalPrimitiveTypeE _primitiveTypeEnum = InternalPrimitiveTypeE.Invalid;
internal Type? _type;
internal bool _isSealed;
internal bool _isArray;
internal bool _isArrayItem;
internal bool _transmitTypeOnObject;
internal bool _transmitTypeOnMember;
internal bool _isParentTypeOnObject;
internal InternalArrayTypeE _arrayEnum;
private bool _sealedStatusChecked;
internal NameInfo() { }
internal void Init()
{
_fullName = null;
_objectId = 0;
_assemId = 0;
_primitiveTypeEnum = InternalPrimitiveTypeE.Invalid;
_type = null;
_isSealed = false;
_transmitTypeOnObject = false;
_transmitTypeOnMember = false;
_isParentTypeOnObject = false;
_isArray = false;
_isArrayItem = false;
_arrayEnum = InternalArrayTypeE.Empty;
_sealedStatusChecked = false;
}
public bool IsSealed
{
get
{
if (!_sealedStatusChecked)
{
Debug.Assert(_type != null);
_isSealed = _type.IsSealed;
_sealedStatusChecked = true;
}
return _isSealed;
}
}
public string? NIname
{
get { return _fullName ??= _type?.FullName; }
set { _fullName = value; }
}
}
internal sealed class PrimitiveArray
{
private readonly InternalPrimitiveTypeE _code;
private readonly bool[] _booleanA = null!;
private readonly char[] _charA = null!;
private readonly double[] _doubleA = null!;
private readonly short[] _int16A = null!;
private readonly int[] _int32A = null!;
private readonly long[] _int64A = null!;
private readonly sbyte[] _sbyteA = null!;
private readonly float[] _singleA = null!;
private readonly ushort[] _uint16A = null!;
private readonly uint[] _uint32A = null!;
private readonly ulong[] _uint64A = null!;
internal PrimitiveArray(InternalPrimitiveTypeE code, Array array)
{
_code = code;
switch (code)
{
case InternalPrimitiveTypeE.Boolean: _booleanA = (bool[])array; break;
case InternalPrimitiveTypeE.Char: _charA = (char[])array; break;
case InternalPrimitiveTypeE.Double: _doubleA = (double[])array; break;
case InternalPrimitiveTypeE.Int16: _int16A = (short[])array; break;
case InternalPrimitiveTypeE.Int32: _int32A = (int[])array; break;
case InternalPrimitiveTypeE.Int64: _int64A = (long[])array; break;
case InternalPrimitiveTypeE.SByte: _sbyteA = (sbyte[])array; break;
case InternalPrimitiveTypeE.Single: _singleA = (float[])array; break;
case InternalPrimitiveTypeE.UInt16: _uint16A = (ushort[])array; break;
case InternalPrimitiveTypeE.UInt32: _uint32A = (uint[])array; break;
case InternalPrimitiveTypeE.UInt64: _uint64A = (ulong[])array; break;
}
}
internal void SetValue(string value, int index)
{
switch (_code)
{
case InternalPrimitiveTypeE.Boolean:
_booleanA[index] = bool.Parse(value);
break;
case InternalPrimitiveTypeE.Char:
if ((value[0] == '_') && (value.Equals("_0x00_")))
{
_charA[index] = char.MinValue;
}
else
{
_charA[index] = char.Parse(value);
}
break;
case InternalPrimitiveTypeE.Double:
_doubleA[index] = double.Parse(value, CultureInfo.InvariantCulture);
break;
case InternalPrimitiveTypeE.Int16:
_int16A[index] = short.Parse(value, CultureInfo.InvariantCulture);
break;
case InternalPrimitiveTypeE.Int32:
_int32A[index] = int.Parse(value, CultureInfo.InvariantCulture);
break;
case InternalPrimitiveTypeE.Int64:
_int64A[index] = long.Parse(value, CultureInfo.InvariantCulture);
break;
case InternalPrimitiveTypeE.SByte:
_sbyteA[index] = sbyte.Parse(value, CultureInfo.InvariantCulture);
break;
case InternalPrimitiveTypeE.Single:
_singleA[index] = float.Parse(value, CultureInfo.InvariantCulture);
break;
case InternalPrimitiveTypeE.UInt16:
_uint16A[index] = ushort.Parse(value, CultureInfo.InvariantCulture);
break;
case InternalPrimitiveTypeE.UInt32:
_uint32A[index] = uint.Parse(value, CultureInfo.InvariantCulture);
break;
case InternalPrimitiveTypeE.UInt64:
_uint64A[index] = ulong.Parse(value, CultureInfo.InvariantCulture);
break;
}
}
}
}
|