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
;
8 using System
.Collections
.Generic
;
15 public class WvDbusIter
16 : WvDbusIterBase
, IEnumerator
<WvAutoCast
>, IEnumerable
<WvAutoCast
>
20 protected WvLog log
= new WvLog("DbusIter");
22 internal WvDbusIter(DataConverter conv
, string sig
, WvBytes b
)
25 log
.print(WvLog
.L
.Debug5
, "Iterating! (sig={0}, bytes={1}-{2})\n",
27 log
.print(WvLog
.L
.Debug5
, wv
.hexdump(b
));
31 internal WvDbusIter(Dbus
.Endian e
, string sig
, WvBytes b
)
32 : this(parse_endian_byte((byte)e
), sig
, b
)
36 static DataConverter
parse_endian_byte(byte e
)
38 if (e
== (byte)Dbus
.Endian
.Little
)
39 return DataConverter
.LittleEndian
;
40 else if (e
== (byte)Dbus
.Endian
.Big
)
41 return DataConverter
.BigEndian
;
43 throw new ArgumentException
44 (wv
.fmt("value '0x{0:x}' must be 'l' or 'B'", e
), "e");
48 public IEnumerator
<WvAutoCast
> GetEnumerator()
50 return new WvDbusIter(conv
, sig
, data
.sub(start
, end
-start
));
52 IEnumerator System
.Collections
.IEnumerable
.GetEnumerator()
54 return new WvDbusIter(conv
, sig
, data
.sub(start
, end
-start
));
65 public bool MoveNext()
67 if (sigpos
>= sig
.Length
|| atend())
69 cur
= new WvAutoCast(null);
74 string sub
= subsig(sig
, sigpos
);
75 cur
= new WvAutoCast(getone(sub
));
86 public WvAutoCast Current
87 { get { return cur; }
}
88 object System
.Collections
.IEnumerator
.Current
89 { get { return cur; }
}
91 public WvAutoCast
pop()
98 class WvDbusIter_Array
99 : WvDbusIterBase
, IEnumerator
<WvAutoCast
>, IEnumerable
<WvAutoCast
>
103 internal WvDbusIter_Array(DataConverter conv
, string sig
, WvBytes b
)
110 public IEnumerator
<WvAutoCast
> GetEnumerator()
112 return new WvDbusIter_Array(conv
, sig
, data
.sub(start
, end
-start
));
114 IEnumerator System
.Collections
.IEnumerable
.GetEnumerator()
116 return new WvDbusIter_Array(conv
, sig
, data
.sub(start
, end
-start
));
126 public bool MoveNext()
132 cur
= new WvAutoCast(getone(sig
));
138 public void Dispose()
142 public WvAutoCast Current
143 { get { return cur; }
}
144 object System
.Collections
.IEnumerator
.Current
145 { get { return cur; }
}
147 public WvAutoCast
pop()
154 public class WvDbusIterBase
156 internal DataConverter conv
;
157 protected string sig
;
158 protected byte[] data
;
159 protected int start
, end
, pos
;
161 internal WvDbusIterBase(DataConverter conv
, string sig
, WvBytes b
)
166 this.start
= b
.start
;
167 this.end
= b
.start
+ b
.len
;
170 protected void _Reset()
175 protected bool atend()
180 protected static string subsig(string sig
, int offset
)
182 Dbus
.DType dtype
= (Dbus
.DType
)sig
[offset
];
185 case Dbus
.DType
.Array
:
186 return "a" + subsig(sig
, offset
+1);
187 case Dbus
.DType
.StructBegin
:
188 case Dbus
.DType
.DictEntryBegin
:
191 for (i
= offset
; i
< sig
.Length
; i
++)
193 Dbus
.DType c
= (Dbus
.DType
)sig
[i
];
194 if (c
== Dbus
.DType
.StructBegin
195 || c
== Dbus
.DType
.DictEntryBegin
)
197 else if (c
== Dbus
.DType
.StructEnd
198 || c
== Dbus
.DType
.DictEntryEnd
)
201 if (depth
<= 0) break;
206 wv
.fmt("Mismatched brackets in '{0}'", sig
));
207 return sig
.Substring(offset
, i
-offset
+1);
210 return sig
.Substring(offset
, 1);
214 protected object getone(string sig
)
216 Dbus
.DType dtype
= (Dbus
.DType
)sig
[0];
220 case Dbus
.DType
.Byte
:
222 case Dbus
.DType
.Boolean
:
223 return ReadBoolean();
224 case Dbus
.DType
.Int16
:
226 case Dbus
.DType
.UInt16
:
228 case Dbus
.DType
.Int32
:
230 case Dbus
.DType
.UInt32
:
232 case Dbus
.DType
.Int64
:
234 case Dbus
.DType
.UInt64
:
236 case Dbus
.DType
.Single
:
238 case Dbus
.DType
.Double
:
240 case Dbus
.DType
.String
:
241 case Dbus
.DType
.ObjectPath
:
243 case Dbus
.DType
.Signature
:
244 return ReadSignature();
245 case Dbus
.DType
.Variant
:
246 return ReadVariant();
247 case Dbus
.DType
.Array
:
248 return ReadArray(subsig(sig
, 1));
249 case Dbus
.DType
.StructBegin
:
250 case Dbus
.DType
.DictEntryBegin
:
251 return ReadStruct(sig
);
253 throw new Exception("Unhandled D-Bus type: " + dtype
);
259 int pad
= (align
- (pos
% align
)) % align
;
260 int upto
= pos
+ pad
;
262 for (; pos
< upto
; pos
++)
265 (wv
.fmt("Read non-zero byte at position 0x{0:x} "
266 + "while expecting padding", pos
));
269 int _advance(int amt
)
273 wv
.assert(pos
<= end
, "Oops, decoded past end of buffer!");
280 return _advance(amt
);
295 uint intval
= ReadUInt32();
303 throw new Exception("Read value " + intval
+ " at position " + pos
+ " while expecting boolean (0/1)");
309 return conv
.GetInt16(data
, advance(2));
314 return (UInt16
)ReadInt16();
319 return conv
.GetInt32(data
, advance(4));
324 return (UInt32
)ReadInt32();
329 return conv
.GetInt64(data
, advance(8));
334 return (UInt64
)ReadInt64();
339 return conv
.GetFloat(data
, advance(4));
344 return conv
.GetDouble(data
, advance(8));
349 uint len
= ReadUInt32();
350 if (len
> Int32
.MaxValue
)
351 throw new Exception(wv
.fmt("Invalid string length ({0})", len
));
357 int len
= ReadLength();
358 string val
= Encoding
.UTF8
.GetString(data
, pos
, len
);
364 string ReadSignature()
366 int len
= ReadByte();
367 return Encoding
.UTF8
.GetString(data
, _advance(len
+1), len
);
372 string vsig
= ReadSignature();
376 IEnumerable
<WvAutoCast
> ReadArray(string subsig
)
378 int len
= ReadLength();
379 pad(Dbus
.Protocol
.GetAlignment((Dbus
.DType
)subsig
[0]));
380 var x
= new WvDbusIter_Array(conv
, subsig
, data
.sub(pos
, len
));
385 IEnumerable
<WvAutoCast
> ReadStruct(string structsig
)
387 Dbus
.DType first
= (Dbus
.DType
)structsig
[0];
388 Dbus
.DType last
= (Dbus
.DType
)structsig
[structsig
.Length
-1];
390 if (first
== Dbus
.DType
.StructBegin
)
391 wv
.assert(last
== Dbus
.DType
.StructEnd
, "No matching ')'");
392 else if (first
== Dbus
.DType
.DictEntryBegin
)
393 wv
.assert(last
== Dbus
.DType
.DictEntryEnd
, "No matching '}'");
396 wv
.fmt("ReadStruct called for unknown type '{0}'",
399 structsig
= structsig
.Substring(1, structsig
.Length
-2);
400 pad(8); // structs are always 8-padded
402 List
<WvAutoCast
> list
= new List
<WvAutoCast
>();
403 for (int subpos
= 0; subpos
< structsig
.Length
; )
405 string sub
= subsig(structsig
, subpos
);
406 list
.Add(new WvAutoCast(getone(sub
)));
407 subpos
+= sub
.Length
;