8a729c2a72bd74086e707e779699c87aa5a20073
[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 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System.Reflection;
31 using System.Collections;
32 using System.IO;
33 using System.Runtime.Remoting.Messaging;
34 using System.Security.Permissions;
35
36 namespace System.Runtime.Serialization.Formatters.Binary {
37
38         public sealed class BinaryFormatter : IRemotingFormatter, IFormatter 
39         {
40                 private FormatterAssemblyStyle assembly_format = FormatterAssemblyStyle.Full;
41                 private SerializationBinder binder;
42                 private StreamingContext context;
43                 private ISurrogateSelector surrogate_selector;
44                 private FormatterTypeStyle type_format = FormatterTypeStyle.TypesAlways;
45                 
46 #if NET_1_1
47                 private TypeFilterLevel filter_level;
48 #endif
49                 
50                 public BinaryFormatter()
51                 {
52                         surrogate_selector=null;
53                         context=new StreamingContext(StreamingContextStates.All);
54                 }
55                 
56                 public BinaryFormatter(ISurrogateSelector selector, StreamingContext context)
57                 {
58                         surrogate_selector=selector;
59                         this.context=context;
60                 }
61
62                 public FormatterAssemblyStyle AssemblyFormat
63                 {
64                         get {
65                                 return(assembly_format);
66                         }
67                         set {
68                                 assembly_format=value;
69                         }
70                 }
71
72                 public SerializationBinder Binder
73                 {
74                         get {
75                                 return(binder);
76                         }
77                         set {
78                                 binder=value;
79                         }
80                 }
81
82                 public StreamingContext Context 
83                 {
84                         get {
85                                 return(context);
86                         }
87                         set {
88                                 context=value;
89                         }
90                 }
91                 
92                 public ISurrogateSelector SurrogateSelector 
93                 {
94                         get {
95                                 return(surrogate_selector);
96                         }
97                         set {
98                                 surrogate_selector=value;
99                         }
100                 }
101                 
102                 public FormatterTypeStyle TypeFormat 
103                 {
104                         get {
105                                 return(type_format);
106                         }
107                         set {
108                                 type_format=value;
109                         }
110                 }
111
112 #if NET_1_1
113                 [System.Runtime.InteropServices.ComVisible (false)]
114                 public TypeFilterLevel FilterLevel 
115                 {
116                         get { return filter_level; }
117                         set { filter_level = value; }
118                 }
119 #endif
120
121                 public object Deserialize(Stream serializationStream)
122                 {
123                         return Deserialize (serializationStream, null);
124                 }
125
126                 public object Deserialize(Stream serializationStream, HeaderHandler handler) 
127                 {
128                         if(serializationStream==null) \r
129                         {
130                                 throw new ArgumentNullException("serializationStream is null");
131                         }
132                         if(serializationStream.CanSeek &&
133                                 serializationStream.Length==0) \r
134                         {
135                                 throw new SerializationException("serializationStream supports seeking, but its length is 0");
136                         }
137
138                         BinaryReader reader = new BinaryReader (serializationStream);
139
140                         bool hasHeader;
141                         ReadBinaryHeader (reader, out hasHeader);
142
143                         // Messages are read using a special static method, which does not use ObjectReader
144                         // if it is not needed. This saves time and memory.
145
146                         BinaryElement elem = (BinaryElement) reader.PeekChar();
147
148                         if (elem == BinaryElement.MethodCall) {
149                                 return MessageFormatter.ReadMethodCall (reader, hasHeader, handler, this);
150                         }
151                         else if (elem == BinaryElement.MethodResponse) {
152                                 return MessageFormatter.ReadMethodResponse (reader, hasHeader, handler, null, this);
153                         }
154                         else {
155                                 ObjectReader serializer = new ObjectReader (this);
156
157                                 object result;
158                                 Header[] headers;
159                                 serializer.ReadObjectGraph (reader, hasHeader, out result, out headers);
160                                 if (handler != null) handler(headers);
161                                 return result;
162                         }
163                 }
164                 
165                 public object DeserializeMethodResponse(Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallmessage)
166                 {
167                         if(serializationStream==null) {
168                                 throw new ArgumentNullException("serializationStream is null");
169                         }
170                         if(serializationStream.CanSeek &&
171                            serializationStream.Length==0) {
172                                 throw new SerializationException("serializationStream supports seeking, but its length is 0");
173                         }
174
175                         BinaryReader reader = new BinaryReader (serializationStream);
176
177                         bool hasHeader;
178                         ReadBinaryHeader (reader, out hasHeader);
179                         return MessageFormatter.ReadMethodResponse (reader, hasHeader, handler, methodCallmessage, this);
180                 }
181
182                 public void Serialize(Stream serializationStream, object graph)
183                 {
184                         Serialize (serializationStream, graph, null);
185                 }
186
187                 [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
188                 public void Serialize(Stream serializationStream, object graph, Header[] headers)
189                 {
190                         if(serializationStream==null) {
191                                 throw new ArgumentNullException ("serializationStream");
192                         }
193
194                         BinaryWriter writer = new BinaryWriter (serializationStream);
195                         WriteBinaryHeader (writer, headers!=null);\r
196 \r
197                         if (graph is IMethodCallMessage) {\r
198                                 MessageFormatter.WriteMethodCall (writer, graph, headers, surrogate_selector, context, assembly_format, type_format);\r
199                         }\r
200                         else if (graph is IMethodReturnMessage)  {\r
201                                 MessageFormatter.WriteMethodResponse (writer, graph, headers, surrogate_selector, context, assembly_format, type_format);\r
202                         }\r
203                         else {\r
204                                 ObjectWriter serializer = new ObjectWriter (surrogate_selector, context, assembly_format, type_format);
205                                 serializer.WriteObjectGraph (writer, graph, headers);
206                         }
207                         writer.Flush();
208                 }
209 \r
210                 [MonoTODO]
211                 [System.Runtime.InteropServices.ComVisible (false)]
212                 public object UnsafeDeserialize(Stream serializationStream, HeaderHandler handler) 
213                 {
214                         throw new NotImplementedException ();
215                 }
216                 
217                 [MonoTODO]
218                 [System.Runtime.InteropServices.ComVisible (false)]
219                 public object UnsafeDeserializeMethodResponse(Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallmessage)
220                 {
221                         throw new NotImplementedException ();
222                 }
223                 
224                 private void WriteBinaryHeader (BinaryWriter writer, bool hasHeaders)\r
225                 {\r
226                         writer.Write ((byte)BinaryElement.Header);\r
227                         writer.Write ((int)1);\r
228                         if (hasHeaders) writer.Write ((int)2);\r
229                         else writer.Write ((int)-1);\r
230                         writer.Write ((int)1);\r
231                         writer.Write ((int)0);\r
232                 }\r
233 \r
234                 private void ReadBinaryHeader (BinaryReader reader, out bool hasHeaders)\r
235                 {\r
236                         reader.ReadByte();\r
237                         reader.ReadInt32();\r
238                         int val = reader.ReadInt32();\r
239                         hasHeaders = (val==2);\r
240                         reader.ReadInt32();\r
241                         reader.ReadInt32();\r
242                 }\r
243         }
244 }