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 <glib.h>
24
#include <libxml/parser.h>
25
#include <libxml/tree.h>
26
#include <stdlib.h>
27
#include <string.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 HELP_TEXT_ATTR ((const xmlChar *) "help_text")
63
#define MIN_ATTR ((const xmlChar *) "min")
64
#define MAX_ATTR ((const xmlChar *) "max")
65
#define CURRENT_ATTR ((const xmlChar *) "current")
66
#define STEP_ATTR ((const xmlChar *) "step")
67
#define COL_HEADER_ATTR ((const xmlChar *) "col_header")
68
#define ROW_HEADER_ATTR ((const xmlChar *) "row_header")
69
#define COL_DESC_ATTR ((const xmlChar *) "col_desc")
70
#define ROW_DESC_ATTR ((const xmlChar *) "row_desc")
71
#define SELECTED_ATTR ((const xmlChar *) "selected")
72
#define SELECTED_COL_ATTR ((const xmlChar *) "selected_col")
73
#define RELATION_TYPE_ATTR ((const xmlChar *) "relation_type")
74
#define RELATION_TARGET_NAME_ATTR ((const xmlChar *) "target_name")
75
#define STATE_TYPE_ATTR ((const xmlChar *) "state_enum")
76
#define ACTION_NAME_ATTR ((const xmlChar *) "action_name")
77
#define ACTION_DES_ATTR ((const xmlChar *) "action_description")
78
#define ACTION_KEY_BIND_ATTR ((const xmlChar *) "key_binding")
79
#define COMP_X_ATTR ((const xmlChar *) "x")
80
#define COMP_Y_ATTR ((const xmlChar *) "y")
81
#define COMP_WIDTH_ATTR ((const xmlChar *) "width")
82
#define COMP_HEIGHT_ATTR ((const xmlChar *) "height")
83
#define COMP_LAYER_ATTR ((const xmlChar *) "layer")
84
#define COMP_ZORDER_ATTR ((const xmlChar *) "zorder")
85
#define COMP_ALPHA_ATTR ((const xmlChar *) "alpha")
86
#define IMAGE_DES_ATTR ((const xmlChar *) "image_description")
87
#define IMAGE_LOCALE_ATTR ((const xmlChar *) "image_locale")
88
#define TEXT_TEXT_ATTR ((const xmlChar *) "text")
89
#define TEXT_BOLD_ATTR ((const xmlChar *) "bold_text")
90
#define TEXT_UNDERLINE_ATTR ((const xmlChar *) "underline_text")
91
#define TEXT_DUMMY_ATTR ((const xmlChar *) "dummy_text")
92
#define START_ATTR ((const xmlChar *) "start")
93
#define END_ATTR ((const xmlChar *) "end")
94
#define LINK_ATTR ((const xmlChar *) "link")
95
#define CELL_X_ATTR ((const xmlChar *) "cell_x")
96
#define CELL_Y_ATTR ((const xmlChar *) "cell_y")
97
#define ROW_SPAN_ATTR ((const xmlChar *) "row_span")
98
#define COLUMN_SPAN_ATTR ((const xmlChar *) "column_span")
99
#define SELECT_ATTR ((const xmlChar *) "selected")
100
#define PAGE_ATTR ((const xmlChar *) "page_no")
101
#define PAGE_NUM_ATTR ((const xmlChar *) "page_number")
102

            
103
MyAtkObject *relation_target = NULL;
104

            
105
static double
106
55
atof_get_prop (xmlNode *node, const xmlChar *attr)
107
{
108
  double ret;
109
55
  xmlChar *str = xmlGetProp (node, attr);
110
55
  if (!str)
111
    return 0;
112
55
  ret = atof ((const char *) str);
113
55
  xmlFree (str);
114

            
115
55
  return ret;
116
}
117

            
118
static int
119
1942
atoi_get_prop (xmlNode *node, const xmlChar *attr)
120
{
121
  int ret;
122
1942
  xmlChar *str = xmlGetProp (node, attr);
123
1942
  if (!str)
124
709
    return 0;
125
1233
  ret = atoi ((const char *) str);
126
1233
  xmlFree (str);
127

            
128
1233
  return ret;
129
}
130

            
131
static AtkAttribute *
132
120
get_atk_attribute (xmlNode *node, const xmlChar *attr)
133
{
134
  xmlChar *str;
135
120
  AtkAttribute *tmp = g_malloc (sizeof (AtkAttribute));
136

            
137
120
  if (!tmp)
138
    return NULL;
139

            
140
120
  str = xmlGetProp (node, attr);
141
120
  tmp->name = g_strdup ((const char *) attr);
142
120
  tmp->value = g_strdup ((const char *) str);
143

            
144
120
  xmlFree (str);
145
120
  return tmp;
146
}
147

            
148
static gpointer
149
1595
create_atk_object_from_element (xmlNode *element)
150
{
151
  xmlNode *child_node;
152
  xmlNode *child_node2;
153

            
154
  gpointer obj;
155
1595
  gpointer child_obj = NULL;
156
1595
  AtkRelationSet *relation_set = NULL;
157
  AtkObject *array[1];
158
  AtkRelation *relation;
159
1595
  AtkStateSet *state_set = NULL;
160
  AtkStateType state_type;
161

            
162
  xmlChar *name;
163
  xmlChar *description;
164
  xmlChar *role;
165
  xmlChar *help_text;
166
  gint relation_type;
167
  gint x_size, y_size;
168
  gint width, height;
169
  gint x_extent, y_extent, w_extent, h_extent;
170
1595
  name = xmlGetProp (element, NAME_ATTR);
171
1595
  description = xmlGetProp (element, DESC_ATTR);
172
1595
  role = xmlGetProp (element, ROLE_ATTR);
173
1595
  help_text = xmlGetProp (element, HELP_TEXT_ATTR);
174
1595
  GType type = MY_TYPE_ATK_OBJECT;
175
  gint layer;
176
  gint zorder;
177
  gdouble alpha;
178

            
179
1595
  if (!xmlStrcmp (element->name, ACCESSIBLE_NODE))
180
1049
    type = MY_TYPE_ATK_OBJECT;
181

            
182
1595
  if (!xmlStrcmp (element->name, ACC_ACTION_NODE))
183
14
    type = MY_TYPE_ATK_ACTION;
184

            
185
1595
  if (!xmlStrcmp (element->name, ACC_COMPONENT_NODE))
186
27
    type = MY_TYPE_ATK_COMPONENT;
187

            
188
1595
  if (!xmlStrcmp (element->name, ACC_DOCUMENT_NODE))
189
5
    type = MY_TYPE_ATK_DOCUMENT;
190

            
191
1595
  if (!xmlStrcmp (element->name, ACC_EDIT_TEXT_NODE))
192
12
    type = MY_TYPE_ATK_EDITABLE_TEXT;
193

            
194
1595
  if (!xmlStrcmp (element->name, ACC_HYPERLINK_NODE))
195
    type = MY_TYPE_ATK_HYPERTEXT;
196

            
197
1595
  if (!xmlStrcmp (element->name, ACC_HYPERTEXT_NODE))
198
10
    type = MY_TYPE_ATK_HYPERTEXT;
199

            
200
1595
  if (!xmlStrcmp (element->name, ACC_IMAGE_NODE))
201
6
    type = MY_TYPE_ATK_IMAGE;
202

            
203
1595
  if (!xmlStrcmp (element->name, ACC_SELECTION_NODE))
204
9
    type = MY_TYPE_ATK_SELECTION;
205

            
206
1595
  if (!xmlStrcmp (element->name, ACC_TEXT_NODE))
207
40
    type = MY_TYPE_ATK_TEXT;
208

            
209
1595
  if (!xmlStrcmp (element->name, ACC_TABLE_NODE))
210
32
    type = MY_TYPE_ATK_TABLE;
211

            
212
1595
  if (!xmlStrcmp (element->name, ACC_TABLE_CELL_NODE))
213
384
    type = MY_TYPE_ATK_TABLE_CELL;
214

            
215
1595
  if (!xmlStrcmp (element->name, ACC_VALUE_NODE))
216
7
    type = MY_TYPE_ATK_VALUE;
217

            
218
1595
  obj = g_object_new (type,
219
                      "accessible-name", name,
220
                      "accessible-description", description,
221
1595
                      "accessible-role", atk_role_for_name ((const gchar *) role),
222
                      "accessible-help-text", help_text,
223
                      NULL);
224
1595
  xmlFree (name);
225
1595
  xmlFree (description);
226
1595
  xmlFree (role);
227

            
228
1595
  name = NULL;
229
1595
  description = NULL;
230
1595
  role = NULL;
231

            
232
1595
  child_node = element->xmlChildrenNode;
233
7287
  while (child_node != NULL)
234
    {
235
10496
      if (!xmlStrcmp (child_node->name, ACCESSIBLE_NODE) ||
236
9594
          !xmlStrcmp (child_node->name, ACC_ACTION_NODE) ||
237
9553
          !xmlStrcmp (child_node->name, ACC_COMPONENT_NODE) ||
238
9521
          !xmlStrcmp (child_node->name, ACC_DOCUMENT_NODE) ||
239
9504
          !xmlStrcmp (child_node->name, ACC_EDIT_TEXT_NODE) ||
240
9492
          !xmlStrcmp (child_node->name, ACC_HYPERLINK_NODE) ||
241
9482
          !xmlStrcmp (child_node->name, ACC_HYPERTEXT_NODE) ||
242
9466
          !xmlStrcmp (child_node->name, ACC_IMAGE_NODE) ||
243
9451
          !xmlStrcmp (child_node->name, ACC_SELECTION_NODE) ||
244
9410
          !xmlStrcmp (child_node->name, ACC_TABLE_NODE) ||
245
8994
          !xmlStrcmp (child_node->name, ACC_TABLE_CELL_NODE) ||
246
8570
          !xmlStrcmp (child_node->name, ACC_TEXT_NODE) ||
247
4265
          !xmlStrcmp (child_node->name, ACC_VALUE_NODE))
248
        {
249
1434
          child_obj = create_atk_object_from_element (child_node);
250
1434
          my_atk_object_add_child (obj, child_obj);
251
        }
252
5692
      child_node2 = child_node->xmlChildrenNode;
253
10563
      while (child_node2 != NULL)
254
        {
255
4871
          if (!xmlStrcmp (child_node2->name, RELATION_NODE))
256
            {
257
50
              xmlChar *relation_target_name = xmlGetProp (child_node2, RELATION_TARGET_NAME_ATTR);
258
50
              relation_type = atoi_get_prop (child_node2, RELATION_TYPE_ATTR);
259
50
              relation_set = atk_object_ref_relation_set (ATK_OBJECT (child_obj));
260
50
              array[0] = ATK_OBJECT (obj);
261
50
              relation = atk_relation_new (array, 1, relation_type);
262
50
              atk_relation_new (array, 1, relation_type);
263
50
              atk_relation_set_add (relation_set, relation);
264
50
              g_object_unref (relation);
265
50
              g_object_unref (relation_set);
266
50
              xmlFree (relation_target_name);
267
            }
268
4871
          if (!xmlStrcmp (child_node2->name, STATE_NODE))
269
            {
270
271
              xmlChar *state_enum = xmlGetProp (child_node2, STATE_TYPE_ATTR);
271

            
272
271
              state_set = atk_object_ref_state_set (ATK_OBJECT (child_obj));
273
271
              state_type = atk_state_type_for_name ((const gchar *) state_enum);
274
271
              atk_state_set_add_state (state_set, state_type);
275
271
              g_object_unref (state_set);
276
271
              xmlFree (state_enum);
277
            }
278
4871
          if (!xmlStrcmp (child_node2->name, ACTION_NODE))
279
            {
280
21
              xmlChar *action_name = xmlGetProp (child_node2, ACTION_NAME_ATTR);
281
21
              xmlChar *action_des = xmlGetProp (child_node2, ACTION_DES_ATTR);
282
21
              xmlChar *action_key_bind = xmlGetProp (child_node2, ACTION_KEY_BIND_ATTR);
283

            
284
21
              my_atk_action_add_action (child_obj, (const gchar *) action_name,
285
                                        (const gchar *) action_des,
286
                                        (const gchar *) action_key_bind);
287
21
              xmlFree (action_key_bind);
288
21
              xmlFree (action_des);
289
21
              xmlFree (action_name);
290
            }
291
4871
          if (!xmlStrcmp (child_node2->name, COMPONENT_NODE))
292
            {
293
27
              x_extent = atoi_get_prop (child_node2, COMP_X_ATTR);
294
27
              y_extent = atoi_get_prop (child_node2, COMP_Y_ATTR);
295
27
              w_extent = atoi_get_prop (child_node2, COMP_WIDTH_ATTR);
296
27
              h_extent = atoi_get_prop (child_node2, COMP_HEIGHT_ATTR);
297
27
              layer = atoi_get_prop (child_node2, COMP_LAYER_ATTR);
298
27
              zorder = atoi_get_prop (child_node2, COMP_ZORDER_ATTR);
299
27
              alpha = atof_get_prop (child_node2, COMP_ALPHA_ATTR);
300
27
              atk_component_set_extents (ATK_COMPONENT (child_obj),
301
                                         x_extent,
302
                                         y_extent,
303
                                         w_extent,
304
                                         h_extent,
305
                                         ATK_XY_SCREEN);
306
27
              my_atk_component_set_layer (ATK_COMPONENT (child_obj), layer);
307
27
              my_atk_component_set_mdi_zorder (ATK_COMPONENT (child_obj), zorder);
308
27
              my_atk_component_set_alpha (ATK_COMPONENT (child_obj), alpha);
309
            }
310
4871
          if (!xmlStrcmp (child_node2->name, DOCUMENT_NODE))
311
            {
312
5
              my_atk_set_document (ATK_DOCUMENT (child_obj),
313
                                   atoi_get_prop (child_node2, PAGE_ATTR),
314
                                   atoi_get_prop (child_node2, PAGE_NUM_ATTR));
315
            }
316
4871
          if (!xmlStrcmp (child_node2->name, HYPERLINK_NODE))
317
            {
318
              xmlChar *text = xmlGetProp (child_node2, TEXT_TEXT_ATTR);
319

            
320
              my_atk_set_hypertext (ATK_HYPERTEXT (child_obj), (const gchar *) text);
321
              xmlFree (text);
322
            }
323
4871
          if (!xmlStrcmp (child_node2->name, HYPERTEXT_NODE))
324
            {
325
10
              xmlChar *text = xmlGetProp (child_node2, TEXT_TEXT_ATTR);
326

            
327
10
              my_atk_set_hypertext (ATK_HYPERTEXT (child_obj), (const gchar *) text);
328
10
              xmlFree (text);
329
            }
330
4871
          if (!xmlStrcmp (child_node2->name, IMAGE_NODE))
331
            {
332
6
              xmlChar *image_des = xmlGetProp (child_node2, IMAGE_DES_ATTR);
333
6
              xmlChar *image_locale = xmlGetProp (child_node2, IMAGE_LOCALE_ATTR);
334
6
              x_size = atoi_get_prop (child_node2, COMP_X_ATTR);
335
6
              y_size = atoi_get_prop (child_node2, COMP_Y_ATTR);
336
6
              width = atoi_get_prop (child_node2, COMP_WIDTH_ATTR);
337
6
              height = atoi_get_prop (child_node2, COMP_HEIGHT_ATTR);
338

            
339
6
              my_atk_set_image (ATK_IMAGE (child_obj),
340
                                (const gchar *) image_des,
341
                                x_size,
342
                                y_size,
343
                                width,
344
                                height,
345
                                (const gchar *) image_locale);
346
6
              xmlFree (image_locale);
347
6
              xmlFree (image_des);
348
            }
349
4871
          if (!xmlStrcmp (child_node2->name, TEXT_NODE))
350
            {
351
40
              xmlChar *text = xmlGetProp (child_node2, TEXT_TEXT_ATTR);
352
40
              AtkAttributeSet *attrSet = NULL;
353
40
              AtkAttribute *a1 = get_atk_attribute (child_node2, TEXT_BOLD_ATTR);
354
40
              AtkAttribute *a2 = get_atk_attribute (child_node2, TEXT_UNDERLINE_ATTR);
355
40
              AtkAttribute *a3 = get_atk_attribute (child_node2, TEXT_DUMMY_ATTR);
356
40
              attrSet = g_slist_append (NULL, a1);
357
40
              attrSet = g_slist_append (attrSet, a2);
358
40
              attrSet = g_slist_append (attrSet, a3);
359
40
              my_atk_set_text (ATK_TEXT (child_obj),
360
                               (const gchar *) text,
361
                               atoi_get_prop (child_node2, COMP_X_ATTR),
362
                               atoi_get_prop (child_node2, COMP_Y_ATTR),
363
                               atoi_get_prop (child_node2, COMP_WIDTH_ATTR),
364
                               atoi_get_prop (child_node2, COMP_HEIGHT_ATTR),
365
                               attrSet);
366
40
              xmlFree (text);
367
            }
368
4871
          if (!xmlStrcmp (child_node2->name, TABLE_CELL_NODE))
369
            {
370
384
              my_atk_set_table_cell (ATK_TABLE_CELL (child_obj),
371
                                     atoi_get_prop (child_node2, CELL_X_ATTR),
372
                                     atoi_get_prop (child_node2, CELL_Y_ATTR),
373
                                     atoi_get_prop (child_node2, ROW_SPAN_ATTR),
374
                                     atoi_get_prop (child_node2, COLUMN_SPAN_ATTR));
375
            }
376
4871
          if (!xmlStrcmp (child_node2->name, VALUE_NODE))
377
            {
378
7
              my_atk_set_value (ATK_VALUE (child_obj),
379
                                atof_get_prop (child_node2, MIN_ATTR),
380
                                atof_get_prop (child_node2, CURRENT_ATTR),
381
                                atof_get_prop (child_node2, MAX_ATTR),
382
                                atof_get_prop (child_node2, STEP_ATTR));
383
            }
384
4871
          child_node2 = child_node2->next;
385
        }
386
5692
      child_node = child_node->next;
387
    }
388
1595
  return obj;
389
}
390

            
391
/*
392
 * Reads the XML from filename and uses it
393
 * to create a tree of MyAtkObjects.
394
 *
395
 * returns: The root object of the tree.
396
 */
397
MyAtkObject *
398
161
atk_object_xml_parse (gchar *filename)
399
{
400
  xmlDoc *doc;
401
  xmlNode *root_element;
402
161
  MyAtkObject *new_atk_object = NULL;
403

            
404
161
  doc = xmlReadFile (filename, NULL, 0);
405
161
  g_assert_nonnull (doc);
406

            
407
161
  root_element = xmlDocGetRootElement (doc);
408

            
409
161
  if (!root_element)
410
    return NULL;
411

            
412
161
  new_atk_object = create_atk_object_from_element (root_element);
413

            
414
161
  xmlFreeDoc (doc);
415
161
  return new_atk_object;
416
}