GF_Err gf_bt_parse_bifs_command()

in src/scene_manager/loader_bt.c [2041:2746]


GF_Err gf_bt_parse_bifs_command(GF_BTParser *parser, char *name, GF_List *cmdList)
{
	s32 pos;
	GF_Route *r;
	GF_Node *n, *newnode;
	GF_Command *com;
	GF_CommandField *inf;
	GF_FieldInfo info;
	char *str, field[1000];
	if (!name) {
		str = gf_bt_get_next(parser, 0);
	} else {
		str = name;
	}
	com = NULL;
	pos = -2;
	/*REPLACE commands*/
	if (!strcmp(str, "REPLACE")) {
		str = gf_bt_get_next(parser, 1);
		if (!strcmp(str, "ROUTE")) {
			str = gf_bt_get_next(parser, 0);
			r = gf_sg_route_find_by_name(parser->load->scene_graph, str);
			if (!r) strcpy(field, str);
			str = gf_bt_get_next(parser, 0);
			if (strcmp(str, "BY")) {
				return gf_bt_report(parser, GF_BAD_PARAM, "BY expected got %s", str);
			}
			com = gf_sg_command_new(parser->load->scene_graph, GF_SG_ROUTE_REPLACE);
			if (r) {
				com->RouteID = r->ID;
			} else {
				com->unres_name = gf_strdup(field);
				com->unresolved = 1;
				gf_list_add(parser->unresolved_routes, com);
			}
			gf_bt_parse_route(parser, 1, 0, com);
			gf_list_add(cmdList, com);
			return parser->last_error;
		}
		/*scene replace*/
		if (!strcmp(str, "SCENE")) {
			str = gf_bt_get_next(parser, 0);
			if (strcmp(str, "BY")) {
				return gf_bt_report(parser, GF_BAD_PARAM, "BY expected got %s", str);
			}
			gf_bt_resolve_routes(parser, 1);
			com = gf_sg_command_new(parser->load->scene_graph, GF_SG_SCENE_REPLACE);
			while (gf_list_count(parser->def_nodes)) gf_list_rem(parser->def_nodes, 0);

			while (1) {
				str = gf_bt_get_next(parser, 0);
				if (!strcmp(str, "PROTO") || !strcmp(str, "EXTERNPROTO")) {
					gf_bt_parse_proto(parser, str, com->new_proto_list);
					if (parser->last_error) goto err;
				} else {
					break;
				}
			}
			n = gf_bt_sf_node(parser, str, NULL, NULL);
			com->node = n;

			if (parser->last_error) goto err;
			gf_list_add(cmdList, com);
			parser->cur_com = com;
			return GF_OK;
		}
		if (!strcmp(str, "LAST")) pos = -1;
		else if (!strcmp(str, "BEGIN")) pos = 0;

		gf_bt_check_code(parser, '.');
		strcpy(field, str);
		n = gf_bt_peek_node(parser, str);
		if (!n) return gf_bt_report(parser, GF_BAD_PARAM, "%s: unknown node", field);

		str = gf_bt_get_next(parser, 0);
		strcpy(field, str);
		if (gf_bt_check_code(parser, '[')) {
			if ( (parser->last_error = gf_bt_parse_int(parser, "index", &pos)) ) return parser->last_error;
			if (!gf_bt_check_code(parser, ']'))
				return gf_bt_report(parser, GF_BAD_PARAM, "] expected");
		}
		/*node replace*/
		if (!strcmp(field, "BY")) {
			com = gf_sg_command_new(parser->load->scene_graph, GF_SG_NODE_REPLACE);
			bd_set_com_node(com, n);
			inf = gf_sg_command_field_new(com);
			inf->new_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
			inf->fieldType = GF_SG_VRML_SFNODE;
			inf->field_ptr = &inf->new_node;
			gf_list_add(cmdList, com);
			parser->cur_com = com;
			return parser->last_error;
		}
		str = gf_bt_get_next(parser, 0);
		if (strcmp(str, "BY")) return gf_bt_report(parser, GF_BAD_PARAM, "BY expected got %s", str);

		parser->last_error = gf_node_get_field_by_name(n, field, &info);
		if (parser->last_error)
			return gf_bt_report(parser, parser->last_error, "%s: Unknown node field", field);

		/*field replace*/
		if (pos==-2) {
			com = gf_sg_command_new(parser->load->scene_graph, GF_SG_FIELD_REPLACE);
			bd_set_com_node(com, n);

			inf = gf_sg_command_field_new(com);
			inf->fieldIndex = info.fieldIndex;
			inf->fieldType = info.fieldType;

			switch (info.fieldType) {
			case GF_SG_VRML_SFNODE:
				newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
				if (!gf_bt_check_ndt(parser, &info, newnode, n)) goto err;
				inf->new_node = newnode;
				inf->field_ptr = &inf->new_node;
				break;
			case GF_SG_VRML_MFNODE:
			{
				GF_ChildNodeItem *last = NULL;
				if (!gf_bt_check_code(parser, '[')) break;
				inf->field_ptr = &inf->node_list;
				while (!gf_bt_check_code(parser, ']')) {
					newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
					if (!newnode) goto err;
					if (parser->last_error!=GF_OK) goto err;
					if (!gf_bt_check_ndt(parser, &info, newnode, n)) goto err;
					gf_node_list_add_child_last(& inf->node_list, newnode, &last);
				}
			}
			break;
			default:
				inf->field_ptr = gf_sg_vrml_field_pointer_new(info.fieldType);
				info.far_ptr = inf->field_ptr;
				if (gf_sg_vrml_is_sf_field(info.fieldType)) {
					gf_bt_sffield(parser, &info, n);
				} else {
					gf_bt_mffield(parser, &info, n);
				}
				if (parser->last_error) goto err;
				break;
			}

			gf_list_add(cmdList, com);
			parser->cur_com = com;
			return parser->last_error;
		}
		/*indexed field replace*/
		com = gf_sg_command_new(parser->load->scene_graph, GF_SG_INDEXED_REPLACE);
		bd_set_com_node(com, n);
		inf = gf_sg_command_field_new(com);
		inf->pos = pos;
		inf->fieldIndex = info.fieldIndex;
		if (gf_sg_vrml_is_sf_field(info.fieldType)) {
			gf_bt_report(parser, GF_BAD_PARAM, "%s: MF type field expected", info.name);
			goto err;
		}
		inf->fieldType = gf_sg_vrml_get_sf_type(info.fieldType);
		switch (info.fieldType) {
		case GF_SG_VRML_MFNODE:
			newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
			if (!gf_bt_check_ndt(parser, &info, newnode, n)) goto err;
			inf->new_node = newnode;
			inf->field_ptr = &inf->new_node;
			break;
		default:
			info.fieldType = inf->fieldType;
			info.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType);
			gf_bt_sffield(parser, &info, n);
			break;
		}
		if (parser->last_error) goto err;
		gf_list_add(cmdList, com);
		parser->cur_com = com;
		return parser->last_error;
	}
	/*XREPLACE commands*/
	if (!strcmp(str, "XREPLACE")) {
		u32 j;
		Bool force_sf=0;
		char csep;
		GF_Node *targetNode, *idxNode, *childNode, *fromNode;
		GF_FieldInfo targetField, idxField, childField, fromField;

		targetNode = idxNode = childNode = fromNode = NULL;
		str = gf_bt_get_next(parser, 1);
		/*get source node*/
		strcpy(field, str);
		targetNode = gf_bt_peek_node(parser, str);
		if (!targetNode) return gf_bt_report(parser, GF_BAD_PARAM, "%s: unknown node", field);
		if (!gf_bt_check_code(parser, '.')) {
			return gf_bt_report(parser, GF_BAD_PARAM, "XREPLACE: '.' expected");
		}
		/*get source field*/
		str = gf_bt_get_next(parser, 0);
		strcpy(field, str);
		parser->last_error = gf_node_get_field_by_name(targetNode, field, &targetField);
		if (parser->last_error)
			return gf_bt_report(parser, parser->last_error, "%s: Unknown node field", field);

		if (gf_bt_check_code(parser, '[')) {
			pos = -2;
			str = gf_bt_get_next(parser, 1);
			force_sf = 1;
			if (sscanf(str, "%d", &pos) != 1) {
				pos = -2;
				if (!strcmp(str, "LAST")) pos = -1;
				else if (!strcmp(str, "first")) pos = 0;
				else {
					strcpy(field, str);
					/*get idx node*/
					idxNode = gf_bt_peek_node(parser, str);
					if (!idxNode) return gf_bt_report(parser, GF_BAD_PARAM, "%s: unknown node", field);
					if (!gf_bt_check_code(parser, '.'))
						return gf_bt_report(parser, GF_BAD_PARAM, "XREPLACE: '.' expected");

					/*get idx field*/
					str = gf_bt_get_next(parser, 0);
					strcpy(field, str);
					parser->last_error = gf_node_get_field_by_name(idxNode, field, &idxField);
					if (parser->last_error)
						return gf_bt_report(parser, parser->last_error, "%s: Unknown node field", field);
				}
			}
			gf_bt_check_code(parser, ']');

			/*check if we have a child node*/
			if (gf_bt_check_code(parser, '.')) {
				s32 apos = pos;
				force_sf = 0;
				if (idxNode) {
					apos = 0;
					switch (idxField.fieldType) {
					case GF_SG_VRML_SFBOOL:
						if (*(SFBool*)idxField.far_ptr) apos = 1;
						break;
					case GF_SG_VRML_SFINT32:
						if (*(SFInt32*)idxField.far_ptr >=0) apos = *(SFInt32*)idxField.far_ptr;
						break;
					case GF_SG_VRML_SFFLOAT:
						if ( (*(SFFloat *)idxField.far_ptr) >=0) apos = (s32) floor( FIX2FLT(*(SFFloat*)idxField.far_ptr) );
						break;
					case GF_SG_VRML_SFTIME:
						if ( (*(SFTime *)idxField.far_ptr) >=0) apos = (s32) floor( (*(SFTime *)idxField.far_ptr) );
						break;
					}
				}
				childNode = gf_node_list_get_child(*(GF_ChildNodeItem **)targetField.far_ptr, apos);
				if (!childNode)
					return gf_bt_report(parser, GF_BAD_PARAM, "Cannot find child node at specified index");

				str = gf_bt_get_next(parser, 0);
				strcpy(field, str);
				parser->last_error = gf_node_get_field_by_name(childNode, field, &childField);
				if (parser->last_error)
					return gf_bt_report(parser, parser->last_error, "%s: Unknown node field", field);
			}
		}

		str = gf_bt_get_next(parser, 0);
		if (strcmp(str, "BY")) return gf_bt_report(parser, GF_BAD_PARAM, "BY expected got %s", str);

		/*peek the next word*/
		j = 0;
		while (strchr(" \n\t\0", parser->line_buffer[parser->line_pos + j])) j++;
		str = parser->line_buffer + parser->line_pos + j;
		j = 0;
		while (!strchr(" .\0", str[j])) j++;
		csep = str[j];
		str[j]=0;
		strcpy(field, str);
		str[j] = csep;
		fromNode = gf_bt_peek_node(parser, field);
		if (fromNode) {
			gf_bt_get_next(parser, 1);

			if (!gf_bt_check_code(parser, '.')) {
				return gf_bt_report(parser, GF_BAD_PARAM, "XREPLACE: '.' expected");
			}
			/*get source field*/
			str = gf_bt_get_next(parser, 0);
			strcpy(field, str);
			parser->last_error = gf_node_get_field_by_name(fromNode, field, &fromField);
			if (parser->last_error)
				return gf_bt_report(parser, parser->last_error, "%s: Unknown node field", field);

		} else {
			/*regular parsing*/
		}

		com = gf_sg_command_new(parser->load->scene_graph, GF_SG_XREPLACE);
		bd_set_com_node(com, targetNode);
		if (fromNode) {
			com->fromNodeID = gf_node_get_id(fromNode);
			com->fromFieldIndex = fromField.fieldIndex;
		}
		if (idxNode) {
			com->toNodeID = gf_node_get_id(idxNode);
			com->toFieldIndex = idxField.fieldIndex;
		}
		if (childNode) {
			com->ChildNodeTag = gf_node_get_tag(childNode);
			if (com->ChildNodeTag==1) {
				com->ChildNodeTag = ((GF_ProtoInstance*)childNode)->proto_interface->ID;
				com->ChildNodeTag = -com->ChildNodeTag ;
			}
			com->child_field = childField.fieldIndex;
		}
		inf = gf_sg_command_field_new(com);
		inf->fieldIndex = targetField.fieldIndex;
		inf->pos = pos;
		if (force_sf) {
			inf->fieldType = gf_sg_vrml_get_sf_type(targetField.fieldType);
		} else if (childNode) {
			inf->fieldType = childField.fieldType;
		} else {
			inf->fieldType = targetField.fieldType;
		}
		if (!fromNode) {
			switch (inf->fieldType) {
			case GF_SG_VRML_SFNODE:
				inf->new_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
				inf->field_ptr = &inf->new_node;
				if (childNode) {
					if (!gf_bt_check_ndt(parser, &childField, inf->new_node, childNode)) goto err;
				} else {
					if (!gf_bt_check_ndt(parser, &targetField, inf->new_node, targetNode)) goto err;
				}
				break;
			case GF_SG_VRML_MFNODE:
			{
				GF_ChildNodeItem *last = NULL;
				if (!gf_bt_check_code(parser, '[')) break;
				inf->field_ptr = &inf->node_list;
				while (!gf_bt_check_code(parser, ']')) {
					newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
					if (!newnode) goto err;
					if (parser->last_error!=GF_OK) goto err;

					if (childNode) {
						if (!gf_bt_check_ndt(parser, &childField, inf->new_node, childNode)) goto err;
					} else {
						if (!gf_bt_check_ndt(parser, &targetField, inf->new_node, targetNode)) goto err;
					}

					gf_node_list_add_child_last(& inf->node_list, newnode, &last);
				}
			}
			break;
			default:
				inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType);
				info.far_ptr = inf->field_ptr;
				info.fieldType = inf->fieldType;

				if (gf_sg_vrml_is_sf_field(inf->fieldType)) {
					gf_bt_sffield(parser, &info, childNode ? childNode : targetNode);
				} else {
					gf_bt_mffield(parser, &info, childNode ? childNode : targetNode);
				}
				if (parser->last_error) goto err;
				break;
			}
		}

		if (parser->last_error) goto err;
		gf_list_add(cmdList, com);
		parser->cur_com = com;
		return parser->last_error;
	}


	/*INSERT commands*/
	if (!strcmp(str, "INSERT") || !strcmp(str, "APPEND")) {
		Bool is_append = !strcmp(str, "APPEND") ? 1 : 0;
		str = gf_bt_get_next(parser, 0);
		if (!strcmp(str, "ROUTE")) {
			com = gf_sg_command_new(parser->load->scene_graph, GF_SG_ROUTE_INSERT);
			gf_bt_parse_route(parser, 0, 1, com);
			if (parser->last_error) goto err;
			gf_list_add(cmdList, com);
			gf_list_add(parser->inserted_routes, com);
			parser->cur_com = com;
			return GF_OK;
		}
		if (strcmp(str, "AT") && strcmp(str, "TO")) {
			return gf_bt_report(parser, GF_BAD_PARAM, (char*) (is_append ? "TO expected got %s" : "AT expected got %s"), str);
		}
		str = gf_bt_get_next(parser, 1);
		strcpy(field, str);
		n = gf_bt_peek_node(parser, str);
		if (!n) {
			return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown node", field);
		}
		if (!gf_bt_check_code(parser, '.')) {
			return gf_bt_report(parser, GF_BAD_PARAM, ". expected");
		}
		str = gf_bt_get_next(parser, 1);
		strcpy(field, str);
		if (!is_append) {
			if (!gf_bt_check_code(parser, '[')) {
				return gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
			}
			gf_bt_parse_int(parser, "index", &pos);
			if (!gf_bt_check_code(parser, ']')) {
				return gf_bt_report(parser, GF_BAD_PARAM, "] expected");
			}
		} else {
			if (gf_bt_check_code(parser, '[')) {
				return gf_bt_report(parser, GF_BAD_PARAM, "[ unexpected in Append command");
			}
			pos = -1;
		}
		gf_node_get_field_by_name(n, field, &info);
		if (!strcmp(field, "children")) {
			newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
			if (parser->last_error) goto err;

			if (!gf_bt_check_ndt(parser, &info, newnode, n)) goto err;
			com = gf_sg_command_new(parser->load->scene_graph, GF_SG_NODE_INSERT);
			bd_set_com_node(com, n);
			inf = gf_sg_command_field_new(com);
			inf->pos = pos;
			inf->new_node = newnode;
			inf->fieldType = GF_SG_VRML_SFNODE;
			inf->field_ptr = &inf->new_node;
			if (parser->last_error) goto err;
			parser->cur_com = com;
			return gf_list_add(cmdList, com);
		}
		if (gf_sg_vrml_is_sf_field(info.fieldType)) {
			gf_bt_report(parser, GF_BAD_PARAM, "%s: MF type field expected", info.name);
			goto err;
		}
		com = gf_sg_command_new(parser->load->scene_graph, GF_SG_INDEXED_INSERT);
		bd_set_com_node(com, n);
		inf = gf_sg_command_field_new(com);
		inf->pos = pos;
		inf->fieldIndex = info.fieldIndex;
		inf->fieldType = gf_sg_vrml_get_sf_type(info.fieldType);
		switch (info.fieldType) {
		case GF_SG_VRML_MFNODE:
			inf->new_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
			inf->field_ptr = &inf->new_node;
			break;
		default:
			info.fieldType = inf->fieldType;
			inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType);
			info.far_ptr = inf->field_ptr;
			gf_bt_sffield(parser, &info, n);
			break;
		}
		if (parser->last_error) goto err;
		gf_list_add(cmdList, com);
		parser->cur_com = com;
		return parser->last_error;
	}
	/*DELETE commands*/
	if (!strcmp(str, "DELETE")) {
		str = gf_bt_get_next(parser, 1);
		if (!strcmp(str, "ROUTE")) {
			str = gf_bt_get_next(parser, 0);
			com = gf_sg_command_new(parser->load->scene_graph, GF_SG_ROUTE_DELETE);
			com->RouteID = gf_bt_get_route(parser, str);
			if (!com->RouteID) {
				com->unres_name = gf_strdup(str);
				com->unresolved = 1;
				gf_list_add(parser->unresolved_routes, com);
			}
			/*for bt<->xmt conversions*/
			com->def_name = gf_strdup(str);
			return gf_list_add(cmdList, com);
		}
		strcpy(field, str);
		n = gf_bt_peek_node(parser, str);
		if (!n) {
			return gf_bt_report(parser, GF_BAD_PARAM, "DELETE %s: Unknown Node", field);
		}
		if (!gf_bt_check_code(parser, '.')) {
			com = gf_sg_command_new(parser->load->scene_graph, GF_SG_NODE_DELETE);
			bd_set_com_node(com, n);
			return gf_list_add(cmdList, com);
		}
		str = gf_bt_get_next(parser, 0);
		if (gf_node_get_field_by_name(n, str, &info) != GF_OK) {
			return gf_bt_report(parser, GF_BAD_PARAM, "%s not a field of node %s", str, gf_node_get_class_name(n) );
		}
		if (gf_bt_check_code(parser, '[')) {
			gf_bt_parse_int(parser, "index", &pos);
			if (!gf_bt_check_code(parser, ']'))
				return gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
		}
		if (gf_sg_vrml_is_sf_field(info.fieldType)) {
			if (info.fieldType == GF_SG_VRML_SFNODE) {
				com = gf_sg_command_new(parser->load->scene_graph, GF_SG_FIELD_REPLACE);
				bd_set_com_node(com, n);
				inf = gf_sg_command_field_new(com);
				inf->fieldIndex = info.fieldIndex;
				inf->fieldType = info.fieldType;
				inf->new_node = NULL;
				inf->field_ptr = &inf->new_node;
				return gf_list_add(cmdList, com);
			}
			return gf_bt_report(parser, GF_BAD_PARAM, "%s is an SFField - cannot indexed delete", info.name);
		}

		com = gf_sg_command_new(parser->load->scene_graph, GF_SG_INDEXED_DELETE);
		bd_set_com_node(com, n);
		inf = gf_sg_command_field_new(com);
		inf->fieldIndex = info.fieldIndex;
		inf->fieldType = info.fieldType;
		inf->pos = pos;
		return gf_list_add(cmdList, com);
	}
	/*Extended BIFS commands*/

	/*GlobalQP commands*/
	if (!strcmp(str, "GLOBALQP")) {
		newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
		if (newnode && (newnode->sgprivate->tag != TAG_MPEG4_QuantizationParameter)) {
			gf_bt_report(parser, GF_BAD_PARAM, "Only QuantizationParameter node allowed in GLOBALQP");
			gf_node_unregister(newnode, NULL);
			return parser->last_error;
		}
		com = gf_sg_command_new(parser->load->scene_graph, GF_SG_GLOBAL_QUANTIZER);
		com->node = NULL;
		inf = gf_sg_command_field_new(com);
		inf->new_node = newnode;
		inf->field_ptr = &inf->new_node;
		inf->fieldType = GF_SG_VRML_SFNODE;
		return gf_list_add(cmdList, com);
	}

	/*MultipleReplace commands*/
	if (!strcmp(str, "MULTIPLEREPLACE")) {
		str = gf_bt_get_next(parser, 0);
		strcpy(field, str);
		n = gf_bt_peek_node(parser, str);
		if (!n) {
			return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown node", field);
		}
		if (!gf_bt_check_code(parser, '{')) {
			return gf_bt_report(parser, GF_BAD_PARAM, "{ expected");
		}
		com = gf_sg_command_new(parser->load->scene_graph, GF_SG_MULTIPLE_REPLACE);
		bd_set_com_node(com, n);

		while (!gf_bt_check_code(parser, '}')) {
			str = gf_bt_get_next(parser, 0);
			parser->last_error = gf_node_get_field_by_name(n, str, &info);
			if (parser->last_error) {
				gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown node field", str);
				goto err;
			}
			inf = gf_sg_command_field_new(com);
			inf->fieldIndex = info.fieldIndex;
			inf->fieldType = info.fieldType;
			inf->pos = -1;

			switch (info.fieldType) {
			case GF_SG_VRML_SFNODE:
				inf->new_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
				if (parser->last_error) goto err;
				if (!gf_bt_check_ndt(parser, &info, inf->new_node, n)) goto err;
				inf->field_ptr = &inf->new_node;
				break;
			case GF_SG_VRML_MFNODE:
			{
				GF_ChildNodeItem *last = NULL;
				if (!gf_bt_check_code(parser, '[')) {
					gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
					goto err;
				}
				info.far_ptr = inf->field_ptr = &inf->node_list;
				while (!gf_bt_check_code(parser, ']')) {
					newnode = gf_bt_sf_node(parser, NULL, NULL, NULL);
					if (parser->last_error!=GF_OK) goto err;
					if (!gf_bt_check_ndt(parser, &info, newnode, n)) goto err;
					gf_node_list_add_child_last( & inf->node_list, newnode, &last);
				}
			}
			break;
			default:
				info.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType);
				if (gf_sg_vrml_is_sf_field(info.fieldType)) {
					gf_bt_sffield(parser, &info, n);
				} else {
					gf_bt_mffield(parser, &info, n);
				}
				if (parser->last_error) goto err;
				break;
			}
		}
		parser->cur_com = com;
		return gf_list_add(cmdList, com);
	}

	/*MultipleIndexReplace commands*/
	if (!strcmp(str, "MULTIPLEINDREPLACE")) {
		str = gf_bt_get_next(parser, 1);
		strcpy(field, str);
		n = gf_bt_peek_node(parser, str);
		if (!n) {
			return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown node", field);
		}
		if (!gf_bt_check_code(parser, '.')) {
			return gf_bt_report(parser, GF_BAD_PARAM, ". expected");
		}
		str = gf_bt_get_next(parser, 0);
		parser->last_error = gf_node_get_field_by_name(n, str, &info);
		if (parser->last_error) {
			return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown field", info.name);
		}
		if (gf_sg_vrml_is_sf_field(info.fieldType)) {
			return gf_bt_report(parser, GF_BAD_PARAM, "Only MF field allowed");
		}
		if (!gf_bt_check_code(parser, '[')) {
			return gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
		}

		com = gf_sg_command_new(parser->load->scene_graph, GF_SG_MULTIPLE_INDEXED_REPLACE);
		bd_set_com_node(com, n);
		info.fieldType = gf_sg_vrml_get_sf_type(info.fieldType);

		while (!gf_bt_check_code(parser, ']')) {
			u32 pos;
			if (gf_bt_parse_int(parser, "position", (SFInt32 *)&pos)) goto err;
			str = gf_bt_get_next(parser, 0);
			if (strcmp(str, "BY")) {
				gf_bt_report(parser, GF_BAD_PARAM, "BY expected");
				goto err;
			}
			inf = gf_sg_command_field_new(com);
			inf->fieldIndex = info.fieldIndex;
			inf->fieldType = info.fieldType;
			inf->pos = pos;
			if (inf->fieldType==GF_SG_VRML_SFNODE) {
				info.far_ptr = inf->field_ptr = &inf->new_node;
				inf->new_node = gf_bt_sf_node(parser, NULL, NULL, NULL);
				if (parser->last_error) goto err;
				if (!gf_bt_check_ndt(parser, &info, inf->new_node, n)) goto err;
				inf->field_ptr = &inf->new_node;
			} else {
				info.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType);
				gf_bt_sffield(parser, &info, n);
				if (parser->last_error) goto err;
			}
		}
		parser->cur_com = com;
		return gf_list_add(cmdList, com);
	}

	if (!strcmp(str, "XDELETE")) {
		str = gf_bt_get_next(parser, 1);
		strcpy(field, str);
		n = gf_bt_peek_node(parser, str);
		if (!n) {
			return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown Node", field);
		}
		com = gf_sg_command_new(parser->load->scene_graph, GF_SG_NODE_DELETE_EX);
		bd_set_com_node(com, n);
		return gf_list_add(cmdList, com);
	}

	if (!strcmp(str, "INSERTPROTO")) {
		if (!gf_bt_check_code(parser, '[')) {
			return gf_bt_report(parser, GF_BAD_PARAM, "[ expected");
		}
		com = gf_sg_command_new(parser->load->scene_graph, GF_SG_PROTO_INSERT);
		while (!gf_bt_check_code(parser, ']')) {
			parser->last_error = gf_bt_parse_proto(parser, NULL, com->new_proto_list);
			if (parser->last_error) goto err;
		}
		gf_list_add(cmdList, com);
		return GF_OK;
	}
	if (!strcmp(str, "DELETEPROTO")) {
		if (!gf_bt_check_code(parser, '[')) {
			com = gf_sg_command_new(parser->load->scene_graph, GF_SG_PROTO_DELETE_ALL);
			str = gf_bt_get_next(parser, 0);
			if (strcmp(str, "ALL")) {
				gf_bt_report(parser, GF_BAD_PARAM, "ALL expected");
				goto err;
			}
			return gf_list_add(cmdList, com);
		}
		com = gf_sg_command_new(parser->load->scene_graph, GF_SG_PROTO_DELETE);
		while (!gf_bt_check_code(parser, ']')) {
			GF_Proto *proto;
			str = gf_bt_get_next(parser, 0);
			proto = gf_sg_find_proto(parser->load->scene_graph, 0, str);
			if (!proto) {
				gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown proto", str);
				goto err;
			}
			com->del_proto_list = (u32*)gf_realloc(com->del_proto_list, sizeof(u32)*(com->del_proto_list_size+1));
			com->del_proto_list[com->del_proto_list_size] = proto->ID;
			com->del_proto_list_size++;
		}
		gf_list_add(cmdList, com);
		return GF_OK;
	}
	return gf_bt_report(parser, GF_BAD_PARAM, "%s: Unknown command syntax, str");

err:
	if (com) gf_sg_command_del(com);
	return parser->last_error;
}