📄 svg_parser.c
字号:
local_de.animation_elt = elt; } } /* For anchor elements, we try to resolve the target element; if are not able to determine the target, we put the element in a list for future processing (each time a new id is defined, we try to resolve the defered elements) */ if (is_svg_anchor_tag(tag)) { /* Parsing the xlink:href attribute */ Bool xlink_href_found = 0; attribute_index=0; memset(&local_de, 0, sizeof(defered_element)); local_de.parent = parent; if (attrs) while (attrs[attribute_index]!=NULL) { if (stricmp(attrs[attribute_index],"xlink:href")==0) { GF_FieldInfo xlink_href_info; gf_node_get_field_by_name((GF_Node *)elt, "xlink:href", &xlink_href_info); gf_svg_parse_attribute((GF_Node *)elt, &xlink_href_info, (char *)attrs[attribute_index+1], 0, 0); break; } attribute_index+=2; } if (!xlink_href_found) { local_de.target = parent; } } /* Parsing all the other attributes, with a special case of id */ attribute_index=0; if (attrs) while (attrs[attribute_index]) { if (!stricmp(attrs[attribute_index], "id")) { svg_parse_element_id(parser, elt, (xmlChar *)attrs[attribute_index+1]); ided = 1; } else if (!stricmp(attrs[attribute_index], "attributeName")) { if (de) de->attributeName = strdup(attrs[attribute_index+1]); else local_de.attributeName = strdup(attrs[attribute_index+1]); } else if (!stricmp(attrs[attribute_index], "to")) { if (de) de->to = strdup(attrs[attribute_index+1]); else local_de.to = strdup(attrs[attribute_index+1]); } else if (!stricmp(attrs[attribute_index], "from")) { if (de) de->from = strdup(attrs[attribute_index+1]); else local_de.from = strdup(attrs[attribute_index+1]); } else if (!stricmp(attrs[attribute_index], "by")) { if (de) de->by = strdup(attrs[attribute_index+1]); else local_de.by = strdup(attrs[attribute_index+1]); } else if (!stricmp(attrs[attribute_index], "values")) { if (de) de->values = strdup(attrs[attribute_index+1]); else local_de.values = strdup(attrs[attribute_index+1]); } else if (!stricmp(attrs[attribute_index], "type")) { if (tag == TAG_SVG_animateTransform) { if (de) de->type = strdup(attrs[attribute_index+1]); else local_de.type = strdup(attrs[attribute_index+1]); } else { GF_FieldInfo info; if (!gf_node_get_field_by_name((GF_Node *)elt, "type", &info)) { gf_svg_parse_attribute((GF_Node *)elt, &info, (xmlChar *)attrs[attribute_index+1], 0, 0); } } } else if (!stricmp(attrs[attribute_index], "language")) { // TODO process this attribute (for scripts) } else if (!stricmp(attrs[attribute_index], "xlink:href")) { if (is_svg_animation_tag(tag)) { /* already dealt with above */ } else { GF_FieldInfo info; if (!gf_node_get_field_by_name((GF_Node *)elt, "xlink:href", &info)) { gf_svg_parse_attribute((GF_Node *)elt, &info, (xmlChar *)attrs[attribute_index+1], 0, 0); } } } else { GF_FieldInfo info; u32 evtType = gf_dom_event_type_by_name((char *) (char *)attrs[attribute_index] + 2); if (evtType != GF_EVENT_UNKNOWN) { SVG_SA_handlerElement *handler; handler = gf_dom_listener_build((GF_Node *) elt, evtType, 0, NULL); handler->textContent = strdup((char *)attrs[attribute_index+1]); gf_node_init((GF_Node *)handler); } else if (!gf_node_get_field_by_name((GF_Node *)elt, (char *)attrs[attribute_index], &info)) { gf_svg_parse_attribute((GF_Node *)elt, &info, (xmlChar *)attrs[attribute_index+1], 0, 0); } else { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG] Unknown attribute %s on element %s\n", (char *)attrs[attribute_index], gf_node_get_class_name((GF_Node *)elt) )); } } attribute_index+=2; } if (!de && is_svg_animation_tag(tag)) svg_parse_sax_defered_animation(parser, elt, local_de); /* if the new element has an id, we try to resolve defered references */ if (ided) { defered_element *previous_de; const char *new_id = gf_node_get_name((GF_Node *)elt); /* dichotomic search in the sorted list of defered animation elements */ previous_de = list_dichotomic_search(parser->defered_animation_elements, new_id, NULL); if (previous_de) { /* defered element 'previous_de' can be resolved by the new elt */ svg_parse_sax_defered_animation(parser, previous_de->animation_elt, *previous_de); } /* defered references for anchor */ { u32 i; u32 count = gf_list_count(parser->unresolved_hrefs); for (i=0; i<count; i++) { href_instance *hi = gf_list_get(parser->unresolved_hrefs, i); if (hi) { SVG_IRI *iri = hi->iri; GF_Node *targ = gf_sg_find_node_by_name(parser->graph, &(iri->iri[1])); if (iri->target) { hi->elt->xlink->href.type = SVG_IRI_ELEMENTID; hi->elt->xlink->href.target = (SVG_SA_Element *)targ; gf_svg_register_iri(parser->graph, &hi->elt->xlink->href); gf_node_init((GF_Node *)hi->elt); gf_list_rem(parser->unresolved_hrefs, i); } } } } } /* We need to init the node at the end of the parsing, after parsing all attributes */ if (!is_svg_animation_tag(tag) && elt) { GF_DOM_Event evt; /*init node*/ gf_node_init((GF_Node *)elt); /*fire initialization event*/ memset(&evt, 0, sizeof(GF_DOM_Event)); evt.type = GF_EVENT_LOAD; gf_dom_event_fire((GF_Node *) elt, NULL, &evt); } return elt;}/* SAX end *//* Constructors and Desctructos of the SVG Parser */SVGParser *NewSVGParser(){ SVGParser *tmp; GF_SAFEALLOC(tmp, SVGParser); return tmp;}void SVGParser_Terminate(SVGParser *parser){ /* there is no more input, indicate the parsing is finished. Is this needed ? xmlParseChunk(ctxt, inputbuffer, 0, 1); */ /* destroy the SAX parser context and file. */ if (parser->sax_handler) free(parser->sax_handler); if (parser->sax_ctx) xmlFreeParserCtxt(parser->sax_ctx); if (parser->sax_file) fclose(parser->sax_file); if (xmllib_is_init) xmlCleanupParser(); xmllib_is_init = 0; gf_list_del(parser->ided_nodes); gf_list_del(parser->unresolved_timing_elements); gf_list_del(parser->unresolved_hrefs); gf_list_del(parser->defered_animation_elements); if (parser->entities) gf_list_del(parser->entities); if (parser->svg_node_stack) gf_list_del(parser->svg_node_stack); if (parser->file_name) free(parser->file_name); free(parser);}static void SVGParser_InitAllParsers(SVGParser *parser){ /* Scene Graph related code */ parser->ided_nodes = gf_list_new(); /* List of elements to be resolved after parsing but before rendering */ parser->unresolved_timing_elements = gf_list_new(); /* xlink:href attributes */ parser->unresolved_hrefs = gf_list_new(); /* defered animation elements */ parser->defered_animation_elements = gf_list_new();}/* Full DOM Parsing and Progressive Parsing functions */GF_Err SVGParser_ParseFullDoc(SVGParser *parser){ xmlDocPtr doc = NULL; xmlNodePtr root = NULL; SVG_SA_Element *n; //u32 d; /* XML Related code */ if (!xmllib_is_init) { xmlInitParser(); LIBXML_TEST_VERSION xmllib_is_init=1; } doc = xmlParseFile(parser->file_name); if (doc == NULL) return GF_BAD_PARAM; root = xmlDocGetRootElement(doc); SVGParser_InitAllParsers(parser); n = svg_parse_dom_element(parser, root, NULL); if (n) svg_init_root_element(parser, (SVG_SA_svgElement *)n); /* Resolve time elements */ while (gf_list_count(parser->unresolved_timing_elements) > 0) { SMIL_Time *v = gf_list_get(parser->unresolved_timing_elements, 0); gf_list_rem(parser->unresolved_timing_elements, 0); v->element = gf_sg_find_node_by_name(parser->graph, v->element_id); if (v->element) { free(v->element_id); v->element_id = NULL; } } /* Resolve hrefs */ while (gf_list_count(parser->unresolved_hrefs) > 0) { href_instance *hi = gf_list_get(parser->unresolved_hrefs, 0); SVG_IRI *iri = hi->iri; GF_Node *targ = gf_sg_find_node_by_name(parser->graph, &(iri->iri[1])); gf_list_rem(parser->unresolved_hrefs, 0); if (targ) { hi->elt->xlink->href.type = SVG_IRI_ELEMENTID; hi->elt->xlink->href.target = (SVG_SA_Element *)targ; gf_svg_register_iri(parser->graph, &hi->elt->xlink->href); if (iri->iri) free(iri->iri); iri->iri = NULL; } } while (gf_list_count(parser->defered_animation_elements)) { defered_element *de = gf_list_get(parser->defered_animation_elements, 0); gf_list_rem(parser->defered_animation_elements, 0); svg_parse_dom_defered_animations(parser, de->node, de->animation_elt, de->parent); free(de); } //scanf("%d", &d); xmlFreeDoc(doc); //scanf("%d", &d); return GF_OK;}static void SVGParser_InitSaxHandler(SVGParser *parser){ GF_SAFEALLOC(parser->sax_handler, xmlSAXHandler) parser->sax_handler->startDocument = svg_start_document; parser->sax_handler->endDocument = svg_end_document; parser->sax_handler->characters = svg_characters; parser->sax_handler->endElement = svg_end_element; parser->sax_handler->startElement = svg_start_element; parser->sax_handler->getEntity = svg_get_entity; parser->sax_handler->entityDecl = svg_entity_decl; parser->sax_handler->cdataBlock = svg_cdata_block;}GF_Err SVGParser_InitProgressiveFileChunk(SVGParser *parser){ char inputbuffer[SAX_MAX_CHARS]; s32 len; /* XML Related code */ if (!xmllib_is_init) { xmlInitParser(); LIBXML_TEST_VERSION xmllib_is_init=1; } parser->sax_file = fopen(parser->file_name, "rb"); if (parser->sax_file == NULL) return GF_IO_ERR; parser->sax_state = UNDEF; SVGParser_InitAllParsers(parser); SVGParser_InitSaxHandler(parser); /* Read a few first byte to check the input used for the * encoding detection at the parser level. */ len = fread(inputbuffer, 1, 4, parser->sax_file); if (len != 4) return GF_OK; parser->nb_bytes_read = len; /* Create a progressive parsing context, the 2 first arguments * are not used since we want to build a tree and not use a SAX * parsing interface. We also pass the first bytes of the document * to allow encoding detection when creating the parser but this * is optional. */ parser->sax_ctx = xmlCreatePushParserCtxt(parser->sax_handler, parser, inputbuffer, len, NULL); /* TODO setup a better error value and verify cleanup: fclose... */ if (parser->sax_ctx == NULL) return GF_IO_ERR; return GF_OK;}GF_Err SVGParser_ParseProgressiveFileChunk(SVGParser *parser){ u32 read_bytes, entry_time, diff; char inputbuffer[SAX_MAX_CHARS]; if (!parser->sax_ctx) return GF_OK; entry_time = gf_sys_clock(); fseek(parser->sax_file, parser->nb_bytes_read, SEEK_SET); while (1) { read_bytes = fread(inputbuffer, 1, SAX_MAX_CHARS, parser->sax_file); if (read_bytes > 0) { xmlParseChunk(parser->sax_ctx, inputbuffer, read_bytes, 0); parser->nb_bytes_read += read_bytes; } if (parser->sax_state == FINISHSVG) return GF_EOS; if (parser->sax_state == ERROR) return GF_IO_ERR; if (parser->load_type == SVG_LOAD_SAX_PROGRESSIVE) { diff = gf_sys_clock() - entry_time; if (diff > parser->sax_max_duration) return GF_OK; } } return GF_OK;}GF_Err SVGParser_ParseMemoryFirstChunk(SVGParser *parser, unsigned char *inBuffer, u32 inBufferLength){ /* XML Related code */ if (!xmllib_is_init) { xmlInitParser(); LIBXML_TEST_VERSION xmllib_is_init=1; } parser->sax_state = UNDEF; SVGParser_InitAllParsers(parser); SVGParser_InitSaxHandler(parser); /* Create a progressive parsing context, the 2 first arguments * are not used since we want to build a tree and not use a SAX * parsing interface. We also pass the first bytes of the document * to allow encoding detection when creating the parser but this * is optional. */ parser->sax_ctx = xmlCreatePushParserCtxt(parser->sax_handler, parser, inBuffer, 4, NULL); /* TODO setup a better error value and verify cleanup: fclose... */ if (parser->sax_ctx == NULL) return GF_IO_ERR; if (inBufferLength > 4) return SVGParser_ParseMemoryNextChunk(parser, inBuffer+4, inBufferLength-4); return GF_OK;}GF_Err SVGParser_ParseMemoryNextChunk(SVGParser *parser, unsigned char *inBuffer, u32 inBufferLength){ if (!parser->sax_ctx) return GF_OK; xmlParseChunk(parser->sax_ctx, inBuffer, inBufferLength, 0); if (parser->sax_state == FINISHSVG) return GF_EOS; if (parser->sax_state == ERROR) return GF_IO_ERR; return GF_OK;}/* The rest of the file is required for DANAE but not used in GPAC */struct danae_parser { u32 type; // 0 = SVG, 1 = LSR void *parser;};void *DANAE_NewSVGParser(char *filename, void *scene_graph){ struct danae_parser *dp; char *ext; if (!filename || !scene_graph) return NULL; if ((ext = strrchr(filename, '.')) == NULL) return NULL; dp = malloc(sizeof(struct danae_parser)); if (!strcmp(ext, ".svg")) { dp->type = 0; dp->parser = NewSVGParser(); ((SVGParser *)dp->parser)->oti = SVGLOADER_OTI_SVG; ((SVGParser *)dp->parser)->file_name = strdup(filename); ((SVGParser *)dp->parser)->graph = scene_graph; } else if (!strcmp(ext, ".xsr")) { dp->type = 0; dp->parser = NewSVGParser(); ((SVGParser *)dp->parser)->oti = SVGLOADER_OTI_LASERML; ((SVGParser *)dp->parser)->file_name = strdup(filename); ((SVGParser *)dp->parser)->graph = scene_graph; } else if (!strcmp(ext, ".lsr")) { dp->type = 1; } return dp;}void DANAE_SVGParser_Parse(void *p){ struct danae_parser *dp = (struct danae_parser *)p; if (!dp->type) { if (((SVGParser *)dp->parser)->oti == SVGLOADER_OTI_SVG) { SVGParser_ParseFullDoc(dp->parser); } else if (((SVGParser *)dp->parser)->oti == SVGLOADER_OTI_LASERML) { SVGParser_ParseLASeR(dp->parser); } } }void DANAE_SVGParser_Terminate(void *p){}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -