2020-12-06 07:33:45 -08:00
|
|
|
#include <Eldbus.h>
|
2015-01-09 08:20:14 -08:00
|
|
|
#include "eldbus_introspection.h"
|
|
|
|
|
|
|
|
typedef struct _Eldbus_Introspection_Element_Parse_Table Eldbus_Introspection_Element_Parse_Table;
|
|
|
|
|
|
|
|
struct _Eldbus_Introspection_Element_Parse_Table
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
void *(*parse)(Eina_Simple_XML_Node_Tag *tag);
|
|
|
|
Eina_List **list;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *_eldbus_introspection_attribute_value_get(Eina_Inlist *, const char *);
|
|
|
|
static void *_eldbus_introspection_parse_node(Eina_Simple_XML_Node_Tag *);
|
|
|
|
static void *_eldbus_introspection_parse_interface(Eina_Simple_XML_Node_Tag *);
|
|
|
|
static void *_eldbus_introspection_parse_method(Eina_Simple_XML_Node_Tag *);
|
|
|
|
static void *_eldbus_introspection_parse_signal(Eina_Simple_XML_Node_Tag *);
|
|
|
|
static void *_eldbus_introspection_parse_argument(Eina_Simple_XML_Node_Tag *);
|
|
|
|
static void *_eldbus_introspection_parse_property(Eina_Simple_XML_Node_Tag *);
|
|
|
|
static void *_eldbus_introspection_parse_annotation(Eina_Simple_XML_Node_Tag *);
|
|
|
|
static void _eldbus_introspection_parse_children(Eina_Inlist *, const Eldbus_Introspection_Element_Parse_Table[]);
|
|
|
|
static void _eldbus_introspection_interface_free(Eldbus_Introspection_Interface *);
|
|
|
|
static void _eldbus_introspection_method_free(Eldbus_Introspection_Method *);
|
|
|
|
static void _eldbus_introspection_signal_free(Eldbus_Introspection_Signal *);
|
|
|
|
static void _eldbus_introspection_argument_free(Eldbus_Introspection_Argument *);
|
|
|
|
static void _eldbus_introspection_property_free(Eldbus_Introspection_Property *);
|
|
|
|
static void _eldbus_introspection_annotation_free(Eldbus_Introspection_Annotation *);
|
|
|
|
|
|
|
|
EAPI Eldbus_Introspection_Node *
|
|
|
|
eldbus_introspection_parse(const char *xml)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Node *node;
|
|
|
|
Eina_Simple_XML_Node_Root *xml_root;
|
|
|
|
Eina_Simple_XML_Node *xml_node;
|
2019-06-15 01:31:51 -07:00
|
|
|
Eina_Inlist *last = NULL;
|
2015-01-09 08:20:14 -08:00
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(xml, NULL);
|
|
|
|
|
|
|
|
node = NULL;
|
|
|
|
xml_root = eina_simple_xml_node_load(xml, strlen(xml), EINA_TRUE);
|
2019-06-15 01:31:51 -07:00
|
|
|
if (xml_root && xml_root->children) last = xml_root->children->last;
|
|
|
|
xml_node = (Eina_Simple_XML_Node *)last;
|
2019-08-10 15:35:44 -07:00
|
|
|
if (!xml_node) goto free_root;
|
2015-01-09 08:20:14 -08:00
|
|
|
EINA_SAFETY_ON_FALSE_GOTO(EINA_SIMPLE_XML_NODE_TAG == xml_node->type, free_root);
|
|
|
|
|
|
|
|
node = (Eldbus_Introspection_Node*)_eldbus_introspection_parse_node((Eina_Simple_XML_Node_Tag*)xml_node);
|
|
|
|
|
|
|
|
free_root:
|
|
|
|
eina_simple_xml_node_root_free(xml_root);
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
_eldbus_introspection_parse_node(Eina_Simple_XML_Node_Tag *tag)
|
|
|
|
{
|
2016-02-17 03:49:28 -08:00
|
|
|
Eldbus_Introspection_Node *node;
|
2015-01-09 08:20:14 -08:00
|
|
|
Eldbus_Introspection_Element_Parse_Table table[] = {
|
|
|
|
{ "node", _eldbus_introspection_parse_node, NULL },
|
|
|
|
{ "interface", _eldbus_introspection_parse_interface, NULL },
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
};
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
node = calloc(1, sizeof(Eldbus_Introspection_Node));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
|
|
|
|
|
|
|
|
name = _eldbus_introspection_attribute_value_get(tag->attributes, "name");
|
|
|
|
node->name = eina_stringshare_add(name);
|
|
|
|
table[0].list = &node->nodes;
|
|
|
|
table[1].list = &node->interfaces;
|
|
|
|
|
|
|
|
_eldbus_introspection_parse_children(tag->children, table);
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
eldbus_introspection_node_free(Eldbus_Introspection_Node *node)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Node *child_node;
|
|
|
|
Eldbus_Introspection_Interface *interface;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(node);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(node->nodes, child_node)
|
|
|
|
eldbus_introspection_node_free(child_node);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(node->interfaces, interface)
|
|
|
|
_eldbus_introspection_interface_free(interface);
|
|
|
|
|
|
|
|
eina_stringshare_del(node->name);
|
|
|
|
free(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
_eldbus_introspection_attribute_value_get(Eina_Inlist *attributes, const char *key)
|
|
|
|
{
|
|
|
|
Eina_Simple_XML_Attribute *attribute;
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(attributes, attribute)
|
|
|
|
{
|
|
|
|
if (strcmp(attribute->key, key) == 0)
|
|
|
|
return attribute->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
_eldbus_introspection_parse_interface(Eina_Simple_XML_Node_Tag *tag)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Interface *interface;
|
|
|
|
Eldbus_Introspection_Element_Parse_Table table[] = {
|
|
|
|
{ "method", _eldbus_introspection_parse_method, NULL },
|
|
|
|
{ "signal", _eldbus_introspection_parse_signal, NULL },
|
|
|
|
{ "property", _eldbus_introspection_parse_property, NULL },
|
|
|
|
{ "annotation", _eldbus_introspection_parse_annotation, NULL },
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
};
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
interface = calloc(1, sizeof(Eldbus_Introspection_Interface));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
|
|
|
|
|
|
|
|
name = _eldbus_introspection_attribute_value_get(tag->attributes, "name");
|
|
|
|
if (!name) goto error;
|
|
|
|
interface->name = eina_stringshare_add(name);
|
|
|
|
table[0].list = &interface->methods;
|
|
|
|
table[1].list = &interface->signals;
|
|
|
|
table[2].list = &interface->properties;
|
|
|
|
table[3].list = &interface->annotations;
|
|
|
|
|
|
|
|
_eldbus_introspection_parse_children(tag->children, table);
|
|
|
|
|
|
|
|
return interface;
|
|
|
|
|
|
|
|
error:
|
|
|
|
_eldbus_introspection_interface_free(interface);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_eldbus_introspection_interface_free(Eldbus_Introspection_Interface *interface)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Method *method;
|
|
|
|
Eldbus_Introspection_Signal *signal;
|
|
|
|
Eldbus_Introspection_Property *property;
|
|
|
|
Eldbus_Introspection_Annotation *annotation;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(interface);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(interface->methods, method)
|
|
|
|
_eldbus_introspection_method_free(method);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(interface->signals, signal)
|
|
|
|
_eldbus_introspection_signal_free(signal);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(interface->properties, property)
|
|
|
|
_eldbus_introspection_property_free(property);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(interface->annotations, annotation)
|
|
|
|
_eldbus_introspection_annotation_free(annotation);
|
|
|
|
|
|
|
|
eina_stringshare_del(interface->name);
|
|
|
|
free(interface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
_eldbus_introspection_parse_method(Eina_Simple_XML_Node_Tag *tag)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Method *method;
|
|
|
|
Eldbus_Introspection_Element_Parse_Table table[] = {
|
|
|
|
{ "arg", _eldbus_introspection_parse_argument, NULL },
|
|
|
|
{ "annotation", _eldbus_introspection_parse_annotation, NULL },
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
};
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
method = calloc(1, sizeof(Eldbus_Introspection_Method));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(method, NULL);
|
|
|
|
|
|
|
|
name = _eldbus_introspection_attribute_value_get(tag->attributes, "name");
|
|
|
|
if (!name) goto error;
|
|
|
|
method->name = eina_stringshare_add(name);
|
|
|
|
table[0].list = &method->arguments;
|
|
|
|
table[1].list = &method->annotations;
|
|
|
|
|
|
|
|
_eldbus_introspection_parse_children(tag->children, table);
|
|
|
|
|
|
|
|
return method;
|
|
|
|
|
|
|
|
error:
|
|
|
|
_eldbus_introspection_method_free(method);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_eldbus_introspection_method_free(Eldbus_Introspection_Method *method)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Argument *argument;
|
|
|
|
Eldbus_Introspection_Annotation *annotation;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(method);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(method->arguments, argument)
|
|
|
|
_eldbus_introspection_argument_free(argument);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(method->annotations, annotation)
|
|
|
|
_eldbus_introspection_annotation_free(annotation);
|
|
|
|
|
|
|
|
eina_stringshare_del(method->name);
|
|
|
|
free(method);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
_eldbus_introspection_parse_signal(Eina_Simple_XML_Node_Tag *tag)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Signal *signal;
|
|
|
|
Eldbus_Introspection_Element_Parse_Table table[] = {
|
|
|
|
{ "arg", _eldbus_introspection_parse_argument, NULL },
|
|
|
|
{ "annotation", _eldbus_introspection_parse_annotation, NULL },
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
};
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
signal = calloc(1, sizeof(Eldbus_Introspection_Signal));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(signal, NULL);
|
|
|
|
|
|
|
|
name = _eldbus_introspection_attribute_value_get(tag->attributes, "name");
|
|
|
|
if (!name) goto error;
|
|
|
|
signal->name = eina_stringshare_add(name);
|
|
|
|
table[0].list = &signal->arguments;
|
|
|
|
table[1].list = &signal->annotations;
|
|
|
|
|
|
|
|
_eldbus_introspection_parse_children(tag->children, table);
|
|
|
|
|
|
|
|
return signal;
|
|
|
|
|
|
|
|
error:
|
|
|
|
_eldbus_introspection_signal_free(signal);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_eldbus_introspection_signal_free(Eldbus_Introspection_Signal *signal)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Argument *argument;
|
|
|
|
Eldbus_Introspection_Annotation *annotation;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(signal);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(signal->arguments, argument)
|
|
|
|
_eldbus_introspection_argument_free(argument);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(signal->annotations, annotation)
|
|
|
|
_eldbus_introspection_annotation_free(annotation);
|
|
|
|
|
|
|
|
eina_stringshare_del(signal->name);
|
|
|
|
free(signal);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
_eldbus_introspection_parse_argument(Eina_Simple_XML_Node_Tag *tag)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Argument *argument;
|
|
|
|
const char *name;
|
|
|
|
const char *type;
|
|
|
|
const char *direction;
|
|
|
|
|
|
|
|
argument = calloc(1, sizeof(Eldbus_Introspection_Argument));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(argument, NULL);
|
|
|
|
|
|
|
|
name = _eldbus_introspection_attribute_value_get(tag->attributes, "name");
|
|
|
|
argument->name = eina_stringshare_add(name);
|
|
|
|
|
|
|
|
type = _eldbus_introspection_attribute_value_get(tag->attributes, "type");
|
|
|
|
if (!type) goto error;
|
|
|
|
argument->type = eina_stringshare_add(type);
|
|
|
|
|
|
|
|
direction = _eldbus_introspection_attribute_value_get(tag->attributes, "direction");
|
|
|
|
if (direction)
|
|
|
|
{
|
|
|
|
if (strcmp(direction, "in") == 0)
|
|
|
|
argument->direction = ELDBUS_INTROSPECTION_ARGUMENT_DIRECTION_IN;
|
|
|
|
else
|
|
|
|
if (strcmp(direction, "out") == 0)
|
|
|
|
argument->direction = ELDBUS_INTROSPECTION_ARGUMENT_DIRECTION_OUT;
|
|
|
|
else
|
|
|
|
argument->direction = ELDBUS_INTROSPECTION_ARGUMENT_DIRECTION_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return argument;
|
|
|
|
|
|
|
|
error:
|
|
|
|
_eldbus_introspection_argument_free(argument);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_eldbus_introspection_argument_free(Eldbus_Introspection_Argument *argument)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(argument);
|
|
|
|
eina_stringshare_del(argument->name);
|
|
|
|
eina_stringshare_del(argument->type);
|
|
|
|
free(argument);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
_eldbus_introspection_parse_property(Eina_Simple_XML_Node_Tag *tag)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Property *property;
|
|
|
|
Eldbus_Introspection_Element_Parse_Table table[] = {
|
|
|
|
{ "annotation", _eldbus_introspection_parse_annotation, NULL },
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
};
|
|
|
|
const char *name;
|
|
|
|
const char *type;
|
|
|
|
const char *access;
|
|
|
|
|
|
|
|
property = calloc(1, sizeof(Eldbus_Introspection_Property));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(property, NULL);
|
|
|
|
|
|
|
|
name = _eldbus_introspection_attribute_value_get(tag->attributes, "name");
|
|
|
|
if (!name) goto error;
|
|
|
|
property->name = eina_stringshare_add(name);
|
|
|
|
|
|
|
|
type = _eldbus_introspection_attribute_value_get(tag->attributes, "type");
|
|
|
|
if (!type) goto error;
|
|
|
|
property->type = eina_stringshare_add(type);
|
|
|
|
|
|
|
|
access = _eldbus_introspection_attribute_value_get(tag->attributes, "access");
|
|
|
|
if (!access) goto error;
|
|
|
|
|
|
|
|
if (strcmp(access, "read") == 0)
|
|
|
|
property->access = ELDBUS_INTROSPECTION_PROPERTY_ACCESS_READ;
|
|
|
|
else if (strcmp(access, "write") == 0)
|
|
|
|
property->access = ELDBUS_INTROSPECTION_PROPERTY_ACCESS_WRITE;
|
|
|
|
else if (strcmp(access, "readwrite") == 0)
|
|
|
|
property->access = ELDBUS_INTROSPECTION_PROPERTY_ACCESS_READWRITE;
|
|
|
|
else
|
|
|
|
EINA_SAFETY_ON_TRUE_GOTO(!!"Unknown property access", error);
|
|
|
|
table[0].list = &property->annotations;
|
|
|
|
|
|
|
|
_eldbus_introspection_parse_children(tag->children, table);
|
|
|
|
return property;
|
|
|
|
|
|
|
|
error:
|
|
|
|
_eldbus_introspection_property_free(property);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_eldbus_introspection_property_free(Eldbus_Introspection_Property *property)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Annotation *annotation;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(property);
|
|
|
|
|
|
|
|
EINA_LIST_FREE(property->annotations, annotation)
|
|
|
|
_eldbus_introspection_annotation_free(annotation);
|
|
|
|
|
|
|
|
eina_stringshare_del(property->name);
|
|
|
|
eina_stringshare_del(property->type);
|
|
|
|
free(property);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
_eldbus_introspection_parse_annotation(Eina_Simple_XML_Node_Tag *tag)
|
|
|
|
{
|
|
|
|
Eldbus_Introspection_Annotation *annotation;
|
|
|
|
const char *name;
|
|
|
|
const char *value;
|
|
|
|
|
|
|
|
annotation = calloc(1, sizeof(Eldbus_Introspection_Annotation));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(annotation, NULL);
|
|
|
|
|
|
|
|
name = _eldbus_introspection_attribute_value_get(tag->attributes, "name");
|
|
|
|
if (!name) goto error;
|
|
|
|
annotation->name = eina_stringshare_add(name);
|
|
|
|
|
|
|
|
value = _eldbus_introspection_attribute_value_get(tag->attributes, "value");
|
|
|
|
if (!value) goto error;
|
|
|
|
annotation->value = eina_stringshare_add(value);
|
|
|
|
|
|
|
|
return annotation;
|
|
|
|
|
|
|
|
error:
|
|
|
|
_eldbus_introspection_annotation_free(annotation);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_eldbus_introspection_annotation_free(Eldbus_Introspection_Annotation *annotation)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(annotation);
|
|
|
|
eina_stringshare_del(annotation->name);
|
|
|
|
eina_stringshare_del(annotation->value);
|
|
|
|
free(annotation);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_eldbus_introspection_parse_children(Eina_Inlist *children, const Eldbus_Introspection_Element_Parse_Table table[])
|
|
|
|
{
|
|
|
|
Eina_Simple_XML_Node *child;
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(children, child)
|
|
|
|
{
|
|
|
|
const Eldbus_Introspection_Element_Parse_Table *it;
|
|
|
|
Eina_Simple_XML_Node_Tag *tag;
|
|
|
|
void *item;
|
|
|
|
|
|
|
|
if (EINA_SIMPLE_XML_NODE_TAG != child->type)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
tag = (Eina_Simple_XML_Node_Tag*) child;
|
|
|
|
|
|
|
|
for (it = table; it->name; ++it)
|
|
|
|
{
|
|
|
|
if (strcmp(tag->name, it->name) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
item = it->parse(tag);
|
|
|
|
if (item)
|
|
|
|
*it->list = eina_list_append(*it->list, item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eldbus_Introspection_Interface *
|
|
|
|
eldbus_introspection_interface_find(Eina_List *interfaces, const char *name)
|
|
|
|
{
|
|
|
|
Eina_List *it;
|
|
|
|
Eldbus_Introspection_Interface *interface;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(interfaces, it, interface)
|
|
|
|
{
|
|
|
|
if (strcmp(interface->name, name) == 0)
|
|
|
|
return interface;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eldbus_Introspection_Property *
|
|
|
|
eldbus_introspection_property_find(Eina_List *properties, const char *name)
|
|
|
|
{
|
|
|
|
Eina_List *it;
|
|
|
|
Eldbus_Introspection_Property *property;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(properties, it, property)
|
|
|
|
{
|
|
|
|
if (strcmp(property->name, name) == 0)
|
|
|
|
return property;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eldbus_Introspection_Argument *
|
|
|
|
eldbus_introspection_argument_find(Eina_List *arguments, const char *name)
|
|
|
|
{
|
|
|
|
Eina_List *it;
|
|
|
|
Eldbus_Introspection_Argument *argument;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(arguments, it, argument)
|
|
|
|
{
|
|
|
|
if (strcmp(argument->name, name) == 0)
|
|
|
|
return argument;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|