static void xmt_node_end()

in src/scene_manager/loader_xmt.c [2600:2935]


static void xmt_node_end(void *sax_cbck, const char *name, const char *name_space)
{
	u32 tag;
	GF_XMTParser *parser = (GF_XMTParser *)sax_cbck;
	XMTNodeStack *top;
	GF_Descriptor *desc;
	GF_Node *node = NULL;
	if (!parser->doc_type || !parser->state) return;

	top = (XMTNodeStack *)gf_list_last(parser->nodes);

	if (!top) {
		/*check descr*/
		desc = (GF_Descriptor*)gf_list_last(parser->descriptors);
		if (desc && (desc->tag == gf_odf_get_tag_by_name((char *)name)) ) {

			/*assign timescales once the ESD has been parsed*/
			if (desc->tag == GF_ODF_ESD_TAG) {
				GF_ESD *esd = (GF_ESD*)desc;
				GF_StreamContext *sc = gf_sm_stream_new(parser->load->ctx, esd->ESID, esd->decoderConfig ? esd->decoderConfig->streamType : 0, esd->decoderConfig ? esd->decoderConfig->objectTypeIndication : 0);
				if (sc && esd->slConfig && esd->slConfig->timestampResolution)
					sc->timeScale = esd->slConfig->timestampResolution;
			}

			gf_list_rem_last(parser->descriptors);
			if (gf_list_count(parser->descriptors)) return;

			if ((parser->doc_type==1) && (parser->state==XMT_STATE_HEAD) && parser->load->ctx && !parser->load->ctx->root_od) {
				parser->load->ctx->root_od = (GF_ObjectDescriptor *)desc;
			}
			else if (!parser->od_command) {
				xmt_report(parser, GF_OK, "Warning: descriptor %s defined outside scene scope - skipping", name);
				gf_odf_desc_del(desc);
			} else {
				switch (parser->od_command->tag) {
				case GF_ODF_ESD_UPDATE_TAG:
					gf_list_add( ((GF_ESDUpdate *)parser->od_command)->ESDescriptors, desc);
					break;
				/*same struct for OD update and IPMP update*/
				case GF_ODF_OD_UPDATE_TAG:
				case GF_ODF_IPMP_UPDATE_TAG:
					gf_list_add( ((GF_ODUpdate *)parser->od_command)->objectDescriptors, desc);
					break;
				}
			}

			return;
		}
		if (parser->state == XMT_STATE_HEAD) {
			if ((parser->doc_type == 1) && !strcmp(name, "Header")) parser->state = XMT_STATE_BODY;
			/*X3D header*/
			else if ((parser->doc_type == 2) && !strcmp(name, "head")) {
				parser->state = XMT_STATE_BODY;
				/*create a group at root level*/
				tag = xmt_get_node_tag(parser, "Group");
				node = gf_node_new(parser->load->scene_graph, tag);
				gf_node_register(node, NULL);
				gf_sg_set_root_node(parser->load->scene_graph, node);
				gf_node_init(node);

				/*create a default top for X3D*/
				GF_SAFEALLOC(parser->x3d_root, XMTNodeStack);
				parser->x3d_root->node = node;
			}
			/*XMT-O header*/
			else if ((parser->doc_type == 3) && !strcmp(name, "head")) parser->state = XMT_STATE_BODY;
		}
		else if (parser->state == XMT_STATE_ELEMENTS) {
			assert((parser->doc_type != 1) || parser->command);
			if (!strcmp(name, "Replace") || !strcmp(name, "Insert") || !strcmp(name, "Delete")) {
				parser->command = NULL;
				parser->state = XMT_STATE_COMMANDS;
			}
			/*end proto*/
			else if (!strcmp(name, "ProtoDeclare") || !strcmp(name, "ExternProtoDeclare"))  {
				GF_Proto *cur = parser->parsing_proto;
				xmt_resolve_routes(parser);
				parser->parsing_proto = (GF_Proto*)cur->userpriv;
				parser->load->scene_graph = cur->parent_graph;
				cur->userpriv = NULL;
			}
			else if (parser->proto_field && !strcmp(name, "field")) parser->proto_field = NULL;
			/*end X3D body*/
			else if ((parser->doc_type == 2) && !strcmp(name, "Scene")) parser->state = XMT_STATE_BODY_END;
		}
		else if (parser->state == XMT_STATE_COMMANDS) {
			/*end XMT-A body*/
			if ((parser->doc_type == 1) && !strcmp(name, "Body")) parser->state = XMT_STATE_BODY_END;
			/*end X3D body*/
			else if ((parser->doc_type == 2) && !strcmp(name, "Scene")) parser->state = XMT_STATE_BODY_END;
			/*end XMT-O body*/
			else if ((parser->doc_type == 3) && !strcmp(name, "body")) parser->state = XMT_STATE_BODY_END;

			/*end scene command*/
			else if (!strcmp(name, "Replace") || !strcmp(name, "Insert") || !strcmp(name, "Delete") )  {
				/*restore parent command if in CommandBuffer*/
				if (parser->command && parser->command_buffer && parser->command_buffer->buffer) {
					//empty <Insert>
					if ((parser->command->tag==GF_SG_ROUTE_INSERT) && !parser->command->fromNodeID) {
						gf_list_del_item(parser->command_buffer->commandList, parser->command);
					}

					parser->command = (GF_Command*) parser->command_buffer->buffer;
					parser->command_buffer->buffer = NULL;
					parser->command_buffer = NULL;
				} else {
					//empty <Insert>
					if (parser->command && (parser->command->tag==GF_SG_ROUTE_INSERT) && !parser->command->fromNodeID) {
						gf_list_del_item(parser->scene_au->commands, parser->command);
					}
					parser->command = NULL;
				}
			}
			/*end OD command*/
			else if (!strcmp(name, "ObjectDescriptorUpdate") || !strcmp(name, "ObjectDescriptorRemove")
			         || !strcmp(name, "ES_DescriptorUpdate") || !strcmp(name, "ES_DescriptorRemove")
			         || !strcmp(name, "IPMP_DescriptorUpdate") || !strcmp(name, "IPMP_DescriptorRemove") ) {
				parser->od_command = NULL;
			}

			else if (!strcmp(name, "par"))
				parser->in_com = 1;


		}
		else if (parser->state == XMT_STATE_BODY_END) {
			/*end XMT-A*/
			if ((parser->doc_type == 1) && !strcmp(name, "XMT-A")) parser->state = XMT_STATE_END;
			/*end X3D*/
			else if ((parser->doc_type == 2) && !strcmp(name, "X3D")) {
				while (1) {
					GF_Node *n = (GF_Node *)gf_list_last(parser->script_to_load);
					if (!n) break;
					gf_list_rem_last(parser->script_to_load);
					gf_sg_script_load(n);
				}
				gf_list_del(parser->script_to_load);
				parser->script_to_load = NULL;
				parser->state = XMT_STATE_END;
			}
			/*end XMT-O*/
			else if ((parser->doc_type == 3) && !strcmp(name, "XMT-O")) parser->state = XMT_STATE_END;
		}
		return;
	}
	/*only remove created nodes ... */
	tag = xmt_get_node_tag(parser, name);
	if (!tag) {
		if (top->container_field.name) {
			if (!strcmp(name, top->container_field.name)) {
				if (top->container_field.fieldType==GF_SG_VRML_SFCOMMANDBUFFER) {
					parser->state = XMT_STATE_ELEMENTS;
					parser->command = (GF_Command *) (void *) parser->command_buffer->buffer;
					parser->command_buffer->buffer = NULL;
					parser->command_buffer = NULL;
				}
				top->container_field.far_ptr = NULL;
				top->container_field.name = NULL;
				top->last = NULL;
			}
			/*end of command inside an command (conditional.buffer replace)*/
			else if (!strcmp(name, "Replace") || !strcmp(name, "Insert") || !strcmp(name, "Delete") )  {
				if (parser->command_buffer) {
					if (parser->command_buffer->bufferSize) {
						parser->command_buffer->bufferSize--;
					} else {
						SFCommandBuffer *prev = (SFCommandBuffer *) parser->command_buffer->buffer;
						parser->command_buffer->buffer = NULL;
						parser->command_buffer = prev;
					}
					/*stay in command parsing mode (state 3) until we find </buffer>*/
					parser->state = XMT_STATE_COMMANDS;
				}
			}
			/*end of protofield node(s) content*/
			else if (!strcmp(name, "node") || !strcmp(name, "nodes")) {
				top->container_field.far_ptr = NULL;
				top->container_field.name = NULL;
				top->last = NULL;
			}
		}
		/*SF/MFNode proto field, just pop node stack*/
		else if (!top->node && !strcmp(name, "field")) {
			gf_list_rem_last(parser->nodes);
			gf_free(top);
		} else if (top->node && top->node->sgprivate->tag == TAG_ProtoNode) {
			if (!strcmp(name, "node") || !strcmp(name, "nodes")) {
				top->container_field.far_ptr = NULL;
				top->container_field.name = NULL;
				top->last = NULL;
			} else if (!strcmp(name, "ProtoInstance")) {
				gf_list_rem_last(parser->nodes);
				node = top->node;
				gf_free(top);
				goto attach_node;
			}
		}
	} else if (top->node->sgprivate->tag==tag) {
		node = top->node;
		gf_list_rem_last(parser->nodes);
		gf_free(top);

attach_node:
		top = (XMTNodeStack*)gf_list_last(parser->nodes);
		/*add node to command*/
		if (!top || (top->container_field.fieldType==GF_SG_VRML_SFCOMMANDBUFFER)) {
			if (parser->doc_type == 1) {
				GF_CommandField *inf;
				Bool single_node = 0;
				assert(parser->command);
				switch (parser->command->tag) {
				case GF_SG_SCENE_REPLACE:
					if (parser->parsing_proto) {
						gf_sg_proto_add_node_code(parser->parsing_proto, node);
						gf_node_register(node, NULL);
					} else if (!parser->command->node) {
						parser->command->node = node;
						gf_node_register(node, NULL);
					} else if (parser->command->node != node) {
						xmt_report(parser, GF_OK, "Warning: top-node already assigned - discarding node %s", name);
						gf_node_register(node, NULL);
						gf_node_unregister(node, NULL);
					}
					break;
				case GF_SG_GLOBAL_QUANTIZER:
				case GF_SG_NODE_INSERT:
				case GF_SG_INDEXED_INSERT:
				case GF_SG_INDEXED_REPLACE:
					single_node = 1;
				case GF_SG_NODE_REPLACE:
				case GF_SG_FIELD_REPLACE:
				case GF_SG_MULTIPLE_REPLACE:
					inf = (GF_CommandField*)gf_list_last(parser->command->command_fields);
					if (!inf) {
						inf = gf_sg_command_field_new(parser->command);
						inf->fieldType = GF_SG_VRML_SFNODE;
					}
					if ((inf->fieldType==GF_SG_VRML_MFNODE) && !inf->node_list) {
						inf->field_ptr = &inf->node_list;
						if (inf->new_node) {
							gf_node_list_add_child(& inf->node_list, inf->new_node);
							inf->new_node = NULL;
						}
					}

					if (inf->new_node) {
						if (single_node) {
							gf_node_unregister(inf->new_node, NULL);
						} else {
							inf->field_ptr = &inf->node_list;
							gf_node_list_add_child(& inf->node_list, inf->new_node);
							inf->fieldType = GF_SG_VRML_MFNODE;
						}
						inf->new_node = NULL;
					}
					gf_node_register(node, NULL);
					if (inf->node_list) {
						gf_node_list_add_child(& inf->node_list, node);
					} else {
						inf->new_node = node;
						inf->field_ptr = &inf->new_node;
					}
					break;
				case GF_SG_PROTO_INSERT:
					if (parser->parsing_proto) {
						gf_sg_proto_add_node_code(parser->parsing_proto, node);
						gf_node_register(node, NULL);
						break;
					}
				default:
					xmt_report(parser, GF_OK, "Warning: node %s defined outside scene scope - skipping", name);
					gf_node_register(node, NULL);
					gf_node_unregister(node, NULL);
					break;

				}
			}
			/*X3D*/
			else if (parser->doc_type == 2) {
				if (parser->parsing_proto) {
					gf_sg_proto_add_node_code(parser->parsing_proto, node);
					gf_node_register(node, NULL);
				} else {
					M_Group *gr = (M_Group *)gf_sg_get_root_node(parser->load->scene_graph);
					if (!gr) {
						xmt_report(parser, GF_OK, "Warning: node %s defined outside scene scope - skipping", name);
						gf_node_register(node, NULL);
						gf_node_unregister(node, NULL);
					} else {
						//node has already been added to its parent with X3d parsing, because of the default container resolving
//						gf_node_list_add_child(& gr->children, node);
//						gf_node_register(node, NULL);
					}
				}
			}
			/*special case: replace scene has already been applied (progressive loading)*/
			else if ((parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) && (parser->load->scene_graph->RootNode!=node) ) {
				gf_node_register(node, NULL);
			} else {
				xmt_report(parser, GF_OK, "Warning: node %s defined outside scene scope - skipping", name);
				gf_node_register(node, NULL);
				gf_node_unregister(node, NULL);
			}
		}
		if (parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) {
			/*load scripts*/
			if (!parser->parsing_proto) {
				if ((tag==TAG_MPEG4_Script)
#ifndef GPAC_DISABLE_X3D
				        || (tag==TAG_X3D_Script)
#endif
				   ) {
					/*it may happen that the script uses itself as a field (not sure this is compliant since this
					implies a cyclic structure, but happens in some X3D conformance seq)*/
					if (!top || (top->node != node)) {
						if (parser->command) {
							if (!parser->command->scripts_to_load) parser->command->scripts_to_load = gf_list_new();
							gf_list_add(parser->command->scripts_to_load, node);
						}
						/*do not load script until all routes are established!!*/
						else if (parser->doc_type==2) {
							gf_list_add(parser->script_to_load, node);
						} else {
							gf_sg_script_load(node);
						}
					}
				}
			}
		}
	} else if (parser->current_node_tag==tag) {
		gf_list_rem_last(parser->nodes);
		gf_free(top);
	} else {
		xmt_report(parser, GF_OK, "Warning: closing element %s doesn't match created node %s", name, gf_node_get_class_name(top->node) );
	}
}