1
// Copyright 2006 Alp Toker <alp@atoker.com>
2
// This software is made available under the MIT License
3
// See COPYING for details
5
//defined by default, since this is not a controversial extension
6
#define PROTO_TYPE_SINGLE
10
using System.Diagnostics;
11
using System.Collections.Generic;
16
public class MessageWriter
18
//TODO: use endianness instead of writing the message is in native format
19
protected EndianFlag endianness;
20
protected MemoryStream stream;
21
protected BinaryWriter bw;
23
//TODO: enable this ctor instead of the current one when endian support is done
24
//public MessageWriter () : this (Connection.NativeEndianness)
25
public MessageWriter () : this (EndianFlag.Little)
29
public MessageWriter (EndianFlag endianness)
31
if (endianness != EndianFlag.Little)
32
throw new NotImplementedException ("Only little-endian message writing is currently supported");
34
this.endianness = endianness;
35
stream = new MemoryStream ();
36
bw = new BinaryWriter (stream);
39
public byte[] ToArray ()
41
//TODO: mark the writer locked or something here
42
return stream.ToArray ();
45
public void CloseWrite ()
47
int needed = Protocol.PadNeeded ((int)stream.Position, 8);
48
for (int i = 0 ; i != needed ; i++)
52
public void Write (byte val)
58
public void Write (bool val)
61
bw.Write ((uint) (val ? 1 : 0));
64
public void Write (short val)
70
public void Write (ushort val)
76
public void Write (int val)
82
public void Write (uint val)
89
public void Write (long val)
95
public void Write (ulong val)
101
#if PROTO_TYPE_SINGLE
102
public void Write (float val)
109
public void Write (double val)
115
public void Write (string val)
117
byte[] utf8_data = Encoding.UTF8.GetBytes (val);
118
Write ((uint)utf8_data.Length);
119
bw.Write (utf8_data);
120
bw.Write ((byte)0); //NULL string terminator
123
public void Write (ObjectPath val)
128
public void Write (Signature val)
131
Write ((byte)val.Length);
132
bw.Write (val.GetBuffer ());
133
bw.Write ((byte)0); //NULL signature terminator
136
public void Write (Type type, object val)
138
if (type == typeof (void))
142
Write (type, (Array)val);
143
} else if (type == typeof (ObjectPath)) {
144
Write ((ObjectPath)val);
145
} else if (type == typeof (Signature)) {
146
Write ((Signature)val);
147
} else if (type.IsGenericType && (type.GetGenericTypeDefinition () == typeof (IDictionary<,>) || type.GetGenericTypeDefinition () == typeof (Dictionary<,>))) {
148
Type[] genArgs = type.GetGenericArguments ();
149
System.Collections.IDictionary idict = (System.Collections.IDictionary)val;
150
WriteFromDict (genArgs[0], genArgs[1], idict);
151
} else if (!type.IsPrimitive && type.IsValueType && !type.IsEnum) {
152
Write (type, (ValueType)val);
154
} else if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>)) {
155
//is it possible to support nullable types?
156
Type[] genArgs = type.GetGenericArguments ();
157
WriteVariant (genArgs[0], val);
160
Write (Signature.TypeToDType (type), val);
164
//helper method, should not be used as it boxes needlessly
165
public void Write (DType dtype, object val)
209
#if PROTO_TYPE_SINGLE
226
case DType.ObjectPath:
228
Write ((ObjectPath)val);
231
case DType.Signature:
233
Write ((Signature)val);
242
throw new Exception ("Unhandled D-Bus type: " + dtype);
247
public void Write (object val)
249
//TODO: maybe support sending null variants
252
throw new NotSupportedException ("Cannot send null variant");
254
Type type = val.GetType ();
256
WriteVariant (type, val);
259
public void WriteVariant (Type type, object val)
261
Signature sig = Signature.GetSig (type);
267
//this requires a seekable stream for now
268
public void Write (Type type, Array val)
271
type = type.GetElementType ();
274
long lengthPos = stream.Position - 4;
276
//advance to the alignment of the element
277
WritePad (Protocol.GetAlignment (Signature.TypeToDType (type)));
279
long startPos = stream.Position;
281
foreach (object elem in val)
284
long endPos = stream.Position;
286
stream.Position = lengthPos;
287
Write ((uint)(endPos - startPos));
289
stream.Position = endPos;
292
public void WriteFromDict (Type keyType, Type valType, System.Collections.IDictionary val)
295
long lengthPos = stream.Position - 4;
297
//advance to the alignment of the element
298
//WritePad (Protocol.GetAlignment (Signature.TypeToDType (type)));
301
long startPos = stream.Position;
303
foreach (System.Collections.DictionaryEntry entry in val)
307
Write (keyType, entry.Key);
308
Write (valType, entry.Value);
311
long endPos = stream.Position;
313
stream.Position = lengthPos;
314
Write ((uint)(endPos - startPos));
316
stream.Position = endPos;
319
public void Write (Type type, ValueType val)
321
WritePad (8); //offset for structs, right?
324
ConstructorInfo[] cis = type.GetConstructors ();
325
if (cis.Length != 0) {
326
System.Reflection.ParameterInfo[] parms = ci.GetParameters ();
328
foreach (ParameterInfo parm in parms) {
332
if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (KeyValuePair<,>)) {
333
System.Reflection.PropertyInfo key_prop = type.GetProperty ("Key");
334
Write (key_prop.PropertyType, key_prop.GetValue (val, null));
336
System.Reflection.PropertyInfo val_prop = type.GetProperty ("Value");
337
Write (val_prop.PropertyType, val_prop.GetValue (val, null));
342
System.Reflection.FieldInfo[] fis = type.GetFields ();
344
foreach (System.Reflection.FieldInfo fi in fis) {
346
//public virtual object GetValueDirect (TypedReference obj);
347
elem = fi.GetValue (val);
348
//Write (Signature.TypeToDType (fi.FieldType), elem);
349
Write (fi.FieldType, elem);
353
//RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider ();
354
public void WritePad (int alignment)
356
stream.Position = Protocol.Padded ((int)stream.Position, alignment);