MHEG5  18.9.0
MHEG5 Documentation
mh5parse.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2009 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 "mh5parse.h"
27 #include "glue_assert.h"
28 #include "glue_memory.h"
29 #include "mh5group.h"
30 #include "mh5json.h"
31 
32 #define BKG_TITLE_TOKEN "t"
33 #define BKG_BOOKING_TOKEN "b"
34 #define BKG_CRIDTYPE_TOKEN "ct"
35 #define BKG_SYNOPSIS_TOKEN "s"
36 #define BKG_LOCATION_TOKEN "l"
37 #define BKG_DVB_TOKEN "dvb://"
38 
39 #define BKG_CRID_TTL_STRING "{\"ct\":\"49\",\"t\":\""
40 #define BKG_SYNOPSIS_STRING "\",\"s\":\""
41 #define BKG_BOOKING_PREFIX "\",\"b\":["
42 #define BKG_LOCATION_PREFIX "\"l\":\"dvb://"
43 #define BKG_DURATION_PREFIX "--PT"
44 #define BKG_BOOKING_ENDFIX "]}"
45 
46 #define MAX_INT_LENGTH 32
47 #define MIN_DATA_BLOCK 32
48 
49 
50 static MHEG5Bool EncodeOctetString(MHEG5Byte **buffer, MHEG5Int *used,
51  MHEG5Int *allocated, MHEG5Byte *data,
52  MHEG5Int len);
53 static MHEG5Bool EncodeChar(MHEG5Byte **buffer, MHEG5Int *used,
54  MHEG5Int *allocated, MHEG5Byte ch);
55 static MHEG5Bool AppendString(MHEG5Byte **buffer, MHEG5Int *used,
56  MHEG5Int *allocated, MHEG5Byte *data,
57  MHEG5Int len);
58 static MHEG5Bool AppendInteger(MHEG5Byte **buffer, MHEG5Int *used,
59  MHEG5Int *allocated, MHEG5Int value);
60 static MHEG5Bool AppendChar(MHEG5Byte **buffer, MHEG5Int *used,
61  MHEG5Int *allocated, MHEG5Byte ch);
62 
63 #ifdef INCLUDE_IC
64 static MHEG5Bool AddOctetString(MHEG5Byte **buffer, MHEG5Int *used,
65  MHEG5Int *allocated, MHEG5Byte *data,
66  MHEG5Int len);
67 static MHEG5Bool AddEncodedChar(MHEG5Byte **buffer, MHEG5Int *used,
68  MHEG5Int *allocated, MHEG5Byte ch);
69 #endif /* INCLUDE_IC */
70 
71 
72 #ifdef INCLUDE_PVR_AU
73 
74 /* JSON callbacks */
75 static void* NewLocation( unsigned int val, void *array, void *cptr );
76 static void* BookingArray( unsigned int val, void *array, void *cptr );
77 static void* DoneLocation( unsigned int val, void *array, void *cptr );
78 
79 static S_STRING title_str;
80 static S_STRING synop_str;
81 static S_STRING ctype_str;
82 static S_BOOKING **p_booking_ptr = NULL;
83 
84 static const S_JSON_MEMBERS booking_members[] = {
85  DECLARE_OBJECT( DoneLocation ),
86  DECLARE_MEMBER( BKG_LOCATION_TOKEN, JST_CBF_STRING, NewLocation, NULL ),
88 };
89 
90 static const S_JSON_MEMBERS crid_members[] = {
91  DECLARE_MEMBER( BKG_CRIDTYPE_TOKEN, JST_PTR_STRING, &ctype_str, NULL ),
92  DECLARE_MEMBER( BKG_TITLE_TOKEN, JST_PTR_ASTRING, &title_str, NULL ),
94  DECLARE_MEMBER( BKG_BOOKING_TOKEN, JST_CBF_ARRAY_OBJ, BookingArray, booking_members ),
96 };
97 
98 #endif /*INCLUDE_PVR_AU*/
99 
100 
108 static MHEG5Bool MHEG5IsDigit(U32BIT ch, U32BIT base, U32BIT *value)
109 {
110  MHEG5Bool rc = MHEG5FALSE;
111 
112  if (ch >= '0' && ch <= '9')
113  {
114  if (ch - '0' < base)
115  {
116  *value = ch - '0';
117  rc = MHEG5TRUE;
118  }
119  }
120  else if (ch >= 'a' && ch <= 'z')
121  {
122  if (base > 10 && ch - 'a' < base - 10)
123  {
124  *value = ch - 'a' + 10;
125  rc = MHEG5TRUE;
126  }
127  }
128  else if (ch >= 'A' && ch <= 'Z')
129  {
130  if (base > 10 && ch - 'A' < base - 10)
131  {
132  *value = ch - 'A' + 10;
133  rc = MHEG5TRUE;
134  }
135  }
136 
137  return rc;
138 }
139 
154 {
155  U32BIT originalNetworkId = 0;
156  U32BIT transportStreamId = 0;
157  U32BIT serviceId = 0;
158  U32BIT value, ndx = 0;
159  MHEG5Bool rtn_val = MHEG5TRUE;
160  enum {ST_FIRST_DIGIT, ST_FIRST_NUMBER, ST_FIRST_DOT,
161  ST_SECOND_NUMBER, ST_SECOND_DOT,
162  ST_THIRD_NUMBER, ST_END, ST_ERROR} state = ST_FIRST_DIGIT;
163 
164  /* URL is dvb://<original network id>.[<transport stream id>].<service id> */
165 
166  while (ndx != length && state != ST_ERROR)
167  {
168  switch (state)
169  {
170  case ST_FIRST_DIGIT:
171  if (!MHEG5IsDigit(buffer[ndx], 16, &value))
172  {
173  state = ST_ERROR;
174  }
175  else
176  {
177  originalNetworkId = value;
178  state = ST_FIRST_NUMBER;
179  }
180  break;
181  case ST_FIRST_NUMBER:
182  if (buffer[ndx] == '.')
183  {
184  state = ST_FIRST_DOT;
185  }
186  else if (!MHEG5IsDigit(buffer[ndx], 16, &value))
187  {
188  state = ST_ERROR;
189  }
190  else
191  {
192  originalNetworkId *= 16;
193  originalNetworkId += value;
194  }
195  break;
196  case ST_FIRST_DOT:
197  if (buffer[ndx] == '.')
198  {
199  state = ST_SECOND_DOT;
200  }
201  else if (!MHEG5IsDigit(buffer[ndx], 16, &value))
202  {
203  state = ST_ERROR;
204  }
205  else
206  {
207  transportStreamId = value;
208  state = ST_SECOND_NUMBER;
209  }
210  break;
211  case ST_SECOND_NUMBER:
212  if (buffer[ndx] == '.')
213  {
214  state = ST_SECOND_DOT;
215  }
216  else if (!MHEG5IsDigit(buffer[ndx], 16, &value))
217  {
218  state = ST_ERROR;
219  }
220  else
221  {
222  transportStreamId *= 16;
223  transportStreamId += value;
224  }
225  break;
226  case ST_SECOND_DOT:
227  if (!MHEG5IsDigit(buffer[ndx], 16, &value))
228  {
229  state = ST_ERROR;
230  }
231  else
232  {
233  serviceId = value;
234  state = ST_THIRD_NUMBER;
235  }
236  break;
237  case ST_THIRD_NUMBER:
238  if (!MHEG5IsDigit(buffer[ndx], 16, &value))
239  {
240  state = ST_ERROR;
241  }
242  else
243  {
244  serviceId *= 16;
245  serviceId += value;
246  }
247  break;
248  default:
249  /* case ST_END, and case ST_ERROR tested outside of switch */
250  ;
251  }
252  ++ndx;
253  }
254  if (state == ST_THIRD_NUMBER)
255  {
256  dvb_loc->original_network_id = (U16BIT)originalNetworkId;
257  dvb_loc->transport_stream_id = (U16BIT)transportStreamId;
258  dvb_loc->service_id = (U16BIT)serviceId;
259  }
260  else
261  {
262  rtn_val = MHEG5FALSE;
263  }
264  return rtn_val;
265 }
266 
267 int MHEG5parseLcn( U8BIT *buf, U8BIT *end )
268 {
269  U8BIT *p;
270  U32BIT value;
271  int lcn = 0;
272 
273  for (p = buf; p != end; p++)
274  {
275  if (MHEG5IsDigit(*p, 10, &value))
276  {
277  lcn = (lcn * 10) + value;
278  }
279  else
280  {
281  break;
282  }
283  }
284  if (p == end)
285  {
286  return lcn;
287  }
288  return -1;
289 }
290 
291 #ifdef INCLUDE_PVR_AU
292 
293 static int ParseLocation( char *in_data, int chrs_left, S_LOCATION *p_loc )
294 {
295  int posn = 0, value;
296 
297  while (posn != chrs_left && in_data[posn] != '@')
298  posn++;
299 
300  if (posn == chrs_left ||
301  strncmp((char *)in_data, (char *)"dvb://", 6) != 0 ||
302  !MHEG5parseDvbUrl((U8BIT *)in_data + 6, posn - 6, &p_loc->dvb_loc ))
303  {
304  posn = -1;
305  }
306  else
307  {
308  int count = 0;
309  posn++;
310  value = 0;
311  while (posn < chrs_left && in_data[posn] != '\"')
312  {
313  if (in_data[posn] >= '0' && in_data[posn] <= '9')
314  {
315  switch (count)
316  {
317  /*YEAR*/
318  case 0: value = (int)(in_data[posn] - '0'); break;
319  case 1: case 2:
320  value = (value * 10) + (int)(in_data[posn] - '0');
321  break;
322  case 3:
323  p_loc->date.year = (value * 10) + (int)(in_data[posn] - '0');
324  break;
325  /*MONTH*/
326  case 4: value = (int)(in_data[posn] - '0'); break;
327  case 5:
328  p_loc->date.month = (value * 10) + (int)(in_data[posn] - '0');
329  break;
330  /*DAY*/
331  case 6: value = (int)(in_data[posn] - '0'); break;
332  case 7:
333  p_loc->date.day = (value * 10) + (int)(in_data[posn] - '0');
334  break;
335  /*TIME-HOUR*/
336  case 9: value = (int)(in_data[posn] - '0'); break;
337  case 10:
338  p_loc->time.hour = (value * 10) + (int)(in_data[posn] - '0');
339  break;
340  /*TIME-MINUTE*/
341  case 12: value = (int)(in_data[posn] - '0'); break;
342  case 13:
343  p_loc->time.minute = (value * 10) + (int)(in_data[posn] - '0');
344  break;
345  /*DURATION-HOUR*/
346  case 17: value = (int)(in_data[posn] - '0'); break;
347  case 18:
348  p_loc->duration.hour = (value * 10) + (int)(in_data[posn] - '0');
349  break;
350  /*DURATION-MINUTE*/
351  case 20: value = (int)(in_data[posn] - '0'); break;
352  case 21:
353  p_loc->duration.minute = (value * 10) + (int)(in_data[posn] - '0');
354  break;
355  default:
356  TRACE(TERROR, ("%c count=%d", in_data[posn], count))
357  posn = chrs_left;
358  break;
359  }
360  }
361  else
362  {
363  switch (count)
364  {
365  case 8:
366  if (in_data[posn] != 'T')
367  {
368  TRACE(TERROR, ("%c %d", in_data[posn], in_data[posn]))
369  posn = chrs_left;
370  }
371  break;
372  case 11:
373  case 17:
374  if (in_data[posn] != ':')
375  {
376  TRACE(TERROR, ("%c %d", in_data[posn], in_data[posn]))
377  posn = chrs_left;
378  }
379  break;
380  case 14:
381  if (in_data[posn] != '-')
382  {
383  TRACE(TERROR, ("%c %d", in_data[posn], in_data[posn]))
384  posn = chrs_left;
385  }
386  break;
387  case 15:
388  if (in_data[posn] != 'P')
389  {
390  TRACE(TERROR, ("%c %d", in_data[posn], in_data[posn]))
391  posn = chrs_left;
392  }
393  break;
394  case 16:
395  if (in_data[posn] != 'T')
396  {
397  TRACE(TERROR, ("%c %d", in_data[posn], in_data[posn]))
398  posn = chrs_left;
399  }
400  break;
401  case 19:
402  if (in_data[posn] != 'H')
403  {
404  TRACE(TERROR, ("%c %d", in_data[posn], in_data[posn]))
405  posn = chrs_left;
406  }
407  break;
408  case 22:
409  if (in_data[posn] != 'M')
410  {
411  TRACE(TERROR, ("%c %d", in_data[posn], in_data[posn]))
412  posn = chrs_left;
413  }
414  break;
415  default:
416  TRACE(TERROR, ("%c count=%d", in_data[posn], count))
417  posn = chrs_left;
418  break;
419  }
420  }
421  posn++;
422  count++;
423  }
424  if (count < 23)
425  {
426  /*error occured*/
427  posn = -1;
428  }
429  }
430  return posn;
431 }
432 
433 static void* NewLocation( unsigned int val, void *array, void *cptr )
434 {
435  S_LOCATION *pLoc = (S_LOCATION *)cptr;
436 
437  memset( pLoc, 0, sizeof(S_LOCATION));
438  if (ParseLocation((char *)array, val, pLoc ) == -1)
439  {
440  return 0;
441  }
442  return cptr;
443 }
444 
445 static void* DoneLocation( unsigned int val, void *array, void *cptr )
446 {
447  S_LOCATION *pLoc = (S_LOCATION *)cptr;
448  return (void *)(pLoc + 1);
449 }
450 
451 static void* BookingArray( unsigned int val, void *array, void *cptr )
452 {
453  S_BOOKING *pBook;
454 
455  switch (val)
456  {
457  default:
458  /* val is number of booking locations */
459  pBook = MHEG5getMem( sizeof(S_BOOKING) + (val * sizeof(S_LOCATION)));
460  if (pBook != NULL)
461  {
462  *p_booking_ptr = pBook;
463  p_booking_ptr = &(pBook->next);
464  pBook->next = NULL;
465  pBook->num_locs = val;
466  pBook->p_locs = (S_LOCATION *)(pBook + 1);
467  return pBook->p_locs;
468  }
469 
470  case JSON_VALUE_FINISH:
471  TRACE(TERROR, ("Array FINISH"))
472  break;
473 
474  case JSON_VALUE_ERROR:
475  TRACE(TERROR, ("Array ERROR"))
476  break;
477  }
478  return 0;
479 }
480 
481 int MHEG5parseDecodeBookings( MHEG5String bookingString, S_CRID_DETAILS *pDetails )
482 { /* Decode string in the format described by the [JSON] schema */
483  int result = FALSE;
484 
485  memset( pDetails, 0, sizeof(S_CRID_DETAILS));
486  p_booking_ptr = &(pDetails->bookings);
487 
488  if (JSON_Parse( bookingString.data, bookingString.len, crid_members, pDetails ) == JSON_OKAY)
489  {
490  if (ctype_str.zlen == 2 && ctype_str.zptr != NULL &&
491  title_str.zptr != NULL && synop_str.zptr != NULL)
492  {
493  if (ctype_str.zptr[0] == '4' && ctype_str.zptr[1] == '9')
494  {
495  result = TRUE;
496  pDetails->type = 49;
497  }
498  else if (ctype_str.zptr[0] == '5' && ctype_str.zptr[1] == '0')
499  {
500  result = TRUE;
501  pDetails->type = 50;
502  }
503  }
504  }
505  ctype_str.zptr = NULL;
506  ctype_str.zlen = 0;
507  pDetails->title = title_str;
508  title_str.zptr = NULL;
509  title_str.zlen = 0;
510  pDetails->description = synop_str;
511  synop_str.zptr = NULL;
512  synop_str.zlen = 0;
513  if (!result)
514  {
515  MHEG5freeDecodeBookings( pDetails );
516  }
517  return result;
518 }
519 
520 void MHEG5freeDecodeBookings( S_CRID_DETAILS *pDetails )
521 {
522  if (pDetails->title.zptr != NULL)
523  {
524  JSON_FreeAstring( &pDetails->title );
525  }
526  if (pDetails->description.zptr != NULL)
527  {
528  JSON_FreeAstring( &pDetails->description );
529  }
530  if (pDetails->bookings != NULL)
531  {
532  S_BOOKING *pNext, *pBook = pDetails->bookings;
533  do
534  {
535  pNext = pBook->next;
536  MHEG5freeMem( pBook );
537  pBook = pNext;
538  }
539  while (pBook != NULL);
540  }
541 }
542 
543 char* ParseCatHexNum( char *p_os, U16BIT num )
544 {
545  const char ch[16] = "0123456789abcdef";
546  if (num > 0x000)
547  {
548  if (num > 0x00f)
549  {
550  if (num > 0x0f0)
551  {
552  if (num > 0xf00)
553  {
554  *p_os = ch[(num >> 12) & 0xf];
555  p_os++;
556  }
557  *p_os = ch[(num >> 8) & 0xf];
558  p_os++;
559  }
560  *p_os = ch[(num >> 4) & 0xf];
561  p_os++;
562  }
563  *p_os = ch[(num >> 0) & 0xf];
564  p_os++;
565  }
566  return p_os;
567 }
568 
569 char* ParseCatDecNum( char *p_os, U16BIT num )
570 {
571  U16BIT n = num, c = 0;
572  char ch[7];
573  while (n != 0)
574  {
575  ch[c++] = (char)(n % 10) + '0';
576  n = n / 10;
577  }
578  while (c < 2)
579  {
580  ch[c++] = '0';
581  }
582  while (c--)
583  {
584  *p_os = ch[c];
585  p_os++;
586  }
587  return p_os;
588 }
589 
590 void MHEG5parseEncodeBooking( S_CRID_DETAILS *pDetails, MHEG5String out_str )
591 {
592  U32BIT n_locs;
593 
594  assert( pDetails );
595  assert( pDetails->bookings );
596 
597  n_locs = pDetails->bookings->num_locs;
598  /* Check that num_locs has some sensible value,
599  * it seems crazy for there to be anywhere near as many as 16 locations for one booking */
600  if (n_locs != 0 && n_locs < 16)
601  {
602  MHEG5Int len;
603 
604  len = sizeof(BKG_CRID_TTL_STRING);
605  len += pDetails->title.zlen;
606  len += sizeof(BKG_SYNOPSIS_STRING);
607  len += pDetails->description.zlen;
608  len += sizeof(BKG_BOOKING_PREFIX);
609  /* 65 is length of '"location":"dvb://233a.1234.5678@20091128T15:00+01:00--PT00H20M",' i.e. max poss for a location */
610  len += 65 * n_locs;
611  len += sizeof(BKG_BOOKING_ENDFIX);
612 
613  out_str.data = (MHEG5Byte *)MHEG5getMem( len );
614 
615  if (out_str.data != NULL)
616  {
617  S_LOCATION *p_loc = pDetails->bookings->p_locs;
618  char *os_data = (char *)out_str.data;
619 
620  len = sizeof(BKG_CRID_TTL_STRING);
621  memcpy(os_data, BKG_CRID_TTL_STRING, len);
622  if (pDetails->type == 50)
623  {
624  while (*os_data != '4')
625  os_data++;
626  *os_data = '5';
627  os_data++;
628  *os_data = '0';
629  os_data = (char *)&out_str.data[len];
630  }
631  else
632  {
633  os_data += len;
634  }
635  memcpy(os_data, pDetails->title.zptr, pDetails->title.zlen);
636  os_data += pDetails->title.zlen;
637 
638  memcpy(os_data, BKG_SYNOPSIS_STRING, sizeof(BKG_SYNOPSIS_STRING));
639  os_data += sizeof(BKG_SYNOPSIS_STRING);
640 
641  memcpy(os_data, pDetails->description.zptr, pDetails->description.zlen);
642  os_data += pDetails->description.zlen;
643 
644  memcpy(os_data, BKG_BOOKING_PREFIX, sizeof(BKG_BOOKING_PREFIX));
645  os_data += sizeof(BKG_BOOKING_PREFIX);
646 
647  do
648  {
649  assert( p_loc->dvb_loc.original_network_id != 0 && p_loc->dvb_loc.service_id != 0 );
650 
651  memcpy(os_data, BKG_LOCATION_PREFIX, sizeof(BKG_LOCATION_PREFIX));
652  os_data += sizeof(BKG_LOCATION_PREFIX);
653 
654  /* dvb location stuff */
655  os_data = ParseCatHexNum( os_data, p_loc->dvb_loc.original_network_id );
656  *os_data = '.';
657  os_data++;
658  os_data = ParseCatHexNum( os_data, p_loc->dvb_loc.transport_stream_id );
659  *os_data = '.';
660  os_data++;
661  os_data = ParseCatHexNum( os_data, p_loc->dvb_loc.service_id );
662  *os_data = '@';
663  os_data++;
664  os_data = ParseCatDecNum( os_data, p_loc->date.year );
665  os_data = ParseCatDecNum( os_data, p_loc->date.month );
666  os_data = ParseCatDecNum( os_data, p_loc->date.day );
667  *os_data = 'T';
668  os_data++;
669  os_data = ParseCatDecNum( os_data, p_loc->time.hour );
670  *os_data = ':';
671  os_data++;
672  os_data = ParseCatDecNum( os_data, p_loc->time.minute );
673  *os_data = '+';
674  os_data++;
675  os_data = ParseCatDecNum( os_data, p_loc->offset.hour );
676  *os_data = ':';
677  os_data++;
678  os_data = ParseCatDecNum( os_data, p_loc->offset.minute );
679 
680  memcpy(os_data, BKG_DURATION_PREFIX, sizeof(BKG_DURATION_PREFIX));
681  os_data += sizeof(BKG_DURATION_PREFIX);
682 
683  os_data = ParseCatDecNum( os_data, p_loc->duration.hour );
684  *os_data = 'H';
685  os_data++;
686  os_data = ParseCatDecNum( os_data, p_loc->duration.minute );
687  *os_data = 'M';
688  os_data++;
689  *os_data = '\"';
690  os_data++;
691  if (n_locs > 1)
692  {
693  *os_data = ',';
694  os_data++;
695  }
696  p_loc++;
697  }
698  while (--n_locs);
699 
700  memcpy(os_data, BKG_BOOKING_ENDFIX, sizeof(BKG_BOOKING_ENDFIX));
701  os_data += sizeof(BKG_BOOKING_ENDFIX);
702 
703  *os_data = 0; /* nul terminate */
704  out_str.len = (int)os_data - (int)out_str.data;
705  }
706  }
707  else
708  {
709  TRACE(TERROR, ("Invalid number of locations %d", n_locs))
710  }
711 }
712 
713 #endif /*INCLUDE_PVR_AU*/
714 
715 
730  MHEG5Int *allocated, MHEG5Generic *value)
731 {
732  MHEG5Bool success;
733  MHEG5Byte *data;
734  MHEG5Int len;
735 
736  switch (value->type)
737  {
738  case MHEG5INT:
739  success = AppendInteger(buffer, used, allocated, value->value.i);
740  break;
741 
742  case MHEG5BOOL:
743  if (value->value.b)
744  {
745  success = AppendString(buffer, used, allocated,
746  (MHEG5Byte *)"True", 4);
747  }
748  else
749  {
750  success = AppendString(buffer, used, allocated,
751  (MHEG5Byte *)"False", 5);
752  }
753  break;
754 
755  case MHEG5OCTETSTRING:
756  success = EncodeOctetString(buffer, used, allocated,
757  value->value.s.data,
758  value->value.s.len);
759  break;
760 
761  case MHEG5CONTENTREF:
762  success = EncodeOctetString(buffer, used, allocated,
763  value->value.s.data,
764  value->value.s.len);
765  break;
766 
767  case MHEG5OBJECTREF:
768  if (value->value.o.gref.len == 0)
769  {
770  data = value->value.o.gref.ptr.group->groupName.data;
771  len = value->value.o.gref.ptr.group->groupName.len;
772  }
773  else
774  {
775  data = value->value.o.gref.ptr.name;
776  len = value->value.o.gref.len;
777  }
778  success = AppendChar(buffer, used, allocated, '(');
779  if (success)
780  {
781  success = EncodeOctetString(buffer, used, allocated, data, len);
782  }
783  if (success)
784  {
785  success = AppendChar(buffer, used, allocated, ' ');
786  }
787  if (success)
788  {
789  success = AppendInteger(buffer, used, allocated, value->value.o.id);
790  }
791  if (success)
792  {
793  success = AppendChar(buffer, used, allocated, ')');
794  }
795  break;
796 
797  default:
798  success = MHEG5FALSE;
799  }
800 
801  return success;
802 }
803 
814 static MHEG5Bool EncodeOctetString(MHEG5Byte **buffer, MHEG5Int *used,
815  MHEG5Int *allocated, MHEG5Byte *data,
816  MHEG5Int len)
817 {
818  MHEG5Int i;
819  MHEG5Bool success;
820 
821  success = MHEG5TRUE;
822  for (i = 0; success && i < len; ++i)
823  {
824  success = EncodeChar(buffer, used, allocated, data[i]);
825  }
826 
827  return success;
828 }
829 
839 static MHEG5Bool EncodeChar(MHEG5Byte **buffer, MHEG5Int *used,
840  MHEG5Int *allocated, MHEG5Byte ch)
841 {
842  MHEG5Bool success;
843  MHEG5Byte digit;
844 
845  if (ch == 0x0d)
846  {
847  /* Carriage-Return */
848  success = AppendChar(buffer, used, allocated, '\n');
849  }
850  else if (ch == 0x09)
851  {
852  /* Tab */
853  success = AppendChar(buffer, used, allocated, '\t');
854  }
855  else if (ch >= 0x20 && ch < 0x7f && ch != '=' && ch != '\'')
856  {
857  /* Printable character */
858  success = AppendChar(buffer, used, allocated, ch);
859  }
860  else
861  {
862  /* Encode */
863  success = AppendChar(buffer, used, allocated, '=');
864  if (success)
865  {
866  digit = (ch >> 4);
867  if (digit < 10)
868  {
869  digit = '0' + digit;
870  }
871  else
872  {
873  digit = 'A' + digit - 10;
874  }
875  success = AppendChar(buffer, used, allocated, digit);
876  }
877  if (success)
878  {
879  digit = ch & 0xf;
880  if (digit < 10)
881  {
882  digit = '0' + digit;
883  }
884  else
885  {
886  digit = 'A' + digit - 10;
887  }
888  success = AppendChar(buffer, used, allocated, digit);
889  }
890  }
891 
892  return success;
893 }
894 
904 static MHEG5Bool AppendString(MHEG5Byte **buffer, MHEG5Int *used,
905  MHEG5Int *allocated, MHEG5Byte *data,
906  MHEG5Int len)
907 {
908  MHEG5Int i;
909  MHEG5Bool success;
910 
911  success = MHEG5TRUE;
912  for (i = 0; success && i < len; ++i)
913  {
914  success = AppendChar(buffer, used, allocated, data[i]);
915  }
916 
917  return success;
918 }
919 
928 static MHEG5Bool AppendInteger(MHEG5Byte **buffer, MHEG5Int *used,
929  MHEG5Int *allocated, MHEG5Int value)
930 {
931  char decimal[MAX_INT_LENGTH];
932  MHEG5Int nbytes, i;
933  MHEG5Bool success;
934 
935  nbytes = sprintf(decimal, "%ld", value);
936  success = MHEG5TRUE;
937  for (i = 0; success && i < nbytes; ++i)
938  {
939  success = AppendChar(buffer, used, allocated, decimal[i]);
940  }
941 
942  return success;
943 }
944 
953 static MHEG5Bool AppendChar(MHEG5Byte **buffer, MHEG5Int *used,
954  MHEG5Int *allocated, MHEG5Byte ch)
955 {
956  MHEG5Int new_size;
957  MHEG5Byte *new_block;
958  MHEG5Bool success;
959 
960  success = MHEG5FALSE;
961 
962  if (*buffer != NULL && *used + 1 < *allocated)
963  {
964  (*buffer)[*used] = ch;
965  ++(*used);
966  (*buffer)[*used] = '\0';
967  success = MHEG5TRUE;
968  }
969  else if (*buffer == NULL)
970  {
971  *buffer = MHEG5getMem(MIN_DATA_BLOCK);
972  if (*buffer != NULL)
973  {
974  (*buffer)[0] = ch;
975  (*buffer)[1] = '\0';
976  *used = 1;
977  *allocated = MIN_DATA_BLOCK;
978  success = MHEG5TRUE;
979  }
980  }
981  else
982  {
983  new_size = *allocated * 2;
984  new_block = MHEG5getMem(new_size);
985  if (new_block != NULL)
986  {
987  memcpy(new_block, *buffer, *used);
988  MHEG5freeMem(*buffer);
989  *buffer = new_block;
990  *allocated = new_size;
991  (*buffer)[*used] = ch;
992  ++(*used);
993  (*buffer)[*used] = '\0';
994  success = MHEG5TRUE;
995  }
996  else
997  {
998  MHEG5freeMem(*buffer);
999  *buffer = NULL;
1000  }
1001  }
1002 
1003  return success;
1004 }
1005 
1006 #ifdef INCLUDE_IC
1007 
1019 MHEG5Bool MHEG5parseEncodeField(MHEG5Byte **buffer, MHEG5Int *used,
1020  MHEG5Int *allocated, MHEG5String *name,
1021  MHEG5Generic *value)
1022 {
1023  MHEG5Byte *data;
1024  MHEG5Int len;
1025  MHEG5Bool success;
1026 
1027  success = MHEG5TRUE;
1028 
1029  if (*buffer != NULL && *used > 0)
1030  {
1031  success = AppendChar(buffer, used, allocated, '&');
1032  }
1033  if (success)
1034  {
1035  success = AddOctetString(buffer, used, allocated,
1036  name->data, name->len);
1037  }
1038  if (success)
1039  {
1040  success = AppendChar(buffer, used, allocated, '=');
1041  }
1042  if (success)
1043  {
1044  switch (value->type)
1045  {
1046  case MHEG5INT:
1047  success = AppendInteger(buffer, used, allocated, value->value.i);
1048  break;
1049  case MHEG5BOOL:
1050  if (value->value.b)
1051  {
1052  success = AddOctetString(buffer, used, allocated,
1053  (MHEG5Byte *)"true", 4);
1054  }
1055  else
1056  {
1057  success = AddOctetString(buffer, used, allocated,
1058  (MHEG5Byte *)"false", 5);
1059  }
1060  break;
1061  case MHEG5OCTETSTRING:
1062  success = AddOctetString(buffer, used, allocated,
1063  value->value.s.data,
1064  value->value.s.len);
1065  break;
1066  case MHEG5CONTENTREF:
1067  success = AddOctetString(buffer, used, allocated,
1068  value->value.s.data,
1069  value->value.s.len);
1070  break;
1071  case MHEG5OBJECTREF:
1072  if (value->value.o.gref.len == 0)
1073  {
1074  data = value->value.o.gref.ptr.group->groupName.data;
1075  len = value->value.o.gref.ptr.group->groupName.len;
1076  }
1077  else
1078  {
1079  data = value->value.o.gref.ptr.name;
1080  len = value->value.o.gref.len;
1081  }
1082  success = AddOctetString(buffer, used, allocated, data, len);
1083  if (success)
1084  {
1085  success = AddEncodedChar(buffer, used, allocated, ',');
1086  }
1087  if (success)
1088  {
1089  success = AppendInteger(buffer, used, allocated,
1090  value->value.o.id);
1091  }
1092  break;
1093  default:
1094  success = MHEG5FALSE;
1095  }
1096  }
1097 
1098  return success;
1099 }
1100 
1110 static MHEG5Bool AddOctetString(MHEG5Byte **buffer, MHEG5Int *used,
1111  MHEG5Int *allocated, MHEG5Byte *data,
1112  MHEG5Int len)
1113 {
1114  MHEG5Int i;
1115  MHEG5Bool success;
1116 
1117  success = MHEG5TRUE;
1118  for (i = 0; success && i < len; ++i)
1119  {
1120  success = AddEncodedChar(buffer, used, allocated, data[i]);
1121  }
1122 
1123  return success;
1124 }
1125 
1134 static MHEG5Bool AddEncodedChar(MHEG5Byte **buffer, MHEG5Int *used,
1135  MHEG5Int *allocated, MHEG5Byte ch)
1136 {
1137  MHEG5Bool success;
1138  static MHEG5Byte hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
1139  '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
1140 
1141  if ((ch >= '0' && ch <= '9') ||
1142  (ch >= 'A' && ch <= 'Z') ||
1143  (ch >= 'a' && ch <= 'z') ||
1144  (ch == '-' || ch == '.' || ch == '_' || ch == '~'))
1145  {
1146  success = AppendChar(buffer, used, allocated, ch);
1147  }
1148  else if (ch == ' ')
1149  {
1150  /* convert to '+' */
1151  success = AppendChar(buffer, used, allocated, '+');
1152  }
1153  else
1154  {
1155  /* percent-encode */
1156  success = AppendChar(buffer, used, allocated, '%');
1157  if (success)
1158  {
1159  success = AppendChar(buffer, used, allocated, hex[ch >> 4]);
1160  }
1161  if (success)
1162  {
1163  success = AppendChar(buffer, used, allocated, hex[ch & 0xf]);
1164  }
1165  }
1166 
1167  return success;
1168 }
1169 
1170 #endif /* INCLUDE_IC */
#define BKG_CRID_TTL_STRING
Definition: mh5parse.c:39
MH5GroupRef gref
Definition: mh5base.h:110
#define JSON_VALUE_FINISH
Definition: mh5json.h:34
E_JSON_STATE JSON_Parse(U8BIT *data, U32BIT size, const S_JSON_MEMBERS *members, void *usr)
Definition: mh5json.c:78
struct s_booking * next
Definition: dvb_pvr.h:70
S_LOCATION * p_locs
Definition: dvb_pvr.h:72
U8BIT hour
Definition: dvb_pvr.h:55
S_STRING description
Definition: dvb_pvr.h:83
U8BIT month
Definition: dvb_pvr.h:49
S32BIT type
Definition: dvb_pvr.h:81
const char * data
Definition: mh5gate.c:56
MHEG5Int i
Definition: mh5base.h:154
#define DECLARE_OBJEND()
Definition: mh5json.h:43
MHEG5String s
Definition: mh5base.h:156
MHEG5ObjectReference o
Definition: mh5base.h:159
U16BIT type
Definition: mh5base.h:151
#define MHEG5getMem
Definition: glue_memory.h:93
#define JSON_VALUE_ERROR
Definition: mh5json.h:35
MHEG5Bool b
Definition: mh5base.h:155
#define DECLARE_MEMBER(token_str, type, ptr, child_object)
Definition: mh5json.h:39
S_PVR_TIME offset
Definition: dvb_pvr.h:64
union sMH5GroupRef::@5 ptr
Implementation of the Group class Description Defines the structure and behaviour of objects used as ...
#define BKG_CRIDTYPE_TOKEN
Definition: mh5parse.c:34
S_STRING title
Definition: dvb_pvr.h:82
union MHEG5Generic::@6 value
U8BIT * zptr
Definition: dtvstring.h:31
S_DVB_LOCATOR dvb_loc
Definition: dvb_pvr.h:61
U16BIT transport_stream_id
Definition: dvblocator.h:33
U16BIT original_network_id
Definition: dvblocator.h:32
uint8_t U8BIT
Definition: techtype.h:82
long MHEG5Int
Definition: mh5base.h:73
#define BKG_BOOKING_TOKEN
Definition: mh5parse.c:33
string parsing utility functions for MHEG5
#define BKG_LOCATION_PREFIX
Definition: mh5parse.c:42
Memory functions.
S_BOOKING * bookings
Definition: dvb_pvr.h:86
#define MHEG5freeMem
Definition: glue_memory.h:94
#define BKG_SYNOPSIS_STRING
Definition: mh5parse.c:40
MHEG5Bool MHEG5parseEncodeQPrintable(MHEG5Byte **buffer, MHEG5Int *used, MHEG5Int *allocated, MHEG5Generic *value)
Add a value to the buffer. The value is QPrintable-encoded, which means that printable characters are...
Definition: mh5parse.c:729
U8BIT minute
Definition: dvb_pvr.h:56
S_PVR_DATE date
Definition: dvb_pvr.h:62
#define BKG_TITLE_TOKEN
Definition: mh5parse.c:32
short MHEG5Bool
Definition: mh5base.h:71
#define MAX_INT_LENGTH
Definition: mh5parse.c:46
#define BKG_BOOKING_ENDFIX
Definition: mh5parse.c:44
unsigned char MHEG5Byte
Definition: mh5base.h:74
#define BKG_DURATION_PREFIX
Definition: mh5parse.c:43
MHEG5Byte * data
Definition: mh5base.h:85
int len
Definition: mh5gate.c:57
MHEG5Bool MHEG5parseDvbUrl(U8BIT *buffer, U32BIT length, S_DVB_LOCATOR *dvb_loc)
Parse a DAVIC style multiplex reference or UK-DTT inherritance format URL. This can be one of the fol...
Definition: mh5parse.c:153
#define MHEG5TRUE
Definition: mh5base.h:49
uint16_t U16BIT
Definition: techtype.h:84
U32BIT num_locs
Definition: dvb_pvr.h:71
U16BIT service_id
Definition: dvblocator.h:34
MHEG5Int len
Definition: mh5base.h:99
MHEG5Byte * name
Definition: mh5base.h:102
MHEG5String groupName
Definition: mh5group.h:53
#define MIN_DATA_BLOCK
Definition: mh5parse.c:47
string parsing utility functions described by the [JSON] schema
Definition: mg_png.c:52
define asserts
#define FALSE
Definition: techtype.h:68
MH5GroupPtr group
Definition: mh5base.h:103
#define BKG_LOCATION_TOKEN
Definition: mh5parse.c:36
MHEG5Int len
Definition: mh5base.h:84
#define BKG_SYNOPSIS_TOKEN
Definition: mh5parse.c:35
U32BIT zlen
Definition: dtvstring.h:30
#define TRUE
Definition: techtype.h:69
S_PVR_TIME time
Definition: dvb_pvr.h:63
S_PVR_TIME duration
Definition: dvb_pvr.h:65
#define BKG_BOOKING_PREFIX
Definition: mh5parse.c:41
int MHEG5parseLcn(U8BIT *buf, U8BIT *end)
Definition: mh5parse.c:267
U16BIT year
Definition: dvb_pvr.h:48
U8BIT name[MAX_NAME_LENGTH+1]
Definition: mh5nvm.c:47
#define MHEG5FALSE
Definition: mh5base.h:48
uint32_t U32BIT
Definition: techtype.h:86
U8BIT day
Definition: dvb_pvr.h:50
#define DECLARE_OBJECT(cb_func)
Definition: mh5json.h:41
void JSON_FreeAstring(S_STRING *p_str)
Definition: mh5json.c:90
#define TRACE(t, x)
Definition: glue_debug.h:118