Mono.Zeroconf – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 // Copyright 2006 Alp Toker <alp@atoker.com>
2 // This software is made available under the MIT License
3 // See COPYING for details
4  
5 using System;
6 using System.Text;
7 using System.Collections.Generic;
8 using System.IO;
9 using System.Reflection;
10  
11 namespace NDesk.DBus
12 {
13 class MessageWriter
14 {
15 protected EndianFlag endianness;
16 protected MemoryStream stream;
17  
18 public Connection connection;
19  
20 //a default constructor is a bad idea for now as we want to make sure the header and content-type match
21 public MessageWriter () : this (Connection.NativeEndianness) {}
22  
23 public MessageWriter (EndianFlag endianness)
24 {
25 this.endianness = endianness;
26 stream = new MemoryStream ();
27 }
28  
29 public byte[] ToArray ()
30 {
31 //TODO: mark the writer locked or something here
32 return stream.ToArray ();
33 }
34  
35 public void CloseWrite ()
36 {
37 WritePad (8);
38 }
39  
40 public void Write (byte val)
41 {
42 stream.WriteByte (val);
43 }
44  
45 public void Write (bool val)
46 {
47 Write ((uint) (val ? 1 : 0));
48 }
49  
50 unsafe protected void MarshalUShort (byte *data)
51 {
52 WritePad (2);
53 byte[] dst = new byte[2];
54  
55 if (endianness == Connection.NativeEndianness) {
56 dst[0] = data[0];
57 dst[1] = data[1];
58 } else {
59 dst[0] = data[1];
60 dst[1] = data[0];
61 }
62  
63 stream.Write (dst, 0, 2);
64 }
65  
66 unsafe public void Write (short val)
67 {
68 MarshalUShort ((byte*)&val);
69 }
70  
71 unsafe public void Write (ushort val)
72 {
73 MarshalUShort ((byte*)&val);
74 }
75  
76 unsafe protected void MarshalUInt (byte *data)
77 {
78 WritePad (4);
79 byte[] dst = new byte[4];
80  
81 if (endianness == Connection.NativeEndianness) {
82 dst[0] = data[0];
83 dst[1] = data[1];
84 dst[2] = data[2];
85 dst[3] = data[3];
86 } else {
87 dst[0] = data[3];
88 dst[1] = data[2];
89 dst[2] = data[1];
90 dst[3] = data[0];
91 }
92  
93 stream.Write (dst, 0, 4);
94 }
95  
96 unsafe public void Write (int val)
97 {
98 MarshalUInt ((byte*)&val);
99 }
100  
101 unsafe public void Write (uint val)
102 {
103 MarshalUInt ((byte*)&val);
104 }
105  
106 unsafe protected void MarshalULong (byte *data)
107 {
108 WritePad (8);
109 byte[] dst = new byte[8];
110  
111 if (endianness == Connection.NativeEndianness) {
112 for (int i = 0; i < 8; ++i)
113 dst[i] = data[i];
114 } else {
115 for (int i = 0; i < 8; ++i)
116 dst[i] = data[7 - i];
117 }
118  
119 stream.Write (dst, 0, 8);
120 }
121  
122 unsafe public void Write (long val)
123 {
124 MarshalULong ((byte*)&val);
125 }
126  
127 unsafe public void Write (ulong val)
128 {
129 MarshalULong ((byte*)&val);
130 }
131  
132 #if !DISABLE_SINGLE
133 unsafe public void Write (float val)
134 {
135 MarshalUInt ((byte*)&val);
136 }
137 #endif
138  
139 unsafe public void Write (double val)
140 {
141 MarshalULong ((byte*)&val);
142 }
143  
144 public void Write (string val)
145 {
146 byte[] utf8_data = Encoding.UTF8.GetBytes (val);
147 Write ((uint)utf8_data.Length);
148 stream.Write (utf8_data, 0, utf8_data.Length);
149 WriteNull ();
150 }
151  
152 public void Write (ObjectPath val)
153 {
154 Write (val.Value);
155 }
156  
157 public void Write (Signature val)
158 {
159 byte[] ascii_data = val.GetBuffer ();
160  
161 if (ascii_data.Length > Protocol.MaxSignatureLength)
162 throw new Exception ("Signature length " + ascii_data.Length + " exceeds maximum allowed " + Protocol.MaxSignatureLength + " bytes");
163  
164 Write ((byte)ascii_data.Length);
165 stream.Write (ascii_data, 0, ascii_data.Length);
166 WriteNull ();
167 }
168  
169 public void WriteComplex (object val, Type type)
170 {
171 if (type == typeof (void))
172 return;
173  
174 if (type.IsArray) {
175 WriteArray (val, type.GetElementType ());
176 } else if (type.IsGenericType && (type.GetGenericTypeDefinition () == typeof (IDictionary<,>) || type.GetGenericTypeDefinition () == typeof (Dictionary<,>))) {
177 Type[] genArgs = type.GetGenericArguments ();
178 System.Collections.IDictionary idict = (System.Collections.IDictionary)val;
179 WriteFromDict (genArgs[0], genArgs[1], idict);
180 } else if (Mapper.IsPublic (type)) {
181 WriteObject (type, val);
182 } else if (!type.IsPrimitive && !type.IsEnum) {
183 WriteValueType (val, type);
184 /*
185 } else if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>)) {
186 //is it possible to support nullable types?
187 Type[] genArgs = type.GetGenericArguments ();
188 WriteVariant (genArgs[0], val);
189 */
190 } else {
191 throw new Exception ("Can't write");
192 }
193 }
194  
195 public void Write (Type type, object val)
196 {
197 if (type == typeof (void))
198 return;
199  
200 if (type.IsArray) {
201 WriteArray (val, type.GetElementType ());
202 } else if (type == typeof (ObjectPath)) {
203 Write ((ObjectPath)val);
204 } else if (type == typeof (Signature)) {
205 Write ((Signature)val);
206 } else if (type == typeof (object)) {
207 Write (val);
208 } else if (type == typeof (string)) {
209 Write ((string)val);
210 } else if (type.IsGenericType && (type.GetGenericTypeDefinition () == typeof (IDictionary<,>) || type.GetGenericTypeDefinition () == typeof (Dictionary<,>))) {
211 Type[] genArgs = type.GetGenericArguments ();
212 System.Collections.IDictionary idict = (System.Collections.IDictionary)val;
213 WriteFromDict (genArgs[0], genArgs[1], idict);
214 } else if (Mapper.IsPublic (type)) {
215 WriteObject (type, val);
216 } else if (!type.IsPrimitive && !type.IsEnum) {
217 WriteValueType (val, type);
218 } else {
219 Write (Signature.TypeToDType (type), val);
220 }
221 }
222  
223 //helper method, should not be used as it boxes needlessly
224 public void Write (DType dtype, object val)
225 {
226 switch (dtype)
227 {
228 case DType.Byte:
229 {
230 Write ((byte)val);
231 }
232 break;
233 case DType.Boolean:
234 {
235 Write ((bool)val);
236 }
237 break;
238 case DType.Int16:
239 {
240 Write ((short)val);
241 }
242 break;
243 case DType.UInt16:
244 {
245 Write ((ushort)val);
246 }
247 break;
248 case DType.Int32:
249 {
250 Write ((int)val);
251 }
252 break;
253 case DType.UInt32:
254 {
255 Write ((uint)val);
256 }
257 break;
258 case DType.Int64:
259 {
260 Write ((long)val);
261 }
262 break;
263 case DType.UInt64:
264 {
265 Write ((ulong)val);
266 }
267 break;
268 #if !DISABLE_SINGLE
269 case DType.Single:
270 {
271 Write ((float)val);
272 }
273 break;
274 #endif
275 case DType.Double:
276 {
277 Write ((double)val);
278 }
279 break;
280 case DType.String:
281 {
282 Write ((string)val);
283 }
284 break;
285 case DType.ObjectPath:
286 {
287 Write ((ObjectPath)val);
288 }
289 break;
290 case DType.Signature:
291 {
292 Write ((Signature)val);
293 }
294 break;
295 case DType.Variant:
296 {
297 Write ((object)val);
298 }
299 break;
300 default:
301 throw new Exception ("Unhandled D-Bus type: " + dtype);
302 }
303 }
304  
305 public void WriteObject (Type type, object val)
306 {
307 ObjectPath path;
308  
309 BusObject bobj = val as BusObject;
310  
311 if (bobj == null && val is MarshalByRefObject) {
312 bobj = ((MarshalByRefObject)val).GetLifetimeService () as BusObject;
313 }
314  
315 if (bobj == null)
316 throw new Exception ("No object reference to write");
317  
318 path = bobj.Path;
319  
320 Write (path);
321 }
322  
323 //variant
324 public void Write (object val)
325 {
326 //TODO: maybe support sending null variants
327  
328 if (val == null)
329 throw new NotSupportedException ("Cannot send null variant");
330  
331 Type type = val.GetType ();
332  
333 WriteVariant (type, val);
334 }
335  
336 public void WriteVariant (Type type, object val)
337 {
338 Signature sig = Signature.GetSig (type);
339  
340 Write (sig);
341 Write (type, val);
342 }
343  
344 //this requires a seekable stream for now
345 public void WriteArray (object obj, Type elemType)
346 {
347 Array val = (Array)obj;
348  
349 //TODO: more fast paths for primitive arrays
350 if (elemType == typeof (byte)) {
351 if (val.Length > Protocol.MaxArrayLength)
352 throw new Exception ("Array length " + val.Length + " exceeds maximum allowed " + Protocol.MaxArrayLength + " bytes");
353  
354 Write ((uint)val.Length);
355 stream.Write ((byte[])val, 0, val.Length);
356 return;
357 }
358  
359 long origPos = stream.Position;
360 Write ((uint)0);
361  
362 //advance to the alignment of the element
363 WritePad (Protocol.GetAlignment (Signature.TypeToDType (elemType)));
364  
365 long startPos = stream.Position;
366  
367 foreach (object elem in val)
368 Write (elemType, elem);
369  
370 long endPos = stream.Position;
371 uint ln = (uint)(endPos - startPos);
372 stream.Position = origPos;
373  
374 if (ln > Protocol.MaxArrayLength)
375 throw new Exception ("Array length " + ln + " exceeds maximum allowed " + Protocol.MaxArrayLength + " bytes");
376  
377 Write (ln);
378 stream.Position = endPos;
379 }
380  
381 public void WriteFromDict (Type keyType, Type valType, System.Collections.IDictionary val)
382 {
383 long origPos = stream.Position;
384 Write ((uint)0);
385  
386 //advance to the alignment of the element
387 //WritePad (Protocol.GetAlignment (Signature.TypeToDType (type)));
388 WritePad (8);
389  
390 long startPos = stream.Position;
391  
392 foreach (System.Collections.DictionaryEntry entry in val)
393 {
394 WritePad (8);
395  
396 Write (keyType, entry.Key);
397 Write (valType, entry.Value);
398 }
399  
400 long endPos = stream.Position;
401 uint ln = (uint)(endPos - startPos);
402 stream.Position = origPos;
403  
404 if (ln > Protocol.MaxArrayLength)
405 throw new Exception ("Dict length " + ln + " exceeds maximum allowed " + Protocol.MaxArrayLength + " bytes");
406  
407 Write (ln);
408 stream.Position = endPos;
409 }
410  
411 public void WriteValueType (object val, Type type)
412 {
413 MethodInfo mi = TypeImplementer.GetWriteMethod (type);
414 mi.Invoke (null, new object[] {this, val});
415 }
416  
417 /*
418 public void WriteValueTypeOld (object val, Type type)
419 {
420 WritePad (8);
421  
422 if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (KeyValuePair<,>)) {
423 System.Reflection.PropertyInfo key_prop = type.GetProperty ("Key");
424 Write (key_prop.PropertyType, key_prop.GetValue (val, null));
425  
426 System.Reflection.PropertyInfo val_prop = type.GetProperty ("Value");
427 Write (val_prop.PropertyType, val_prop.GetValue (val, null));
428  
429 return;
430 }
431  
432 FieldInfo[] fis = type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
433  
434 foreach (System.Reflection.FieldInfo fi in fis) {
435 object elem;
436 elem = fi.GetValue (val);
437 Write (fi.FieldType, elem);
438 }
439 }
440 */
441  
442 public void WriteNull ()
443 {
444 stream.WriteByte (0);
445 }
446  
447 public void WritePad (int alignment)
448 {
449 int needed = Protocol.PadNeeded ((int)stream.Position, alignment);
450 for (int i = 0 ; i != needed ; i++)
451 stream.WriteByte (0);
452 }
453 }
454 }