disable broken tests on net_4_0
[mcs.git] / class / corlib / System.Runtime.Serialization.Formatters.Binary / MessageFormatter.cs
blob8d9a0d46d6a6e51a2223ac887ae2c92258a501d5
1 //
2 // System.Runtime.Remoting.MessageFormatter.cs
3 //
4 // Author: Lluis Sanchez Gual (lluis@ideary.com)
5 //
6 // (C) 2003, Lluis Sanchez Gual
7 //
9 //
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System;
33 using System.IO;
34 using System.Reflection;
35 using System.Collections;
36 using System.Runtime.Remoting;
37 using System.Runtime.Serialization;
38 using System.Runtime.Remoting.Messaging;
40 namespace System.Runtime.Serialization.Formatters.Binary
42 internal class MessageFormatter
44 public static void WriteMethodCall (BinaryWriter writer, object obj, Header[] headers, ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat, FormatterTypeStyle typeFormat)
46 IMethodCallMessage call = (IMethodCallMessage)obj;
47 writer.Write ((byte) BinaryElement.MethodCall);
49 MethodFlags methodFlags;
50 int infoArraySize = 0;
51 object info = null;
52 object[] extraProperties = null;
54 if (call.LogicalCallContext != null && call.LogicalCallContext.HasInfo)
56 methodFlags = MethodFlags.IncludesLogicalCallContext;
57 infoArraySize++;
59 else
60 methodFlags = MethodFlags.ExcludeLogicalCallContext;
62 if (RemotingServices.IsMethodOverloaded (call))
64 infoArraySize++;
65 methodFlags |= MethodFlags.IncludesSignature;
68 if (call.Properties.Count > MethodCallDictionary.InternalKeys.Length)
70 extraProperties = GetExtraProperties (call.Properties, MethodCallDictionary.InternalKeys);
71 infoArraySize++;
74 if (call.MethodBase.IsGenericMethod) {
75 infoArraySize++;
76 methodFlags |= MethodFlags.GenericArguments;
78 if (call.ArgCount == 0)
79 methodFlags |= MethodFlags.NoArguments;
80 else {
81 if (AllTypesArePrimitive (call.Args))
82 methodFlags |= MethodFlags.PrimitiveArguments;
83 else {
84 if (infoArraySize == 0)
85 methodFlags |= MethodFlags.ArgumentsInSimpleArray;
86 else {
87 methodFlags |= MethodFlags.ArgumentsInMultiArray;
88 infoArraySize++;
93 writer.Write ((int) methodFlags);
95 // Method name
96 writer.Write ((byte) BinaryTypeCode.String);
97 writer.Write (call.MethodName);
99 // Class name
100 writer.Write ((byte) BinaryTypeCode.String);
101 writer.Write (call.TypeName);
103 // Arguments
105 if ((methodFlags & MethodFlags.PrimitiveArguments) > 0)
107 writer.Write ((uint)call.Args.Length);
108 for (int n=0; n<call.ArgCount; n++)
110 object arg = call.GetArg(n);
111 if (arg != null) {
112 writer.Write (BinaryCommon.GetTypeCode (arg.GetType()));
113 ObjectWriter.WritePrimitiveValue (writer, arg);
115 else
116 writer.Write ((byte)BinaryTypeCode.Null);
120 if ( infoArraySize > 0)
122 object[] ainfo = new object[infoArraySize];
123 int n=0;
124 if ((methodFlags & MethodFlags.ArgumentsInMultiArray) > 0) ainfo[n++] = call.Args;
125 if ((methodFlags & MethodFlags.GenericArguments) > 0) ainfo[n++] = call.MethodBase.GetGenericArguments ();
126 if ((methodFlags & MethodFlags.IncludesSignature) > 0) ainfo[n++] = call.MethodSignature;
127 if ((methodFlags & MethodFlags.IncludesLogicalCallContext) > 0) ainfo[n++] = call.LogicalCallContext;
128 if (extraProperties != null) ainfo[n++] = extraProperties;
129 info = ainfo;
131 else if ((methodFlags & MethodFlags.ArgumentsInSimpleArray) > 0)
132 info = call.Args;
134 if (info != null)
136 ObjectWriter objectWriter = new ObjectWriter (surrogateSelector, context, assemblyFormat, typeFormat);
137 objectWriter.WriteObjectGraph (writer, info, headers);
139 else
140 writer.Write ((byte) BinaryElement.End);
143 public static void WriteMethodResponse (BinaryWriter writer, object obj, Header[] headers, ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat, FormatterTypeStyle typeFormat)
145 IMethodReturnMessage resp = (IMethodReturnMessage)obj;
146 writer.Write ((byte) BinaryElement.MethodResponse);
148 string[] internalProperties = MethodReturnDictionary.InternalReturnKeys;
150 int infoArrayLength = 0;
151 object info = null;
152 object[] extraProperties = null;
154 // Type of return value
156 ReturnTypeTag returnTypeTag;
157 MethodFlags contextFlag = MethodFlags.ExcludeLogicalCallContext;
159 if (resp.Exception != null) {
160 returnTypeTag = ReturnTypeTag.Exception | ReturnTypeTag.Null;
161 internalProperties = MethodReturnDictionary.InternalExceptionKeys;
162 infoArrayLength = 1;
164 else if (resp.ReturnValue == null) {
165 returnTypeTag = ReturnTypeTag.Null;
167 else if (IsMethodPrimitive(resp.ReturnValue.GetType())) {
168 returnTypeTag = ReturnTypeTag.PrimitiveType;
170 else {
171 returnTypeTag = ReturnTypeTag.ObjectType;
172 infoArrayLength++;
175 // Message flags
177 MethodFlags formatFlag;
179 if ((resp.LogicalCallContext != null) && resp.LogicalCallContext.HasInfo)
181 contextFlag = MethodFlags.IncludesLogicalCallContext;
182 infoArrayLength++;
185 if (resp.Properties.Count > internalProperties.Length && ((returnTypeTag & ReturnTypeTag.Exception) == 0))
187 extraProperties = GetExtraProperties (resp.Properties, internalProperties);
188 infoArrayLength++;
191 if (resp.OutArgCount == 0)
192 formatFlag = MethodFlags.NoArguments;
193 else
195 if (AllTypesArePrimitive (resp.Args))
196 formatFlag = MethodFlags.PrimitiveArguments;
197 else
199 if (infoArrayLength == 0)
200 formatFlag = MethodFlags.ArgumentsInSimpleArray;
201 else {
202 formatFlag = MethodFlags.ArgumentsInMultiArray;
203 infoArrayLength++;
208 writer.Write ((byte) (contextFlag | formatFlag));
209 writer.Write ((byte) returnTypeTag);
211 // FIXME: what are the following 2 bytes for?
212 writer.Write ((byte) 0);
213 writer.Write ((byte) 0);
215 // Arguments
217 if (returnTypeTag == ReturnTypeTag.PrimitiveType)
219 writer.Write (BinaryCommon.GetTypeCode (resp.ReturnValue.GetType()));
220 ObjectWriter.WritePrimitiveValue (writer, resp.ReturnValue);
223 if (formatFlag == MethodFlags.PrimitiveArguments)
225 writer.Write ((uint)resp.ArgCount);
226 for (int n=0; n<resp.ArgCount; n++)
228 object val = resp.GetArg(n);
229 if (val != null) {
230 writer.Write (BinaryCommon.GetTypeCode (val.GetType()));
231 ObjectWriter.WritePrimitiveValue (writer, val);
233 else
234 writer.Write ((byte)BinaryTypeCode.Null);
238 if (infoArrayLength > 0)
240 object[] infoArray = new object[infoArrayLength];
241 int n = 0;
243 if ((returnTypeTag & ReturnTypeTag.Exception) != 0)
244 infoArray[n++] = resp.Exception;
246 if (formatFlag == MethodFlags.ArgumentsInMultiArray)
247 infoArray[n++] = resp.Args;
249 if (returnTypeTag == ReturnTypeTag.ObjectType)
250 infoArray[n++] = resp.ReturnValue;
252 if (contextFlag == MethodFlags.IncludesLogicalCallContext)
253 infoArray[n++] = resp.LogicalCallContext;
255 if (extraProperties != null)
256 infoArray[n++] = extraProperties;
258 info = infoArray;
260 else if ((formatFlag & MethodFlags.ArgumentsInSimpleArray) > 0)
261 info = resp.Args;
263 if (info != null)
265 ObjectWriter objectWriter = new ObjectWriter (surrogateSelector, context, assemblyFormat, typeFormat);
266 objectWriter.WriteObjectGraph (writer, info, headers);
268 else
269 writer.Write ((byte) BinaryElement.End);
272 public static object ReadMethodCall (BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, BinaryFormatter formatter)
274 BinaryElement elem = (BinaryElement)reader.ReadByte(); // The element code
275 return ReadMethodCall (elem, reader, hasHeaders, headerHandler, formatter);
278 public static object ReadMethodCall (BinaryElement elem, BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, BinaryFormatter formatter)
280 if (elem != BinaryElement.MethodCall) throw new SerializationException("Invalid format. Expected BinaryElement.MethodCall, found " + elem);
282 MethodFlags flags = (MethodFlags) reader.ReadInt32();
284 if (((BinaryTypeCode)reader.ReadByte()) != BinaryTypeCode.String) throw new SerializationException ("Invalid format");
285 string methodName = reader.ReadString();
287 if (((BinaryTypeCode)reader.ReadByte()) != BinaryTypeCode.String) throw new SerializationException ("Invalid format");
288 string className = reader.ReadString();
290 //bool hasContextInfo = (flags & MethodFlags.IncludesLogicalCallContext) > 0;
292 object[] arguments = null;
293 object methodSignature = null;
294 object callContext = null;
295 object[] extraProperties = null;
296 Header[] headers = null;
297 Type[] genericArguments = null;
299 if ((flags & MethodFlags.PrimitiveArguments) > 0)
301 uint count = reader.ReadUInt32();
302 arguments = new object[count];
303 for (int n=0; n<count; n++)
305 Type type = BinaryCommon.GetTypeFromCode (reader.ReadByte());
306 arguments[n] = ObjectReader.ReadPrimitiveTypeValue (reader, type);
310 if ((flags & MethodFlags.NeedsInfoArrayMask) > 0)
312 ObjectReader objectReader = new ObjectReader (formatter);
314 object result;
315 objectReader.ReadObjectGraph (reader, hasHeaders, out result, out headers);
316 object[] msgInfo = (object[]) result;
318 if ((flags & MethodFlags.ArgumentsInSimpleArray) > 0) {
319 arguments = msgInfo;
321 else
323 int n = 0;
324 if ((flags & MethodFlags.ArgumentsInMultiArray) > 0) {
325 if (msgInfo.Length > 1) arguments = (object[]) msgInfo[n++];
326 else arguments = new object[0];
329 if ((flags & MethodFlags.GenericArguments) > 0)
330 genericArguments = (Type[]) msgInfo[n++];
332 if ((flags & MethodFlags.IncludesSignature) > 0)
333 methodSignature = msgInfo[n++];
335 if ((flags & MethodFlags.IncludesLogicalCallContext) > 0)
336 callContext = msgInfo[n++];
338 if (n < msgInfo.Length)
339 extraProperties = (object[]) msgInfo[n];
342 else {
343 reader.ReadByte (); // Reads the stream ender
346 if (arguments == null) arguments = new object[0];
348 string uri = null;
349 if (headerHandler != null)
350 uri = headerHandler(headers) as string;
352 Header[] methodInfo = new Header[7];
353 methodInfo[0] = new Header("__MethodName", methodName);
354 methodInfo[1] = new Header("__MethodSignature", methodSignature);
355 methodInfo[2] = new Header("__TypeName", className);
356 methodInfo[3] = new Header("__Args", arguments);
357 methodInfo[4] = new Header("__CallContext", callContext);
358 methodInfo[5] = new Header("__Uri", uri);
359 methodInfo[6] = new Header("__GenericArguments", genericArguments);
361 MethodCall call = new MethodCall (methodInfo);
363 if (extraProperties != null) {
364 foreach (DictionaryEntry entry in extraProperties)
365 call.Properties [(string)entry.Key] = entry.Value;
368 return call;
371 public static object ReadMethodResponse (BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, IMethodCallMessage methodCallMessage, BinaryFormatter formatter)
373 BinaryElement elem = (BinaryElement) reader.ReadByte ();
374 return ReadMethodResponse (elem, reader, hasHeaders, headerHandler, methodCallMessage, formatter);
377 public static object ReadMethodResponse (BinaryElement elem, BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, IMethodCallMessage methodCallMessage, BinaryFormatter formatter)
379 if (elem != BinaryElement.MethodResponse) throw new SerializationException("Invalid format. Expected BinaryElement.MethodResponse, found " + elem);
381 MethodFlags flags = (MethodFlags) reader.ReadByte ();
382 ReturnTypeTag typeTag = (ReturnTypeTag) reader.ReadByte ();
383 bool hasContextInfo = (flags & MethodFlags.IncludesLogicalCallContext) > 0;
385 // FIXME: find a meaning for those 2 bytes
386 reader.ReadByte();
387 reader.ReadByte();
389 object returnValue = null;
390 object[] outArgs = null;
391 LogicalCallContext callContext = null;
392 Exception exception = null;
393 object[] extraProperties = null;
394 Header[] headers = null;
396 if ((typeTag & ReturnTypeTag.PrimitiveType) > 0)
398 Type type = BinaryCommon.GetTypeFromCode (reader.ReadByte());
399 returnValue = ObjectReader.ReadPrimitiveTypeValue (reader, type);
402 if ((flags & MethodFlags.PrimitiveArguments) > 0)
404 uint count = reader.ReadUInt32();
405 outArgs = new object[count];
406 for (int n=0; n<count; n++) {
407 Type type = BinaryCommon.GetTypeFromCode (reader.ReadByte());
408 outArgs[n] = ObjectReader.ReadPrimitiveTypeValue (reader, type);
412 if (hasContextInfo || (typeTag & ReturnTypeTag.ObjectType) > 0 ||
413 (typeTag & ReturnTypeTag.Exception) > 0 ||
414 (flags & MethodFlags.ArgumentsInSimpleArray) > 0 ||
415 (flags & MethodFlags.ArgumentsInMultiArray) > 0)
417 // There objects that need to be deserialized using an ObjectReader
419 ObjectReader objectReader = new ObjectReader (formatter);
420 object result;
421 objectReader.ReadObjectGraph (reader, hasHeaders, out result, out headers);
422 object[] msgInfo = (object[]) result;
424 if ((typeTag & ReturnTypeTag.Exception) > 0) {
425 exception = (Exception) msgInfo[0];
426 if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[1];
428 else if ((flags & MethodFlags.NoArguments) > 0 || (flags & MethodFlags.PrimitiveArguments) > 0) {
429 int n = 0;
430 if ((typeTag & ReturnTypeTag.ObjectType) > 0) returnValue = msgInfo [n++];
431 if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[n++];
432 if (n < msgInfo.Length) extraProperties = (object[]) msgInfo[n];
434 else if ((flags & MethodFlags.ArgumentsInSimpleArray) > 0) {
435 outArgs = msgInfo;
437 else {
438 int n = 0;
439 outArgs = (object[]) msgInfo[n++];
440 if ((typeTag & ReturnTypeTag.ObjectType) > 0) returnValue = msgInfo[n++];
441 if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[n++];
442 if (n < msgInfo.Length) extraProperties = (object[]) msgInfo[n];
445 else {
446 reader.ReadByte (); // Reads the stream ender
449 if (headerHandler != null)
450 headerHandler(headers);
452 if (exception != null)
453 return new ReturnMessage (exception, methodCallMessage);
454 else
456 int argCount = (outArgs!=null) ? outArgs.Length : 0;
457 ReturnMessage result = new ReturnMessage (returnValue, outArgs, argCount, callContext, methodCallMessage);
459 if (extraProperties != null) {
460 foreach (DictionaryEntry entry in extraProperties)
461 result.Properties [(string)entry.Key] = entry.Value;
464 return result;
468 private static bool AllTypesArePrimitive(object[] objects)
470 foreach (object ob in objects)
472 if (ob != null && !IsMethodPrimitive(ob.GetType()))
473 return false;
475 return true;
478 // When serializing methods, string are considered primitive types
479 public static bool IsMethodPrimitive (Type type)
481 return type.IsPrimitive || type == typeof(string) || type == typeof (DateTime) || type == typeof (Decimal);
484 static object[] GetExtraProperties (IDictionary properties, string[] internalKeys)
486 object[] extraProperties = new object [properties.Count - internalKeys.Length];
488 int n = 0;
489 IDictionaryEnumerator e = properties.GetEnumerator();
490 while (e.MoveNext())
491 if (!IsInternalKey ((string) e.Entry.Key, internalKeys)) extraProperties [n++] = e.Entry;
493 return extraProperties;
496 static bool IsInternalKey (string key, string[] internalKeys)
498 foreach (string ikey in internalKeys)
499 if (key == ikey) return true;
500 return false;