MHEG5  18.9.0
MHEG5 Documentation
mh5json.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2010 Ocean Blue Software Ltd
4  *
5  * This file is part of a DTVKit Software Component
6  * You are permitted to copy, modify or distribute this file subject to the terms
7  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
8  *
9  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
10  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * If you or your organisation is not a member of DTVKit then you have access
14  * to this source code outside of the terms of the licence agreement
15  * and you are expected to delete this and any associated files immediately.
16  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
17  *******************************************************************************/
25 /*---includes for this file--------------------------------------------------*/
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "mh5debug.h"
31 #include "mh5json.h"
32 
33 #include "mh5memory.h" /*for string memory alloc*/
34 
35 /*---constant definitions for this file--------------------------------------*/
36 #define SPECIAL_CHARS "{}[]:,\" \n\r\t"
37 #define OPEN_CURLY '{'
38 #define CLSE_CURLY '}'
39 #define OPEN_SQUARE '['
40 #define CLSE_SQUARE ']'
41 #define COMMA ','
42 #define DBLE_QUOTE '\"'
43 
44 #define MIN_AFTER_TOKEN 6
45 #define NEXT_CHAR(p, l) p++; l--;
46 #define SKIP_TO_CHAR(p, l, c) do { NEXT_CHAR(p, l) } while (*p != c && l != 0)
47 #define SKIP_DATA(pc, lt) while (lt != 0 && strchr(special_chars, *pc) == NULL) { NEXT_CHAR(pc, lt) }
48 #define SKIP_SPACES(pc, lt) while (lt != 0 && (*pc == ' ' || *pc == '\n' || *pc == '\r' || *pc == '\t')) { NEXT_CHAR(pc, lt) }
49 #define TPARSE TSTATE
50 
51 /*---local typedef structs for this file-------------------------------------*/
52 
53 /*---local (static) variable declarations for this file----------------------*/
54 static const char *const special_chars = SPECIAL_CHARS;
55 
56 /*---local function prototypes for this file---------------------------------*/
57 
58 static E_JSON_STATE ParseJsonObject( char **ppData, U32BIT *pLeft,
59  const S_JSON_MEMBERS *members, void *usr );
60 static E_JSON_STATE ParseJsonMember( char **ppData, U32BIT *pLeft,
61  const S_JSON_MEMBERS *members, void *usr );
62 
63 static unsigned int JsonArrayCount( char *pData, U32BIT Left );
64 
65 static void ParseJsonArrayObject( char **ppData, U32BIT *pLeft,
66  const S_JSON_MEMBERS *members, void *usr );
67 
68 /*---global function definitions---------------------------------------------*/
69 
78 E_JSON_STATE JSON_Parse( U8BIT *data, U32BIT size, const S_JSON_MEMBERS *members, void *usr )
79 {
80  char *in_data = (char *)data;
81  U32BIT left = size;
82 
83  return ParseJsonObject( &in_data, &left, members, usr );
84 }
85 
90 void JSON_FreeAstring( S_STRING *p_str )
91 {
92  assert( p_str != NULL );
93  STR_DataFree( p_str->zptr, p_str->zlen );
94 }
95 
100 void JSON_FreeUintArray( U32BIT *p_uint )
101 {
102 }
103 
110 void JSON_FreeStrArray( S_STRING **pp_str )
111 {
112 }
113 
114 /*---local function definitions----------------------------------------------*/
115 
116 
126 static E_JSON_STATE ParseJsonMember( char **ppData, U32BIT *pLeft,
127  const S_JSON_MEMBERS *members, void *usr )
128 {
129  const S_JSON_MEMBERS *pMmber = members;
130  E_JSON_STATE state = JSON_ERROR;
131  char *pData = *ppData;
132  U32BIT left = *pLeft;
133  unsigned int value;
134 
135  if (*pData == DBLE_QUOTE && left > MIN_AFTER_TOKEN)
136  {
137  NEXT_CHAR(pData, left)
138  /* search for known token in array */
139  while (pMmber->tk_len != 0 &&
140  (pData[pMmber->tk_len] != DBLE_QUOTE || memcmp(pData, pMmber->tk_str, pMmber->tk_len)))
141  {
142  pMmber++;
143  }
144  /* Note: here, if token is not recogised, then pMmber->tk_len==0 and pMmber->u.ptr==NULL */
145 
146  SKIP_TO_CHAR( pData, left, DBLE_QUOTE); /* move past token - recognised or not */
147  NEXT_CHAR(pData, left) /* move past double quote */
148  SKIP_SPACES(pData, left)
149 
150  if (*pData == ':' && left > 1)
151  {
152  NEXT_CHAR(pData, left) /* move past colon */
153  SKIP_SPACES(pData, left)
154  switch (*pData)
155  {
156  default:
157  if (*pData >= '0' && *pData <= '9') /* Integer */
158  {
159  value = 0;
160  do
161  {
162  value *= 10;
163  value += *pData - '0';
164  NEXT_CHAR(pData, left)
165  }
166  while (*pData >= '0' && *pData <= '9' && left != 0);
167  if (pMmber->u.ptr != NULL)
168  {
169  switch (pMmber->type)
170  {
171  case JST_PTR_INTEGER:
172  *pMmber->u.p_uint = value;
173  break;
174  case JST_CBF_INTEGER:
175  (void)(pMmber->u.cb_func)( value, NULL, usr );
176 
177  default:;
178  }
179  }
180  state = JSON_NEXT;
181  }
182  else
183  {
184  SKIP_DATA(pData, left)
185  }
186  break;
187 
188  case DBLE_QUOTE: /*string*/
189  {
190  char *pStr = pData + 1;
191  do
192  {
193  NEXT_CHAR(pData, left)
194  }
195  while (*pData != DBLE_QUOTE && left != 0);
196  if (*pData == DBLE_QUOTE)
197  {
198  if (pMmber->u.ptr != NULL)
199  {
200  value = (unsigned int)(pData - pStr); /* string length */
201  switch (pMmber->type)
202  {
203  case JST_PTR_STRING:
204  pMmber->u.p_str->zlen = value;
205  pMmber->u.p_str->zptr = (U8BIT *)pStr;
206  break;
207 
208  case JST_CBF_STRING:
209  (void)(pMmber->u.cb_func)( value, pStr, usr );
210  break;
211 
212  case JST_PTR_ASTRING:
213  case JST_CBF_ASTRING:
214  {
215  U8BIT *pAstr = STR_DataAlloc( value );
216  if (pAstr != NULL)
217  {
218  memcpy(pAstr, pStr, value);
219  assert(pAstr[value] == 0); /* done by STR_DataAlloc */
220  if (pMmber->type == JST_PTR_ASTRING)
221  {
222  assert(pMmber->u.p_str->zptr == NULL);
223  pMmber->u.p_str->zlen = value;
224  pMmber->u.p_str->zptr = pAstr;
225  }
226  else
227  {
228  (void)(pMmber->u.cb_func)( value, pAstr, usr );
229  }
230  }
231  }
232  break;
233 
234  default:;
235  }
236  }
237  if (left != 0)
238  {
239  NEXT_CHAR(pData, left) /*move pass the second double quote*/
240  }
241  state = JSON_NEXT;
242  }
243  }
244  break;
245 
246  case OPEN_SQUARE: /*array of...*/
247  {
248  NEXT_CHAR(pData, left) /* move pass opening square bracket */
249  SKIP_SPACES(pData, left)
250 
251  if (pMmber->u.ptr != NULL || pMmber->pChildren != NULL)
252  {
253  switch (pMmber->type)
254  {
255  case JST_CBF_ARRAY_OBJ:
256  ParseJsonArrayObject( &pData, &left, pMmber, usr );
257  break;
258  case JST_CBF_ARRAY_INT: /*not supported*/
259  case JST_CBF_ARRAY_STR: /*not supported*/
260  default:;
261  }
262  }
263  /* Skip to end of array - required if there was an error in parsing array */
264  while (*pData != CLSE_SQUARE && left != 0)
265  {
266  NEXT_CHAR(pData, left)
267  }
268  if (left != 0)
269  {
270  NEXT_CHAR(pData, left) /* move pass closing square bracket */
271  }
272  state = JSON_NEXT;
273  }
274  break;
275 
276  case OPEN_CURLY:
277  if (pMmber->type != JST_CBF_OBJECT ||
278  pMmber->pChildren == NULL)
279  {
280  state = JSON_ERROR;
281  }
282  else
283  {
284  state = ParseJsonObject( &pData, &left, pMmber->pChildren, usr );
285  }
286  break;
287  }
288  }
289  *ppData = pData;
290  *pLeft = left;
291  }
292  return state;
293 }
294 
304 static E_JSON_STATE ParseJsonObject( char **ppData, U32BIT *pLeft,
305  const S_JSON_MEMBERS *members, void *usr )
306 {
307  E_JSON_STATE state;
308  char *pData = *ppData;
309  U32BIT left = *pLeft;
310 
311  SKIP_SPACES(pData, left)
312 
313  if (*pData == OPEN_CURLY && left > MIN_AFTER_TOKEN)
314  {
315  NEXT_CHAR(pData, left)
316  SKIP_SPACES(pData, left)
317  state = JSON_MAIN;
318  assert( members->type != JST_CBF_OBJECT );
319 
320  while (left > 0 && state > JSON_OKAY)
321  {
322  switch (*pData)
323  {
324  case DBLE_QUOTE:
325  if (state == JSON_MAIN)
326  {
327  state = ParseJsonMember( &pData, &left, members, usr );
328  }
329  else
330  {
331  TRACE(TERROR, (""))
332  state = JSON_ERROR;
333  }
334  break;
335 
336  case COMMA:
337  if (state == JSON_NEXT)
338  {
339  state = JSON_MAIN;
340  NEXT_CHAR(pData, left)
341  }
342  else
343  {
344  TRACE(TERROR, (""))
345  state = JSON_ERROR;
346  }
347  break;
348 
349  case CLSE_CURLY:
350  if (state == JSON_NEXT)
351  {
352  state = JSON_OKAY;
353  NEXT_CHAR(pData, left)
354  }
355  else
356  {
357  TRACE(TERROR, (""))
358  state = JSON_ERROR;
359  }
360  break;
361 
362  default:
363  TRACE(TERROR, (""))
364  state = JSON_ERROR;
365  }
366  SKIP_SPACES(pData, left)
367  }
368  }
369  else
370  {
371  TRACE(TERROR, (""))
372  state = JSON_ERROR;
373  }
374  *ppData = pData;
375  *pLeft = left;
376  return state;
377 }
378 
385 static unsigned int JsonArrayCount( char *pData, U32BIT left )
386 {
387  unsigned int count = 0;
388  int has_content = 0;
389 
390  while (left > 0 && *pData != CLSE_SQUARE)
391  {
392  switch (*pData)
393  {
394  case DBLE_QUOTE: /* Array of string */
395  do
396  {
397  NEXT_CHAR(pData, left)
398  }
399  while (left > 0 && *pData != DBLE_QUOTE);
400  has_content = 1;
401  break;
402 
403  case OPEN_CURLY: /* Array of object */
404  do
405  {
406  NEXT_CHAR(pData, left)
407  }
408  while (left > 0 && *pData != CLSE_CURLY);
409  has_content = 1;
410  break;
411 
412  default: /* Array of integer (or special_consts - not supported yet) */
413  if (*pData >= '0' && *pData <= '9')
414  {
415  has_content = 1;
416  }
417  break;
418 
419  case COMMA: /* value separator */
420  has_content = 0;
421  count++;
422  break;
423  }
424  NEXT_CHAR(pData, left)
425  }
426  if (has_content)
427  {
428  count++;
429  }
430  return count;
431 }
432 
440 static void ParseJsonArrayObject( char **ppData, U32BIT *pLeft,
441  const S_JSON_MEMBERS *pMmber, void *usr )
442 {
443  E_JSON_STATE state;
444  char *pData = *ppData;
445  U32BIT left = *pLeft;
446 
447  /* First tell callback how many object items */
448  if (pMmber->u.cb_func != NULL)
449  {
450  usr = (pMmber->u.cb_func)( JsonArrayCount(pData, left), NULL, usr );
451  }
452 
453  state = JSON_MAIN;
454  while (left > 0 && state > JSON_OKAY)
455  {
456  switch (*pData)
457  {
458  case OPEN_CURLY:
459  {
460  const S_JSON_MEMBERS *pChild = pMmber->pChildren;
461 
462  if (state == JSON_MAIN &&
463  ParseJsonObject( &pData, &left, (pChild->type == JST_CBF_OBJECT) ? (pChild + 1) : pChild, usr ) == JSON_OKAY)
464  {
465  /* finished object - check to see if there is callback for it */
466  if (pChild->type == JST_CBF_OBJECT && pChild->u.ptr != NULL)
467  {
468  usr = (pChild->u.cb_func)( JSON_VALUE_FINISH, NULL, usr );
469  }
470  state = JSON_NEXT;
471  }
472  else
473  {
474  TRACE(TERROR, (""))
475  while (*pData != CLSE_CURLY && left != 0)
476  {
477  NEXT_CHAR(pData, left)
478  }
479  state = JSON_ERROR;
480  }
481  }
482  break;
483 
484  case COMMA:
485  if (state == JSON_NEXT)
486  {
487  state = JSON_MAIN;
488  NEXT_CHAR(pData, left)
489  }
490  else
491  {
492  TRACE(TERROR, (""))
493  state = JSON_ERROR;
494  }
495  break;
496 
497  case CLSE_SQUARE:
498  if (state == JSON_NEXT)
499  {
500  /*close this array*/
501  state = JSON_OKAY;
502  }
503  else
504  {
505  TRACE(TERROR, (""))
506  state = JSON_ERROR;
507  }
508  break;
509 
510  default:
511  TRACE(TERROR, (""))
512  state = JSON_ERROR;
513  }
514  SKIP_SPACES(pData, left)
515  }
516  if (pMmber->u.cb_func != NULL)
517  {
518  (pMmber->u.cb_func)((state == JSON_OKAY) ? JSON_VALUE_FINISH : JSON_VALUE_ERROR, NULL, usr );
519  }
520  *ppData = pData;
521  *pLeft = left;
522 }
523 
const char * tk_str
Definition: mh5json.h:107
#define SKIP_DATA(pc, lt)
Definition: mh5json.c:47
#define JSON_VALUE_FINISH
Definition: mh5json.h:34
#define SKIP_TO_CHAR(p, l, c)
Definition: mh5json.c:46
void JSON_FreeStrArray(S_STRING **pp_str)
Definition: mh5json.c:110
union s_json_members::@9 u
const char * data
Definition: mh5gate.c:56
#define SPECIAL_CHARS
Definition: mh5json.c:36
void * ptr
Definition: mh5json.h:111
#define OPEN_CURLY
Definition: mh5json.c:37
unsigned char * STR_DataAlloc(unsigned int size)
Definition: glue_memory.c:596
#define DBLE_QUOTE
Definition: mh5json.c:42
E_JSON_STATE JSON_Parse(U8BIT *data, U32BIT size, const S_JSON_MEMBERS *members, void *usr)
Definition: mh5json.c:78
unsigned int tk_len
Definition: mh5json.h:106
#define JSON_VALUE_ERROR
Definition: mh5json.h:35
#define CLSE_SQUARE
Definition: mh5json.c:40
U8BIT * zptr
Definition: dtvstring.h:31
#define NEXT_CHAR(p, l)
Definition: mh5json.c:45
#define CLSE_CURLY
Definition: mh5json.c:38
uint8_t U8BIT
Definition: techtype.h:82
#define SKIP_SPACES(pc, lt)
Definition: mh5json.c:48
#define COMMA
Definition: mh5json.c:41
#define OPEN_SQUARE
Definition: mh5json.c:39
#define MIN_AFTER_TOKEN
Definition: mh5json.c:44
void STR_DataFree(unsigned char *data, unsigned int size)
Definition: glue_memory.c:668
E_JSON_TYPE type
Definition: mh5json.h:108
void JSON_FreeUintArray(U32BIT *p_uint)
Definition: mh5json.c:100
Mheg5 logging and debug printing.
redirection include
void JSON_FreeAstring(S_STRING *p_str)
Definition: mh5json.c:90
string parsing utility functions described by the [JSON] schema
const struct s_json_members * pChildren
Definition: mh5json.h:116
U32BIT zlen
Definition: dtvstring.h:30
S_STRING * p_str
Definition: mh5json.h:114
uint32_t U32BIT
Definition: techtype.h:86
E_JSON_STATE
Definition: mh5json.h:66
JsonCallback cb_func
Definition: mh5json.h:112
#define TRACE(t, x)
Definition: glue_debug.h:118
U32BIT * p_uint
Definition: mh5json.h:113