Mono.Zeroconf – Blame information for rev 1
?pathlinks?
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 | } |