HomePort
rest_xml.c
Go to the documentation of this file.
1 /*
2  * Copyright 2011 Aalborg University. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are
5  * permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this list of
8  * conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11  * of conditions and the following disclaimer in the documentation and/or other materials
12  * provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY Aalborg University ''AS IS'' AND ANY EXPRESS OR IMPLIED
15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Aalborg University OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  * The views and conclusions contained in the software and documentation are those of the
25  * authors and should not be interpreted as representing official policies, either expressed
26  */
27 
28 #include "rest_xml.h"
29 #include <time.h>
30 #include <mxml.h>
31 #include <hpd/common/hpd_common.h>
33 
34 static const char * const REST_XML_VERSION = "1.0";
35 
36 // TODO Fix ugly hack to get context through mxml ?
38 
39 static void rest_xml_on_mxml_error(const char *msg)
40 {
41  HPD_LOG_DEBUG(rest_xml_global_context, "%s", msg);
42 }
43 
44 #define REST_XML_BEGIN(CONTEXT) do { \
45  if (rest_xml_global_context) HPD_LOG_WARN((CONTEXT), "Global context is already set (trying anyways)..."); \
46  rest_xml_global_context = (CONTEXT); \
47  mxmlSetErrorCallback(rest_xml_on_mxml_error); \
48 } while (0) \
49 
50 #define REST_XML_END() do { \
51  rest_xml_global_context = NULL; \
52 } while (0)
53 
54 #define REST_XML_RETURN_XML_ERROR(CONTEXT) HPD_LOG_RETURN(context, HPD_E_UNKNOWN, "Xml error")
55 
56 static hpd_error_t rest_xml_add(mxml_node_t *parent, const char *key, const char *val, const hpd_module_t *context)
57 {
58  mxmlElementSetAttr(parent, key, val);
59  if (!mxmlElementGetAttr(parent, key)) REST_XML_RETURN_XML_ERROR(context);
60  return HPD_E_SUCCESS;
61 }
62 
63 static hpd_error_t rest_xml_add_attr(mxml_node_t *parent, hpd_pair_t *pair, const hpd_module_t *context)
64 {
65  hpd_error_t rc;
66 
67  // Get key and value
68  const char *key, *val;
69  if ((rc = hpd_pair_get(pair, &key, &val))) return rc;
70 
71  return rest_xml_add(parent, key, val, context);
72 }
73 
74 static hpd_error_t rest_xml_add_parameter(mxml_node_t *parent, hpd_parameter_id_t *parameter, const hpd_module_t *context)
75 {
76  hpd_error_t rc;
77 
78  // Create node
79  mxml_node_t *xml;
80  if (!(xml = mxmlNewElement(parent, HPD_REST_KEY_PARAMETER))) REST_XML_RETURN_XML_ERROR(context);
81 
82  // Add id
83  const char *id;
84  if ((rc = hpd_parameter_get_id(parameter, &id))) return rc;
85  if ((rc = rest_xml_add(xml, HPD_REST_KEY_ID, id, context))) return rc;
86 
87  // Add attributes
88  hpd_pair_t *pair;
89  hpd_parameter_foreach_attr(rc, pair, parameter)
90  if ((rc = rest_xml_add_attr(xml, pair, context))) return rc;
91  if (rc) return rc;
92 
93  return HPD_E_SUCCESS;
94 }
95 
96 static hpd_error_t rest_xml_add_service(mxml_node_t *parent, hpd_service_id_t *service, hpd_rest_t *rest, const hpd_module_t *context)
97 {
98  hpd_error_t rc;
99 
100  // Create node
101  mxml_node_t *xml;
102  if (!(xml = mxmlNewElement(parent, HPD_REST_KEY_SERVICE))) REST_XML_RETURN_XML_ERROR(context);
103 
104  // Add id
105  const char *id;
106  if ((rc = hpd_service_get_id(service, &id))) return rc;
107  if ((rc = rest_xml_add(xml, HPD_REST_KEY_ID, id, context))) return rc;
108 
109  // Add url
110  char *url;
111  if ((rc = hpd_rest_url_create(rest, service, &url))) return rc;
112  if ((rc = rest_xml_add(xml, HPD_REST_KEY_URI, url, context))) {
113  free(url);
114  return rc;
115  }
116  free(url);
117 
118  // Add actions
119  hpd_action_t *action;
120  hpd_service_foreach_action(rc, action, service) {
121  hpd_method_t method;
122  if ((rc = hpd_action_get_method(action, &method))) return rc;
123  switch (method) {
124  case HPD_M_NONE:break;
125  case HPD_M_GET:
126  if ((rc = rest_xml_add(xml, HPD_REST_KEY_GET, HPD_REST_VAL_TRUE, context))) return rc;
127  break;
128  case HPD_M_PUT:
129  if ((rc = rest_xml_add(xml, HPD_REST_KEY_PUT, HPD_REST_VAL_TRUE, context))) return rc;
130  break;
131  case HPD_M_COUNT:break;
132  }
133  }
134  if (rc) return rc;
135 
136  // Add attributes
137  hpd_pair_t *pair;
138  hpd_service_foreach_attr(rc, pair, service)
139  if ((rc = rest_xml_add_attr(xml, pair, context))) return rc;
140  if (rc) return rc;
141 
142  // Add parameters
143  hpd_parameter_id_t *parameter;
144  hpd_service_foreach_parameter(rc, parameter, service) {
145  if ((rc = rest_xml_add_parameter(xml, parameter, context))) return rc;
146  }
147  if (rc) return rc;
148 
149  return HPD_E_SUCCESS;
150 }
151 
152 static hpd_error_t rest_xml_add_device(mxml_node_t *parent, hpd_device_id_t *device, hpd_rest_t *rest, const hpd_module_t *context)
153 {
154  hpd_error_t rc;
155 
156  // Create object
157  mxml_node_t *xml;
158  if (!(xml = mxmlNewElement(parent, HPD_REST_KEY_DEVICE))) REST_XML_RETURN_XML_ERROR(context);
159 
160  // Add id
161  const char *id;
162  if ((rc = hpd_device_get_id(device, &id))) return rc;
163  if ((rc = rest_xml_add(xml, HPD_REST_KEY_ID, id, context))) return rc;
164 
165  // Add attributes
166  hpd_pair_t *pair;
167  hpd_device_foreach_attr(rc, pair, device)
168  if ((rc = rest_xml_add_attr(xml, pair, context))) return rc;
169  if (rc) return rc;
170 
171  // Add services
172  hpd_service_id_t *service;
173  hpd_device_foreach_service(rc, service, device) {
174  if ((rc = rest_xml_add_service(xml, service, rest, context))) return rc;
175  }
176  if (rc) return rc;
177 
178  return HPD_E_SUCCESS;
179 }
180 
181 static hpd_error_t rest_xml_add_adapter(mxml_node_t *parent, hpd_adapter_id_t *adapter, hpd_rest_t *rest, const hpd_module_t *context)
182 {
183  hpd_error_t rc;
184 
185  // Create object
186  mxml_node_t *json;
187  if (!(json = mxmlNewElement(parent, HPD_REST_KEY_ADAPTER))) REST_XML_RETURN_XML_ERROR(context);
188 
189  // Add id
190  const char *id;
191  if ((rc = hpd_adapter_get_id(adapter, &id))) return rc;
192  if ((rc = rest_xml_add(json, HPD_REST_KEY_ID, id, context))) return rc;
193 
194  // Add attributes
195  hpd_pair_t *pair;
196  hpd_adapter_foreach_attr(rc, pair, adapter) {
197  if ((rc = rest_xml_add_attr(json, pair, context))) return rc;
198  }
199  if (rc) return rc;
200 
201  // Add devices
202  hpd_device_id_t *device;
203  hpd_adapter_foreach_device(rc, device, adapter) {
204  if ((rc = rest_xml_add_device(json, device, rest, context))) return rc;
205  }
206  if (rc) return rc;
207 
208  return HPD_E_SUCCESS;
209 }
210 
211 static hpd_error_t rest_xml_add_configuration(mxml_node_t *parent, hpd_t *hpd, hpd_rest_t *rest, const hpd_module_t *context)
212 {
213  hpd_error_t rc;
214 
215  // Create object
216  mxml_node_t *xml;
217  if (!(xml = mxmlNewElement(parent, HPD_REST_KEY_CONFIGURATION))) REST_XML_RETURN_XML_ERROR(context);
218 
219  // Add encoded charset
220 #ifdef CURL_ICONV_CODESET_OF_HOST
221  curl_version_info_data *curl_ver = curl_version_info(CURLVERSION_NOW);
222  if (curl_ver->features & CURL_VERSION_CONV && curl_ver->iconv_ver_num != 0)
223  if ((rc = rest_xml_add(xml, HPD_REST_KEY_URL_ENCODED_CHARSET, CURL_ICONV_CODESET_OF_HOST, context))) return rc;
224  else
225  if ((rc = rest_xml_add(xml, HPD_REST_KEY_URL_ENCODED_CHARSET, HPD_REST_VAL_ASCII, context))) return rc;
226 #else
227  if ((rc = rest_xml_add(xml, HPD_REST_KEY_URL_ENCODED_CHARSET, HPD_REST_VAL_ASCII, context))) return rc;
228 #endif
229 
230  // Add adapters
231  hpd_adapter_id_t *adapter;
232  hpd_foreach_adapter(rc, adapter, hpd) {
233  if ((rc = rest_xml_add_adapter(xml, adapter, rest, context))) return rc;
234  }
235  if (rc) return rc;
236 
237  return HPD_E_SUCCESS;
238 }
239 
241 {
242  REST_XML_BEGIN(context);
243 
244  hpd_error_t rc;
245 
246  mxml_node_t *xml;
247  if (!(xml = mxmlNewXML(REST_XML_VERSION))) {
248  REST_XML_END();
249  REST_XML_RETURN_XML_ERROR(context);
250  }
251 
252  if ((rc = rest_xml_add_configuration(xml, hpd, rest, context))) goto error;
253 
254  if (!((*out) = mxmlSaveAllocString(xml, MXML_NO_CALLBACK))) {
255  mxmlDelete(xml);
256  REST_XML_END();
257  REST_XML_RETURN_XML_ERROR(context);
258  }
259 
260  mxmlDelete(xml);
261  REST_XML_END();
262  return HPD_E_SUCCESS;
263 
264  error:
265  mxmlDelete(xml);
266  REST_XML_END();
267  return rc;
268 }
269 
270 static hpd_error_t rest_xml_add_value(mxml_node_t *parent, char *value, const hpd_module_t *context)
271 {
272  hpd_error_t rc;
273 
274  mxml_node_t *xml;
275  if (!(xml = mxmlNewElement(parent, HPD_REST_KEY_VALUE))) REST_XML_RETURN_XML_ERROR(context);
276 
277  char timestamp[21];
278  if ((rc = hpd_rest_get_timestamp(context, timestamp))) return rc;
279  if ((rc = rest_xml_add(xml, HPD_REST_KEY_TIMESTAMP, timestamp, context))) return rc;
280 
281  if (!mxmlNewText(xml, 0, value)) REST_XML_RETURN_XML_ERROR(context);
282 
283  return HPD_E_SUCCESS;
284 }
285 
287 {
288  REST_XML_BEGIN(context);
289 
290  hpd_error_t rc;
291 
292  mxml_node_t *xml;
293  if (!(xml = mxmlNewXML(REST_XML_VERSION))) {
294  REST_XML_END();
295  REST_XML_RETURN_XML_ERROR(context);
296  }
297 
298  if ((rc = rest_xml_add_value(xml, value, context))) goto error;
299 
300  if (!((*out) = mxmlSaveAllocString(xml, MXML_NO_CALLBACK))) {
301  mxmlDelete(xml);
302  REST_XML_END();
303  REST_XML_RETURN_XML_ERROR(context);
304  }
305 
306  mxmlDelete(xml);
307  REST_XML_END();
308  return HPD_E_SUCCESS;
309 
310  error:
311  mxmlDelete(xml);
312  REST_XML_END();
313  return rc;
314 }
315 
316 hpd_error_t hpd_rest_xml_parse_value(const char *in, const hpd_module_t *context, char **out)
317 {
318  REST_XML_BEGIN(context);
319 
320  mxml_node_t *xml;
321  if (!(xml = mxmlLoadString(NULL, in, MXML_TEXT_CALLBACK))) {
322  REST_XML_END();
323  HPD_LOG_RETURN(context, HPD_E_ARGUMENT, "XML parsing error");
324  }
325 
326  mxml_node_t *node;
327  node = mxmlFindElement(xml, xml, HPD_REST_KEY_VALUE, NULL, NULL, MXML_DESCEND);
328  if (!node) {
329  mxmlDelete(xml);
330  REST_XML_END();
331  HPD_LOG_RETURN(context, HPD_E_ARGUMENT, "XML parsing error");
332  }
333 
334  size_t len = 1;
335  HPD_CALLOC(*out, len, char);
336  for (node = node->child; node && node->type == MXML_TEXT; node = node->next) {
337  int whitespaces = node->value.text.whitespace;
338  char *string = node->value.text.string;
339  HPD_REALLOC(*out, len + whitespaces + strlen(string), char);
340  for (int i = 0; i < whitespaces; i++) strcat(*out, " ");
341  strcat(*out, string);
342  }
343 
344  mxmlDelete(xml);
345  REST_XML_END();
346  return HPD_E_SUCCESS;
347 
348  alloc_error:
349  mxmlDelete(xml);
350  REST_XML_END();
351  HPD_LOG_RETURN_E_ALLOC(context);
352 }
353 
354 
static const char *const HPD_REST_KEY_CONFIGURATION
Definition: rest_intern.h:49
static hpd_error_t rest_xml_add_value(mxml_node_t *parent, char *value, const hpd_module_t *context)
Definition: rest_xml.c:270
#define hpd_device_foreach_service(RC, SERVICE, DEVICE)
#define HPD_LOG_RETURN(CONTEXT, E, FMT,...)
static const char *const HPD_REST_KEY_VALUE
Definition: rest_intern.h:48
static const char *const HPD_REST_VAL_ASCII
Definition: rest_intern.h:53
#define hpd_service_foreach_parameter(RC, PARAMETER, SERVICE)
static const char *const REST_XML_VERSION
Definition: rest_xml.c:34
data value
Definition: map.c:34
static hpd_error_t rest_xml_add_adapter(mxml_node_t *parent, hpd_adapter_id_t *adapter, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_xml.c:181
#define REST_XML_BEGIN(CONTEXT)
Definition: rest_xml.c:44
static const char *const HPD_REST_KEY_PARAMETER
Definition: rest_intern.h:43
static hpd_error_t rest_xml_add(mxml_node_t *parent, const char *key, const char *val, const hpd_module_t *context)
Definition: rest_xml.c:56
char * url
static hpd_error_t rest_xml_add_configuration(mxml_node_t *parent, hpd_t *hpd, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_xml.c:211
free(data.url)
#define hpd_parameter_foreach_attr(RC, PAIR, ID)
const hpd_module_t * context
Definition: rest.c:57
static const char *const HPD_REST_KEY_URL_ENCODED_CHARSET
Definition: rest_intern.h:46
hpd_error_t hpd_rest_get_timestamp(const hpd_module_t *context, char *str)
Definition: rest.c:115
#define HPD_CALLOC(PTR, NUM, CAST)
Allocates and zeros a structure.
Definition: hpd_common.h:44
#define hpd_service_foreach_attr(RC, PAIR, ID)
static const char *const HPD_REST_KEY_DEVICE
Definition: rest_intern.h:45
#define hpd_device_foreach_attr(RC, PAIR, ID)
hpd_error_t hpd_adapter_get_id(const hpd_adapter_id_t *aid, const char **id)
[id_t functions]
#define REST_XML_RETURN_XML_ERROR(CONTEXT)
Definition: rest_xml.c:54
hpd_error_t hpd_parameter_get_id(const hpd_parameter_id_t *pid, const char **id)
[hpd_service_t functions]
static const char *const HPD_REST_KEY_ID
Definition: rest_intern.h:39
hpd_error_t hpd_device_get_id(const hpd_device_id_t *did, const char **id)
[hpd_adapter_t functions]
#define hpd_adapter_foreach_device(RC, DEVICE, ADAPTER)
data key
#define hpd_service_foreach_action(RC, ACTION, ID)
[hpd_parameter_t functions]
static const char *const HPD_REST_KEY_GET
Definition: rest_intern.h:41
hpd_error_t hpd_service_get_id(const hpd_service_id_t *sid, const char **id)
[hpd_device_t functions]
static const hpd_module_t * rest_xml_global_context
Definition: rest_xml.c:37
static const char *const HPD_REST_KEY_SERVICE
Definition: rest_intern.h:44
enum hpd_error hpd_error_t
Definition: hpd_types.h:167
#define HPD_LOG_RETURN_E_ALLOC(CONTEXT)
static const char *const HPD_REST_KEY_PUT
Definition: rest_intern.h:42
static hpd_error_t rest_xml_add_attr(mxml_node_t *parent, hpd_pair_t *pair, const hpd_module_t *context)
Definition: rest_xml.c:63
static const char *const HPD_REST_VAL_TRUE
Definition: rest_intern.h:52
static void rest_xml_on_mxml_error(const char *msg)
Definition: rest_xml.c:39
Definition: daemon.h:50
static const char *const HPD_REST_KEY_ADAPTER
Definition: rest_intern.h:47
Definition: rest.c:53
static const char *const HPD_REST_KEY_URI
Definition: rest_intern.h:40
hpd_error_t hpd_rest_url_create(hpd_rest_t *rest, hpd_service_id_t *service, char **url)
Definition: rest.c:124
hpd_error_t hpd_action_get_method(const hpd_action_t *action, hpd_method_t *method)
[model foreach loops]
#define REST_XML_END()
Definition: rest_xml.c:50
hpd_error_t hpd_rest_xml_get_configuration(hpd_t *hpd, hpd_rest_t *rest, const hpd_module_t *context, char **out)
Definition: rest_xml.c:240
#define hpd_foreach_adapter(RC, ADAPTER, HPD)
[Browsing functions]
static hpd_error_t rest_xml_add_parameter(mxml_node_t *parent, hpd_parameter_id_t *parameter, const hpd_module_t *context)
Definition: rest_xml.c:74
hpd_error_t hpd_pair_get(const hpd_pair_t *pair, const char **key, const char **value)
Definition: map.c:229
hpd_error_t hpd_rest_xml_get_value(char *value, const hpd_module_t *context, char **out)
Definition: rest_xml.c:286
static hpd_error_t rest_xml_add_service(mxml_node_t *parent, hpd_service_id_t *service, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_xml.c:96
#define HPD_REALLOC(PTR, NUM, CAST)
CAST is for c++ compatibility (tests).
Definition: hpd_common.h:52
enum hpd_method hpd_method_t
[hpd_log_level_t]
Definition: hpd_types.h:166
hpd_error_t hpd_rest_xml_parse_value(const char *in, const hpd_module_t *context, char **out)
Definition: rest_xml.c:316
static hpd_error_t rest_xml_add_device(mxml_node_t *parent, hpd_device_id_t *device, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_xml.c:152
static const char *const HPD_REST_KEY_TIMESTAMP
Definition: rest_intern.h:50
#define HPD_LOG_DEBUG(CONTEXT, FMT,...)
#define hpd_adapter_foreach_attr(RC, PAIR, ID)