LCOV - code coverage report
Current view: top level - scene_manager - loader_xmt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1181 1734 68.1 %
Date: 2021-04-29 23:48:07 Functions: 47 56 83.9 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Management 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/scene_manager.h>
      27             : #include <gpac/constants.h>
      28             : #include <gpac/utf.h>
      29             : #include <gpac/network.h>
      30             : #include <gpac/xml.h>
      31             : #include <gpac/internal/bifs_dev.h>
      32             : #include <gpac/internal/scenegraph_dev.h>
      33             : #include <gpac/nodes_x3d.h>
      34             : 
      35             : #ifndef GPAC_DISABLE_LOADER_XMT
      36             : 
      37             : void gf_sm_update_bitwrapper_buffer(GF_Node *node, const char *fileName);
      38             : 
      39             : /*for QP types*/
      40             : #include "../bifs/quant.h"
      41             : 
      42             : typedef struct
      43             : {
      44             :         GF_Node *node;
      45             :         GF_FieldInfo container_field;
      46             :         GF_ChildNodeItem *last;
      47             : } XMTNodeStack;
      48             : 
      49             : 
      50             : /**/
      51             : enum
      52             : {
      53             :         /*document is not yet initialized*/
      54             :         XMT_STATE_INIT = 0,
      55             :         /*document head is being parsed*/
      56             :         XMT_STATE_HEAD = 1,
      57             :         /*document body being parsed*/
      58             :         XMT_STATE_BODY = 2,
      59             :         /*commands are being parsed*/
      60             :         XMT_STATE_COMMANDS = 3,
      61             :         /*elements are being parsed*/
      62             :         XMT_STATE_ELEMENTS = 4,
      63             :         /*end of body parsing*/
      64             :         XMT_STATE_BODY_END = 5,
      65             :         /*end of parsing*/
      66             :         XMT_STATE_END = 6,
      67             : };
      68             : 
      69             : 
      70             : typedef struct
      71             : {
      72             :         /*1: XMT-A, 2: X3D, 3: XMT-O (not supported yet) */
      73             :         u32 doc_type;
      74             :         /*0: not init, 1: header, 2: body*/
      75             :         u32 state;
      76             :         u32 current_node_tag;
      77             : 
      78             :         GF_SceneLoader *load;
      79             :         GF_Err last_error;
      80             :         GF_SAXParser *sax_parser;
      81             :         XMTNodeStack *x3d_root;
      82             : 
      83             :         /* stack of nodes for SAX parsing*/
      84             :         GF_List *nodes;
      85             :         /* stack of descriptors for SAX parsing*/
      86             :         GF_List *descriptors;
      87             : 
      88             :         GF_List *peeked_nodes;
      89             :         GF_List *def_nodes;
      90             :         GF_List *inserted_routes, *unresolved_routes;
      91             : 
      92             :         /* OD and ESD links*/
      93             :         GF_List *od_links, *esd_links;
      94             :         /*set when parsing proto*/
      95             :         GF_Proto *parsing_proto;
      96             :         GF_ProtoFieldInterface *proto_field;
      97             : 
      98             :         GF_StreamContext *scene_es;
      99             :         GF_AUContext *scene_au;
     100             :         u32 base_scene_id;
     101             :         /*current scene command*/
     102             :         GF_Command *command;
     103             :         SFCommandBuffer *command_buffer;
     104             : 
     105             :         GF_StreamContext *od_es;
     106             :         GF_AUContext *od_au;
     107             :         u32 base_od_id;
     108             :         /*current od command*/
     109             :         GF_ODCom *od_command;
     110             : 
     111             : 
     112             :         /*current stream ID, AU time and RAP flag*/
     113             :         u32 stream_id;
     114             :         Double au_time;
     115             :         Bool au_is_rap;
     116             :         Bool in_com;
     117             :         GF_List *script_to_load;
     118             : } GF_XMTParser;
     119             : 
     120             : 
     121             : typedef struct
     122             : {
     123             :         char *desc_name;
     124             :         u32 ID;
     125             :         /*store nodes referring to this URL*/
     126             :         GF_List *mf_urls;
     127             :         GF_ObjectDescriptor *od;
     128             : } XMT_ODLink;
     129             : 
     130             : typedef struct
     131             : {
     132             :         char *desc_name;
     133             :         u32 ESID;
     134             :         GF_ESD *esd;
     135             :         char *OCR_Name;
     136             :         char *Depends_Name;
     137             : } XMT_ESDLink;
     138             : 
     139             : 
     140           5 : static GF_Err xmt_report(GF_XMTParser *parser, GF_Err e, char *format, ...)
     141             : {
     142             : #ifndef GPAC_DISABLE_LOG
     143           5 :         if (gf_log_tool_level_on(GF_LOG_PARSER, e ? GF_LOG_ERROR : GF_LOG_WARNING)) {
     144             :                 char szMsg[2048];
     145             :                 va_list args;
     146           5 :                 va_start(args, format);
     147             :                 vsnprintf(szMsg, 2048, format, args);
     148           5 :                 va_end(args);
     149           5 :                 GF_LOG((u32) (e ? GF_LOG_ERROR : GF_LOG_WARNING), GF_LOG_PARSER, ("[XMT Parsing] %s (line %d)\n", szMsg, gf_xml_sax_get_line(parser->sax_parser)) );
     150             :         }
     151             : #endif
     152           5 :         if (e) parser->last_error = e;
     153           5 :         return e;
     154             : }
     155          45 : static void xmt_progress(void *cbk, u64 done, u64 total)
     156             : {
     157          45 :         gf_set_progress("XMT Parsing", done, total);
     158          45 : }
     159             : static Bool xmt_esid_available(GF_XMTParser *parser, u16 ESID)
     160             : {
     161             :         u32 i;
     162             :         XMT_ESDLink *esdl;
     163           0 :         i=0;
     164           0 :         while ((esdl = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
     165           0 :                 if (esdl->ESID == ESID) return 0;
     166             :         }
     167             :         return 1;
     168             : }
     169             : 
     170          20 : static char *xmt_get_es_name(GF_XMTParser *parser, u16 ESID)
     171             : {
     172             :         u32 i;
     173             :         XMT_ESDLink *esdl;
     174          20 :         i=0;
     175          50 :         while ((esdl = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
     176          30 :                 if (esdl->ESID == ESID) return esdl->desc_name;
     177             :         }
     178             :         return NULL;
     179             : }
     180             : 
     181          25 : static void xmt_new_od_link(GF_XMTParser *parser, GF_ObjectDescriptor *od, char *name, u32 ID)
     182             : {
     183             :         u32 i, j, count;
     184             :         XMT_ODLink *odl;
     185             : 
     186          25 :         if (!ID) {
     187           0 :                 if (!strnicmp(name, "od", 2)) ID = atoi(name + 2);
     188           0 :                 else if (!strnicmp(name, "iod", 3)) ID = atoi(name+ 3);
     189             :                 /*be careful, an url like "11-regression-test.mp4" will return 1 on sscanf :)*/
     190           0 :                 else if (sscanf(name, "%u", &ID) == 1) {
     191             :                         char szURL[20];
     192           0 :                         sprintf(szURL, "%u", ID);
     193           0 :                         if (strcmp(szURL, name)) {
     194           0 :                                 ID = 0;
     195             :                         } else {
     196             :                                 name = NULL;
     197             :                         }
     198             :                 }
     199             :         }
     200             : 
     201          25 :         count = gf_list_count(parser->od_links);
     202          60 :         for (i=0; i<count; i++) {
     203          40 :                 odl = (XMT_ODLink*)gf_list_get(parser->od_links, i);
     204          40 :                 if ( (ID && (odl->ID == ID))
     205          40 :                         || (odl->od == od)
     206          40 :                         || (odl->desc_name && name && !strcmp(odl->desc_name, name))
     207             :                    ) {
     208           5 :                         if (!odl->od) odl->od = od;
     209           5 :                         if (!odl->desc_name && name) odl->desc_name = gf_strdup(name);
     210           5 :                         if (!od->objectDescriptorID) {
     211           5 :                                 od->objectDescriptorID = ID;
     212           0 :                         } else if (ID && (od->objectDescriptorID != ID)) {
     213           0 :                                 xmt_report(parser, GF_BAD_PARAM, "Conflicting OD IDs %d vs %d\n", ID, od->objectDescriptorID);
     214             :                         }
     215             : 
     216          25 :                         for (j=i+1; j<count; j++) {
     217          20 :                                 XMT_ODLink *l2 = (XMT_ODLink*)gf_list_get(parser->od_links, j);
     218          20 :                                 if (l2->od == od) {
     219           0 :                                         odl->ID = od->objectDescriptorID = odl->od->objectDescriptorID;
     220           0 :                                         gf_list_rem(parser->od_links, j);
     221           0 :                                         if (l2->desc_name) gf_free(l2->desc_name);
     222           0 :                                         gf_list_del(l2->mf_urls);
     223           0 :                                         gf_free(l2);
     224           0 :                                         break;
     225             :                                 }
     226             :                         }
     227             :                         return;
     228             :                 }
     229             :         }
     230          20 :         GF_SAFEALLOC(odl, XMT_ODLink);
     231          20 :         if (!odl) return;
     232             : 
     233          20 :         odl->mf_urls = gf_list_new();
     234          20 :         odl->od = od;
     235          20 :         if (ID) od->objectDescriptorID = ID;
     236          20 :         if (name) odl->desc_name = gf_strdup(name);
     237          20 :         gf_list_add(parser->od_links, odl);
     238             : }
     239             : 
     240          30 : static void xmt_new_od_link_from_node(GF_XMTParser *parser, char *name, MFURL *url)
     241             : {
     242             :         u32 i, ID;
     243             :         XMT_ODLink *odl;
     244             : 
     245             :         /*find OD_ID*/
     246          30 :         ID = 0;
     247          50 :         if (!strnicmp(name, "od", 2)) ID = atoi(name + 2);
     248          10 :         else if (!strnicmp(name, "iod", 3)) ID = atoi(name + 3);
     249             :         /*be careful, an url like "11-regression-test.mp4" will return 1 on sscanf :)*/
     250          10 :         else if (sscanf(name, "%u", &ID) == 1) {
     251             :                 char szURL[20];
     252           0 :                 sprintf(szURL, "%u", ID);
     253           0 :                 if (strcmp(szURL, name)) {
     254           0 :                         ID = 0;
     255             :                 } else {
     256             :                         name = NULL;
     257             :                 }
     258             :         }
     259          10 :         else ID = 0;
     260             : 
     261             :         /*write OD_ID*/
     262             :         assert(url->count);
     263          30 :         i = url->count - 1;
     264          30 :         url->vals[i].OD_ID = 0;
     265          30 :         url->vals->OD_ID = ID;
     266             : 
     267          30 :         i=0;
     268         110 :         while ((odl = (XMT_ODLink*)gf_list_enum(parser->od_links, &i))) {
     269         100 :                 if ( (name && odl->desc_name && !strcmp(odl->desc_name, name))
     270          80 :                         || (ID && odl->od && odl->od->objectDescriptorID==ID)
     271          80 :                         || (ID && (odl->ID==ID))
     272             :                    ) {
     273          20 :                         if (url && (gf_list_find(odl->mf_urls, url)<0) ) gf_list_add(odl->mf_urls, url);
     274          20 :                         return;
     275             :                 }
     276             :         }
     277          10 :         GF_SAFEALLOC(odl, XMT_ODLink);
     278          10 :         if (!odl) return;
     279             : 
     280          10 :         odl->mf_urls = gf_list_new();
     281          10 :         if (url) gf_list_add(odl->mf_urls, url);
     282          10 :         if (ID) odl->ID = ID;
     283          10 :         else odl->desc_name = gf_strdup(name);
     284          10 :         gf_list_add(parser->od_links, odl);
     285             : }
     286          30 : static void xmt_new_esd_link(GF_XMTParser *parser, GF_ESD *esd, char *desc_name, u32 binID)
     287             : {
     288             :         u32 i, j;
     289             :         XMT_ESDLink *esdl;
     290             : 
     291          30 :         i=0;
     292         105 :         while ((esdl = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
     293          75 :                 if (esdl->esd  && (esd!=esdl->esd)) continue;
     294           0 :                 if (!esdl->esd) {
     295           0 :                         if (!esdl->ESID || !desc_name || strcmp(esdl->desc_name, desc_name)) continue;
     296           0 :                         esdl->esd = esd;
     297             :                 }
     298           0 :                 if (binID) {
     299             :                         /*remove temp links*/
     300           0 :                         if (esdl->ESID == (u16) ( ( (PTR_TO_U_CAST esdl) >> 16) | ( (PTR_TO_U_CAST esdl) & 0x0000FFFF) ) ) {
     301             :                                 GF_StreamContext *sc;
     302           0 :                                 j=0;
     303           0 :                                 while ((sc = (GF_StreamContext *)gf_list_enum(parser->load->ctx->streams, &j))) {
     304           0 :                                         if (sc->ESID!=esdl->ESID) continue;
     305             :                                         /*reassign*/
     306           0 :                                         sc->ESID = binID;
     307             :                                         break;
     308             :                                 }
     309             :                         }
     310           0 :                         esdl->ESID = esdl->esd->ESID = binID;
     311             :                 }
     312           0 :                 if (desc_name && !esdl->desc_name) {
     313           0 :                         esdl->desc_name = gf_strdup(desc_name);
     314           0 :                         if (!esdl->ESID && !strnicmp(desc_name, "es", 2)) esdl->ESID = atoi(&desc_name[2]);
     315             :                 }
     316           0 :                 return;
     317             :         }
     318          30 :         GF_SAFEALLOC(esdl, XMT_ESDLink);
     319          30 :         if (!esdl) return;
     320             : 
     321          30 :         esdl->esd = esd;
     322          30 :         esd->ESID = esdl->ESID = binID;
     323          30 :         if (desc_name) {
     324          30 :                 if (!esdl->ESID && !strnicmp(desc_name, "es", 2)) esdl->ESID = atoi(&desc_name[2]);
     325          30 :                 esdl->desc_name = gf_strdup(desc_name);
     326             :         }
     327          30 :         if (!esd->ESID) {
     328           0 :                 esd->ESID = 1;
     329           0 :                 while (!xmt_esid_available(parser, esd->ESID)) esd->ESID++;
     330           0 :                 esdl->ESID = esd->ESID;
     331             :         }
     332             : 
     333          30 :         gf_list_add(parser->esd_links, esdl);
     334             : }
     335           0 : static Bool xmt_set_depend_id(GF_XMTParser *parser, GF_ESD *desc, char *es_name, Bool is_ocr_dep)
     336             : {
     337             :         u32 i;
     338             :         XMT_ESDLink *esdl;
     339           0 :         if (!desc || !es_name) return 0;
     340             : 
     341           0 :         i=0;
     342           0 :         while ((esdl = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
     343           0 :                 if (esdl->esd == desc) {
     344           0 :                         if (is_ocr_dep)
     345           0 :                                 esdl->OCR_Name = gf_strdup(es_name);
     346             :                         else
     347           0 :                                 esdl->Depends_Name = gf_strdup(es_name);
     348             :                         return 1;
     349             :                 }
     350             :         }
     351             :         return 0;
     352             : }
     353             : 
     354          10 : static u32 xmt_get_od_id(GF_XMTParser *parser, char *od_name)
     355             : {
     356             :         u32 i, ID;
     357             :         XMT_ODLink *l;
     358          10 :         if (sscanf(od_name, "%u", &ID)==1) return ID;
     359             : 
     360          10 :         i=0;
     361          20 :         while ((l = (XMT_ODLink*)gf_list_enum(parser->od_links, &i))) {
     362          20 :                 if (!l->od) continue;
     363          20 :                 if (l->desc_name && !strcmp(l->desc_name, od_name)) return l->od->objectDescriptorID;
     364             :         }
     365             :         return 0;
     366             : }
     367             : 
     368           5 : static u32 xmt_get_esd_id(GF_XMTParser *parser, char *esd_name)
     369             : {
     370             :         u32 i, ID;
     371             :         XMT_ESDLink *l;
     372           5 :         if (sscanf(esd_name, "%u", &ID)==1) return ID;
     373             : 
     374           5 :         i=0;
     375          15 :         while ((l = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
     376          15 :                 if (!l->esd) continue;
     377          15 :                 if (l->desc_name && !strcmp(l->desc_name, esd_name)) return l->esd->ESID;
     378             :         }
     379             :         return 0;
     380             : }
     381           0 : static u32 xmt_locate_stream(GF_XMTParser *parser, char *stream_name)
     382             : {
     383             :         XMT_ESDLink *esdl;
     384             :         u32 i;
     385             :         char szN[200];
     386             : 
     387           0 :         i=0;
     388           0 :         while ((esdl = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
     389           0 :                 if (esdl->desc_name && !strcmp(esdl->desc_name, stream_name)) return esdl->ESID;
     390           0 :                 if (esdl->ESID) {
     391             :                         sprintf(szN, "es%d", esdl->ESID);
     392           0 :                         if (!strcmp(szN, stream_name)) return esdl->ESID;
     393           0 :                         sprintf(szN, "%d", esdl->ESID);
     394           0 :                         if (!strcmp(szN, stream_name)) return esdl->ESID;
     395             :                 }
     396             :         }
     397           0 :         if (parser->load->ctx) {
     398             :                 GF_StreamContext *sc;
     399           0 :                 i=0;
     400           0 :                 while ((sc = gf_list_enum(parser->load->ctx->streams, &i))) {
     401           0 :                         if (sc->name && !strcmp(sc->name, stream_name)) return sc->ESID;
     402           0 :                         sprintf(szN, "%d", sc->ESID);
     403           0 :                         if (!strcmp(szN, stream_name)) return sc->ESID;
     404             :                 }
     405             :         }
     406             :         /*create a temp one*/
     407           0 :         esdl = (XMT_ESDLink *)gf_malloc(sizeof(XMT_ESDLink));
     408             :         memset(esdl, 0, sizeof(XMT_ESDLink));
     409           0 :         esdl->ESID = (u16) ( (PTR_TO_U_CAST esdl) >> 16) | ( (PTR_TO_U_CAST esdl) & 0x0000FFFF);
     410           0 :         if (!strnicmp(stream_name, "es", 2)) esdl->ESID = atoi(&stream_name[2]);
     411           0 :         esdl->desc_name = gf_strdup(stream_name);
     412           0 :         gf_list_add(parser->esd_links, esdl);
     413           0 :         return esdl->ESID;
     414             : }
     415           0 : static Bool xmt_odid_available(GF_XMTParser *parser, u16 ODID)
     416             : {
     417             :         u32 i;
     418             :         XMT_ODLink *l;
     419           0 :         i=0;
     420           0 :         while ((l = (XMT_ODLink*)gf_list_enum(parser->od_links, &i))) {
     421           0 :                 if (l->ID == ODID) return 0;
     422           0 :                 if (l->od && l->od->objectDescriptorID == ODID) return 0;
     423             :         }
     424             :         return 1;
     425             : }
     426             : 
     427           5 : static void xmt_resolve_od_links(GF_XMTParser *parser)
     428             : {
     429             :         u32 i, j;
     430             :         XMT_ESDLink *esdl, *esdl2;
     431             :         XMT_ODLink *l;
     432             :         char szURL[5000];
     433             : 
     434             :         /*fix ESD IDs*/
     435           5 :         i=0;
     436          40 :         while ((esdl = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
     437          30 :                 if (!esdl->esd) {
     438           0 :                         xmt_report(parser, GF_BAD_PARAM, "Stream %s ID %d has no associated ES descriptor\n", esdl->desc_name ? esdl->desc_name : "", esdl->ESID);
     439           0 :                         i--;
     440           0 :                         gf_list_rem(parser->esd_links, i);
     441           0 :                         if (esdl->desc_name) gf_free(esdl->desc_name);
     442           0 :                         gf_free(esdl);
     443           0 :                         continue;
     444             :                 }
     445          30 :                 if (esdl->ESID) esdl->esd->ESID = esdl->ESID;
     446           0 :                 else if (!esdl->esd->ESID) {
     447             :                         u16 ESID = 1;
     448           0 :                         while (!xmt_esid_available(parser, ESID)) ESID++;
     449           0 :                         esdl->esd->ESID = ESID;
     450             :                 }
     451             :         }
     452             : 
     453             :         /*set OCR es ids*/
     454           5 :         i=0;
     455          40 :         while ((esdl = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
     456             :                 Bool use_old_fmt;
     457             :                 u16 ocr_id;
     458             :                 char szTest[50];
     459             : 
     460          30 :                 esdl->esd->OCRESID = 0;
     461          30 :                 if (!esdl->OCR_Name) continue;
     462             : 
     463             :                 use_old_fmt = 0;
     464           0 :                 ocr_id = atoi(esdl->OCR_Name);
     465           0 :                 sprintf(szTest, "%d", ocr_id);
     466           0 :                 if (!stricmp(szTest, esdl->OCR_Name)) use_old_fmt = 1;
     467             : 
     468           0 :                 j=0;
     469           0 :                 while ((esdl2 = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &j))) {
     470           0 :                         if (esdl2->desc_name && !strcmp(esdl2->desc_name, esdl->OCR_Name)) {
     471           0 :                                 esdl->esd->OCRESID = esdl2->esd->ESID;
     472           0 :                                 break;
     473             :                         }
     474           0 :                         if (use_old_fmt && (esdl2->esd->ESID==ocr_id)) {
     475           0 :                                 esdl->esd->OCRESID = ocr_id;
     476           0 :                                 break;
     477             :                         }
     478             :                 }
     479           0 :                 if (!esdl->esd->OCRESID) {
     480           0 :                         xmt_report(parser, GF_OK, "WARNING: Could not find clock reference %s for ES %s - forcing self-synchronization", esdl->OCR_Name, esdl->desc_name);
     481             :                 }
     482           0 :                 gf_free(esdl->OCR_Name);
     483           0 :                 esdl->OCR_Name = NULL;
     484             :         }
     485             : 
     486             :         /*set dependsOn es ids*/
     487           5 :         i=0;
     488          40 :         while ((esdl = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
     489             :                 Bool use_old_fmt;
     490             :                 u16 dep_id;
     491             :                 char szTest[50];
     492             : 
     493          30 :                 esdl->esd->dependsOnESID = 0;
     494          30 :                 if (!esdl->Depends_Name) continue;
     495             : 
     496             :                 use_old_fmt = 0;
     497           0 :                 dep_id = atoi(esdl->Depends_Name);
     498           0 :                 sprintf(szTest, "%d", dep_id);
     499           0 :                 if (!stricmp(szTest, esdl->Depends_Name)) use_old_fmt = 1;
     500             : 
     501           0 :                 j=0;
     502           0 :                 while ((esdl2 = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &j))) {
     503           0 :                         if (esdl2->desc_name && !strcmp(esdl2->desc_name, esdl->Depends_Name)) {
     504           0 :                                 esdl->esd->dependsOnESID = esdl2->esd->ESID;
     505           0 :                                 break;
     506             :                         }
     507           0 :                         if (use_old_fmt && (esdl2->esd->ESID==dep_id)) {
     508           0 :                                 esdl->esd->dependsOnESID = dep_id;
     509           0 :                                 break;
     510             :                         }
     511             :                 }
     512           0 :                 if (!esdl->esd->dependsOnESID) {
     513           0 :                         xmt_report(parser, GF_OK, "WARNING: Could not find stream dependence %s for ES %s - forcing self-synchronization", esdl->Depends_Name, esdl->desc_name);
     514             :                 }
     515           0 :                 gf_free(esdl->Depends_Name);
     516           0 :                 esdl->Depends_Name = NULL;
     517             :         }
     518             : 
     519          35 :         while (gf_list_count(parser->esd_links)) {
     520          30 :                 esdl = (XMT_ESDLink *)gf_list_get(parser->esd_links, 0);
     521          30 :                 gf_list_rem(parser->esd_links, 0);
     522          30 :                 if (esdl->desc_name) gf_free(esdl->desc_name);
     523          30 :                 gf_free(esdl);
     524             :         }
     525             : 
     526           5 :         i=0;
     527          40 :         while ((l = (XMT_ODLink*)gf_list_enum(parser->od_links, &i))) {
     528          30 :                 if (l->od && !l->od->objectDescriptorID) {
     529             :                         u16 ODID = 1;
     530           0 :                         while (!xmt_odid_available(parser, ODID)) ODID++;
     531           0 :                         l->od->objectDescriptorID = ODID;
     532             :                 }
     533          30 :                 if (l->od) {
     534          20 :                         if (!l->ID) l->ID = l->od->objectDescriptorID;
     535             :                         assert(l->ID == l->od->objectDescriptorID);
     536             :                 }
     537             :         }
     538             : 
     539             :         /*unroll dep in case some URLs reference ODs by their binary IDs not their string ones*/
     540           5 :         i=0;
     541          40 :         while ((l = (XMT_ODLink*)gf_list_enum(parser->od_links, &i))) {
     542             :                 XMT_ODLink *l2;
     543             :                 /*not OD URL*/
     544          30 :                 if (!l->ID) continue;
     545          20 :                 j=i+1;
     546          90 :                 while ((l2 = (XMT_ODLink*)gf_list_enum(parser->od_links, &j))) {
     547             :                         /*not OD URL*/
     548          50 :                         if (!l2->ID) continue;
     549          15 :                         if (l->ID == l2->ID) {
     550           0 :                                 while (gf_list_count(l2->mf_urls)) {
     551           0 :                                         MFURL *url = (MFURL *)gf_list_get(l2->mf_urls, 0);
     552           0 :                                         gf_list_rem(l2->mf_urls, 0);
     553           0 :                                         gf_list_add(l->mf_urls, url);
     554             :                                 }
     555           0 :                                 j--;
     556           0 :                                 gf_list_rem(parser->od_links, j);
     557           0 :                                 if (l2->desc_name) gf_free(l2->desc_name);
     558           0 :                                 gf_list_del(l2->mf_urls);
     559           0 :                                 gf_free(l2);
     560             :                         }
     561             :                 }
     562             :         }
     563             : 
     564          35 :         while (gf_list_count(parser->od_links) ) {
     565          30 :                 l = (XMT_ODLink*)gf_list_get(parser->od_links, 0);
     566          30 :                 if (!l->od) {
     567             :                         /*if no ID found this is not an OD URL*/
     568          10 :                         if (l->ID) {
     569           0 :                                 if (l->desc_name) {
     570           0 :                                         xmt_report(parser, GF_OK, "WARNING: OD \"%s\" (ID %d) not assigned", l->desc_name, l->ID);
     571             :                                 } else {
     572           0 :                                         xmt_report(parser, GF_OK, "WARNING: OD ID %d not assigned", l->ID);
     573             :                                 }
     574             :                         }
     575             :                 } else {
     576             :                         MFURL *the_url;
     577          20 :                         j=0;
     578          60 :                         while ((the_url = (MFURL *)gf_list_enum(l->mf_urls, &j))) {
     579             :                                 u32 k;
     580             :                                 char *seg = NULL;
     581          20 :                                 for (k=0; k<the_url->count; k++) {
     582          20 :                                         SFURL *url = &the_url->vals[k];
     583          20 :                                         if (url->url) seg = strstr(url->url, "#");
     584          20 :                                         if (seg) {
     585           0 :                                                 sprintf(szURL, "od:%d#%s", l->od->objectDescriptorID, seg+1);
     586           0 :                                                 gf_free(url->url);
     587           0 :                                                 url->url = gf_strdup(szURL);
     588             :                                         } else {
     589          20 :                                                 if (url->url) gf_free(url->url);
     590          20 :                                                 url->url = NULL;
     591          20 :                                                 url->OD_ID = l->od->objectDescriptorID;
     592             :                                         }
     593             :                                 }
     594             :                         }
     595             :                 }
     596             : 
     597          30 :                 if (l->desc_name) gf_free(l->desc_name);
     598          30 :                 gf_list_del(l->mf_urls);
     599          30 :                 gf_free(l);
     600          30 :                 gf_list_rem(parser->od_links, 0);
     601             :         }
     602           5 : }
     603             : 
     604             : 
     605         235 : static u32 xmt_get_next_node_id(GF_XMTParser *parser)
     606             : {
     607             :         u32 ID;
     608         235 :         GF_SceneGraph *sc = parser->load->scene_graph;
     609         235 :         if (parser->parsing_proto) sc = gf_sg_proto_get_graph(parser->parsing_proto);
     610         235 :         ID = gf_sg_get_next_available_node_id(sc);
     611         235 :         if (parser->load->ctx && (ID>parser->load->ctx->max_node_id))
     612         205 :                 parser->load->ctx->max_node_id = ID;
     613         235 :         return ID;
     614             : }
     615         260 : static u32 xmt_get_node_id(GF_XMTParser *parser, char *name)
     616             : {
     617             :         GF_Node *n = NULL;
     618         260 :         u32 ID = 0;
     619         260 :         if (sscanf(name, "N%u", &ID) == 1) {
     620             :                 u32 k=1;
     621         175 :                 ID++;
     622         635 :                 while (name && name[k]) {
     623         285 :                         if (strchr("0123456789", name[k])==0) {
     624           0 :                                 ID = 0;
     625           0 :                                 break;
     626             :                         }
     627         285 :                         k++;
     628             :                 }
     629         175 :                 if (ID) {
     630         175 :                         n = gf_sg_find_node(parser->load->scene_graph, ID);
     631         175 :                         if (!n) {
     632          25 :                                 if (parser->load->ctx && (parser->load->ctx->max_node_id<ID)) parser->load->ctx->max_node_id=ID;
     633          25 :                                 return ID;
     634             :                         }
     635             :                 }
     636             :         }
     637         235 :         ID = xmt_get_next_node_id(parser);
     638         235 :         if (n) {
     639         150 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[XMT Parsing] (line %d) Binary ID %s already assigned to %s - keeping internal ID %d\n", gf_xml_sax_get_line(parser->sax_parser), name, gf_node_get_name(n), ID));
     640             :         }
     641         235 :         return ID;
     642             : }
     643             : 
     644        3530 : static u32 xmt_get_node_tag(GF_XMTParser *parser, const char *node_name)
     645             : {
     646             :         u32 tag;
     647             :         /*if VRML and allowing non MPEG4 nodes, use X3D*/
     648        3530 :         if ((parser->doc_type==2) && !(parser->load->flags & GF_SM_LOAD_MPEG4_STRICT)) {
     649             : #ifndef GPAC_DISABLE_X3D
     650           0 :                 tag = gf_node_x3d_type_by_class_name(node_name);
     651           0 :                 if (!tag)
     652             : #endif
     653           0 :                         tag = gf_node_mpeg4_type_by_class_name(node_name);
     654             :         } else {
     655        3530 :                 tag = gf_node_mpeg4_type_by_class_name(node_name);
     656             :                 /*if allowing non MPEG4 nodes, try X3D*/
     657             : #ifndef GPAC_DISABLE_X3D
     658        3530 :                 if (!tag && !(parser->load->flags & GF_SM_LOAD_MPEG4_STRICT)) tag = gf_node_x3d_type_by_class_name(node_name);
     659             : #endif
     660             :         }
     661        3530 :         return tag;
     662             : }
     663             : 
     664         295 : static GF_Node *xmt_find_node(GF_XMTParser *parser, char *ID)
     665             : {
     666             :         u32 i, count, tag;
     667             :         Bool is_proto;
     668             :         char *node_class;
     669             :         GF_Node *n;
     670         295 :         if (!ID) return NULL;
     671         295 :         n = gf_sg_find_node_by_name(parser->load->scene_graph, ID);
     672         295 :         if (n) return n;
     673             : 
     674           5 :         count = gf_list_count(parser->peeked_nodes);
     675           5 :         for (i=0; i<count; i++) {
     676           0 :                 n = (GF_Node*)gf_list_get(parser->peeked_nodes, i);
     677           0 :                 if (!strcmp(gf_node_get_name(n), ID)) return n;
     678             :         }
     679           5 :         node_class = gf_xml_sax_peek_node(parser->sax_parser, "DEF", ID, "ProtoInstance", "name", "<par", &is_proto);
     680           5 :         if (!node_class) return NULL;
     681             : 
     682             :         n = NULL;
     683           5 :         if (is_proto) {
     684             :                 GF_Proto *p;
     685           0 :                 GF_SceneGraph *sg = parser->load->scene_graph;
     686             :                 while (1) {
     687           0 :                         p = gf_sg_find_proto(sg, 0, node_class);
     688           0 :                         if (p) break;
     689           0 :                         sg = sg->parent_scene;
     690           0 :                         if (!sg) break;
     691             :                 }
     692           0 :                 if (!p) {
     693           0 :                         xmt_report(parser, GF_BAD_PARAM, "%s: not a valid/supported proto", node_class);
     694           0 :                         gf_free(node_class);
     695           0 :                         return NULL;
     696             :                 }
     697           0 :                 n = gf_sg_proto_create_instance(parser->load->scene_graph, p);
     698             :         } else {
     699           5 :                 tag = xmt_get_node_tag(parser, node_class);
     700           5 :                 n = gf_node_new(parser->load->scene_graph, tag);
     701             :         }
     702           5 :         gf_free(node_class);
     703           5 :         if (n) {
     704           5 :                 u32 nID = xmt_get_node_id(parser, ID);
     705           5 :                 gf_node_set_id(n, nID, ID);
     706           5 :                 if (!parser->parsing_proto) gf_node_init(n);
     707           5 :                 gf_list_add(parser->peeked_nodes, n);
     708             :         }
     709             :         return n;
     710             : }
     711             : 
     712             : #define XMT_GET_ONE_VAL \
     713             :         char value[100];        \
     714             :         u32 i;                  \
     715             :         char *str = a_value;    \
     716             :         if (!str) {             \
     717             :                 xmt_report(parser, GF_BAD_PARAM, "%s: Number expected", name);        \
     718             :                 return 0;               \
     719             :         }               \
     720             :         while (str[0] == ' ') str += 1; \
     721             :         i = 0;  \
     722             :         while ((str[i] != ' ') && str[i]) {     \
     723             :                 value[i] = str[i];                      \
     724             :                 i++;                            \
     725             :         }                                       \
     726             :         value[i] = 0;   \
     727             :         while ((str[i] == ' ') && str[i]) i++;
     728             : 
     729         560 : static u32 xmt_parse_int(GF_XMTParser *parser, const char *name, SFInt32 *val, char *a_value)
     730             : {
     731         560 :         XMT_GET_ONE_VAL
     732         560 :         *val = atoi(value);
     733         560 :         return i;
     734             : }
     735        3625 : static u32 xmt_parse_float(GF_XMTParser *parser, const char *name, SFFloat *val, char *a_value)
     736             : {
     737        3625 :         XMT_GET_ONE_VAL
     738        3625 :         *val = FLT2FIX(atof(value));
     739        3625 :         return i;
     740             : }
     741           5 : static u32 xmt_parse_time(GF_XMTParser *parser, const char *name, SFTime *val, char *a_value)
     742             : {
     743           5 :         XMT_GET_ONE_VAL
     744           5 :         *val = atof(value);
     745           5 :         return i;
     746             : }
     747         160 : static u32 xmt_parse_bool(GF_XMTParser *parser, const char *name, SFBool *val, char *a_value)
     748             : {
     749         160 :         XMT_GET_ONE_VAL
     750         160 :         if (!stricmp(value, "1") || !stricmp(value, "true"))
     751         115 :                 *val = 1;
     752             :         else
     753          45 :                 *val = 0;
     754             :         return i;
     755             : }
     756             : 
     757         150 : static u32 xmt_parse_string(GF_XMTParser *parser, const char *name, SFString *val, Bool is_mf, char *a_value)
     758             : {
     759             :         char *value;
     760             :         char sep[10];
     761             :         u32 len;
     762             :         u32 i=0;
     763             :         u32 k=0;
     764             :         char *str = a_value;
     765         150 :         if (!str) return 0;
     766             : 
     767             :         /*SF string, no inspection*/
     768         150 :         if (!is_mf) {
     769          25 :                 len = (u32) strlen(str);
     770          25 :                 if (val->buffer) gf_free(val->buffer);
     771          25 :                 val->buffer = NULL;
     772          25 :                 if (len) val->buffer = gf_strdup(str);
     773          25 :                 return len+1;
     774             :         }
     775             : 
     776             :         /*now this is the REAL pain:
     777             :                 X3D allows '"String1" "String2"' and therefore '"String &quot;test&quot;"'
     778             :                 XMT allows '&quot;String1&quot; &quot;String2&quot;' and therefore '&quot;String \&quot;test\&quot;&quot;'
     779             :         thus translating the string from xml to UTF may screw up the separators !! We need to identify them
     780             :         */
     781             : 
     782             :         i = 0;
     783           0 :         while ((str[i]==' ') || (str[i]=='\t')) i++;
     784         125 :         if (!strncmp(&str[i], "&quot;", 6)) strcpy(sep, "&quot;");
     785         125 :         else if (!strncmp(&str[i], "&apos;", 6)) strcpy(sep, "&apos;");
     786         125 :         else if (str[i]=='\'') strcpy(sep, "\'");
     787         125 :         else if (str[i]=='\"') strcpy(sep, "\"");
     788             :         /*handle as a single field (old GPAC XMT & any unknown cases...*/
     789             :         else {
     790          10 :                 len = (u32) strlen(str);
     791          10 :                 if (val->buffer) gf_free(val->buffer);
     792          10 :                 val->buffer = NULL;
     793          10 :                 if (len) val->buffer = gf_strdup(str);
     794             :                 return len;
     795             :         }
     796             :         k = 0;
     797         115 :         i += (u32) strlen(sep);
     798             : 
     799         115 :         value = gf_strdup(str);
     800             : 
     801         115 :         if (strncmp(&str[i], sep, strlen(sep))) {
     802             : 
     803        2215 :                 while (str[i]) {
     804        2215 :                         if ((str[i] == '\\') && !strncmp(&str[i+1], sep, strlen(sep))) {
     805             :                                 i++;
     806           0 :                                 continue;
     807             :                         }
     808        2215 :                         value[k] = str[i];
     809        2215 :                         i++;
     810        2215 :                         k++;
     811        2215 :                         if (!strncmp(&str[i], sep, strlen(sep)) && (str[i-1] != '\\')) break;
     812             :                 }
     813             :         }
     814         115 :         value[k] = 0;
     815         115 :         len = (u32) strlen(sep) + i;
     816             : 
     817         115 :         if (val->buffer) gf_free(val->buffer);
     818         115 :         val->buffer = NULL;
     819         115 :         if (strlen(value)) val->buffer = gf_strdup(value);
     820         115 :         gf_free(value);
     821             :         return len;
     822             : }
     823             : 
     824          30 : static u32 xmt_parse_url(GF_XMTParser *parser, const char *name, MFURL *val, GF_Node *owner, Bool is_mf, char *a_value)
     825             : {
     826             :         SFString sfstr;
     827             :         u32 res, idx;
     828             :         char value[5000], *tmp;
     829             : 
     830             :         /*parse as a string*/
     831          30 :         sfstr.buffer = NULL;
     832          30 :         res = xmt_parse_string(parser, name, &sfstr, is_mf, a_value);
     833          30 :         if (parser->last_error) return res;
     834             : 
     835             :         assert(val->count);
     836          30 :         idx = val->count - 1;
     837          30 :         if (val->vals[idx].url) gf_free(val->vals[idx].url);
     838          30 :         val->vals[idx].url = sfstr.buffer;
     839          30 :         val->vals[idx].OD_ID = 0;
     840             :         /*empty*/
     841          30 :         if (!val->vals[idx].url) return res;
     842             : 
     843             :         /*remove segments & viewpoints info to create OD link*/
     844             :         strcpy(value, val->vals[idx].url);
     845          30 :         tmp = strstr(value, "#");
     846          30 :         if (tmp) tmp[0] = 0;
     847             : 
     848             :         /*according to XMT-A spec, both 'od:' and 'od://' are tolerated in XMT-A*/
     849          30 :         if (!strnicmp(value, "od://", 5))
     850          20 :                 xmt_new_od_link_from_node(parser, value+5, val);
     851          10 :         else if (!strnicmp(value, "od:", 3))
     852           0 :                 xmt_new_od_link_from_node(parser, value+3, val);
     853             :         else
     854          10 :                 xmt_new_od_link_from_node(parser, value, val);
     855             :         return res;
     856             : }
     857             : 
     858             : 
     859           5 : static u32 xmt_parse_script(GF_XMTParser *parser, const char *name, SFScript *val, Bool is_mf, char *a_value)
     860             : {
     861             :         SFString sfstr;
     862             :         u32 res;
     863             : 
     864             :         /*parse as a string*/
     865           5 :         sfstr.buffer = NULL;
     866           5 :         res = xmt_parse_string(parser, name, &sfstr, is_mf, a_value);
     867           5 :         if (parser->last_error) return res;
     868             : 
     869           5 :         if (val->script_text) gf_free(val->script_text);
     870           5 :         val->script_text = (char*)sfstr.buffer;
     871             :         return res;
     872             : }
     873             : 
     874             : static void xmt_offset_time(GF_XMTParser *parser, Double *time)
     875             : {
     876          13 :         if (time && parser)
     877          13 :                 *time += parser->au_time;
     878             : }
     879           5 : static void xmt_check_time_offset(GF_XMTParser *parser, GF_Node *n, GF_FieldInfo *info)
     880             : {
     881           5 :         if (!(parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK)) return;
     882           1 :         if (gf_node_get_tag(n) != TAG_ProtoNode) {
     883           1 :                 if (!stricmp(info->name, "startTime") || !stricmp(info->name, "stopTime"))
     884           1 :                         xmt_offset_time(parser, (Double *)info->far_ptr);
     885           0 :         } else if (gf_sg_proto_field_is_sftime_offset(n, info)) {
     886           0 :                 xmt_offset_time(parser, (Double *)info->far_ptr);
     887             :         }
     888             : }
     889             : 
     890        2805 : static u32 xmt_parse_sf_field(GF_XMTParser *parser, GF_FieldInfo *info, GF_Node *n, char *a_value)
     891             : {
     892             :         u32 res = 0;
     893        2805 :         switch (info->fieldType) {
     894         545 :         case GF_SG_VRML_SFINT32:
     895         545 :                 res = xmt_parse_int(parser, info->name, (SFInt32 *)info->far_ptr, a_value);
     896         545 :                 break;
     897         160 :         case GF_SG_VRML_SFBOOL:
     898         160 :                 res = xmt_parse_bool(parser, info->name, (SFBool *)info->far_ptr, a_value);
     899         160 :                 break;
     900        1000 :         case GF_SG_VRML_SFFLOAT:
     901        1000 :                 res = xmt_parse_float(parser, info->name, (SFFloat *)info->far_ptr, a_value);
     902        1000 :                 break;
     903           5 :         case GF_SG_VRML_SFTIME:
     904           5 :                 res = xmt_parse_time(parser, info->name, (SFTime *)info->far_ptr, a_value);
     905           5 :                 if (n) xmt_check_time_offset(parser, n, info);
     906             :                 break;
     907         255 :         case GF_SG_VRML_SFCOLOR:
     908         255 :                 res = xmt_parse_float(parser, info->name, & ((SFColor *)info->far_ptr)->red, a_value);
     909         255 :                 res += xmt_parse_float(parser, info->name, & ((SFColor *)info->far_ptr)->green, a_value + res);
     910         255 :                 res += xmt_parse_float(parser, info->name, & ((SFColor *)info->far_ptr)->blue, a_value + res);
     911         255 :                 break;
     912         580 :         case GF_SG_VRML_SFVEC2F:
     913         580 :                 res = xmt_parse_float(parser, info->name, & ((SFVec2f *)info->far_ptr)->x, a_value);
     914         580 :                 res += xmt_parse_float(parser, info->name, & ((SFVec2f *)info->far_ptr)->y, a_value + res);
     915         580 :                 break;
     916         220 :         case GF_SG_VRML_SFVEC3F:
     917         220 :                 res = xmt_parse_float(parser, info->name, & ((SFVec3f *)info->far_ptr)->x, a_value);
     918         220 :                 res += xmt_parse_float(parser, info->name, & ((SFVec3f *)info->far_ptr)->y, a_value + res);
     919         220 :                 res += xmt_parse_float(parser, info->name, & ((SFVec3f *)info->far_ptr)->z, a_value + res);
     920         220 :                 break;
     921          10 :         case GF_SG_VRML_SFROTATION:
     922          10 :                 res = xmt_parse_float(parser, info->name, & ((SFRotation *)info->far_ptr)->x, a_value);
     923          10 :                 res += xmt_parse_float(parser, info->name, & ((SFRotation *)info->far_ptr)->y, a_value + res);
     924          10 :                 res += xmt_parse_float(parser, info->name, & ((SFRotation *)info->far_ptr)->z, a_value + res);
     925          10 :                 res += xmt_parse_float(parser, info->name, & ((SFRotation *)info->far_ptr)->q, a_value + res);
     926          10 :                 break;
     927          25 :         case GF_SG_VRML_SFSTRING:
     928          25 :                 res = xmt_parse_string(parser, info->name, (SFString*)info->far_ptr, 0, a_value);
     929          25 :                 if (n && (n->sgprivate->tag==TAG_MPEG4_BitWrapper)) {
     930           0 :                         gf_sm_update_bitwrapper_buffer(n, parser->load->fileName);
     931             :                 }
     932             :                 break;
     933           0 :         case GF_SG_VRML_SFSCRIPT:
     934           0 :                 res = xmt_parse_script(parser, info->name, (SFScript *)info->far_ptr, 0, a_value);
     935           0 :                 break;
     936           0 :         case GF_SG_VRML_SFCOMMANDBUFFER:
     937             :         {
     938           0 :                 SFCommandBuffer *cb = (SFCommandBuffer *)info->far_ptr;
     939           0 :                 if (parser->command_buffer) {
     940           0 :                         cb->buffer = (unsigned char*)parser->command_buffer;
     941             :                 } else {
     942           0 :                         cb->buffer = (unsigned char*)parser->command;
     943             :                 }
     944           0 :                 parser->command_buffer = cb;
     945             :         }
     946           0 :         break;
     947             : 
     948           5 :         case GF_SG_VRML_SFIMAGE:
     949             :         {
     950             :                 u32 k, size, v;
     951           5 :                 SFImage *img = (SFImage *)info->far_ptr;
     952           5 :                 res = xmt_parse_int(parser, "width", (SFInt32*)&img->width, a_value);
     953           5 :                 if (parser->last_error) return res;
     954           5 :                 res += xmt_parse_int(parser, "height", (SFInt32*)&img->height, a_value + res);
     955           5 :                 if (parser->last_error) return res;
     956           5 :                 res += xmt_parse_int(parser, "nbComp", (SFInt32*)&v, a_value + res);
     957           5 :                 if (parser->last_error) return res;
     958           5 :                 img->numComponents = v;
     959           5 :                 size = img->width * img->height * img->numComponents;
     960           5 :                 if (img->pixels) gf_free(img->pixels);
     961           5 :                 img->pixels = (unsigned char*)gf_malloc(sizeof(char) * size);
     962           5 :                 a_value += res;
     963             :                 res = 0;
     964          85 :                 for (k=0; k<size; k++) {
     965             :                         char *name = "pixels";
     966          80 :                         XMT_GET_ONE_VAL
     967          80 :                         if (strstr(value, "0x")) sscanf(value, "%x", &v);
     968           0 :                         else sscanf(value, "%u", &v);
     969          80 :                         switch (img->numComponents) {
     970          80 :                         case 1:
     971          80 :                                 img->pixels[k] = (char) v;
     972          80 :                                 break;
     973           0 :                         case 2:
     974           0 :                                 img->pixels[k] = (char) (v>>8)&0xFF;
     975           0 :                                 img->pixels[k+1] = (char) (v)&0xFF;
     976             :                                 k++;
     977           0 :                                 break;
     978           0 :                         case 3:
     979           0 :                                 img->pixels[k] = (char) (v>>16)&0xFF;
     980           0 :                                 img->pixels[k+1] = (char) (v>>8)&0xFF;
     981           0 :                                 img->pixels[k+2] = (char) (v)&0xFF;
     982             :                                 k+=2;
     983           0 :                                 break;
     984           0 :                         case 4:
     985           0 :                                 img->pixels[k] = (char) (v>>24)&0xFF;
     986           0 :                                 img->pixels[k+1] = (char) (v>>16)&0xFF;
     987           0 :                                 img->pixels[k+2] = (char) (v>>8)&0xFF;
     988           0 :                                 img->pixels[k+3] = (char) (v)&0xFF;
     989             :                                 k+=3;
     990           0 :                                 break;
     991             :                         }
     992          80 :                         res += i;
     993          80 :                         a_value += i;
     994             :                 }
     995             :         }
     996           5 :         break;
     997             : 
     998           0 :         default:
     999           0 :                 parser->last_error = GF_NOT_SUPPORTED;
    1000           0 :                 break;
    1001             :         }
    1002             :         return res;
    1003             : }
    1004             : 
    1005         250 : static void xmt_parse_mf_field(GF_XMTParser *parser, GF_FieldInfo *info, GF_Node *n, char *value)
    1006             : {
    1007             :         u32 res;
    1008             :         GF_FieldInfo sfInfo;
    1009         250 :         sfInfo.fieldType = gf_sg_vrml_get_sf_type(info->fieldType);
    1010         250 :         sfInfo.name = info->name;
    1011         250 :         gf_sg_vrml_mf_reset(info->far_ptr, info->fieldType);
    1012             : 
    1013         250 :         if (!value || !strlen(value)) return;
    1014             : 
    1015        2305 :         while (value[0] && !parser->last_error) {
    1016             : 
    1017        2115 :                 while (value[0] == ' ')
    1018          60 :                         value++;
    1019        2055 :                 if (!value[0]) break;
    1020             : 
    1021        2055 :                 gf_sg_vrml_mf_append(info->far_ptr, info->fieldType, &sfInfo.far_ptr);
    1022             : 
    1023             :                 /*special case for MF type based on string (MFString, MFURL and MFScript), we need to take care
    1024             :                 of all possible forms of XML multi string encoding*/
    1025        2055 :                 if (sfInfo.fieldType == GF_SG_VRML_SFSTRING) {
    1026          90 :                         res = xmt_parse_string(parser, info->name, (SFString*)sfInfo.far_ptr, 1, value);
    1027        1965 :                 } else if (sfInfo.fieldType == GF_SG_VRML_SFURL) {
    1028          30 :                         res = xmt_parse_url(parser, info->name, (MFURL *)info->far_ptr, n, 1, value);
    1029        1935 :                 } else if (sfInfo.fieldType == GF_SG_VRML_SFSCRIPT) {
    1030           5 :                         res = xmt_parse_script(parser, info->name, (SFScript*)sfInfo.far_ptr, 1, value);
    1031             :                 } else {
    1032        1930 :                         res = xmt_parse_sf_field(parser, &sfInfo, n, value);
    1033             :                 }
    1034        2055 :                 if (res) {
    1035        2055 :                         value += res;
    1036             :                 } else {
    1037             :                         break;
    1038             :                 }
    1039             :         }
    1040             : }
    1041             : 
    1042          10 : static Bool xmt_has_been_def(GF_XMTParser *parser, char *node_name)
    1043             : {
    1044             :         u32 i, count;
    1045          10 :         count = gf_list_count(parser->def_nodes);
    1046         170 :         for (i=0; i<count; i++) {
    1047         175 :                 GF_Node *n = (GF_Node *)gf_list_get(parser->def_nodes, i);
    1048         175 :                 if (!strcmp(gf_node_get_name(n), node_name)) return 1;
    1049             :         }
    1050             :         return 0;
    1051             : }
    1052             : 
    1053          15 : static u32 xmt_get_route(GF_XMTParser *parser, char *name, Bool del_com)
    1054             : {
    1055             :         u32 i;
    1056             :         GF_Command *com;
    1057          15 :         GF_Route *r = gf_sg_route_find_by_name(parser->load->scene_graph, name);
    1058          15 :         if (r) return r->ID;
    1059          15 :         i=0;
    1060          15 :         while ((com = (GF_Command *)gf_list_enum(parser->inserted_routes, &i))) {
    1061          10 :                 if (com->def_name && !strcmp(com->def_name, name)) {
    1062          10 :                         if (del_com) gf_list_rem(parser->inserted_routes, i);
    1063          10 :                         return com->RouteID;
    1064             :                 }
    1065             :         }
    1066             :         return 0;
    1067             : }
    1068             : 
    1069           5 : static Bool xmt_route_id_used(GF_XMTParser *parser, u32 ID)
    1070             : {
    1071             :         u32 i;
    1072             :         GF_Command *com;
    1073           5 :         GF_Route *r = gf_sg_route_find(parser->load->scene_graph, ID);
    1074           5 :         if (r) return 1;
    1075           5 :         i=0;
    1076           5 :         while ((com = (GF_Command *)gf_list_enum(parser->inserted_routes, &i))) {
    1077           0 :                 if (com->RouteID == ID) return 1;
    1078             :         }
    1079             :         return 0;
    1080             : }
    1081           0 : static u32 xmt_get_next_route_id(GF_XMTParser *parser)
    1082             : {
    1083             :         u32 ID;
    1084           0 :         GF_SceneGraph *sc = parser->load->scene_graph;
    1085           0 :         if (parser->parsing_proto) sc = gf_sg_proto_get_graph(parser->parsing_proto);
    1086             : 
    1087           0 :         ID = gf_sg_get_next_available_route_id(sc);
    1088           0 :         if (parser->load->ctx && (ID>parser->load->ctx->max_route_id))
    1089           0 :                 parser->load->ctx->max_route_id = ID;
    1090           0 :         return ID;
    1091             : }
    1092             : 
    1093          20 : static void xmt_resolve_routes(GF_XMTParser *parser)
    1094             : {
    1095             :         /*resolve all commands*/
    1096             :         while (1) {
    1097          20 :                 GF_Command *com = (GF_Command *)gf_list_last(parser->unresolved_routes);
    1098          20 :                 if (!com) break;
    1099           0 :                 gf_list_rem_last(parser->unresolved_routes);
    1100           0 :                 switch (com->tag) {
    1101           0 :                 case GF_SG_ROUTE_DELETE:
    1102             :                 case GF_SG_ROUTE_REPLACE:
    1103           0 :                         com->RouteID = xmt_get_route(parser, com->unres_name, 0);
    1104           0 :                         if (!com->RouteID) {
    1105           0 :                                 xmt_report(parser, GF_BAD_PARAM, "Cannot resolve GF_Route DEF %s", com->unres_name);
    1106             :                         } else {
    1107           0 :                                 com->unresolved = 0;
    1108             :                         }
    1109           0 :                         gf_free(com->unres_name);
    1110           0 :                         com->unres_name = NULL;
    1111           0 :                         break;
    1112             :                 }
    1113             :         }
    1114          10 :         while (gf_list_count(parser->inserted_routes)) gf_list_rem(parser->inserted_routes, 0);
    1115          20 : }
    1116          40 : static void xmt_parse_route(GF_XMTParser *parser, const GF_XMLAttribute *attributes, u32 nb_attributes, Bool is_insert, GF_Command *com)
    1117             : {
    1118             :         GF_Route *r;
    1119             :         char *toN, *toNF, *fromN, *fromNF, *ID;
    1120             :         GF_Node *orig, *dest;
    1121             :         GF_Err e;
    1122             :         u32 rID, i;
    1123             :         GF_FieldInfo orig_field, dest_field;
    1124             : 
    1125             :         toN = toNF = fromN = fromNF = ID = NULL;
    1126             : 
    1127         165 :         for (i=0; i<nb_attributes; i++) {
    1128         165 :                 GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1129         165 :                 if (!att->value || !strlen(att->value)) continue;
    1130         165 :                 if (!strcmp(att->name, "fromNode")) fromN = att->value;
    1131         125 :                 else if (!strcmp(att->name, "fromField")) fromNF = att->value;
    1132          85 :                 else if (!strcmp(att->name, "toNode")) toN = att->value;
    1133          45 :                 else if (!strcmp(att->name, "toField")) toNF = att->value;
    1134           5 :                 else if (!strcmp(att->name, "DEF")) ID = att->value;
    1135             :         }
    1136             : 
    1137          40 :         orig = xmt_find_node(parser, fromN);
    1138          40 :         if (!orig) {
    1139           0 :                 xmt_report(parser, GF_BAD_PARAM, "ROUTE: Cannot find origin node %s", fromN);
    1140          40 :                 return;
    1141             :         }
    1142          40 :         if (fromNF) {
    1143          40 :                 e = gf_node_get_field_by_name(orig, fromNF, &orig_field);
    1144          40 :                 if (e != GF_OK) {
    1145           0 :                         char *sz = strstr(fromNF, "_changed");
    1146           0 :                         if (sz) {
    1147           0 :                                 sz[0] = 0;
    1148           0 :                                 e = gf_node_get_field_by_name(orig, fromNF, &orig_field);
    1149             :                         }
    1150             :                 }
    1151             :         } else {
    1152             :                 e = GF_BAD_PARAM;
    1153             :         }
    1154          40 :         if (e!=GF_OK) {
    1155           0 :                 xmt_report(parser, GF_BAD_PARAM, "%s is not an attribute of node %s", fromNF, fromN);
    1156             :                 return;
    1157             :         }
    1158             : 
    1159          40 :         dest = xmt_find_node(parser, toN);
    1160          40 :         if (!dest) {
    1161           0 :                 xmt_report(parser, GF_BAD_PARAM, "ROUTE: Cannot find destination node %s", toN);
    1162             :                 return;
    1163             :         }
    1164          40 :         if (toNF) {
    1165          40 :                 e = gf_node_get_field_by_name(dest, toNF, &dest_field);
    1166          40 :                 if ((e != GF_OK) && !strnicmp(toNF, "set_", 4))
    1167           0 :                         e = gf_node_get_field_by_name(dest, &toNF[4], &dest_field);
    1168             :         } else {
    1169             :                 e = GF_BAD_PARAM;
    1170             :         }
    1171          40 :         if (e != GF_OK) {
    1172           0 :                 xmt_report(parser, GF_BAD_PARAM, "%s is not an attribute of node %s", toNF, toN);
    1173             :                 return;
    1174             :         }
    1175             : 
    1176             :         rID = 0;
    1177          40 :         if (ID && strlen(ID)) {
    1178           5 :                 rID = xmt_get_route(parser, ID, 0);
    1179           5 :                 if (!rID && (ID[0]=='R') ) {
    1180          10 :                         rID = atoi(&ID[1]);
    1181           5 :                         if (rID) {
    1182           5 :                                 rID++;
    1183           5 :                                 if (xmt_route_id_used(parser, rID)) rID = 0;
    1184             :                         }
    1185             :                 }
    1186           5 :                 if (!rID) rID = xmt_get_next_route_id(parser);
    1187             :         }
    1188          40 :         if (com) {
    1189             :                 /*for insert command*/
    1190          40 :                 if (rID) {
    1191           5 :                         com->RouteID = rID;
    1192           5 :                         com->def_name = gf_strdup(ID);
    1193             :                         /*whenever not inserting in graph, keep track of max defined ID*/
    1194           5 :                         gf_sg_set_max_defined_route_id(parser->load->scene_graph, rID);
    1195           5 :                         if (rID>parser->load->ctx->max_route_id) parser->load->ctx->max_route_id = rID;
    1196             : 
    1197             :                 }
    1198          40 :                 com->fromNodeID = gf_node_get_id(orig);
    1199          40 :                 com->fromFieldIndex = orig_field.fieldIndex;
    1200          40 :                 com->toNodeID = gf_node_get_id(dest);
    1201          40 :                 com->toFieldIndex = dest_field.fieldIndex;
    1202             :                 return;
    1203             :         }
    1204           0 :         r = gf_sg_route_new(parser->load->scene_graph, orig, orig_field.fieldIndex, dest, dest_field.fieldIndex);
    1205           0 :         if (rID) {
    1206           0 :                 gf_sg_route_set_id(r, rID);
    1207           0 :                 gf_sg_route_set_name(r, ID);
    1208             :         }
    1209             : }
    1210             : 
    1211             : 
    1212         965 : static void xmt_update_timenode(GF_XMTParser *parser, GF_Node *node)
    1213             : {
    1214         965 :         if (!(parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK)) return;
    1215             : 
    1216         193 :         switch (gf_node_get_tag(node)) {
    1217           1 :         case TAG_MPEG4_AnimationStream:
    1218           1 :                 xmt_offset_time(parser, & ((M_AnimationStream*)node)->startTime);
    1219           1 :                 xmt_offset_time(parser, & ((M_AnimationStream*)node)->stopTime);
    1220             :                 break;
    1221           1 :         case TAG_MPEG4_AudioBuffer:
    1222           1 :                 xmt_offset_time(parser, & ((M_AudioBuffer*)node)->startTime);
    1223           1 :                 xmt_offset_time(parser, & ((M_AudioBuffer*)node)->stopTime);
    1224             :                 break;
    1225           1 :         case TAG_MPEG4_AudioClip:
    1226           1 :                 xmt_offset_time(parser, & ((M_AudioClip*)node)->startTime);
    1227           1 :                 xmt_offset_time(parser, & ((M_AudioClip*)node)->stopTime);
    1228             :                 break;
    1229           1 :         case TAG_MPEG4_AudioSource:
    1230           1 :                 xmt_offset_time(parser, & ((M_AudioSource*)node)->startTime);
    1231           1 :                 xmt_offset_time(parser, & ((M_AudioSource*)node)->stopTime);
    1232             :                 break;
    1233           1 :         case TAG_MPEG4_MovieTexture:
    1234           1 :                 xmt_offset_time(parser, & ((M_MovieTexture*)node)->startTime);
    1235           1 :                 xmt_offset_time(parser, & ((M_MovieTexture*)node)->stopTime);
    1236             :                 break;
    1237           1 :         case TAG_MPEG4_TimeSensor:
    1238           1 :                 xmt_offset_time(parser, & ((M_TimeSensor*)node)->startTime);
    1239           1 :                 xmt_offset_time(parser, & ((M_TimeSensor*)node)->stopTime);
    1240             :                 break;
    1241           4 :         case TAG_ProtoNode:
    1242             :         {
    1243             :                 u32 i, nbFields;
    1244             :                 GF_FieldInfo inf;
    1245           4 :                 nbFields = gf_node_get_num_fields_in_mode(node, GF_SG_FIELD_CODING_ALL);
    1246          34 :                 for (i=0; i<nbFields; i++) {
    1247          30 :                         gf_node_get_field(node, i, &inf);
    1248          30 :                         if (inf.fieldType != GF_SG_VRML_SFTIME) continue;
    1249           0 :                         xmt_check_time_offset(parser, node, &inf);
    1250             :                 }
    1251             :         }
    1252           4 :         break;
    1253             :         }
    1254             : }
    1255             : 
    1256         220 : static void xmt_strip_name(const char *in, char *out)
    1257             : {
    1258         220 :         while (in[0]==' ') in++;
    1259             :         strcpy(out, in);
    1260           0 :         while (out[strlen(out)-1] == ' ') out[strlen(out)-1] = 0;
    1261         220 : }
    1262             : 
    1263         110 : static u32 xmt_get_ft_by_name(const char *_name)
    1264             : {
    1265             :         char name[1024];
    1266         110 :         xmt_strip_name(_name, name);
    1267             : 
    1268         110 :         if (!strcmp(name, "Boolean") || !strcmp(name, "SFBool")) return GF_SG_VRML_SFBOOL;
    1269          90 :         else if (!strcmp(name, "Integer") || !strcmp(name, "SFInt32")) return GF_SG_VRML_SFINT32;
    1270          90 :         else if (!strcmp(name, "Color") || !strcmp(name, "SFColor")) return GF_SG_VRML_SFCOLOR;
    1271          70 :         else if (!strcmp(name, "Vector2") || !strcmp(name, "SFVec2f")) return GF_SG_VRML_SFVEC2F;
    1272          50 :         else if (!strcmp(name, "Image") || !strcmp(name, "SFImage")) return GF_SG_VRML_SFIMAGE;
    1273          50 :         else if (!strcmp(name, "Time") || !strcmp(name, "SFTime")) return GF_SG_VRML_SFTIME;
    1274          45 :         else if (!strcmp(name, "Float") || !strcmp(name, "SFFloat")) return GF_SG_VRML_SFFLOAT;
    1275          15 :         else if (!strcmp(name, "Vector3") || !strcmp(name, "SFVec3f")) return GF_SG_VRML_SFVEC3F;
    1276          15 :         else if (!strcmp(name, "Rotation") || !strcmp(name, "SFRotation")) return GF_SG_VRML_SFROTATION;
    1277          15 :         else if (!strcmp(name, "String") || !strcmp(name, "SFString")) return GF_SG_VRML_SFSTRING;
    1278          15 :         else if (!strcmp(name, "Node") || !strcmp(name, "SFNode")) return GF_SG_VRML_SFNODE;
    1279           0 :         else if (!strcmp(name, "Booleans") || !strcmp(name, "MFBool")) return GF_SG_VRML_MFBOOL;
    1280           0 :         else if (!strcmp(name, "Integers") || !strcmp(name, "MFInt32")) return GF_SG_VRML_MFINT32;
    1281           0 :         else if (!strcmp(name, "Colors") || !strcmp(name, "MFColor")) return GF_SG_VRML_MFCOLOR;
    1282           0 :         else if (!strcmp(name, "Vector2s") || !strcmp(name, "Vector2Array") || !strcmp(name, "MFVec2f")) return GF_SG_VRML_MFVEC2F;
    1283           0 :         else if (!strcmp(name, "Images") || !strcmp(name, "MFImage")) return GF_SG_VRML_MFIMAGE;
    1284           0 :         else if (!strcmp(name, "Times") || !strcmp(name, "MFTime")) return GF_SG_VRML_MFTIME;
    1285           0 :         else if (!strcmp(name, "Floats") || !strcmp(name, "MFFloat")) return GF_SG_VRML_MFFLOAT;
    1286           0 :         else if (!strcmp(name, "Vector3s") || !strcmp(name, "Vector3Array") || !strcmp(name, "MFVec3f")) return GF_SG_VRML_MFVEC3F;
    1287           0 :         else if (!strcmp(name, "Rotations") || !strcmp(name, "MFRotation")) return GF_SG_VRML_MFROTATION;
    1288           0 :         else if (!strcmp(name, "Strings") || !strcmp(name, "MFString")) return GF_SG_VRML_MFSTRING;
    1289           0 :         else if (!strcmp(name, "Nodes") || !strcmp(name, "MFNode")) return GF_SG_VRML_MFNODE;
    1290             : 
    1291           0 :         else if (!strcmp(name, "SFColorRGBA")) return GF_SG_VRML_SFCOLORRGBA;
    1292           0 :         else if (!strcmp(name, "MFColorRGBA")) return GF_SG_VRML_MFCOLORRGBA;
    1293           0 :         else if (!strcmp(name, "SFDouble")) return GF_SG_VRML_SFDOUBLE;
    1294           0 :         else if (!strcmp(name, "MFDouble")) return GF_SG_VRML_MFDOUBLE;
    1295           0 :         else if (!strcmp(name, "SFVec3d")) return GF_SG_VRML_SFVEC3D;
    1296           0 :         else if (!strcmp(name, "MFVec3d")) return GF_SG_VRML_MFVEC3D;
    1297           0 :         else if (!strcmp(name, "SFVec2d")) return GF_SG_VRML_SFVEC2D;
    1298           0 :         else if (!strcmp(name, "MFVec2d")) return GF_SG_VRML_MFVEC2D;
    1299           0 :         else return GF_SG_VRML_UNKNOWN;
    1300             : }
    1301          10 : static u32 xmt_get_script_et_by_name(const char *_name)
    1302             : {
    1303             :         char name[1024];
    1304          10 :         xmt_strip_name((char *)_name, name);
    1305             : 
    1306          10 :         if (!strcmp(name, "eventIn") || !strcmp(name, "inputOnly") ) return GF_SG_SCRIPT_TYPE_EVENT_IN;
    1307           5 :         else if (!strcmp(name, "eventOut") || !strcmp(name, "outputOnly")) return GF_SG_SCRIPT_TYPE_EVENT_OUT;
    1308           5 :         else if (!strcmp(name, "field") || !strcmp(name, "initializeOnly") ) return GF_SG_SCRIPT_TYPE_FIELD;
    1309           0 :         else return GF_SG_EVENT_UNKNOWN;
    1310             : }
    1311         100 : static u32 xmt_get_et_by_name(const char *_name)
    1312             : {
    1313             :         char name[1024];
    1314         100 :         xmt_strip_name((char *)_name, name);
    1315             : 
    1316         100 :         if (!strcmp(name, "eventIn") || !strcmp(name, "inputOnly") ) return GF_SG_EVENT_IN;
    1317          90 :         else if (!strcmp(name, "eventOut") || !strcmp(name, "outputOnly")) return GF_SG_EVENT_OUT;
    1318          90 :         else if (!strcmp(name, "field") || !strcmp(name, "initializeOnly") ) return GF_SG_EVENT_FIELD;
    1319          90 :         else if (!strcmp(name, "exposedField") || !strcmp(name, "inputOutput")) return GF_SG_EVENT_EXPOSED_FIELD;
    1320           0 :         else return GF_SG_EVENT_UNKNOWN;
    1321             : }
    1322             : 
    1323          10 : static void xmt_parse_script_field(GF_XMTParser *parser, GF_Node *node, const GF_XMLAttribute *attributes, u32 nb_attributes)
    1324             : {
    1325             :         GF_ScriptField *scfield;
    1326             :         GF_FieldInfo field;
    1327             :         u32 fieldType, eventType, i;
    1328             :         char *val = NULL;
    1329             :         char *fieldName = NULL;
    1330             :         fieldType = eventType = 0;
    1331             : 
    1332          40 :         for (i=0; i<nb_attributes; i++) {
    1333          30 :                 GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
    1334          30 :                 if (!att->value || !strlen(att->value)) continue;
    1335          30 :                 if (!strcmp(att->name, "name")) fieldName = att->value;
    1336          20 :                 else if (!strcmp(att->name, "type")) fieldType = xmt_get_ft_by_name(att->value);
    1337          10 :                 else if (!strcmp(att->name, "vrml97Hint") || !strcmp(att->name, "accessType")) eventType = xmt_get_script_et_by_name(att->value);
    1338           0 :                 else if (strstr(att->name, "value") || strstr(att->name, "Value")) val = att->value;
    1339             :         }
    1340          10 :         scfield = gf_sg_script_field_new(node, eventType, fieldType, fieldName);
    1341             : 
    1342          10 :         if (!scfield) {
    1343           0 :                 xmt_report(parser, GF_BAD_PARAM, "Cannot create script field - please check syntax");
    1344           0 :                 return;
    1345             :         }
    1346          10 :         if (val) {
    1347           0 :                 gf_node_get_field_by_name(node, fieldName, &field);
    1348           0 :                 if (gf_sg_vrml_is_sf_field(fieldType)) {
    1349           0 :                         xmt_parse_sf_field(parser, &field, node, val);
    1350             :                 } else {
    1351           0 :                         xmt_parse_mf_field(parser, &field, node, val);
    1352             :                 }
    1353             :         }
    1354             : }
    1355             : 
    1356          15 : static u32 xmt_get_next_proto_id(GF_XMTParser *parser)
    1357             : {
    1358             :         u32 ID;
    1359          15 :         GF_SceneGraph *sc = parser->load->scene_graph;
    1360          15 :         if (parser->parsing_proto) sc = gf_sg_proto_get_graph(parser->parsing_proto);
    1361          15 :         ID = gf_sg_get_next_available_proto_id(sc);
    1362          15 :         if (parser->load->ctx && (ID>parser->load->ctx->max_node_id))
    1363          10 :                 parser->load->ctx->max_proto_id = ID;
    1364          15 :         return ID;
    1365             : }
    1366             : 
    1367          15 : static void xmt_parse_proto(GF_XMTParser *parser, const GF_XMLAttribute *attributes, u32 nb_attributes, GF_List *proto_list)
    1368             : {
    1369             :         GF_FieldInfo info;
    1370             :         GF_Proto *proto;
    1371             :         char *szName, *extURL;
    1372             :         u32 ID, i;
    1373             : 
    1374             :         szName = extURL = NULL;
    1375          50 :         for (i=0; i<nb_attributes; i++) {
    1376          35 :                 GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
    1377          35 :                 if (!att->value || !strlen(att->value)) continue;
    1378          35 :                 if (!strcmp(att->name, "name")) szName = att->value;
    1379             : //              else if (!strcmp(att->name, "protoID")) ID = atoi(att->value);
    1380          20 :                 else if (!strcmp(att->name, "locations")) extURL = att->value;
    1381          15 :                 else if (!strcmp(att->name, "url")) extURL = att->value;
    1382             :         }
    1383             : 
    1384          15 :         ID = xmt_get_next_proto_id(parser);
    1385          15 :         proto = gf_sg_proto_new(parser->load->scene_graph, ID, szName, proto_list ? 1 : 0);
    1386          15 :         if (proto_list) gf_list_add(proto_list, proto);
    1387          15 :         if (parser->load->ctx && (parser->load->ctx->max_proto_id<ID)) parser->load->ctx->max_proto_id=ID;
    1388             : 
    1389             :         /*store previous proto*/
    1390          15 :         proto->userpriv = parser->parsing_proto;
    1391          15 :         parser->parsing_proto = proto;
    1392          15 :         parser->load->scene_graph = gf_sg_proto_get_graph(proto);
    1393             : 
    1394          15 :         if (extURL) {
    1395           5 :                 info.fieldType = GF_SG_VRML_MFURL;
    1396           5 :                 info.far_ptr = &proto->ExternProto;
    1397           5 :                 info.name = "ExternURL";
    1398           5 :                 xmt_parse_mf_field(parser, &info, NULL, extURL);
    1399             :         }
    1400          15 : }
    1401           0 : static u32 xmt_get_protofield_qp_type(const char *QP_Type)
    1402             : {
    1403             : #ifndef GPAC_DISABLE_BIFS
    1404           0 :         if (!strcmp(QP_Type, "position3D")) return QC_3DPOS;
    1405           0 :         else if (!strcmp(QP_Type, "position2D")) return QC_2DPOS;
    1406           0 :         else if (!strcmp(QP_Type, "drawingOrder")) return QC_ORDER;
    1407           0 :         else if (!strcmp(QP_Type, "color")) return QC_COLOR;
    1408           0 :         else if (!strcmp(QP_Type, "textureCoordinate")) return QC_TEXTURE_COORD;
    1409           0 :         else if (!strcmp(QP_Type, "angle")) return QC_ANGLE;
    1410           0 :         else if (!strcmp(QP_Type, "scale")) return QC_SCALE;
    1411           0 :         else if (!strcmp(QP_Type, "keys")) return QC_INTERPOL_KEYS;
    1412           0 :         else if (!strcmp(QP_Type, "normals")) return QC_NORMALS;
    1413           0 :         else if (!strcmp(QP_Type, "rotations")) return QC_ROTATION;
    1414           0 :         else if (!strcmp(QP_Type, "size3D")) return QC_SIZE_3D;
    1415           0 :         else if (!strcmp(QP_Type, "size2D")) return QC_SIZE_2D;
    1416           0 :         else if (!strcmp(QP_Type, "linear")) return QC_LINEAR_SCALAR;
    1417           0 :         else if (!strcmp(QP_Type, "coordIndex")) return QC_COORD_INDEX;
    1418             : #endif
    1419           0 :         return 0;
    1420             : }
    1421             : 
    1422           0 : static GF_Err x3d_get_default_container(GF_Node *par, GF_Node *n, GF_FieldInfo *info)
    1423             : {
    1424             :         u32 i, count;
    1425           0 :         count = gf_node_get_field_count(par);
    1426             :         /*get the first field/exposedField accepting this child*/
    1427           0 :         for (i=0; i<count; i++) {
    1428           0 :                 gf_node_get_field(par, i, info);
    1429           0 :                 if ((info->fieldType!=GF_SG_VRML_SFNODE) && (info->fieldType!=GF_SG_VRML_MFNODE)) continue;
    1430           0 :                 if ((info->eventType==GF_SG_EVENT_OUT) || (info->eventType==GF_SG_EVENT_IN)) continue;
    1431           0 :                 if (gf_node_in_table(n, info->NDTtype)) return GF_OK;
    1432             :         }
    1433             :         return GF_BAD_PARAM;
    1434             : }
    1435             : 
    1436             : 
    1437        2020 : static GF_Node *xmt_parse_element(GF_XMTParser *parser, char *name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes, XMTNodeStack *parent)
    1438             : {
    1439             :         GF_Err e;
    1440             :         GF_FieldInfo info;
    1441             :         u32     tag, i, ID;
    1442             :         Bool register_def = 0;
    1443             :         Bool is_script = 0;
    1444             :         GF_Node *node;
    1445             :         GF_FieldInfo container;
    1446             :         char *def_name;
    1447             :         GF_Proto *proto = NULL;
    1448             : 
    1449             :         node = NULL;
    1450        2020 :         if (!strcmp(name, "NULL")) return NULL;
    1451        2020 :         if (!strcmp(name, "ROUTE")) {
    1452          30 :                 if (!parser->parsing_proto && (parser->doc_type==1) ) {
    1453          30 :                         GF_Command *sgcom = gf_sg_command_new(parser->load->scene_graph, GF_SG_ROUTE_INSERT);
    1454          30 :                         gf_list_add(parser->scene_au->commands, sgcom);
    1455          30 :                         xmt_parse_route(parser, attributes, nb_attributes, 0, sgcom);
    1456          30 :                         if (sgcom->RouteID) gf_list_add(parser->inserted_routes, sgcom);
    1457             :                 } else {
    1458           0 :                         xmt_parse_route(parser, attributes, nb_attributes, 0, NULL);
    1459             :                 }
    1460             :                 return NULL;
    1461             :         }
    1462        3770 :         if (parent && parent->node && ((parent->node->sgprivate->tag==TAG_MPEG4_Script)
    1463             : #ifndef GPAC_DISABLE_X3D
    1464        1780 :                                        || (parent->node->sgprivate->tag==TAG_X3D_Script)
    1465             : #endif
    1466             :                                       ) ) {
    1467             :                 is_script = 1;
    1468          20 :                 if (!strcmp(name, "field")) {
    1469          10 :                         xmt_parse_script_field(parser, parent->node, attributes, nb_attributes);
    1470             :                         return NULL;
    1471             :                 }
    1472          10 :                 else if (!strcmp(name, "node") || !strcmp(name, "nodes") ) return NULL;
    1473             :         }
    1474             : 
    1475             :         /*proto declaration*/
    1476        1975 :         if (!strcmp(name, "ProtoDeclare") || !strcmp(name, "ExternProtoDeclare")) {
    1477          15 :                 if (!parser->parsing_proto && parser->command && !parser->command->new_proto_list) parser->command->new_proto_list = gf_list_new();
    1478          15 :                 xmt_parse_proto(parser, attributes, nb_attributes, (!parser->parsing_proto && parser->command) ? parser->command->new_proto_list : NULL);
    1479             :                 return NULL;
    1480             :         }
    1481             :         /*proto parsing*/
    1482        1960 :         if (parser->parsing_proto) {
    1483         315 :                 if (!strcmp(name, "IS"))
    1484             :                         return NULL;
    1485             : 
    1486         275 :                 if (!strcmp(name, "field")) {
    1487             :                         char *fieldName = NULL;
    1488             :                         char *value = NULL;
    1489             :                         u32 fType, eType;
    1490             :                         fType = eType = 0;
    1491             : 
    1492         380 :                         for (i=0; i<nb_attributes; i++) {
    1493         380 :                                 GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
    1494         380 :                                 if (!att->value || !strlen(att->value)) continue;
    1495             : 
    1496         380 :                                 if (!strcmp(att->name, "name")) fieldName  = att->value;
    1497         280 :                                 else if (!strcmp(att->name, "type")) fType = xmt_get_ft_by_name(att->value);
    1498         180 :                                 else if (!strcmp(att->name, "vrml97Hint") || !strcmp(att->name, "accessType") ) eType = xmt_get_et_by_name(att->value);
    1499          80 :                                 else if (strstr(att->name, "value") || strstr(att->name, "Value")) value = att->value;
    1500             :                         }
    1501         100 :                         parser->proto_field = gf_sg_proto_field_new(parser->parsing_proto, fType, eType, fieldName);
    1502         100 :                         if (value && strlen(value)) {
    1503          80 :                                 gf_sg_proto_field_get_field(parser->proto_field, &info);
    1504          80 :                                 if (gf_sg_vrml_is_sf_field(fType)) {
    1505          80 :                                         xmt_parse_sf_field(parser, &info, NULL, value);
    1506             :                                 } else {
    1507           0 :                                         xmt_parse_mf_field(parser, &info, NULL, value);
    1508             :                                 }
    1509          20 :                         } else if (gf_sg_vrml_get_sf_type(fType) != GF_SG_VRML_SFNODE) {
    1510             :                                 /*value not specified for exter proto*/
    1511             :                         }
    1512             :                         /*SF/MFNode proto field: push node stack with container info but no parent*/
    1513             :                         else {
    1514             :                                 XMTNodeStack *pf_stack;
    1515          10 :                                 GF_SAFEALLOC(pf_stack, XMTNodeStack);
    1516          10 :                                 if (pf_stack) {
    1517          10 :                                         gf_sg_proto_field_get_field(parser->proto_field, &pf_stack->container_field);
    1518          10 :                                         gf_list_add(parser->nodes, pf_stack);
    1519             :                                 }
    1520             :                         }
    1521             :                         return NULL;
    1522             :                 }
    1523             : 
    1524             :                 /*X3D style*/
    1525         175 :                 if (!strcmp(name, "ProtoInterface") || !strcmp(name, "ProtoBody"))
    1526             :                         return NULL;
    1527             :                 /*XMT1 decl for SFNode proto fields*/
    1528         175 :                 if (parser->proto_field && (!strcmp(name, "node") || !strcmp(name, "nodes")) )
    1529             :                         return NULL;
    1530             :                 /*anim & QP info */
    1531         165 :                 if (parser->proto_field  && !strcmp(name, "InterfaceCodingParameters")) {
    1532             :                         u32 qp_type, nbBits, hasMinMax, qp_sftype;
    1533             :                         Fixed ftMin, ftMax;
    1534           0 :                         ftMin = ftMax = 0;
    1535             :                         qp_type = hasMinMax = nbBits = 0;
    1536           0 :                         for (i=0; i<nb_attributes; i++) {
    1537           0 :                                 GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1538           0 :                                 if (!att->value || !strlen(att->value)) continue;
    1539           0 :                                 if (!strcmp(att->name, "quantCategory")) qp_type = xmt_get_protofield_qp_type(att->value);
    1540           0 :                                 else if (!strcmp(att->name, "nbBits")) nbBits = atoi(att->value);
    1541           0 :                                 else if (!strncmp(att->name, "position3DM", 11) || !strncmp(att->name, "position2DM", 11)
    1542           0 :                                          || !strncmp(att->name, "drawOrderM", 10) || !strncmp(att->name, "colorM", 6)
    1543           0 :                                          || !strncmp(att->name, "textureCoordinateM", 18) || !strncmp(att->name, "angleM", 6)
    1544           0 :                                          || !strncmp(att->name, "scaleM", 6) || !strncmp(att->name, "keyM", 4) || !strncmp(att->name, "sizeM", 5)
    1545             :                                         ) {
    1546             :                                         hasMinMax = 1;
    1547           0 :                                         if (strstr(att->name, "Min")) xmt_parse_float(parser, att->name, &ftMin, att->value);
    1548           0 :                                         else xmt_parse_float(parser, att->name, &ftMax, att->value);
    1549             :                                 }
    1550             :                         }
    1551           0 :                         if (gf_sg_vrml_get_sf_type(parser->proto_field->FieldType) == GF_SG_VRML_SFINT32) {
    1552             :                                 qp_sftype = GF_SG_VRML_SFINT32;
    1553             :                         } else {
    1554             :                                 qp_sftype = GF_SG_VRML_SFFLOAT;
    1555             :                         }
    1556           0 :                         gf_bifs_proto_field_set_aq_info(parser->proto_field, qp_type, hasMinMax, qp_sftype, &ftMin, &ftMax, nbBits);
    1557             :                         return NULL;
    1558             :                 }
    1559             :                 /*connect */
    1560         165 :                 if (!strcmp(name, "connect")) {
    1561             :                         GF_ProtoFieldInterface *pf;
    1562             :                         GF_FieldInfo pfield, nfield;
    1563             :                         char *atField, *atProtoField;
    1564          55 :                         XMTNodeStack *last = (XMTNodeStack*)gf_list_last(parser->nodes);
    1565             :                         is_script = 0;
    1566          55 :                         if (!last) {
    1567           0 :                                 xmt_report(parser, GF_OK, "connect: no parent node specified - skipping");
    1568             :                                 return NULL;
    1569             :                         }
    1570             :                         atField = atProtoField = NULL;
    1571         110 :                         for (i=0; i<nb_attributes; i++) {
    1572         110 :                                 GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
    1573         110 :                                 if (!att->value || !strlen(att->value)) continue;
    1574         110 :                                 if (!strcmp(att->name, "nodeField")) atField = att->value;
    1575          55 :                                 else if (!strcmp(att->name, "protoField")) atProtoField = att->value;
    1576             :                         }
    1577          55 :                         if (!atField) {
    1578           0 :                                 xmt_report(parser, GF_OK, "connect: Missing node field - skipping");
    1579             :                                 return NULL;
    1580             :                         }
    1581          55 :                         if (!atProtoField) {
    1582           0 :                                 xmt_report(parser, GF_OK, "connect: Missing proto field - skipping");
    1583             :                                 return NULL;
    1584             :                         }
    1585          55 :                         if ( (e = gf_node_get_field_by_name(last->node, atField, &nfield)) != GF_OK) {
    1586           0 :                                 u32 l_tag = gf_node_get_tag(last->node);
    1587           0 :                                 if ((l_tag!=TAG_MPEG4_Script)
    1588             : #ifndef GPAC_DISABLE_X3D
    1589           0 :                                         && (l_tag!=TAG_X3D_Script)
    1590             : #endif
    1591             :                                    ) {
    1592           0 :                                         xmt_report(parser, e, "connect: %s not an field of node %s", atField, gf_node_get_class_name(last->node) );
    1593             :                                         return NULL;
    1594             :                                 }
    1595             :                                 is_script = 1;
    1596             :                         }
    1597          55 :                         pf = gf_sg_proto_field_find_by_name(parser->parsing_proto, atProtoField);
    1598          55 :                         if (!pf) {
    1599           0 :                                 xmt_report(parser, GF_BAD_PARAM, "connect: Proto field %s is not defined", atProtoField);
    1600             :                                 return NULL;
    1601             :                         }
    1602          55 :                         gf_sg_proto_field_get_field(pf, &pfield);
    1603          55 :                         if (is_script) {
    1604           0 :                                 gf_sg_script_field_new(last->node, pfield.eventType, pfield.fieldType, atField);
    1605           0 :                                 gf_node_get_field_by_name(last->node, atField, &nfield);
    1606             :                         }
    1607          55 :                         e = gf_sg_proto_field_set_ised(parser->parsing_proto, pfield.fieldIndex, last->node, nfield.fieldIndex);
    1608          55 :                         if (e) xmt_report(parser, GF_BAD_PARAM, "connect: %s", gf_error_to_string(e));
    1609             :                         return NULL;
    1610             :                 }
    1611             :         }
    1612             :         /*proto instance field*/
    1613        1755 :         if (!strcmp(name, "fieldValue")) {
    1614             :                 char *field, *value;
    1615         130 :                 if (!parent || !parent->node || (parent->node->sgprivate->tag != TAG_ProtoNode)) {
    1616           0 :                         xmt_report(parser, GF_OK, "Warning: fieldValue not a valid node");
    1617             :                         return NULL;
    1618             :                 }
    1619             :                 field = value = NULL;
    1620         245 :                 for (i=0; i<nb_attributes; i++) {
    1621         245 :                         GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
    1622         245 :                         if (!att->value || !strlen(att->value)) continue;
    1623         245 :                         if (!strcmp(att->name, "name")) field = att->value;
    1624         115 :                         else if (!strstr(att->name, "Value") || !strstr(att->name, "value")) value = att->value;
    1625             :                 }
    1626         130 :                 if (!field) {
    1627           0 :                         xmt_report(parser, GF_OK, "Warning: unspecified proto field name - skipping");
    1628             :                         return NULL;
    1629             :                 }
    1630         130 :                 e = gf_node_get_field_by_name(parent->node, field, &info);
    1631         130 :                 if (e) {
    1632           0 :                         xmt_report(parser, GF_OK, "Warning: Unknown proto field %s - skipping", field);
    1633             :                         return NULL;
    1634             :                 }
    1635         130 :                 if (value) {
    1636         115 :                         if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    1637         115 :                                 xmt_parse_sf_field(parser, &info, parent->node, value);
    1638             :                         } else {
    1639           0 :                                 xmt_parse_mf_field(parser, &info, parent->node, value);
    1640             :                         }
    1641         115 :                         gf_sg_proto_mark_field_loaded(parent->node, &info);
    1642          15 :                 } else if (gf_sg_vrml_get_sf_type(info.fieldType) == GF_SG_VRML_SFNODE) {
    1643          15 :                         parent->container_field = info;
    1644          15 :                         parent->last = NULL;
    1645             :                 }
    1646             :                 return NULL;
    1647             :         }
    1648        1625 :         if (parent && parent->node && (parent->node->sgprivate->tag == TAG_ProtoNode) && (!strcmp(name, "node") || !strcmp(name, "nodes")) ) {
    1649             :                 return NULL;
    1650             :         }
    1651             : 
    1652             :         ID = 0;
    1653             :         def_name = NULL;
    1654             :         tag = 0;
    1655             : 
    1656        1610 :         if (!strcmp(name, "ProtoInstance")) {
    1657             :                 char *proto_name = NULL;
    1658             :                 char *proto_use = NULL;
    1659             :                 node = NULL;
    1660          25 :                 for (i=0; i<nb_attributes; i++) {
    1661          25 :                         GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
    1662          25 :                         if (!att->value || !strlen(att->value)) continue;
    1663          25 :                         if (!strcmp(att->name, "name")) {
    1664             :                                 proto_name = att->value;
    1665          20 :                                 att->value = NULL;
    1666           5 :                         } else if (!strcmp(att->name, "USE")) {
    1667             :                                 proto_use = att->value;
    1668             :                         }
    1669             :                 }
    1670          20 :                 if (proto_use) {
    1671           0 :                         node = xmt_find_node(parser, proto_use);
    1672             :                         e = GF_OK;
    1673           0 :                         if (!node)
    1674           0 :                                 e = xmt_report(parser, GF_BAD_PARAM, "Warning: Cannot find node %s referenced in USE - skipping", proto_use);
    1675             : 
    1676           0 :                         if (e) return NULL;
    1677             :                         ID = 0;
    1678             :                         register_def = 0;
    1679             :                         tag = 0;
    1680          20 :                 } else if (proto_name) {
    1681          20 :                         GF_SceneGraph *sg = parser->load->scene_graph;
    1682             :                         while (1) {
    1683          20 :                                 proto = gf_sg_find_proto(sg, 0, proto_name);
    1684          20 :                                 if (proto) break;
    1685           0 :                                 sg = sg->parent_scene;
    1686           0 :                                 if (!sg) break;
    1687             :                         }
    1688          20 :                         if (!proto) {
    1689           0 :                                 xmt_report(parser, GF_BAD_PARAM, "%s: not a valid/supported proto", proto_name);
    1690             :                                 return NULL;
    1691             :                         }
    1692          20 :                         node = gf_sg_proto_create_instance(parser->load->scene_graph, proto);
    1693             :                 }
    1694             :         } else {
    1695        1590 :                 tag = xmt_get_node_tag(parser, name);
    1696             : 
    1697        1590 :                 if (!tag) {
    1698             :                         /*XMT-A weird syntax*/
    1699         585 :                         if (parent) {
    1700         580 :                                 if (gf_node_get_field_by_name(parent->node, name, &parent->container_field)==GF_OK) {
    1701         580 :                                         parent->last = NULL;
    1702         580 :                                         if (parent->container_field.fieldType==GF_SG_VRML_SFCOMMANDBUFFER) {
    1703          35 :                                                 parser->command_buffer = (SFCommandBuffer*)parent->container_field.far_ptr;
    1704             :                                                 /*store command*/
    1705          35 :                                                 parser->command_buffer->buffer = (unsigned char *)parser->command;
    1706          35 :                                                 parser->state = XMT_STATE_COMMANDS;
    1707             :                                         }
    1708             :                                         return NULL;
    1709             :                                 }
    1710           0 :                                 if (!strcmp(name, "store") && (parent->container_field.fieldType==GF_SG_VRML_MFATTRREF)) {
    1711             :                                         GF_FieldInfo pinfo;
    1712             :                                         GF_Node *atNode = NULL;
    1713             :                                         char *fieldName = NULL;
    1714           0 :                                         for (i=0; i<nb_attributes; i++) {
    1715           0 :                                                 GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1716           0 :                                                 if (!att->value || !strlen(att->value)) continue;
    1717           0 :                                                 if (!strcmp(att->name, "node")) {
    1718           0 :                                                         atNode = xmt_find_node(parser, att->value);
    1719           0 :                                                         if (!atNode) xmt_report(parser, GF_BAD_PARAM, "Cannot locate node %s", att->value);
    1720             :                                                 }
    1721           0 :                                                 if (!strcmp(att->name, "field")) fieldName = att->value;
    1722             :                                         }
    1723           0 :                                         if (!fieldName || !atNode) {
    1724           0 :                                                 xmt_report(parser, GF_BAD_PARAM, "Node or field name missing in <store>");
    1725           0 :                                         } else if (gf_node_get_field_by_name(atNode, fieldName, &pinfo) != GF_OK) {
    1726           0 :                                                 xmt_report(parser, GF_BAD_PARAM, "Field %s not a member of node %s", fieldName, gf_node_get_class_name(node) );
    1727             :                                         } else {
    1728             :                                                 SFAttrRef *ptr;
    1729           0 :                                                 gf_sg_vrml_mf_append(parent->container_field.far_ptr , GF_SG_VRML_MFATTRREF, (void **) &ptr);
    1730           0 :                                                 ptr->node = atNode;
    1731           0 :                                                 ptr->fieldIndex = pinfo.fieldIndex;
    1732             :                                         }
    1733             :                                         return NULL;
    1734             :                                 }
    1735           0 :                                 parent->container_field.far_ptr = NULL;
    1736             :                         }
    1737           5 :                         else if (parser->command && (parser->command->tag == GF_SG_MULTIPLE_REPLACE)) {
    1738           5 :                                 if (gf_node_get_field_by_name(parser->command->node, name, &container)==GF_OK) {
    1739           5 :                                         GF_CommandField *field = gf_sg_command_field_new(parser->command);
    1740           5 :                                         field->fieldIndex = container.fieldIndex;
    1741           5 :                                         field->fieldType = container.fieldType;
    1742             :                                         return NULL;
    1743             :                                 }
    1744             :                         }
    1745           0 :                         xmt_report(parser, GF_NON_COMPLIANT_BITSTREAM, "Warning: %s is not a valid node - skipping", name);
    1746             :                         return NULL;
    1747             :                 }
    1748        1005 :                 node = gf_node_new(parser->load->scene_graph, tag);
    1749        1005 :                 if (!node) {
    1750           0 :                         xmt_report(parser, GF_SG_UNKNOWN_NODE, "Warning: %s is not a supported node - skipping", name);
    1751             :                         return NULL;
    1752             :                 }
    1753             :         }
    1754             : 
    1755        1025 :         parser->current_node_tag = tag;
    1756             : 
    1757        1025 :         if (parent) container = parent->container_field;
    1758             :         else {
    1759          80 :                 container.far_ptr = NULL;
    1760          80 :                 container.fieldIndex = 0;
    1761          80 :                 container.fieldType = 0;
    1762             :         }
    1763             : 
    1764        1095 :         for (i=0; i<nb_attributes; i++) {
    1765        1125 :                 GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1766        1125 :                 if (!att->value || !strlen(att->value)) continue;
    1767             : 
    1768        1105 :                 if (!strcmp(att->name, "DEF")) {
    1769         260 :                         GF_Node *undef_node = gf_sg_find_node_by_name(parser->load->scene_graph, att->value);
    1770             :                         register_def = 1;
    1771         260 :                         if (undef_node) {
    1772          10 :                                 gf_list_del_item(parser->peeked_nodes, undef_node);
    1773             :                                 /*if we see twice a DEF N1 then force creation of a new node*/
    1774          10 :                                 if (xmt_has_been_def(parser, att->value)) {
    1775           5 :                                         ID = xmt_get_node_id(parser, att->value);
    1776           5 :                                         xmt_report(parser, GF_OK, "Warning: Node %s has been defined several times - IDs may get corrupted", att->value);
    1777             :                                 } else {
    1778           5 :                                         gf_node_register(node, NULL);
    1779           5 :                                         gf_node_unregister(node, NULL);
    1780             :                                         node = undef_node;
    1781             :                                         ID = 0;
    1782             :                                 }
    1783             :                         } else {
    1784         250 :                                 ID = xmt_get_node_id(parser, att->value);
    1785             : 
    1786             :                         }
    1787         260 :                         def_name = att->value;
    1788             :                 }
    1789             :                 /*USE node*/
    1790         845 :                 else if (!strcmp(att->name, "USE")) {
    1791             :                         GF_Node *def_node;
    1792             : 
    1793          30 :                         def_node = xmt_find_node(parser, att->value);
    1794             : 
    1795             :                         e = GF_OK;
    1796          30 :                         if (!def_node)
    1797           0 :                                 e = xmt_report(parser, GF_BAD_PARAM, "Warning: Cannot find node %s referenced in USE - skipping", att->value);
    1798          30 :                         else if (tag != gf_node_get_tag(def_node)) {
    1799           0 :                                 xmt_report(parser, GF_OK, "Warning: Node type %s doesn't match type %s of node %s", gf_node_get_class_name(node), gf_node_get_class_name(def_node), att->value);
    1800             :                         }
    1801             : 
    1802             :                         /*DESTROY NODE*/
    1803          30 :                         gf_node_register(node, NULL);
    1804          30 :                         gf_node_unregister(node, NULL);
    1805             : 
    1806          30 :                         if (e) return NULL;
    1807             : 
    1808             :                         node = def_node;
    1809             :                         ID = 0;
    1810             :                         register_def = 0;
    1811             :                         tag = 0;
    1812             :                         break;
    1813             :                 }
    1814             :                 /*X3D stuff*/
    1815         815 :                 else if (!strcmp(att->name, "containerField")) {
    1816           0 :                         if (parent) {
    1817           0 :                                 if (gf_node_get_field_by_name(parent->node, att->value, &container) != GF_OK) {
    1818           0 :                                         xmt_report(parser, GF_BAD_PARAM, "Warning: Container field %s not member of node %s", att->value, name);
    1819           0 :                                         container.far_ptr = NULL;
    1820             :                                 }
    1821             :                         }
    1822             :                 }
    1823             :                 /*ignored ones*/
    1824         815 :                 else if (!strcmp(att->name, "bboxCenter") || !strcmp(att->name, "bboxSize")) {
    1825             :                 }
    1826             :                 /*all other fields*/
    1827             :                 else {
    1828         815 :                         e = gf_node_get_field_by_name(node, att->name, &info);
    1829         815 :                         if (e) xmt_report(parser, GF_OK, "Warning: Unknown field \"%s\" for node %s - skipping", att->name, name);
    1830         815 :                         else if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    1831         570 :                                 xmt_parse_sf_field(parser, &info, node, att->value);
    1832             :                         } else {
    1833         245 :                                 xmt_parse_mf_field(parser, &info, node, att->value);
    1834             :                         }
    1835             :                 }
    1836             :         }
    1837             : 
    1838        1025 :         if (!parser->parsing_proto) xmt_update_timenode(parser, node);
    1839             : 
    1840        1025 :         if (register_def) {
    1841         260 :                 gf_node_register(node, NULL);
    1842         260 :                 gf_list_add(parser->def_nodes, node);
    1843             :         }
    1844        1025 :         if (ID) gf_node_set_id(node, ID, def_name);
    1845             : 
    1846        1025 :         if (is_script) {
    1847           5 :                 u32 last_field = gf_node_get_field_count(parent->node);
    1848           5 :                 gf_node_get_field(parent->node, last_field-1, &container);
    1849             :         }
    1850             : 
    1851        1025 :         if (parent) {
    1852         945 :                 if (!container.far_ptr) {
    1853           0 :                         if (parser->doc_type==2) {
    1854           0 :                                 x3d_get_default_container(parent->node, node, &container);
    1855           0 :                                 parent->last = NULL;
    1856             :                         }
    1857           0 :                         if (!container.far_ptr) {
    1858           0 :                                 gf_node_get_field_by_name(parent->node, "children", &container);
    1859           0 :                                 parent->last = NULL;
    1860             :                         }
    1861             : 
    1862             :                 }
    1863         945 :                 if (container.fieldType == GF_SG_VRML_SFNODE) {
    1864         465 :                         if (* ((GF_Node **)container.far_ptr) ) gf_node_unregister(* ((GF_Node **)container.far_ptr) , parent->node);
    1865         465 :                         * ((GF_Node **)container.far_ptr) = node;
    1866         465 :                         gf_node_register(node, parent->node);
    1867         465 :                         parent->container_field.far_ptr = NULL;
    1868         465 :                         parent->last = NULL;
    1869         480 :                 } else if (container.fieldType == GF_SG_VRML_MFNODE) {
    1870         480 :                         gf_node_list_add_child_last( (GF_ChildNodeItem **)container.far_ptr, node, &parent->last);
    1871         480 :                         gf_node_register(node, parent->node);
    1872             :                 }
    1873             :                 assert(parent->node);
    1874         945 :                 gf_node_changed(parent->node, NULL);
    1875             :         }
    1876             : 
    1877        1025 :         if (!parser->parsing_proto && (tag || proto) )
    1878         935 :                 gf_node_init(node);
    1879             : 
    1880             :         /*For Ivica: load proto as soon as found when in playback mode*/
    1881        1025 :         if ( (parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) && proto && !parser->parsing_proto) {
    1882           4 :                 parser->last_error = gf_sg_proto_load_code(node);
    1883             :         }
    1884             :         return node;
    1885             : }
    1886             : 
    1887             : 
    1888         260 : GF_Descriptor *xmt_parse_descriptor(GF_XMTParser *parser, char *name, const GF_XMLAttribute *attributes, u32 nb_attributes, GF_Descriptor *parent)
    1889             : {
    1890             :         GF_Err e;
    1891             :         u32 i;
    1892             :         u32 fake_desc = 0;
    1893             :         GF_Descriptor *desc;
    1894             :         char *xmt_desc_name = NULL, *ocr_ref = NULL, *dep_ref = NULL;
    1895             :         u32 binaryID = 0;
    1896         260 :         u8 tag = gf_odf_get_tag_by_name(name);
    1897             : 
    1898         260 :         if (!tag) {
    1899         140 :                 if (!parent) return NULL;
    1900         130 :                 switch (parent->tag) {
    1901          55 :                 case GF_ODF_IOD_TAG:
    1902             :                 case GF_ODF_OD_TAG:
    1903          55 :                         if (!strcmp(name, "Profiles")) fake_desc = 1;
    1904          50 :                         else if (!strcmp(name, "Descr")) fake_desc = 1;
    1905          25 :                         else if (!strcmp(name, "esDescr")) fake_desc = 1;
    1906           0 :                         else if (!strcmp(name, "URL")) fake_desc = 1;
    1907             :                         else return NULL;
    1908             :                         break;
    1909          40 :                 case GF_ODF_ESD_TAG:
    1910          40 :                         if (!strcmp(name, "decConfigDescr")) fake_desc = 1;
    1911          20 :                         else if (!strcmp(name, "slConfigDescr")) fake_desc = 1;
    1912             :                         else return NULL;
    1913             :                         break;
    1914          15 :                 case GF_ODF_DCD_TAG:
    1915          15 :                         if (!strcmp(name, "decSpecificInfo")) fake_desc = 1;
    1916             :                         else return NULL;
    1917             :                         break;
    1918           0 :                 case GF_ODF_SLC_TAG:
    1919           0 :                         if (!strcmp(name, "custom")) fake_desc = 1;
    1920             :                         else return NULL;
    1921             :                         break;
    1922          10 :                 case GF_ODF_MUXINFO_TAG:
    1923          10 :                         if (!strcmp(name, "MP4MuxHints")) fake_desc = 1;
    1924             :                         else return NULL;
    1925             :                         break;
    1926          10 :                 case GF_ODF_BIFS_CFG_TAG:
    1927          10 :                         if (!strcmp(name, "commandStream")) fake_desc = 1;
    1928           5 :                         else if (!strcmp(name, "size")) fake_desc = 2;
    1929             :                         else return NULL;
    1930             :                         break;
    1931             :                 default:
    1932             :                         return NULL;
    1933             :                 }
    1934         120 :         }
    1935             :         if (fake_desc) {
    1936             :                 tag = parent->tag;
    1937             :                 desc = parent;
    1938             :         } else {
    1939         120 :                 desc = gf_odf_desc_new(tag);
    1940         120 :                 if (!desc) return NULL;
    1941             :         }
    1942             : 
    1943         460 :         for (i=0; i<nb_attributes; i++) {
    1944         210 :                 GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1945         210 :                 if (!att->value || !strlen(att->value)) continue;
    1946         265 :                 if (!strcmp(att->name, "binaryID")) binaryID = atoi(att->value);
    1947         155 :                 else if (!stricmp(att->name, "objectDescriptorID")) xmt_desc_name = att->value;
    1948         130 :                 else if (!strcmp(att->name, "ES_ID")) xmt_desc_name = att->value;
    1949         100 :                 else if (!strcmp(att->name, "OCR_ES_ID")) ocr_ref = att->value;
    1950         100 :                 else if (!strcmp(att->name, "dependsOn_ES_ID")) dep_ref = att->value;
    1951             :                 else {
    1952         100 :                         e = gf_odf_set_field(desc, att->name, att->value);
    1953         100 :                         if (e) xmt_report(parser, e, "Warning: %s not a valid attribute for descriptor %s", att->name, name);
    1954             :                         //store src path but do not concatenate, othewise we break BT<->XMT conversion ...
    1955         100 :                         if ((desc->tag==GF_ODF_MUXINFO_TAG) && (!stricmp(att->name, "fileName") || !stricmp(att->name, "url"))) {
    1956             :                                 GF_MuxInfo *mux = (GF_MuxInfo *) desc;
    1957          10 :                                 if (!mux->src_url)
    1958          10 :                                         mux->src_url = gf_strdup(parser->load->src_url ? parser->load->src_url : parser->load->fileName);
    1959             :                         }
    1960             :                 }
    1961             :         }
    1962         250 :         if (binaryID || xmt_desc_name) {
    1963          55 :                 if ((tag == GF_ODF_IOD_TAG) || (tag == GF_ODF_OD_TAG))
    1964          25 :                         xmt_new_od_link(parser, (GF_ObjectDescriptor *)desc, xmt_desc_name, binaryID);
    1965          30 :                 else if (tag == GF_ODF_ESD_TAG) {
    1966          30 :                         xmt_new_esd_link(parser, (GF_ESD *) desc, xmt_desc_name, binaryID);
    1967             : 
    1968             :                         /*set references once the esd link has been established*/
    1969          30 :                         if (ocr_ref) xmt_set_depend_id(parser, (GF_ESD *) desc, ocr_ref, 1);
    1970          30 :                         if (dep_ref) xmt_set_depend_id(parser, (GF_ESD *) desc, dep_ref, 0);
    1971             :                 }
    1972             :         }
    1973             : 
    1974         250 :         if (fake_desc) {
    1975         130 :                 if (fake_desc==2) {
    1976             :                         GF_BIFSConfig *bcfg = (GF_BIFSConfig *)desc;
    1977           5 :                         parser->load->ctx->scene_width = bcfg->pixelWidth;
    1978           5 :                         parser->load->ctx->scene_height = bcfg->pixelHeight;
    1979           5 :                         parser->load->ctx->is_pixel_metrics = bcfg->pixelMetrics;
    1980             :                 }
    1981             :                 return NULL;
    1982             :         }
    1983         120 :         if (parent) {
    1984          95 :                 e = gf_odf_desc_add_desc(parent, desc);
    1985          95 :                 if (e) {
    1986           0 :                         xmt_report(parser, GF_OK, "Invalid child descriptor");
    1987           0 :                         gf_odf_desc_del(desc);
    1988           0 :                         return NULL;
    1989             :                 }
    1990             :                 /*finally check for scene manager streams (scene description, OD, ...)*/
    1991          95 :                 if (parent->tag == GF_ODF_ESD_TAG) {
    1992             :                         GF_ESD *esd = (GF_ESD *)parent;
    1993          50 :                         if (esd->decoderConfig) {
    1994          40 :                                 switch (esd->decoderConfig->streamType) {
    1995          20 :                                 case GF_STREAM_SCENE:
    1996             :                                 case GF_STREAM_OD:
    1997          20 :                                         if (!esd->decoderConfig->objectTypeIndication) esd->decoderConfig->objectTypeIndication = 1;
    1998             :                                         /*watchout for default BIFS stream*/
    1999          20 :                                         if (parser->scene_es && !parser->base_scene_id && (esd->decoderConfig->streamType==GF_STREAM_SCENE)) {
    2000           0 :                                                 parser->scene_es->ESID = parser->base_scene_id = esd->ESID;
    2001           0 :                                                 parser->scene_es->timeScale = (esd->slConfig && esd->slConfig->timestampResolution) ? esd->slConfig->timestampResolution : 1000;
    2002             :                                         } else {
    2003             :                                                 char *s_name;
    2004          20 :                                                 GF_StreamContext *sc = gf_sm_stream_new(parser->load->ctx, esd->ESID, esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication);
    2005             :                                                 /*set default timescale for systems tracks (ignored for other)*/
    2006          20 :                                                 if (sc) sc->timeScale = (esd->slConfig && esd->slConfig->timestampResolution) ? esd->slConfig->timestampResolution : 1000;
    2007          20 :                                                 if (!parser->base_scene_id && (esd->decoderConfig->streamType==GF_STREAM_SCENE)) parser->base_scene_id = esd->ESID;
    2008          15 :                                                 else if (!parser->base_od_id && (esd->decoderConfig->streamType==GF_STREAM_OD)) parser->base_od_id = esd->ESID;
    2009             : 
    2010          20 :                                                 s_name = xmt_get_es_name(parser, esd->ESID);
    2011          20 :                                                 if (sc && s_name && !sc->name) sc->name = gf_strdup(s_name);
    2012             :                                         }
    2013             :                                         break;
    2014             :                                 }
    2015             :                         }
    2016             :                 }
    2017             :         }
    2018             :         return desc;
    2019             : }
    2020             : 
    2021         390 : static void xmt_parse_command(GF_XMTParser *parser, const char *name, const GF_XMLAttribute *attributes, u32 nb_attributes)
    2022             : {
    2023             :         GF_Err e;
    2024             :         GF_FieldInfo info;
    2025             :         GF_CommandField *field;
    2026             :         u32 i;
    2027         390 :         if (!strcmp(name, "Scene")) {
    2028          15 :                 parser->state = XMT_STATE_ELEMENTS;
    2029         385 :                 return;
    2030             :         }
    2031         375 :         if (!parser->in_com)
    2032           5 :                 parser->stream_id = parser->load->force_es_id;
    2033             : 
    2034         375 :         if (!strcmp(name, "par")) {
    2035          90 :                 parser->in_com = 1;
    2036         180 :                 for (i=0; i<nb_attributes; i++) {
    2037          90 :                         GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    2038          90 :                         if (!att->value || !strlen(att->value)) continue;
    2039         180 :                         if (!strcmp(att->name, "begin")) parser->au_time = atof(att->value);
    2040           0 :                         else if (!strcmp(att->name, "isRAP")) parser->au_is_rap = !strcmp(att->value, "yes") ? 1 : 0;
    2041           0 :                         else if (!strcmp(att->name, "atES_ID")) {
    2042           0 :                                 parser->stream_id = xmt_locate_stream(parser, att->value);
    2043           0 :                                 if (!parser->stream_id) xmt_report(parser, GF_OK, "Warning: Cannot locate command's target stream %s", att->value);
    2044             :                         }
    2045             :                 }
    2046             :                 return;
    2047             :         }
    2048             :         /*ROUTE insert/replace*/
    2049         285 :         if (!strcmp(name, "ROUTE")) {
    2050          10 :                 if (!parser->command || ((parser->command->tag!=GF_SG_ROUTE_REPLACE) && (parser->command->tag!=GF_SG_ROUTE_INSERT))) {
    2051           0 :                         xmt_report(parser, GF_BAD_PARAM, "ROUTE declared outside command scope");
    2052           0 :                         return;
    2053             :                 }
    2054          10 :                 if (parser->command->tag==GF_SG_ROUTE_INSERT) {
    2055           5 :                         xmt_parse_route(parser, attributes, nb_attributes, 1, parser->command);
    2056           5 :                         gf_list_add(parser->inserted_routes, parser->command);
    2057             :                 } else {
    2058           5 :                         xmt_parse_route(parser, attributes, nb_attributes, 0, parser->command);
    2059           5 :                         if (!parser->command->RouteID) {
    2060           0 :                                 parser->command->unresolved = 1;
    2061           0 :                                 if (gf_list_find(parser->unresolved_routes, parser->command)<0)
    2062           0 :                                         gf_list_add(parser->unresolved_routes, parser->command);
    2063             :                         }
    2064             :                 }
    2065             :                 return;
    2066             :         }
    2067             :         /*multiple replace*/
    2068         275 :         if (!strcmp(name, "repField")) {
    2069             :                 char *fieldName = NULL;
    2070             :                 char *fieldValue = NULL;
    2071             :                 assert(parser->command);
    2072          15 :                 if (!parser->command->node) return;
    2073          20 :                 for (i=0; i<nb_attributes; i++) {
    2074          20 :                         GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    2075          20 :                         if (!att->value || !strlen(att->value)) continue;
    2076          20 :                         if (!strcmp(att->name, "atField")) fieldName = att->value;
    2077          10 :                         else if (!strcmp(att->name, "value")) fieldValue = att->value;
    2078             :                 }
    2079          15 :                 if (!fieldName) {
    2080           5 :                         parser->state = XMT_STATE_ELEMENTS;
    2081           5 :                         return;
    2082             :                 }
    2083          10 :                 e = gf_node_get_field_by_name(parser->command->node, fieldName, &info);
    2084          10 :                 if (e) {
    2085           0 :                         xmt_report(parser, GF_BAD_PARAM, "Warning: Field %s not a member of node %s ", fieldName, gf_node_get_class_name(parser->command->node) );
    2086           0 :                         return;
    2087             :                 }
    2088          10 :                 if (gf_sg_vrml_get_sf_type(info.fieldType) == GF_SG_VRML_SFNODE) {
    2089           0 :                         parser->state = XMT_STATE_ELEMENTS;
    2090           0 :                         return;
    2091             :                 }
    2092          10 :                 if (!fieldValue) return;
    2093             : 
    2094          10 :                 field = gf_sg_command_field_new(parser->command);
    2095          10 :                 field->fieldIndex = info.fieldIndex;
    2096          10 :                 field->fieldType = info.fieldType;
    2097          10 :                 field->field_ptr = gf_sg_vrml_field_pointer_new(info.fieldType);
    2098          10 :                 info.far_ptr = field->field_ptr;
    2099          10 :                 if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    2100          10 :                         xmt_parse_sf_field(parser, &info, parser->command->node, fieldValue);
    2101             :                 } else {
    2102           0 :                         xmt_parse_mf_field(parser, &info, parser->command->node, fieldValue);
    2103             :                 }
    2104             :                 return;
    2105             :         }
    2106             :         /*multiple index replace*/
    2107         260 :         if (!strcmp(name, "repValue")) {
    2108             :                 s32 position = -1;
    2109             :                 char *fieldValue = NULL;
    2110             :                 assert(parser->command);
    2111          15 :                 if (!parser->command->node) return;
    2112          30 :                 for (i=0; i<nb_attributes; i++) {
    2113          30 :                         GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    2114          30 :                         if (!att->value || !strlen(att->value)) continue;
    2115          30 :                         if (!strcmp(att->name, "position")) {
    2116          15 :                                 if (!strcmp(att->value, "BEGIN")) position = 0;
    2117          15 :                                 else if (!strcmp(att->value, "END")) position = -1;
    2118             :                                 else position = atoi(att->value);
    2119             :                         }
    2120          15 :                         else if (!strcmp(att->name, "value")) fieldValue = att->value;
    2121             :                 }
    2122          15 :                 gf_node_get_field(parser->command->node, parser->command->fromFieldIndex, &info);
    2123          15 :                 if (info.fieldType == GF_SG_VRML_MFNODE) {
    2124           0 :                         field = gf_sg_command_field_new(parser->command);
    2125           0 :                         field->fieldIndex = info.fieldIndex;
    2126           0 :                         field->fieldType = GF_SG_VRML_SFNODE;
    2127           0 :                         field->pos = position;
    2128           0 :                         parser->state = XMT_STATE_ELEMENTS;
    2129          15 :                 } else if (fieldValue) {
    2130          15 :                         field = gf_sg_command_field_new(parser->command);
    2131          15 :                         field->fieldIndex = info.fieldIndex;
    2132          15 :                         field->fieldType = info.fieldType = gf_sg_vrml_get_sf_type(info.fieldType);
    2133          15 :                         field->field_ptr = gf_sg_vrml_field_pointer_new(info.fieldType);
    2134          15 :                         field->pos = position;
    2135          15 :                         info.far_ptr = field->field_ptr;
    2136          15 :                         xmt_parse_sf_field(parser, &info, parser->command->node, fieldValue);
    2137             :                 }
    2138             :                 return;
    2139             :         }
    2140             : 
    2141             : 
    2142             :         /*BIFS command*/
    2143         245 :         if (!strcmp(name, "Replace") || !strcmp(name, "Insert") || !strcmp(name, "Delete")) {
    2144             :                 GF_Node *atNode;
    2145             :                 u8 tag = GF_SG_UNDEFINED;
    2146             :                 u32 stream_id;
    2147         225 :                 Double au_time = parser->au_time;
    2148         225 :                 Bool au_is_rap = parser->au_is_rap;
    2149             :                 char *nodeName = NULL;
    2150             :                 char *fieldName = NULL;
    2151             :                 char *fieldValue = NULL;
    2152             :                 char *routeName = NULL;
    2153             :                 char *extended = NULL;
    2154             :                 char *idxNode = NULL;
    2155             :                 char *idxField = NULL;
    2156             :                 char *childField = NULL;
    2157             :                 char *fromNode = NULL;
    2158             :                 char *fromField = NULL;
    2159             : 
    2160             :                 s32 position = -2;
    2161             : 
    2162         225 :                 if (!parser->stream_id) parser->stream_id = parser->base_scene_id;
    2163         225 :                 stream_id = parser->stream_id;
    2164             : 
    2165         720 :                 for (i=0; i<nb_attributes; i++) {
    2166         495 :                         GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
    2167         495 :                         if (!att->value || !strlen(att->value)) continue;
    2168         495 :                         if (!strcmp(att->name, "begin")) au_time = atoi(att->value);
    2169         495 :                         else if (!strcmp(att->name, "isRAP")) au_is_rap = !strcmp(att->value, "yes") ? 1 : 0;
    2170         495 :                         else if (!strcmp(att->name, "atES_ID")) {
    2171           0 :                                 stream_id = xmt_locate_stream(parser, att->value);
    2172           0 :                                 if (!stream_id) {
    2173           0 :                                         xmt_report(parser, GF_OK, "Warning: Cannot locate command's target stream %s", att->value);
    2174           0 :                                         stream_id = parser->stream_id;
    2175             :                                 }
    2176             :                         }
    2177         495 :                         else if (!strcmp(att->name, "atNode")) nodeName = att->value;
    2178         320 :                         else if (!strcmp(att->name, "atField")) fieldName = att->value;
    2179         210 :                         else if (!strcmp(att->name, "value")) fieldValue = att->value;
    2180         120 :                         else if (!strcmp(att->name, "atRoute")) routeName = att->value;
    2181         110 :                         else if (!strcmp(att->name, "extended")) extended = att->value;
    2182          75 :                         else if (!strcmp(att->name, "atIndexNode")) idxNode = att->value;
    2183          70 :                         else if (!strcmp(att->name, "atIndexField")) idxField = att->value;
    2184          65 :                         else if (!strcmp(att->name, "atChildField")) childField = att->value;
    2185          60 :                         else if (!strcmp(att->name, "fromNode")) fromNode = att->value;
    2186          55 :                         else if (!strcmp(att->name, "fromField")) fromField = att->value;
    2187          50 :                         else if (!strcmp(att->name, "position")) {
    2188          50 :                                 if (!strcmp(att->value, "BEGIN")) position = 0;
    2189          20 :                                 else if (!strcmp(att->value, "END")) position = -1;
    2190             :                                 else position = atoi(att->value);
    2191             :                         }
    2192             :                 }
    2193             : 
    2194             :                 /*if we are parsing in an already loaded context and no time is given, force a time != 0 to create a new command*/
    2195         225 :                 if (!au_time && (parser->load->flags&GF_SM_LOAD_CONTEXT_READY))
    2196             :                         au_time = 0.001;
    2197             : 
    2198             :                 atNode = NULL;
    2199         225 :                 if (nodeName) {
    2200         175 :                         if (fieldName) {
    2201         110 :                                 if (position>-2) {
    2202          25 :                                         if (!strcmp(name, "Replace")) tag = GF_SG_INDEXED_REPLACE;
    2203          10 :                                         else if (!strcmp(name, "Insert")) tag = GF_SG_INDEXED_INSERT;
    2204           5 :                                         else if (!strcmp(name, "Delete")) tag = GF_SG_INDEXED_DELETE;
    2205             :                                 } else {
    2206          85 :                                         if (!strcmp(name, "Replace")) {
    2207          85 :                                                 if ((idxNode && idxField) || childField || (fromNode && fromField)) {
    2208             :                                                         tag = GF_SG_XREPLACE;
    2209             :                                                 } else {
    2210             :                                                         tag = GF_SG_FIELD_REPLACE;
    2211             :                                                 }
    2212             :                                         }
    2213             :                                 }
    2214             :                         } else {
    2215          65 :                                 if (!strcmp(name, "Replace")) {
    2216             :                                         tag = GF_SG_NODE_REPLACE;
    2217          30 :                                         parser->state = XMT_STATE_ELEMENTS;
    2218             :                                 }
    2219          35 :                                 else if (!strcmp(name, "Insert")) {
    2220             :                                         tag = GF_SG_NODE_INSERT;
    2221          25 :                                         parser->state = XMT_STATE_ELEMENTS;
    2222             :                                 }
    2223          10 :                                 else if (!strcmp(name, "Delete")) tag = GF_SG_NODE_DELETE;
    2224             :                         }
    2225             : 
    2226         175 :                         atNode = xmt_find_node(parser, nodeName);
    2227         175 :                         if (!atNode) {
    2228           0 :                                 xmt_report(parser, GF_BAD_PARAM, "Warning: Cannot locate node %s for command %s", nodeName, name);
    2229           0 :                                 return;
    2230             :                         }
    2231         175 :                         if (fieldName) {
    2232         110 :                                 e = gf_node_get_field_by_name(atNode, fieldName, &info);
    2233         110 :                                 if (e) {
    2234           0 :                                         xmt_report(parser, GF_BAD_PARAM, "Warning: Field %s not a member of node %s ", fieldName, nodeName);
    2235           0 :                                         return;
    2236             :                                 }
    2237             :                         }
    2238             :                 }
    2239          50 :                 else if (routeName) {
    2240          10 :                         if (!strcmp(name, "Replace")) tag = GF_SG_ROUTE_REPLACE;
    2241           5 :                         else if (!strcmp(name, "Delete")) tag = GF_SG_ROUTE_DELETE;
    2242             :                 }
    2243          40 :                 else if (!strcmp(name, "Replace")) {
    2244             :                         tag = GF_SG_SCENE_REPLACE;
    2245             :                         au_is_rap = 1;
    2246         280 :                         while (gf_list_count(parser->def_nodes)) {
    2247         260 :                                 GF_Node *anode = gf_list_pop_back(parser->def_nodes);
    2248         260 :                                 gf_node_unregister(anode, NULL);
    2249             :                         }
    2250             :                 }
    2251          20 :                 else if (!strcmp(name, "Insert"))
    2252             :                         tag = GF_SG_ROUTE_INSERT;
    2253             : 
    2254         225 :                 if (extended) {
    2255          35 :                         if (!strcmp(extended, "globalQuant")) {
    2256             :                                 tag = GF_SG_GLOBAL_QUANTIZER;
    2257           5 :                                 parser->state = XMT_STATE_ELEMENTS;
    2258             :                         }
    2259          30 :                         else if (!strcmp(extended, "fields")) {
    2260             :                                 tag = GF_SG_MULTIPLE_REPLACE;
    2261           5 :                                 parser->state = XMT_STATE_COMMANDS;
    2262             :                         }
    2263          25 :                         else if (!strcmp(extended, "indices")) {
    2264             :                                 tag = GF_SG_MULTIPLE_INDEXED_REPLACE;
    2265           5 :                                 parser->state = XMT_STATE_COMMANDS;
    2266             :                         }
    2267          20 :                         else if (!strcmp(extended, "deleteOrder")) tag = GF_SG_NODE_DELETE_EX;
    2268          15 :                         else if (!strcmp(extended, "allProtos")) tag = GF_SG_PROTO_DELETE_ALL;
    2269          10 :                         else if (!strcmp(extended, "proto") || !strcmp(extended, "protos")) {
    2270          10 :                                 if (!strcmp(name, "Insert")) {
    2271           5 :                                         parser->state = XMT_STATE_ELEMENTS;
    2272             :                                         tag = GF_SG_PROTO_INSERT;
    2273             :                                 }
    2274           5 :                                 else if (!strcmp(name, "Delete")) tag = GF_SG_PROTO_DELETE;
    2275             :                         }
    2276             :                         else {
    2277           0 :                                 xmt_report(parser, GF_BAD_PARAM, "Warning: Unknown extended command %s", extended);
    2278           0 :                                 return;
    2279             :                         }
    2280             : 
    2281             :                 }
    2282             : 
    2283         190 :                 if (tag == GF_SG_UNDEFINED) {
    2284           0 :                         xmt_report(parser, GF_BAD_PARAM, "Warning: Unknown scene command %s", name);
    2285           0 :                         return;
    2286             :                 }
    2287             : 
    2288         225 :                 parser->command = gf_sg_command_new(parser->load->scene_graph, tag);
    2289         225 :                 if (parser->command_buffer) {
    2290          65 :                         gf_list_add(parser->command_buffer->commandList, parser->command);
    2291          65 :                         parser->command_buffer->bufferSize++;
    2292             :                 } else {
    2293         160 :                         GF_StreamContext *stream = gf_sm_stream_find(parser->load->ctx, (u16) stream_id);
    2294         160 :                         if (!stream || (stream->streamType!=GF_STREAM_SCENE)) stream_id = parser->base_scene_id;
    2295             : 
    2296         160 :                         parser->scene_es = gf_sm_stream_new(parser->load->ctx, (u16) stream_id, GF_STREAM_SCENE, GF_CODECID_BIFS);
    2297         160 :                         parser->scene_au = gf_sm_stream_au_new(parser->scene_es, 0, au_time, au_is_rap);
    2298         160 :                         gf_list_add(parser->scene_au->commands, parser->command);
    2299             :                 }
    2300             : 
    2301         225 :                 if (atNode) {
    2302         175 :                         parser->command->node = atNode;
    2303         175 :                         gf_node_register(atNode, NULL);
    2304         175 :                         if (tag == GF_SG_MULTIPLE_INDEXED_REPLACE) {
    2305           5 :                                 parser->command->fromFieldIndex = info.fieldIndex;
    2306           5 :                                 return;
    2307             :                         }
    2308         170 :                         if (fieldName) {
    2309         105 :                                 field = gf_sg_command_field_new(parser->command);
    2310         105 :                                 field->fieldIndex = info.fieldIndex;
    2311             : 
    2312         105 :                                 if (idxNode && idxField) {
    2313           5 :                                         GF_Node *iNode = xmt_find_node(parser, idxNode);
    2314           5 :                                         if (iNode) {
    2315             :                                                 GF_FieldInfo idxF;
    2316           5 :                                                 parser->command->toNodeID = gf_node_get_id(iNode);
    2317           5 :                                                 gf_node_get_field_by_name(iNode, idxField, &idxF);
    2318           5 :                                                 parser->command->toFieldIndex = idxF.fieldIndex;
    2319             :                                                 position = 0;
    2320           5 :                                                 switch (idxF.fieldType) {
    2321           0 :                                                 case GF_SG_VRML_SFBOOL:
    2322           0 :                                                         if (*(SFBool*)idxF.far_ptr) position = 1;
    2323             :                                                         break;
    2324           5 :                                                 case GF_SG_VRML_SFINT32:
    2325           5 :                                                         if (*(SFInt32*)idxF.far_ptr >=0) position = *(SFInt32*)idxF.far_ptr;
    2326             :                                                         break;
    2327           0 :                                                 case GF_SG_VRML_SFFLOAT:
    2328           0 :                                                         if ( (*(SFFloat *)idxF.far_ptr) >=0) position = (s32) floor( FIX2FLT(*(SFFloat*)idxF.far_ptr) );
    2329             :                                                         break;
    2330           0 :                                                 case GF_SG_VRML_SFTIME:
    2331           0 :                                                         if ( (*(SFTime *)idxF.far_ptr) >=0) position = (s32) floor( (*(SFTime *)idxF.far_ptr) );
    2332             :                                                         break;
    2333             :                                                 }
    2334             :                                         }
    2335             :                                 }
    2336         105 :                                 if (childField) {
    2337           5 :                                         GF_Node *child = gf_node_list_get_child( ((GF_ParentNode*)atNode)->children, position);
    2338           5 :                                         if (child) {
    2339           5 :                                                 parser->command->ChildNodeTag = gf_node_get_tag(child);
    2340           5 :                                                 if (parser->command->ChildNodeTag == TAG_ProtoNode) {
    2341           0 :                                                         s32 p_id = gf_sg_proto_get_id(gf_node_get_proto(child));
    2342           0 :                                                         parser->command->ChildNodeTag = -p_id;
    2343             :                                                 }
    2344             :                                                 /*get field in the info struct for later parsing*/
    2345           5 :                                                 gf_node_get_field_by_name(child, childField, &info);
    2346           5 :                                                 parser->command->child_field = info.fieldIndex;
    2347             :                                         }
    2348             :                                 }
    2349             :                                 /*do not keep position info if index node is used*/
    2350         105 :                                 if (idxNode && idxField) position = -2;
    2351             : 
    2352         105 :                                 if (fromNode && fromField) {
    2353           5 :                                         GF_Node *fNode = xmt_find_node(parser, fromNode);
    2354           5 :                                         if (fNode) {
    2355             :                                                 GF_FieldInfo fField;
    2356           5 :                                                 parser->command->fromNodeID = gf_node_get_id(fNode);
    2357           5 :                                                 gf_node_get_field_by_name(fNode, fromField, &fField);
    2358           5 :                                                 parser->command->fromFieldIndex = fField.fieldIndex;
    2359             :                                         }
    2360             :                                 }
    2361         105 :                                 if (!fromNode && !fromField) {
    2362         100 :                                         if (gf_sg_vrml_get_sf_type(info.fieldType) != GF_SG_VRML_SFNODE) {
    2363          90 :                                                 if (position==-2) {
    2364          75 :                                                         field->fieldType = info.fieldType;
    2365          75 :                                                         field->field_ptr = gf_sg_vrml_field_pointer_new(info.fieldType);
    2366          75 :                                                         info.far_ptr = field->field_ptr;
    2367          75 :                                                         if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    2368          75 :                                                                 xmt_parse_sf_field(parser, &info, atNode, fieldValue);
    2369             :                                                         } else {
    2370           0 :                                                                 xmt_parse_mf_field(parser, &info, atNode, fieldValue);
    2371             :                                                         }
    2372             :                                                 } else {
    2373          15 :                                                         field->fieldType = info.fieldType = gf_sg_vrml_get_sf_type(info.fieldType);
    2374          15 :                                                         field->pos = position;
    2375          15 :                                                         if (tag != GF_SG_INDEXED_DELETE) {
    2376          10 :                                                                 field->field_ptr = gf_sg_vrml_field_pointer_new(info.fieldType);
    2377          10 :                                                                 info.far_ptr = field->field_ptr;
    2378          10 :                                                                 xmt_parse_sf_field(parser, &info, atNode, fieldValue);
    2379             :                                                         }
    2380             :                                                 }
    2381             :                                         } else {
    2382          10 :                                                 field->pos = position;
    2383          10 :                                                 if ((position==-2) && (info.fieldType==GF_SG_VRML_MFNODE)) {
    2384           0 :                                                         field->fieldType = GF_SG_VRML_MFNODE;
    2385             :                                                 } else {
    2386          10 :                                                         field->fieldType = GF_SG_VRML_SFNODE;
    2387             :                                                 }
    2388          10 :                                                 parser->state = XMT_STATE_ELEMENTS;
    2389             :                                         }
    2390             :                                 }
    2391          65 :                         } else if (tag==GF_SG_NODE_INSERT) {
    2392          25 :                                 field = gf_sg_command_field_new(parser->command);
    2393          25 :                                 field->fieldType = GF_SG_VRML_SFNODE;
    2394          25 :                                 field->pos = position;
    2395          25 :                                 parser->state = XMT_STATE_ELEMENTS;
    2396             :                         }
    2397             :                 }
    2398          50 :                 else if (routeName) {
    2399          10 :                         u32 rID = xmt_get_route(parser, routeName, 0);
    2400          10 :                         if (!rID) {
    2401           0 :                                 parser->command->unres_name = gf_strdup(routeName);
    2402           0 :                                 parser->command->unresolved = 1;
    2403           0 :                                 gf_list_add(parser->unresolved_routes, parser->command);
    2404             :                         } else {
    2405          10 :                                 parser->command->RouteID = rID;
    2406             :                                 /*for bt<->xmt conversions*/
    2407          10 :                                 parser->command->def_name = gf_strdup(routeName);
    2408             :                         }
    2409             :                 }
    2410          40 :                 else if (tag == GF_SG_PROTO_DELETE) {
    2411             :                         char *sep;
    2412           5 :                         while (fieldValue) {
    2413             :                                 GF_Proto *p;
    2414           5 :                                 sep = strchr(fieldValue, ' ');
    2415           5 :                                 if (sep) sep[0] = 0;
    2416           5 :                                 p = gf_sg_find_proto(parser->load->scene_graph, 0, fieldValue);
    2417          10 :                                 if (!p) p = gf_sg_find_proto(parser->load->scene_graph, atoi(fieldValue), NULL);
    2418             : 
    2419           5 :                                 if (!p) xmt_report(parser, GF_OK, "Warning: Cannot locate proto %s - skipping", fieldValue);
    2420             :                                 else {
    2421           5 :                                         parser->command->del_proto_list = (u32*)gf_realloc(parser->command->del_proto_list, sizeof(u32) * (parser->command->del_proto_list_size+1));
    2422           5 :                                         parser->command->del_proto_list[parser->command->del_proto_list_size] = p->ID;
    2423           5 :                                         parser->command->del_proto_list_size++;
    2424             :                                 }
    2425           5 :                                 if (!sep) break;
    2426           0 :                                 sep[0] = ' ';
    2427           0 :                                 fieldValue = sep+1;
    2428             :                         }
    2429             :                 }
    2430             : 
    2431             :                 return;
    2432             :         }
    2433             : 
    2434             :         /*OD commands*/
    2435          20 :         if (!strcmp(name, "ObjectDescriptorUpdate") || !strcmp(name, "ObjectDescriptorRemove")
    2436           5 :                 || !strcmp(name, "ES_DescriptorUpdate") || !strcmp(name, "ES_DescriptorRemove")
    2437           0 :                 || !strcmp(name, "IPMP_DescriptorUpdate") || !strcmp(name, "IPMP_DescriptorRemove") ) {
    2438             :                 u32 stream_id;
    2439             :                 u8 tag = 0;
    2440             :                 GF_StreamContext *stream;
    2441             :                 char *od_ids = NULL;
    2442             :                 char *es_ids = NULL;
    2443          20 :                 Double au_time = parser->au_time;
    2444          20 :                 Bool au_is_rap = parser->au_is_rap;
    2445             : 
    2446          20 :                 if (!parser->stream_id) parser->stream_id = parser->base_od_id;
    2447          20 :                 stream_id = parser->stream_id;
    2448             : 
    2449          35 :                 for (i=0; i<nb_attributes; i++) {
    2450          15 :                         GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    2451          15 :                         if (!att->value || !strlen(att->value)) continue;
    2452          15 :                         if (!strcmp(att->name, "begin")) au_time = atoi(att->value);
    2453          15 :                         else if (!strcmp(att->name, "isRAP")) au_is_rap = !strcmp(att->value, "yes") ? 1 : 0;
    2454          15 :                         else if (!stricmp(att->name, "objectDescriptorId")) od_ids = att->value;
    2455           5 :                         else if (!strcmp(att->name, "ES_ID")) es_ids = att->value;
    2456             :                 }
    2457             : 
    2458             :                 /*if we are parsing in an already loaded context and no time is given, force a time != 0 to create a new command*/
    2459          20 :                 if (!au_time && (parser->load->flags&GF_SM_LOAD_CONTEXT_READY))
    2460             :                         au_time = 0.001;
    2461             : 
    2462          20 :                 if (!strcmp(name, "ObjectDescriptorUpdate")) tag = GF_ODF_OD_UPDATE_TAG;
    2463          10 :                 else if (!strcmp(name, "ES_DescriptorUpdate")) tag = GF_ODF_ESD_UPDATE_TAG;
    2464          10 :                 else if (!strcmp(name, "IPMP_DescriptorUpdate")) tag = GF_ODF_IPMP_UPDATE_TAG;
    2465          10 :                 else if (!strcmp(name, "ObjectDescriptorRemove")) {
    2466           5 :                         if (!od_ids) return;
    2467             :                         tag = GF_ODF_OD_REMOVE_TAG;
    2468             :                 }
    2469           5 :                 else if (!strcmp(name, "ES_DescriptorRemove")) {
    2470           5 :                         if (!od_ids || !es_ids) return;
    2471             :                         tag = GF_ODF_ESD_REMOVE_TAG;
    2472             :                 }
    2473           0 :                 else if (!strcmp(name, "IPMP_DescriptorRemove")) tag = GF_ODF_IPMP_REMOVE_TAG;
    2474             : 
    2475          20 :                 stream = gf_sm_stream_find(parser->load->ctx, (u16) stream_id);
    2476          20 :                 if (stream && (stream->streamType!=GF_STREAM_OD)) stream_id = parser->base_od_id;
    2477          20 :                 parser->od_es = gf_sm_stream_new(parser->load->ctx, (u16) stream_id, GF_STREAM_OD, GF_CODECID_OD_V1);
    2478          20 :                 parser->od_au = gf_sm_stream_au_new(parser->od_es, 0, au_time, au_is_rap);
    2479          20 :                 parser->od_command = gf_odf_com_new(tag);
    2480          20 :                 gf_list_add(parser->od_au->commands, parser->od_command);
    2481             : 
    2482          20 :                 if (tag == GF_ODF_ESD_REMOVE_TAG) {
    2483             :                         char *sep;
    2484           5 :                         GF_ESDRemove *esdR = (GF_ESDRemove *) parser->od_command ;
    2485           5 :                         esdR->ODID = xmt_get_od_id(parser, od_ids);
    2486          10 :                         while (es_ids) {
    2487             :                                 u32 es_id;
    2488           5 :                                 sep = strchr(es_ids, ' ');
    2489           5 :                                 if (sep) sep[0] = 0;
    2490           5 :                                 es_id = xmt_get_esd_id(parser, es_ids);
    2491           5 :                                 if (!es_id) xmt_report(parser, GF_OK, "Warning: Cannot find ES Descriptor %s - skipping", es_ids);
    2492             :                                 else {
    2493           5 :                                         esdR->ES_ID = (u16*)gf_realloc(esdR->ES_ID, sizeof(u16) * (esdR->NbESDs+1));
    2494           5 :                                         esdR->ES_ID[esdR->NbESDs] = es_id;
    2495           5 :                                         esdR->NbESDs++;
    2496             :                                 }
    2497           5 :                                 if (!sep) break;
    2498           0 :                                 sep[0] = ' ';
    2499           0 :                                 es_ids = sep+1;
    2500             :                         }
    2501             :                 }
    2502          15 :                 else if (tag == GF_ODF_OD_REMOVE_TAG) {
    2503             :                         char *sep;
    2504           5 :                         GF_ODRemove *odR = (GF_ODRemove *) parser->od_command ;
    2505          10 :                         while (od_ids) {
    2506             :                                 u32 od_id;
    2507           5 :                                 sep = strchr(od_ids, ' ');
    2508           5 :                                 if (sep) sep[0] = 0;
    2509           5 :                                 od_id = xmt_get_od_id(parser, od_ids);
    2510           5 :                                 if (!od_id) xmt_report(parser, GF_OK, "Warning: Cannot find Object Descriptor %s - skipping", od_ids);
    2511             :                                 else {
    2512           5 :                                         odR->OD_ID = (u16*)gf_realloc(odR->OD_ID, sizeof(u16) * (odR->NbODs+1));
    2513           5 :                                         odR->OD_ID[odR->NbODs] = od_id;
    2514           5 :                                         odR->NbODs++;
    2515             :                                 }
    2516           5 :                                 if (!sep) break;
    2517           0 :                                 sep[0] = ' ';
    2518           0 :                                 od_ids = sep+1;
    2519             :                         }
    2520             :                 }
    2521             :         }
    2522             : }
    2523             : 
    2524        2685 : static void xmt_node_start(void *sax_cbck, const char *name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes)
    2525             : {
    2526             :         GF_Node *elt;
    2527             :         XMTNodeStack *top, *new_top;
    2528             :         GF_XMTParser *parser = (GF_XMTParser *)sax_cbck;
    2529             : 
    2530        2685 :         if (parser->last_error) {
    2531           0 :                 gf_xml_sax_suspend(parser->sax_parser, 1);
    2532           0 :                 if (parser->command_buffer)
    2533           0 :                         parser->command_buffer->buffer = NULL;
    2534             :                 return;
    2535             :         }
    2536             : 
    2537             :         /*init doc type*/
    2538        2685 :         if (!parser->doc_type) {
    2539           5 :                 if (!strcmp(name, "XMT-A")) parser->doc_type = 1;
    2540           0 :                 else if (!strcmp(name, "X3D")) {
    2541           0 :                         parser->doc_type = 2;
    2542           0 :                         parser->script_to_load = gf_list_new();
    2543             :                 }
    2544           0 :                 else if (!strcmp(name, "XMT-O")) parser->doc_type = 3;
    2545             :                 return;
    2546             :         }
    2547             : 
    2548             :         /*init doc state with already loaded context (for chunk encoding)*/
    2549        2680 :         if ((parser->state == XMT_STATE_INIT) && (parser->load->flags & GF_SM_LOAD_CONTEXT_READY) && (parser->doc_type == 1)) {
    2550           0 :                 parser->state = XMT_STATE_COMMANDS;
    2551             :         }
    2552             :         /*init doc state for regular parsing*/
    2553        2680 :         else if (parser->state == XMT_STATE_INIT) {
    2554             :                 /*XMT-A header*/
    2555           5 :                 if ((parser->doc_type == 1) && !strcmp(name, "Header")) parser->state = XMT_STATE_HEAD;
    2556             :                 /*X3D header*/
    2557           0 :                 else if ((parser->doc_type == 2) && !strcmp(name, "head")) parser->state = XMT_STATE_HEAD;
    2558             :                 /*XMT-O header*/
    2559           0 :                 else if ((parser->doc_type == 3) && !strcmp(name, "head")) parser->state = XMT_STATE_HEAD;
    2560             : 
    2561             :                 return;
    2562             :         }
    2563             : 
    2564             :         /*XMT-A header: parse OD/IOD*/
    2565        2675 :         if ((parser->doc_type == 1) && (parser->state == XMT_STATE_HEAD)) {
    2566             :                 GF_Descriptor *desc, *par;
    2567          90 :                 par = (GF_Descriptor *)gf_list_last(parser->descriptors);
    2568          90 :                 desc = xmt_parse_descriptor(parser, (char *) name, attributes, nb_attributes, par);
    2569          90 :                 if (desc) gf_list_add(parser->descriptors, desc);
    2570             :                 return;
    2571             :         }
    2572        2585 :         if (parser->state==XMT_STATE_END) {
    2573           0 :                 if (!strcmp(name, "head")) {
    2574           0 :                         parser->state = XMT_STATE_HEAD;
    2575             :                 } else {
    2576           0 :                         parser->state = XMT_STATE_COMMANDS;
    2577             :                 }
    2578             :         }
    2579             : 
    2580             :         /*scene content*/
    2581        2585 :         if (parser->state==XMT_STATE_BODY) {
    2582             :                 /*XMT-A body*/
    2583           5 :                 if ((parser->doc_type == 1) && !strcmp(name, "Body")) parser->state = XMT_STATE_COMMANDS;
    2584             :                 /*X3D scene*/
    2585           0 :                 else if ((parser->doc_type == 2) && !strcmp(name, "Scene")) {
    2586           0 :                         parser->state = XMT_STATE_ELEMENTS;
    2587           0 :                         if (parser->load->ctx) {
    2588           0 :                                 parser->load->ctx->is_pixel_metrics = 0;
    2589           0 :                                 parser->load->ctx->scene_width = parser->load->ctx->scene_height = 0;
    2590             :                         }
    2591           0 :                         gf_sg_set_scene_size_info(parser->load->scene_graph, 0, 0, 0);
    2592             :                 }
    2593             :                 /*XMT-O body*/
    2594           0 :                 else if ((parser->doc_type == 3) && !strcmp(name, "body")) parser->state = XMT_STATE_COMMANDS;
    2595             :                 return;
    2596             :         }
    2597             :         /*XMT-A command*/
    2598        2580 :         if ((parser->doc_type == 1) && (parser->state == XMT_STATE_COMMANDS)) {
    2599             :                 /*OD command*/
    2600         560 :                 if (parser->od_command) {
    2601             :                         GF_Descriptor *desc, *par;
    2602         170 :                         par = (GF_Descriptor *)gf_list_last(parser->descriptors);
    2603         170 :                         desc = xmt_parse_descriptor(parser, (char *) name, attributes, nb_attributes, par);
    2604         170 :                         if (desc) gf_list_add(parser->descriptors, desc);
    2605             :                 } else {
    2606         390 :                         xmt_parse_command(parser, name, attributes, nb_attributes);
    2607             :                 }
    2608             :                 return;
    2609             :         }
    2610             : 
    2611             : 
    2612             :         /*node*/
    2613        2020 :         if (parser->state != XMT_STATE_ELEMENTS) return;
    2614             : 
    2615        2020 :         top = (XMTNodeStack*)gf_list_last(parser->nodes);
    2616        2020 :         if (!top) top = parser->x3d_root;
    2617             : 
    2618        2020 :         elt = xmt_parse_element(parser, (char *) name, name_space, attributes, nb_attributes, top);
    2619        2020 :         if (!elt) return;
    2620        1025 :         GF_SAFEALLOC(new_top, XMTNodeStack);
    2621        1025 :         if (!new_top) return;
    2622             : 
    2623        1025 :         new_top->node = elt;
    2624        1025 :         gf_list_add(parser->nodes, new_top);
    2625             : 
    2626             :         /*assign root node here to enable progressive loading*/
    2627        1025 :         if (!top && (parser->doc_type == 1) && !parser->parsing_proto && parser->command && (parser->command->tag==GF_SG_SCENE_REPLACE) && !parser->command->node) {
    2628          10 :                 parser->command->node = elt;
    2629          10 :                 gf_node_register(elt, NULL);
    2630             :         }
    2631             : }
    2632             : 
    2633        2675 : static void xmt_node_end(void *sax_cbck, const char *name, const char *name_space)
    2634             : {
    2635             :         u32 tag;
    2636             :         GF_XMTParser *parser = (GF_XMTParser *)sax_cbck;
    2637             :         XMTNodeStack *top;
    2638             :         GF_Descriptor *desc;
    2639             :         GF_Node *node = NULL;
    2640        2675 :         if (!parser->doc_type || !parser->state) return;
    2641             : 
    2642        2675 :         top = (XMTNodeStack *)gf_list_last(parser->nodes);
    2643             : 
    2644        2675 :         if (!top) {
    2645             :                 /*check descr*/
    2646         740 :                 desc = (GF_Descriptor*)gf_list_last(parser->descriptors);
    2647         740 :                 if (desc && (desc->tag == gf_odf_get_tag_by_name((char *)name)) ) {
    2648             : 
    2649             :                         /*assign timescales once the ESD has been parsed*/
    2650         120 :                         if (desc->tag == GF_ODF_ESD_TAG) {
    2651             :                                 GF_ESD *esd = (GF_ESD*)desc;
    2652          30 :                                 GF_StreamContext *sc = gf_sm_stream_new(parser->load->ctx, esd->ESID, esd->decoderConfig ? esd->decoderConfig->streamType : 0, esd->decoderConfig ? esd->decoderConfig->objectTypeIndication : 0);
    2653          30 :                                 if (sc && esd->slConfig && esd->slConfig->timestampResolution)
    2654           0 :                                         sc->timeScale = esd->slConfig->timestampResolution;
    2655             :                         }
    2656             : 
    2657         120 :                         gf_list_rem_last(parser->descriptors);
    2658         120 :                         if (gf_list_count(parser->descriptors)) return;
    2659             : 
    2660          25 :                         if ((parser->doc_type==1) && (parser->state==XMT_STATE_HEAD) && parser->load->ctx && !parser->load->ctx->root_od) {
    2661           5 :                                 parser->load->ctx->root_od = (GF_ObjectDescriptor *)desc;
    2662             :                         }
    2663          20 :                         else if (!parser->od_command) {
    2664           0 :                                 xmt_report(parser, GF_OK, "Warning: descriptor %s defined outside scene scope - skipping", name);
    2665           0 :                                 gf_odf_desc_del(desc);
    2666             :                         } else {
    2667          20 :                                 switch (parser->od_command->tag) {
    2668           0 :                                 case GF_ODF_ESD_UPDATE_TAG:
    2669           0 :                                         gf_list_add( ((GF_ESDUpdate *)parser->od_command)->ESDescriptors, desc);
    2670           0 :                                         break;
    2671             :                                 /*same struct for OD update and IPMP update*/
    2672          20 :                                 case GF_ODF_OD_UPDATE_TAG:
    2673             :                                 case GF_ODF_IPMP_UPDATE_TAG:
    2674          20 :                                         gf_list_add( ((GF_ODUpdate *)parser->od_command)->objectDescriptors, desc);
    2675          20 :                                         break;
    2676             :                                 }
    2677             :                         }
    2678             : 
    2679             :                         return;
    2680             :                 }
    2681         620 :                 if (parser->state == XMT_STATE_HEAD) {
    2682          55 :                         if ((parser->doc_type == 1) && !strcmp(name, "Header")) parser->state = XMT_STATE_BODY;
    2683             :                         /*X3D header*/
    2684          50 :                         else if ((parser->doc_type == 2) && !strcmp(name, "head")) {
    2685           0 :                                 parser->state = XMT_STATE_BODY;
    2686             :                                 /*create a group at root level*/
    2687           0 :                                 tag = xmt_get_node_tag(parser, "Group");
    2688           0 :                                 node = gf_node_new(parser->load->scene_graph, tag);
    2689           0 :                                 gf_node_register(node, NULL);
    2690           0 :                                 gf_sg_set_root_node(parser->load->scene_graph, node);
    2691           0 :                                 gf_node_init(node);
    2692             : 
    2693             :                                 /*create a default top for X3D*/
    2694           0 :                                 GF_SAFEALLOC(parser->x3d_root, XMTNodeStack);
    2695           0 :                                 if (!parser->x3d_root) {
    2696           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("Failed to allocate X3D root\n"));
    2697             :                                         return;
    2698             :                                 }
    2699           0 :                                 parser->x3d_root->node = node;
    2700             :                         }
    2701             :                         /*XMT-O header*/
    2702          50 :                         else if ((parser->doc_type == 3) && !strcmp(name, "head")) parser->state = XMT_STATE_BODY;
    2703             :                 }
    2704         565 :                 else if (parser->state == XMT_STATE_ELEMENTS) {
    2705             :                         assert((parser->doc_type != 1) || parser->command);
    2706         245 :                         if (!strcmp(name, "Replace") || !strcmp(name, "Insert") || !strcmp(name, "Delete")) {
    2707          85 :                                 parser->command = NULL;
    2708          85 :                                 parser->state = XMT_STATE_COMMANDS;
    2709             :                         }
    2710         160 :                         else if (!strcmp(name, "repField")) {
    2711           5 :                                 parser->state = XMT_STATE_COMMANDS;
    2712             :                         }
    2713             :                         /*end proto*/
    2714         170 :                         else if (!strcmp(name, "ProtoDeclare") || !strcmp(name, "ExternProtoDeclare"))  {
    2715          15 :                                 GF_Proto *cur = parser->parsing_proto;
    2716          15 :                                 xmt_resolve_routes(parser);
    2717          15 :                                 parser->parsing_proto = (GF_Proto*)cur->userpriv;
    2718          15 :                                 parser->load->scene_graph = cur->parent_graph;
    2719          15 :                                 cur->userpriv = NULL;
    2720             :                         }
    2721         140 :                         else if (parser->proto_field && !strcmp(name, "field")) parser->proto_field = NULL;
    2722             :                         /*end X3D body*/
    2723          50 :                         else if ((parser->doc_type == 2) && !strcmp(name, "Scene")) parser->state = XMT_STATE_BODY_END;
    2724             :                 }
    2725         320 :                 else if (parser->state == XMT_STATE_COMMANDS) {
    2726             :                         /*end XMT-A body*/
    2727         315 :                         if ((parser->doc_type == 1) && !strcmp(name, "Body")) parser->state = XMT_STATE_BODY_END;
    2728             :                         /*end X3D body*/
    2729         310 :                         else if ((parser->doc_type == 2) && !strcmp(name, "Scene")) parser->state = XMT_STATE_BODY_END;
    2730             :                         /*end XMT-O body*/
    2731         310 :                         else if ((parser->doc_type == 3) && !strcmp(name, "body")) parser->state = XMT_STATE_BODY_END;
    2732             : 
    2733             :                         /*end scene command*/
    2734         310 :                         else if (!strcmp(name, "Replace") || !strcmp(name, "Insert") || !strcmp(name, "Delete") )  {
    2735             :                                 /*restore parent command if in CommandBuffer*/
    2736          75 :                                 if (parser->command && parser->command_buffer && parser->command_buffer->buffer) {
    2737             :                                         //empty <Insert>
    2738           0 :                                         if ((parser->command->tag==GF_SG_ROUTE_INSERT) && !parser->command->fromNodeID) {
    2739           0 :                                                 gf_list_del_item(parser->command_buffer->commandList, parser->command);
    2740             :                                         }
    2741             : 
    2742           0 :                                         parser->command = (GF_Command*) parser->command_buffer->buffer;
    2743           0 :                                         parser->command_buffer->buffer = NULL;
    2744           0 :                                         parser->command_buffer = NULL;
    2745             :                                 } else {
    2746             :                                         //empty <Insert>
    2747          75 :                                         if (parser->command && (parser->command->tag==GF_SG_ROUTE_INSERT) && !parser->command->fromNodeID) {
    2748           0 :                                                 gf_list_del_item(parser->scene_au->commands, parser->command);
    2749             :                                         }
    2750          75 :                                         parser->command = NULL;
    2751             :                                 }
    2752             :                         }
    2753             :                         /*end OD command*/
    2754         235 :                         else if (!strcmp(name, "ObjectDescriptorUpdate") || !strcmp(name, "ObjectDescriptorRemove")
    2755         220 :                                  || !strcmp(name, "ES_DescriptorUpdate") || !strcmp(name, "ES_DescriptorRemove")
    2756         215 :                                  || !strcmp(name, "IPMP_DescriptorUpdate") || !strcmp(name, "IPMP_DescriptorRemove") ) {
    2757          20 :                                 parser->od_command = NULL;
    2758             :                         }
    2759             : 
    2760         215 :                         else if (!strcmp(name, "par"))
    2761          90 :                                 parser->in_com = 1;
    2762             : 
    2763             : 
    2764             :                 }
    2765           5 :                 else if (parser->state == XMT_STATE_BODY_END) {
    2766             :                         /*end XMT-A*/
    2767           5 :                         if ((parser->doc_type == 1) && !strcmp(name, "XMT-A")) parser->state = XMT_STATE_END;
    2768             :                         /*end X3D*/
    2769           0 :                         else if ((parser->doc_type == 2) && !strcmp(name, "X3D")) {
    2770           0 :                                 while (1) {
    2771           0 :                                         GF_Node *n = (GF_Node *)gf_list_last(parser->script_to_load);
    2772           0 :                                         if (!n) break;
    2773           0 :                                         gf_list_rem_last(parser->script_to_load);
    2774           0 :                                         gf_sg_script_load(n);
    2775             :                                 }
    2776           0 :                                 gf_list_del(parser->script_to_load);
    2777           0 :                                 parser->script_to_load = NULL;
    2778           0 :                                 parser->state = XMT_STATE_END;
    2779             :                         }
    2780             :                         /*end XMT-O*/
    2781           0 :                         else if ((parser->doc_type == 3) && !strcmp(name, "XMT-O")) parser->state = XMT_STATE_END;
    2782             :                 }
    2783             :                 return;
    2784             :         }
    2785             :         /*only remove created nodes ... */
    2786        1935 :         tag = xmt_get_node_tag(parser, name);
    2787        1935 :         if (!tag) {
    2788         930 :                 if (top->container_field.name) {
    2789         660 :                         if (!strcmp(name, top->container_field.name)) {
    2790         570 :                                 if (top->container_field.fieldType==GF_SG_VRML_SFCOMMANDBUFFER) {
    2791          35 :                                         parser->state = XMT_STATE_ELEMENTS;
    2792          35 :                                         parser->command = (GF_Command *) (void *) parser->command_buffer->buffer;
    2793          35 :                                         parser->command_buffer->buffer = NULL;
    2794          35 :                                         parser->command_buffer = NULL;
    2795             :                                 }
    2796         570 :                                 top->container_field.far_ptr = NULL;
    2797         570 :                                 top->container_field.name = NULL;
    2798         570 :                                 top->last = NULL;
    2799             :                         }
    2800             :                         /*end of command inside an command (conditional.buffer replace)*/
    2801          90 :                         else if (!strcmp(name, "Replace") || !strcmp(name, "Insert") || !strcmp(name, "Delete") )  {
    2802          65 :                                 if (parser->command_buffer) {
    2803          65 :                                         if (parser->command_buffer->bufferSize) {
    2804          65 :                                                 parser->command_buffer->bufferSize--;
    2805             :                                         } else {
    2806           0 :                                                 SFCommandBuffer *prev = (SFCommandBuffer *) parser->command_buffer->buffer;
    2807           0 :                                                 parser->command_buffer->buffer = NULL;
    2808           0 :                                                 parser->command_buffer = prev;
    2809             :                                         }
    2810             :                                         /*stay in command parsing mode (state 3) until we find </buffer>*/
    2811          65 :                                         parser->state = XMT_STATE_COMMANDS;
    2812             :                                 }
    2813             :                         }
    2814             :                         /*end of protofield node(s) content*/
    2815          25 :                         else if (!strcmp(name, "node") || !strcmp(name, "nodes")) {
    2816          25 :                                 top->container_field.far_ptr = NULL;
    2817          25 :                                 top->container_field.name = NULL;
    2818          25 :                                 top->last = NULL;
    2819             :                         }
    2820             :                 }
    2821             :                 /*SF/MFNode proto field, just pop node stack*/
    2822         270 :                 else if (!top->node && !strcmp(name, "field")) {
    2823          10 :                         gf_list_rem_last(parser->nodes);
    2824          10 :                         gf_free(top);
    2825         260 :                 } else if (top->node && top->node->sgprivate->tag == TAG_ProtoNode) {
    2826         150 :                         if (!strcmp(name, "node") || !strcmp(name, "nodes")) {
    2827           0 :                                 top->container_field.far_ptr = NULL;
    2828           0 :                                 top->container_field.name = NULL;
    2829           0 :                                 top->last = NULL;
    2830         150 :                         } else if (!strcmp(name, "ProtoInstance")) {
    2831          20 :                                 gf_list_rem_last(parser->nodes);
    2832          20 :                                 node = top->node;
    2833          20 :                                 gf_free(top);
    2834          20 :                                 goto attach_node;
    2835             :                         }
    2836             :                 }
    2837        1005 :         } else if (top->node->sgprivate->tag==tag) {
    2838             :                 node = top->node;
    2839        1005 :                 gf_list_rem_last(parser->nodes);
    2840        1005 :                 gf_free(top);
    2841             : 
    2842        1025 : attach_node:
    2843        1025 :                 top = (XMTNodeStack*)gf_list_last(parser->nodes);
    2844             :                 /*add node to command*/
    2845        1025 :                 if (!top || (top->container_field.fieldType==GF_SG_VRML_SFCOMMANDBUFFER)) {
    2846          80 :                         if (parser->doc_type == 1) {
    2847             :                                 GF_CommandField *inf;
    2848             :                                 Bool single_node = 0;
    2849             :                                 assert(parser->command);
    2850          80 :                                 switch (parser->command->tag) {
    2851          25 :                                 case GF_SG_SCENE_REPLACE:
    2852          25 :                                         if (parser->parsing_proto) {
    2853          15 :                                                 gf_sg_proto_add_node_code(parser->parsing_proto, node);
    2854          15 :                                                 gf_node_register(node, NULL);
    2855          10 :                                         } else if (!parser->command->node) {
    2856           0 :                                                 parser->command->node = node;
    2857           0 :                                                 gf_node_register(node, NULL);
    2858          10 :                                         } else if (parser->command->node != node) {
    2859           0 :                                                 xmt_report(parser, GF_OK, "Warning: top-node already assigned - discarding node %s", name);
    2860           0 :                                                 gf_node_register(node, NULL);
    2861           0 :                                                 gf_node_unregister(node, NULL);
    2862             :                                         }
    2863             :                                         break;
    2864          30 :                                 case GF_SG_GLOBAL_QUANTIZER:
    2865             :                                 case GF_SG_NODE_INSERT:
    2866             :                                 case GF_SG_INDEXED_INSERT:
    2867             :                                 case GF_SG_INDEXED_REPLACE:
    2868             :                                         single_node = 1;
    2869          50 :                                 case GF_SG_NODE_REPLACE:
    2870             :                                 case GF_SG_FIELD_REPLACE:
    2871             :                                 case GF_SG_MULTIPLE_REPLACE:
    2872          50 :                                         inf = (GF_CommandField*)gf_list_last(parser->command->command_fields);
    2873          50 :                                         if (!inf) {
    2874          20 :                                                 inf = gf_sg_command_field_new(parser->command);
    2875          20 :                                                 inf->fieldType = GF_SG_VRML_SFNODE;
    2876             :                                         }
    2877          50 :                                         if ((inf->fieldType==GF_SG_VRML_MFNODE) && !inf->node_list) {
    2878           0 :                                                 inf->field_ptr = &inf->node_list;
    2879           0 :                                                 if (inf->new_node) {
    2880           0 :                                                         gf_node_list_add_child(& inf->node_list, inf->new_node);
    2881           0 :                                                         inf->new_node = NULL;
    2882             :                                                 }
    2883             :                                         }
    2884             : 
    2885          50 :                                         if (inf->new_node) {
    2886           0 :                                                 if (single_node) {
    2887           0 :                                                         gf_node_unregister(inf->new_node, NULL);
    2888             :                                                 } else {
    2889           0 :                                                         inf->field_ptr = &inf->node_list;
    2890           0 :                                                         gf_node_list_add_child(& inf->node_list, inf->new_node);
    2891           0 :                                                         inf->fieldType = GF_SG_VRML_MFNODE;
    2892             :                                                 }
    2893           0 :                                                 inf->new_node = NULL;
    2894             :                                         }
    2895          50 :                                         gf_node_register(node, NULL);
    2896          50 :                                         if (inf->node_list) {
    2897           0 :                                                 gf_node_list_add_child(& inf->node_list, node);
    2898             :                                         } else {
    2899          50 :                                                 inf->new_node = node;
    2900          50 :                                                 inf->field_ptr = &inf->new_node;
    2901             :                                         }
    2902             :                                         break;
    2903           5 :                                 case GF_SG_PROTO_INSERT:
    2904           5 :                                         if (parser->parsing_proto) {
    2905           5 :                                                 gf_sg_proto_add_node_code(parser->parsing_proto, node);
    2906           5 :                                                 gf_node_register(node, NULL);
    2907           5 :                                                 break;
    2908             :                                         }
    2909             :                                 default:
    2910           0 :                                         xmt_report(parser, GF_OK, "Warning: node %s defined outside scene scope - skipping", name);
    2911           0 :                                         gf_node_register(node, NULL);
    2912           0 :                                         gf_node_unregister(node, NULL);
    2913           0 :                                         break;
    2914             : 
    2915             :                                 }
    2916             :                         }
    2917             :                         /*X3D*/
    2918           0 :                         else if (parser->doc_type == 2) {
    2919           0 :                                 if (parser->parsing_proto) {
    2920           0 :                                         gf_sg_proto_add_node_code(parser->parsing_proto, node);
    2921           0 :                                         gf_node_register(node, NULL);
    2922             :                                 } else {
    2923           0 :                                         M_Group *gr = (M_Group *)gf_sg_get_root_node(parser->load->scene_graph);
    2924           0 :                                         if (!gr) {
    2925           0 :                                                 xmt_report(parser, GF_OK, "Warning: node %s defined outside scene scope - skipping", name);
    2926           0 :                                                 gf_node_register(node, NULL);
    2927           0 :                                                 gf_node_unregister(node, NULL);
    2928             :                                         } else {
    2929             :                                                 //node has already been added to its parent with X3d parsing, because of the default container resolving
    2930             : //                                              gf_node_list_add_child(& gr->children, node);
    2931             : //                                              gf_node_register(node, NULL);
    2932             :                                         }
    2933             :                                 }
    2934             :                         }
    2935             :                         /*special case: replace scene has already been applied (progressive loading)*/
    2936           0 :                         else if ((parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) && (parser->load->scene_graph->RootNode!=node) ) {
    2937           0 :                                 gf_node_register(node, NULL);
    2938             :                         } else {
    2939           0 :                                 xmt_report(parser, GF_OK, "Warning: node %s defined outside scene scope - skipping", name);
    2940           0 :                                 gf_node_register(node, NULL);
    2941           0 :                                 gf_node_unregister(node, NULL);
    2942             :                         }
    2943             :                 }
    2944        1025 :                 if (parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) {
    2945             :                         /*load scripts*/
    2946         205 :                         if (!parser->parsing_proto) {
    2947         386 :                                 if ((tag==TAG_MPEG4_Script)
    2948             : #ifndef GPAC_DISABLE_X3D
    2949         193 :                                         || (tag==TAG_X3D_Script)
    2950             : #endif
    2951             :                                    ) {
    2952             :                                         /*it may happen that the script uses itself as a field (not sure this is compliant since this
    2953             :                                         implies a cyclic structure, but happens in some X3D conformance seq)*/
    2954           1 :                                         if (!top || (top->node != node)) {
    2955           1 :                                                 if (parser->command) {
    2956           1 :                                                         if (!parser->command->scripts_to_load) parser->command->scripts_to_load = gf_list_new();
    2957           1 :                                                         gf_list_add(parser->command->scripts_to_load, node);
    2958             :                                                 }
    2959             :                                                 /*do not load script until all routes are established!!*/
    2960           0 :                                                 else if (parser->doc_type==2) {
    2961           0 :                                                         gf_list_add(parser->script_to_load, node);
    2962             :                                                 } else {
    2963           0 :                                                         gf_sg_script_load(node);
    2964             :                                                 }
    2965             :                                         }
    2966             :                                 }
    2967             :                         }
    2968             :                 }
    2969           0 :         } else if (parser->current_node_tag==tag) {
    2970           0 :                 gf_list_rem_last(parser->nodes);
    2971           0 :                 gf_free(top);
    2972             :         } else {
    2973           0 :                 xmt_report(parser, GF_NON_COMPLIANT_BITSTREAM, "Warning: closing element %s doesn't match created node %s", name, gf_node_get_class_name(top->node) );
    2974             :         }
    2975             : }
    2976             : 
    2977        4355 : static void xmt_text_content(void *sax_cbck, const char *text_content, Bool is_cdata)
    2978             : {
    2979             :         const char *buf;
    2980             :         u32 len;
    2981             :         GF_XMTParser *parser = (GF_XMTParser *)sax_cbck;
    2982             :         GF_Node *node;
    2983        4355 :         XMTNodeStack *top = (XMTNodeStack *)gf_list_last(parser->nodes);
    2984        4355 :         if (!top || !top->node) return;
    2985             : 
    2986             :         node = top->node;
    2987             : 
    2988             :         buf = text_content;
    2989        2995 :         len = (u32) strlen(buf);
    2990             : 
    2991        2995 :         if (!len) return;
    2992             : 
    2993        2995 :         switch (gf_node_get_tag((GF_Node *)node)) {
    2994          30 :         case TAG_MPEG4_Script:
    2995             : #ifndef GPAC_DISABLE_X3D
    2996             :         case TAG_X3D_Script:
    2997             : #endif
    2998          30 :                 if (is_cdata) {
    2999             :                         SFScript *sc_f;
    3000             :                         M_Script *sc = (M_Script *) node;
    3001           0 :                         gf_sg_vrml_mf_reset(& sc->url, GF_SG_VRML_MFSCRIPT);
    3002           0 :                         gf_sg_vrml_mf_append(& sc->url, GF_SG_VRML_MFSCRIPT, (void **) &sc_f);
    3003           0 :                         sc->url.vals[0].script_text = gf_strdup(text_content);
    3004             :                 }
    3005             :                 break;
    3006             :         default:
    3007             :                 break;
    3008             :         }
    3009             : }
    3010             : 
    3011             : 
    3012           5 : static GF_XMTParser *xmt_new_parser(GF_SceneLoader *load)
    3013             : {
    3014             :         GF_XMTParser *parser;
    3015           5 :         if ((load->type==GF_SM_LOAD_XSR) && !load->ctx) return NULL;
    3016           5 :         GF_SAFEALLOC(parser, GF_XMTParser);
    3017           5 :         if (!parser) return NULL;
    3018             : 
    3019           5 :         parser->nodes = gf_list_new();
    3020           5 :         parser->descriptors = gf_list_new();
    3021           5 :         parser->od_links = gf_list_new();
    3022           5 :         parser->esd_links = gf_list_new();
    3023           5 :         parser->def_nodes = gf_list_new();
    3024           5 :         parser->peeked_nodes = gf_list_new();
    3025           5 :         parser->inserted_routes = gf_list_new();
    3026           5 :         parser->unresolved_routes = gf_list_new();
    3027             : 
    3028           5 :         parser->sax_parser = gf_xml_sax_new(xmt_node_start, xmt_node_end, xmt_text_content, parser);
    3029           5 :         parser->load = load;
    3030           5 :         load->loader_priv = parser;
    3031           5 :         if (load->ctx) load->ctx->is_pixel_metrics = 1;
    3032             : 
    3033             :         return parser;
    3034             : }
    3035             : 
    3036           0 : static GF_Err xmt_restore_context(GF_SceneLoader *load)
    3037             : {
    3038             :         u32 i;
    3039             :         GF_StreamContext *sc;
    3040           0 :         GF_XMTParser *parser = (GF_XMTParser *)load->loader_priv;
    3041           0 :         if (!parser || !load->ctx) return GF_BAD_PARAM;
    3042             : 
    3043             :         /*restore context - note that base layer are ALWAYS declared BEFORE enhancement layers with gpac parsers*/
    3044           0 :         i=0;
    3045           0 :         while ((sc = (GF_StreamContext*)gf_list_enum(load->ctx->streams, &i))) {
    3046           0 :                 switch (sc->streamType) {
    3047           0 :                 case GF_STREAM_SCENE:
    3048             :                 case GF_STREAM_PRIVATE_SCENE:
    3049           0 :                         if (!parser->scene_es)
    3050           0 :                                 parser->scene_es = sc;
    3051             :                         break;
    3052           0 :                 case GF_STREAM_OD:
    3053           0 :                         if (!parser->od_es)
    3054           0 :                                 parser->od_es = sc;
    3055             :                         break;
    3056             :                 default:
    3057             :                         break;
    3058             :                 }
    3059             :         }
    3060             :         /*scene creation - pick up a size*/
    3061           0 :         if (!parser->scene_es) {
    3062           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("XMT: No BIFS Streams found in existing context - creating one\n"));
    3063           0 :                 parser->scene_es = gf_sm_stream_new(load->ctx, 0, GF_STREAM_SCENE, GF_CODECID_BIFS);
    3064           0 :                 parser->load->ctx->scene_width = 0;
    3065           0 :                 parser->load->ctx->scene_height = 0;
    3066           0 :                 parser->load->ctx->is_pixel_metrics = 1;
    3067             :         }
    3068           0 :         else parser->base_scene_id = parser->scene_es->ESID;
    3069           0 :         if (parser->od_es) parser->base_od_id = parser->od_es->ESID;
    3070             : 
    3071           0 :         parser->doc_type = (load->type==GF_SM_LOAD_X3D) ? 2 : 1;
    3072           0 :         return GF_OK;
    3073             : }
    3074             : 
    3075             : 
    3076           5 : static GF_Err load_xmt_initialize(GF_SceneLoader *load, const char *str_data)
    3077             : {
    3078             :         GF_Err e;
    3079             :         GF_XMTParser *parser;
    3080             : 
    3081           5 :         if (str_data) {
    3082             :                 char BOM[5];
    3083           0 :                 if (strlen(str_data)<4) return GF_BAD_PARAM;
    3084           0 :                 BOM[0] = str_data[0];
    3085           0 :                 BOM[1] = str_data[1];
    3086           0 :                 BOM[2] = str_data[2];
    3087           0 :                 BOM[3] = str_data[3];
    3088           0 :                 BOM[4] = 0;
    3089           0 :                 parser = xmt_new_parser(load);
    3090           0 :                 e = gf_xml_sax_init(parser->sax_parser, (unsigned char*)BOM);
    3091           0 :                 if (e) {
    3092           0 :                         xmt_report(parser, e, "Error initializing SAX parser");
    3093           0 :                         return e;
    3094             :                 }
    3095           0 :                 str_data += 4;
    3096           5 :         } else if (load->fileName) {
    3097           5 :                 parser = xmt_new_parser(load);
    3098             :         } else {
    3099             :                 return GF_BAD_PARAM;
    3100             :         }
    3101             : 
    3102             :         /*chunk parsing*/
    3103           5 :         if (load->flags & GF_SM_LOAD_CONTEXT_READY) {
    3104           0 :                 GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("XMT: MPEG-4 (XMT) Chunk Parsing\n"));
    3105             : 
    3106           0 :                 e = xmt_restore_context(load);
    3107           0 :                 if (e) return e;
    3108             : 
    3109             :         } else {
    3110           5 :                 GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("XMT: MPEG-4 (XMT) Scene Parsing\n"));
    3111             :         }
    3112             : 
    3113           5 :         if (str_data) {
    3114           0 :                 return gf_xml_sax_parse(parser->sax_parser, str_data);
    3115             :         }
    3116             :         return GF_OK;
    3117             : }
    3118             : 
    3119             : 
    3120           5 : static GF_Err load_xmt_run(GF_SceneLoader *load)
    3121             : {
    3122             :         GF_Err e;
    3123           5 :         GF_XMTParser *parser = (GF_XMTParser *)load->loader_priv;
    3124           5 :         if (!parser) {
    3125           0 :                 e = load_xmt_initialize(load, NULL);
    3126           0 :                 if (e) return e;
    3127           0 :                 parser = (GF_XMTParser *)load->loader_priv;
    3128           0 :                 if (!parser) return GF_OUT_OF_MEM;
    3129             :         }
    3130             : 
    3131           5 :         e = gf_xml_sax_parse_file(parser->sax_parser, (const char *)load->fileName, xmt_progress);
    3132           5 :         if (e==GF_OK) e = parser->last_error;
    3133             : 
    3134           5 :         xmt_resolve_routes(parser);
    3135           5 :         xmt_resolve_od_links(parser);
    3136             : 
    3137           5 :         parser->last_error=GF_OK;
    3138           5 :         if (e<0) return xmt_report(parser, e, "Invalid XML document: %s", gf_xml_sax_get_error(parser->sax_parser));
    3139             : 
    3140             :         return GF_OK;
    3141             : }
    3142             : 
    3143           0 : static GF_Err load_xmt_parse_string(GF_SceneLoader *load, const char *str)
    3144             : {
    3145             :         GF_Err e;
    3146           0 :         GF_XMTParser *parser = (GF_XMTParser *)load->loader_priv;
    3147           0 :         if (!parser) {
    3148           0 :                 return load_xmt_initialize(load, str);
    3149             :         }
    3150           0 :         e = gf_xml_sax_parse(parser->sax_parser, str);
    3151           0 :         if (e==GF_OK) e = parser->last_error;
    3152             : 
    3153           0 :         xmt_resolve_routes(parser);
    3154           0 :         xmt_resolve_od_links(parser);
    3155             : 
    3156           0 :         parser->last_error=GF_OK;
    3157           0 :         if (e<0) return xmt_report(parser, e, "Invalid XML document: %s", gf_xml_sax_get_error(parser->sax_parser));
    3158             :         return GF_OK;
    3159             : }
    3160             : 
    3161           6 : static void load_xmt_done(GF_SceneLoader *load)
    3162             : {
    3163           6 :         GF_XMTParser *parser = (GF_XMTParser *)load->loader_priv;
    3164           6 :         if (!parser) return;
    3165             : 
    3166           0 :         while (1) {
    3167           5 :                 XMTNodeStack *st = (XMTNodeStack *)gf_list_last(parser->nodes);
    3168           5 :                 if (!st) break;
    3169           0 :                 gf_list_rem_last(parser->nodes);
    3170           0 :                 gf_node_register(st->node, NULL);
    3171           0 :                 gf_node_unregister(st->node, NULL);
    3172           0 :                 gf_free(st);
    3173             :         }
    3174           5 :         if (parser->x3d_root) gf_free(parser->x3d_root);
    3175           5 :         gf_list_del(parser->nodes);
    3176           5 :         gf_list_del(parser->descriptors);
    3177           5 :         gf_list_del(parser->def_nodes);
    3178           5 :         gf_list_del(parser->peeked_nodes);
    3179             : 
    3180           5 :         gf_list_del(parser->inserted_routes);
    3181           5 :         gf_list_del(parser->unresolved_routes);
    3182           5 :         gf_list_del(parser->od_links);
    3183           5 :         gf_list_del(parser->esd_links);
    3184           5 :         gf_xml_sax_del(parser->sax_parser);
    3185           5 :         if (parser->script_to_load) gf_list_del(parser->script_to_load);
    3186           5 :         gf_free(parser);
    3187           5 :         load->loader_priv = NULL;
    3188             : }
    3189             : 
    3190           0 : static GF_Err load_xmt_suspend(GF_SceneLoader *load, Bool suspend)
    3191             : {
    3192           0 :         GF_XMTParser *parser = (GF_XMTParser *)load->loader_priv;
    3193           0 :         if (parser) gf_xml_sax_suspend(parser->sax_parser, suspend);
    3194           0 :         return GF_OK;
    3195             : }
    3196             : 
    3197             : 
    3198           5 : GF_Err gf_sm_load_init_xmt(GF_SceneLoader *load)
    3199             : {
    3200           5 :         load->process = load_xmt_run;
    3201           5 :         load->done = load_xmt_done;
    3202           5 :         load->parse_string = load_xmt_parse_string;
    3203           5 :         load->suspend = load_xmt_suspend;
    3204           5 :         if (load->fileName) return load_xmt_initialize(load, NULL);
    3205             :         return GF_OK;
    3206             : }
    3207             : 
    3208             : 
    3209             : #endif /*GPAC_DISABLE_LOADER_XMT*/

Generated by: LCOV version 1.13