1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; https://wiki.gnome.org/Accessibility)
4  *
5  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include <glib.h>
26 #include <libxml/parser.h>
27 #include <libxml/tree.h>
28 
29 #include "my-atk.h"
30 
31 #define ACCESSIBLE_NODE ((const xmlChar *) "accessible")
32 #define ACC_ACTION_NODE ((const xmlChar *) "accessible_action")
33 #define ACC_COMPONENT_NODE ((const xmlChar *) "accessible_component")
34 #define ACC_DOCUMENT_NODE ((const xmlChar *) "accessible_document")
35 #define ACC_HYPERLINK_NODE ((const xmlChar *) "accessible_hyperlink")
36 #define ACC_HYPERTEXT_NODE ((const xmlChar *) "accessible_hypertext")
37 #define ACC_IMAGE_NODE ((const xmlChar *) "accessible_image")
38 #define ACC_TABLE_NODE ((const xmlChar *) "accessible_table")
39 #define ACC_TABLE_CELL_NODE ((const xmlChar *) "accessible_table_cell")
40 #define ACC_EDIT_TEXT_NODE ((const xmlChar *) "accessible_editable_text")
41 #define ACC_TEXT_NODE ((const xmlChar *) "accessible_text")
42 #define ACC_SELECTION_NODE ((const xmlChar *) "accessible_selection")
43 #define ACC_VALUE_NODE ((const xmlChar *) "accessible_value")
44 #define ACTION_NODE ((const xmlChar *) "action")
45 #define DOCUMENT_NODE ((const xmlChar *) "document")
46 #define INTERFACE_NODE  ((const xmlChar *) "interface")
47 #define RELATION_NODE ((const xmlChar *) "relation")
48 #define STATE_NODE ((const xmlChar *) "state")
49 #define COMPONENT_NODE ((const xmlChar *) "component")
50 #define HYPERLINK_NODE ((const xmlChar *) "hyperlink")
51 #define HYPERTEXT_NODE ((const xmlChar *) "hypertext")
52 #define IMAGE_NODE ((const xmlChar *) "image")
53 #define TABLE_NODE ((const xmlChar *) "table")
54 #define TABLE_CELL_NODE ((const xmlChar *) "table_cell")
55 #define TEXT_NODE ((const xmlChar *) "text_node")
56 #define VALUE_NODE ((const xmlChar *) "value_node")
57 #define SELECT_NODE ((const xmlChar *) "select_node")
58 
59 #define NAME_ATTR ((const xmlChar *) "name")
60 #define DESC_ATTR ((const xmlChar *) "description")
61 #define ROLE_ATTR ((const xmlChar *) "role")
62 #define MIN_ATTR ((const xmlChar *) "min")
63 #define MAX_ATTR ((const xmlChar *) "max")
64 #define CURRENT_ATTR ((const xmlChar *) "current")
65 #define STEP_ATTR ((const xmlChar *) "step")
66 #define COL_HEADER_ATTR ((const xmlChar *) "col_header")
67 #define ROW_HEADER_ATTR ((const xmlChar *) "row_header")
68 #define COL_DESC_ATTR ((const xmlChar *) "col_desc")
69 #define ROW_DESC_ATTR ((const xmlChar *) "row_desc")
70 #define SELECTED_ATTR ((const xmlChar *) "selected")
71 #define SELECTED_COL_ATTR ((const xmlChar *) "selected_col")
72 #define RELATION_TYPE_ATTR ((const xmlChar *) "relation_type")
73 #define RELATION_TARGET_NAME_ATTR ((const xmlChar *) "target_name")
74 #define STATE_TYPE_ATTR ((const xmlChar *) "state_enum")
75 #define ACTION_NAME_ATTR ((const xmlChar *) "action_name")
76 #define ACTION_DES_ATTR ((const xmlChar *) "action_description")
77 #define ACTION_KEY_BIND_ATTR ((const xmlChar *) "key_binding")
78 #define COMP_X_ATTR ((const xmlChar *) "x")
79 #define COMP_Y_ATTR ((const xmlChar *) "y")
80 #define COMP_WIDTH_ATTR ((const xmlChar *) "width")
81 #define COMP_HEIGHT_ATTR ((const xmlChar *) "height")
82 #define COMP_LAYER_ATTR ((const xmlChar *) "layer")
83 #define COMP_ZORDER_ATTR ((const xmlChar *) "zorder")
84 #define COMP_ALPHA_ATTR ((const xmlChar *) "alpha")
85 #define IMAGE_DES_ATTR ((const xmlChar *) "image_description")
86 #define IMAGE_LOCALE_ATTR ((const xmlChar *) "image_locale")
87 #define TEXT_TEXT_ATTR ((const xmlChar *) "text")
88 #define TEXT_BOLD_ATTR ((const xmlChar *) "bold_text")
89 #define TEXT_UNDERLINE_ATTR ((const xmlChar *) "underline_text")
90 #define TEXT_DUMMY_ATTR ((const xmlChar *) "dummy_text")
91 #define START_ATTR ((const xmlChar *) "start")
92 #define END_ATTR ((const xmlChar *) "end")
93 #define LINK_ATTR ((const xmlChar *) "link")
94 #define CELL_X_ATTR ((const xmlChar *) "cell_x")
95 #define CELL_Y_ATTR ((const xmlChar *) "cell_y")
96 #define ROW_SPAN_ATTR ((const xmlChar *) "row_span")
97 #define COLUMN_SPAN_ATTR ((const xmlChar *) "column_span")
98 #define SELECT_ATTR ((const xmlChar *) "selected")
99 #define PAGE_ATTR ((const xmlChar *) "page_no")
100 #define PAGE_NUM_ATTR ((const xmlChar *) "page_number")
101 
102 MyAtkObject *relation_target = NULL;
103 
atof_get_prop(xmlNode * node,const xmlChar * attr)104 static double atof_get_prop (xmlNode *node, const xmlChar *attr)
105 {
106   double ret;
107   xmlChar *str = xmlGetProp (node, attr);
108   if (!str)
109     return 0;
110   ret = atof ((const char *)str);
111   xmlFree(str);
112 
113   return ret;
114 }
115 
atoi_get_prop(xmlNode * node,const xmlChar * attr)116 static int atoi_get_prop (xmlNode *node, const xmlChar *attr)
117 {
118   int ret;
119   xmlChar *str = xmlGetProp (node, attr);
120   if (!str)
121     return 0;
122   ret = atoi ((const char *)str);
123   xmlFree(str);
124 
125   return ret;
126 }
127 
128 static AtkAttribute *
get_atk_attribute(xmlNode * node,const xmlChar * attr)129 get_atk_attribute (xmlNode *node, const xmlChar *attr)
130 {
131   xmlChar *str;
132   AtkAttribute *tmp = g_malloc (sizeof (AtkAttribute));
133 
134   if (!tmp)
135     return NULL;
136 
137   str = xmlGetProp (node, attr);
138   tmp->name = g_strdup ((const char *)attr);
139   tmp->value = g_strdup ((const char *)str);
140 
141   free (str);
142   return tmp;
143 }
144 
145 static gpointer
create_atk_object_from_element(xmlNode * element)146 create_atk_object_from_element (xmlNode *element)
147 {
148   xmlNode *child_node;
149   xmlNode *child_node2;
150 
151   gpointer obj;
152   gpointer child_obj = NULL;
153   AtkRelationSet *relation_set = NULL;
154   AtkObject *array[1];
155   AtkRelation *relation;
156   AtkStateSet *state_set = NULL;
157   AtkStateType state_type;
158 
159   xmlChar *name;
160   xmlChar *description;
161   xmlChar *state_enum;
162   xmlChar *role;
163   gint relation_type;
164   xmlChar *relation_target_name;
165   xmlChar *action_name;
166   xmlChar *action_des;
167   xmlChar *action_key_bind;
168   xmlChar *image_des;
169   xmlChar *image_locale;
170   xmlChar *text;
171   gint x_size, y_size;
172   gint width, height;
173   gint x_extent, y_extent, w_extent, h_extent;
174   name = xmlGetProp (element, NAME_ATTR);
175   description = xmlGetProp (element, DESC_ATTR);
176   role = xmlGetProp (element, ROLE_ATTR);
177   GType type = MY_TYPE_ATK_OBJECT;
178   gint layer;
179   gint zorder;
180   gdouble alpha;
181 
182   if (!xmlStrcmp (element->name, ACCESSIBLE_NODE))
183     type = MY_TYPE_ATK_OBJECT;
184 
185   if (!xmlStrcmp (element->name, ACC_ACTION_NODE))
186     type = MY_TYPE_ATK_ACTION;
187 
188   if (!xmlStrcmp (element->name, ACC_COMPONENT_NODE))
189     type = MY_TYPE_ATK_COMPONENT;
190 
191   if (!xmlStrcmp (element->name, ACC_DOCUMENT_NODE))
192     type = MY_TYPE_ATK_DOCUMENT;
193 
194   if (!xmlStrcmp (element->name, ACC_EDIT_TEXT_NODE))
195     type = MY_TYPE_ATK_EDITABLE_TEXT;
196 
197   if (!xmlStrcmp (element->name, ACC_HYPERLINK_NODE))
198     type = MY_TYPE_ATK_HYPERTEXT;
199 
200   if (!xmlStrcmp (element->name, ACC_HYPERTEXT_NODE))
201     type = MY_TYPE_ATK_HYPERTEXT;
202 
203   if (!xmlStrcmp (element->name, ACC_IMAGE_NODE))
204     type = MY_TYPE_ATK_IMAGE;
205 
206   if (!xmlStrcmp (element->name, ACC_SELECTION_NODE))
207     type = MY_TYPE_ATK_SELECTION;
208 
209   if (!xmlStrcmp (element->name, ACC_TEXT_NODE))
210     type = MY_TYPE_ATK_TEXT;
211 
212   if (!xmlStrcmp (element->name, ACC_TABLE_NODE))
213     type = MY_TYPE_ATK_TABLE;
214 
215   if (!xmlStrcmp (element->name, ACC_TABLE_CELL_NODE))
216     type = MY_TYPE_ATK_TABLE_CELL;
217 
218   if (!xmlStrcmp (element->name, ACC_VALUE_NODE))
219     type = MY_TYPE_ATK_VALUE;
220 
221 
222   obj = g_object_new (type,
223                       "accessible-name", name,
224                       "accessible-description", description,
225                       "accessible-role", atk_role_for_name ((const gchar *)role),
226                       NULL);
227   child_node = element->xmlChildrenNode;
228   while (child_node != NULL) {
229     if (!xmlStrcmp (child_node->name, ACCESSIBLE_NODE) ||
230         !xmlStrcmp (child_node->name, ACC_ACTION_NODE) ||
231         !xmlStrcmp (child_node->name, ACC_COMPONENT_NODE) ||
232         !xmlStrcmp (child_node->name, ACC_DOCUMENT_NODE) ||
233         !xmlStrcmp (child_node->name, ACC_EDIT_TEXT_NODE) ||
234         !xmlStrcmp (child_node->name, ACC_HYPERLINK_NODE) ||
235         !xmlStrcmp (child_node->name, ACC_HYPERTEXT_NODE) ||
236         !xmlStrcmp (child_node->name, ACC_IMAGE_NODE) ||
237         !xmlStrcmp (child_node->name, ACC_SELECTION_NODE) ||
238         !xmlStrcmp (child_node->name, ACC_TABLE_NODE) ||
239         !xmlStrcmp (child_node->name, ACC_TABLE_CELL_NODE) ||
240         !xmlStrcmp (child_node->name, ACC_TEXT_NODE) ||
241         !xmlStrcmp (child_node->name, ACC_VALUE_NODE)) {
242       child_obj = create_atk_object_from_element (child_node);
243       my_atk_object_add_child (obj, child_obj);
244     }
245     child_node2 = child_node->xmlChildrenNode;
246     while (child_node2 != NULL) {
247       if (!xmlStrcmp (child_node2->name, RELATION_NODE)) {
248         relation_type = atoi_get_prop (child_node2, RELATION_TYPE_ATTR);
249         relation_target_name = xmlGetProp (child_node2, RELATION_TARGET_NAME_ATTR);
250         relation_set = atk_object_ref_relation_set (ATK_OBJECT (child_obj));
251         array[0] = ATK_OBJECT (obj);
252         relation = atk_relation_new (array, 1, relation_type);
253         atk_relation_new (array, 1, relation_type);
254         atk_relation_set_add (relation_set, relation);
255         g_object_unref (relation);
256         g_object_unref (relation_set);
257         xmlFree (relation_target_name);
258       }
259       if (!xmlStrcmp (child_node2->name, STATE_NODE)) {
260         state_set = atk_object_ref_state_set (ATK_OBJECT (child_obj));
261         state_enum = xmlGetProp (child_node2, STATE_TYPE_ATTR);
262         state_type = atk_state_type_for_name ((const gchar *)state_enum);
263         atk_state_set_add_state (state_set, state_type);
264         g_object_unref (state_set);
265         xmlFree (state_enum);
266       }
267       if (!xmlStrcmp (child_node2->name, ACTION_NODE)) {
268         action_name = xmlGetProp (child_node2, ACTION_NAME_ATTR);
269         action_des = xmlGetProp (child_node2, ACTION_DES_ATTR);
270         action_key_bind = xmlGetProp (child_node2, ACTION_KEY_BIND_ATTR);
271         my_atk_action_add_action (child_obj, (const gchar *)action_name,
272                                   (const gchar *)action_des,
273                                   (const gchar *)action_key_bind);
274       }
275       if (!xmlStrcmp (child_node2->name, COMPONENT_NODE)) {
276         x_extent = atoi_get_prop (child_node2, COMP_X_ATTR);
277         y_extent = atoi_get_prop (child_node2, COMP_Y_ATTR);
278         w_extent = atoi_get_prop (child_node2, COMP_WIDTH_ATTR);
279         h_extent = atoi_get_prop (child_node2, COMP_HEIGHT_ATTR);
280         layer = atoi_get_prop (child_node2, COMP_LAYER_ATTR);
281         zorder = atoi_get_prop (child_node2, COMP_ZORDER_ATTR);
282         alpha = atof_get_prop (child_node2, COMP_ALPHA_ATTR);
283         atk_component_set_extents (ATK_COMPONENT (child_obj),
284                                    x_extent,
285                                    y_extent,
286                                    w_extent,
287                                    h_extent,
288                                    ATK_XY_SCREEN);
289         my_atk_component_set_layer (ATK_COMPONENT (child_obj), layer);
290         my_atk_component_set_mdi_zorder (ATK_COMPONENT (child_obj), zorder);
291         my_atk_component_set_alpha (ATK_COMPONENT (child_obj), alpha);
292       }
293       if (!xmlStrcmp (child_node2->name, DOCUMENT_NODE)) {
294         my_atk_set_document (ATK_DOCUMENT(child_obj),
295                              atoi_get_prop (child_node2, PAGE_ATTR),
296                              atoi_get_prop (child_node2, PAGE_NUM_ATTR));
297       }
298       if (!xmlStrcmp (child_node2->name, HYPERLINK_NODE)) {
299         xmlChar *text = xmlGetProp (child_node2, TEXT_TEXT_ATTR);
300 
301         my_atk_set_hypertext (ATK_HYPERTEXT (child_obj), (const gchar *)text);
302         xmlFree (text);
303       }
304       if (!xmlStrcmp (child_node2->name, HYPERTEXT_NODE)) {
305         xmlChar *text = xmlGetProp (child_node2, TEXT_TEXT_ATTR);
306 
307         my_atk_set_hypertext (ATK_HYPERTEXT (child_obj), (const gchar *)text);
308         xmlFree (text);
309       }
310       if (!xmlStrcmp (child_node2->name, IMAGE_NODE)) {
311         image_des = xmlGetProp (child_node2, IMAGE_DES_ATTR);
312         x_size = atoi_get_prop (child_node2, COMP_X_ATTR);
313         y_size = atoi_get_prop (child_node2, COMP_Y_ATTR);
314         width = atoi_get_prop (child_node2, COMP_WIDTH_ATTR);
315         height = atoi_get_prop (child_node2, COMP_HEIGHT_ATTR);
316         image_locale = xmlGetProp (child_node2, IMAGE_LOCALE_ATTR);
317 
318         my_atk_set_image (ATK_IMAGE (child_obj),
319                           (const gchar *)image_des,
320                           x_size,
321                           y_size,
322                           width,
323                           height,
324                           (const gchar *)image_locale);
325       }
326       if (!xmlStrcmp (child_node2->name, TEXT_NODE)) {
327         text = xmlGetProp (child_node2, TEXT_TEXT_ATTR);
328         AtkAttributeSet *attrSet = NULL;
329         AtkAttribute *a1 = get_atk_attribute (child_node2, TEXT_BOLD_ATTR);
330         AtkAttribute *a2 = get_atk_attribute (child_node2, TEXT_UNDERLINE_ATTR);
331         AtkAttribute *a3 = get_atk_attribute (child_node2, TEXT_DUMMY_ATTR);
332         attrSet = g_slist_append(NULL, a1);
333         attrSet = g_slist_append(attrSet, a2);
334         attrSet = g_slist_append(attrSet, a3);
335         my_atk_set_text (ATK_TEXT (child_obj),
336                          (const gchar *)text,
337                          atoi_get_prop (child_node2, COMP_X_ATTR),
338                          atoi_get_prop (child_node2, COMP_Y_ATTR),
339                          atoi_get_prop (child_node2, COMP_WIDTH_ATTR),
340                          atoi_get_prop (child_node2, COMP_HEIGHT_ATTR),
341                          attrSet);
342       }
343       if (!xmlStrcmp (child_node2->name, TABLE_CELL_NODE)) {
344         my_atk_set_table_cell (ATK_TABLE_CELL (child_obj),
345                                atoi_get_prop (child_node2, CELL_X_ATTR),
346                                atoi_get_prop (child_node2, CELL_Y_ATTR),
347                                atoi_get_prop (child_node2, ROW_SPAN_ATTR),
348                                atoi_get_prop (child_node2, COLUMN_SPAN_ATTR));
349       }
350       if (!xmlStrcmp (child_node2->name, VALUE_NODE)) {
351         my_atk_set_value (ATK_VALUE(child_obj),
352                           atof_get_prop (child_node2, MIN_ATTR),
353                           atof_get_prop (child_node2, CURRENT_ATTR),
354                           atof_get_prop (child_node2, MAX_ATTR),
355                           atof_get_prop (child_node2, STEP_ATTR));
356       }
357       child_node2 = child_node2->next;
358     }
359     child_node = child_node->next;
360   }
361   return obj;
362 }
363 
364 /*
365  * Reads the XML from filename and uses it
366  * to create a tree of MyAtkObjects.
367  *
368  * returns: The root object of the tree.
369  */
370 MyAtkObject *
atk_object_xml_parse(gchar * filename)371 atk_object_xml_parse (gchar *filename)
372 {
373   xmlDoc *doc;
374   xmlNode *root_element;
375   MyAtkObject *new_atk_object = NULL;
376 
377   doc = xmlReadFile (filename, NULL, 0);
378   g_assert (doc != NULL);
379 
380   root_element = xmlDocGetRootElement (doc);
381 
382   if (!root_element)
383     return NULL;
384 
385   new_atk_object = create_atk_object_from_element (root_element);
386 
387   xmlFreeDoc (doc);
388   return new_atk_object;
389 }
390