The Labs \ Source Viewer \ SSCLI \ System.Runtime.Serialization.Formatters.Binary \ ObjectWriter

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class: ObjectWriter
  18. **
  19. **
  20. ** Purpose: Serializes an object graph into XML in SOAP format
  21. **
  22. **
  23. ===========================================================*/
  24. namespace System.Runtime.Serialization.Formatters.Binary
  25. {
  26.     using System;
  27.     using System.IO;
  28.     using System.Reflection;
  29.     using System.Reflection.Cache;
  30.     using System.Collections;
  31.     using System.Collections.Generic;
  32.     using System.Text;
  33.     using System.Runtime.Remoting;
  34.     using System.Runtime.Remoting.Messaging;
  35.     using System.Runtime.Serialization;
  36.     using System.Security.Permissions;
  37.     using System.Security;
  38.     using System.Diagnostics;
  39.     using System.Globalization;
  40.    
  41.     internal sealed class ObjectWriter
  42.     {
  43.         private Queue m_objectQueue;
  44.         private ObjectIDGenerator m_idGenerator;
  45.         private int m_currentId;
  46.        
  47.         private ISurrogateSelector m_surrogates;
  48.         private StreamingContext m_context;
  49.         private __BinaryWriter serWriter;
  50.         private SerializationObjectManager m_objectManager;
  51.        
  52.         private long topId;
  53.         private string topName = null;
  54.         private Header[] headers;
  55.        
  56.         private InternalFE formatterEnums;
  57.        
  58.         private SerObjectInfoInit serObjectInfoInit = null;
  59.        
  60.         private IFormatterConverter m_formatterConverter;
  61.        
  62.         internal object[] crossAppDomainArray = null;
  63.         internal ArrayList internalCrossAppDomainArray = null;
  64.        
  65.         // XMLObjectWriter Constructor
  66.         internal ObjectWriter(ISurrogateSelector selector, StreamingContext context, InternalFE formatterEnums)
  67.         {
  68.             m_currentId = 1;
  69.             m_surrogates = selector;
  70.             m_context = context;
  71.             this.formatterEnums = formatterEnums;
  72.             m_objectManager = new SerializationObjectManager(context);
  73.             SerTrace.InfoLog(formatterEnums.FEtypeFormat + " " + ((Enum)formatterEnums.FEserializerTypeEnum));
  74.            
  75.            
  76.         }
  77.        
  78.         // Commences the process of serializing the entire graph.
  79.         // initialize the graph walker.
  80.         internal void Serialize(object graph, Header[] inHeaders, __BinaryWriter serWriter, bool fCheck)
  81.         {
  82.             SerTrace.Log(this, "Serialize Entry 2 ", graph, ((headers == null) ? " no headers " : "headers "));
  83.            
  84.             if (fCheck) {
  85.                 CodeAccessPermission.DemandInternal(PermissionType.SecuritySerialization);
  86.             }
  87.            
  88.             if (graph == null)
  89.                 throw new ArgumentNullException("graph", Environment.GetResourceString("ArgumentNull_Graph"));
  90.            
  91.             if (serWriter == null)
  92.                 throw new ArgumentNullException("serWriter", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentNull_WithParamName"), "serWriter"));
  93.            
  94.             this.serWriter = serWriter;
  95.             this.headers = inHeaders;
  96.            
  97.             SerTrace.Log(this, "Serialize New SerializedTypeTable");
  98.             serWriter.WriteBegin();
  99.             long headerId = 0;
  100.             object obj;
  101.             long objectId;
  102.             bool isNew;
  103.             bool bMethodCall = false;
  104.             bool bMethodReturn = false;
  105.            
  106.             // Special case IMethodCallMessage and IMethodReturnMessage for performance
  107.             IMethodCallMessage mess = graph as IMethodCallMessage;
  108.             if (mess != null) {
  109.                 bMethodCall = true;
  110.                 graph = WriteMethodCall(mess);
  111.             }
  112.             else {
  113.                 IMethodReturnMessage mr = graph as IMethodReturnMessage;
  114.                 if (mr != null) {
  115.                     bMethodReturn = true;
  116.                     graph = WriteMethodReturn(mr);
  117.                 }
  118.             }
  119.            
  120.             if (graph == null) {
  121.                 WriteSerializedStreamHeader(topId, headerId);
  122.                
  123.                 if (bMethodCall)
  124.                     serWriter.WriteMethodCall();
  125.                 else if (bMethodReturn)
  126.                     serWriter.WriteMethodReturn();
  127.                
  128.                 serWriter.WriteSerializationHeaderEnd();
  129.                 serWriter.WriteEnd();
  130.                 return;
  131.             }
  132.            
  133.             // allocations if methodCall or methodResponse and no graph
  134.             m_idGenerator = new ObjectIDGenerator();
  135.             m_objectQueue = new Queue();
  136.             m_formatterConverter = new FormatterConverter();
  137.             serObjectInfoInit = new SerObjectInfoInit();
  138.            
  139.             topId = InternalGetId(graph, false, null, out isNew);
  140.            
  141.            
  142.             if (headers != null)
  143.                 headerId = InternalGetId(headers, false, null, out isNew);
  144.             else
  145.                 headerId = -1;
  146.            
  147.             WriteSerializedStreamHeader(topId, headerId);
  148.            
  149.            
  150.             if (bMethodCall)
  151.                 serWriter.WriteMethodCall();
  152.             else if (bMethodReturn)
  153.                 serWriter.WriteMethodReturn();
  154.            
  155.            
  156.             SerTrace.Log(this, "Serialize Schedule 0");
  157.            
  158.             // Write out SerializedStream header
  159.             if ((headers != null) && (headers.Length > 0))
  160.                 m_objectQueue.Enqueue(headers);
  161.            
  162.             if (graph != null)
  163.                 m_objectQueue.Enqueue(graph);
  164.            
  165.             while ((obj = GetNext(out objectId)) != null) {
  166.                 SerTrace.Log(this, "Serialize GetNext ", obj);
  167.                 WriteObjectInfo objectInfo = null;
  168.                
  169.                 // GetNext will return either an object or a WriteObjectInfo.
  170.                 // A WriteObjectInfo is returned if this object was member of another object
  171.                 if (obj is WriteObjectInfo) {
  172.                     SerTrace.Log(this, "Serialize GetNext recognizes WriteObjectInfo");
  173.                     objectInfo = (WriteObjectInfo)obj;
  174.                 }
  175.                 else {
  176.                     objectInfo = WriteObjectInfo.Serialize(obj, m_surrogates, m_context, serObjectInfoInit, m_formatterConverter, this);
  177.                     objectInfo.assemId = GetAssemblyId(objectInfo);
  178.                 }
  179.                
  180.                
  181.                 objectInfo.objectId = objectId;
  182.                 NameInfo typeNameInfo = TypeToNameInfo(objectInfo);
  183.                 Write(objectInfo, typeNameInfo, typeNameInfo);
  184.                 PutNameInfo(typeNameInfo);
  185.                 objectInfo.ObjectEnd();
  186.             }
  187.            
  188.             serWriter.WriteSerializationHeaderEnd();
  189.             serWriter.WriteEnd();
  190.            
  191.             // Invoke OnSerialized Event
  192.             m_objectManager.RaiseOnSerializedEvent();
  193.            
  194.             SerTrace.Log(this, "Serialize Exit ");
  195.         }
  196.        
  197.         private object[] WriteMethodCall(IMethodCallMessage mcm)
  198.         {
  199.             // In header
  200.             string uri = mcm.Uri;
  201.             string methodName = mcm.MethodName;
  202.             string typeName = mcm.TypeName;
  203.            
  204.             // Optional
  205.             object methodSignature = null;
  206.             object callContext = null;
  207.             object[] properties = null;
  208.            
  209.             // instantiation args
  210.             Type[] instArgs = null;
  211.             if (mcm.MethodBase.IsGenericMethod)
  212.                 instArgs = mcm.MethodBase.GetGenericArguments();
  213.            
  214.             // args
  215.             object[] args = mcm.Args;
  216.            
  217.             IInternalMessage iim = mcm as IInternalMessage;
  218.            
  219.             // user properties (everything but special entries)
  220.             if ((iim == null) || iim.HasProperties())
  221.                 properties = StoreUserPropertiesForMethodMessage(mcm);
  222.            
  223.             // handle method signature
  224.             if (mcm.MethodSignature != null && RemotingServices.IsMethodOverloaded(mcm))
  225.                 methodSignature = mcm.MethodSignature;
  226.            
  227.             // handle call context
  228.             LogicalCallContext lcc = mcm.LogicalCallContext;
  229.             if (lcc == null) {
  230.                 callContext = null;
  231.             }
  232.             else if (lcc.HasInfo)
  233.                 callContext = lcc;
  234.             else {
  235.                 // just smuggle the call id string
  236.                 callContext = lcc.RemotingData.LogicalCallID;
  237.             }
  238.            
  239.             return serWriter.WriteCallArray(uri, methodName, typeName, instArgs, args, methodSignature, callContext, properties);
  240.         }
  241.        
  242.        
  243.         private object[] WriteMethodReturn(IMethodReturnMessage mrm)
  244.         {
  245.             object returnValue = mrm.ReturnValue;
  246.             object[] args = mrm.Args;
  247.             Exception exception = mrm.Exception;
  248.             object callContext;
  249.             object[] properties = null;
  250.            
  251.             ReturnMessage retMsg = mrm as ReturnMessage;
  252.            
  253.             // user properties (everything but special entries)
  254.             if ((retMsg == null) || retMsg.HasProperties())
  255.                 properties = StoreUserPropertiesForMethodMessage(mrm);
  256.            
  257.             // handle call context
  258.             LogicalCallContext lcc = mrm.LogicalCallContext;
  259.             if (lcc == null) {
  260.                 callContext = null;
  261.             }
  262.             else if (lcc.HasInfo)
  263.                 callContext = lcc;
  264.             else {
  265.                 // just smuggle the call id string
  266.                 callContext = lcc.RemotingData.LogicalCallID;
  267.             }
  268.            
  269.             return serWriter.WriteReturnArray(returnValue, args, exception, callContext, properties);
  270.         }
  271.        
  272.         // returns number of entries added to argsToSerialize
  273.         private static object[] StoreUserPropertiesForMethodMessage(IMethodMessage msg)
  274.         {
  275.             ArrayList argsToSerialize = null;
  276.             IDictionary properties = msg.Properties;
  277.            
  278.             if (properties == null)
  279.                 return null;
  280.            
  281.             MessageDictionary dict = properties as MessageDictionary;
  282.             if (dict != null) {
  283.                 if (dict.HasUserData()) {
  284.                     int co = 0;
  285.                     foreach (DictionaryEntry entry in dict.InternalDictionary) {
  286.                         if (argsToSerialize == null)
  287.                             argsToSerialize = new ArrayList();
  288.                         argsToSerialize.Add(entry);
  289.                         co++;
  290.                     }
  291.                    
  292.                     return argsToSerialize.ToArray();
  293.                 }
  294.                 else {
  295.                     return null;
  296.                 }
  297.             }
  298.             else {
  299.                 int co = 0;
  300.                 foreach (DictionaryEntry entry in properties) {
  301.                     if (argsToSerialize == null)
  302.                         argsToSerialize = new ArrayList();
  303.                     argsToSerialize.Add(entry);
  304.                     co++;
  305.                 }
  306.                
  307.                 if (argsToSerialize != null)
  308.                     return argsToSerialize.ToArray();
  309.                 else
  310.                     return null;
  311.             }
  312.            
  313.         }
  314.         // StoreUserPropertiesForMethodMessage
  315.         internal SerializationObjectManager ObjectManager {
  316.             get { return m_objectManager; }
  317.         }
  318.        
  319.         // Writes a given object to the stream.
  320.         private void Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
  321.         {
  322.             #if _DEBUG
  323.             SerTrace.Log(this, "Write 1 Entry objectInfo ", objectInfo, ", memberNameInfo ", memberNameInfo, ", typeNameInfo ", typeNameInfo);
  324.             memberNameInfo.Dump("Write memberNameInfo");
  325.             typeNameInfo.Dump("Write typeNameInfo");
  326.             #endif
  327.             object obj = objectInfo.obj;
  328.             if (obj == null)
  329.                 throw new ArgumentNullException("objectInfo.obj", Environment.GetResourceString("ArgumentNull_Obj"));
  330.            
  331.             SerTrace.Log(this, "Write 1 objectInfo obj ", objectInfo.obj, " objectId ", objectInfo.objectId, " objectType ", objectInfo.objectType);
  332.             Type objType = objectInfo.objectType;
  333.             long objectId = objectInfo.objectId;
  334.            
  335.            
  336.             SerTrace.Log(this, "Write 1 ", obj, " ObjectId ", objectId);
  337.            
  338.             if (objType == Converter.typeofString) {
  339.                 // Top level String
  340.                 memberNameInfo.NIobjectId = objectId;
  341.                 serWriter.WriteObjectString((int)objectId, obj.ToString());
  342.             }
  343.             else {
  344.                
  345.                 if (objectInfo.isArray) {
  346.                     WriteArray(objectInfo, memberNameInfo, null);
  347.                 }
  348.                 else {
  349.                     string[] memberNames;
  350.                     Type[] memberTypes;
  351.                     object[] memberData;
  352.                    
  353.                     objectInfo.GetMemberInfo(out memberNames, out memberTypes, out memberData);
  354.                    
  355.                     // Only Binary needs to transmit types for ISerializable because the binary formatter transmits the types in URT format.
  356.                     // Soap transmits all types as strings, so it is up to the ISerializable object to convert the string back to its URT type
  357.                     if (objectInfo.isSi || CheckTypeFormat(formatterEnums.FEtypeFormat, FormatterTypeStyle.TypesAlways)) {
  358.                         SerTrace.Log(this, "Write 1 TransmitOnObject ");
  359.                         memberNameInfo.NItransmitTypeOnObject = true;
  360.                         memberNameInfo.NIisParentTypeOnObject = true;
  361.                         typeNameInfo.NItransmitTypeOnObject = true;
  362.                         typeNameInfo.NIisParentTypeOnObject = true;
  363.                     }
  364.                    
  365.                     WriteObjectInfo[] memberObjectInfos = new WriteObjectInfo[memberNames.Length];
  366.                    
  367.                     // Get assembly information
  368.                     // Binary Serializer, assembly names need to be
  369.                     // written before objects are referenced.
  370.                     // GetAssemId here will write out the
  371.                     // assemblyStrings at the right Binary
  372.                     // Serialization object boundary.
  373.                     for (int i = 0; i < memberTypes.Length; i++) {
  374.                         Type type;
  375.                         if (memberTypes[i] != null)
  376.                             type = memberTypes[i];
  377.                         else if (memberData[i] != null)
  378.                             type = GetType(memberData[i]);
  379.                         else
  380.                             type = Converter.typeofObject;
  381.                        
  382.                         SerTrace.Log(this, "Write 1 member type ", type);
  383.                         InternalPrimitiveTypeE code = ToCode(type);
  384.                         if ((code == InternalPrimitiveTypeE.Invalid) && (type != Converter.typeofString)) {
  385.                             SerTrace.Log(this, "Write 1 Create ObjectInfo ", memberTypes[i], " memberData ", memberData[i]);
  386.                             if (memberData[i] != null) {
  387.                                 memberObjectInfos[i] = WriteObjectInfo.Serialize(memberData[i], m_surrogates, m_context, serObjectInfoInit, m_formatterConverter, this);
  388.                                 memberObjectInfos[i].assemId = GetAssemblyId(memberObjectInfos[i]);
  389.                             }
  390.                             else {
  391.                                 memberObjectInfos[i] = WriteObjectInfo.Serialize(memberTypes[i], m_surrogates, m_context, serObjectInfoInit, m_formatterConverter);
  392.                                 memberObjectInfos[i].assemId = GetAssemblyId(memberObjectInfos[i]);
  393.                             }
  394.                         }
  395.                     }
  396.                     Write(objectInfo, memberNameInfo, typeNameInfo, memberNames, memberTypes, memberData, memberObjectInfos);
  397.                     SerTrace.Log(this, "Write 1 ", obj, " type ", GetType(obj));
  398.                 }
  399.             }
  400.             SerTrace.Log(this, "Write 1 Exit ", obj);
  401.         }
  402.        
  403.         // Writes a given object to the stream.
  404.         private void Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo, string[] memberNames, Type[] memberTypes, object[] memberData, WriteObjectInfo[] memberObjectInfos)
  405.         {
  406.             SerTrace.Log(this, "Write 2 Entry obj ", objectInfo.obj, ". objectId ", objectInfo.objectId, ", objType ", typeNameInfo.NIname, ", memberName ", memberNameInfo.NIname, ", memberType ",
  407.             typeNameInfo.NIname);
  408.            
  409.             int numItems = memberNames.Length;
  410.             NameInfo topNameInfo = null;
  411.            
  412.             if (memberNameInfo != null) {
  413.                 SerTrace.Log(this, "Write 2 ObjectBegin, memberName ", memberNameInfo.NIname);
  414.                 memberNameInfo.NIobjectId = objectInfo.objectId;
  415.                 serWriter.WriteObject(memberNameInfo, typeNameInfo, numItems, memberNames, memberTypes, memberObjectInfos);
  416.             }
  417.             else if ((objectInfo.objectId == topId) && (topName != null)) {
  418.                 SerTrace.Log(this, "Write 2 ObjectBegin, topId method name ", topName);
  419.                 topNameInfo = MemberToNameInfo(topName);
  420.                 topNameInfo.NIobjectId = objectInfo.objectId;
  421.                 serWriter.WriteObject(topNameInfo, typeNameInfo, numItems, memberNames, memberTypes, memberObjectInfos);
  422.             }
  423.             else {
  424.                 if (objectInfo.objectType != Converter.typeofString) {
  425.                     SerTrace.Log(this, "Write 2 ObjectBegin, default ", typeNameInfo.NIname);
  426.                     typeNameInfo.NIobjectId = objectInfo.objectId;
  427.                     serWriter.WriteObject(typeNameInfo, null, numItems, memberNames, memberTypes, memberObjectInfos);
  428.                 }
  429.             }
  430.            
  431.             if (memberNameInfo.NIisParentTypeOnObject) {
  432.                 memberNameInfo.NItransmitTypeOnObject = true;
  433.                 memberNameInfo.NIisParentTypeOnObject = false;
  434.             }
  435.             else
  436.                 memberNameInfo.NItransmitTypeOnObject = false;
  437.            
  438.            
  439.             // Write members
  440.             for (int i = 0; i < numItems; i++) {
  441.                 WriteMemberSetup(objectInfo, memberNameInfo, typeNameInfo, memberNames[i], memberTypes[i], memberData[i], memberObjectInfos[i]);
  442.             }
  443.            
  444.             if (memberNameInfo != null) {
  445.                 memberNameInfo.NIobjectId = objectInfo.objectId;
  446.                 serWriter.WriteObjectEnd(memberNameInfo, typeNameInfo);
  447.             }
  448.             else if ((objectInfo.objectId == topId) && (topName != null)) {
  449.                 serWriter.WriteObjectEnd(topNameInfo, typeNameInfo);
  450.                 PutNameInfo(topNameInfo);
  451.             }
  452.             else {
  453.                 if (objectInfo.objectType != Converter.typeofString) {
  454.                     string objectName = objectInfo.GetTypeFullName();
  455.                     serWriter.WriteObjectEnd(typeNameInfo, typeNameInfo);
  456.                 }
  457.             }
  458.            
  459.             SerTrace.Log(this, "Write 2 Exit");
  460.         }
  461.        
  462.         private void WriteMemberSetup(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo, string memberName, Type memberType, object memberData, WriteObjectInfo memberObjectInfo)
  463.         {
  464.             NameInfo newMemberNameInfo = MemberToNameInfo(memberName);
  465.             // newMemberNameInfo contains the member type
  466.            
  467.             if (memberObjectInfo != null)
  468.                 newMemberNameInfo.NIassemId = memberObjectInfo.assemId;
  469.             newMemberNameInfo.NItype = memberType;
  470.            
  471.             // newTypeNameInfo contains the data type
  472.             NameInfo newTypeNameInfo = null;
  473.             if (memberObjectInfo == null) {
  474.                 newTypeNameInfo = TypeToNameInfo(memberType);
  475.             }
  476.             else {
  477.                 newTypeNameInfo = TypeToNameInfo(memberObjectInfo);
  478.             }
  479.            
  480.             newMemberNameInfo.NItransmitTypeOnObject = memberNameInfo.NItransmitTypeOnObject;
  481.             newMemberNameInfo.NIisParentTypeOnObject = memberNameInfo.NIisParentTypeOnObject;
  482.             WriteMembers(newMemberNameInfo, newTypeNameInfo, memberData, objectInfo, typeNameInfo, memberObjectInfo);
  483.             PutNameInfo(newMemberNameInfo);
  484.             PutNameInfo(newTypeNameInfo);
  485.         }
  486.        
  487.        
  488.         // Writes the members of an object
  489.         private void WriteMembers(NameInfo memberNameInfo, NameInfo memberTypeNameInfo, object memberData, WriteObjectInfo objectInfo, NameInfo typeNameInfo, WriteObjectInfo memberObjectInfo)
  490.         {
  491.             SerTrace.Log(this, "WriteMembers Entry memberType: ", memberTypeNameInfo.NIname, " memberName: ", memberNameInfo.NIname, " data: ", memberData, " objectId: ", objectInfo.objectId, " Container object ",
  492.             objectInfo.obj, " memberObjectinfo ", memberObjectInfo);
  493.             Type memberType = memberNameInfo.NItype;
  494.             bool assignUniqueIdToValueType = false;
  495.            
  496.             // Types are transmitted for a member as follows:
  497.             // The member is of type object
  498.             // The member object of type is ISerializable and
  499.             // Binary - Types always transmitted.
  500.            
  501.             if (memberType == Converter.typeofObject || Nullable.GetUnderlyingType(memberType) != null) {
  502.                 memberTypeNameInfo.NItransmitTypeOnMember = true;
  503.                 memberNameInfo.NItransmitTypeOnMember = true;
  504.             }
  505.            
  506.             if (CheckTypeFormat(formatterEnums.FEtypeFormat, FormatterTypeStyle.TypesAlways) || (objectInfo.isSi)) {
  507.                 memberTypeNameInfo.NItransmitTypeOnObject = true;
  508.                 memberNameInfo.NItransmitTypeOnObject = true;
  509.                 memberNameInfo.NIisParentTypeOnObject = true;
  510.             }
  511.            
  512.             if (CheckForNull(objectInfo, memberNameInfo, memberTypeNameInfo, memberData)) {
  513.                 return;
  514.             }
  515.            
  516.             object outObj = memberData;
  517.             Type outType = null;
  518.            
  519.             // If member type does not equal data type, transmit type on object.
  520.             if (memberTypeNameInfo.NIprimitiveTypeEnum == InternalPrimitiveTypeE.Invalid) {
  521.                 outType = GetType(outObj);
  522.                 if (memberType != outType) {
  523.                     memberTypeNameInfo.NItransmitTypeOnMember = true;
  524.                     memberNameInfo.NItransmitTypeOnMember = true;
  525.                 }
  526.             }
  527.            
  528.             if (memberType == Converter.typeofObject) {
  529.                 assignUniqueIdToValueType = true;
  530.                 memberType = GetType(memberData);
  531.                 if (memberObjectInfo == null)
  532.                     TypeToNameInfo(memberType, memberTypeNameInfo);
  533.                 else
  534.                     TypeToNameInfo(memberObjectInfo, memberTypeNameInfo);
  535.                 SerTrace.Log(this, "WriteMembers memberType Object, actual memberType ", memberType);
  536.             }
  537.            
  538.             if (memberObjectInfo != null && memberObjectInfo.isArray) {
  539.                 // Array
  540.                 SerTrace.Log(this, "WriteMembers IsArray");
  541.                
  542.                 long arrayId = 0;
  543.                 if (outType == null)
  544.                     outType = GetType(outObj);
  545.                 // outObj is an array. It can never be a value type..
  546.                 arrayId = Schedule(outObj, false, null, memberObjectInfo);
  547.                 if (arrayId > 0) {
  548.                     // Array as object
  549.                     SerTrace.Log(this, "WriteMembers Schedule 3");
  550.                     memberNameInfo.NIobjectId = arrayId;
  551.                     WriteObjectRef(memberNameInfo, arrayId);
  552.                 }
  553.                 else {
  554.                     // Nested Array
  555.                     serWriter.WriteMemberNested(memberNameInfo);
  556.                    
  557.                     memberObjectInfo.objectId = arrayId;
  558.                     memberNameInfo.NIobjectId = arrayId;
  559.                     WriteArray(memberObjectInfo, memberNameInfo, memberObjectInfo);
  560.                     objectInfo.ObjectEnd();
  561.                    
  562.                 }
  563.                 SerTrace.Log(this, "WriteMembers Array Exit ");
  564.                 return;
  565.             }
  566.            
  567.             if (!WriteKnownValueClass(memberNameInfo, memberTypeNameInfo, memberData)) {
  568.                 SerTrace.Log(this, "WriteMembers Object ", memberData);
  569.                
  570.                 {
  571.                     SerTrace.Log(this, "WriteMembers Schedule 4 ", outType, " memberInfo ", memberObjectInfo);
  572.                     if (outType == null)
  573.                         outType = GetType(outObj);
  574.                     long memberObjectId = Schedule(outObj, assignUniqueIdToValueType, outType, memberObjectInfo);
  575.                     if (memberObjectId < 0) {
  576.                         // Nested object
  577.                         SerTrace.Log(this, "WriteMembers Nesting");
  578.                        
  579.                         memberObjectInfo.objectId = memberObjectId;
  580.                         NameInfo newTypeNameInfo = TypeToNameInfo(memberObjectInfo);
  581.                         newTypeNameInfo.NIobjectId = memberObjectId;
  582.                         Write(memberObjectInfo, memberNameInfo, newTypeNameInfo);
  583.                         PutNameInfo(newTypeNameInfo);
  584.                         memberObjectInfo.ObjectEnd();
  585.                     }
  586.                     else {
  587.                         // Object reference
  588.                         memberNameInfo.NIobjectId = memberObjectId;
  589.                         WriteObjectRef(memberNameInfo, memberObjectId);
  590.                     }
  591.                 }
  592.             }
  593.            
  594.             SerTrace.Log(this, "WriteMembers Exit ");
  595.         }
  596.        
  597.         // Writes out an array
  598.         private void WriteArray(WriteObjectInfo objectInfo, NameInfo memberNameInfo, WriteObjectInfo memberObjectInfo)
  599.         {
  600.             SerTrace.Log(this, "WriteArray Entry ", objectInfo.obj, " ", objectInfo.objectId);
  601.            
  602.             bool isAllocatedMemberNameInfo = false;
  603.             if (memberNameInfo == null) {
  604.                 memberNameInfo = TypeToNameInfo(objectInfo);
  605.                 isAllocatedMemberNameInfo = true;
  606.             }
  607.            
  608.             memberNameInfo.NIisArray = true;
  609.            
  610.             long objectId = objectInfo.objectId;
  611.             memberNameInfo.NIobjectId = objectInfo.objectId;
  612.            
  613.             // Get array type
  614.             System.Array array = (System.Array)objectInfo.obj;
  615.             //Type arrayType = array.GetType();
  616.             Type arrayType = objectInfo.objectType;
  617.            
  618.             // Get type of array element
  619.             Type arrayElemType = arrayType.GetElementType();
  620.             WriteObjectInfo arrayElemObjectInfo = null;
  621.             if (!arrayElemType.IsPrimitive) {
  622.                 arrayElemObjectInfo = WriteObjectInfo.Serialize(arrayElemType, m_surrogates, m_context, serObjectInfoInit, m_formatterConverter);
  623.                 arrayElemObjectInfo.assemId = GetAssemblyId(arrayElemObjectInfo);
  624.             }
  625.            
  626.            
  627.             NameInfo arrayElemTypeNameInfo = null;
  628.             if (arrayElemObjectInfo == null)
  629.                 arrayElemTypeNameInfo = TypeToNameInfo(arrayElemType);
  630.             else
  631.                 arrayElemTypeNameInfo = TypeToNameInfo(arrayElemObjectInfo);
  632.             arrayElemTypeNameInfo.NIisArray = arrayElemTypeNameInfo.NItype.IsArray;
  633.            
  634.             NameInfo arrayNameInfo = memberNameInfo;
  635.             arrayNameInfo.NIobjectId = objectId;
  636.             arrayNameInfo.NIisArray = true;
  637.             arrayElemTypeNameInfo.NIobjectId = objectId;
  638.             arrayElemTypeNameInfo.NItransmitTypeOnMember = memberNameInfo.NItransmitTypeOnMember;
  639.             arrayElemTypeNameInfo.NItransmitTypeOnObject = memberNameInfo.NItransmitTypeOnObject;
  640.             arrayElemTypeNameInfo.NIisParentTypeOnObject = memberNameInfo.NIisParentTypeOnObject;
  641.            
  642.             // Get rank and length information
  643.             int rank = array.Rank;
  644.             int[] lengthA = new int[rank];
  645.             int[] lowerBoundA = new int[rank];
  646.             int[] upperBoundA = new int[rank];
  647.             for (int i = 0; i < rank; i++) {
  648.                 lengthA[i] = array.GetLength(i);
  649.                 lowerBoundA[i] = array.GetLowerBound(i);
  650.                 upperBoundA[i] = array.GetUpperBound(i);
  651.             }
  652.            
  653.             InternalArrayTypeE arrayEnum;
  654.            
  655.             if (arrayElemTypeNameInfo.NIisArray) {
  656.                 if (rank == 1)
  657.                     arrayEnum = InternalArrayTypeE.Jagged;
  658.                 else
  659.                     arrayEnum = InternalArrayTypeE.Rectangular;
  660.             }
  661.             else if (rank == 1)
  662.                 arrayEnum = InternalArrayTypeE.Single;
  663.             else
  664.                 arrayEnum = InternalArrayTypeE.Rectangular;
  665.            
  666.             arrayElemTypeNameInfo.NIarrayEnum = arrayEnum;
  667.            
  668.             SerTrace.Log(this, "WriteArray ArrayInfo type ", arrayType, " rank ", rank);
  669.            
  670.            
  671.             // Byte array
  672.             if ((arrayElemType == Converter.typeofByte) && (rank == 1) && (lowerBoundA[0] == 0)) {
  673.                 serWriter.WriteObjectByteArray(memberNameInfo, arrayNameInfo, arrayElemObjectInfo, arrayElemTypeNameInfo, lengthA[0], lowerBoundA[0], (byte[])array);
  674.                 return;
  675.             }
  676.            
  677.             if (arrayElemType == Converter.typeofObject || Nullable.GetUnderlyingType(arrayElemType) != null) {
  678.                 memberNameInfo.NItransmitTypeOnMember = true;
  679.                 arrayElemTypeNameInfo.NItransmitTypeOnMember = true;
  680.             }
  681.            
  682.             if (CheckTypeFormat(formatterEnums.FEtypeFormat, FormatterTypeStyle.TypesAlways)) {
  683.                 memberNameInfo.NItransmitTypeOnObject = true;
  684.                 arrayElemTypeNameInfo.NItransmitTypeOnObject = true;
  685.             }
  686.            
  687.             if (arrayEnum == InternalArrayTypeE.Single) {
  688.                 // Single Dimensional array
  689.                 SerTrace.Log(this, "WriteArray ARRAY_SINGLE ");
  690.                
  691.                 // BinaryFormatter array of primitive types is written out in the WriteSingleArray statement
  692.                 // as a byte buffer
  693.                 serWriter.WriteSingleArray(memberNameInfo, arrayNameInfo, arrayElemObjectInfo, arrayElemTypeNameInfo, lengthA[0], lowerBoundA[0], array);
  694.                
  695.                 if (!(Converter.IsWriteAsByteArray(arrayElemTypeNameInfo.NIprimitiveTypeEnum) && (lowerBoundA[0] == 0))) {
  696.                     object[] objectA = null;
  697.                     if (!arrayElemType.IsValueType) {
  698.                         // Non-primitive type array
  699.                         objectA = (object[])array;
  700.                     }
  701.                    
  702.                     int upperBound = upperBoundA[0] + 1;
  703.                     for (int i = lowerBoundA[0]; i < upperBound; i++) {
  704.                         if (objectA == null)
  705.                             WriteArrayMember(objectInfo, arrayElemTypeNameInfo, array.GetValue(i));
  706.                         else
  707.                             WriteArrayMember(objectInfo, arrayElemTypeNameInfo, objectA[i]);
  708.                     }
  709.                     serWriter.WriteItemEnd();
  710.                 }
  711.             }
  712.             else if (arrayEnum == InternalArrayTypeE.Jagged) {
  713.                 // Jagged Array
  714.                 SerTrace.Log(this, "WriteArray ARRAY_JAGGED");
  715.                
  716.                 arrayNameInfo.NIobjectId = objectId;
  717.                
  718.                 serWriter.WriteJaggedArray(memberNameInfo, arrayNameInfo, arrayElemObjectInfo, arrayElemTypeNameInfo, lengthA[0], lowerBoundA[0]);
  719.                
  720.                 object[] objectA = (object[])array;
  721.                 for (int i = lowerBoundA[0]; i < upperBoundA[0] + 1; i++) {
  722.                     WriteArrayMember(objectInfo, arrayElemTypeNameInfo, objectA[i]);
  723.                 }
  724.                 serWriter.WriteItemEnd();
  725.             }
  726.             else {
  727.                 // Rectangle Array
  728.                 // Get the length for all the ranks
  729.                 SerTrace.Log(this, "WriteArray ARRAY_RECTANGLE");
  730.                
  731.                 arrayNameInfo.NIobjectId = objectId;
  732.                 serWriter.WriteRectangleArray(memberNameInfo, arrayNameInfo, arrayElemObjectInfo, arrayElemTypeNameInfo, rank, lengthA, lowerBoundA);
  733.                
  734.                 IndexTraceMessage("WriteArray Rectangle ", lengthA);
  735.                
  736.                 // Check for a length of zero
  737.                 bool bzero = false;
  738.                 for (int i = 0; i < rank; i++) {
  739.                     if (lengthA[i] == 0) {
  740.                         bzero = true;
  741.                         break;
  742.                     }
  743.                 }
  744.                
  745.                 if (!bzero)
  746.                     WriteRectangle(objectInfo, rank, lengthA, array, arrayElemTypeNameInfo, lowerBoundA);
  747.                 serWriter.WriteItemEnd();
  748.             }
  749.            
  750.             serWriter.WriteObjectEnd(memberNameInfo, arrayNameInfo);
  751.            
  752.             PutNameInfo(arrayElemTypeNameInfo);
  753.             if (isAllocatedMemberNameInfo)
  754.                 PutNameInfo(memberNameInfo);
  755.            
  756.             SerTrace.Log(this, "WriteArray Exit ");
  757.         }
  758.        
  759.         // Writes out an array element
  760.         private void WriteArrayMember(WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, object data)
  761.         {
  762.             SerTrace.Log(this, "WriteArrayMember ", data, " baseArrayName ", arrayElemTypeNameInfo.NIname);
  763.            
  764.             arrayElemTypeNameInfo.NIisArrayItem = true;
  765.            
  766.             if (CheckForNull(objectInfo, arrayElemTypeNameInfo, arrayElemTypeNameInfo, data))
  767.                 return;
  768.            
  769.             NameInfo actualTypeInfo = null;
  770.            
  771.             Type dataType = null;
  772.            
  773.             bool isObjectOnMember = false;
  774.            
  775.             if (arrayElemTypeNameInfo.NItransmitTypeOnMember)
  776.                 isObjectOnMember = true;
  777.            
  778.             if (!isObjectOnMember && !arrayElemTypeNameInfo.IsSealed) {
  779.                 dataType = GetType(data);
  780.                 if (arrayElemTypeNameInfo.NItype != dataType)
  781.                     isObjectOnMember = true;
  782.             }
  783.            
  784.             if (isObjectOnMember) {
  785.                 // Object array, need type of member
  786.                 if (dataType == null)
  787.                     dataType = GetType(data);
  788.                 actualTypeInfo = TypeToNameInfo(dataType);
  789.                 actualTypeInfo.NItransmitTypeOnMember = true;
  790.                 actualTypeInfo.NIobjectId = arrayElemTypeNameInfo.NIobjectId;
  791.                 actualTypeInfo.NIassemId = arrayElemTypeNameInfo.NIassemId;
  792.                 actualTypeInfo.NIisArrayItem = true;
  793.             }
  794.             else {
  795.                 actualTypeInfo = arrayElemTypeNameInfo;
  796.                 actualTypeInfo.NIisArrayItem = true;
  797.             }
  798.            
  799.             if (!WriteKnownValueClass(arrayElemTypeNameInfo, actualTypeInfo, data)) {
  800.                 object obj = data;
  801.                 bool assignUniqueIdForValueTypes = false;
  802.                 if (arrayElemTypeNameInfo.NItype == Converter.typeofObject)
  803.                     assignUniqueIdForValueTypes = true;
  804.                
  805.                 long arrayId = Schedule(obj, assignUniqueIdForValueTypes, actualTypeInfo.NItype);
  806.                 arrayElemTypeNameInfo.NIobjectId = arrayId;
  807.                 actualTypeInfo.NIobjectId = arrayId;
  808.                 if (arrayId < 1) {
  809.                     WriteObjectInfo newObjectInfo = WriteObjectInfo.Serialize(obj, m_surrogates, m_context, serObjectInfoInit, m_formatterConverter, this);
  810.                     newObjectInfo.objectId = arrayId;
  811.                     if (arrayElemTypeNameInfo.NItype != Converter.typeofObject && Nullable.GetUnderlyingType(arrayElemTypeNameInfo.NItype) == null)
  812.                         newObjectInfo.assemId = actualTypeInfo.NIassemId;
  813.                     else
  814.                         newObjectInfo.assemId = GetAssemblyId(newObjectInfo);
  815.                     SerTrace.Log(this, "WriteArrayMembers nested");
  816.                     NameInfo typeNameInfo = TypeToNameInfo(newObjectInfo);
  817.                     typeNameInfo.NIobjectId = arrayId;
  818.                     newObjectInfo.objectId = arrayId;
  819.                     Write(newObjectInfo, actualTypeInfo, typeNameInfo);
  820.                    
  821.                     newObjectInfo.ObjectEnd();
  822.                 }
  823.                 else {
  824.                     serWriter.WriteItemObjectRef(arrayElemTypeNameInfo, (int)arrayId);
  825.                 }
  826.                
  827.             }
  828.             if (arrayElemTypeNameInfo.NItransmitTypeOnMember)
  829.                 PutNameInfo(actualTypeInfo);
  830.         }
  831.        
  832.        
  833.         // Iterates over a Rectangle array, for each element of the array invokes WriteArrayMember
  834.        
  835.         private void WriteRectangle(WriteObjectInfo objectInfo, int rank, int[] maxA, System.Array array, NameInfo arrayElemNameTypeInfo, int[] lowerBoundA)
  836.         {
  837.             IndexTraceMessage("WriteRectangle Entry " + rank, maxA);
  838.             int[] currentA = new int[rank];
  839.             int[] indexMap = null;
  840.             bool isLowerBound = false;
  841.             if (lowerBoundA != null) {
  842.                 for (int i = 0; i < rank; i++) {
  843.                     if (lowerBoundA[i] != 0)
  844.                         isLowerBound = true;
  845.                 }
  846.             }
  847.             if (isLowerBound)
  848.                 indexMap = new int[rank];
  849.            
  850.             bool isLoop = true;
  851.             while (isLoop) {
  852.                 isLoop = false;
  853.                 if (isLowerBound) {
  854.                     for (int i = 0; i < rank; i++) {
  855.                         indexMap[i] = currentA[i] + lowerBoundA[i];
  856.                     }
  857.                    
  858.                     WriteArrayMember(objectInfo, arrayElemNameTypeInfo, array.GetValue(indexMap));
  859.                 }
  860.                 else
  861.                     WriteArrayMember(objectInfo, arrayElemNameTypeInfo, array.GetValue(currentA));
  862.                 for (int irank = rank - 1; irank > -1; irank--) {
  863.                     // Find the current or lower dimension which can be incremented.
  864.                     if (currentA[irank] < maxA[irank] - 1) {
  865.                         // The current dimension is at maximum. Increase the next lower dimension by 1
  866.                         currentA[irank]++;
  867.                         if (irank < rank - 1) {
  868.                             // The current dimension and higher dimensions are zeroed.
  869.                             for (int i = irank + 1; i < rank; i++)
  870.                                 currentA[i] = 0;
  871.                         }
  872.                         isLoop = true;
  873.                         break;
  874.                     }
  875.                    
  876.                 }
  877.             }
  878.             SerTrace.Log(this, "WriteRectangle Exit ");
  879.         }
  880.        
  881.         // Traces a message with an array of int
  882.         [Conditional("SER_LOGGING")]
  883.         private void IndexTraceMessage(string message, int[] index)
  884.         {
  885.             StringBuilder sb = new StringBuilder(10);
  886.             sb.Append("[");
  887.             for (int i = 0; i < index.Length; i++) {
  888.                 sb.Append(index[i]);
  889.                 if (i != index.Length - 1)
  890.                     sb.Append(",");
  891.             }
  892.             sb.Append("]");
  893.             SerTrace.Log(this, message + " ", sb.ToString());
  894.         }
  895.        
  896.        
  897.         // This gives back the next object to be serialized. Objects
  898.         // are returned in a FIFO order based on how they were passed
  899.         // to Schedule. The id of the object is put into the objID parameter
  900.         // and the Object itself is returned from the function.
  901.         private object GetNext(out long objID)
  902.         {
  903.             SerTrace.Log(this, "GetNext Entry ");
  904.             bool isNew;
  905.            
  906.             //The Queue is empty here. We'll throw if we try to dequeue the empty queue.
  907.             if (m_objectQueue.Count == 0) {
  908.                 objID = 0;
  909.                 SerTrace.Log(this, "GetNext Exit null");
  910.                 return null;
  911.             }
  912.            
  913.             object obj = m_objectQueue.Dequeue();
  914.             object realObj = null;
  915.            
  916.             // A WriteObjectInfo is queued if this object was a member of another object
  917.             SerTrace.Log(this, "GetNext ", obj);
  918.             if (obj is WriteObjectInfo) {
  919.                 SerTrace.Log(this, "GetNext recognizes WriteObjectInfo");
  920.                 realObj = ((WriteObjectInfo)obj).obj;
  921.             }
  922.             else
  923.                 realObj = obj;
  924.             objID = m_idGenerator.HasId(realObj, out isNew);
  925.             if (isNew) {
  926.                 SerTrace.Log(this, "Object ", realObj, " has never been assigned an id.");
  927.                 throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_ObjNoID"), realObj));
  928.             }
  929.            
  930.             SerTrace.Log(this, "GetNext Exit " + objID, " ", realObj);
  931.             return obj;
  932.         }
  933.        
  934.         object previousObj = null;
  935.         long previousId = 0;
  936.         // If the type is a value type, we dont attempt to generate a unique id, unless its a boxed entity
  937.         // (in which case, there might be 2 references to the same boxed obj. in a graph.)
  938.         // "assignUniqueIdToValueType" is true, if the field type holding reference to "obj" is Object.
  939.         private long InternalGetId(object obj, bool assignUniqueIdToValueType, Type type, out bool isNew)
  940.         {
  941.             if (obj == previousObj) {
  942.                 // good for benchmarks
  943.                 isNew = false;
  944.                 return previousId;
  945.             }
  946.             m_idGenerator.m_currentCount = m_currentId;
  947.             if (type != null && type.IsValueType) {
  948.                 if (!assignUniqueIdToValueType) {
  949.                     isNew = false;
  950.                     return -1 * m_currentId++;
  951.                 }
  952.             }
  953.             m_currentId++;
  954.             long retId = m_idGenerator.GetId(obj, out isNew);
  955.            
  956.             previousObj = obj;
  957.             previousId = retId;
  958.             return retId;
  959.         }
  960.        
  961.        
  962.         // Schedules an object for later serialization if it hasn't already been scheduled.
  963.         // We get an ID for obj and put it on the queue for later serialization
  964.         // if this is a new object id.
  965.        
  966.         private long Schedule(object obj, bool assignUniqueIdToValueType, Type type)
  967.         {
  968.             return Schedule(obj, assignUniqueIdToValueType, type, null);
  969.         }
  970.        
  971.         private long Schedule(object obj, bool assignUniqueIdToValueType, Type type, WriteObjectInfo objectInfo)
  972.         {
  973.             SerTrace.Log(this, "Schedule Entry obj ", obj, " type ", type, " objectInfo ", objectInfo);
  974.            
  975.             bool isNew;
  976.             long id;
  977.            
  978.             if (obj == null) {
  979.                 SerTrace.Log(this, "Schedule Obj Null, id = 0 ");
  980.                 return 0;
  981.             }
  982.            
  983.             id = InternalGetId(obj, assignUniqueIdToValueType, type, out isNew);
  984.            
  985.             if (isNew && id > 0) {
  986.                 if (objectInfo == null)
  987.                     m_objectQueue.Enqueue(obj);
  988.                 else
  989.                     m_objectQueue.Enqueue(objectInfo);
  990.                
  991.             }
  992.            
  993.             SerTrace.Log(this, "Schedule Exit, id: ", id, " isNew: ", isNew);
  994.             return id;
  995.         }
  996.        
  997.        
  998.         // Determines if a type is a primitive type, if it is it is written
  999.        
  1000.         private bool WriteKnownValueClass(NameInfo memberNameInfo, NameInfo typeNameInfo, object data)
  1001.         {
  1002.             #if _DEBUG
  1003.             SerTrace.Log(this, "WriteKnownValueClass Entry ", typeNameInfo.NIname, " ", data, " ", memberNameInfo.NIname);
  1004.             memberNameInfo.Dump("WriteKnownValueClass memberNameInfo");
  1005.             typeNameInfo.Dump("WriteKnownValueClass typeNameInfo");
  1006.             #endif
  1007.            
  1008.             if (typeNameInfo.NItype == Converter.typeofString) {
  1009.                 WriteString(memberNameInfo, typeNameInfo, data);
  1010.             }
  1011.             else {
  1012.                 if (typeNameInfo.NIprimitiveTypeEnum == InternalPrimitiveTypeE.Invalid) {
  1013.                     SerTrace.Log(this, "WriteKnownValueClass Exit false");
  1014.                     return false;
  1015.                 }
  1016.                 else {
  1017.                     if (typeNameInfo.NIisArray)
  1018.                         serWriter.WriteItem(memberNameInfo, typeNameInfo, data);
  1019.                     // null if an array
  1020.                     else {
  1021.                         serWriter.WriteMember(memberNameInfo, typeNameInfo, data);
  1022.                     }
  1023.                 }
  1024.             }
  1025.            
  1026.             SerTrace.Log(this, "WriteKnownValueClass Exit true");
  1027.             return true;
  1028.         }
  1029.        
  1030.        
  1031.         // Writes an object reference to the stream.
  1032.         private void WriteObjectRef(NameInfo nameInfo, long objectId)
  1033.         {
  1034.             SerTrace.Log(this, "WriteObjectRef Entry ", nameInfo.NIname, " ", objectId);
  1035.             serWriter.WriteMemberObjectRef(nameInfo, (int)objectId);
  1036.            
  1037.             SerTrace.Log(this, "WriteObjectRef Exit ");
  1038.         }
  1039.        
  1040.        
  1041.        
  1042.         // Writes a string into the XML stream
  1043.         private void WriteString(NameInfo memberNameInfo, NameInfo typeNameInfo, object stringObject)
  1044.         {
  1045.             SerTrace.Log(this, "WriteString stringObject ", stringObject, " memberName ", memberNameInfo.NIname);
  1046.             bool isFirstTime = true;
  1047.            
  1048.             long stringId = -1;
  1049.            
  1050.             if (!CheckTypeFormat(formatterEnums.FEtypeFormat, FormatterTypeStyle.XsdString))
  1051.                 stringId = InternalGetId(stringObject, false, null, out isFirstTime);
  1052.            
  1053.             typeNameInfo.NIobjectId = stringId;
  1054.             SerTrace.Log(this, "WriteString stringId ", stringId, " isFirstTime ", isFirstTime);
  1055.            
  1056.             if ((isFirstTime) || (stringId < 0))
  1057.                 serWriter.WriteMemberString(memberNameInfo, typeNameInfo, (string)stringObject);
  1058.             else
  1059.                 WriteObjectRef(memberNameInfo, stringId);
  1060.         }
  1061.        
  1062.         // Writes a null member into the stream
  1063.         private bool CheckForNull(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo, object data)
  1064.         {
  1065.             #if _DEBUG
  1066.             SerTrace.Log(this, "CheckForNull Entry data ", Util.PString(data), ", memberType ", Util.PString(typeNameInfo.NItype));
  1067.             #endif
  1068.             bool isNull = false;
  1069.            
  1070.             if (data == null)
  1071.                 // || Convert.IsDBNull(data)
  1072.                 isNull = true;
  1073.            
  1074.             // Optimization, Null members are only written for Binary
  1075.             if ((isNull) && (((formatterEnums.FEserializerTypeEnum == InternalSerializerTypeE.Binary)) || memberNameInfo.NIisArrayItem || memberNameInfo.NItransmitTypeOnObject || memberNameInfo.NItransmitTypeOnMember || objectInfo.isSi || (CheckTypeFormat(formatterEnums.FEtypeFormat, FormatterTypeStyle.TypesAlways)))) {
  1076.                 SerTrace.Log(this, "CheckForNull Write");
  1077.                
  1078.                 if (typeNameInfo.NIisArrayItem) {
  1079.                     if (typeNameInfo.NIarrayEnum == InternalArrayTypeE.Single)
  1080.                         serWriter.WriteDelayedNullItem();
  1081.                     else
  1082.                         serWriter.WriteNullItem(memberNameInfo, typeNameInfo);
  1083.                 }
  1084.                 else
  1085.                    
  1086.                     serWriter.WriteNullMember(memberNameInfo, typeNameInfo);
  1087.             }
  1088.             SerTrace.Log(this, "CheckForNull Exit ", isNull);
  1089.             return isNull;
  1090.         }
  1091.        
  1092.        
  1093.         // Writes the SerializedStreamHeader
  1094.         private void WriteSerializedStreamHeader(long topId, long headerId)
  1095.         {
  1096.             serWriter.WriteSerializationHeader((int)topId, (int)headerId, 1, 0);
  1097.         }
  1098.        
  1099.        
  1100.         // Transforms a type to the serialized string form. URT Primitive types are converted to XMLData Types
  1101.         private NameInfo TypeToNameInfo(Type type, WriteObjectInfo objectInfo, InternalPrimitiveTypeE code, NameInfo nameInfo)
  1102.         {
  1103.             SerTrace.Log(this, "TypeToNameInfo Entry type ", type, ", objectInfo ", objectInfo, ", code ", ((Enum)code).ToString());
  1104.             if (nameInfo == null)
  1105.                 nameInfo = GetNameInfo();
  1106.             else
  1107.                 nameInfo.Init();
  1108.            
  1109.             if (code == InternalPrimitiveTypeE.Invalid) {
  1110.                 if (objectInfo != null) {
  1111.                     nameInfo.NIname = objectInfo.GetTypeFullName();
  1112.                     nameInfo.NIassemId = objectInfo.assemId;
  1113.                 }
  1114.             }
  1115.             nameInfo.NIprimitiveTypeEnum = code;
  1116.             nameInfo.NItype = type;
  1117.            
  1118.             SerTrace.Log(this, "TypeToNameInfo Exit ", type, " typeName " + nameInfo.NIname);
  1119.             return nameInfo;
  1120.         }
  1121.        
  1122.         private NameInfo TypeToNameInfo(Type type)
  1123.         {
  1124.             return TypeToNameInfo(type, null, ToCode(type), null);
  1125.         }
  1126.        
  1127.         private NameInfo TypeToNameInfo(WriteObjectInfo objectInfo)
  1128.         {
  1129.             return TypeToNameInfo(objectInfo.objectType, objectInfo, ToCode(objectInfo.objectType), null);
  1130.         }
  1131.        
  1132.         private NameInfo TypeToNameInfo(WriteObjectInfo objectInfo, NameInfo nameInfo)
  1133.         {
  1134.             return TypeToNameInfo(objectInfo.objectType, objectInfo, ToCode(objectInfo.objectType), nameInfo);
  1135.         }
  1136.        
  1137.         private void TypeToNameInfo(Type type, NameInfo nameInfo)
  1138.         {
  1139.             TypeToNameInfo(type, null, ToCode(type), nameInfo);
  1140.         }
  1141.        
  1142.         private NameInfo MemberToNameInfo(string name)
  1143.         {
  1144.             NameInfo memberNameInfo = GetNameInfo();
  1145.             memberNameInfo.NIname = name;
  1146.             return memberNameInfo;
  1147.         }
  1148.        
  1149.         Type previousType = null;
  1150.         InternalPrimitiveTypeE previousCode = InternalPrimitiveTypeE.Invalid;
  1151.         internal InternalPrimitiveTypeE ToCode(Type type)
  1152.         {
  1153.             if (previousType == type) {
  1154.                 return previousCode;
  1155.             }
  1156.             else {
  1157.                 InternalPrimitiveTypeE code = Converter.ToCode(type);
  1158.                 if (code != InternalPrimitiveTypeE.Invalid) {
  1159.                     previousType = type;
  1160.                     previousCode = code;
  1161.                 }
  1162.                 return code;
  1163.             }
  1164.         }
  1165.        
  1166.        
  1167.         private Hashtable assemblyToIdTable = null;
  1168.         private long GetAssemblyId(WriteObjectInfo objectInfo)
  1169.         {
  1170.             //use objectInfo to get assembly string with new criteria
  1171.             SerTrace.Log(this, "GetAssemblyId Entry ", objectInfo.objectType, " isSi ", objectInfo.isSi);
  1172.             if (assemblyToIdTable == null)
  1173.                 assemblyToIdTable = new Hashtable(5);
  1174.            
  1175.             long assemId = 0;
  1176.             bool isNew = false;
  1177.             string assemblyString = objectInfo.GetAssemblyString();
  1178.             string serializedAssemblyString = assemblyString;
  1179.             if (assemblyString.Length == 0) {
  1180.                 assemId = 0;
  1181.             }
  1182.             else if (assemblyString.Equals(Converter.urtAssemblyString)) {
  1183.                 // Urt type is an assemId of 0. No assemblyString needs
  1184.                 // to be sent
  1185.                 SerTrace.Log(this, "GetAssemblyId urt Assembly String ");
  1186.                 assemId = 0;
  1187.             }
  1188.             else {
  1189.                 // Assembly needs to be sent
  1190.                 // Need to prefix assembly string to separate the string names from the
  1191.                 // assemblyName string names. That is a string can have the same value
  1192.                 // as an assemblyNameString, but it is serialized differently
  1193.                
  1194.                 if (assemblyToIdTable.ContainsKey(assemblyString)) {
  1195.                     assemId = (long)assemblyToIdTable[assemblyString];
  1196.                     isNew = false;
  1197.                 }
  1198.                 else {
  1199.                     assemId = InternalGetId("___AssemblyString___" + assemblyString, false, null, out isNew);
  1200.                     assemblyToIdTable[assemblyString] = assemId;
  1201.                 }
  1202.                
  1203.                 serWriter.WriteAssembly(objectInfo.GetTypeFullName(), objectInfo.objectType, serializedAssemblyString, (int)assemId, isNew, false);
  1204.             }
  1205.             SerTrace.Log(this, "GetAssemblyId Exit id ", assemId, " isNew ", isNew, " assemblyString ", serializedAssemblyString);
  1206.             return assemId;
  1207.         }
  1208.        
  1209.         private Type GetType(object obj)
  1210.         {
  1211.             Type type = null;
  1212.             if (RemotingServices.IsTransparentProxy(obj))
  1213.                 type = Converter.typeofMarshalByRefObject;
  1214.             else
  1215.                 type = obj.GetType();
  1216.             return type;
  1217.         }
  1218.        
  1219.         private SerStack niPool = new SerStack("NameInfo Pool");
  1220.        
  1221.         private NameInfo GetNameInfo()
  1222.         {
  1223.             NameInfo nameInfo = null;
  1224.            
  1225.             if (!niPool.IsEmpty()) {
  1226.                 nameInfo = (NameInfo)niPool.Pop();
  1227.                 nameInfo.Init();
  1228.             }
  1229.             else
  1230.                 nameInfo = new NameInfo();
  1231.            
  1232.             return nameInfo;
  1233.         }
  1234.        
  1235.         private bool CheckTypeFormat(FormatterTypeStyle test, FormatterTypeStyle want)
  1236.         {
  1237.             return (test & want) == want;
  1238.         }
  1239.        
  1240.         private void PutNameInfo(NameInfo nameInfo)
  1241.         {
  1242.             niPool.Push(nameInfo);
  1243.         }
  1244.        
  1245.     }
  1246. }

Developer Fusion