Coverage Report

Created: 2026-01-23 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/scenegraph/vrml_script.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2012
6
 *          All rights reserved
7
 *
8
 *  This file is part of GPAC / Scene Graph sub-project
9
 *
10
 *  GPAC is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU Lesser General Public License as published by
12
 *  the Free Software Foundation; either version 2, or (at your option)
13
 *  any later version.
14
 *
15
 *  GPAC is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU Lesser General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU Lesser General Public
21
 *  License along with this library; see the file COPYING.  If not, write to
22
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
 *
24
 */
25
26
#include <gpac/internal/scenegraph_dev.h>
27
/*MPEG4 & X3D tags (for node tables & script handling)*/
28
#include <gpac/nodes_mpeg4.h>
29
#include <gpac/nodes_x3d.h>
30
#include "qjs_common.h"
31
32
#ifndef GPAC_DISABLE_VRML
33
34
35
static u32 script_get_nb_static_field(GF_Node *node)
36
0
{
37
0
  return (node->sgprivate->tag==TAG_MPEG4_Script) ? 3 : 4;
38
0
}
39
40
void Script_PreDestroy(GF_Node *node, void *eff, Bool is_destroy)
41
0
{
42
0
  GF_ScriptPriv *priv;
43
44
0
  if (!is_destroy) return;
45
46
0
  priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate;
47
48
0
  if (priv->JS_PreDestroy) priv->JS_PreDestroy(node);
49
50
  //destroy extra fields
51
0
  while (gf_list_count(priv->fields)) {
52
0
    GF_ScriptField *field = (GF_ScriptField *)gf_list_get(priv->fields, 0);
53
0
    gf_list_rem(priv->fields, 0);
54
0
    if (field->pField) {
55
      //if Node unregister
56
0
      switch (field->fieldType) {
57
      //specific case for GF_Node in script
58
0
      case GF_SG_VRML_SFNODE:
59
0
        gf_node_unregister((GF_Node *) field->pField, node);
60
0
        break;
61
0
      case GF_SG_VRML_MFNODE:
62
0
        gf_node_unregister_children(node, (GF_ChildNodeItem*) field->pField);
63
0
        break;
64
0
      default:
65
0
        gf_sg_vrml_field_pointer_del(field->pField, field->fieldType);
66
0
        break;
67
0
      }
68
0
    }
69
0
    if (field->name) gf_free(field->name);
70
0
    gf_free(field);
71
0
  }
72
0
  gf_list_del(priv->fields);
73
0
  gf_free(priv);
74
0
}
75
76
u32 gf_sg_script_get_num_fields(GF_Node *node, u8 IndexMode)
77
0
{
78
0
  u32 nb_static;
79
0
  GF_ScriptPriv *priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate;
80
0
  switch (IndexMode) {
81
0
  case GF_SG_FIELD_CODING_IN:
82
0
    return priv->numIn;
83
0
  case GF_SG_FIELD_CODING_OUT:
84
0
    return priv->numOut;
85
0
  case GF_SG_FIELD_CODING_DEF:
86
0
    return priv->numDef;
87
0
  case GF_SG_FIELD_CODING_DYN:
88
0
    return 0;
89
0
  default:
90
0
    nb_static = script_get_nb_static_field(node);
91
0
    return priv ? gf_list_count(priv->fields) + nb_static : nb_static;
92
0
  }
93
0
}
94
95
GF_EXPORT
96
GF_Err gf_sg_script_get_field_index(GF_Node *node, u32 inField, u8 IndexMode, u32 *allField)
97
0
{
98
0
  u32 i;
99
0
  GF_ScriptField *sf;
100
0
  u32 nb_static = script_get_nb_static_field(node);
101
0
  GF_ScriptPriv *priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate;
102
0
  i=0;
103
0
  while (priv && (sf = (GF_ScriptField *)gf_list_enum(priv->fields, &i))) {
104
0
    *allField = i-1+nb_static;
105
0
    switch (IndexMode) {
106
0
    case GF_SG_FIELD_CODING_IN:
107
0
      if ((u32)sf->IN_index==inField) return GF_OK;
108
0
      break;
109
0
    case GF_SG_FIELD_CODING_DEF:
110
0
      if ((u32)sf->DEF_index==inField) return GF_OK;
111
0
      break;
112
0
    case GF_SG_FIELD_CODING_OUT:
113
0
      if ((u32)sf->OUT_index==inField) return GF_OK;
114
0
      break;
115
0
    case GF_SG_FIELD_CODING_DYN:
116
0
      return GF_BAD_PARAM;
117
0
    default:
118
0
      if (inField==i-1+nb_static) return GF_OK;
119
0
      break;
120
0
    }
121
0
  }
122
  /*try with default*/
123
124
0
  if (gf_sg_mpeg4_node_get_field_count(node, IndexMode) <= inField)
125
0
    return GF_NON_COMPLIANT_BITSTREAM;
126
127
0
  return gf_sg_mpeg4_node_get_field_index(node, inField, IndexMode, allField);
128
0
}
129
130
131
GF_Err gf_sg_script_get_field(GF_Node *node, GF_FieldInfo *info)
132
0
{
133
0
  GF_ScriptField *field;
134
0
  GF_ScriptPriv *priv;
135
0
  u32 nb_static;
136
137
0
  if (!info || !node) return GF_BAD_PARAM;
138
139
0
  priv = (GF_ScriptPriv *)gf_node_get_private(node);
140
0
  nb_static = script_get_nb_static_field(node);
141
142
  //static fields
143
0
  if (info->fieldIndex < nb_static) {
144
0
    if (nb_static==3) return gf_sg_mpeg4_node_get_field(node, info);
145
0
#ifndef GPAC_DISABLE_X3D
146
0
    return gf_sg_x3d_node_get_field(node, info);
147
#else
148
    return GF_NOT_SUPPORTED;
149
#endif
150
0
  }
151
152
  //dyn fields
153
0
  field = (GF_ScriptField *)gf_list_get(priv->fields, info->fieldIndex - nb_static);
154
0
  if (!field) return GF_BAD_PARAM;
155
156
0
  info->eventType = field->eventType;
157
0
  info->fieldType = field->fieldType;
158
0
  info->name = field->name;
159
  //we need the eventIn name to activate the function...
160
0
  info->on_event_in = NULL;
161
162
  //setup pointer (special cases for nodes)
163
0
  switch (field->fieldType) {
164
0
  case GF_SG_VRML_SFNODE:
165
0
  case GF_SG_VRML_MFNODE:
166
0
    info->far_ptr = &field->pField;
167
0
    info->NDTtype = NDT_SFWorldNode;
168
0
    break;
169
0
  default:
170
0
    info->far_ptr = field->pField;
171
0
    break;
172
0
  }
173
0
  return GF_OK;
174
0
}
175
176
void gf_sg_script_init(GF_Node *node)
177
0
{
178
0
  GF_ScriptPriv *priv;
179
180
181
0
  GF_SAFEALLOC(priv, GF_ScriptPriv)
182
0
  if (!priv) {
183
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to create script node\n"));
184
0
    return;
185
0
  }
186
0
  priv->fields = gf_list_new();
187
188
0
  gf_node_set_private(node, priv);
189
0
  node->sgprivate->UserCallback = Script_PreDestroy;
190
191
  //URL is exposedField (in, out Def)
192
0
  priv->numDef = priv->numIn = priv->numOut = script_get_nb_static_field(node) - 2;
193
  //directOutput and mustEvaluate are fields (def)
194
0
  priv->numDef += 2;
195
0
}
196
197
GF_EXPORT
198
GF_ScriptField *gf_sg_script_field_new(GF_Node *node, u32 eventType, u32 fieldType, const char *name)
199
0
{
200
0
  GF_ScriptPriv *priv;
201
0
  GF_ScriptField *field;
202
0
  if (!name || ((node->sgprivate->tag != TAG_MPEG4_Script)
203
0
#ifndef GPAC_DISABLE_X3D
204
0
                && (node->sgprivate->tag != TAG_X3D_Script)
205
0
#endif
206
0
               ))
207
0
    return NULL;
208
209
0
  if (eventType > GF_SG_SCRIPT_TYPE_EVENT_OUT) return NULL;
210
0
  priv = (GF_ScriptPriv *)gf_node_get_private(node);
211
212
0
  GF_SAFEALLOC(field, GF_ScriptField)
213
0
  if (!field) {
214
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to create script field\n"));
215
0
    return NULL;
216
0
  }
217
0
  field->fieldType = fieldType;
218
0
  field->name = gf_strdup(name);
219
220
0
  field->DEF_index = field->IN_index = field->OUT_index = -1;
221
0
  switch (eventType) {
222
0
  case GF_SG_SCRIPT_TYPE_FIELD:
223
0
    field->DEF_index = priv->numDef;
224
0
    priv->numDef++;
225
0
    field->eventType = GF_SG_EVENT_FIELD;
226
0
    break;
227
0
  case GF_SG_SCRIPT_TYPE_EVENT_IN:
228
0
    field->IN_index = priv->numIn;
229
0
    priv->numIn++;
230
0
    field->eventType = GF_SG_EVENT_IN;
231
0
    break;
232
0
  case GF_SG_SCRIPT_TYPE_EVENT_OUT:
233
0
    field->OUT_index = priv->numOut;
234
0
    field->eventType = GF_SG_EVENT_OUT;
235
0
    priv->numOut++;
236
0
    break;
237
0
  }
238
  //+ static fields
239
0
  field->ALL_index = script_get_nb_static_field(node) + gf_list_count(priv->fields);
240
0
  gf_list_add(priv->fields, field);
241
242
  //create field entry
243
0
  if ((fieldType != GF_SG_VRML_SFNODE) && (fieldType != GF_SG_VRML_MFNODE) ) {
244
0
    field->pField = gf_sg_vrml_field_pointer_new(fieldType);
245
0
  }
246
247
0
  return field;
248
0
}
249
250
251
GF_Err gf_sg_script_prepare_clone(GF_Node *dest, GF_Node *orig)
252
0
{
253
0
  u32 i, type;
254
0
  GF_ScriptField *sf;
255
0
  GF_ScriptPriv *dest_priv, *orig_priv;
256
0
  orig_priv = (GF_ScriptPriv *)orig->sgprivate->UserPrivate;
257
0
  dest_priv = (GF_ScriptPriv *)dest->sgprivate->UserPrivate;
258
0
  if (!orig_priv || !dest_priv) return GF_BAD_PARAM;
259
260
0
  i=0;
261
0
  while ((sf = (GF_ScriptField *)gf_list_enum(orig_priv->fields, &i))) {
262
0
    switch (sf->eventType) {
263
0
    case GF_SG_EVENT_IN:
264
0
      type = GF_SG_SCRIPT_TYPE_EVENT_IN;
265
0
      break;
266
0
    case GF_SG_EVENT_OUT:
267
0
      type = GF_SG_SCRIPT_TYPE_EVENT_OUT;
268
0
      break;
269
0
    case GF_SG_EVENT_FIELD:
270
0
      type = GF_SG_SCRIPT_TYPE_FIELD;
271
0
      break;
272
0
    default:
273
0
      return GF_BAD_PARAM;
274
0
    }
275
0
    gf_sg_script_field_new(dest, type, sf->fieldType, sf->name);
276
0
  }
277
0
  return GF_OK;
278
0
}
279
280
GF_EXPORT
281
GF_Err gf_sg_script_field_get_info(GF_ScriptField *field, GF_FieldInfo *info)
282
0
{
283
0
  if (!field || !info) return GF_BAD_PARAM;
284
0
  memset(info, 0, sizeof(GF_FieldInfo));
285
286
0
  info->fieldIndex = field->ALL_index;
287
0
  info->eventType = field->eventType;
288
0
  info->fieldType = field->fieldType;
289
0
  info->name = field->name;
290
291
  //setup pointer (special cases for nodes)
292
0
  switch (field->fieldType) {
293
0
  case GF_SG_VRML_SFNODE:
294
0
  case GF_SG_VRML_MFNODE:
295
0
    info->far_ptr = &field->pField;
296
0
    info->NDTtype = NDT_SFWorldNode;
297
0
    break;
298
0
  default:
299
0
    info->far_ptr = field->pField;
300
0
    break;
301
0
  }
302
0
  return GF_OK;
303
0
}
304
305
GF_EXPORT
306
void gf_sg_script_event_in(GF_Node *node, GF_FieldInfo *in_field)
307
0
{
308
0
  GF_ScriptPriv *priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate;
309
0
  if (priv->JS_EventIn) priv->JS_EventIn(node, in_field);
310
0
}
311
312
313
#endif /*GPAC_DISABLE_VRML*/