in src/scene_manager/loader_xmt.c [1989:2491]
static void xmt_parse_command(GF_XMTParser *parser, const char *name, const GF_XMLAttribute *attributes, u32 nb_attributes)
{
GF_Err e;
GF_FieldInfo info;
GF_CommandField *field;
u32 i;
if (!strcmp(name, "Scene")) {
parser->state = XMT_STATE_ELEMENTS;
return;
}
if (!parser->in_com)
parser->stream_id = parser->load->force_es_id;
if (!strcmp(name, "par")) {
parser->in_com = 1;
for (i=0; i<nb_attributes; i++) {
GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
if (!att->value || !strlen(att->value)) continue;
if (!strcmp(att->name, "begin")) parser->au_time = atof(att->value);
else if (!strcmp(att->name, "isRAP")) parser->au_is_rap = !strcmp(att->value, "yes") ? 1 : 0;
else if (!strcmp(att->name, "atES_ID")) {
parser->stream_id = xmt_locate_stream(parser, att->value);
if (!parser->stream_id) xmt_report(parser, GF_OK, "Warning: Cannot locate command's target stream %s", att->value);
}
}
return;
}
/*ROUTE insert/replace*/
if (!strcmp(name, "ROUTE")) {
if (!parser->command || ((parser->command->tag!=GF_SG_ROUTE_REPLACE) && (parser->command->tag!=GF_SG_ROUTE_INSERT))) {
xmt_report(parser, GF_BAD_PARAM, "ROUTE declared outside command scope");
return;
}
if (parser->command->tag==GF_SG_ROUTE_INSERT) {
xmt_parse_route(parser, attributes, nb_attributes, 1, parser->command);
gf_list_add(parser->inserted_routes, parser->command);
} else {
xmt_parse_route(parser, attributes, nb_attributes, 0, parser->command);
if (!parser->command->RouteID) {
parser->command->unresolved = 1;
if (gf_list_find(parser->unresolved_routes, parser->command)<0)
gf_list_add(parser->unresolved_routes, parser->command);
}
}
return;
}
/*multiple replace*/
if (!strcmp(name, "repField")) {
char *fieldName = NULL;
char *fieldValue = NULL;
assert(parser->command);
if (!parser->command->node) return;
for (i=0; i<nb_attributes; i++) {
GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
if (!att->value || !strlen(att->value)) continue;
if (!strcmp(att->name, "atField")) fieldName = att->value;
else if (!strcmp(att->name, "value")) fieldValue = att->value;
}
if (!fieldName) {
parser->state = XMT_STATE_ELEMENTS;
return;
}
e = gf_node_get_field_by_name(parser->command->node, fieldName, &info);
if (e) {
xmt_report(parser, GF_BAD_PARAM, "Warning: Field %s not a member of node %s ", fieldName, gf_node_get_class_name(parser->command->node) );
return;
}
if (gf_sg_vrml_get_sf_type(info.fieldType) == GF_SG_VRML_SFNODE) {
parser->state = XMT_STATE_ELEMENTS;
return;
}
if (!fieldValue) return;
field = gf_sg_command_field_new(parser->command);
field->fieldIndex = info.fieldIndex;
field->fieldType = info.fieldType;
if (fieldValue) {
field->field_ptr = gf_sg_vrml_field_pointer_new(info.fieldType);
info.far_ptr = field->field_ptr;
if (gf_sg_vrml_is_sf_field(info.fieldType)) {
xmt_parse_sf_field(parser, &info, parser->command->node, fieldValue);
} else {
xmt_parse_mf_field(parser, &info, parser->command->node, fieldValue);
}
} else {
parser->state = XMT_STATE_ELEMENTS;
}
return;
}
/*multiple index replace*/
if (!strcmp(name, "repValue")) {
s32 position = -1;
char *fieldValue = NULL;
assert(parser->command);
if (!parser->command->node) return;
for (i=0; i<nb_attributes; i++) {
GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
if (!att->value || !strlen(att->value)) continue;
if (!strcmp(att->name, "position")) {
if (!strcmp(att->value, "BEGIN")) position = 0;
else if (!strcmp(att->value, "END")) position = -1;
else position = atoi(att->value);
}
else if (!strcmp(att->name, "value")) fieldValue = att->value;
}
gf_node_get_field(parser->command->node, parser->command->fromFieldIndex, &info);
if (info.fieldType == GF_SG_VRML_MFNODE) {
field = gf_sg_command_field_new(parser->command);
field->fieldIndex = info.fieldIndex;
field->fieldType = GF_SG_VRML_SFNODE;
field->pos = position;
parser->state = XMT_STATE_ELEMENTS;
} else if (fieldValue) {
field = gf_sg_command_field_new(parser->command);
field->fieldIndex = info.fieldIndex;
field->fieldType = info.fieldType = gf_sg_vrml_get_sf_type(info.fieldType);
field->field_ptr = gf_sg_vrml_field_pointer_new(info.fieldType);
field->pos = position;
info.far_ptr = field->field_ptr;
xmt_parse_sf_field(parser, &info, parser->command->node, fieldValue);
}
return;
}
/*BIFS command*/
if (!strcmp(name, "Replace") || !strcmp(name, "Insert") || !strcmp(name, "Delete")) {
GF_Node *atNode;
u8 tag = GF_SG_UNDEFINED;
u32 stream_id;
Double au_time = parser->au_time;
Bool au_is_rap = parser->au_is_rap;
char *nodeName = NULL;
char *fieldName = NULL;
char *fieldValue = NULL;
char *routeName = NULL;
char *extended = NULL;
char *idxNode = NULL;
char *idxField = NULL;
char *childField = NULL;
char *fromNode = NULL;
char *fromField = NULL;
s32 position = -2;
if (!parser->stream_id) parser->stream_id = parser->base_scene_id;
stream_id = parser->stream_id;
for (i=0; i<nb_attributes; i++) {
GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
if (!att->value || !strlen(att->value)) continue;
if (!strcmp(att->name, "begin")) au_time = atoi(att->value);
else if (!strcmp(att->name, "isRAP")) au_is_rap = !strcmp(att->value, "yes") ? 1 : 0;
else if (!strcmp(att->name, "atES_ID")) {
stream_id = xmt_locate_stream(parser, att->value);
if (!stream_id) {
xmt_report(parser, GF_OK, "Warning: Cannot locate command's target stream %s", att->value);
stream_id = parser->stream_id;
}
}
else if (!strcmp(att->name, "atNode")) nodeName = att->value;
else if (!strcmp(att->name, "atField")) fieldName = att->value;
else if (!strcmp(att->name, "value")) fieldValue = att->value;
else if (!strcmp(att->name, "atRoute")) routeName = att->value;
else if (!strcmp(att->name, "extended")) extended = att->value;
else if (!strcmp(att->name, "atIndexNode")) idxNode = att->value;
else if (!strcmp(att->name, "atIndexField")) idxField = att->value;
else if (!strcmp(att->name, "atChildField")) childField = att->value;
else if (!strcmp(att->name, "fromNode")) fromNode = att->value;
else if (!strcmp(att->name, "fromField")) fromField = att->value;
else if (!strcmp(att->name, "position")) {
if (!strcmp(att->value, "BEGIN")) position = 0;
else if (!strcmp(att->value, "END")) position = -1;
else position = atoi(att->value);
}
}
/*if we are parsing in an already loaded context and no time is given, force a time != 0 to create a new command*/
if (!au_time && (parser->load->flags&GF_SM_LOAD_CONTEXT_READY))
au_time = 0.001;
atNode = NULL;
if (nodeName) {
if (fieldName) {
if (position>-2) {
if (!strcmp(name, "Replace")) tag = GF_SG_INDEXED_REPLACE;
else if (!strcmp(name, "Insert")) tag = GF_SG_INDEXED_INSERT;
else if (!strcmp(name, "Delete")) tag = GF_SG_INDEXED_DELETE;
} else {
if (!strcmp(name, "Replace")) {
if ((idxNode && idxField) || childField || (fromNode && fromField)) {
tag = GF_SG_XREPLACE;
} else {
tag = GF_SG_FIELD_REPLACE;
}
}
}
} else {
if (!strcmp(name, "Replace")) {
tag = GF_SG_NODE_REPLACE;
parser->state = XMT_STATE_ELEMENTS;
}
else if (!strcmp(name, "Insert")) {
tag = GF_SG_NODE_INSERT;
parser->state = XMT_STATE_ELEMENTS;
}
else if (!strcmp(name, "Delete")) tag = GF_SG_NODE_DELETE;
}
atNode = xmt_find_node(parser, nodeName);
if (!atNode) {
xmt_report(parser, GF_BAD_PARAM, "Warning: Cannot locate node %s for command %s", nodeName, name);
return;
}
if (fieldName) {
e = gf_node_get_field_by_name(atNode, fieldName, &info);
if (e) {
xmt_report(parser, GF_BAD_PARAM, "Warning: Field %s not a member of node %s ", fieldName, nodeName);
return;
}
}
}
else if (routeName) {
if (!strcmp(name, "Replace")) tag = GF_SG_ROUTE_REPLACE;
else if (!strcmp(name, "Delete")) tag = GF_SG_ROUTE_DELETE;
}
else if (!strcmp(name, "Replace")) {
tag = GF_SG_SCENE_REPLACE;
au_is_rap = 1;
gf_list_reset(parser->def_nodes);
}
else if (!strcmp(name, "Insert"))
tag = GF_SG_ROUTE_INSERT;
if (extended) {
if (!strcmp(extended, "globalQuant")) {
tag = GF_SG_GLOBAL_QUANTIZER;
parser->state = XMT_STATE_ELEMENTS;
}
else if (!strcmp(extended, "fields")) {
tag = GF_SG_MULTIPLE_REPLACE;
parser->state = XMT_STATE_COMMANDS;
}
else if (!strcmp(extended, "indices")) {
tag = GF_SG_MULTIPLE_INDEXED_REPLACE;
parser->state = XMT_STATE_COMMANDS;
}
else if (!strcmp(extended, "deleteOrder")) tag = GF_SG_NODE_DELETE_EX;
else if (!strcmp(extended, "allProtos")) tag = GF_SG_PROTO_DELETE_ALL;
else if (!strcmp(extended, "proto") || !strcmp(extended, "protos")) {
if (!strcmp(name, "Insert")) {
parser->state = XMT_STATE_ELEMENTS;
tag = GF_SG_PROTO_INSERT;
}
else if (!strcmp(name, "Delete")) tag = GF_SG_PROTO_DELETE;
}
else {
xmt_report(parser, GF_BAD_PARAM, "Warning: Unknown extended command %s", extended);
return;
}
}
if (tag == GF_SG_UNDEFINED) {
xmt_report(parser, GF_BAD_PARAM, "Warning: Unknown scene command %s", name);
return;
}
parser->command = gf_sg_command_new(parser->load->scene_graph, tag);
if (parser->command_buffer) {
gf_list_add(parser->command_buffer->commandList, parser->command);
parser->command_buffer->bufferSize++;
} else {
GF_StreamContext *stream = gf_sm_stream_find(parser->load->ctx, (u16) stream_id);
if (!stream || (stream->streamType!=GF_STREAM_SCENE)) stream_id = parser->base_scene_id;
parser->scene_es = gf_sm_stream_new(parser->load->ctx, (u16) stream_id, GF_STREAM_SCENE, GPAC_OTI_SCENE_BIFS);
parser->scene_au = gf_sm_stream_au_new(parser->scene_es, 0, au_time, au_is_rap);
gf_list_add(parser->scene_au->commands, parser->command);
}
if (atNode) {
parser->command->node = atNode;
gf_node_register(atNode, NULL);
if (tag == GF_SG_MULTIPLE_INDEXED_REPLACE) {
parser->command->fromFieldIndex = info.fieldIndex;
return;
}
if (fieldName) {
field = gf_sg_command_field_new(parser->command);
field->fieldIndex = info.fieldIndex;
if (idxNode && idxField) {
GF_Node *iNode = xmt_find_node(parser, idxNode);
if (iNode) {
GF_FieldInfo idxF;
parser->command->toNodeID = gf_node_get_id(iNode);
gf_node_get_field_by_name(iNode, idxField, &idxF);
parser->command->toFieldIndex = idxF.fieldIndex;
position = 0;
switch (idxF.fieldType) {
case GF_SG_VRML_SFBOOL:
if (*(SFBool*)idxF.far_ptr) position = 1;
break;
case GF_SG_VRML_SFINT32:
if (*(SFInt32*)idxF.far_ptr >=0) position = *(SFInt32*)idxF.far_ptr;
break;
case GF_SG_VRML_SFFLOAT:
if ( (*(SFFloat *)idxF.far_ptr) >=0) position = (s32) floor( FIX2FLT(*(SFFloat*)idxF.far_ptr) );
break;
case GF_SG_VRML_SFTIME:
if ( (*(SFTime *)idxF.far_ptr) >=0) position = (s32) floor( (*(SFTime *)idxF.far_ptr) );
break;
}
}
}
if (childField) {
GF_Node *child = gf_node_list_get_child( ((GF_ParentNode*)atNode)->children, position);
if (child) {
parser->command->ChildNodeTag = gf_node_get_tag(child);
if (parser->command->ChildNodeTag == TAG_ProtoNode) {
s32 p_id = gf_sg_proto_get_id(gf_node_get_proto(child));
parser->command->ChildNodeTag = -p_id;
}
/*get field in the info struct for later parsing*/
gf_node_get_field_by_name(child, childField, &info);
parser->command->child_field = info.fieldIndex;
}
}
/*do not keep position info if index node is used*/
if (idxNode && idxField) position = -2;
if (fromNode && fromField) {
GF_Node *fNode = xmt_find_node(parser, fromNode);
if (fNode) {
GF_FieldInfo fField;
parser->command->fromNodeID = gf_node_get_id(fNode);
gf_node_get_field_by_name(fNode, fromField, &fField);
parser->command->fromFieldIndex = fField.fieldIndex;
}
}
if (!fromNode && !fromField) {
if (gf_sg_vrml_get_sf_type(info.fieldType) != GF_SG_VRML_SFNODE) {
if (position==-2) {
field->fieldType = info.fieldType;
field->field_ptr = gf_sg_vrml_field_pointer_new(info.fieldType);
info.far_ptr = field->field_ptr;
if (gf_sg_vrml_is_sf_field(info.fieldType)) {
xmt_parse_sf_field(parser, &info, atNode, fieldValue);
} else {
xmt_parse_mf_field(parser, &info, atNode, fieldValue);
}
} else {
field->fieldType = info.fieldType = gf_sg_vrml_get_sf_type(info.fieldType);
field->pos = position;
if (tag != GF_SG_INDEXED_DELETE) {
field->field_ptr = gf_sg_vrml_field_pointer_new(info.fieldType);
info.far_ptr = field->field_ptr;
xmt_parse_sf_field(parser, &info, atNode, fieldValue);
}
}
} else {
field->pos = position;
if ((position==-2) && (info.fieldType==GF_SG_VRML_MFNODE)) {
field->fieldType = GF_SG_VRML_MFNODE;
} else {
field->fieldType = GF_SG_VRML_SFNODE;
}
parser->state = XMT_STATE_ELEMENTS;
}
}
} else if (tag==GF_SG_NODE_INSERT) {
field = gf_sg_command_field_new(parser->command);
field->fieldType = GF_SG_VRML_SFNODE;
field->pos = position;
parser->state = XMT_STATE_ELEMENTS;
}
}
else if (routeName) {
u32 rID = xmt_get_route(parser, routeName, 0);
if (!rID) {
parser->command->unres_name = gf_strdup(routeName);
parser->command->unresolved = 1;
gf_list_add(parser->unresolved_routes, parser->command);
} else {
parser->command->RouteID = rID;
/*for bt<->xmt conversions*/
parser->command->def_name = gf_strdup(routeName);
}
}
else if (tag == GF_SG_PROTO_DELETE) {
char *sep;
while (fieldValue) {
GF_Proto *p;
sep = strchr(fieldValue, ' ');
if (sep) sep[0] = 0;
p = gf_sg_find_proto(parser->load->scene_graph, 0, fieldValue);
if (!p) p = gf_sg_find_proto(parser->load->scene_graph, atoi(fieldValue), NULL);
if (!p) xmt_report(parser, GF_OK, "Warning: Cannot locate proto %s - skipping", fieldValue);
else {
parser->command->del_proto_list = (u32*)gf_realloc(parser->command->del_proto_list, sizeof(u32) * (parser->command->del_proto_list_size+1));
parser->command->del_proto_list[parser->command->del_proto_list_size] = p->ID;
parser->command->del_proto_list_size++;
}
if (!sep) break;
sep[0] = ' ';
fieldValue = sep+1;
}
}
return;
}
/*OD commands*/
if (!strcmp(name, "ObjectDescriptorUpdate") || !strcmp(name, "ObjectDescriptorRemove")
|| !strcmp(name, "ES_DescriptorUpdate") || !strcmp(name, "ES_DescriptorRemove")
|| !strcmp(name, "IPMP_DescriptorUpdate") || !strcmp(name, "IPMP_DescriptorRemove") ) {
u32 stream_id;
u8 tag = 0;
GF_StreamContext *stream;
char *od_ids = NULL;
char *es_ids = NULL;
Double au_time = parser->au_time;
Bool au_is_rap = parser->au_is_rap;
if (!parser->stream_id) parser->stream_id = parser->base_od_id;
stream_id = parser->stream_id;
for (i=0; i<nb_attributes; i++) {
GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
if (!att->value || !strlen(att->value)) continue;
if (!strcmp(att->name, "begin")) au_time = atoi(att->value);
else if (!strcmp(att->name, "isRAP")) au_is_rap = !strcmp(att->value, "yes") ? 1 : 0;
else if (!stricmp(att->name, "objectDescriptorId")) od_ids = att->value;
else if (!strcmp(att->name, "ES_ID")) es_ids = att->value;
}
/*if we are parsing in an already loaded context and no time is given, force a time != 0 to create a new command*/
if (!au_time && (parser->load->flags&GF_SM_LOAD_CONTEXT_READY))
au_time = 0.001;
if (!strcmp(name, "ObjectDescriptorUpdate")) tag = GF_ODF_OD_UPDATE_TAG;
else if (!strcmp(name, "ES_DescriptorUpdate")) tag = GF_ODF_ESD_UPDATE_TAG;
else if (!strcmp(name, "IPMP_DescriptorUpdate")) tag = GF_ODF_IPMP_UPDATE_TAG;
else if (!strcmp(name, "ObjectDescriptorRemove")) {
if (!od_ids) return;
tag = GF_ODF_OD_REMOVE_TAG;
}
else if (!strcmp(name, "ES_DescriptorRemove")) {
if (!od_ids || !es_ids) return;
tag = GF_ODF_ESD_REMOVE_TAG;
}
else if (!strcmp(name, "IPMP_DescriptorRemove")) tag = GF_ODF_IPMP_REMOVE_TAG;
stream = gf_sm_stream_find(parser->load->ctx, (u16) stream_id);
if (stream && (stream->streamType!=GF_STREAM_OD)) stream_id = parser->base_od_id;
parser->od_es = gf_sm_stream_new(parser->load->ctx, (u16) stream_id, GF_STREAM_OD, 0);
parser->od_au = gf_sm_stream_au_new(parser->od_es, 0, au_time, au_is_rap);
parser->od_command = gf_odf_com_new(tag);
gf_list_add(parser->od_au->commands, parser->od_command);
if (tag == GF_ODF_ESD_REMOVE_TAG) {
char *sep;
GF_ESDRemove *esdR = (GF_ESDRemove *) parser->od_command ;
esdR->ODID = xmt_get_od_id(parser, od_ids);
while (es_ids) {
u32 es_id;
sep = strchr(es_ids, ' ');
if (sep) sep[0] = 0;
es_id = xmt_get_esd_id(parser, es_ids);
if (!es_id) xmt_report(parser, GF_OK, "Warning: Cannot find ES Descriptor %s - skipping", es_ids);
else {
esdR->ES_ID = (u16*)gf_realloc(esdR->ES_ID, sizeof(u16) * (esdR->NbESDs+1));
esdR->ES_ID[esdR->NbESDs] = es_id;
esdR->NbESDs++;
}
if (!sep) break;
sep[0] = ' ';
es_ids = sep+1;
}
}
else if (tag == GF_ODF_OD_REMOVE_TAG) {
char *sep;
GF_ODRemove *odR = (GF_ODRemove *) parser->od_command ;
while (od_ids) {
u32 od_id;
sep = strchr(od_ids, ' ');
if (sep) sep[0] = 0;
od_id = xmt_get_od_id(parser, od_ids);
if (!od_id) xmt_report(parser, GF_OK, "Warning: Cannot find Object Descriptor %s - skipping", od_ids);
else {
odR->OD_ID = (u16*)gf_realloc(odR->OD_ID, sizeof(u16) * (odR->NbODs+1));
odR->OD_ID[odR->NbODs] = od_id;
odR->NbODs++;
}
if (!sep) break;
sep[0] = ' ';
es_ids = sep+1;
}
}
}
}