(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / MessageFormatter.cs
blobda6937d37c4f918f238a0e4a98c5d451af8c3a36
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)
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.ArgCount == 0)
75 methodFlags |= MethodFlags.NoArguments;
76 else {
77 if (AllTypesArePrimitive (call.Args))
78 methodFlags |= MethodFlags.PrimitiveArguments;
79 else {
80 if (infoArraySize == 0)
81 methodFlags |= MethodFlags.ArgumentsInSimpleArray;
82 else {
83 methodFlags |= MethodFlags.ArgumentsInMultiArray;
84 infoArraySize++;
89 writer.Write ((byte) (methodFlags));
91 // FIXME: what are the following 3 bytes for?
92 writer.Write ((byte) 0);
93 writer.Write ((byte) 0);
94 writer.Write ((byte) 0);
96 // Method name
97 writer.Write ((byte) BinaryTypeCode.String);
98 writer.Write (call.MethodName);
100 // Class name
101 writer.Write ((byte) BinaryTypeCode.String);
102 writer.Write (call.TypeName);
104 // Arguments
106 if ((methodFlags & MethodFlags.PrimitiveArguments) > 0)
108 writer.Write ((uint)call.Args.Length);
109 for (int n=0; n<call.ArgCount; n++)
111 object arg = call.GetArg(n);
112 if (arg != null) {
113 writer.Write (BinaryCommon.GetTypeCode (arg.GetType()));
114 ObjectWriter.WritePrimitiveValue (writer, arg);
116 else
117 writer.Write ((byte)BinaryTypeCode.Null);
121 if ( infoArraySize > 0)
123 object[] ainfo = new object[infoArraySize];
124 int n=0;
125 if ((methodFlags & MethodFlags.ArgumentsInMultiArray) > 0) ainfo[n++] = call.Args;
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);
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)
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;
158 if (resp.Exception != null) {
159 returnTypeTag = ReturnTypeTag.Exception | ReturnTypeTag.Null;
160 info = new object[] {resp.Exception};
161 internalProperties = MethodReturnDictionary.InternalExceptionKeys;
163 else if (resp.ReturnValue == null) {
164 returnTypeTag = ReturnTypeTag.Null;
166 else if (IsMethodPrimitive(resp.ReturnValue.GetType())) {
167 returnTypeTag = ReturnTypeTag.PrimitiveType;
169 else {
170 returnTypeTag = ReturnTypeTag.ObjectType;
171 infoArrayLength++;
174 // Message flags
176 MethodFlags contextFlag;
177 MethodFlags formatFlag;
179 if ((resp.LogicalCallContext != null) && resp.LogicalCallContext.HasInfo && ((returnTypeTag & ReturnTypeTag.Exception) == 0))
181 contextFlag = MethodFlags.IncludesLogicalCallContext;
182 infoArrayLength++;
184 else
185 contextFlag = MethodFlags.ExcludeLogicalCallContext;
187 if (resp.Properties.Count > internalProperties.Length && ((returnTypeTag & ReturnTypeTag.Exception) == 0))
189 extraProperties = GetExtraProperties (resp.Properties, internalProperties);
190 infoArrayLength++;
193 if (resp.OutArgCount == 0)
194 formatFlag = MethodFlags.NoArguments;
195 else
197 if (AllTypesArePrimitive (resp.Args))
198 formatFlag = MethodFlags.PrimitiveArguments;
199 else
201 if (infoArrayLength == 0)
202 formatFlag = MethodFlags.ArgumentsInSimpleArray;
203 else {
204 formatFlag = MethodFlags.ArgumentsInMultiArray;
205 infoArrayLength++;
210 writer.Write ((byte) (contextFlag | formatFlag));
211 writer.Write ((byte) returnTypeTag);
213 // FIXME: what are the following 2 bytes for?
214 writer.Write ((byte) 0);
215 writer.Write ((byte) 0);
217 // Arguments
219 if (returnTypeTag == ReturnTypeTag.PrimitiveType)
221 writer.Write (BinaryCommon.GetTypeCode (resp.ReturnValue.GetType()));
222 ObjectWriter.WritePrimitiveValue (writer, resp.ReturnValue);
225 if (formatFlag == MethodFlags.PrimitiveArguments)
227 writer.Write ((uint)resp.ArgCount);
228 for (int n=0; n<resp.ArgCount; n++)
230 object val = resp.GetArg(n);
231 if (val != null) {
232 writer.Write (BinaryCommon.GetTypeCode (val.GetType()));
233 ObjectWriter.WritePrimitiveValue (writer, val);
235 else
236 writer.Write ((byte)BinaryTypeCode.Null);
240 if (infoArrayLength > 0)
242 object[] infoArray = new object[infoArrayLength];
243 int n = 0;
245 if (formatFlag == MethodFlags.ArgumentsInMultiArray)
246 infoArray[n++] = resp.Args;
248 if (returnTypeTag == ReturnTypeTag.ObjectType)
249 infoArray[n++] = resp.ReturnValue;
251 if (contextFlag == MethodFlags.IncludesLogicalCallContext)
252 infoArray[n++] = resp.LogicalCallContext;
254 if (extraProperties != null)
255 infoArray[n++] = extraProperties;
257 info = infoArray;
259 else if ((formatFlag & MethodFlags.ArgumentsInSimpleArray) > 0)
260 info = resp.Args;
262 if (info != null)
264 ObjectWriter objectWriter = new ObjectWriter (surrogateSelector, context, assemblyFormat);
265 objectWriter.WriteObjectGraph (writer, info, headers);
267 else
268 writer.Write ((byte) BinaryElement.End);
271 public static object ReadMethodCall (BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, BinaryFormatter formatter)
273 BinaryElement elem = (BinaryElement)reader.ReadByte(); // The element code
274 if (elem != BinaryElement.MethodCall) throw new SerializationException("Invalid format. Expected BinaryElement.MethodCall, found " + elem);
276 MethodFlags flags = (MethodFlags) reader.ReadByte();
278 // FIXME: find a meaning for those 3 bytes
279 reader.ReadByte();
280 reader.ReadByte();
281 reader.ReadByte();
283 if (((BinaryTypeCode)reader.ReadByte()) != BinaryTypeCode.String) throw new SerializationException ("Invalid format");
284 string methodName = reader.ReadString();
286 if (((BinaryTypeCode)reader.ReadByte()) != BinaryTypeCode.String) throw new SerializationException ("Invalid format");
287 string className = reader.ReadString();
289 bool hasContextInfo = (flags & MethodFlags.IncludesLogicalCallContext) > 0;
291 object[] arguments = null;
292 object methodSignature = null;
293 object callContext = null;
294 object[] extraProperties = null;
295 Header[] headers = null;
297 if ((flags & MethodFlags.PrimitiveArguments) > 0)
299 uint count = reader.ReadUInt32();
300 arguments = new object[count];
301 for (int n=0; n<count; n++)
303 Type type = BinaryCommon.GetTypeFromCode (reader.ReadByte());
304 arguments[n] = ObjectReader.ReadPrimitiveTypeValue (reader, type);
308 if ((flags & MethodFlags.NeedsInfoArrayMask) > 0)
310 ObjectReader objectReader = new ObjectReader (formatter);
312 object result;
313 objectReader.ReadObjectGraph (reader, hasHeaders, out result, out headers);
314 object[] msgInfo = (object[]) result;
316 if ((flags & MethodFlags.ArgumentsInSimpleArray) > 0) {
317 arguments = msgInfo;
319 else
321 int n = 0;
322 if ((flags & MethodFlags.ArgumentsInMultiArray) > 0) {
323 if (msgInfo.Length > 1) arguments = (object[]) msgInfo[n++];
324 else arguments = new object[0];
327 if ((flags & MethodFlags.IncludesSignature) > 0)
328 methodSignature = msgInfo[n++];
330 if ((flags & MethodFlags.IncludesLogicalCallContext) > 0)
331 callContext = msgInfo[n++];
333 if (n < msgInfo.Length)
334 extraProperties = (object[]) msgInfo[n];
337 else {
338 reader.ReadByte (); // Reads the stream ender
341 if (arguments == null) arguments = new object[0];
343 string uri = null;
344 if (headerHandler != null)
345 uri = headerHandler(headers) as string;
347 Header[] methodInfo = new Header[6];
348 methodInfo[0] = new Header("__MethodName", methodName);
349 methodInfo[1] = new Header("__MethodSignature", methodSignature);
350 methodInfo[2] = new Header("__TypeName", className);
351 methodInfo[3] = new Header("__Args", arguments);
352 methodInfo[4] = new Header("__CallContext", callContext);
353 methodInfo[5] = new Header("__Uri", uri);
355 MethodCall call = new MethodCall (methodInfo);
357 if (extraProperties != null) {
358 foreach (DictionaryEntry entry in extraProperties)
359 call.Properties [(string)entry.Key] = entry.Value;
362 return call;
365 public static object ReadMethodResponse (BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, IMethodCallMessage methodCallMessage, BinaryFormatter formatter)
367 BinaryElement elem = (BinaryElement)reader.ReadByte(); // The element code
368 if (elem != BinaryElement.MethodResponse) throw new SerializationException("Invalid format. Expected BinaryElement.MethodResponse, found " + elem);
370 MethodFlags flags = (MethodFlags) reader.ReadByte ();
371 ReturnTypeTag typeTag = (ReturnTypeTag) reader.ReadByte ();
372 bool hasContextInfo = (flags & MethodFlags.IncludesLogicalCallContext) > 0;
374 // FIXME: find a meaning for those 2 bytes
375 reader.ReadByte();
376 reader.ReadByte();
378 object returnValue = null;
379 object[] outArgs = null;
380 LogicalCallContext callContext = null;
381 Exception exception = null;
382 object[] extraProperties = null;
383 Header[] headers = null;
385 if ((typeTag & ReturnTypeTag.PrimitiveType) > 0)
387 Type type = BinaryCommon.GetTypeFromCode (reader.ReadByte());
388 returnValue = ObjectReader.ReadPrimitiveTypeValue (reader, type);
391 if ((flags & MethodFlags.PrimitiveArguments) > 0)
393 uint count = reader.ReadUInt32();
394 outArgs = new object[count];
395 for (int n=0; n<count; n++) {
396 Type type = BinaryCommon.GetTypeFromCode (reader.ReadByte());
397 outArgs[n] = ObjectReader.ReadPrimitiveTypeValue (reader, type);
401 if (hasContextInfo || (typeTag & ReturnTypeTag.ObjectType) > 0 ||
402 (typeTag & ReturnTypeTag.Exception) > 0 ||
403 (flags & MethodFlags.ArgumentsInSimpleArray) > 0 ||
404 (flags & MethodFlags.ArgumentsInMultiArray) > 0)
406 // There objects that need to be deserialized using an ObjectReader
408 ObjectReader objectReader = new ObjectReader (formatter);
409 object result;
410 objectReader.ReadObjectGraph (reader, hasHeaders, out result, out headers);
411 object[] msgInfo = (object[]) result;
413 if ((typeTag & ReturnTypeTag.Exception) > 0) {
414 exception = (Exception) msgInfo[0];
416 else if ((flags & MethodFlags.NoArguments) > 0 || (flags & MethodFlags.PrimitiveArguments) > 0) {
417 int n = 0;
418 if ((typeTag & ReturnTypeTag.ObjectType) > 0) returnValue = msgInfo [n++];
419 if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[n++];
420 if (n < msgInfo.Length) extraProperties = (object[]) msgInfo[n];
422 else if ((flags & MethodFlags.ArgumentsInSimpleArray) > 0) {
423 outArgs = msgInfo;
425 else {
426 int n = 0;
427 outArgs = (object[]) msgInfo[n++];
428 if ((typeTag & ReturnTypeTag.ObjectType) > 0) returnValue = msgInfo[n++];
429 if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[n++];
430 if (n < msgInfo.Length) extraProperties = (object[]) msgInfo[n];
433 else {
434 reader.ReadByte (); // Reads the stream ender
437 if (headerHandler != null)
438 headerHandler(headers);
440 if (exception != null)
441 return new ReturnMessage (exception, methodCallMessage);
442 else
444 int argCount = (outArgs!=null) ? outArgs.Length : 0;
445 ReturnMessage result = new ReturnMessage (returnValue, outArgs, argCount, callContext, methodCallMessage);
447 if (extraProperties != null) {
448 foreach (DictionaryEntry entry in extraProperties)
449 result.Properties [(string)entry.Key] = entry.Value;
452 return result;
456 private static bool AllTypesArePrimitive(object[] objects)
458 foreach (object ob in objects)
460 if (ob != null && !IsMethodPrimitive(ob.GetType()))
461 return false;
463 return true;
466 // When serializing methods, string are considered primitive types
467 public static bool IsMethodPrimitive (Type type)
469 return type.IsPrimitive || type == typeof(string) || type == typeof (DateTime) || type == typeof (Decimal);
472 static object[] GetExtraProperties (IDictionary properties, string[] internalKeys)
474 object[] extraProperties = new object [properties.Count - internalKeys.Length];
476 int n = 0;
477 IDictionaryEnumerator e = properties.GetEnumerator();
478 while (e.MoveNext())
479 if (!IsInternalKey ((string) e.Entry.Key, internalKeys)) extraProperties [n++] = e.Entry;
481 return extraProperties;
484 static bool IsInternalKey (string key, string[] internalKeys)
486 foreach (string ikey in internalKeys)
487 if (key == ikey) return true;
488 return false;