private CodeTypeContainer GetNextDBusType(StringReader sr, Stack <CodeTypeContainer> containers, CodeNamespace @namespace, ICodeDelegate @delegate) { CodeTypeContainer container; int code; switch (code = sr.Read()) { case '(': // STRUCT container = CodeTypeContainer.CreateStruct(); containers.Push(container); var i = 1; do { var type = GetNextDBusType(sr, containers, @namespace, @delegate); // Seeing ourselves signals that we are complete if (type == container) { break; } // Add each member as a property var property = Declare.Property("Item" + i++, type.Reference); container.Members.Add(property.BackingField); container.Members.Add(property); } while (true); // Empty structures are not allowed; there must be at least one type code between // the parentheses. [1] // [1] http://dbus.freedesktop.org/doc/dbus-specification.html#container-types if (container.Members.Count == 0) { throw new InvalidDataException("Empty structures are not allowed; " + "there must be at least one type code between the parentheses."); } var j = 2; var name = @delegate.Name + "Data"; while (@namespace.ContainsTypeName(name)) { name = @delegate.Name + "Data" + j++; } container.Name = name; @namespace.Types.Add(container); return(container); case 'a': // ARRAY container = CodeTypeContainer.CreateArray(); containers.Push(container); // The array type code must be followed by a single complete type. [1] var nextType = GetNextDBusType(sr, containers, @namespace, @delegate); if (GetContainerType(nextType) == Container.DictEntryArray && !nextType.IsComplete) { nextType.IsComplete = true; return(nextType); } containers.Pop(); container.SetArrayElementType(nextType); return(container); case '{': // DICT_ENTRY // Implementations must not accept dict entries outside of arrays... [1] if (GetContainerType(containers.Pop()) != Container.Array) { throw new InvalidDataException("DICT_ENTRY must occur in an array. e.g.: type=\"a{us}\""); } container = CodeTypeContainer.CreateIDictionary(); containers.Push(container); var key = GetNextDBusType(sr, containers, @namespace, @delegate); // ...the first single complete type (the "key") must be a basic type rather than // a container type. [1] if (GetContainerType(key) != Container.None && key.Name != typeof(object).ToString()) { throw new InvalidDataException("The key for DICT_ENTRY must be a basic type."); } var value = GetNextDBusType(sr, containers, @namespace, @delegate); container.TypeArguments.Add(key.Reference); container.TypeArguments.Add(value.Reference); containers.Pop(); ImportNamespaces(container.RequiredImports); return(container); case ')': // STRUCT closing delimiter return(containers.Pop()); case '}': // DICT_ENTRY closing delimiter return(containers.Pop()); case -1: // Stream end Messenger.SendWarning(this, "Reached end of stream."); return(containers.Pop()); default: // Basic types return(GetBasicType(code)); } }