Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / mscorlib / system / runtime / serialization / objectclonehelper.cs
1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 /*============================================================
7  **
8  ** Class: ObjectCloneHelper
9  **
10  **
11  ** Purpose: Helper methods used by ObjectClone to process ISerializable objects etc
12  **
13  **
14  ===========================================================*/
15 #if FEATURE_REMOTING
16
17 namespace System.Runtime.Serialization
18 {
19     using System.Runtime.Remoting;
20     using System.Runtime.Remoting.Proxies;
21     using System.Runtime.Remoting.Messaging;
22     using System.Runtime.Serialization;
23     using System;
24     using System.Collections;
25     using System.Reflection;
26     using System.Diagnostics;
27     using System.Globalization;
28
29     internal static class ObjectCloneHelper
30     {
31         static readonly IFormatterConverter s_converter = new FormatterConverter();
32         // Currently object cloner is used only to clone stuff across domains. If its used to clone objects within a domain
33         // the Clone context will need to be created too..
34         static readonly StreamingContext    s_cloneContext = new StreamingContext(StreamingContextStates.CrossAppDomain);
35         static readonly ISerializationSurrogate  s_RemotingSurrogate = new RemotingSurrogate();
36         static readonly ISerializationSurrogate  s_ObjRefRemotingSurrogate = new ObjRefSurrogate();
37         
38         [System.Security.SecurityCritical]  // auto-generated
39         internal static object GetObjectData(object serObj, out string typeName, out string assemName, out string[] fieldNames, out object[] fieldValues)
40         {
41             Type objectType = null;
42             object retObj = null;
43             
44             if (RemotingServices.IsTransparentProxy(serObj))
45                 objectType = typeof(MarshalByRefObject);
46             else
47                 objectType = serObj.GetType();
48                 
49             SerializationInfo  si  = new SerializationInfo(objectType, s_converter);
50             if (serObj is ObjRef)
51             {
52                 s_ObjRefRemotingSurrogate.GetObjectData(serObj, si, s_cloneContext);
53             }
54             else if (RemotingServices.IsTransparentProxy(serObj) || serObj is MarshalByRefObject)
55             {
56 #if !MONO
57                 // We can only try to smuggle objref's for actual CLR objects
58                 //   or for RemotingProxy's.
59                 if (!RemotingServices.IsTransparentProxy(serObj) ||
60                     RemotingServices.GetRealProxy(serObj) is RemotingProxy)
61                 {                
62                     ObjRef objRef = RemotingServices.MarshalInternal((MarshalByRefObject)serObj, null, null);
63                     if (objRef.CanSmuggle())
64                     {
65                         if (RemotingServices.IsTransparentProxy(serObj))
66                         {
67                             RealProxy rp = RemotingServices.GetRealProxy(serObj);
68                             objRef.SetServerIdentity(rp._srvIdentity);
69                             objRef.SetDomainID(rp._domainID);
70                         }
71                         else
72                         {
73                             ServerIdentity srvId = (ServerIdentity)MarshalByRefObject.GetIdentity((MarshalByRefObject)serObj);
74                             srvId.SetHandle();
75                             objRef.SetServerIdentity(srvId.GetHandle());
76                             objRef.SetDomainID(AppDomain.CurrentDomain.GetId());
77                         }
78                         objRef.SetMarshaledObject();
79                         retObj = objRef;
80                     }
81                 }
82 #endif
83                 if (retObj == null)
84                 {
85                     // Deal with the non-smugglable remoting objects
86                     s_RemotingSurrogate.GetObjectData(serObj, si, s_cloneContext);
87                 }
88                 
89             }
90             else if (serObj is ISerializable)
91             {
92                 ((ISerializable)serObj).GetObjectData(si, s_cloneContext);
93             }
94             else
95             {
96                 // Getting here means a bug in cloner
97                 throw new ArgumentException(Environment.GetResourceString("Arg_SerializationException"));
98             }
99
100             if (retObj == null)
101             {
102                 typeName = si.FullTypeName;
103                 assemName = si.AssemblyName;
104                 fieldNames = si.MemberNames;
105                 fieldValues = si.MemberValues;
106             }
107             else
108             {
109                 typeName = null;
110                 assemName = null;
111                 fieldNames = null;
112                 fieldValues = null;
113             }
114
115             return retObj;
116         }
117
118         [System.Security.SecurityCritical]  // auto-generated
119         internal static SerializationInfo PrepareConstructorArgs(object serObj, string[] fieldNames, object[] fieldValues, out StreamingContext context)
120         {
121             SerializationInfo si = null;
122             if (serObj is ISerializable)
123             {
124                 si = new SerializationInfo(serObj.GetType(), s_converter);
125
126                 for (int i =0; i < fieldNames.Length; i++)
127                 {
128                     if (fieldNames[i] != null)
129                         si.AddValue(fieldNames[i], fieldValues[i]);
130                 }
131             }
132             else
133             {
134                 // We have a case where the from object was ISerializable and to object is not
135                 // @
136
137                 Hashtable fields = new Hashtable();
138                 int incomingFieldIndex = 0;
139                 int numIncomingFields = 0;
140                 for (; incomingFieldIndex < fieldNames.Length; incomingFieldIndex++)
141                 {
142                     if (fieldNames[incomingFieldIndex] != null)
143                     {
144                         fields[fieldNames[incomingFieldIndex]] = fieldValues[incomingFieldIndex];
145                         numIncomingFields++;
146                     }
147                 }
148                 
149                 MemberInfo[] mi = FormatterServices.GetSerializableMembers(serObj.GetType());
150
151                 for (int index = 0; index < mi.Length; index++)
152                 {
153                     string fieldName = mi[index].Name;
154                     if (!fields.Contains(fieldName))
155                     {
156                         // If we are missing a field value then it's not necessarily
157                         // the end of the world: check whether the field is marked
158                         // [OptionalField].
159                         Object [] attrs = mi[index].GetCustomAttributes(typeof(OptionalFieldAttribute), false);
160                         if (attrs == null || attrs.Length == 0)
161                             throw new SerializationException(Environment.GetResourceString("Serialization_MissingMember",
162                                                                            mi[index],
163                                                                            serObj.GetType(),
164                                                                            typeof(OptionalFieldAttribute).FullName));
165                         continue;
166                     }
167
168                     object value = fields[fieldName];
169
170                     FormatterServices.SerializationSetValue(mi[index], serObj, value);
171                 }
172             }
173
174             context = s_cloneContext;
175             return si;
176         }
177     }
178
179 }
180 #endif // FEATURE_REMOTING