3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
8 ** Class: CommonClasses
11 ** Purpose: utility classes
14 ===========================================================*/
17 // All classes and methods in here are only for the internal use by the XML and Binary Formatters.
18 // They are public so that the XMLFormatter can address them. Eventually they will
19 // be signed so that they can't be used by external applications.
21 namespace System.Runtime.Serialization.Formatters.Binary
24 using System.Collections;
25 using System.Reflection;
27 using System.Globalization;
28 using System.Runtime.Serialization.Formatters;
29 using System.Runtime.Remoting;
30 using System.Runtime.Remoting.Messaging;
31 using System.Runtime.InteropServices;
32 using System.Runtime.Serialization;
33 using System.Diagnostics;
35 // The ParseRecord class holds the parsed XML information. There is a
36 // ParsedRecord for each XML Element
37 internal sealed class ParseRecord
42 // disable csharp compiler warning #0414: field assigned unused value
43 #pragma warning disable 0414
44 internal static int parseRecordIdCount = 1;
46 internal int PRparseRecordId = 0;
47 #pragma warning restore 0414
50 internal InternalParseTypeE PRparseTypeEnum = InternalParseTypeE.Empty;
51 internal InternalObjectTypeE PRobjectTypeEnum = InternalObjectTypeE.Empty;
52 internal InternalArrayTypeE PRarrayTypeEnum = InternalArrayTypeE.Empty;
53 internal InternalMemberTypeE PRmemberTypeEnum = InternalMemberTypeE.Empty;
54 internal InternalMemberValueE PRmemberValueEnum = InternalMemberValueE.Empty;
55 internal InternalObjectPositionE PRobjectPositionEnum = InternalObjectPositionE.Empty;
58 internal String PRname;
61 internal String PRvalue;
62 internal Object PRvarValue;
65 internal String PRkeyDt;
66 internal Type PRdtType;
67 internal InternalPrimitiveTypeE PRdtTypeCode;
68 // disable csharp compiler warning #0414: field assigned unused value
69 #pragma warning disable 0414
70 internal bool PRisVariant = false; // Used by Binary
71 internal bool PRisEnum = false;
72 #pragma warning restore 0414
75 internal long PRobjectId;
78 internal long PRidRef;
83 internal String PRarrayElementTypeString;
84 internal Type PRarrayElementType;
85 internal bool PRisArrayVariant = false;
86 internal InternalPrimitiveTypeE PRarrayElementTypeCode;
88 // Parsed array information
90 internal int[] PRlengthA;
91 // disable csharp compiler warning #0414: field assigned unused value
92 #pragma warning disable 0414
93 internal int[] PRpositionA;
94 internal int[] PRlowerBoundA;
95 internal int[] PRupperBoundA;
96 #pragma warning restore 0414
98 // Array map for placing array elements in array
99 internal int[] PRindexMap;
100 internal int PRmemberIndex;
101 internal int PRlinearlength;
102 internal int[] PRrectangularMap;
103 internal bool PRisLowerBound;
105 // SerializedStreamHeader information
106 // disable csharp compiler warning #0414: field assigned unused value
107 #pragma warning disable 0414
108 internal long PRtopId;
109 internal long PRheaderId;
110 #pragma warning restore 0414
113 // MemberInfo accumulated during parsing of members
115 internal ReadObjectInfo PRobjectInfo;
117 // ValueType Fixup needed
118 internal bool PRisValueTypeFixup = false;
121 internal Object PRnewObj;
122 internal Object[] PRobjectA; //optimization, will contain object[]
123 internal PrimitiveArray PRprimitiveArray; // for Primitive Soap arrays, optimization
124 internal bool PRisRegistered; // Used when registering nested classes
125 internal Object[] PRmemberData; // member data is collected here before populating
126 internal SerializationInfo PRsi;
128 internal int PRnullCount; // Count of consecutive nulls within an array
131 internal ParseRecord()
137 // Get a String describing the ParseRecord
139 public String Trace()
141 return "ParseRecord"+PRparseRecordId+" ParseType "+ ((Enum)PRparseTypeEnum).ToString() +" name "+PRname+" keyDt "+Util.PString(PRkeyDt);
145 // Initialize ParseRecord. Called when reusing.
149 PRparseTypeEnum = InternalParseTypeE.Empty;
150 PRobjectTypeEnum = InternalObjectTypeE.Empty;
151 PRarrayTypeEnum = InternalArrayTypeE.Empty;
152 PRmemberTypeEnum = InternalMemberTypeE.Empty;
153 PRmemberValueEnum = InternalMemberValueE.Empty;
154 PRobjectPositionEnum = InternalObjectPositionE.Empty;
165 PRdtTypeCode = InternalPrimitiveTypeE.Invalid;
176 // Array Element Type
177 PRarrayElementTypeString = null;
178 PRarrayElementType = null;
179 PRisArrayVariant = false;
180 PRarrayElementTypeCode = InternalPrimitiveTypeE.Invalid;
183 // Parsed array information
187 PRlowerBoundA = null;
188 PRupperBoundA = null;
190 // Array map for placing array elements in array
194 PRrectangularMap = null;
195 PRisLowerBound = false;
197 // SerializedStreamHeader information
201 // ValueType Fixup needed
202 PRisValueTypeFixup = false;
206 PRprimitiveArray = null;
208 PRisRegistered = false;
215 #if _DEBUG // Dump ParseRecord.
216 [Conditional("SER_LOGGING")]
219 SerTrace.Log("ParseRecord Dump ",PRparseRecordId);
220 SerTrace.Log("Enums");
221 Util.NVTrace("ParseType",((Enum)PRparseTypeEnum).ToString());
222 Util.NVTrace("ObjectType",((Enum)PRobjectTypeEnum).ToString());
223 Util.NVTrace("ArrayType",((Enum)PRarrayTypeEnum).ToString());
224 Util.NVTrace("MemberType",((Enum)PRmemberTypeEnum).ToString());
225 Util.NVTrace("MemberValue",((Enum)PRmemberValueEnum).ToString());
226 Util.NVTrace("ObjectPosition",((Enum)PRobjectPositionEnum).ToString());
227 SerTrace.Log("Basics");
228 Util.NVTrace("Name",PRname);
229 Util.NVTrace("Value ",PRvalue);
230 Util.NVTrace("varValue ",PRvarValue);
231 if (PRvarValue != null)
232 Util.NVTrace("varValue type",PRvarValue.GetType());
234 Util.NVTrace("keyDt",PRkeyDt);
235 Util.NVTrace("dtType",PRdtType);
236 Util.NVTrace("code",((Enum)PRdtTypeCode).ToString());
237 Util.NVTrace("objectID",PRobjectId);
238 Util.NVTrace("idRef",PRidRef);
239 Util.NVTrace("isEnum",PRisEnum);
240 SerTrace.Log("Array ");
241 Util.NVTrace("arrayElementTypeString",PRarrayElementTypeString);
242 Util.NVTrace("arrayElementType",PRarrayElementType);
243 Util.NVTrace("arrayElementTypeCode",((Enum)PRarrayElementTypeCode).ToString());
244 Util.NVTrace("isArrayVariant",PRisArrayVariant);
245 Util.NVTrace("rank",PRrank);
246 Util.NVTrace("dimensions", Util.PArray(PRlengthA));
247 Util.NVTrace("position", Util.PArray(PRpositionA));
248 Util.NVTrace("lowerBoundA", Util.PArray(PRlowerBoundA));
249 Util.NVTrace("upperBoundA", Util.PArray(PRupperBoundA));
250 SerTrace.Log("Header ");
251 Util.NVTrace("nullCount", PRnullCount);
253 SerTrace.Log("New Object");
254 if (PRnewObj != null)
255 Util.NVTrace("newObj", PRnewObj);
261 internal interface ITrace
267 // Implements a stack used for parsing
268 internal sealed class SerStack
270 internal Object[] objects = new Object[5];
271 internal String stackId;
272 internal int top = -1;
273 // disable csharp compiler warning #0414: field assigned unused value
274 #pragma warning disable 0414
275 internal int next = 0;
276 #pragma warning restore 0414
283 internal SerStack(String stackId) {
284 this.stackId = stackId;
287 // Push the object onto the stack
288 internal void Push(Object obj) {
290 SerTrace.Log(this, "Push ",stackId," ",((obj is ITrace)?((ITrace)obj).Trace():""));
292 if (top == (objects.Length -1))
296 objects[++top] = obj;
299 // Pop the object from the stack
300 internal Object Pop() {
304 Object obj = objects[top];
305 objects[top--] = null;
307 SerTrace.Log(this, "Pop ",stackId," ",((obj is ITrace)?((ITrace)obj).Trace():""));
312 internal void IncreaseCapacity() {
313 int size = objects.Length * 2;
314 Object[] newItems = new Object[size];
315 Array.Copy(objects, 0, newItems, 0, objects.Length);
319 // Gets the object on the top of the stack
320 internal Object Peek() {
324 SerTrace.Log(this, "Peek ",stackId," ",((objects[top] is ITrace)?((ITrace)objects[top]).Trace():""));
329 // Gets the second entry in the stack.
330 internal Object PeekPeek() {
334 SerTrace.Log(this, "PeekPeek ",stackId," ",((objects[top - 1] is ITrace)?((ITrace)objects[top - 1]).Trace():""));
336 return objects[top - 1];
339 // The number of entries in the stack
340 internal int Count() {
344 // The number of entries in the stack
345 internal bool IsEmpty() {
352 [Conditional("SER_LOGGING")]
355 for (int i=0; i<Count(); i++)
357 Object obj = objects[i];
359 SerTrace.Log(this, "Stack Dump ",stackId," "+((obj is ITrace)?((ITrace)obj).Trace():""));
366 // Implements a Growable array
369 internal sealed class SizedArray : ICloneable
371 internal Object[] objects = null;
372 internal Object[] negObjects = null;
374 internal SizedArray()
376 objects = new Object[16];
377 negObjects = new Object[4];
380 internal SizedArray(int length)
382 objects = new Object[length];
383 negObjects = new Object[length];
386 private SizedArray(SizedArray sizedArray)
388 objects = new Object[sizedArray.objects.Length];
389 sizedArray.objects.CopyTo(objects, 0);
390 negObjects = new Object[sizedArray.negObjects.Length];
391 sizedArray.negObjects.CopyTo(negObjects, 0);
394 public Object Clone()
396 return new SizedArray(this);
399 internal Object this[int index]
405 if (-index > negObjects.Length - 1)
407 return negObjects[-index];
411 if (index > objects.Length - 1)
413 return objects[index];
420 if (-index > negObjects.Length-1 )
422 IncreaseCapacity(index);
424 negObjects[-index] = value;
429 if (index > objects.Length-1 )
431 IncreaseCapacity(index);
433 if (objects[index] != null)
435 //Console.WriteLine("SizedArray Setting a non-zero "+index+" "+value);
437 objects[index] = value;
442 internal void IncreaseCapacity(int index)
448 int size = Math.Max(negObjects.Length * 2, (-index)+1);
449 Object[] newItems = new Object[size];
450 Array.Copy(negObjects, 0, newItems, 0, negObjects.Length);
451 negObjects = newItems;
455 int size = Math.Max(objects.Length * 2, index+1);
456 Object[] newItems = new Object[size];
457 Array.Copy(objects, 0, newItems, 0, objects.Length);
463 throw new SerializationException(Environment.GetResourceString("Serialization_CorruptedStream"));
470 internal sealed class IntSizedArray : ICloneable
472 internal int[] objects = new int[16];
473 internal int[] negObjects = new int[4];
475 public IntSizedArray()
479 private IntSizedArray(IntSizedArray sizedArray)
481 objects = new int[sizedArray.objects.Length];
482 sizedArray.objects.CopyTo(objects, 0);
483 negObjects = new int[sizedArray.negObjects.Length];
484 sizedArray.negObjects.CopyTo(negObjects, 0);
487 public Object Clone()
489 return new IntSizedArray(this);
493 internal int this[int index]
499 if (-index > negObjects.Length-1 )
501 return negObjects[-index];
505 if (index > objects.Length-1 )
507 return objects[index];
514 if (-index > negObjects.Length-1 )
516 IncreaseCapacity(index);
518 negObjects[-index] = value;
523 if (index > objects.Length-1 )
525 IncreaseCapacity(index);
527 objects[index] = value;
532 internal void IncreaseCapacity(int index)
538 int size = Math.Max(negObjects.Length * 2, (-index)+1);
539 int[] newItems = new int[size];
540 Array.Copy(negObjects, 0, newItems, 0, negObjects.Length);
541 negObjects = newItems;
545 int size = Math.Max(objects.Length * 2, index+1);
546 int[] newItems = new int[size];
547 Array.Copy(objects, 0, newItems, 0, objects.Length);
553 throw new SerializationException(Environment.GetResourceString("Serialization_CorruptedStream"));
558 internal sealed class NameCache
560 static System.Collections.Concurrent.ConcurrentDictionary<string, object> ht = new System.Collections.Concurrent.ConcurrentDictionary<string, object>();
563 internal Object GetCachedValue(String name)
567 return ht.TryGetValue(name, out value) ? value : null;
570 internal void SetCachedValue(Object value)
578 internal static class Util
580 // Replaces a null string with an empty string
581 internal static String PString(String value)
589 // Converts an object to a string and checks for nulls
591 internal static String PString(Object value)
596 return value.ToString();
599 // Converts a single int array to a string
601 internal static String PArray(int[] array)
605 StringBuilder sb = new StringBuilder(10);
607 for (int i=0; i<array.Length; i++)
610 if (i != array.Length -1)
614 return sb.ToString();
620 // Traces an name value pair
622 [Conditional("SER_LOGGING")]
623 internal static void NVTrace(String name, String value)
625 SerTrace.Log(" "+name+((value == null)?" = null":" = "+value));
628 // Traces an name value pair
629 [Conditional("SER_LOGGING")]
630 internal static void NVTrace(String name, Object value)
632 SerTrace.Log(" "+name+((value == null)?" = null":" = "+value.ToString()));
635 // Traces an name value pair
637 [Conditional("_LOGGING")]
638 internal static void NVTraceI(String name, String value)
640 BCLDebug.Trace("Binary", " "+name+((value == null)?" = null":" = "+value));
643 // Traces an name value pair
644 [Conditional("_LOGGING")]
645 internal static void NVTraceI(String name, Object value)
647 BCLDebug.Trace("Binary", " "+name+((value == null)?" = null":" = "+value.ToString()));
653 // Used to fixup value types. Only currently used for valuetypes which are array items.
654 internal sealed class ValueFixup
656 internal ValueFixupEnum valueFixupEnum = ValueFixupEnum.Empty;
657 internal Array arrayObj;
658 internal int[] indexMap;
659 internal Object header = null;
660 internal Object memberObject;
661 internal static volatile MemberInfo valueInfo;
662 internal ReadObjectInfo objectInfo;
663 internal String memberName;
665 internal ValueFixup(Array arrayObj, int[] indexMap)
668 SerTrace.Log(this, "Array Constructor ",arrayObj);
670 valueFixupEnum = ValueFixupEnum.Array;
671 this.arrayObj = arrayObj;
672 this.indexMap = indexMap;
675 internal ValueFixup(Object memberObject, String memberName, ReadObjectInfo objectInfo)
678 SerTrace.Log(this, "Member Constructor ",memberObject);
680 valueFixupEnum = ValueFixupEnum.Member;
681 this.memberObject = memberObject;
682 this.memberName = memberName;
683 this.objectInfo = objectInfo;
686 [System.Security.SecurityCritical] // auto-generated
687 internal void Fixup(ParseRecord record, ParseRecord parent) {
688 Object obj = record.PRnewObj;
690 SerTrace.Log(this, "Fixup ",obj," ",((Enum)valueFixupEnum).ToString());
692 switch (valueFixupEnum)
694 case ValueFixupEnum.Array:
695 arrayObj.SetValue(obj, indexMap);
697 case ValueFixupEnum.Header:
698 Type type = typeof(Header);
699 if (valueInfo == null)
701 MemberInfo[] valueInfos = type.GetMember("Value");
702 if (valueInfos.Length != 1)
703 throw new SerializationException(Environment.GetResourceString("Serialization_HeaderReflection",valueInfos.Length));
704 valueInfo = valueInfos[0];
706 FormatterServices.SerializationSetValue(valueInfo, header, obj);
708 case ValueFixupEnum.Member:
709 SerTrace.Log(this, "Fixup Member new object value ",obj," memberObject ",memberObject);
713 SerTrace.Log(this, "Recording a fixup on member: ", memberName,
714 " in object id", parent.PRobjectId, " Required Object ", record.PRobjectId);
715 objectInfo.objectManager.RecordDelayedFixup(parent.PRobjectId, memberName, record.PRobjectId);
716 // Console.WriteLine("SerializationInfo: Main Object ({0}): {1}. SubObject ({2}): {3}", parent.PRobjectId,
717 // objectInfo.obj, record.PRobjectId, obj);
721 MemberInfo memberInfo = objectInfo.GetMemberInfo(memberName);
722 SerTrace.Log(this, "Recording a fixup on member:", memberInfo, " in object id ",
723 parent.PRobjectId," Required Object", record.PRobjectId);
724 if (memberInfo != null)
725 objectInfo.objectManager.RecordFixup(parent.PRobjectId, memberInfo, record.PRobjectId);
726 // Console.WriteLine("MemberFixup: Main Object({0}): {1}. SubObject({2}): {3}", parent.PRobjectId,
727 // objectInfo.obj.GetType(), record.PRobjectId, obj.GetType());
735 public String Trace()
737 return "ValueFixup"+((Enum)valueFixupEnum).ToString();
742 // Class used to transmit Enums from the XML and Binary Formatter class to the ObjectWriter and ObjectReader class
743 internal sealed class InternalFE
745 internal FormatterTypeStyle FEtypeFormat;
746 internal FormatterAssemblyStyle FEassemblyFormat;
747 internal TypeFilterLevel FEsecurityLevel;
748 internal InternalSerializerTypeE FEserializerTypeEnum;
752 internal sealed class NameInfo
754 internal String NIFullName; // Name from SerObjectInfo.GetType
755 internal long NIobjectId;
756 internal long NIassemId;
757 internal InternalPrimitiveTypeE NIprimitiveTypeEnum = InternalPrimitiveTypeE.Invalid;
758 internal Type NItype;
759 internal bool NIisSealed;
760 internal bool NIisArray;
761 internal bool NIisArrayItem;
762 internal bool NItransmitTypeOnObject;
763 internal bool NItransmitTypeOnMember;
764 internal bool NIisParentTypeOnObject;
765 internal InternalArrayTypeE NIarrayEnum;
777 NIprimitiveTypeEnum = InternalPrimitiveTypeE.Invalid;
780 NItransmitTypeOnObject = false;
781 NItransmitTypeOnMember = false;
782 NIisParentTypeOnObject = false;
784 NIisArrayItem = false;
785 NIarrayEnum = InternalArrayTypeE.Empty;
786 NIsealedStatusChecked = false;
790 [Conditional("SER_LOGGING")]
791 internal void Dump(String value)
793 Util.NVTrace("name", NIFullName);
794 Util.NVTrace("objectId", NIobjectId);
795 Util.NVTrace("assemId", NIassemId);
796 Util.NVTrace("primitiveTypeEnum", ((Enum)NIprimitiveTypeEnum).ToString());
797 Util.NVTrace("type", NItype);
798 Util.NVTrace("isSealed", NIisSealed);
799 Util.NVTrace("transmitTypeOnObject", NItransmitTypeOnObject);
800 Util.NVTrace("transmitTypeOnMember", NItransmitTypeOnMember);
801 Util.NVTrace("isParentTypeOnObject", NIisParentTypeOnObject);
802 Util.NVTrace("isArray", NIisArray);
803 Util.NVTrace("isArrayItem", NIisArrayItem);
804 Util.NVTrace("arrayEnum", ((Enum)NIarrayEnum).ToString());
807 private bool NIsealedStatusChecked = false;
811 if (!NIsealedStatusChecked)
813 NIisSealed = NItype.IsSealed;
814 NIsealedStatusChecked = true;
823 if (this.NIFullName == null)
824 this.NIFullName = NItype.FullName;
826 return this.NIFullName;
829 this.NIFullName = value;
834 internal sealed class PrimitiveArray
836 InternalPrimitiveTypeE code;
837 Boolean[] booleanA = null;
839 Double[] doubleA = null;
840 Int16[] int16A = null;
841 Int32[] int32A = null;
842 Int64[] int64A = null;
843 SByte[] sbyteA = null;
844 Single[] singleA = null;
845 UInt16[] uint16A = null;
846 UInt32[] uint32A = null;
847 UInt64[] uint64A = null;
850 internal PrimitiveArray(InternalPrimitiveTypeE code, Array array)
855 internal void Init(InternalPrimitiveTypeE code, Array array)
860 case InternalPrimitiveTypeE.Boolean:
861 booleanA = (Boolean[])array;
863 case InternalPrimitiveTypeE.Char:
864 charA = (Char[])array;
866 case InternalPrimitiveTypeE.Double:
867 doubleA = (Double[])array;
869 case InternalPrimitiveTypeE.Int16:
870 int16A = (Int16[])array;
872 case InternalPrimitiveTypeE.Int32:
873 int32A = (Int32[])array;
875 case InternalPrimitiveTypeE.Int64:
876 int64A = (Int64[])array;
878 case InternalPrimitiveTypeE.SByte:
879 sbyteA = (SByte[])array;
881 case InternalPrimitiveTypeE.Single:
882 singleA = (Single[])array;
884 case InternalPrimitiveTypeE.UInt16:
885 uint16A = (UInt16[])array;
887 case InternalPrimitiveTypeE.UInt32:
888 uint32A = (UInt32[])array;
890 case InternalPrimitiveTypeE.UInt64:
891 uint64A = (UInt64[])array;
896 internal void SetValue(String value, int index)
900 case InternalPrimitiveTypeE.Boolean:
901 booleanA[index] = Boolean.Parse(value);
903 case InternalPrimitiveTypeE.Char:
904 if ((value[0] == '_') && (value.Equals("_0x00_")))
905 charA[index] = Char.MinValue;
907 charA[index] = Char.Parse(value);
909 case InternalPrimitiveTypeE.Double:
910 doubleA[index] = Double.Parse(value, CultureInfo.InvariantCulture);
912 case InternalPrimitiveTypeE.Int16:
913 int16A[index] = Int16.Parse(value, CultureInfo.InvariantCulture);
915 case InternalPrimitiveTypeE.Int32:
916 int32A[index] = Int32.Parse(value, CultureInfo.InvariantCulture);
918 case InternalPrimitiveTypeE.Int64:
919 int64A[index] = Int64.Parse(value, CultureInfo.InvariantCulture);
921 case InternalPrimitiveTypeE.SByte:
922 sbyteA[index] = SByte.Parse(value, CultureInfo.InvariantCulture);
924 case InternalPrimitiveTypeE.Single:
925 singleA[index] = Single.Parse(value, CultureInfo.InvariantCulture);
927 case InternalPrimitiveTypeE.UInt16:
928 uint16A[index] = UInt16.Parse(value, CultureInfo.InvariantCulture);
930 case InternalPrimitiveTypeE.UInt32:
931 uint32A[index] = UInt32.Parse(value, CultureInfo.InvariantCulture);
933 case InternalPrimitiveTypeE.UInt64:
934 uint64A[index] = UInt64.Parse(value, CultureInfo.InvariantCulture);