2004-12-08 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / MessageFormatter.cs
index 040f1a1d9ca8b4511a6757b012fa6798c8bafd26..8347f04482343753eb869167295202084d2caa72 100644 (file)
@@ -5,22 +5,43 @@
 //
 // (C) 2003, Lluis Sanchez Gual
 //\r
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 \r
 using System;\r
 using System.IO;\r
-using System.Runtime.Serialization;\r
 using System.Reflection;\r
+using System.Collections;\r
 using System.Runtime.Remoting;\r
+using System.Runtime.Serialization;\r
 using System.Runtime.Remoting.Messaging;\r
 \r
 namespace System.Runtime.Serialization.Formatters.Binary\r
 {\r
-       /// <summary>\r
-       /// Summary description for MessageFormatter.\r
-       /// </summary>\r
        internal class MessageFormatter\r
        {\r
-               public static void WriteMethodCall (BinaryWriter writer, object obj, Header[] headers, ISurrogateSelector surrogateSelector, StreamingContext context)\r
+               public static void WriteMethodCall (BinaryWriter writer, object obj, Header[] headers, ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat)\r
                {\r
                        IMethodCallMessage call = (IMethodCallMessage)obj;\r
                        writer.Write ((byte) BinaryElement.MethodCall);\r
@@ -28,6 +49,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        MethodFlags methodFlags;\r
                        int infoArraySize = 0;\r
                        object info = null;\r
+                       object[] extraProperties = null;\r
 \r
                        if (call.LogicalCallContext != null && call.LogicalCallContext.HasInfo)\r
                        {\r
@@ -43,7 +65,13 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                methodFlags |= MethodFlags.IncludesSignature;\r
                        }\r
 \r
-                       if (call.InArgCount == 0)\r
+                       if (call.Properties.Count > MethodCallDictionary.InternalKeys.Length)\r
+                       {\r
+                               extraProperties = GetExtraProperties (call.Properties, MethodCallDictionary.InternalKeys);\r
+                               infoArraySize++;\r
+                       }\r
+\r
+                       if (call.ArgCount == 0)\r
                                methodFlags |= MethodFlags.NoArguments;\r
                        else {\r
                                if (AllTypesArePrimitive (call.Args)) \r
@@ -78,7 +106,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        if ((methodFlags & MethodFlags.PrimitiveArguments) > 0)\r
                        {\r
                                writer.Write ((uint)call.Args.Length);\r
-                               for (int n=0; n<call.InArgCount; n++)\r
+                               for (int n=0; n<call.ArgCount; n++)\r
                                {\r
                                        object arg = call.GetArg(n);\r
                                        if (arg != null) {\r
@@ -97,6 +125,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                if ((methodFlags & MethodFlags.ArgumentsInMultiArray) > 0) ainfo[n++] = call.Args;\r
                                if ((methodFlags & MethodFlags.IncludesSignature) > 0) ainfo[n++] = call.MethodSignature;\r
                                if ((methodFlags & MethodFlags.IncludesLogicalCallContext) > 0) ainfo[n++] = call.LogicalCallContext;\r
+                               if (extraProperties != null) ainfo[n++] = extraProperties;\r
                                info = ainfo;\r
                        }\r
                        else if ((methodFlags & MethodFlags.ArgumentsInSimpleArray) > 0)\r
@@ -104,20 +133,23 @@ namespace System.Runtime.Serialization.Formatters.Binary
 \r
                        if (info != null)\r
                        {\r
-                               ObjectWriter objectWriter = new ObjectWriter(surrogateSelector, context);\r
+                               ObjectWriter objectWriter = new ObjectWriter (surrogateSelector, context, assemblyFormat);\r
                                objectWriter.WriteObjectGraph (writer, info, headers);\r
                        }\r
                        else\r
                                writer.Write ((byte) BinaryElement.End);\r
                }\r
 \r
-               public static void WriteMethodResponse (BinaryWriter writer, object obj, Header[] headers, ISurrogateSelector surrogateSelector, StreamingContext context)\r
+               public static void WriteMethodResponse (BinaryWriter writer, object obj, Header[] headers, ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat)\r
                {\r
                        IMethodReturnMessage resp = (IMethodReturnMessage)obj;\r
                        writer.Write ((byte) BinaryElement.MethodResponse);\r
 \r
+                       string[] internalProperties = MethodReturnDictionary.InternalReturnKeys;\r
+\r
                        int infoArrayLength = 0;\r
                        object info = null;\r
+                       object[] extraProperties = null;\r
 \r
                        // Type of return value\r
 \r
@@ -126,6 +158,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        if (resp.Exception != null) {\r
                                returnTypeTag = ReturnTypeTag.Exception | ReturnTypeTag.Null;\r
                                info = new object[] {resp.Exception};\r
+                               internalProperties = MethodReturnDictionary.InternalExceptionKeys;\r
                        }\r
                        else if (resp.ReturnValue == null) {\r
                                returnTypeTag = ReturnTypeTag.Null;\r
@@ -151,11 +184,17 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        else\r
                                contextFlag = MethodFlags.ExcludeLogicalCallContext;\r
 \r
+                       if (resp.Properties.Count > internalProperties.Length && ((returnTypeTag & ReturnTypeTag.Exception) == 0))\r
+                       {\r
+                               extraProperties = GetExtraProperties (resp.Properties, internalProperties);\r
+                               infoArrayLength++;\r
+                       }\r
+\r
                        if (resp.OutArgCount == 0)\r
                                formatFlag = MethodFlags.NoArguments;\r
                        else \r
                        {\r
-                               if (AllTypesArePrimitive (resp.OutArgs)) \r
+                               if (AllTypesArePrimitive (resp.Args)) \r
                                        formatFlag = MethodFlags.PrimitiveArguments;\r
                                else \r
                                {\r
@@ -185,10 +224,10 @@ namespace System.Runtime.Serialization.Formatters.Binary
 \r
                        if (formatFlag == MethodFlags.PrimitiveArguments)\r
                        {\r
-                               writer.Write ((uint)resp.OutArgCount);\r
-                               for (int n=0; n<resp.OutArgCount; n++)\r
+                               writer.Write ((uint)resp.ArgCount);\r
+                               for (int n=0; n<resp.ArgCount; n++)\r
                                {\r
-                                       object val = resp.GetOutArg(n);\r
+                                       object val = resp.GetArg(n);\r
                                        if (val != null) {\r
                                                writer.Write (BinaryCommon.GetTypeCode (val.GetType()));\r
                                                ObjectWriter.WritePrimitiveValue (writer, val);\r
@@ -204,7 +243,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                int n = 0;\r
 \r
                                if (formatFlag == MethodFlags.ArgumentsInMultiArray)\r
-                                       infoArray[n++] = resp.OutArgs;\r
+                                       infoArray[n++] = resp.Args;\r
 \r
                                if (returnTypeTag == ReturnTypeTag.ObjectType)\r
                                        infoArray[n++] = resp.ReturnValue;\r
@@ -212,21 +251,24 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                if (contextFlag == MethodFlags.IncludesLogicalCallContext)\r
                                        infoArray[n++] = resp.LogicalCallContext;\r
 \r
+                               if (extraProperties != null)\r
+                                       infoArray[n++] = extraProperties;\r
+\r
                                info = infoArray;\r
                        }\r
                        else if ((formatFlag & MethodFlags.ArgumentsInSimpleArray) > 0)\r
-                               info = resp.OutArgs;\r
+                               info = resp.Args;\r
 \r
                        if (info != null)\r
                        {\r
-                               ObjectWriter objectWriter = new ObjectWriter(surrogateSelector, context);\r
+                               ObjectWriter objectWriter = new ObjectWriter (surrogateSelector, context, assemblyFormat);\r
                                objectWriter.WriteObjectGraph (writer, info, headers);\r
                        }\r
                        else\r
                                writer.Write ((byte) BinaryElement.End);\r
                }\r
 \r
-               public static object ReadMethodCall (BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, ISurrogateSelector surrogateSelector, StreamingContext context)\r
+               public static object ReadMethodCall (BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, BinaryFormatter formatter)\r
                {\r
                        BinaryElement elem = (BinaryElement)reader.ReadByte();  // The element code\r
                        if (elem != BinaryElement.MethodCall) throw new SerializationException("Invalid format. Expected BinaryElement.MethodCall, found " +  elem);\r
@@ -244,11 +286,13 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        if (((BinaryTypeCode)reader.ReadByte()) != BinaryTypeCode.String) throw new SerializationException ("Invalid format");\r
                        string className = reader.ReadString();\r
 \r
-                       bool hasContextInfo = (flags & MethodFlags.IncludesLogicalCallContext) > 0;
+                       //bool hasContextInfo = (flags & MethodFlags.IncludesLogicalCallContext) > 0;
 
                        object[] arguments = null;
                        object methodSignature = null;
                        object callContext = null;
+                       object[] extraProperties = null;
+                       Header[] headers = null;
 
                        if ((flags & MethodFlags.PrimitiveArguments) > 0)
                        {
@@ -263,8 +307,11 @@ namespace System.Runtime.Serialization.Formatters.Binary
 
                        if ((flags & MethodFlags.NeedsInfoArrayMask) > 0)\r
                        {\r
-                               ObjectReader objectReader = new ObjectReader(surrogateSelector, context);\r
-                               object[] msgInfo = (object[]) objectReader.ReadObjectGraph (reader, hasHeaders, headerHandler);\r
+                               ObjectReader objectReader = new ObjectReader (formatter);\r
+\r
+                               object result;\r
+                               objectReader.ReadObjectGraph (reader, hasHeaders, out result, out headers);\r
+                               object[] msgInfo = (object[]) result;\r
 \r
                                if ((flags & MethodFlags.ArgumentsInSimpleArray) > 0) {\r
                                        arguments = msgInfo;\r
@@ -273,7 +320,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                {\r
                                        int n = 0;\r
                                        if ((flags & MethodFlags.ArgumentsInMultiArray) > 0) {\r
-                                               if (msgInfo.Length > 1) arguments = (object[])msgInfo[n++];\r
+                                               if (msgInfo.Length > 1) arguments = (object[]) msgInfo[n++];\r
                                                else arguments = new object[0];\r
                                        }\r
 \r
@@ -281,7 +328,10 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                                methodSignature = msgInfo[n++];\r
 \r
                                        if ((flags & MethodFlags.IncludesLogicalCallContext) > 0) \r
-                                               callContext = msgInfo[n];\r
+                                               callContext = msgInfo[n++];\r
+\r
+                                       if (n < msgInfo.Length)\r
+                                               extraProperties = (object[]) msgInfo[n];\r
                                }\r
                        }\r
                        else {\r
@@ -290,17 +340,29 @@ namespace System.Runtime.Serialization.Formatters.Binary
 \r
                        if (arguments == null) arguments = new object[0];\r
 \r
-                       Header[] methodInfo = new Header[5];\r
+                       string uri = null;\r
+                       if (headerHandler != null)\r
+                               uri = headerHandler(headers) as string;\r
+\r
+                       Header[] methodInfo = new Header[6];\r
                        methodInfo[0] = new Header("__MethodName", methodName);
                        methodInfo[1] = new Header("__MethodSignature", methodSignature);
                        methodInfo[2] = new Header("__TypeName", className);
                        methodInfo[3] = new Header("__Args", arguments);
                        methodInfo[4] = new Header("__CallContext", callContext);
+                       methodInfo[5] = new Header("__Uri", uri);
+
+                       MethodCall call = new MethodCall (methodInfo);
 
-                       return new MethodCall (methodInfo);
+                       if (extraProperties != null) {
+                               foreach (DictionaryEntry entry in extraProperties)
+                                       call.Properties [(string)entry.Key] = entry.Value;
+                       }
+
+                       return call;
                }\r
 \r
-               public static object ReadMethodResponse (BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, IMethodCallMessage methodCallMessage, ISurrogateSelector surrogateSelector, StreamingContext context)\r
+               public static object ReadMethodResponse (BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, IMethodCallMessage methodCallMessage, BinaryFormatter formatter)\r
                {\r
                        BinaryElement elem = (BinaryElement)reader.ReadByte();  // The element code\r
                        if (elem != BinaryElement.MethodResponse) throw new SerializationException("Invalid format. Expected BinaryElement.MethodResponse, found " +  elem);\r
@@ -317,6 +379,8 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        object[] outArgs = null;\r
                        LogicalCallContext callContext = null;\r
                        Exception exception = null;\r
+                       object[] extraProperties = null;
+                       Header[] headers = null;
 \r
                        if ((typeTag & ReturnTypeTag.PrimitiveType) > 0)
                        {\r
@@ -341,16 +405,19 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        {\r
                                // There objects that need to be deserialized using an ObjectReader\r
 \r
-                               ObjectReader objectReader = new ObjectReader(surrogateSelector, context);\r
-                               object[] msgInfo = (object[]) objectReader.ReadObjectGraph (reader, hasHeaders, headerHandler);\r
+                               ObjectReader objectReader = new ObjectReader (formatter);\r
+                               object result;\r
+                               objectReader.ReadObjectGraph (reader, hasHeaders, out result, out headers);\r
+                               object[] msgInfo = (object[]) result;\r
 \r
                                if ((typeTag & ReturnTypeTag.Exception) > 0) {\r
                                        exception = (Exception) msgInfo[0];\r
                                }\r
-                               if ((flags & MethodFlags.NoArguments) > 0 || (flags & MethodFlags.PrimitiveArguments) > 0) {\r
+                               else if ((flags & MethodFlags.NoArguments) > 0 || (flags & MethodFlags.PrimitiveArguments) > 0) {\r
                                        int n = 0;\r
                                        if ((typeTag & ReturnTypeTag.ObjectType) > 0) returnValue = msgInfo [n++];\r
-                                       if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[n];\r
+                                       if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[n++];\r
+                                       if (n < msgInfo.Length) extraProperties = (object[]) msgInfo[n];\r
                                }\r
                                else if ((flags & MethodFlags.ArgumentsInSimpleArray) > 0) {\r
                                        outArgs = msgInfo;\r
@@ -359,19 +426,30 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                        int n = 0;\r
                                        outArgs = (object[]) msgInfo[n++];\r
                                        if ((typeTag & ReturnTypeTag.ObjectType) > 0) returnValue = msgInfo[n++];\r
-                                       if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[n];\r
+                                       if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[n++];\r
+                                       if (n < msgInfo.Length) extraProperties = (object[]) msgInfo[n];\r
                                }\r
                        }\r
                        else {\r
                                reader.ReadByte ();     // Reads the stream ender\r
                        }\r
 \r
+                       if (headerHandler != null) \r
+                               headerHandler(headers);\r
+\r
                        if (exception != null)\r
                                return new ReturnMessage (exception, methodCallMessage);\r
                        else\r
                        {\r
                                int argCount = (outArgs!=null) ? outArgs.Length : 0;\r
-                               return new ReturnMessage (returnValue, outArgs, argCount, callContext, methodCallMessage);\r
+                               ReturnMessage result = new ReturnMessage (returnValue, outArgs, argCount, callContext, methodCallMessage);\r
+\r
+                               if (extraProperties != null) {
+                                       foreach (DictionaryEntry entry in extraProperties)
+                                               result.Properties [(string)entry.Key] = entry.Value;
+                               }
+
+                               return result;
                        }\r
                }\r
 \r
@@ -391,5 +469,24 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        return type.IsPrimitive || type == typeof(string) || type == typeof (DateTime) || type == typeof (Decimal);\r
                }\r
 \r
+               static object[] GetExtraProperties (IDictionary properties, string[] internalKeys)\r
+               {\r
+                       object[] extraProperties = new object [properties.Count - internalKeys.Length];\r
+                       \r
+                       int n = 0;\r
+                       IDictionaryEnumerator e = properties.GetEnumerator();\r
+                       while (e.MoveNext())\r
+                               if (!IsInternalKey ((string) e.Entry.Key, internalKeys)) extraProperties [n++] = e.Entry;\r
+\r
+                       return extraProperties;\r
+               }\r
+\r
+               static bool IsInternalKey (string key, string[] internalKeys)\r
+               {\r
+                       foreach (string ikey in internalKeys)\r
+                               if (key == ikey) return true;\r
+                       return false;\r
+               }\r
+\r
        }\r
 }\r