MHEG5  18.9.0
MHEG5 Documentation
mh5filegroup.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 "stb_os.h"
27 /* This code implements Australia profiles File Group requirements
28  * Only include rest of file if config allows
29  */
30 #ifdef INCLUDE_DSM_FG
31 
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "stb_nvm.h"
36 #include "glue_debug.h"
37 #include "glue_memory.h"
38 #include "glue_timers.h"
39 #include "glue_queue.h"
40 #include "mh5json.h"
41 #include "mh5gate.h"
42 #include "dsm_control.h"
43 #include "glue_dsmcc.h"
44 #include "mh5support.h"
45 #include "mh5fileorm.h"
46 #include "mh5filegroup.h"
47 
48 /*---constant definitions for this file--------------------------------------*/
49 
50 #define VERSION_TOKEN "version"
51 #define SIZE_TOKEN "size"
52 #define NODES_TOKEN "nodes"
53 #define NODE_TOKEN "node"
54 #define COUNT_TOKEN "count"
55 
56 #define MANIFEST_TIMEOUT 500 /* 500 msecs */
57 #define MANIFEST_TIME_STOP 600 /* (5 mins / 500 msecs) */
58 #define MAX_MAN_HDR_SIZE 224 /* this plus manifest file size must be less than MAX_MANIFEST_FILE_SIZE */
59 #define MAX_PATH_LEN 64
60 #define GROUP_DIR_LEN 8
61 
62 #define MAX_SIZE_OF_CACHED_FILE (32 * 1024)
63 
64 #define USE_FROM_CAROUSEL 0x80
65 #define USE_VERSION_FLAG 0x40
66 
67 #define FG_PROFILE_ALL 0x00
68 #define FG_PROFILE_HD_GRAPHICS 0x01
69 #define FG_PROFILE_HD_VIDEO 0x02
70 #define FG_PROFILE_IC 0x03
71 #define FG_PROFILE_ICS 0x04
72 #define FG_PROFILE_ICES 0x05
73 #define FG_PROFILE_LIFECYCLE 0x06
74 #define FG_PROFILE_NATIVE_APP 0x07
75 #define FG_PROFILE_DL_FONT 0x08
76 #define FG_PROFILE_SI 0x80
77 #define FG_PROFILE_PVR 0x81
78 
79 #define INVALID_NODE_COUNTER 1000 /* any number greater than 999 */
80 
81 #define MAX_SPECIAL_OWNER_ID 0x0003
82 #define MAX_SPECIAL_GROUP_ID 0x0009
83 #define NAME_CHAR_OFFSET 17
84 
85 /*---local typedef structs for this file-------------------------------------*/
86 
87 
88 typedef struct s_node
89 {
90  U16BIT count;
91  U16BIT nflen;
92  char *nfname;
93  union
94  {
95  /* for single file (count==0), use 'content' for file data */
96  S_CONTENT content;
97  /* for multiple files (count!=0), use 'contents' which points to array of file data */
98  S_CONTENT *contents;
99  } u;
100 } S_NODE;
101 
102 typedef enum
103 {
104  FGS_PASSIVE,
105  FGS_STALE,
106  FGS_LOADING,
107  FGS_PENDING,
108  FGS_ACTIVE,
109  FGS_ERROR
110 } E_FGS_STATUS;
111 
112 /* structure to hold loaded groups of files - saved (or to be saved) in NVM */
113 typedef struct s_stored_group
114 {
115  struct s_stored_group *next;
116  S_CarouselInfoFileGroup crsl_usr_info;
117  H_ObjCarousel hOC;
118  S_STRING loc_str;
119  U8BIT dir_name[GROUP_DIR_LEN];
120  U32BIT group_size;
121  U32BIT man_file_size;
122  U32BIT last_accessed;
123  E_FGS_STATUS status;
124  E_FS_ORIGIN origin;
125  MHEG5Int offset;
126  U16BIT file_version;
127  U16BIT total_nodes;
128  S_NODE *nodes;
129 } S_STORED_GROUP;
130 
131 /* structure to hold client file requests */
132 typedef struct s_fgc_request
133 {
134  struct s_fgc_request *next;
135  F_DSM_CBLOAD cb_func;
136  S_STORED_GROUP *pSG;
137  S_CONTENT *pClientContent;
138  S_CONTENT *pFgCtnt;
139 } S_FGC_REQUEST;
140 
141 /* structure to hold file requests to DSM-CC */
142 typedef struct s_dsm_file_rqst
143 {
144  S_STORED_GROUP *sfg;
145  S_CONTENT *pFgCtnt;
146  char *fname;
147 } S_DSM_FILE_RQST;
148 
149 /* structure to hold (global) manifest list (and state of manifest requests to DSM-CC */
150 /* structure to hold (global) manifest list (and state of manifest requests to DSM-CC */
151 typedef struct s_FGManifest
152 {
153  void *ormRqst;
154 } S_FGManifest;
155 
156 typedef struct s_manifest_rqst
157 {
158  struct s_manifest_rqst *next;
159  H_DsmControl dsmInst;
160  H_ObjCarousel hOC;
161  U16BIT total;
162  U8BIT outstanding;
163  U8BIT cachePriority;
164  S_CarouselInfoFileGroup *pFG;
165 } S_ManRequest;
166 
167 /*---local function prototypes for this file---------------------------------*/
168 
169 static S_STORED_GROUP* GetStoredGroup( U16BIT owner_id, U16BIT group_id );
170 static S_STORED_GROUP* FindValidGroup( E_FS_ORIGIN origin, const char **pname, S_CONTENT **ppCtnt );
171 static BOOLEAN HasMissingFileData( S_STORED_GROUP *pSGrp );
172 static void ManifestLoadGood( void *userData, S_CONTENT *pContent );
173 static void ManifestLoadFail( void *userData );
174 static void FileLoadedGood( void *userData, S_CONTENT *pContent );
175 static void FileLoadedFail( void *userData );
176 static void LoadAllFileData( S_STORED_GROUP *pSGrp, U8BIT cachePriority );
177 static void GetAllFileData( S_STORED_GROUP *pSGrp, U8BIT cachePriority );
178 static E_FsStatus ReadFileData( S_STORED_GROUP *pSGrp, const char *fname, S_CONTENT *pCtnt );
179 static BOOLEAN DeleteFileInNvm( S_STORED_GROUP *pSGrp, const char *fname );
180 static void DeleteAllFiles( S_STORED_GROUP *pSGrp );
181 static void FileGroupFree( S_STORED_GROUP *pSGrp );
182 
183 /* JSON callbacks */
184 static void* NodesArray( unsigned int val, void *array, void *gptr );
185 static void* NodeFinish( unsigned int val, void *array, void *gptr );
186 
187 /*---local (static) variable declarations for this file----------------------*/
188 
189 static const char hex_digits_low[] = "0123456789abcdef";
190 static S_STRING tmp_node_filename = { 0, NULL };
191 static U32BIT tmp_node_count = 0;
192 static U32BIT tmp_group_version = 0;
193 static U32BIT tmp_group_size = 0;
194 
195 static const S_JSON_MEMBERS group_node_members[] = {
196  DECLARE_OBJECT((void *)NodeFinish ),
197  DECLARE_MEMBER( NODE_TOKEN, JST_PTR_STRING, &tmp_node_filename, NULL ),
198  DECLARE_MEMBER( COUNT_TOKEN, JST_PTR_INTEGER, &tmp_node_count, NULL ),
200 };
201 
202 static const S_JSON_MEMBERS file_group_members[] = {
203  DECLARE_MEMBER( VERSION_TOKEN, JST_PTR_INTEGER, &tmp_group_version, NULL ),
204  DECLARE_MEMBER( SIZE_TOKEN, JST_PTR_INTEGER, &tmp_group_size, NULL ),
205  DECLARE_MEMBER( NODES_TOKEN, JST_CBF_ARRAY_OBJ, (void *)NodesArray, group_node_members ),
207 };
208 
209 static S_JSON_MEMBERS fg_cache_members[] = {
210  DECLARE_MEMBER( "ids", JST_PTR_INTEGER, NULL, NULL ),
211  DECLARE_MEMBER( "prop", JST_PTR_INTEGER, NULL, NULL ),
212  DECLARE_MEMBER( "path", JST_PTR_ASTRING, NULL, NULL ),
213  DECLARE_MEMBER( "group", JST_CBF_OBJECT, NULL, file_group_members ),
215 };
216 
217 static S_STORED_GROUP *stored_group_list = NULL;
218 static S_FGC_REQUEST *fg_request_head = NULL;
219 static S_FGC_REQUEST *fg_request_tail = NULL;
220 static U32BIT fg_nvm_max_limit = 0;
221 static S_ManRequest *fg_manifest_rqst = NULL;
222 static H_Timer fgManifestTimer = NULL;
223 static H_ObjCarousel fgTimerOC = NULL;
224 static U32BIT fgRequestCount = 0;
225 
226 /*---local function definitions----------------------------------------------*/
227 
228 
229 static E_FS_ORIGIN GetOrigin( S_STRING loc, MHEG5Int *pOffset )
230 {
231  E_FS_ORIGIN origin;
232  MHEG5String ref;
233  ref.len = loc.zlen;
234  ref.data = loc.zptr;
235  if ( !MHEG5ResolveOrigin(&ref, &origin, pOffset) || *pOffset <= 1 )
236  {
237  origin = ORIGIN_DSM;
238  }
239  return origin;
240 }
241 
249 static BOOLEAN FileRead( const char *filename, U8BIT *data, U32BIT size )
250 {
251  BOOLEAN rslt = FALSE;
252  void *file;
253  file = STB_NVMOpenFile((U8BIT*)filename, FILE_MODE_READ);
254  if (file == NULL)
255  {
256  TRACE(TERROR, ("%s", filename))
257  }
258  else
259  {
260  if (STB_NVMReadFile(file, data, size) != size)
261  {
262  TRACE(TERROR, ("%s sz %d", filename, size))
263  }
264  else
265  {
266  rslt = TRUE;
267  }
268  STB_NVMCloseFile( file );
269  }
270  return rslt;
271 }
272 
273 static S_STORED_GROUP* AddCachedManifestFile( char *filename )
274 {
275  S_STORED_GROUP *pSGrp = NULL;
276  U32BIT size, *pU32;
277  U8BIT *data;
278 
279  if (!STB_NVMFileSize((U8BIT*) filename, &size))
280  {
281  TRACE(TERROR, ("%s", filename))
282  }
283  else
284  {
285  data = DSMAlloc( size );
286 
287  if (data == NULL)
288  {
289  TRACE(TERROR, ("sz %d", size))
290  }
291  else
292  {
293  if (!FileRead(filename, data, size))
294  {
295  TRACE(TERROR, ("%s", filename))
296  }
297  else
298  {
299  pSGrp = DSMAlloc( sizeof(S_STORED_GROUP));
300  if (pSGrp == NULL)
301  {
302  TRACE(TERROR, ("malloc()"))
303  }
304  else
305  {
306  memset(pSGrp, 0, sizeof(S_STORED_GROUP));
307  tmp_group_size = 0;
308  pSGrp->man_file_size = size;
309  pSGrp->last_accessed = STB_OSGetClockMilliseconds();
310  pSGrp->total_nodes = 0;
311  pSGrp->nodes = NULL;
312  pU32 = (U32BIT *)&pSGrp->crsl_usr_info;
313  fg_cache_members[0].u.p_uint = pU32;
314  fg_cache_members[1].u.p_uint = pU32 + 1;
315  fg_cache_members[2].u.p_str = &pSGrp->loc_str;
316  if (JSON_Parse( data, size, fg_cache_members, pSGrp ) != JSON_OKAY)
317  {
318  TRACE(TERROR, ("%s", filename))
319  FileGroupFree( pSGrp );
320  pSGrp = NULL;
321  }
322  else
323  {
324  assert( tmp_group_size != 0 );
325  assert( pSGrp->total_nodes != 0 );
326  assert( pSGrp->nodes != NULL );
327  TRACE(TDSMFG, ("Success : owner 0x%x, group 0x%x, size %d",
328  pSGrp->crsl_usr_info.owner_id, pSGrp->crsl_usr_info.group_id, tmp_group_size))
329  pSGrp->group_size = tmp_group_size;
330  pSGrp->file_version = (U16BIT)tmp_group_version;
331  memcpy( pSGrp->dir_name, filename, 4 );
332  memcpy( pSGrp->dir_name + 4, filename + 5, 4 );
333  pSGrp->origin = GetOrigin(pSGrp->loc_str,&(pSGrp->offset));
334  #ifdef INCLUDE_SA_PROFILE
336  && pSGrp->crsl_usr_info.owner_id <= MAX_SPECIAL_OWNER_ID
337  && pSGrp->crsl_usr_info.group_id <= MAX_SPECIAL_GROUP_ID )
338  {
339  pSGrp->status = FGS_ACTIVE;
340  }
341  else
342  #endif
343  #ifdef INCLUDE_AU_PROFILE
344  if (!(pSGrp->crsl_usr_info.use_flags & USE_FROM_CAROUSEL))
345  {
346  pSGrp->status = FGS_PENDING;
347  }
348  else
349  #endif
350  {
351  pSGrp->status = FGS_PASSIVE;
352  }
353  pSGrp->next = stored_group_list;
354  stored_group_list = pSGrp;
355  }
356  }
357  }
358  /* free manifest file data */
359  DSMFree( data );
360  }
361  }
362  return pSGrp;
363 }
364 
365 /*---global function definitions---------------------------------------------*/
366 
373 void FG_Initialise( U32BIT nvmSize )
374 {
375  int n;
376  void *dir;
378  U16BIT owner, group;
379  char filename[MAX_PATH_LEN];
380 
381  assert( stored_group_list == NULL );
382  fg_nvm_max_limit = nvmSize;
383 
384  dir = STB_NVMOpenDirectory((U8BIT *) "" ); /* root dir should have manifest files */
385  if (dir == NULL)
386  {
387  TRACE(TERROR, (""))
388  }
389  else
390  {
391  TRACE(TDSMFG, (" "))
392  while (STB_NVMReadDirectory(dir, (U8BIT *) filename, MAX_PATH_LEN, &type))
393  {
394  if (type == DIR_ENTRY_FILE &&
395  strlen(filename) == 13 &&
396  memcmp(filename + 9, ".man", 4) == 0 &&
397  filename[4] == '-')
398  {
399  TRACE(TDSMFG, ("found: %s", filename))
400  owner = 0;
401  for (n = 0; n != 4; n++)
402  {
403  owner <<= 4;
404  if (filename[n] >= '0' && filename[n] <= '9')
405  {
406  owner |= filename[n] - '0';
407  }
408  else if (filename[n] >= 'a' && filename[n] <= 'f')
409  {
410  owner |= filename[n] + 10 - 'a';
411  }
412  else
413  {
414  TRACE(TERROR, ("invalid char 0x%x", filename[n]))
415  break;
416  }
417  }
418  if (n != 4)
419  {
420  TRACE(TERROR, (" n %d", n))
421  }
422  else
423  {
424  group = 0;
425  for (n = 5; n != 9; n++)
426  {
427  group <<= 4;
428  if (filename[n] >= '0' && filename[n] <= '9')
429  {
430  group |= filename[n] - '0';
431  }
432  else if (filename[n] >= 'a' && filename[n] <= 'f')
433  {
434  group |= filename[n] + 10 - 'a';
435  }
436  else
437  {
438  TRACE(TERROR, ("invalid char 0x%x", filename[n]))
439  break;
440  }
441  }
442  if (n != 9)
443  {
444  TRACE(TERROR, ("n %d", n))
445  }
446  else
447  {
448  /* Succesfully obtain group with sensible ID's in filename */
449  assert( GetStoredGroup( owner, group ) == NULL );
450  (void)AddCachedManifestFile( filename );
451  }
452  }
453  }
454  }
455 
456  STB_NVMCloseDirectory( dir );
457  }
458 }
459 
464 void FG_Terminate( void )
465 {
466  S_STORED_GROUP *pSGrp;
467 
468  TRACE(TDSMFG, (" "))
469  /* Clear entire cache */
470  while (stored_group_list != NULL)
471  {
472  pSGrp = stored_group_list;
473  stored_group_list = stored_group_list->next;
474  FileGroupFree( pSGrp );
475  }
476 }
477 
478 static void SetFilename( U16BIT owner_id, U16BIT group_id, char *fname )
479 {
480  const char *digits = hex_digits_low;
481  U16BIT tmp, n;
482  /* fill in owner and group IDs into the file name */
483  tmp = group_id;
484  /* Initialise file name with extension '.man' -
485  * assuming filename format is '0000-0000' i.e. length of 9 */
486  strcpy(fname + 9, ".man");
487  n = 8;
488  do
489  {
490  fname[n] = digits[tmp & 0xf];
491  tmp >>= 4;
492  n--;
493  }
494  while (n != 4);
495  fname[4] = '-';
496  tmp = owner_id;
497  n--;
498  do
499  {
500  fname[n] = digits[tmp & 0xf];
501  tmp >>= 4;
502  }
503  while (n--);
504 }
505 
506 static MHEG5Bool FileGroupRequired( U8BIT receiver_profile )
507 {
508  MHEG5Bool result = MHEG5TRUE;
509  switch (receiver_profile)
510  {
511  case FG_PROFILE_HD_GRAPHICS:
512  result = MH5_SupportHDGraphics();
513  break;
514  case FG_PROFILE_HD_VIDEO:
515  result = MH5_SupportHDVideo();
516  break;
517  case FG_PROFILE_IC:
519  break;
520  case FG_PROFILE_ICS:
521  result = MH5_SupportICStreaming();
522  break;
523  case FG_PROFILE_ICES:
524  /* ICEncyrptedStreamExtension is not supported? */
525  result = MHEG5FALSE;
526  break;
527  case FG_PROFILE_NATIVE_APP:
528  result = MH5_SupportNativeApplication();
529  break;
530  case FG_PROFILE_DL_FONT:
531  result = MH5_SupportFontClass();
532  break;
533  case FG_PROFILE_SI:
535  break;
536  case FG_PROFILE_PVR:
537  result = MH5_SupportPVRExtension();
538  break;
539  default:
540  case FG_PROFILE_LIFECYCLE:
541  /* fallthrough - always support Lifecycle (NDT) */
542  case FG_PROFILE_ALL:
543  result = MHEG5TRUE;
544  break;
545  }
546  return result;
547 }
548 
549 static S_ManRequest *FindManRequest(H_ObjCarousel hOC)
550 {
551  S_ManRequest *pManRqst = fg_manifest_rqst;
552  while ((pManRqst != NULL) && (hOC != pManRqst->hOC))
553  {
554  pManRqst = pManRqst->next;
555  }
556  return pManRqst;
557 }
558 
559 static void FreeManRequest(S_ManRequest *pManRqst)
560 {
561  S_CONTENT *pContent;
562  U16BIT total;
563  if (pManRqst->outstanding)
564  {
565  /* cancel outstanding manifest file requests */
566  pContent = (S_CONTENT *)(pManRqst + 1);
567  for (total = pManRqst->total; total--; pContent++)
568  {
569  if (pContent->user_data != 0)
570  {
571  if (pContent->destroy)
572  {
573  TRACE(TDSMFG, ("destory fsh=%p",pContent->fs_handle ))
574  pContent->destroy( pContent->fs_handle );
575  pContent->destroy = NULL;
576  pContent->fs_handle = NULL;
577  }
578  pManRqst->outstanding--;
579  if (!pManRqst->outstanding)
580  break;
581  }
582  }
583  DSMCC_ClientUnloadFileGroups( pManRqst->dsmInst, pManRqst->hOC, pManRqst->pFG );
584  }
585  DSMFree( pManRqst );
586 }
587 
592 static void DisableStoreGroupsFromCarousel( H_ObjCarousel hOC )
593 {
594  S_STORED_GROUP *pStoreGrp = stored_group_list;
595  while (pStoreGrp != NULL)
596  {
597  if (pStoreGrp->hOC == hOC)
598  {
600  || pStoreGrp->crsl_usr_info.owner_id > MAX_SPECIAL_OWNER_ID
601  || pStoreGrp->crsl_usr_info.group_id > MAX_SPECIAL_GROUP_ID )
602  {
603  pStoreGrp->status = FGS_PASSIVE;
604  pStoreGrp->hOC = NULL;
605  }
606  }
607  pStoreGrp = pStoreGrp->next;
608  }
609 }
610 
611 static void ClearManRequest( H_ObjCarousel hOC )
612 {
613  S_ManRequest *pManRqst, **ppManRqst;
614 
615  TRACE(TDSMFG, ("ObjCrsl=%p", hOC))
616  pManRqst = fg_manifest_rqst;
617  ppManRqst = &fg_manifest_rqst;
618  while (pManRqst != NULL)
619  {
620  if (hOC == pManRqst->hOC)
621  {
622  *ppManRqst = pManRqst->next;
623  DisableStoreGroupsFromCarousel(hOC);
624  FreeManRequest( pManRqst );
625  break;
626  }
627  ppManRqst = &(pManRqst->next);
628  pManRqst = pManRqst->next;
629  }
630 }
631 
632 static void AddManRequest(H_ObjCarousel hOC)
633 {
634  S_ManRequest *pManRqst;
635  S_CarouselInfoFileGroup *pFG;
636  H_DsmControl dsmInst;
637  U16BIT total;
638 
639  dsmInst = MHEG5_DsmccInstance();
640  if (!DSMCC_ClientLoadFileGroups(dsmInst, hOC, &total, &pFG))
641  {
642  TRACE(TERROR, ("DSMCC_ClientLoadFileGroups failure ObjCrsl=%p",hOC))
643  pManRqst = NULL;
644  }
645  else
646  {
647  TRACE(TDSMFG, ("ObjCrsl=%p total=%d", hOC, total ))
648  pManRqst = DSMAlloc( sizeof(S_ManRequest) + (total * sizeof(S_FGManifest)) );
649  if (pManRqst == NULL)
650  {
651  TRACE(TERROR, ("Memory failure"))
652  DSMCC_ClientUnloadFileGroups( dsmInst, hOC, pFG );
653  }
654  else
655  {
656  pManRqst->next = fg_manifest_rqst;
657  fg_manifest_rqst = pManRqst;
658  pManRqst->dsmInst = dsmInst;
659  pManRqst->hOC = hOC;
660  pManRqst->total = total;
661  pManRqst->outstanding = 0;
662  pManRqst->cachePriority = 0;
663  pManRqst->pFG = pFG;
664  memset(pManRqst+1, 0, total * sizeof(S_FGManifest));
665  }
666  }
667 }
668 
669 static BOOLEAN LoadManifest( H_ObjCarousel hOC, S_CarouselInfoFileGroup *pFG, U8BIT cachePriority, S_FGManifest *pFgm )
670 {
671  S_STORED_GROUP *pSGrp;
672  char filename[16];
673  S_STRING location, name;
674  MHEG5Int os;
675  BOOLEAN result = FALSE;
676 
677  location.zptr = pFG->location;
678  location.zlen = strlen((char *) location.zptr);
679  SetFilename( pFG->owner_id, pFG->group_id, filename );
680  name.zlen = 13;
681  name.zptr = (U8BIT*)filename;
682 
684  {
685  /* For South Africa profile, USE_FROM_CAROUSEL bit must be set */
686  pFG->use_flags |= USE_FROM_CAROUSEL;
687  }
688  pSGrp = GetStoredGroup( pFG->owner_id, pFG->group_id );
689  if (pSGrp == NULL)
690  {
691  /* Any cached group, should have been obtained in FG_Initialise,
692  * but does not do any harm to give it another try.
693  * Some platforms do not succeed in obtaining files at that early stage. */
694  pSGrp = AddCachedManifestFile( filename );
695  TRACE(TDSMFG, ("%s, Group was not in memory %p", filename, pSGrp))
696  }
697  else
698  {
699  TRACE(TDSMFG, ("%s, pSGrp %p", filename, pSGrp))
700  TRACE(TDSMFG, ("cgrp_ver=%d file_ver=%d flgs=%x",pFG->group_version,pSGrp->file_version,pFG->use_flags))
701  }
702  if (pSGrp == NULL ||
703  ((pFG->use_flags & USE_VERSION_FLAG) && pFG->group_version != pSGrp->file_version))
704  {
705  if ( pSGrp != NULL )
706  {
707  pSGrp->hOC = hOC;
709  pSGrp->crsl_usr_info.owner_id > MAX_SPECIAL_OWNER_ID ||
710  pSGrp->crsl_usr_info.group_id > MAX_SPECIAL_GROUP_ID)
711  {
712  TRACE(TDSMFG,("Stale group %x,%x",pSGrp->crsl_usr_info.owner_id,pSGrp->crsl_usr_info.group_id))
713  pSGrp->status = FGS_STALE;
714 
715  }
716  else
717  {
718  TRACE(TDSMFG,("Starting update of special group %x,%x",pSGrp->crsl_usr_info.owner_id,pSGrp->crsl_usr_info.group_id))
719  }
720  }
721  /* Request file containing group manifest */
722  pFgm->ormRqst = MHEG5FileOrmRetrieve( GetOrigin(location,&os), location, name, cachePriority,
723  pFG, ManifestLoadGood, ManifestLoadFail );
724  result = TRUE;
725  }
726 #ifdef INCLUDE_AU_PROFILE
727  else if (!(pSGrp->crsl_usr_info.use_flags & USE_FROM_CAROUSEL))
728  {
729  /* An "All or Nothing" group */
730  pSGrp->hOC = hOC;
731  // should be pSGrp->status == FGS_PENDING
732  /* make requests for all files in the group */
733  LoadAllFileData( pSGrp, cachePriority );
734  if (pSGrp->status != FGS_ERROR &&
735  HasMissingFileData( pSGrp ) == FALSE)
736  {
737  pSGrp->status = FGS_ACTIVE;
738  }
739  }
740 #endif //INCLUDE_AU_PROFILE
741  else
742  {
743  /* ensure have got all files updated in NVM */
744  pSGrp->status = FGS_ACTIVE;
745  GetAllFileData( pSGrp, cachePriority );
746  pSGrp->hOC = hOC;
747  }
748  return result;
749 }
750 
758 static void FetchManifests( H_ObjCarousel hOC, U8BIT cachePriority )
759 {
760  S_CarouselInfoFileGroup *pFG;
761  S_FGManifest *pFgm;
762  S_ManRequest *pManRqst;
763  U16BIT total;
764 
765  if (fgTimerOC == hOC)
766  {
767  fgTimerOC = NULL;
768  }
769  pManRqst = FindManRequest(hOC);
770  if (pManRqst != NULL)
771  {
772  pFG = pManRqst->pFG;
773  if (!pManRqst->outstanding && pFG != NULL)
774  {
775  pManRqst->cachePriority = cachePriority;
776  pFgm = (S_FGManifest *)(pManRqst + 1);
777  for(total = pManRqst->total; total--; pFG++, pFgm++)
778  {
779  if (!FileGroupRequired( pFG->receiver_profile ))
780  {
781  TRACE(TDSMFG, ("Group not required (0x%x,0x%x)", pFG->owner_id, pFG->group_id))
782  }
783  else
784  {
785  pManRqst->outstanding++;
786  if (!LoadManifest( hOC, pFG, cachePriority, pFgm ))
787  {
788  pManRqst->outstanding--;
789  }
790  }
791  }
792  }
793  }
794 }
795 
802 void FG_NotifyCarouselUnLoaded( H_ObjCarousel hOC )
803 {
804  S_ManRequest *pManRqst, **ppManRqst;
805 
806  TRACE(TDSMFG, ("ObjCrsl=%p", hOC))
807  if (fgTimerOC == hOC)
808  {
809  fgTimerOC = NULL;
810  }
811  pManRqst = fg_manifest_rqst;
812  ppManRqst = &fg_manifest_rqst;
813  while (pManRqst != NULL)
814  {
815  if (hOC == pManRqst->hOC)
816  {
817  *ppManRqst = pManRqst->next;
818  pManRqst->hOC = NULL;
819  DisableStoreGroupsFromCarousel(hOC);
820  FreeManRequest( pManRqst );
821  break;
822  }
823  ppManRqst = &(pManRqst->next);
824  pManRqst = pManRqst->next;
825  }
826  if (fgManifestTimer != NULL)
827  {
828  VT_TimerDestroy( fgManifestTimer );
829  fgManifestTimer = NULL;
830  }
831 }
832 
839 {
840  H_ObjCarousel hOC = param->hCarousel;
841  TRACE(TDSMFG, ("hOC=%p",hOC))
842  AddManRequest(hOC);
843  FetchManifests( hOC, FRP_CACHE_DEFAULT );
844 }
845 
852 {
853  H_ObjCarousel hOC = param->hCarousel;
854  TRACE(TDSMFG, ("hOC=%p",hOC))
855  ClearManRequest(hOC);
856  AddManRequest(hOC);
857  FetchManifests( hOC, 0 );
858 }
859 
866 {
867  H_ObjCarousel hOC = param->hCarousel;
868  TRACE(TDSMFG, ("hOC=%p",hOC))
869  ClearManRequest(hOC);
870  AddManRequest(hOC);
871  FetchManifests( hOC, 0 );
872 }
873 
878 static void FreeContent( S_CONTENT *pFgCtnt )
879 {
880  if (pFgCtnt->data != NULL)
881  {
882  assert( pFgCtnt->destroy != NULL );
883  if (pFgCtnt->destroy != NULL)
884  {
885  pFgCtnt->destroy( pFgCtnt->fs_handle );
886  pFgCtnt->destroy = NULL;
887  pFgCtnt->fs_handle = NULL;
888  }
889  pFgCtnt->data = NULL;
890  }
891 }
892 
897 static void ReleaseContent( S_CONTENT *pFgCtnt )
898 {
899  S_FGC_REQUEST *pRqst;
900  /* check that there is no other outstanding client usage */
901  pRqst = fg_request_head;
902  while (pRqst != NULL)
903  {
904  if (pRqst->pFgCtnt == pFgCtnt)
905  {
906  break;
907  }
908  pRqst = pRqst->next;
909  }
910  if (pRqst == NULL &&
911  pFgCtnt->size > MAX_SIZE_OF_CACHED_FILE)
912  {
913  FreeContent( pFgCtnt );
914  }
915 }
916 
923 static void RemoveClientRqst( void *dsmFileRef )
924 {
925  S_FGC_REQUEST *p_rqst, *p_prv;
926  if (dsmFileRef != NULL)
927  {
928  TRACE(TDSMFG, ("ref=%p", dsmFileRef))
929  if (fg_request_head != NULL)
930  {
931  if (dsmFileRef == fg_request_head)
932  {
933  fg_request_head = fg_request_head->next;
934  if (fg_request_head == NULL)
935  {
936  fg_request_tail = NULL;
937  }
938  ReleaseContent(((S_FGC_REQUEST *)dsmFileRef)->pFgCtnt );
939  TRACE(TDSMFG, ("ref=%p", dsmFileRef))
940  DSMFree( dsmFileRef );
941  }
942  else
943  {
944  p_prv = fg_request_head;
945  p_rqst = fg_request_head->next;
946  while (p_rqst != NULL)
947  {
948  if (p_rqst == dsmFileRef)
949  {
950  p_prv->next = p_rqst->next;
951  if (p_rqst->next == NULL)
952  {
953  fg_request_tail = p_prv;
954  }
955  ReleaseContent( p_rqst->pFgCtnt );
956  TRACE(TDSMFG, ("ref=%p", dsmFileRef))
957  DSMFree( dsmFileRef );
958  break;
959  }
960  p_prv = p_rqst;
961  p_rqst = p_rqst->next;
962  }
963  }
964  }
965  }
966 }
967 
975 static E_FsStatus AquireFileData( S_STORED_GROUP *pSGrp, const char *fname,
976  S_CONTENT *pCtnt, U8BIT cachePriority )
977 {
978  E_FsStatus fstat;
979  S_DSM_FILE_RQST *pDsmRqst;
980  S_STRING name;
981  assert( pCtnt->data == NULL );
982  if (pCtnt->user_data != NULL)
983  {
984  TRACE(TDSMFG, ("another request for %s at %p", fname, pCtnt->user_data))
985  fstat = FS_STATUS_PENDING;
986  }
987  else
988  {
989  name.zlen = strlen(fname);
990  name.zptr = (U8BIT*)fname;
991  pDsmRqst = DSMAlloc( sizeof(S_DSM_FILE_RQST) + name.zlen + 10 );
992  if (pDsmRqst == NULL)
993  {
994  fstat = FS_STATUS_ERROR;
995  }
996  else
997  {
998  pDsmRqst->fname = (char *)(pDsmRqst + 1);
999  memcpy( pDsmRqst->fname, pSGrp->dir_name, GROUP_DIR_LEN );
1000  pDsmRqst->fname[8] = '/';
1001  strcpy( pDsmRqst->fname + 9, fname );
1002  pDsmRqst->sfg = pSGrp;
1003  pDsmRqst->pFgCtnt = pCtnt;
1004  pCtnt->user_data = MHEG5FileOrmRetrieve(pSGrp->origin, pSGrp->loc_str, name, cachePriority,
1005  pDsmRqst, FileLoadedGood, FileLoadedFail);
1006  if (pCtnt->user_data == NULL)
1007  {
1008  fstat = (pCtnt->data==NULL)? FS_STATUS_ERROR : FS_STATUS_OK;
1009  }
1010  else
1011  {
1012  fstat = FS_STATUS_PENDING;
1013  }
1014  }
1015  }
1016  return fstat;
1017 }
1018 
1024 E_FsStatus FG_LoadRequest( E_FS_ORIGIN origin, const char *fname,
1025  F_DSM_CBLOAD cb_func, S_CONTENT *pContent, U8BIT cachePriority )
1026 {
1027  E_FsStatus fstat;
1028  S_CONTENT *pCtnt;
1029  S_STORED_GROUP *pSG;
1030 
1031  assert( cb_func != NULL );
1032  assert( pContent != NULL );
1033  assert( pContent->destroy == NULL );
1034 
1035  pSG = FindValidGroup( origin, &fname, &pCtnt );
1036  if (pCtnt == NULL)
1037  {
1038  /* file not in any valid file groups */
1039  fstat = FS_STATUS_INVALID;
1040  TRACE(TDSMFG, ("%s not in active file group", fname))
1041  }
1042  else
1043  {
1044  S_FGC_REQUEST *pRqst = DSMAlloc( sizeof(S_FGC_REQUEST));
1045  if (pRqst == NULL)
1046  {
1047  TRACE(TERROR, ("%s", fname))
1048  fstat = FS_STATUS_ERROR;
1049  }
1050  else
1051  {
1052  pRqst->next = NULL;
1053  pRqst->cb_func = cb_func;
1054  pRqst->pFgCtnt = pCtnt;
1055  pRqst->pClientContent = pContent;
1056  pRqst->pSG = pSG;
1057  if (fg_request_tail == NULL)
1058  {
1059  fg_request_head = pRqst;
1060  }
1061  else
1062  {
1063  fg_request_tail->next = pRqst;
1064  }
1065  fg_request_tail = pRqst;
1066  pSG->last_accessed = STB_OSGetClockMilliseconds();
1067  switch (pSG->status)
1068  {
1069  case FGS_PENDING:
1070  TRACE(TDSMFG, ("FGS_PENDING %s", fname))
1071  fstat = FS_STATUS_PENDING;
1072  break;
1073 
1074  case FGS_ERROR:
1075  TRACE(TERROR, ("FGS_ERROR %s", fname))
1076  fstat = FS_STATUS_ERROR;
1077  break;
1078 
1079  case FGS_ACTIVE:
1080  if (cachePriority == 0)
1081  {
1082  FreeContent( pCtnt );
1083  DeleteFileInNvm( pSG, fname );
1084  fstat = FS_STATUS_PENDING;
1085  }
1086  else if (pCtnt->data != NULL)
1087  {
1088  /* File in the Group Store */
1089  TRACE(TDSMFG, ("FGS_ACTIVE getting %s from store", fname))
1090  fstat = FS_STATUS_OK;
1091  }
1092  else
1093  {
1094  fstat = ReadFileData( pSG, fname, pCtnt );
1095  }
1096  if (fstat == FS_STATUS_OK)
1097  {
1098  pContent->size = pCtnt->size;
1099  pContent->data = pCtnt->data;
1100  }
1101  else
1102  {
1103  /* Request file */
1104  TRACE(TDSMFG, ("FGS_ACTIVE request %s from carousel", fname))
1105  fstat = AquireFileData( pSG, fname, pCtnt, cachePriority );
1106  }
1107  break;
1108  default:
1109  fstat = FS_STATUS_ERROR;
1110  TRACE(TERROR, ("state unknown %d (fname=%s)", pSG->status, fname))
1111  break;
1112  }
1113  if (fstat == FS_STATUS_ERROR)
1114  {
1115  RemoveClientRqst( pRqst );
1116  }
1117  else
1118  {
1119  pContent->fs_handle = pRqst;
1120  pContent->destroy = RemoveClientRqst;
1121  }
1122  }
1123  }
1124  TRACE(TDSMFG, ("fstat=%d", fstat))
1125  return fstat;
1126 }
1127 
1133 E_FsStatus FG_FileExists( E_FS_ORIGIN origin, const char *fname )
1134 {
1135  E_FsStatus fstat;
1136  S_CONTENT *pCtnt;
1137  S_STORED_GROUP *pSG;
1138 
1139  pSG = FindValidGroup( origin, &fname, &pCtnt);
1140  if (pCtnt == NULL)
1141  {
1142  /* file not in any valid file groups */
1143  fstat = FS_STATUS_INVALID;
1144  TRACE(TDSMFG, ("%s not in active file group", fname))
1145  }
1146  else
1147  {
1148  TRACE(TDSMFG, (" %s", fname))
1149  switch (pSG->status)
1150  {
1151  case FGS_PENDING:
1152  case FGS_ACTIVE:
1153  /* File in the Group Store */
1154  fstat = FS_STATUS_OK;
1155  break;
1156 
1157  case FGS_ERROR:
1158  TRACE(TERROR, (" %s", fname))
1159  fstat = FS_STATUS_ERROR;
1160  break;
1161 
1162  default:
1163  fstat = FS_STATUS_INVALID;
1164  }
1165  }
1166  return fstat;
1167 }
1168 
1174 void FG_FactoryReset( void )
1175 {
1176  S_STORED_GROUP *pSGrp;
1177  H_ObjCarousel hOC;
1178 
1179  /* Clear entire cache */
1180  while (stored_group_list != NULL)
1181  {
1182  pSGrp = stored_group_list;
1183  stored_group_list = stored_group_list->next;
1184  DeleteAllFiles( pSGrp );
1185  FileGroupFree( pSGrp );
1186  }
1187 
1188  hOC = DSMCC_CurrentCarousel(MHEG5_DsmccInstance());
1189  /* re-load file groups from current Object Carousel */
1190  if (hOC != NULL)
1191  {
1192  FetchManifests( hOC, FRP_CACHE_DEFAULT );
1193  }
1194 }
1195 
1196 /*---local function definitions----------------------------------------------*/
1197 
1198 
1205 static S_STORED_GROUP* GetStoredGroup( U16BIT owner_id, U16BIT group_id )
1206 {
1207  S_STORED_GROUP *pStoreGrp = stored_group_list;
1208  while (pStoreGrp != NULL)
1209  {
1210  if (pStoreGrp->crsl_usr_info.owner_id == owner_id &&
1211  pStoreGrp->crsl_usr_info.group_id == group_id)
1212  {
1213  break;
1214  }
1215  pStoreGrp = pStoreGrp->next;
1216  }
1217  return pStoreGrp;
1218 }
1219 
1224 static U32BIT FileGroupTotalSize( void )
1225 {
1226  S_STORED_GROUP *pStoreGrp = stored_group_list;
1227  U32BIT total = 0;
1228  while (pStoreGrp != NULL)
1229  {
1230  total += pStoreGrp->group_size + pStoreGrp->man_file_size;
1231  pStoreGrp = pStoreGrp->next;
1232  }
1233  return total;
1234 }
1235 
1241 static void FileGroupRemove( S_STORED_GROUP *pSGrp )
1242 {
1243  assert( pSGrp != NULL );
1244  /* Remove group from the list - if it is in it */
1245  if (stored_group_list)
1246  {
1247  if (pSGrp == stored_group_list)
1248  {
1249  stored_group_list = pSGrp->next;
1250  }
1251  else
1252  {
1253  S_STORED_GROUP *pPrev = stored_group_list;
1254  while (pPrev->next != pSGrp && pPrev->next != NULL)
1255  {
1256  pPrev = pPrev->next;
1257  }
1258  if (pPrev->next == pSGrp)
1259  {
1260  pPrev->next = pSGrp->next;
1261  }
1262  }
1263  }
1264 }
1265 
1271 static void FileGroupFree( S_STORED_GROUP *pSGrp )
1272 {
1273  assert( pSGrp != NULL );
1274  /* Free all data associated with this stored group */
1275  if (pSGrp->nodes != NULL)
1276  {
1277  U16BIT remaining_nodes = pSGrp->total_nodes;
1278  S_NODE *pNode = pSGrp->nodes + remaining_nodes;
1279 
1280  while (remaining_nodes > 0)
1281  {
1282  pNode--;
1283  remaining_nodes--;
1284 
1285  if (pNode->count != 0)
1286  {
1287  if (pNode->u.contents != NULL)
1288  {
1289  U16BIT c = pNode->count;
1290  S_CONTENT *pCtnt = pNode->u.contents;
1291  pCtnt += c;
1292  do
1293  {
1294  pCtnt--;
1295  c--;
1296  FreeContent( pCtnt );
1297  }
1298  while (c != 0);
1299  /* free array of contents */
1300  DSMFree( pNode->u.contents );
1301  }
1302  }
1303  else
1304  {
1305  /* just file data (i.e one file) */
1306  FreeContent( &(pNode->u.content));
1307  }
1308  if (pNode->nfname != NULL)
1309  {
1310  STR_DataFree((U8BIT *)pNode->nfname, pNode->nflen ); /* Free filename string */
1311  }
1312  }
1313  DSMFree( pSGrp->nodes ); /* free nodes list */
1314  MH5GlueStringFree( &pSGrp->loc_str );
1315  }
1316  DSMFree( pSGrp ); /* free store group */
1317 }
1318 
1324 static void DeleteStoredGroup( U16BIT owner_id, U16BIT group_id )
1325 {
1326  S_STORED_GROUP *pSGrp = GetStoredGroup( owner_id, group_id );
1327  if (pSGrp != NULL)
1328  {
1329  TRACE(TDSMFG, ("Delete OLD version 0x%x", pSGrp->file_version))
1330  /* remove old group from store - should already be marked as FGS_STALE */
1331  DeleteAllFiles( pSGrp );
1332  FileGroupRemove( pSGrp );
1333  FileGroupFree( pSGrp );
1334  }
1335 }
1336 
1337 static S_CONTENT* FindMatchingNode( S_NODE *pNode, U16BIT total, const char *fname )
1338 {
1339  U16BIT filelen, baselen, fnumber;
1340  filelen = strlen(fname);
1341  fnumber = INVALID_NODE_COUNTER;
1342  baselen = filelen;
1343  if (baselen > 3)
1344  {
1345  baselen--;
1346  while (fname[baselen] >= '0' && fname[baselen] <= '9')
1347  {
1348  if (baselen == filelen - 3)
1349  {
1350  fnumber = ((fname[baselen] - '0') * 100) + ((fname[baselen + 1] - '0') * 10) + (fname[baselen + 2] - '0');
1351  if (fnumber == 0)
1352  {
1353  // spec says number must be "001 to count", so set to invalid value
1354  fnumber = INVALID_NODE_COUNTER;
1355  }
1356  else
1357  {
1358  fnumber--;
1359  }
1360  break;
1361  }
1362  baselen--;
1363  }
1364  }
1365  while (total--)
1366  {
1367  if (pNode->count == 0)
1368  {
1369  if (pNode->nflen == filelen &&
1370  !memcmp(pNode->nfname, fname, filelen))
1371  {
1372  /*fount it!*/
1373  return &(pNode->u.content);
1374  }
1375  }
1376  else if (fnumber < pNode->count && pNode->u.contents != NULL)
1377  {
1378  if (pNode->nflen == baselen &&
1379  !memcmp(pNode->nfname, fname, baselen))
1380  {
1381  /*fount it!*/
1382  return pNode->u.contents + fnumber;
1383  }
1384  }
1385  pNode++;
1386  }
1387  return NULL;
1388 }
1389 
1390 static const char* MatchingLocation( E_FS_ORIGIN origin, const char *pname, S_STRING location, MHEG5Int offset )
1391 {
1392  if (origin == ORIGIN_DSM && location.zlen == 0)
1393  {
1394  /* default location */
1395  return pname;
1396  }
1397  if (location.zptr != NULL)
1398  {
1399  location.zptr += offset;
1400  location.zlen -= offset;
1401  if (MHEG5strncmp(pname, location.zptr, location.zlen) == 0)
1402  {
1403  return pname + location.zlen;
1404  }
1405  }
1406  return NULL;
1407 }
1408 
1416 static S_STORED_GROUP* FindValidGroup( E_FS_ORIGIN origin, const char** pname, S_CONTENT** ppCtnt )
1417 {
1418  S_STORED_GROUP* pSGrp;
1419  S_CONTENT *pCtnt;
1420  const char *fname;
1421 
1422  *ppCtnt = NULL;
1423  pSGrp = stored_group_list;
1424  while ( pSGrp != NULL )
1425  {
1426  TRACE(TDSMFG,("ID (0x%x,0x%x) nodes=%d ver=%d origin=%d status=%d",
1427  pSGrp->crsl_usr_info.owner_id, pSGrp->crsl_usr_info.group_id,
1428  pSGrp->total_nodes, pSGrp->file_version, pSGrp->origin, pSGrp->status))
1429  if (pSGrp->status > FGS_LOADING &&
1430  pSGrp->nodes != NULL &&
1431  pSGrp->origin == origin)
1432  {
1433  fname = MatchingLocation( origin, *pname, pSGrp->loc_str, pSGrp->offset );
1434  if ( fname != NULL )
1435  {
1436  if (fname[0] == '/') fname++;
1437  TRACE(TDSMFG,("matching location: path=%s fname=%s",*pname,fname))
1438  pCtnt = FindMatchingNode( pSGrp->nodes, pSGrp->total_nodes, fname );
1439  if ( pCtnt != NULL )
1440  {
1441  TRACE(TDSMFG,("==== Found it path %s fname %s ====",*pname,fname))
1442  *ppCtnt = pCtnt;
1443  *pname = fname;
1444  break;
1445  }
1446  }
1447  }
1448  pSGrp = pSGrp->next;
1449  }
1450  return pSGrp;
1451 }
1452 
1458 static BOOLEAN HasMissingFileData( S_STORED_GROUP *pSGrp )
1459 {
1460  S_NODE *pNode;
1461  S_CONTENT *pCtnt;
1462  U16BIT n, c, total;
1463  BOOLEAN result = FALSE;
1464 
1465  assert(pSGrp->nodes != NULL);
1466 
1467  pNode = pSGrp->nodes;
1468  for (n = 0; n != pSGrp->total_nodes; n++, pNode++)
1469  {
1470  if (pNode->count == 0)
1471  {
1472  if (pNode->u.content.data == NULL)
1473  {
1474  result = TRUE;
1475  break;
1476  }
1477  }
1478  else
1479  {
1480  pCtnt = pNode->u.contents;
1481  total = pNode->count + 1;
1482  for (c = 1; c != total; c++, pCtnt++)
1483  {
1484  if (pCtnt->data == NULL)
1485  {
1486  result = TRUE;
1487  break;
1488  }
1489  }
1490  if (result == TRUE)
1491  {
1492  break;
1493  }
1494  }
1495  }
1496  return result;
1497 }
1498 
1506 static BOOLEAN FulfilRequest( S_CONTENT *pCtnt, E_FsStatus fstat )
1507 {
1508  S_FGC_REQUEST *p_rqst;
1509  BOOLEAN found = FALSE;
1510  TRACE(TDSMFG, ("pCtnt=%p fstat=%d", pCtnt, fstat));
1511  p_rqst = fg_request_head;
1512  while (p_rqst != NULL)
1513  {
1514  if (p_rqst->pFgCtnt == pCtnt)
1515  {
1516  /* do callback */
1517  if (p_rqst->cb_func != NULL)
1518  {
1519  p_rqst->pClientContent->size = pCtnt->size;
1520  p_rqst->pClientContent->data = pCtnt->data;
1521  p_rqst->cb_func( fstat, p_rqst->pClientContent );
1522  p_rqst->cb_func = NULL;
1523  }
1524  found = TRUE;
1525  }
1526  p_rqst = p_rqst->next;
1527  }
1528  return found;
1529 }
1530 
1538 static void FulfilOutstandingFileRequests( S_STORED_GROUP *pSGrp, E_FsStatus fstat )
1539 {
1540  S_NODE *pNode;
1541  S_CONTENT *pCtnt;
1542  U16BIT n, c, total;
1543 
1544  assert(pSGrp->nodes != NULL);
1545  assert((pSGrp->crsl_usr_info.use_flags & USE_FROM_CAROUSEL) == 0);
1546  assert(fg_request_head != NULL);
1547 
1548  pNode = pSGrp->nodes;
1549  for (n = 0; n != pSGrp->total_nodes; n++, pNode++)
1550  {
1551  if (pNode->count == 0)
1552  {
1553  assert( pNode->u.content.data != NULL );
1554  (void)FulfilRequest( &(pNode->u.content), fstat );
1555  }
1556  else
1557  {
1558  pCtnt = pNode->u.contents;
1559  total = pNode->count + 1;
1560  for (c = 1; c != total; c++, pCtnt++)
1561  {
1562  assert( pCtnt->data != NULL );
1563  (void)FulfilRequest( pCtnt, fstat );
1564  }
1565  }
1566  }
1567 }
1568 
1575 static BOOLEAN FileExistsInNvm( S_STORED_GROUP *pSGrp, char *fname )
1576 {
1577  U32BIT size;
1578  BOOLEAN exists;
1579  char fullname[MAX_PATH_LEN];
1580  memcpy( fullname, pSGrp->dir_name, GROUP_DIR_LEN );
1581  fullname[8] = '/';
1582  strcpy( fullname + 9, fname );
1583  if (STB_NVMFileSize( (U8BIT*) fullname, &size ))
1584  {
1585  exists = TRUE;
1586  }
1587  else
1588  {
1589  exists = FALSE;
1590  }
1591  return exists;
1592 }
1593 
1600 static BOOLEAN DeleteFileInNvm( S_STORED_GROUP *pSGrp, const char *fname )
1601 {
1602  char fullname[MAX_PATH_LEN];
1603  memcpy( fullname, pSGrp->dir_name, GROUP_DIR_LEN );
1604  fullname[8] = '/';
1605  strcpy( fullname + 9, fname );
1606  return STB_NVMDeleteFile((U8BIT*)fullname);
1607 }
1608 
1615 static E_FsStatus ReadFileData( S_STORED_GROUP *pSGrp, const char *fname, S_CONTENT *pCtnt )
1616 {
1617  U8BIT *data;
1618  U32BIT size;
1619  E_FsStatus fstat;
1620  char fullname[MAX_PATH_LEN];
1621 
1622  assert( pCtnt->data == NULL );
1623 
1624  memcpy( fullname, pSGrp->dir_name, GROUP_DIR_LEN );
1625  fullname[8] = '/';
1626  strcpy( fullname + 9, fname );
1627 
1628  if (STB_NVMFileSize( (U8BIT*) fullname, &size ))
1629  {
1630  data = DSMAlloc((size == 0) ? 1 : size );
1631  if (data == NULL)
1632  {
1633  TRACE(TERROR, ("%s", fullname))
1634  fstat = FS_STATUS_ERROR;
1635  }
1636  else if (size == 0)
1637  {
1638  TRACE(TDSMFG, ("%s in NVM is zero len", fname))
1639  pCtnt->size = 0;
1640  pCtnt->data = data;
1641  pCtnt->destroy = DSMFree;
1642  pCtnt->fs_handle = data;
1643  *data = 0;
1644  fstat = FS_STATUS_OK;
1645  }
1646  else if (FileRead( fullname, data, size ))
1647  {
1648  TRACE(TDSMFG, ("Read %s from NVM", fname))
1649  pCtnt->size = size;
1650  pCtnt->data = data;
1651  pCtnt->destroy = DSMFree;
1652  pCtnt->fs_handle = data;
1653  fstat = FS_STATUS_OK;
1654  }
1655  else
1656  {
1657  TRACE(TERROR, ("%s sz %d", fullname, size))
1658  fstat = FS_STATUS_ERROR;
1659  DSMFree( data );
1660  }
1661  }
1662  else
1663  {
1664  TRACE(TDSMFG, ("%s not in NVM", fname))
1665  fstat = FS_STATUS_NONE;
1666  }
1667  return fstat;
1668 }
1669 
1676 static void LoadAllFileData( S_STORED_GROUP *pSGrp, U8BIT cachePriority )
1677 {
1678  S_NODE *pNode;
1679  S_CONTENT *pCtnt;
1680  char *pNumb;
1681  U16BIT n, c, total;
1682 
1683  assert(pSGrp->nodes != NULL);
1684 
1685  pNode = pSGrp->nodes;
1686  for (n = 0; n != pSGrp->total_nodes; n++, pNode++)
1687  {
1688  if (pNode->count == 0)
1689  {
1690  if (pNode->u.content.data == NULL &&
1691  ReadFileData( pSGrp, pNode->nfname, &(pNode->u.content)) != FS_STATUS_OK)
1692  {
1693  AquireFileData( pSGrp, pNode->nfname, &(pNode->u.content), cachePriority );
1694  }
1695  }
1696  else
1697  {
1698  pNumb = pNode->nfname + pNode->nflen;
1699  pCtnt = pNode->u.contents;
1700  total = pNode->count + 1;
1701  for (c = 1; c != total; c++, pCtnt++)
1702  {
1703  pNumb[0] = '0' + ((c / 100) % 10);
1704  pNumb[1] = '0' + ((c / 10) % 10);
1705  pNumb[2] = '0' + (c % 10);
1706  if (pCtnt->data == NULL &&
1707  ReadFileData( pSGrp, pNode->nfname, pCtnt ) != FS_STATUS_OK)
1708  {
1709  AquireFileData( pSGrp, pNode->nfname, pCtnt, cachePriority );
1710  }
1711  }
1712  *pNumb = 0; /*null end char again*/
1713  }
1714  }
1715 }
1716 
1723 static void GetAllFileData( S_STORED_GROUP *pSGrp, U8BIT cachePriority )
1724 {
1725  S_NODE *pNode;
1726  S_CONTENT *pCtnt;
1727  char *pNumb;
1728  U16BIT n, c, total;
1729 
1730  assert(pSGrp->nodes != NULL);
1731 
1732  pNode = pSGrp->nodes;
1733  for (n = 0; n != pSGrp->total_nodes; n++, pNode++)
1734  {
1735  if (pNode->count == 0)
1736  {
1737  if (pNode->u.content.data == NULL &&
1738  !FileExistsInNvm( pSGrp, pNode->nfname ))
1739  {
1740  AquireFileData( pSGrp, pNode->nfname, &(pNode->u.content), cachePriority );
1741  }
1742  }
1743  else
1744  {
1745  pNumb = pNode->nfname + pNode->nflen;
1746  pCtnt = pNode->u.contents;
1747  total = pNode->count + 1;
1748  for (c = 1; c != total; c++, pCtnt++)
1749  {
1750  pNumb[0] = '0' + ((c / 100) % 10);
1751  pNumb[1] = '0' + ((c / 10) % 10);
1752  pNumb[2] = '0' + (c % 10);
1753  if (pCtnt->data == NULL &&
1754  !FileExistsInNvm( pSGrp, pNode->nfname ))
1755  {
1756  AquireFileData( pSGrp, pNode->nfname, pCtnt, cachePriority );
1757  }
1758  }
1759  *pNumb = 0; /*null end char again*/
1760  }
1761  }
1762 }
1763 
1769 static void DeleteAllFiles( S_STORED_GROUP *pSGrp )
1770 {
1771  S_NODE *pNode;
1772  char *pNumb;
1773  U16BIT n, c, total;
1774  char fullname[MAX_PATH_LEN];
1775 
1776  memcpy( fullname, pSGrp->dir_name, GROUP_DIR_LEN );
1777  fullname[8] = '/';
1778 
1779  assert(pSGrp->nodes != NULL);
1780 
1781  pNode = pSGrp->nodes;
1782  for (n = 0; n != pSGrp->total_nodes; n++, pNode++)
1783  {
1784  if (pNode->count == 0)
1785  {
1786  strcpy( fullname + 9, pNode->nfname );
1787  STB_NVMDeleteFile( (U8BIT*) fullname );
1788  }
1789  else
1790  {
1791  pNumb = pNode->nfname + pNode->nflen;
1792  total = pNode->count + 1;
1793  for (c = 1; c != total; c++)
1794  {
1795  pNumb[0] = '0' + ((c / 100) % 10);
1796  pNumb[1] = '0' + ((c / 10) % 10);
1797  pNumb[2] = '0' + (c % 10);
1798  strcpy( fullname + 9, pNode->nfname );
1799  STB_NVMDeleteFile( (U8BIT*) fullname );
1800  }
1801  *pNumb = 0; /*null end char again*/
1802  }
1803  }
1804  fullname[8] = fullname[7];
1805  fullname[7] = fullname[6];
1806  fullname[6] = fullname[5];
1807  fullname[5] = fullname[4];
1808  fullname[4] = '-';
1809  fullname[9] = '.';
1810  fullname[10] = 'm';
1811  fullname[11] = 'a';
1812  fullname[12] = 'n';
1813  fullname[13] = 0;
1814  STB_NVMDeleteFile( (U8BIT*) fullname );
1815 }
1816 
1817 static BOOLEAN RemoveLeastDesiredGroup( void )
1818 {
1819  S_STORED_GROUP *pSGrp;
1820  BOOLEAN found = FALSE;
1822 
1823  assert( stored_group_list != NULL );
1824 
1825  pSGrp = stored_group_list;
1826  do
1827  {
1828  #ifdef INCLUDE_SA_PROFILE
1830  || pSGrp->crsl_usr_info.owner_id > MAX_SPECIAL_OWNER_ID
1831  || pSGrp->crsl_usr_info.group_id > MAX_SPECIAL_GROUP_ID )
1832  #endif
1833  {
1834  if ( last > pSGrp->last_accessed )
1835  {
1836  last = pSGrp->last_accessed;
1837  }
1838  }
1839  pSGrp = pSGrp->next;
1840  }
1841  while (pSGrp != NULL);
1842 
1843  pSGrp = stored_group_list;
1844  while (pSGrp != NULL)
1845  {
1846  if (last == pSGrp->last_accessed)
1847  {
1848  DeleteAllFiles( pSGrp );
1849  FileGroupRemove( pSGrp );
1850  FileGroupFree( pSGrp );
1851  found = TRUE;
1852  break;
1853  }
1854  pSGrp = pSGrp->next;
1855  }
1856  return found;
1857 }
1858 
1859 static void RequestManifest(S_DsmccEvent *params)
1860 {
1861  H_ObjCarousel hOC = params->hCarousel;
1862  if (fgTimerOC == hOC)
1863  {
1864  if (hOC == DSMCC_CurrentCarousel(MHEG5_DsmccInstance()))
1865  {
1866  ClearManRequest(hOC);
1867  AddManRequest(hOC);
1868  FetchManifests( hOC, 0 );
1869  }
1870  /* else ignore - could be re-booting with new carousel */
1871  }
1872 }
1873 
1874 static void ManifestTimeoutFunc( BOOLEAN trig, void *ptr, H_Timer timer )
1875 {
1876  H_ObjCarousel hOC = (H_ObjCarousel) ptr;
1877  S_MhegMessage event_msg;
1878  if (trig == TRUE)
1879  {
1880  TRACE(TERROR, ("fgRequestCount=%d", fgRequestCount))
1881  event_msg.proc_msg_func = (F_MSG_PROCESS)RequestManifest;
1882  event_msg.data_type = DT_NONE;
1883  event_msg.data.dsmEvent.hCarousel = hOC;
1884  VQ_PutMsg(&event_msg, PRTY_NORMAL);
1885  }
1886  if (timer == fgManifestTimer)
1887  {
1888  fgManifestTimer = NULL;
1889  }
1890 }
1891 
1892 static void SetManifestTimer(H_ObjCarousel hOC)
1893 {
1894  if (fgRequestCount != MANIFEST_TIME_STOP)
1895  {
1896  fgRequestCount++;
1897  if (fgManifestTimer != NULL)
1898  {
1899  VT_TimerDestroy( fgManifestTimer );
1900  fgManifestTimer = NULL;
1901  }
1902  fgTimerOC = hOC;
1903  (void)VT_TimerCreate( MANIFEST_TIMEOUT, ManifestTimeoutFunc, (void *) hOC, &fgManifestTimer );
1904  }
1905 }
1906 
1914 static S_STORED_GROUP* ParseManifestFile( U8BIT *data, U32BIT size, void *gptr, H_ObjCarousel hOC )
1915 {
1916  S_CarouselInfoFileGroup *pGrp = (S_CarouselInfoFileGroup *)gptr;
1917  S_STORED_GROUP *pSGrp;
1918 
1919  pSGrp = DSMAlloc( sizeof(S_STORED_GROUP));
1920  if (pSGrp == NULL)
1921  {
1922  TRACE(TERROR, ("malloc()"))
1923  }
1924  else
1925  {
1926  tmp_group_size = 0;
1927  tmp_group_version = pGrp->group_version;
1928 
1929  memset(pSGrp, 0, sizeof(S_STORED_GROUP));
1930 
1931  TRACE(TDSMFG, ("owner_id 0x%x, group_id 0x%x, use_flags 0x%x, ver 0x%x", pGrp->owner_id, pGrp->group_id, pGrp->use_flags, pGrp->group_version))
1932  if (JSON_Parse( data, size, file_group_members, pSGrp ) != JSON_OKAY)
1933  {
1934  FileGroupFree( pSGrp );
1935  pSGrp = NULL;
1936  }
1937  else if (tmp_group_version != pGrp->group_version)
1938  {
1939  TRACE(TERROR, ("Version mis-match file:0x%x srg:0x%x", tmp_group_version, pGrp->group_version))
1940  FileGroupFree( pSGrp );
1941  pSGrp = NULL;
1942  /* Set a timer to re-load the file groups - assuming there is a delay
1943  * between signalling of new version and transmission of its manifest file */
1944  SetManifestTimer(hOC);
1945  }
1946  else
1947  {
1948  /* reset global request counter, since we have received manifest file with correct version */
1949  fgRequestCount = 0;
1950 
1951  if (tmp_group_size == 0 || pSGrp->total_nodes == 0 || pSGrp->nodes == NULL ||
1952  tmp_group_size + size + MAX_MAN_HDR_SIZE > fg_nvm_max_limit)
1953  {
1954  if (tmp_group_size == 0 || pSGrp->total_nodes == 0 || pSGrp->nodes == NULL)
1955  {
1956  TRACE(TDSMFG,("Delete empty group (%x,%x)",pGrp->owner_id,pGrp->group_id))
1957  }
1958  else
1959  {
1960  TRACE(TERROR, ("FG Cache overflow; required:0x%x maximum:0x%x", (tmp_group_size+size+MAX_MAN_HDR_SIZE), fg_nvm_max_limit))
1961  }
1962  /* remove new group - do this way in case of any allocs during JSON parse */
1963  FileGroupFree( pSGrp );
1964  pSGrp = NULL;
1965  /* Group should no longer exist in the store either */
1966  DeleteStoredGroup( pGrp->owner_id, pGrp->group_id );
1967  }
1968  else
1969  {
1970  /* New file group */
1971  pSGrp->group_size = tmp_group_size;
1972  pSGrp->file_version = (U16BIT)tmp_group_version;
1973  pSGrp->crsl_usr_info = *pGrp;
1974  pSGrp->loc_str = MH5GlueStringCreate( strlen((char *) pGrp->location), pGrp->location );
1975  pSGrp->origin = GetOrigin(pSGrp->loc_str,&(pSGrp->offset));
1976  #ifdef INCLUDE_SA_PROFILE
1978  && pGrp->owner_id <= MAX_SPECIAL_OWNER_ID
1979  && pGrp->group_id <= MAX_SPECIAL_GROUP_ID )
1980  {
1981  TRACE(TDSMFG,("Loading new group %x,%x ver %d",pGrp->owner_id,pGrp->group_id,tmp_group_version))
1982  pSGrp->status = FGS_LOADING;
1983  }
1984  else
1985  #endif
1986  {
1987  TRACE(TDSMFG,("Delete old stale group (%x,%x) new ver %d",pGrp->owner_id,pGrp->group_id,tmp_group_version))
1988  DeleteStoredGroup( pGrp->owner_id, pGrp->group_id );
1989  #ifdef INCLUDE_AU_PROFILE
1990  if ( !(pSGrp->crsl_usr_info.use_flags & USE_FROM_CAROUSEL) )
1991  {
1992  pSGrp->status = FGS_PENDING;
1993  }
1994  else
1995  #endif
1996  {
1997  pSGrp->status = FGS_ACTIVE;
1998  }
1999  }
2000  /* before add to the list, check the cache available size */
2001  tmp_group_size += size + MAX_MAN_HDR_SIZE; /* add max man file size */
2002  while (tmp_group_size + FileGroupTotalSize() > fg_nvm_max_limit)
2003  {
2004  if ( !RemoveLeastDesiredGroup() ) break;
2005  }
2006  /* add group to list */
2007  pSGrp->next = stored_group_list;
2008  stored_group_list = pSGrp;
2009  }
2010  }
2011  }
2012  return pSGrp;
2013 }
2014 
2023 static U32BIT SaveManifestFile( const char *fname, U8BIT *data, U32BIT size, S_CarouselInfoFileGroup *pFG )
2024 {
2025  void *file;
2026  U32BIT hdr_size, val;
2027  S_JSON_MEMBERS *pJM;
2028  S_STRING location;
2029  char *pCh;
2030  char hdr_data[MAX_MAN_HDR_SIZE];
2031 
2032  TRACE(TDSMFG, (" %s", fname))
2033 
2034  file = STB_NVMOpenFile( (U8BIT*)fname, FILE_MODE_OVERWRITE );
2035  if (file == NULL)
2036  {
2037  TRACE(TERROR, ("STB_NVMOpenFile failed for %s", fname))
2038  hdr_size = 0;
2039  }
2040  else
2041  {
2042  hdr_data[0] = '{';
2043  hdr_size = 1;
2044  /* there are three fields in header
2045  * 1. owner and group IDs
2046  * 2. the other four (one byte) properties
2047  * 3. group location (path)
2048  */
2049  pJM = fg_cache_members;
2050  pJM->u.p_uint = (U32BIT *)pFG;
2051  pJM[1].u.p_uint = pJM->u.p_uint + 1;
2052  pJM[2].u.p_str = &location;
2053  location.zptr = pFG->location;
2054  location.zlen = strlen((char *) location.zptr);
2055  while (pJM->tk_len != 0)
2056  {
2057  if (hdr_size != 1)
2058  {
2059  hdr_data[hdr_size++] = ',';
2060  hdr_data[hdr_size++] = '\n';
2061  }
2062  hdr_data[hdr_size++] = '\"';
2063  memcpy(hdr_data + hdr_size, pJM->tk_str, pJM->tk_len);
2064  hdr_size += pJM->tk_len;
2065  hdr_data[hdr_size++] = '\"';
2066  hdr_data[hdr_size++] = ':';
2067  switch (pJM->type)
2068  {
2069  case JST_PTR_INTEGER:
2070  memcpy(hdr_data + hdr_size, " ", 10);
2071  hdr_size += 10;
2072  pCh = hdr_data + hdr_size - 1;
2073  *pCh = '0';
2074  val = *pJM->u.p_uint;
2075  while (val != 0)
2076  {
2077  *pCh = '0' + (val % 10);
2078  val /= 10;
2079  pCh--;
2080  }
2081  break;
2082  case JST_PTR_ASTRING:
2083  hdr_data[hdr_size++] = '\"';
2084  val = pJM->u.p_str->zlen;
2085  if (val)
2086  {
2087  memcpy(hdr_data + hdr_size, pJM->u.p_str->zptr, val);
2088  hdr_size += val;
2089  }
2090  hdr_data[hdr_size++] = '\"';
2091  break;
2092  default:;
2093  }
2094  pJM++;
2095  }
2096  hdr_data[hdr_size++] = '\n';
2097  if (STB_NVMWriteFile( file, (U8BIT *)hdr_data, hdr_size) == hdr_size &&
2098  STB_NVMWriteFile( file, data, size ) == size &&
2099  STB_NVMWriteFile( file, (U8BIT *)"}\n", 2 ) == 2)
2100  {
2101  hdr_size += size + 2;
2102  }
2103  else
2104  {
2105  TRACE(TERROR, ("STB_NVMWriteFile failed for %s", fname))
2106  hdr_size = 0;
2107  }
2108  STB_NVMCloseFile( file );
2109  }
2110  return hdr_size;
2111 }
2112 
2119 void ManifestLoadGood( void *userData, S_CONTENT *pContent )
2120 {
2121  S_CarouselInfoFileGroup *pFG;
2122  S_FGManifest *pFgm;
2123  S_STORED_GROUP *pSGrp;
2124  S_ManRequest *pManRqst;
2125  char filename[16];
2126  U32BIT size;
2127  TRACE(TDSMFG, ("##########################"));
2128  assert( fg_manifest_rqst != NULL );
2129  pFG = (S_CarouselInfoFileGroup *)userData;
2130  pManRqst = fg_manifest_rqst;
2131  while (pManRqst != NULL)
2132  {
2133  if (pFG >= pManRqst->pFG && pFG < (pManRqst->pFG + pManRqst->total))
2134  {
2135  break;
2136  }
2137  pManRqst = pManRqst->next;
2138  }
2139  if (pManRqst == NULL)
2140  {
2141  TRACE(TERROR,("Manifest request not found"))
2142  }
2143  else
2144  {
2145  assert( pManRqst->outstanding != 0 );
2146  pFgm = (S_FGManifest *)(pManRqst + 1);
2147  pFgm += pFG - pManRqst->pFG;
2148  pFgm->ormRqst = NULL;
2149 
2150  pSGrp = ParseManifestFile( pContent->data, pContent->size, pFG, pManRqst->hOC );
2151  if (pSGrp != NULL)
2152  {
2153  /* reconstruct filename from owner and group ids */
2154  SetFilename( pFG->owner_id, pFG->group_id, filename );
2155  if (pSGrp->status == FGS_LOADING)
2156  {
2157  /* Set first char of name to offset char -avoiding clash with original stored group name */
2158  filename[0] += NAME_CHAR_OFFSET;
2159  }
2160  size = SaveManifestFile( filename, pContent->data, pContent->size, pFG );
2161  if (size == 0)
2162  {
2163  FileGroupRemove( pSGrp );
2164  FileGroupFree( pSGrp );
2165  }
2166  else
2167  {
2168  pSGrp->hOC = pManRqst->hOC;
2169  pSGrp->man_file_size = size;
2170  pSGrp->last_accessed = STB_OSGetClockMilliseconds();
2171  /* next assumes GROUP_DIR_LEN is 8 */
2172  memcpy( pSGrp->dir_name, filename, 4 );
2173  memcpy( pSGrp->dir_name + 4, filename + 5, 4 );
2174  /* make requests for all files in the group */
2175  if (!(pSGrp->crsl_usr_info.use_flags & USE_FROM_CAROUSEL))
2176  {
2177  LoadAllFileData( pSGrp, pManRqst->cachePriority );
2178  }
2179  else
2180  {
2181  GetAllFileData( pSGrp, pManRqst->cachePriority );
2182  }
2183  }
2184  }
2185  if (pContent->destroy)
2186  {
2187  pContent->destroy( pContent->fs_handle );
2188  pContent->destroy = NULL;
2189  pContent->fs_handle = NULL;
2190  }
2191 
2192  /* clear content's user_data so that can later detect which is still outstanding */
2193  pManRqst->outstanding--;
2194  if (!pManRqst->outstanding)
2195  {
2196  DSMCC_ClientUnloadFileGroups( pManRqst->dsmInst, pManRqst->hOC, pManRqst->pFG );
2197  }
2198  }
2199 }
2200 
2207 void ManifestLoadFail( void *userData )
2208 {
2209  S_CarouselInfoFileGroup *pFG;
2210  S_FGManifest *pFgm;
2211  S_ManRequest *pManRqst;
2212  TRACE(TDSMFG, ("##########################"));
2213  assert( fg_manifest_rqst != NULL );
2214  pFG = (S_CarouselInfoFileGroup *)userData;
2215  pManRqst = fg_manifest_rqst;
2216  while (pManRqst != NULL)
2217  {
2218  if (pFG >= pManRqst->pFG && pFG < (pManRqst->pFG + pManRqst->total))
2219  {
2220  break;
2221  }
2222  pManRqst = pManRqst->next;
2223  }
2224  if (pManRqst == NULL)
2225  {
2226  TRACE(TERROR,("Manifest request not found"))
2227  }
2228  else
2229  {
2230  assert( pManRqst->outstanding != 0 );
2231  pFgm = (S_FGManifest *)(pManRqst + 1);
2232  pFgm += pFG - pManRqst->pFG;
2233  pFgm->ormRqst = NULL;
2234 
2235  /* clear content's user_data so that can later detect which is still outstanding */
2236  pManRqst->outstanding--;
2237  if (!pManRqst->outstanding)
2238  {
2239  DSMCC_ClientUnloadFileGroups( pManRqst->dsmInst, pManRqst->hOC, pManRqst->pFG );
2240  }
2241  }
2242 }
2243 
2244 static void SwitchToNewStoredGroup(S_STORED_GROUP* pSGrp)
2245 {
2246  S_STORED_GROUP* pOrigSG;
2247  U8BIT oldname[16];
2248  U8BIT newname[16];
2249  U8BIT olddir[10];
2250  U8BIT newdir[10];
2251  BOOLEAN error = FALSE;
2252 
2253  assert(pSGrp->crsl_usr_info.owner_id <= MAX_SPECIAL_OWNER_ID && pSGrp->crsl_usr_info.group_id <= MAX_SPECIAL_GROUP_ID);
2254 
2255  SetFilename( pSGrp->crsl_usr_info.owner_id, pSGrp->crsl_usr_info.group_id, oldname );
2256  strcpy(newname,oldname);
2257  memcpy( olddir, oldname, 4 );
2258  memcpy( olddir+4, oldname+5, 4 );
2259  olddir[8] = 0;
2260  strcpy(newdir,olddir);
2261 
2262  pOrigSG = stored_group_list;
2263  while ( pOrigSG != NULL )
2264  {
2265  if ( pOrigSG->crsl_usr_info.owner_id == pSGrp->crsl_usr_info.owner_id
2266  && pOrigSG->crsl_usr_info.group_id == pSGrp->crsl_usr_info.group_id )
2267  {
2268  assert( memcmp(olddir,pOrigSG->dir_name,8) == 0 );
2269  newname[1] += NAME_CHAR_OFFSET;
2270  newdir[1] += NAME_CHAR_OFFSET;
2271  if ( !STB_NVMMoveFile( oldname, newname ) )
2272  {
2273  error = TRUE;
2274  }
2275  else if ( !STB_NVMMoveFile( olddir, newdir ) )
2276  {
2277  error = TRUE;
2278  STB_NVMMoveFile( newname, oldname );
2279  }
2280  else
2281  {
2282  memcpy( pOrigSG->dir_name, newdir, 8 );
2283  }
2284  newname[1] -= NAME_CHAR_OFFSET;
2285  newdir[1] -= NAME_CHAR_OFFSET;
2286  break;
2287  }
2288  pOrigSG = pOrigSG->next;
2289  }
2290  if (!error)
2291  {
2292  oldname[0] += NAME_CHAR_OFFSET;
2293  olddir[0] += NAME_CHAR_OFFSET;
2294  assert( memcmp(olddir,pSGrp->dir_name,8) == 0 );
2295  if ( !STB_NVMMoveFile( oldname, newname ) )
2296  {
2297  error = TRUE;
2298  }
2299  else if ( !STB_NVMMoveFile( olddir, newdir ) )
2300  {
2301  error = TRUE;
2302  STB_NVMMoveFile( newname, oldname );
2303  }
2304  if ( error )
2305  {
2306  TRACE(TERROR,("failed to move to new Store group: %s",newdir))
2307  if (pOrigSG != NULL)
2308  {
2309  /* Restore old group */
2310  oldname[0] -= NAME_CHAR_OFFSET;
2311  olddir[0] -= NAME_CHAR_OFFSET;
2312  newname[1] += NAME_CHAR_OFFSET;
2313  newdir[1] += NAME_CHAR_OFFSET;
2314  STB_NVMMoveFile( newname, oldname );
2315  STB_NVMMoveFile( newdir, olddir );
2316  memcpy( pOrigSG->dir_name, olddir, 8 );
2317  }
2318  DeleteAllFiles( pSGrp );
2319  FileGroupRemove( pSGrp );
2320  FileGroupFree( pSGrp );
2321  }
2322  else
2323  {
2324  memcpy( pSGrp->dir_name, newname, 8 );
2325  pSGrp->status = FGS_ACTIVE;
2326  if (pOrigSG != NULL)
2327  {
2328  DeleteAllFiles( pOrigSG );
2329  FileGroupRemove( pOrigSG );
2330  FileGroupFree( pOrigSG );
2331  }
2332  }
2333  }
2334 }
2335 
2345 static void FileLoadedGood( void *userData, S_CONTENT *pContent )
2346 {
2347  S_DSM_FILE_RQST *pDsmRqst = (S_DSM_FILE_RQST *)userData;
2348  S_STORED_GROUP *pSGrp = pDsmRqst->sfg;
2349  U32BIT size = pContent->size;
2350  U8BIT *data = NULL;
2351  void *file;
2352 
2353  TRACE(TDSMFG, ("########### GOOD ###############"));
2354 
2355  /* Update NVM copy of file data */
2356  file = STB_NVMOpenFile((U8BIT*) pDsmRqst->fname, FILE_MODE_OVERWRITE);
2357  if (file != NULL)
2358  {
2359  if (STB_NVMWriteFile(file, pContent->data, size) != size)
2360  {
2361  TRACE(TERROR, ("STB_NVMWriteFile failed for %s", pDsmRqst->fname))
2362  }
2363  STB_NVMCloseFile( file );
2364  }
2365  switch (pSGrp->status)
2366  {
2367  case FGS_ACTIVE:
2368  case FGS_LOADING:
2369  if (size > MAX_SIZE_OF_CACHED_FILE)
2370  {
2371  break;
2372  }
2373  /* else fall though */
2374  case FGS_PENDING:
2375  /* FG keeps a copy of file data memory */
2376  data = DSMAlloc((size == 0) ? 1 : size );
2377  if (data == NULL)
2378  {
2379  TRACE(TERROR, ("malloc(%d)", size))
2380  }
2381  break;
2382  default:;
2383  }
2384  if (data == NULL)
2385  {
2386  TRACE(TDSMFG, ("Using DSMCC content data"))
2387  *(pDsmRqst->pFgCtnt) = *pContent;
2388  memset(pContent,0,sizeof(S_CONTENT));
2389  pContent = pDsmRqst->pFgCtnt;
2390  }
2391  else
2392  {
2393  if (size == 0)
2394  {
2395  data[0] = 0;
2396  }
2397  else
2398  {
2399  memcpy(data, pContent->data, size);
2400  }
2401  /* free DSM memory resource */
2402  if (pContent->destroy)
2403  {
2404  pContent->destroy( pContent->fs_handle );
2405  memset(pContent,0,sizeof(S_CONTENT));
2406  }
2407  /* Save data in FG Content */
2408  pContent = pDsmRqst->pFgCtnt;
2409  pContent->size = size;
2410  pContent->data = data;
2411  pContent->destroy = DSMFree;
2412  pContent->fs_handle = data;
2413  }
2414  switch (pSGrp->status)
2415  {
2416  case FGS_ACTIVE:
2417  /* find and fulfil any Client request for this file */
2418  if (!FulfilRequest( pContent, FS_STATUS_OK ))
2419  {
2420  TRACE(TERROR,("Request not found for %s",pDsmRqst->fname))
2421  if (data == NULL && pContent->destroy != NULL)
2422  {
2423  pContent->destroy( pContent->fs_handle );
2424  pContent->destroy = NULL;
2425  pContent->fs_handle = NULL;
2426  pContent->data = NULL;
2427  }
2428  }
2429  break;
2430  case FGS_LOADING:
2431  if ( !HasMissingFileData(pSGrp) )
2432  {
2433  SwitchToNewStoredGroup(pSGrp);
2434  }
2435  break;
2436  case FGS_PENDING:
2437  if (!HasMissingFileData(pSGrp))
2438  {
2439  pSGrp->status = FGS_ACTIVE;
2440  if (fg_request_head != NULL)
2441  {
2442  FulfilOutstandingFileRequests( pSGrp, FS_STATUS_OK );
2443  }
2444  }
2445  break;
2446  default:;
2447  }
2448  pContent->user_data = NULL;
2449  DSMFree( pDsmRqst );
2450 }
2451 
2457 static void FileLoadedFail( void *userData )
2458 {
2459  S_DSM_FILE_RQST *pDsmRqst = (S_DSM_FILE_RQST *)userData;
2460  S_STORED_GROUP *pSGrp = pDsmRqst->sfg;
2461 
2462  TRACE(TDSMFG, ("########### FAIL ###############"));
2463  switch (pSGrp->status)
2464  {
2465  case FGS_ACTIVE:
2466  FulfilRequest( pDsmRqst->pFgCtnt, FS_STATUS_ERROR );
2467  break;
2468  case FGS_LOADING:
2469  break;
2470  case FGS_PENDING:
2471  pSGrp->status = FGS_ERROR;
2472  if (fg_request_head != NULL)
2473  {
2474  TRACE(TERROR, (" status Error, use_flg 0x%x", pSGrp->crsl_usr_info.use_flags))
2475  FulfilOutstandingFileRequests( pSGrp, FS_STATUS_ERROR );
2476  }
2477  break;
2478  default:;
2479  }
2480  pDsmRqst->pFgCtnt->user_data = NULL;
2481  DSMFree( pDsmRqst );
2482 }
2483 
2484 /*---local function definitions----------------------------------------------*/
2485 
2486 
2487 static void* NodesArray( unsigned int val, void *array, void *gptr )
2488 {
2489  S_STORED_GROUP *pSGrp;
2490  S_NODE *pNode = NULL;
2491  switch (val)
2492  {
2493  case JSON_VALUE_FINISH:
2494  TRACE(TDSMFG, ("Array FINISH"))
2495  break;
2496 
2497  case JSON_VALUE_ERROR:
2498  TRACE(TERROR, ("Array ERROR"))
2499  break;
2500 
2501  default:
2502  /* val is number of nodes */
2503  if (gptr != NULL)
2504  {
2505  pSGrp = (S_STORED_GROUP *)gptr;
2506  pSGrp->total_nodes = val;
2507  if (val == 0)
2508  {
2509  TRACE(TDSMFG,("Group has zero nodes - it will be deleted"))
2510  }
2511  else
2512  {
2513  pNode = DSMAlloc( val * sizeof(S_NODE));
2514  if (pNode != NULL)
2515  {
2516  memset(pNode, 0, val * sizeof(S_NODE));
2517  }
2518  }
2519  pSGrp->nodes = pNode;
2520  tmp_node_filename.zlen = 0;
2521  tmp_node_filename.zptr = NULL;
2522  tmp_node_count = 0;
2523  }
2524  }
2525  return pNode;
2526 }
2527 
2528 static void* NodeFinish( unsigned int val, void *array, void *gptr )
2529 {
2530  S_NODE *pNode;
2531  char *pName;
2532  if (val == JSON_VALUE_FINISH && gptr != NULL && tmp_node_filename.zptr != NULL)
2533  {
2534  pNode = (S_NODE *)gptr;
2535 
2536  TRACE(TDSMFG, ("File=%.*s", (int)tmp_node_filename.zlen, tmp_node_filename.zptr))
2537 
2538  /* Strip off leading slashes and backslashes */
2539  while (tmp_node_filename.zlen != 0 &&
2540  ((*tmp_node_filename.zptr == '/') || (*tmp_node_filename.zptr == '\\')))
2541  {
2542  tmp_node_filename.zptr++;
2543  tmp_node_filename.zlen--;
2544  }
2545  if (tmp_node_filename.zlen != 0) /*should always be non-zero if it's a sensible file name*/
2546  {
2547  if (tmp_node_count == 0)
2548  {
2549  pName = (char *)STR_DataAlloc( tmp_node_filename.zlen );
2550  }
2551  else
2552  {
2553  /* reserve 3 extra bytes for '000' extension <- used by GetAllFileData() */
2554  pName = (char *)STR_DataAlloc( tmp_node_filename.zlen + 3 );
2555  }
2556  if (pName != NULL)
2557  {
2558  memcpy(pName, tmp_node_filename.zptr, tmp_node_filename.zlen);
2559  pName[tmp_node_filename.zlen] = 0;
2560  pNode->nfname = pName;
2561  pNode->nflen = (U16BIT)tmp_node_filename.zlen;
2562  if (tmp_node_count == 0)
2563  {
2564  memset( &(pNode->u.content), 0, sizeof(S_CONTENT));
2565  pNode->count = 0;
2566  }
2567  else
2568  {
2569  S_CONTENT *pCtnt;
2570 
2571  pName[tmp_node_filename.zlen + 3] = 0; /*null extra end char*/
2572 
2573  if (tmp_node_count > 999)
2574  {
2575  tmp_node_count = 999;
2576  }
2577  pCtnt = (S_CONTENT *)DSMAlloc( tmp_node_count * sizeof(S_CONTENT));
2578  if (pCtnt != NULL)
2579  {
2580  memset(pCtnt, 0, tmp_node_count * sizeof(S_CONTENT));
2581  pNode->count = (U16BIT)tmp_node_count;
2582  pNode->u.contents = pCtnt;
2583  }
2584  else
2585  {
2586  TRACE(TERROR, ("malloc(%ld)", tmp_node_count * sizeof(S_CONTENT)))
2587  }
2588  }
2589  }
2590  pNode++; /* return pointer to next node */
2591  }
2592  tmp_node_count = 0;
2593  tmp_node_filename.zptr = NULL;
2594  }
2595  else
2596  {
2597  pNode = NULL;
2598  }
2599  return pNode;
2600 }
2601 
2602 #endif /*INCLUDE_DSM_FG*/
U32BIT STB_OSGetClockMilliseconds(void)
Get Current Computer Clock Time.
void * STB_NVMOpenFile(U8BIT *name, E_STB_DSK_FILE_MODE mode)
Opens an existing file or creates a new one.
const char * tk_str
Definition: mh5json.h:107
E_MhegErr VQ_PutMsg(S_MhegMessage *pMsg, E_PRIORITY priority)
Post event or section message on queue. Copies data into queue.
Definition: glue_queue.c:248
void FG_FactoryReset(void)
In the "factory reset", we clear all file groups from cache store. Then re-aquire file groups for the...
#define JSON_VALUE_FINISH
Definition: mh5json.h:34
F_DESTROY destroy
Definition: fs_types.h:56
void STB_NVMCloseDirectory(void *dir)
Closes the directory for reading.
S_STRING MH5GlueStringCreate(U32BIT size, U8BIT *data)
Definition: glue_memory.c:956
union s_json_members::@9 u
U32BIT size
Definition: fs_types.h:54
E_JSON_STATE JSON_Parse(U8BIT *data, U32BIT size, const S_JSON_MEMBERS *members, void *usr)
Definition: mh5json.c:78
File acceleration for Australia and Souh Africa.
Interface functions to DSM-CC instance for MHEG5.
E_MhegErr VT_TimerCreate(U32BIT millisecs, F_TimerCallback callback, void *callerRef, H_Timer *pTimerHandle)
Set a timer for a certain number of millseconds. When the timer expires a specified callback will be ...
Definition: glue_timers.c:223
MHEG5Bool MHEG5ResolveOrigin(MHEG5String *ref, E_FS_ORIGIN *pOrigin, MHEG5Int *offset)
Resolve the origin of a reference.
Definition: mh5gate.c:208
H_ObjCarousel hCarousel
Definition: glue_queue.h:87
void FG_NotifyCarouselUnLoaded(H_ObjCarousel hOC)
Tell File Group that the Object Carousel has been unloaded, so all file groups on this carousel shoul...
const char * data
Definition: mh5gate.c:56
void * H_Timer
Definition: glue_timers.h:58
MHEG5Bool MH5_SupportHDGraphics(void)
Returns whether supporting HD Graphics extension.
Definition: mh5support.c:465
#define DECLARE_OBJEND()
Definition: mh5json.h:43
void FG_NotifyListChanged(S_DsmccEvent *param)
Tell File Group that File Groups have changed in Object Carousel&#39;s SRG User Info. ...
Debug tracing.
MHEG5 queue.
void * MHEG5FileOrmRetrieve(E_FS_ORIGIN origin, S_STRING location, S_STRING name, U16BIT priority, void *userData, F_CB_Good cbGood, F_CB_Fail cbFail)
Retrieve of a file. The file will be loaded and one of the callback functions called when request is ...
Definition: mh5fileorm.c:1290
unsigned char * STR_DataAlloc(unsigned int size)
Definition: glue_memory.c:596
E_STB_DIR_ENTRY_TYPE
Definition: stb_nvm.h:48
unsigned int tk_len
Definition: mh5json.h:106
BOOLEAN STB_NVMMoveFile(U8BIT *oldname, U8BIT *newname)
Move/Rename a file or a directory. The original name and the new name may contain a path - the last e...
#define JSON_VALUE_ERROR
Definition: mh5json.h:35
#define DECLARE_MEMBER(token_str, type, ptr, child_object)
Definition: mh5json.h:39
E_FsStatus FG_LoadRequest(E_FS_ORIGIN origin, const char *fname, F_FS_CALLBACK cb_func, S_CONTENT *pContent, U8BIT cachePriority)
Request file from file group stores.
MHEG5Bool MH5_SupportPVRExtension(void)
Return whether PVR extension (ETSI, and originally NZ) is supported.
Definition: mh5support.c:498
void * MHEG5_DsmccInstance(void)
Get the DSMCC instance handle.
Definition: glue_dsmcc.c:778
void STB_NVMCloseFile(void *file)
Flushes and closes an open file.
U8BIT * zptr
Definition: dtvstring.h:31
void MH5GlueStringFree(S_STRING *pStr)
Definition: glue_memory.c:986
#define FRP_CACHE_DEFAULT
Definition: mh5fileorm.h:38
MHEG5Bool MH5_SupportICStreaming(void)
Return whether Interaction channel Streaming is supported.
Definition: mh5support.c:436
BOOLEAN STB_NVMFileSize(U8BIT *filename, U32BIT *filesize)
Returns the size in KB of the given file.
#define MAX_PATH_LEN
Definition: mh5tps.c:48
void(* F_MSG_PROCESS)(void *data)
Function to Process voyager message.
Definition: glue_queue.h:70
uint8_t U8BIT
Definition: techtype.h:82
void * STB_NVMOpenDirectory(U8BIT *dir_name)
Opens a directory in order to read the entries.
long MHEG5Int
Definition: mh5base.h:73
MHEG5Bool MH5_SupportHDVideo(void)
Returns whether supporting HD Video extension.
Definition: mh5support.c:474
Memory functions.
void STR_DataFree(unsigned char *data, unsigned int size)
Definition: glue_memory.c:668
Implement Functions to support Service Gateways. Functions for standarizing several GroupIDs like +DS...
E_JSON_TYPE type
Definition: mh5json.h:108
short MHEG5Bool
Definition: mh5base.h:71
U32BIT STB_NVMReadFile(void *file, U8BIT *data, U32BIT size)
Reads data from an open file.
MHEG5Byte * data
Definition: mh5base.h:85
#define MHEG5TRUE
Definition: mh5base.h:49
MHEG5Bool MH5_SupportNativeApplication(void)
Return whether Native Application extension is supported.
Definition: mh5support.c:483
#define MHEG5strncmp(a, b, n)
Definition: mh5base.h:52
uint16_t U16BIT
Definition: techtype.h:84
#define DSMAlloc
Definition: glue_memory.h:87
File System types.
void * user_data
Definition: fs_types.h:58
BOOLEAN STB_NVMReadDirectory(void *dir, U8BIT *filename, U16BIT filename_len, E_STB_DIR_ENTRY_TYPE *entry_type)
Reads the next entry from the directory, returning the name of the entry and the type of the entry...
MHEG5Bool MH5_SupportMhegProfile(E_MHEG_PROFILE profile)
Return whether Mheg profile (UK, NZ, AU, HK, SA, FREESAT) is currently supported. ...
Definition: mh5support.c:451
File interface functions to DSMCC component.
string parsing utility functions described by the [JSON] schema
U32BIT STB_NVMWriteFile(void *file, U8BIT *data, U32BIT size)
Writes data to an open file.
#define FALSE
Definition: techtype.h:68
The timer module allows the use of timers within the MHEG5 component. These timers can be set by othe...
#define DSMFree
Definition: glue_memory.h:88
void FG_Initialise(U32BIT nvmSize)
Initialise - retrieve data from NVM storage for any file groups and allocate the file group list...
MHEG5Bool MH5_SupportInteractionChannel(void)
Return whether Interaction channel is supported by current profile.
Definition: mh5support.c:423
MHEG5Int len
Definition: mh5base.h:84
MHEG5Bool MH5_SupportServiceInfoExtension(void)
Return whether Service Info extension is supported.
Definition: mh5support.c:513
U8BIT * data
Definition: fs_types.h:55
U8BIT BOOLEAN
Definition: techtype.h:99
U32BIT zlen
Definition: dtvstring.h:30
#define TRUE
Definition: techtype.h:69
void FG_Terminate(void)
Terminate - free data associated with all file groups.
FS_HANDLE fs_handle
Definition: fs_types.h:57
MHEG5Bool MH5_SupportFontClass(void)
Return whether font class is supported by current profile.
Definition: mh5support.c:560
S_STRING * p_str
Definition: mh5json.h:114
E_FS_ORIGIN
Definition: mh5gate.h:48
void FG_NotifyVersionChanged(S_DsmccEvent *param)
Tell File Group of version changed for File Group(s) in Object Carousel&#39;s SRG User Info...
void FG_NotifyListLoaded(S_DsmccEvent *param)
Tell File Group that File Groups have loaded in Object Carousel&#39;s SRG User Info.
E_FsStatus FG_FileExists(E_FS_ORIGIN origin, const char *fname)
Request file from file group stores.
#define MHEG5FALSE
Definition: mh5base.h:48
uint32_t U32BIT
Definition: techtype.h:86
E_FsStatus
Definition: fs_types.h:34
E_MhegErr VT_TimerDestroy(H_Timer timerHandle)
Destroy the specified timer. A callback will not be invoked for this timer after this function return...
Definition: glue_timers.c:324
Engine support utility functions for MHEG5.
#define DECLARE_OBJECT(cb_func)
Definition: mh5json.h:41
BOOLEAN STB_NVMDeleteFile(U8BIT *filename)
Deletes the file.
#define TRACE(t, x)
Definition: glue_debug.h:118
Header file - Function prototypes for operating system.
U32BIT * p_uint
Definition: mh5json.h:113