1
// Copyright 2006 Alp Toker <alp@atoker.com>
2
// This software is made available under the MIT License
3
// See COPYING for details
7
using System.Collections.Generic;
9
using System.Reflection;
15
protected EndianFlag endianness;
16
protected MemoryStream stream;
18
public Connection connection;
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)
23
public MessageWriter (EndianFlag endianness)
25
this.endianness = endianness;
26
stream = new MemoryStream ();
29
public byte[] ToArray ()
31
//TODO: mark the writer locked or something here
32
return stream.ToArray ();
35
public void CloseWrite ()
37
int needed = Protocol.PadNeeded ((int)stream.Position, 8);
38
for (int i = 0 ; i != needed ; i++)
42
public void Write (byte val)
44
stream.WriteByte (val);
47
public void Write (bool val)
49
Write ((uint) (val ? 1 : 0));
52
unsafe protected void MarshalUShort (byte *data)
55
byte[] dst = new byte[2];
57
if (endianness == Connection.NativeEndianness) {
65
stream.Write (dst, 0, 2);
68
unsafe public void Write (short val)
70
MarshalUShort ((byte*)&val);
73
unsafe public void Write (ushort val)
75
MarshalUShort ((byte*)&val);
78
unsafe protected void MarshalUInt (byte *data)
81
byte[] dst = new byte[4];
83
if (endianness == Connection.NativeEndianness) {
95
stream.Write (dst, 0, 4);
98
unsafe public void Write (int val)
100
MarshalUInt ((byte*)&val);
103
unsafe public void Write (uint val)
105
MarshalUInt ((byte*)&val);
108
unsafe protected void MarshalULong (byte *data)
111
byte[] dst = new byte[8];
113
if (endianness == Connection.NativeEndianness) {
114
for (int i = 0; i < 8; ++i)
117
for (int i = 0; i < 8; ++i)
118
dst[i] = data[7 - i];
121
stream.Write (dst, 0, 8);
124
unsafe public void Write (long val)
126
MarshalULong ((byte*)&val);
129
unsafe public void Write (ulong val)
131
MarshalULong ((byte*)&val);
135
unsafe public void Write (float val)
137
MarshalUInt ((byte*)&val);
141
unsafe public void Write (double val)
143
MarshalULong ((byte*)&val);
146
public void Write (string val)
148
byte[] utf8_data = Encoding.UTF8.GetBytes (val);
149
Write ((uint)utf8_data.Length);
150
stream.Write (utf8_data, 0, utf8_data.Length);
151
stream.WriteByte (0); //NULL string terminator
154
public void Write (ObjectPath val)
159
public void Write (Signature val)
161
byte[] ascii_data = val.GetBuffer ();
162
Write ((byte)ascii_data.Length);
163
stream.Write (ascii_data, 0, ascii_data.Length);
164
stream.WriteByte (0); //NULL signature terminator
167
public void Write (Type type, object val)
169
if (type == typeof (void))
173
Write (type, (Array)val);
174
} else if (type == typeof (ObjectPath)) {
175
Write ((ObjectPath)val);
176
} else if (type == typeof (Signature)) {
177
Write ((Signature)val);
178
} else if (type == typeof (object)) {
180
} else if (type == typeof (string)) {
182
} else if (type.IsGenericType && (type.GetGenericTypeDefinition () == typeof (IDictionary<,>) || type.GetGenericTypeDefinition () == typeof (Dictionary<,>))) {
183
Type[] genArgs = type.GetGenericArguments ();
184
System.Collections.IDictionary idict = (System.Collections.IDictionary)val;
185
WriteFromDict (genArgs[0], genArgs[1], idict);
186
} else if (Mapper.IsPublic (type)) {
187
WriteObject (type, val);
188
} else if (!type.IsPrimitive && !type.IsEnum) {
189
WriteStruct (type, val);
191
} else if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>)) {
192
//is it possible to support nullable types?
193
Type[] genArgs = type.GetGenericArguments ();
194
WriteVariant (genArgs[0], val);
197
Write (Signature.TypeToDType (type), val);
201
//helper method, should not be used as it boxes needlessly
202
public void Write (DType dtype, object val)
263
case DType.ObjectPath:
265
Write ((ObjectPath)val);
268
case DType.Signature:
270
Write ((Signature)val);
279
throw new Exception ("Unhandled D-Bus type: " + dtype);
283
public void WriteObject (Type type, object val)
287
BusObject bobj = val as BusObject;
289
if (bobj == null && val is MarshalByRefObject) {
290
bobj = ((MarshalByRefObject)val).GetLifetimeService () as BusObject;
294
throw new Exception ("No object reference to write");
302
public void Write (object val)
304
//TODO: maybe support sending null variants
307
throw new NotSupportedException ("Cannot send null variant");
309
Type type = val.GetType ();
311
WriteVariant (type, val);
314
public void WriteVariant (Type type, object val)
316
Signature sig = Signature.GetSig (type);
322
//this requires a seekable stream for now
323
public void Write (Type type, Array val)
325
Type elemType = type.GetElementType ();
327
//TODO: more fast paths for primitive arrays
328
if (elemType == typeof (byte)) {
329
Write ((uint)val.Length);
330
stream.Write ((byte[])val, 0, val.Length);
335
long lengthPos = stream.Position - 4;
337
//advance to the alignment of the element
338
WritePad (Protocol.GetAlignment (Signature.TypeToDType (elemType)));
340
long startPos = stream.Position;
342
foreach (object elem in val)
343
Write (elemType, elem);
345
long endPos = stream.Position;
347
stream.Position = lengthPos;
348
Write ((uint)(endPos - startPos));
350
stream.Position = endPos;
353
public void WriteFromDict (Type keyType, Type valType, System.Collections.IDictionary val)
356
long lengthPos = stream.Position - 4;
358
//advance to the alignment of the element
359
//WritePad (Protocol.GetAlignment (Signature.TypeToDType (type)));
362
long startPos = stream.Position;
364
foreach (System.Collections.DictionaryEntry entry in val)
368
Write (keyType, entry.Key);
369
Write (valType, entry.Value);
372
long endPos = stream.Position;
374
stream.Position = lengthPos;
375
Write ((uint)(endPos - startPos));
377
stream.Position = endPos;
380
public void WriteStruct (Type type, object val)
382
WritePad (8); //offset for structs, right?
385
ConstructorInfo[] cis = type.GetConstructors ();
386
if (cis.Length != 0) {
387
System.Reflection.ParameterInfo[] parms = ci.GetParameters ();
389
foreach (ParameterInfo parm in parms) {
393
if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (KeyValuePair<,>)) {
394
System.Reflection.PropertyInfo key_prop = type.GetProperty ("Key");
395
Write (key_prop.PropertyType, key_prop.GetValue (val, null));
397
System.Reflection.PropertyInfo val_prop = type.GetProperty ("Value");
398
Write (val_prop.PropertyType, val_prop.GetValue (val, null));
403
FieldInfo[] fis = type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
405
foreach (System.Reflection.FieldInfo fi in fis) {
407
//public virtual object GetValueDirect (TypedReference obj);
408
elem = fi.GetValue (val);
409
//Write (Signature.TypeToDType (fi.FieldType), elem);
410
Write (fi.FieldType, elem);
414
public void WritePad (int alignment)
416
stream.Position = Protocol.Padded ((int)stream.Position, alignment);