Allow schema files that are missing checksums on the !!SCHEMAMATIC line.
[versaplex.git] / wvdbus-sharp / msgiter.cs
blob94aa6afe9c7355d6f7c7304a895cdd60f2630d50
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 Mono;
6 using System;
7 using System.Collections;
8 using System.Collections.Generic;
9 using System.Linq;
10 using System.Text;
11 using Wv.Extensions;
13 namespace Wv
15 public class WvDbusIter
16 : WvDbusIterBase, IEnumerator<WvAutoCast>, IEnumerable<WvAutoCast>
18 int sigpos;
19 WvAutoCast cur;
20 protected WvLog log = new WvLog("DbusIter");
22 internal WvDbusIter(DataConverter conv, string sig, WvBytes b)
23 : base(conv, sig, b)
25 log.print(WvLog.L.Debug5, "Iterating! (sig={0}, bytes={1}-{2})\n",
26 sig, b.start, b.len);
27 log.print(WvLog.L.Debug5, wv.hexdump(b));
28 Reset();
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;
42 else
43 throw new ArgumentException
44 (wv.fmt("value '0x{0:x}' must be 'l' or 'B'", e), "e");
47 // IEnumerable
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));
57 // IEnumerator
58 public void Reset()
60 sigpos = 0;
61 _Reset();
64 // IEnumerator
65 public bool MoveNext()
67 if (sigpos >= sig.Length || atend())
69 cur = new WvAutoCast(null);
70 return false;
72 else
74 string sub = subsig(sig, sigpos);
75 cur = new WvAutoCast(getone(sub));
76 sigpos += sub.Length;
77 return true;
81 // IEnumerator
82 public void Dispose()
86 public WvAutoCast Current
87 { get { return cur; } }
88 object System.Collections.IEnumerator.Current
89 { get { return cur; } }
91 public WvAutoCast pop()
93 MoveNext();
94 return Current;
98 class WvDbusIter_Array
99 : WvDbusIterBase, IEnumerator<WvAutoCast>, IEnumerable<WvAutoCast>
101 WvAutoCast cur;
103 internal WvDbusIter_Array(DataConverter conv, string sig, WvBytes b)
104 : base(conv, sig, b)
106 Reset();
109 // IEnumerable
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));
119 // IEnumerator
120 public void Reset()
122 _Reset();
125 // IEnumerator
126 public bool MoveNext()
128 if (atend())
129 return false;
130 else
132 cur = new WvAutoCast(getone(sig));
133 return true;
137 // IEnumerator
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()
149 MoveNext();
150 return Current;
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)
163 this.conv = conv;
164 this.sig = sig;
165 this.data = b.bytes;
166 this.start = b.start;
167 this.end = b.start + b.len;
170 protected void _Reset()
172 pos = start;
175 protected bool atend()
177 return pos >= end;
180 protected static string subsig(string sig, int offset)
182 Dbus.DType dtype = (Dbus.DType)sig[offset];
183 switch (dtype)
185 case Dbus.DType.Array:
186 return "a" + subsig(sig, offset+1);
187 case Dbus.DType.StructBegin:
188 case Dbus.DType.DictEntryBegin:
190 int depth = 0, i;
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)
196 depth++;
197 else if (c == Dbus.DType.StructEnd
198 || c == Dbus.DType.DictEntryEnd)
200 depth--;
201 if (depth <= 0) break;
205 wv.assert(depth==0,
206 wv.fmt("Mismatched brackets in '{0}'", sig));
207 return sig.Substring(offset, i-offset+1);
209 default:
210 return sig.Substring(offset, 1);
214 protected object getone(string sig)
216 Dbus.DType dtype = (Dbus.DType)sig[0];
218 switch (dtype)
220 case Dbus.DType.Byte:
221 return ReadByte();
222 case Dbus.DType.Boolean:
223 return ReadBoolean();
224 case Dbus.DType.Int16:
225 return ReadInt16();
226 case Dbus.DType.UInt16:
227 return ReadUInt16();
228 case Dbus.DType.Int32:
229 return ReadInt32();
230 case Dbus.DType.UInt32:
231 return ReadUInt32();
232 case Dbus.DType.Int64:
233 return ReadInt64();
234 case Dbus.DType.UInt64:
235 return ReadUInt64();
236 case Dbus.DType.Single:
237 return ReadSingle();
238 case Dbus.DType.Double:
239 return ReadDouble();
240 case Dbus.DType.String:
241 case Dbus.DType.ObjectPath:
242 return ReadString();
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);
252 default:
253 throw new Exception("Unhandled D-Bus type: " + dtype);
257 void pad(int align)
259 int pad = (align - (pos % align)) % align;
260 int upto = pos + pad;
262 for (; pos < upto; pos++)
263 if (data[pos] != 0)
264 throw new Exception
265 (wv.fmt("Read non-zero byte at position 0x{0:x} "
266 + "while expecting padding", pos));
269 int _advance(int amt)
271 int oldpos = pos;
272 pos += amt;
273 wv.assert(pos <= end, "Oops, decoded past end of buffer!");
274 return oldpos;
277 int advance(int amt)
279 pad(amt);
280 return _advance(amt);
283 void ReadNull()
285 advance(1);
288 byte ReadByte()
290 return data[pos++];
293 bool ReadBoolean()
295 uint intval = ReadUInt32();
297 switch (intval) {
298 case 0:
299 return false;
300 case 1:
301 return true;
302 default:
303 throw new Exception("Read value " + intval + " at position " + pos + " while expecting boolean (0/1)");
307 short ReadInt16()
309 return conv.GetInt16(data, advance(2));
312 ushort ReadUInt16()
314 return (UInt16)ReadInt16();
317 int ReadInt32()
319 return conv.GetInt32(data, advance(4));
322 uint ReadUInt32()
324 return (UInt32)ReadInt32();
327 long ReadInt64()
329 return conv.GetInt64(data, advance(8));
332 ulong ReadUInt64()
334 return (UInt64)ReadInt64();
337 float ReadSingle()
339 return conv.GetFloat(data, advance(4));
342 double ReadDouble()
344 return conv.GetDouble(data, advance(8));
347 int ReadLength()
349 uint len = ReadUInt32();
350 if (len > Int32.MaxValue)
351 throw new Exception(wv.fmt("Invalid string length ({0})", len));
352 return (int)len;
355 string ReadString()
357 int len = ReadLength();
358 string val = Encoding.UTF8.GetString(data, pos, len);
359 _advance(len);
360 ReadNull();
361 return val;
364 string ReadSignature()
366 int len = ReadByte();
367 return Encoding.UTF8.GetString(data, _advance(len+1), len);
370 object ReadVariant()
372 string vsig = ReadSignature();
373 return getone(vsig);
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));
381 _advance(len);
382 return x;
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 '}'");
394 else
395 wv.assert(false,
396 wv.fmt("ReadStruct called for unknown type '{0}'",
397 (char)first));
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;
410 return list;