LCOV - code coverage report
Current view: top level - scene_manager - loader_bt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1516 1993 76.1 %
Date: 2021-04-29 23:48:07 Functions: 43 47 91.5 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2019
       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/utf.h>
      28             : #include <gpac/constants.h>
      29             : #include <gpac/network.h>
      30             : #include <gpac/internal/bifs_dev.h>
      31             : #include <gpac/internal/scenegraph_dev.h>
      32             : 
      33             : #include <gpac/nodes_x3d.h>
      34             : /*for key codes...*/
      35             : #include <gpac/user.h>
      36             : #include <gpac/color.h>
      37             : 
      38             : 
      39             : #if !defined(GPAC_DISABLE_LOADER_BT) && !defined(GPAC_DISABLE_ZLIB)
      40             : 
      41             : #include <gpac/mpeg4_odf.h>
      42             : 
      43             : /*since 0.2.2, we use zlib for bt reading to handle wrl.gz files*/
      44             : #include <zlib.h>
      45             : 
      46             : void gf_sm_update_bitwrapper_buffer(GF_Node *node, const char *fileName);
      47             : 
      48             : void load_bt_done(GF_SceneLoader *load);
      49             : 
      50             : #define BT_LINE_SIZE    4000
      51             : 
      52             : typedef struct
      53             : {
      54             :         char *name;
      55             :         char *value;
      56             : } BTDefSymbol;
      57             : 
      58             : typedef struct
      59             : {
      60             :         GF_SceneLoader *load;
      61             :         Bool initialized;
      62             :         gzFile gz_in;
      63             :         u32 file_size, file_pos;
      64             : 
      65             :         /*create from string only*/
      66             :         GF_List *top_nodes;
      67             : 
      68             :         GF_Err last_error;
      69             :         u32 line;
      70             : 
      71             :         Bool done, in_com;
      72             :         u32 is_wrl;
      73             :         /*0: no unicode, 1: UTF-16BE, 2: UTF-16LE*/
      74             :         u32 unicode_type;
      75             : 
      76             :         GF_List *def_symbols;
      77             : 
      78             :         /*routes are not created in the graph when parsing, so we need to track insert and delete/replace*/
      79             :         GF_List *unresolved_routes, *inserted_routes, *peeked_nodes;
      80             :         GF_List *undef_nodes, *def_nodes;
      81             : 
      82             :         char *line_buffer;
      83             :         char cur_buffer[500];
      84             :         s32 line_size, line_pos, line_start_pos;
      85             : 
      86             :         u32 block_comment;
      87             : 
      88             :         /*set when parsing proto*/
      89             :         GF_Proto *parsing_proto;
      90             :         Bool is_extern_proto_field;
      91             : 
      92             :         /*current stream ID, AU time and RAP flag*/
      93             :         u32 stream_id;
      94             :         u32 au_time;
      95             :         Bool au_is_rap;
      96             : 
      97             :         /*current BIFS stream & AU*/
      98             :         GF_StreamContext *bifs_es;
      99             :         GF_AUContext *bifs_au;
     100             :         u32 base_bifs_id;
     101             :         GF_Command *cur_com;
     102             : 
     103             :         /*current OD stream & AU*/
     104             :         GF_StreamContext *od_es;
     105             :         GF_AUContext *od_au;
     106             :         u32 base_od_id;
     107             : 
     108             :         GF_List *scripts;
     109             : 
     110             :         u32 def_w, def_h;
     111             : 
     112             : } GF_BTParser;
     113             : 
     114             : GF_Err gf_bt_parse_bifs_command(GF_BTParser *parser, char *name, GF_List *cmdList);
     115             : GF_Route *gf_bt_parse_route(GF_BTParser *parser, Bool skip_def, Bool is_insert, GF_Command *com);
     116             : void gf_bt_resolve_routes(GF_BTParser *parser, Bool clean);
     117             : 
     118             : GF_Node *gf_bt_peek_node(GF_BTParser *parser, char *defID);
     119             : 
     120         433 : static GF_Err gf_bt_report(GF_BTParser *parser, GF_Err e, char *format, ...)
     121             : {
     122             : #ifndef GPAC_DISABLE_LOG
     123         433 :         if (format && gf_log_tool_level_on(GF_LOG_PARSER, e ? GF_LOG_ERROR : GF_LOG_WARNING)) {
     124             :                 char szMsg[2048];
     125             :                 va_list args;
     126           2 :                 va_start(args, format);
     127             :                 vsnprintf(szMsg, 2048, format, args);
     128           2 :                 va_end(args);
     129           2 :                 GF_LOG((u32) (e ? GF_LOG_ERROR : GF_LOG_WARNING), GF_LOG_PARSER, ("[BT/WRL Parsing] %s (line %d)\n", szMsg, parser->line));
     130             :         }
     131             : #endif
     132         433 :         if (e) parser->last_error = e;
     133         433 :         return e;
     134             : }
     135             : 
     136             : 
     137      644670 : void gf_bt_check_line(GF_BTParser *parser)
     138             : {
     139             :         while (1) {
     140     1001246 :                 switch (parser->line_buffer[parser->line_pos]) {
     141      178288 :                 case ' ':
     142             :                 case '\t':
     143             :                 case '\n':
     144             :                 case '\r':
     145      178288 :                         parser->line_pos++;
     146      178288 :                         continue;
     147             :                 default:
     148             :                         break;
     149             :                 }
     150             :                 break;
     151             :         }
     152             : 
     153      644670 :         if (parser->line_buffer[parser->line_pos]=='#') {
     154           1 :                 parser->line_size = parser->line_pos;
     155             :         }
     156      644669 :         else if ((parser->line_buffer[parser->line_pos]=='/') && (parser->line_buffer[parser->line_pos+1]=='/') ) parser->line_size = parser->line_pos;
     157             : 
     158      644670 :         if (parser->line_size == parser->line_pos) {
     159             :                 /*string based input - done*/
     160       80904 :                 if (!parser->gz_in) {
     161          14 :                         parser->done = 1;
     162          14 :                         return;
     163             :                 }
     164             : 
     165       80947 : next_line:
     166       81670 :                 parser->line_start_pos = (s32) gf_gztell(parser->gz_in);
     167       81670 :                 parser->line_buffer[0] = 0;
     168       81670 :                 if (parser->unicode_type) {
     169             :                         u8 c1, c2;
     170             :                         unsigned short wchar;
     171             :                         unsigned short l[BT_LINE_SIZE];
     172        4590 :                         unsigned short *dst = l;
     173             :                         Bool is_ret = 0;
     174             :                         u32 last_space_pos, last_space_pos_stream;
     175             :                         u32 go = BT_LINE_SIZE - 1;
     176             :                         last_space_pos = last_space_pos_stream = 0;
     177       93505 :                         while (go && !gf_gzeof(parser->gz_in) ) {
     178       88910 :                                 c1 = gf_gzgetc(parser->gz_in);
     179       88910 :                                 c2 = gf_gzgetc(parser->gz_in);
     180             :                                 /*Little-endian order*/
     181       88910 :                                 if (parser->unicode_type==2) {
     182       88910 :                                         if (c2) {
     183           5 :                                                 wchar = c2;
     184           5 :                                                 wchar <<=8;
     185           5 :                                                 wchar |= c1;
     186             :                                         }
     187       88905 :                                         else wchar = c1;
     188             :                                 } else {
     189           0 :                                         wchar = c1;
     190           0 :                                         if (c2) {
     191           0 :                                                 wchar <<= 8;
     192           0 :                                                 wchar |= c2;
     193             :                                         }
     194             :                                 }
     195       88910 :                                 *dst = wchar;
     196       88910 :                                 if (wchar=='\r') is_ret = 1;
     197       88910 :                                 else if (wchar=='\n') {
     198        4585 :                                         dst++;
     199        4585 :                                         break;
     200             :                                 }
     201       84325 :                                 else if (is_ret) {
     202           0 :                                         u32 fpos = (u32) gf_gztell(parser->gz_in);
     203           0 :                                         gf_gzseek(parser->gz_in, fpos-2, SEEK_SET);
     204           0 :                                         break;
     205             :                                 }
     206       84325 :                                 if (wchar==' ') {
     207             :                                         //last_space_pos_stream = (u32) gf_gztell(parser->gz_in);
     208       26550 :                                         last_space_pos = (u32) (dst - l);
     209             :                                 }
     210       84325 :                                 dst++;
     211       84325 :                                 go--;
     212             : 
     213             :                         }
     214        4590 :                         *dst = 0;
     215             :                         /*long line, rewind stream to last space*/
     216        4590 :                         if (!go) {
     217           0 :                                 u32 rew_pos = (u32)  (gf_gztell(parser->gz_in) - 2*(dst - &l[last_space_pos]) );
     218           0 :                                 gf_gzseek(parser->gz_in, rew_pos, SEEK_SET);
     219           0 :                                 l[last_space_pos+1] = 0;
     220             :                         }
     221             :                         /*check eof*/
     222        4590 :                         if (l[0]==0xFFFF) {
     223           5 :                                 parser->done = 1;
     224          10 :                                 return;
     225             :                         }
     226             :                         /*convert to mbc string*/
     227        4585 :                         dst = l;
     228        4585 :                         gf_utf8_wcstombs(parser->line_buffer, BT_LINE_SIZE, (const unsigned short **) &dst);
     229             : 
     230        4585 :                         if (!strlen(parser->line_buffer) && gf_gzeof(parser->gz_in)) {
     231           0 :                                 parser->done = 1;
     232           0 :                                 return;
     233             :                         }
     234             :                 } else {
     235       77080 :                         if ((gf_gzgets(parser->gz_in, parser->line_buffer, BT_LINE_SIZE) == NULL)
     236       76080 :                                 || (!strlen(parser->line_buffer) && gf_gzeof(parser->gz_in))) {
     237        1000 :                                 parser->done = 1;
     238        1000 :                                 return;
     239             :                         }
     240             :                         /*watchout for long lines*/
     241       76080 :                         if (1 + strlen(parser->line_buffer) == BT_LINE_SIZE) {
     242             :                                 u32 rew, pos, go;
     243             :                                 rew = 0;
     244             :                                 go = 1;
     245             :                                 while (go) {
     246           0 :                                         switch (parser->line_buffer[strlen(parser->line_buffer)-1]) {
     247             :                                         case ' ':
     248             :                                         case ',':
     249             :                                         case '[':
     250             :                                         case ']':
     251             :                                                 go = 0;
     252             :                                                 break;
     253           0 :                                         default:
     254           0 :                                                 parser->line_buffer[strlen(parser->line_buffer)-1] = 0;
     255           0 :                                                 rew++;
     256           0 :                                                 break;
     257             :                                         }
     258             :                                 }
     259           0 :                                 pos = (u32) gf_gztell(parser->gz_in);
     260           0 :                                 gf_gzseek(parser->gz_in, pos-rew, SEEK_SET);
     261             :                         }
     262             :                 }
     263             : 
     264             : 
     265       80811 :                 while (1) {
     266             :                         char c;
     267      161476 :                         u32 len = (u32) strlen(parser->line_buffer);
     268      161476 :                         if (!len) break;
     269      158880 :                         c = parser->line_buffer[len-1];
     270      158880 :                         if (!strchr("\n\r\t", c)) break;
     271       80811 :                         parser->line_buffer[len-1] = 0;
     272             :                 }
     273             : 
     274             : 
     275       80665 :                 parser->line_size = (u32) strlen(parser->line_buffer);
     276       80665 :                 parser->line_pos = 0;
     277       80665 :                 parser->line++;
     278             : 
     279             :                 {
     280       80665 :                         u32 pos = (u32) gf_gztell(parser->gz_in);
     281       80665 :                         if (pos>=parser->file_pos) {
     282       80561 :                                 parser->file_pos = pos;
     283       80561 :                                 if (parser->line>1) gf_set_progress("BT Parsing", pos, parser->file_size);
     284             :                         }
     285             :                 }
     286             : 
     287      475654 :                 while ((parser->line_buffer[parser->line_pos]==' ') || (parser->line_buffer[parser->line_pos]=='\t'))
     288      394989 :                         parser->line_pos++;
     289       80665 :                 if ( (parser->line_buffer[parser->line_pos]=='#')
     290       80033 :                         || ( (parser->line_buffer[parser->line_pos]=='/') && (parser->line_buffer[parser->line_pos+1]=='/')) ) {
     291             : 
     292         723 :                         if (parser->line==1) {
     293          60 :                                 if (strstr(parser->line_buffer, "VRML")) {
     294          10 :                                         if (strstr(parser->line_buffer, "VRML V2.0")) parser->is_wrl = 1;
     295             :                                         /*although not std, many files use this*/
     296           0 :                                         else if (strstr(parser->line_buffer, "VRML2.0")) parser->is_wrl = 1;
     297             :                                         else {
     298           0 :                                                 gf_bt_report(parser, GF_NOT_SUPPORTED, "%s: VRML Version Not Supported", parser->line_buffer);
     299           0 :                                                 return;
     300             :                                         }
     301             :                                 }
     302          50 :                                 else if (strstr(parser->line_buffer, "X3D")) {
     303          18 :                                         if (strstr(parser->line_buffer, "X3D V3.0")) parser->is_wrl = 2;
     304             :                                         else {
     305           0 :                                                 gf_bt_report(parser, GF_NOT_SUPPORTED, "%s: X3D Version Not Supported", parser->line_buffer);
     306           0 :                                                 return;
     307             :                                         }
     308             :                                 }
     309             :                         }
     310         723 :                         if (!strnicmp(parser->line_buffer+parser->line_pos, "#define ", 8) && !parser->block_comment) {
     311             :                                 char *buf, *sep;
     312          15 :                                 parser->line_pos+=8;
     313          15 :                                 buf = parser->line_buffer+parser->line_pos;
     314          15 :                                 sep = strchr(buf, ' ');
     315          15 :                                 if (sep && (sep[1]!='\n') ) {
     316             :                                         BTDefSymbol *def;
     317          15 :                                         GF_SAFEALLOC(def, BTDefSymbol);
     318          15 :                                         if (!def) {
     319           0 :                                                 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("Fail to allocate DEF node\n"));
     320             :                                                 return;
     321             :                                         }
     322          15 :                                         sep[0] = 0;
     323          15 :                                         def->name = gf_strdup(buf);
     324          15 :                                         sep[0] = ' ';
     325          15 :                                         buf = sep+1;
     326          15 :                                         while (strchr(" \t", buf[0])) buf++;
     327          15 :                                         def->value = gf_strdup(buf);
     328          15 :                                         gf_list_add(parser->def_symbols, def);
     329             :                                 }
     330             :                         }
     331         708 :                         else if (!strnicmp(parser->line_buffer+parser->line_pos, "#if ", 4)) {
     332             :                                 u32 len = 0;
     333          22 :                                 parser->line_pos+=4;
     334             :                                 while (1) {
     335         176 :                                         if (parser->line_pos+(s32)len==parser->line_size) break;
     336          77 :                                         if (strchr(" \n\t", parser->line_buffer[parser->line_pos+len]))
     337             :                                                 break;
     338          77 :                                         len++;
     339             :                                 }
     340          22 :                                 if (len) {
     341          22 :                                         if (len==1) {
     342          17 :                                                 if (!strnicmp(parser->line_buffer+parser->line_pos, "0", len)) {
     343          14 :                                                         parser->block_comment++;
     344             :                                                 }
     345             :                                         } else {
     346             :                                                 u32 i, count;
     347             :                                                 char *keyWord = NULL;
     348           5 :                                                 count = gf_list_count(parser->def_symbols);
     349          10 :                                                 for (i=0; i<count; i++) {
     350          10 :                                                         BTDefSymbol *def = (BTDefSymbol *)gf_list_get(parser->def_symbols, i);
     351          10 :                                                         if (!strnicmp(parser->line_buffer+parser->line_pos, def->name, len)) {
     352           5 :                                                                 keyWord = def->value;
     353           5 :                                                                 break;
     354             :                                                         }
     355             :                                                 }
     356           5 :                                                 if (keyWord && !strcmp(keyWord, "0")) {
     357           5 :                                                         parser->block_comment++;
     358             :                                                 }
     359             :                                         }
     360             :                                 }
     361             :                         }
     362         686 :                         else if (!strnicmp(parser->line_buffer+parser->line_pos, "#endif", 6)) {
     363          22 :                                 if (parser->block_comment) parser->block_comment--;
     364             :                         }
     365         664 :                         else if (!strnicmp(parser->line_buffer+parser->line_pos, "#else", 5)) {
     366          10 :                                 if (parser->block_comment)
     367          10 :                                         parser->block_comment--;
     368             :                                 else
     369           0 :                                         parser->block_comment++;
     370             :                         }
     371         654 :                         else if (!strnicmp(parser->line_buffer+parser->line_pos, "#size", 5)) {
     372             :                                 char *buf;
     373          39 :                                 parser->line_pos+=6;
     374          39 :                                 buf = parser->line_buffer+parser->line_pos;
     375          78 :                                 while (strchr(" \t", buf[0]))
     376           0 :                                         buf++;
     377          39 :                                 sscanf(buf, "%dx%d", &parser->def_w, &parser->def_h);
     378             :                         }
     379             :                         goto next_line;
     380             :                 }
     381             : 
     382       79942 :                 if (parser->block_comment)
     383             :                         goto next_line;
     384             : 
     385             :                 /*brute-force replacement of defined symbols (!!FIXME - no mem checking done !!)*/
     386       79885 :                 if (parser->line_pos < parser->line_size) {
     387             :                         u32 i, count;
     388       77215 :                         count = gf_list_count(parser->def_symbols);
     389             :                         while (1) {
     390             :                                 Bool found = 0;
     391       90245 :                                 for (i=0; i<count; i++) {
     392             :                                         u32 symb_len, val_len, copy_len;
     393       13020 :                                         BTDefSymbol *def = (BTDefSymbol *)gf_list_get(parser->def_symbols, i);
     394       13020 :                                         char *start = strstr(parser->line_buffer, def->name);
     395       13020 :                                         if (!start) continue;
     396          10 :                                         symb_len = (u32) strlen(def->name);
     397          10 :                                         if (!strchr(" \n\r\t,[]{}\'\"", start[symb_len])) continue;
     398          10 :                                         val_len = (u32) strlen(def->value);
     399          10 :                                         copy_len = (u32) strlen(start + symb_len) + 1;
     400          10 :                                         memmove(start + val_len, start + symb_len, sizeof(char)*copy_len);
     401          10 :                                         memcpy(start, def->value, sizeof(char)*val_len);
     402          10 :                                         parser->line_size = (u32) strlen(parser->line_buffer);
     403             :                                         found = 1;
     404             :                                 }
     405       77225 :                                 if (!found) break;
     406             :                         }
     407             :                 }
     408             :         }
     409      643651 :         if (!parser->line_size) {
     410        2596 :                 if (!gf_gzeof(parser->gz_in)) gf_bt_check_line(parser);
     411           0 :                 else parser->done = 1;
     412             :         }
     413      641055 :         else if (!parser->done && (parser->line_size == parser->line_pos)) gf_bt_check_line(parser);
     414             : }
     415             : 
     416           0 : void gf_bt_force_line(GF_BTParser *parser)
     417             : {
     418           5 :         parser->line_pos = parser->line_size;
     419           0 : }
     420             : 
     421           0 : Bool gf_bt_check_code(GF_BTParser *parser, char code)
     422             : {
     423      437016 :         gf_bt_check_line(parser);
     424      437016 :         if (parser->line_buffer[parser->line_pos]==code) {
     425      124446 :                 parser->line_pos++;
     426           0 :                 return 1;
     427             :         }
     428             :         return 0;
     429             : }
     430             : 
     431      201243 : char *gf_bt_get_next(GF_BTParser *parser, Bool point_break)
     432             : {
     433             :         u32 has_quote;
     434             :         Bool go = 1;
     435             :         s32 i;
     436      201243 :         gf_bt_check_line(parser);
     437             :         i=0;
     438             :         has_quote = 0;
     439      201243 :         while (go) {
     440     1184980 :                 if (parser->line_buffer[parser->line_pos + i] == '\"') {
     441         515 :                         if (!has_quote) has_quote = 1;
     442             :                         else has_quote = 0;
     443         515 :                         parser->line_pos += 1;
     444             : 
     445         515 :                         if (parser->line_pos+i==parser->line_size) break;
     446         296 :                         continue;
     447             :                 }
     448     1184465 :                 if (!has_quote) {
     449     1178641 :                         switch (parser->line_buffer[parser->line_pos + i]) {
     450             :                         case 0:
     451             :                         case ' ':
     452             :                         case '\t':
     453             :                         case '\r':
     454             :                         case '\n':
     455             :                         case '{':
     456             :                         case '}':
     457             :                         case ']':
     458             :                         case '[':
     459             :                         case ',':
     460             :                                 go = 0;
     461             :                                 break;
     462       28930 :                         case '.':
     463       28930 :                                 if (point_break) go = 0;
     464             :                                 break;
     465             :                         }
     466             :                         if (!go) break;
     467             :                 }
     468     1003441 :                 parser->cur_buffer[i] = parser->line_buffer[parser->line_pos + i];
     469     1003441 :                 i++;
     470     1003441 :                 if (parser->line_pos+i==parser->line_size) break;
     471             :         }
     472      201243 :         parser->cur_buffer[i] = 0;
     473      201243 :         parser->line_pos += i;
     474      201243 :         return parser->cur_buffer;
     475             : }
     476             : 
     477        5724 : char *gf_bt_get_string(GF_BTParser *parser, u8 string_delim)
     478             : {
     479             :         char *res;
     480             :         s32 i, size;
     481             : 
     482             : #define BT_STR_CHECK_ALLOC      \
     483             :                 if (i==size) {          \
     484             :                         res = (char*)gf_realloc(res, sizeof(char) * (size+500+1));      \
     485             :                         size += 500;    \
     486             :                 }       \
     487             : 
     488        5724 :         res = (char*)gf_malloc(sizeof(char) * 500);
     489             :         size = 500;
     490        5724 :         while (parser->line_buffer[parser->line_pos]==' ') parser->line_pos++;
     491             : 
     492        5724 :         if (parser->line_pos==parser->line_size) {
     493           0 :                 if (gf_gzeof(parser->gz_in)) return NULL;
     494           0 :                 gf_bt_check_line(parser);
     495             :         }
     496        5724 :         if (!string_delim) string_delim = '"';
     497             : 
     498             :         i=0;
     499             :         while (1) {
     500      184691 :                 if (parser->line_buffer[parser->line_pos] == string_delim)
     501        5732 :                         if ( !parser->line_pos || (parser->line_buffer[parser->line_pos-1] != '\\') ) break;
     502             : 
     503      178967 :                 BT_STR_CHECK_ALLOC
     504             : 
     505      178967 :                 if ((parser->line_buffer[parser->line_pos]=='/') && (parser->line_buffer[parser->line_pos+1]=='/') && (parser->line_buffer[parser->line_pos-1]!=':') ) {
     506             :                         /*this looks like a comment*/
     507          11 :                         if (!strchr(&parser->line_buffer[parser->line_pos], string_delim)) {
     508          11 :                                 gf_bt_check_line(parser);
     509          11 :                                 continue;
     510             :                         }
     511             :                 }
     512      178956 :                 if ((parser->line_buffer[parser->line_pos] != '\\') || (parser->line_buffer[parser->line_pos+1] != string_delim)) {
     513             :                         /*handle UTF-8 - WARNING: if parser is in unicode string is already utf8 multibyte chars*/
     514      178948 :                         if (!parser->unicode_type && parser->line_buffer[parser->line_pos] & 0x80) {
     515             :                                 char c = parser->line_buffer[parser->line_pos];
     516             :                                 /*non UTF8 (likely some win-CP)*/
     517          23 :                                 if ( (parser->line_buffer[parser->line_pos+1] & 0xc0) != 0x80) {
     518          23 :                                         res[i] = 0xc0 | ( (parser->line_buffer[parser->line_pos] >> 6) & 0x3 );
     519          23 :                                         i++;
     520          23 :                                         BT_STR_CHECK_ALLOC
     521          23 :                                         parser->line_buffer[parser->line_pos] &= 0xbf;
     522             :                                 }
     523             :                                 /*UTF8 2 bytes char*/
     524           0 :                                 else if ( (c & 0xe0) == 0xc0) {
     525           0 :                                         res[i] = parser->line_buffer[parser->line_pos];
     526           0 :                                         parser->line_pos++;
     527           0 :                                         i++;
     528           0 :                                         BT_STR_CHECK_ALLOC
     529             :                                 }
     530             :                                 /*UTF8 3 bytes char*/
     531           0 :                                 else if ( (c & 0xf0) == 0xe0) {
     532           0 :                                         res[i] = parser->line_buffer[parser->line_pos];
     533           0 :                                         parser->line_pos++;
     534           0 :                                         i++;
     535           0 :                                         BT_STR_CHECK_ALLOC
     536           0 :                                         res[i] = parser->line_buffer[parser->line_pos];
     537           0 :                                         parser->line_pos++;
     538           0 :                                         i++;
     539           0 :                                         BT_STR_CHECK_ALLOC
     540             :                                 }
     541             :                                 /*UTF8 4 bytes char*/
     542           0 :                                 else if ( (c & 0xf8) == 0xf0) {
     543           0 :                                         res[i] = parser->line_buffer[parser->line_pos];
     544           0 :                                         parser->line_pos++;
     545           0 :                                         i++;
     546           0 :                                         BT_STR_CHECK_ALLOC
     547           0 :                                         res[i] = parser->line_buffer[parser->line_pos];
     548           0 :                                         parser->line_pos++;
     549           0 :                                         i++;
     550           0 :                                         BT_STR_CHECK_ALLOC
     551           0 :                                         res[i] = parser->line_buffer[parser->line_pos];
     552           0 :                                         parser->line_pos++;
     553           0 :                                         i++;
     554           0 :                                         BT_STR_CHECK_ALLOC
     555             :                                 }
     556             :                         }
     557             : 
     558      178948 :                         res[i] = parser->line_buffer[parser->line_pos];
     559      178948 :                         i++;
     560             :                 }
     561      178956 :                 parser->line_pos++;
     562      178956 :                 if (parser->line_pos==parser->line_size) {
     563        2124 :                         gf_bt_check_line(parser);
     564             :                 }
     565             : 
     566             :         }
     567             : 
     568             : #undef  BT_STR_CHECK_ALLOC
     569             : 
     570        5724 :         res[i] = 0;
     571        5724 :         parser->line_pos += 1;
     572        5724 :         return res;
     573             : }
     574             : 
     575      113386 : Bool gf_bt_check_externproto_field(GF_BTParser *parser, char *str)
     576             : {
     577      113386 :         if (!parser->is_extern_proto_field) return 0;
     578         217 :         if (!strcmp(str, "") || !strcmp(str, "field") || !strcmp(str, "eventIn") || !strcmp(str, "eventOut") || !strcmp(str, "exposedField")) {
     579           0 :                 parser->last_error = GF_EOS;
     580           0 :                 return 1;
     581             :         }
     582             :         return 0;
     583             : }
     584             : 
     585      108976 : static Bool check_keyword(GF_BTParser *parser, char *str, s32 *val)
     586             : {
     587             :         s32 res;
     588             :         char *sep;
     589      108976 :         sep = strchr(str, '$');
     590      108976 :         if (!sep) return 0;
     591           0 :         sep++;
     592           0 :         if (!strcmp(sep, "F1")) res = GF_KEY_F1;
     593           0 :         else if (!strcmp(sep, "F2")) res = GF_KEY_F2;
     594           0 :         else if (!strcmp(sep, "F3")) res = GF_KEY_F3;
     595           0 :         else if (!strcmp(sep, "F4")) res = GF_KEY_F4;
     596           0 :         else if (!strcmp(sep, "F5")) res = GF_KEY_F5;
     597           0 :         else if (!strcmp(sep, "F6")) res = GF_KEY_F6;
     598           0 :         else if (!strcmp(sep, "F7")) res = GF_KEY_F7;
     599           0 :         else if (!strcmp(sep, "F8")) res = GF_KEY_F8;
     600           0 :         else if (!strcmp(sep, "F9")) res = GF_KEY_F9;
     601           0 :         else if (!strcmp(sep, "F10")) res = GF_KEY_F10;
     602           0 :         else if (!strcmp(sep, "F11")) res = GF_KEY_F11;
     603           0 :         else if (!strcmp(sep, "F12")) res = GF_KEY_F12;
     604           0 :         else if (!strcmp(sep, "HOME")) res = GF_KEY_HOME;
     605           0 :         else if (!strcmp(sep, "END")) res = GF_KEY_END;
     606           0 :         else if (!strcmp(sep, "PREV")) res = GF_KEY_PAGEUP;
     607           0 :         else if (!strcmp(sep, "NEXT")) res = GF_KEY_PAGEDOWN;
     608           0 :         else if (!strcmp(sep, "UP")) res = GF_KEY_UP;
     609           0 :         else if (!strcmp(sep, "DOWN")) res = GF_KEY_DOWN;
     610           0 :         else if (!strcmp(sep, "LEFT")) res = GF_KEY_LEFT;
     611           0 :         else if (!strcmp(sep, "RIGHT")) res = GF_KEY_RIGHT;
     612           0 :         else if (!strcmp(sep, "RETURN")) res = GF_KEY_ENTER;
     613           0 :         else if (!strcmp(sep, "BACK")) res = GF_KEY_BACKSPACE;
     614           0 :         else if (!strcmp(sep, "TAB")) res = GF_KEY_TAB;
     615           0 :         else if (strlen(sep)==1) {
     616             :                 char c;
     617           0 :                 sscanf(sep, "%c", &c);
     618           0 :                 res = c;
     619             :         } else {
     620           0 :                 gf_bt_report(parser, GF_OK, "unrecognized keyword %s - skipping", str);
     621             :                 res = 0;
     622             :         }
     623           0 :         if (strchr(str, '-')) *val = -res;
     624           0 :         else *val = res;
     625             :         return 1;
     626             : }
     627             : 
     628       49563 : GF_Err gf_bt_parse_float(GF_BTParser *parser, const char *name, Fixed *val)
     629             : {
     630             :         s32 var;
     631             :         Float f;
     632       49563 :         char *str = gf_bt_get_next(parser, 0);
     633       49563 :         if (!str) return parser->last_error = GF_IO_ERR;
     634       49563 :         if (gf_bt_check_externproto_field(parser, str)) return GF_OK;
     635             : 
     636       49563 :         if (check_keyword(parser, str, &var)) {
     637           0 :                 *val = INT2FIX(var);
     638           0 :                 return GF_OK;
     639             :         }
     640       49563 :         if (sscanf(str, "%g", &f) != 1) {
     641           0 :                 return gf_bt_report(parser, GF_BAD_PARAM, "%s: Number expected", name);
     642             :         }
     643       49563 :         *val = FLT2FIX(f);
     644       49563 :         return GF_OK;
     645             : }
     646         205 : GF_Err gf_bt_parse_double(GF_BTParser *parser, const char *name, SFDouble *val)
     647             : {
     648         205 :         char *str = gf_bt_get_next(parser, 0);
     649         205 :         if (!str) return parser->last_error = GF_IO_ERR;
     650         205 :         if (gf_bt_check_externproto_field(parser, str)) return GF_OK;
     651         205 :         if (sscanf(str, "%lf", val) != 1) {
     652           0 :                 return gf_bt_report(parser, GF_BAD_PARAM, "%s: Number expected", name);
     653             :         }
     654             :         return GF_OK;
     655             : }
     656       59413 : GF_Err gf_bt_parse_int(GF_BTParser *parser, const char *name, SFInt32 *val)
     657             : {
     658       59413 :         char *str = gf_bt_get_next(parser, 0);
     659       59413 :         if (!str) return parser->last_error = GF_IO_ERR;
     660       59413 :         if (gf_bt_check_externproto_field(parser, str)) return GF_OK;
     661             : 
     662       59413 :         if (check_keyword(parser, str, val)) return GF_OK;
     663             :         /*URL ODID*/
     664       59413 :         if (!strnicmp(str, "od:", 3)) str += 3;
     665       59413 :         if (sscanf(str, "%d", val) != 1) {
     666           0 :                 return gf_bt_report(parser, GF_BAD_PARAM, "%s: Number expected", name);
     667             :         }
     668             :         return GF_OK;
     669             : }
     670        1964 : GF_Err gf_bt_parse_bool(GF_BTParser *parser, const char *name, SFBool *val)
     671             : {
     672        1964 :         char *str = gf_bt_get_next(parser, 0);
     673        1964 :         if (!str) return parser->last_error = GF_IO_ERR;
     674        1964 :         if (gf_bt_check_externproto_field(parser, str)) return GF_OK;
     675             : 
     676        1964 :         if (!stricmp(str, "true") || !strcmp(str, "1") ) {
     677        1343 :                 *val = 1;
     678             :         }
     679         621 :         else if (!stricmp(str, "false") || !strcmp(str, "0") ) {
     680         621 :                 *val = 0;
     681             :         } else {
     682           0 :                 return gf_bt_report(parser, GF_BAD_PARAM, "%s: Boolean expected", name);
     683             :         }
     684             :         return GF_OK;
     685             : }
     686             : 
     687        2233 : GF_Err gf_bt_parse_color(GF_BTParser *parser, const char *name, SFColor *col)
     688             : {
     689             :         Float f;
     690             :         u32 val;
     691        2233 :         char *str = gf_bt_get_next(parser, 0);
     692        2233 :         if (!str) return parser->last_error = GF_IO_ERR;
     693        2233 :         if (gf_bt_check_externproto_field(parser, str)) return GF_OK;
     694             : 
     695        2233 :         if (sscanf(str, "%f", &f) == 1) {
     696        2220 :                 col->red = FLT2FIX(f);
     697             :                 /*many VRML files use ',' separator*/
     698             :                 gf_bt_check_code(parser, ',');
     699        2220 :                 gf_bt_parse_float(parser, name, & col->green);
     700             :                 gf_bt_check_code(parser, ',');
     701        2220 :                 gf_bt_parse_float(parser, name, & col->blue);
     702        2220 :                 return parser->last_error;
     703             :         }
     704          13 :         val = gf_color_parse(str);
     705          13 :         if (!val) {
     706           0 :                 return gf_bt_report(parser, GF_BAD_PARAM, "%s: Number or name expected", name);
     707             :         }
     708          13 :         col->red = INT2FIX((val>>16) & 0xFF) / 255;
     709          13 :         col->green = INT2FIX((val>>8) & 0xFF) / 255;
     710          13 :         col->blue = INT2FIX(val & 0xFF) / 255;
     711          13 :         return parser->last_error;
     712             : }
     713             : 
     714           8 : GF_Err gf_bt_parse_colorRGBA(GF_BTParser *parser, const char *name, SFColorRGBA *col)
     715             : {
     716             :         Float f;
     717           8 :         char *str = gf_bt_get_next(parser, 0);
     718           8 :         if (!str) return parser->last_error = GF_IO_ERR;
     719           8 :         if (gf_bt_check_externproto_field(parser, str)) return GF_OK;
     720             : 
     721             :         /*HTML code*/
     722           8 :         if (str[0]=='$') {
     723             :                 u32 val;
     724           0 :                 sscanf(str, "%x", &val);
     725           0 :                 col->red = INT2FIX((val>>24) & 0xFF) / 255;
     726           0 :                 col->green = INT2FIX((val>>16) & 0xFF) / 255;
     727           0 :                 col->blue = INT2FIX((val>>8) & 0xFF) / 255;
     728           0 :                 col->alpha = INT2FIX(val & 0xFF) / 255;
     729           0 :                 return parser->last_error;
     730             :         }
     731           8 :         if (sscanf(str, "%f", &f) != 1) {
     732           0 :                 return gf_bt_report(parser, GF_BAD_PARAM, "%s: Number expected", name);
     733             :         }
     734           8 :         col->red = FLT2FIX(f);
     735             :         gf_bt_check_code(parser, ',');
     736           8 :         gf_bt_parse_float(parser, name, & col->green);
     737             :         gf_bt_check_code(parser, ',');
     738           8 :         gf_bt_parse_float(parser, name, & col->blue);
     739             :         gf_bt_check_code(parser, ',');
     740           8 :         gf_bt_parse_float(parser, name, & col->alpha);
     741           8 :         return parser->last_error;
     742             : }
     743             : 
     744             : static void gf_bt_offset_time(GF_BTParser *parser, Double *time)
     745             : {
     746         418 :         if (!parser->is_wrl) {
     747             :                 Double res;
     748         418 :                 res = parser->au_time;
     749         418 :                 res /= parser->bifs_es->timeScale;
     750         418 :                 *time += res;
     751             :         }
     752             : }
     753             : 
     754         223 : static void gf_bt_check_time_offset(GF_BTParser *parser, GF_Node *n, GF_FieldInfo *info)
     755             : {
     756         223 :         if (!n || !(parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK)) return;
     757         206 :         if (gf_node_get_tag(n) != TAG_ProtoNode) {
     758         175 :                 if (!stricmp(info->name, "startTime") || !stricmp(info->name, "stopTime"))
     759          54 :                         gf_bt_offset_time(parser, (Double *)info->far_ptr);
     760          31 :         } else if (gf_sg_proto_field_is_sftime_offset(n, info)) {
     761          10 :                 gf_bt_offset_time(parser, (Double *)info->far_ptr);
     762             :         }
     763             : }
     764       14112 : static void gf_bt_update_timenode(GF_BTParser *parser, GF_Node *node)
     765             : {
     766       14112 :         if (!node || !(parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK)) return;
     767             : 
     768       12456 :         switch (gf_node_get_tag(node)) {
     769           7 :         case TAG_MPEG4_AnimationStream:
     770             :                 gf_bt_offset_time(parser, & ((M_AnimationStream*)node)->startTime);
     771             :                 gf_bt_offset_time(parser, & ((M_AnimationStream*)node)->stopTime);
     772             :                 break;
     773           2 :         case TAG_MPEG4_AudioBuffer:
     774             :                 gf_bt_offset_time(parser, & ((M_AudioBuffer*)node)->startTime);
     775             :                 gf_bt_offset_time(parser, & ((M_AudioBuffer*)node)->stopTime);
     776             :                 break;
     777           6 :         case TAG_MPEG4_AudioClip:
     778             :                 gf_bt_offset_time(parser, & ((M_AudioClip*)node)->startTime);
     779             :                 gf_bt_offset_time(parser, & ((M_AudioClip*)node)->stopTime);
     780             :                 break;
     781           7 :         case TAG_MPEG4_AudioSource:
     782             :                 gf_bt_offset_time(parser, & ((M_AudioSource*)node)->startTime);
     783             :                 gf_bt_offset_time(parser, & ((M_AudioSource*)node)->stopTime);
     784             :                 break;
     785          35 :         case TAG_MPEG4_MovieTexture:
     786             :                 gf_bt_offset_time(parser, & ((M_MovieTexture*)node)->startTime);
     787             :                 gf_bt_offset_time(parser, & ((M_MovieTexture*)node)->stopTime);
     788             :                 break;
     789         120 :         case TAG_MPEG4_TimeSensor:
     790             :                 gf_bt_offset_time(parser, & ((M_TimeSensor*)node)->startTime);
     791             :                 gf_bt_offset_time(parser, & ((M_TimeSensor*)node)->stopTime);
     792             :                 break;
     793          74 :         case TAG_ProtoNode:
     794             :         {
     795             :                 u32 i, nbFields;
     796             :                 GF_FieldInfo inf;
     797          74 :                 nbFields = gf_node_get_num_fields_in_mode(node, GF_SG_FIELD_CODING_ALL);
     798         436 :                 for (i=0; i<nbFields; i++) {
     799         362 :                         gf_node_get_field(node, i, &inf);
     800         362 :                         if (inf.fieldType != GF_SG_VRML_SFTIME) continue;
     801          18 :                         gf_bt_check_time_offset(parser, node, &inf);
     802             :                 }
     803             :         }
     804          74 :         break;
     805             :         }
     806             : }
     807             : 
     808             : 
     809       90648 : void gf_bt_sffield(GF_BTParser *parser, GF_FieldInfo *info, GF_Node *n)
     810             : {
     811       90648 :         switch (info->fieldType) {
     812       59032 :         case GF_SG_VRML_SFINT32:
     813       59032 :                 gf_bt_parse_int(parser, info->name, (SFInt32 *)info->far_ptr);
     814       59032 :                 if (parser->last_error) return;
     815             :                 break;
     816        1964 :         case GF_SG_VRML_SFBOOL:
     817        1964 :                 gf_bt_parse_bool(parser, info->name, (SFBool *)info->far_ptr);
     818        1964 :                 if (parser->last_error) return;
     819             :                 break;
     820        4654 :         case GF_SG_VRML_SFFLOAT:
     821        4654 :                 gf_bt_parse_float(parser, info->name, (SFFloat *)info->far_ptr);
     822        4654 :                 if (parser->last_error) return;
     823             :                 break;
     824           0 :         case GF_SG_VRML_SFDOUBLE:
     825           0 :                 gf_bt_parse_double(parser, info->name, (SFDouble *)info->far_ptr);
     826           0 :                 if (parser->last_error) return;
     827             :                 break;
     828         205 :         case GF_SG_VRML_SFTIME:
     829         205 :                 gf_bt_parse_double(parser, info->name, (SFDouble *)info->far_ptr);
     830         205 :                 if (parser->last_error) return;
     831         205 :                 gf_bt_check_time_offset(parser, n, info);
     832         205 :                 break;
     833        2233 :         case GF_SG_VRML_SFCOLOR:
     834        2233 :                 gf_bt_parse_color(parser, info->name, (SFColor *)info->far_ptr);
     835        2233 :                 break;
     836           8 :         case GF_SG_VRML_SFCOLORRGBA:
     837           8 :                 gf_bt_parse_colorRGBA(parser, info->name, (SFColorRGBA *)info->far_ptr);
     838           8 :                 break;
     839        7935 :         case GF_SG_VRML_SFVEC2F:
     840        7935 :                 gf_bt_parse_float(parser, info->name, & ((SFVec2f *)info->far_ptr)->x);
     841        7935 :                 if (parser->last_error) return;
     842             :                 /*many VRML files use ',' separator*/
     843             :                 gf_bt_check_code(parser, ',');
     844        7935 :                 gf_bt_parse_float(parser, info->name, & ((SFVec2f *)info->far_ptr)->y);
     845        7935 :                 if (parser->last_error) return;
     846             :                 break;
     847           0 :         case GF_SG_VRML_SFVEC2D:
     848           0 :                 gf_bt_parse_double(parser, info->name, & ((SFVec2d *)info->far_ptr)->x);
     849           0 :                 if (parser->last_error) return;
     850             :                 /*many VRML files use ',' separator*/
     851             :                 gf_bt_check_code(parser, ',');
     852           0 :                 gf_bt_parse_double(parser, info->name, & ((SFVec2d *)info->far_ptr)->y);
     853           0 :                 if (parser->last_error) return;
     854             :                 break;
     855        8027 :         case GF_SG_VRML_SFVEC3F:
     856        8027 :                 gf_bt_parse_float(parser, info->name, & ((SFVec3f *)info->far_ptr)->x);
     857        8027 :                 if (parser->last_error) return;
     858             :                 /*many VRML files use ',' separator*/
     859             :                 gf_bt_check_code(parser, ',');
     860        8027 :                 gf_bt_parse_float(parser, info->name, & ((SFVec3f *)info->far_ptr)->y);
     861        8027 :                 if (parser->last_error) return;
     862             :                 /*many VRML files use ',' separator*/
     863             :                 gf_bt_check_code(parser, ',');
     864        8027 :                 gf_bt_parse_float(parser, info->name, & ((SFVec3f *)info->far_ptr)->z);
     865        8027 :                 if (parser->last_error) return;
     866             :                 break;
     867           0 :         case GF_SG_VRML_SFVEC3D:
     868           0 :                 gf_bt_parse_double(parser, info->name, & ((SFVec3d *)info->far_ptr)->x);
     869           0 :                 if (parser->last_error) return;
     870             :                 /*many VRML files use ',' separator*/
     871             :                 gf_bt_check_code(parser, ',');
     872           0 :                 gf_bt_parse_double(parser, info->name, & ((SFVec3d *)info->far_ptr)->y);
     873           0 :                 if (parser->last_error) return;
     874             :                 /*many VRML files use ',' separator*/
     875             :                 gf_bt_check_code(parser, ',');
     876           0 :                 gf_bt_parse_double(parser, info->name, & ((SFVec3d *)info->far_ptr)->z);
     877           0 :                 if (parser->last_error) return;
     878             :                 break;
     879           6 :         case GF_SG_VRML_SFVEC4F:
     880           6 :                 gf_bt_parse_float(parser, info->name, & ((SFVec4f *)info->far_ptr)->x);
     881           6 :                 if (parser->last_error) return;
     882             :                 /*many VRML files use ',' separator*/
     883             :                 gf_bt_check_code(parser, ',');
     884           6 :                 gf_bt_parse_float(parser, info->name, & ((SFVec4f *)info->far_ptr)->y);
     885           6 :                 if (parser->last_error) return;
     886             :                 /*many VRML files use ',' separator*/
     887             :                 gf_bt_check_code(parser, ',');
     888           6 :                 gf_bt_parse_float(parser, info->name, & ((SFVec4f *)info->far_ptr)->z);
     889           6 :                 if (parser->last_error) return;
     890             :                 /*many VRML files use ',' separator*/
     891             :                 gf_bt_check_code(parser, ',');
     892           6 :                 gf_bt_parse_float(parser, info->name, & ((SFVec4f *)info->far_ptr)->q);
     893           6 :                 if (parser->last_error) return;
     894             :                 break;
     895         116 :         case GF_SG_VRML_SFROTATION:
     896         116 :                 gf_bt_parse_float(parser, info->name, & ((SFRotation *)info->far_ptr)->x);
     897         116 :                 if (parser->last_error) return;
     898         116 :                 gf_bt_parse_float(parser, info->name, & ((SFRotation *)info->far_ptr)->y);
     899         116 :                 if (parser->last_error) return;
     900         116 :                 gf_bt_parse_float(parser, info->name, & ((SFRotation *)info->far_ptr)->z);
     901         116 :                 if (parser->last_error) return;
     902         116 :                 gf_bt_parse_float(parser, info->name, & ((SFRotation *)info->far_ptr)->q);
     903         116 :                 if (parser->last_error) return;
     904             :                 break;
     905        5519 :         case GF_SG_VRML_SFSTRING:
     906             :         {
     907             :                 u8 delim = 0;
     908             :                 if (gf_bt_check_code(parser, '\"')) delim = '\"';
     909             :                 else if (gf_bt_check_code(parser, '\'')) delim = '\'';
     910             :                 if (delim) {
     911        5519 :                         char *str = gf_bt_get_string(parser, delim);
     912        5519 :                         if (!str)
     913             :                                 goto err;
     914        5519 :                         if (((SFString *)info->far_ptr)->buffer) gf_free(((SFString *)info->far_ptr)->buffer);
     915        5519 :                         ((SFString *)info->far_ptr)->buffer = NULL;
     916        5519 :                         if (strlen(str))
     917        5089 :                                 ((SFString *)info->far_ptr)->buffer = str;
     918             :                         else
     919         430 :                                 gf_free(str);
     920             : 
     921        5519 :                         if (n && (n->sgprivate->tag==TAG_MPEG4_BitWrapper)) {
     922          15 :                                 gf_sm_update_bitwrapper_buffer(n, parser->load->fileName);
     923             :                         }
     924             :                 } else {
     925             :                         goto err;
     926             :                 }
     927             :         }
     928             :         break;
     929         334 :         case GF_SG_VRML_SFURL:
     930             :         {
     931             :                 u8 delim = 0;
     932             :                 if (gf_bt_check_code(parser, '\"')) delim = '\"';
     933             :                 else if (gf_bt_check_code(parser, '\'')) delim = '\'';
     934             :                 if (delim) {
     935         160 :                         SFURL *url = (SFURL *)info->far_ptr;
     936         160 :                         char *str = gf_bt_get_string(parser, delim);
     937         160 :                         if (!str) goto err;
     938         160 :                         if (url->url) gf_free(url->url);
     939         160 :                         url->url = NULL;
     940         160 :                         url->OD_ID = 0;
     941         160 :                         if (strchr(str, '#')) {
     942          13 :                                 url->url = str;
     943             :                         } else {
     944         147 :                                 u32 id = 0;
     945             :                                 char *odstr = str;
     946         147 :                                 if (!strnicmp(str, "od://", 5)) odstr += 5;
     947         147 :                                 else if (!strnicmp(str, "od:", 3)) odstr += 3;
     948             :                                 /*be careful, an url like "11-regression-test.mp4" will return 1 on sscanf :)*/
     949         147 :                                 if (sscanf(odstr, "%u", &id) == 1) {
     950             :                                         char szURL[20];
     951          39 :                                         sprintf(szURL, "%u", id);
     952          39 :                                         if (strcmp(szURL, odstr)) id=0;
     953             :                                 }
     954         147 :                                 if (id) {
     955          39 :                                         url->OD_ID = id;
     956          39 :                                         gf_free(str);
     957             :                                 } else {
     958         108 :                                         url->url = str;
     959             :                                 }
     960             :                         }
     961             :                 } else {
     962             :                         s32 val;
     963         174 :                         gf_bt_parse_int(parser, info->name, & val );
     964         174 :                         if (parser->last_error) return;
     965         174 :                         ((SFURL *)info->far_ptr)->OD_ID = val;
     966             :                 }
     967             :         }
     968             :         break;
     969         554 :         case GF_SG_VRML_SFCOMMANDBUFFER:
     970             :         {
     971         554 :                 SFCommandBuffer *cb = (SFCommandBuffer *)info->far_ptr;
     972             :                 if (gf_bt_check_code(parser, '{')) {
     973         554 :                         GF_Command *prev_com = parser->cur_com;
     974        1844 :                         while (!parser->last_error) {
     975             :                                 if (gf_bt_check_code(parser, '}')) break;
     976         736 :                                 parser->last_error = gf_bt_parse_bifs_command(parser, NULL, cb->commandList);
     977             :                         }
     978         554 :                         parser->cur_com = prev_com;
     979             :                 }
     980             :         }
     981             :         break;
     982          14 :         case GF_SG_VRML_SFIMAGE:
     983             :         {
     984             :                 u32 i, size, v;
     985          14 :                 SFImage *img = (SFImage *)info->far_ptr;
     986          14 :                 gf_bt_parse_int(parser, "width", (SFInt32 *)&img->width);
     987          14 :                 if (parser->last_error) return;
     988          14 :                 gf_bt_parse_int(parser, "height", (SFInt32 *)&img->height);
     989          14 :                 if (parser->last_error) return;
     990          14 :                 gf_bt_parse_int(parser, "nbComp", (SFInt32 *)&v);
     991          14 :                 if (parser->last_error) return;
     992          14 :                 img->numComponents = v;
     993          14 :                 size = img->width * img->height * img->numComponents;
     994          14 :                 if (img->pixels) gf_free(img->pixels);
     995          14 :                 img->pixels = (unsigned char*)gf_malloc(sizeof(char) * size);
     996         238 :                 for (i=0; i<size; i++) {
     997         224 :                         char *str = gf_bt_get_next(parser, 0);
     998         224 :                         if (strstr(str, "0x")) sscanf(str, "%x", &v);
     999           0 :                         else sscanf(str, "%u", &v);
    1000         224 :                         switch (img->numComponents) {
    1001         176 :                         case 1:
    1002         176 :                                 img->pixels[i] = (char) v;
    1003         176 :                                 break;
    1004          16 :                         case 2:
    1005          16 :                                 img->pixels[i] = (char) (v>>8)&0xFF;
    1006          16 :                                 img->pixels[i+1] = (char) (v)&0xFF;
    1007             :                                 i++;
    1008          16 :                                 break;
    1009          16 :                         case 3:
    1010          16 :                                 img->pixels[i] = (char) (v>>16)&0xFF;
    1011          16 :                                 img->pixels[i+1] = (char) (v>>8)&0xFF;
    1012          16 :                                 img->pixels[i+2] = (char) (v)&0xFF;
    1013             :                                 i+=2;
    1014          16 :                                 break;
    1015          16 :                         case 4:
    1016          16 :                                 img->pixels[i] = (char) (v>>24)&0xFF;
    1017          16 :                                 img->pixels[i+1] = (char) (v>>16)&0xFF;
    1018          16 :                                 img->pixels[i+2] = (char) (v>>8)&0xFF;
    1019          16 :                                 img->pixels[i+3] = (char) (v)&0xFF;
    1020             :                                 i+=3;
    1021          16 :                                 break;
    1022             :                         }
    1023             :                 }
    1024             :         }
    1025          14 :         break;
    1026          45 :         case GF_SG_VRML_SFSCRIPT:
    1027             :         {
    1028          45 :                 SFScript *sc = (SFScript *) info->far_ptr;
    1029             :                 if (!gf_bt_check_code(parser, '\"')) {
    1030           0 :                         gf_bt_report(parser, GF_BAD_PARAM, "\" expected in Script");
    1031             :                 }
    1032          45 :                 sc->script_text = (char*)gf_bt_get_string(parser, '\"');
    1033             :         }
    1034          45 :         break;
    1035           2 :         case GF_SG_VRML_SFATTRREF:
    1036             :         {
    1037           2 :                 SFAttrRef *ar = (SFAttrRef*) info->far_ptr;
    1038           2 :                 char *str = gf_bt_get_next(parser, 1);
    1039             :                 if (!gf_bt_check_code(parser, '.')) {
    1040           0 :                         gf_bt_report(parser, GF_BAD_PARAM, "'.' expected in SFAttrRef");
    1041             :                 } else {
    1042             :                         GF_FieldInfo pinfo;
    1043           2 :                         ar->node = gf_bt_peek_node(parser, str);
    1044           2 :                         str = gf_bt_get_next(parser, 0);
    1045           2 :                         if (gf_node_get_field_by_name(ar->node, str, &pinfo) != GF_OK) {
    1046           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "field %s is not a member of node %s", str, gf_node_get_class_name(ar->node) );
    1047             :                         } else {
    1048           2 :                                 ar->fieldIndex = pinfo.fieldIndex;
    1049             :                         }
    1050             :                 }
    1051             : 
    1052             :         }
    1053             :         break;
    1054           0 :         default:
    1055           0 :                 parser->last_error = GF_NOT_SUPPORTED;
    1056           0 :                 break;
    1057             : 
    1058             :         }
    1059             :         gf_bt_check_code(parser, ',');
    1060             :         return;
    1061           0 : err:
    1062           0 :         gf_bt_report(parser, GF_BAD_PARAM, "%s: Invalid field syntax", info->name);
    1063             : }
    1064             : 
    1065        3733 : void gf_bt_mffield(GF_BTParser *parser, GF_FieldInfo *info, GF_Node *n)
    1066             : {
    1067             :         GF_FieldInfo sfInfo;
    1068             :         Bool force_single = 0;
    1069             : 
    1070             :         if (!gf_bt_check_code(parser, '[')) {
    1071         112 :                 if (parser->is_extern_proto_field) return;
    1072             :                 force_single = 1;
    1073             :         }
    1074             : 
    1075        3733 :         sfInfo.fieldType = gf_sg_vrml_get_sf_type(info->fieldType);
    1076        3733 :         sfInfo.name = info->name;
    1077        3733 :         gf_sg_vrml_mf_reset(info->far_ptr, info->fieldType);
    1078             : 
    1079        3733 :         while (!gf_bt_check_code(parser, ']')) {
    1080       79647 :                 gf_sg_vrml_mf_append(info->far_ptr, info->fieldType, &sfInfo.far_ptr);
    1081       79647 :                 gf_bt_sffield(parser, &sfInfo, n);
    1082       79647 :                 if (parser->last_error) return;
    1083             : 
    1084             :                 gf_bt_check_code(parser, ',');
    1085       79647 :                 if (force_single) break;
    1086             :         }
    1087             : }
    1088             : 
    1089       17454 : Bool gf_bt_check_ndt(GF_BTParser *parser, GF_FieldInfo *info, GF_Node *node, GF_Node *parent)
    1090             : {
    1091       17454 :         if (!node) return 1;
    1092       17433 :         if (parent->sgprivate->tag == TAG_MPEG4_Script) return 1;
    1093             : #ifndef GPAC_DISABLE_X3D
    1094       17269 :         if (parent->sgprivate->tag == TAG_X3D_Script) return 1;
    1095             : #endif
    1096       17268 :         if (node->sgprivate->tag == TAG_UndefinedNode) return 1;
    1097             : 
    1098             :         /*this handles undefined nodes*/
    1099       17258 :         if (gf_node_in_table(node, info->NDTtype)) return 1;
    1100             :         /*not found*/
    1101           0 :         gf_bt_report(parser, GF_BAD_PARAM, "node %s not valid in field %s\n", gf_node_get_class_name(node), info->name);
    1102           0 :         gf_node_unregister(node, parent);
    1103           0 :         return 0;
    1104             : }
    1105             : 
    1106        3141 : u32 gf_bt_get_next_node_id(GF_BTParser *parser)
    1107             : {
    1108             :         u32 ID;
    1109        3141 :         GF_SceneGraph *sc = parser->load->scene_graph;
    1110        3141 :         if (parser->parsing_proto) sc = gf_sg_proto_get_graph(parser->parsing_proto);
    1111        3141 :         ID = gf_sg_get_next_available_node_id(sc);
    1112        3141 :         if (parser->load->ctx && (ID>parser->load->ctx->max_node_id))
    1113        3065 :                 parser->load->ctx->max_node_id = ID;
    1114        3141 :         return ID;
    1115             : }
    1116          25 : u32 gf_bt_get_next_route_id(GF_BTParser *parser)
    1117             : {
    1118             :         u32 ID;
    1119          25 :         GF_SceneGraph *sg = parser->load->scene_graph;
    1120          25 :         if (parser->parsing_proto) sg = gf_sg_proto_get_graph(parser->parsing_proto);
    1121             : 
    1122          25 :         ID = gf_sg_get_next_available_route_id(sg);
    1123          25 :         if (parser->load->ctx && (ID>parser->load->ctx->max_route_id))
    1124          25 :                 parser->load->ctx->max_route_id = ID;
    1125          25 :         return ID;
    1126             : }
    1127          92 : u32 gf_bt_get_next_proto_id(GF_BTParser *parser)
    1128             : {
    1129             :         u32 ID;
    1130          92 :         GF_SceneGraph *sc = parser->load->scene_graph;
    1131          92 :         if (parser->parsing_proto) sc = gf_sg_proto_get_graph(parser->parsing_proto);
    1132          92 :         ID = gf_sg_get_next_available_proto_id(sc);
    1133          92 :         if (parser->load->ctx && (ID>parser->load->ctx->max_node_id))
    1134          80 :                 parser->load->ctx->max_proto_id = ID;
    1135          92 :         return ID;
    1136             : }
    1137             : 
    1138        3503 : u32 gf_bt_get_def_id(GF_BTParser *parser, char *defName)
    1139             : {
    1140             :         GF_Node *n=NULL;
    1141        3503 :         u32 ID=0;
    1142        3503 :         if (sscanf(defName, "N%u", &ID) == 1) {
    1143             :                 u32 k=1;
    1144        1969 :                 while (defName[k]) {
    1145        1279 :                         if (strchr("0123456789", defName[k])==0) {
    1146           0 :                                 ID = 0;
    1147           0 :                                 break;
    1148             :                         }
    1149        1279 :                         k++;
    1150             :                 }
    1151         690 :                 if (ID) {
    1152         657 :                         ID ++;
    1153         657 :                         n = gf_sg_find_node(parser->load->scene_graph, ID);
    1154         657 :                         if (!n) {
    1155         362 :                                 if (parser->load->ctx && (parser->load->ctx->max_node_id<ID)) parser->load->ctx->max_node_id=ID;
    1156         362 :                                 return ID;
    1157             :                         }
    1158             :                 }
    1159             :         }
    1160             : 
    1161        3141 :         ID = gf_bt_get_next_node_id(parser);
    1162        3141 :         if (n) {
    1163         295 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[BT Parsing] (line %d) Binary ID %d already assigned to %s - keeping internal ID %d", parser->line, gf_node_get_name(n), ID));
    1164             :         }
    1165        3141 :         return ID;
    1166             : }
    1167             : 
    1168        1148 : Bool gf_bt_set_field_is(GF_BTParser *parser, GF_FieldInfo *info, GF_Node *n)
    1169             : {
    1170             :         GF_Err e;
    1171             :         u32 i;
    1172             :         GF_ProtoFieldInterface *pfield;
    1173             :         GF_FieldInfo pinfo;
    1174             :         char *str;
    1175        1148 :         gf_bt_check_line(parser);
    1176             :         i=0;
    1177        1148 :         while ((parser->line_buffer[parser->line_pos + i] == ' ') || (parser->line_buffer[parser->line_pos + i] == '\t')) i++;
    1178        1148 :         if (strnicmp(&parser->line_buffer[parser->line_pos + i] , "IS", 2)) return 0;
    1179             : 
    1180         316 :         gf_bt_get_next(parser, 0);
    1181         316 :         str = gf_bt_get_next(parser, 0);
    1182             : 
    1183             :         /*that's an ISed field*/
    1184         316 :         pfield = gf_sg_proto_field_find_by_name(parser->parsing_proto, str);
    1185         316 :         if (!pfield) {
    1186           0 :                 gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown proto field", str);
    1187           0 :                 return 1;
    1188             :         }
    1189         316 :         gf_sg_proto_field_get_field(pfield, &pinfo);
    1190         316 :         e = gf_sg_proto_field_set_ised(parser->parsing_proto, pinfo.fieldIndex, n, info->fieldIndex);
    1191         316 :         if (e) gf_bt_report(parser, GF_BAD_PARAM, "IS: Invalid field type for field %s", info->name);
    1192             :         return 1;
    1193             : }
    1194             : 
    1195        1106 : void gf_bt_check_unresolved_nodes(GF_BTParser *parser)
    1196             : {
    1197             :         u32 i, count;
    1198        1106 :         count = gf_list_count(parser->undef_nodes);
    1199        1106 :         if (!count) return;
    1200           0 :         for (i=0; i<count; i++) {
    1201           0 :                 GF_Node *n = (GF_Node *)gf_list_get(parser->undef_nodes, i);
    1202           0 :                 gf_bt_report(parser, GF_BAD_PARAM, "Cannot find node %s\n", gf_node_get_name(n) );
    1203           0 :                 gf_node_unregister(n, NULL);
    1204             :         }
    1205           0 :         parser->last_error = GF_BAD_PARAM;
    1206             : }
    1207             : 
    1208          22 : Bool gf_bt_has_been_def(GF_BTParser *parser, char *node_name)
    1209             : {
    1210             :         u32 i, count;
    1211          22 :         count = gf_list_count(parser->def_nodes);
    1212         252 :         for (i=0; i<count; i++) {
    1213         230 :                 GF_Node *n = (GF_Node *) gf_list_get(parser->def_nodes, i);
    1214         230 :                 if (!strcmp(gf_node_get_name(n), node_name)) return 1;
    1215             :         }
    1216             :         return 0;
    1217             : }
    1218             : 
    1219       14730 : u32 gf_bt_get_node_tag(GF_BTParser *parser, char *node_name)
    1220             : {
    1221             :         u32 tag;
    1222             :         /*if VRML and allowing non MPEG4 nodes, use X3D*/
    1223       14730 :         if (parser->is_wrl && !(parser->load->flags & GF_SM_LOAD_MPEG4_STRICT)) {
    1224             : #ifndef GPAC_DISABLE_X3D
    1225         246 :                 tag = gf_node_x3d_type_by_class_name(node_name);
    1226         246 :                 if (!tag)
    1227             : #endif
    1228           1 :                         tag = gf_node_mpeg4_type_by_class_name(node_name);
    1229         246 :                 if (tag) return tag;
    1230             : #ifndef GPAC_DISABLE_X3D
    1231           0 :                 if (!strcmp(node_name, "Rectangle")) return TAG_X3D_Rectangle2D;
    1232           0 :                 if (!strcmp(node_name, "Circle")) return TAG_X3D_Circle2D;
    1233             : #endif
    1234             :         } else {
    1235       14484 :                 tag = gf_node_mpeg4_type_by_class_name(node_name);
    1236       14484 :                 if (!tag) {
    1237         129 :                         if (!strcmp(node_name, "Rectangle2D")) return TAG_MPEG4_Rectangle;
    1238         129 :                         if (!strcmp(node_name, "Circle2D")) return TAG_MPEG4_Circle;
    1239             : #ifndef GPAC_DISABLE_X3D
    1240         129 :                         if (!(parser->load->flags & GF_SM_LOAD_MPEG4_STRICT)) return gf_node_x3d_type_by_class_name(node_name);
    1241             : #endif
    1242             :                 }
    1243             :         }
    1244             :         return tag;
    1245             : }
    1246             : 
    1247       18079 : GF_Node *gf_bt_sf_node(GF_BTParser *parser, char *node_name, GF_Node *parent, char *szDEFName)
    1248             : {
    1249             :         u32 tag, ID;
    1250             :         Bool is_script, replace_prev, register_def;
    1251             :         GF_Proto *proto;
    1252             :         GF_Node *node, *newnode, *undef_node;
    1253             :         GF_FieldInfo info;
    1254             :         Bool init_node;
    1255             :         char *name;
    1256             :         char * str;
    1257             : 
    1258             :         init_node = 0;
    1259             : 
    1260       18079 :         if (node_name) {
    1261             :                 str = node_name;
    1262             :         } else {
    1263       17515 :                 str = gf_bt_get_next(parser, 0);
    1264             :         }
    1265             :         name = NULL;
    1266       18079 :         if (!strcmp(str, "NULL")) return NULL;
    1267             : 
    1268             :         ID = 0;
    1269             :         register_def = 0;
    1270             :         replace_prev = 0;
    1271             :         undef_node = NULL;
    1272       18027 :         if (!strcmp(str, "DEF")) {
    1273             :                 register_def = 1;
    1274        3431 :                 str = gf_bt_get_next(parser, 0);
    1275        3431 :                 name = gf_strdup(str);
    1276        3431 :                 str = gf_bt_get_next(parser, 0);
    1277       14596 :         } else if (szDEFName) {
    1278          72 :                 name = gf_strdup(szDEFName);
    1279             :                 register_def = 1;
    1280             :         }
    1281       18027 :         if (name) {
    1282        3503 :                 undef_node = gf_sg_find_node_by_name(parser->load->scene_graph, name);
    1283        3503 :                 if (undef_node) {
    1284          22 :                         gf_list_del_item(parser->peeked_nodes, undef_node);
    1285          22 :                         ID = gf_node_get_id(undef_node);
    1286             :                         /*if we see twice a DEF N1 then force creation of a new node*/
    1287          22 :                         if (gf_bt_has_been_def(parser, name)) {
    1288             :                                 undef_node = NULL;
    1289           0 :                                 ID = gf_bt_get_def_id(parser, name);
    1290           0 :                                 gf_bt_report(parser, GF_OK, "Node %s has been DEFed several times, IDs may get corrupted", name);
    1291             :                         }
    1292             :                 } else {
    1293        3481 :                         ID = gf_bt_get_def_id(parser, name);
    1294             :                 }
    1295             :         }
    1296       14524 :         else if (!strcmp(str, "USE")) {
    1297        3310 :                 str = gf_bt_get_next(parser, 0);
    1298        3310 :                 node = gf_sg_find_node_by_name(parser->load->scene_graph, str);
    1299        3310 :                 if (!node) {
    1300             :                         /*create a temp node (undefined)*/
    1301           9 :                         node = gf_node_new(parser->load->scene_graph, TAG_UndefinedNode);
    1302           9 :                         ID = gf_bt_get_def_id(parser, str);
    1303           9 :                         gf_node_set_id(node, ID, str);
    1304           9 :                         gf_node_register(node, NULL);
    1305           9 :                         gf_list_add(parser->undef_nodes, node);
    1306             :                 }
    1307        3310 :                 gf_node_register(node, parent);
    1308        3310 :                 return node;
    1309             :         }
    1310             :         proto = NULL;
    1311       14717 :         tag = gf_bt_get_node_tag(parser, str);
    1312       14717 :         if (!tag) {
    1313         129 :                 GF_SceneGraph *sg = parser->load->scene_graph;
    1314             :                 while (1) {
    1315         151 :                         proto = gf_sg_find_proto(sg, 0, str);
    1316         151 :                         if (proto) break;
    1317          22 :                         sg = sg->parent_scene;
    1318          22 :                         if (!sg) break;
    1319             :                 }
    1320         129 :                 if (!proto) {
    1321             :                         /*locate proto*/
    1322           0 :                         gf_bt_report(parser, GF_BAD_PARAM, "%s: not a valid/supported node", str);
    1323           0 :                         return NULL;
    1324             :                 }
    1325             :                 tag = TAG_ProtoNode;
    1326             :         }
    1327       14717 :         if (undef_node && (undef_node->sgprivate->tag == tag)) {
    1328             :                 node = undef_node;
    1329             :         } else {
    1330       14704 :                 if (undef_node) replace_prev = 1;
    1331       14704 :                 if (proto) {
    1332         129 :                         node = gf_sg_proto_create_instance(parser->load->scene_graph, proto);
    1333             :                 } else {
    1334       14575 :                         node = gf_node_new(parser->load->scene_graph, tag);
    1335             :                 }
    1336       14704 :                 if (!parser->parsing_proto) init_node = 1;
    1337             :         }
    1338             :         is_script = 0;
    1339       29434 :         if ((tag==TAG_MPEG4_Script)
    1340             : #ifndef GPAC_DISABLE_X3D
    1341       14717 :                 || (tag==TAG_X3D_Script)
    1342             : #endif
    1343             :            )
    1344             :                 is_script = 1;
    1345             : 
    1346       14717 :         if (!node) {
    1347           0 :                 parser->last_error = GF_SG_UNKNOWN_NODE;
    1348           0 :                 return NULL;
    1349             :         }
    1350       14717 :         if (register_def) gf_list_add(parser->def_nodes, node);
    1351             : 
    1352       14717 :         gf_node_register(node, parent);
    1353             : 
    1354             :         /*VRML: "The transformation hierarchy shall be a directed acyclic graph; results are undefined if a node
    1355             :         in the transformation hierarchy is its own ancestor"
    1356             :         that's good, because the scene graph can't handle cyclic graphs (destroy will never be called).
    1357             :         However we still have to register the node before parsing it, to update node registry and get correct IDs*/
    1358       14717 :         if (name) {
    1359        3503 :                 if (!undef_node || replace_prev) {
    1360        3490 :                         gf_node_set_id(node, ID, name);
    1361             :                 }
    1362        3503 :                 gf_free(name);
    1363             :                 name = NULL;
    1364             :         }
    1365       14717 :         if (!parser->parsing_proto) gf_bt_update_timenode(parser, node);
    1366             : 
    1367             :         if (gf_bt_check_code(parser, '{')) {
    1368             : 
    1369             :                 while (1) {
    1370             :                         if (gf_bt_check_code(parser, '}'))
    1371             :                                 break;
    1372             : 
    1373       25177 :                         str = gf_bt_get_next(parser, 0);
    1374       25177 :                         if (!str) {
    1375           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "Invalid node syntax");
    1376           0 :                                 goto err;
    1377             :                         }
    1378             :                         /*VRML/X3D specific */
    1379       25177 :                         if (parser->is_wrl) {
    1380             :                                 /*we ignore bboxCenter and bboxSize*/
    1381         398 :                                 if (!strcmp(str, "bboxCenter") || !strcmp(str, "bboxSize")) {
    1382             :                                         Fixed f;
    1383           2 :                                         gf_bt_parse_float(parser, "x", &f);
    1384           2 :                                         gf_bt_parse_float(parser, "y", &f);
    1385           2 :                                         gf_bt_parse_float(parser, "z", &f);
    1386           2 :                                         continue;
    1387             :                                 }
    1388             :                                 /*some VRML files declare routes almost anywhere*/
    1389         396 :                                 if (!strcmp(str, "ROUTE")) {
    1390           0 :                                         gf_bt_parse_route(parser, 1, 0, NULL);
    1391           0 :                                         continue;
    1392             :                                 }
    1393             :                         }
    1394             : 
    1395       25175 :                         parser->last_error = gf_node_get_field_by_name(node, str, &info);
    1396             : 
    1397             :                         /*check common VRML fields removed in MPEG4*/
    1398       25175 :                         if (parser->last_error) {
    1399         320 :                                 if (!parser->is_wrl) {
    1400             :                                         /*we ignore 'solid' for MPEG4 box/cone/etc*/
    1401         312 :                                         if (!strcmp(str, "solid")) {
    1402             :                                                 SFBool b;
    1403           0 :                                                 gf_bt_parse_bool(parser, "solid", &b);
    1404           0 :                                                 parser->last_error = GF_OK;
    1405           0 :                                                 continue;
    1406             :                                         }
    1407             :                                         /*we ignore 'description' for MPEG4 sensors*/
    1408         312 :                                         else if (!strcmp(str, "description")) {
    1409           0 :                                                 char *tmpstr = gf_bt_get_string(parser, 0);
    1410           0 :                                                 gf_free(tmpstr);
    1411           0 :                                                 parser->last_error = GF_OK;
    1412           0 :                                                 continue;
    1413             :                                         }
    1414             :                                         /*remaps X3D to old VRML/MPEG4*/
    1415         312 :                                         else if ((tag==TAG_MPEG4_LOD) && !strcmp(str, "children")) {
    1416             :                                                 str = "level";
    1417           0 :                                                 parser->last_error = gf_node_get_field_by_name(node, str, &info);
    1418             :                                         }
    1419         312 :                                         else if ((tag==TAG_MPEG4_Switch) && !strcmp(str, "children")) {
    1420             :                                                 str = "choice";
    1421           0 :                                                 parser->last_error = gf_node_get_field_by_name(node, str, &info);
    1422             :                                         }
    1423         312 :                                         else if (!strcmp(str, "enabled")) {
    1424             :                                                 SFBool b;
    1425           0 :                                                 gf_bt_parse_bool(parser, "collide", &b);
    1426           0 :                                                 parser->last_error = GF_OK;
    1427           0 :                                                 continue;
    1428             :                                         }
    1429             :                                 } else {
    1430             :                                         /*remaps old VRML/MPEG4 to X3D if possible*/
    1431             : #ifndef GPAC_DISABLE_X3D
    1432           8 :                                         if ((tag==TAG_X3D_LOD) && !strcmp(str, "level")) {
    1433             :                                                 str = "children";
    1434           0 :                                                 parser->last_error = gf_node_get_field_by_name(node, str, &info);
    1435             :                                         }
    1436           8 :                                         else if ((tag==TAG_X3D_Switch) && !strcmp(str, "choice")) {
    1437             :                                                 str = "children";
    1438           0 :                                                 parser->last_error = gf_node_get_field_by_name(node, str, &info);
    1439             :                                         }
    1440             :                                         else
    1441             : #endif
    1442           8 :                                                 if (!strcmp(str, "collide")) {
    1443             :                                                         SFBool b;
    1444           0 :                                                         gf_bt_parse_bool(parser, "enabled", &b);
    1445           0 :                                                         parser->last_error = GF_OK;
    1446           0 :                                                         continue;
    1447             :                                                 }
    1448             :                                 }
    1449             :                         }
    1450             : 
    1451       25175 :                         if (is_script && parser->last_error) {
    1452             :                                 u32 eType, fType;
    1453             : 
    1454         320 :                                 if (!strcmp(str, "eventIn") || !strcmp(str, "inputOnly")) eType = GF_SG_SCRIPT_TYPE_EVENT_IN;
    1455         208 :                                 else if (!strcmp(str, "eventOut") || !strcmp(str, "outputOnly")) eType = GF_SG_SCRIPT_TYPE_EVENT_OUT;
    1456         193 :                                 else if (!strcmp(str, "field") || !strcmp(str, "initializeOnly")) eType = GF_SG_SCRIPT_TYPE_FIELD;
    1457             :                                 else {
    1458           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown script event type", str);
    1459           0 :                                         goto err;
    1460             :                                 }
    1461         320 :                                 str = gf_bt_get_next(parser, 0);
    1462         320 :                                 fType = gf_sg_field_type_by_name(str);
    1463         320 :                                 if (fType==GF_SG_VRML_UNKNOWN) {
    1464           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown script field type", str);
    1465           0 :                                         goto err;
    1466             :                                 }
    1467         320 :                                 parser->last_error = GF_OK;
    1468         320 :                                 str = gf_bt_get_next(parser, 0);
    1469         320 :                                 gf_sg_script_field_new(node, eType, fType, str);
    1470         320 :                                 parser->last_error = gf_node_get_field_by_name(node, str, &info);
    1471             : 
    1472         320 :                                 if (parser->parsing_proto && gf_bt_set_field_is(parser, &info, node)) continue;
    1473         320 :                                 if ((eType == GF_SG_SCRIPT_TYPE_EVENT_IN) || (eType == GF_SG_SCRIPT_TYPE_EVENT_OUT)) continue;
    1474             :                         }
    1475             : 
    1476       25048 :                         if (parser->last_error) {
    1477           0 :                                 gf_bt_report(parser, parser->last_error, "%s: Unknown field", str);
    1478           0 :                                 goto err;
    1479             :                         }
    1480             : 
    1481       25048 :                         if (proto) gf_sg_proto_mark_field_loaded(node, &info);
    1482       25048 :                         if (parser->parsing_proto && gf_bt_set_field_is(parser, &info, node)) continue;
    1483             : 
    1484       24732 :                         switch (info.fieldType) {
    1485        7918 :                         case GF_SG_VRML_SFNODE:
    1486             :                                 /*if redefining node reset it - this happens with CreateVrmlFromString*/
    1487        7918 :                                 if (* ((GF_Node **)info.far_ptr) ) {
    1488           0 :                                         gf_node_unregister(* ((GF_Node **)info.far_ptr), node);
    1489           0 :                                         * ((GF_Node **)info.far_ptr) = NULL;
    1490             :                                 }
    1491             : 
    1492        7918 :                                 newnode = gf_bt_sf_node(parser, NULL, node, NULL);
    1493        7918 :                                 if (!newnode && parser->last_error) goto err;
    1494        7918 :                                 if (newnode) {
    1495        7918 :                                         if (!gf_bt_check_ndt(parser, &info, newnode, node)) goto err;
    1496             : 
    1497        7918 :                                         * ((GF_Node **)info.far_ptr) = newnode;
    1498             :                                 }
    1499             :                                 break;
    1500        3343 :                         case GF_SG_VRML_MFNODE:
    1501             :                         {
    1502        3343 :                                 GF_ChildNodeItem *last = NULL;
    1503             :                                 Bool single_child = 0;
    1504             :                                 if (!gf_bt_check_code(parser, '[')) {
    1505           0 :                                         if (parser->is_wrl) single_child = 1;
    1506             :                                         else break;
    1507             :                                 }
    1508             : 
    1509             :                                 /*if redefining node reset it - this happens with CreateVrmlFromString*/
    1510        3343 :                                 if (undef_node==node) {
    1511           0 :                                         gf_node_unregister_children(node, *(GF_ChildNodeItem **)info.far_ptr);
    1512           0 :                                         *(GF_ChildNodeItem **)info.far_ptr = NULL;
    1513             :                                 }
    1514             : 
    1515       12753 :                                 while (single_child || !gf_bt_check_code(parser, ']')) {
    1516             :                                         /*VRML seems to allow that*/
    1517             :                                         gf_bt_check_code(parser, ',');
    1518        9410 :                                         newnode = gf_bt_sf_node(parser, NULL, node, NULL);
    1519        9410 :                                         if (!newnode && parser->last_error) goto err;
    1520        9410 :                                         if (newnode) {
    1521        9410 :                                                 if (!gf_bt_check_ndt(parser, &info, newnode, node)) goto err;
    1522        9410 :                                                 gf_node_list_add_child_last( (GF_ChildNodeItem **)info.far_ptr, newnode, &last);
    1523             :                                         }
    1524        9410 :                                         if (single_child) break;
    1525             :                                 }
    1526             :                         }
    1527        3343 :                         break;
    1528       13471 :                         default:
    1529       13471 :                                 if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    1530        9816 :                                         gf_bt_sffield(parser, &info, node);
    1531             :                                 } else {
    1532        3655 :                                         gf_bt_mffield(parser, &info, node);
    1533             :                                 }
    1534       13471 :                                 if (parser->last_error) goto err;
    1535             :                                 break;
    1536             :                         }
    1537             :                         /*VRML seems to allow that*/
    1538             :                         gf_bt_check_code(parser, ',');
    1539             :                 }
    1540             :         }
    1541             :         /*VRML seems to allow that*/
    1542             :         gf_bt_check_code(parser, ',');
    1543             : 
    1544             :         /*we must init the node once ID is set in case we're creating rendering stacks*/
    1545       14717 :         if (init_node && (gf_node_get_tag(node)!=TAG_ProtoNode) ) gf_node_init(node);
    1546             : 
    1547             :         /*remove temp node*/
    1548       14717 :         if (replace_prev) {
    1549           9 :                 gf_node_replace(undef_node, node, 0);
    1550           9 :                 gf_node_unregister(undef_node, NULL);
    1551           9 :                 gf_list_del_item(parser->undef_nodes, undef_node);
    1552             :         }
    1553             : 
    1554       14717 :         if (!parser->parsing_proto && is_script && (parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) ) {
    1555          35 :                 if (parser->cur_com) {
    1556          34 :                         if (!parser->cur_com->scripts_to_load) parser->cur_com->scripts_to_load = gf_list_new();
    1557          34 :                         gf_list_add(parser->cur_com->scripts_to_load, node);
    1558             :                 } else {
    1559             :                         /*postpone script init since it may use routes/nodes not yet defined ...*/
    1560           1 :                         gf_list_add(parser->scripts, node);
    1561             :                 }
    1562             :         }
    1563             :         /*For Ivica: load proto as soon as found when in playback mode*/
    1564       14717 :         if ( (parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) && proto && !parser->parsing_proto) {
    1565          74 :                 parser->last_error = gf_sg_proto_load_code(node);
    1566             :         }
    1567             :         return node;
    1568             : 
    1569           0 : err:
    1570           0 :         gf_node_unregister(node, parent);
    1571           0 :         if (name) gf_free(name);
    1572             :         return NULL;
    1573             : }
    1574             : /*
    1575             :         locate node, if not defined yet parse ahead in current AU
    1576             :         optimization: we actually peek ALL DEF NODES till end of AU
    1577             : */
    1578        3935 : GF_Node *gf_bt_peek_node(GF_BTParser *parser, char *defID)
    1579             : {
    1580             :         GF_Node *n, *the_node;
    1581             :         u32 tag, ID;
    1582             :         Bool prev_is_insert = 0;
    1583             :         char *ret;
    1584             :         char nName[1000];
    1585             :         u32 pos, line, line_pos, i, count;
    1586             : 
    1587        3935 :         n = gf_sg_find_node_by_name(parser->load->scene_graph, defID);
    1588        3935 :         if (n) return n;
    1589             : 
    1590          24 :         count = gf_list_count(parser->peeked_nodes);
    1591          24 :         for (i=0; i<count; i++) {
    1592           0 :                 n = (GF_Node *)gf_list_get(parser->peeked_nodes, i);
    1593           0 :                 if (!strcmp(gf_node_get_name(n), defID)) return n;
    1594             :         }
    1595             : 
    1596             :         the_node = NULL;
    1597          24 :         pos = parser->line_start_pos;
    1598          24 :         line_pos = parser->line_pos;
    1599          24 :         line = parser->line;
    1600             :         strcpy(nName, defID);
    1601             : 
    1602             :         n = NULL;
    1603         272 :         while (!parser->done && !the_node) {
    1604         234 :                 char *str = gf_bt_get_next(parser, 0);
    1605             :                 gf_bt_check_code(parser, '[');
    1606             :                 gf_bt_check_code(parser, ']');
    1607             :                 gf_bt_check_code(parser, '{');
    1608             :                 gf_bt_check_code(parser, '}');
    1609             :                 gf_bt_check_code(parser, ',');
    1610             :                 gf_bt_check_code(parser, '.');
    1611             : 
    1612         234 :                 if ( (!prev_is_insert && !strcmp(str, "AT")) || !strcmp(str, "PROTO") ) {
    1613             :                         /*only check in current command (but be aware of conditionals..)*/
    1614          10 :                         if (gf_list_find(parser->bifs_au->commands, parser->cur_com)) {
    1615             :                                 break;
    1616             :                         }
    1617           0 :                         continue;
    1618             :                 }
    1619         224 :                 if (!strcmp(str, "INSERT")) prev_is_insert = 1;
    1620             :                 else prev_is_insert = 0;
    1621             : 
    1622         224 :                 if (strcmp(str, "DEF")) continue;
    1623          13 :                 str = gf_bt_get_next(parser, 0);
    1624          13 :                 ret = gf_strdup(str);
    1625          13 :                 str = gf_bt_get_next(parser, 0);
    1626          13 :                 if (!strcmp(str, "ROUTE")) {
    1627           0 :                         gf_free(ret);
    1628           0 :                         continue;
    1629             :                 }
    1630             : 
    1631          13 :                 tag = gf_bt_get_node_tag(parser, str);
    1632          13 :                 if (!tag) {
    1633             :                         GF_Proto *p;
    1634           0 :                         GF_SceneGraph *sg = parser->load->scene_graph;
    1635             :                         while (1) {
    1636           0 :                                 p = gf_sg_find_proto(sg, 0, str);
    1637           0 :                                 if (p) break;
    1638           0 :                                 sg = sg->parent_scene;
    1639           0 :                                 if (!sg) break;
    1640             :                         }
    1641           0 :                         if (!p) {
    1642             :                                 /*locate proto*/
    1643           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "%s: not a valid/supported node", str);
    1644           0 :                                 gf_free(ret);
    1645           0 :                                 return NULL;
    1646             :                         }
    1647           0 :                         n = gf_sg_proto_create_instance(parser->load->scene_graph, p);
    1648             :                 } else {
    1649          13 :                         n = gf_node_new(parser->load->scene_graph, tag);
    1650             :                 }
    1651          13 :                 ID = gf_bt_get_def_id(parser, ret);
    1652          13 :                 if (n) {
    1653          13 :                         gf_node_set_id(n, ID, ret);
    1654          13 :                         gf_list_add(parser->peeked_nodes, n);
    1655          13 :                         if (!parser->parsing_proto) gf_node_init(n);
    1656          13 :                         if (!strcmp(ret, nName)) the_node = n;
    1657             :                 }
    1658          13 :                 gf_free(ret);
    1659             : 
    1660             :                 /*NO REGISTER on peek (both scene graph or DEF list) because peek is only used to get node type
    1661             :                 and fields, never to insert in the graph*/
    1662             : 
    1663             :                 /*go on till end of AU*/
    1664             :         }
    1665             :         /*restore context*/
    1666          24 :         parser->done = 0;
    1667          24 :         gf_gzrewind(parser->gz_in);
    1668          24 :         gf_gzseek(parser->gz_in, pos, SEEK_SET);
    1669          24 :         parser->line_pos = parser->line_size;
    1670          24 :         gf_bt_check_line(parser);
    1671          24 :         parser->line = line;
    1672          24 :         parser->line_pos = line_pos;
    1673             : 
    1674          24 :         return the_node;
    1675             : }
    1676             : 
    1677         104 : u32 gf_bt_get_route(GF_BTParser *parser, char *name)
    1678             : {
    1679             :         u32 i;
    1680             :         GF_Command *com;
    1681         104 :         GF_Route *r = gf_sg_route_find_by_name(parser->load->scene_graph, name);
    1682         104 :         if (r) return r->ID;
    1683         101 :         i=0;
    1684         394 :         while ((com = (GF_Command *)gf_list_enum(parser->inserted_routes, &i))) {
    1685         257 :                 if (com->def_name && !strcmp(com->def_name, name)) return com->RouteID;
    1686             :         }
    1687             :         return 0;
    1688             : }
    1689             : 
    1690           8 : Bool gf_bt_route_id_used(GF_BTParser *parser, u32 ID)
    1691             : {
    1692             :         u32 i;
    1693             :         GF_Command *com;
    1694           8 :         GF_Route *r = gf_sg_route_find(parser->load->scene_graph, ID);
    1695           8 :         if (r) return 1;
    1696           8 :         i=0;
    1697          60 :         while ((com = (GF_Command *)gf_list_enum(parser->inserted_routes, &i))) {
    1698          44 :                 if (com->RouteID == ID) return 1;
    1699             :         }
    1700             :         return 0;
    1701             : }
    1702             : 
    1703         516 : static u32 get_evt_type(char *eventName)
    1704             : {
    1705         516 :         if (!strcmp(eventName, "eventIn") || !strcmp(eventName, "inputOnly")) return GF_SG_EVENT_IN;
    1706         493 :         else if (!strcmp(eventName, "eventOut") || !strcmp(eventName, "outputOnly")) return GF_SG_EVENT_OUT;
    1707         484 :         else if (!strcmp(eventName, "field") || !strcmp(eventName, "initializeOnly")) return GF_SG_EVENT_FIELD;
    1708         482 :         else if (!strcmp(eventName, "exposedField") || !strcmp(eventName, "inputOutput")) return GF_SG_EVENT_EXPOSED_FIELD;
    1709           0 :         else return GF_SG_EVENT_UNKNOWN;
    1710             : }
    1711             : 
    1712          92 : GF_Err gf_bt_parse_proto(GF_BTParser *parser, char *proto_code, GF_List *proto_list)
    1713             : {
    1714             :         GF_FieldInfo info;
    1715          92 :         u32 fType, eType, QPType=0, pID;
    1716             :         Bool externProto;
    1717             :         GF_Proto *proto, *prevproto;
    1718             :         GF_ProtoFieldInterface *pfield;
    1719             :         GF_SceneGraph *sg;
    1720             :         char *str, *name;
    1721             :         char szDefName[1024];
    1722             :         Bool isDEF;
    1723             : 
    1724          92 :         if (proto_code)
    1725             :                 str = proto_code;
    1726             :         else
    1727          10 :                 str = gf_bt_get_next(parser, 0);
    1728             : 
    1729          92 :         externProto = !strcmp(str, "EXTERNPROTO") ? 1 : 0;
    1730          92 :         str = gf_bt_get_next(parser, 0);
    1731          92 :         name = gf_strdup(str);
    1732             :         if (!gf_bt_check_code(parser, '[')) {
    1733           0 :                 return gf_bt_report(parser, GF_BAD_PARAM, "[ expected in proto declare");
    1734             :         }
    1735          92 :         pID = gf_bt_get_next_proto_id(parser);
    1736             :         /*if redefinition remove it - WRL only, may be used by loadVRMLFormString*/
    1737          92 :         if (!proto_list && parser->is_wrl) {
    1738           0 :                 proto = gf_sg_find_proto(parser->load->scene_graph, pID, name);
    1739           0 :                 if (proto) gf_sg_proto_del(proto);
    1740             :         }
    1741          92 :         proto = gf_sg_proto_new(parser->load->scene_graph, pID, name, proto_list ? 1 : 0);
    1742          92 :         if (proto_list) gf_list_add(proto_list, proto);
    1743          92 :         if (parser->load->ctx && (parser->load->ctx->max_proto_id<pID)) parser->load->ctx->max_proto_id = pID;
    1744             : 
    1745             :         /*hack for VRML, where externProto default field values are not mandatory*/
    1746          92 :         parser->is_extern_proto_field = externProto;
    1747             : 
    1748          92 :         gf_free(name);
    1749             :         /*get all fields*/
    1750         700 :         while (!parser->last_error && !gf_bt_check_code(parser, ']')) {
    1751         516 :                 str = gf_bt_get_next(parser, 0);
    1752             : 
    1753           0 : next_field:
    1754             :                 if (gf_bt_check_code(parser, ']')) break;
    1755             : 
    1756         516 :                 eType = get_evt_type(str);
    1757         516 :                 if (eType==GF_SG_EVENT_UNKNOWN) {
    1758           0 :                         gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown event type", str);
    1759           0 :                         goto err;
    1760             :                 }
    1761         516 :                 str = gf_bt_get_next(parser, 0);
    1762         516 :                 fType = gf_sg_field_type_by_name(str);
    1763         516 :                 if (fType==GF_SG_VRML_UNKNOWN) {
    1764           0 :                         gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown field type", str);
    1765           0 :                         goto err;
    1766             :                 }
    1767         516 :                 str = gf_bt_get_next(parser, 0);
    1768         516 :                 pfield = gf_sg_proto_field_new(proto, fType, eType, str);
    1769         516 :                 if ((eType==GF_SG_EVENT_IN) || (eType==GF_SG_EVENT_OUT)) continue;
    1770             : 
    1771         484 :                 gf_sg_proto_field_get_field(pfield, &info);
    1772         484 :                 if (fType==GF_SG_VRML_SFNODE) {
    1773          54 :                         str = gf_bt_get_next(parser, 0);
    1774          54 :                         if (strcmp(str, "NULL")) {
    1775           0 :                                 if ( (!strlen(str) || (get_evt_type(str)!=GF_SG_EVENT_UNKNOWN)) && parser->is_extern_proto_field) goto next_field;
    1776           0 :                                 pfield->def_sfnode_value = gf_bt_sf_node(parser, str, NULL, NULL);
    1777             :                         }
    1778         430 :                 } else if (fType==GF_SG_VRML_MFNODE) {
    1779          15 :                         GF_ChildNodeItem *last = NULL;
    1780             :                         if (gf_bt_check_code(parser, '[')) {
    1781             :                                 while (1) {
    1782             :                                         GF_Node *pf_node;
    1783             :                                         if (gf_bt_check_code(parser, ']')) break;
    1784           0 :                                         pf_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
    1785           0 :                                         if (pf_node) gf_node_list_add_child_last( &pfield->def_mfnode_value, pf_node, &last);
    1786             :                                 }
    1787             :                         }
    1788         415 :                 } else if (gf_sg_vrml_is_sf_field(fType)) {
    1789         403 :                         gf_bt_sffield(parser, &info, NULL);
    1790             :                         /*value not specified for externproto*/
    1791         403 :                         if (parser->last_error==GF_EOS) {
    1792           0 :                                 parser->last_error=GF_OK;
    1793           0 :                                 goto next_field;
    1794             :                         }
    1795             :                 } else {
    1796          12 :                         gf_bt_mffield(parser, &info, NULL);
    1797             :                 }
    1798             :                 /*check QP info*/
    1799         484 :                 if (!gf_bt_check_code(parser, '{')) continue;
    1800           0 :                 if (gf_bt_check_code(parser, '}')) continue;
    1801           0 :                 str = gf_bt_get_next(parser, 0);
    1802           0 :                 if (!strcmp(str, "QP")) {
    1803             :                         u32 nbBits, hasMin;
    1804             :                         Fixed ftMin, ftMax;
    1805           0 :                         gf_bt_parse_int(parser, "QPType", (SFInt32*)&QPType);
    1806             : 
    1807           0 :                         nbBits = 0;
    1808           0 :                         str = gf_bt_get_next(parser, 0);
    1809           0 :                         if (!strcmp(str, "nbBits")) {
    1810           0 :                                 gf_bt_parse_int(parser, "nbBits", (SFInt32*)&nbBits);
    1811           0 :                                 str = gf_bt_get_next(parser, 0);
    1812             :                         }
    1813             :                         hasMin = 0;
    1814             :                         eType = 0;
    1815           0 :                         if (!strcmp(str, "b")) {
    1816             :                                 hasMin = 1;
    1817             :                                 if (!gf_bt_check_code(parser, '{')) {
    1818           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "%s: Invalid proto coding parameter declare", str);
    1819           0 :                                         goto err;
    1820             :                                 }
    1821           0 :                                 gf_bt_parse_float(parser, "min", &ftMin);
    1822           0 :                                 gf_bt_parse_float(parser, "max", &ftMax);
    1823             :                                 if (!gf_bt_check_code(parser, '}')) {
    1824           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "Invalid proto coding parameter declare");
    1825           0 :                                         goto err;
    1826             :                                 }
    1827           0 :                                 if (gf_sg_vrml_get_sf_type(fType) == GF_SG_VRML_SFINT32) {
    1828             :                                         eType = GF_SG_VRML_SFINT32;
    1829             :                                 } else {
    1830             :                                         eType = GF_SG_VRML_SFFLOAT;
    1831             :                                 }
    1832             :                         }
    1833           0 :                         gf_bifs_proto_field_set_aq_info(pfield, QPType, hasMin, eType, &ftMin, &ftMax, nbBits);
    1834             :                         if (!gf_bt_check_code(parser, '}')) {
    1835           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "Invalid proto coding parameter declare");
    1836           0 :                                 goto err;
    1837             :                         }
    1838             :                 }
    1839             :         }
    1840          92 :         parser->is_extern_proto_field = 0;
    1841             : 
    1842          92 :         if (externProto) {
    1843             :                 SFURL *url;
    1844             :                 Bool has_urls = 0;
    1845             :                 if (gf_bt_check_code(parser, '[')) has_urls = 1;
    1846             : 
    1847          35 :                 gf_sg_vrml_mf_reset(&proto->ExternProto, GF_SG_VRML_MFURL);
    1848             :                 do {
    1849          35 :                         str = gf_bt_get_next(parser, 0);
    1850          35 :                         gf_sg_vrml_mf_append(&proto->ExternProto, GF_SG_VRML_MFURL, (void **) &url);
    1851          35 :                         if (!strnicmp(str, "od:", 3)) {
    1852           3 :                                 sscanf(str, "od:%u", &url->OD_ID);
    1853             :                         } else {
    1854          32 :                                 if (!sscanf(str, "%u", &url->OD_ID)) {
    1855          32 :                                         url->url = gf_strdup(str);
    1856             :                                 } else {
    1857             :                                         char szURL[20];
    1858           0 :                                         sprintf(szURL, "%d", url->OD_ID);
    1859           0 :                                         if (strcmp(szURL, str)) {
    1860           0 :                                                 url->OD_ID = 0;
    1861           0 :                                                 url->url = gf_strdup(str);
    1862             :                                         }
    1863             :                                 }
    1864             :                         }
    1865          35 :                         if (has_urls) {
    1866             :                                 gf_bt_check_code(parser, ',');
    1867             :                                 if (gf_bt_check_code(parser, ']')) has_urls = 0;
    1868             :                         }
    1869          18 :                 } while (has_urls);
    1870             :                 return GF_OK;
    1871             :         }
    1872             : 
    1873             :         /*parse proto code */
    1874             :         if (!gf_bt_check_code(parser, '{')) {
    1875           0 :                 gf_bt_report(parser, GF_OK, "empty proto body");
    1876           0 :                 return GF_OK;
    1877             :         }
    1878             : 
    1879          57 :         prevproto = parser->parsing_proto;
    1880          57 :         sg = parser->load->scene_graph;
    1881          57 :         parser->parsing_proto = proto;
    1882          57 :         parser->load->scene_graph = gf_sg_proto_get_graph(proto);
    1883             : 
    1884             :         isDEF = 0;
    1885          57 :         while (!gf_bt_check_code(parser, '}')) {
    1886         192 :                 str = gf_bt_get_next(parser, 0);
    1887         383 :                 if (!strcmp(str, "PROTO") || !strcmp(str, "EXTERNPROTO")) {
    1888           1 :                         gf_bt_parse_proto(parser, str, NULL);
    1889         191 :                 } else if (!strcmp(str, "DEF")) {
    1890             :                         isDEF = 1;
    1891          60 :                         str = gf_bt_get_next(parser, 0);
    1892             :                         strcpy(szDefName, str);
    1893         131 :                 } else if (!strcmp(str, "ROUTE")) {
    1894          31 :                         GF_Route *r = gf_bt_parse_route(parser, 1, 0, NULL);
    1895          31 :                         if (isDEF) {
    1896           2 :                                 u32 rID = gf_bt_get_route(parser, szDefName);
    1897           2 :                                 if (!rID) rID = gf_bt_get_next_route_id(parser);
    1898           2 :                                 parser->last_error = gf_sg_route_set_id(r, rID);
    1899           2 :                                 gf_sg_route_set_name(r, szDefName);
    1900             :                                 isDEF = 0;
    1901             :                         }
    1902             :                 } else {
    1903         100 :                         GF_Node *n = gf_bt_sf_node(parser, str, NULL, isDEF ? szDefName : NULL);
    1904             :                         isDEF = 0;
    1905         100 :                         if (!n) goto err;
    1906             :                         if ((0) && isDEF) {
    1907             :                                 u32 ID = gf_bt_get_def_id(parser, szDefName);
    1908             :                                 isDEF = 0;
    1909             :                                 gf_node_set_id(n, ID, szDefName);
    1910             :                         }
    1911         100 :                         gf_sg_proto_add_node_code(proto, n);
    1912             :                 }
    1913             :         }
    1914          57 :         gf_bt_resolve_routes(parser, 1);
    1915          57 :         gf_bt_check_unresolved_nodes(parser);
    1916          57 :         parser->load->scene_graph = sg;
    1917          57 :         parser->parsing_proto = prevproto;
    1918          57 :         return parser->last_error;
    1919             : 
    1920           0 : err:
    1921           0 :         if (proto_list) gf_list_del_item(proto_list, proto);
    1922           0 :         gf_sg_proto_del(proto);
    1923           0 :         return parser->last_error;
    1924             : }
    1925             : 
    1926             : 
    1927        1428 : GF_Route *gf_bt_parse_route(GF_BTParser *parser, Bool skip_def, Bool is_insert, GF_Command *com)
    1928             : {
    1929             :         GF_Route *r;
    1930             :         char *str, nstr[1000], rName[1000];
    1931             :         u32 rID;
    1932             :         GF_Node *orig, *dest;
    1933             :         GF_FieldInfo orig_field, dest_field;
    1934             :         GF_Err e;
    1935             : 
    1936             :         rID = 0;
    1937        1428 :         strcpy(nstr, gf_bt_get_next(parser, 1));
    1938        1428 :         if (!skip_def && !strcmp(nstr, "DEF")) {
    1939          23 :                 str = gf_bt_get_next(parser, 0);
    1940             :                 strcpy(rName, str);
    1941          23 :                 rID = gf_bt_get_route(parser, rName);
    1942          23 :                 if (!rID && (str[0]=='R') ) {
    1943          18 :                         rID = atoi(&str[1]);
    1944           9 :                         if (rID) {
    1945           8 :                                 rID++;
    1946           8 :                                 if (gf_bt_route_id_used(parser, rID)) rID = 0;
    1947             :                         }
    1948             :                 }
    1949          23 :                 if (!rID) rID = gf_bt_get_next_route_id(parser);
    1950          23 :                 strcpy(nstr, gf_bt_get_next(parser, 1));
    1951             :         }
    1952        1428 :         orig = gf_bt_peek_node(parser, nstr);
    1953        1428 :         if (!orig) {
    1954           0 :                 gf_bt_report(parser, GF_BAD_PARAM, "cannot find node %s", nstr);
    1955           0 :                 return NULL;
    1956             :         }
    1957             :         if (!gf_bt_check_code(parser, '.')) {
    1958           0 :                 gf_bt_report(parser, GF_BAD_PARAM, ". expected in route decl");
    1959           0 :                 return NULL;
    1960             :         }
    1961        1428 :         str = gf_bt_get_next(parser, 0);
    1962        1428 :         e = gf_node_get_field_by_name(orig, str, &orig_field);
    1963             :         /*VRML loosy syntax*/
    1964        1428 :         if ((e != GF_OK) && parser->is_wrl && !strnicmp(str, "set_", 4))
    1965           0 :                 e = gf_node_get_field_by_name(orig, &str[4], &orig_field);
    1966             : 
    1967        1428 :         if ((e != GF_OK) && parser->is_wrl && strstr(str, "_changed")) {
    1968             :                 char *s = strstr(str, "_changed");
    1969           0 :                 s[0] = 0;
    1970           0 :                 e = gf_node_get_field_by_name(orig, str, &orig_field);
    1971             :         }
    1972             : 
    1973        1428 :         if (e != GF_OK) {
    1974           0 :                 gf_bt_report(parser, GF_BAD_PARAM, "%s not a field of node %s (%s)", str, gf_node_get_name(orig), gf_node_get_class_name(orig));
    1975           0 :                 return NULL;
    1976             :         }
    1977        1428 :         str = gf_bt_get_next(parser, 0);
    1978        1428 :         if (strcmp(str, "TO")) {
    1979           0 :                 gf_bt_report(parser, GF_BAD_PARAM, "TO expected in route declaration - got \"%s\"", str);
    1980           0 :                 return NULL;
    1981             :         }
    1982             : 
    1983        1428 :         strcpy(nstr, gf_bt_get_next(parser, 1));
    1984        1428 :         dest = gf_bt_peek_node(parser, nstr);
    1985        1428 :         if (!dest) {
    1986           0 :                 gf_bt_report(parser, GF_BAD_PARAM, "cannot find node %s", nstr);
    1987           0 :                 return NULL;
    1988             :         }
    1989             :         if (!gf_bt_check_code(parser, '.')) {
    1990           0 :                 gf_bt_report(parser, GF_BAD_PARAM, ". expected in route decl");
    1991           0 :                 return NULL;
    1992             :         }
    1993        1428 :         str = gf_bt_get_next(parser, 0);
    1994        1428 :         e = gf_node_get_field_by_name(dest, str, &dest_field);
    1995             :         /*VRML loosy syntax*/
    1996        1428 :         if ((e != GF_OK) && parser->is_wrl && !strnicmp(str, "set_", 4))
    1997           0 :                 e = gf_node_get_field_by_name(dest, &str[4], &dest_field);
    1998             : 
    1999        1428 :         if ((e != GF_OK) && parser->is_wrl && strstr(str, "_changed")) {
    2000             :                 char *s = strstr(str, "_changed");
    2001           0 :                 s[0] = 0;
    2002           0 :                 e = gf_node_get_field_by_name(dest, str, &dest_field);
    2003             :         }
    2004             : 
    2005        1428 :         if (e != GF_OK) {
    2006           0 :                 gf_bt_report(parser, GF_BAD_PARAM, "%s not a field of node %s (%s)", str, gf_node_get_name(dest), gf_node_get_class_name(dest));
    2007           0 :                 return NULL;
    2008             :         }
    2009        1428 :         if (com) {
    2010        1377 :                 com->fromNodeID = gf_node_get_id(orig);
    2011        1377 :                 com->fromFieldIndex = orig_field.fieldIndex;
    2012        1377 :                 com->toNodeID = gf_node_get_id(dest);
    2013        1377 :                 com->toFieldIndex = dest_field.fieldIndex;
    2014        1377 :                 if (rID) {
    2015          23 :                         com->RouteID = rID;
    2016          23 :                         com->def_name = gf_strdup(rName);
    2017             :                         /*whenever inserting routes, keep track of max defined ID*/
    2018          23 :                         if (is_insert) {
    2019          23 :                                 gf_sg_set_max_defined_route_id(parser->load->scene_graph, rID);
    2020          23 :                                 if (parser->load->ctx && (rID>parser->load->ctx->max_route_id))
    2021           8 :                                         parser->load->ctx->max_route_id = rID;
    2022             :                         }
    2023             :                 }
    2024             :                 return NULL;
    2025             :         }
    2026          51 :         r = gf_sg_route_new(parser->load->scene_graph, orig, orig_field.fieldIndex, dest, dest_field.fieldIndex);
    2027          51 :         if (r && rID) {
    2028           0 :                 gf_sg_route_set_id(r, rID);
    2029           0 :                 gf_sg_route_set_name(r, rName);
    2030             :         }
    2031             :         return r;
    2032             : }
    2033             : 
    2034         960 : void gf_bt_resolve_routes(GF_BTParser *parser, Bool clean)
    2035             : {
    2036             :         /*resolve all commands*/
    2037        1941 :         while(gf_list_count(parser->unresolved_routes) ) {
    2038          21 :                 GF_Command *com = (GF_Command *)gf_list_get(parser->unresolved_routes, 0);
    2039          21 :                 gf_list_rem(parser->unresolved_routes, 0);
    2040          21 :                 switch (com->tag) {
    2041          21 :                 case GF_SG_ROUTE_DELETE:
    2042             :                 case GF_SG_ROUTE_REPLACE:
    2043          21 :                         com->RouteID = gf_bt_get_route(parser, com->unres_name);
    2044          21 :                         if (!com->RouteID) gf_bt_report(parser, GF_BAD_PARAM, "Cannot resolve Route %s", com->unres_name);
    2045          21 :                         gf_free(com->unres_name);
    2046          21 :                         com->unres_name = NULL;
    2047          21 :                         com->unresolved = 0;
    2048          21 :                         break;
    2049             :                 }
    2050             :         }
    2051             : 
    2052         960 :         if (!clean) return;
    2053          71 :         while (gf_list_count(parser->inserted_routes)) gf_list_rem(parser->inserted_routes, 0);
    2054             : }
    2055             : 
    2056             : 
    2057             : static void bd_set_com_node(GF_Command *com, GF_Node *node)
    2058             : {
    2059        1045 :         com->node = node;
    2060        1045 :         gf_node_register(com->node, NULL);
    2061             : }
    2062             : 
    2063        1211 : GF_Err gf_bt_parse_bifs_command(GF_BTParser *parser, char *name, GF_List *cmdList)
    2064             : {
    2065             :         s32 pos;
    2066             :         GF_Route *r;
    2067             :         GF_Node *n, *newnode;
    2068             :         GF_Command *com;
    2069             :         GF_CommandField *inf;
    2070             :         GF_FieldInfo info;
    2071             :         char *str, field[1000];
    2072        1211 :         if (!name) {
    2073         736 :                 str = gf_bt_get_next(parser, 0);
    2074             :         } else {
    2075             :                 str = name;
    2076             :         }
    2077             :         com = NULL;
    2078        1211 :         pos = -2;
    2079             :         /*REPLACE commands*/
    2080        1211 :         if (!strcmp(str, "REPLACE")) {
    2081         919 :                 str = gf_bt_get_next(parser, 1);
    2082         919 :                 if (!strcmp(str, "ROUTE")) {
    2083          20 :                         str = gf_bt_get_next(parser, 0);
    2084          20 :                         r = gf_sg_route_find_by_name(parser->load->scene_graph, str);
    2085          20 :                         if (!r) strcpy(field, str);
    2086          20 :                         str = gf_bt_get_next(parser, 0);
    2087          20 :                         if (strcmp(str, "BY")) {
    2088           0 :                                 return gf_bt_report(parser, GF_BAD_PARAM, "BY expected got %s", str);
    2089             :                         }
    2090          20 :                         com = gf_sg_command_new(parser->load->scene_graph, GF_SG_ROUTE_REPLACE);
    2091          20 :                         if (r) {
    2092           2 :                                 com->RouteID = r->ID;
    2093             :                         } else {
    2094          18 :                                 com->unres_name = gf_strdup(field);
    2095          18 :                                 com->unresolved = 1;
    2096          18 :                                 gf_list_add(parser->unresolved_routes, com);
    2097             :                         }
    2098          20 :                         gf_bt_parse_route(parser, 1, 0, com);
    2099          20 :                         gf_list_add(cmdList, com);
    2100          20 :                         return parser->last_error;
    2101             :                 }
    2102             :                 /*scene replace*/
    2103         899 :                 if (!strcmp(str, "SCENE")) {
    2104          32 :                         str = gf_bt_get_next(parser, 0);
    2105          32 :                         if (strcmp(str, "BY")) {
    2106           0 :                                 return gf_bt_report(parser, GF_BAD_PARAM, "BY expected got %s", str);
    2107             :                         }
    2108          32 :                         gf_bt_resolve_routes(parser, 1);
    2109          32 :                         com = gf_sg_command_new(parser->load->scene_graph, GF_SG_SCENE_REPLACE);
    2110          32 :                         while (gf_list_count(parser->def_nodes)) gf_list_rem(parser->def_nodes, 0);
    2111             : 
    2112             :                         while (1) {
    2113          52 :                                 str = gf_bt_get_next(parser, 0);
    2114          52 :                                 if (!strcmp(str, "PROTO") || !strcmp(str, "EXTERNPROTO")) {
    2115          20 :                                         gf_bt_parse_proto(parser, str, com->new_proto_list);
    2116          20 :                                         if (parser->last_error) goto err;
    2117             :                                 } else {
    2118             :                                         break;
    2119             :                                 }
    2120             :                         }
    2121          32 :                         n = gf_bt_sf_node(parser, str, NULL, NULL);
    2122          32 :                         com->node = n;
    2123             : 
    2124          32 :                         if (parser->last_error) goto err;
    2125          32 :                         gf_list_add(cmdList, com);
    2126          32 :                         parser->cur_com = com;
    2127          32 :                         return GF_OK;
    2128             :                 }
    2129         867 :                 if (!strcmp(str, "LAST")) pos = -1;
    2130         867 :                 else if (!strcmp(str, "BEGIN")) pos = 0;
    2131             : 
    2132             :                 gf_bt_check_code(parser, '.');
    2133             :                 strcpy(field, str);
    2134         867 :                 n = gf_bt_peek_node(parser, str);
    2135         867 :                 if (!n) return gf_bt_report(parser, GF_BAD_PARAM, "%s: unknown node", field);
    2136             : 
    2137         865 :                 str = gf_bt_get_next(parser, 0);
    2138             :                 strcpy(field, str);
    2139             :                 if (gf_bt_check_code(parser, '[')) {
    2140          53 :                         if ( (parser->last_error = gf_bt_parse_int(parser, "index", &pos)) ) return parser->last_error;
    2141             :                         if (!gf_bt_check_code(parser, ']'))
    2142           0 :                                 return gf_bt_report(parser, GF_BAD_PARAM, "] expected");
    2143             :                 }
    2144             :                 /*node replace*/
    2145         865 :                 if (!strcmp(field, "BY")) {
    2146          51 :                         com = gf_sg_command_new(parser->load->scene_graph, GF_SG_NODE_REPLACE);
    2147             :                         bd_set_com_node(com, n);
    2148          51 :                         inf = gf_sg_command_field_new(com);
    2149          51 :                         inf->new_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2150          51 :                         inf->fieldType = GF_SG_VRML_SFNODE;
    2151          51 :                         inf->field_ptr = &inf->new_node;
    2152          51 :                         gf_list_add(cmdList, com);
    2153          51 :                         parser->cur_com = com;
    2154          51 :                         return parser->last_error;
    2155             :                 }
    2156         814 :                 str = gf_bt_get_next(parser, 0);
    2157         814 :                 if (strcmp(str, "BY"))
    2158           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "BY expected got %s", str);
    2159             : 
    2160         814 :                 parser->last_error = gf_node_get_field_by_name(n, field, &info);
    2161         814 :                 if (parser->last_error)
    2162           0 :                         return gf_bt_report(parser, parser->last_error, "%s: Unknown node field", field);
    2163             : 
    2164             :                 /*field replace*/
    2165         814 :                 if (pos==-2) {
    2166         761 :                         com = gf_sg_command_new(parser->load->scene_graph, GF_SG_FIELD_REPLACE);
    2167             :                         bd_set_com_node(com, n);
    2168             : 
    2169         761 :                         inf = gf_sg_command_field_new(com);
    2170         761 :                         inf->fieldIndex = info.fieldIndex;
    2171         761 :                         inf->fieldType = info.fieldType;
    2172             : 
    2173         761 :                         switch (info.fieldType) {
    2174           6 :                         case GF_SG_VRML_SFNODE:
    2175           6 :                                 newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2176           6 :                                 if (!gf_bt_check_ndt(parser, &info, newnode, n)) goto err;
    2177           6 :                                 inf->new_node = newnode;
    2178           6 :                                 inf->field_ptr = &inf->new_node;
    2179           6 :                                 break;
    2180           5 :                         case GF_SG_VRML_MFNODE:
    2181             :                         {
    2182           5 :                                 GF_ChildNodeItem *last = NULL;
    2183             :                                 if (!gf_bt_check_code(parser, '[')) break;
    2184           5 :                                 inf->field_ptr = &inf->node_list;
    2185           5 :                                 while (!gf_bt_check_code(parser, ']')) {
    2186           5 :                                         newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2187           5 :                                         if (!newnode) goto err;
    2188           5 :                                         if (parser->last_error!=GF_OK) goto err;
    2189           5 :                                         if (!gf_bt_check_ndt(parser, &info, newnode, n)) goto err;
    2190           5 :                                         gf_node_list_add_child_last(& inf->node_list, newnode, &last);
    2191             :                                 }
    2192             :                         }
    2193           5 :                         break;
    2194         750 :                         default:
    2195         750 :                                 inf->field_ptr = gf_sg_vrml_field_pointer_new(info.fieldType);
    2196         750 :                                 info.far_ptr = inf->field_ptr;
    2197         750 :                                 if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    2198         684 :                                         gf_bt_sffield(parser, &info, n);
    2199             :                                 } else {
    2200          66 :                                         gf_bt_mffield(parser, &info, n);
    2201             :                                 }
    2202         750 :                                 if (parser->last_error) goto err;
    2203             :                                 break;
    2204             :                         }
    2205             : 
    2206         761 :                         gf_list_add(cmdList, com);
    2207         761 :                         parser->cur_com = com;
    2208         761 :                         return parser->last_error;
    2209             :                 }
    2210             :                 /*indexed field replace*/
    2211          53 :                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_INDEXED_REPLACE);
    2212             :                 bd_set_com_node(com, n);
    2213          53 :                 inf = gf_sg_command_field_new(com);
    2214          53 :                 inf->pos = pos;
    2215          53 :                 inf->fieldIndex = info.fieldIndex;
    2216          53 :                 if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    2217           0 :                         gf_bt_report(parser, GF_BAD_PARAM, "%s: MF type field expected", info.name);
    2218           0 :                         goto err;
    2219             :                 }
    2220          53 :                 inf->fieldType = gf_sg_vrml_get_sf_type(info.fieldType);
    2221          53 :                 switch (info.fieldType) {
    2222          25 :                 case GF_SG_VRML_MFNODE:
    2223          25 :                         newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2224          25 :                         if (!gf_bt_check_ndt(parser, &info, newnode, n)) goto err;
    2225          25 :                         inf->new_node = newnode;
    2226          25 :                         inf->field_ptr = &inf->new_node;
    2227          25 :                         break;
    2228          28 :                 default:
    2229          28 :                         info.fieldType = inf->fieldType;
    2230          28 :                         info.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType);
    2231          28 :                         gf_bt_sffield(parser, &info, n);
    2232          28 :                         break;
    2233             :                 }
    2234          53 :                 if (parser->last_error) goto err;
    2235          53 :                 gf_list_add(cmdList, com);
    2236          53 :                 parser->cur_com = com;
    2237          53 :                 return parser->last_error;
    2238             :         }
    2239             :         /*XREPLACE commands*/
    2240         292 :         if (!strcmp(str, "XREPLACE")) {
    2241             :                 u32 j;
    2242             :                 Bool force_sf=0;
    2243             :                 char csep;
    2244             :                 GF_Node *targetNode, *idxNode, *childNode, *fromNode;
    2245             :                 GF_FieldInfo targetField, idxField, childField, fromField;
    2246             : 
    2247             :                 idxNode = childNode = fromNode = NULL;
    2248          20 :                 str = gf_bt_get_next(parser, 1);
    2249             :                 /*get source node*/
    2250             :                 strcpy(field, str);
    2251          20 :                 targetNode = gf_bt_peek_node(parser, str);
    2252          40 :                 if (!targetNode) return gf_bt_report(parser, GF_BAD_PARAM, "%s: unknown node", field);
    2253             :                 if (!gf_bt_check_code(parser, '.')) {
    2254           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "XREPLACE: '.' expected");
    2255             :                 }
    2256             :                 /*get source field*/
    2257          20 :                 str = gf_bt_get_next(parser, 0);
    2258             :                 strcpy(field, str);
    2259          20 :                 parser->last_error = gf_node_get_field_by_name(targetNode, field, &targetField);
    2260          20 :                 if (parser->last_error)
    2261           0 :                         return gf_bt_report(parser, parser->last_error, "%s: Unknown node field", field);
    2262             : 
    2263             :                 if (gf_bt_check_code(parser, '[')) {
    2264          10 :                         pos = -2;
    2265          10 :                         str = gf_bt_get_next(parser, 1);
    2266             :                         force_sf = 1;
    2267          10 :                         if (sscanf(str, "%d", &pos) != 1) {
    2268          10 :                                 pos = -2;
    2269          10 :                                 if (!strcmp(str, "LAST")) pos = -1;
    2270          10 :                                 else if (!strcmp(str, "first")) pos = 0;
    2271             :                                 else {
    2272             :                                         strcpy(field, str);
    2273             :                                         /*get idx node*/
    2274          10 :                                         idxNode = gf_bt_peek_node(parser, str);
    2275          10 :                                         if (!idxNode) return gf_bt_report(parser, GF_BAD_PARAM, "%s: unknown node", field);
    2276             :                                         if (!gf_bt_check_code(parser, '.'))
    2277           0 :                                                 return gf_bt_report(parser, GF_BAD_PARAM, "XREPLACE: '.' expected");
    2278             : 
    2279             :                                         /*get idx field*/
    2280          10 :                                         str = gf_bt_get_next(parser, 0);
    2281             :                                         strcpy(field, str);
    2282          10 :                                         parser->last_error = gf_node_get_field_by_name(idxNode, field, &idxField);
    2283          10 :                                         if (parser->last_error)
    2284           0 :                                                 return gf_bt_report(parser, parser->last_error, "%s: Unknown node field", field);
    2285             :                                 }
    2286             :                         }
    2287             :                         gf_bt_check_code(parser, ']');
    2288             : 
    2289             :                         /*check if we have a child node*/
    2290             :                         if (gf_bt_check_code(parser, '.')) {
    2291          10 :                                 s32 apos = pos;
    2292             :                                 force_sf = 0;
    2293          10 :                                 if (idxNode) {
    2294             :                                         apos = 0;
    2295          10 :                                         switch (idxField.fieldType) {
    2296           0 :                                         case GF_SG_VRML_SFBOOL:
    2297           0 :                                                 if (*(SFBool*)idxField.far_ptr) apos = 1;
    2298             :                                                 break;
    2299          10 :                                         case GF_SG_VRML_SFINT32:
    2300          10 :                                                 if (*(SFInt32*)idxField.far_ptr >=0) apos = *(SFInt32*)idxField.far_ptr;
    2301             :                                                 break;
    2302           0 :                                         case GF_SG_VRML_SFFLOAT:
    2303           0 :                                                 if ( (*(SFFloat *)idxField.far_ptr) >=0) apos = (s32) floor( FIX2FLT(*(SFFloat*)idxField.far_ptr) );
    2304             :                                                 break;
    2305           0 :                                         case GF_SG_VRML_SFTIME:
    2306           0 :                                                 if ( (*(SFTime *)idxField.far_ptr) >=0) apos = (s32) floor( (*(SFTime *)idxField.far_ptr) );
    2307             :                                                 break;
    2308             :                                         }
    2309             :                                 }
    2310          10 :                                 childNode = gf_node_list_get_child(*(GF_ChildNodeItem **)targetField.far_ptr, apos);
    2311          10 :                                 if (!childNode)
    2312           0 :                                         return gf_bt_report(parser, GF_BAD_PARAM, "Cannot find child node at specified index");
    2313             : 
    2314          10 :                                 str = gf_bt_get_next(parser, 0);
    2315             :                                 strcpy(field, str);
    2316          10 :                                 parser->last_error = gf_node_get_field_by_name(childNode, field, &childField);
    2317          10 :                                 if (parser->last_error)
    2318           0 :                                         return gf_bt_report(parser, parser->last_error, "%s: Unknown node field", field);
    2319             :                         }
    2320             :                 }
    2321             : 
    2322          20 :                 str = gf_bt_get_next(parser, 0);
    2323          20 :                 if (strcmp(str, "BY"))
    2324           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "BY expected got %s", str);
    2325             : 
    2326             :                 /*peek the next word*/
    2327             :                 j = 0;
    2328          20 :                 while (strchr(" \n\t\0", parser->line_buffer[parser->line_pos + j])) j++;
    2329          20 :                 str = parser->line_buffer + parser->line_pos + j;
    2330             :                 j = 0;
    2331          20 :                 while (!strchr(" .\0", str[j])) j++;
    2332             :                 csep = str[j];
    2333          20 :                 str[j]=0;
    2334             :                 strcpy(field, str);
    2335          20 :                 str[j] = csep;
    2336          20 :                 fromNode = gf_bt_peek_node(parser, field);
    2337          20 :                 if (fromNode) {
    2338          10 :                         gf_bt_get_next(parser, 1);
    2339             : 
    2340             :                         if (!gf_bt_check_code(parser, '.')) {
    2341           0 :                                 return gf_bt_report(parser, GF_BAD_PARAM, "XREPLACE: '.' expected");
    2342             :                         }
    2343             :                         /*get source field*/
    2344          10 :                         str = gf_bt_get_next(parser, 0);
    2345             :                         strcpy(field, str);
    2346          10 :                         parser->last_error = gf_node_get_field_by_name(fromNode, field, &fromField);
    2347          10 :                         if (parser->last_error)
    2348           0 :                                 return gf_bt_report(parser, parser->last_error, "%s: Unknown node field", field);
    2349             : 
    2350             :                 } else {
    2351             :                         /*regular parsing*/
    2352             :                 }
    2353             : 
    2354          20 :                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_XREPLACE);
    2355             :                 bd_set_com_node(com, targetNode);
    2356          20 :                 if (fromNode) {
    2357          10 :                         com->fromNodeID = gf_node_get_id(fromNode);
    2358          10 :                         com->fromFieldIndex = fromField.fieldIndex;
    2359             :                 }
    2360          20 :                 if (idxNode) {
    2361          10 :                         com->toNodeID = gf_node_get_id(idxNode);
    2362          10 :                         com->toFieldIndex = idxField.fieldIndex;
    2363             :                 }
    2364          20 :                 if (childNode) {
    2365          10 :                         com->ChildNodeTag = gf_node_get_tag(childNode);
    2366          10 :                         if (com->ChildNodeTag==1) {
    2367           0 :                                 com->ChildNodeTag = ((GF_ProtoInstance*)childNode)->proto_interface->ID;
    2368           0 :                                 com->ChildNodeTag = -com->ChildNodeTag ;
    2369             :                         }
    2370          10 :                         com->child_field = childField.fieldIndex;
    2371             :                 }
    2372          20 :                 inf = gf_sg_command_field_new(com);
    2373          20 :                 inf->fieldIndex = targetField.fieldIndex;
    2374          20 :                 inf->pos = pos;
    2375          20 :                 if (force_sf) {
    2376           0 :                         inf->fieldType = gf_sg_vrml_get_sf_type(targetField.fieldType);
    2377          20 :                 } else if (childNode) {
    2378          10 :                         inf->fieldType = childField.fieldType;
    2379             :                 } else {
    2380          10 :                         inf->fieldType = targetField.fieldType;
    2381             :                 }
    2382          20 :                 if (!fromNode) {
    2383          10 :                         switch (inf->fieldType) {
    2384           0 :                         case GF_SG_VRML_SFNODE:
    2385           0 :                                 inf->new_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2386           0 :                                 inf->field_ptr = &inf->new_node;
    2387           0 :                                 if (childNode) {
    2388           0 :                                         if (!gf_bt_check_ndt(parser, &childField, inf->new_node, childNode)) goto err;
    2389             :                                 } else {
    2390           0 :                                         if (!gf_bt_check_ndt(parser, &targetField, inf->new_node, targetNode)) goto err;
    2391             :                                 }
    2392             :                                 break;
    2393           0 :                         case GF_SG_VRML_MFNODE:
    2394             :                         {
    2395           0 :                                 GF_ChildNodeItem *last = NULL;
    2396             :                                 if (!gf_bt_check_code(parser, '[')) break;
    2397           0 :                                 inf->field_ptr = &inf->node_list;
    2398           0 :                                 while (!gf_bt_check_code(parser, ']')) {
    2399           0 :                                         newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2400           0 :                                         if (!newnode) goto err;
    2401           0 :                                         if (parser->last_error!=GF_OK) goto err;
    2402             : 
    2403           0 :                                         if (childNode) {
    2404           0 :                                                 if (!gf_bt_check_ndt(parser, &childField, inf->new_node, childNode)) goto err;
    2405             :                                         } else {
    2406           0 :                                                 if (!gf_bt_check_ndt(parser, &targetField, inf->new_node, targetNode)) goto err;
    2407             :                                         }
    2408             : 
    2409           0 :                                         gf_node_list_add_child_last(& inf->node_list, newnode, &last);
    2410             :                                 }
    2411             :                         }
    2412           0 :                         break;
    2413          10 :                         default:
    2414          10 :                                 inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType);
    2415          10 :                                 info.far_ptr = inf->field_ptr;
    2416          10 :                                 info.fieldType = inf->fieldType;
    2417          10 :                                 info.name = targetField.name;
    2418             : 
    2419          10 :                                 if (gf_sg_vrml_is_sf_field(inf->fieldType)) {
    2420          10 :                                         gf_bt_sffield(parser, &info, childNode ? childNode : targetNode);
    2421             :                                 } else {
    2422           0 :                                         gf_bt_mffield(parser, &info, childNode ? childNode : targetNode);
    2423             :                                 }
    2424          10 :                                 if (parser->last_error) goto err;
    2425             :                                 break;
    2426             :                         }
    2427          10 :                 }
    2428             : 
    2429          20 :                 if (parser->last_error) goto err;
    2430          20 :                 gf_list_add(cmdList, com);
    2431          20 :                 parser->cur_com = com;
    2432          20 :                 return parser->last_error;
    2433             :         }
    2434             : 
    2435             : 
    2436             :         /*INSERT commands*/
    2437         272 :         if (!strcmp(str, "INSERT") || !strcmp(str, "APPEND")) {
    2438         122 :                 Bool is_append = !strcmp(str, "APPEND") ? 1 : 0;
    2439         122 :                 str = gf_bt_get_next(parser, 0);
    2440         122 :                 if (!strcmp(str, "ROUTE")) {
    2441          37 :                         com = gf_sg_command_new(parser->load->scene_graph, GF_SG_ROUTE_INSERT);
    2442          37 :                         gf_bt_parse_route(parser, 0, 1, com);
    2443          37 :                         if (parser->last_error) goto err;
    2444          37 :                         gf_list_add(cmdList, com);
    2445          37 :                         gf_list_add(parser->inserted_routes, com);
    2446          37 :                         parser->cur_com = com;
    2447          37 :                         return GF_OK;
    2448             :                 }
    2449          85 :                 if (strcmp(str, "AT") && strcmp(str, "TO")) {
    2450           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, (char*) (is_append ? "TO expected got %s" : "AT expected got %s"), str);
    2451             :                 }
    2452          85 :                 str = gf_bt_get_next(parser, 1);
    2453             :                 strcpy(field, str);
    2454          85 :                 n = gf_bt_peek_node(parser, str);
    2455          85 :                 if (!n) {
    2456           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown node", field);
    2457             :                 }
    2458             :                 if (!gf_bt_check_code(parser, '.')) {
    2459           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, ". expected");
    2460             :                 }
    2461          85 :                 str = gf_bt_get_next(parser, 1);
    2462             :                 strcpy(field, str);
    2463          85 :                 if (!is_append) {
    2464             :                         if (!gf_bt_check_code(parser, '[')) {
    2465           0 :                                 return gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
    2466             :                         }
    2467          30 :                         gf_bt_parse_int(parser, "index", &pos);
    2468             :                         if (!gf_bt_check_code(parser, ']')) {
    2469           0 :                                 return gf_bt_report(parser, GF_BAD_PARAM, "] expected");
    2470             :                         }
    2471             :                 } else {
    2472             :                         if (gf_bt_check_code(parser, '[')) {
    2473           0 :                                 return gf_bt_report(parser, GF_BAD_PARAM, "[ unexpected in Append command");
    2474             :                         }
    2475          55 :                         pos = -1;
    2476             :                 }
    2477          85 :                 gf_node_get_field_by_name(n, field, &info);
    2478          85 :                 if (!strcmp(field, "children")) {
    2479          75 :                         newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2480          75 :                         if (parser->last_error) goto err;
    2481             : 
    2482          75 :                         if (!gf_bt_check_ndt(parser, &info, newnode, n)) goto err;
    2483          75 :                         com = gf_sg_command_new(parser->load->scene_graph, GF_SG_NODE_INSERT);
    2484             :                         bd_set_com_node(com, n);
    2485          75 :                         inf = gf_sg_command_field_new(com);
    2486          75 :                         inf->pos = pos;
    2487          75 :                         inf->new_node = newnode;
    2488          75 :                         inf->fieldType = GF_SG_VRML_SFNODE;
    2489          75 :                         inf->field_ptr = &inf->new_node;
    2490          75 :                         if (parser->last_error) goto err;
    2491          75 :                         parser->cur_com = com;
    2492          75 :                         return gf_list_add(cmdList, com);
    2493             :                 }
    2494          10 :                 if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    2495           0 :                         gf_bt_report(parser, GF_BAD_PARAM, "%s: MF type field expected", info.name);
    2496             :                         goto err;
    2497             :                 }
    2498          10 :                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_INDEXED_INSERT);
    2499             :                 bd_set_com_node(com, n);
    2500          10 :                 inf = gf_sg_command_field_new(com);
    2501          10 :                 inf->pos = pos;
    2502          10 :                 inf->fieldIndex = info.fieldIndex;
    2503          10 :                 inf->fieldType = gf_sg_vrml_get_sf_type(info.fieldType);
    2504          10 :                 switch (info.fieldType) {
    2505           0 :                 case GF_SG_VRML_MFNODE:
    2506           0 :                         inf->new_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2507           0 :                         inf->field_ptr = &inf->new_node;
    2508           0 :                         break;
    2509          10 :                 default:
    2510          10 :                         info.fieldType = inf->fieldType;
    2511          10 :                         inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType);
    2512          10 :                         info.far_ptr = inf->field_ptr;
    2513          10 :                         gf_bt_sffield(parser, &info, n);
    2514          10 :                         break;
    2515             :                 }
    2516          10 :                 if (parser->last_error) goto err;
    2517          10 :                 gf_list_add(cmdList, com);
    2518          10 :                 parser->cur_com = com;
    2519          10 :                 return parser->last_error;
    2520             :         }
    2521             :         /*DELETE commands*/
    2522         150 :         if (!strcmp(str, "DELETE")) {
    2523          75 :                 str = gf_bt_get_next(parser, 1);
    2524          75 :                 if (!strcmp(str, "ROUTE")) {
    2525          35 :                         str = gf_bt_get_next(parser, 0);
    2526          35 :                         com = gf_sg_command_new(parser->load->scene_graph, GF_SG_ROUTE_DELETE);
    2527          35 :                         com->RouteID = gf_bt_get_route(parser, str);
    2528          35 :                         if (!com->RouteID) {
    2529           3 :                                 com->unres_name = gf_strdup(str);
    2530           3 :                                 com->unresolved = 1;
    2531           3 :                                 gf_list_add(parser->unresolved_routes, com);
    2532             :                         }
    2533             :                         /*for bt<->xmt conversions*/
    2534          35 :                         com->def_name = gf_strdup(str);
    2535          35 :                         return gf_list_add(cmdList, com);
    2536             :                 }
    2537             :                 strcpy(field, str);
    2538          40 :                 n = gf_bt_peek_node(parser, str);
    2539          40 :                 if (!n) {
    2540           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "DELETE %s: Unknown Node", field);
    2541             :                 }
    2542             :                 if (!gf_bt_check_code(parser, '.')) {
    2543          25 :                         com = gf_sg_command_new(parser->load->scene_graph, GF_SG_NODE_DELETE);
    2544             :                         bd_set_com_node(com, n);
    2545          25 :                         return gf_list_add(cmdList, com);
    2546             :                 }
    2547          15 :                 str = gf_bt_get_next(parser, 0);
    2548          15 :                 if (gf_node_get_field_by_name(n, str, &info) != GF_OK) {
    2549           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "%s not a field of node %s", str, gf_node_get_class_name(n) );
    2550             :                 }
    2551             :                 if (gf_bt_check_code(parser, '[')) {
    2552          10 :                         gf_bt_parse_int(parser, "index", &pos);
    2553             :                         if (!gf_bt_check_code(parser, ']'))
    2554           0 :                                 return gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
    2555             :                 }
    2556          15 :                 if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    2557           5 :                         if (info.fieldType == GF_SG_VRML_SFNODE) {
    2558           5 :                                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_FIELD_REPLACE);
    2559             :                                 bd_set_com_node(com, n);
    2560           5 :                                 inf = gf_sg_command_field_new(com);
    2561           5 :                                 inf->fieldIndex = info.fieldIndex;
    2562           5 :                                 inf->fieldType = info.fieldType;
    2563           5 :                                 inf->new_node = NULL;
    2564           5 :                                 inf->field_ptr = &inf->new_node;
    2565           5 :                                 return gf_list_add(cmdList, com);
    2566             :                         }
    2567           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "%s is an SFField - cannot indexed delete", info.name);
    2568             :                 }
    2569             : 
    2570          10 :                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_INDEXED_DELETE);
    2571             :                 bd_set_com_node(com, n);
    2572          10 :                 inf = gf_sg_command_field_new(com);
    2573          10 :                 inf->fieldIndex = info.fieldIndex;
    2574          10 :                 inf->fieldType = info.fieldType;
    2575          10 :                 inf->pos = pos;
    2576          10 :                 return gf_list_add(cmdList, com);
    2577             :         }
    2578             :         /*Extended BIFS commands*/
    2579             : 
    2580             :         /*GlobalQP commands*/
    2581          75 :         if (!strcmp(str, "GLOBALQP")) {
    2582          10 :                 newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2583          10 :                 if (newnode && (newnode->sgprivate->tag != TAG_MPEG4_QuantizationParameter)) {
    2584           0 :                         gf_bt_report(parser, GF_BAD_PARAM, "Only QuantizationParameter node allowed in GLOBALQP");
    2585           0 :                         gf_node_unregister(newnode, NULL);
    2586           0 :                         return parser->last_error;
    2587             :                 }
    2588          10 :                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_GLOBAL_QUANTIZER);
    2589          10 :                 com->node = NULL;
    2590          10 :                 inf = gf_sg_command_field_new(com);
    2591          10 :                 inf->new_node = newnode;
    2592          10 :                 inf->field_ptr = &inf->new_node;
    2593          10 :                 inf->fieldType = GF_SG_VRML_SFNODE;
    2594          10 :                 return gf_list_add(cmdList, com);
    2595             :         }
    2596             : 
    2597             :         /*MultipleReplace commands*/
    2598          65 :         if (!strcmp(str, "MULTIPLEREPLACE")) {
    2599          15 :                 str = gf_bt_get_next(parser, 0);
    2600             :                 strcpy(field, str);
    2601          15 :                 n = gf_bt_peek_node(parser, str);
    2602          15 :                 if (!n) {
    2603           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown node", field);
    2604             :                 }
    2605             :                 if (!gf_bt_check_code(parser, '{')) {
    2606           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "{ expected");
    2607             :                 }
    2608          15 :                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_MULTIPLE_REPLACE);
    2609             :                 bd_set_com_node(com, n);
    2610             : 
    2611             :                 while (!gf_bt_check_code(parser, '}')) {
    2612          35 :                         str = gf_bt_get_next(parser, 0);
    2613          35 :                         parser->last_error = gf_node_get_field_by_name(n, str, &info);
    2614          35 :                         if (parser->last_error) {
    2615           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown node field", str);
    2616           0 :                                 goto err;
    2617             :                         }
    2618          35 :                         inf = gf_sg_command_field_new(com);
    2619          35 :                         inf->fieldIndex = info.fieldIndex;
    2620          35 :                         inf->fieldType = info.fieldType;
    2621          35 :                         inf->pos = -1;
    2622             : 
    2623          35 :                         switch (info.fieldType) {
    2624          10 :                         case GF_SG_VRML_SFNODE:
    2625          10 :                                 inf->new_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2626          10 :                                 if (parser->last_error) goto err;
    2627          10 :                                 if (!gf_bt_check_ndt(parser, &info, inf->new_node, n)) goto err;
    2628          10 :                                 inf->field_ptr = &inf->new_node;
    2629          10 :                                 break;
    2630           5 :                         case GF_SG_VRML_MFNODE:
    2631             :                         {
    2632           5 :                                 GF_ChildNodeItem *last = NULL;
    2633             :                                 if (!gf_bt_check_code(parser, '[')) {
    2634           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
    2635           0 :                                         goto err;
    2636             :                                 }
    2637           5 :                                 info.far_ptr = inf->field_ptr = &inf->node_list;
    2638           5 :                                 while (!gf_bt_check_code(parser, ']')) {
    2639           5 :                                         newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2640           5 :                                         if (parser->last_error!=GF_OK) goto err;
    2641           5 :                                         if (!gf_bt_check_ndt(parser, &info, newnode, n)) goto err;
    2642           5 :                                         gf_node_list_add_child_last( & inf->node_list, newnode, &last);
    2643             :                                 }
    2644             :                         }
    2645           5 :                         break;
    2646          20 :                         default:
    2647          20 :                                 info.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType);
    2648          20 :                                 if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    2649          20 :                                         gf_bt_sffield(parser, &info, n);
    2650             :                                 } else {
    2651           0 :                                         gf_bt_mffield(parser, &info, n);
    2652             :                                 }
    2653          20 :                                 if (parser->last_error) goto err;
    2654             :                                 break;
    2655             :                         }
    2656             :                 }
    2657          15 :                 parser->cur_com = com;
    2658          15 :                 return gf_list_add(cmdList, com);
    2659             :         }
    2660             : 
    2661             :         /*MultipleIndexReplace commands*/
    2662          50 :         if (!strcmp(str, "MULTIPLEINDREPLACE")) {
    2663          10 :                 str = gf_bt_get_next(parser, 1);
    2664             :                 strcpy(field, str);
    2665          10 :                 n = gf_bt_peek_node(parser, str);
    2666          10 :                 if (!n) {
    2667           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown node", field);
    2668             :                 }
    2669             :                 if (!gf_bt_check_code(parser, '.')) {
    2670           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, ". expected");
    2671             :                 }
    2672          10 :                 str = gf_bt_get_next(parser, 0);
    2673          10 :                 parser->last_error = gf_node_get_field_by_name(n, str, &info);
    2674          10 :                 if (parser->last_error) {
    2675           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown field", info.name);
    2676             :                 }
    2677          10 :                 if (gf_sg_vrml_is_sf_field(info.fieldType)) {
    2678           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "Only MF field allowed");
    2679             :                 }
    2680             :                 if (!gf_bt_check_code(parser, '[')) {
    2681           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
    2682             :                 }
    2683             : 
    2684          10 :                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_MULTIPLE_INDEXED_REPLACE);
    2685             :                 bd_set_com_node(com, n);
    2686          10 :                 info.fieldType = gf_sg_vrml_get_sf_type(info.fieldType);
    2687             : 
    2688          10 :                 while (!gf_bt_check_code(parser, ']')) {
    2689          30 :                         pos=0;
    2690          30 :                         if (gf_bt_parse_int(parser, "position", (SFInt32 *)&pos)) goto err;
    2691          30 :                         str = gf_bt_get_next(parser, 0);
    2692          30 :                         if (strcmp(str, "BY")) {
    2693           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "BY expected");
    2694           0 :                                 goto err;
    2695             :                         }
    2696          30 :                         inf = gf_sg_command_field_new(com);
    2697          30 :                         inf->fieldIndex = info.fieldIndex;
    2698          30 :                         inf->fieldType = info.fieldType;
    2699          30 :                         inf->pos = pos;
    2700          30 :                         if (inf->fieldType==GF_SG_VRML_SFNODE) {
    2701           0 :                                 info.far_ptr = inf->field_ptr = &inf->new_node;
    2702           0 :                                 inf->new_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
    2703           0 :                                 if (parser->last_error) goto err;
    2704           0 :                                 if (!gf_bt_check_ndt(parser, &info, inf->new_node, n)) goto err;
    2705           0 :                                 inf->field_ptr = &inf->new_node;
    2706             :                         } else {
    2707          30 :                                 info.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType);
    2708          30 :                                 gf_bt_sffield(parser, &info, n);
    2709          30 :                                 if (parser->last_error) goto err;
    2710             :                         }
    2711             :                 }
    2712          10 :                 parser->cur_com = com;
    2713          10 :                 return gf_list_add(cmdList, com);
    2714             :         }
    2715             : 
    2716          40 :         if (!strcmp(str, "XDELETE")) {
    2717          10 :                 str = gf_bt_get_next(parser, 1);
    2718             :                 strcpy(field, str);
    2719          10 :                 n = gf_bt_peek_node(parser, str);
    2720          10 :                 if (!n) {
    2721           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown Node", field);
    2722             :                 }
    2723          10 :                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_NODE_DELETE_EX);
    2724             :                 bd_set_com_node(com, n);
    2725          10 :                 return gf_list_add(cmdList, com);
    2726             :         }
    2727             : 
    2728          30 :         if (!strcmp(str, "INSERTPROTO")) {
    2729             :                 if (!gf_bt_check_code(parser, '[')) {
    2730           0 :                         return gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
    2731             :                 }
    2732          10 :                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_PROTO_INSERT);
    2733          10 :                 while (!gf_bt_check_code(parser, ']')) {
    2734          10 :                         parser->last_error = gf_bt_parse_proto(parser, NULL, com->new_proto_list);
    2735          10 :                         if (parser->last_error) goto err;
    2736             :                 }
    2737          10 :                 gf_list_add(cmdList, com);
    2738          10 :                 return GF_OK;
    2739             :         }
    2740          20 :         if (!strcmp(str, "DELETEPROTO")) {
    2741             :                 if (!gf_bt_check_code(parser, '[')) {
    2742          10 :                         com = gf_sg_command_new(parser->load->scene_graph, GF_SG_PROTO_DELETE_ALL);
    2743          10 :                         str = gf_bt_get_next(parser, 0);
    2744          10 :                         if (strcmp(str, "ALL")) {
    2745           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "ALL expected");
    2746           0 :                                 goto err;
    2747             :                         }
    2748          10 :                         return gf_list_add(cmdList, com);
    2749             :                 }
    2750          10 :                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_PROTO_DELETE);
    2751          10 :                 while (!gf_bt_check_code(parser, ']')) {
    2752             :                         GF_Proto *proto;
    2753          10 :                         str = gf_bt_get_next(parser, 0);
    2754          10 :                         proto = gf_sg_find_proto(parser->load->scene_graph, 0, str);
    2755          10 :                         if (!proto) {
    2756           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown proto", str);
    2757           0 :                                 goto err;
    2758             :                         }
    2759          10 :                         com->del_proto_list = (u32*)gf_realloc(com->del_proto_list, sizeof(u32)*(com->del_proto_list_size+1));
    2760          10 :                         com->del_proto_list[com->del_proto_list_size] = proto->ID;
    2761          10 :                         com->del_proto_list_size++;
    2762             :                 }
    2763          10 :                 gf_list_add(cmdList, com);
    2764          10 :                 return GF_OK;
    2765             :         }
    2766           0 :         return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown command syntax, str");
    2767             : 
    2768           0 : err:
    2769           0 :         if (com) gf_sg_command_del(com);
    2770           0 :         return parser->last_error;
    2771             : }
    2772             : 
    2773             : GF_Descriptor *gf_bt_parse_descriptor(GF_BTParser *parser, char *name);
    2774             : 
    2775             : #ifndef GPAC_MINIMAL_ODF
    2776             : GF_IPMPX_Data *gf_bt_parse_ipmpx(GF_BTParser *parser, char *name)
    2777             : {
    2778             :         char *str, field[500];
    2779             :         GF_IPMPX_Data *desc, *subdesc;
    2780             :         GF_Descriptor *oddesc;
    2781             :         GF_Err e;
    2782             :         u32 type;
    2783             :         u8 tag;
    2784             :         if (name) {
    2785             :                 str = name;
    2786             :         } else {
    2787             :                 str = gf_bt_get_next(parser, 0);
    2788             :         }
    2789             :         tag = gf_ipmpx_get_tag(str);
    2790             :         if (!tag) {
    2791             :                 gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown IPMPX Data", str);
    2792             :                 return NULL;
    2793             :         }
    2794             :         desc = gf_ipmpx_data_new(tag);
    2795             : 
    2796             :         if (!desc) return NULL;
    2797             :         if (!gf_bt_check_code(parser, '{')) return desc;
    2798             : 
    2799             :         while (1) {
    2800             :                 /*done*/
    2801             :                 if (gf_bt_check_code(parser, '}')) break;
    2802             :                 str = gf_bt_get_next(parser, 0);
    2803             :                 strcpy(field, str);
    2804             :                 type = gf_ipmpx_get_field_type(desc, str);
    2805             :                 switch (type) {
    2806             :                 /*single descriptor*/
    2807             :                 case GF_ODF_FT_OD:
    2808             :                         assert(desc->tag==GF_IPMPX_CONNECT_TOOL_TAG);
    2809             :                         str = gf_bt_get_next(parser, 0);
    2810             :                         oddesc = gf_bt_parse_descriptor(parser, str);
    2811             :                         if (!oddesc) {
    2812             :                                 gf_bt_report(parser, GF_BAD_PARAM, "Unknown desc %s in field %s", str, field);
    2813             :                                 gf_ipmpx_data_del(desc);
    2814             :                                 return NULL;
    2815             :                         }
    2816             :                         assert(oddesc->tag==GF_ODF_IPMP_TAG);
    2817             :                         ((GF_IPMPX_ConnectTool *)desc)->toolDescriptor = (GF_IPMP_Descriptor *)oddesc;
    2818             :                         break;
    2819             :                 /*descriptor list*/
    2820             :                 case GF_ODF_FT_OD_LIST:
    2821             :                         assert(desc->tag==GF_IPMPX_GET_TOOLS_RESPONSE_TAG);
    2822             :                         if (gf_bt_check_code(parser, '[')) {
    2823             :                                 while (!gf_bt_check_code(parser, ']')) {
    2824             :                                         GF_Descriptor *ipmp_t = gf_bt_parse_descriptor(parser, NULL);
    2825             :                                         if (!ipmp_t) {
    2826             :                                                 gf_ipmpx_data_del(desc);
    2827             :                                                 parser->last_error = GF_BAD_PARAM;
    2828             :                                                 return NULL;
    2829             :                                         }
    2830             :                                         assert(ipmp_t->tag==GF_ODF_IPMP_TOOL_TAG);
    2831             :                                         gf_list_add( ((GF_IPMPX_GetToolsResponse *)desc)->ipmp_tools, ipmp_t);
    2832             :                                 }
    2833             :                         }
    2834             :                         break;
    2835             : 
    2836             :                 /*IPMPX ByteArray list*/
    2837             :                 case GF_ODF_FT_IPMPX_BA_LIST:
    2838             :                         if (gf_bt_check_code(parser, '[')) {
    2839             :                                 while (!gf_bt_check_code(parser, ']')) {
    2840             :                                         str = gf_bt_get_next(parser, 0);
    2841             :                                         if (!str) continue;
    2842             :                                         if (gf_ipmpx_set_byte_array(desc, field, str) != GF_OK) {
    2843             :                                                 gf_bt_report(parser, GF_OK, "Invalid ipmpx %s in field %s - skipping", str, field);
    2844             :                                         }
    2845             :                                         gf_bt_check_code(parser, ',');
    2846             :                                 }
    2847             :                         }
    2848             :                         break;
    2849             :                 /*IPMPX ByteArray: check if declared as sub-data or not*/
    2850             :                 case GF_ODF_FT_IPMPX_BA:
    2851             :                         str = NULL;
    2852             :                         if (gf_bt_check_code(parser, '{')) {
    2853             :                                 str = gf_bt_get_next(parser, 0);
    2854             :                                 if (stricmp(str, "array")) {
    2855             :                                         gf_bt_report(parser, GF_BAD_PARAM, "IPMP ByteArray syntax is %s { array \"...\" } or %s \"....\"\n", field, field);
    2856             :                                         gf_ipmpx_data_del(desc);
    2857             :                                         return NULL;
    2858             :                                 }
    2859             :                                 str = gf_bt_get_next(parser, 0);
    2860             :                                 gf_bt_check_code(parser, '}');
    2861             :                         } else {
    2862             :                                 str = gf_bt_get_next(parser, 0);
    2863             :                         }
    2864             :                         e = gf_ipmpx_set_byte_array(desc, field, str);
    2865             :                         if (e) {
    2866             :                                 gf_bt_report(parser, e, "Error assigning IPMP ByteArray %s\n", field);
    2867             :                                 gf_ipmpx_data_del(desc);
    2868             :                                 return NULL;
    2869             :                         }
    2870             :                         break;
    2871             :                 /*IPMPX Data list*/
    2872             :                 case GF_ODF_FT_IPMPX_LIST:
    2873             :                         if (gf_bt_check_code(parser, '[')) {
    2874             :                                 while (!gf_bt_check_code(parser, ']')) {
    2875             :                                         subdesc = gf_bt_parse_ipmpx(parser, NULL);
    2876             :                                         if (!subdesc) {
    2877             :                                                 gf_ipmpx_data_del(desc);
    2878             :                                                 parser->last_error = GF_BAD_PARAM;
    2879             :                                                 return NULL;
    2880             :                                         }
    2881             :                                         if (gf_ipmpx_set_sub_data(desc, field, subdesc) != GF_OK) {
    2882             :                                                 gf_bt_report(parser, GF_BAD_PARAM, "Invalid ipmpx %s in field %s - skipping", str, field);
    2883             :                                                 gf_ipmpx_data_del(subdesc);
    2884             :                                         }
    2885             :                                 }
    2886             :                         }
    2887             :                         break;
    2888             :                 /*regular IPMPX Data*/
    2889             :                 case GF_ODF_FT_IPMPX:
    2890             :                         str = gf_bt_get_next(parser, 0);
    2891             :                         subdesc = gf_bt_parse_ipmpx(parser, str);
    2892             :                         if (!subdesc) {
    2893             :                                 gf_bt_report(parser, GF_BAD_PARAM, "Unknown ipmpx %s in field %s", str, field);
    2894             :                                 gf_ipmpx_data_del(desc);
    2895             :                                 return NULL;
    2896             :                         }
    2897             :                         if (gf_ipmpx_set_sub_data(desc, field, subdesc) != GF_OK) {
    2898             :                                 gf_bt_report(parser, GF_BAD_PARAM, "Invalid ipmpx in field %s - skipping", field);
    2899             :                                 gf_ipmpx_data_del(subdesc);
    2900             :                         }
    2901             :                         break;
    2902             :                 default:
    2903             :                         str = gf_bt_get_next(parser, 0);
    2904             :                         parser->last_error = gf_ipmpx_set_field(desc, field, str);
    2905             : 
    2906             :                         if (parser->last_error) {
    2907             :                                 gf_bt_report(parser, GF_BAD_PARAM, "Invalid value %s in field %s", str, field);
    2908             :                                 gf_ipmpx_data_del(desc);
    2909             :                                 return NULL;
    2910             :                         }
    2911             :                         break;
    2912             :                 }
    2913             :         }
    2914             :         return desc;
    2915             : }
    2916             : #endif
    2917             : 
    2918        1827 : static void gf_bt_add_desc(GF_BTParser *parser, GF_Descriptor *par, GF_Descriptor *child, char *fieldName)
    2919             : {
    2920        1827 :         GF_Err e = gf_odf_desc_add_desc(par, child);
    2921        1827 :         if (e) {
    2922           0 :                 gf_bt_report(parser, GF_OK, "Invalid child descriptor in field %s - skipping", fieldName);
    2923           0 :                 gf_odf_desc_del(child);
    2924             :         }
    2925        1827 : }
    2926             : 
    2927        2388 : GF_Descriptor *gf_bt_parse_descriptor(GF_BTParser *parser, char *name)
    2928             : {
    2929             :         char *str, field[500];
    2930             :         GF_Descriptor *desc, *subdesc;
    2931             :         u32 type;
    2932             :         u8 tag;
    2933        2388 :         if (name) {
    2934             :                 str = name;
    2935             :         } else {
    2936         711 :                 str = gf_bt_get_next(parser, 0);
    2937             :         }
    2938        2388 :         tag = gf_odf_get_tag_by_name(str);
    2939        2388 :         if (!tag) {
    2940           0 :                 gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown descriptor", str);
    2941           0 :                 return NULL;
    2942             :         }
    2943        2388 :         desc = gf_odf_desc_new(tag);
    2944             : 
    2945        2388 :         if (!desc) return NULL;
    2946             :         if (!gf_bt_check_code(parser, '{')) return desc;
    2947             : 
    2948             :         while (1) {
    2949             :                 Bool is_anim_mask = 0;
    2950             :                 /*done*/
    2951             :                 if (gf_bt_check_code(parser, '}')) break;
    2952        7254 :                 str = gf_bt_get_next(parser, 0);
    2953             :                 strcpy(field, str);
    2954             : 
    2955        7254 :                 if ((tag==GF_ODF_BIFS_CFG_TAG) && !strcmp(field, "animationMask")) {
    2956           0 :                         gf_bt_get_next(parser, 0);
    2957             :                         if (gf_bt_check_code(parser, '{')) is_anim_mask = 1;
    2958           0 :                         str = gf_bt_get_next(parser, 0);
    2959             :                         strcpy(field, str);
    2960             :                 }
    2961             : 
    2962        7254 :                 type = gf_odf_get_field_type(desc, str);
    2963        7254 :                 switch (type) {
    2964             : #ifndef GPAC_MINIMAL_ODF
    2965             :                 /*IPMPX list*/
    2966             :                 case GF_ODF_FT_IPMPX_LIST:
    2967             :                         if(desc->tag!=GF_ODF_IPMP_TAG) {
    2968             :                                 gf_bt_report(parser, GF_BAD_PARAM, "IPMPX_Data list only allowed in GF_IPMP_Descriptor");
    2969             :                                 gf_odf_desc_del(desc);
    2970             :                                 return NULL;
    2971             :                         }
    2972             :                         if (gf_bt_check_code(parser, '[')) {
    2973             :                                 while (!gf_bt_check_code(parser, ']')) {
    2974             :                                         GF_IPMPX_Data *ipmpx = gf_bt_parse_ipmpx(parser, NULL);
    2975             :                                         if (!ipmpx) {
    2976             :                                                 gf_odf_desc_del(desc);
    2977             :                                                 parser->last_error = GF_BAD_PARAM;
    2978             :                                                 return NULL;
    2979             :                                         }
    2980             :                                         gf_list_add( ((GF_IPMP_Descriptor *)desc)->ipmpx_data, ipmpx);
    2981             :                                 }
    2982             :                         }
    2983             :                         break;
    2984             :                 /*IPMPX*/
    2985             :                 case GF_ODF_FT_IPMPX:
    2986             :                         if(desc->tag!=GF_ODF_IPMP_TOOL_TAG) {
    2987             :                                 gf_bt_report(parser, GF_BAD_PARAM, "IPMPX_Data only allowed in GF_IPMP_Tool");
    2988             :                                 gf_odf_desc_del(desc);
    2989             :                                 return NULL;
    2990             :                         }
    2991             :                         if (gf_bt_check_code(parser, '[')) {
    2992             :                                 while (!gf_bt_check_code(parser, ']')) {
    2993             :                                         GF_IPMPX_Data *ipmpx = gf_bt_parse_ipmpx(parser, NULL);
    2994             :                                         if (!ipmpx) {
    2995             :                                                 gf_odf_desc_del(desc);
    2996             :                                                 parser->last_error = GF_BAD_PARAM;
    2997             :                                                 return NULL;
    2998             :                                         }
    2999             :                                         if (ipmpx->tag==GF_IPMPX_PARAMETRIC_DESCRIPTION_TAG) {
    3000             :                                                 GF_IPMP_Tool *it = (GF_IPMP_Tool *)desc;
    3001             :                                                 if (it->toolParamDesc) gf_ipmpx_data_del((GF_IPMPX_Data *)it->toolParamDesc);
    3002             :                                                 it->toolParamDesc = (GF_IPMPX_ParametricDescription*)ipmpx;
    3003             :                                         } else {
    3004             :                                                 gf_bt_report(parser, GF_OK, "Only ToolParametricDescription allowed in GF_IPMP_Tool - skipping");
    3005             :                                                 gf_ipmpx_data_del(ipmpx);
    3006             :                                         }
    3007             :                                 }
    3008             :                         }
    3009             :                         break;
    3010             : #endif
    3011             : 
    3012             :                 /*descriptor list*/
    3013             :                 case GF_ODF_FT_OD_LIST:
    3014             :                         if (gf_bt_check_code(parser, '[')) {
    3015             :                                 while (!gf_bt_check_code(parser, ']')) {
    3016         711 :                                         subdesc = gf_bt_parse_descriptor(parser, NULL);
    3017         711 :                                         if (!subdesc) {
    3018           0 :                                                 gf_odf_desc_del(desc);
    3019           0 :                                                 parser->last_error = GF_BAD_PARAM;
    3020           0 :                                                 return NULL;
    3021             :                                         }
    3022         711 :                                         gf_bt_add_desc(parser, desc, subdesc, field);
    3023             :                                 }
    3024             :                         }
    3025         556 :                         if (is_anim_mask)
    3026             :                                 gf_bt_check_code(parser, '}');
    3027             :                         break;
    3028             :                 /*single descriptor*/
    3029        1116 :                 case GF_ODF_FT_OD:
    3030        1116 :                         str = gf_bt_get_next(parser, 0);
    3031        1116 :                         subdesc = gf_bt_parse_descriptor(parser, str);
    3032        1116 :                         if (!subdesc) {
    3033           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "Unknown desc %s in field %s", str, field);
    3034           0 :                                 gf_odf_desc_del(desc);
    3035           0 :                                 return NULL;
    3036             :                         }
    3037        1116 :                         gf_bt_add_desc(parser, desc, subdesc, field);
    3038        1116 :                         break;
    3039             :                 /*regular field*/
    3040        5582 :                 default:
    3041        5582 :                         str = gf_bt_get_next(parser, 0);
    3042        5582 :                         parser->last_error = gf_odf_set_field(desc, field, str);
    3043             : 
    3044        5582 :                         if (parser->last_error) {
    3045           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "Invalid value %s in field %s", str, field);
    3046           0 :                                 gf_odf_desc_del(desc);
    3047           0 :                                 return NULL;
    3048             :                         }
    3049             :                         break;
    3050             :                 }
    3051             :         }
    3052        2388 :         if (desc->tag == GF_ODF_BIFS_CFG_TAG) {
    3053             :                 GF_BIFSConfig *bcfg = (GF_BIFSConfig *)desc;
    3054         374 :                 if (!parser->load->ctx->scene_width) {
    3055         372 :                         parser->load->ctx->scene_width = bcfg->pixelWidth;
    3056         372 :                         parser->load->ctx->scene_height = bcfg->pixelHeight;
    3057         372 :                         parser->load->ctx->is_pixel_metrics = bcfg->pixelMetrics;
    3058             :                 }
    3059             : 
    3060             :                 /*for bt->xmt*/
    3061         374 :                 if (!bcfg->version) bcfg->version = 1;
    3062             :         }
    3063        2014 :         else if (desc->tag==GF_ODF_ESD_TAG) {
    3064             :                 GF_ESD *esd  =(GF_ESD*)desc;
    3065         692 :                 if (esd->decoderConfig) {
    3066             :                         GF_StreamContext *sc=NULL;
    3067             :                         GF_MuxInfo *mux;
    3068             :                         /*watchout for default BIFS stream*/
    3069         539 :                         if (parser->bifs_es && !parser->base_bifs_id && (esd->decoderConfig->streamType==GF_STREAM_SCENE)) {
    3070         372 :                                 parser->bifs_es->ESID = parser->base_bifs_id = esd->ESID;
    3071         372 :                                 parser->bifs_es->timeScale = (esd->slConfig && esd->slConfig->timestampResolution) ? esd->slConfig->timestampResolution : 1000;
    3072         372 :                                 sc = parser->bifs_es;
    3073             :                         } else {
    3074         167 :                                 sc = gf_sm_stream_new(parser->load->ctx, esd->ESID, esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication);
    3075             :                                 /*set default timescale for systems tracks (ignored for other)*/
    3076         167 :                                 if (sc) sc->timeScale = (esd->slConfig && esd->slConfig->timestampResolution) ? esd->slConfig->timestampResolution : 1000;
    3077             :                                 /*assign base OD*/
    3078         167 :                                 if (!parser->base_od_id && (esd->decoderConfig->streamType==GF_STREAM_OD)) parser->base_od_id = esd->ESID;
    3079             :                         }
    3080             :                         /*assign broadcast parameter tools*/
    3081         539 :                         mux = gf_sm_get_mux_info(esd);
    3082         539 :                         if (sc && mux) {
    3083           5 :                                 sc->aggregate_on_esid = mux->aggregate_on_esid;
    3084           5 :                                 if (!mux->carousel_period_plus_one) sc->carousel_period  = (u32) -1;
    3085           0 :                                 else sc->carousel_period = mux->carousel_period_plus_one - 1;
    3086             :                         }
    3087             :                 }
    3088        1322 :         } else if (desc->tag==GF_ODF_MUXINFO_TAG) {
    3089             :                 GF_MuxInfo *mi = (GF_MuxInfo *)desc;
    3090         158 :                 if (! mi->src_url) {
    3091         158 :                         mi->src_url = gf_strdup(parser->load->src_url ? parser->load->src_url : parser->load->fileName);
    3092             :                 }
    3093             :         }
    3094             :         return desc;
    3095             : }
    3096             : 
    3097         168 : void gf_bt_parse_od_command(GF_BTParser *parser, char *name)
    3098             : {
    3099         168 :         u32 val=0;
    3100             :         char *str;
    3101             : 
    3102         168 :         if (!strcmp(name, "UPDATE")) {
    3103         146 :                 str = gf_bt_get_next(parser, 0);
    3104             :                 /*OD update*/
    3105         146 :                 if (!strcmp(str, "OD")) {
    3106             :                         GF_ODUpdate *odU;
    3107             :                         if (!gf_bt_check_code(parser, '[')) {
    3108           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
    3109           0 :                                 return;
    3110             :                         }
    3111         141 :                         odU = (GF_ODUpdate *) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG);
    3112         141 :                         gf_list_add(parser->od_au->commands, odU);
    3113         465 :                         while (!parser->done) {
    3114             :                                 GF_Descriptor *desc;
    3115         324 :                                 str = gf_bt_get_next(parser, 0);
    3116             :                                 if (gf_bt_check_code(parser, ']')) break;
    3117         183 :                                 if (strcmp(str, "ObjectDescriptor") && strcmp(str, "InitialObjectDescriptor")) {
    3118           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "Object Descriptor expected got %s", str);
    3119           0 :                                         break;
    3120             :                                 }
    3121         183 :                                 desc = gf_bt_parse_descriptor(parser, str);
    3122         183 :                                 if (!desc) break;
    3123         183 :                                 gf_list_add(odU->objectDescriptors, desc);
    3124             :                         }
    3125             :                         return;
    3126             :                 }
    3127             :                 /*ESD update*/
    3128           5 :                 if (!strcmp(str, "ESD")) {
    3129             :                         GF_ESDUpdate *esdU;
    3130           5 :                         str = gf_bt_get_next(parser, 0);
    3131           5 :                         if (strcmp(str, "IN")) {
    3132           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "IN expected got %s", str);
    3133           0 :                                 return;
    3134             :                         }
    3135           5 :                         esdU = (GF_ESDUpdate *) gf_odf_com_new(GF_ODF_ESD_UPDATE_TAG);
    3136           5 :                         parser->last_error = gf_bt_parse_int(parser, "OD_ID", (SFInt32*)&val);
    3137           5 :                         if (parser->last_error) return;
    3138           5 :                         esdU->ODID = val;
    3139           5 :                         gf_list_add(parser->od_au->commands, esdU);
    3140             : 
    3141             :                         if (!gf_bt_check_code(parser, '[')) {
    3142           5 :                                 str = gf_bt_get_next(parser, 0);
    3143           5 :                                 if (strcmp(str, "esDescr")) {
    3144           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "esDescr expected got %s", str);
    3145           0 :                                         return;
    3146             :                                 }
    3147             :                                 if (!gf_bt_check_code(parser, '[')) {
    3148           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
    3149           0 :                                         return;
    3150             :                                 }
    3151             :                         }
    3152             : 
    3153          10 :                         while (!parser->done) {
    3154             :                                 GF_Descriptor *desc;
    3155          10 :                                 str = gf_bt_get_next(parser, 0);
    3156             :                                 if (gf_bt_check_code(parser, ']')) break;
    3157           5 :                                 if (strcmp(str, "ES_Descriptor")) {
    3158           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "ES_Descriptor expected got %s", str);
    3159           0 :                                         break;
    3160             :                                 }
    3161           5 :                                 desc = gf_bt_parse_descriptor(parser, str);
    3162           5 :                                 if (!desc) break;
    3163           5 :                                 gf_list_add(esdU->ESDescriptors, desc);
    3164             :                         }
    3165             :                         return;
    3166             :                 }
    3167             :                 /*IPMP descriptor update*/
    3168           0 :                 if (!strcmp(str, "IPMPD") || !strcmp(str, "IPMPDX")) {
    3169             :                         GF_IPMPUpdate *ipU;
    3170             :                         if (!gf_bt_check_code(parser, '[')) {
    3171           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
    3172           0 :                                 return;
    3173             :                         }
    3174           0 :                         ipU = (GF_IPMPUpdate *) gf_odf_com_new(GF_ODF_IPMP_UPDATE_TAG);
    3175           0 :                         gf_list_add(parser->od_au->commands, ipU);
    3176           0 :                         while (!parser->done) {
    3177             :                                 GF_Descriptor *desc;
    3178           0 :                                 str = gf_bt_get_next(parser, 0);
    3179             :                                 if (gf_bt_check_code(parser, ']')) break;
    3180           0 :                                 if (strcmp(str, "IPMP_Descriptor")) {
    3181           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "IPMP_Descriptor expected got %s", str);
    3182           0 :                                         break;
    3183             :                                 }
    3184           0 :                                 desc = gf_bt_parse_descriptor(parser, str);
    3185           0 :                                 if (!desc) break;
    3186           0 :                                 gf_list_add(ipU->IPMPDescList, desc);
    3187             :                         }
    3188             :                         return;
    3189             :                 }
    3190           0 :                 gf_bt_report(parser, GF_BAD_PARAM, "unknown OD command", str);
    3191           0 :                 return;
    3192             :         }
    3193          22 :         if (!strcmp(name, "REMOVE")) {
    3194          22 :                 str = gf_bt_get_next(parser, 0);
    3195             :                 /*OD remove*/
    3196          22 :                 if (!strcmp(str, "OD")) {
    3197             :                         GF_ODRemove *odR;
    3198             :                         if (!gf_bt_check_code(parser, '[')) {
    3199           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
    3200           0 :                                 return;
    3201             :                         }
    3202          11 :                         odR = (GF_ODRemove *) gf_odf_com_new(GF_ODF_OD_REMOVE_TAG);
    3203          11 :                         gf_list_add(parser->od_au->commands, odR);
    3204          11 :                         while (!parser->done) {
    3205             :                                 u32 id;
    3206             :                                 if (gf_bt_check_code(parser, ']')) break;
    3207          11 :                                 gf_bt_parse_int(parser, "ODID", (SFInt32*)&id);
    3208          11 :                                 if (parser->last_error) return;
    3209          11 :                                 odR->OD_ID = (u16*)gf_realloc(odR->OD_ID, sizeof(u16) * (odR->NbODs+1));
    3210          11 :                                 odR->OD_ID[odR->NbODs] = id;
    3211          11 :                                 odR->NbODs++;
    3212             :                         }
    3213             :                         return;
    3214             :                 }
    3215             :                 /*ESD remove*/
    3216          11 :                 if (!strcmp(str, "ESD")) {
    3217             :                         u32 odid;
    3218             :                         GF_ESDRemove *esdR;
    3219          11 :                         str = gf_bt_get_next(parser, 0);
    3220          11 :                         if (strcmp(str, "FROM")) {
    3221           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "FROM expected got %s", str);
    3222           0 :                                 return;
    3223             :                         }
    3224          11 :                         gf_bt_parse_int(parser, "ODID", (SFInt32*)&odid);
    3225          11 :                         if (parser->last_error) return;
    3226             : 
    3227             :                         if (!gf_bt_check_code(parser, '[')) {
    3228           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
    3229           0 :                                 return;
    3230             :                         }
    3231          11 :                         esdR = (GF_ESDRemove *) gf_odf_com_new(GF_ODF_ESD_REMOVE_TAG);
    3232          11 :                         esdR->ODID = odid;
    3233          11 :                         gf_list_add(parser->od_au->commands, esdR);
    3234          11 :                         while (!parser->done) {
    3235             :                                 u32 id;
    3236             :                                 if (gf_bt_check_code(parser, ']')) break;
    3237          11 :                                 gf_bt_parse_int(parser, "ES_ID", (SFInt32*)&id);
    3238          11 :                                 if (parser->last_error) return;
    3239          11 :                                 esdR->ES_ID = (u16*)gf_realloc(esdR->ES_ID, sizeof(u16) * (esdR->NbESDs+1));
    3240          11 :                                 esdR->ES_ID[esdR->NbESDs] = id;
    3241          11 :                                 esdR->NbESDs++;
    3242             :                         }
    3243             :                         return;
    3244             :                 }
    3245           0 :                 gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown OD command", str);
    3246           0 :                 return;
    3247             :         }
    3248             : }
    3249             : 
    3250             : 
    3251             : 
    3252         871 : GF_Err gf_bt_loader_run_intern(GF_BTParser *parser, GF_Command *init_com, Bool initial_run)
    3253             : {
    3254             :         char *str;
    3255             :         GF_Node *node, *vrml_root_node;
    3256             :         Bool force_new_com;
    3257             :         GF_Route *r;
    3258             :         Bool has_id;
    3259             :         char szDEFName[1000];
    3260             : 
    3261             :         vrml_root_node = NULL;
    3262             :         has_id = 0;
    3263             : 
    3264         871 :         if (init_com)
    3265         406 :                 parser->in_com = 0 ;
    3266             : 
    3267         871 :         parser->cur_com = init_com;
    3268             : 
    3269         871 :         force_new_com = (parser->load->flags & GF_SM_LOAD_CONTEXT_READY) ? 1 : 0;
    3270             : 
    3271             : 
    3272             :         /*create a default root node for all VRML nodes*/
    3273         871 :         if (parser->is_wrl && !parser->top_nodes) {
    3274          56 :                 if (initial_run ) {
    3275             : #ifndef GPAC_DISABLE_X3D
    3276          28 :                         vrml_root_node = gf_node_new(parser->load->scene_graph, (parser->load->flags & GF_SM_LOAD_MPEG4_STRICT) ? TAG_MPEG4_Group : TAG_X3D_Group);
    3277             : #else
    3278             :                         vrml_root_node = gf_node_new(parser->load->scene_graph, TAG_MPEG4_Group);
    3279             : #endif
    3280          28 :                         gf_node_register(vrml_root_node, NULL);
    3281          28 :                         gf_node_init(vrml_root_node);
    3282          28 :                         gf_sg_set_root_node(parser->load->scene_graph, vrml_root_node);
    3283             :                 } else {
    3284          28 :                         vrml_root_node = gf_sg_get_root_node(parser->load->scene_graph);
    3285             :                 }
    3286             :         }
    3287             : 
    3288         871 :         if (!parser->in_com)
    3289         841 :                 parser->stream_id = parser->load->force_es_id;
    3290             : 
    3291             :         /*parse all top-level items*/
    3292        4370 :         while (!parser->last_error) {
    3293        4368 :                 str = gf_bt_get_next(parser, 0);
    3294        4368 :                 if (parser->done) break;
    3295             : 
    3296             :                 /*X3D specific things (ignored for now)*/
    3297        3529 :                 if (!strcmp(str, "PROFILE")) gf_bt_force_line(parser);
    3298        3524 :                 else if (!strcmp(str, "COMPONENT")) gf_bt_force_line(parser);
    3299        3524 :                 else if (!strcmp(str, "META")) gf_bt_force_line(parser);
    3300        3524 :                 else if (!strcmp(str, "IMPORT") || !strcmp(str, "EXPORT")) {
    3301           0 :                         gf_bt_report(parser, GF_NOT_SUPPORTED, "X3D IMPORT/EXPORT not implemented");
    3302           0 :                         break;
    3303             :                 }
    3304             : 
    3305             :                 /*IOD*/
    3306        3524 :                 else if (!strcmp(str, "InitialObjectDescriptor") || !strcmp(str, "ObjectDescriptor")) {
    3307         373 :                         parser->load->ctx->root_od = (GF_ObjectDescriptor *) gf_bt_parse_descriptor(parser, str);
    3308             :                 }
    3309             :                 /*explicit command*/
    3310        3151 :                 else if (!strcmp(str, "AT") || !strcmp(str, "RAP")) {
    3311         318 :                         parser->au_is_rap = 0;
    3312         318 :                         if (!strcmp(str, "RAP")) {
    3313          28 :                                 parser->au_is_rap = 1;
    3314          28 :                                 str = gf_bt_get_next(parser, 0);
    3315          28 :                                 if (strcmp(str, "AT")) {
    3316           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "AT expected got %s", str);
    3317           0 :                                         parser->last_error = GF_BAD_PARAM;
    3318           0 :                                         break;
    3319             :                                 }
    3320             :                         }
    3321             :                         force_new_com = 0;
    3322         318 :                         str = gf_bt_get_next(parser, 0);
    3323         318 :                         if (str[0] == 'D') {
    3324         260 :                                 parser->au_time += atoi(&str[1]);
    3325             :                         } else {
    3326         188 :                                 if (sscanf(str, "%u", &parser->au_time) != 1) {
    3327           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "Number expected got %s", str);
    3328           0 :                                         break;
    3329             :                                 }
    3330             :                         }
    3331         318 :                         if (parser->last_error) break;
    3332             :                         /*reset all contexts*/
    3333         318 :                         if (parser->od_au && (parser->od_au->timing != parser->au_time)) parser->od_au = NULL;
    3334         318 :                         if (parser->bifs_au && (parser->bifs_au->timing != parser->au_time)) {
    3335         175 :                                 gf_bt_check_unresolved_nodes(parser);
    3336         175 :                                 parser->bifs_au = NULL;
    3337             :                         }
    3338             : 
    3339         318 :                         parser->stream_id = 0;
    3340             :                         /*fix for mp4tool bt which doesn't support RAP signaling: assume the first AU
    3341             :                         is always RAP*/
    3342         318 :                         if (!parser->au_time) parser->au_is_rap = 1;
    3343             : 
    3344         318 :                         parser->in_com = 1;
    3345             : 
    3346             :                         if (!gf_bt_check_code(parser, '{')) {
    3347           4 :                                 str = gf_bt_get_next(parser, 0);
    3348           4 :                                 if (!strcmp(str, "IN")) {
    3349           4 :                                         gf_bt_parse_int(parser, "IN", (SFInt32*)&parser->stream_id);
    3350           4 :                                         if (parser->last_error) break;
    3351             :                                 }
    3352             :                                 if (!gf_bt_check_code(parser, '{')) {
    3353           0 :                                         gf_bt_report(parser, GF_BAD_PARAM, "{ expected");
    3354             :                                 }
    3355             :                         }
    3356             :                         /*done loading init frame*/
    3357         318 :                         if (init_com && parser->au_time) break;
    3358             :                 }
    3359        2833 :                 else if (!strcmp(str, "PROTO") || !strcmp(str, "EXTERNPROTO")) {
    3360          61 :                         gf_bt_parse_proto(parser, str, init_com ? init_com->new_proto_list : NULL);
    3361             :                 }
    3362             :                 /*compatibility for old bt (mp4tool) in ProtoLibs*/
    3363        2772 :                 else if (!strcmp(str, "NULL")) {
    3364             :                 }
    3365        2772 :                 else if (!strcmp(str, "DEF")) {
    3366          37 :                         str = gf_bt_get_next(parser, 0);
    3367             :                         strcpy(szDEFName, str);
    3368             :                         has_id = 1;
    3369             :                 }
    3370        2735 :                 else if (!strcmp(str, "ROUTE")) {
    3371             :                         GF_Command *com = NULL;
    3372        1340 :                         if (!parser->top_nodes && parser->bifs_au && !parser->is_wrl) {
    3373             :                                 /*if doing a scene replace, we need route insert stuff*/
    3374        1320 :                                 com = gf_sg_command_new(parser->load->scene_graph, GF_SG_ROUTE_INSERT);
    3375        1320 :                                 gf_list_add(parser->bifs_au->commands, com);
    3376        1320 :                                 gf_list_add(parser->inserted_routes, com);
    3377             :                         }
    3378             : 
    3379        1340 :                         r = gf_bt_parse_route(parser, 1, 0, com);
    3380        1340 :                         if (has_id) {
    3381          23 :                                 u32 rID = gf_bt_get_route(parser, szDEFName);
    3382          23 :                                 if (!rID) rID = gf_bt_get_next_route_id(parser);
    3383          23 :                                 if (com) {
    3384          23 :                                         com->RouteID = rID;
    3385          23 :                                         com->def_name = gf_strdup(szDEFName);
    3386          23 :                                         gf_sg_set_max_defined_route_id(parser->load->scene_graph, rID);
    3387           0 :                                 } else if (r) {
    3388           0 :                                         gf_sg_route_set_id(r, rID);
    3389           0 :                                         gf_sg_route_set_name(r, szDEFName);
    3390             :                                 }
    3391             :                                 has_id = 0;
    3392             :                         }
    3393             :                 }
    3394             :                 /*OD commands*/
    3395        1395 :                 else if (!strcmp(str, "UPDATE") || !strcmp(str, "REMOVE")) {
    3396         168 :                         Bool is_base_stream = parser->stream_id ? 0 : 1;
    3397         168 :                         if (!parser->stream_id || parser->stream_id==parser->bifs_es->ESID) parser->stream_id = parser->base_od_id;
    3398             : 
    3399         168 :                         if (parser->od_es && (parser->od_es->ESID != parser->stream_id)) {
    3400             :                                 GF_StreamContext *prev = parser->od_es;
    3401           0 :                                 parser->od_es = gf_sm_stream_new(parser->load->ctx, (u16) parser->stream_id, GF_STREAM_OD, GF_CODECID_OD_V1);
    3402             :                                 /*force new AU if stream changed*/
    3403           0 :                                 if (parser->od_es != prev) {
    3404           0 :                                         parser->bifs_au = NULL;
    3405           0 :                                         parser->od_au = NULL;
    3406             :                                 }
    3407             :                         }
    3408         168 :                         if (!parser->od_es) parser->od_es = gf_sm_stream_new(parser->load->ctx, (u16) parser->stream_id, GF_STREAM_OD, GF_CODECID_OD_V1);
    3409         168 :                         if (!parser->od_au) parser->od_au = gf_sm_stream_au_new(parser->od_es, parser->au_time, 0, parser->au_is_rap);
    3410         168 :                         gf_bt_parse_od_command(parser, str);
    3411         168 :                         if (is_base_stream) parser->stream_id= 0;
    3412             :                 }
    3413             :                 /*BIFS commands*/
    3414        1227 :                 else if (!strcmp(str, "REPLACE") || !strcmp(str, "INSERT") || !strcmp(str, "APPEND") || !strcmp(str, "DELETE")
    3415             :                          /*BIFS extended commands*/
    3416         847 :                          || !strcmp(str, "GLOBALQP") || !strcmp(str, "MULTIPLEREPLACE") || !strcmp(str, "MULTIPLEINDREPLACE") || !strcmp(str, "XDELETE") || !strcmp(str, "DELETEPROTO") || !strcmp(str, "INSERTPROTO")
    3417         772 :                          || !strcmp(str, "XREPLACE")
    3418             :                         ) {
    3419         475 :                         Bool is_base_stream = parser->stream_id ? 0 : 1;
    3420             : 
    3421         475 :                         if (!parser->stream_id) parser->stream_id = parser->base_bifs_id;
    3422         475 :                         if (!parser->stream_id || (parser->od_es && (parser->stream_id==parser->od_es->ESID)) ) parser->stream_id = parser->base_bifs_id;
    3423             : 
    3424         475 :                         if (parser->bifs_es->ESID != parser->stream_id) {
    3425             :                                 GF_StreamContext *prev = parser->bifs_es;
    3426           3 :                                 parser->bifs_es = gf_sm_stream_new(parser->load->ctx, (u16) parser->stream_id, GF_STREAM_SCENE, GF_CODECID_BIFS);
    3427             :                                 /*force new AU if stream changed*/
    3428           3 :                                 if (parser->bifs_es != prev) {
    3429           3 :                                         gf_bt_check_unresolved_nodes(parser);
    3430           3 :                                         parser->bifs_au = NULL;
    3431             :                                 }
    3432             :                         }
    3433         475 :                         if (force_new_com) {
    3434             :                                 force_new_com = 0;
    3435           2 :                                 parser->bifs_au = gf_list_last(parser->bifs_es->AUs);
    3436           2 :                                 parser->au_time = (u32) (parser->bifs_au ? parser->bifs_au->timing : 0) + 1;
    3437           2 :                                 parser->bifs_au = NULL;
    3438             :                         }
    3439             : 
    3440         475 :                         if (!parser->bifs_au) parser->bifs_au = gf_sm_stream_au_new(parser->bifs_es, parser->au_time, 0, parser->au_is_rap);
    3441         475 :                         gf_bt_parse_bifs_command(parser, str, parser->bifs_au->commands);
    3442         475 :                         if (is_base_stream) parser->stream_id= 0;
    3443             :                 }
    3444             :                 /*implicit BIFS command on SFTopNodes only*/
    3445         752 :                 else if (!strcmp(str, "OrderedGroup")
    3446         416 :                          || !strcmp(str, "Group")
    3447         340 :                          || !strcmp(str, "Layer2D")
    3448         340 :                          || !strcmp(str, "Layer3D")
    3449             :                          /* VRML parsing: all nodes are allowed*/
    3450         340 :                          || parser->is_wrl
    3451             :                         )
    3452             :                 {
    3453             : 
    3454         432 :                         node = gf_bt_sf_node(parser, str, vrml_root_node, has_id ? szDEFName : NULL);
    3455             :                         has_id = 0;
    3456         432 :                         if (!node) break;
    3457         432 :                         if (parser->top_nodes) {
    3458           0 :                                 gf_list_add(parser->top_nodes, node);
    3459         432 :                         } else if (!vrml_root_node) {
    3460         394 :                                 if (init_com) init_com->node = node;
    3461           0 :                                 else if (parser->load->flags & GF_SM_LOAD_CONTEXT_READY) {
    3462           0 :                                         GF_Command *com = gf_sg_command_new(parser->load->scene_graph, GF_SG_SCENE_REPLACE);
    3463             :                                         assert(!parser->bifs_au);
    3464             :                                         assert(parser->bifs_es);
    3465           0 :                                         parser->bifs_au = gf_sm_stream_au_new(parser->bifs_es, 0, 0, 1);
    3466           0 :                                         gf_list_add(parser->bifs_au->commands, com);
    3467           0 :                                         com->node = node;
    3468             :                                 }
    3469             :                         } else {
    3470          38 :                                 gf_node_insert_child(vrml_root_node, node, -1);
    3471             :                         }
    3472             : 
    3473             :                         /*
    3474             :                         if (!gf_sg_get_root_node(parser->load->scene_graph)) {
    3475             :                                 gf_node_register(node, NULL);
    3476             :                                 gf_sg_set_root_node(parser->load->scene_graph, node);
    3477             :                         }
    3478             :                         */
    3479             :                 }
    3480             : 
    3481             :                 /*if in command, check command end*/
    3482             :                 else {
    3483             :                         /*check command end*/
    3484         320 :                         if (/*in_com && */gf_bt_check_code(parser, '}')) parser->in_com = 0;
    3485           0 :                         else if (strlen(str)) {
    3486           0 :                                 gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown top-level element", str);
    3487             :                         }
    3488         320 :                         parser->au_is_rap = 0;
    3489             :                 }
    3490             :         }
    3491         871 :         gf_bt_resolve_routes(parser, 0);
    3492         871 :         gf_bt_check_unresolved_nodes(parser);
    3493             : 
    3494             :         /*load scripts*/
    3495        1743 :         while (gf_list_count(parser->scripts)) {
    3496           1 :                 GF_Node *n = (GF_Node *)gf_list_get(parser->scripts, 0);
    3497           1 :                 gf_list_rem(parser->scripts, 0);
    3498           1 :                 gf_sg_script_load(n);
    3499             :         }
    3500         871 :         return parser->last_error;
    3501             : }
    3502             : 
    3503         439 : static GF_Err gf_sm_load_bt_initialize(GF_SceneLoader *load, const char *str, Bool input_only)
    3504             : {
    3505             :         u32 size;
    3506             :         gzFile gzInput;
    3507             :         GF_Err e;
    3508             :         unsigned char BOM[5];
    3509         439 :         GF_BTParser *parser = load->loader_priv;
    3510             : 
    3511         439 :         parser->last_error = GF_OK;
    3512             : 
    3513         439 :         if (load->fileName) {
    3514         435 :                 FILE *test = gf_fopen(load->fileName, "rb");
    3515         435 :                 if (!test) return GF_URL_ERROR;
    3516             : 
    3517         435 :                 size = (u32) gf_fsize(test);
    3518         435 :                 gf_fclose(test);
    3519             : 
    3520         435 :                 gzInput = gf_gzopen(load->fileName, "rb");
    3521         435 :                 if (!gzInput) return GF_IO_ERR;
    3522             : 
    3523         435 :                 parser->line_buffer = (char *) gf_malloc(sizeof(char)*BT_LINE_SIZE);
    3524             :                 memset(parser->line_buffer, 0, sizeof(char)*BT_LINE_SIZE);
    3525         435 :                 parser->file_size = size;
    3526             : 
    3527         435 :                 parser->line_pos = parser->line_size = 0;
    3528         435 :                 gf_gzgets(gzInput, (char*) BOM, 5);
    3529         435 :                 gf_gzseek(gzInput, 0, SEEK_SET);
    3530         435 :                 parser->gz_in = gzInput;
    3531             : 
    3532             :         } else {
    3533           4 :                 if (!str || (strlen(str)<5) ) {
    3534             :                         /*wait for first string data to be fed to the parser (for load from string)*/
    3535           2 :                         parser->initialized = 0;
    3536           2 :                         return GF_OK;
    3537             :                 }
    3538             :                 strncpy((char *) BOM, str, 5);
    3539             :         }
    3540             : 
    3541             :         /*0: no unicode, 1: UTF-16BE, 2: UTF-16LE*/
    3542         437 :         if ((BOM[0]==0xFF) && (BOM[1]==0xFE)) {
    3543           5 :                 if (!BOM[2] && !BOM[3]) {
    3544           0 :                         gf_bt_report(parser, GF_NOT_SUPPORTED, "UTF-32 Text Files not supported");
    3545           0 :                         return GF_NOT_SUPPORTED;
    3546             :                 } else {
    3547           5 :                         parser->unicode_type = 2;
    3548           5 :                         if (parser->gz_in) gf_gzseek(parser->gz_in, 2, SEEK_CUR);
    3549             :                 }
    3550         432 :         } else if ((BOM[0]==0xFE) && (BOM[1]==0xFF)) {
    3551           0 :                 if (!BOM[2] && !BOM[3]) {
    3552           0 :                         gf_bt_report(parser, GF_NOT_SUPPORTED, "UTF-32 Text Files not supported");
    3553           0 :                         return GF_NOT_SUPPORTED;
    3554             :                 } else {
    3555           0 :                         parser->unicode_type = 1;
    3556           0 :                         if (parser->gz_in) gf_gzseek(parser->gz_in, 2, SEEK_CUR);
    3557             :                 }
    3558         432 :         } else if ((BOM[0]==0xEF) && (BOM[1]==0xBB) && (BOM[2]==0xBF)) {
    3559             :                 /*we handle UTF8 as asci*/
    3560           0 :                 parser->unicode_type = 0;
    3561           0 :                 if (parser->gz_in) gf_gzseek(parser->gz_in, 3, SEEK_CUR);
    3562             :         }
    3563         437 :         parser->initialized = 1;
    3564             : 
    3565         437 :         if ( load->fileName )
    3566             :         {
    3567         435 :                 char *sep = gf_file_ext_start(load->fileName);
    3568         435 :                 if (sep && !strnicmp(sep, ".wrl", 4)) parser->is_wrl = 1;
    3569             :         }
    3570             : 
    3571         437 :         if (input_only) return GF_OK;
    3572             : 
    3573             :         /*initalize default streams in the context*/
    3574             : 
    3575             :         /*chunk parsing*/
    3576         437 :         if (load->flags & GF_SM_LOAD_CONTEXT_READY) {
    3577             :                 u32 i;
    3578             :                 GF_StreamContext *sc;
    3579           3 :                 if (!load->ctx) return GF_BAD_PARAM;
    3580             : 
    3581             :                 /*restore context - note that base layer are ALWAYS declared BEFORE enhancement layers with gpac parsers*/
    3582           3 :                 i=0;
    3583           9 :                 while ((sc = (GF_StreamContext*)gf_list_enum(load->ctx->streams, &i))) {
    3584           3 :                         switch (sc->streamType) {
    3585           2 :                         case GF_STREAM_SCENE:
    3586           2 :                                 if (!parser->bifs_es) parser->bifs_es = sc;
    3587             :                                 break;
    3588           1 :                         case GF_STREAM_OD:
    3589           1 :                                 if (!parser->od_es) parser->od_es = sc;
    3590             :                                 break;
    3591             :                         default:
    3592             :                                 break;
    3593             :                         }
    3594             :                 }
    3595             :                 /*need at least one scene stream*/
    3596           3 :                 if (!parser->bifs_es) {
    3597           2 :                         parser->bifs_es = gf_sm_stream_new(load->ctx, 0, GF_STREAM_SCENE, GF_CODECID_BIFS);
    3598           2 :                         parser->load->ctx->scene_width = 0;
    3599           2 :                         parser->load->ctx->scene_height = 0;
    3600           2 :                         parser->load->ctx->is_pixel_metrics = 1;
    3601             :                 }
    3602           1 :                 else parser->base_bifs_id = parser->bifs_es->ESID;
    3603           3 :                 if (parser->od_es) parser->base_od_id = parser->od_es->ESID;
    3604             : 
    3605           3 :                 GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("BT: MPEG-4 (BT) Scene Chunk Parsing"));
    3606             :         }
    3607             :         /*context is not initialized - check for VRML*/
    3608             :         else {
    3609             :                 GF_Command *com;
    3610             : 
    3611             : 
    3612         434 :                 parser->load = NULL;
    3613         434 :                 gf_bt_check_line(parser);
    3614         434 :                 parser->load = load;
    3615         434 :                 if (load->ctx && parser->def_w && parser->def_h) {
    3616          29 :                         load->ctx->scene_width = parser->def_w;
    3617          29 :                         load->ctx->scene_height = parser->def_h;
    3618             :                 }
    3619             : 
    3620             :                 /*create at least one empty BIFS stream*/
    3621         434 :                 if (!parser->is_wrl && load->ctx) {
    3622         406 :                         parser->bifs_es = gf_sm_stream_new(load->ctx, 0, GF_STREAM_SCENE, GF_CODECID_BIFS);
    3623         406 :                         parser->bifs_au = gf_sm_stream_au_new(parser->bifs_es, 0, 0, 1);
    3624         406 :                         parser->load->ctx->is_pixel_metrics = 1;
    3625             :                 }
    3626             : 
    3627         434 :                 GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ( ((parser->is_wrl==2) ? "BT: X3D (WRL) Scene Parsing\n" : (parser->is_wrl ? "BT: VRML Scene Parsing\n" : "BT: MPEG-4 Scene Parsing\n")) ));
    3628             : 
    3629             :                 /*default scene replace - we create it no matter what since it is used to store BIFS config when parsing IOD.*/
    3630             :                 com = NULL;
    3631         434 :                 if (!parser->is_wrl) {
    3632         406 :                         com = gf_sg_command_new(parser->load->scene_graph, GF_SG_SCENE_REPLACE);
    3633         406 :                         gf_list_add(parser->bifs_au->commands, com);
    3634             :                 }
    3635             : 
    3636             :                 /*and perform initial load*/
    3637         434 :                 e = gf_bt_loader_run_intern(parser, com, 1);
    3638         434 :                 if (e) return e;
    3639             :         }
    3640             :         return GF_OK;
    3641             : }
    3642             : 
    3643         844 : void load_bt_done(GF_SceneLoader *load)
    3644             : {
    3645         844 :         GF_BTParser *parser = (GF_BTParser *)load->loader_priv;
    3646         844 :         if (!parser) return;
    3647         437 :         gf_list_del(parser->unresolved_routes);
    3648         437 :         gf_list_del(parser->inserted_routes);
    3649         437 :         gf_list_del(parser->undef_nodes);
    3650         437 :         gf_list_del(parser->def_nodes);
    3651         437 :         gf_list_del(parser->peeked_nodes);
    3652         889 :         while (gf_list_count(parser->def_symbols)) {
    3653          15 :                 BTDefSymbol *d = (BTDefSymbol *)gf_list_get(parser->def_symbols, 0);
    3654          15 :                 gf_list_rem(parser->def_symbols, 0);
    3655          15 :                 gf_free(d->name);
    3656          15 :                 gf_free(d->value);
    3657          15 :                 gf_free(d);
    3658             :         }
    3659         437 :         gf_list_del(parser->def_symbols);
    3660         437 :         gf_list_del(parser->scripts);
    3661             : 
    3662         437 :         if (parser->gz_in) gf_gzclose(parser->gz_in);
    3663         437 :         if (parser->line_buffer) gf_free(parser->line_buffer);
    3664         437 :         gf_free(parser);
    3665         437 :         load->loader_priv = NULL;
    3666             : }
    3667             : 
    3668         435 : GF_Err load_bt_run(GF_SceneLoader *load)
    3669             : {
    3670             :         GF_Err e;
    3671         435 :         GF_BTParser *parser = (GF_BTParser *)load->loader_priv;
    3672         435 :         if (!parser) return GF_BAD_PARAM;
    3673             : 
    3674         435 :         if (!parser->initialized) {
    3675           0 :                 e = gf_sm_load_bt_initialize(load, NULL, 1);
    3676           0 :                 if (e) return e;
    3677             :         }
    3678             : 
    3679         435 :         e = gf_bt_loader_run_intern(parser, NULL, 0);
    3680             : 
    3681         435 :         if ((e<0) || parser->done) {
    3682         435 :                 parser->done = 0;
    3683         435 :                 parser->initialized = 0;
    3684         435 :                 if (parser->gz_in) {
    3685         435 :                         gf_gzclose(parser->gz_in);
    3686         435 :                         parser->gz_in = NULL;
    3687             :                 }
    3688             : 
    3689         435 :                 if (parser->line_buffer) {
    3690         435 :                         gf_free(parser->line_buffer);
    3691         435 :                         parser->line_buffer = NULL;
    3692             :                 }
    3693         435 :                 parser->file_size = 0;
    3694         435 :                 parser->line_pos = parser->line_size = 0;
    3695         435 :                 load->fileName = NULL;
    3696             :         }
    3697             :         return e;
    3698             : }
    3699             : 
    3700             : 
    3701           2 : GF_Err load_bt_parse_string(GF_SceneLoader *load, const char *str)
    3702             : {
    3703             :         GF_Err e;
    3704             :         char *dup_str;
    3705           2 :         GF_BTParser *parser = (GF_BTParser *)load->loader_priv;
    3706           2 :         if (!parser) return GF_BAD_PARAM;
    3707             : 
    3708           2 :         if (parser->done) {
    3709           0 :                 parser->done = 0;
    3710           0 :                 parser->initialized = 0;
    3711           0 :                 parser->file_size = 0;
    3712           0 :                 parser->line_pos = 0;
    3713             :         }
    3714           2 :         parser->line_buffer = dup_str = gf_strdup(str);
    3715           2 :         parser->line_size = (s32)strlen(str);
    3716             : 
    3717           2 :         if (!parser->initialized) {
    3718           2 :                 e = gf_sm_load_bt_initialize(load, str, 0);
    3719           2 :                 if (e) {
    3720           0 :                         gf_free(dup_str);
    3721           0 :                         return e;
    3722             :                 }
    3723             :         }
    3724           2 :         e = gf_bt_loader_run_intern(parser, NULL, 0);
    3725           2 :         parser->line_buffer = NULL;
    3726           2 :         parser->line_size = 0;
    3727           2 :         gf_free(dup_str);
    3728           2 :         return e;
    3729             : }
    3730             : 
    3731           0 : GF_Err load_bt_suspend(GF_SceneLoader *load, Bool suspend)
    3732             : {
    3733           0 :         return GF_OK;
    3734             : }
    3735             : 
    3736         437 : GF_Err gf_sm_load_init_bt(GF_SceneLoader *load)
    3737             : {
    3738             :         GF_Err e;
    3739             :         GF_BTParser *parser;
    3740             : 
    3741         437 :         if (!load || (!load->ctx && !load->scene_graph) ) return GF_BAD_PARAM;
    3742         437 :         if (!load->scene_graph) load->scene_graph = load->ctx->scene_graph;
    3743             : 
    3744         437 :         GF_SAFEALLOC(parser, GF_BTParser);
    3745         437 :         if (!parser) return GF_OUT_OF_MEM;
    3746         437 :         parser->load = load;
    3747         437 :         load->loader_priv = parser;
    3748         437 :         parser->def_symbols = gf_list_new();
    3749         437 :         parser->unresolved_routes = gf_list_new();
    3750         437 :         parser->inserted_routes = gf_list_new();
    3751         437 :         parser->undef_nodes = gf_list_new();
    3752         437 :         parser->def_nodes = gf_list_new();
    3753         437 :         parser->peeked_nodes = gf_list_new();
    3754         437 :         parser->scripts = gf_list_new();
    3755             : 
    3756         437 :         load->process = load_bt_run;
    3757         437 :         load->done = load_bt_done;
    3758         437 :         load->suspend = load_bt_suspend;
    3759         437 :         load->parse_string = load_bt_parse_string;
    3760             : 
    3761             : #ifdef GPAC_ENABLE_COVERAGE
    3762         437 :         if (gf_sys_is_cov_mode()) {
    3763         431 :                 gf_bt_report(parser, GF_OK, NULL);
    3764             :         }
    3765             : #endif
    3766             : 
    3767         437 :         e = gf_sm_load_bt_initialize(load, NULL, 0);
    3768         437 :         if (e) {
    3769           0 :                 load_bt_done(load);
    3770           0 :                 return e;
    3771             :         }
    3772             :         return GF_OK;
    3773             : }
    3774             : 
    3775             : 
    3776             : GF_EXPORT
    3777           0 : GF_List *gf_sm_load_bt_from_string(GF_SceneGraph *in_scene, char *node_str, Bool force_wrl)
    3778             : {
    3779             :         GF_SceneLoader ctx;
    3780             :         GF_BTParser parser;
    3781             :         memset(&ctx, 0, sizeof(GF_SceneLoader));
    3782           0 :         ctx.scene_graph = in_scene;
    3783             :         memset(&parser, 0, sizeof(GF_BTParser));
    3784           0 :         parser.line_buffer = node_str;
    3785           0 :         parser.line_size = (u32) strlen(node_str);
    3786           0 :         parser.load = &ctx;
    3787           0 :         parser.top_nodes = gf_list_new();
    3788           0 :         parser.undef_nodes = gf_list_new();
    3789           0 :         parser.def_nodes = gf_list_new();
    3790           0 :         parser.peeked_nodes = gf_list_new();
    3791           0 :         parser.is_wrl = force_wrl;
    3792           0 :         gf_bt_loader_run_intern(&parser, NULL, 1);
    3793           0 :         gf_list_del(parser.undef_nodes);
    3794           0 :         gf_list_del(parser.def_nodes);
    3795           0 :         gf_list_del(parser.peeked_nodes);
    3796           0 :         while (gf_list_count(parser.def_symbols)) {
    3797           0 :                 BTDefSymbol *d = (BTDefSymbol *)gf_list_get(parser.def_symbols, 0);
    3798           0 :                 gf_list_rem(parser.def_symbols, 0);
    3799           0 :                 gf_free(d->name);
    3800           0 :                 gf_free(d->value);
    3801           0 :                 gf_free(d);
    3802             :         }
    3803           0 :         gf_list_del(parser.def_symbols);
    3804           0 :         gf_list_del(parser.scripts);
    3805             : 
    3806           0 :         return parser.top_nodes;
    3807             : }
    3808             : 
    3809             : #endif /*GPAC_DISABLE_LOADER_BT*/

Generated by: LCOV version 1.13