Coverage Report

Created: 2026-06-08 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/scenegraph/commands.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
27
#include <gpac/internal/scenegraph_dev.h>
28
/*MPEG4 tags (for internal nodes)*/
29
#include <gpac/nodes_mpeg4.h>
30
31
#include <gpac/internal/laser_dev.h>
32
33
34
GF_EXPORT
35
GF_Command *gf_sg_command_new(GF_SceneGraph *graph, u32 tag)
36
294
{
37
294
  GF_Command *ptr;
38
294
  GF_SAFEALLOC(ptr, GF_Command);
39
294
  if (!ptr) return NULL;
40
294
  ptr->tag = tag;
41
294
  ptr->in_scene = graph;
42
294
  ptr->command_fields = gf_list_new();
43
294
  if (tag < GF_SG_LAST_BIFS_COMMAND) ptr->new_proto_list = gf_list_new();
44
294
  return ptr;
45
294
}
46
47
GF_EXPORT
48
void gf_sg_command_del(GF_Command *com)
49
294
{
50
294
#ifndef GPAC_DISABLE_VRML
51
294
  u32 i;
52
294
  GF_Proto *proto;
53
294
#endif
54
294
  if (!com) return;
55
56
294
  if (com->tag < GF_SG_LAST_BIFS_COMMAND) {
57
294
#ifndef GPAC_DISABLE_VRML
58
304
    while (gf_list_count(com->command_fields)) {
59
10
      GF_CommandField *inf = (GF_CommandField *)gf_list_get(com->command_fields, 0);
60
10
      gf_list_rem(com->command_fields, 0);
61
62
10
      switch (inf->fieldType) {
63
2
      case GF_SG_VRML_SFNODE:
64
2
        if (inf->new_node) gf_node_try_destroy(com->in_scene, inf->new_node, NULL);
65
2
        break;
66
0
      case GF_SG_VRML_MFNODE:
67
0
        if (inf->field_ptr) {
68
0
          GF_ChildNodeItem *child;
69
0
          child = inf->node_list;
70
0
          while (child) {
71
0
            GF_ChildNodeItem *cur = child;
72
0
            gf_node_try_destroy(com->in_scene, child->node, NULL);
73
0
            child = child->next;
74
0
            gf_free(cur);
75
0
          }
76
0
        }
77
0
        break;
78
8
      default:
79
8
        if (inf->field_ptr) gf_sg_vrml_field_pointer_del(inf->field_ptr, inf->fieldType);
80
8
        break;
81
10
      }
82
10
      gf_free(inf);
83
10
    }
84
294
#endif
85
294
  } else {
86
0
#ifndef GPAC_DISABLE_SVG
87
0
    while (gf_list_count(com->command_fields)) {
88
0
      GF_CommandField *inf = (GF_CommandField *)gf_list_get(com->command_fields, 0);
89
0
      gf_list_rem(com->command_fields, 0);
90
91
0
      if (inf->new_node)
92
0
        gf_node_try_destroy(com->in_scene, inf->new_node, NULL);
93
0
      else if (inf->node_list) {
94
0
        GF_ChildNodeItem *child;
95
0
        child = inf->node_list;
96
0
        while (child) {
97
0
          GF_ChildNodeItem *cur = child;
98
0
          gf_node_try_destroy(com->in_scene, child->node, NULL);
99
0
          child = child->next;
100
0
          gf_free(cur);
101
0
        }
102
0
      } else if (inf->field_ptr) {
103
0
        gf_svg_delete_attribute_value(inf->fieldType, inf->field_ptr, com->in_scene);
104
0
      }
105
0
      gf_free(inf);
106
0
    }
107
0
#endif
108
0
  }
109
294
  gf_list_del(com->command_fields);
110
111
294
#ifndef GPAC_DISABLE_VRML
112
294
  i=0;
113
345
  while ((proto = (GF_Proto*)gf_list_enum(com->new_proto_list, &i))) {
114
51
    gf_sg_proto_del(proto);
115
51
  }
116
294
  gf_list_del(com->new_proto_list);
117
294
#endif
118
119
294
  if (com->node) {
120
12
    gf_node_try_destroy(com->in_scene, com->node, NULL);
121
12
  }
122
123
294
  if (com->del_proto_list) gf_free(com->del_proto_list);
124
294
  if (com->def_name) gf_free(com->def_name);
125
294
  if (com->scripts_to_load) gf_list_del(com->scripts_to_load);
126
294
  if (com->unres_name) gf_free(com->unres_name);
127
294
  gf_free(com);
128
294
}
129
130
static void SG_CheckFieldChange(GF_Node *node, GF_FieldInfo *field)
131
0
{
132
  /*and propagate eventIn if any*/
133
0
  if (field->on_event_in) {
134
0
    field->on_event_in(node, NULL);
135
0
  }
136
0
#ifndef GPAC_DISABLE_VRML
137
0
  else if ((field->eventType==GF_SG_EVENT_IN) && (gf_node_get_tag(node) == TAG_MPEG4_Script)) {
138
0
    gf_sg_script_event_in(node, field);
139
0
  }
140
0
  else {
141
    /*Notify eventOut in all cases to handle protos*/
142
0
    gf_node_event_out(node, field->fieldIndex);
143
0
  }
144
0
#endif
145
  /*signal node modif*/
146
0
  gf_node_changed(node, field);
147
0
}
148
149
#ifndef GPAC_DISABLE_SVG
150
static void gf_node_unregister_children_deactivate(GF_Node *container, GF_ChildNodeItem *child)
151
0
{
152
0
  while (child) {
153
0
    GF_ChildNodeItem *cur;
154
0
    gf_node_deactivate(child->node);
155
0
    gf_node_unregister(child->node, container);
156
0
    cur = child;
157
0
    child = child->next;
158
0
    gf_free(cur);
159
0
  }
160
0
}
161
#endif
162
163
164
GF_EXPORT
165
GF_Err gf_sg_command_apply(GF_SceneGraph *graph, GF_Command *com, Double time_offset)
166
0
{
167
0
  GF_Err e;
168
0
#if !defined(GPAC_DISABLE_VRML) || !defined(GPAC_DISABLE_SVG)
169
0
  GF_CommandField *inf;
170
0
  GF_Node *node;
171
0
#endif
172
173
0
#ifndef GPAC_DISABLE_VRML
174
0
  GF_FieldInfo field;
175
0
  void *slot_ptr;
176
0
  GF_Node *def;
177
0
#endif
178
179
0
  if (!com || !graph) return GF_BAD_PARAM;
180
181
0
  if (com->never_apply) return GF_OK;
182
183
0
  e = GF_OK;
184
0
  switch (com->tag) {
185
0
#ifndef GPAC_DISABLE_VRML
186
0
  case GF_SG_SCENE_REPLACE:
187
    /*unregister root*/
188
0
    gf_node_unregister(graph->RootNode, NULL);
189
    /*remove all protos and routes*/
190
0
    while (gf_list_count(graph->routes_to_activate))
191
0
      gf_list_rem(graph->routes_to_activate, 0);
192
193
0
    if (!com->aggregated) {
194
      /*destroy all routes*/
195
0
      while (gf_list_count(graph->Routes)) {
196
0
        GF_Route *r = (GF_Route *)gf_list_get(graph->Routes, 0);
197
        /*this will unregister the route from the graph, so don't delete the chain entry*/
198
0
        gf_sg_route_del(r);
199
0
      }
200
      /*destroy all proto*/
201
0
      while (gf_list_count(graph->protos)) {
202
0
        GF_Proto *p = (GF_Proto*)gf_list_get(graph->protos, 0);
203
        /*this will unregister the proto from the graph, so don't delete the chain entry*/
204
0
        gf_sg_proto_del(p);
205
0
      }
206
0
    }
207
    /*DO NOT TOUCH node registry*/
208
    /*DO NOT TOUCH UNREGISTERED PROTOS*/
209
210
    /*if no protos (previously aggregated command) create proto list*/
211
0
    if (!graph->protos) graph->protos = gf_list_new();
212
213
    /*move all protos in graph*/
214
0
    while (gf_list_count(com->new_proto_list)) {
215
0
      GF_Proto *p = (GF_Proto*)gf_list_get(com->new_proto_list, 0);
216
0
      gf_list_rem(com->new_proto_list, 0);
217
0
      gf_list_del_item(graph->unregistered_protos, p);
218
0
      gf_list_add(graph->protos, p);
219
0
    }
220
    /*assign new root (no need to register/unregister)*/
221
0
    graph->RootNode = com->node;
222
0
    com->node = NULL;
223
0
    break;
224
225
0
  case GF_SG_NODE_REPLACE:
226
0
    if (!gf_list_count(com->command_fields)) return GF_OK;
227
0
    inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
228
0
    e = gf_node_replace(com->node, inf->new_node, 0);
229
    //TOCHECK - this is commented as registering shouldn't happen (already done at command creation) and creates mem leak
230
//    if (inf->new_node) gf_node_register(inf->new_node, NULL);
231
0
    break;
232
233
0
  case GF_SG_MULTIPLE_REPLACE:
234
0
  case GF_SG_FIELD_REPLACE:
235
0
  {
236
0
    u32 j;
237
0
    GF_ChildNodeItem *list, *cur, *prev;
238
0
    j=0;
239
0
    while ((inf = (GF_CommandField*)gf_list_enum(com->command_fields, &j))) {
240
0
      e = gf_node_get_field(com->node, inf->fieldIndex, &field);
241
0
      if (e) return e;
242
243
0
      switch (field.fieldType) {
244
0
      case GF_SG_VRML_SFNODE:
245
0
      {
246
0
        node = *((GF_Node **) field.far_ptr);
247
0
        e = gf_node_unregister(node, com->node);
248
0
        *((GF_Node **) field.far_ptr) = inf->new_node;
249
0
        if (!e) gf_node_register(inf->new_node, com->node);
250
0
        break;
251
0
      }
252
0
      case GF_SG_VRML_MFNODE:
253
0
        gf_node_unregister_children(com->node, * ((GF_ChildNodeItem **) field.far_ptr));
254
0
        * ((GF_ChildNodeItem **) field.far_ptr) = NULL;
255
256
0
        list = * ((GF_ChildNodeItem **) inf->field_ptr);
257
0
        prev=NULL;
258
0
        while (list) {
259
0
          cur = gf_malloc(sizeof(GF_ChildNodeItem));
260
0
          cur->next = NULL;
261
0
          cur->node = list->node;
262
0
          if (prev) {
263
0
            prev->next = cur;
264
0
          } else {
265
0
            * ((GF_ChildNodeItem **) field.far_ptr) = cur;
266
0
          }
267
0
          gf_node_register(list->node, com->node);
268
0
          prev = cur;
269
0
          list = list->next;
270
0
        }
271
0
        break;
272
0
      case GF_SG_VRML_SFCOMMANDBUFFER:
273
0
      {
274
0
        u32 i, count;
275
0
        GF_SceneGraph *sg;
276
0
        SFCommandBuffer *cb_dst = (SFCommandBuffer *)field.far_ptr;
277
0
        SFCommandBuffer *cb_src = (SFCommandBuffer *)inf->field_ptr;
278
279
        /*reset dest*/
280
0
        if (!cb_dst->commandList) cb_dst->commandList = gf_list_new();
281
282
0
        while (gf_list_count(cb_dst->commandList)) {
283
0
          GF_Command *sub_com = (GF_Command *)gf_list_get(cb_dst->commandList, 0);
284
0
          gf_sg_command_del(sub_com);
285
0
          gf_list_rem(cb_dst->commandList, 0);
286
0
        }
287
0
        if (cb_dst->buffer) {
288
0
          gf_free(cb_dst->buffer);
289
0
          cb_dst->buffer = NULL;
290
0
        }
291
292
        /*clone command list*/
293
0
        sg = gf_node_get_graph(com->node);
294
0
        count = gf_list_count(cb_src->commandList);
295
0
        for (i=0; i<count; i++) {
296
0
          GF_Command *sub_com = (GF_Command *)gf_list_get(cb_src->commandList, i);
297
0
          GF_Command *new_com = gf_sg_vrml_command_clone(sub_com, sg, 0);
298
0
          gf_list_add(cb_dst->commandList, new_com);
299
0
        }
300
0
      }
301
0
      break;
302
303
0
      default:
304
        /*this is a regular field, reset it and clone - we cannot switch pointers since the
305
        original fields are NOT pointers*/
306
0
        if (!gf_sg_vrml_is_sf_field(field.fieldType)) {
307
0
          e = gf_sg_vrml_mf_reset(field.far_ptr, field.fieldType);
308
0
        }
309
0
        if (e) return e;
310
0
        gf_sg_vrml_field_copy(field.far_ptr, inf->field_ptr, field.fieldType);
311
312
0
        if ((field.fieldType==GF_SG_VRML_SFTIME) && !strstr(field.name, "media"))
313
0
          *(SFTime *)field.far_ptr = *(SFTime *)field.far_ptr + time_offset;
314
0
        break;
315
0
      }
316
0
      SG_CheckFieldChange(com->node, &field);
317
0
    }
318
0
    break;
319
0
  }
320
321
0
  case GF_SG_MULTIPLE_INDEXED_REPLACE:
322
0
  case GF_SG_INDEXED_REPLACE:
323
0
  {
324
0
    u32 sftype, i=0;
325
0
    while ((inf = (GF_CommandField*)gf_list_enum(com->command_fields, &i))) {
326
0
      e = gf_node_get_field(com->node, inf->fieldIndex, &field);
327
0
      if (e) return e;
328
329
      /*if MFNode remove the child and set new node*/
330
0
      if (field.fieldType == GF_SG_VRML_MFNODE) {
331
        /*we must remove the node before in case the new node uses the same ID (not forbidden) and this
332
        command removes the last instance of the node with the same ID*/
333
0
        gf_node_replace_child(com->node, (GF_ChildNodeItem**) field.far_ptr, inf->pos, inf->new_node);
334
0
        if (inf->new_node) gf_node_register(inf->new_node, NULL);
335
0
      }
336
      /*erase the field item*/
337
0
      else {
338
0
        if (!field.far_ptr) return GF_NON_COMPLIANT_BITSTREAM;
339
0
        if ((inf->pos < 0) || ((u32) inf->pos >= ((GenMFField *) field.far_ptr)->count) ) {
340
0
          inf->pos = ((GenMFField *)field.far_ptr)->count - 1;
341
          /*may happen with text and default value*/
342
0
          if (inf->pos < 0) {
343
0
            inf->pos = 0;
344
0
            gf_sg_vrml_mf_alloc(field.far_ptr, field.fieldType, 1);
345
0
          }
346
0
        }
347
0
        e = gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, & slot_ptr, inf->pos);
348
0
        if (e) return e;
349
0
        sftype = gf_sg_vrml_get_sf_type(field.fieldType);
350
0
        gf_sg_vrml_field_copy(slot_ptr, inf->field_ptr, sftype);
351
        /*note we don't add time offset, since there's no MFTime*/
352
0
      }
353
0
      SG_CheckFieldChange(com->node, &field);
354
0
    }
355
0
    break;
356
0
  }
357
0
  case GF_SG_ROUTE_REPLACE:
358
0
  {
359
0
    GF_Route *r;
360
0
    char *name;
361
0
    r = gf_sg_route_find(graph, com->RouteID);
362
0
    def = gf_sg_find_node(graph, com->fromNodeID);
363
0
    node = gf_sg_find_node(graph, com->toNodeID);
364
0
    if (!node || !def) return GF_SG_UNKNOWN_NODE;
365
0
    name = NULL;
366
0
    if (r) {
367
0
      name = r->name;
368
0
      r->name = NULL;
369
0
      gf_sg_route_del(r);
370
0
    }
371
0
    r = gf_sg_route_new(graph, def, com->fromFieldIndex, node, com->toFieldIndex);
372
0
    gf_sg_route_set_id(r, com->RouteID);
373
0
    if (name) {
374
0
      gf_sg_route_set_name(r, name);
375
0
      gf_free(name);
376
0
    }
377
0
    break;
378
0
  }
379
0
  case GF_SG_NODE_DELETE_EX:
380
0
  case GF_SG_NODE_DELETE:
381
0
  {
382
0
    if (com->node) gf_node_replace(com->node, NULL, (com->tag==GF_SG_NODE_DELETE_EX) ? 1 : 0);
383
0
    break;
384
0
  }
385
0
  case GF_SG_ROUTE_DELETE:
386
0
  {
387
0
    return gf_sg_route_del_by_id(graph, com->RouteID);
388
0
  }
389
0
  case GF_SG_INDEXED_DELETE:
390
0
  {
391
0
    if (!gf_list_count(com->command_fields)) return GF_OK;
392
0
    inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
393
394
0
    e = gf_node_get_field(com->node, inf->fieldIndex, &field);
395
0
    if (e) return e;
396
0
    if (gf_sg_vrml_is_sf_field(field.fieldType)) return GF_NON_COMPLIANT_BITSTREAM;
397
398
    /*then we need special handling in case of a node*/
399
0
    if (gf_sg_vrml_get_sf_type(field.fieldType) == GF_SG_VRML_SFNODE) {
400
0
      e = gf_node_replace_child(com->node, (GF_ChildNodeItem **) field.far_ptr, inf->pos, NULL);
401
0
    } else {
402
0
      if (!field.far_ptr) return GF_NON_COMPLIANT_BITSTREAM;
403
0
      if ((inf->pos < 0) || ((u32) inf->pos >= ((GenMFField *) field.far_ptr)->count) ) {
404
0
        inf->pos = ((GenMFField *)field.far_ptr)->count - 1;
405
0
      }
406
      /*this is a regular MFField, just remove the item (gf_realloc)*/
407
0
      e = gf_sg_vrml_mf_remove(field.far_ptr, field.fieldType, inf->pos);
408
0
    }
409
    /*deletion -> node has changed*/
410
0
    if (!e) SG_CheckFieldChange(com->node, &field);
411
0
    break;
412
0
  }
413
0
  case GF_SG_NODE_INSERT:
414
0
  {
415
0
    if (!gf_list_count(com->command_fields)) return GF_OK;
416
0
    inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
417
418
0
    e = gf_node_insert_child(com->node, inf->new_node, inf->pos);
419
0
    if (!e) e = gf_node_register(inf->new_node, com->node);
420
0
    if (!e) {
421
0
      gf_node_event_out(com->node, inf->fieldIndex);
422
0
      gf_node_changed(com->node, NULL);
423
0
    }
424
0
    break;
425
0
  }
426
0
  case GF_SG_ROUTE_INSERT:
427
0
  {
428
0
    GF_Route *r;
429
0
    def = gf_sg_find_node(graph, com->fromNodeID);
430
0
    node = gf_sg_find_node(graph, com->toNodeID);
431
0
    if (!node || !def) return GF_SG_UNKNOWN_NODE;
432
0
    r = gf_sg_route_new(graph, def, com->fromFieldIndex, node, com->toFieldIndex);
433
0
    if (com->RouteID) gf_sg_route_set_id(r, com->RouteID);
434
0
    if (com->def_name) {
435
0
      gf_sg_route_set_name(r, com->def_name);
436
0
      gf_free(com->def_name);
437
0
      com->def_name = NULL;
438
0
    }
439
0
    break;
440
0
  }
441
0
  case GF_SG_INDEXED_INSERT:
442
0
  {
443
0
    u32 sftype;
444
0
    if (!gf_list_count(com->command_fields)) return GF_OK;
445
0
    inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
446
0
    e = gf_node_get_field(com->node, inf->fieldIndex, &field);
447
0
    if (e) return e;
448
449
    /*rescale the MFField and parse the SFField*/
450
0
    if (field.fieldType != GF_SG_VRML_MFNODE) {
451
0
      if (inf->pos == -1) {
452
0
        e = gf_sg_vrml_mf_append(field.far_ptr, field.fieldType, & slot_ptr);
453
0
      } else {
454
0
        e = gf_sg_vrml_mf_insert(field.far_ptr, field.fieldType, & slot_ptr, inf->pos);
455
0
      }
456
0
      if (e) return e;
457
0
      sftype = gf_sg_vrml_get_sf_type(field.fieldType);
458
0
      gf_sg_vrml_field_copy(slot_ptr, inf->field_ptr, sftype);
459
0
    } else {
460
0
      if (inf->new_node) {
461
0
        if (inf->pos == -1) {
462
0
          gf_node_list_add_child( (GF_ChildNodeItem **) field.far_ptr, inf->new_node);
463
0
        } else {
464
0
          gf_node_list_insert_child((GF_ChildNodeItem **) field.far_ptr, inf->new_node, inf->pos);
465
0
        }
466
0
        gf_node_register(inf->new_node, com->node);
467
0
      }
468
0
    }
469
0
    if (!e) SG_CheckFieldChange(com->node, &field);
470
0
    break;
471
0
  }
472
0
  case GF_SG_PROTO_INSERT:
473
    /*destroy all proto*/
474
0
    while (gf_list_count(com->new_proto_list)) {
475
0
      GF_Proto *p = (GF_Proto*)gf_list_get(com->new_proto_list, 0);
476
0
      gf_list_rem(com->new_proto_list, 0);
477
0
      gf_list_del_item(graph->unregistered_protos, p);
478
0
      gf_list_add(graph->protos, p);
479
0
    }
480
0
    return GF_OK;
481
0
  case GF_SG_PROTO_DELETE:
482
0
  {
483
0
    u32 i;
484
0
    for (i=0; i<com->del_proto_list_size; i++) {
485
      /*note this will check for unregistered protos, but since IDs are unique we are sure we will
486
      not destroy an unregistered one*/
487
0
      GF_Proto *proto = gf_sg_find_proto(graph, com->del_proto_list[i], NULL);
488
0
      if (proto) gf_sg_proto_del(proto);
489
0
    }
490
0
  }
491
0
  return GF_OK;
492
0
  case GF_SG_PROTO_DELETE_ALL:
493
    /*destroy all proto*/
494
0
    while (gf_list_count(graph->protos)) {
495
0
      GF_Proto *p = (GF_Proto*)gf_list_get(graph->protos, 0);
496
0
      gf_list_rem(graph->protos, 0);
497
      /*this will unregister the proto from the graph, so don't delete the chain entry*/
498
0
      gf_sg_proto_del(p);
499
0
    }
500
    /*DO NOT TOUCH UNREGISTERED PROTOS*/
501
0
    return GF_OK;
502
0
  case GF_SG_XREPLACE:
503
0
  {
504
0
    s32 pos = -2;
505
0
    GF_Node *target = NULL;
506
0
    GF_ChildNodeItem *list, *cur;
507
0
    GF_FieldInfo value;
508
0
    inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
509
0
    if (!inf) return GF_SG_UNKNOWN_NODE;
510
511
0
    e = gf_node_get_field(com->node, inf->fieldIndex, &field);
512
0
    if (e) return e;
513
0
    target = com->node;
514
515
0
    if (!gf_sg_vrml_is_sf_field(field.fieldType)) {
516
0
      GF_FieldInfo idxField;
517
0
      if ((inf->pos != -2) || com->toNodeID) {
518
0
        if (com->toNodeID) {
519
0
          GF_Node *idxNode = gf_sg_find_node(graph, com->toNodeID);
520
0
          if (!idxNode) return GF_SG_UNKNOWN_NODE;
521
522
0
          if (gf_node_get_field(idxNode, com->toFieldIndex, &idxField) != GF_OK) return GF_OK;
523
0
          pos = 0;
524
0
          switch (idxField.fieldType) {
525
0
          case GF_SG_VRML_SFBOOL:
526
0
            if (*(SFBool*)idxField.far_ptr) pos = 1;
527
0
            break;
528
0
          case GF_SG_VRML_SFINT32:
529
0
            if (*(SFInt32*)idxField.far_ptr >=0) pos = *(SFInt32*)idxField.far_ptr;
530
0
            break;
531
0
          case GF_SG_VRML_SFFLOAT:
532
0
            if ( (*(SFFloat *)idxField.far_ptr) >=0) pos = (s32) floor( FIX2FLT(*(SFFloat*)idxField.far_ptr) );
533
0
            break;
534
0
          case GF_SG_VRML_SFTIME:
535
0
            if ( (*(SFTime *)idxField.far_ptr) >=0) pos = (s32) floor( (*(SFTime *)idxField.far_ptr) );
536
0
            break;
537
0
          }
538
0
        } else {
539
0
          pos = inf->pos;
540
0
        }
541
0
      }
542
0
    }
543
    /*override target node*/
544
0
    if ((field.fieldType==GF_SG_VRML_MFNODE) && (pos>=-1) && com->ChildNodeTag) {
545
0
      target = gf_node_list_get_child(*(GF_ChildNodeItem **)field.far_ptr, pos);
546
0
      if (!target) return GF_SG_UNKNOWN_NODE;
547
0
      if (gf_node_get_field(target, com->child_field, &field) != GF_OK) return GF_SG_UNKNOWN_NODE;
548
0
      pos=-2;
549
0
    }
550
551
0
    if (com->fromNodeID) {
552
0
      GF_Node *fromNode = gf_sg_find_node(graph, com->fromNodeID);
553
0
      if (!fromNode) return GF_SG_UNKNOWN_NODE;
554
0
      e = gf_node_get_field(fromNode, com->fromFieldIndex, &value);
555
0
      if (e) return e;
556
0
    } else {
557
0
      value.far_ptr = inf->field_ptr;
558
0
      value.fieldType = inf->fieldType;
559
0
    }
560
    /*indexed replacement*/
561
0
    if (pos>=-1) {
562
      /*if MFNode remove the child and set new node*/
563
0
      if (field.fieldType == GF_SG_VRML_MFNODE) {
564
0
        GF_Node *nn = *(GF_Node**)value.far_ptr;
565
0
        gf_node_replace_child(target, (GF_ChildNodeItem**) field.far_ptr, pos, nn);
566
0
        if (nn) gf_node_register(nn, NULL);
567
0
      }
568
      /*erase the field item*/
569
0
      else {
570
0
        u32 sftype;
571
0
        if (!field.far_ptr) return GF_NON_COMPLIANT_BITSTREAM;
572
0
        if ((pos < 0) || ((u32) pos >= ((GenMFField *) field.far_ptr)->count) ) {
573
0
          pos = ((GenMFField *)field.far_ptr)->count - 1;
574
          /*may happen with text and default value*/
575
0
          if (pos < 0) {
576
0
            pos = 0;
577
0
            gf_sg_vrml_mf_alloc(field.far_ptr, field.fieldType, 1);
578
0
          }
579
0
        }
580
0
        e = gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, & slot_ptr, pos);
581
0
        if (e) return e;
582
0
        sftype = gf_sg_vrml_get_sf_type(field.fieldType);
583
0
        gf_sg_vrml_field_copy(slot_ptr, value.far_ptr, sftype);
584
        /*note we don't add time offset, since there's no MFTime*/
585
0
      }
586
0
    } else {
587
0
      GF_ChildNodeItem *prev;
588
0
      switch (field.fieldType) {
589
0
      case GF_SG_VRML_SFNODE:
590
0
      {
591
0
        node = *((GF_Node **) field.far_ptr);
592
0
        e = gf_node_unregister(node, target);
593
0
        *((GF_Node **) field.far_ptr) = *((GF_Node **) value.far_ptr) ;
594
0
        if (!e) gf_node_register(*(GF_Node **) value.far_ptr, target);
595
0
        break;
596
0
      }
597
0
      case GF_SG_VRML_MFNODE:
598
0
        gf_node_unregister_children(target, * ((GF_ChildNodeItem **) field.far_ptr));
599
0
        * ((GF_ChildNodeItem **) field.far_ptr) = NULL;
600
601
0
        list = * ((GF_ChildNodeItem **) value.far_ptr);
602
0
        prev=NULL;
603
0
        while (list) {
604
0
          cur = gf_malloc(sizeof(GF_ChildNodeItem));
605
0
          cur->next = NULL;
606
0
          cur->node = list->node;
607
0
          if (prev) {
608
0
            prev->next = cur;
609
0
          } else {
610
0
            * ((GF_ChildNodeItem **) field.far_ptr) = cur;
611
0
          }
612
0
          gf_node_register(list->node, target);
613
0
          prev = cur;
614
0
          list = list->next;
615
0
        }
616
0
        break;
617
618
0
      default:
619
0
        if (!gf_sg_vrml_is_sf_field(field.fieldType)) {
620
0
          e = gf_sg_vrml_mf_reset(field.far_ptr, field.fieldType);
621
0
        }
622
0
        if (e) return e;
623
0
        gf_sg_vrml_field_clone(field.far_ptr, value.far_ptr, field.fieldType, graph);
624
625
0
        if ((field.fieldType==GF_SG_VRML_SFTIME) && !strstr(field.name, "media"))
626
0
          *(SFTime *)field.far_ptr = *(SFTime *)field.far_ptr + time_offset;
627
0
        break;
628
0
      }
629
0
    }
630
0
    SG_CheckFieldChange(target, &field);
631
0
  }
632
0
  return GF_OK;
633
  /*only used by BIFS*/
634
0
  case GF_SG_GLOBAL_QUANTIZER:
635
0
    return GF_OK;
636
637
0
#endif /*GPAC_DISABLE_VRML*/
638
639
640
0
#ifndef GPAC_DISABLE_SVG
641
  /*laser commands*/
642
0
  case GF_SG_LSR_NEW_SCENE:
643
    /*DO NOT TOUCH node registry*/
644
645
    /*assign new root (no need to register/unregister)*/
646
0
    graph->RootNode = com->node;
647
0
    com->node = NULL;
648
0
    break;
649
0
  case GF_SG_LSR_DELETE:
650
0
    if (!com->node) return GF_NON_COMPLIANT_BITSTREAM;
651
0
    if (!gf_list_count(com->command_fields)) {
652
0
      gf_node_replace(com->node, NULL, 0);
653
0
      gf_node_deactivate(com->node);
654
0
      return GF_OK;
655
0
    }
656
0
    inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
657
0
    node = gf_node_list_get_child(((SVG_Element *)com->node)->children, inf->pos);
658
0
    if (node) {
659
0
      e = gf_node_replace_child(com->node, &((SVG_Element *)com->node)->children, inf->pos, NULL);
660
0
      gf_node_deactivate(node);
661
0
    }
662
0
    break;
663
0
  case GF_SG_LSR_INSERT:
664
0
    inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
665
0
    if (!com->node || !inf) return GF_NON_COMPLIANT_BITSTREAM;
666
0
    if (inf->new_node) {
667
0
      if (inf->pos<0)
668
0
        gf_node_list_add_child(& ((SVG_Element *)com->node)->children, inf->new_node);
669
0
      else
670
0
        gf_node_list_insert_child(& ((SVG_Element *)com->node)->children, inf->new_node, inf->pos);
671
672
0
      gf_node_register(inf->new_node, com->node);
673
0
      gf_node_activate(inf->new_node);
674
0
      gf_node_changed(com->node, NULL);
675
0
    } else {
676
      /*NOT SUPPORTED*/
677
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[LASeR] VALUE INSERTION NOT SUPPORTED\n"));
678
0
    }
679
0
    break;
680
0
  case GF_SG_LSR_ADD:
681
0
  case GF_SG_LSR_REPLACE:
682
0
    inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
683
0
    if (!com->node || !inf) return GF_NON_COMPLIANT_BITSTREAM;
684
0
    if (inf->new_node) {
685
0
      if (inf->pos<0) {
686
        /*if fieldIndex (eg attributeName) is set, this is children replacement*/
687
0
        if (inf->fieldIndex>0) {
688
0
          gf_node_unregister_children_deactivate(com->node, ((SVG_Element *)com->node)->children);
689
0
          ((SVG_Element *)com->node)->children = NULL;
690
0
          gf_node_list_add_child(& ((SVG_Element *)com->node)->children, inf->new_node);
691
0
          gf_node_register(inf->new_node, com->node);
692
0
          gf_node_activate(inf->new_node);
693
0
        } else {
694
0
          e = gf_node_replace(com->node, inf->new_node, 0);
695
0
          gf_node_activate(inf->new_node);
696
0
        }
697
0
      } else {
698
0
        node = gf_node_list_get_child( ((SVG_Element *)com->node)->children, inf->pos);
699
0
        gf_node_replace_child(com->node, & ((SVG_Element *)com->node)->children, inf->pos, inf->new_node);
700
0
        gf_node_register(inf->new_node, com->node);
701
0
        if (node) gf_node_deactivate(node);
702
0
        gf_node_activate(inf->new_node);
703
0
      }
704
      /*signal node modif*/
705
0
      gf_node_changed(com->node, NULL);
706
0
      return e;
707
0
    } else if (inf->node_list) {
708
0
      GF_ChildNodeItem *child, *cur, *prev;
709
0
      gf_node_unregister_children_deactivate(com->node, ((SVG_Element *)com->node)->children);
710
0
      ((SVG_Element *)com->node)->children = NULL;
711
712
0
      prev = NULL;
713
0
      child = inf->node_list;
714
0
      while (child) {
715
0
        cur = (GF_ChildNodeItem*)gf_malloc(sizeof(GF_ChildNodeItem));
716
0
        cur->next = NULL;
717
0
        cur->node = child->node;
718
0
        gf_node_register(child->node, com->node);
719
0
        gf_node_activate(child->node);
720
0
        if (prev) prev->next = cur;
721
0
        else ((SVG_Element *)com->node)->children = cur;
722
0
        prev = cur;
723
0
        child = child->next;
724
0
      }
725
      /*signal node modif*/
726
0
      gf_node_changed(com->node, NULL);
727
0
      return GF_OK;
728
0
    }
729
    /*attribute modif*/
730
0
    else if (inf->field_ptr) {
731
0
      GF_FieldInfo a, b;
732
0
      memset(&a, 0, sizeof(GF_FieldInfo));
733
0
      memset(&b, 0, sizeof(GF_FieldInfo));
734
0
      if (inf->fieldIndex==(u32) -2) {
735
0
        GF_Point2D scale, translate;
736
0
        Fixed rotate;
737
0
        GF_Matrix2D *dest;
738
0
        gf_node_get_field_by_name(com->node, "transform", &a);
739
0
        dest = (GF_Matrix2D*)a.far_ptr;
740
741
0
        if (com->tag==GF_SG_LSR_REPLACE) {
742
0
          if (gf_mx2d_decompose(dest, &scale, &rotate, &translate)) {
743
0
            gf_mx2d_init(*dest);
744
0
            if (inf->fieldType==SVG_TRANSFORM_SCALE) scale = *(GF_Point2D *)inf->field_ptr;
745
0
            else if (inf->fieldType==SVG_TRANSFORM_TRANSLATE) translate = *(GF_Point2D *)inf->field_ptr;
746
0
            else if (inf->fieldType==SVG_TRANSFORM_ROTATE) rotate = ((SVG_Point_Angle*)inf->field_ptr)->angle;
747
748
0
            gf_mx2d_add_scale(dest, scale.x, scale.y);
749
0
            gf_mx2d_add_rotation(dest, 0, 0, rotate);
750
0
            gf_mx2d_add_translation(dest, translate.x, translate.y);
751
0
          }
752
0
        } else {
753
0
          GF_Point2D *pt = (GF_Point2D *)inf->field_ptr;
754
0
          if (inf->fieldType==SVG_TRANSFORM_SCALE) gf_mx2d_add_scale(dest, pt->x, pt->y);
755
0
          else if (inf->fieldType==SVG_TRANSFORM_TRANSLATE) gf_mx2d_add_translation(dest, pt->x, pt->y);
756
0
          else if (inf->fieldType == SVG_TRANSFORM_ROTATE) gf_mx2d_add_rotation(dest, 0, 0, ((SVG_Point_Angle*)inf->field_ptr)->angle);
757
0
        }
758
        /*signal node modif*/
759
0
        gf_node_changed(com->node, &a);
760
0
      } else {
761
0
        if ((inf->fieldIndex==(u32) -1) && (inf->fieldType==DOM_String_datatype)) {
762
0
          char *str = *(SVG_String*)inf->field_ptr;
763
764
0
          if (com->tag == GF_SG_LSR_REPLACE) {
765
0
            GF_DOMText *t = ((SVG_Element*)com->node)->children ? (GF_DOMText*) ((SVG_Element*)com->node)->children->node :NULL;
766
0
            if (t && (t->sgprivate->tag==TAG_DOMText)) {
767
0
              if (t->textContent) gf_free(t->textContent);
768
0
              t->textContent = NULL;
769
0
              if (str) t->textContent = gf_strdup(str);
770
0
            }
771
0
          } else {
772
0
            if (str) gf_dom_add_text_node(com->node, gf_strdup(str));
773
0
          }
774
          /*signal node modif*/
775
0
          gf_node_changed(com->node, NULL);
776
0
        }
777
0
        else if ((inf->fieldIndex==TAG_LSR_ATT_scale)
778
0
                 || (inf->fieldIndex==TAG_LSR_ATT_translation)
779
0
                 || (inf->fieldIndex==TAG_LSR_ATT_rotation)
780
0
                ) {
781
0
          SVG_Transform *mx;
782
0
          gf_node_get_attribute_by_tag(com->node, TAG_SVG_ATT_transform, 1, 0, &a);
783
0
          mx = a.far_ptr;
784
0
          if (com->tag == GF_SG_LSR_REPLACE) {
785
0
            GF_Point2D scale, translate;
786
0
            SVG_Point_Angle rotate;
787
0
            if (gf_mx2d_decompose(&mx->mat, &scale, &rotate.angle, &translate)) {
788
0
              gf_mx2d_init(mx->mat);
789
0
              if (inf->fieldIndex==TAG_LSR_ATT_scale) scale = *(GF_Point2D *)inf->field_ptr;
790
0
              else if (inf->fieldIndex==TAG_LSR_ATT_translation) translate = *(GF_Point2D *)inf->field_ptr;
791
0
              else if (inf->fieldIndex==TAG_LSR_ATT_rotation) rotate = *(SVG_Point_Angle*)inf->field_ptr;
792
793
0
              gf_mx2d_add_scale(&mx->mat, scale.x, scale.y);
794
0
              gf_mx2d_add_rotation(&mx->mat, 0, 0, rotate.angle);
795
0
              gf_mx2d_add_translation(&mx->mat, translate.x, translate.y);
796
0
            }
797
0
          } else {
798
0
            if (inf->fieldIndex==TAG_LSR_ATT_scale) gf_mx2d_add_scale(&mx->mat, ((GF_Point2D*)inf->field_ptr)->x, ((GF_Point2D*)inf->field_ptr)->y);
799
0
            if (inf->fieldIndex==TAG_LSR_ATT_translation) gf_mx2d_add_translation(&mx->mat, ((GF_Point2D*)inf->field_ptr)->x, ((GF_Point2D*)inf->field_ptr)->y);
800
0
            if (inf->fieldIndex==TAG_LSR_ATT_rotation) gf_mx2d_add_rotation(&mx->mat, 0, 0, ((SVG_Point_Angle*)inf->field_ptr)->angle);
801
0
          }
802
          /*signal node modif*/
803
0
          gf_node_changed(com->node, &a);
804
0
        }
805
0
        else if (gf_node_get_attribute_by_tag(com->node, inf->fieldIndex, 1, 0, &a) == GF_OK) {
806
0
          b = a;
807
0
          b.far_ptr = inf->field_ptr;
808
0
          if (com->tag == GF_SG_LSR_REPLACE) {
809
0
            gf_svg_attributes_copy(&a, &b, 0);
810
0
          } else {
811
0
            gf_svg_attributes_add(&a, &b, &a, 0);
812
0
          }
813
0
          if (a.fieldType==XMLRI_datatype) {
814
0
            gf_node_dirty_set(com->node, GF_SG_SVG_XLINK_HREF_DIRTY, 0);
815
0
          }
816
          /*signal node modif*/
817
0
          gf_node_changed(com->node, &a);
818
0
        }
819
0
      }
820
0
    } else if (com->fromNodeID) {
821
0
      GF_FieldInfo a, b;
822
0
      memset(&a, 0, sizeof(GF_FieldInfo));
823
0
      memset(&b, 0, sizeof(GF_FieldInfo));
824
0
      GF_Node *fromNode = gf_sg_find_node(graph, com->fromNodeID);
825
0
      if (!fromNode) return GF_NON_COMPLIANT_BITSTREAM;
826
0
      if (gf_node_get_field(fromNode, com->fromFieldIndex, &b) != GF_OK) return GF_NON_COMPLIANT_BITSTREAM;
827
828
0
      if ((inf->fieldIndex==(u32) -1) && (inf->fieldType==DOM_String_datatype)) {
829
0
        char *str = inf->field_ptr ? *(SVG_String*)inf->field_ptr : NULL;
830
831
0
        if (com->tag == GF_SG_LSR_REPLACE) {
832
0
          GF_DOMText *t = ((SVG_Element*)com->node)->children ? (GF_DOMText*) ((SVG_Element*)com->node)->children->node :NULL;
833
0
          if (t && (t->sgprivate->tag==TAG_DOMText)) {
834
0
            if (t->textContent) gf_free(t->textContent);
835
0
            t->textContent = NULL;
836
0
            if (str) t->textContent = gf_strdup(str);
837
0
          }
838
0
        } else {
839
0
          if (str) gf_dom_add_text_node(com->node, gf_strdup(str));
840
0
        }
841
0
      } else {
842
0
        gf_node_get_field(com->node, inf->fieldIndex, &a);
843
0
        if (com->tag == GF_SG_LSR_REPLACE) {
844
0
          e = gf_svg_attributes_copy(&a, &b, 0);
845
0
        } else {
846
0
          e = gf_svg_attributes_add(&a, &b, &a, 0);
847
0
        }
848
0
      }
849
0
      gf_node_changed(com->node, &a);
850
0
      return e;
851
0
    } else {
852
0
      return GF_NON_COMPLIANT_BITSTREAM;
853
0
    }
854
0
    break;
855
0
  case GF_SG_LSR_ACTIVATE:
856
0
    gf_node_activate(com->node);
857
0
    break;
858
0
  case GF_SG_LSR_DEACTIVATE:
859
0
    gf_node_deactivate(com->node);
860
0
    gf_node_changed(com->node, NULL);
861
0
    break;
862
0
  case GF_SG_LSR_SEND_EVENT:
863
0
  {
864
0
    GF_DOM_Event evt;
865
0
    memset(&evt, 0, sizeof(GF_DOM_Event));
866
0
    evt.type = com->send_event_name;
867
0
    evt.detail = com->send_event_integer;
868
0
    evt.clientX = com->send_event_x;
869
0
    evt.clientY = com->send_event_y;
870
0
    gf_dom_event_fire(com->node, &evt);
871
0
  }
872
0
  break;
873
0
#endif
874
875
0
  default:
876
0
    return GF_NOT_SUPPORTED;
877
0
  }
878
0
  if (e) return e;
879
880
0
#ifndef GPAC_DISABLE_VRML
881
0
  if (com->scripts_to_load) {
882
0
    while (gf_list_count(com->scripts_to_load)) {
883
0
      GF_Node *script = (GF_Node *)gf_list_get(com->scripts_to_load, 0);
884
0
      gf_list_rem(com->scripts_to_load, 0);
885
0
      gf_sg_script_load(script);
886
0
    }
887
0
    gf_list_del(com->scripts_to_load);
888
0
    com->scripts_to_load = NULL;
889
0
  }
890
0
#endif
891
892
0
  return GF_OK;
893
0
}
894
895
GF_EXPORT
896
GF_CommandField *gf_sg_command_field_new(GF_Command *com)
897
10
{
898
10
  GF_CommandField *ptr;
899
10
  GF_SAFEALLOC(ptr, GF_CommandField);
900
10
  if (ptr)
901
10
    gf_list_add(com->command_fields, ptr);
902
10
  return ptr;
903
10
}
904
905
906
GF_EXPORT
907
GF_Err gf_sg_command_apply_list(GF_SceneGraph *graph, GF_List *comList, Double time_offset)
908
0
{
909
0
  GF_Err e;
910
0
  GF_Command *com;
911
0
  u32 i=0;
912
0
  while ((com = (GF_Command *)gf_list_enum(comList, &i))) {
913
0
    e = gf_sg_command_apply(graph, com, time_offset);
914
0
    if (e) return e;
915
0
  }
916
0
  return GF_OK;
917
0
}
918
919
#ifndef GPAC_DISABLE_VRML
920
GF_Command *gf_sg_vrml_command_clone(GF_Command *com, GF_SceneGraph *inGraph, Bool force_clone)
921
0
{
922
0
  u32 i, count;
923
0
  GF_Command *dest;
924
925
  /*FIXME - to do*/
926
0
  if (gf_list_count(com->new_proto_list)) return NULL;
927
0
  dest = gf_sg_command_new(inGraph, com->tag);
928
929
0
  if (com->in_scene!=inGraph) force_clone = 1;
930
931
  /*node the command applies to - may be NULL*/
932
0
  if (force_clone) {
933
0
    dest->node = gf_node_clone(inGraph, com->node, NULL, "", 0);
934
0
  } else {
935
0
    dest->node = com->node;
936
0
    gf_node_register(dest->node, NULL);
937
0
  }
938
  /*route insert, replace and delete*/
939
0
  dest->RouteID = com->RouteID;
940
0
  if (com->def_name) dest->def_name = gf_strdup(com->def_name);
941
  //this is an union
942
  //if (com->send_event_string) dest->send_event_string = gf_strdup(com->send_event_string);
943
944
0
  dest->fromNodeID = com->fromNodeID;
945
0
  dest->fromFieldIndex = com->fromFieldIndex;
946
0
  dest->toNodeID = com->toNodeID;
947
0
  dest->toFieldIndex = com->toFieldIndex;
948
0
  dest->send_event_integer = com->send_event_integer;
949
0
  dest->send_event_x = com->send_event_x;
950
0
  dest->send_event_y = com->send_event_y;
951
952
0
  dest->del_proto_list_size = com->del_proto_list_size;
953
0
  if (com->del_proto_list_size) {
954
0
    dest->del_proto_list = (u32*)gf_malloc(sizeof(u32) * com->del_proto_list_size);
955
0
    memcpy(dest->del_proto_list, com->del_proto_list, sizeof(u32) * com->del_proto_list_size);
956
0
  }
957
0
  count = gf_list_count(com->command_fields);
958
0
  for (i=0; i<count; i++) {
959
0
    GF_CommandField *fo = (GF_CommandField *)gf_list_get(com->command_fields, i);
960
0
    GF_CommandField *fd = (GF_CommandField *)gf_sg_command_field_new(dest);
961
962
0
    fd->fieldIndex = fo->fieldIndex;
963
0
    fd->fieldType = fo->fieldType;
964
0
    fd->pos = fo->pos;
965
966
    /*FIXME - this can also be LASeR commands, not supported for now*/
967
0
    if (fo->field_ptr) {
968
0
      fd->field_ptr = gf_sg_vrml_field_pointer_new(fd->fieldType);
969
0
      gf_sg_vrml_field_clone(fd->field_ptr, fo->field_ptr, fo->fieldType, dest->in_scene);
970
0
    }
971
972
0
    if (fo->new_node) {
973
0
      if (force_clone) {
974
0
        fd->new_node = gf_node_clone(inGraph, fo->new_node, dest->node, "", 0);
975
0
      } else {
976
0
        fd->new_node = fo->new_node;
977
0
        gf_node_register(fd->new_node, NULL);
978
0
      }
979
0
      fd->field_ptr = &fd->new_node;
980
0
    }
981
0
    if (fo->node_list) {
982
0
      GF_ChildNodeItem *child, *cur, *prev;
983
0
      prev = NULL;
984
0
      child = fo->node_list;
985
0
      while (child) {
986
0
        cur = (GF_ChildNodeItem*) gf_malloc(sizeof(GF_ChildNodeItem));
987
0
        if (force_clone) {
988
0
          cur->node = gf_node_clone(inGraph, child->node, dest->node, "", 0);
989
0
        } else {
990
0
          cur->node = child->node;
991
0
          gf_node_register(cur->node, NULL);
992
0
        }
993
0
        cur->next = NULL;
994
0
        if (prev) prev->next = cur;
995
0
        else fd->node_list = cur;
996
0
        prev = cur;
997
0
        child = child->next;
998
0
      }
999
0
      fd->field_ptr = &fd->node_list;
1000
0
    }
1001
0
  }
1002
0
  return dest;
1003
0
}
1004
1005
#endif
1006