// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================ ** ** Class: CommonClasses ** ** ** Purpose: utility classes ** ** ===========================================================*/ // All classes and methods in here are only for the internal use by the XML and Binary Formatters. // They are public so that the XMLFormatter can address them. Eventually they will // be signed so that they can't be used by external applications. namespace System.Runtime.Serialization.Formatters.Binary { using System; using System.Collections; using System.Reflection; using System.Text; using System.Globalization; using System.Runtime.Serialization.Formatters; using System.Runtime.Remoting; using System.Runtime.Remoting.Messaging; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Diagnostics; // The ParseRecord class holds the parsed XML information. There is a // ParsedRecord for each XML Element internal sealed class ParseRecord #if _DEBUG : ITrace #endif { // disable csharp compiler warning #0414: field assigned unused value #pragma warning disable 0414 internal static int parseRecordIdCount = 1; internal int PRparseRecordId = 0; #pragma warning restore 0414 // Enums internal InternalParseTypeE PRparseTypeEnum = InternalParseTypeE.Empty; internal InternalObjectTypeE PRobjectTypeEnum = InternalObjectTypeE.Empty; internal InternalArrayTypeE PRarrayTypeEnum = InternalArrayTypeE.Empty; internal InternalMemberTypeE PRmemberTypeEnum = InternalMemberTypeE.Empty; internal InternalMemberValueE PRmemberValueEnum = InternalMemberValueE.Empty; internal InternalObjectPositionE PRobjectPositionEnum = InternalObjectPositionE.Empty; // Object internal String PRname; // Value internal String PRvalue; internal Object PRvarValue; // dt attribute internal String PRkeyDt; internal Type PRdtType; internal InternalPrimitiveTypeE PRdtTypeCode; // disable csharp compiler warning #0414: field assigned unused value #pragma warning disable 0414 internal bool PRisVariant = false; // Used by Binary internal bool PRisEnum = false; #pragma warning restore 0414 // Object ID internal long PRobjectId; // Reference ID internal long PRidRef; // Array // Array Element Type internal String PRarrayElementTypeString; internal Type PRarrayElementType; internal bool PRisArrayVariant = false; internal InternalPrimitiveTypeE PRarrayElementTypeCode; // Parsed array information internal int PRrank; internal int[] PRlengthA; // disable csharp compiler warning #0414: field assigned unused value #pragma warning disable 0414 internal int[] PRpositionA; internal int[] PRlowerBoundA; internal int[] PRupperBoundA; #pragma warning restore 0414 // Array map for placing array elements in array internal int[] PRindexMap; internal int PRmemberIndex; internal int PRlinearlength; internal int[] PRrectangularMap; internal bool PRisLowerBound; // SerializedStreamHeader information // disable csharp compiler warning #0414: field assigned unused value #pragma warning disable 0414 internal long PRtopId; internal long PRheaderId; #pragma warning restore 0414 // MemberInfo accumulated during parsing of members internal ReadObjectInfo PRobjectInfo; // ValueType Fixup needed internal bool PRisValueTypeFixup = false; // Created object internal Object PRnewObj; internal Object[] PRobjectA; //optimization, will contain object[] internal PrimitiveArray PRprimitiveArray; // for Primitive Soap arrays, optimization internal bool PRisRegistered; // Used when registering nested classes internal Object[] PRmemberData; // member data is collected here before populating internal SerializationInfo PRsi; internal int PRnullCount; // Count of consecutive nulls within an array internal ParseRecord() { } #if _DEBUG // Get a String describing the ParseRecord // ITrace public String Trace() { return "ParseRecord"+PRparseRecordId+" ParseType "+ ((Enum)PRparseTypeEnum).ToString() +" name "+PRname+" keyDt "+Util.PString(PRkeyDt); } #endif // Initialize ParseRecord. Called when reusing. internal void Init() { // Enums PRparseTypeEnum = InternalParseTypeE.Empty; PRobjectTypeEnum = InternalObjectTypeE.Empty; PRarrayTypeEnum = InternalArrayTypeE.Empty; PRmemberTypeEnum = InternalMemberTypeE.Empty; PRmemberValueEnum = InternalMemberValueE.Empty; PRobjectPositionEnum = InternalObjectPositionE.Empty; // Object PRname = null; // Value PRvalue = null; // dt attribute PRkeyDt = null; PRdtType = null; PRdtTypeCode = InternalPrimitiveTypeE.Invalid; PRisEnum = false; // Object ID PRobjectId = 0; // Reference ID PRidRef = 0; // Array // Array Element Type PRarrayElementTypeString = null; PRarrayElementType = null; PRisArrayVariant = false; PRarrayElementTypeCode = InternalPrimitiveTypeE.Invalid; // Parsed array information PRrank = 0; PRlengthA = null; PRpositionA = null; PRlowerBoundA = null; PRupperBoundA = null; // Array map for placing array elements in array PRindexMap = null; PRmemberIndex = 0; PRlinearlength = 0; PRrectangularMap = null; PRisLowerBound = false; // SerializedStreamHeader information PRtopId = 0; PRheaderId = 0; // ValueType Fixup needed PRisValueTypeFixup = false; PRnewObj = null; PRobjectA = null; PRprimitiveArray = null; PRobjectInfo = null; PRisRegistered = false; PRmemberData = null; PRsi = null; PRnullCount = 0; } #if _DEBUG // Dump ParseRecord. [Conditional("SER_LOGGING")] internal void Dump() { SerTrace.Log("ParseRecord Dump ",PRparseRecordId); SerTrace.Log("Enums"); Util.NVTrace("ParseType",((Enum)PRparseTypeEnum).ToString()); Util.NVTrace("ObjectType",((Enum)PRobjectTypeEnum).ToString()); Util.NVTrace("ArrayType",((Enum)PRarrayTypeEnum).ToString()); Util.NVTrace("MemberType",((Enum)PRmemberTypeEnum).ToString()); Util.NVTrace("MemberValue",((Enum)PRmemberValueEnum).ToString()); Util.NVTrace("ObjectPosition",((Enum)PRobjectPositionEnum).ToString()); SerTrace.Log("Basics"); Util.NVTrace("Name",PRname); Util.NVTrace("Value ",PRvalue); Util.NVTrace("varValue ",PRvarValue); if (PRvarValue != null) Util.NVTrace("varValue type",PRvarValue.GetType()); Util.NVTrace("keyDt",PRkeyDt); Util.NVTrace("dtType",PRdtType); Util.NVTrace("code",((Enum)PRdtTypeCode).ToString()); Util.NVTrace("objectID",PRobjectId); Util.NVTrace("idRef",PRidRef); Util.NVTrace("isEnum",PRisEnum); SerTrace.Log("Array "); Util.NVTrace("arrayElementTypeString",PRarrayElementTypeString); Util.NVTrace("arrayElementType",PRarrayElementType); Util.NVTrace("arrayElementTypeCode",((Enum)PRarrayElementTypeCode).ToString()); Util.NVTrace("isArrayVariant",PRisArrayVariant); Util.NVTrace("rank",PRrank); Util.NVTrace("dimensions", Util.PArray(PRlengthA)); Util.NVTrace("position", Util.PArray(PRpositionA)); Util.NVTrace("lowerBoundA", Util.PArray(PRlowerBoundA)); Util.NVTrace("upperBoundA", Util.PArray(PRupperBoundA)); SerTrace.Log("Header "); Util.NVTrace("nullCount", PRnullCount); SerTrace.Log("New Object"); if (PRnewObj != null) Util.NVTrace("newObj", PRnewObj); } #endif } #if _DEBUG internal interface ITrace { String Trace(); } #endif // Implements a stack used for parsing internal sealed class SerStack { internal Object[] objects = new Object[5]; internal String stackId; internal int top = -1; // disable csharp compiler warning #0414: field assigned unused value #pragma warning disable 0414 internal int next = 0; #pragma warning restore 0414 internal SerStack() { stackId = "System"; } internal SerStack(String stackId) { this.stackId = stackId; } // Push the object onto the stack internal void Push(Object obj) { #if _DEBUG SerTrace.Log(this, "Push ",stackId," ",((obj is ITrace)?((ITrace)obj).Trace():"")); #endif 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; #if _DEBUG SerTrace.Log(this, "Pop ",stackId," ",((obj is ITrace)?((ITrace)obj).Trace():"")); #endif return obj; } internal void IncreaseCapacity() { int size = objects.Length * 2; Object[] newItems = new Object[size]; Array.Copy(objects, 0, newItems, 0, objects.Length); objects = newItems; } // Gets the object on the top of the stack internal Object Peek() { if (top < 0) return null; #if _DEBUG SerTrace.Log(this, "Peek ",stackId," ",((objects[top] is ITrace)?((ITrace)objects[top]).Trace():"")); #endif return objects[top]; } // Gets the second entry in the stack. internal Object PeekPeek() { if (top < 1) return null; #if _DEBUG SerTrace.Log(this, "PeekPeek ",stackId," ",((objects[top - 1] is ITrace)?((ITrace)objects[top - 1]).Trace():"")); #endif return objects[top - 1]; } // The number of entries in the stack internal int Count() { return top + 1; } // The number of entries in the stack internal bool IsEmpty() { if (top > 0) return false; else return true; } [Conditional("SER_LOGGING")] internal void Dump() { for (int i=0; i negObjects.Length - 1) return null; return negObjects[-index]; } else { if (index > objects.Length - 1) return null; return objects[index]; } } set { if (index < 0) { if (-index > negObjects.Length-1 ) { IncreaseCapacity(index); } negObjects[-index] = value; } else { if (index > objects.Length-1 ) { IncreaseCapacity(index); } if (objects[index] != null) { //Console.WriteLine("SizedArray Setting a non-zero "+index+" "+value); } 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, 0, newItems, 0, negObjects.Length); negObjects = newItems; } else { int size = Math.Max(objects.Length * 2, index+1); Object[] newItems = new Object[size]; Array.Copy(objects, 0, newItems, 0, objects.Length); objects = newItems; } } catch (Exception) { throw new SerializationException(Environment.GetResourceString("Serialization_CorruptedStream")); } } } [Serializable] 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() { return new IntSizedArray(this); } internal int this[int index] { get { if (index < 0) { if (-index > negObjects.Length-1 ) return 0; return negObjects[-index]; } else { if (index > objects.Length-1 ) return 0; return 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, 0, newItems, 0, negObjects.Length); negObjects = newItems; } else { int size = Math.Max(objects.Length * 2, index+1); int[] newItems = new int[size]; Array.Copy(objects, 0, newItems, 0, objects.Length); objects = newItems; } } catch (Exception) { throw new SerializationException(Environment.GetResourceString("Serialization_CorruptedStream")); } } } internal sealed class NameCache { static System.Collections.Concurrent.ConcurrentDictionary ht = new System.Collections.Concurrent.ConcurrentDictionary(); String name = null; internal Object GetCachedValue(String name) { this.name = name; object value; return ht.TryGetValue(name, out value) ? value : null; } internal void SetCachedValue(Object value) { ht[name] = value; } } #if _DEBUG // Utilities internal static class Util { // Replaces a null string with an empty string internal static String PString(String value) { if (value == null) return ""; else return value; } // Converts an object to a string and checks for nulls internal static String PString(Object value) { if (value == null) return ""; else return value.ToString(); } // Converts a single int array to a string internal static String PArray(int[] array) { if (array != null) { StringBuilder sb = new StringBuilder(10); sb.Append("["); for (int i=0; i