2004-12-08 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / BinaryFormatter.cs
1 // BinaryFormatter.cs
2 //
3 // Author:
4 //      Dick Porter (dick@ximian.com)
5 //  Lluis Sanchez Gual (lluis@ideary.com)
6 //
7 // (C) 2002 Ximian, Inc.  http://www.ximian.com
8
9 //
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 //
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.
30 //
31
32 using System.Runtime.Serialization.Formatters;
33 using System.Runtime.Serialization;
34 using System.Reflection;
35 using System.Collections;
36 using System.IO;
37 using System.Runtime.Remoting.Messaging;
38
39 namespace System.Runtime.Serialization.Formatters.Binary {
40
41         public sealed class BinaryFormatter : IRemotingFormatter, IFormatter 
42         {
43                 private FormatterAssemblyStyle assembly_format = FormatterAssemblyStyle.Full;
44                 private SerializationBinder binder;
45                 private StreamingContext context;
46                 private ISurrogateSelector surrogate_selector;
47                 private FormatterTypeStyle type_format;                 // TODO: Do something with this
48                 
49 #if NET_1_1
50                 private TypeFilterLevel filter_level;
51 #endif
52                 
53                 public BinaryFormatter()
54                 {
55                         surrogate_selector=null;
56                         context=new StreamingContext(StreamingContextStates.All);
57                 }
58                 
59                 public BinaryFormatter(ISurrogateSelector selector, StreamingContext context)
60                 {
61                         surrogate_selector=selector;
62                         this.context=context;
63                 }
64
65                 public FormatterAssemblyStyle AssemblyFormat
66                 {
67                         get {
68                                 return(assembly_format);
69                         }
70                         set {
71                                 assembly_format=value;
72                         }
73                 }
74
75                 public SerializationBinder Binder
76                 {
77                         get {
78                                 return(binder);
79                         }
80                         set {
81                                 binder=value;
82                         }
83                 }
84
85                 public StreamingContext Context 
86                 {
87                         get {
88                                 return(context);
89                         }
90                         set {
91                                 context=value;
92                         }
93                 }
94                 
95                 public ISurrogateSelector SurrogateSelector 
96                 {
97                         get {
98                                 return(surrogate_selector);
99                         }
100                         set {
101                                 surrogate_selector=value;
102                         }
103                 }
104                 
105                 public FormatterTypeStyle TypeFormat 
106                 {
107                         get {
108                                 return(type_format);
109                         }
110                         set {
111                                 type_format=value;
112                         }
113                 }
114
115 #if NET_1_1
116                 [System.Runtime.InteropServices.ComVisible (false)]
117                 public TypeFilterLevel FilterLevel 
118                 {
119                         get { return filter_level; }
120                         set { filter_level = value; }
121                 }
122 #endif
123
124                 public object Deserialize(Stream serializationStream)
125                 {
126                         return Deserialize (serializationStream, null);
127                 }
128
129                 public object Deserialize(Stream serializationStream, HeaderHandler handler) 
130                 {
131                         if(serializationStream==null) \r
132                         {
133                                 throw new ArgumentNullException("serializationStream is null");
134                         }
135                         if(serializationStream.CanSeek &&
136                                 serializationStream.Length==0) \r
137                         {
138                                 throw new SerializationException("serializationStream supports seeking, but its length is 0");
139                         }
140
141                         BinaryReader reader = new BinaryReader (serializationStream);
142
143                         bool hasHeader;
144                         ReadBinaryHeader (reader, out hasHeader);
145
146                         // Messages are read using a special static method, which does not use ObjectReader
147                         // if it is not needed. This saves time and memory.
148
149                         BinaryElement elem = (BinaryElement) reader.PeekChar();
150
151                         if (elem == BinaryElement.MethodCall) {
152                                 return MessageFormatter.ReadMethodCall (reader, hasHeader, handler, this);
153                         }
154                         else if (elem == BinaryElement.MethodResponse) {
155                                 return MessageFormatter.ReadMethodResponse (reader, hasHeader, handler, null, this);
156                         }
157                         else {
158                                 ObjectReader serializer = new ObjectReader (this);
159
160                                 object result;
161                                 Header[] headers;
162                                 serializer.ReadObjectGraph (reader, hasHeader, out result, out headers);
163                                 if (handler != null) handler(headers);
164                                 return result;
165                         }
166                 }
167                 
168                 public object DeserializeMethodResponse(Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallmessage)
169                 {
170                         if(serializationStream==null) {
171                                 throw new ArgumentNullException("serializationStream is null");
172                         }
173                         if(serializationStream.CanSeek &&
174                            serializationStream.Length==0) {
175                                 throw new SerializationException("serializationStream supports seeking, but its length is 0");
176                         }
177
178                         BinaryReader reader = new BinaryReader (serializationStream);
179
180                         bool hasHeader;
181                         ReadBinaryHeader (reader, out hasHeader);
182                         return MessageFormatter.ReadMethodResponse (reader, hasHeader, handler, methodCallmessage, this);
183                 }
184
185                 public void Serialize(Stream serializationStream, object graph)
186                 {
187                         Serialize (serializationStream, graph, null);
188                 }
189
190                 public void Serialize(Stream serializationStream, object graph, Header[] headers)
191                 {
192                         if(serializationStream==null) {
193                                 throw new ArgumentNullException("serializationStream is null");
194                         }
195
196                         BinaryWriter writer = new BinaryWriter (serializationStream);
197                         WriteBinaryHeader (writer, headers!=null);\r
198 \r
199                         if (graph is IMethodCallMessage) {\r
200                                 MessageFormatter.WriteMethodCall (writer, graph, headers, surrogate_selector, context, assembly_format);\r
201                         }\r
202                         else if (graph is IMethodReturnMessage)  {\r
203                                 MessageFormatter.WriteMethodResponse (writer, graph, headers, surrogate_selector, context, assembly_format);\r
204                         }\r
205                         else {\r
206                                 ObjectWriter serializer = new ObjectWriter (surrogate_selector, context, assembly_format);
207                                 serializer.WriteObjectGraph (writer, graph, headers);
208                         }
209                         writer.Flush();
210                 }
211 \r
212                 [MonoTODO]
213                 [System.Runtime.InteropServices.ComVisible (false)]
214                 public object UnsafeDeserialize(Stream serializationStream, HeaderHandler handler) 
215                 {
216                         throw new NotImplementedException ();
217                 }
218                 
219                 [MonoTODO]
220                 [System.Runtime.InteropServices.ComVisible (false)]
221                 public object UnsafeDeserializeMethodResponse(Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallmessage)
222                 {
223                         throw new NotImplementedException ();
224                 }
225                 
226                 private void WriteBinaryHeader (BinaryWriter writer, bool hasHeaders)\r
227                 {\r
228                         writer.Write ((byte)BinaryElement.Header);\r
229                         writer.Write ((int)1);\r
230                         if (hasHeaders) writer.Write ((int)2);\r
231                         else writer.Write ((int)-1);\r
232                         writer.Write ((int)1);\r
233                         writer.Write ((int)0);\r
234                 }\r
235 \r
236                 private void ReadBinaryHeader (BinaryReader reader, out bool hasHeaders)\r
237                 {\r
238                         reader.ReadByte();\r
239                         reader.ReadInt32();\r
240                         int val = reader.ReadInt32();\r
241                         hasHeaders = (val==2);\r
242                         reader.ReadInt32();\r
243                         reader.ReadInt32();\r
244                 }\r
245         }
246 }