Contiki-NG
lwm2m-json.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, Eistec AB.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /**
32  * \addtogroup lwm2m
33  * @{
34  */
35 
36 /**
37  * \file
38  * Implementation of the Contiki OMA LWM2M JSON writer
39  * \author
40  * Joakim NohlgĂ„rd <joakim.nohlgard@eistec.se>
41  * Joakim Eriksson <joakime@sics.se> added JSON reader parts
42  */
43 
44 #include "lwm2m-object.h"
45 #include "lwm2m-json.h"
46 #include "lwm2m-plain-text.h"
47 #include <stdio.h>
48 #include <stddef.h>
49 #include <stdint.h>
50 #include <inttypes.h>
51 
52 /* Log configuration */
53 #include "coap-log.h"
54 #define LOG_MODULE "lwm2m-json"
55 #define LOG_LEVEL LOG_LEVEL_NONE
56 /*---------------------------------------------------------------------------*/
57 
58 /* {"e":[{"n":"111/1","v":123},{"n":"111/2","v":42}]} */
59 
60 /* Begin String */
61 #define T_NONE 0
62 #define T_STRING_B 1
63 #define T_STRING 2
64 #define T_NAME 4
65 #define T_VNUM 5
66 #define T_OBJ 6
67 #define T_VAL 7
68 
69 /* Simlified JSON style reader for reading in values from a LWM2M JSON
70  string */
71 int
72 lwm2m_json_next_token(lwm2m_context_t *ctx, struct json_data *json)
73 {
74  int pos = ctx->inbuf->pos;
75  uint8_t type = T_NONE;
76  uint8_t vpos_start = 0;
77  uint8_t vpos_end = 0;
78  uint8_t cont;
79  uint8_t wscount = 0;
80 
81  json->name_len = 0;
82  json->value_len = 0;
83 
84  cont = 1;
85  /* We will be either at start, or at a specific position */
86  while(pos < ctx->inbuf->size && cont) {
87  uint8_t c = ctx->inbuf->buffer[pos++];
88  switch(c) {
89  case '{': type = T_OBJ; break;
90  case '}':
91  case ',':
92  if(type == T_VAL || type == T_STRING) {
93  json->value = &ctx->inbuf->buffer[vpos_start];
94  json->value_len = vpos_end - vpos_start - wscount;
95  type = T_NONE;
96  cont = 0;
97  }
98  wscount = 0;
99  break;
100  case '\\':
101  /* stuffing */
102  if(pos < ctx->inbuf->size) {
103  pos++;
104  vpos_end = pos;
105  }
106  break;
107  case '"':
108  if(type == T_STRING_B) {
109  type = T_STRING;
110  vpos_end = pos - 1;
111  wscount = 0;
112  } else {
113  type = T_STRING_B;
114  vpos_start = pos;
115  }
116  break;
117  case ':':
118  if(type == T_STRING) {
119  json->name = &ctx->inbuf->buffer[vpos_start];
120  json->name_len = vpos_end - vpos_start;
121  vpos_start = vpos_end = pos;
122  type = T_VAL;
123  } else {
124  /* Could be in string or at illegal pos */
125  if(type != T_STRING_B) {
126  LOG_DBG("ERROR - illegal ':'\n");
127  }
128  }
129  break;
130  /* ignore whitespace */
131  case ' ':
132  case '\n':
133  case '\t':
134  if(type != T_STRING_B) {
135  if(vpos_start == pos - 1) {
136  vpos_start = pos;
137  } else {
138  wscount++;
139  }
140  }
141  default:
142  vpos_end = pos;
143  }
144  }
145 
146  if(cont == 0 && pos < ctx->inbuf->size) {
147  ctx->inbuf->pos = pos;
148  }
149  /* OK if cont == 0 othewise we failed */
150  return cont == 0 && pos < ctx->inbuf->size;
151 }
152 /*---------------------------------------------------------------------------*/
153 static size_t
154 init_write(lwm2m_context_t *ctx)
155 {
156  int len = snprintf((char *)&ctx->outbuf->buffer[ctx->outbuf->len],
157  ctx->outbuf->size - ctx->outbuf->len, "{\"bn\":\"/%u/%u/\",\"e\":[",
158  ctx->object_id, ctx->object_instance_id);
159  ctx->writer_flags = 0; /* set flags to zero */
160  if((len < 0) || (len >= ctx->outbuf->size)) {
161  return 0;
162  }
163  return len;
164 }
165 /*---------------------------------------------------------------------------*/
166 static size_t
167 end_write(lwm2m_context_t *ctx)
168 {
169  int len = snprintf((char *)&ctx->outbuf->buffer[ctx->outbuf->len],
170  ctx->outbuf->size - ctx->outbuf->len, "]}");
171  if((len < 0) || (len >= ctx->outbuf->size - ctx->outbuf->len)) {
172  return 0;
173  }
174  return len;
175 }
176 /*---------------------------------------------------------------------------*/
177 static size_t
178 enter_sub(lwm2m_context_t *ctx)
179 {
180  /* set some flags in state */
181  LOG_DBG("Enter sub-resource rsc=%d\n", ctx->resource_id);
182  ctx->writer_flags |= WRITER_RESOURCE_INSTANCE;
183  return 0;
184 }
185 /*---------------------------------------------------------------------------*/
186 static size_t
187 exit_sub(lwm2m_context_t *ctx)
188 {
189  /* clear out state info */
190  LOG_DBG("Exit sub-resource rsc=%d\n", ctx->resource_id);
191  ctx->writer_flags &= ~WRITER_RESOURCE_INSTANCE;
192  return 0;
193 }
194 /*---------------------------------------------------------------------------*/
195 static size_t
196 write_boolean(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
197  int value)
198 {
199  char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
200  int len;
201  if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
202  len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"bv\":%s}", sep, ctx->resource_id, ctx->resource_instance_id, value ? "true" : "false");
203  } else {
204  len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"bv\":%s}", sep, ctx->resource_id, value ? "true" : "false");
205  }
206  if((len < 0) || (len >= outlen)) {
207  return 0;
208  }
209  LOG_DBG("JSON: Write bool:%s\n", outbuf);
210 
211  ctx->writer_flags |= WRITER_OUTPUT_VALUE;
212  return len;
213 }
214 /*---------------------------------------------------------------------------*/
215 static size_t
216 write_int(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
217  int32_t value)
218 {
219  char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
220  int len;
221  if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
222  len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"v\":%"PRId32"}", sep, ctx->resource_id, ctx->resource_instance_id, value);
223  } else {
224  len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"v\":%"PRId32"}", sep, ctx->resource_id, value);
225  }
226  if((len < 0) || (len >= outlen)) {
227  return 0;
228  }
229  LOG_DBG("Write int:%s\n", outbuf);
230 
231  ctx->writer_flags |= WRITER_OUTPUT_VALUE;
232  return len;
233 }
234 /*---------------------------------------------------------------------------*/
235 static size_t
236 write_float32fix(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
237  int32_t value, int bits)
238 {
239  char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
240  size_t len = 0;
241  int res;
242  if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
243  res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"v\":", sep, ctx->resource_id, ctx->resource_instance_id);
244  } else {
245  res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"v\":", sep, ctx->resource_id);
246  }
247  if(res <= 0 || res >= outlen) {
248  return 0;
249  }
250  len += res;
251  outlen -= res;
252  res = lwm2m_plain_text_write_float32fix(&outbuf[len], outlen, value, bits);
253  if((res <= 0) || (res >= outlen)) {
254  return 0;
255  }
256  len += res;
257  outlen -= res;
258  res = snprintf((char *)&outbuf[len], outlen, "}");
259  if((res <= 0) || (res >= outlen)) {
260  return 0;
261  }
262  len += res;
263  ctx->writer_flags |= WRITER_OUTPUT_VALUE;
264  return len;
265 }
266 /*---------------------------------------------------------------------------*/
267 static size_t
268 write_string(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
269  const char *value, size_t stringlen)
270 {
271  char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
272  size_t i;
273  size_t len = 0;
274  int res;
275  LOG_DBG("{\"n\":\"%u\",\"sv\":\"", ctx->resource_id);
276  if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
277  res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"sv\":\"", sep,
278  ctx->resource_id, ctx->resource_instance_id);
279  } else {
280  res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"sv\":\"", sep,
281  ctx->resource_id);
282  }
283  if(res < 0 || res >= outlen) {
284  return 0;
285  }
286  len += res;
287  for (i = 0; i < stringlen && len < outlen; ++i) {
288  /* Escape special characters */
289  /* TODO: Handle UTF-8 strings */
290  if(value[i] < '\x20') {
291  LOG_DBG_("\\x%x", value[i]);
292  res = snprintf((char *)&outbuf[len], outlen - len, "\\x%x", value[i]);
293  if((res < 0) || (res >= (outlen - len))) {
294  return 0;
295  }
296  len += res;
297  continue;
298  } else if(value[i] == '"' || value[i] == '\\') {
299  LOG_DBG_("\\");
300  outbuf[len] = '\\';
301  ++len;
302  if(len >= outlen) {
303  return 0;
304  }
305  }
306  LOG_DBG_("%c", value[i]);
307  outbuf[len] = value[i];
308  ++len;
309  if(len >= outlen) {
310  return 0;
311  }
312  }
313  LOG_DBG_("\"}\n");
314  res = snprintf((char *)&outbuf[len], outlen - len, "\"}");
315  if((res < 0) || (res >= (outlen - len))) {
316  return 0;
317  }
318 
319  LOG_DBG("JSON: Write string:%s\n", outbuf);
320 
321  len += res;
322  ctx->writer_flags |= WRITER_OUTPUT_VALUE;
323  return len;
324 }
325 /*---------------------------------------------------------------------------*/
326 const lwm2m_writer_t lwm2m_json_writer = {
327  init_write,
328  end_write,
329  enter_sub,
330  exit_sub,
331  write_int,
332  write_string,
333  write_float32fix,
334  write_boolean
335 };
336 /*---------------------------------------------------------------------------*/
337 
338 /*---------------------------------------------------------------------------*/
339 /** @} */
Log support for CoAP
Header file for the LWM2M object API
Header file for the Contiki OMA LWM2M plain text reader / writer
Header file for the Contiki OMA LWM2M JSON writer